github.com/golang/dep@v0.5.4/internal/importers/importertest/testcase.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 importertest 6 7 import ( 8 "bytes" 9 "io/ioutil" 10 "log" 11 "sort" 12 "strings" 13 "testing" 14 15 "github.com/golang/dep" 16 "github.com/golang/dep/gps" 17 "github.com/golang/dep/internal/test" 18 "github.com/pkg/errors" 19 ) 20 21 // TestCase is a common set of validations applied to the result 22 // of an importer converting from an external config format to dep's. 23 type TestCase struct { 24 DefaultConstraintFromLock bool 25 WantSourceRepo string 26 WantConstraint string 27 WantRevision gps.Revision 28 WantVersion string 29 WantIgnored []string 30 WantRequired []string 31 WantWarning string 32 } 33 34 // NewTestContext creates a unique context with its own GOPATH for a single test. 35 func NewTestContext(h *test.Helper) *dep.Ctx { 36 h.TempDir("src") 37 pwd := h.Path(".") 38 discardLogger := log.New(ioutil.Discard, "", 0) 39 40 return &dep.Ctx{ 41 GOPATH: pwd, 42 Out: discardLogger, 43 Err: discardLogger, 44 } 45 } 46 47 // Execute and validate the test case. 48 func (tc TestCase) Execute(t *testing.T, convert func(logger *log.Logger, sm gps.SourceManager) (*dep.Manifest, *dep.Lock)) error { 49 h := test.NewHelper(t) 50 defer h.Cleanup() 51 // Disable parallel tests until we can resolve this error on the Windows builds: 52 // "remote repository at https://github.com/carolynvs/deptest-importers does not exist, or is inaccessible" 53 //h.Parallel() 54 55 ctx := NewTestContext(h) 56 sm, err := ctx.SourceManager() 57 h.Must(err) 58 defer sm.Release() 59 60 // Capture stderr so we can verify warnings 61 output := &bytes.Buffer{} 62 ctx.Err = log.New(output, "", 0) 63 64 manifest, lock := convert(ctx.Err, sm) 65 return tc.validate(manifest, lock, output) 66 } 67 68 // validate returns an error if any of the testcase validations failed. 69 func (tc TestCase) validate(manifest *dep.Manifest, lock *dep.Lock, output *bytes.Buffer) error { 70 if !equalSlice(manifest.Ignored, tc.WantIgnored) { 71 return errors.Errorf("unexpected set of ignored projects: \n\t(GOT) %#v \n\t(WNT) %#v", 72 manifest.Ignored, tc.WantIgnored) 73 } 74 75 if !equalSlice(manifest.Required, tc.WantRequired) { 76 return errors.Errorf("unexpected set of required projects: \n\t(GOT) %#v \n\t(WNT) %#v", 77 manifest.Required, tc.WantRequired) 78 } 79 80 wantConstraintCount := 0 81 if tc.WantConstraint != "" { 82 wantConstraintCount = 1 83 } 84 gotConstraintCount := len(manifest.Constraints) 85 if gotConstraintCount != wantConstraintCount { 86 return errors.Errorf("unexpected number of constraints: \n\t(GOT) %v \n\t(WNT) %v", 87 gotConstraintCount, wantConstraintCount) 88 } 89 90 if tc.WantConstraint != "" { 91 d, ok := manifest.Constraints[Project] 92 if !ok { 93 return errors.Errorf("Expected the manifest to have a dependency for '%v'", 94 Project) 95 } 96 97 gotConstraint := d.Constraint.String() 98 if gotConstraint != tc.WantConstraint { 99 return errors.Errorf("unexpected constraint: \n\t(GOT) %v \n\t(WNT) %v", 100 gotConstraint, tc.WantConstraint) 101 } 102 103 } 104 105 // Lock checks. 106 wantLockCount := 0 107 if tc.WantRevision != "" { 108 wantLockCount = 1 109 } 110 gotLockCount := 0 111 if lock != nil { 112 gotLockCount = len(lock.P) 113 } 114 if gotLockCount != wantLockCount { 115 return errors.Errorf("unexpected number of locked projects: \n\t(GOT) %v \n\t(WNT) %v", 116 gotLockCount, wantLockCount) 117 } 118 119 if tc.WantRevision != "" { 120 lp := lock.P[0] 121 122 gotProjectRoot := lp.Ident().ProjectRoot 123 if gotProjectRoot != Project { 124 return errors.Errorf("unexpected root project in lock: \n\t(GOT) %v \n\t(WNT) %v", 125 gotProjectRoot, Project) 126 } 127 128 gotSource := lp.Ident().Source 129 if gotSource != tc.WantSourceRepo { 130 return errors.Errorf("unexpected source repository: \n\t(GOT) %v \n\t(WNT) %v", 131 gotSource, tc.WantSourceRepo) 132 } 133 134 // Break down the locked "version" into a version (optional) and revision 135 var gotVersion string 136 var gotRevision gps.Revision 137 if lpv, ok := lp.Version().(gps.PairedVersion); ok { 138 gotVersion = lpv.String() 139 gotRevision = lpv.Revision() 140 } else if lr, ok := lp.Version().(gps.Revision); ok { 141 gotRevision = lr 142 } else { 143 return errors.New("could not determine the type of the locked version") 144 } 145 146 if gotRevision != tc.WantRevision { 147 return errors.Errorf("unexpected locked revision: \n\t(GOT) %v \n\t(WNT) %v", 148 gotRevision, 149 tc.WantRevision) 150 } 151 if gotVersion != tc.WantVersion { 152 return errors.Errorf("unexpected locked version: \n\t(GOT) %v \n\t(WNT) %v", 153 gotVersion, 154 tc.WantVersion) 155 } 156 } 157 158 if tc.WantWarning != "" { 159 gotWarning := output.String() 160 if !strings.Contains(gotWarning, tc.WantWarning) { 161 return errors.Errorf("Expected the output to include the warning '%s' but got '%s'\n", tc.WantWarning, gotWarning) 162 } 163 } 164 165 return nil 166 } 167 168 // equalSlice is comparing two string slices for equality. 169 func equalSlice(a, b []string) bool { 170 if a == nil && b == nil { 171 return true 172 } 173 174 if a == nil || b == nil { 175 return false 176 } 177 178 if len(a) != len(b) { 179 return false 180 } 181 182 sort.Strings(a) 183 sort.Strings(b) 184 for i := range a { 185 if a[i] != b[i] { 186 return false 187 } 188 } 189 190 return true 191 }