...

Source file src/golang.org/x/mod/modfile/work_test.go

Documentation: golang.org/x/mod/modfile

     1  // Copyright 2021 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package modfile
     6  
     7  import (
     8  	"bytes"
     9  	"os"
    10  	"path/filepath"
    11  	"strings"
    12  	"testing"
    13  )
    14  
    15  // TODO(#45713): Update these tests once AddUse sets the module path.
    16  var workAddUseTests = []struct {
    17  	desc       string
    18  	in         string
    19  	path       string
    20  	modulePath string
    21  	out        string
    22  }{
    23  	{
    24  		`empty`,
    25  		``,
    26  		`foo`, `bar`,
    27  		`use foo`,
    28  	},
    29  	{
    30  		`go_stmt_only`,
    31  		`go 1.17
    32  		`,
    33  		`foo`, `bar`,
    34  		`go 1.17
    35  		use foo
    36  		`,
    37  	},
    38  	{
    39  		`use_line_present`,
    40  		`go 1.17
    41  		use baz`,
    42  		`foo`, `bar`,
    43  		`go 1.17
    44  		use (
    45  			baz
    46  		  foo
    47  		)
    48  		`,
    49  	},
    50  	{
    51  		`use_block_present`,
    52  		`go 1.17
    53  		use (
    54  			baz
    55  			quux
    56  		)
    57  		`,
    58  		`foo`, `bar`,
    59  		`go 1.17
    60  		use (
    61  			baz
    62  		  quux
    63  			foo
    64  		)
    65  		`,
    66  	},
    67  	{
    68  		`use_and_replace_present`,
    69  		`go 1.17
    70  		use baz
    71  		replace a => ./b
    72  		`,
    73  		`foo`, `bar`,
    74  		`go 1.17
    75  		use (
    76  			baz
    77  			foo
    78  		)
    79  		replace a => ./b
    80  		`,
    81  	},
    82  }
    83  
    84  var workDropUseTests = []struct {
    85  	desc string
    86  	in   string
    87  	path string
    88  	out  string
    89  }{
    90  	{
    91  		`empty`,
    92  		``,
    93  		`foo`,
    94  		``,
    95  	},
    96  	{
    97  		`go_stmt_only`,
    98  		`go 1.17
    99  		`,
   100  		`foo`,
   101  		`go 1.17
   102  		`,
   103  	},
   104  	{
   105  		`single_use`,
   106  		`go 1.17
   107  		use foo`,
   108  		`foo`,
   109  		`go 1.17
   110  		`,
   111  	},
   112  	{
   113  		`use_block`,
   114  		`go 1.17
   115  		use (
   116  			foo
   117  			bar
   118  			baz
   119  		)`,
   120  		`bar`,
   121  		`go 1.17
   122  		use (
   123  			foo
   124  			baz
   125  		)`,
   126  	},
   127  	{
   128  		`use_multi`,
   129  		`go 1.17
   130  		use (
   131  			foo
   132  			bar
   133  			baz
   134  		)
   135  		use foo
   136  		use quux
   137  		use foo`,
   138  		`foo`,
   139  		`go 1.17
   140  		use (
   141  			bar
   142  			baz
   143  		)
   144  		use quux`,
   145  	},
   146  }
   147  
   148  var workAddGoTests = []struct {
   149  	desc    string
   150  	in      string
   151  	version string
   152  	out     string
   153  }{
   154  	{
   155  		`empty`,
   156  		``,
   157  		`1.17`,
   158  		`go 1.17
   159  		`,
   160  	},
   161  	{
   162  		`comment`,
   163  		`// this is a comment`,
   164  		`1.17`,
   165  		`// this is a comment
   166  
   167  		go 1.17`,
   168  	},
   169  	{
   170  		`use_after_replace`,
   171  		`
   172  		replace example.com/foo => ../bar
   173  		use foo
   174  		`,
   175  		`1.17`,
   176  		`
   177  		go 1.17
   178  		replace example.com/foo => ../bar
   179  		use foo
   180  		`,
   181  	},
   182  	{
   183  		`use_before_replace`,
   184  		`use foo
   185  		replace example.com/foo => ../bar
   186  		`,
   187  		`1.17`,
   188  		`
   189  		go 1.17
   190  		use foo
   191  		replace example.com/foo => ../bar
   192  		`,
   193  	},
   194  	{
   195  		`use_only`,
   196  		`use foo
   197  		`,
   198  		`1.17`,
   199  		`
   200  		go 1.17
   201  		use foo
   202  		`,
   203  	},
   204  	{
   205  		`already_have_go`,
   206  		`go 1.17
   207  		`,
   208  		`1.18`,
   209  		`
   210  		go 1.18
   211  		`,
   212  	},
   213  }
   214  
   215  var workAddToolchainTests = []struct {
   216  	desc    string
   217  	in      string
   218  	version string
   219  	out     string
   220  }{
   221  	{
   222  		`empty`,
   223  		``,
   224  		`go1.17`,
   225  		`toolchain go1.17
   226  		`,
   227  	},
   228  	{
   229  		`aftergo`,
   230  		`// this is a comment
   231  		use foo
   232  
   233  		go 1.17
   234  
   235  		use bar
   236  		`,
   237  		`go1.17`,
   238  		`// this is a comment
   239  		use foo
   240  
   241  		go 1.17
   242  
   243  		toolchain go1.17
   244  
   245  		use bar
   246  		`,
   247  	},
   248  	{
   249  		`already_have_toolchain`,
   250  		`go 1.17
   251  
   252  		toolchain go1.18
   253  		`,
   254  		`go1.19`,
   255  		`go 1.17
   256  
   257  		toolchain go1.19
   258  		`,
   259  	},
   260  }
   261  
   262  var workSortBlocksTests = []struct {
   263  	desc, in, out string
   264  }{
   265  	{
   266  		`use_duplicates_not_removed`,
   267  		`go 1.17
   268  		use foo
   269  		use bar
   270  		use (
   271  			foo
   272  		)`,
   273  		`go 1.17
   274  		use foo
   275  		use bar
   276  		use (
   277  			foo
   278  		)`,
   279  	},
   280  	{
   281  		`replace_duplicates_removed`,
   282  		`go 1.17
   283  		use foo
   284  		replace x.y/z v1.0.0 => ./a
   285  		replace x.y/z v1.1.0 => ./b
   286  		replace (
   287  			x.y/z v1.0.0 => ./c
   288  		)
   289  		`,
   290  		`go 1.17
   291  		use foo
   292  		replace x.y/z v1.1.0 => ./b
   293  		replace (
   294  			x.y/z v1.0.0 => ./c
   295  		)
   296  		`,
   297  	},
   298  }
   299  
   300  func TestAddUse(t *testing.T) {
   301  	for _, tt := range workAddUseTests {
   302  		t.Run(tt.desc, func(t *testing.T) {
   303  			testWorkEdit(t, tt.in, tt.out, func(f *WorkFile) error {
   304  				return f.AddUse(tt.path, tt.modulePath)
   305  			})
   306  		})
   307  	}
   308  }
   309  
   310  func TestDropUse(t *testing.T) {
   311  	for _, tt := range workDropUseTests {
   312  		t.Run(tt.desc, func(t *testing.T) {
   313  			testWorkEdit(t, tt.in, tt.out, func(f *WorkFile) error {
   314  				if err := f.DropUse(tt.path); err != nil {
   315  					return err
   316  				}
   317  				f.Cleanup()
   318  				return nil
   319  			})
   320  		})
   321  	}
   322  }
   323  
   324  func TestWorkAddGo(t *testing.T) {
   325  	for _, tt := range workAddGoTests {
   326  		t.Run(tt.desc, func(t *testing.T) {
   327  			testWorkEdit(t, tt.in, tt.out, func(f *WorkFile) error {
   328  				return f.AddGoStmt(tt.version)
   329  			})
   330  		})
   331  	}
   332  }
   333  
   334  func TestWorkAddToolchain(t *testing.T) {
   335  	for _, tt := range workAddToolchainTests {
   336  		t.Run(tt.desc, func(t *testing.T) {
   337  			testWorkEdit(t, tt.in, tt.out, func(f *WorkFile) error {
   338  				return f.AddToolchainStmt(tt.version)
   339  			})
   340  		})
   341  	}
   342  }
   343  
   344  func TestWorkSortBlocks(t *testing.T) {
   345  	for _, tt := range workSortBlocksTests {
   346  		t.Run(tt.desc, func(t *testing.T) {
   347  			testWorkEdit(t, tt.in, tt.out, func(f *WorkFile) error {
   348  				f.SortBlocks()
   349  				return nil
   350  			})
   351  		})
   352  	}
   353  }
   354  
   355  // Test that when files in the testdata directory are parsed
   356  // and printed and parsed again, we get the same parse tree
   357  // both times.
   358  func TestWorkPrintParse(t *testing.T) {
   359  	outs, err := filepath.Glob("testdata/work/*")
   360  	if err != nil {
   361  		t.Fatal(err)
   362  	}
   363  	for _, out := range outs {
   364  		out := out
   365  		name := filepath.Base(out)
   366  		t.Run(name, func(t *testing.T) {
   367  			t.Parallel()
   368  			data, err := os.ReadFile(out)
   369  			if err != nil {
   370  				t.Fatal(err)
   371  			}
   372  
   373  			base := "testdata/work/" + filepath.Base(out)
   374  			f, err := parse(base, data)
   375  			if err != nil {
   376  				t.Fatalf("parsing original: %v", err)
   377  			}
   378  
   379  			ndata := Format(f)
   380  			f2, err := parse(base, ndata)
   381  			if err != nil {
   382  				t.Fatalf("parsing reformatted: %v", err)
   383  			}
   384  
   385  			eq := eqchecker{file: base}
   386  			if err := eq.check(f, f2); err != nil {
   387  				t.Errorf("not equal (parse/Format/parse): %v", err)
   388  			}
   389  
   390  			pf1, err := ParseWork(base, data, nil)
   391  			if err != nil {
   392  				t.Errorf("should parse %v: %v", base, err)
   393  			}
   394  			if err == nil {
   395  				pf2, err := ParseWork(base, ndata, nil)
   396  				if err != nil {
   397  					t.Fatalf("Parsing reformatted: %v", err)
   398  				}
   399  				eq := eqchecker{file: base}
   400  				if err := eq.check(pf1, pf2); err != nil {
   401  					t.Errorf("not equal (parse/Format/Parse): %v", err)
   402  				}
   403  
   404  				ndata2 := Format(pf1.Syntax)
   405  				pf3, err := ParseWork(base, ndata2, nil)
   406  				if err != nil {
   407  					t.Fatalf("Parsing reformatted2: %v", err)
   408  				}
   409  				eq = eqchecker{file: base}
   410  				if err := eq.check(pf1, pf3); err != nil {
   411  					t.Errorf("not equal (Parse/Format/Parse): %v", err)
   412  				}
   413  				ndata = ndata2
   414  			}
   415  
   416  			if strings.HasSuffix(out, ".in") {
   417  				golden, err := os.ReadFile(strings.TrimSuffix(out, ".in") + ".golden")
   418  				if err != nil {
   419  					t.Fatal(err)
   420  				}
   421  				if !bytes.Equal(ndata, golden) {
   422  					t.Errorf("formatted %s incorrectly: diff shows -golden, +ours", base)
   423  					tdiff(t, string(golden), string(ndata))
   424  					return
   425  				}
   426  			}
   427  		})
   428  	}
   429  }
   430  
   431  func testWorkEdit(t *testing.T, in, want string, transform func(f *WorkFile) error) *WorkFile {
   432  	t.Helper()
   433  	parse := ParseWork
   434  	f, err := parse("in", []byte(in), nil)
   435  	if err != nil {
   436  		t.Fatal(err)
   437  	}
   438  	g, err := parse("out", []byte(want), nil)
   439  	if err != nil {
   440  		t.Fatal(err)
   441  	}
   442  	golden := Format(g.Syntax)
   443  
   444  	if err := transform(f); err != nil {
   445  		t.Fatal(err)
   446  	}
   447  	out := Format(f.Syntax)
   448  	if err != nil {
   449  		t.Fatal(err)
   450  	}
   451  	if !bytes.Equal(out, golden) {
   452  		t.Errorf("have:\n%s\nwant:\n%s", out, golden)
   453  	}
   454  
   455  	return f
   456  }
   457  

View as plain text