github.com/golang/dep@v0.5.4/manifest_test.go (about)

     1  // Copyright 2016 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 dep
     6  
     7  import (
     8  	"bytes"
     9  	"errors"
    10  	"fmt"
    11  	"io/ioutil"
    12  	"log"
    13  	"reflect"
    14  	"strings"
    15  	"testing"
    16  
    17  	"github.com/golang/dep/gps"
    18  	"github.com/golang/dep/internal/test"
    19  )
    20  
    21  func TestReadManifest(t *testing.T) {
    22  	h := test.NewHelper(t)
    23  	defer h.Cleanup()
    24  
    25  	mf := h.GetTestFile("manifest/golden.toml")
    26  	defer mf.Close()
    27  	got, _, err := readManifest(mf)
    28  	if err != nil {
    29  		t.Fatalf("should have read manifest correctly, but got err %q", err)
    30  	}
    31  
    32  	c, _ := gps.NewSemverConstraint("^0.12.0")
    33  	want := Manifest{
    34  		Constraints: map[gps.ProjectRoot]gps.ProjectProperties{
    35  			gps.ProjectRoot("github.com/golang/dep"): {
    36  				Constraint: c,
    37  			},
    38  			gps.ProjectRoot("github.com/babble/brook"): {
    39  				Constraint: gps.Revision("d05d5aca9f895d19e9265839bffeadd74a2d2ecb"),
    40  			},
    41  		},
    42  		Ovr: map[gps.ProjectRoot]gps.ProjectProperties{
    43  			gps.ProjectRoot("github.com/golang/dep"): {
    44  				Source:     "https://github.com/golang/dep",
    45  				Constraint: gps.NewBranch("master"),
    46  			},
    47  		},
    48  		Ignored: []string{"github.com/foo/bar"},
    49  		PruneOptions: gps.CascadingPruneOptions{
    50  			DefaultOptions:    gps.PruneNestedVendorDirs | gps.PruneNonGoFiles,
    51  			PerProjectOptions: make(map[gps.ProjectRoot]gps.PruneOptionSet),
    52  		},
    53  	}
    54  
    55  	if !reflect.DeepEqual(got.Constraints, want.Constraints) {
    56  		t.Error("Valid manifest's dependencies did not parse as expected")
    57  	}
    58  	if !reflect.DeepEqual(got.Ovr, want.Ovr) {
    59  		t.Error("Valid manifest's overrides did not parse as expected")
    60  	}
    61  	if !reflect.DeepEqual(got.Ignored, want.Ignored) {
    62  		t.Error("Valid manifest's ignored did not parse as expected")
    63  	}
    64  	if !reflect.DeepEqual(got.PruneOptions, want.PruneOptions) {
    65  		t.Error("Valid manifest's prune options did not parse as expected")
    66  		t.Error(got.PruneOptions, want.PruneOptions)
    67  	}
    68  }
    69  
    70  func TestWriteManifest(t *testing.T) {
    71  	h := test.NewHelper(t)
    72  	defer h.Cleanup()
    73  
    74  	golden := "manifest/golden.toml"
    75  	want := h.GetTestFileString(golden)
    76  	c, _ := gps.NewSemverConstraint("^0.12.0")
    77  	m := NewManifest()
    78  	m.Constraints[gps.ProjectRoot("github.com/golang/dep")] = gps.ProjectProperties{
    79  		Constraint: c,
    80  	}
    81  	m.Constraints[gps.ProjectRoot("github.com/babble/brook")] = gps.ProjectProperties{
    82  		Constraint: gps.Revision("d05d5aca9f895d19e9265839bffeadd74a2d2ecb"),
    83  	}
    84  	m.Ovr[gps.ProjectRoot("github.com/golang/dep")] = gps.ProjectProperties{
    85  		Source:     "https://github.com/golang/dep",
    86  		Constraint: gps.NewBranch("master"),
    87  	}
    88  	m.Ignored = []string{"github.com/foo/bar"}
    89  	m.PruneOptions = gps.CascadingPruneOptions{
    90  		DefaultOptions:    gps.PruneNestedVendorDirs | gps.PruneNonGoFiles,
    91  		PerProjectOptions: make(map[gps.ProjectRoot]gps.PruneOptionSet),
    92  	}
    93  
    94  	got, err := m.MarshalTOML()
    95  	if err != nil {
    96  		t.Fatalf("error while marshaling valid manifest to TOML: %q", err)
    97  	}
    98  
    99  	if string(got) != want {
   100  		if *test.UpdateGolden {
   101  			if err = h.WriteTestFile(golden, string(got)); err != nil {
   102  				t.Fatal(err)
   103  			}
   104  		} else {
   105  			t.Errorf("valid manifest did not marshal to TOML as expected:\n(GOT):\n%s\n(WNT):\n%s", string(got), want)
   106  		}
   107  	}
   108  }
   109  
   110  func TestReadManifestErrors(t *testing.T) {
   111  	h := test.NewHelper(t)
   112  	defer h.Cleanup()
   113  	var err error
   114  
   115  	tests := []struct {
   116  		name string
   117  		file string
   118  	}{
   119  		{"multiple constraints", "manifest/error1.toml"},
   120  		{"multiple dependencies", "manifest/error2.toml"},
   121  		{"multiple overrides", "manifest/error3.toml"},
   122  	}
   123  
   124  	for _, tst := range tests {
   125  		mf := h.GetTestFile(tst.file)
   126  		defer mf.Close()
   127  		_, _, err = readManifest(mf)
   128  		if err == nil {
   129  			t.Errorf("reading manifest with %s should have caused error, but did not", tst.name)
   130  		} else if !strings.Contains(err.Error(), tst.name) {
   131  			t.Errorf("unexpected error %q; expected %s error", err, tst.name)
   132  		}
   133  	}
   134  }
   135  
   136  func TestValidateManifest(t *testing.T) {
   137  	cases := []struct {
   138  		name       string
   139  		tomlString string
   140  		wantWarn   []error
   141  		wantError  error
   142  	}{
   143  		{
   144  			name: "valid required",
   145  			tomlString: `
   146  			required = ["github.com/foo/bar"]
   147  			`,
   148  			wantWarn:  []error{},
   149  			wantError: nil,
   150  		},
   151  		{
   152  			name: "invalid required",
   153  			tomlString: `
   154  			required = "github.com/foo/bar"
   155  			`,
   156  			wantWarn:  []error{},
   157  			wantError: errInvalidRequired,
   158  		},
   159  		{
   160  			name: "empty required",
   161  			tomlString: `
   162  			required = []
   163  			`,
   164  			wantWarn:  []error{},
   165  			wantError: nil,
   166  		},
   167  		{
   168  			name: "invalid required list",
   169  			tomlString: `
   170  			required = [1, 2, 3]
   171  			`,
   172  			wantWarn:  []error{},
   173  			wantError: errInvalidRequired,
   174  		},
   175  		{
   176  			name: "invalid required format",
   177  			tomlString: `
   178  			[[required]]
   179  			  name = "foo"
   180  			`,
   181  			wantWarn:  []error{},
   182  			wantError: errInvalidRequired,
   183  		},
   184  		{
   185  			name: "valid ignored",
   186  			tomlString: `
   187  			ignored = ["foo"]
   188  			`,
   189  			wantWarn:  []error{},
   190  			wantError: nil,
   191  		},
   192  		{
   193  			name: "invalid ignored",
   194  			tomlString: `
   195  			ignored = "foo"
   196  			`,
   197  			wantWarn:  []error{},
   198  			wantError: errInvalidIgnored,
   199  		},
   200  		{
   201  			name: "empty ignored",
   202  			tomlString: `
   203  			ignored = []
   204  			`,
   205  			wantWarn:  []error{},
   206  			wantError: nil,
   207  		},
   208  		{
   209  			name: "invalid ignored list",
   210  			tomlString: `
   211  			ignored = [1, 2, 3]
   212  			`,
   213  			wantWarn:  []error{},
   214  			wantError: errInvalidIgnored,
   215  		},
   216  		{
   217  			name: "invalid ignored format",
   218  			tomlString: `
   219  			[[ignored]]
   220  			  name = "foo"
   221  			`,
   222  			wantWarn:  []error{},
   223  			wantError: errInvalidIgnored,
   224  		},
   225  		{
   226  			name: "valid metadata",
   227  			tomlString: `
   228  			[metadata]
   229  			  authors = "foo"
   230  			  version = "1.0.0"
   231  			`,
   232  			wantWarn:  []error{},
   233  			wantError: nil,
   234  		},
   235  		{
   236  			name: "invalid metadata",
   237  			tomlString: `
   238  			foo = "some-value"
   239  			version = 14
   240  
   241  			[[bar]]
   242  			  author = "xyz"
   243  
   244  			[[constraint]]
   245  			  name = "github.com/foo/bar"
   246  			  version = ""
   247  			`,
   248  			wantWarn: []error{
   249  				errors.New("unknown field in manifest: foo"),
   250  				errors.New("unknown field in manifest: bar"),
   251  				errors.New("unknown field in manifest: version"),
   252  			},
   253  			wantError: nil,
   254  		},
   255  		{
   256  			name: "invalid metadata format",
   257  			tomlString: `
   258  			metadata = "project-name"
   259  
   260  			[[constraint]]
   261  			  name = "github.com/foo/bar"
   262  			`,
   263  			wantWarn: []error{
   264  				errInvalidMetadata,
   265  				errors.New("branch, version, revision, or source should be provided for \"github.com/foo/bar\""),
   266  			},
   267  			wantError: nil,
   268  		},
   269  		{
   270  			name: "plain constraint",
   271  			tomlString: `
   272  			[[constraint]]
   273  			  name = "github.com/foo/bar"
   274  			`,
   275  			wantWarn: []error{
   276  				errors.New("branch, version, revision, or source should be provided for \"github.com/foo/bar\""),
   277  			},
   278  			wantError: nil,
   279  		},
   280  		{
   281  			name: "empty constraint",
   282  			tomlString: `
   283  			[[constraint]]
   284  			`,
   285  			wantWarn: []error{
   286  				errNoName,
   287  			},
   288  			wantError: nil,
   289  		},
   290  		{
   291  			name: "invalid constraint",
   292  			tomlString: `
   293  			constraint = "foo"
   294  			`,
   295  			wantWarn:  []error{},
   296  			wantError: errInvalidConstraint,
   297  		},
   298  		{
   299  			name: "invalid constraint list",
   300  			tomlString: `
   301  			constraint = ["foo", "bar"]
   302  			`,
   303  			wantWarn:  []error{},
   304  			wantError: errInvalidConstraint,
   305  		},
   306  		{
   307  			name: "valid override",
   308  			tomlString: `
   309  			[[override]]
   310  			  name = "github.com/foo/bar"
   311  			`,
   312  			wantWarn:  []error{},
   313  			wantError: nil,
   314  		},
   315  		{
   316  			name: "empty override",
   317  			tomlString: `
   318  			[[override]]
   319  			`,
   320  			wantWarn: []error{
   321  				errNoName,
   322  			},
   323  			wantError: nil,
   324  		},
   325  		{
   326  			name: "invalid override",
   327  			tomlString: `
   328  			override = "bar"
   329  			`,
   330  			wantWarn:  []error{},
   331  			wantError: errInvalidOverride,
   332  		},
   333  		{
   334  			name: "invalid override list",
   335  			tomlString: `
   336  			override = ["foo", "bar"]
   337  			`,
   338  			wantWarn:  []error{},
   339  			wantError: errInvalidOverride,
   340  		},
   341  		{
   342  			name: "invalid fields",
   343  			tomlString: `
   344  			[[constraint]]
   345  			  name = "github.com/foo/bar"
   346  			  location = "some-value"
   347  			  link = "some-other-value"
   348  			  metadata = "foo"
   349  
   350  			[[override]]
   351  			  nick = "foo"
   352  			`,
   353  			wantWarn: []error{
   354  				errors.New("invalid key \"location\" in \"constraint\""),
   355  				errors.New("invalid key \"link\" in \"constraint\""),
   356  				errors.New("metadata in \"constraint\" should be a TOML table"),
   357  				errors.New("branch, version, revision, or source should be provided for \"github.com/foo/bar\""),
   358  				errors.New("invalid key \"nick\" in \"override\""),
   359  				errNoName,
   360  			},
   361  			wantError: nil,
   362  		},
   363  		{
   364  			name: "constraint metadata",
   365  			tomlString: `
   366  			[[constraint]]
   367  			  name = "github.com/foo/bar"
   368  
   369  			  [constraint.metadata]
   370  			    color = "blue"
   371  			`,
   372  			wantWarn: []error{
   373  				errors.New("branch, version, revision, or source should be provided for \"github.com/foo/bar\""),
   374  			},
   375  			wantError: nil,
   376  		},
   377  		{
   378  			name: "invalid revision",
   379  			tomlString: `
   380  			[[constraint]]
   381  			  name = "github.com/foo/bar"
   382  			  revision = "b86ad16"
   383  			`,
   384  			wantWarn: []error{
   385  				errors.New("revision \"b86ad16\" should not be in abbreviated form"),
   386  			},
   387  			wantError: nil,
   388  		},
   389  		{
   390  			name: "invalid hg revision",
   391  			tomlString: `
   392  			[[constraint]]
   393  			  name = "foobar.com/hg"
   394  			  revision = "8d43f8c0b836"
   395  			`,
   396  			wantWarn:  []error{errors.New("revision \"8d43f8c0b836\" should not be in abbreviated form")},
   397  			wantError: nil,
   398  		},
   399  		{
   400  			name: "valid prune options",
   401  			tomlString: `
   402  			[prune]
   403  			  non-go = true
   404  			`,
   405  			wantWarn:  []error{},
   406  			wantError: nil,
   407  		},
   408  		{
   409  			name: "invalid root prune options",
   410  			tomlString: `
   411  			[prune]
   412  			  non-go = false
   413  			`,
   414  			wantWarn:  []error{},
   415  			wantError: errInvalidRootPruneValue,
   416  		},
   417  		{
   418  			name: "root options should not contain a name",
   419  			tomlString: `
   420  			[prune]
   421  			  go-tests = true
   422  			  name = "github.com/golang/dep"
   423  			`,
   424  			wantWarn: []error{
   425  				errRootPruneContainsName,
   426  			},
   427  			wantError: nil,
   428  		},
   429  		{
   430  			name: "invalid prune project",
   431  			tomlString: `
   432  			[prune]
   433  			  non-go = true
   434  
   435  			  [prune.project]
   436  			    name = "github.com/org/project"
   437  			    non-go = true
   438  			`,
   439  			wantWarn:  []error{},
   440  			wantError: errInvalidPruneProject,
   441  		},
   442  	}
   443  
   444  	for _, c := range cases {
   445  		t.Run(c.name, func(t *testing.T) {
   446  			errs, err := validateManifest(c.tomlString)
   447  
   448  			// compare validation errors
   449  			if err != c.wantError {
   450  				t.Fatalf("manifest errors are not as expected: \n\t(GOT) %v \n\t(WNT) %v", err, c.wantError)
   451  			}
   452  
   453  			// compare length of error slice
   454  			if len(errs) != len(c.wantWarn) {
   455  				t.Fatalf("number of manifest errors are not as expected: \n\t(GOT) %v errors(%v)\n\t(WNT) %v errors(%v).", len(errs), errs, len(c.wantWarn), c.wantWarn)
   456  			}
   457  
   458  			// check if the expected errors exist in actual errors slice
   459  			for _, er := range errs {
   460  				if !containsErr(c.wantWarn, er) {
   461  					t.Fatalf("manifest errors are not as expected: \n\t(MISSING) %v\n\t(FROM) %v", er, c.wantWarn)
   462  				}
   463  			}
   464  		})
   465  	}
   466  }
   467  
   468  func TestCheckRedundantPruneOptions(t *testing.T) {
   469  	cases := []struct {
   470  		name         string
   471  		pruneOptions gps.CascadingPruneOptions
   472  		wantWarn     []error
   473  	}{
   474  		{
   475  			name: "all redundant on true",
   476  			pruneOptions: gps.CascadingPruneOptions{
   477  				DefaultOptions: 15,
   478  				PerProjectOptions: map[gps.ProjectRoot]gps.PruneOptionSet{
   479  					"github.com/golang/dep": {
   480  						NestedVendor:   pvtrue,
   481  						UnusedPackages: pvtrue,
   482  						NonGoFiles:     pvtrue,
   483  						GoTests:        pvtrue,
   484  					},
   485  				},
   486  			},
   487  			wantWarn: []error{
   488  				fmt.Errorf("redundant prune option %q set for %q", "unused-packages", "github.com/golang/dep"),
   489  				fmt.Errorf("redundant prune option %q set for %q", "non-go", "github.com/golang/dep"),
   490  				fmt.Errorf("redundant prune option %q set for %q", "go-tests", "github.com/golang/dep"),
   491  			},
   492  		},
   493  		{
   494  			name: "all redundant on false",
   495  			pruneOptions: gps.CascadingPruneOptions{
   496  				DefaultOptions: 1,
   497  				PerProjectOptions: map[gps.ProjectRoot]gps.PruneOptionSet{
   498  					"github.com/golang/dep": {
   499  						NestedVendor:   pvtrue,
   500  						UnusedPackages: pvfalse,
   501  						NonGoFiles:     pvfalse,
   502  						GoTests:        pvfalse,
   503  					},
   504  				},
   505  			},
   506  			wantWarn: []error{
   507  				fmt.Errorf("redundant prune option %q set for %q", "unused-packages", "github.com/golang/dep"),
   508  				fmt.Errorf("redundant prune option %q set for %q", "non-go", "github.com/golang/dep"),
   509  				fmt.Errorf("redundant prune option %q set for %q", "go-tests", "github.com/golang/dep"),
   510  			},
   511  		},
   512  		{
   513  			name: "redundancy mix across multiple projects",
   514  			pruneOptions: gps.CascadingPruneOptions{
   515  				DefaultOptions: 7,
   516  				PerProjectOptions: map[gps.ProjectRoot]gps.PruneOptionSet{
   517  					"github.com/golang/dep": {
   518  						NestedVendor: pvtrue,
   519  						NonGoFiles:   pvtrue,
   520  						GoTests:      pvtrue,
   521  					},
   522  					"github.com/other/project": {
   523  						NestedVendor:   pvtrue,
   524  						UnusedPackages: pvfalse,
   525  						GoTests:        pvfalse,
   526  					},
   527  				},
   528  			},
   529  			wantWarn: []error{
   530  				fmt.Errorf("redundant prune option %q set for %q", "non-go", "github.com/golang/dep"),
   531  				fmt.Errorf("redundant prune option %q set for %q", "go-tests", "github.com/other/project"),
   532  			},
   533  		},
   534  	}
   535  
   536  	for _, c := range cases {
   537  		t.Run(c.name, func(t *testing.T) {
   538  			errs := checkRedundantPruneOptions(c.pruneOptions)
   539  
   540  			// compare length of error slice
   541  			if len(errs) != len(c.wantWarn) {
   542  				t.Fatalf("number of manifest errors are not as expected:\n\t(GOT) %v errors(%v)\n\t(WNT) %v errors(%v).", len(errs), errs, len(c.wantWarn), c.wantWarn)
   543  			}
   544  
   545  			for _, er := range errs {
   546  				if !containsErr(c.wantWarn, er) {
   547  					t.Fatalf("manifest errors are not as expected:\n\t(MISSING)\n%v\n\t(FROM)\n%v", er, c.wantWarn)
   548  				}
   549  			}
   550  		})
   551  	}
   552  }
   553  
   554  func TestValidateProjectRoots(t *testing.T) {
   555  	cases := []struct {
   556  		name      string
   557  		manifest  Manifest
   558  		wantError error
   559  		wantWarn  []string
   560  	}{
   561  		{
   562  			name:      "empty Manifest",
   563  			manifest:  Manifest{},
   564  			wantError: nil,
   565  			wantWarn:  []string{},
   566  		},
   567  		{
   568  			name: "valid project root",
   569  			manifest: Manifest{
   570  				Constraints: map[gps.ProjectRoot]gps.ProjectProperties{
   571  					gps.ProjectRoot("github.com/golang/dep"): {
   572  						Constraint: gps.Any(),
   573  					},
   574  				},
   575  			},
   576  			wantError: nil,
   577  			wantWarn:  []string{},
   578  		},
   579  		{
   580  			name: "invalid project roots in Constraints and Overrides",
   581  			manifest: Manifest{
   582  				Constraints: map[gps.ProjectRoot]gps.ProjectProperties{
   583  					gps.ProjectRoot("github.com/golang/dep/foo"): {
   584  						Constraint: gps.Any(),
   585  					},
   586  					gps.ProjectRoot("github.com/golang/go/xyz"): {
   587  						Constraint: gps.Any(),
   588  					},
   589  					gps.ProjectRoot("github.com/golang/fmt"): {
   590  						Constraint: gps.Any(),
   591  					},
   592  				},
   593  				Ovr: map[gps.ProjectRoot]gps.ProjectProperties{
   594  					gps.ProjectRoot("github.com/golang/mock/bar"): {
   595  						Constraint: gps.Any(),
   596  					},
   597  					gps.ProjectRoot("github.com/golang/mock"): {
   598  						Constraint: gps.Any(),
   599  					},
   600  				},
   601  			},
   602  			wantError: errInvalidProjectRoot,
   603  			wantWarn: []string{
   604  				"the name for \"github.com/golang/dep/foo\" should be changed to \"github.com/golang/dep\"",
   605  				"the name for \"github.com/golang/mock/bar\" should be changed to \"github.com/golang/mock\"",
   606  				"the name for \"github.com/golang/go/xyz\" should be changed to \"github.com/golang/go\"",
   607  			},
   608  		},
   609  		{
   610  			name: "invalid source path",
   611  			manifest: Manifest{
   612  				Constraints: map[gps.ProjectRoot]gps.ProjectProperties{
   613  					gps.ProjectRoot("github.com/golang"): {
   614  						Constraint: gps.Any(),
   615  					},
   616  				},
   617  			},
   618  			wantError: errInvalidProjectRoot,
   619  			wantWarn:  []string{},
   620  		},
   621  	}
   622  
   623  	h := test.NewHelper(t)
   624  	defer h.Cleanup()
   625  
   626  	h.TempDir("src")
   627  	pwd := h.Path(".")
   628  
   629  	// Capture the stderr to verify the warnings
   630  	stderrOutput := &bytes.Buffer{}
   631  	errLogger := log.New(stderrOutput, "", 0)
   632  	ctx := &Ctx{
   633  		GOPATH: pwd,
   634  		Out:    log.New(ioutil.Discard, "", 0),
   635  		Err:    errLogger,
   636  	}
   637  
   638  	sm, err := ctx.SourceManager()
   639  	h.Must(err)
   640  	defer sm.Release()
   641  
   642  	for _, c := range cases {
   643  		t.Run(c.name, func(t *testing.T) {
   644  			// Empty the buffer for every case
   645  			stderrOutput.Reset()
   646  			err := ValidateProjectRoots(ctx, &c.manifest, sm)
   647  			if err != c.wantError {
   648  				t.Fatalf("unexpected error while validating project roots:\n\t(GOT): %v\n\t(WNT): %v", err, c.wantError)
   649  			}
   650  
   651  			warnings := stderrOutput.String()
   652  			for _, warn := range c.wantWarn {
   653  				if !strings.Contains(warnings, warn) {
   654  					t.Fatalf("expected ValidateProjectRoot errors to contain: %q", warn)
   655  				}
   656  			}
   657  		})
   658  	}
   659  }
   660  
   661  //func TestFromRawPruneOptions(t *testing.T) {
   662  //cases := []struct {
   663  //name            string
   664  //rawPruneOptions rawPruneOptions
   665  //wantOptions     gps.CascadingPruneOptions
   666  //}{
   667  //{
   668  //name: "global all options project no options",
   669  //rawPruneOptions: rawPruneOptions{
   670  //UnusedPackages: true,
   671  //NonGoFiles:     true,
   672  //GoTests:        true,
   673  //Projects: []map[string]interface{}{
   674  //{
   675  //"name": "github.com/golang/dep",
   676  //pruneOptionUnusedPackages: false,
   677  //pruneOptionNonGo:          false,
   678  //pruneOptionGoTests:        false,
   679  //},
   680  //},
   681  //},
   682  //wantOptions: gps.CascadingPruneOptions{
   683  //DefaultOptions: 15,
   684  //PerProjectOptions: map[gps.ProjectRoot]gps.PruneOptionSet{
   685  //"github.com/golang/dep": gps.PruneOptionSet{
   686  //NestedVendor:   pvtrue,
   687  //UnusedPackages: pvfalse,
   688  //NonGoFiles:     pvfalse,
   689  //GoTests:        pvfalse,
   690  //},
   691  //},
   692  //},
   693  //},
   694  //{
   695  //name: "global all options project mixed options",
   696  //rawPruneOptions: rawPruneOptions{
   697  //UnusedPackages: true,
   698  //NonGoFiles:     true,
   699  //GoTests:        true,
   700  //Projects: []map[string]interface{}{
   701  //{
   702  //"name": "github.com/golang/dep",
   703  //pruneOptionUnusedPackages: false,
   704  //},
   705  //},
   706  //},
   707  //wantOptions: gps.CascadingPruneOptions{
   708  //DefaultOptions: 15,
   709  //PerProjectOptions: map[gps.ProjectRoot]gps.PruneOptionSet{
   710  //"github.com/golang/dep": gps.PruneOptionSet{
   711  //NestedVendor:   pvtrue,
   712  //UnusedPackages: pvfalse,
   713  //},
   714  //},
   715  //},
   716  //},
   717  //{
   718  //name: "global no options project all options",
   719  //rawPruneOptions: rawPruneOptions{
   720  //UnusedPackages: false,
   721  //NonGoFiles:     false,
   722  //GoTests:        false,
   723  //Projects: []map[string]interface{}{
   724  //{
   725  //"name": "github.com/golang/dep",
   726  //pruneOptionUnusedPackages: true,
   727  //pruneOptionNonGo:          true,
   728  //pruneOptionGoTests:        true,
   729  //},
   730  //},
   731  //},
   732  //wantOptions: gps.CascadingPruneOptions{
   733  //DefaultOptions: 1,
   734  //PerProjectOptions: map[gps.ProjectRoot]gps.PruneOptionSet{
   735  //"github.com/golang/dep": gps.PruneOptionSet{
   736  //NestedVendor:   pvtrue,
   737  //UnusedPackages: pvtrue,
   738  //NonGoFiles:     pvtrue,
   739  //GoTests:        pvtrue,
   740  //},
   741  //},
   742  //},
   743  //},
   744  //}
   745  
   746  //for _, c := range cases {
   747  //t.Run(c.name, func(t *testing.T) {
   748  //opts, err := fromRawPruneOptions(c.rawPruneOptions)
   749  //if err != nil {
   750  //t.Fatal(err)
   751  //}
   752  
   753  //if !reflect.DeepEqual(opts, c.wantOptions) {
   754  //t.Fatalf("rawPruneOptions are not as expected:\n\t(GOT) %v\n\t(WNT) %v", opts, c.wantOptions)
   755  //}
   756  //})
   757  //}
   758  //}
   759  
   760  func TestToRawPruneOptions(t *testing.T) {
   761  	cases := []struct {
   762  		name         string
   763  		pruneOptions gps.CascadingPruneOptions
   764  		wantOptions  rawPruneOptions
   765  	}{
   766  		{
   767  			name:         "all options",
   768  			pruneOptions: gps.CascadingPruneOptions{DefaultOptions: 15},
   769  			wantOptions: rawPruneOptions{
   770  				UnusedPackages: true,
   771  				NonGoFiles:     true,
   772  				GoTests:        true,
   773  			},
   774  		},
   775  		{
   776  			name:         "no options",
   777  			pruneOptions: gps.CascadingPruneOptions{DefaultOptions: 1},
   778  			wantOptions: rawPruneOptions{
   779  				UnusedPackages: false,
   780  				NonGoFiles:     false,
   781  				GoTests:        false,
   782  			},
   783  		},
   784  	}
   785  
   786  	for _, c := range cases {
   787  		t.Run(c.name, func(t *testing.T) {
   788  			raw := toRawPruneOptions(c.pruneOptions)
   789  
   790  			if !reflect.DeepEqual(raw, c.wantOptions) {
   791  				t.Fatalf("rawPruneOptions are not as expected:\n\t(GOT) %v\n\t(WNT) %v", raw, c.wantOptions)
   792  			}
   793  		})
   794  	}
   795  }
   796  
   797  func TestToRawPruneOptions_Panic(t *testing.T) {
   798  	pruneOptions := gps.CascadingPruneOptions{
   799  		DefaultOptions: 1,
   800  		PerProjectOptions: map[gps.ProjectRoot]gps.PruneOptionSet{
   801  			"github.com/carolynvs/deptest": {
   802  				NestedVendor: pvtrue,
   803  			},
   804  		},
   805  	}
   806  	defer func() {
   807  		if err := recover(); err == nil {
   808  			t.Error("toRawPruneOptions did not panic with non-empty ProjectOptions")
   809  		}
   810  	}()
   811  	_ = toRawPruneOptions(pruneOptions)
   812  }
   813  
   814  func containsErr(s []error, e error) bool {
   815  	for _, a := range s {
   816  		if a.Error() == e.Error() {
   817  			return true
   818  		}
   819  	}
   820  	return false
   821  }