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  }