1package assertion 2 3import ( 4 "fmt" 5 "reflect" 6 7 "github.com/onsi/gomega/types" 8) 9 10type Assertion struct { 11 actualInput interface{} 12 failWrapper *types.GomegaFailWrapper 13 offset int 14 extra []interface{} 15} 16 17func New(actualInput interface{}, failWrapper *types.GomegaFailWrapper, offset int, extra ...interface{}) *Assertion { 18 return &Assertion{ 19 actualInput: actualInput, 20 failWrapper: failWrapper, 21 offset: offset, 22 extra: extra, 23 } 24} 25 26func (assertion *Assertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { 27 assertion.failWrapper.TWithHelper.Helper() 28 return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...) 29} 30 31func (assertion *Assertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { 32 assertion.failWrapper.TWithHelper.Helper() 33 return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...) 34} 35 36func (assertion *Assertion) To(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { 37 assertion.failWrapper.TWithHelper.Helper() 38 return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...) 39} 40 41func (assertion *Assertion) ToNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { 42 assertion.failWrapper.TWithHelper.Helper() 43 return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...) 44} 45 46func (assertion *Assertion) NotTo(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { 47 assertion.failWrapper.TWithHelper.Helper() 48 return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...) 49} 50 51func (assertion *Assertion) buildDescription(optionalDescription ...interface{}) string { 52 switch len(optionalDescription) { 53 case 0: 54 return "" 55 default: 56 return fmt.Sprintf(optionalDescription[0].(string), optionalDescription[1:]...) + "\n" 57 } 58} 59 60func (assertion *Assertion) match(matcher types.GomegaMatcher, desiredMatch bool, optionalDescription ...interface{}) bool { 61 matches, err := matcher.Match(assertion.actualInput) 62 description := assertion.buildDescription(optionalDescription...) 63 assertion.failWrapper.TWithHelper.Helper() 64 if err != nil { 65 assertion.failWrapper.Fail(description+err.Error(), 2+assertion.offset) 66 return false 67 } 68 if matches != desiredMatch { 69 var message string 70 if desiredMatch { 71 message = matcher.FailureMessage(assertion.actualInput) 72 } else { 73 message = matcher.NegatedFailureMessage(assertion.actualInput) 74 } 75 assertion.failWrapper.Fail(description+message, 2+assertion.offset) 76 return false 77 } 78 79 return true 80} 81 82func (assertion *Assertion) vetExtras(optionalDescription ...interface{}) bool { 83 success, message := vetExtras(assertion.extra) 84 if success { 85 return true 86 } 87 88 description := assertion.buildDescription(optionalDescription...) 89 assertion.failWrapper.TWithHelper.Helper() 90 assertion.failWrapper.Fail(description+message, 2+assertion.offset) 91 return false 92} 93 94func vetExtras(extras []interface{}) (bool, string) { 95 for i, extra := range extras { 96 if extra != nil { 97 zeroValue := reflect.Zero(reflect.TypeOf(extra)).Interface() 98 if !reflect.DeepEqual(zeroValue, extra) { 99 message := fmt.Sprintf("Unexpected non-nil/non-zero extra argument at index %d:\n\t<%T>: %#v", i+1, extra, extra) 100 return false, message 101 } 102 } 103 } 104 return true, "" 105} 106