github.com/golang/dep@v0.5.4/internal/test/integration/testcase.go (about) 1 // Copyright 2017 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 integration 6 7 import ( 8 "encoding/json" 9 "io/ioutil" 10 "os" 11 "path/filepath" 12 "strings" 13 "testing" 14 "unicode" 15 16 "github.com/golang/dep/internal/test" 17 ) 18 19 // TestCase manages a test case directory structure and content 20 type TestCase struct { 21 t *testing.T 22 name string 23 rootPath string 24 initialPath string 25 finalPath string 26 Commands [][]string `json:"commands"` 27 ShouldFail bool `json:"should-fail"` 28 ErrorExpected string `json:"error-expected"` 29 GopathInitial map[string]string `json:"gopath-initial"` 30 VendorInitial map[string]string `json:"vendor-initial"` 31 VendorFinal []string `json:"vendor-final"` 32 InitPath string `json:"init-path"` 33 34 RequiredFeatureFlag string `json:"feature"` 35 } 36 37 // NewTestCase creates a new TestCase. 38 func NewTestCase(t *testing.T, dir, name string) *TestCase { 39 rootPath := filepath.FromSlash(filepath.Join(dir, name)) 40 n := &TestCase{ 41 t: t, 42 name: name, 43 rootPath: rootPath, 44 initialPath: filepath.Join(rootPath, "initial"), 45 finalPath: filepath.Join(rootPath, "final"), 46 } 47 j, err := ioutil.ReadFile(filepath.Join(rootPath, "testcase.json")) 48 if err != nil { 49 t.Fatal(err) 50 } 51 err = json.Unmarshal(j, n) 52 if err != nil { 53 t.Fatal(err) 54 } 55 56 // Flip ShouldFail on if it's not set, but there's an expected error. 57 if n.ErrorExpected != "" && !n.ShouldFail { 58 n.ShouldFail = true 59 } 60 return n 61 } 62 63 // InitialPath represents the initial set of files in a project. 64 func (tc *TestCase) InitialPath() string { 65 return tc.initialPath 66 } 67 68 // UpdateFile updates the golden file with the working result. 69 func (tc *TestCase) UpdateFile(goldenPath, workingPath string) { 70 exists, working, err := getFile(workingPath) 71 if err != nil { 72 tc.t.Fatalf("Error reading project file %s: %s", goldenPath, err) 73 } 74 75 golden := filepath.Join(tc.finalPath, goldenPath) 76 if exists { 77 if err := tc.WriteFile(golden, working); err != nil { 78 tc.t.Fatal(err) 79 } 80 } else { 81 err := os.Remove(golden) 82 if err != nil && !os.IsNotExist(err) { 83 tc.t.Fatal(err) 84 } 85 } 86 } 87 88 // CompareFile compares the golden file with the working result. 89 func (tc *TestCase) CompareFile(goldenPath, working string) { 90 golden := filepath.Join(tc.finalPath, goldenPath) 91 92 gotExists, got, err := getFile(working) 93 if err != nil { 94 tc.t.Fatalf("Error reading project file %q: %s", goldenPath, err) 95 } 96 wantExists, want, err := getFile(golden) 97 if err != nil { 98 tc.t.Fatalf("Error reading testcase file %q: %s", goldenPath, err) 99 } 100 101 if wantExists && gotExists { 102 if want != got { 103 tc.t.Errorf("%s was not as expected\n(WNT):\n%s\n(GOT):\n%s", filepath.Base(goldenPath), want, got) 104 } 105 } else if !wantExists && gotExists { 106 tc.t.Errorf("%q created where none was expected", goldenPath) 107 } else if wantExists && !gotExists { 108 tc.t.Errorf("%q not created where one was expected", goldenPath) 109 } 110 } 111 112 // UpdateOutput updates the golden file for stdout with the working result. 113 func (tc *TestCase) UpdateOutput(stdout string) { 114 stdoutPath := filepath.Join(tc.rootPath, "stdout.txt") 115 _, err := os.Stat(stdoutPath) 116 if err != nil { 117 if os.IsNotExist(err) { 118 // Don't update the stdout.txt file if it doesn't exist. 119 return 120 } 121 panic(err) 122 } 123 124 if err := tc.WriteFile(stdoutPath, stdout); err != nil { 125 tc.t.Fatal(err) 126 } 127 } 128 129 // CompareOutput compares expected and actual stdout output. 130 func (tc *TestCase) CompareOutput(stdout string) { 131 expected, err := ioutil.ReadFile(filepath.Join(tc.rootPath, "stdout.txt")) 132 if err != nil { 133 if os.IsNotExist(err) { 134 // Nothing to verify 135 return 136 } 137 panic(err) 138 } 139 140 expStr := normalizeLines(string(expected)) 141 stdout = normalizeLines(stdout) 142 143 if expStr != stdout { 144 tc.t.Errorf("stdout was not as expected\n(WNT):\n%s\n(GOT):\n%s\n", expStr, stdout) 145 } 146 } 147 148 // normalizeLines returns a version with trailing whitespace stripped from each line. 149 func normalizeLines(s string) string { 150 lines := strings.Split(s, "\n") 151 for i := range lines { 152 lines[i] = strings.TrimRightFunc(lines[i], unicode.IsSpace) 153 } 154 return strings.Join(lines, "\n") 155 } 156 157 // CompareError compares expected and actual stderr output. 158 func (tc *TestCase) CompareError(err error, stderr string) { 159 wantExists, want := tc.ErrorExpected != "", tc.ErrorExpected 160 gotExists, got := stderr != "" && err != nil, stderr 161 162 if wantExists && gotExists { 163 switch c := strings.Count(got, want); c { 164 case 0: 165 tc.t.Errorf("error did not contain expected string:\n\t(GOT): %s\n\t(WNT): %s", got, want) 166 case 1: 167 default: 168 tc.t.Errorf("expected error %s matches %d times to actual error %s", want, c, got) 169 } 170 } else if !wantExists && gotExists { 171 tc.t.Fatalf("error raised where none was expected: \n%v", stderr) 172 } else if wantExists && !gotExists { 173 tc.t.Error("error not raised where one was expected:", want) 174 } 175 } 176 177 // CompareCmdFailure checks to see if the failure/success (in the sense of an 178 // exit code) was as expected by the test fixture. 179 func (tc *TestCase) CompareCmdFailure(gotFail bool) { 180 if gotFail == tc.ShouldFail { 181 return 182 } 183 184 if tc.ShouldFail { 185 tc.t.Errorf("expected command to fail, but it did not") 186 } else { 187 tc.t.Errorf("expected command not to fail, but it did") 188 } 189 } 190 191 // CompareVendorPaths validates the vendor directory contents. 192 func (tc *TestCase) CompareVendorPaths(gotVendorPaths []string) { 193 if *test.UpdateGolden { 194 tc.VendorFinal = gotVendorPaths 195 } else { 196 wantVendorPaths := tc.VendorFinal 197 if len(gotVendorPaths) != len(wantVendorPaths) { 198 tc.t.Fatalf("Wrong number of vendor paths created: want %d got %d", len(wantVendorPaths), len(gotVendorPaths)) 199 } 200 for ind := range gotVendorPaths { 201 if gotVendorPaths[ind] != wantVendorPaths[ind] { 202 tc.t.Errorf("Mismatch in vendor paths created: want %s got %s", wantVendorPaths, gotVendorPaths) 203 } 204 } 205 } 206 } 207 208 // WriteFile writes a file using the default file permissions. 209 func (tc *TestCase) WriteFile(src string, content string) error { 210 return ioutil.WriteFile(src, []byte(content), 0666) 211 } 212 213 func getFile(path string) (bool, string, error) { 214 _, err := os.Stat(path) 215 if err != nil { 216 return false, "", nil 217 } 218 f, err := ioutil.ReadFile(path) 219 if err != nil { 220 return true, "", err 221 } 222 return true, string(f), nil 223 }