assert.go 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. package assert
  2. import (
  3. "bytes"
  4. "fmt"
  5. "runtime"
  6. "strings"
  7. "testing"
  8. )
  9. func On(t *testing.T) *Assert {
  10. return &Assert{
  11. t: t,
  12. }
  13. }
  14. type Assert struct {
  15. t *testing.T
  16. }
  17. func (v *Assert) Fail(message string) {
  18. v.t.Fatal(decorate(message))
  19. }
  20. func getCaller() (string, int) {
  21. stackLevel := 3
  22. for {
  23. _, file, line, ok := runtime.Caller(stackLevel)
  24. if strings.Contains(file, "assert") {
  25. stackLevel++
  26. } else {
  27. if ok {
  28. // Truncate file name at last file name separator.
  29. if index := strings.LastIndex(file, "/"); index >= 0 {
  30. file = file[index+1:]
  31. } else if index = strings.LastIndex(file, "\\"); index >= 0 {
  32. file = file[index+1:]
  33. }
  34. } else {
  35. file = "???"
  36. line = 1
  37. }
  38. return file, line
  39. }
  40. }
  41. }
  42. // decorate prefixes the string with the file and line of the call site
  43. // and inserts the final newline if needed and indentation tabs for formatting.
  44. func decorate(s string) string {
  45. file, line := getCaller()
  46. buf := new(bytes.Buffer)
  47. // Every line is indented at least one tab.
  48. buf.WriteString(" ")
  49. fmt.Fprintf(buf, "%s:%d: ", file, line)
  50. lines := strings.Split(s, "\n")
  51. if l := len(lines); l > 1 && lines[l-1] == "" {
  52. lines = lines[:l-1]
  53. }
  54. for i, line := range lines {
  55. if i > 0 {
  56. // Second and subsequent lines are indented an extra tab.
  57. buf.WriteString("\n\t\t")
  58. }
  59. buf.WriteString(line)
  60. }
  61. buf.WriteByte('\n')
  62. return buf.String()
  63. }