reports.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. package reporting
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "runtime"
  6. "strings"
  7. "github.com/smartystreets/goconvey/convey/gotest"
  8. )
  9. ////////////////// ScopeReport ////////////////////
  10. type ScopeReport struct {
  11. Title string
  12. File string
  13. Line int
  14. }
  15. func NewScopeReport(title string) *ScopeReport {
  16. file, line, _ := gotest.ResolveExternalCaller()
  17. self := new(ScopeReport)
  18. self.Title = title
  19. self.File = file
  20. self.Line = line
  21. return self
  22. }
  23. ////////////////// ScopeResult ////////////////////
  24. type ScopeResult struct {
  25. Title string
  26. File string
  27. Line int
  28. Depth int
  29. Assertions []*AssertionResult
  30. Output string
  31. }
  32. func newScopeResult(title string, depth int, file string, line int) *ScopeResult {
  33. self := new(ScopeResult)
  34. self.Title = title
  35. self.Depth = depth
  36. self.File = file
  37. self.Line = line
  38. self.Assertions = []*AssertionResult{}
  39. return self
  40. }
  41. /////////////////// StoryReport /////////////////////
  42. type StoryReport struct {
  43. Test T
  44. Name string
  45. File string
  46. Line int
  47. }
  48. func NewStoryReport(test T) *StoryReport {
  49. file, line, name := gotest.ResolveExternalCaller()
  50. name = removePackagePath(name)
  51. self := new(StoryReport)
  52. self.Test = test
  53. self.Name = name
  54. self.File = file
  55. self.Line = line
  56. return self
  57. }
  58. // name comes in looking like "github.com/smartystreets/goconvey/examples.TestName".
  59. // We only want the stuff after the last '.', which is the name of the test function.
  60. func removePackagePath(name string) string {
  61. parts := strings.Split(name, ".")
  62. return parts[len(parts)-1]
  63. }
  64. /////////////////// FailureView ////////////////////////
  65. type FailureView struct {
  66. Message string
  67. Expected string
  68. Actual string
  69. }
  70. ////////////////////AssertionResult //////////////////////
  71. type AssertionResult struct {
  72. File string
  73. Line int
  74. Expected string
  75. Actual string
  76. Failure string
  77. Error interface{}
  78. StackTrace string
  79. Skipped bool
  80. }
  81. func NewFailureReport(failure string) *AssertionResult {
  82. report := new(AssertionResult)
  83. report.File, report.Line = caller()
  84. report.StackTrace = stackTrace()
  85. parseFailure(failure, report)
  86. return report
  87. }
  88. func parseFailure(failure string, report *AssertionResult) {
  89. view := new(FailureView)
  90. err := json.Unmarshal([]byte(failure), view)
  91. if err == nil {
  92. report.Failure = view.Message
  93. report.Expected = view.Expected
  94. report.Actual = view.Actual
  95. } else {
  96. report.Failure = failure
  97. }
  98. }
  99. func NewErrorReport(err interface{}) *AssertionResult {
  100. report := new(AssertionResult)
  101. report.File, report.Line = caller()
  102. report.StackTrace = fullStackTrace()
  103. report.Error = fmt.Sprintf("%v", err)
  104. return report
  105. }
  106. func NewSuccessReport() *AssertionResult {
  107. return new(AssertionResult)
  108. }
  109. func NewSkipReport() *AssertionResult {
  110. report := new(AssertionResult)
  111. report.File, report.Line = caller()
  112. report.StackTrace = fullStackTrace()
  113. report.Skipped = true
  114. return report
  115. }
  116. func caller() (file string, line int) {
  117. file, line, _ = gotest.ResolveExternalCaller()
  118. return
  119. }
  120. func stackTrace() string {
  121. buffer := make([]byte, 1024*64)
  122. n := runtime.Stack(buffer, false)
  123. return removeInternalEntries(string(buffer[:n]))
  124. }
  125. func fullStackTrace() string {
  126. buffer := make([]byte, 1024*64)
  127. n := runtime.Stack(buffer, true)
  128. return removeInternalEntries(string(buffer[:n]))
  129. }
  130. func removeInternalEntries(stack string) string {
  131. lines := strings.Split(stack, newline)
  132. filtered := []string{}
  133. for _, line := range lines {
  134. if !isExternal(line) {
  135. filtered = append(filtered, line)
  136. }
  137. }
  138. return strings.Join(filtered, newline)
  139. }
  140. func isExternal(line string) bool {
  141. for _, p := range internalPackages {
  142. if strings.Contains(line, p) {
  143. return true
  144. }
  145. }
  146. return false
  147. }
  148. // NOTE: any new packages that host goconvey packages will need to be added here!
  149. // An alternative is to scan the goconvey directory and then exclude stuff like
  150. // the examples package but that's nasty too.
  151. var internalPackages = []string{
  152. "goconvey/assertions",
  153. "goconvey/convey",
  154. "goconvey/execution",
  155. "goconvey/gotest",
  156. "goconvey/reporting",
  157. }