Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 

874 řádky
21 KiB

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