...

Source file src/cuelang.org/go/mod/modfile/modfile_test.go

Documentation: cuelang.org/go/mod/modfile

     1  // Copyright 2023 CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package modfile
    16  
    17  import (
    18  	"strings"
    19  	"testing"
    20  
    21  	"github.com/go-quicktest/qt"
    22  	"github.com/google/go-cmp/cmp/cmpopts"
    23  
    24  	"cuelang.org/go/cue/errors"
    25  	"cuelang.org/go/internal/cuetest"
    26  	"cuelang.org/go/mod/module"
    27  )
    28  
    29  var parseTests = []struct {
    30  	testName     string
    31  	parse        func(modfile []byte, filename string) (*File, error)
    32  	data         string
    33  	wantError    string
    34  	want         *File
    35  	wantVersions []module.Version
    36  	wantDefaults map[string]string
    37  }{{
    38  	testName: "NoDeps",
    39  	parse:    Parse,
    40  	data: `
    41  module: "foo.com/bar@v0"
    42  `,
    43  	want: &File{
    44  		Module: "foo.com/bar@v0",
    45  	},
    46  	wantDefaults: map[string]string{
    47  		"foo.com/bar": "v0",
    48  	},
    49  }, {
    50  	testName: "WithDeps",
    51  	parse:    Parse,
    52  	data: `
    53  language: version: "v0.4.3"
    54  module: "foo.com/bar@v0"
    55  deps: "example.com@v1": {
    56  	default: true
    57  	v: "v1.2.3"
    58  }
    59  deps: "other.com/something@v0": v: "v0.2.3"
    60  `,
    61  	want: &File{
    62  		Language: &Language{
    63  			Version: "v0.4.3",
    64  		},
    65  		Module: "foo.com/bar@v0",
    66  		Deps: map[string]*Dep{
    67  			"example.com@v1": {
    68  				Default: true,
    69  				Version: "v1.2.3",
    70  			},
    71  			"other.com/something@v0": {
    72  				Version: "v0.2.3",
    73  			},
    74  		},
    75  	},
    76  	wantVersions: parseVersions("example.com@v1.2.3", "other.com/something@v0.2.3"),
    77  	wantDefaults: map[string]string{
    78  		"foo.com/bar": "v0",
    79  		"example.com": "v1",
    80  	},
    81  }, {
    82  	testName: "AmbiguousDefaults",
    83  	parse:    Parse,
    84  	data: `
    85  module: "foo.com/bar@v0"
    86  deps: "example.com@v1": {
    87  	default: true
    88  	v: "v1.2.3"
    89  }
    90  deps: "example.com@v2": {
    91  	default: true
    92  	v: "v2.0.0"
    93  }
    94  `,
    95  	wantError: `multiple default major versions found for example.com`,
    96  }, {
    97  	testName: "AmbiguousDefaultsWithMainModule",
    98  	parse:    Parse,
    99  	data: `
   100  module: "foo.com/bar@v0"
   101  deps: "foo.com/bar@v1": {
   102  	default: true
   103  	v: "v1.2.3"
   104  }
   105  `,
   106  	wantError: `multiple default major versions found for foo.com/bar`,
   107  }, {
   108  	testName: "MisspelledLanguageVersionField",
   109  	parse:    Parse,
   110  	data: `
   111  langugage: version: "v0.4.3"
   112  module: "foo.com/bar@v0"
   113  `,
   114  	wantError: `langugage: field not allowed:
   115      cuelang.org/go/mod/modfile/schema.cue:28:8
   116      cuelang.org/go/mod/modfile/schema.cue:30:2
   117      module.cue:2:1`,
   118  }, {
   119  	testName: "InvalidLanguageVersion",
   120  	parse:    Parse,
   121  	data: `
   122  language: version: "vblah"
   123  module: "foo.com/bar@v0"`,
   124  	wantError: `language version "vblah" in module.cue is not well formed`,
   125  }, {
   126  	testName: "EmptyLanguageVersion",
   127  	parse:    Parse,
   128  	data: `
   129  language: {}
   130  module: "foo.com/bar@v0"`,
   131  	wantError: `language version "" in module.cue is not well formed`,
   132  }, {
   133  	testName: "NonCanonicalLanguageVersion",
   134  	parse:    Parse,
   135  	data: `
   136  module: "foo.com/bar@v0"
   137  language: version: "v0.8"
   138  `,
   139  	wantError: `language version v0.8 in module.cue is not canonical`,
   140  }, {
   141  	testName: "InvalidDepVersion",
   142  	parse:    Parse,
   143  	data: `
   144  module: "foo.com/bar@v1"
   145  deps: "example.com@v1": v: "1.2.3"
   146  `,
   147  	wantError: `invalid module.cue file module.cue: cannot make version from module "example.com@v1", version "1.2.3": version "1.2.3" \(of module "example.com@v1"\) is not well formed`,
   148  }, {
   149  	testName: "NonCanonicalVersion",
   150  	parse:    Parse,
   151  	data: `
   152  module: "foo.com/bar@v1"
   153  deps: "example.com@v1": v: "v1.2"
   154  `,
   155  	wantError: `invalid module.cue file module.cue: cannot make version from module "example.com@v1", version "v1.2": version "v1.2" \(of module "example.com@v1"\) is not canonical`,
   156  }, {
   157  	testName: "NonCanonicalModule",
   158  	parse:    Parse,
   159  	data: `
   160  module: "foo.com/bar"
   161  `,
   162  	wantError: `module path "foo.com/bar" in module.cue does not contain major version`,
   163  }, {
   164  	testName: "NonCanonicalDep",
   165  	parse:    Parse,
   166  	data: `
   167  module: "foo.com/bar@v1"
   168  deps: "example.com": v: "v1.2.3"
   169  `,
   170  	wantError: `invalid module.cue file module.cue: no major version in "example.com"`,
   171  }, {
   172  	testName: "MismatchedMajorVersion",
   173  	parse:    Parse,
   174  	data: `
   175  module: "foo.com/bar@v1"
   176  deps: "example.com@v1": v: "v0.1.2"
   177  `,
   178  	wantError: `invalid module.cue file module.cue: cannot make version from module "example.com@v1", version "v0.1.2": mismatched major version suffix in "example.com@v1" \(version v0.1.2\)`,
   179  }, {
   180  	testName: "NonStrictNoMajorVersions",
   181  	parse:    ParseNonStrict,
   182  	data: `
   183  module: "foo.com/bar"
   184  deps: "example.com": v: "v1.2.3"
   185  `,
   186  	want: &File{
   187  		Module: "foo.com/bar@v0",
   188  		Deps: map[string]*Dep{
   189  			"example.com": {
   190  				Version: "v1.2.3",
   191  			},
   192  		},
   193  	},
   194  	wantVersions: parseVersions("example.com@v1.2.3"),
   195  	wantDefaults: map[string]string{
   196  		"foo.com/bar": "v0",
   197  	},
   198  }, {
   199  	testName: "LegacyWithExtraFields",
   200  	parse:    ParseLegacy,
   201  	data: `
   202  module: "foo.com/bar"
   203  something: 4
   204  cue: lang: "xxx"
   205  `,
   206  	want: &File{
   207  		Module: "foo.com/bar",
   208  	},
   209  }}
   210  
   211  func TestParse(t *testing.T) {
   212  	for _, test := range parseTests {
   213  		t.Run(test.testName, func(t *testing.T) {
   214  			f, err := test.parse([]byte(test.data), "module.cue")
   215  			if test.wantError != "" {
   216  				gotErr := strings.TrimSuffix(errors.Details(err, nil), "\n")
   217  				qt.Assert(t, qt.Matches(gotErr, test.wantError))
   218  				return
   219  			}
   220  			qt.Assert(t, qt.IsNil(err), qt.Commentf("details: %v", strings.TrimSuffix(errors.Details(err, nil), "\n")))
   221  			qt.Assert(t, qt.CmpEquals(f, test.want, cmpopts.IgnoreUnexported(File{})))
   222  			qt.Assert(t, qt.DeepEquals(f.DepVersions(), test.wantVersions))
   223  			qt.Assert(t, qt.DeepEquals(f.DefaultMajorVersions(), test.wantDefaults))
   224  		})
   225  	}
   226  }
   227  
   228  func TestFormat(t *testing.T) {
   229  	type formatTest struct {
   230  		name      string
   231  		file      *File
   232  		wantError string
   233  		want      string
   234  	}
   235  	tests := []formatTest{{
   236  		name: "WithLanguage",
   237  		file: &File{
   238  			Language: &Language{
   239  				Version: "v0.4.3",
   240  			},
   241  			Module: "foo.com/bar@v0",
   242  			Deps: map[string]*Dep{
   243  				"example.com@v1": {
   244  					Version: "v1.2.3",
   245  				},
   246  				"other.com/something@v0": {
   247  					Version: "v0.2.3",
   248  				},
   249  			},
   250  		},
   251  		want: `module: "foo.com/bar@v0"
   252  language: {
   253  	version: "v0.4.3"
   254  }
   255  deps: {
   256  	"example.com@v1": {
   257  		v: "v1.2.3"
   258  	}
   259  	"other.com/something@v0": {
   260  		v: "v0.2.3"
   261  	}
   262  }
   263  `}, {
   264  		name: "WithoutLanguage",
   265  		file: &File{
   266  			Module: "foo.com/bar@v0",
   267  			Language: &Language{
   268  				Version: "v0.4.3",
   269  			},
   270  		},
   271  		want: `module: "foo.com/bar@v0"
   272  language: {
   273  	version: "v0.4.3"
   274  }
   275  `}, {
   276  		name: "WithInvalidModuleVersion",
   277  		file: &File{
   278  			Module: "foo.com/bar@v0",
   279  			Language: &Language{
   280  				Version: "badversion--",
   281  			},
   282  		},
   283  		wantError: `cannot round-trip module file: language version "badversion--" in - is not well formed`,
   284  	}, {
   285  		name: "WithNonNilEmptyDeps",
   286  		file: &File{
   287  			Module: "foo.com/bar@v0",
   288  			Deps:   map[string]*Dep{},
   289  		},
   290  		want: `module: "foo.com/bar@v0"
   291  `,
   292  	}}
   293  	cuetest.Run(t, tests, func(t *cuetest.T, test *formatTest) {
   294  		data, err := test.file.Format()
   295  		if test.wantError != "" {
   296  			qt.Assert(t, qt.ErrorMatches(err, test.wantError))
   297  			return
   298  		}
   299  		qt.Assert(t, qt.IsNil(err))
   300  		t.Equal(string(data), test.want)
   301  
   302  		// Check that it round-trips.
   303  		f, err := Parse(data, "")
   304  		qt.Assert(t, qt.IsNil(err))
   305  		qt.Assert(t, qt.CmpEquals(f, test.file, cmpopts.IgnoreUnexported(File{}), cmpopts.EquateEmpty()))
   306  	})
   307  }
   308  
   309  func parseVersions(vs ...string) []module.Version {
   310  	vvs := make([]module.Version, 0, len(vs))
   311  	for _, v := range vs {
   312  		vvs = append(vvs, module.MustParseVersion(v))
   313  	}
   314  	return vvs
   315  }
   316  

View as plain text