format.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. package testjson
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/fatih/color"
  6. )
  7. // EventFormatter is a function which handles an event and returns a string to
  8. // output for the event.
  9. type EventFormatter func(event TestEvent, output *Execution) (string, error)
  10. func debugFormat(event TestEvent, _ *Execution) (string, error) {
  11. return fmt.Sprintf("%s %s %s (%.3f) [%d] %s\n",
  12. event.Package,
  13. event.Test,
  14. event.Action,
  15. event.Elapsed,
  16. event.Time.Unix(),
  17. event.Output), nil
  18. }
  19. // go test -v
  20. func standardVerboseFormat(event TestEvent, _ *Execution) (string, error) {
  21. if event.Action == ActionOutput {
  22. return event.Output, nil
  23. }
  24. return "", nil
  25. }
  26. // go test
  27. func standardQuietFormat(event TestEvent, _ *Execution) (string, error) {
  28. if !event.PackageEvent() {
  29. return "", nil
  30. }
  31. if event.Output != "PASS\n" && !isCoverageOutput(event.Output) {
  32. return event.Output, nil
  33. }
  34. return "", nil
  35. }
  36. func shortVerboseFormat(event TestEvent, exec *Execution) (string, error) {
  37. result := colorEvent(event)(strings.ToUpper(string(event.Action)))
  38. formatTest := func() string {
  39. return fmt.Sprintf("%s %s.%s %s\n",
  40. result,
  41. relativePackagePath(event.Package),
  42. event.Test,
  43. event.ElapsedFormatted())
  44. }
  45. switch {
  46. case isPkgFailureOutput(event):
  47. return event.Output, nil
  48. case event.PackageEvent():
  49. switch event.Action {
  50. case ActionSkip:
  51. result = colorEvent(event)("EMPTY")
  52. fallthrough
  53. case ActionPass, ActionFail:
  54. return fmt.Sprintf("%s %s\n", result, relativePackagePath(event.Package)), nil
  55. }
  56. case event.Action == ActionFail:
  57. return exec.Output(event.Package, event.Test) + formatTest(), nil
  58. case event.Action == ActionPass:
  59. return formatTest(), nil
  60. }
  61. return "", nil
  62. }
  63. // isPkgFailureOutput returns true if the event is package output, and the output
  64. // doesn't match any of the expected framing messages. Events which match this
  65. // pattern should be package-level failures (ex: exit(1) or panic in an init() or
  66. // TestMain).
  67. func isPkgFailureOutput(event TestEvent) bool {
  68. out := event.Output
  69. return all(
  70. event.PackageEvent(),
  71. event.Action == ActionOutput,
  72. out != "PASS\n",
  73. out != "FAIL\n",
  74. !strings.HasPrefix(out, "FAIL\t"+event.Package),
  75. !strings.HasPrefix(out, "ok \t"+event.Package),
  76. !strings.HasPrefix(out, "? \t"+event.Package),
  77. )
  78. }
  79. func all(cond ...bool) bool {
  80. for _, c := range cond {
  81. if !c {
  82. return false
  83. }
  84. }
  85. return true
  86. }
  87. func shortFormat(event TestEvent, exec *Execution) (string, error) {
  88. if !event.PackageEvent() {
  89. return "", nil
  90. }
  91. fmtElapsed := func() string {
  92. d := elapsedDuration(event.Elapsed)
  93. if d == 0 {
  94. return ""
  95. }
  96. return fmt.Sprintf(" (%s)", d)
  97. }
  98. fmtCoverage := func() string {
  99. pkg := exec.Package(event.Package)
  100. if pkg.coverage == "" {
  101. return ""
  102. }
  103. return " (" + pkg.coverage + ")"
  104. }
  105. fmtEvent := func(action string) (string, error) {
  106. return fmt.Sprintf("%s %s%s%s\n",
  107. action,
  108. relativePackagePath(event.Package),
  109. fmtElapsed(),
  110. fmtCoverage(),
  111. ), nil
  112. }
  113. withColor := colorEvent(event)
  114. switch event.Action {
  115. case ActionSkip:
  116. return fmtEvent(withColor("∅"))
  117. case ActionPass:
  118. return fmtEvent(withColor("✓"))
  119. case ActionFail:
  120. return fmtEvent(withColor("✖"))
  121. }
  122. return "", nil
  123. }
  124. func dotsFormat(event TestEvent, exec *Execution) (string, error) {
  125. pkg := exec.Package(event.Package)
  126. withColor := colorEvent(event)
  127. switch {
  128. case event.PackageEvent():
  129. return "", nil
  130. case event.Action == ActionRun && pkg.Total == 1:
  131. return "[" + relativePackagePath(event.Package) + "]", nil
  132. case event.Action == ActionPass:
  133. return withColor("·"), nil
  134. case event.Action == ActionFail:
  135. return withColor("✖"), nil
  136. case event.Action == ActionSkip:
  137. return withColor("↷"), nil
  138. }
  139. return "", nil
  140. }
  141. func colorEvent(event TestEvent) func(format string, a ...interface{}) string {
  142. switch event.Action {
  143. case ActionPass:
  144. return color.GreenString
  145. case ActionFail:
  146. return color.RedString
  147. case ActionSkip:
  148. return color.YellowString
  149. }
  150. return color.WhiteString
  151. }
  152. // NewEventFormatter returns a formatter for printing events.
  153. func NewEventFormatter(format string) EventFormatter {
  154. switch format {
  155. case "debug":
  156. return debugFormat
  157. case "standard-verbose":
  158. return standardVerboseFormat
  159. case "standard-quiet":
  160. return standardQuietFormat
  161. case "dots":
  162. return dotsFormat
  163. case "short-verbose":
  164. return shortVerboseFormat
  165. case "short":
  166. return shortFormat
  167. default:
  168. return nil
  169. }
  170. }