...

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

Documentation: golang.org/x/mod/modfile

     1  // Copyright 2018 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  	"fmt"
    10  	"strings"
    11  	"testing"
    12  
    13  	"golang.org/x/mod/module"
    14  )
    15  
    16  var addRequireTests = []struct {
    17  	desc string
    18  	in   string
    19  	path string
    20  	vers string
    21  	out  string
    22  }{
    23  	{
    24  		`existing`,
    25  		`
    26  		module m
    27  		require x.y/z v1.2.3
    28  		`,
    29  		"x.y/z", "v1.5.6",
    30  		`
    31  		module m
    32  		require x.y/z v1.5.6
    33  		`,
    34  	},
    35  	{
    36  		`existing2`,
    37  		`
    38  		module m
    39  		require (
    40  			x.y/z v1.2.3 // first
    41  			x.z/a v0.1.0 // first-a
    42  		)
    43  		require x.y/z v1.4.5 // second
    44  		require (
    45  			x.y/z v1.6.7 // third
    46  			x.z/a v0.2.0 // third-a
    47  		)
    48  		`,
    49  		"x.y/z", "v1.8.9",
    50  		`
    51  		module m
    52  
    53  		require (
    54  			x.y/z v1.8.9 // first
    55  			x.z/a v0.1.0 // first-a
    56  		)
    57  
    58  		require x.z/a v0.2.0 // third-a
    59  		`,
    60  	},
    61  	{
    62  		`new`,
    63  		`
    64  		module m
    65  		require x.y/z v1.2.3
    66  		`,
    67  		"x.y/w", "v1.5.6",
    68  		`
    69  		module m
    70  		require (
    71  			x.y/z v1.2.3
    72  			x.y/w v1.5.6
    73  		)
    74  		`,
    75  	},
    76  	{
    77  		`new2`,
    78  		`
    79  		module m
    80  		require x.y/z v1.2.3
    81  		require x.y/q/v2 v2.3.4
    82  		`,
    83  		"x.y/w", "v1.5.6",
    84  		`
    85  		module m
    86  		require x.y/z v1.2.3
    87  		require (
    88  			x.y/q/v2 v2.3.4
    89  			x.y/w v1.5.6
    90  		)
    91  		`,
    92  	},
    93  	{
    94  		`unattached_comments`,
    95  		`
    96  		module m
    97  		require (
    98  			foo v0.0.0-00010101000000-000000000000
    99  			// bar v0.0.0-00010101000000-000000000000
   100  		)
   101  		`,
   102  		"foo", "v0.0.0-00010101000000-000000000000",
   103  		`
   104  		module m
   105  		require (
   106  			foo v0.0.0-00010101000000-000000000000
   107  			// bar v0.0.0-00010101000000-000000000000
   108  		)
   109  		`,
   110  	},
   111  }
   112  
   113  type require struct {
   114  	path, vers string
   115  	indirect   bool
   116  }
   117  
   118  var setRequireTests = []struct {
   119  	desc string
   120  	in   string
   121  	mods []require
   122  	out  string
   123  }{
   124  	{
   125  		`https://golang.org/issue/45932`,
   126  		`module m
   127  		require (
   128  			x.y/a v1.2.3 //indirect
   129  			x.y/b v1.2.3
   130  			x.y/c v1.2.3
   131  		)
   132  		`,
   133  		[]require{
   134  			{"x.y/a", "v1.2.3", false},
   135  			{"x.y/b", "v1.2.3", false},
   136  			{"x.y/c", "v1.2.3", false},
   137  		},
   138  		`module m
   139  		require (
   140  			x.y/a v1.2.3
   141  			x.y/b v1.2.3
   142  			x.y/c v1.2.3
   143  		)
   144  		`,
   145  	},
   146  	{
   147  		`existing`,
   148  		`module m
   149  		require (
   150  			x.y/b v1.2.3
   151  
   152  			x.y/a v1.2.3
   153  			x.y/d v1.2.3
   154  		)
   155  		`,
   156  		[]require{
   157  			{"x.y/a", "v1.2.3", false},
   158  			{"x.y/b", "v1.2.3", false},
   159  			{"x.y/c", "v1.2.3", false},
   160  		},
   161  		`module m
   162  		require (
   163  			x.y/a v1.2.3
   164  			x.y/b v1.2.3
   165  			x.y/c v1.2.3
   166  		)
   167  		`,
   168  	},
   169  	{
   170  		`existing_indirect`,
   171  		`module m
   172  		require (
   173  			x.y/a v1.2.3
   174  			x.y/b v1.2.3 //
   175  			x.y/c v1.2.3 //c
   176  			x.y/d v1.2.3 //   c
   177  			x.y/e v1.2.3 // indirect
   178  			x.y/f v1.2.3 //indirect
   179  			x.y/g v1.2.3 //	indirect
   180  		)
   181  		`,
   182  		[]require{
   183  			{"x.y/a", "v1.2.3", true},
   184  			{"x.y/b", "v1.2.3", true},
   185  			{"x.y/c", "v1.2.3", true},
   186  			{"x.y/d", "v1.2.3", true},
   187  			{"x.y/e", "v1.2.3", true},
   188  			{"x.y/f", "v1.2.3", true},
   189  			{"x.y/g", "v1.2.3", true},
   190  		},
   191  		`module m
   192  		require (
   193  			x.y/a v1.2.3 // indirect
   194  			x.y/b v1.2.3 // indirect
   195  			x.y/c v1.2.3 // indirect; c
   196  			x.y/d v1.2.3 // indirect; c
   197  			x.y/e v1.2.3 // indirect
   198  			x.y/f v1.2.3 //indirect
   199  			x.y/g v1.2.3 //	indirect
   200  		)
   201  		`,
   202  	},
   203  	{
   204  		`existing_multi`,
   205  		`module m
   206  		require x.y/a v1.2.3
   207  		require x.y/b v1.2.3
   208  		require x.y/c v1.0.0 // not v1.2.3!
   209  		require x.y/d v1.2.3 // comment kept
   210  		require x.y/e v1.2.3 // comment kept
   211  		require x.y/f v1.2.3 // indirect
   212  		require x.y/g v1.2.3 // indirect
   213  		`,
   214  		[]require{
   215  			{"x.y/h", "v1.2.3", false},
   216  			{"x.y/a", "v1.2.3", false},
   217  			{"x.y/b", "v1.2.3", false},
   218  			{"x.y/c", "v1.2.3", false},
   219  			{"x.y/d", "v1.2.3", false},
   220  			{"x.y/e", "v1.2.3", true},
   221  			{"x.y/f", "v1.2.3", false},
   222  			{"x.y/g", "v1.2.3", false},
   223  		},
   224  		`module m
   225  		require x.y/a v1.2.3
   226  
   227  		require x.y/b v1.2.3
   228  
   229  		require x.y/c v1.2.3 // not v1.2.3!
   230  
   231  		require x.y/d v1.2.3 // comment kept
   232  
   233  		require x.y/e v1.2.3 // indirect; comment kept
   234  
   235  		require x.y/f v1.2.3
   236  
   237  		require (
   238  			x.y/g v1.2.3
   239  			x.y/h v1.2.3
   240  		)
   241  		`,
   242  	},
   243  	{
   244  		`existing_duplicate`,
   245  		`module m
   246  		require (
   247  			x.y/a v1.0.0 // zero
   248  			x.y/a v1.1.0 // one
   249  			x.y/a v1.2.3 // two
   250  		)
   251  		`,
   252  		[]require{
   253  			{"x.y/a", "v1.2.3", true},
   254  		},
   255  		`module m
   256  		require x.y/a v1.2.3 // indirect; zero
   257  		`,
   258  	},
   259  	{
   260  		`existing_duplicate_multi`,
   261  		`module m
   262  		require x.y/a v1.0.0 // zero
   263  		require x.y/a v1.1.0 // one
   264  		require x.y/a v1.2.3 // two
   265  		`,
   266  		[]require{
   267  			{"x.y/a", "v1.2.3", true},
   268  		},
   269  		`module m
   270  		require x.y/a v1.2.3 // indirect; zero
   271  		`,
   272  	},
   273  }
   274  
   275  var setRequireSeparateIndirectTests = []struct {
   276  	desc string
   277  	in   string
   278  	mods []require
   279  	out  string
   280  }{
   281  	{
   282  		`https://golang.org/issue/45932`,
   283  		`module m
   284  		require (
   285  			x.y/a v1.2.3 //indirect
   286  			x.y/b v1.2.3
   287  			x.y/c v1.2.3
   288  		)
   289  		`,
   290  		[]require{
   291  			{"x.y/a", "v1.2.3", false},
   292  			{"x.y/b", "v1.2.3", false},
   293  			{"x.y/c", "v1.2.3", false},
   294  		},
   295  		`module m
   296  		require (
   297  			x.y/a v1.2.3
   298  			x.y/b v1.2.3
   299  			x.y/c v1.2.3
   300  		)
   301  		`,
   302  	},
   303  	{
   304  		`existing`,
   305  		`module m
   306  		require (
   307  			x.y/b v1.2.3
   308  
   309  			x.y/a v1.2.3
   310  			x.y/d v1.2.3
   311  		)
   312  		`,
   313  		[]require{
   314  			{"x.y/a", "v1.2.3", false},
   315  			{"x.y/b", "v1.2.3", false},
   316  			{"x.y/c", "v1.2.3", false},
   317  		},
   318  		`module m
   319  		require (
   320  			x.y/a v1.2.3
   321  			x.y/b v1.2.3
   322  			x.y/c v1.2.3
   323  		)
   324  		`,
   325  	},
   326  	{
   327  		`existing_indirect`,
   328  		`module m
   329  		require (
   330  			x.y/a v1.2.3
   331  			x.y/b v1.2.3 //
   332  			x.y/c v1.2.3 //c
   333  			x.y/d v1.2.3 //   c
   334  			x.y/e v1.2.3 // indirect
   335  			x.y/f v1.2.3 //indirect
   336  			x.y/g v1.2.3 //	indirect
   337  		)
   338  		`,
   339  		[]require{
   340  			{"x.y/a", "v1.2.3", true},
   341  			{"x.y/b", "v1.2.3", true},
   342  			{"x.y/c", "v1.2.3", true},
   343  			{"x.y/d", "v1.2.3", true},
   344  			{"x.y/e", "v1.2.3", true},
   345  			{"x.y/f", "v1.2.3", true},
   346  			{"x.y/g", "v1.2.3", true},
   347  		},
   348  		`module m
   349  		require (
   350  			x.y/a v1.2.3 // indirect
   351  			x.y/b v1.2.3 // indirect
   352  			x.y/c v1.2.3 // indirect; c
   353  			x.y/d v1.2.3 // indirect; c
   354  			x.y/e v1.2.3 // indirect
   355  			x.y/f v1.2.3 //indirect
   356  			x.y/g v1.2.3 //	indirect
   357  		)
   358  		`,
   359  	},
   360  	{
   361  		`existing_line`,
   362  		`module m
   363  		require x.y/a v1.0.0
   364  		require x.y/c v1.0.0 // indirect
   365  		`,
   366  		[]require{
   367  			{"x.y/a", "v1.2.3", false},
   368  			{"x.y/b", "v1.2.3", false},
   369  			{"x.y/c", "v1.2.3", true},
   370  			{"x.y/d", "v1.2.3", true},
   371  		},
   372  		`module m
   373  		require (
   374  			x.y/a v1.2.3
   375  			x.y/b v1.2.3
   376  		)
   377  		require (
   378  			x.y/c v1.2.3 // indirect
   379  			x.y/d v1.2.3 // indirect
   380  		)`,
   381  	},
   382  	{
   383  		`existing_multi`,
   384  		`module m
   385  		require x.y/a v1.2.3
   386  		require x.y/b v1.2.3 // demoted to indirect
   387  		require x.y/c v1.0.0 // not v1.2.3!
   388  		require x.y/d v1.2.3 // comment kept
   389  		require x.y/e v1.2.3 // comment kept
   390  		require x.y/f v1.2.3 // indirect; promoted to direct
   391  		// promoted to direct
   392  		require x.y/g v1.2.3 // indirect
   393  		require x.y/i v1.2.3 // indirect
   394  		require x.y/j v1.2.3 // indirect
   395  		`,
   396  		[]require{
   397  			{"x.y/h", "v1.2.3", false}, // out of alphabetical order
   398  			{"x.y/i", "v1.2.3", true},
   399  			{"x.y/j", "v1.2.3", true},
   400  			{"x.y/a", "v1.2.3", false},
   401  			{"x.y/b", "v1.2.3", true},
   402  			{"x.y/c", "v1.2.3", false},
   403  			{"x.y/d", "v1.2.3", false},
   404  			{"x.y/e", "v1.2.3", true},
   405  			{"x.y/f", "v1.2.3", false},
   406  			{"x.y/g", "v1.2.3", false},
   407  		},
   408  		`module m
   409  		require (
   410  			x.y/a v1.2.3
   411  			x.y/h v1.2.3
   412  		)
   413  		require x.y/b v1.2.3 // indirect; demoted to indirect
   414  		require x.y/c v1.2.3 // not v1.2.3!
   415  		require x.y/d v1.2.3 // comment kept
   416  		require x.y/e v1.2.3 // indirect; comment kept
   417  		require x.y/f v1.2.3 // promoted to direct
   418  		// promoted to direct
   419  		require x.y/g v1.2.3
   420  		require x.y/i v1.2.3 // indirect
   421  		require x.y/j v1.2.3 // indirect
   422  		`,
   423  	},
   424  	{
   425  		`existing_duplicate`,
   426  		`module m
   427  		require (
   428  			x.y/a v1.0.0 // zero
   429  			x.y/a v1.1.0 // one
   430  			x.y/a v1.2.3 // two
   431  		)
   432  		`,
   433  		[]require{
   434  			{"x.y/a", "v1.2.3", true},
   435  		},
   436  		`module m
   437  		require x.y/a v1.2.3 // indirect; zero
   438  		`,
   439  	},
   440  	{
   441  		`existing_duplicate_multi`,
   442  		`module m
   443  		require x.y/a v1.0.0 // zero
   444  		require x.y/a v1.1.0 // one
   445  		require x.y/a v1.2.3 // two
   446  		`,
   447  		[]require{
   448  			{"x.y/a", "v1.2.3", true},
   449  		},
   450  		`module m
   451  		require x.y/a v1.2.3 // indirect; zero
   452  		`,
   453  	},
   454  	{
   455  		`existing_duplicate_mix_indirect`,
   456  		`module m
   457  		require (
   458  			x.y/a v1.0.0 // zero
   459  			x.y/a v1.1.0 // indirect; one
   460  			x.y/a v1.2.3 // indirect; two
   461  		)
   462  		`,
   463  		[]require{
   464  			{"x.y/a", "v1.2.3", true},
   465  		},
   466  		`module m
   467  		require x.y/a v1.2.3 // indirect; zero
   468  		`,
   469  	},
   470  	{
   471  		`existing_duplicate_mix_direct`,
   472  		`module m
   473  		require (
   474  			x.y/a v1.0.0 // indirect; zero
   475  			x.y/a v1.1.0 // one
   476  			x.y/a v1.2.3 // two
   477  		)
   478  		`,
   479  		[]require{
   480  			{"x.y/a", "v1.2.3", false},
   481  		},
   482  		`module m
   483  		require x.y/a v1.2.3 // zero
   484  		`,
   485  	},
   486  	{
   487  		`add_indirect_after_last_direct`,
   488  		`module m
   489  		require (
   490  			x.y/a v1.0.0 // comment a preserved
   491  			x.y/d v1.0.0 // comment d preserved
   492  		)
   493  		require (
   494  			x.y/b v1.0.0 // comment b preserved
   495  			x.y/e v1.0.0 // comment e preserved
   496  		)
   497  		go 1.17
   498  		`,
   499  		[]require{
   500  			{"x.y/a", "v1.2.3", false},
   501  			{"x.y/b", "v1.2.3", false},
   502  			{"x.y/c", "v1.2.3", true},
   503  			{"x.y/d", "v1.2.3", false},
   504  			{"x.y/e", "v1.2.3", false},
   505  			{"x.y/f", "v1.2.3", true},
   506  		},
   507  		`module m
   508  		require (
   509  			x.y/a v1.2.3 // comment a preserved
   510  			x.y/d v1.2.3 // comment d preserved
   511  		)
   512  		require (
   513  			x.y/b v1.2.3 // comment b preserved
   514  			x.y/e v1.2.3 // comment e preserved
   515  		)
   516  		require (
   517  			x.y/c v1.2.3 // indirect
   518  			x.y/f v1.2.3 // indirect
   519  		)
   520  		go 1.17
   521  		`,
   522  	},
   523  	{
   524  		`add_direct_before_first_indirect`,
   525  		`module m
   526  		require (
   527  			x.y/b v1.0.0 // indirect; comment b preserved
   528  			x.y/e v1.0.0 // indirect; comment d preserved
   529  		)
   530  		require (
   531  			x.y/c v1.0.0 // indirect; comment c preserved
   532  			x.y/f v1.0.0 // indirect; comment e preserved
   533  		)
   534  		`,
   535  		[]require{
   536  			{"x.y/a", "v1.2.3", false},
   537  			{"x.y/b", "v1.2.3", true},
   538  			{"x.y/c", "v1.2.3", true},
   539  			{"x.y/d", "v1.2.3", false},
   540  			{"x.y/e", "v1.2.3", true},
   541  			{"x.y/f", "v1.2.3", true},
   542  		},
   543  		`module m
   544  		require (
   545  			x.y/b v1.2.3 // indirect; comment b preserved
   546  			x.y/e v1.2.3 // indirect; comment d preserved
   547  		)
   548  		require (
   549  			x.y/c v1.2.3 // indirect; comment c preserved
   550  			x.y/f v1.2.3 // indirect; comment e preserved
   551  		)
   552  		require (
   553  			x.y/a v1.2.3
   554  			x.y/d v1.2.3
   555  		)
   556  		`,
   557  	},
   558  	{
   559  		`add_indirect_after_mixed`,
   560  		`module m
   561  		require (
   562  			x.y/a v1.0.0
   563  			x.y/b v1.0.0 // indirect
   564  		)
   565  		`,
   566  		[]require{
   567  			{"x.y/a", "v1.2.3", false},
   568  			{"x.y/b", "v1.2.3", true},
   569  			{"x.y/c", "v1.2.3", true},
   570  			{"x.y/d", "v1.2.3", false},
   571  			{"x.y/e", "v1.2.3", true},
   572  		},
   573  		`module m
   574  		require (
   575  			x.y/a v1.2.3
   576  			x.y/d v1.2.3
   577  		)
   578  		require (
   579  			x.y/b v1.2.3 // indirect
   580  			x.y/c v1.2.3 // indirect
   581  			x.y/e v1.2.3 // indirect
   582  		)
   583  		`,
   584  	},
   585  	{
   586  		`preserve_block_comment_indirect_to_direct`,
   587  		`module m
   588  		// save
   589  		require (
   590  			x.y/a v1.2.3 // indirect
   591  		)
   592  		`,
   593  		[]require{
   594  			{"x.y/a", "v1.2.3", false},
   595  		},
   596  		`module m
   597  
   598  		// save
   599  		require x.y/a v1.2.3
   600  		`,
   601  	},
   602  	{
   603  		`preserve_block_comment_direct_to_indirect`,
   604  		`module m
   605  		// save
   606  		require (
   607  			x.y/a v1.2.3
   608  		)
   609  		`,
   610  		[]require{
   611  			{"x.y/a", "v1.2.3", true},
   612  		},
   613  		`module m
   614  
   615  		// save
   616  		require x.y/a v1.2.3 // indirect
   617  		`,
   618  	},
   619  	{
   620  		`regroup_flat_uncommented_block`,
   621  		`module m
   622  		require (
   623  			x.y/a v1.0.0 // a
   624  			x.y/b v1.0.0 // indirect; b
   625  			x.y/c v1.0.0 // indirect
   626  		)`,
   627  		[]require{
   628  			{"x.y/a", "v1.2.3", false},
   629  			{"x.y/b", "v1.2.3", true},
   630  			{"x.y/c", "v1.2.3", true},
   631  			{"x.y/d", "v1.2.3", false},
   632  		},
   633  		`module m
   634  		require (
   635  			x.y/a v1.2.3 // a
   636  			x.y/d v1.2.3
   637  		)
   638  		require (
   639  			x.y/b v1.2.3 // indirect; b
   640  			x.y/c v1.2.3 // indirect
   641  		)`,
   642  	},
   643  	{
   644  		`dont_regroup_flat_commented_block`,
   645  		`module m
   646  		// dont regroup
   647  		require (
   648  			x.y/a v1.0.0
   649  			x.y/b v1.0.0 // indirect
   650  			x.y/c v1.0.0 // indirect
   651  		)`,
   652  		[]require{
   653  			{"x.y/a", "v1.2.3", false},
   654  			{"x.y/b", "v1.2.3", true},
   655  			{"x.y/c", "v1.2.3", true},
   656  			{"x.y/d", "v1.2.3", false},
   657  		},
   658  		`module m
   659  		// dont regroup
   660  		require (
   661  			x.y/a v1.2.3
   662  			x.y/b v1.2.3 // indirect
   663  			x.y/c v1.2.3 // indirect
   664  		)
   665  		require x.y/d v1.2.3`,
   666  	},
   667  }
   668  
   669  var addGoTests = []struct {
   670  	desc    string
   671  	in      string
   672  	version string
   673  	out     string
   674  }{
   675  	{
   676  		`module_only`,
   677  		`module m
   678  		`,
   679  		`1.14`,
   680  		`module m
   681  		go 1.14
   682  		`,
   683  	},
   684  	{
   685  		`module_before_require`,
   686  		`module m
   687  		require x.y/a v1.2.3
   688  		`,
   689  		`1.14`,
   690  		`module m
   691  		go 1.14
   692  		require x.y/a v1.2.3
   693  		`,
   694  	},
   695  	{
   696  		`require_before_module`,
   697  		`require x.y/a v1.2.3
   698  		module example.com/inverted
   699  		`,
   700  		`1.14`,
   701  		`require x.y/a v1.2.3
   702  		module example.com/inverted
   703  		go 1.14
   704  		`,
   705  	},
   706  	{
   707  		`require_only`,
   708  		`require x.y/a v1.2.3
   709  		`,
   710  		`1.14`,
   711  		`require x.y/a v1.2.3
   712  		go 1.14
   713  		`,
   714  	},
   715  }
   716  
   717  var dropGoTests = []struct {
   718  	desc string
   719  	in   string
   720  	out  string
   721  }{
   722  	{
   723  		`module_only`,
   724  		`module m
   725  		go 1.14
   726  		`,
   727  		`module m
   728  		`,
   729  	},
   730  	{
   731  		`module_before_require`,
   732  		`module m
   733  		go 1.14
   734  		require x.y/a v1.2.3
   735  		`,
   736  		`module m
   737  		require x.y/a v1.2.3
   738  		`,
   739  	},
   740  	{
   741  		`require_before_module`,
   742  		`require x.y/a v1.2.3
   743  		module example.com/inverted
   744  		go 1.14
   745  		`,
   746  		`require x.y/a v1.2.3
   747  		module example.com/inverted
   748  		`,
   749  	},
   750  	{
   751  		`require_only`,
   752  		`require x.y/a v1.2.3
   753  		go 1.14
   754  		`,
   755  		`require x.y/a v1.2.3
   756  		`,
   757  	},
   758  }
   759  
   760  var addToolchainTests = []struct {
   761  	desc    string
   762  	in      string
   763  	version string
   764  	out     string
   765  }{
   766  	{
   767  		`empty`,
   768  		``,
   769  		`go1.17`,
   770  		`toolchain go1.17
   771  		`,
   772  	},
   773  	{
   774  		`aftergo`,
   775  		`// this is a comment
   776  		require x v1.0.0
   777  
   778  		go 1.17
   779  
   780  		require y v1.0.0
   781  		`,
   782  		`go1.17`,
   783  		`// this is a comment
   784  		require x v1.0.0
   785  
   786  		go 1.17
   787  
   788  		toolchain go1.17
   789  
   790  		require y v1.0.0
   791  		`,
   792  	},
   793  	{
   794  		`already_have_toolchain`,
   795  		`go 1.17
   796  
   797  		toolchain go1.18
   798  		`,
   799  		`go1.19`,
   800  		`go 1.17
   801  
   802  		toolchain go1.19
   803  		`,
   804  	},
   805  }
   806  
   807  var dropToolchainTests = []struct {
   808  	desc string
   809  	in   string
   810  	out  string
   811  }{
   812  	{
   813  		`empty`,
   814  		`toolchain go1.17
   815  		`,
   816  		``,
   817  	},
   818  	{
   819  		`aftergo`,
   820  		`// this is a comment
   821  		require x v1.0.0
   822  
   823  		go 1.17
   824  
   825  		toolchain go1.17
   826  
   827  		require y v1.0.0
   828  		`,
   829  		`// this is a comment
   830  		require x v1.0.0
   831  
   832  		go 1.17
   833  
   834  		require y v1.0.0
   835  		`,
   836  	},
   837  	{
   838  		`already_have_toolchain`,
   839  		`go 1.17
   840  
   841  		toolchain go1.18
   842  		`,
   843  		`go 1.17
   844  		`,
   845  	},
   846  }
   847  
   848  var addExcludeTests = []struct {
   849  	desc    string
   850  	in      string
   851  	path    string
   852  	version string
   853  	out     string
   854  }{
   855  	{
   856  		`compatible`,
   857  		`module m
   858  		`,
   859  		`example.com`,
   860  		`v1.2.3`,
   861  		`module m
   862  		exclude example.com v1.2.3
   863  		`,
   864  	},
   865  	{
   866  		`gopkg.in v0`,
   867  		`module m
   868  		`,
   869  		`gopkg.in/foo.v0`,
   870  		`v0.2.3`,
   871  		`module m
   872  		exclude gopkg.in/foo.v0 v0.2.3
   873  		`,
   874  	},
   875  	{
   876  		`gopkg.in v1`,
   877  		`module m
   878  		`,
   879  		`gopkg.in/foo.v1`,
   880  		`v1.2.3`,
   881  		`module m
   882  		exclude gopkg.in/foo.v1 v1.2.3
   883  		`,
   884  	},
   885  }
   886  
   887  var addRetractTests = []struct {
   888  	desc      string
   889  	in        string
   890  	low       string
   891  	high      string
   892  	rationale string
   893  	out       string
   894  }{
   895  	{
   896  		`new_singleton`,
   897  		`module m
   898  		`,
   899  		`v1.2.3`,
   900  		`v1.2.3`,
   901  		``,
   902  		`module m
   903  		retract v1.2.3
   904  		`,
   905  	},
   906  	{
   907  		`new_interval`,
   908  		`module m
   909  		`,
   910  		`v1.0.0`,
   911  		`v1.1.0`,
   912  		``,
   913  		`module m
   914  		retract [v1.0.0, v1.1.0]`,
   915  	},
   916  	{
   917  		`duplicate_with_rationale`,
   918  		`module m
   919  		retract v1.2.3
   920  		`,
   921  		`v1.2.3`,
   922  		`v1.2.3`,
   923  		`bad`,
   924  		`module m
   925  		retract (
   926  			v1.2.3
   927  			// bad
   928  			v1.2.3
   929  		)
   930  		`,
   931  	},
   932  	{
   933  		`duplicate_multiline_rationale`,
   934  		`module m
   935  		retract [v1.2.3, v1.2.3]
   936  		`,
   937  		`v1.2.3`,
   938  		`v1.2.3`,
   939  		`multi
   940  line`,
   941  		`module m
   942  		retract	(
   943  			[v1.2.3, v1.2.3]
   944  			// multi
   945  			// line
   946  			v1.2.3
   947  		)
   948  		`,
   949  	},
   950  	{
   951  		`duplicate_interval`,
   952  		`module m
   953  		retract [v1.0.0, v1.1.0]
   954  		`,
   955  		`v1.0.0`,
   956  		`v1.1.0`,
   957  		``,
   958  		`module m
   959  		retract (
   960  			[v1.0.0, v1.1.0]
   961  			[v1.0.0, v1.1.0]
   962  		)
   963  		`,
   964  	},
   965  	{
   966  		`duplicate_singleton`,
   967  		`module m
   968  		retract v1.2.3
   969  		`,
   970  		`v1.2.3`,
   971  		`v1.2.3`,
   972  		``,
   973  		`module m
   974  		retract	(
   975  			v1.2.3
   976  			v1.2.3
   977  		)
   978  		`,
   979  	},
   980  }
   981  
   982  var dropRetractTests = []struct {
   983  	desc string
   984  	in   string
   985  	low  string
   986  	high string
   987  	out  string
   988  }{
   989  	{
   990  		`singleton_no_match`,
   991  		`module m
   992  		retract v1.2.3
   993  		`,
   994  		`v1.0.0`,
   995  		`v1.0.0`,
   996  		`module m
   997  		retract v1.2.3
   998  		`,
   999  	},
  1000  	{
  1001  		`singleton_match_one`,
  1002  		`module m
  1003  		retract v1.2.2
  1004  		retract v1.2.3
  1005  		retract v1.2.4
  1006  		`,
  1007  		`v1.2.3`,
  1008  		`v1.2.3`,
  1009  		`module m
  1010  		retract v1.2.2
  1011  		retract v1.2.4
  1012  		`,
  1013  	},
  1014  	{
  1015  		`singleton_match_all`,
  1016  		`module m
  1017  		retract v1.2.3 // first
  1018  		retract v1.2.3 // second
  1019  		`,
  1020  		`v1.2.3`,
  1021  		`v1.2.3`,
  1022  		`module m
  1023  		`,
  1024  	},
  1025  	{
  1026  		`interval_match`,
  1027  		`module m
  1028  		retract [v1.2.3, v1.2.3]
  1029  		`,
  1030  		`v1.2.3`,
  1031  		`v1.2.3`,
  1032  		`module m
  1033  		`,
  1034  	},
  1035  	{
  1036  		`interval_superset_no_match`,
  1037  		`module m
  1038  		retract [v1.0.0, v1.1.0]
  1039  		`,
  1040  		`v1.0.0`,
  1041  		`v1.2.0`,
  1042  		`module m
  1043  		retract [v1.0.0, v1.1.0]
  1044  		`,
  1045  	},
  1046  	{
  1047  		`singleton_match_middle`,
  1048  		`module m
  1049  		retract v1.2.3
  1050  		`,
  1051  		`v1.2.3`,
  1052  		`v1.2.3`,
  1053  		`module m
  1054  		`,
  1055  	},
  1056  	{
  1057  		`interval_match_middle_block`,
  1058  		`module m
  1059  		retract (
  1060  			v1.0.0
  1061  			[v1.1.0, v1.2.0]
  1062  			v1.3.0
  1063  		)
  1064  		`,
  1065  		`v1.1.0`,
  1066  		`v1.2.0`,
  1067  		`module m
  1068  		retract (
  1069  			v1.0.0
  1070  			v1.3.0
  1071  		)
  1072  		`,
  1073  	},
  1074  	{
  1075  		`interval_match_all`,
  1076  		`module m
  1077  		retract [v1.0.0, v1.1.0]
  1078  		retract [v1.0.0, v1.1.0]
  1079  		`,
  1080  		`v1.0.0`,
  1081  		`v1.1.0`,
  1082  		`module m
  1083  		`,
  1084  	},
  1085  }
  1086  
  1087  var retractRationaleTests = []struct {
  1088  	desc, in, want string
  1089  }{
  1090  	{
  1091  		`no_comment`,
  1092  		`module m
  1093  		retract v1.0.0`,
  1094  		``,
  1095  	},
  1096  	{
  1097  		`prefix_one`,
  1098  		`module m
  1099  		//   prefix
  1100  		retract v1.0.0
  1101  		`,
  1102  		`prefix`,
  1103  	},
  1104  	{
  1105  		`prefix_multiline`,
  1106  		`module m
  1107  		//  one
  1108  		//
  1109  		//     two
  1110  		//
  1111  		// three
  1112  		retract v1.0.0`,
  1113  		`one
  1114  
  1115  two
  1116  
  1117  three`,
  1118  	},
  1119  	{
  1120  		`suffix`,
  1121  		`module m
  1122  		retract v1.0.0 // suffix
  1123  		`,
  1124  		`suffix`,
  1125  	},
  1126  	{
  1127  		`prefix_suffix_after`,
  1128  		`module m
  1129  		// prefix
  1130  		retract v1.0.0 // suffix
  1131  		`,
  1132  		`prefix
  1133  suffix`,
  1134  	},
  1135  	{
  1136  		`block_only`,
  1137  		`// block
  1138  		retract (
  1139  			v1.0.0
  1140  		)
  1141  		`,
  1142  		`block`,
  1143  	},
  1144  	{
  1145  		`block_and_line`,
  1146  		`// block
  1147  		retract (
  1148  			// line
  1149  			v1.0.0
  1150  		)
  1151  		`,
  1152  		`line`,
  1153  	},
  1154  }
  1155  
  1156  var moduleDeprecatedTests = []struct {
  1157  	desc, in, want string
  1158  }{
  1159  	// retractRationaleTests exercises some of the same code, so these tests
  1160  	// don't exhaustively cover comment extraction.
  1161  	{
  1162  		`no_comment`,
  1163  		`module m`,
  1164  		``,
  1165  	},
  1166  	{
  1167  		`other_comment`,
  1168  		`// yo
  1169  		module m`,
  1170  		``,
  1171  	},
  1172  	{
  1173  		`deprecated_no_colon`,
  1174  		`//Deprecated
  1175  		module m`,
  1176  		``,
  1177  	},
  1178  	{
  1179  		`deprecated_no_space`,
  1180  		`//Deprecated:blah
  1181  		module m`,
  1182  		`blah`,
  1183  	},
  1184  	{
  1185  		`deprecated_simple`,
  1186  		`// Deprecated: blah
  1187  		module m`,
  1188  		`blah`,
  1189  	},
  1190  	{
  1191  		`deprecated_lowercase`,
  1192  		`// deprecated: blah
  1193  		module m`,
  1194  		``,
  1195  	},
  1196  	{
  1197  		`deprecated_multiline`,
  1198  		`// Deprecated: one
  1199  		// two
  1200  		module m`,
  1201  		"one\ntwo",
  1202  	},
  1203  	{
  1204  		`deprecated_mixed`,
  1205  		`// some other comment
  1206  		// Deprecated: blah
  1207  		module m`,
  1208  		``,
  1209  	},
  1210  	{
  1211  		`deprecated_middle`,
  1212  		`// module m is Deprecated: blah
  1213  		module m`,
  1214  		``,
  1215  	},
  1216  	{
  1217  		`deprecated_multiple`,
  1218  		`// Deprecated: a
  1219  		// Deprecated: b
  1220  		module m`,
  1221  		"a\nDeprecated: b",
  1222  	},
  1223  	{
  1224  		`deprecated_paragraph`,
  1225  		`// Deprecated: a
  1226  		// b
  1227  		//
  1228  		// c
  1229  		module m`,
  1230  		"a\nb",
  1231  	},
  1232  	{
  1233  		`deprecated_paragraph_space`,
  1234  		`// Deprecated: the next line has a space
  1235  		//
  1236  		// c
  1237  		module m`,
  1238  		"the next line has a space",
  1239  	},
  1240  	{
  1241  		`deprecated_suffix`,
  1242  		`module m // Deprecated: blah`,
  1243  		`blah`,
  1244  	},
  1245  	{
  1246  		`deprecated_mixed_suffix`,
  1247  		`// some other comment
  1248  		module m // Deprecated: blah`,
  1249  		``,
  1250  	},
  1251  	{
  1252  		`deprecated_mixed_suffix_paragraph`,
  1253  		`// some other comment
  1254  		//
  1255  		module m // Deprecated: blah`,
  1256  		`blah`,
  1257  	},
  1258  	{
  1259  		`deprecated_block`,
  1260  		`// Deprecated: blah
  1261  		module (
  1262  			m
  1263  		)`,
  1264  		`blah`,
  1265  	},
  1266  }
  1267  
  1268  var sortBlocksTests = []struct {
  1269  	desc, in, out string
  1270  	strict        bool
  1271  }{
  1272  	{
  1273  		`exclude_duplicates_removed`,
  1274  		`module m
  1275  		exclude x.y/z v1.0.0 // a
  1276  		exclude x.y/z v1.0.0 // b
  1277  		exclude (
  1278  			x.y/w v1.1.0
  1279  			x.y/z v1.0.0 // c
  1280  		)
  1281  		`,
  1282  		`module m
  1283  		exclude x.y/z v1.0.0 // a
  1284  		exclude (
  1285  			x.y/w v1.1.0
  1286  		)`,
  1287  		true,
  1288  	},
  1289  	{
  1290  		`replace_duplicates_removed`,
  1291  		`module m
  1292  		replace x.y/z v1.0.0 => ./a
  1293  		replace x.y/z v1.1.0 => ./b
  1294  		replace (
  1295  			x.y/z v1.0.0 => ./c
  1296  		)
  1297  		`,
  1298  		`module m
  1299  		replace x.y/z v1.1.0 => ./b
  1300  		replace (
  1301  			x.y/z v1.0.0 => ./c
  1302  		)
  1303  		`,
  1304  		true,
  1305  	},
  1306  	{
  1307  		`retract_duplicates_not_removed`,
  1308  		`module m
  1309  		// block
  1310  		retract (
  1311  			v1.0.0 // one
  1312  			v1.0.0 // two
  1313  		)`,
  1314  		`module m
  1315  		// block
  1316  		retract (
  1317  			v1.0.0 // one
  1318  			v1.0.0 // two
  1319  		)`,
  1320  		true,
  1321  	},
  1322  	// Tests below this point just check sort order.
  1323  	// Non-retract blocks are sorted lexicographically in ascending order.
  1324  	// retract blocks are sorted using semver in descending order.
  1325  	{
  1326  		`sort_lexicographically`,
  1327  		`module m
  1328  		sort (
  1329  			aa
  1330  			cc
  1331  			bb
  1332  			zz
  1333  			v1.2.0
  1334  			v1.11.0
  1335  		)`,
  1336  		`module m
  1337  		sort (
  1338  			aa
  1339  			bb
  1340  			cc
  1341  			v1.11.0
  1342  			v1.2.0
  1343  			zz
  1344  		)
  1345  		`,
  1346  		false,
  1347  	},
  1348  	{
  1349  		`sort_retract`,
  1350  		`module m
  1351  		retract (
  1352  			[v1.2.0, v1.3.0]
  1353  			[v1.1.0, v1.3.0]
  1354  			[v1.1.0, v1.2.0]
  1355  			v1.0.0
  1356  			v1.1.0
  1357  			v1.2.0
  1358  			v1.3.0
  1359  			v1.4.0
  1360  		)
  1361  		`,
  1362  		`module m
  1363  		retract (
  1364  			v1.4.0
  1365  			v1.3.0
  1366  			[v1.2.0, v1.3.0]
  1367  			v1.2.0
  1368  			[v1.1.0, v1.3.0]
  1369  			[v1.1.0, v1.2.0]
  1370  			v1.1.0
  1371  			v1.0.0
  1372  		)
  1373  		`,
  1374  		false,
  1375  	},
  1376  	// Exclude blocks are sorted using semver in ascending order
  1377  	// in go.mod files that opt in to Go version 1.21 or newer.
  1378  	{
  1379  		`sort_exclude_go121_semver`,
  1380  		`module m
  1381  		go 1.21
  1382  		exclude (
  1383  			b.example/m v0.9.0
  1384  			a.example/m v1.0.0
  1385  			b.example/m v0.10.0
  1386  			c.example/m v1.1.0
  1387  			b.example/m v0.11.0
  1388  		)`,
  1389  		`module m
  1390  		go 1.21
  1391  		exclude (
  1392  			a.example/m v1.0.0
  1393  			b.example/m v0.9.0
  1394  			b.example/m v0.10.0
  1395  			b.example/m v0.11.0
  1396  			c.example/m v1.1.0
  1397  		)
  1398  		`,
  1399  		true,
  1400  	},
  1401  	{
  1402  		`sort_exclude_!go121_lexicographically`, // Maintain the previous (less featureful) behavior to avoid unnecessary churn.
  1403  		`module m
  1404  		exclude (
  1405  			b.example/m v0.9.0
  1406  			a.example/m v1.0.0
  1407  			b.example/m v0.10.0
  1408  			c.example/m v1.1.0
  1409  			b.example/m v0.11.0
  1410  		)`,
  1411  		`module m
  1412  		exclude (
  1413  			a.example/m v1.0.0
  1414  			b.example/m v0.10.0
  1415  			b.example/m v0.11.0
  1416  			b.example/m v0.9.0
  1417  			c.example/m v1.1.0
  1418  		)
  1419  		`,
  1420  		true,
  1421  	},
  1422  }
  1423  
  1424  var addRetractValidateVersionTests = []struct {
  1425  	desc      string
  1426  	path      string
  1427  	low, high string
  1428  	wantErr   string
  1429  }{
  1430  	{
  1431  		`blank_version`,
  1432  		`example.com/m`,
  1433  		``,
  1434  		``,
  1435  		`version "" invalid: must be of the form v1.2.3`,
  1436  	},
  1437  	{
  1438  		`missing prefix`,
  1439  		`example.com/m`,
  1440  		`1.0.0`,
  1441  		`1.0.0`,
  1442  		`version "1.0.0" invalid: must be of the form v1.2.3`,
  1443  	},
  1444  	{
  1445  		`non-canonical`,
  1446  		`example.com/m`,
  1447  		`v1.2`,
  1448  		`v1.2`,
  1449  		`version "v1.2" invalid: must be of the form v1.2.3`,
  1450  	},
  1451  	{
  1452  		`invalid range`,
  1453  		`example.com/m`,
  1454  		`v1.2.3`,
  1455  		`v1.3`,
  1456  		`version "v1.3" invalid: must be of the form v1.2.3`,
  1457  	},
  1458  	{
  1459  		`mismatched major`,
  1460  		`example.com/m/v2`,
  1461  		`v1.0.0`,
  1462  		`v1.0.0`,
  1463  		`version "v1.0.0" invalid: should be v2, not v1`,
  1464  	},
  1465  	{
  1466  		`missing +incompatible`,
  1467  		`example.com/m`,
  1468  		`v2.0.0`,
  1469  		`v2.0.0`,
  1470  		`version "v2.0.0" invalid: should be v2.0.0+incompatible (or module example.com/m/v2)`,
  1471  	},
  1472  }
  1473  
  1474  var addExcludeValidateVersionTests = []struct {
  1475  	desc    string
  1476  	path    string
  1477  	version string
  1478  	wantErr string
  1479  }{
  1480  	{
  1481  		`blank version`,
  1482  		`example.com/m`,
  1483  		``,
  1484  		`version "" invalid: must be of the form v1.2.3`,
  1485  	},
  1486  	{
  1487  		`missing prefix`,
  1488  		`example.com/m`,
  1489  		`1.0.0`,
  1490  		`version "1.0.0" invalid: must be of the form v1.2.3`,
  1491  	},
  1492  	{
  1493  		`non-canonical`,
  1494  		`example.com/m`,
  1495  		`v1.2`,
  1496  		`version "v1.2" invalid: must be of the form v1.2.3`,
  1497  	},
  1498  	{
  1499  		`mismatched major`,
  1500  		`example.com/m/v2`,
  1501  		`v1.2.3`,
  1502  		`version "v1.2.3" invalid: should be v2, not v1`,
  1503  	},
  1504  	{
  1505  		`missing +incompatible`,
  1506  		`example.com/m`,
  1507  		`v2.3.4`,
  1508  		`version "v2.3.4" invalid: should be v2.3.4+incompatible (or module example.com/m/v2)`,
  1509  	},
  1510  }
  1511  
  1512  var fixVersionTests = []struct {
  1513  	desc, in, want, wantErr string
  1514  	fix                     VersionFixer
  1515  }{
  1516  	{
  1517  		desc: `require`,
  1518  		in:   `require example.com/m 1.0.0`,
  1519  		want: `require example.com/m v1.0.0`,
  1520  		fix:  fixV,
  1521  	},
  1522  	{
  1523  		desc: `replace`,
  1524  		in:   `replace example.com/m 1.0.0 => example.com/m 1.1.0`,
  1525  		want: `replace example.com/m v1.0.0 => example.com/m v1.1.0`,
  1526  		fix:  fixV,
  1527  	},
  1528  	{
  1529  		desc:    `replace_version_in_path`,
  1530  		in:      `replace example.com/m@v1.0.0 => example.com/m@v1.1.0`,
  1531  		wantErr: `replacement module must match format 'path version', not 'path@version'`,
  1532  		fix:     fixV,
  1533  	},
  1534  	{
  1535  		desc:    `replace_version_in_later_path`,
  1536  		in:      `replace example.com/m => example.com/m@v1.1.0`,
  1537  		wantErr: `replacement module must match format 'path version', not 'path@version'`,
  1538  		fix:     fixV,
  1539  	},
  1540  	{
  1541  		desc: `exclude`,
  1542  		in:   `exclude example.com/m 1.0.0`,
  1543  		want: `exclude example.com/m v1.0.0`,
  1544  		fix:  fixV,
  1545  	},
  1546  	{
  1547  		desc: `retract_single`,
  1548  		in: `module example.com/m
  1549  		retract 1.0.0`,
  1550  		want: `module example.com/m
  1551  		retract v1.0.0`,
  1552  		fix: fixV,
  1553  	},
  1554  	{
  1555  		desc: `retract_interval`,
  1556  		in: `module example.com/m
  1557  		retract [1.0.0, 1.1.0]`,
  1558  		want: `module example.com/m
  1559  		retract [v1.0.0, v1.1.0]`,
  1560  		fix: fixV,
  1561  	},
  1562  	{
  1563  		desc:    `retract_nomod`,
  1564  		in:      `retract 1.0.0`,
  1565  		wantErr: `in:1: no module directive found, so retract cannot be used`,
  1566  		fix:     fixV,
  1567  	},
  1568  }
  1569  
  1570  var modifyEmptyFilesTests = []struct {
  1571  	desc       string
  1572  	operations func(f *File)
  1573  	want       string
  1574  }{
  1575  	{
  1576  		desc: `addGoStmt`,
  1577  		operations: func(f *File) {
  1578  			f.AddGoStmt("1.20")
  1579  		},
  1580  		want: `go 1.20`,
  1581  	},
  1582  }
  1583  
  1584  func fixV(path, version string) (string, error) {
  1585  	if path != "example.com/m" {
  1586  		return "", fmt.Errorf("module path must be example.com/m")
  1587  	}
  1588  	return "v" + version, nil
  1589  }
  1590  
  1591  func TestAddRequire(t *testing.T) {
  1592  	for _, tt := range addRequireTests {
  1593  		t.Run(tt.desc, func(t *testing.T) {
  1594  			testEdit(t, tt.in, tt.out, true, func(f *File) error {
  1595  				err := f.AddRequire(tt.path, tt.vers)
  1596  				f.Cleanup()
  1597  				return err
  1598  			})
  1599  		})
  1600  	}
  1601  }
  1602  
  1603  func TestSetRequire(t *testing.T) {
  1604  	for _, tt := range setRequireTests {
  1605  		t.Run(tt.desc, func(t *testing.T) {
  1606  			var mods []*Require
  1607  			for _, mod := range tt.mods {
  1608  				mods = append(mods, &Require{
  1609  					Mod: module.Version{
  1610  						Path:    mod.path,
  1611  						Version: mod.vers,
  1612  					},
  1613  					Indirect: mod.indirect,
  1614  				})
  1615  			}
  1616  
  1617  			f := testEdit(t, tt.in, tt.out, true, func(f *File) error {
  1618  				f.SetRequire(mods)
  1619  				f.Cleanup()
  1620  				return nil
  1621  			})
  1622  
  1623  			if len(f.Require) != len(mods) {
  1624  				t.Errorf("after Cleanup, len(Require) = %v; want %v", len(f.Require), len(mods))
  1625  			}
  1626  		})
  1627  	}
  1628  }
  1629  
  1630  func TestSetRequireSeparateIndirect(t *testing.T) {
  1631  	for _, tt := range setRequireSeparateIndirectTests {
  1632  		t.Run(tt.desc, func(t *testing.T) {
  1633  			var mods []*Require
  1634  			for _, mod := range tt.mods {
  1635  				mods = append(mods, &Require{
  1636  					Mod: module.Version{
  1637  						Path:    mod.path,
  1638  						Version: mod.vers,
  1639  					},
  1640  					Indirect: mod.indirect,
  1641  				})
  1642  			}
  1643  
  1644  			f := testEdit(t, tt.in, tt.out, true, func(f *File) error {
  1645  				f.SetRequireSeparateIndirect(mods)
  1646  				f.Cleanup()
  1647  				return nil
  1648  			})
  1649  
  1650  			if len(f.Require) != len(mods) {
  1651  				t.Errorf("after Cleanup, len(Require) = %v; want %v", len(f.Require), len(mods))
  1652  			}
  1653  		})
  1654  	}
  1655  }
  1656  
  1657  func TestAddGo(t *testing.T) {
  1658  	for _, tt := range addGoTests {
  1659  		t.Run(tt.desc, func(t *testing.T) {
  1660  			testEdit(t, tt.in, tt.out, true, func(f *File) error {
  1661  				return f.AddGoStmt(tt.version)
  1662  			})
  1663  		})
  1664  	}
  1665  }
  1666  
  1667  func TestDropGo(t *testing.T) {
  1668  	for _, tt := range dropGoTests {
  1669  		t.Run(tt.desc, func(t *testing.T) {
  1670  			testEdit(t, tt.in, tt.out, true, func(f *File) error {
  1671  				f.DropGoStmt()
  1672  				return nil
  1673  			})
  1674  		})
  1675  	}
  1676  }
  1677  
  1678  func TestAddToolchain(t *testing.T) {
  1679  	for _, tt := range addToolchainTests {
  1680  		t.Run(tt.desc, func(t *testing.T) {
  1681  			testEdit(t, tt.in, tt.out, true, func(f *File) error {
  1682  				return f.AddToolchainStmt(tt.version)
  1683  			})
  1684  		})
  1685  	}
  1686  }
  1687  
  1688  func TestDropToolchain(t *testing.T) {
  1689  	for _, tt := range dropToolchainTests {
  1690  		t.Run(tt.desc, func(t *testing.T) {
  1691  			testEdit(t, tt.in, tt.out, true, func(f *File) error {
  1692  				f.DropToolchainStmt()
  1693  				return nil
  1694  			})
  1695  		})
  1696  	}
  1697  }
  1698  
  1699  func TestAddExclude(t *testing.T) {
  1700  	for _, tt := range addExcludeTests {
  1701  		t.Run(tt.desc, func(t *testing.T) {
  1702  			testEdit(t, tt.in, tt.out, true, func(f *File) error {
  1703  				return f.AddExclude(tt.path, tt.version)
  1704  			})
  1705  		})
  1706  	}
  1707  }
  1708  
  1709  func TestAddRetract(t *testing.T) {
  1710  	for _, tt := range addRetractTests {
  1711  		t.Run(tt.desc, func(t *testing.T) {
  1712  			testEdit(t, tt.in, tt.out, true, func(f *File) error {
  1713  				return f.AddRetract(VersionInterval{Low: tt.low, High: tt.high}, tt.rationale)
  1714  			})
  1715  		})
  1716  	}
  1717  }
  1718  
  1719  func TestDropRetract(t *testing.T) {
  1720  	for _, tt := range dropRetractTests {
  1721  		t.Run(tt.desc, func(t *testing.T) {
  1722  			testEdit(t, tt.in, tt.out, true, func(f *File) error {
  1723  				if err := f.DropRetract(VersionInterval{Low: tt.low, High: tt.high}); err != nil {
  1724  					return err
  1725  				}
  1726  				f.Cleanup()
  1727  				return nil
  1728  			})
  1729  		})
  1730  	}
  1731  }
  1732  
  1733  func TestRetractRationale(t *testing.T) {
  1734  	for _, tt := range retractRationaleTests {
  1735  		t.Run(tt.desc, func(t *testing.T) {
  1736  			f, err := Parse("in", []byte(tt.in), nil)
  1737  			if err != nil {
  1738  				t.Fatal(err)
  1739  			}
  1740  			if len(f.Retract) != 1 {
  1741  				t.Fatalf("got %d retract directives; want 1", len(f.Retract))
  1742  			}
  1743  			if got := f.Retract[0].Rationale; got != tt.want {
  1744  				t.Errorf("got %q; want %q", got, tt.want)
  1745  			}
  1746  		})
  1747  	}
  1748  }
  1749  
  1750  func TestModuleDeprecated(t *testing.T) {
  1751  	for _, tt := range moduleDeprecatedTests {
  1752  		t.Run(tt.desc, func(t *testing.T) {
  1753  			f, err := Parse("in", []byte(tt.in), nil)
  1754  			if err != nil {
  1755  				t.Fatal(err)
  1756  			}
  1757  			if f.Module.Deprecated != tt.want {
  1758  				t.Errorf("got %q; want %q", f.Module.Deprecated, tt.want)
  1759  			}
  1760  		})
  1761  	}
  1762  }
  1763  
  1764  func TestSortBlocks(t *testing.T) {
  1765  	for _, tt := range sortBlocksTests {
  1766  		t.Run(tt.desc, func(t *testing.T) {
  1767  			testEdit(t, tt.in, tt.out, tt.strict, func(f *File) error {
  1768  				f.SortBlocks()
  1769  				return nil
  1770  			})
  1771  		})
  1772  	}
  1773  }
  1774  
  1775  func testEdit(t *testing.T, in, want string, strict bool, transform func(f *File) error) *File {
  1776  	t.Helper()
  1777  	parse := Parse
  1778  	if !strict {
  1779  		parse = ParseLax
  1780  	}
  1781  	f, err := parse("in", []byte(in), nil)
  1782  	if err != nil {
  1783  		t.Fatal(err)
  1784  	}
  1785  	g, err := parse("out", []byte(want), nil)
  1786  	if err != nil {
  1787  		t.Fatal(err)
  1788  	}
  1789  	golden, err := g.Format()
  1790  	if err != nil {
  1791  		t.Fatal(err)
  1792  	}
  1793  
  1794  	if err := transform(f); err != nil {
  1795  		t.Fatal(err)
  1796  	}
  1797  	out, err := f.Format()
  1798  	if err != nil {
  1799  		t.Fatal(err)
  1800  	}
  1801  	if !bytes.Equal(out, golden) {
  1802  		t.Errorf("have:\n%s\nwant:\n%s", out, golden)
  1803  	}
  1804  
  1805  	return f
  1806  }
  1807  
  1808  func TestAddRetractValidateVersion(t *testing.T) {
  1809  	for _, tt := range addRetractValidateVersionTests {
  1810  		t.Run(tt.desc, func(t *testing.T) {
  1811  			f := new(File)
  1812  			if tt.path != "" {
  1813  				if err := f.AddModuleStmt(tt.path); err != nil {
  1814  					t.Fatal(err)
  1815  				}
  1816  				t.Logf("module %s", AutoQuote(tt.path))
  1817  			}
  1818  			interval := VersionInterval{Low: tt.low, High: tt.high}
  1819  			if err := f.AddRetract(interval, ``); err == nil || err.Error() != tt.wantErr {
  1820  				errStr := "<nil>"
  1821  				if err != nil {
  1822  					errStr = fmt.Sprintf("%#q", err)
  1823  				}
  1824  				t.Fatalf("f.AddRetract(%+v, ``) = %s\nwant %#q", interval, errStr, tt.wantErr)
  1825  			}
  1826  		})
  1827  	}
  1828  }
  1829  
  1830  func TestAddExcludeValidateVersion(t *testing.T) {
  1831  	for _, tt := range addExcludeValidateVersionTests {
  1832  		t.Run(tt.desc, func(t *testing.T) {
  1833  			f, err := Parse("in", []byte("module m"), nil)
  1834  			if err != nil {
  1835  				t.Fatal(err)
  1836  			}
  1837  			if err = f.AddExclude(tt.path, tt.version); err == nil || err.Error() != tt.wantErr {
  1838  				errStr := "<nil>"
  1839  				if err != nil {
  1840  					errStr = fmt.Sprintf("%#q", err)
  1841  				}
  1842  				t.Fatalf("f.AddExclude(%q, %q) = %s\nwant %#q", tt.path, tt.version, errStr, tt.wantErr)
  1843  			}
  1844  		})
  1845  	}
  1846  }
  1847  
  1848  func TestFixVersion(t *testing.T) {
  1849  	for _, tt := range fixVersionTests {
  1850  		t.Run(tt.desc, func(t *testing.T) {
  1851  			inFile, err := Parse("in", []byte(tt.in), tt.fix)
  1852  			if err != nil {
  1853  				if tt.wantErr == "" {
  1854  					t.Fatalf("unexpected error: %v", err)
  1855  				}
  1856  				if errMsg := err.Error(); !strings.Contains(errMsg, tt.wantErr) {
  1857  					t.Fatalf("got error %q; want error containing %q", errMsg, tt.wantErr)
  1858  				}
  1859  				return
  1860  			}
  1861  			got, err := inFile.Format()
  1862  			if err != nil {
  1863  				t.Fatal(err)
  1864  			}
  1865  
  1866  			outFile, err := Parse("out", []byte(tt.want), nil)
  1867  			if err != nil {
  1868  				t.Fatal(err)
  1869  			}
  1870  			want, err := outFile.Format()
  1871  			if err != nil {
  1872  				t.Fatal(err)
  1873  			}
  1874  
  1875  			if !bytes.Equal(got, want) {
  1876  				t.Fatalf("got:\n%s\nwant:\n%s", got, want)
  1877  			}
  1878  		})
  1879  	}
  1880  }
  1881  
  1882  func TestAddOnEmptyFile(t *testing.T) {
  1883  	for _, tt := range modifyEmptyFilesTests {
  1884  		t.Run(tt.desc, func(t *testing.T) {
  1885  			f := &File{}
  1886  			tt.operations(f)
  1887  
  1888  			expect, err := Parse("out", []byte(tt.want), nil)
  1889  			if err != nil {
  1890  				t.Fatal(err)
  1891  			}
  1892  			golden, err := expect.Format()
  1893  			if err != nil {
  1894  				t.Fatal(err)
  1895  			}
  1896  			got, err := f.Format()
  1897  			if err != nil {
  1898  				t.Fatal(err)
  1899  			}
  1900  
  1901  			if !bytes.Equal(got, golden) {
  1902  				t.Fatalf("got:\n%s\nwant:\n%s", got, golden)
  1903  			}
  1904  		})
  1905  	}
  1906  }
  1907  

View as plain text