run.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. // Copyright 2015 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. // run runs the docs tests found in this directory.
  5. package main
  6. import (
  7. "bytes"
  8. "flag"
  9. "fmt"
  10. "io/ioutil"
  11. "os"
  12. "os/exec"
  13. "path/filepath"
  14. "regexp"
  15. "runtime"
  16. "strings"
  17. )
  18. const usage = `go run run.go [tests]
  19. run.go runs the docs tests in this directory.
  20. If no tests are provided, it runs all tests.
  21. Tests may be specified without their .go suffix.
  22. `
  23. func main() {
  24. flag.Usage = func() {
  25. fmt.Fprintf(os.Stderr, usage)
  26. flag.PrintDefaults()
  27. os.Exit(2)
  28. }
  29. flag.Parse()
  30. if flag.NArg() == 0 {
  31. // run all tests
  32. fixcgo()
  33. } else {
  34. // run specified tests
  35. onlyTest(flag.Args()...)
  36. }
  37. tmpdir, err := ioutil.TempDir("", "go-progs")
  38. if err != nil {
  39. fmt.Fprintln(os.Stderr, err)
  40. os.Exit(1)
  41. }
  42. // ratec limits the number of tests running concurrently.
  43. // None of the tests are intensive, so don't bother
  44. // trying to manually adjust for slow builders.
  45. ratec := make(chan bool, runtime.NumCPU())
  46. errc := make(chan error, len(tests))
  47. for _, tt := range tests {
  48. tt := tt
  49. ratec <- true
  50. go func() {
  51. errc <- test(tmpdir, tt.file, tt.want)
  52. <-ratec
  53. }()
  54. }
  55. var rc int
  56. for range tests {
  57. if err := <-errc; err != nil {
  58. fmt.Fprintln(os.Stderr, err)
  59. rc = 1
  60. }
  61. }
  62. os.Remove(tmpdir)
  63. os.Exit(rc)
  64. }
  65. // test builds the test in the given file.
  66. // If want is non-empty, test also runs the test
  67. // and checks that the output matches the regexp want.
  68. func test(tmpdir, file, want string) error {
  69. // Build the program.
  70. prog := filepath.Join(tmpdir, file)
  71. cmd := exec.Command("go", "build", "-o", prog, file+".go")
  72. out, err := cmd.CombinedOutput()
  73. if err != nil {
  74. return fmt.Errorf("go build %s.go failed: %v\nOutput:\n%s", file, err, out)
  75. }
  76. defer os.Remove(prog)
  77. // Only run the test if we have output to check.
  78. if want == "" {
  79. return nil
  80. }
  81. cmd = exec.Command(prog)
  82. out, err = cmd.CombinedOutput()
  83. if err != nil {
  84. return fmt.Errorf("%s failed: %v\nOutput:\n%s", file, err, out)
  85. }
  86. // Canonicalize output.
  87. out = bytes.TrimRight(out, "\n")
  88. out = bytes.Replace(out, []byte{'\n'}, []byte{' '}, -1)
  89. // Check the result.
  90. match, err := regexp.Match(want, out)
  91. if err != nil {
  92. return fmt.Errorf("failed to parse regexp %q: %v", want, err)
  93. }
  94. if !match {
  95. return fmt.Errorf("%s.go:\n%q\ndoes not match %s", file, out, want)
  96. }
  97. return nil
  98. }
  99. type testcase struct {
  100. file string
  101. want string
  102. }
  103. var tests = []testcase{
  104. // defer_panic_recover
  105. {"defer", `^0 3210 2$`},
  106. {"defer2", `^Calling g. Printing in g 0 Printing in g 1 Printing in g 2 Printing in g 3 Panicking! Defer in g 3 Defer in g 2 Defer in g 1 Defer in g 0 Recovered in f 4 Returned normally from f.$`},
  107. // effective_go
  108. {"eff_bytesize", `^1.00YB 9.09TB$`},
  109. {"eff_qr", ""},
  110. {"eff_sequence", `^\[-1 2 6 16 44\]$`},
  111. {"eff_unused2", ""},
  112. // error_handling
  113. {"error", ""},
  114. {"error2", ""},
  115. {"error3", ""},
  116. {"error4", ""},
  117. // law_of_reflection
  118. {"interface", ""},
  119. {"interface2", `^type: float64$`},
  120. // c_go_cgo
  121. {"cgo1", ""},
  122. {"cgo2", ""},
  123. {"cgo3", ""},
  124. {"cgo4", ""},
  125. // timeout
  126. {"timeout1", ""},
  127. {"timeout2", ""},
  128. // gobs
  129. {"gobs1", ""},
  130. {"gobs2", ""},
  131. // json
  132. {"json1", `^$`},
  133. {"json2", `the reciprocal of i is`},
  134. {"json3", `Age is int 6`},
  135. {"json4", `^$`},
  136. {"json5", ""},
  137. // image_package
  138. {"image_package1", `^X is 2 Y is 1$`},
  139. {"image_package2", `^3 4 false$`},
  140. {"image_package3", `^3 4 true$`},
  141. {"image_package4", `^image.Point{X:2, Y:1}$`},
  142. {"image_package5", `^{255 0 0 255}$`},
  143. {"image_package6", `^8 4 true$`},
  144. // other
  145. {"go1", `^Christmas is a holiday: true .*go1.go already exists$`},
  146. {"slices", ""},
  147. }
  148. func onlyTest(files ...string) {
  149. var new []testcase
  150. NextFile:
  151. for _, file := range files {
  152. file = strings.TrimSuffix(file, ".go")
  153. for _, tt := range tests {
  154. if tt.file == file {
  155. new = append(new, tt)
  156. continue NextFile
  157. }
  158. }
  159. fmt.Fprintf(os.Stderr, "test %s.go not found\n", file)
  160. os.Exit(1)
  161. }
  162. tests = new
  163. }
  164. func skipTest(file string) {
  165. for i, tt := range tests {
  166. if tt.file == file {
  167. copy(tests[i:], tests[i+1:])
  168. tests = tests[:len(tests)-1]
  169. return
  170. }
  171. }
  172. panic("delete(" + file + "): not found")
  173. }
  174. func fixcgo() {
  175. if os.Getenv("CGO_ENABLED") != "1" {
  176. skipTest("cgo1")
  177. skipTest("cgo2")
  178. skipTest("cgo3")
  179. skipTest("cgo4")
  180. return
  181. }
  182. switch runtime.GOOS {
  183. case "freebsd":
  184. // cgo1 and cgo2 don't run on freebsd, srandom has a different signature
  185. skipTest("cgo1")
  186. skipTest("cgo2")
  187. case "netbsd":
  188. // cgo1 and cgo2 don't run on netbsd, srandom has a different signature
  189. skipTest("cgo1")
  190. skipTest("cgo2")
  191. }
  192. }