utesting.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. // Copyright 2020 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. // Package utesting provides a standalone replacement for package testing.
  17. //
  18. // This package exists because package testing cannot easily be embedded into a
  19. // standalone go program. It provides an API that mirrors the standard library
  20. // testing API.
  21. package utesting
  22. import (
  23. "bytes"
  24. "fmt"
  25. "io"
  26. "regexp"
  27. "runtime"
  28. "sync"
  29. "time"
  30. )
  31. // Test represents a single test.
  32. type Test struct {
  33. Name string
  34. Fn func(*T)
  35. }
  36. // Result is the result of a test execution.
  37. type Result struct {
  38. Name string
  39. Failed bool
  40. Output string
  41. Duration time.Duration
  42. }
  43. // MatchTests returns the tests whose name matches a regular expression.
  44. func MatchTests(tests []Test, expr string) []Test {
  45. var results []Test
  46. re, err := regexp.Compile(expr)
  47. if err != nil {
  48. return nil
  49. }
  50. for _, test := range tests {
  51. if re.MatchString(test.Name) {
  52. results = append(results, test)
  53. }
  54. }
  55. return results
  56. }
  57. // RunTests executes all given tests in order and returns their results.
  58. // If the report writer is non-nil, a test report is written to it in real time.
  59. func RunTests(tests []Test, report io.Writer) []Result {
  60. results := make([]Result, len(tests))
  61. for i, test := range tests {
  62. var output io.Writer
  63. buffer := new(bytes.Buffer)
  64. output = buffer
  65. if report != nil {
  66. output = io.MultiWriter(buffer, report)
  67. }
  68. start := time.Now()
  69. results[i].Name = test.Name
  70. results[i].Failed = run(test, output)
  71. results[i].Duration = time.Since(start)
  72. results[i].Output = buffer.String()
  73. if report != nil {
  74. printResult(results[i], report)
  75. }
  76. }
  77. return results
  78. }
  79. func printResult(r Result, w io.Writer) {
  80. pd := r.Duration.Truncate(100 * time.Microsecond)
  81. if r.Failed {
  82. fmt.Fprintf(w, "-- FAIL %s (%v)\n", r.Name, pd)
  83. } else {
  84. fmt.Fprintf(w, "-- OK %s (%v)\n", r.Name, pd)
  85. }
  86. }
  87. // CountFailures returns the number of failed tests in the result slice.
  88. func CountFailures(rr []Result) int {
  89. count := 0
  90. for _, r := range rr {
  91. if r.Failed {
  92. count++
  93. }
  94. }
  95. return count
  96. }
  97. // Run executes a single test.
  98. func Run(test Test) (bool, string) {
  99. output := new(bytes.Buffer)
  100. failed := run(test, output)
  101. return failed, output.String()
  102. }
  103. func run(test Test, output io.Writer) bool {
  104. t := &T{output: output}
  105. done := make(chan struct{})
  106. go func() {
  107. defer close(done)
  108. defer func() {
  109. if err := recover(); err != nil {
  110. buf := make([]byte, 4096)
  111. i := runtime.Stack(buf, false)
  112. t.Logf("panic: %v\n\n%s", err, buf[:i])
  113. t.Fail()
  114. }
  115. }()
  116. test.Fn(t)
  117. }()
  118. <-done
  119. return t.failed
  120. }
  121. // T is the value given to the test function. The test can signal failures
  122. // and log output by calling methods on this object.
  123. type T struct {
  124. mu sync.Mutex
  125. failed bool
  126. output io.Writer
  127. }
  128. // FailNow marks the test as having failed and stops its execution by calling
  129. // runtime.Goexit (which then runs all deferred calls in the current goroutine).
  130. func (t *T) FailNow() {
  131. t.Fail()
  132. runtime.Goexit()
  133. }
  134. // Fail marks the test as having failed but continues execution.
  135. func (t *T) Fail() {
  136. t.mu.Lock()
  137. defer t.mu.Unlock()
  138. t.failed = true
  139. }
  140. // Failed reports whether the test has failed.
  141. func (t *T) Failed() bool {
  142. t.mu.Lock()
  143. defer t.mu.Unlock()
  144. return t.failed
  145. }
  146. // Log formats its arguments using default formatting, analogous to Println, and records
  147. // the text in the error log.
  148. func (t *T) Log(vs ...interface{}) {
  149. t.mu.Lock()
  150. defer t.mu.Unlock()
  151. fmt.Fprintln(t.output, vs...)
  152. }
  153. // Logf formats its arguments according to the format, analogous to Printf, and records
  154. // the text in the error log. A final newline is added if not provided.
  155. func (t *T) Logf(format string, vs ...interface{}) {
  156. t.mu.Lock()
  157. defer t.mu.Unlock()
  158. if len(format) == 0 || format[len(format)-1] != '\n' {
  159. format += "\n"
  160. }
  161. fmt.Fprintf(t.output, format, vs...)
  162. }
  163. // Error is equivalent to Log followed by Fail.
  164. func (t *T) Error(vs ...interface{}) {
  165. t.Log(vs...)
  166. t.Fail()
  167. }
  168. // Errorf is equivalent to Logf followed by Fail.
  169. func (t *T) Errorf(format string, vs ...interface{}) {
  170. t.Logf(format, vs...)
  171. t.Fail()
  172. }
  173. // Fatal is equivalent to Log followed by FailNow.
  174. func (t *T) Fatal(vs ...interface{}) {
  175. t.Log(vs...)
  176. t.FailNow()
  177. }
  178. // Fatalf is equivalent to Logf followed by FailNow.
  179. func (t *T) Fatalf(format string, vs ...interface{}) {
  180. t.Logf(format, vs...)
  181. t.FailNow()
  182. }