PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/github.com/smartystreets/assertions/internal/ogletest/integration_test.go

https://gitlab.com/CORP-RESELLER/advanced-ssh-config
Go | 265 lines | 151 code | 47 blank | 67 comment | 44 complexity | 8e5c32b2ca2ffe866e4282f227893636 MD5 | raw file
  1. // Copyright 2011 Aaron Jacobs. All Rights Reserved.
  2. // Author: aaronjjacobs@gmail.com (Aaron Jacobs)
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. package ogletest_test
  16. import (
  17. "errors"
  18. "flag"
  19. "fmt"
  20. "go/build"
  21. "io/ioutil"
  22. "os"
  23. "os/exec"
  24. "path"
  25. "regexp"
  26. "strings"
  27. "syscall"
  28. "testing"
  29. )
  30. const ogletestPkg = "github.com/smartystreets/assertions/internal/ogletest"
  31. var dumpNew = flag.Bool("dump_new", false, "Dump new golden files.")
  32. var objDir string
  33. ////////////////////////////////////////////////////////////////////////
  34. // Helpers
  35. ////////////////////////////////////////////////////////////////////////
  36. // Install the possibly locally-modified copy of ogletest, so that these
  37. // integration tests run using the package currently being worked on by the
  38. // programmer. Also install other dependencies needed by the test cases, so
  39. // that `go test` complaining about non-up-to-date packages doesn't make it
  40. // into the golden files.
  41. func installLocalPackages() error {
  42. cmd := exec.Command(
  43. "go",
  44. "install",
  45. ogletestPkg,
  46. "github.com/smartystreets/assertions/internal/oglemock",
  47. "github.com/smartystreets/assertions/internal/ogletest/test_cases/mock_image")
  48. output, err := cmd.CombinedOutput()
  49. if err != nil {
  50. return errors.New(fmt.Sprintf("%v:\n%s", err, output))
  51. }
  52. return nil
  53. }
  54. // getCaseNames looks for integration test cases as files in the test_cases
  55. // directory.
  56. func getCaseNames() ([]string, error) {
  57. // Open the test cases directory.
  58. dir, err := os.Open("test_cases")
  59. if err != nil {
  60. return nil, errors.New(fmt.Sprintf("Opening dir: %v", err))
  61. }
  62. // Get a list of the names in the directory.
  63. names, err := dir.Readdirnames(0)
  64. if err != nil {
  65. return nil, errors.New(fmt.Sprintf("Readdirnames: %v", err))
  66. }
  67. // Filter the names.
  68. result := make([]string, len(names))
  69. resultLen := 0
  70. for _, name := range names {
  71. // Skip golden files and hidden files.
  72. if strings.HasPrefix(name, "golden.") || strings.HasPrefix(name, ".") {
  73. continue
  74. }
  75. // Check for the right format.
  76. if !strings.HasSuffix(name, ".test.go") {
  77. continue
  78. }
  79. // Store the name minus the extension.
  80. result[resultLen] = name[:len(name)-8]
  81. resultLen++
  82. }
  83. return result[:resultLen], nil
  84. }
  85. func writeContentsToFileOrDie(contents []byte, path string) {
  86. if err := ioutil.WriteFile(path, contents, 0600); err != nil {
  87. panic("ioutil.WriteFile: " + err.Error())
  88. }
  89. }
  90. func readFileOrDie(path string) []byte {
  91. contents, err := ioutil.ReadFile(path)
  92. if err != nil {
  93. panic("ioutil.ReadFile: " + err.Error())
  94. }
  95. return contents
  96. }
  97. // cleanOutput transforms the supplied output so that it no longer contains
  98. // information that changes from run to run, making the golden tests less
  99. // flaky.
  100. func cleanOutput(o []byte, testPkg string) []byte {
  101. // Replace references to the last component of the test package name, which
  102. // contains a unique number.
  103. o = []byte(strings.Replace(string(o), path.Base(testPkg), "somepkg", -1))
  104. // Replace things that look like line numbers and process counters in stack
  105. // traces.
  106. stackFrameRe := regexp.MustCompile(`\t\S+\.(c|go):\d+`)
  107. o = stackFrameRe.ReplaceAll(o, []byte("\tsome_file.txt:0"))
  108. // Replace full paths in failure messages with fake paths.
  109. pathRe := regexp.MustCompile(`/\S+/(\w+\.(?:go|s):\d+)`)
  110. o = pathRe.ReplaceAll(o, []byte("/some/path/$1"))
  111. // Replace unstable timings in gotest fail messages.
  112. timingRe1 := regexp.MustCompile(`--- FAIL: .* \(\d\.\d{2}s\)`)
  113. o = timingRe1.ReplaceAll(o, []byte("--- FAIL: TestSomething (1.23s)"))
  114. timingRe2 := regexp.MustCompile(`FAIL.*somepkg\s*\d\.\d{2,}s`)
  115. o = timingRe2.ReplaceAll(o, []byte("FAIL somepkg 1.234s"))
  116. timingRe3 := regexp.MustCompile(`ok.*somepkg\s*\d\.\d{2,}s`)
  117. o = timingRe3.ReplaceAll(o, []byte("ok somepkg 1.234s"))
  118. timingRe4 := regexp.MustCompile(`SlowTest \([0-9.]+ms\)`)
  119. o = timingRe4.ReplaceAll(o, []byte("SlowTest (1234ms)"))
  120. return o
  121. }
  122. // Create a temporary package directory somewhere that 'go test' can find, and
  123. // return the directory and package name.
  124. func createTempPackageDir(caseName string) (dir, pkg string) {
  125. // Figure out where the local source code for ogletest is.
  126. buildPkg, err := build.Import(ogletestPkg, "", build.FindOnly)
  127. if err != nil {
  128. panic("Finding ogletest tree: " + err.Error())
  129. }
  130. // Create a temporary directory underneath this.
  131. ogletestPkgDir := buildPkg.Dir
  132. prefix := fmt.Sprintf("tmp-%s-", caseName)
  133. dir, err = ioutil.TempDir(ogletestPkgDir, prefix)
  134. if err != nil {
  135. panic("ioutil.TempDir: " + err.Error())
  136. }
  137. pkg = path.Join("github.com/smartystreets/assertions/internal/ogletest", dir[len(ogletestPkgDir):])
  138. return
  139. }
  140. // runTestCase runs the case with the supplied name (e.g. "passing"), and
  141. // returns its output and exit code.
  142. func runTestCase(name string) ([]byte, int, error) {
  143. // Create a temporary directory for the test files.
  144. testDir, testPkg := createTempPackageDir(name)
  145. defer os.RemoveAll(testDir)
  146. // Create the test source file.
  147. sourceFile := name + ".test.go"
  148. testContents := readFileOrDie(path.Join("test_cases", sourceFile))
  149. writeContentsToFileOrDie(testContents, path.Join(testDir, name+"_test.go"))
  150. // Invoke 'go test'. Use the package directory as working dir instead of
  151. // giving the package name as an argument so that 'go test' prints passing
  152. // test output. Special case: pass a test filter to the filtered case.
  153. cmd := exec.Command("go", "test")
  154. if name == "filtered" {
  155. cmd.Args = append(cmd.Args, "--ogletest.run=Test(Bar|Baz)")
  156. }
  157. cmd.Dir = testDir
  158. output, err := cmd.CombinedOutput()
  159. // Clean up the process's output.
  160. output = cleanOutput(output, testPkg)
  161. // Did the process exist with zero code?
  162. if err == nil {
  163. return output, 0, nil
  164. }
  165. // Make sure the process actually exited.
  166. exitError, ok := err.(*exec.ExitError)
  167. if !ok || !exitError.Exited() {
  168. return nil, 0, errors.New("exec.Command.Output: " + err.Error())
  169. }
  170. return output, exitError.Sys().(syscall.WaitStatus).ExitStatus(), nil
  171. }
  172. // checkGolden file checks the supplied actual output for the named test case
  173. // against the golden file for that case. If requested by the user, it rewrites
  174. // the golden file on failure.
  175. func checkAgainstGoldenFile(caseName string, output []byte) bool {
  176. goldenFile := path.Join("test_cases", "golden."+caseName+"_test")
  177. goldenContents := readFileOrDie(goldenFile)
  178. result := string(output) == string(goldenContents)
  179. if !result && *dumpNew {
  180. writeContentsToFileOrDie(output, goldenFile)
  181. }
  182. return result
  183. }
  184. ////////////////////////////////////////////////////////////////////////
  185. // Tests
  186. ////////////////////////////////////////////////////////////////////////
  187. func TestGoldenFiles(t *testing.T) {
  188. // Ensure the local package is installed. This will prevent the test cases
  189. // from using the installed version, which may be out of date.
  190. err := installLocalPackages()
  191. if err != nil {
  192. t.Fatalf("Error installing local ogletest: %v", err)
  193. }
  194. // We expect there to be at least one case.
  195. caseNames, err := getCaseNames()
  196. if err != nil || len(caseNames) == 0 {
  197. t.Fatalf("Error getting cases: %v", err)
  198. }
  199. // Run each test case.
  200. for _, caseName := range caseNames {
  201. // Run the test case.
  202. output, exitCode, err := runTestCase(caseName)
  203. if err != nil {
  204. t.Fatalf("Running test case %s: %v", caseName, err)
  205. }
  206. // Check the status code. We assume all test cases fail except for the
  207. // passing one.
  208. shouldPass := (caseName == "passing" || caseName == "no_cases")
  209. didPass := exitCode == 0
  210. if shouldPass != didPass {
  211. t.Errorf("Bad exit code for test case %s: %d", caseName, exitCode)
  212. }
  213. // Check the output against the golden file.
  214. if !checkAgainstGoldenFile(caseName, output) {
  215. t.Errorf("Output for test case %s doesn't match golden file.", caseName)
  216. }
  217. }
  218. }