discovery.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. package convey
  2. type actionSpecifier uint8
  3. const (
  4. noSpecifier actionSpecifier = iota
  5. skipConvey
  6. focusConvey
  7. )
  8. type suite struct {
  9. Situation string
  10. Test t
  11. Focus bool
  12. Func func(C) // nil means skipped
  13. FailMode FailureMode
  14. }
  15. func newSuite(situation string, failureMode FailureMode, f func(C), test t, specifier actionSpecifier) *suite {
  16. ret := &suite{
  17. Situation: situation,
  18. Test: test,
  19. Func: f,
  20. FailMode: failureMode,
  21. }
  22. switch specifier {
  23. case skipConvey:
  24. ret.Func = nil
  25. case focusConvey:
  26. ret.Focus = true
  27. }
  28. return ret
  29. }
  30. func discover(items []interface{}) *suite {
  31. name, items := parseName(items)
  32. test, items := parseGoTest(items)
  33. failure, items := parseFailureMode(items)
  34. action, items := parseAction(items)
  35. specifier, items := parseSpecifier(items)
  36. if len(items) != 0 {
  37. conveyPanic(parseError)
  38. }
  39. return newSuite(name, failure, action, test, specifier)
  40. }
  41. func item(items []interface{}) interface{} {
  42. if len(items) == 0 {
  43. conveyPanic(parseError)
  44. }
  45. return items[0]
  46. }
  47. func parseName(items []interface{}) (string, []interface{}) {
  48. if name, parsed := item(items).(string); parsed {
  49. return name, items[1:]
  50. }
  51. conveyPanic(parseError)
  52. panic("never get here")
  53. }
  54. func parseGoTest(items []interface{}) (t, []interface{}) {
  55. if test, parsed := item(items).(t); parsed {
  56. return test, items[1:]
  57. }
  58. return nil, items
  59. }
  60. func parseFailureMode(items []interface{}) (FailureMode, []interface{}) {
  61. if mode, parsed := item(items).(FailureMode); parsed {
  62. return mode, items[1:]
  63. }
  64. return FailureInherits, items
  65. }
  66. func parseAction(items []interface{}) (func(C), []interface{}) {
  67. switch x := item(items).(type) {
  68. case nil:
  69. return nil, items[1:]
  70. case func(C):
  71. return x, items[1:]
  72. case func():
  73. return func(C) { x() }, items[1:]
  74. }
  75. conveyPanic(parseError)
  76. panic("never get here")
  77. }
  78. func parseSpecifier(items []interface{}) (actionSpecifier, []interface{}) {
  79. if len(items) == 0 {
  80. return noSpecifier, items
  81. }
  82. if spec, ok := items[0].(actionSpecifier); ok {
  83. return spec, items[1:]
  84. }
  85. conveyPanic(parseError)
  86. panic("never get here")
  87. }
  88. // This interface allows us to pass the *testing.T struct
  89. // throughout the internals of this package without ever
  90. // having to import the "testing" package.
  91. type t interface {
  92. Fail()
  93. }
  94. const parseError = "You must provide a name (string), then a *testing.T (if in outermost scope), an optional FailureMode, and then an action (func())."