You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

114 lines
3.0 KiB

  1. package matchers
  2. import (
  3. "fmt"
  4. "reflect"
  5. "github.com/onsi/gomega/format"
  6. )
  7. type PanicMatcher struct {
  8. Expected interface{}
  9. object interface{}
  10. }
  11. func (matcher *PanicMatcher) Match(actual interface{}) (success bool, err error) {
  12. if actual == nil {
  13. return false, fmt.Errorf("PanicMatcher expects a non-nil actual.")
  14. }
  15. actualType := reflect.TypeOf(actual)
  16. if actualType.Kind() != reflect.Func {
  17. return false, fmt.Errorf("PanicMatcher expects a function. Got:\n%s", format.Object(actual, 1))
  18. }
  19. if !(actualType.NumIn() == 0 && actualType.NumOut() == 0) {
  20. return false, fmt.Errorf("PanicMatcher expects a function with no arguments and no return value. Got:\n%s", format.Object(actual, 1))
  21. }
  22. success = false
  23. defer func() {
  24. if e := recover(); e != nil {
  25. matcher.object = e
  26. if matcher.Expected == nil {
  27. success = true
  28. return
  29. }
  30. valueMatcher, valueIsMatcher := matcher.Expected.(omegaMatcher)
  31. if !valueIsMatcher {
  32. valueMatcher = &EqualMatcher{Expected: matcher.Expected}
  33. }
  34. success, err = valueMatcher.Match(e)
  35. if err != nil {
  36. err = fmt.Errorf("PanicMatcher's value matcher failed with:\n%s%s", format.Indent, err.Error())
  37. }
  38. }
  39. }()
  40. reflect.ValueOf(actual).Call([]reflect.Value{})
  41. return
  42. }
  43. func (matcher *PanicMatcher) FailureMessage(actual interface{}) (message string) {
  44. if matcher.Expected == nil {
  45. // We wanted any panic to occur, but none did.
  46. return format.Message(actual, "to panic")
  47. }
  48. if matcher.object == nil {
  49. // We wanted a panic with a specific value to occur, but none did.
  50. switch matcher.Expected.(type) {
  51. case omegaMatcher:
  52. return format.Message(actual, "to panic with a value matching", matcher.Expected)
  53. default:
  54. return format.Message(actual, "to panic with", matcher.Expected)
  55. }
  56. }
  57. // We got a panic, but the value isn't what we expected.
  58. switch matcher.Expected.(type) {
  59. case omegaMatcher:
  60. return format.Message(
  61. actual,
  62. fmt.Sprintf(
  63. "to panic with a value matching\n%s\nbut panicked with\n%s",
  64. format.Object(matcher.Expected, 1),
  65. format.Object(matcher.object, 1),
  66. ),
  67. )
  68. default:
  69. return format.Message(
  70. actual,
  71. fmt.Sprintf(
  72. "to panic with\n%s\nbut panicked with\n%s",
  73. format.Object(matcher.Expected, 1),
  74. format.Object(matcher.object, 1),
  75. ),
  76. )
  77. }
  78. }
  79. func (matcher *PanicMatcher) NegatedFailureMessage(actual interface{}) (message string) {
  80. if matcher.Expected == nil {
  81. // We didn't want any panic to occur, but one did.
  82. return format.Message(actual, fmt.Sprintf("not to panic, but panicked with\n%s", format.Object(matcher.object, 1)))
  83. }
  84. // We wanted a to ensure a panic with a specific value did not occur, but it did.
  85. switch matcher.Expected.(type) {
  86. case omegaMatcher:
  87. return format.Message(
  88. actual,
  89. fmt.Sprintf(
  90. "not to panic with a value matching\n%s\nbut panicked with\n%s",
  91. format.Object(matcher.Expected, 1),
  92. format.Object(matcher.object, 1),
  93. ),
  94. )
  95. default:
  96. return format.Message(actual, "not to panic with", matcher.Expected)
  97. }
  98. }