github.com/onsi/gomega@v1.32.0/matchers/with_transform_test.go (about) 1 package matchers_test 2 3 import ( 4 "errors" 5 6 . "github.com/onsi/ginkgo/v2" 7 . "github.com/onsi/gomega" 8 . "github.com/onsi/gomega/matchers" 9 ) 10 11 var _ = Describe("WithTransformMatcher", func() { 12 13 var plus1 = func(i int) int { return i + 1 } 14 15 Context("Panic if transform function invalid", func() { 16 panicsWithTransformer := func(transform interface{}) { 17 Expect(func() { WithTransform(transform, nil) }).WithOffset(1).To(Panic()) 18 } 19 It("nil", func() { 20 panicsWithTransformer(nil) 21 }) 22 Context("Invalid number of args, but correct return value count", func() { 23 It("zero", func() { 24 panicsWithTransformer(func() int { return 5 }) 25 }) 26 It("two", func() { 27 panicsWithTransformer(func(i, j int) int { return 5 }) 28 }) 29 }) 30 Context("Invalid number of return values, but correct number of arguments", func() { 31 It("zero", func() { 32 panicsWithTransformer(func(i int) {}) 33 }) 34 It("two", func() { 35 panicsWithTransformer(func(i int) (int, int) { return 5, 6 }) 36 }) 37 }) 38 Context("Invalid number of return values, but correct number of arguments", func() { 39 It("Two return values, but second return value not an error", func() { 40 panicsWithTransformer(func(interface{}) (int, int) { return 5, 6 }) 41 }) 42 }) 43 }) 44 45 When("the actual value is incompatible", func() { 46 It("fails to pass int to func(string)", func() { 47 actual, transform := int(0), func(string) int { return 0 } 48 success, err := WithTransform(transform, Equal(0)).Match(actual) 49 Expect(success).To(BeFalse()) 50 Expect(err).To(HaveOccurred()) 51 Expect(err.Error()).To(ContainSubstring("function expects 'string'")) 52 Expect(err.Error()).To(ContainSubstring("have 'int'")) 53 }) 54 55 It("fails to pass string to func(interface)", func() { 56 actual, transform := "bang", func(error) int { return 0 } 57 success, err := WithTransform(transform, Equal(0)).Match(actual) 58 Expect(success).To(BeFalse()) 59 Expect(err).To(HaveOccurred()) 60 Expect(err.Error()).To(ContainSubstring("function expects 'error'")) 61 Expect(err.Error()).To(ContainSubstring("have 'string'")) 62 }) 63 64 It("fails to pass nil interface to func(int)", func() { 65 actual, transform := error(nil), func(int) int { return 0 } 66 success, err := WithTransform(transform, Equal(0)).Match(actual) 67 Expect(success).To(BeFalse()) 68 Expect(err).To(HaveOccurred()) 69 Expect(err.Error()).To(ContainSubstring("function expects 'int'")) 70 Expect(err.Error()).To(ContainSubstring("have '<nil>'")) 71 }) 72 73 It("fails to pass nil interface to func(pointer)", func() { 74 actual, transform := error(nil), func(*string) int { return 0 } 75 success, err := WithTransform(transform, Equal(0)).Match(actual) 76 Expect(success).To(BeFalse()) 77 Expect(err).To(HaveOccurred()) 78 Expect(err.Error()).To(ContainSubstring("function expects '*string'")) 79 Expect(err.Error()).To(ContainSubstring("have '<nil>'")) 80 }) 81 }) 82 83 It("works with positive cases", func() { 84 Expect(1).To(WithTransform(plus1, Equal(2))) 85 Expect(1).To(WithTransform(plus1, WithTransform(plus1, Equal(3)))) 86 Expect(1).To(WithTransform(plus1, And(Equal(2), BeNumerically(">", 1)))) 87 88 // transform expects custom type 89 type S struct { 90 A int 91 B string 92 } 93 transformer := func(s S) string { return s.B } 94 Expect(S{1, "hi"}).To(WithTransform(transformer, Equal("hi"))) 95 96 // transform expects interface 97 errString := func(e error) string { 98 if e == nil { 99 return "safe" 100 } 101 return e.Error() 102 } 103 Expect(nil).To(WithTransform(errString, Equal("safe")), "handles nil actual values") 104 Expect(errors.New("abc")).To(WithTransform(errString, Equal("abc"))) 105 }) 106 107 It("works with negative cases", func() { 108 Expect(1).ToNot(WithTransform(plus1, Equal(3))) 109 Expect(1).ToNot(WithTransform(plus1, WithTransform(plus1, Equal(2)))) 110 }) 111 112 Context("failure messages", func() { 113 When("match fails", func() { 114 It("gives a descriptive message", func() { 115 m := WithTransform(plus1, Equal(3)) 116 Expect(m.Match(1)).To(BeFalse()) 117 Expect(m.FailureMessage(1)).To(Equal("Expected\n <int>: 2\nto equal\n <int>: 3")) 118 }) 119 }) 120 121 When("match succeeds, but expected it to fail", func() { 122 It("gives a descriptive message", func() { 123 m := Not(WithTransform(plus1, Equal(3))) 124 Expect(m.Match(2)).To(BeFalse()) 125 Expect(m.FailureMessage(2)).To(Equal("Expected\n <int>: 3\nnot to equal\n <int>: 3")) 126 }) 127 }) 128 129 When("transform fails", func() { 130 It("reports the transformation error", func() { 131 actual, trafo := "foo", func(string) (string, error) { return "", errors.New("that does not transform") } 132 success, err := WithTransform(trafo, Equal(actual)).Match(actual) 133 Expect(success).To(BeFalse()) 134 Expect(err).To(HaveOccurred()) 135 Expect(err.Error()).To(MatchRegexp(": that does not transform$")) 136 }) 137 }) 138 139 Context("actual value is incompatible with transform function's argument type", func() { 140 It("gracefully fails if transform cannot be performed", func() { 141 m := WithTransform(plus1, Equal(3)) 142 result, err := m.Match("hi") // give it a string but transform expects int; doesn't panic 143 Expect(result).To(BeFalse()) 144 Expect(err).To(MatchError("Transform function expects 'int' but we have 'string'")) 145 }) 146 }) 147 }) 148 149 Context("MatchMayChangeInTheFuture()", func() { 150 It("Propagates value from wrapped matcher on the transformed value", func() { 151 m := WithTransform(plus1, Or()) // empty Or() always returns false, and indicates it cannot change 152 Expect(m.Match(1)).To(BeFalse()) 153 Expect(m.(*WithTransformMatcher).MatchMayChangeInTheFuture(1)).To(BeFalse()) // empty Or() indicates cannot change 154 }) 155 It("Defaults to true", func() { 156 m := WithTransform(plus1, Equal(2)) // Equal does not have this method 157 Expect(m.Match(1)).To(BeTrue()) 158 Expect(m.(*WithTransformMatcher).MatchMayChangeInTheFuture(1)).To(BeTrue()) // defaults to true 159 }) 160 }) 161 })