check.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876
  1. // Package check is a rich testing extension for Go's testing package.
  2. //
  3. // For details about the project, see:
  4. //
  5. // http://labix.org/gocheck
  6. //
  7. package check
  8. import (
  9. "bytes"
  10. "errors"
  11. "fmt"
  12. "io"
  13. "io/ioutil"
  14. "os"
  15. "path"
  16. "path/filepath"
  17. "reflect"
  18. "regexp"
  19. "runtime"
  20. "strconv"
  21. "strings"
  22. "sync"
  23. "sync/atomic"
  24. "time"
  25. )
  26. // -----------------------------------------------------------------------
  27. // Internal type which deals with suite method calling.
  28. const (
  29. fixtureKd = iota
  30. testKd
  31. )
  32. type funcKind int
  33. const (
  34. succeededSt = iota
  35. failedSt
  36. skippedSt
  37. panickedSt
  38. fixturePanickedSt
  39. missedSt
  40. )
  41. type funcStatus uint32
  42. // A method value can't reach its own Method structure.
  43. type methodType struct {
  44. reflect.Value
  45. Info reflect.Method
  46. }
  47. func newMethod(receiver reflect.Value, i int) *methodType {
  48. return &methodType{receiver.Method(i), receiver.Type().Method(i)}
  49. }
  50. func (method *methodType) PC() uintptr {
  51. return method.Info.Func.Pointer()
  52. }
  53. func (method *methodType) suiteName() string {
  54. t := method.Info.Type.In(0)
  55. if t.Kind() == reflect.Ptr {
  56. t = t.Elem()
  57. }
  58. return t.Name()
  59. }
  60. func (method *methodType) String() string {
  61. return method.suiteName() + "." + method.Info.Name
  62. }
  63. func (method *methodType) matches(re *regexp.Regexp) bool {
  64. return (re.MatchString(method.Info.Name) ||
  65. re.MatchString(method.suiteName()) ||
  66. re.MatchString(method.String()))
  67. }
  68. type C struct {
  69. method *methodType
  70. kind funcKind
  71. testName string
  72. _status funcStatus
  73. logb *logger
  74. logw io.Writer
  75. done chan *C
  76. reason string
  77. mustFail bool
  78. tempDir *tempDir
  79. benchMem bool
  80. startTime time.Time
  81. timer
  82. }
  83. func (c *C) status() funcStatus {
  84. return funcStatus(atomic.LoadUint32((*uint32)(&c._status)))
  85. }
  86. func (c *C) setStatus(s funcStatus) {
  87. atomic.StoreUint32((*uint32)(&c._status), uint32(s))
  88. }
  89. func (c *C) stopNow() {
  90. runtime.Goexit()
  91. }
  92. // logger is a concurrency safe byte.Buffer
  93. type logger struct {
  94. sync.Mutex
  95. writer bytes.Buffer
  96. }
  97. func (l *logger) Write(buf []byte) (int, error) {
  98. l.Lock()
  99. defer l.Unlock()
  100. return l.writer.Write(buf)
  101. }
  102. func (l *logger) WriteTo(w io.Writer) (int64, error) {
  103. l.Lock()
  104. defer l.Unlock()
  105. return l.writer.WriteTo(w)
  106. }
  107. func (l *logger) String() string {
  108. l.Lock()
  109. defer l.Unlock()
  110. return l.writer.String()
  111. }
  112. // -----------------------------------------------------------------------
  113. // Handling of temporary files and directories.
  114. type tempDir struct {
  115. sync.Mutex
  116. path string
  117. counter int
  118. }
  119. func (td *tempDir) newPath() string {
  120. td.Lock()
  121. defer td.Unlock()
  122. if td.path == "" {
  123. path, err := ioutil.TempDir("", "check-")
  124. if err != nil {
  125. panic("Couldn't create temporary directory: " + err.Error())
  126. }
  127. td.path = path
  128. }
  129. result := filepath.Join(td.path, strconv.Itoa(td.counter))
  130. td.counter++
  131. return result
  132. }
  133. func (td *tempDir) removeAll() {
  134. td.Lock()
  135. defer td.Unlock()
  136. if td.path != "" {
  137. err := os.RemoveAll(td.path)
  138. if err != nil {
  139. fmt.Fprintf(os.Stderr, "WARNING: Error cleaning up temporaries: "+err.Error())
  140. }
  141. }
  142. }
  143. // Create a new temporary directory which is automatically removed after
  144. // the suite finishes running.
  145. func (c *C) MkDir() string {
  146. path := c.tempDir.newPath()
  147. if err := os.Mkdir(path, 0700); err != nil {
  148. panic(fmt.Sprintf("Couldn't create temporary directory %s: %s", path, err.Error()))
  149. }
  150. return path
  151. }
  152. // -----------------------------------------------------------------------
  153. // Low-level logging functions.
  154. func (c *C) log(args ...interface{}) {
  155. c.writeLog([]byte(fmt.Sprint(args...) + "\n"))
  156. }
  157. func (c *C) logf(format string, args ...interface{}) {
  158. c.writeLog([]byte(fmt.Sprintf(format+"\n", args...)))
  159. }
  160. func (c *C) logNewLine() {
  161. c.writeLog([]byte{'\n'})
  162. }
  163. func (c *C) writeLog(buf []byte) {
  164. c.logb.Write(buf)
  165. if c.logw != nil {
  166. c.logw.Write(buf)
  167. }
  168. }
  169. func hasStringOrError(x interface{}) (ok bool) {
  170. _, ok = x.(fmt.Stringer)
  171. if ok {
  172. return
  173. }
  174. _, ok = x.(error)
  175. return
  176. }
  177. func (c *C) logValue(label string, value interface{}) {
  178. if label == "" {
  179. if hasStringOrError(value) {
  180. c.logf("... %#v (%q)", value, value)
  181. } else {
  182. c.logf("... %#v", value)
  183. }
  184. } else if value == nil {
  185. c.logf("... %s = nil", label)
  186. } else {
  187. if hasStringOrError(value) {
  188. fv := fmt.Sprintf("%#v", value)
  189. qv := fmt.Sprintf("%q", value)
  190. if fv != qv {
  191. c.logf("... %s %s = %s (%s)", label, reflect.TypeOf(value), fv, qv)
  192. return
  193. }
  194. }
  195. if s, ok := value.(string); ok && isMultiLine(s) {
  196. c.logf(`... %s %s = "" +`, label, reflect.TypeOf(value))
  197. c.logMultiLine(s)
  198. } else {
  199. c.logf("... %s %s = %#v", label, reflect.TypeOf(value), value)
  200. }
  201. }
  202. }
  203. func formatMultiLine(s string, quote bool) []byte {
  204. b := make([]byte, 0, len(s)*2)
  205. i := 0
  206. n := len(s)
  207. for i < n {
  208. j := i + 1
  209. for j < n && s[j-1] != '\n' {
  210. j++
  211. }
  212. b = append(b, "... "...)
  213. if quote {
  214. b = strconv.AppendQuote(b, s[i:j])
  215. } else {
  216. b = append(b, s[i:j]...)
  217. b = bytes.TrimSpace(b)
  218. }
  219. if quote && j < n {
  220. b = append(b, " +"...)
  221. }
  222. b = append(b, '\n')
  223. i = j
  224. }
  225. return b
  226. }
  227. func (c *C) logMultiLine(s string) {
  228. c.writeLog(formatMultiLine(s, true))
  229. }
  230. func isMultiLine(s string) bool {
  231. for i := 0; i+1 < len(s); i++ {
  232. if s[i] == '\n' {
  233. return true
  234. }
  235. }
  236. return false
  237. }
  238. func (c *C) logString(issue string) {
  239. c.log("... ", issue)
  240. }
  241. func (c *C) logCaller(skip int) {
  242. // This is a bit heavier than it ought to be.
  243. skip++ // Our own frame.
  244. pc, callerFile, callerLine, ok := runtime.Caller(skip)
  245. if !ok {
  246. return
  247. }
  248. var testFile string
  249. var testLine int
  250. testFunc := runtime.FuncForPC(c.method.PC())
  251. if runtime.FuncForPC(pc) != testFunc {
  252. for {
  253. skip++
  254. if pc, file, line, ok := runtime.Caller(skip); ok {
  255. // Note that the test line may be different on
  256. // distinct calls for the same test. Showing
  257. // the "internal" line is helpful when debugging.
  258. if runtime.FuncForPC(pc) == testFunc {
  259. testFile, testLine = file, line
  260. break
  261. }
  262. } else {
  263. break
  264. }
  265. }
  266. }
  267. if testFile != "" && (testFile != callerFile || testLine != callerLine) {
  268. c.logCode(testFile, testLine)
  269. }
  270. c.logCode(callerFile, callerLine)
  271. }
  272. func (c *C) logCode(path string, line int) {
  273. c.logf("%s:%d:", nicePath(path), line)
  274. code, err := printLine(path, line)
  275. if code == "" {
  276. code = "..." // XXX Open the file and take the raw line.
  277. if err != nil {
  278. code += err.Error()
  279. }
  280. }
  281. c.log(indent(code, " "))
  282. }
  283. var valueGo = filepath.Join("reflect", "value.go")
  284. var asmGo = filepath.Join("runtime", "asm_")
  285. func (c *C) logPanic(skip int, value interface{}) {
  286. skip++ // Our own frame.
  287. initialSkip := skip
  288. for ; ; skip++ {
  289. if pc, file, line, ok := runtime.Caller(skip); ok {
  290. if skip == initialSkip {
  291. c.logf("... Panic: %s (PC=0x%X)\n", value, pc)
  292. }
  293. name := niceFuncName(pc)
  294. path := nicePath(file)
  295. if strings.Contains(path, "/gopkg.in/check.v") {
  296. continue
  297. }
  298. if name == "Value.call" && strings.HasSuffix(path, valueGo) {
  299. continue
  300. }
  301. if (name == "call16" || name == "call32") && strings.Contains(path, asmGo) {
  302. continue
  303. }
  304. c.logf("%s:%d\n in %s", nicePath(file), line, name)
  305. } else {
  306. break
  307. }
  308. }
  309. }
  310. func (c *C) logSoftPanic(issue string) {
  311. c.log("... Panic: ", issue)
  312. }
  313. func (c *C) logArgPanic(method *methodType, expectedType string) {
  314. c.logf("... Panic: %s argument should be %s",
  315. niceFuncName(method.PC()), expectedType)
  316. }
  317. // -----------------------------------------------------------------------
  318. // Some simple formatting helpers.
  319. var initWD, initWDErr = os.Getwd()
  320. func init() {
  321. if initWDErr == nil {
  322. initWD = strings.Replace(initWD, "\\", "/", -1) + "/"
  323. }
  324. }
  325. func nicePath(path string) string {
  326. if initWDErr == nil {
  327. if strings.HasPrefix(path, initWD) {
  328. return path[len(initWD):]
  329. }
  330. }
  331. return path
  332. }
  333. func niceFuncPath(pc uintptr) string {
  334. function := runtime.FuncForPC(pc)
  335. if function != nil {
  336. filename, line := function.FileLine(pc)
  337. return fmt.Sprintf("%s:%d", nicePath(filename), line)
  338. }
  339. return "<unknown path>"
  340. }
  341. func niceFuncName(pc uintptr) string {
  342. function := runtime.FuncForPC(pc)
  343. if function != nil {
  344. name := path.Base(function.Name())
  345. if i := strings.Index(name, "."); i > 0 {
  346. name = name[i+1:]
  347. }
  348. if strings.HasPrefix(name, "(*") {
  349. if i := strings.Index(name, ")"); i > 0 {
  350. name = name[2:i] + name[i+1:]
  351. }
  352. }
  353. if i := strings.LastIndex(name, ".*"); i != -1 {
  354. name = name[:i] + "." + name[i+2:]
  355. }
  356. if i := strings.LastIndex(name, "·"); i != -1 {
  357. name = name[:i] + "." + name[i+2:]
  358. }
  359. return name
  360. }
  361. return "<unknown function>"
  362. }
  363. // -----------------------------------------------------------------------
  364. // Result tracker to aggregate call results.
  365. type Result struct {
  366. Succeeded int
  367. Failed int
  368. Skipped int
  369. Panicked int
  370. FixturePanicked int
  371. ExpectedFailures int
  372. Missed int // Not even tried to run, related to a panic in the fixture.
  373. RunError error // Houston, we've got a problem.
  374. WorkDir string // If KeepWorkDir is true
  375. }
  376. type resultTracker struct {
  377. result Result
  378. _lastWasProblem bool
  379. _waiting int
  380. _missed int
  381. _expectChan chan *C
  382. _doneChan chan *C
  383. _stopChan chan bool
  384. }
  385. func newResultTracker() *resultTracker {
  386. return &resultTracker{_expectChan: make(chan *C), // Synchronous
  387. _doneChan: make(chan *C, 32), // Asynchronous
  388. _stopChan: make(chan bool)} // Synchronous
  389. }
  390. func (tracker *resultTracker) start() {
  391. go tracker._loopRoutine()
  392. }
  393. func (tracker *resultTracker) waitAndStop() {
  394. <-tracker._stopChan
  395. }
  396. func (tracker *resultTracker) expectCall(c *C) {
  397. tracker._expectChan <- c
  398. }
  399. func (tracker *resultTracker) callDone(c *C) {
  400. tracker._doneChan <- c
  401. }
  402. func (tracker *resultTracker) _loopRoutine() {
  403. for {
  404. var c *C
  405. if tracker._waiting > 0 {
  406. // Calls still running. Can't stop.
  407. select {
  408. // XXX Reindent this (not now to make diff clear)
  409. case <-tracker._expectChan:
  410. tracker._waiting++
  411. case c = <-tracker._doneChan:
  412. tracker._waiting--
  413. switch c.status() {
  414. case succeededSt:
  415. if c.kind == testKd {
  416. if c.mustFail {
  417. tracker.result.ExpectedFailures++
  418. } else {
  419. tracker.result.Succeeded++
  420. }
  421. }
  422. case failedSt:
  423. tracker.result.Failed++
  424. case panickedSt:
  425. if c.kind == fixtureKd {
  426. tracker.result.FixturePanicked++
  427. } else {
  428. tracker.result.Panicked++
  429. }
  430. case fixturePanickedSt:
  431. // Track it as missed, since the panic
  432. // was on the fixture, not on the test.
  433. tracker.result.Missed++
  434. case missedSt:
  435. tracker.result.Missed++
  436. case skippedSt:
  437. if c.kind == testKd {
  438. tracker.result.Skipped++
  439. }
  440. }
  441. }
  442. } else {
  443. // No calls. Can stop, but no done calls here.
  444. select {
  445. case tracker._stopChan <- true:
  446. return
  447. case <-tracker._expectChan:
  448. tracker._waiting++
  449. case <-tracker._doneChan:
  450. panic("Tracker got an unexpected done call.")
  451. }
  452. }
  453. }
  454. }
  455. // -----------------------------------------------------------------------
  456. // The underlying suite runner.
  457. type suiteRunner struct {
  458. suite interface{}
  459. setUpSuite, tearDownSuite *methodType
  460. setUpTest, tearDownTest *methodType
  461. tests []*methodType
  462. tracker *resultTracker
  463. tempDir *tempDir
  464. keepDir bool
  465. output *outputWriter
  466. reportedProblemLast bool
  467. benchTime time.Duration
  468. benchMem bool
  469. }
  470. type RunConf struct {
  471. Output io.Writer
  472. Stream bool
  473. Verbose bool
  474. Filter string
  475. Benchmark bool
  476. BenchmarkTime time.Duration // Defaults to 1 second
  477. BenchmarkMem bool
  478. KeepWorkDir bool
  479. }
  480. // Create a new suiteRunner able to run all methods in the given suite.
  481. func newSuiteRunner(suite interface{}, runConf *RunConf) *suiteRunner {
  482. var conf RunConf
  483. if runConf != nil {
  484. conf = *runConf
  485. }
  486. if conf.Output == nil {
  487. conf.Output = os.Stdout
  488. }
  489. if conf.Benchmark {
  490. conf.Verbose = true
  491. }
  492. suiteType := reflect.TypeOf(suite)
  493. suiteNumMethods := suiteType.NumMethod()
  494. suiteValue := reflect.ValueOf(suite)
  495. runner := &suiteRunner{
  496. suite: suite,
  497. output: newOutputWriter(conf.Output, conf.Stream, conf.Verbose),
  498. tracker: newResultTracker(),
  499. benchTime: conf.BenchmarkTime,
  500. benchMem: conf.BenchmarkMem,
  501. tempDir: &tempDir{},
  502. keepDir: conf.KeepWorkDir,
  503. tests: make([]*methodType, 0, suiteNumMethods),
  504. }
  505. if runner.benchTime == 0 {
  506. runner.benchTime = 1 * time.Second
  507. }
  508. var filterRegexp *regexp.Regexp
  509. if conf.Filter != "" {
  510. regexp, err := regexp.Compile(conf.Filter)
  511. if err != nil {
  512. msg := "Bad filter expression: " + err.Error()
  513. runner.tracker.result.RunError = errors.New(msg)
  514. return runner
  515. }
  516. filterRegexp = regexp
  517. }
  518. for i := 0; i != suiteNumMethods; i++ {
  519. method := newMethod(suiteValue, i)
  520. switch method.Info.Name {
  521. case "SetUpSuite":
  522. runner.setUpSuite = method
  523. case "TearDownSuite":
  524. runner.tearDownSuite = method
  525. case "SetUpTest":
  526. runner.setUpTest = method
  527. case "TearDownTest":
  528. runner.tearDownTest = method
  529. default:
  530. prefix := "Test"
  531. if conf.Benchmark {
  532. prefix = "Benchmark"
  533. }
  534. if !strings.HasPrefix(method.Info.Name, prefix) {
  535. continue
  536. }
  537. if filterRegexp == nil || method.matches(filterRegexp) {
  538. runner.tests = append(runner.tests, method)
  539. }
  540. }
  541. }
  542. return runner
  543. }
  544. // Run all methods in the given suite.
  545. func (runner *suiteRunner) run() *Result {
  546. if runner.tracker.result.RunError == nil && len(runner.tests) > 0 {
  547. runner.tracker.start()
  548. if runner.checkFixtureArgs() {
  549. c := runner.runFixture(runner.setUpSuite, "", nil)
  550. if c == nil || c.status() == succeededSt {
  551. for i := 0; i != len(runner.tests); i++ {
  552. c := runner.runTest(runner.tests[i])
  553. if c.status() == fixturePanickedSt {
  554. runner.skipTests(missedSt, runner.tests[i+1:])
  555. break
  556. }
  557. }
  558. } else if c != nil && c.status() == skippedSt {
  559. runner.skipTests(skippedSt, runner.tests)
  560. } else {
  561. runner.skipTests(missedSt, runner.tests)
  562. }
  563. runner.runFixture(runner.tearDownSuite, "", nil)
  564. } else {
  565. runner.skipTests(missedSt, runner.tests)
  566. }
  567. runner.tracker.waitAndStop()
  568. if runner.keepDir {
  569. runner.tracker.result.WorkDir = runner.tempDir.path
  570. } else {
  571. runner.tempDir.removeAll()
  572. }
  573. }
  574. return &runner.tracker.result
  575. }
  576. // Create a call object with the given suite method, and fork a
  577. // goroutine with the provided dispatcher for running it.
  578. func (runner *suiteRunner) forkCall(method *methodType, kind funcKind, testName string, logb *logger, dispatcher func(c *C)) *C {
  579. var logw io.Writer
  580. if runner.output.Stream {
  581. logw = runner.output
  582. }
  583. if logb == nil {
  584. logb = new(logger)
  585. }
  586. c := &C{
  587. method: method,
  588. kind: kind,
  589. testName: testName,
  590. logb: logb,
  591. logw: logw,
  592. tempDir: runner.tempDir,
  593. done: make(chan *C, 1),
  594. timer: timer{benchTime: runner.benchTime},
  595. startTime: time.Now(),
  596. benchMem: runner.benchMem,
  597. }
  598. runner.tracker.expectCall(c)
  599. go (func() {
  600. runner.reportCallStarted(c)
  601. defer runner.callDone(c)
  602. dispatcher(c)
  603. })()
  604. return c
  605. }
  606. // Same as forkCall(), but wait for call to finish before returning.
  607. func (runner *suiteRunner) runFunc(method *methodType, kind funcKind, testName string, logb *logger, dispatcher func(c *C)) *C {
  608. c := runner.forkCall(method, kind, testName, logb, dispatcher)
  609. <-c.done
  610. return c
  611. }
  612. // Handle a finished call. If there were any panics, update the call status
  613. // accordingly. Then, mark the call as done and report to the tracker.
  614. func (runner *suiteRunner) callDone(c *C) {
  615. value := recover()
  616. if value != nil {
  617. switch v := value.(type) {
  618. case *fixturePanic:
  619. if v.status == skippedSt {
  620. c.setStatus(skippedSt)
  621. } else {
  622. c.logSoftPanic("Fixture has panicked (see related PANIC)")
  623. c.setStatus(fixturePanickedSt)
  624. }
  625. default:
  626. c.logPanic(1, value)
  627. c.setStatus(panickedSt)
  628. }
  629. }
  630. if c.mustFail {
  631. switch c.status() {
  632. case failedSt:
  633. c.setStatus(succeededSt)
  634. case succeededSt:
  635. c.setStatus(failedSt)
  636. c.logString("Error: Test succeeded, but was expected to fail")
  637. c.logString("Reason: " + c.reason)
  638. }
  639. }
  640. runner.reportCallDone(c)
  641. c.done <- c
  642. }
  643. // Runs a fixture call synchronously. The fixture will still be run in a
  644. // goroutine like all suite methods, but this method will not return
  645. // while the fixture goroutine is not done, because the fixture must be
  646. // run in a desired order.
  647. func (runner *suiteRunner) runFixture(method *methodType, testName string, logb *logger) *C {
  648. if method != nil {
  649. c := runner.runFunc(method, fixtureKd, testName, logb, func(c *C) {
  650. c.ResetTimer()
  651. c.StartTimer()
  652. defer c.StopTimer()
  653. c.method.Call([]reflect.Value{reflect.ValueOf(c)})
  654. })
  655. return c
  656. }
  657. return nil
  658. }
  659. // Run the fixture method with runFixture(), but panic with a fixturePanic{}
  660. // in case the fixture method panics. This makes it easier to track the
  661. // fixture panic together with other call panics within forkTest().
  662. func (runner *suiteRunner) runFixtureWithPanic(method *methodType, testName string, logb *logger, skipped *bool) *C {
  663. if skipped != nil && *skipped {
  664. return nil
  665. }
  666. c := runner.runFixture(method, testName, logb)
  667. if c != nil && c.status() != succeededSt {
  668. if skipped != nil {
  669. *skipped = c.status() == skippedSt
  670. }
  671. panic(&fixturePanic{c.status(), method})
  672. }
  673. return c
  674. }
  675. type fixturePanic struct {
  676. status funcStatus
  677. method *methodType
  678. }
  679. // Run the suite test method, together with the test-specific fixture,
  680. // asynchronously.
  681. func (runner *suiteRunner) forkTest(method *methodType) *C {
  682. testName := method.String()
  683. return runner.forkCall(method, testKd, testName, nil, func(c *C) {
  684. var skipped bool
  685. defer runner.runFixtureWithPanic(runner.tearDownTest, testName, nil, &skipped)
  686. defer c.StopTimer()
  687. benchN := 1
  688. for {
  689. runner.runFixtureWithPanic(runner.setUpTest, testName, c.logb, &skipped)
  690. mt := c.method.Type()
  691. if mt.NumIn() != 1 || mt.In(0) != reflect.TypeOf(c) {
  692. // Rather than a plain panic, provide a more helpful message when
  693. // the argument type is incorrect.
  694. c.setStatus(panickedSt)
  695. c.logArgPanic(c.method, "*check.C")
  696. return
  697. }
  698. if strings.HasPrefix(c.method.Info.Name, "Test") {
  699. c.ResetTimer()
  700. c.StartTimer()
  701. c.method.Call([]reflect.Value{reflect.ValueOf(c)})
  702. return
  703. }
  704. if !strings.HasPrefix(c.method.Info.Name, "Benchmark") {
  705. panic("unexpected method prefix: " + c.method.Info.Name)
  706. }
  707. runtime.GC()
  708. c.N = benchN
  709. c.ResetTimer()
  710. c.StartTimer()
  711. c.method.Call([]reflect.Value{reflect.ValueOf(c)})
  712. c.StopTimer()
  713. if c.status() != succeededSt || c.duration >= c.benchTime || benchN >= 1e9 {
  714. return
  715. }
  716. perOpN := int(1e9)
  717. if c.nsPerOp() != 0 {
  718. perOpN = int(c.benchTime.Nanoseconds() / c.nsPerOp())
  719. }
  720. // Logic taken from the stock testing package:
  721. // - Run more iterations than we think we'll need for a second (1.5x).
  722. // - Don't grow too fast in case we had timing errors previously.
  723. // - Be sure to run at least one more than last time.
  724. benchN = max(min(perOpN+perOpN/2, 100*benchN), benchN+1)
  725. benchN = roundUp(benchN)
  726. skipped = true // Don't run the deferred one if this panics.
  727. runner.runFixtureWithPanic(runner.tearDownTest, testName, nil, nil)
  728. skipped = false
  729. }
  730. })
  731. }
  732. // Same as forkTest(), but wait for the test to finish before returning.
  733. func (runner *suiteRunner) runTest(method *methodType) *C {
  734. c := runner.forkTest(method)
  735. <-c.done
  736. return c
  737. }
  738. // Helper to mark tests as skipped or missed. A bit heavy for what
  739. // it does, but it enables homogeneous handling of tracking, including
  740. // nice verbose output.
  741. func (runner *suiteRunner) skipTests(status funcStatus, methods []*methodType) {
  742. for _, method := range methods {
  743. runner.runFunc(method, testKd, "", nil, func(c *C) {
  744. c.setStatus(status)
  745. })
  746. }
  747. }
  748. // Verify if the fixture arguments are *check.C. In case of errors,
  749. // log the error as a panic in the fixture method call, and return false.
  750. func (runner *suiteRunner) checkFixtureArgs() bool {
  751. succeeded := true
  752. argType := reflect.TypeOf(&C{})
  753. for _, method := range []*methodType{runner.setUpSuite, runner.tearDownSuite, runner.setUpTest, runner.tearDownTest} {
  754. if method != nil {
  755. mt := method.Type()
  756. if mt.NumIn() != 1 || mt.In(0) != argType {
  757. succeeded = false
  758. runner.runFunc(method, fixtureKd, "", nil, func(c *C) {
  759. c.logArgPanic(method, "*check.C")
  760. c.setStatus(panickedSt)
  761. })
  762. }
  763. }
  764. }
  765. return succeeded
  766. }
  767. func (runner *suiteRunner) reportCallStarted(c *C) {
  768. runner.output.WriteCallStarted("START", c)
  769. }
  770. func (runner *suiteRunner) reportCallDone(c *C) {
  771. runner.tracker.callDone(c)
  772. switch c.status() {
  773. case succeededSt:
  774. if c.mustFail {
  775. runner.output.WriteCallSuccess("FAIL EXPECTED", c)
  776. } else {
  777. runner.output.WriteCallSuccess("PASS", c)
  778. }
  779. case skippedSt:
  780. runner.output.WriteCallSuccess("SKIP", c)
  781. case failedSt:
  782. runner.output.WriteCallProblem("FAIL", c)
  783. case panickedSt:
  784. runner.output.WriteCallProblem("PANIC", c)
  785. case fixturePanickedSt:
  786. // That's a testKd call reporting that its fixture
  787. // has panicked. The fixture call which caused the
  788. // panic itself was tracked above. We'll report to
  789. // aid debugging.
  790. runner.output.WriteCallProblem("PANIC", c)
  791. case missedSt:
  792. runner.output.WriteCallSuccess("MISS", c)
  793. }
  794. }