├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── asserter ├── Makefile ├── asserter.go └── asserter_test.go ├── base ├── Makefile ├── comparison.go ├── defs.go ├── matcher_test.go └── matchers.go ├── collections ├── Makefile ├── collections.go └── collections_test.go ├── core ├── Makefile ├── comparison_test.go ├── core.go └── core_test.go ├── doc.go ├── logic ├── Makefile ├── doc.go ├── logic.go └── logic_test.go ├── reflect ├── Makefile ├── doc.go ├── reflect.go └── reflect_test.go ├── slices ├── Makefile ├── slices.go └── slices_test.go └── strings ├── Makefile ├── strings.go └── strings_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | _* 2 | *.out 3 | *.[568] 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD License 2 | 3 | Copyright (c) 2010 Mick Killianey. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions 7 | are met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above 13 | copyright notice, this list of conditions and the following 14 | disclaimer in the documentation and/or other materials provided 15 | with the distribution. 16 | 17 | * None of the names of Mick Killianey, Hamcrest, or the names or 18 | pseudonyms of any contributor to this project may be used to 19 | endorse or promote products derived from this software without 20 | specific prior written permission. 21 | 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Mick Killianey. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | include $(GOROOT)/src/Make.inc 6 | 7 | PREFIX = github.com/rdrdr/hamcrest 8 | 9 | all: clean install test 10 | 11 | .PHONY: all bench clean install nuke test 12 | 13 | 14 | 15 | DEPS=\ 16 | $(PREFIX)/base \ 17 | $(PREFIX)/asserter \ 18 | $(PREFIX)/core \ 19 | $(PREFIX)/reflect \ 20 | $(PREFIX)/logic \ 21 | $(PREFIX)/slices \ 22 | $(PREFIX)/collections \ 23 | $(PREFIX)/strings \ 24 | 25 | 26 | .PHONY: all bench clean install nuke test 27 | 28 | all: clean install test bench 29 | 30 | bench: install 31 | make -C base bench 32 | make -C asserter bench 33 | make -C core bench 34 | make -C reflect bench 35 | make -C logic bench 36 | make -C slices bench 37 | make -C collections bench 38 | make -C strings bench 39 | 40 | clean: 41 | make -C base clean 42 | make -C asserter clean 43 | make -C core clean 44 | make -C reflect clean 45 | make -C logic clean 46 | make -C slices clean 47 | make -C collections clean 48 | make -C strings clean 49 | 50 | install: 51 | make -C base install 52 | make -C asserter install 53 | make -C core install 54 | make -C reflect install 55 | make -C logic install 56 | make -C slices install 57 | make -C collections install 58 | make -C strings install 59 | 60 | nuke: 61 | make -C base nuke 62 | make -C asserter nuke 63 | make -C core nuke 64 | make -C reflect nuke 65 | make -C logic nuke 66 | make -C slices nuke 67 | make -C collections nuke 68 | make -C strings nuke 69 | 70 | test: install 71 | make -C base test 72 | make -C asserter test 73 | make -C core test 74 | make -C reflect test 75 | make -C logic test 76 | make -C slices test 77 | make -C collections test 78 | make -C strings test 79 | 80 | .PHONY: force 81 | force :; 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Note: 2 | ===== 3 | This has not been maintained and/or updated since 2011. 4 | Perhaps consider [corbym/gocrest](https://github.com/corbym/gocrest), instead. 5 | 6 | 7 | 8 | Introduction 9 | ============ 10 | 11 | Hamcrest is a fluent framework for declarative Matcher objects 12 | that, when applied to input values, produce self-describing 13 | results. 14 | 15 | Installation: 16 | ======== 17 | 18 | To install, run `make install` from the same directory as this 19 | `README.md` file. 20 | 21 | Packages 22 | ======== 23 | 24 | `hamcrest.go` comes in several packages that you assemble to fit your needs: 25 | 26 | * `hamcrest/base`: Defines the types `Matcher`, `Result` and `SelfDescribing` 27 | and provides factory functions to create them. (Unless you want to define 28 | your own custom Matchers, you'll only use this indirectly.) 29 | 30 | * `hamcrest/core`: Defines a set of Matchers for doing basic comparisons, 31 | equality testing, nil checking, and grouping/composition matchers. 32 | 33 | * `hamcrest/slices`: Matchers on slices, such as `EachElem`, `AnyElem`, 34 | `ToLen`, `Empty`. 35 | 36 | * `hamcrest/reflect`: Matchers using type reflection, such as `ToType`, 37 | `SameTypeAs`, `SliceOf`, `MapOf`, etc. 38 | 39 | * `hamcrest/strings`: Matchers for strings. 40 | 41 | * `hamcrest/asserter`: Defines an `Asserter` that can be used in conjunction 42 | with Hamcrest Matchers to produce helpful logging messages at runtime 43 | (to stdout, stderr, or any object that implements io.Writer) or in 44 | unit tests (using `testing.T` from Go's standard `testing` package). 45 | 46 | Note: the `asserter` package isn't *really* part of Hamcrest: it's just 47 | a handy way of using the Hamcrest results in conjunction with the 48 | standard Go testing package. 49 | 50 | You may also choose to write your own Matchers (see *Custom matchers*, below). 51 | 52 | 53 | How to use hamcrest for testing: 54 | ================================ 55 | 56 | To use Hamcrest matchers, create an `Asserter` and use it to 57 | `Check` or `Assert` that values meet the criteria of those 58 | matchers: 59 | 60 | func TestPoint(t *testing.T) { 61 | p := Point(3, 4) 62 | we := asserter.Using(t) 63 | we.AssertThat(p.X, EqualTo(3).Comment("x coord")) 64 | we.AssertThat(p.Y, EqualTo(4).Comment("y coord")) 65 | we.CheckThat(p, ToString(EqualTo("[3, 4]"))) 66 | we.CheckThat(p.Magnitude(), EqualTo(5).Comment("magnitude")) 67 | } 68 | 69 | (`Assert` methods fail immediately, as `testing.T.FailNow()` does, 70 | while `Check` methods defer failure, as `testing.T.Fail()` does.) 71 | 72 | The `AssertThat` and `CheckThat` functions are designed to create 73 | conditional checks that read fluently as self-commenting code, and 74 | are self-describing when failures occur. For example, the above 75 | test might fail with this message: 76 | 77 | FAILURE on input &Point{X:3, Y:4} 78 | Did not match ToString(EqualTo([3, 4])) 79 | Because: String() was "[4, 3]" 80 | Did not match EqualTo[[3, 4]] 81 | Because: "[4, 3]" was not equal to "[3, 4]" 82 | 83 | Or: 84 | FAILURE on input 5 85 | Did not match EqualTo(5) 86 | Because: uint 5 could not be compared to int 5 87 | Comment: magnitude 88 | 89 | Note that the majority of the text descriptions are generated 90 | automatically by the matchers. For typical uses of Hamcrest 91 | matchers, the code is largely self-documenting, and the error 92 | messages are detailed. 93 | 94 | Effort invested in good self-describing matchers can be leveraged 95 | across many tests. 96 | 97 | 98 | Examples of using Hamcrest at runtime: 99 | ====================================== 100 | 101 | Just as in the testing example, create an `Asserter`, but use a factory 102 | method such as `UsingStderr()`, which returns an `Asserter` that logs 103 | problems to stderr and calls `panic` on `FailNow`: 104 | 105 | import ( 106 | "github.com/rdrdr/hamcrest/asserter" 107 | ) 108 | 109 | var we = asserter.UsingStderr() 110 | 111 | Use that asserter during init() to make sure globals are properly 112 | initialized: 113 | 114 | import ( 115 | "github.com/rdrdr/hamcrest/asserter" 116 | "github.com/rdrdr/hamcrest/slices" 117 | . "github.com/rdrdr/hamcrest/core" 118 | "github.com/rdrdr/hamcrest/strings" 119 | ) 120 | var we = asserter.UsingStderr() 121 | 122 | type Server struct { 123 | hostname string 124 | port uint16 125 | } 126 | var servers = []Server { 127 | { "news.foo.com", 8000 }, 128 | { "news.bar.com", 8888 }, 129 | } 130 | 131 | func init() { 132 | ToHostname := Applying(func(s Server) string { 133 | return s.hostname 134 | }, "TransformServerToHostname") 135 | IsInOneOfOurDomains := AnyOf(strings.HasSuffix(".foo.com"), 136 | strings.HasSuffix(".bar.com")) 137 | we.FailNowUnless(servers, 138 | slices.EachElem(ToHostname(IsInOneOfOurDomains))) 139 | } 140 | 141 | Or use the asserter at runtime to guarantee that a method's 142 | preconditions are met: 143 | 144 | var IsValidFilenameForTextFile = AllOf( 145 | strings.HasSuffix(".txt").Comment("Must have .txt extension."), 146 | Not(strings.HasPattern("[ \\t\\n\\r]")).Comment("whitespace not permitted"), 147 | Not(strings.HasPattern("[:////\\\\]")).Comment("path separators not permitted")) 148 | 149 | func WriteTo(filename string) bool { 150 | we.AssertThat(filename, IsValidFilenameForTextFile) 151 | // Use filename here. 152 | } 153 | 154 | Or use the asserter with `defer` to program by contract, knowing that you 155 | can later swap out your typical `Asserter` with an 156 | `asserter.ThatDoesNothing()` to bypass those checks: 157 | 158 | IsWellFormedMD5 := AllOf( 159 | ToLen(EqualTo(32)).Comment("MD5 hashes have length 32"), 160 | strings.HasPattern("^([0-9][A-F][a-f])+$").Comment("hex digits"))) 161 | 162 | func MD5(data []byte) (result string) { 163 | we.AssertNonNil(data) 164 | defer we.AssertThat(result, IsWellFormedMD5) 165 | 166 | // calculate MD5 of data 167 | } 168 | 169 | 170 | Or use it during development to write your tests in the same file as your code: 171 | 172 | func EncodePigLatin(input string) string { 173 | ...implementation... 174 | } 175 | 176 | func init() { 177 | we := asserter.UsingStderr() 178 | ToEncoded := Applying(EncodePigLatin, "in PigLatin form") 179 | we.AssertThat("simple", ToEncoded(EqualTo("imple-say"))) 180 | we.AssertThat("Capital"), ToEncoded(EqualTo("Apital-Cay"))) 181 | we.AssertThat("prefix"), ToEncoded(EqualTo("efix-pray"))) 182 | we.AssertThat("oops"), ToEncoded(EqualTo("oops-ay"))) 183 | we.AssertThat("your psychotic y!"), 184 | ToEncoded(EqualTo("our-yay ychotic-psay y-ay!"))) 185 | } 186 | 187 | At some future point, this structure will make it easier to cut-and-paste 188 | each `init()` block into your testing suite. While moving the block over, 189 | replace: 190 | 191 | func init() { 192 | we := asserter.UsingStderr() 193 | ... 194 | 195 | With an `Asserter` that uses the testing infrastructure, instead: 196 | 197 | func Test_EncodePigLatin(t *testing.T) { 198 | we := asserter.Using(t) 199 | ... 200 | 201 | A note on library design: 202 | ========================= 203 | 204 | Hamcrest is designed to be a fluent library. The Go syntax requires external 205 | symbols be preceded by their package name, which can lead to occasionally 206 | awkward constructions: 207 | we.CheckThat("foobar", core.AllOf(strings.HasPrefix("foo"), strings.HasSuffix("bar"))) 208 | 209 | To avoid this clunkiness, Hamcrest matchers are generated by functions that 210 | you can assign to local names: 211 | AllOf := core.AllOf 212 | StartsWith := strings.HasPrefix 213 | EndsWith := strings.HasSuffix 214 | we.CheckThat("foobar", AllOf(StartsWith("foo"), EndsWith("bar"))) 215 | 216 | 217 | Performance note: 218 | ================= 219 | Note: Hamcrest matchers allocate Description and Result objects to 220 | explain in great detail why they did or did not match. However, these 221 | objects are lazily evaluated. Users should be generally aware that 222 | there is an *object allocation* cost to using Hamcrest matchers, but 223 | there is (generally) no *string construction* cost unless a Hamcrest 224 | Matcher or Result is explicitly asked to self-describe. 225 | 226 | Still, users who are particularly sensitive to performance concerns 227 | may wish to think carefully before using Hamcrest matchers in 228 | performance-critical bottlenecks. 229 | 230 | 231 | A tour of common matchers 232 | ========================= 233 | 234 | Hamcrest comes with a library of useful matchers. Here are some of the most 235 | common ones. 236 | 237 | * `Anything` - matches any input. 238 | * `True` - only matches bool `true`. 239 | * `False` - only matches bool `false`. 240 | * `Not(matcher)` - logical not of `matcher`. 241 | * `If(m1).Then(m2)` - checks that whenever `m1` matches, so does `m2`. 242 | * `IfAndOnlyIf(m1).Then(m2)` - checks that `m1` and `m2` both match/don't match. 243 | * `EqualTo(y)` - matches any value `x` where `x == y` is legal and true. 244 | * `NotEqualTo(y)` - matches any value `x` where `x != y` is legal and true. 245 | * `DeepEqualTo(y)` - matches any value `x` where `reflect.DeepEquals(x, y)` is true. 246 | * `GreaterThan(y)` - matches any value `x` where `x > y` is legal and true. 247 | * `GreaterThanOrEqualTo(y)` - matches any value `x` where `x <= y` is legal and true. 248 | * `LessThan(y)` - matches any value `x` where `x < y` is legal and true. 249 | * `LessThanOrEqualTo(y)` - matches any value `x` where `x <= y` is legal and true. 250 | * `Nil` - matches values of any type with an `IsNil() bool` method that returns true for the given object. 251 | * `NonNil` - matches values of any type with an `IsNil() bool` method that returns false for the given object. 252 | * `AnyOf(matchers...)` - short-circuiting n-ary logical Or. 253 | * `AllOf(matchers...)` - short-circuiting n-ary logical And. 254 | 255 | Syntactic sugar 256 | =============== 257 | 258 | Hamcrest strives to make your tests as readable as possible. For example, 259 | the `Is` matcher is a wrapper that doesn't add any extra behavior to the 260 | underlying matcher. The following assertions are equivalent: 261 | 262 | we.AssertThat(x, EqualTo(y)); 263 | we.AssertThat(x, Is(EqualTo(y))) 264 | 265 | Similarly, it is possible to simulate common logical conditions using the `logic` 266 | package for readability: 267 | 268 | * `Is(matcher)` - equivalent to `matcher` 269 | * `Both(matcher1).And(matcher2)` - short-circuiting logical `And`, equivalent to `AllOf(matcher1, matcher2)` 270 | * `Either(matcher1).Or(matcher2)` - short-circuiting logical `Or`, equivalent to `AnyOf(matcher1, matcher2)` 271 | * `Neither(matcher1).Nor(matcher2)` - short-circuiting logical `Nor` 272 | * `If(matcher1).Then(matcher2)` - short-circuiting logical `If/Then` 273 | * `Iff(matcher1).Then(matcher2)` - logical `IfAndOnlyIf` (note: iff never short-circuits) 274 | * `Either(matcher1).Xor(matcher)` - logical `Xor` (note: xor never short-circuits) 275 | 276 | 277 | Custom matchers 278 | =============== 279 | 280 | Example: 281 | 282 | func IsMultipleOf(k int) *base.Matcher { 283 | match := func(n int) bool { 284 | return n % k == 0 285 | } 286 | return base.NewMatcherf(match, "multiple of %v", k) 287 | } 288 | 289 | And used: 290 | 291 | we.CheckThat(recordSize, IsMultipleOf(8).Comment( 292 | "profiling suggests better performance than multiple of 4")) 293 | 294 | Or, if you want more control over the error messages: 295 | 296 | func IsMultipleOf(k int) *base.Matcher { 297 | match := func(actual interface{}) *base.Result { 298 | if n, ok := actual.(int); ok { 299 | if remainder := n % k; remainder != 0 { 300 | return base.NewResultf(false, 301 | "was not a multiple of %v (remainder %v)", k, remainder) 302 | } 303 | return base.NewResultf(true, "was a multiple of %v", k) 304 | } 305 | return base.NewResultf(false, "was a %T, expected an int!", actual) 306 | } 307 | return base.NewMatcherf(match, "multiple of %v", k) 308 | } 309 | 310 | 311 | 312 | -------------------------------------------------------------------------------- /asserter/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Mick Killianey. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | include $(GOROOT)/src/Make.inc 6 | 7 | TARG=github.com/rdrdr/hamcrest/asserter 8 | GOFILES=\ 9 | asserter.go\ 10 | 11 | include $(GOROOT)/src/Make.pkg 12 | -------------------------------------------------------------------------------- /asserter/asserter.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package asserter 6 | 7 | import ( 8 | "fmt" 9 | "io" 10 | "os" 11 | "github.com/rdrdr/hamcrest/base" 12 | ) 13 | 14 | 15 | // Used by an Asserter to write log/error messages. 16 | // 17 | // A bit hacky...this was reverse-engineered to conform to testing.T. 18 | type Logger interface { 19 | Logf(format string, args ...interface{}) 20 | Failed() bool 21 | Fail() 22 | FailNow() 23 | } 24 | 25 | // Applies matchers to values, writing descriptions of the 26 | // results to a Logger. 27 | type Asserter interface { 28 | // Returns true if Fail() has been called. 29 | Failed() bool 30 | 31 | // Marks this asserter as having a failed assertion 32 | // but continues execution. 33 | Fail() 34 | 35 | // Marks this asserter as having a failed assertion 36 | // and invokes the immediate failure action. 37 | FailNow() 38 | 39 | // Writes the given result to the underlying logger. 40 | LogResult(result *base.Result) 41 | 42 | // On a successful match, describes the result of applying 43 | // the given matcher to the given value. 44 | LogWhen(value interface{}, matcher *base.Matcher) 45 | 46 | // On an unsuccessful match, describes the result of applying 47 | // the given matcher to the given value. 48 | LogUnless(value interface{}, matcher *base.Matcher) 49 | 50 | // On a successful match, describes the result of applying 51 | // the given matcher to the given value and invokes Fail(). 52 | FailWhen(value interface{}, matcher *base.Matcher) 53 | 54 | // On an unsuccessful match, describes the result of applying 55 | // the given matcher to the given value and invokes Fail(). 56 | FailUnless(value interface{}, matcher *base.Matcher) 57 | 58 | // On a successful match, describes the result of applying 59 | // the given matcher to the given value and invokes FailNow(). 60 | FailNowWhen(value interface{}, matcher *base.Matcher) 61 | 62 | // On an unsuccessful match, describes the result of applying 63 | // the given matcher to the given value and invokes FailNow(). 64 | FailNowUnless(value interface{}, matcher *base.Matcher) 65 | 66 | // Equivalent to FailUnless. 67 | CheckThat(value interface{}, matcher *base.Matcher) 68 | 69 | // Equivalent to FailUnless with the True matcher. 70 | CheckTrue(value bool, messages ...interface{}) 71 | 72 | // Equivalent to FailUnless with the False matcher. 73 | CheckFalse(value bool, messages ...interface{}) 74 | 75 | // Equivalent to FailUnless with the Nil matcher. 76 | CheckNil(value interface{}, messages ...interface{}) 77 | 78 | // Equivalent to FailUnless with the NonNil matcher. 79 | CheckNonNil(value interface{}, messages ...interface{}) 80 | 81 | // Equivalent to FailNowUnless. 82 | AssertThat(value interface{}, matcher *base.Matcher) 83 | 84 | // Equivalent to FailNowUnless with the True matcher. 85 | AssertTrue(value bool, messages ...interface{}) 86 | 87 | // Equivalent to FailNowUnless with the False matcher. 88 | AssertFalse(value bool, messages ...interface{}) 89 | 90 | // Equivalent to FailNowUnless with the Nil matcher. 91 | AssertNil(value interface{}, messages ...interface{}) 92 | 93 | // Equivalent to FailNowUnless with the NonNil matcher. 94 | AssertNonNil(value interface{}, messages ...interface{}) 95 | } 96 | 97 | // Convenience function to create an Asserter from a Logger. 98 | // Note that (*testing.T) satisfies Logger, and can be used here. 99 | func Using(logger Logger) Asserter { 100 | return &_Asserter{logger:logger} 101 | } 102 | 103 | // Convenience function to create an Asserter from an io.Writer 104 | // and invoke panic() when the logger is asked to FailNow(). 105 | func UsingWriter(writer io.Writer) Asserter { 106 | failNow := func() { panic("Invoked FailNow()") } 107 | return UsingWriterAndFailNow(writer, failNow) 108 | } 109 | 110 | // Convenience function to create an Asserter from an io.Writer, 111 | // and a custom FailNow() function. 112 | func UsingWriterAndFailNow(writer io.Writer, failNow func()) Asserter { 113 | return Using(&_LoggerUsingWriter{writer:writer, failNow:failNow, failed:false}) 114 | } 115 | 116 | // Convenience function to create an Asserter for stderr, 117 | // as per UsingWriter(). 118 | func UsingStderr() Asserter { 119 | return UsingWriter(os.Stderr) 120 | } 121 | 122 | // Convenience function to create an Asserter for stdout, 123 | // as per UsingWriter(). 124 | func UsingStdout() Asserter { 125 | return UsingWriter(os.Stdout) 126 | } 127 | 128 | // Convenience function to create an Asserter for stdout, 129 | // as per UsingWriter(). 130 | func UsingFileNamed(filename string) Asserter { 131 | fileFlags := os.O_CREATE | os.O_APPEND | os.O_WRONLY | os.O_NONBLOCK 132 | f, err := os.Open(filename, fileFlags, 0666) 133 | if err != nil { 134 | panic("Can't open file named " + filename) 135 | } 136 | return UsingWriter(f) 137 | } 138 | 139 | // Convenience function to return an Asserter for which every 140 | // operation is a no-op. 141 | func ThatDoesNothing() Asserter { 142 | return &_NullAsserter{} 143 | } 144 | 145 | // -------------------------------------------------------------------- 146 | // Implementation 147 | // -------------------------------------------------------------------- 148 | 149 | type _Flusher1 interface { Flush() } 150 | type _Flusher2 interface { Flush() os.Error } 151 | 152 | type _LoggerUsingWriter struct { 153 | writer io.Writer 154 | failNow func() 155 | failed bool 156 | } 157 | 158 | func (self *_LoggerUsingWriter) Logf(format string, messages ...interface{}) { 159 | fmt.Fprintf(self.writer, format, messages...) 160 | } 161 | func (self *_LoggerUsingWriter) Failed() bool { 162 | return self.failed 163 | } 164 | func (self *_LoggerUsingWriter) Fail() { 165 | self.failed = true 166 | } 167 | func (self *_LoggerUsingWriter) FailNow() { 168 | self.failed = true 169 | self.failNow() 170 | } 171 | 172 | func (self *_LoggerUsingWriter) Flush() { 173 | switch w := self.writer.(type) { 174 | case _Flusher1: w.Flush() 175 | case _Flusher2: w.Flush() 176 | } 177 | } 178 | 179 | 180 | type _NullAsserter struct {} 181 | 182 | func (self *_NullAsserter) Fail() {} 183 | func (self *_NullAsserter) FailNow() {} 184 | func (self *_NullAsserter) Failed() bool { return false } 185 | func (self *_NullAsserter) LogResult(result *base.Result) { } 186 | func (self *_NullAsserter) LogWhen(value interface{}, matcher *base.Matcher) { } 187 | func (self *_NullAsserter) LogUnless(value interface{}, matcher *base.Matcher) { } 188 | func (self *_NullAsserter) FailWhen(value interface{}, matcher *base.Matcher) { } 189 | func (self *_NullAsserter) FailUnless(value interface{}, matcher *base.Matcher) { } 190 | func (self *_NullAsserter) FailNowWhen(value interface{}, matcher *base.Matcher) { } 191 | func (self *_NullAsserter) FailNowUnless(value interface{}, matcher *base.Matcher) { } 192 | func (self *_NullAsserter) CheckThat(value interface{}, matcher *base.Matcher) { } 193 | func (self *_NullAsserter) CheckTrue(value bool, comments ...interface{}) { } 194 | func (self *_NullAsserter) CheckFalse(value bool, comments ...interface{}) { } 195 | func (self *_NullAsserter) CheckNil(value interface{}, comments ...interface{}) { } 196 | func (self *_NullAsserter) CheckNonNil(value interface{}, comments ...interface{}) { } 197 | func (self *_NullAsserter) AssertThat(value interface{}, matcher *base.Matcher) { } 198 | func (self *_NullAsserter) AssertTrue(value bool, comments ...interface{}) { } 199 | func (self *_NullAsserter) AssertFalse(value bool, comments ...interface{}) { } 200 | func (self *_NullAsserter) AssertNil(value interface{}, comments ...interface{}) { } 201 | func (self *_NullAsserter) AssertNonNil(value interface{}, comments ...interface{}) { } 202 | 203 | type _Asserter struct { 204 | logger Logger 205 | } 206 | 207 | func (self *_Asserter) Fail() { 208 | self.logger.Fail() 209 | } 210 | 211 | func (self *_Asserter) FailNow() { 212 | self.logger.FailNow() 213 | } 214 | 215 | func (self *_Asserter) Failed() bool { 216 | return self.logger.Failed() 217 | } 218 | 219 | func safeMatch(value interface{}, matcher *base.Matcher) (result *base.Result) { 220 | defer func() { 221 | if x := recover(); x != nil { 222 | result = base.NewResultf(false, "Panic: %v", x). 223 | WithMatcherAndValue(matcher, value) 224 | } 225 | }() 226 | result = matcher.Match(value) 227 | return 228 | } 229 | 230 | 231 | // Insert final newline if needed and indent tabs after internal newlines. 232 | func (self *_Asserter) _LogResult(indent string, result *base.Result) { 233 | value := result.Value() 234 | logger := self.logger 235 | if result.Matched() { 236 | logger.Logf("%vMATCHED input: %v\n", indent, value) 237 | } else { 238 | logger.Logf("%vDID NOT MATCH input: %v\n", indent, value) 239 | } 240 | detailsIndent := indent + "\t" 241 | matcher := result.Matcher() 242 | if matcher != nil { 243 | logger.Logf("%vMatcher: %v\n", detailsIndent, matcher) 244 | } 245 | logger.Logf("%vBecause: %v\n", detailsIndent, result) 246 | if matcher != nil { 247 | for _, comment := range matcher.Comments() { 248 | logger.Logf("%vComment: %v\n", detailsIndent, comment) 249 | } 250 | if causes := result.Causes(); len(causes) > 0 { 251 | if len(causes) == 1 { 252 | logger.Logf("%vCauses: (1 cause)\n", detailsIndent) 253 | } else { 254 | logger.Logf("%vCauses: (%v causes)\n", detailsIndent, len(causes)) 255 | } 256 | for _, cause := range result.Causes() { 257 | self._LogResult(detailsIndent, cause) 258 | } 259 | } 260 | switch w := self.logger.(type) { 261 | case _Flusher1: w.Flush() 262 | case _Flusher2: w.Flush() 263 | } 264 | } 265 | } 266 | 267 | func (self *_Asserter) LogResult(result *base.Result) { 268 | self._LogResult("", result) 269 | } 270 | 271 | func (self *_Asserter) LogWhen(value interface{}, matcher *base.Matcher) { 272 | if result := safeMatch(value, matcher); result.Matched() { 273 | self.LogResult(result) 274 | } 275 | } 276 | 277 | func (self *_Asserter) LogUnless(value interface{}, matcher *base.Matcher) { 278 | if result := safeMatch(value, matcher); !result.Matched() { 279 | self.LogResult(result) 280 | } 281 | } 282 | 283 | func (self *_Asserter) FailWhen(value interface{}, matcher *base.Matcher) { 284 | if result := safeMatch(value, matcher); result.Matched() { 285 | self.LogResult(result) 286 | self.Fail() 287 | } 288 | } 289 | 290 | func (self *_Asserter) FailUnless(value interface{}, matcher *base.Matcher) { 291 | if result := safeMatch(value, matcher); !result.Matched() { 292 | self.LogResult(result) 293 | self.Fail() 294 | } 295 | } 296 | 297 | func (self *_Asserter) FailNowWhen(value interface{}, matcher *base.Matcher) { 298 | if result := safeMatch(value, matcher); result.Matched() { 299 | self.LogResult(result) 300 | self.FailNow() 301 | } 302 | } 303 | func (self *_Asserter) FailNowUnless(value interface{}, matcher *base.Matcher) { 304 | if result := safeMatch(value, matcher); !result.Matched() { 305 | self.LogResult(result) 306 | self.FailNow() 307 | } 308 | } 309 | 310 | func (self *_Asserter) CheckThat(value interface{}, matcher *base.Matcher) { 311 | self.FailUnless(value, matcher) 312 | } 313 | 314 | func _SelfDescribing(args interface{}) base.SelfDescribing { 315 | return base.Description("%v", args) 316 | } 317 | 318 | func (self *_Asserter) CheckTrue(value bool, comments ...interface{}) { 319 | self.CheckThat(value, base.True().Comment(comments...)) 320 | } 321 | 322 | func (self *_Asserter) CheckFalse(value bool, comments ...interface{}) { 323 | self.CheckThat(value, base.False().Comment(comments...)) 324 | } 325 | 326 | func (self *_Asserter) CheckNil(value interface{}, comments ...interface{}) { 327 | self.CheckThat(value, base.Nil().Comment(comments...)) 328 | } 329 | 330 | func (self *_Asserter) CheckNonNil(value interface{}, comments ...interface{}) { 331 | self.CheckThat(value, base.NonNil().Comment(comments...)) 332 | } 333 | 334 | func (self *_Asserter) AssertThat(value interface{}, matcher *base.Matcher) { 335 | self.FailNowUnless(value, matcher) 336 | } 337 | 338 | func (self *_Asserter) AssertTrue(value bool, comments ...interface{}) { 339 | self.AssertThat(value, base.True().Comment(comments...)) 340 | } 341 | 342 | func (self *_Asserter) AssertFalse(value bool, comments ...interface{}) { 343 | self.AssertThat(value, base.False().Comment(comments...)) 344 | } 345 | 346 | func (self *_Asserter) AssertNil(value interface{}, comments ...interface{}) { 347 | self.AssertThat(value, base.Nil().Comment(comments...)) 348 | } 349 | 350 | func (self *_Asserter) AssertNonNil(value interface{}, comments ...interface{}) { 351 | self.AssertThat(value, base.NonNil().Comment(comments...)) 352 | } 353 | -------------------------------------------------------------------------------- /asserter/asserter_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package asserter 6 | 7 | import ( 8 | "bytes" 9 | "strings" 10 | "testing" 11 | "github.com/rdrdr/hamcrest/base" 12 | ) 13 | 14 | func newBuffer() *bytes.Buffer{ 15 | return bytes.NewBuffer(make([]byte, 0, 1000)) 16 | } 17 | 18 | func checkResultIsMatching(t *testing.T, result *base.Result, message string) { 19 | if !result.Matched() { 20 | t.Errorf("Expected matching result, was [%v] %v", result, message) 21 | } 22 | } 23 | 24 | func checkResultIsNonMatching(t *testing.T, result *base.Result, message string) { 25 | if result.Matched() { 26 | t.Errorf("Expected non-matching result, was [%v] %v", result, message) 27 | } 28 | } 29 | 30 | func checkBufferIsEmpty(t *testing.T, buffer *bytes.Buffer) { 31 | if buffer.Len() > 0 { 32 | t.Errorf("Should not have written to buffer, was (len: %v):\n%v", 33 | buffer.Len(), buffer.String()) 34 | } 35 | } 36 | 37 | func checkAsserterFailed(t *testing.T, asserter Asserter) { 38 | if !asserter.Failed() { 39 | t.Errorf("Should have failed") 40 | } 41 | } 42 | 43 | func checkAsserterDidNotFail(t *testing.T, asserter Asserter) { 44 | if asserter.Failed() { 45 | t.Errorf("Should not have failed") 46 | } 47 | } 48 | 49 | func checkBufferContainsStrings( 50 | t *testing.T, buffer *bytes.Buffer, pieces...string) { 51 | src := buffer.String() 52 | for _, piece := range pieces { 53 | if !strings.Contains(src, piece) { 54 | t.Errorf("Expected string to contain [%v], was [%v]", piece, src) 55 | } 56 | } 57 | } 58 | 59 | func checkBufferContainsMatchingStrings(t *testing.T, buffer *bytes.Buffer) { 60 | checkBufferContainsStrings(t, buffer, 61 | MATCHING_VALUE, MATCHING_RESULT, MATCHER_DESCRIPTION) 62 | checkBufferContainsStrings(t, buffer, MATCHER_COMMENTS...) 63 | } 64 | 65 | func checkBufferContainsNonMatchingStrings(t *testing.T, buffer *bytes.Buffer) { 66 | checkBufferContainsStrings(t, buffer, 67 | NONMATCHING_VALUE, NONMATCHING_RESULT, MATCHER_DESCRIPTION) 68 | checkBufferContainsStrings(t, buffer, MATCHER_COMMENTS...) 69 | } 70 | 71 | // Sample matcher and values for tests below 72 | var MATCHING_VALUE = "expected_value" 73 | var NONMATCHING_VALUE = "different_value" 74 | var MATCHING_RESULT = "was_matching" 75 | var NONMATCHING_RESULT = "was_nonmatching" 76 | var MATCHER_DESCRIPTION = "matcher_message" 77 | var MATCHER_COMMENT1 = "matcher_message_1_with_%v" // catch accidental expansion 78 | var MATCHER_COMMENT2 = 2 79 | var MATCHER_COMMENTS = []string{ MATCHER_COMMENT1, "2" } 80 | var MATCHER = base.NewMatcherf( 81 | func (actual interface{}) *base.Result { 82 | if actual == MATCHING_VALUE { 83 | return base.NewResultf(true, MATCHING_RESULT) 84 | } 85 | return base.NewResultf(false, NONMATCHING_RESULT) 86 | }, MATCHER_DESCRIPTION).Comment(MATCHER_COMMENT1, MATCHER_COMMENT2) 87 | 88 | 89 | func Test_LogResult(t *testing.T) { 90 | comment := "pithy comment" 91 | for _, matched := range []bool{true, false} { 92 | buffer := newBuffer() 93 | asserter := UsingWriter(buffer) 94 | result := base.NewResultf(matched, comment) 95 | asserter.LogResult(result) 96 | checkBufferContainsStrings(t, buffer, comment) 97 | } 98 | } 99 | 100 | func Test_LogWhen_onNonMatchingResult(t *testing.T) { 101 | buffer := newBuffer() 102 | asserter := UsingWriter(buffer) 103 | asserter.LogWhen(NONMATCHING_VALUE, MATCHER) 104 | checkBufferIsEmpty(t, buffer) 105 | } 106 | 107 | func Test_LogWhen_onMatchingResult(t *testing.T) { 108 | buffer := newBuffer() 109 | asserter := UsingWriter(buffer) 110 | asserter.LogWhen(MATCHING_VALUE, MATCHER) 111 | checkBufferContainsMatchingStrings(t, buffer) 112 | } 113 | 114 | func Test_LogUnless_onMatchingResult(t *testing.T) { 115 | buffer := newBuffer() 116 | asserter := UsingWriter(buffer) 117 | asserter.LogUnless(MATCHING_VALUE, MATCHER) 118 | checkBufferIsEmpty(t, buffer) 119 | } 120 | 121 | func Test_LogUnless_onNonMatchingResult(t *testing.T) { 122 | buffer := newBuffer() 123 | asserter := UsingWriter(buffer) 124 | asserter.LogUnless(NONMATCHING_VALUE, MATCHER) 125 | checkBufferContainsNonMatchingStrings(t, buffer) 126 | 127 | } 128 | 129 | func Test_FailWhen_onNonMatchingResult(t *testing.T) { 130 | buffer := newBuffer() 131 | asserter := UsingWriter(buffer) 132 | asserter.FailWhen(false, base.True()) 133 | checkBufferIsEmpty(t, buffer) 134 | checkAsserterDidNotFail(t, asserter) 135 | } 136 | func Test_FailWhen_onMatchingResult(t *testing.T) { 137 | buffer := newBuffer() 138 | asserter := UsingWriter(buffer) 139 | asserter.FailWhen(MATCHING_VALUE, MATCHER) 140 | checkBufferContainsMatchingStrings(t, buffer) 141 | checkAsserterFailed(t, asserter) 142 | } 143 | 144 | func Test_FailUnless_onMatchingResult(t *testing.T) { 145 | buffer := newBuffer() 146 | asserter := UsingWriter(buffer) 147 | asserter.FailUnless(MATCHING_VALUE, MATCHER) 148 | checkBufferIsEmpty(t, buffer) 149 | checkAsserterDidNotFail(t, asserter) 150 | } 151 | func Test_FailUnless_onNonMatchingResult(t *testing.T) { 152 | buffer := newBuffer() 153 | asserter := UsingWriter(buffer) 154 | asserter.FailUnless(NONMATCHING_VALUE, MATCHER) 155 | checkBufferContainsNonMatchingStrings(t, buffer) 156 | checkAsserterFailed(t, asserter) 157 | } 158 | 159 | 160 | func Test_FailNowWhen_onNonMatchingResult(t *testing.T) { 161 | buffer := newBuffer() 162 | calledFailNow := false 163 | asserter := UsingWriterAndFailNow(buffer, func() { calledFailNow = true}) 164 | asserter.FailNowWhen(NONMATCHING_VALUE, MATCHER) 165 | checkBufferIsEmpty(t, buffer) 166 | checkAsserterDidNotFail(t, asserter) 167 | if calledFailNow { 168 | t.Error("Should not have called failNow") 169 | } 170 | } 171 | func Test_FailNowWhen_onMatchingResult(t *testing.T) { 172 | buffer := newBuffer() 173 | calledFailNow := false 174 | asserter := UsingWriterAndFailNow(buffer, func() { calledFailNow = true}) 175 | asserter.FailNowWhen(MATCHING_VALUE, MATCHER) 176 | checkBufferContainsMatchingStrings(t, buffer) 177 | checkAsserterFailed(t, asserter) 178 | if !calledFailNow { 179 | t.Error("Should have called failNow") 180 | } 181 | } 182 | 183 | func Test_FailNowUnless_onMatchingResult(t *testing.T) { 184 | buffer := newBuffer() 185 | calledFailNow := false 186 | asserter := UsingWriterAndFailNow(buffer, func() { calledFailNow = true}) 187 | asserter.FailNowUnless(MATCHING_VALUE, MATCHER) 188 | checkBufferIsEmpty(t, buffer) 189 | checkAsserterDidNotFail(t, asserter) 190 | if calledFailNow { 191 | t.Error("Should not have called failNow") 192 | } 193 | } 194 | func Test_FailNowUnless_onNonMatchingResult(t *testing.T) { 195 | buffer := newBuffer() 196 | calledFailNow := false 197 | asserter := UsingWriterAndFailNow(buffer, func() { calledFailNow = true}) 198 | asserter.FailNowUnless(NONMATCHING_VALUE, MATCHER) 199 | checkBufferContainsNonMatchingStrings(t, buffer) 200 | checkAsserterFailed(t, asserter) 201 | if !calledFailNow { 202 | t.Error("Should have called failNow") 203 | } 204 | } 205 | 206 | func Test_CheckThat_onMatchingResult(t *testing.T) { 207 | buffer := newBuffer() 208 | calledFailNow := false 209 | asserter := UsingWriterAndFailNow(buffer, func() { calledFailNow = true} ) 210 | asserter.CheckThat(MATCHING_VALUE, MATCHER) 211 | checkBufferIsEmpty(t, buffer) 212 | checkAsserterDidNotFail(t, asserter) 213 | if calledFailNow { 214 | t.Error("Should not have called failNow") 215 | } 216 | } 217 | 218 | func Test_CheckThat_onNonMatchingResult(t *testing.T) { 219 | buffer := newBuffer() 220 | calledFailNow := false 221 | asserter := UsingWriterAndFailNow(buffer, func() { calledFailNow = true} ) 222 | asserter.CheckThat(NONMATCHING_VALUE, MATCHER) 223 | checkBufferContainsNonMatchingStrings(t, buffer) 224 | checkAsserterFailed(t, asserter) 225 | if calledFailNow { 226 | t.Error("Should not have called failNow") 227 | } 228 | } 229 | 230 | func Test_AssertThat(t *testing.T) { 231 | buffer := newBuffer() 232 | calledFailNow := false 233 | asserter := UsingWriterAndFailNow(buffer, func() { calledFailNow = true} ) 234 | asserter.AssertThat(NONMATCHING_VALUE, MATCHER) 235 | checkBufferContainsNonMatchingStrings(t, buffer) 236 | checkAsserterFailed(t, asserter) 237 | if !calledFailNow { 238 | t.Error("Should have called failNow") 239 | } 240 | } 241 | 242 | func Test_NullAsserter(t *testing.T) { 243 | asserter := ThatDoesNothing() 244 | snooped := false 245 | snoopMatcher := base.NewMatcherf(func(v interface{}) *base.Result { 246 | snooped = true 247 | return base.NewResultf(true, "snooped!") 248 | }, "Snoop") 249 | asserter.AssertThat("x", snoopMatcher) 250 | if snooped { 251 | t.Fatal("Calling AssertThat() should not invoke matcher!") 252 | } 253 | asserter.AssertTrue(false, "Should ignore attempts to AssertTrue") 254 | asserter.AssertFalse(true, "Should ignore attempts to AssertFalse") 255 | asserter.AssertNil("ha!", "Should ignore attempts to AssertNil") 256 | asserter.AssertNonNil(nil, "Should ignore attempts to AssertNonNil") 257 | } -------------------------------------------------------------------------------- /base/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Mick Killianey. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | include $(GOROOT)/src/Make.inc 6 | 7 | TARG=github.com/rdrdr/hamcrest/base 8 | GOFILES=\ 9 | comparison.go \ 10 | defs.go \ 11 | matchers.go \ 12 | 13 | include $(GOROOT)/src/Make.pkg 14 | 15 | -------------------------------------------------------------------------------- /base/comparison.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package base 6 | 7 | import ( 8 | "reflect" 9 | ) 10 | 11 | 12 | type _Comparison int8 13 | 14 | const ( 15 | _LESS_THAN = _Comparison(iota) 16 | _ORDERED_EQUAL_TO 17 | _GREATER_THAN 18 | _UNORDERED_EQUAL_TO 19 | _UNORDERED_NOT_EQUAL_TO 20 | _INCOMPARABLE_TYPES 21 | ) 22 | 23 | func (c _Comparison) _Describe(x, y interface{}) SelfDescribing { 24 | switch c { 25 | case _LESS_THAN: 26 | return Description("%v was less than %v", x, y) 27 | case _ORDERED_EQUAL_TO: 28 | return Description("%v was equal to %v", x, y) 29 | case _GREATER_THAN: 30 | return Description("%v was greater than %v", x, y) 31 | case _UNORDERED_EQUAL_TO: 32 | return Description("%v was (unordered) equal to %v", x, y) 33 | case _UNORDERED_NOT_EQUAL_TO: 34 | return Description("%v was (unordered) not equal to %v", x, y) 35 | case _INCOMPARABLE_TYPES: 36 | return Description("types %T and %T cannot be compared", x, y) 37 | } 38 | return Description("Unrecognized %v on %v and %v",int8(c), x, y) 39 | } 40 | 41 | // All the messiness of determining whether or not two objects 42 | // can be compared (and if they can be, what the result is). 43 | func _Compare(x interface{}, y interface{}) _Comparison { 44 | switch i := x.(type) { 45 | case int: 46 | switch j := y.(type) { 47 | case int: 48 | if i < j { return _LESS_THAN 49 | } else if i > j { return _GREATER_THAN 50 | } else { return _ORDERED_EQUAL_TO 51 | } 52 | default: return _INCOMPARABLE_TYPES 53 | } 54 | case int8: 55 | switch j := y.(type) { 56 | case int8: 57 | if i < j { return _LESS_THAN 58 | } else if i > j { return _GREATER_THAN 59 | } else { return _ORDERED_EQUAL_TO 60 | } 61 | default: return _INCOMPARABLE_TYPES 62 | } 63 | case int16: 64 | switch j := y.(type) { 65 | case int16: 66 | if i < j { return _LESS_THAN 67 | } else if i > j { return _GREATER_THAN 68 | } else { return _ORDERED_EQUAL_TO 69 | } 70 | default: return _INCOMPARABLE_TYPES 71 | } 72 | case int32: 73 | switch j := y.(type) { 74 | case int32: 75 | if i < j { return _LESS_THAN 76 | } else if i > j { return _GREATER_THAN 77 | } else { return _ORDERED_EQUAL_TO 78 | } 79 | default: return _INCOMPARABLE_TYPES 80 | } 81 | case int64: 82 | switch j := y.(type) { 83 | case int64: 84 | if i < j { return _LESS_THAN 85 | } else if i > j { return _GREATER_THAN 86 | } else { return _ORDERED_EQUAL_TO 87 | } 88 | default: return _INCOMPARABLE_TYPES 89 | } 90 | case uint: 91 | switch j := y.(type) { 92 | case uint: 93 | if i < j { return _LESS_THAN 94 | } else if i > j { return _GREATER_THAN 95 | } else { return _ORDERED_EQUAL_TO 96 | } 97 | default: return _INCOMPARABLE_TYPES 98 | } 99 | case uint8: 100 | switch j := y.(type) { 101 | case uint8: 102 | if i < j { return _LESS_THAN 103 | } else if i > j { return _GREATER_THAN 104 | } else { return _ORDERED_EQUAL_TO 105 | } 106 | default: return _INCOMPARABLE_TYPES 107 | } 108 | case uint16: 109 | switch j := y.(type) { 110 | case uint16: 111 | if i < j { return _LESS_THAN 112 | } else if i > j { return _GREATER_THAN 113 | } else { return _ORDERED_EQUAL_TO 114 | } 115 | default: return _INCOMPARABLE_TYPES 116 | } 117 | case uint32: 118 | switch j := y.(type) { 119 | case uint32: 120 | if i < j { return _LESS_THAN 121 | } else if i > j { return _GREATER_THAN 122 | } else { return _ORDERED_EQUAL_TO 123 | } 124 | default: return _INCOMPARABLE_TYPES 125 | } 126 | case uint64: 127 | switch j := y.(type) { 128 | case uint64: 129 | if i < j { return _LESS_THAN 130 | } else if i > j { return _GREATER_THAN 131 | } else { return _ORDERED_EQUAL_TO 132 | } 133 | default: return _INCOMPARABLE_TYPES 134 | } 135 | case float32: 136 | switch j := y.(type) { 137 | case float32: 138 | if i < j { return _LESS_THAN 139 | } else if i > j { return _GREATER_THAN 140 | } else if i == j { return _ORDERED_EQUAL_TO 141 | } else { return _UNORDERED_NOT_EQUAL_TO 142 | } 143 | default: return _INCOMPARABLE_TYPES 144 | } 145 | case float64: 146 | switch j := y.(type) { 147 | case float64: 148 | if i < j { return _LESS_THAN 149 | } else if i > j { return _GREATER_THAN 150 | } else if i == j { return _ORDERED_EQUAL_TO 151 | } else { return _UNORDERED_NOT_EQUAL_TO 152 | } 153 | default: return _INCOMPARABLE_TYPES 154 | } 155 | case string: 156 | switch j := y.(type) { 157 | case string: 158 | if i < j { return _LESS_THAN 159 | } else if i > j { return _GREATER_THAN 160 | } else if i == j { return _ORDERED_EQUAL_TO 161 | } else { return _UNORDERED_NOT_EQUAL_TO 162 | } 163 | } 164 | default: 165 | if reflect.Typeof(x) == reflect.Typeof(y) { 166 | if x == y { 167 | return _UNORDERED_EQUAL_TO 168 | } 169 | return _UNORDERED_NOT_EQUAL_TO 170 | } 171 | } 172 | return _INCOMPARABLE_TYPES 173 | } 174 | 175 | // Returns a matcher that matches values that are greater-than the given 176 | // expected value, using the greater-than (<) operator. 177 | func GreaterThan(expected interface{}) *Matcher { 178 | match := func(actual interface{}) *Result { 179 | c := _Compare(actual, expected) 180 | switch c { 181 | case _GREATER_THAN: 182 | return NewResult(true, c._Describe(actual, expected)) 183 | default: 184 | return NewResult(false, c._Describe(actual, expected)) 185 | } 186 | panic("every case should have a return") 187 | } 188 | return NewMatcherf(match, "GreaterThan(%v)", expected) 189 | } 190 | 191 | // Returns a matcher that matches values that are greater-than-or-equal-to 192 | // the given expected value, using the greater-than-or-equal-to (>=) operator. 193 | func GreaterThanOrEqualTo(expected interface{}) *Matcher { 194 | match := func(actual interface{}) *Result { 195 | c := _Compare(actual, expected) 196 | switch c { 197 | case _GREATER_THAN, _ORDERED_EQUAL_TO: 198 | return NewResult(true, c._Describe(actual, expected)) 199 | default: 200 | return NewResult(false, c._Describe(actual, expected)) 201 | } 202 | panic("every case should have a return") 203 | } 204 | return NewMatcherf(match, "GreaterThanOrEqualTo(%v)", expected) 205 | } 206 | 207 | // Returns a matcher that matches values that are less-than the given 208 | // expected value, using the less-than (<) operator. 209 | func LessThan(expected interface{}) *Matcher { 210 | match := func(actual interface{}) *Result { 211 | c := _Compare(actual, expected) 212 | switch c { 213 | case _LESS_THAN: 214 | return NewResult(true, c._Describe(actual, expected)) 215 | default: 216 | return NewResult(false, c._Describe(actual, expected)) 217 | } 218 | panic("every case should have a return") 219 | } 220 | return NewMatcherf(match, "LessThan(%v)", expected) 221 | } 222 | 223 | // Returns a matcher that matches values that are less-than-or-equal-to 224 | // the given expected value, using the less-than-or-equal-to (<=) operator. 225 | func LessThanOrEqualTo(expected interface{}) *Matcher { 226 | match := func(actual interface{}) *Result { 227 | c := _Compare(actual, expected) 228 | switch c { 229 | case _LESS_THAN, _ORDERED_EQUAL_TO: 230 | return NewResult(true, c._Describe(actual, expected)) 231 | default: 232 | return NewResult(false, c._Describe(actual, expected)) 233 | } 234 | panic("every case should have a return") 235 | } 236 | return NewMatcherf(match, "LessThanOrEqualTo(%v)", expected) 237 | } 238 | 239 | // Returns a matcher that matches values that are equal to the 240 | // given expected value, using the equality (==) operator. 241 | func EqualTo(expected interface{}) *Matcher { 242 | match := func(actual interface{}) *Result { 243 | c := _Compare(actual, expected) 244 | switch c { 245 | case _ORDERED_EQUAL_TO, _UNORDERED_EQUAL_TO: 246 | return NewResult(true, c._Describe(actual, expected)) 247 | default: 248 | return NewResult(false, c._Describe(actual, expected)) 249 | } 250 | panic("every case should have a return") 251 | } 252 | return NewMatcherf(match, "EqualTo(%v)", expected) 253 | } 254 | 255 | // Returns a matcher that matches values that are not equal to the 256 | // given expected value, using the inequality (!=) operator. 257 | func NotEqualTo(expected interface{}) *Matcher { 258 | match := func(actual interface{}) *Result { 259 | c := _Compare(actual, expected) 260 | switch c { 261 | case _ORDERED_EQUAL_TO, _UNORDERED_EQUAL_TO: 262 | return NewResult(false, c._Describe(actual, expected)) 263 | default: 264 | return NewResult(true, c._Describe(actual, expected)) 265 | } 266 | panic("every case should have a return") 267 | } 268 | return NewMatcherf(match, "NotEqualTo(%v)", expected) 269 | } 270 | 271 | -------------------------------------------------------------------------------- /base/defs.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package base 6 | 7 | import ( 8 | "fmt" 9 | "reflect" 10 | ) 11 | 12 | // -------------------------------------------------------------------- 13 | // Description 14 | // -------------------------------------------------------------------- 15 | 16 | // Hamcrest descriptions implement both fmt.Stringer and fmt.Formatter. 17 | type SelfDescribing interface { 18 | fmt.Formatter 19 | fmt.Stringer 20 | } 21 | 22 | type _Description struct { 23 | format string 24 | args []interface{} 25 | } 26 | 27 | // Implements fmt.Formatter. 28 | func (self *_Description) Format(s fmt.State, ch int) { 29 | fmt.Fprintf(s, self.format, self.args...) 30 | } 31 | 32 | // Implements fmt.Stringer. 33 | func (self *_Description) String() string { 34 | return fmt.Sprintf(self.format, self.args...) 35 | } 36 | 37 | 38 | // Creates an object that implements fmt.Formatter and fmt.Stringer using 39 | // args with the same meanings as fmt.Fprintf. Note that this object 40 | // stores its given parameters and evaluates them lazily. 41 | func Description(format string, args...interface{}) SelfDescribing { 42 | return &_Description{format:format, args:args} 43 | } 44 | 45 | 46 | // -------------------------------------------------------------------- 47 | // Result 48 | // -------------------------------------------------------------------- 49 | 50 | // Self-describing result of applying a Matcher to an input value. 51 | type Result struct { 52 | description SelfDescribing 53 | matched bool 54 | value interface{} 55 | matcher *Matcher 56 | causes []*Result 57 | } 58 | // Creates a new Result using the given description. 59 | func NewResult(matched bool, description SelfDescribing) *Result { 60 | return &Result{ matched: matched, description: description } 61 | } 62 | 63 | // Creates a new Result using the given format/args as a description. 64 | func NewResultf(matched bool, format string, args...interface{}) *Result { 65 | return NewResult(matched, Description(format, args...)) 66 | } 67 | 68 | // Returns true if the Match was successful. 69 | func (self *Result) Matched() bool { 70 | return self.matched 71 | } 72 | 73 | // Returns the Matcher that produced this Result, or nil if this Result 74 | // was not generated by a Matcher. 75 | func (self *Result) Matcher() *Matcher { 76 | return self.matcher 77 | } 78 | 79 | // Returns the value that was given to the Matcher to produce this Result. 80 | // 81 | // Note: If `Matcher()` returns nil, then this will also return nil. 82 | func (self *Result) Value() interface{} { 83 | return self.value 84 | } 85 | 86 | // Implements fmt.Stringer. 87 | func (self *Result) String() string { 88 | if self == nil { 89 | return "" 90 | } 91 | return self.description.String() 92 | } 93 | 94 | // Implements fmt.Formatter. 95 | func (self *Result) Format(s fmt.State, ch int) { 96 | if self == nil { 97 | fmt.Fprintf(s, self.String()) 98 | } else { 99 | self.description.Format(s, ch) 100 | } 101 | } 102 | 103 | // Returns a slice of sub-Results that caused this Result to 104 | // either match or not match. 105 | func (self *Result) Causes() []*Result { 106 | if self.causes == nil { 107 | return nil 108 | } 109 | causes := make([]*Result, len(self.causes)) 110 | copy(causes, self.causes) 111 | return causes 112 | } 113 | 114 | // Returns a new Result, identical to this one, except with 115 | // the given causes. 116 | func (self *Result) WithCauses(causes... *Result) *Result { 117 | return &Result{ 118 | matched:self.matched, 119 | description:self.description, 120 | matcher:self.matcher, 121 | value:self.value, 122 | causes:causes} 123 | } 124 | 125 | // Returns a new Result, identical to this one, except with 126 | // the given matcher and value. 127 | func (self *Result) WithMatcherAndValue(matcher *Matcher, value interface{}) *Result { 128 | if matcher == nil && value != nil { 129 | panic("Cannot create a Result with no Matcher but a non-nil value...") 130 | } 131 | return &Result{ 132 | matched:self.matched, 133 | description:self.description, 134 | matcher:matcher, 135 | value:value, 136 | causes:self.Causes()} 137 | } 138 | 139 | // -------------------------------------------------------------------- 140 | // Matcher 141 | // -------------------------------------------------------------------- 142 | 143 | // Self-describing criteria that may match (or not match) an input value. 144 | // Creators of new matchers are *strongly* encouraged not to implement 145 | // Matcher directly, but to create new matchers using the NewMatcher 146 | // factory function. 147 | type Matcher struct { 148 | description SelfDescribing 149 | match func(v interface{}) *Result 150 | comments []SelfDescribing 151 | } 152 | 153 | // Creates a new Matcher using the given matching function, with the 154 | // given description. 155 | // 156 | // Matching functions must have exactly one input parameter. Matching 157 | // functions must return a *Result or a bool as its first output value. 158 | // If the first output value is a *Result, that must be its only output 159 | // value. If the first output value is bool, then that value is used 160 | // for Result.Matched(), and if present, any second output value is used 161 | // as the result description. For example, the following signatures are 162 | // all legal matcher functions: 163 | // 164 | // func(interface{}) *Result 165 | // func(interface{}) bool 166 | // func(interface{}) (bool, os.Error) 167 | // func(string) *Result 168 | // func(...*int) bool 169 | // func(...io.Reader) (bool os.Error) 170 | func NewMatcher(fn interface{}, description SelfDescribing) *Matcher { 171 | match := normalizeMatchFunction(fn) 172 | return &Matcher{ match: match, description: description } 173 | } 174 | 175 | // Creates a new Matcher using the given matching function, with the 176 | // given format/args as a description. 177 | func NewMatcherf(fn interface{}, format string, args...interface{}) *Matcher { 178 | match := normalizeMatchFunction(fn) 179 | return NewMatcher(match, Description(format, args...)) 180 | } 181 | 182 | func normalizeMatchFunction(fn interface{}) func(interface{}) *Result { 183 | if match, ok := fn.(func(interface{}) *Result); ok { 184 | return match 185 | } 186 | if funcValue, ok := reflect.NewValue(fn).(*reflect.FuncValue); ok { 187 | funcType := funcValue.Type().(*reflect.FuncType) 188 | numIn := funcType.NumIn() 189 | numOut := funcType.NumOut() 190 | var constructInputValues func(actual interface{}) ([]reflect.Value, interface{}) 191 | if numIn == 1 { 192 | constructInputValues = func(actual interface{}) (values []reflect.Value, err interface{}) { 193 | defer func() { 194 | err = recover() 195 | }() 196 | actualValue := reflect.NewValue(actual) 197 | inType := funcType.In(0) 198 | if funcType.DotDotDot() { 199 | sliceValue := reflect.MakeSlice(inType.(*reflect.SliceType), 1, 1) 200 | inputValue := sliceValue.Elem(0) 201 | inputValue.SetValue(actualValue) 202 | values = []reflect.Value{ sliceValue } 203 | } else { 204 | inputValue := reflect.MakeZero(inType) 205 | inputValue.SetValue(actualValue) 206 | values = []reflect.Value{ inputValue } 207 | } 208 | return 209 | } 210 | } else { 211 | reason := fmt.Sprintf("Can't use %T as a matcher: must have one input, had %v", 212 | fn, numIn) 213 | panic(reason) 214 | } 215 | outType0 := funcType.Out(0) 216 | var resultType = reflect.Typeof(&Result{}) 217 | var boolType = reflect.Typeof(true) 218 | var interpretOutputValues func(values []reflect.Value) *Result 219 | if numOut == 1 && outType0 == resultType { 220 | interpretOutputValues = func(values []reflect.Value) (result *Result) { 221 | defer func() { 222 | if err := recover(); err != nil { 223 | result = NewResultf(false, 224 | "Error: expected *Result from %T, got %v", fn, values) 225 | } 226 | }() 227 | result = values[0].Interface().(*Result) 228 | return 229 | } 230 | } else if outType0 == boolType && (numOut == 1 || numOut == 2) { 231 | interpretOutputValues = func(values []reflect.Value) (result *Result) { 232 | defer func() { 233 | if err := recover(); err != nil { 234 | result = NewResultf(false, 235 | "Error: expected bool from %T, got %v", fn, values) 236 | } 237 | }() 238 | b := values[0].Interface().(bool) 239 | if len(values) > 1 { 240 | result = NewResultf(b, "%v", values[1].Interface()) 241 | } else if b { 242 | result = NewResultf(true, "Matched") 243 | } else { 244 | result = NewResultf(false, "Did not match") 245 | } 246 | return 247 | } 248 | } else { 249 | panic(fmt.Sprintf("Can't use %T as a matcher function", fn)) 250 | } 251 | return func(actual interface{}) *Result { 252 | inputValues, problem := constructInputValues(actual) 253 | if problem != nil { 254 | return NewResultf(false, "Could not apply %T to input of type %T: %v", 255 | fn, actual, problem) 256 | } 257 | outputValues := funcValue.Call(inputValues) 258 | return interpretOutputValues(outputValues) 259 | } 260 | 261 | } 262 | return nil 263 | } 264 | 265 | // Implementation of SelfDescribing: fmt.Formatter. 266 | func (self *Matcher) Format(s fmt.State, ch int) { 267 | if self == nil { 268 | fmt.Fprintf(s, "") 269 | } else { 270 | self.description.Format(s, ch) 271 | } 272 | } 273 | 274 | // Implementation of SelfDescribing: fmt.Stringer. 275 | func (self *Matcher) String() string { 276 | if self == nil { 277 | return "" 278 | } 279 | return self.description.String() 280 | } 281 | 282 | // Tests the given input value to see if it meets this Matcher's criteria. 283 | func (self *Matcher) Match(value interface{}) *Result { 284 | result := self.match(value) 285 | result.matcher = self 286 | result.value = value 287 | return result 288 | } 289 | 290 | // Returns a slice of messages that supplement the description. 291 | func (self *Matcher) Comments() []SelfDescribing { 292 | comments := make([]SelfDescribing, len(self.comments)) 293 | copy(comments, self.comments) 294 | return comments 295 | } 296 | 297 | // Returns a *new* Matcher similar to this one, but with the 298 | // given additional comment. 299 | func (self *Matcher) Comment(comments...interface{}) *Matcher { 300 | all := make([]SelfDescribing, 0, len(self.comments) + len(comments)) 301 | copy(all, self.comments) 302 | for _, comment := range comments { 303 | selfDescribing, ok := comment.(SelfDescribing) 304 | if !ok { 305 | selfDescribing = Description("%v", comment) 306 | } 307 | all = append(all, selfDescribing) 308 | } 309 | return &Matcher{description:self.description, match:self.match, comments:all} 310 | } 311 | 312 | // Returns a *new* Matcher similar to this one, but with the 313 | // given additional format/args as a comment. 314 | func (self *Matcher) Commentf(format string, args...interface{}) *Matcher { 315 | all := make([]SelfDescribing, 0, len(self.comments) + 1) 316 | copy(all, self.comments) 317 | all = append(all, Description(format, args...)) 318 | return &Matcher{description:self.description, match:self.match, comments:all} 319 | } 320 | 321 | -------------------------------------------------------------------------------- /base/matcher_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package base 6 | 7 | import ( 8 | "fmt" 9 | "strings" 10 | "testing" 11 | ) 12 | 13 | func Test_Description(t *testing.T) { 14 | description := Description("%v %v", "foo", "bar") 15 | descriptionString := description.String() 16 | if descriptionString != "foo bar" { 17 | t.Errorf("Description should be 'foo bar', was %v", descriptionString) 18 | } 19 | } 20 | 21 | func attemptMatch(matcher *Matcher, input interface{}) (result *Result, err interface{}) { 22 | defer func() { 23 | if err = recover(); err != nil { 24 | result = nil 25 | } 26 | }() 27 | result = matcher.Match(input) 28 | return 29 | } 30 | 31 | func checkResultIsMatching(t *testing.T, matcher *Matcher, input interface{}, message string) *Result { 32 | result, err := attemptMatch(matcher, input) 33 | if err != nil { 34 | t.Errorf("Expected matching result from applying %v to %#v, was panic [%v]", 35 | matcher, input, err) 36 | return nil 37 | } 38 | if !result.Matched() { 39 | t.Errorf("Expected matching result from applying %v to %#v, was [%v] %v", 40 | matcher, input, result, message) 41 | } 42 | return result 43 | } 44 | 45 | func checkResultIsNonMatching(t *testing.T, matcher *Matcher, input interface{}, message string) *Result { 46 | result, err := attemptMatch(matcher, input) 47 | if err != nil { 48 | t.Errorf("Expected non-matching result from applying %v to %#v, was panic [%v]", 49 | matcher, input, err) 50 | return nil 51 | } 52 | if result.Matched() { 53 | t.Errorf("Expected non-matching result from applying %v to %#v, was [%v]. Message: %v", 54 | result.Matcher(), result.Value(), result, message) 55 | } 56 | return result 57 | } 58 | 59 | func Test_Matched(t *testing.T) { 60 | matcher := Matched() 61 | passResult := NewResultf(true, "pass") 62 | failResult := NewResultf(false, "fail") 63 | 64 | checkResultIsMatching(t, matcher, passResult, "matching") 65 | checkResultIsNonMatching(t, matcher, failResult, "non-matching") 66 | checkResultIsNonMatching(t, matcher, nil, "nil") 67 | checkResultIsNonMatching(t, matcher, "foo", "not a Result") 68 | } 69 | 70 | func Test_DidNotMatch(t *testing.T) { 71 | matcher := DidNotMatch() 72 | passResult := NewResultf(true, "pass") 73 | failResult := NewResultf(false, "fail") 74 | 75 | checkResultIsNonMatching(t, matcher, passResult, "matching") 76 | checkResultIsMatching(t, matcher, failResult, "non-matching") 77 | checkResultIsNonMatching(t, matcher, nil, "nil") 78 | checkResultIsNonMatching(t, matcher, "foo", "not a Result") 79 | } 80 | 81 | func Test_NewMatcher_Func_InterfaceIn_ResultOut(t *testing.T) { 82 | matcherName := "foo matcher" 83 | trueMessage := "bar true" 84 | falseMessage := "baz false" 85 | function := func(v interface{}) *Result { 86 | if b, ok := v.(bool); b && ok { 87 | return NewResultf(true, trueMessage) 88 | } 89 | return NewResultf(false, falseMessage) 90 | } 91 | matcher := NewMatcherf(function, matcherName) 92 | if s := fmt.Sprint(matcher); !strings.Contains(s, matcherName) { 93 | t.Fatalf("String should have contained %v, but was: %v", matcherName, s) 94 | } 95 | 96 | if result := matcher.Match(true); !result.Matched() { 97 | t.Fatalf("Result should have matched, but was: %v", result) 98 | } else if s := fmt.Sprint(result); !strings.Contains(s, trueMessage) { 99 | t.Fatalf("String should have contained %v, but was: %v", trueMessage, s) 100 | } 101 | if result := matcher.Match(false); result.Matched() { 102 | t.Fatalf("Result should not have matched, but did: %v", result) 103 | } else if s := fmt.Sprint(result); !strings.Contains(s, falseMessage) { 104 | t.Fatalf("String should have contained %v, but was: %v", falseMessage, s) 105 | } 106 | } 107 | 108 | func Test_NewMatcher_Func_StringIn_BoolOut(t *testing.T) { 109 | matcherName := "foo matcher" 110 | trueMessage := "Matched" 111 | falseMessage := "Did not match" 112 | errorMessage := "Could not apply" 113 | function := func(s string) bool { 114 | if s == "bar" { 115 | return true 116 | } 117 | return false 118 | } 119 | matcher := NewMatcherf(function, matcherName) 120 | if s := fmt.Sprint(matcher); !strings.Contains(s, matcherName) { 121 | t.Fatalf("String should have contained %v, but was: %v", matcherName, s) 122 | } 123 | 124 | if result := matcher.Match("bar"); !result.Matched() { 125 | t.Fatalf("Result should have matched, but was: %v", result) 126 | } else if s := fmt.Sprint(result); !strings.Contains(s, trueMessage) { 127 | t.Fatalf("String should have contained %v, but was: %v", trueMessage, s) 128 | } 129 | if result := matcher.Match("foo"); result.Matched() { 130 | t.Fatalf("Result should not have matched, but did: %v", result) 131 | } else if s := fmt.Sprint(result); !strings.Contains(s, falseMessage) { 132 | t.Fatalf("String should have contained %v, but was: %v", falseMessage, s) 133 | } 134 | if result := matcher.Match(39); result.Matched() { 135 | t.Fatalf("Result should not have matched, but did: %v", result) 136 | } else if s := fmt.Sprint(result); !strings.Contains(s, errorMessage) { 137 | t.Fatalf("String should have contained %v, but was: %v", errorMessage, s) 138 | } 139 | } 140 | 141 | 142 | func Test_NewMatcher_Func_StringDotDotDotIn_BoolStringOut(t *testing.T) { 143 | matcherName := "foo matcher" 144 | trueMessage := "bar true" 145 | falseMessage := "baz false" 146 | errorMessage := "Could not apply" 147 | function := func(s... string) (bool, string) { 148 | if len(s) >= 1 && s[0] == "bar" { 149 | return true, trueMessage 150 | } 151 | return false, falseMessage 152 | } 153 | matcher := NewMatcherf(function, matcherName) 154 | if s := fmt.Sprint(matcher); !strings.Contains(s, matcherName) { 155 | t.Fatalf("String should have contained %v, but was: %v", matcherName, s) 156 | } 157 | 158 | if result := matcher.Match("bar"); !result.Matched() { 159 | t.Fatalf("Result should have matched, but was: %v", result) 160 | } else if s := fmt.Sprint(result); !strings.Contains(s, trueMessage) { 161 | t.Fatalf("String should have contained %v, but was: %v", trueMessage, s) 162 | } 163 | if result := matcher.Match("foo"); result.Matched() { 164 | t.Fatalf("Result should not have matched, but did: %v", result) 165 | } else if s := fmt.Sprint(result); !strings.Contains(s, falseMessage) { 166 | t.Fatalf("String should have contained %v, but was: %v", falseMessage, s) 167 | } 168 | if result := matcher.Match(39); result.Matched() { 169 | t.Fatalf("Result should not have matched, but did: %v", result) 170 | } else if s := fmt.Sprint(result); !strings.Contains(s, errorMessage) { 171 | t.Fatalf("String should have contained %v, but was: %v", errorMessage, s) 172 | } 173 | } 174 | 175 | 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /base/matchers.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package base 6 | 7 | import ( 8 | "reflect" 9 | ) 10 | 11 | 12 | // -------------------------------------------------------------------- 13 | // Matchers 14 | // -------------------------------------------------------------------- 15 | 16 | // Returns a Matcher that matches the boolean value true. 17 | func Matched() *Matcher { 18 | return _Matched 19 | } 20 | var _Matched *Matcher // singleton 21 | func init() { 22 | match := func (actual interface{}) *Result { 23 | if result, ok := actual.(*Result); ok { 24 | if result.Matched() { 25 | return NewResultf(true, "was a matching result").WithCauses(result) 26 | } 27 | return NewResultf(false, "was a result that did not match").WithCauses(result) 28 | } 29 | return NewResultf(false, "[%v] was not a result", actual) 30 | } 31 | _Matched = NewMatcherf(match, "Matched") 32 | } 33 | 34 | // Returns a Matcher that matches the boolean value false. 35 | func DidNotMatch() *Matcher { 36 | return _DidNotMatch 37 | } 38 | var _DidNotMatch *Matcher // singleton 39 | func init() { 40 | match := func (actual interface{}) *Result { 41 | if result, ok := actual.(*Result); ok { 42 | if result.Matched() { 43 | return NewResultf(false, "was a matching result").WithCauses(result) 44 | } 45 | return NewResultf(true, "was a result that did not match").WithCauses(result) 46 | } 47 | return NewResultf(false, "[%v] was not a result", actual) 48 | } 49 | _DidNotMatch = NewMatcherf(match, "DidNotMatch") 50 | } 51 | 52 | // Returns a Matcher that matches the boolean value true. 53 | func True() *Matcher { 54 | return _True 55 | } 56 | var _True *Matcher // singleton 57 | func init() { 58 | match := func (actual interface{}) *Result { 59 | if b, ok := actual.(bool); ok { 60 | if b { 61 | return NewResultf(true, "was true") 62 | } 63 | return NewResultf(false, "was not true") 64 | } 65 | return NewResultf(false, "[%v] was not bool", actual) 66 | } 67 | _True = NewMatcherf(match, "True") 68 | } 69 | 70 | // Returns a Matcher that matches the boolean value false. 71 | func False() *Matcher { 72 | return _False 73 | } 74 | var _False *Matcher // singleton 75 | func init() { 76 | match := func (actual interface{}) *Result { 77 | if b, ok := actual.(bool); ok { 78 | if !b { 79 | return NewResultf(true, "was false") 80 | } 81 | return NewResultf(false, "was not false") 82 | } 83 | return NewResultf(false, "[%v] was not bool", actual) 84 | } 85 | _False = NewMatcherf(match, "False") 86 | } 87 | 88 | // Helper function for Nil/NonNil 89 | func _detectNil(actual interface{}) bool { 90 | if actual == nil { 91 | return true 92 | } 93 | if value, ok := reflect.NewValue(actual).(_CanAskIsNil); ok { 94 | return value.IsNil() 95 | } 96 | return false 97 | } 98 | type _CanAskIsNil interface { IsNil() bool } 99 | 100 | 101 | // Returns a Matcher that matches if the actual value is nil 102 | // or the nil value of its type. (Note that this is *not* 103 | // equivalent to DeeplyEqualTo(nil).) 104 | func Nil() *Matcher { 105 | return _Nil 106 | } 107 | var _Nil *Matcher // singleton 108 | func init() { 109 | match := func (actual interface{}) *Result { 110 | if _detectNil(actual) { 111 | return NewResultf(true, "was nil") 112 | } 113 | return NewResultf(false, "[%v] was not nil", actual) 114 | } 115 | _Nil = NewMatcherf(match, "Nil") 116 | } 117 | 118 | // Returns a Matcher that matches if the actual value is 119 | // neither nil nor the nil value of its type. (Note that 120 | // this is *not* equivalent to Not(DeeplyEqualTo(nil)).) 121 | func NonNil() *Matcher { 122 | return _NonNil 123 | } 124 | var _NonNil *Matcher 125 | func init() { 126 | match := func (actual interface{}) *Result { 127 | if _detectNil(actual) { 128 | return NewResultf(false, "was nil") 129 | } 130 | return NewResultf(true, "[%v] was not nil", actual) 131 | } 132 | _NonNil = NewMatcherf(match, "NonNil") 133 | } 134 | 135 | // Returns a Matcher that checks if the actual value is (deeply) 136 | // equal to the given expected value, using `reflect.DeepEqual`. 137 | // 138 | // For an equality test equivalent to `==`, see the 139 | // `hamcrest/comparison` package. 140 | func DeepEqualTo(expected interface{}) *Matcher { 141 | match := func (actual interface{}) *Result { 142 | if reflect.DeepEqual(expected, actual) { 143 | return NewResultf(true, 144 | "was deeply equal to [%v]", expected) 145 | } 146 | return NewResultf(false, 147 | "[%v] was not deeply equal to [%v]", actual, expected) 148 | } 149 | return NewMatcherf(match, "DeepEqualTo[%v]", expected) 150 | } 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /collections/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Mick Killianey. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | include $(GOROOT)/src/Make.inc 6 | 7 | TARG=github.com/rdrdr/hamcrest/collections 8 | GOFILES=\ 9 | collections.go\ 10 | 11 | include $(GOROOT)/src/Make.pkg 12 | -------------------------------------------------------------------------------- /collections/collections.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package collections 6 | 7 | import ( 8 | "github.com/rdrdr/hamcrest/base" 9 | "reflect" 10 | ) 11 | 12 | type _ElemAndLen interface { 13 | Elem(i int) reflect.Value 14 | Len() int 15 | } 16 | 17 | // Returns a matcher that matches on any array or slice input value 18 | // if the given matcher matches at least one element of that array 19 | // or slice. 20 | // 21 | // The returned matcher does not match any non-array-or-slice value. 22 | func AnyElement(matcher *base.Matcher) *base.Matcher { 23 | match := func(actual interface{}) *base.Result { 24 | v := reflect.NewValue(actual) 25 | if value, ok := v.(_ElemAndLen); ok { 26 | n := value.Len() 27 | for i := 0; i < n; i++ { 28 | elem := value.Elem(i).Interface() 29 | result := matcher.Match(elem) 30 | if result.Matched() { 31 | return base.NewResultf(true, 32 | "Matched element %v of %v: %v", i+1, n, elem). 33 | WithCauses(result) 34 | } 35 | } 36 | return base.NewResultf(false, 37 | "Matched none of the %v elements", n) 38 | } 39 | return matcher.Match(v) 40 | } 41 | return base.NewMatcherf(match, "AnyElement[%v]", matcher) 42 | } 43 | 44 | // Returns a matcher that matches on any array or slice input value 45 | // if the given matcher matches every element of that array or slice. 46 | // 47 | // The returned matcher does not match any non-array-or-slice value. 48 | func EveryElement(matcher *base.Matcher) *base.Matcher { 49 | match := func(actual interface{}) *base.Result { 50 | v := reflect.NewValue(actual) 51 | var value _ElemAndLen 52 | var ok bool 53 | value, ok = v.(*reflect.ArrayValue) 54 | if !ok { 55 | value, ok = v.(*reflect.SliceValue) 56 | } 57 | if !ok { 58 | return base.NewResultf(false, 59 | "Was not array or slice: was type %T", actual) 60 | } 61 | n := value.Len() 62 | for i := 0; i < n; i++ { 63 | elem := value.Elem(i).Interface() 64 | result := matcher.Match(elem) 65 | if !result.Matched() { 66 | return base.NewResultf(false, 67 | "Failed to match element %v of %v: %v", 68 | i+1, n, elem). 69 | WithCauses(result) 70 | } 71 | } 72 | return base.NewResultf(true, 73 | "Matched all of the %v elements", n) 74 | } 75 | return base.NewMatcherf(match, "EveryElement[%v]", matcher) 76 | } 77 | 78 | func AnyMapElement(matcher *base.Matcher) *base.Matcher { 79 | match := func(actual interface{}) *base.Result { 80 | v := reflect.NewValue(actual) 81 | value, ok := v.(*reflect.MapValue) 82 | if !ok { 83 | return base.NewResultf(false, 84 | "Was not map: was type %T", actual) 85 | } 86 | keys := value.Keys() 87 | for i, keyValue := range value.Keys() { 88 | elem := value.Elem(keyValue).Interface() 89 | result := matcher.Match(elem) 90 | if result.Matched() { 91 | return base.NewResultf(true, 92 | "Matched map element [%v/%v] with key [%v]: %v", 93 | i+1, len(keys), keyValue.Interface(), elem). 94 | WithCauses(result) 95 | } 96 | } 97 | return base.NewResultf(false, 98 | "Matched none of the %v elements", len(keys)) 99 | } 100 | return base.NewMatcherf(match, "AnyMapElement[%v]", matcher) 101 | } 102 | 103 | func EveryMapElement(matcher *base.Matcher) *base.Matcher { 104 | match := func(actual interface{}) *base.Result { 105 | v := reflect.NewValue(actual) 106 | value, ok := v.(*reflect.MapValue) 107 | if !ok { 108 | return base.NewResultf(false, 109 | "Was not map: was type %T", actual) 110 | } 111 | keys := value.Keys() 112 | for i, keyValue := range keys { 113 | elem := value.Elem(keyValue).Interface() 114 | result := matcher.Match(elem) 115 | if !result.Matched() { 116 | return base.NewResultf(false, 117 | "Failed to match map element [%v/%v] with key[%v]: %v", 118 | i+1, len(keys), keyValue.Interface(), elem). 119 | WithCauses(result) 120 | } 121 | } 122 | return base.NewResultf(true, 123 | "Matched all of the %v map elements", len(keys)) 124 | } 125 | return base.NewMatcherf(match, "EveryMapElement[%v]", matcher) 126 | } 127 | 128 | type _HasLen interface { Len() int } 129 | 130 | // Applies the given matcher to the length of the input element, 131 | // if the input element is an array, slice, or map. 132 | func ToLen(matcher *base.Matcher) *base.Matcher { 133 | match := func(actual interface{}) *base.Result { 134 | value := reflect.NewValue(actual) 135 | if hasLen, ok := value.(_HasLen); ok { 136 | length := hasLen.Len() 137 | result := matcher.Match(length) 138 | return base.NewResultf(result.Matched(), "Len() returned %v", length) 139 | } 140 | return base.NewResultf(false, 141 | "Can't determine Len() for %T", actual) 142 | } 143 | return base.NewMatcherf(match, "ToLen[%v]", matcher) 144 | } 145 | 146 | 147 | // Matches any input element that is an empty array, slice, or map. 148 | func Empty() *base.Matcher { 149 | match := func(actual interface{}) *base.Result { 150 | value := reflect.NewValue(actual) 151 | if hasLen, ok := value.(_HasLen); ok { 152 | length := hasLen.Len() 153 | return base.NewResultf(length == 0, 154 | "Len() returned %v", length) 155 | } 156 | return base.NewResultf(false, "Can't determine length of type %T", actual) 157 | } 158 | return base.NewMatcherf(match, "Empty") 159 | } 160 | 161 | -------------------------------------------------------------------------------- /collections/collections_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package collections 6 | 7 | import ( 8 | "github.com/rdrdr/hamcrest/asserter" 9 | . "github.com/rdrdr/hamcrest/core" 10 | //"reflect" 11 | //"runtime" 12 | "testing" 13 | ) 14 | 15 | func Test_AnyElement_ofArray(t *testing.T) { 16 | we := asserter.Using(t) 17 | we.CheckThat([3]int{1, 2, 3}, AnyElement(EqualTo(1)).Comment("first element")) 18 | we.CheckThat([3]int{1, 2, 3}, AnyElement(EqualTo(2)).Comment("middle element")) 19 | we.CheckThat([3]int{1, 2, 3}, AnyElement(EqualTo(3)).Comment("last element")) 20 | we.CheckThat([3]int{1, 2, 3}, Not(AnyElement(EqualTo(4))).Comment("none matching")) 21 | we.CheckThat([0]int{}, Not(AnyElement(Anything())).Comment("no elements")) 22 | } 23 | 24 | func Test_EveryElement_ofArray(t *testing.T) { 25 | we := asserter.Using(t) 26 | we.CheckThat([3]int{1, 2, 3}, EveryElement(LessThan(4)).Comment("all elements")) 27 | we.CheckThat([3]int{2, 1, 1}, Not(EveryElement(LessThan(2))).Comment("all but first")) 28 | we.CheckThat([3]int{1, 2, 1}, Not(EveryElement(LessThan(2))).Comment("all but middle")) 29 | we.CheckThat([3]int{1, 1, 2}, Not(EveryElement(LessThan(2))).Comment("all but last")) 30 | we.CheckThat([0]int{}, EveryElement(Anything()).Comment("no elements")) 31 | } 32 | 33 | func Test_AnyElement_ofSlice(t *testing.T) { 34 | we := asserter.Using(t) 35 | we.CheckThat([]int{1, 2, 3}, AnyElement(EqualTo(1)).Comment("first element")) 36 | we.CheckThat([]int{1, 2, 3}, AnyElement(EqualTo(2)).Comment("middle element")) 37 | we.CheckThat([]int{1, 2, 3}, AnyElement(EqualTo(3)).Comment("last element")) 38 | we.CheckThat([]int{1, 2, 3}, Not(AnyElement(EqualTo(4))).Comment("none matching")) 39 | we.CheckThat([]int{}, Not(AnyElement(Anything())).Comment("no elements")) 40 | } 41 | 42 | func Test_EveryElement_ofSlice(t *testing.T) { 43 | we := asserter.Using(t) 44 | we.CheckThat([]int{1, 2, 3}, EveryElement(LessThan(4)).Comment("all elements")) 45 | we.CheckThat([]int{2, 1, 1}, Not(EveryElement(LessThan(2))).Comment("all but first")) 46 | we.CheckThat([]int{1, 2, 1}, Not(EveryElement(LessThan(2))).Comment("all but middle")) 47 | we.CheckThat([]int{1, 1, 2}, Not(EveryElement(LessThan(2))).Comment("all but last")) 48 | we.CheckThat([]int{}, EveryElement(Anything()).Comment("no elements")) 49 | } 50 | 51 | func Test_AnyMapElement(t *testing.T) { 52 | we := asserter.Using(t) 53 | twoMap := map[string]int{ "foo": 1, "bar": 2 } 54 | emptyMap := map[string]int{} 55 | we.CheckThat(twoMap, AnyMapElement(EqualTo(1)). 56 | Comment("entry [foo: 1]")) 57 | we.CheckThat(twoMap, AnyMapElement(EqualTo(2)). 58 | Comment("entry [bar: 2]")) 59 | we.CheckThat(twoMap, Not(AnyMapElement(EqualTo(3))). 60 | Comment("neither entry matches")) 61 | we.CheckThat(emptyMap, Not(AnyMapElement(Anything())). 62 | Comment("no entries")) 63 | } 64 | 65 | func Test_EveryMapElement(t *testing.T) { 66 | we := asserter.Using(t) 67 | twoMap := map[string]int{ "foo": 1, "bar": 2 } 68 | emptyMap := map[string]int{} 69 | we.CheckThat(twoMap, EveryMapElement(GreaterThan(0)). 70 | Comment("all entries")) 71 | we.CheckThat(twoMap, Not(EveryMapElement(GreaterThan(1))). 72 | Comment("not entry [foo: 1]")) 73 | we.CheckThat(twoMap, Not(EveryMapElement(LessThan(2))). 74 | Comment("not entry [bar: 2]")) 75 | we.CheckThat(emptyMap, EveryMapElement(Anything()). 76 | Comment("no entries")) 77 | } 78 | 79 | func Test_ToLen_onArrays(t *testing.T) { 80 | we := asserter.Using(t) 81 | empty := [...]string{} 82 | hasTwo := [...]string{"itsy", "bitsy"} 83 | we.CheckThat(empty, ToLen(EqualTo(0))) 84 | we.CheckThat(hasTwo, ToLen(EqualTo(2))) 85 | } 86 | 87 | func Test_ToLen_onSlices(t *testing.T) { 88 | we := asserter.Using(t) 89 | empty := []string{} 90 | hasTwo := []string{"itsy", "bitsy"} 91 | we.CheckThat(empty, ToLen(Is(EqualTo(0)))) 92 | we.CheckThat(hasTwo, ToLen(Is(EqualTo(2)))) 93 | } 94 | 95 | func Test_ToLen_onMaps(t *testing.T) { 96 | we := asserter.Using(t) 97 | empty := map[string]int{} 98 | hasTwo := map[string]int{ "foo": 1, "bar": 2 } 99 | we.CheckThat(empty, ToLen(Is(EqualTo(0)))) 100 | we.CheckThat(hasTwo, ToLen(Is(EqualTo(2)))) 101 | } 102 | 103 | func Test_Empty_onArrays(t *testing.T) { 104 | we := asserter.Using(t) 105 | empty := [...]string{} 106 | hasTwo := [...]string{"itsy", "bitsy"} 107 | we.CheckThat(empty, Is(Empty())) 108 | we.CheckThat(hasTwo, Is(Not(Empty()))) 109 | } 110 | 111 | func Test_Empty_onSlices(t *testing.T) { 112 | we := asserter.Using(t) 113 | empty := []string{} 114 | hasTwo := []string{"itsy", "bitsy"} 115 | we.CheckThat(empty, Is(Empty())) 116 | we.CheckThat(hasTwo, Is(Not(Empty()))) 117 | } 118 | 119 | func Test_Empty_onMaps(t *testing.T) { 120 | we := asserter.Using(t) 121 | empty := map[string]int{} 122 | hasTwo := map[string]int{ "foo": 1, "bar": 2 } 123 | we.CheckThat(empty, Is(Empty())) 124 | we.CheckThat(hasTwo, Is(Not(Empty()))) 125 | } 126 | 127 | -------------------------------------------------------------------------------- /core/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Mick Killianey. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | include $(GOROOT)/src/Make.inc 6 | 7 | TARG=github.com/rdrdr/hamcrest/core 8 | GOFILES=\ 9 | core.go\ 10 | 11 | include $(GOROOT)/src/Make.pkg 12 | -------------------------------------------------------------------------------- /core/comparison_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package core 6 | 7 | import ( 8 | "github.com/rdrdr/hamcrest/asserter" 9 | "testing" 10 | ) 11 | 12 | func Test_GreaterThan(t *testing.T) { 13 | we := asserter.Using(t) 14 | we.CheckThat(3, GreaterThan(2)) 15 | we.CheckThat(3, Not(GreaterThan(3))) 16 | we.CheckThat(3, Not(GreaterThan(4))) 17 | 18 | we.CheckThat(3, Not(GreaterThan("2"))) 19 | we.CheckThat("3", Not(GreaterThan(2))) 20 | we.CheckThat(t, Not(GreaterThan(t))) 21 | 22 | we.CheckThat(nil, Not(GreaterThan(3))) 23 | we.CheckThat(3, Not(GreaterThan(nil))) 24 | } 25 | 26 | func Test_GreaterThanOrEqualTo(t *testing.T) { 27 | we := asserter.Using(t) 28 | 29 | we.CheckThat(3, GreaterThanOrEqualTo(2)) 30 | we.CheckThat(3, GreaterThanOrEqualTo(3)) 31 | we.CheckThat(3, Not(GreaterThanOrEqualTo(4))) 32 | 33 | we.CheckThat(3, Not(GreaterThanOrEqualTo("2"))) 34 | we.CheckThat("3", Not(GreaterThanOrEqualTo(2))) 35 | we.CheckThat(t, Not(GreaterThanOrEqualTo(t))) 36 | 37 | we.CheckThat(nil, Not(GreaterThanOrEqualTo(3))) 38 | we.CheckThat(3, Not(GreaterThanOrEqualTo(nil))) 39 | } 40 | 41 | func Test_LessThan(t *testing.T) { 42 | we := asserter.Using(t) 43 | 44 | we.CheckThat(3, Not(LessThan(2))) 45 | we.CheckThat(3, Not(LessThan(3))) 46 | we.CheckThat(3, LessThan(4)) 47 | 48 | we.CheckThat(3, Not(LessThan("4"))) 49 | we.CheckThat("3", Not(LessThan(4))) 50 | we.CheckThat(t, Not(LessThan(t))) 51 | 52 | we.CheckThat(nil, Not(LessThan(3))) 53 | we.CheckThat(3, Not(LessThan(nil))) 54 | } 55 | 56 | func Test_LessThanOrEqualTo(t *testing.T) { 57 | we := asserter.Using(t) 58 | 59 | we.CheckThat(3, Not(LessThanOrEqualTo(2))) 60 | we.CheckThat(3, LessThanOrEqualTo(3)) 61 | we.CheckThat(3, LessThanOrEqualTo(4)) 62 | 63 | we.CheckThat(3, Not(LessThanOrEqualTo("4"))) 64 | we.CheckThat("3", Not(LessThanOrEqualTo(4))) 65 | we.CheckThat(t, Not(LessThanOrEqualTo(t))) 66 | 67 | we.CheckThat(nil, Not(LessThanOrEqualTo(3))) 68 | we.CheckThat(3, Not(LessThanOrEqualTo(nil))) 69 | } 70 | 71 | func Test_EqualTo(t *testing.T) { 72 | we := asserter.Using(t) 73 | 74 | we.CheckThat(3, Not(EqualTo(2))) 75 | we.CheckThat(3, EqualTo(3)) 76 | 77 | we.CheckThat(3, Not(EqualTo("3"))) 78 | we.CheckThat(int(3), Not(EqualTo(uint(3)))) 79 | 80 | we.CheckThat(3, Not(EqualTo(nil))) 81 | we.CheckThat(nil, Not(EqualTo(3))) 82 | } 83 | 84 | func Test_NotEqualTo(t *testing.T) { 85 | we := asserter.Using(t) 86 | 87 | we.CheckThat(3, NotEqualTo(2)) 88 | we.CheckThat(3, Not(NotEqualTo(3))) 89 | 90 | we.CheckThat(3, NotEqualTo("3")) 91 | we.CheckThat(int(3), NotEqualTo(uint(3))) 92 | 93 | we.CheckThat(3, NotEqualTo(nil)) 94 | we.CheckThat(nil, NotEqualTo(3)) 95 | } 96 | 97 | func checkOrderingOfOneAndTwo(we asserter.Asserter, one interface{}, two interface{}) { 98 | we.CheckThat(one, LessThan(two)) 99 | we.CheckThat(one, Not(LessThan(one))) 100 | we.CheckThat(two, Not(LessThan(one))) 101 | 102 | we.CheckThat(one, LessThanOrEqualTo(two)) 103 | we.CheckThat(one, LessThanOrEqualTo(one)) 104 | we.CheckThat(two, Not(LessThanOrEqualTo(one))) 105 | 106 | we.CheckThat(one, Not(GreaterThan(two))) 107 | we.CheckThat(one, Not(GreaterThan(one))) 108 | we.CheckThat(two, GreaterThan(one)) 109 | 110 | we.CheckThat(one, Not(GreaterThanOrEqualTo(two))) 111 | we.CheckThat(one, GreaterThanOrEqualTo(one)) 112 | we.CheckThat(two, GreaterThanOrEqualTo(one)) 113 | 114 | we.CheckThat(one, EqualTo(one)) 115 | we.CheckThat(one, Not(EqualTo(two))) 116 | we.CheckThat(one, NotEqualTo(two)) 117 | we.CheckThat(one, Not(NotEqualTo(one))) 118 | } 119 | 120 | func TestOrderingOfTypes(t *testing.T) { 121 | we := asserter.Using(t) 122 | checkOrderingOfOneAndTwo(we, int(1), int(2)) 123 | checkOrderingOfOneAndTwo(we, int8(1), int8(2)) 124 | checkOrderingOfOneAndTwo(we, int16(1), int16(2)) 125 | checkOrderingOfOneAndTwo(we, int32(1), int32(2)) 126 | checkOrderingOfOneAndTwo(we, int64(1), int64(2)) 127 | checkOrderingOfOneAndTwo(we, uint(1), uint(2)) 128 | checkOrderingOfOneAndTwo(we, uint8(1), uint8(2)) 129 | checkOrderingOfOneAndTwo(we, uint16(1), uint16(2)) 130 | checkOrderingOfOneAndTwo(we, uint32(1), uint32(2)) 131 | checkOrderingOfOneAndTwo(we, uint64(1), uint64(2)) 132 | checkOrderingOfOneAndTwo(we, float32(1), float32(2)) 133 | checkOrderingOfOneAndTwo(we, float64(1), float64(2)) 134 | checkOrderingOfOneAndTwo(we, string("1"), string("2")) 135 | } 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /core/core.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package core 6 | 7 | import ( 8 | "fmt" 9 | "github.com/rdrdr/hamcrest/base" 10 | "reflect" 11 | ) 12 | 13 | // Returns a Matcher that matches any input value. 14 | func Anything() *base.Matcher { 15 | return _Anything 16 | } 17 | var _Anything *base.Matcher // singleton 18 | func init() { 19 | match := func (actual interface{}) *base.Result { 20 | return base.NewResultf(true, "always matches") 21 | } 22 | _Anything = base.NewMatcherf(match, "Anything") 23 | } 24 | 25 | 26 | // Returns a Matcher that matches the boolean value true. 27 | func True() *base.Matcher { 28 | return base.True() 29 | } 30 | 31 | // Returns a Matcher that matches the boolean value false. 32 | func False() *base.Matcher { 33 | return base.False() 34 | } 35 | 36 | // Returns a Matcher that matches on values that cause the given 37 | // functionOrMatcher to panic. 38 | // 39 | // functionOrMatcher should either be a function that accepts one 40 | // parameter or a Matcher. 41 | func PanicWhenApplying(functionOrMatcher interface{}, name string) *base.Matcher { 42 | var doSomething func(interface{}) 43 | if matcher, ok := functionOrMatcher.(*base.Matcher); ok { 44 | doSomething = func(actual interface{}) { matcher.Match(actual) } 45 | } else { 46 | value := reflect.NewValue(functionOrMatcher) 47 | if funcValue, ok := value.(*reflect.FuncValue); ok { 48 | funcType := funcValue.Type().(*reflect.FuncType) 49 | numIn := funcType.NumIn() 50 | if numIn == 0 { 51 | panic(fmt.Sprintf("func must accept a single arg, was %T", functionOrMatcher)) 52 | } 53 | inType := funcType.In(0) 54 | switch { 55 | case numIn == 1: // always ok 56 | case numIn == 2 && funcType.DotDotDot(): // ok 57 | default: 58 | panic(fmt.Sprintf("func must accept a single arg, was %T", functionOrMatcher)) 59 | } 60 | doSomething = func(actual interface{}) { 61 | actualValue := reflect.NewValue(actual) 62 | argValues := make([]reflect.Value, numIn, numIn) 63 | if numIn == 1 && funcType.DotDotDot() { 64 | inSlice := reflect.MakeSlice(inType.(*reflect.SliceType), 1, 1) 65 | inValue := inSlice.Elem(0) 66 | inValue.SetValue(actualValue) 67 | argValues[0] = inSlice 68 | } else { 69 | inValue := reflect.MakeZero(inType) 70 | inValue.SetValue(actualValue) 71 | argValues[0] = inValue 72 | if numIn == 2 && funcType.DotDotDot() { 73 | inType2 := funcType.In(1) 74 | argValues[1] = reflect.MakeSlice(inType2.(*reflect.SliceType), 0, 0) 75 | } 76 | } 77 | funcValue.Call(argValues) 78 | } 79 | } 80 | } 81 | match := func (actual interface{}) (result *base.Result) { 82 | defer func() { 83 | if recover() != nil { 84 | result = base.NewResultf(true, "Panicked") 85 | } 86 | }() 87 | doSomething(actual) 88 | result = base.NewResultf(false, "Did not panic") 89 | return 90 | } 91 | return base.NewMatcherf(match, 92 | "PanicWhenApplying[%v]", name) 93 | } 94 | 95 | 96 | // Returns a Matcher that decorates another matcher and only matches 97 | // when the underlying matcher does not match (and vice versa). 98 | func Not(matcher *base.Matcher) *base.Matcher { 99 | match := func (actual interface{}) *base.Result { 100 | result := matcher.Match(actual) 101 | if result.Matched() { 102 | return base.NewResultf(false, 103 | "'Not' failed because inner matcher passed: %v", matcher). 104 | WithCauses(result) 105 | } 106 | return base.NewResultf(true, 107 | "'Not' passed because inner matcher failed: %v", matcher). 108 | WithCauses(result) 109 | } 110 | return base.NewMatcherf(match, "Not[%v]", matcher) 111 | } 112 | 113 | // Returns a Matcher that decorates another matcher. 114 | func Is(matcher *base.Matcher) *base.Matcher { 115 | match := func (actual interface{}) *base.Result { 116 | result := matcher.Match(actual) 117 | return base.NewResult(result.Matched(), result). 118 | WithCauses(result.Causes()...) 119 | } 120 | return base.NewMatcherf(match, "Is[%v]", matcher) 121 | } 122 | 123 | 124 | // Returns a Matcher that matches if the actual value is nil 125 | // or the nil value of its type. (Note that this is *not* 126 | // equivalent to DeeplyEqualTo(nil).) 127 | func Nil() *base.Matcher { 128 | return base.Nil() 129 | } 130 | 131 | // Returns a Matcher that matches if the actual value is 132 | // neither nil nor the nil value of its type. (Note that 133 | // this is *not* equivalent to Not(DeeplyEqualTo(nil)).) 134 | func NonNil() *base.Matcher { 135 | return base.NonNil() 136 | } 137 | 138 | // Returns a Matcher that checks if the actual value is (deeply) 139 | // equal to the given expected value, using reflect.DeepEqual. 140 | // 141 | // For an equality test equivalent to `==`, see the 142 | // `hamcrest/comparison` package. 143 | func DeepEqualTo(expected interface{}) *base.Matcher { 144 | return base.DeepEqualTo(expected) 145 | } 146 | 147 | // Returns a matcher that matches values that are greater-than the given 148 | // expected value, using the greater-than (<) operator. 149 | func GreaterThan(expected interface{}) *base.Matcher { 150 | return base.GreaterThan(expected) 151 | } 152 | 153 | // Returns a matcher that matches values that are greater-than-or-equal-to 154 | // the given expected value, using the greater-than-or-equal-to (>=) operator. 155 | func GreaterThanOrEqualTo(expected interface{}) *base.Matcher { 156 | return base.GreaterThanOrEqualTo(expected) 157 | } 158 | 159 | // Returns a matcher that matches values that are less-than the given 160 | // expected value, using the less-than (<) operator. 161 | func LessThan(expected interface{}) *base.Matcher { 162 | return base.LessThan(expected) 163 | } 164 | 165 | // Returns a matcher that matches values that are less-than-or-equal-to 166 | // the given expected value, using the less-than-or-equal-to (<=) operator. 167 | func LessThanOrEqualTo(expected interface{}) *base.Matcher { 168 | return base.LessThanOrEqualTo(expected) 169 | } 170 | 171 | // Returns a matcher that matches values that are equal to the 172 | // given expected value, using the equality (==) operator. 173 | func EqualTo(expected interface{}) *base.Matcher { 174 | return base.EqualTo(expected) 175 | } 176 | 177 | // Returns a matcher that matches values that are not equal to the 178 | // given expected value, using the inequality (!=) operator. 179 | func NotEqualTo(expected interface{}) *base.Matcher { 180 | return base.NotEqualTo(expected) 181 | } 182 | 183 | // Returns a short-circuiting Matcher that matches whenever all of 184 | // the given matchers match a given input value. If any component 185 | // matcher fails to match an input value, later matchers are not 186 | // attempted. 187 | func AllOf(matchers...*base.Matcher) *base.Matcher { 188 | match := func (actual interface{}) *base.Result { 189 | var results []*base.Result 190 | for index, matcher := range matchers { 191 | result := matcher.Match(actual) 192 | results := append(results, result) 193 | if !result.Matched() { 194 | return base.NewResultf(false, 195 | "Failed matcher %v of %v: [%v]", 196 | index+1, len(matchers), matcher). 197 | WithCauses(results...) 198 | } 199 | } 200 | return base.NewResultf(true, 201 | "Matched all %v matchers", len(matchers)). 202 | WithCauses(results...) 203 | } 204 | descriptions := make([]interface{}, len(matchers), len(matchers)) 205 | for index, matcher := range matchers { 206 | descriptions[index] = base.Description("[#%v: %v]", index+1, matcher) 207 | } 208 | return base.NewMatcherf(match, "AllOf%v", descriptions) 209 | } 210 | 211 | // Returns a short-circuiting Matcher that matches whenever all of 212 | // the given matchers match a given input value. If any component 213 | // matcher fails to match an input value, later matchers are not 214 | // attempted. 215 | func AnyOf(matchers...*base.Matcher) *base.Matcher { 216 | match := func (actual interface{}) *base.Result { 217 | var results []*base.Result 218 | for index, matcher := range matchers { 219 | result := matcher.Match(actual) 220 | results := append(results, result) 221 | if result.Matched() { 222 | return base.NewResultf(true, 223 | "Matched on matcher %v of %v: [%v]", 224 | index+1, len(matchers), matcher). 225 | WithCauses(results...) 226 | } 227 | } 228 | return base.NewResultf(false, 229 | "Matched none of the %v matchers", len(matchers)). 230 | WithCauses(results...) 231 | } 232 | descriptions := make([]interface{}, len(matchers), len(matchers)) 233 | for index, matcher := range matchers { 234 | descriptions[index] = base.Description("[#%v: %v]", index+1, matcher) 235 | } 236 | return base.NewMatcherf(match, "AnyOf%v", descriptions) 237 | } 238 | 239 | 240 | // Returns a function that composes the given function with a Matcher, such as: 241 | // ToLength := Composer(func(s string) int { return len(s) }, "ToLength") 242 | // And then: 243 | // HasLengthThree := ToLength(Is(EqualTo(3))) 244 | // HasLengthThree.Match("no").Matched() // false 245 | // HasLengthThree.Match("yes").Matched() // true 246 | // 247 | // The given function must be able to accept a single argument and 248 | // return a single argument. 249 | func Applying(function interface{}, name string) func(*base.Matcher) *base.Matcher { 250 | funcValue := reflect.NewValue(function).(*reflect.FuncValue) 251 | funcType := funcValue.Type().(*reflect.FuncType) 252 | numIn := funcType.NumIn() 253 | numOut := funcType.NumOut() 254 | if numIn == 0 { 255 | panic(fmt.Sprintf("function must accept at least one value, was %v by function %v", numIn, function)) 256 | } 257 | if numOut == 0 { 258 | panic(fmt.Sprintf("function must return at least one value, was %v by function %v", numOut, function)) 259 | } 260 | return func(matcher *base.Matcher) *base.Matcher { 261 | match := func (actual interface{}) *base.Result { 262 | Assign := func(dst reflect.Value, src reflect.Value) (ok bool) { 263 | defer func() { recover(); }() 264 | dst.SetValue(src) 265 | ok = true 266 | return 267 | } 268 | actualValue := reflect.NewValue(actual) 269 | argValues := make([]reflect.Value, numIn, numIn) 270 | if numIn > 0 { 271 | inType := funcType.In(0) 272 | if numIn == 1 && funcType.DotDotDot() { 273 | inSlice := reflect.MakeSlice(inType.(*reflect.SliceType), 1, 1) 274 | if !Assign(inSlice.Elem(0), actualValue) { 275 | return base.NewResultf(false, 276 | "Cannot use %T as input to %T", actual, function) 277 | } 278 | argValues[0] = inSlice 279 | } else { 280 | inValue := reflect.MakeZero(inType) 281 | if !Assign(inValue, actualValue) { 282 | return base.NewResultf(false, 283 | "Cannot use %T as input to %T", actual, function) 284 | } 285 | argValues[0] = inValue 286 | } 287 | for i := 1; i < numIn; i++ { 288 | inType = funcType.In(i) 289 | argValues[i] = reflect.MakeZero(inType) 290 | } 291 | } 292 | outValues := funcValue.Call(argValues) 293 | outValue := outValues[0] 294 | out := outValue.Interface() 295 | result := matcher.Match(out) 296 | return base.NewResultf(result.Matched(), 297 | "%v(%#v) = %v", name, actual, out). 298 | WithCauses(result) 299 | } 300 | return base.NewMatcherf(match, "%v[%v]", name, matcher) 301 | } 302 | } 303 | -------------------------------------------------------------------------------- /core/core_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package core 6 | 7 | import ( 8 | "github.com/rdrdr/hamcrest/base" 9 | "github.com/rdrdr/hamcrest/asserter" 10 | "fmt" 11 | "reflect" 12 | "testing" 13 | ) 14 | 15 | var Matched = base.Matched() 16 | var DidNotMatch = base.DidNotMatch() 17 | 18 | type Stringer interface { String() string } 19 | 20 | var uninitialized struct { 21 | _pointer *bool 22 | _func func() 23 | _slice []int 24 | _chan chan int 25 | _map map[int]bool 26 | _interface interface{} 27 | } 28 | 29 | func checkMatcherIsMatchingOnNils(t *testing.T, matcher *base.Matcher) { 30 | we := asserter.Using(t) 31 | we.CheckThat(matcher.Match(nil), Matched.Comment("nil")) 32 | we.CheckThat(matcher.Match(uninitialized._pointer), Matched.Comment("uninitialized pointer")) 33 | we.CheckThat(matcher.Match(uninitialized._func), Matched.Comment("uninitialized func")) 34 | we.CheckThat(matcher.Match(uninitialized._slice), Matched.Comment("uninitialized slice")) 35 | we.CheckThat(matcher.Match(uninitialized._chan), Matched.Comment("uninitialized chan")) 36 | we.CheckThat(matcher.Match(uninitialized._map), Matched.Comment("uninitialized map")) 37 | we.CheckThat(matcher.Match(uninitialized._interface), Matched.Comment("uninitialized interface")) 38 | } 39 | 40 | func checkMatcherIsNonMatchingOnNils(t *testing.T, matcher *base.Matcher) { 41 | we := asserter.Using(t) 42 | we.CheckThat(matcher.Match(nil), DidNotMatch.Comment("nil")) 43 | we.CheckThat(matcher.Match(uninitialized._pointer), DidNotMatch.Comment("uninitialized pointer")) 44 | we.CheckThat(matcher.Match(uninitialized._func), DidNotMatch.Comment("uninitialized func")) 45 | we.CheckThat(matcher.Match(uninitialized._slice), DidNotMatch.Comment("uninitialized slice")) 46 | we.CheckThat(matcher.Match(uninitialized._chan), DidNotMatch.Comment("uninitialized chan")) 47 | we.CheckThat(matcher.Match(uninitialized._map), DidNotMatch.Comment("uninitialized map")) 48 | we.CheckThat(matcher.Match(uninitialized._interface), DidNotMatch.Comment("uninitialized interface")) 49 | } 50 | 51 | var sampleValues []interface{} 52 | func init() { 53 | sampleValues = []interface{}{ 54 | true, 55 | false, 56 | int(42), int8(42), int16(42), int32(42), int64(42), 57 | uint(42), uint8(42), uint16(42), uint32(42), uint64(42), 58 | float32(42), float64(42), 59 | complex(42,42), complex64(42), complex128(42), 60 | "42", 61 | struct {Field int} {Field:42}, 62 | &struct {Field int} {Field:42}, 63 | reflect.Typeof(struct {Field int} {Field:42}), 64 | make(chan int, 42), 65 | func() int { return 42 }, 66 | map[string]int{ "forty":40, "two":2, "forty-two":42 }, 67 | []int{40, 41, 42}, 68 | [...]int{40, 41, 42}, 69 | [42]int{2:40, 40:2}, 70 | nil, 71 | uninitialized, 72 | uninitialized._chan, 73 | uninitialized._func, 74 | uninitialized._interface, 75 | uninitialized._map, 76 | uninitialized._pointer, 77 | uninitialized._slice, 78 | } 79 | } 80 | 81 | func logSamples(t *testing.T, matcher *base.Matcher) { 82 | t.Logf("Sample results for: %v\n", matcher) 83 | we := asserter.Using(t) 84 | for index, value := range sampleValues { 85 | t.Logf("Sample #%v: %T[value: %v]\n", index+1, value, value) 86 | we.LogResult(matcher.Match(value)) 87 | } 88 | } 89 | 90 | // Check Matchers 91 | func TestAnything(t *testing.T) { 92 | we := asserter.Using(t) 93 | matcher := Anything() 94 | we.CheckThat(matcher.Match(true), Matched) 95 | we.CheckThat(matcher.Match(false), Matched) 96 | we.CheckThat(matcher.Match("foo"), Matched) 97 | checkMatcherIsMatchingOnNils(t, matcher) 98 | logSamples(t, matcher) 99 | } 100 | 101 | func Test_True(t *testing.T) { 102 | we := asserter.Using(t) 103 | matcher := True() 104 | we.CheckThat(matcher.Match(true), Matched) 105 | we.CheckThat(matcher.Match(false), DidNotMatch) 106 | we.CheckThat(matcher.Match("true"), DidNotMatch) 107 | we.CheckThat(matcher.Match(1), DidNotMatch) 108 | checkMatcherIsNonMatchingOnNils(t, matcher) 109 | logSamples(t, matcher) 110 | } 111 | 112 | func Test_False(t *testing.T) { 113 | we := asserter.Using(t) 114 | matcher := False() 115 | we.CheckThat(matcher.Match(true), DidNotMatch) 116 | we.CheckThat(matcher.Match(false), Matched) 117 | we.CheckThat(matcher.Match("false"), DidNotMatch) 118 | we.CheckThat(matcher.Match(0), DidNotMatch) 119 | checkMatcherIsNonMatchingOnNils(t, matcher) 120 | logSamples(t, matcher) 121 | } 122 | 123 | func Test_Not(t *testing.T) { 124 | we := asserter.Using(t) 125 | matcher := Not(True()) 126 | we.CheckThat(matcher.Match(true), DidNotMatch) 127 | we.CheckThat(matcher.Match(false), Matched) 128 | logSamples(t, matcher) 129 | } 130 | 131 | func Test_Is(t *testing.T) { 132 | we := asserter.Using(t) 133 | matcher := Is(True()) 134 | we.CheckThat(matcher.Match(true), Matched) 135 | we.CheckThat(matcher.Match(false), DidNotMatch) 136 | logSamples(t, matcher) 137 | } 138 | 139 | func Test_Nil(t *testing.T) { 140 | we := asserter.Using(t) 141 | matcher := Nil() 142 | we.CheckThat(matcher.Match(false), DidNotMatch) 143 | we.CheckThat(matcher.Match(0), DidNotMatch) 144 | we.CheckThat(matcher.Match("nil"), DidNotMatch) 145 | checkMatcherIsMatchingOnNils(t, matcher) 146 | logSamples(t, matcher) 147 | } 148 | 149 | func Test_NonNil(t *testing.T) { 150 | we := asserter.Using(t) 151 | matcher := NonNil() 152 | we.CheckThat(matcher.Match(false), Matched) 153 | we.CheckThat(matcher.Match(0), Matched) 154 | we.CheckThat(matcher.Match("nil"), Matched) 155 | checkMatcherIsNonMatchingOnNils(t, matcher) 156 | logSamples(t, matcher) 157 | } 158 | 159 | type _DeepEqualType struct { x int } 160 | func Test_DeepEqualTo(t *testing.T) { 161 | we := asserter.Using(t) 162 | data := []interface{} { 163 | nil, true, false, 164 | int(42), uint(42), float64(42), complex128(42), 165 | struct { x int } { x: 42 }, 166 | struct { x int } { x: 42 }, 167 | &struct { x int } { x: 42 }, 168 | struct { y int } { y: 42 }, 169 | _DeepEqualType { x: 42 }, 170 | &_DeepEqualType { x: 42 }, 171 | []int { 42 }, 172 | []int { 42 }, 173 | map[int]int{ 42: 42 }, 174 | map[int]int{ 42: 42 }, 175 | make(chan int, 42), 176 | make(chan int, 42), 177 | } 178 | for _, x := range data { 179 | matcher := DeepEqualTo(x) 180 | for _, y := range data { 181 | message := fmt.Sprintf("%T[%v] and %T[%v]", x, x, y, y) 182 | if reflect.DeepEqual(x, y) { 183 | we.CheckThat(matcher.Match(y), Matched.Comment(message)) 184 | } else { 185 | we.CheckThat(matcher.Match(y), DidNotMatch.Comment(message)) 186 | } 187 | } 188 | } 189 | logSamples(t, DeepEqualTo(42)) 190 | } 191 | 192 | func Test_AllOf(t *testing.T) { 193 | we := asserter.Using(t) 194 | yes, no := Anything(), Not(Anything()) 195 | calledSnoop := false 196 | snoop := base.NewMatcherf(func(v interface{}) *base.Result { 197 | calledSnoop = true 198 | return base.NewResultf(false, "snooped!") 199 | }, "Snoop") 200 | 201 | we.CheckThat(AllOf(yes, yes, yes).Match(0), Matched.Comment("all matched")) 202 | we.CheckThat(AllOf(yes, yes, no).Match(0), DidNotMatch.Comment("not all matched")) 203 | we.CheckThat(AllOf(yes).Match(0), Matched.Comment("can pass one matcher")) 204 | we.CheckThat(AllOf(no).Match(0), DidNotMatch.Comment("can fail one matcher")) 205 | we.CheckThat(AllOf(yes, no, snoop).Match(0), DidNotMatch.Comment("can short-circuit")) 206 | we.CheckFalse(calledSnoop, "AllOf should short-circuit on first non-match") 207 | logSamples(t, AllOf(Not(True()), NonNil(), EqualTo(42))) 208 | } 209 | 210 | func Test_AnyOf(t *testing.T) { 211 | we := asserter.Using(t) 212 | yes, no := Anything(), Not(Anything()) 213 | calledSnoop := false 214 | snoop := base.NewMatcherf(func(v interface{}) *base.Result { 215 | calledSnoop = true 216 | return base.NewResultf(false, "snooped!") 217 | }, "Snoop") 218 | we.CheckThat(AnyOf(no, no, no).Match(0), DidNotMatch.Comment("none matched")) 219 | we.CheckThat(AnyOf(no, no, yes).Match(0), Matched.Comment("one matched")) 220 | we.CheckThat(AnyOf(yes).Match(0), Matched.Comment("can pass one matcher")) 221 | we.CheckThat(AnyOf(no).Match(0), DidNotMatch.Comment("can fail one matcher")) 222 | we.CheckThat(AnyOf(no, yes, snoop).Match(0), Matched.Comment("can short-circuit")) 223 | we.CheckFalse(calledSnoop, "AnyOf should short-circuit on first match") 224 | logSamples(t, AnyOf(True(), Nil(), EqualTo(42))) 225 | } 226 | 227 | func Test_Applying_onFunction_FromType_ToType(t *testing.T) { 228 | we := asserter.Using(t) 229 | IsEven := Applying(func(n int) bool { return n&1 == 0 }, "IsEven") 230 | ToLength := Applying(func(s string) int { return len(s) }, "ToLength") 231 | ToString := Applying(func(i int) string { return fmt.Sprint(i) }, "ToString") 232 | 233 | ValueIsEven := IsEven(Is(True())) 234 | LengthIsEven := ToString(ToLength(ValueIsEven)) 235 | 236 | we.CheckThat(ValueIsEven.Match(123), DidNotMatch) 237 | we.CheckThat(LengthIsEven.Match(123), DidNotMatch) 238 | 239 | we.CheckThat(ValueIsEven.Match(1234), Matched) 240 | we.CheckThat(LengthIsEven.Match(1234), Matched) 241 | 242 | we.CheckThat(ValueIsEven.Match(124), Matched) 243 | we.CheckThat(LengthIsEven.Match(124), DidNotMatch) 244 | 245 | we.CheckThat(ValueIsEven.Match(1233), DidNotMatch) 246 | we.CheckThat(LengthIsEven.Match(1233), Matched) 247 | 248 | logSamples(t, ValueIsEven) 249 | logSamples(t, LengthIsEven) 250 | } 251 | 252 | func Test_Applying_onFunction_FromTypeDotDotDot_ToType(t *testing.T) { 253 | we := asserter.Using(t) 254 | IsEven := Applying(func(n...int) bool { return n[0]&1 == 0 }, "IsEven") 255 | ToLength := Applying(func(s... string) int { return len(s[0]) }, "ToLength") 256 | ToString := Applying(func(i... int) string { return fmt.Sprint(i[0]) }, "ToString") 257 | 258 | ValueIsEven := IsEven(Is(True())) 259 | LengthIsEven := ToString(ToLength(ValueIsEven)) 260 | 261 | we.CheckThat(ValueIsEven.Match(123), DidNotMatch) 262 | we.CheckThat(LengthIsEven.Match(123), DidNotMatch) 263 | 264 | we.CheckThat(ValueIsEven.Match(1234), Matched) 265 | we.CheckThat(LengthIsEven.Match(1234), Matched) 266 | 267 | we.CheckThat(ValueIsEven.Match(124), Matched) 268 | we.CheckThat(LengthIsEven.Match(124), DidNotMatch) 269 | 270 | we.CheckThat(ValueIsEven.Match(1233), DidNotMatch) 271 | we.CheckThat(LengthIsEven.Match(1233), Matched) 272 | 273 | logSamples(t, ValueIsEven) 274 | logSamples(t, LengthIsEven) 275 | } 276 | 277 | func Test_Applying_onFunction_FromTypeTypeDotDotDot_ToType(t *testing.T) { 278 | we := asserter.Using(t) 279 | IsEven := Applying(func(n int, other...string) bool { return n&1 == 0 }, "IsEven") 280 | ToLength := Applying(func(s string, other...int) int { return len(s) }, "ToLength") 281 | ToString := Applying(func(i int, other... string) string { return fmt.Sprint(i) }, "ToString") 282 | 283 | ValueIsEven := IsEven(Is(True())) 284 | LengthIsEven := ToString(ToLength(ValueIsEven)) 285 | 286 | we.CheckThat(ValueIsEven.Match(123), DidNotMatch) 287 | we.CheckThat(LengthIsEven.Match(123), DidNotMatch) 288 | 289 | we.CheckThat(ValueIsEven.Match(1234), Matched) 290 | we.CheckThat(LengthIsEven.Match(1234), Matched) 291 | 292 | we.CheckThat(ValueIsEven.Match(124), Matched) 293 | we.CheckThat(LengthIsEven.Match(124), DidNotMatch) 294 | 295 | we.CheckThat(ValueIsEven.Match(1233), DidNotMatch) 296 | we.CheckThat(LengthIsEven.Match(1233), Matched) 297 | 298 | logSamples(t, ValueIsEven) 299 | logSamples(t, LengthIsEven) 300 | } 301 | 302 | func Test_PanicWhen_onFunctionAcceptingInterface(t *testing.T) { 303 | we := asserter.Using(t) 304 | panicOnBools := PanicWhenApplying(func (v interface{}) { 305 | if _, ok := v.(bool); ok { 306 | panic("no bools!") 307 | } 308 | }, "DisallowBools") 309 | 310 | we.CheckThat(panicOnBools.Match("true"), DidNotMatch) 311 | we.CheckThat(panicOnBools.Match(true), Matched) 312 | we.CheckThat(panicOnBools.Match(nil), DidNotMatch) 313 | 314 | logSamples(t, panicOnBools) 315 | } 316 | 317 | func Test_PanicWhen_onFunctionAcceptingBool(t *testing.T) { 318 | we := asserter.Using(t) 319 | 320 | var functionInvoked bool 321 | PanicOnFalse := PanicWhenApplying(func (b bool) { 322 | functionInvoked = true 323 | if !b { panic("Must be true") } 324 | }, "PanicOnFalse") 325 | 326 | functionInvoked = false 327 | we.CheckThat(PanicOnFalse.Match("true"), Matched. 328 | Comment("Should panic when can't invoke function")) 329 | we.CheckFalse(functionInvoked, "Shouldn't have invoked function") 330 | 331 | functionInvoked = false 332 | we.CheckThat(PanicOnFalse.Match(nil), Matched. 333 | Comment("Can't invoke function with string")) 334 | we.CheckFalse(functionInvoked, "Shouldn't have invoked function") 335 | 336 | functionInvoked = false 337 | we.CheckThat(PanicOnFalse.Match(true), DidNotMatch) 338 | we.CheckTrue(functionInvoked, "Should have invoked function") 339 | 340 | functionInvoked = false 341 | we.CheckThat(PanicOnFalse.Match(false), Matched) 342 | we.CheckTrue(functionInvoked, "Should have invoked function") 343 | 344 | logSamples(t, PanicOnFalse) 345 | } 346 | 347 | func Test_PanicWhen_onFunctionAcceptingOneArgDotDotDot(t *testing.T) { 348 | we := asserter.Using(t) 349 | 350 | var functionInvoked bool 351 | PanicOn13 := PanicWhenApplying(func (args...int) { 352 | functionInvoked = true 353 | if args[0] == 13 { 354 | panic("Superstition") 355 | } 356 | }, "Disallow13") 357 | 358 | functionInvoked = false 359 | we.CheckThat(PanicOn13.Match("thirteen"), Matched. 360 | Comment("Should panic when can't invoke function")) 361 | we.CheckFalse(functionInvoked, "Shouldn't have invoked function") 362 | 363 | functionInvoked = false 364 | we.CheckThat(PanicOn13.Match(12), DidNotMatch) 365 | we.CheckTrue(functionInvoked, "Should have invoked function") 366 | 367 | functionInvoked = false 368 | we.CheckThat(PanicOn13.Match(13), Matched) 369 | we.CheckTrue(functionInvoked, "Should have invoked function") 370 | 371 | logSamples(t, PanicOn13) 372 | } 373 | 374 | func Test_PanicWhen_onFunctionAcceptingTwoArgsDotDotDot(t *testing.T) { 375 | we := asserter.Using(t) 376 | 377 | var functionInvoked bool 378 | PanicOn13 := PanicWhenApplying(func (arg int, why...string) { 379 | functionInvoked = true 380 | if arg == 13 { 381 | panic("Superstition") 382 | } 383 | }, "Disallow13") 384 | 385 | functionInvoked = false 386 | we.CheckThat(PanicOn13.Match("thirteen"), Matched. 387 | Comment("Should panic when can't invoke function")) 388 | we.CheckFalse(functionInvoked, "Shouldn't have invoked function") 389 | 390 | functionInvoked = false 391 | we.CheckThat(PanicOn13.Match(12), DidNotMatch) 392 | we.CheckTrue(functionInvoked, "Should have invoked function") 393 | 394 | functionInvoked = false 395 | we.CheckThat(PanicOn13.Match(13), Matched) 396 | we.CheckTrue(functionInvoked, "Should have invoked function") 397 | 398 | logSamples(t, PanicOn13) 399 | } 400 | 401 | 402 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | Provides Matchers that detect when certain conditions are/aren't met 7 | on input values and give plain-text explanations. 8 | 9 | Note that although Hamcrest is not a "testing" library, its 10 | matchers happen to be useful for testing. To support this use, 11 | see the "asserter" subpackage. 12 | */ 13 | package hamcrest 14 | -------------------------------------------------------------------------------- /logic/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Mick Killianey. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | include $(GOROOT)/src/Make.inc 6 | 7 | TARG=github.com/rdrdr/hamcrest/logic 8 | GOFILES=\ 9 | logic.go\ 10 | 11 | include $(GOROOT)/src/Make.pkg 12 | -------------------------------------------------------------------------------- /logic/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | Provides Matchers for common logical operations, such as "and", "or", 7 | "nor", "exclusive or", "if-then" and "if-and-only-if". 8 | */ 9 | package logic 10 | -------------------------------------------------------------------------------- /logic/logic.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package logic 6 | 7 | import ( 8 | "github.com/rdrdr/hamcrest/base" 9 | ) 10 | 11 | // First part of a builder for a short-circuiting both/and matcher: 12 | // matcher := Both(Matcher1).And(Matcher2) 13 | func Both(matcher *base.Matcher) *BothClause { 14 | return &BothClause{matcher:matcher} 15 | } 16 | 17 | // Intermediate state in the construction of a Both/And clause. 18 | type BothClause struct { 19 | matcher *base.Matcher 20 | } 21 | 22 | // Second part of a builder for a short-circuiting both/and matcher. 23 | func (self *BothClause) And(matcher2 *base.Matcher) *base.Matcher { 24 | matcher1 := self.matcher 25 | match := func(actual interface{}) *base.Result { 26 | result1 := matcher1.Match(actual) 27 | if !result1.Matched() { 28 | return base.NewResultf(false, 29 | "first part of 'Both/And' did not match [%v]", actual). 30 | WithCauses(result1) 31 | } 32 | result2 := matcher2.Match(actual) 33 | if !result2.Matched() { 34 | return base.NewResultf(false, 35 | "second part of 'Both/And' did not match [%v]", actual). 36 | WithCauses(result2) 37 | } 38 | return base.NewResultf(true, 39 | "both parts of 'Both/And' matched [%v]", actual). 40 | WithCauses(result1, result2) 41 | } 42 | return base.NewMatcherf(match, "both [%v] and [%v]", matcher1, matcher2) 43 | } 44 | 45 | 46 | // First part of a builder for a short-circuiting either/or matcher or 47 | // a either/xor matcher, such as: 48 | // matcher := Either(matcher1).Or(matcher2) 49 | // or: 50 | // matcher := Either(matcher1).Xor(matcher2) 51 | func Either(matcher *base.Matcher) *EitherClause { 52 | return &EitherClause{matcher:matcher} 53 | } 54 | 55 | // Intermediate state in the construction of an Either/Or 56 | // or Either/Xor clause. 57 | type EitherClause struct { 58 | matcher *base.Matcher 59 | } 60 | 61 | // Second part of a builder for a short-circuiting either/or matcher: 62 | // matcher := Either(matcher1).Or(matcher2) 63 | // This matcher short-circuits without invoking the second matcher if 64 | // the first matcher successfully matches, and matches whenever either 65 | // of the two component matches successfully matches. 66 | func (self *EitherClause) Or(matcher2 *base.Matcher) *base.Matcher { 67 | matcher1 := self.matcher 68 | match := func(actual interface{}) *base.Result { 69 | result1 := matcher1.Match(actual) 70 | if result1.Matched() { 71 | return base.NewResultf(true, 72 | "first part of 'Either/Or' matched [%v]", 73 | actual). 74 | WithCauses(result1) 75 | } 76 | result2 := matcher2.Match(actual) 77 | if result2.Matched() { 78 | return base.NewResultf(true, 79 | "second part of 'Either/Or' matched [%v]", 80 | actual). 81 | WithCauses(result2) 82 | } 83 | return base.NewResultf(false, 84 | "neither part of 'Either/Or' matched [%v]", actual). 85 | WithCauses(result1, result2) 86 | } 87 | return base.NewMatcherf(match, 88 | "either [%v] or [%v]", matcher1, matcher2) 89 | } 90 | 91 | // Second part of a builder for an either/xor matcher: 92 | // matcher := Either(matcher1).Xor(matcher2) 93 | // This matcher matches when exactly one of the two matchers matches 94 | // a given value; if both or neither of the matchers is successful, 95 | // xor fails to match. Note that this is *never* a short-circuiting 96 | // operation. 97 | func (self *EitherClause) Xor(matcher2 *base.Matcher) *base.Matcher { 98 | matcher1 := self.matcher 99 | match := func(actual interface{}) *base.Result { 100 | result1 := matcher1.Match(actual) 101 | result2 := matcher2.Match(actual) 102 | if result1.Matched() { 103 | if result2.Matched() { 104 | return base.NewResultf(false, 105 | "both parts of 'Either/Xor' matched [%v]", actual). 106 | WithCauses(result1, result2) 107 | } 108 | return base.NewResultf(true, 109 | "only the first part of 'Either/Xor' matched [%v]", actual). 110 | WithCauses(result1, result2) 111 | } 112 | if result2.Matched() { 113 | return base.NewResultf(true, 114 | "only the second part of 'Either/Xor' matched [%v]", actual). 115 | WithCauses(result1, result2) 116 | } 117 | return base.NewResultf(false, 118 | "neither part of 'Either/Xor' matched [%v]", actual). 119 | WithCauses(result1, result2) 120 | } 121 | return base.NewMatcherf(match, "either [%v] xor [%v]", matcher1, matcher2) 122 | } 123 | 124 | // First part of a builder for a short-circuiting neither/nor matcher: 125 | // matcher := Neither(matcher1).Nor(matcher2) 126 | // such that the second matcher is only tested if the first matcher 127 | // fails to match, and the resulting matcher matches if either matches. 128 | // Note that the expression is logically equivalent to: 129 | // Both(Not(matcher1)).And(Not(matcher2)) 130 | // But may be more readable in practice. 131 | func Neither(matcher *base.Matcher) *NeitherClause { 132 | return &NeitherClause{matcher:matcher} 133 | } 134 | 135 | // Intermediate state in the construction of a Neither/Nor clause. 136 | type NeitherClause struct { 137 | matcher *base.Matcher 138 | } 139 | 140 | // Creates a matcher that passes when neither this matcher nor the 141 | // other matcher pass. This operation is short-circuiting, so that 142 | // if the first matcher matches, the second is not attempted. 143 | // Note that this is logically equivalent to: 144 | // Both(Not(matcher1)).And(Not(matcher2)) 145 | // But may be more readable in practice. 146 | func (self *NeitherClause) Nor(matcher2 *base.Matcher) *base.Matcher { 147 | matcher1 := self.matcher 148 | match := func(actual interface{}) *base.Result { 149 | result1 := matcher1.Match(actual) 150 | if result1.Matched() { 151 | return base.NewResultf(false, 152 | "first part of 'Nor' matched [%v]", actual). 153 | WithCauses(result1) 154 | } 155 | result2 := matcher2.Match(actual) 156 | if result2.Matched() { 157 | return base.NewResultf(false, 158 | "second part of 'Nor' matched [%v]", actual). 159 | WithCauses(result2) 160 | } 161 | return base.NewResultf(true, 162 | "neither part of 'Nor' matched [%v]", actual). 163 | WithCauses(result1, result2) 164 | } 165 | return base.NewMatcherf(match, "neither [%v] nor [%v]", matcher1, matcher2) 166 | } 167 | 168 | 169 | 170 | // First part of a builder for a short-circuiting if/then matcher: 171 | // matcher := If(AntecedentMatcher).Then(ConsequentMatcher) 172 | // such that the consequent is only tested when the antecedent 173 | // matches, and the resulting matcher only fails to match when the 174 | // consequent fails to match. Note that this is logically 175 | // equivalent to: 176 | // Either(Not(AntecedentMatcher)).Or(ConsequentMatcher) 177 | // But may be more readable in practice. 178 | func If(antecedent *base.Matcher) *IfClause { 179 | return &IfClause{antecedent:antecedent} 180 | } 181 | 182 | // Temporary builder state in the middle of constructing 183 | // an If/Then clause. 184 | type IfClause struct { 185 | antecedent *base.Matcher 186 | } 187 | 188 | // Constructs a short-circuiting if/then matcher: 189 | // matcher := If(AntecedentMatcher).Then(ConsequentMatcher) 190 | // such that the consequent is only tested when the antecedent 191 | // matches, and the resulting matcher only fails to match when the 192 | // consequent fails to match. Note that this is logically 193 | // equivalent to: 194 | // Either(Not(AntecedentMatcher)).Or(ConsequentMatcher) 195 | // But may be more readable in practice. 196 | func (self *IfClause) Then(consequent *base.Matcher) *base.Matcher { 197 | antecedent := self.antecedent 198 | match := func(actual interface{}) *base.Result { 199 | result1 := antecedent.Match(actual) 200 | if !result1.Matched() { 201 | return base.NewResultf(true, 202 | "'If/Then' matched because antecedent failed on [%v]", actual). 203 | WithCauses(result1) 204 | } 205 | result2 := consequent.Match(actual) 206 | if result2.Matched() { 207 | return base.NewResultf(true, 208 | "'If/Then' matched because consequent matched on [%v]", actual). 209 | WithCauses(result2) 210 | } 211 | return base.NewResultf(false, 212 | "'If/Then' failed on [%v]", actual). 213 | WithCauses(result1, result2) 214 | } 215 | return base.NewMatcherf(match, 216 | "if [%v] then [%v]", antecedent, consequent) 217 | } 218 | 219 | 220 | // First part of a builder for an if-and-only-if expression: 221 | // matcher := IfAndOnlyIf(AntecedentMatcher).Then(ConsequentMatcher) 222 | // This is logically equivalent to: 223 | // Either(Not(AntecedentMatcher)).Xor(ConsequentMatcher) 224 | // But may be more readable in practice. 225 | func IfAndOnlyIf(antecedent *base.Matcher) *IfAndOnlyIfClause { 226 | return &IfAndOnlyIfClause{antecedent:antecedent} 227 | } 228 | 229 | // Temporary builder state in the middle of constructing 230 | // an IfAndOnlyIf/Then clause. 231 | type IfAndOnlyIfClause struct { 232 | antecedent *base.Matcher 233 | } 234 | 235 | // Constructs an if-and-only-if/then matcher: 236 | // matcher := IfAndOnlyIf(AntecedentMatcher).Then(ConsequentMatcher) 237 | // that matches when both or neither of the Antecedent and the 238 | // Consequent match. Note that this is logically equivalent to: 239 | // Either(Not(AntecedentMatcher)).Xor(ConsequentMatcher) 240 | // But may be more readable in practice. 241 | func (self *IfAndOnlyIfClause) Then(consequent *base.Matcher) *base.Matcher { 242 | antecedent := self.antecedent 243 | match := func(actual interface{}) *base.Result { 244 | result1 := antecedent.Match(actual) 245 | result2 := consequent.Match(actual) 246 | if result1.Matched() { 247 | if result2.Matched() { 248 | return base.NewResultf(true, 249 | "Matched because both parts of 'Iff/Then' matched on [%v]", actual). 250 | WithCauses(result1, result2) 251 | } 252 | return base.NewResultf(false, 253 | "Failed because only the first part of 'Iff/Then' matched on [%v]", actual). 254 | WithCauses(result1, result2) 255 | } 256 | if result2.Matched() { 257 | return base.NewResultf(false, 258 | "Failed because only the second part of 'IFf/Then' matched on [%v]", actual). 259 | WithCauses(result1, result2) 260 | } 261 | return base.NewResultf(true, 262 | "Matched because neither part of 'Iff/Then' matched on [%v]", actual). 263 | WithCauses(result1, result2) 264 | } 265 | return base.NewMatcherf(match, "if and only if [%v] then [%v]", antecedent, consequent) 266 | } 267 | 268 | -------------------------------------------------------------------------------- /logic/logic_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package logic 6 | 7 | import ( 8 | "github.com/rdrdr/hamcrest/base" 9 | . "github.com/rdrdr/hamcrest/core" 10 | "reflect" 11 | "testing" 12 | ) 13 | 14 | func checkResultIsMatching(t *testing.T, result *base.Result, message string) { 15 | if !result.Matched() { 16 | t.Errorf("Expected matching result, was [%v] %v", result, message) 17 | } 18 | } 19 | 20 | func checkResultIsNonMatching(t *testing.T, result *base.Result, message string) { 21 | if result.Matched() { 22 | t.Errorf("Expected non-matching result, was [%v] %v", result, message) 23 | } 24 | } 25 | 26 | type Stringer interface { String() string } 27 | 28 | var uninitialized struct { 29 | _pointer *bool 30 | _func func() 31 | _slice []int 32 | _chan chan int 33 | _map map[int]bool 34 | _interface interface{} 35 | } 36 | 37 | func checkMatcherIsMatchingOnNils(t *testing.T, matcher *base.Matcher) { 38 | checkResultIsMatching(t, matcher.Match(nil), "nil") 39 | checkResultIsMatching(t, matcher.Match(uninitialized._pointer), "uninitialized pointer") 40 | checkResultIsMatching(t, matcher.Match(uninitialized._func), "uninitialized func") 41 | checkResultIsMatching(t, matcher.Match(uninitialized._slice), "uninitialized slice") 42 | checkResultIsMatching(t, matcher.Match(uninitialized._chan), "uninitialized chan") 43 | checkResultIsMatching(t, matcher.Match(uninitialized._map), "uninitialized map") 44 | checkResultIsMatching(t, matcher.Match(uninitialized._interface), "uninitialized interface") 45 | } 46 | 47 | func checkMatcherIsNonMatchingOnNils(t *testing.T, matcher *base.Matcher) { 48 | checkResultIsNonMatching(t, matcher.Match(nil), "nil") 49 | checkResultIsNonMatching(t, matcher.Match(uninitialized._pointer), "uninitialized pointer") 50 | checkResultIsNonMatching(t, matcher.Match(uninitialized._func), "uninitialized func") 51 | checkResultIsNonMatching(t, matcher.Match(uninitialized._slice), "uninitialized slice") 52 | checkResultIsNonMatching(t, matcher.Match(uninitialized._chan), "uninitialized chan") 53 | checkResultIsNonMatching(t, matcher.Match(uninitialized._map), "uninitialized map") 54 | checkResultIsNonMatching(t, matcher.Match(uninitialized._interface), "uninitialized interface") 55 | } 56 | 57 | func logSamples(t *testing.T, matcher *base.Matcher) { 58 | t.Logf("Sample results for: %v\n", matcher) 59 | t.Logf("\ton true: %v\n", matcher.Match(true)) 60 | t.Logf("\ton false: %v\n", matcher.Match(false)) 61 | t.Logf("\ton int: %v\n", matcher.Match(42)) 62 | t.Logf("\ton uint: %v\n", matcher.Match(uint(42))) 63 | t.Logf("\ton float: %v\n", matcher.Match(42.0)) 64 | t.Logf("\ton string: %v\n", matcher.Match("foobar")) 65 | t.Logf("\ton struct: %v\n", matcher.Match(struct {Field int} {Field:42})) 66 | t.Logf("\ton type: %v\n", matcher.Match(reflect.Typeof(uninitialized))) 67 | 68 | t.Logf("\ton channel: %v\n", matcher.Match(make(chan int, 1))) 69 | t.Logf("\ton function: %v\n", matcher.Match(func() int { return 1 })) 70 | t.Logf("\ton function: %v\n", matcher.Match(interface{}(nil))) 71 | t.Logf("\ton map: %v\n", matcher.Match(map[int]string{1:"one", 2:"two"})) 72 | t.Logf("\ton pointer: %v\n", matcher.Match(&struct {Field int} {Field:42})) 73 | t.Logf("\ton slice: %v\n", matcher.Match([]int{1})) 74 | 75 | t.Logf("\ton nil: %v\n", matcher.Match(nil)) 76 | t.Logf("\ton nil channel: %v\n", matcher.Match(uninitialized._chan)) 77 | t.Logf("\ton nil function: %v\n", matcher.Match(uninitialized._func)) 78 | t.Logf("\ton nil interface: %v\n", matcher.Match(uninitialized._interface)) 79 | t.Logf("\ton nil map: %v\n", matcher.Match(uninitialized._map)) 80 | t.Logf("\ton nil pointer: %v\n", matcher.Match(uninitialized._pointer)) 81 | t.Logf("\ton nil slice: %v\n", matcher.Match(uninitialized._slice)) 82 | } 83 | 84 | // Check Matchers 85 | func Test_BothAnd(t *testing.T) { 86 | yes, no := Anything(), Not(Anything()) 87 | calledSnoop := false 88 | snoop := base.NewMatcherf(func(v interface{}) *base.Result { 89 | calledSnoop = true 90 | return base.NewResultf(false, "snooped!") 91 | }, "Snoop") 92 | 93 | if result := Both(yes).And(yes).Match(0); !result.Matched() { 94 | t.Errorf("yes and yes should match, was [%v]", result) 95 | } 96 | if result := Both(yes).And(no).Match(0); result.Matched() { 97 | t.Errorf("yes and no should not match, was [%v]", result) 98 | } 99 | result := Both(no).And(snoop).Match(0) 100 | if calledSnoop { 101 | t.Errorf("no and snoop should short-circuit before calling snoop") 102 | } 103 | if result.Matched() { 104 | t.Errorf("no and snoop should not match, was [%v]", result) 105 | } 106 | logSamples(t, Both(yes).And(yes)) 107 | logSamples(t, Both(yes).And(no)) 108 | logSamples(t, Both(no).And(yes)) 109 | logSamples(t, Both(no).And(no)) 110 | } 111 | 112 | func Test_EitherOr(t *testing.T) { 113 | yes, no := Anything(), Not(Anything()) 114 | calledSnoop := false 115 | snoop := base.NewMatcherf(func(v interface{}) *base.Result { 116 | calledSnoop = true 117 | return base.NewResultf(false, "snooped!") 118 | }, "Snoop") 119 | 120 | if result := Either(no).Or(no).Match(0); result.Matched() { 121 | t.Errorf("no or no should not match, was [%v]", result) 122 | } 123 | if result := Either(no).Or(yes).Match(0); !result.Matched() { 124 | t.Errorf("no or yes should match, was [%v]", result) 125 | } 126 | result := Either(yes).Or(snoop).Match(0) 127 | if calledSnoop { 128 | t.Errorf("yes or snoop should short-circuit before calling snoop") 129 | } 130 | if !result.Matched() { 131 | t.Errorf("yes or snoop should match, was [%v]", result) 132 | } 133 | logSamples(t, Either(yes).Or(yes)) 134 | logSamples(t, Either(yes).Or(no)) 135 | logSamples(t, Either(no).Or(yes)) 136 | logSamples(t, Either(no).Or(no)) 137 | } 138 | 139 | func Test_EitherXor(t *testing.T) { 140 | yes, no := Anything(), Not(Anything()) 141 | if result := Either(no).Xor(no).Match(0); result.Matched() { 142 | t.Errorf("no xor no should not match, was [%v]", result) 143 | } 144 | if result := Either(yes).Xor(yes).Match(0); result.Matched() { 145 | t.Errorf("yes xor yes should not match, was [%v]", result) 146 | } 147 | if result := Either(no).Xor(yes).Match(0); !result.Matched() { 148 | t.Errorf("no xor yes should match, was [%v]", result) 149 | } 150 | if result := Either(yes).Xor(no).Match(0); !result.Matched() { 151 | t.Errorf("yes xor no should match, was [%v]", result) 152 | } 153 | logSamples(t, Either(yes).Xor(yes)) 154 | logSamples(t, Either(yes).Xor(no)) 155 | logSamples(t, Either(no).Xor(yes)) 156 | logSamples(t, Either(no).Xor(no)) 157 | } 158 | 159 | func Test_NeitherNor(t *testing.T) { 160 | yes, no := Anything(), Not(Anything()) 161 | calledSnoop := false 162 | snoop := base.NewMatcherf(func(v interface{}) *base.Result { 163 | calledSnoop = true 164 | return base.NewResultf(false, "snooped!") 165 | }, "Snoop") 166 | 167 | if result := Neither(no).Nor(no).Match(0); !result.Matched() { 168 | t.Errorf("no nor no should match, was [%v]", result) 169 | } 170 | if result := Neither(no).Nor(yes).Match(0); result.Matched() { 171 | t.Errorf("no nor yes should not match, was [%v]", result) 172 | } 173 | result := Neither(yes).Nor(snoop).Match(0) 174 | if calledSnoop { 175 | t.Errorf("yes nor snoop should short-circuit before calling snoop") 176 | } 177 | if result.Matched() { 178 | t.Errorf("yes nor snoop should not match, was [%v]", result) 179 | } 180 | logSamples(t, Neither(yes).Nor(yes)) 181 | logSamples(t, Neither(yes).Nor(no)) 182 | logSamples(t, Neither(no).Nor(yes)) 183 | logSamples(t, Neither(no).Nor(no)) 184 | } 185 | 186 | func Test_IfThen(t *testing.T) { 187 | yes, no := Anything(), Not(Anything()) 188 | calledSnoop := false 189 | snoop := base.NewMatcherf(func(v interface{}) *base.Result { 190 | calledSnoop = true 191 | return base.NewResultf(false, "snooped!") 192 | }, "Snoop") 193 | 194 | if result := If(yes).Then(yes).Match(0); !result.Matched() { 195 | t.Errorf("if yes then yes should match, was [%v]", result) 196 | } 197 | if result := If(yes).Then(no).Match(0); result.Matched() { 198 | t.Errorf("if yes then no should not match, was [%v]", result) 199 | } 200 | result := If(no).Then(snoop).Match(0) 201 | if calledSnoop { 202 | t.Errorf("If-no-then-snoop should short-circuit before calling snoop") 203 | } 204 | if !result.Matched() { 205 | t.Errorf("if-no-then-snoop should match on failing antecedent, was [%v]", 206 | result) 207 | } 208 | logSamples(t, If(yes).Then(yes)) 209 | logSamples(t, If(yes).Then(no)) 210 | logSamples(t, If(no).Then(yes)) 211 | logSamples(t, If(no).Then(no)) 212 | } 213 | 214 | func Test_IfAndOnlyIfThen(t *testing.T) { 215 | yes, no := Anything(), Not(Anything()) 216 | Iff := IfAndOnlyIf 217 | if result := Iff(no).Then(no).Match(0); !result.Matched() { 218 | t.Errorf("iff no then no should match, was [%v]", result) 219 | } 220 | if result := Iff(yes).Then(yes).Match(0); !result.Matched() { 221 | t.Errorf("iff yes then yes should match, was [%v]", result) 222 | } 223 | if result := Iff(no).Then(yes).Match(0); result.Matched() { 224 | t.Errorf("iff no then yes should not match, was [%v]", result) 225 | } 226 | if result := Iff(yes).Then(no).Match(0); result.Matched() { 227 | t.Errorf("iff yes then no should match, was [%v]", result) 228 | } 229 | logSamples(t, Iff(yes).Then(yes)) 230 | logSamples(t, Iff(yes).Then(no)) 231 | logSamples(t, Iff(no).Then(yes)) 232 | logSamples(t, Iff(no).Then(no)) 233 | } 234 | -------------------------------------------------------------------------------- /reflect/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Mick Killianey. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | include $(GOROOT)/src/Make.inc 6 | 7 | TARG=github.com/rdrdr/hamcrest/reflect 8 | GOFILES=\ 9 | reflect.go\ 10 | 11 | include $(GOROOT)/src/Make.pkg 12 | -------------------------------------------------------------------------------- /reflect/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | Hamcrest Matchers related to the standard Go "reflect" package. 7 | 8 | These matchers operate on the type of the object involved. 9 | */ 10 | package reflect 11 | -------------------------------------------------------------------------------- /reflect/reflect.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package reflect 6 | 7 | import ( 8 | "github.com/rdrdr/hamcrest/base" 9 | . "github.com/rdrdr/hamcrest/core" 10 | "reflect" 11 | ) 12 | 13 | // Returns a new matcher that applies the type of its input 14 | // element to the given matcher. 15 | func ToType(matcher *base.Matcher) *base.Matcher { 16 | match := func(actual interface{}) *base.Result { 17 | actualType := reflect.Typeof(actual) 18 | result := matcher.Match(actualType) 19 | return base.NewResultf(result.Matched(), 20 | "reflect.Typeof() returned %v", actualType). 21 | WithCauses(result) 22 | } 23 | return base.NewMatcherf(match, "ToType(%v)", matcher) 24 | } 25 | 26 | // Returns a matcher that matches any object with the same 27 | // type as the given example. 28 | func SameTypeAs(example interface{}) *base.Matcher { 29 | exampleType := reflect.Typeof(example) 30 | return _TypeMatcher(exampleType.Name(), exampleType) 31 | } 32 | 33 | func _TypeMatcher(name string, expectedType reflect.Type) *base.Matcher { 34 | match := func(actual interface{}) *base.Result { 35 | if actual == nil { 36 | return base.NewResultf(false, "was nil") 37 | } 38 | actualType := reflect.Typeof(actual) 39 | if reflect.DeepEqual(actualType, expectedType) { 40 | return base.NewResultf(true, "was of type %v", expectedType) 41 | } 42 | return base.NewResultf(false, 43 | "was a %v, not a %v", actualType, expectedType) 44 | } 45 | return base.NewMatcherf(match, "Typeof[%v]", expectedType) 46 | } 47 | 48 | var ( 49 | boolType = reflect.Typeof(false) 50 | boolMatcher = _TypeMatcher("Bool", boolType) 51 | boolTypeMatcher = DeepEqualTo(boolType) 52 | 53 | intType = reflect.Typeof(int(0)) 54 | intMatcher = _TypeMatcher("Int", intType) 55 | intTypeMatcher = DeepEqualTo(intType) 56 | 57 | int8Type = reflect.Typeof(int8(0)) 58 | int8Matcher = _TypeMatcher("Int8", int8Type) 59 | int8TypeMatcher = DeepEqualTo(int8Type) 60 | 61 | int16Type = reflect.Typeof(int16(0)) 62 | int16Matcher = _TypeMatcher("Int16", int16Type) 63 | int16TypeMatcher = DeepEqualTo(int16Type) 64 | 65 | int32Type = reflect.Typeof(int32(0)) 66 | int32Matcher = _TypeMatcher("Int32", int32Type) 67 | int32TypeMatcher = DeepEqualTo(int32Type) 68 | 69 | int64Type = reflect.Typeof(int64(0)) 70 | int64Matcher = _TypeMatcher("Int64", int64Type) 71 | int64TypeMatcher = DeepEqualTo(int64Type) 72 | 73 | uintType = reflect.Typeof(uint(0)) 74 | uintMatcher = _TypeMatcher("Uint", uintType) 75 | uintTypeMatcher = DeepEqualTo(uintType) 76 | 77 | uint8Type = reflect.Typeof(uint8(0)) 78 | uint8Matcher = _TypeMatcher("Uint8", uint8Type) 79 | uint8TypeMatcher = DeepEqualTo(uint8Type) 80 | 81 | uint16Type = reflect.Typeof(uint16(0)) 82 | uint16Matcher = _TypeMatcher("Uint16", uint16Type) 83 | uint16TypeMatcher = DeepEqualTo(uint16Type) 84 | 85 | uint32Type = reflect.Typeof(uint32(0)) 86 | uint32Matcher = _TypeMatcher("Uint32", uint32Type) 87 | uint32TypeMatcher = DeepEqualTo(uint32Type) 88 | 89 | uint64Type = reflect.Typeof(uint64(0)) 90 | uint64Matcher = _TypeMatcher("Uint64", uint64Type) 91 | uint64TypeMatcher = DeepEqualTo(uint64Type) 92 | 93 | uintptrType = reflect.Typeof(uintptr(0)) 94 | uintptrMatcher = _TypeMatcher("Uintptr", uintptrType) 95 | uintptrTypeMatcher = DeepEqualTo(uintptrType) 96 | 97 | float32Type = reflect.Typeof(float32(0)) 98 | float32Matcher = _TypeMatcher("Float32", float32Type) 99 | float32TypeMatcher = DeepEqualTo(float32Type) 100 | 101 | float64Type = reflect.Typeof(float64(0)) 102 | float64Matcher = _TypeMatcher("Float64", float64Type) 103 | float64TypeMatcher = DeepEqualTo(float64Type) 104 | 105 | complexType = reflect.Typeof(complex(0, 0i)) 106 | complexMatcher = _TypeMatcher("Complex", complexType) 107 | complexTypeMatcher = DeepEqualTo(complexType) 108 | 109 | complex64Type = reflect.Typeof(complex64(0i)) 110 | complex64Matcher = _TypeMatcher("Complex64", complex64Type) 111 | complex64TypeMatcher = DeepEqualTo(complex64Type) 112 | 113 | complex128Type = reflect.Typeof(complex128(0i)) 114 | complex128Matcher = _TypeMatcher("Complex128", complex128Type) 115 | complex128TypeMatcher = DeepEqualTo(complex128Type) 116 | 117 | stringType = reflect.Typeof("") 118 | stringMatcher = _TypeMatcher("String", stringType) 119 | stringTypeMatcher = DeepEqualTo(stringType) 120 | ) 121 | 122 | func Bool() *base.Matcher { return boolMatcher } 123 | func Int() *base.Matcher { return intMatcher } 124 | func Int8() *base.Matcher { return int8Matcher } 125 | func Int16() *base.Matcher { return int16Matcher } 126 | func Int32() *base.Matcher { return int32Matcher } 127 | func Int64() *base.Matcher { return int64Matcher } 128 | func Uint() *base.Matcher { return uintMatcher } 129 | func Uint8() *base.Matcher { return uint8Matcher } 130 | func Uint16() *base.Matcher { return uint16Matcher } 131 | func Uint32() *base.Matcher { return uint32Matcher } 132 | func Uint64() *base.Matcher { return uint64Matcher } 133 | func Float32() *base.Matcher { return float32Matcher } 134 | func Float64() *base.Matcher { return float64Matcher } 135 | func Complex() *base.Matcher { return complexMatcher } 136 | func Complex64() *base.Matcher { return complex64Matcher } 137 | func Complex128() *base.Matcher { return complex128Matcher } 138 | func String() *base.Matcher { return stringMatcher } 139 | 140 | func BoolType() *base.Matcher { return boolTypeMatcher } 141 | func IntType() *base.Matcher { return intTypeMatcher } 142 | func Int8Type() *base.Matcher { return int8TypeMatcher } 143 | func Int16Type() *base.Matcher { return int16TypeMatcher } 144 | func Int32Type() *base.Matcher { return int32TypeMatcher } 145 | func Int64Type() *base.Matcher { return int64TypeMatcher } 146 | func UintType() *base.Matcher { return uintTypeMatcher } 147 | func Uint8Type() *base.Matcher { return uint8TypeMatcher } 148 | func Uint16Type() *base.Matcher { return uint16TypeMatcher } 149 | func Uint32Type() *base.Matcher { return uint32TypeMatcher } 150 | func Uint64Type() *base.Matcher { return uint64TypeMatcher } 151 | func Float32Type() *base.Matcher { return float32TypeMatcher } 152 | func Float64Type() *base.Matcher { return float64TypeMatcher } 153 | func ComplexType() *base.Matcher { return complexTypeMatcher } 154 | func Complex64Type() *base.Matcher { return complex64TypeMatcher } 155 | func Complex128Type() *base.Matcher { return complex128TypeMatcher } 156 | func StringType() *base.Matcher { return stringTypeMatcher } 157 | 158 | 159 | // Returns a new matcher that, on any input that is a *reflect.ArrayType, 160 | // extracts the type of element and matches it against the given matcher. 161 | // 162 | // If the given input is not an *reflect.ArrayType, this fails to match. 163 | // Note: this matches array *types*, not arrays. (See ArrayOf.) 164 | func ArrayTypeOf(elementTypeMatcher *base.Matcher) *base.Matcher { 165 | match := func(actual interface{}) *base.Result { 166 | if arrayType, ok := actual.(*reflect.ArrayType); ok { 167 | elementType := arrayType.Elem() 168 | result := elementTypeMatcher.Match(elementType) 169 | return base.NewResultf( 170 | result.Matched(), 171 | "was ArrayType with elements of type %v", elementType.Name()). 172 | WithCauses(result) 173 | } 174 | return base.NewResultf(false, 175 | "was of type %T, not an ArrayType", actual) 176 | } 177 | return base.NewMatcherf(match, "ArrayTypeOf(%v)", elementTypeMatcher) 178 | } 179 | 180 | // Returns a new matcher that, on any input that is an array, extracts 181 | // its type and matches it against the given matcher. 182 | // 183 | // If the given input is not an array, this fails to match. 184 | // Note: this matches *arrays*, not array *types*. (See ArrayTypeOf.) 185 | func ArrayOf(elementTypeMatcher *base.Matcher) *base.Matcher { 186 | match := func(actual interface{}) *base.Result { 187 | actualType := reflect.Typeof(actual) 188 | if arrayType, ok := actualType.(*reflect.ArrayType); ok { 189 | elementType := arrayType.Elem() 190 | result := elementTypeMatcher.Match(elementType) 191 | return base.NewResultf( 192 | result.Matched(), 193 | "was array with elements of type %v", elementType). 194 | WithCauses(result) 195 | } 196 | return base.NewResultf(false, "was of type %T, not an array", actual) 197 | } 198 | return base.NewMatcherf(match, "ArrayOf(%v)", elementTypeMatcher) 199 | } 200 | 201 | // Returns a new matcher that, on any input that is a *reflect.ChanType, 202 | // extracts its element type and matches it against the given matcher. 203 | // 204 | // If the given input is not a *reflect.ChanType, this fails to match. 205 | // Note: this matches channel *types*, not *channels*. (See ChannelOf.) 206 | func ChannelTypeOf(elementTypeMatcher *base.Matcher) *base.Matcher { 207 | match := func(actual interface{}) *base.Result { 208 | if channelType, ok := actual.(*reflect.ChanType); ok { 209 | elementType := channelType.Elem() 210 | result := elementTypeMatcher.Match(elementType) 211 | return base.NewResultf( 212 | result.Matched(), 213 | "was *reflect.ChanType with elements of type %v", elementType). 214 | WithCauses(result) 215 | } 216 | return base.NewResultf(false, 217 | "was of type %T, not a *reflect.ChanType", actual) 218 | } 219 | return base.NewMatcherf(match, "ChannelTypeOf(%v)", elementTypeMatcher) 220 | } 221 | 222 | // Returns a new matcher that, on any input that is a channel, extracts 223 | // its type and matches it against the given matcher. 224 | // 225 | // If the given input is not a channel, this fails to match. 226 | // Note: this matches *channels*, not channel *types*. (See ChannelTypeOf.) 227 | func ChannelOf(elementTypeMatcher *base.Matcher) *base.Matcher { 228 | match := func(actual interface{}) *base.Result { 229 | actualType := reflect.Typeof(actual) 230 | if channelType, ok := actualType.(*reflect.ChanType); ok { 231 | elementType := channelType.Elem() 232 | result := elementTypeMatcher.Match(elementType) 233 | return base.NewResultf(result.Matched(), 234 | "was channel with elements of type %v", 235 | elementType). 236 | WithCauses(result) 237 | } 238 | return base.NewResultf(false, "was of type %T, not a channel", actual) 239 | } 240 | return base.NewMatcherf(match, "ChannelOf(%v)", elementTypeMatcher) 241 | } 242 | 243 | // Returns a new matcher that, on any input that is a *reflect.SliceType, 244 | // extracts the type of element and matches it against the given matcher. 245 | // 246 | // If the given input is not an *reflect.SliceType, this fails to match. 247 | // Note: this matches slice *types*, not slices. (See SliceOf.) 248 | func SliceTypeOf(elementTypeMatcher *base.Matcher) *base.Matcher { 249 | match := func(actual interface{}) *base.Result { 250 | if sliceType, ok := actual.(*reflect.SliceType); ok { 251 | elementType := sliceType.Elem() 252 | result := elementTypeMatcher.Match(elementType) 253 | return base.NewResultf( 254 | result.Matched(), 255 | "was SliceType with elements of type %v", elementType.Name()). 256 | WithCauses(result) 257 | } 258 | return base.NewResultf(false, "was of type %T, not a slice", actual) 259 | } 260 | return base.NewMatcherf(match, "SliceTypeOf(%v)", elementTypeMatcher) 261 | } 262 | 263 | // Returns a new matcher that, on any input that is an array, extracts 264 | // its type and matches it against the given matcher. 265 | // 266 | // If the given input is not an array, this fails to match. 267 | // Note: this matches *slices*, not slice *types*. (See SliceTypeOf.) 268 | func SliceOf(elementTypeMatcher *base.Matcher) *base.Matcher { 269 | match := func(actual interface{}) *base.Result { 270 | actualType := reflect.Typeof(actual) 271 | if sliceType, ok := actualType.(*reflect.SliceType); ok { 272 | elementType := sliceType.Elem() 273 | result := elementTypeMatcher.Match(elementType) 274 | return base.NewResultf( 275 | result.Matched(), 276 | "was slice with elements of type %v", elementType). 277 | WithCauses(result) 278 | } 279 | return base.NewResultf(false, "was of type %T, not a slice", actual) 280 | } 281 | return base.NewMatcherf(match, "SliceOf(%v)", elementTypeMatcher) 282 | } 283 | 284 | // Returns a new matcher that, on any input that is a *reflect.MapType, 285 | // extracts the type of keys and element and matches them against two 286 | // given matchers. 287 | // 288 | // If the given input is not an *reflect.MapType, this fails to match. 289 | // Note: this matches map *types*, not maps. (See MapOf.) 290 | func MapTypeOf(keyTypeMatcher, elementTypeMatcher *base.Matcher) *base.Matcher { 291 | match := func(actual interface{}) *base.Result { 292 | if mapType, ok := actual.(*reflect.MapType); ok { 293 | keyType := mapType.Key() 294 | elementType := mapType.Elem() 295 | keyResult := keyTypeMatcher.Match(keyType) 296 | if !keyResult.Matched() { 297 | return base.NewResultf(false, 298 | "was MapType with keys of type %v", keyType). 299 | WithCauses(keyResult) 300 | } 301 | elementResult := elementTypeMatcher.Match(elementType) 302 | return base.NewResultf(elementResult.Matched(), 303 | "was MapType with keys/elements of type %v/%v", 304 | keyType, elementType). 305 | WithCauses(keyResult, elementResult) 306 | } 307 | return base.NewResultf(false, "was of type %T, not a MapType", actual) 308 | } 309 | return base.NewMatcherf(match, 310 | "MapTypeOf(%v, %v)", keyTypeMatcher, elementTypeMatcher) 311 | } 312 | 313 | // Returns a new matcher that, on any input that is a map, extracts the 314 | // type of keys and elements and matches them against the given matchers. 315 | // 316 | // If the given input is not an map, this fails to match. 317 | // Note: this matches maps, not map *types*. (See MapTypeOf.) 318 | // 319 | // This matcher is logically equivalent to: 320 | // AllOf(MapWithKeyType(keyTypeMatcher), MapWithElementType(elementTypeMatcher)) 321 | // but may be easier to read/type. 322 | func MapOf(keyTypeMatcher, elementTypeMatcher *base.Matcher) *base.Matcher { 323 | return ToType(MapTypeOf(keyTypeMatcher, elementTypeMatcher)) 324 | } 325 | 326 | 327 | 328 | // Returns a new matcher that, on any input that is a *reflect.PtrType, 329 | // extracts the type of object that it thinks it's pointing to (the 330 | // "pointee") and matches it against the given matcher. 331 | // 332 | // If the given input is not an *reflect.PtrType, this fails to match. 333 | // Note: this matches pointer *types*, not pointers. (See PointerOf.) 334 | func PtrTypeTo(pointeeTypeMatcher *base.Matcher) *base.Matcher { 335 | match := func(actual interface{}) *base.Result { 336 | if ptrType, ok := actual.(*reflect.PtrType); ok { 337 | elementType := ptrType.Elem() 338 | result := pointeeTypeMatcher.Match(elementType) 339 | return base.NewResultf( 340 | result.Matched(), 341 | "was PtrType pointing to type %v", elementType.Name()). 342 | WithCauses(result) 343 | } 344 | return base.NewResultf(false, 345 | "was type %T, not a PtrType", actual) 346 | } 347 | return base.NewMatcherf(match, 348 | "PtrTypeTo(%v)", pointeeTypeMatcher) 349 | } 350 | 351 | // Returns a new matcher that, on any input that is a pointer, extracts the 352 | // type of object that it thinks it's pointing to (the "pointee") and 353 | // matches it against the given matcher. 354 | // 355 | // If the given input is not an pointer, this fails to match. 356 | // Note: this matches *pointers*, not pointer *types*. (See PtrTypeTo.) 357 | func PtrTo(pointeeTypeMatcher *base.Matcher) *base.Matcher { 358 | match := func(actual interface{}) *base.Result { 359 | actualType := reflect.Typeof(actual) 360 | if ptrType, ok := actualType.(*reflect.PtrType); ok { 361 | elementType := ptrType.Elem() 362 | result := pointeeTypeMatcher.Match(elementType) 363 | return base.NewResultf( 364 | result.Matched(), "was PtrType to type %v", elementType). 365 | WithCauses(result) 366 | } 367 | return base.NewResultf(false, 368 | "was type %T, not a pointer", actual) 369 | } 370 | return base.NewMatcherf(match, 371 | "PtrTo(%v)", pointeeTypeMatcher) 372 | } 373 | 374 | 375 | 376 | 377 | -------------------------------------------------------------------------------- /reflect/reflect_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package reflect 6 | 7 | import ( 8 | "github.com/rdrdr/hamcrest/asserter" 9 | "github.com/rdrdr/hamcrest/base" 10 | . "github.com/rdrdr/hamcrest/core" 11 | "testing" 12 | ) 13 | 14 | var Matched = base.Matched() 15 | var DidNotMatch = base.DidNotMatch() 16 | 17 | func Test_SameTypeAs(t *testing.T) { 18 | we := asserter.Using(t) 19 | 20 | we.CheckThat(SameTypeAs(false).Match(true), Matched) 21 | we.CheckThat(SameTypeAs(true).Match(false), Matched) 22 | 23 | we.CheckThat(SameTypeAs(2).Match(1), Matched) 24 | we.CheckThat(SameTypeAs(int(2)).Match(uint(1)), DidNotMatch) 25 | } 26 | 27 | func Test_Bool_And_BoolType(t *testing.T) { 28 | we := asserter.Using(t) 29 | checkMatch := func(v interface{}) { 30 | we.CheckThat(Bool().Match(v), Matched) 31 | we.CheckThat(ToType(Is(BoolType())).Match(v), Matched) 32 | } 33 | checkNonMatch := func(v interface{}) { 34 | we.CheckThat(Bool().Match(v), DidNotMatch) 35 | we.CheckThat(ToType(Is(BoolType())).Match(v), DidNotMatch) 36 | } 37 | checkMatch(true) 38 | checkNonMatch("true") 39 | checkMatch(false) 40 | checkNonMatch("false") 41 | checkNonMatch(nil) 42 | checkNonMatch(interface{}(nil)) 43 | } 44 | 45 | func Test_Int(t *testing.T) { 46 | we := asserter.Using(t) 47 | checkMatch := func(v interface{}) { 48 | we.CheckThat(v, Is(Int())) 49 | we.CheckThat(v, ToType(Is(IntType()))) 50 | } 51 | checkNonMatch := func(v interface{}) { 52 | we.CheckThat(v, Is(Not(Int()))) 53 | we.CheckThat(v, ToType(Is(Not(IntType())))) 54 | } 55 | checkMatch(1) 56 | checkNonMatch("1") 57 | checkMatch(0) 58 | checkNonMatch(0.0) 59 | checkNonMatch(0i) 60 | checkMatch(-1) 61 | checkNonMatch(nil) 62 | checkNonMatch(true) 63 | checkNonMatch(interface{}(nil)) 64 | } 65 | 66 | func Test_Int8(t *testing.T) { 67 | we := asserter.Using(t) 68 | we.CheckThat(int8(1), Is(Int8())) 69 | we.CheckThat(int8(1), ToType(Is(Int8Type()))) 70 | we.CheckThat(int(1), Is(Not(Int8()))) 71 | we.CheckThat(int(1), ToType(Is(Not(Int8Type())))) 72 | } 73 | 74 | func Test_Int16(t *testing.T) { 75 | we := asserter.Using(t) 76 | we.CheckThat(int16(1), Is(Int16())) 77 | we.CheckThat(int16(1), ToType(Is(Int16Type()))) 78 | we.CheckThat(int(1), Is(Not(Int16()))) 79 | we.CheckThat(int(1), ToType(Is(Not(Int16Type())))) 80 | } 81 | 82 | func Test_Int32(t *testing.T) { 83 | we := asserter.Using(t) 84 | we.CheckThat(int32(1), Is(Int32())) 85 | we.CheckThat(int32(1), ToType(Is(Int32Type()))) 86 | we.CheckThat(int(1), Is(Not(Int32()))) 87 | we.CheckThat(int(1), ToType(Is(Not(Int32Type())))) 88 | } 89 | 90 | func Test_Int64(t *testing.T) { 91 | we := asserter.Using(t) 92 | we.CheckThat(int64(1), Is(Int64())) 93 | we.CheckThat(int64(1), ToType(Is(Int64Type()))) 94 | we.CheckThat(int(1), Is(Not(Int64()))) 95 | we.CheckThat(int(1), ToType(Is(Not(Int64Type())))) 96 | } 97 | 98 | func Test_Uint(t *testing.T) { 99 | we := asserter.Using(t) 100 | we.CheckThat(uint(1), Is(Uint())) 101 | we.CheckThat(uint(1), ToType(Is(UintType()))) 102 | we.CheckThat(int(1), Is(Not(Uint()))) 103 | we.CheckThat(int(1), ToType(Is(Not(UintType())))) 104 | } 105 | 106 | func Test_Uint8(t *testing.T) { 107 | we := asserter.Using(t) 108 | we.CheckThat(uint8(1), Is(Uint8())) 109 | we.CheckThat(uint8(1), ToType(Is(Uint8Type()))) 110 | we.CheckThat(uint(1), Is(Not(Uint8()))) 111 | we.CheckThat(uint(1), ToType(Is(Not(Uint8Type())))) 112 | } 113 | 114 | func Test_Uint16(t *testing.T) { 115 | we := asserter.Using(t) 116 | we.CheckThat(uint16(1), Is(Uint16())) 117 | we.CheckThat(uint16(1), ToType(Is(Uint16Type()))) 118 | we.CheckThat(uint(1), Is(Not(Uint16()))) 119 | we.CheckThat(uint(1), ToType(Is(Not(Uint16Type())))) 120 | } 121 | 122 | func Test_Uint32(t *testing.T) { 123 | we := asserter.Using(t) 124 | we.CheckThat(uint32(1), Is(Uint32())) 125 | we.CheckThat(uint32(1), ToType(Is(Uint32Type()))) 126 | we.CheckThat(uint(1), Is(Not(Uint32()))) 127 | we.CheckThat(uint(1), ToType(Is(Not(Uint32Type())))) 128 | } 129 | 130 | func Test_Uint64(t *testing.T) { 131 | we := asserter.Using(t) 132 | we.CheckThat(uint64(1), Is(Uint64())) 133 | we.CheckThat(uint64(1), ToType(Is(Uint64Type()))) 134 | we.CheckThat(uint(1), Is(Not(Uint64()))) 135 | we.CheckThat(uint(1), ToType(Is(Not(Uint64Type())))) 136 | } 137 | 138 | func Test_Float32(t *testing.T) { 139 | we := asserter.Using(t) 140 | checkMatch := func(v interface{}) { 141 | we.CheckThat(v, Is(Float32())) 142 | we.CheckThat(v, ToType(Is(Float32Type()))) 143 | } 144 | checkNonMatch := func(v interface{}) { 145 | we.CheckThat(v, Is(Not(Float32()))) 146 | we.CheckThat(v, ToType(Is(Not(Float32Type())))) 147 | } 148 | checkMatch(float32(1.0)) 149 | checkNonMatch("1.0") 150 | checkNonMatch(0) 151 | checkNonMatch(float64(0.0)) 152 | checkNonMatch(complex64(0)) 153 | checkNonMatch(nil) 154 | checkNonMatch(true) 155 | checkNonMatch(interface{}(nil)) 156 | } 157 | 158 | func Test_Float64(t *testing.T) { 159 | we := asserter.Using(t) 160 | we.CheckThat(float64(1.0), Is(Float64())) 161 | we.CheckThat(float64(1.0), ToType(Is(Float64Type()))) 162 | we.CheckThat(float32(1.0), Is(Not(Float64()))) 163 | we.CheckThat(float32(1.0), ToType(Is(Not(Float64Type())))) 164 | we.CheckThat(complex128(1.0), Is(Not(Float64()))) 165 | we.CheckThat(complex128(1.0), ToType(Is(Not(Float64Type())))) 166 | } 167 | 168 | func Test_Complex64(t *testing.T) { 169 | we := asserter.Using(t) 170 | checkMatch := func(v interface{}) { 171 | we.CheckThat(v, Is(Complex64())) 172 | we.CheckThat(v, ToType(Is(Complex64Type()))) 173 | } 174 | checkNonMatch := func(v interface{}) { 175 | we.CheckThat(v, Is(Not(Complex64()))) 176 | we.CheckThat(v, ToType(Is(Not(Complex64Type())))) 177 | } 178 | checkMatch(complex64(1.0)) 179 | checkMatch(complex64(1.0i)) 180 | checkNonMatch("1+0i") 181 | checkNonMatch(1) 182 | checkNonMatch(float32(1.0)) 183 | checkNonMatch(float64(1.0)) 184 | checkNonMatch(complex128(1.0)) 185 | checkNonMatch(complex128(1.0)) 186 | checkNonMatch(nil) 187 | checkNonMatch(true) 188 | checkNonMatch(interface{}(nil)) 189 | } 190 | 191 | func Test_Complex128(t *testing.T) { 192 | we := asserter.Using(t) 193 | we.CheckThat(complex128(1.0i), Is(Complex128())) 194 | we.CheckThat(complex128(1.0i), ToType(Is(Complex128Type()))) 195 | we.CheckThat(complex64(1.0i), Is(Not(Complex128()))) 196 | we.CheckThat(complex64(1.0i), ToType(Is(Not(Complex128Type())))) 197 | we.CheckThat(float64(1.0), Is(Not(Complex128()))) 198 | we.CheckThat(float64(1.0), ToType(Is(Not(Complex128Type())))) 199 | } 200 | 201 | func Test_String(t *testing.T) { 202 | we := asserter.Using(t) 203 | checkMatch := func(v interface{}) { 204 | we.CheckThat(v, Is(String())) 205 | we.CheckThat(v, ToType(Is(StringType()))) 206 | } 207 | checkNonMatch := func(v interface{}) { 208 | we.CheckThat(v, Is(Not(String()))) 209 | we.CheckThat(v, ToType(Is(Not(StringType())))) 210 | } 211 | checkMatch("") 212 | checkMatch("non-empty") 213 | checkNonMatch(nil) 214 | checkNonMatch(true) 215 | checkNonMatch(1) 216 | checkNonMatch(1.0) 217 | checkNonMatch(1i) 218 | checkNonMatch(interface{}(nil)) 219 | } 220 | 221 | func Test_ArrayOf(t *testing.T) { 222 | we := asserter.Using(t) 223 | boolArray := [2]bool {true, false} 224 | intArray := [3]int {1, 2, 3} 225 | intArrayArray := [2][3]int { {1, 2, 3}, {4, 5, 6} } 226 | 227 | we.CheckThat(boolArray, Is(ArrayOf(Anything()))) 228 | we.CheckThat(intArray, Is(ArrayOf(Anything()))) 229 | we.CheckThat(intArrayArray, Is(ArrayOf(Anything()))) 230 | 231 | we.CheckThat(boolArray, Is(ArrayOf(BoolType()))) 232 | we.CheckThat(boolArray, ToType(Is(ArrayTypeOf(BoolType())))) 233 | 234 | we.CheckThat(intArray, Is(Not(ArrayOf(BoolType())))) 235 | we.CheckThat(intArray, Is(ArrayOf(IntType()))) 236 | 237 | we.CheckThat(intArrayArray, Is(Not(ArrayOf(IntType())))) 238 | we.CheckThat(intArrayArray, Is(Not(ArrayOf(ArrayOf(IntType()))))) 239 | 240 | intSlice := make([]int, 0, 1) 241 | we.CheckThat(intSlice, Is(Not(ArrayOf(Anything())))) 242 | } 243 | 244 | func Test_ArrayTypeOf(t *testing.T) { 245 | we := asserter.Using(t) 246 | boolArray := [2]bool {true, false} 247 | intArray := [3]int {1, 2, 3} 248 | intArrayArray := [2][3]int { {1, 2, 3}, {4, 5, 6} } 249 | 250 | we.CheckThat(boolArray, ToType(Is(ArrayTypeOf(Anything())))) 251 | we.CheckThat(intArray, ToType(Is(ArrayTypeOf(Anything())))) 252 | we.CheckThat(intArrayArray, ToType(Is(ArrayTypeOf(Anything())))) 253 | 254 | we.CheckThat(boolArray, ToType(Is(ArrayTypeOf(BoolType())))) 255 | we.CheckThat(boolArray, ToType(Is(Not(ArrayTypeOf(IntType()))))) 256 | 257 | we.CheckThat(intArray, ToType(Is(Not(ArrayTypeOf(BoolType()))))) 258 | we.CheckThat(intArray, ToType(Is(ArrayTypeOf(IntType())))) 259 | 260 | we.CheckThat(intArrayArray, Is(Not(ArrayTypeOf(ArrayOf(IntType()))))) 261 | we.CheckThat(intArrayArray, Is(ArrayOf(ArrayTypeOf(IntType())))) 262 | we.CheckThat(intArrayArray, ToType(Is(ArrayTypeOf(ArrayTypeOf(IntType()))))) 263 | 264 | intSlice := make([]int, 0, 1) 265 | we.CheckThat(intSlice, ToType(Is(Not(ArrayTypeOf(Anything()))))) 266 | } 267 | 268 | func Test_ChanOf(t *testing.T) { 269 | we := asserter.Using(t) 270 | intObj := 1 271 | intChan := make(chan int, 1) 272 | intChanIn := func(ch chan int) chan<- int { return ch }(intChan) 273 | intChanOut := func(ch chan int) <-chan int { return ch }(intChan) 274 | 275 | we.CheckThat(intObj, Is(Not(ChannelOf(Anything())))) 276 | 277 | we.CheckThat(intChan, Is(ChannelOf(IntType()))) 278 | we.CheckThat(intChan, Is(Not(ChannelOf(StringType())))) 279 | 280 | we.CheckThat(intChanIn, Is(ChannelOf(IntType()))) 281 | we.CheckThat(intChanIn, Is(Not(ChannelOf(StringType())))) 282 | 283 | we.CheckThat(intChanOut, Is(ChannelOf(IntType()))) 284 | we.CheckThat(intChanOut, Is(Not(ChannelOf(StringType())))) 285 | } 286 | 287 | func Test_ChanTypeOf(t *testing.T) { 288 | we := asserter.Using(t) 289 | intObj := 1 290 | intChan := make(chan int, 1) 291 | intChanIn := func(ch chan int) chan<- int { return ch }(intChan) 292 | intChanOut := func(ch chan int) <-chan int { return ch }(intChan) 293 | 294 | we.CheckThat(intObj, ToType(Is(Not(ChannelTypeOf(Anything()))))) 295 | 296 | we.CheckThat(intChan, ToType(Is(ChannelTypeOf(IntType())))) 297 | we.CheckThat(intChan, ToType(Is(Not(ChannelTypeOf(StringType()))))) 298 | 299 | we.CheckThat(intChanIn, ToType(Is(ChannelTypeOf(IntType())))) 300 | we.CheckThat(intChanIn, ToType(Is(Not(ChannelTypeOf(StringType()))))) 301 | 302 | we.CheckThat(intChanOut, ToType(Is(ChannelTypeOf(IntType())))) 303 | we.CheckThat(intChanOut, ToType(Is(Not(ChannelTypeOf(StringType()))))) 304 | } 305 | 306 | func Test_SliceTypeOf(t *testing.T) { 307 | we := asserter.Using(t) 308 | boolSlice := make([]bool, 0, 1) 309 | intSlice := make([]int, 0, 1) 310 | intSliceSlice := make([][]int, 0, 1) 311 | 312 | we.CheckThat(boolSlice, Is(SliceOf(BoolType()))) 313 | we.CheckThat(boolSlice, Is(Not(SliceOf(IntType())))) 314 | we.CheckThat(boolSlice, ToType(Is(SliceTypeOf(BoolType())))) 315 | we.CheckThat(boolSlice, ToType(Is(Not(SliceTypeOf(IntType()))))) 316 | 317 | we.CheckThat(intSlice, Is(Not(SliceOf(BoolType())))) 318 | we.CheckThat(intSlice, Is(SliceOf(IntType()))) 319 | we.CheckThat(intSlice, ToType(Is(Not(SliceTypeOf(BoolType()))))) 320 | we.CheckThat(intSlice, ToType(Is(SliceTypeOf(IntType())))) 321 | 322 | we.CheckThat(intSliceSlice, Is(Not(SliceOf(IntType())))) 323 | we.CheckThat(intSliceSlice, Is(Not(SliceOf(SliceOf(IntType()))))) 324 | we.CheckThat(intSliceSlice, Is(Not(SliceTypeOf(SliceOf(IntType()))))) 325 | we.CheckThat(intSliceSlice, Is(SliceOf(SliceTypeOf(IntType())))) 326 | we.CheckThat(intSliceSlice, ToType(Is(SliceTypeOf(SliceTypeOf(IntType()))))) 327 | 328 | var intArray = [3]int{1, 2, 3} 329 | we.CheckThat(intArray, Is(Not(SliceOf(Anything())))) 330 | we.CheckThat(intArray, ToType(Is(Not(SliceTypeOf(Anything()))))) 331 | } 332 | 333 | func Test_MapOf(t *testing.T) { 334 | we := asserter.Using(t) 335 | intStringMap := map[int]string{1: "one", 2: "two"} 336 | 337 | we.CheckThat(intStringMap, Is(MapOf(IntType(), StringType()))) 338 | we.CheckThat(intStringMap, Is(Not(MapOf(StringType(), StringType())))) 339 | we.CheckThat(intStringMap, Is(Not(MapOf(IntType(), IntType())))) 340 | we.CheckThat(intStringMap, Is(Not(MapOf(StringType(), IntType())))) 341 | } 342 | 343 | func Test_MapTypeOf(t *testing.T) { 344 | we := asserter.Using(t) 345 | intStringMap := map[int]string{1: "one", 2: "two"} 346 | 347 | we.CheckThat(intStringMap, ToType(Is(MapTypeOf(IntType(), StringType())))) 348 | we.CheckThat(intStringMap, ToType(Is(Not(MapTypeOf(StringType(), StringType()))))) 349 | we.CheckThat(intStringMap, ToType(Is(Not(MapTypeOf(IntType(), IntType()))))) 350 | we.CheckThat(intStringMap, ToType(Is(Not(MapTypeOf(StringType(), IntType()))))) 351 | } 352 | 353 | func Test_PtrTypeTo(t *testing.T) { 354 | we := asserter.Using(t) 355 | intObj := 1 356 | intPtr := &intObj 357 | intPtrPtr := &intPtr 358 | 359 | we.CheckThat(intObj, Is(Not(PtrTo(Anything())))) 360 | 361 | we.CheckThat(intPtr, Is(PtrTo(IntType()))) 362 | we.CheckThat(intPtr, Is(Not(PtrTo(StringType())))) 363 | 364 | we.CheckThat(intPtr, ToType(Is(PtrTypeTo(IntType())))) 365 | we.CheckThat(intPtr, ToType(Is(Not(PtrTypeTo(StringType()))))) 366 | 367 | we.CheckThat(intPtrPtr, ToType(Is(Not(PtrTypeTo(IntType()))))) 368 | we.CheckThat(intPtrPtr, ToType(Is(PtrTypeTo(PtrTypeTo(IntType()))))) 369 | } 370 | 371 | -------------------------------------------------------------------------------- /slices/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Mick Killianey. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | include $(GOROOT)/src/Make.inc 6 | 7 | TARG=github.com/rdrdr/hamcrest/slices 8 | GOFILES=\ 9 | slices.go\ 10 | 11 | include $(GOROOT)/src/Make.pkg 12 | -------------------------------------------------------------------------------- /slices/slices.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package slices 6 | 7 | import ( 8 | "github.com/rdrdr/hamcrest/base" 9 | "reflect" 10 | ) 11 | 12 | type _ElemAndLen interface { 13 | Elem(i int) reflect.Value 14 | Len() int 15 | } 16 | 17 | // Returns a matcher that matches on any array or slice input value 18 | // if the given matcher matches at least one element of that array 19 | // or slice. 20 | // 21 | // The returned matcher does not match any non-array-or-slice value. 22 | func AnyElem(matcher *base.Matcher) *base.Matcher { 23 | match := func(actual interface{}) *base.Result { 24 | v := reflect.NewValue(actual) 25 | if value, ok := v.(_ElemAndLen); ok { 26 | n := value.Len() 27 | for i := 0; i < n; i++ { 28 | elem := value.Elem(i).Interface() 29 | result := matcher.Match(elem) 30 | if result.Matched() { 31 | return base.NewResultf(true, 32 | "Matched element %v of %v: %v", i+1, n, elem). 33 | WithCauses(result) 34 | } 35 | } 36 | return base.NewResultf(false, 37 | "Matched none of the %v elements", n) 38 | } 39 | return matcher.Match(v) 40 | } 41 | return base.NewMatcherf(match, "AnyElement[%v]", matcher) 42 | } 43 | 44 | // Returns a matcher that matches on any array or slice input value 45 | // if the given matcher matches every element of that array or slice. 46 | // 47 | // The returned matcher does not match any non-array-or-slice value. 48 | func EachElem(matcher *base.Matcher) *base.Matcher { 49 | match := func(actual interface{}) *base.Result { 50 | v := reflect.NewValue(actual) 51 | var value _ElemAndLen 52 | var ok bool 53 | value, ok = v.(*reflect.ArrayValue) 54 | if !ok { 55 | value, ok = v.(*reflect.SliceValue) 56 | } 57 | if !ok { 58 | return base.NewResultf(false, 59 | "Was not array or slice: was type %T", actual) 60 | } 61 | n := value.Len() 62 | for i := 0; i < n; i++ { 63 | elem := value.Elem(i).Interface() 64 | result := matcher.Match(elem) 65 | if !result.Matched() { 66 | return base.NewResultf(false, 67 | "Failed to match element %v of %v: %v", 68 | i+1, n, elem). 69 | WithCauses(result) 70 | } 71 | } 72 | return base.NewResultf(true, 73 | "Matched all of the %v elements", n) 74 | } 75 | return base.NewMatcherf(match, "EveryElement[%v]", matcher) 76 | } 77 | 78 | type _HasLen interface { Len() int } 79 | 80 | // Applies the given matcher to the length of the input element. 81 | func ToLen(matcher *base.Matcher) *base.Matcher { 82 | match := func(actual interface{}) *base.Result { 83 | value := reflect.NewValue(actual) 84 | if hasLen, ok := value.(_HasLen); ok { 85 | length := hasLen.Len() 86 | result := matcher.Match(length) 87 | return base.NewResultf(result.Matched(), "Len() returned %v", length) 88 | } 89 | return base.NewResultf(false, 90 | "Can't determine Len() for %T", actual) 91 | } 92 | return base.NewMatcherf(match, "ToLen[%v]", matcher) 93 | } 94 | 95 | // Matches any input element that is an empty array, slice, or map. 96 | func Empty() *base.Matcher { 97 | match := func(actual interface{}) *base.Result { 98 | value := reflect.NewValue(actual) 99 | if hasLen, ok := value.(_HasLen); ok { 100 | length := hasLen.Len() 101 | return base.NewResultf(length == 0, 102 | "Len() returned %v", length) 103 | } 104 | return base.NewResultf(false, "Can't determine length of type %T", actual) 105 | } 106 | return base.NewMatcherf(match, "Empty") 107 | } 108 | 109 | -------------------------------------------------------------------------------- /slices/slices_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package slices 6 | 7 | import ( 8 | "github.com/rdrdr/hamcrest/asserter" 9 | . "github.com/rdrdr/hamcrest/core" 10 | "github.com/rdrdr/hamcrest/base" 11 | "testing" 12 | ) 13 | 14 | var Matched = base.Matched() 15 | var DidNotMatch = base.DidNotMatch() 16 | 17 | func Test_AnyElem(t *testing.T) { 18 | we := asserter.Using(t) 19 | we.CheckThat(AnyElem(EqualTo(1)).Match([]int{1, 2, 3}), 20 | Matched.Comment("first element")) 21 | we.CheckThat(AnyElem(EqualTo(2)).Match([]int{1, 2, 3}), 22 | Matched.Comment("middle element")) 23 | we.CheckThat(AnyElem(EqualTo(3)).Match([]int{1, 2, 3}), 24 | Matched.Comment("last element")) 25 | we.CheckThat(AnyElem(EqualTo(4)).Match([]int{1, 2, 3}), 26 | DidNotMatch.Comment("None of the three match")) 27 | we.CheckThat(AnyElem(Anything()).Match([]int{}), 28 | DidNotMatch.Comment("no elements")) 29 | } 30 | 31 | func Test_EachElem(t *testing.T) { 32 | we := asserter.Using(t) 33 | we.CheckThat(EachElem(NotEqualTo(1)).Match([]int{1, 2, 3}), 34 | DidNotMatch.Comment("all but first element")) 35 | we.CheckThat(EachElem(NotEqualTo(2)).Match([]int{1, 2, 3}), 36 | DidNotMatch.Comment("all but middle element")) 37 | we.CheckThat(EachElem(NotEqualTo(3)).Match([]int{1, 2, 3}), 38 | DidNotMatch.Comment("all but last element")) 39 | we.CheckThat(EachElem(NotEqualTo(4)).Match([]int{1, 2, 3}), 40 | Matched.Comment("all match")) 41 | we.CheckThat(EachElem(Anything()).Match([]int{}), 42 | Matched.Comment("no elements")) 43 | } 44 | 45 | func Test_ToLen(t *testing.T) { 46 | we := asserter.Using(t) 47 | IsLength2 := ToLen(Is(EqualTo(2))) 48 | we.CheckThat(IsLength2.Match([]int{}), DidNotMatch.Comment("no elements")) 49 | we.CheckThat(IsLength2.Match([]int{7}), DidNotMatch.Comment("too few")) 50 | we.CheckThat(IsLength2.Match([]int{7, 8}), Matched.Comment("just right")) 51 | we.CheckThat(IsLength2.Match([]int{7, 8, 9}), DidNotMatch.Comment("too many")) 52 | } 53 | 54 | func Test_Empty(t *testing.T) { 55 | we := asserter.Using(t) 56 | we.CheckThat(Empty().Match([]int{}), Matched.Comment("no ints")) 57 | we.CheckThat(Empty().Match([]string{}), Matched.Comment("no strings")) 58 | we.CheckThat(Empty().Match([]string{"not", "empty"}), DidNotMatch) 59 | } 60 | -------------------------------------------------------------------------------- /strings/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Mick Killianey. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | include $(GOROOT)/src/Make.inc 6 | 7 | TARG=github.com/rdrdr/hamcrest/strings 8 | GOFILES=\ 9 | strings.go\ 10 | 11 | include $(GOROOT)/src/Make.pkg 12 | -------------------------------------------------------------------------------- /strings/strings.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package strings 6 | 7 | import ( 8 | "fmt" 9 | "github.com/rdrdr/hamcrest/base" 10 | "regexp" 11 | "strings" 12 | ) 13 | 14 | // Applies the given matcher to the result of writing the input object's 15 | // to a string by using fmt.Sprintf("%v", object). 16 | func ToString(matcher *base.Matcher) *base.Matcher { 17 | match := func(actual interface{}) *base.Result { 18 | if stringer, ok := actual.(fmt.Stringer); ok { 19 | s := stringer.String() 20 | result := matcher.Match(s) 21 | return base.NewResultf( 22 | result.Matched(), "String() returned %v", s). 23 | WithCauses(result) 24 | } 25 | s := fmt.Sprintf("%v", actual) 26 | result := matcher.Match(s) 27 | return base.NewResultf(result.Matched(), 28 | "Not a fmt.Stringer, but prints as %v", s). 29 | WithCauses(result) 30 | } 31 | return base.NewMatcherf(match, "ToString(%v)", matcher) 32 | } 33 | 34 | 35 | // Applies the given matcher to the result of writing the input object's 36 | // to a string by using fmt.Sprintf("%#v", object). 37 | func ToGoString(matcher *base.Matcher) *base.Matcher { 38 | match := func(actual interface{}) *base.Result { 39 | if gostringer, ok := actual.(fmt.GoStringer); ok { 40 | s := gostringer.GoString() 41 | result := matcher.Match(s) 42 | return base.NewResultf(result.Matched(), 43 | "GoString() returned %v", s). 44 | WithCauses(result) 45 | } 46 | s := fmt.Sprintf("%#v", actual) 47 | result := matcher.Match(s) 48 | return base.NewResultf(result.Matched(), 49 | "Not a fmt.GoStringer, but prints as %v", s). 50 | WithCauses(result) 51 | } 52 | return base.NewMatcherf(match, "ToGoString(%v)", matcher) 53 | } 54 | 55 | 56 | // Creates a new matcher that applies the given matcher to the result of 57 | // converting an input string to lowercase (using strings.ToLower). 58 | // If the input value is not a string, the matcher fails to match. 59 | func ToLower(matcher *base.Matcher) *base.Matcher { 60 | match := func(s string) *base.Result { 61 | lower := strings.ToLower(s) 62 | result := matcher.Match(lower) 63 | return base.NewResultf(result.Matched(), 64 | "ToLower is %v", lower). 65 | WithCauses(result) 66 | } 67 | return base.NewMatcherf(match, "ToLower(%v)", matcher) 68 | } 69 | 70 | 71 | // Creates a new matcher that applies the given matcher to the result of 72 | // converting an input string to uppercase (using strings.ToUpper). 73 | // If the input value is not a string, the matcher fails to match. 74 | func ToUpper(matcher *base.Matcher) *base.Matcher { 75 | match := func(s string) *base.Result { 76 | upper := strings.ToUpper(s) 77 | result := matcher.Match(upper) 78 | return base.NewResultf(result.Matched(), 79 | "ToUpper is %v", upper). 80 | WithCauses(result) 81 | } 82 | return base.NewMatcherf(match, "ToUpper(%v)", matcher) 83 | } 84 | 85 | func EqualToIgnoringCase(expected string) *base.Matcher { 86 | expectedToLower := strings.ToLower(expected) 87 | match := func(actual string) *base.Result { 88 | actualToLower := strings.ToLower(actual) 89 | if actualToLower == expectedToLower { 90 | return base.NewResultf(true, 91 | "\"%v\" matches \"%v\" (ignoring case)", 92 | actual, expected) 93 | } 94 | return base.NewResultf(false, 95 | "\"%v\" differs from \"%v\" (ignoring case)", 96 | actual, expected) 97 | } 98 | return base.NewMatcherf(match, "EqualToIgnoringCase(\"%v\")", expected) 99 | } 100 | 101 | 102 | 103 | // Creates a new matcher that applies the given matcher to the result of 104 | // converting an input string its length. (using the `len()` builtin). 105 | // If the input value is not a string, the matcher fails to match. 106 | func ToLen(matcher *base.Matcher) *base.Matcher { 107 | match := func(s string) *base.Result { 108 | length := len(s) 109 | result := matcher.Match(length) 110 | return base.NewResultf(result.Matched(), 111 | "length is %v", length). 112 | WithCauses(result) 113 | } 114 | return base.NewMatcherf(match, "ToLen(%v)", matcher) 115 | } 116 | 117 | 118 | // Matches strings that begin with the given prefix. 119 | func HasPrefix(prefix string) *base.Matcher { 120 | maxLength := len(prefix) + 8 // arbitrary extra amount 121 | match := func (s string) *base.Result { 122 | continued := "" 123 | if len(s) > maxLength { 124 | s, continued = s[:maxLength], "..." 125 | } 126 | if strings.HasPrefix(s, prefix) { 127 | return base.NewResultf(true, 128 | "\"%v%v\" starts with \"%v\"", s, continued, prefix) 129 | } 130 | return base.NewResultf(false, 131 | "\"%v%v\" does not start with \"%v\"", s, continued, prefix) 132 | } 133 | return base.NewMatcherf(match, "HasPrefix(\"%v\")", prefix) 134 | } 135 | 136 | // Matches strings that end with the given prefix. 137 | func HasSuffix(suffix string) *base.Matcher { 138 | maxLength := len(suffix) + 8 // arbitrary extra amount 139 | match := func (s string) *base.Result { 140 | continued := "" 141 | if len(s) > maxLength { 142 | continued, s = "...", s[len(s) - maxLength:] 143 | } 144 | if strings.HasSuffix(s, suffix) { 145 | return base.NewResultf(true, 146 | "\"%v%v\" ends with \"%v\"", s, continued, suffix) 147 | } 148 | return base.NewResultf(false, 149 | "\"%v%v\" does not end with \"%v\"", s, continued, suffix) 150 | } 151 | return base.NewMatcherf(match, "HasSuffix(\"%v\")", suffix) 152 | } 153 | 154 | 155 | // Matches strings that contain the given substring. 156 | func Contains(substring string) *base.Matcher { 157 | match := func (s string) *base.Result { 158 | extra := 8 159 | if foundStart := strings.Index(s, substring); foundStart >= 0 { 160 | foundEnd := foundStart + len(substring) 161 | start, end := foundStart - extra, foundEnd + extra 162 | prefix, suffix := "", "" 163 | if start <= 0 { 164 | start = 0 165 | } else { 166 | prefix = "..." 167 | } 168 | if end >= len(s) { 169 | end = len(s) 170 | } else { 171 | suffix = "..." 172 | } 173 | return base.NewResultf(true, 174 | "substring \"%v\" appears in \"%v%v[%v]%v%v\"", substring, 175 | prefix, s[start:foundStart], substring, s[foundEnd:end], suffix) 176 | } 177 | return base.NewResultf(false, 178 | "substring \"%v\" does not appear in \"%v\"", 179 | substring, s) 180 | } 181 | return base.NewMatcherf(match, "Contains(\"%v\")", substring) 182 | } 183 | 184 | // Matches strings that contain the given regexp pattern, using 185 | // the same syntax as the standard regexp package. 186 | func HasPattern(pattern string) *base.Matcher { 187 | re := regexp.MustCompile(pattern) 188 | match := func (s string) *base.Result { 189 | if found := re.FindStringIndex(s); found != nil { 190 | start, end := found[0], found[1] 191 | return base.NewResultf(true, 192 | "pattern \"%v\" matched substring[%v:%v]=\"%v\"", 193 | pattern, start, end, s[start:end]) 194 | } 195 | return base.NewResultf(false, 196 | "pattern \"%v\" not found in \"%v\"", pattern, s) 197 | } 198 | return base.NewMatcherf(match, "HasPattern[\"%v\"]", pattern) 199 | } 200 | 201 | type WithPatternClause struct { 202 | re *regexp.Regexp 203 | group int 204 | } 205 | 206 | // Returns a short-circuiting function that applies the matcher to each 207 | // occurrence of the pattern in an input string, until a failing pattern 208 | // is found (in which case the output matcher fails to match) or all 209 | // matching instances are exhausted (in which case the output matcher 210 | // successfully matches). 211 | // 212 | // For example: 213 | // EachPattern("q.")(EqualTo("qu")) 214 | // would match: 215 | // "quick quack mq" (two matches of "q.", both equal to "qu") 216 | // but not: 217 | // "quick qs for mq" (two matches of "q.", second is not "qu") 218 | func EachPattern(pattern string) func(matcher *base.Matcher) *base.Matcher { 219 | re := regexp.MustCompile(pattern) 220 | return func(matcher *base.Matcher) *base.Matcher { 221 | match := func(s string) *base.Result { 222 | matches := re.FindAllStringIndex(s, -1) 223 | if matches == nil { 224 | return base.NewResultf(true, 225 | "No occurrences of pattern \"%v\"", pattern) 226 | } 227 | for index, loc := range matches { 228 | start, end := loc[0], loc[1] 229 | substring := s[start:end] 230 | result := matcher.Match(substring) 231 | if !result.Matched() { 232 | return base.NewResultf(false, 233 | "did not match substring[%v:%v]=\"%v\", occurrence #%v (of %v) of pattern \"%v\"", 234 | start, end, substring, index+1, len(matches), pattern) 235 | } 236 | } 237 | return base.NewResultf(true, 238 | "Matched every occurrence (all %v) of pattern \"%v\"", 239 | len(matches), pattern) 240 | } 241 | return base.NewMatcherf(match, 242 | "EachPattern[\"%v\"][%v]", pattern, matcher) 243 | } 244 | } 245 | 246 | // Variant of EachPattern() that uses the given subgroup of the pattern. 247 | func EachPatternGroup(pattern string, group int) func(matcher *base.Matcher) *base.Matcher { 248 | re := regexp.MustCompile(pattern) 249 | if num := re.NumSubexp(); num < group { 250 | println("Illegal group #", group, ": there are only ", num, "groups.") 251 | panic("Group index out of bounds.") 252 | } 253 | return func(matcher *base.Matcher) *base.Matcher { 254 | match := func(s string) *base.Result { 255 | matches := re.FindAllStringSubmatchIndex(s, -1) 256 | if matches == nil { 257 | return base.NewResultf(true, 258 | "No occurrences of pattern \"%v\"", pattern) 259 | } 260 | for index, loc := range matches { 261 | substart, subend := loc[2*group], loc[2*group+1] 262 | substring := s[substart:subend] 263 | result := matcher.Match(substring) 264 | if !result.Matched() { 265 | start, end := loc[0], loc[1] 266 | prefix, suffix := s[start:substart], s[subend:end] 267 | return base.NewResultf(false, 268 | "did not match substring[%v:%v], [%v:%v]=\"%v[%v]%v\", occurrence #%v (of %v) of pattern \"%v\"", 269 | substart, subend, start, end, 270 | prefix, substring, suffix, index+1, len(matches), pattern) 271 | } 272 | } 273 | return base.NewResultf(true, 274 | "Matched every occurrence (all %v) of pattern \"%v\", group %v", 275 | len(matches), pattern, group) 276 | } 277 | return base.NewMatcherf(match, 278 | "EachPatternGroup[\"%v\", %v][%v]", pattern, group, matcher) 279 | } 280 | } 281 | 282 | 283 | // Returns a short-circuiting function that applies the matcher to each 284 | // occurrence of the pattern in an input string, until a matching pattern 285 | // is found (in which case the matcher successfully matches) or all 286 | // matching instances are exhausted (in which case the output matcher 287 | // fails to match). 288 | // 289 | // For example: 290 | // AnyPattern("x.")(EqualTo("xy")) 291 | // would match: 292 | // "six sax are sexy" (three matches of "x.", third is "xy") 293 | // but not: 294 | // "pox pix are pixelated" (three matches of "x.", none is "xy") 295 | func AnyPattern(pattern string) func(matcher *base.Matcher) *base.Matcher { 296 | re := regexp.MustCompile(pattern) 297 | return func(matcher *base.Matcher) *base.Matcher { 298 | match := func(s string) *base.Result { 299 | matches := re.FindAllStringIndex(s, -1) 300 | if matches == nil { 301 | return base.NewResultf(false, 302 | "No occurrences of pattern \"%v\"", pattern) 303 | } 304 | 305 | for index, loc := range matches { 306 | start, end := loc[0], loc[1] 307 | substring := s[start:end] 308 | result := matcher.Match(substring) 309 | if result.Matched() { 310 | return base.NewResultf(true, 311 | "matched substring[%v:%v]=\"%v\", occurrence #%v (of %v) of pattern \"%v\"", 312 | start, end, substring, index+1, len(matches), pattern) 313 | } 314 | } 315 | return base.NewResultf(false, 316 | "Did not match any occurrence (of %v) of pattern \"%v\"", 317 | len(matches), pattern) 318 | } 319 | return base.NewMatcherf(match, 320 | "AnyPattern[\"%v\"][%v]", pattern, matcher) 321 | } 322 | } 323 | 324 | 325 | // Variant of AnyPattern() that uses the given subgroup of the pattern. 326 | func AnyPatternGroup(pattern string, group int) func(matcher *base.Matcher) *base.Matcher { 327 | re := regexp.MustCompile(pattern) 328 | if num := re.NumSubexp(); num < group { 329 | println("Illegal group #", group, ": there are only ", num, "groups.") 330 | panic("Group index out of bounds.") 331 | } 332 | return func(matcher *base.Matcher) *base.Matcher { 333 | match := func(s string) *base.Result { 334 | matches := re.FindAllStringSubmatchIndex(s, -1) 335 | if matches == nil { 336 | return base.NewResultf(false, 337 | "No occurrences of pattern \"%v\"", pattern) 338 | } 339 | 340 | for index, loc := range matches { 341 | substart, subend := loc[2*group], loc[2*group + 1] 342 | substring := s[substart:subend] 343 | result := matcher.Match(substring) 344 | if result.Matched() { 345 | start, end := loc[0], loc[1] 346 | prefix, suffix := s[start:substart], s[subend:end] 347 | return base.NewResultf(true, 348 | "matched substring[%v:%v], [%v:%v]=\"%v[%v]%v\", occurrence #%v (of %v) of pattern \"%v\"", 349 | substart, subend, start, end, 350 | prefix, substring, suffix, index+1, len(matches), pattern) 351 | } 352 | } 353 | return base.NewResultf(false, 354 | "Did not match any occurrence (of %v) of pattern \"%v\"", 355 | len(matches), pattern) 356 | } 357 | return base.NewMatcherf(match, 358 | "AnyPatternGroup[\"%v\", %v][%v]", pattern, group, matcher) 359 | } 360 | } 361 | 362 | 363 | // Returns a function that applies the matcher to the first occurrence of 364 | // the pattern in an input string. 365 | // 366 | // For example: 367 | // OnPattern("h.s")(EqualTo("his")) 368 | // would match: 369 | // "hers and his" (because the first instance of "h.s" is equal to "his") 370 | // but none of: 371 | // "just hers" (no instances of "h.s") 372 | // "has chisel" (the first instance of "h.s" is not "his") 373 | func OnPattern(pattern string) func(matcher *base.Matcher) *base.Matcher { 374 | re := regexp.MustCompile(pattern) 375 | return func(matcher *base.Matcher) *base.Matcher { 376 | match := func(s string) *base.Result { 377 | matches := re.FindStringIndex(s) 378 | if matches == nil { 379 | return base.NewResultf(false, 380 | "No occurrences of pattern \"%v\"", pattern) 381 | } 382 | start, end := matches[0], matches[1] 383 | substring := s[start:end] 384 | result := matcher.Match(substring) 385 | return base.NewResultf(result.Matched(), 386 | "Found substring[%v:%v]=\"%v\" for pattern \"%v\"", 387 | start, end, substring, pattern).WithCauses(result) 388 | } 389 | return base.NewMatcherf(match, 390 | "OnPattern[\"%v\"][%v]", pattern, matcher) 391 | } 392 | } 393 | 394 | 395 | // Variant of OnPattern() that uses the given subgroup of the pattern. 396 | func OnPatternGroup(pattern string, group int) func(matcher *base.Matcher) *base.Matcher { 397 | re := regexp.MustCompile(pattern) 398 | if num := re.NumSubexp(); num < group { 399 | println("Illegal group #", group, ": there are only ", num, "groups.") 400 | panic("Group index out of bounds.") 401 | } 402 | return func(matcher *base.Matcher) *base.Matcher { 403 | match := func(s string) *base.Result { 404 | loc := re.FindStringSubmatchIndex(s) 405 | if loc == nil { 406 | return base.NewResultf(false, 407 | "No occurrences of pattern \"%v\"", pattern) 408 | } 409 | start, end := loc[0], loc[1] 410 | substart, subend := loc[group*2], loc[group*2+1] 411 | prefix := s[start:substart] 412 | substring := s[substart:subend] 413 | suffix := s[subend:end] 414 | result := matcher.Match(substring) 415 | return base.NewResultf(result.Matched(), 416 | "Found substring[%v:%v], [%v:%v]=\"%v[%v]%v\" for pattern \"%v\"", 417 | substart, subend, start, end, 418 | prefix, substring, suffix, pattern).WithCauses(result) 419 | } 420 | return base.NewMatcherf(match, 421 | "OnPatternGroup[\"%v\", %v][%v]", pattern, group, matcher) 422 | } 423 | } 424 | 425 | -------------------------------------------------------------------------------- /strings/strings_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Mick Killianey. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package strings 6 | 7 | import ( 8 | "fmt" 9 | "github.com/rdrdr/hamcrest/asserter" 10 | "github.com/rdrdr/hamcrest/base" 11 | . "github.com/rdrdr/hamcrest/core" 12 | "testing" 13 | ) 14 | 15 | var Matched = base.Matched() 16 | var DidNotMatch = base.DidNotMatch() 17 | 18 | type _Stringer struct { s string } 19 | func (self *_Stringer) String() string { 20 | return string(self.s) 21 | } 22 | 23 | type _Formatter struct { s string } 24 | func (self *_Formatter) Format(s fmt.State, ch int) { 25 | fmt.Fprint(s, string(self.s)) 26 | } 27 | 28 | type _GoStringer struct { s string } 29 | func (self *_GoStringer) GoString() string { 30 | return string(self.s) 31 | } 32 | 33 | func Test_ToString_builtinTypes(t *testing.T) { 34 | we := asserter.Using(t) 35 | we.CheckThat(EqualTo("123").Match(123), DidNotMatch) 36 | we.CheckThat(ToString(EqualTo("123")).Match(123), Matched) 37 | } 38 | 39 | func Test_ToString_onTypesThatImplementStringer(t *testing.T) { 40 | we := asserter.Using(t) 41 | stringer := &_Stringer{s:"123"} 42 | we.CheckThat(EqualTo("123").Match(stringer), DidNotMatch) 43 | we.CheckThat(ToString(EqualTo("123")).Match(stringer), Matched) 44 | } 45 | 46 | func Test_ToString_onTypesThatImplementFormatter(t *testing.T) { 47 | we := asserter.Using(t) 48 | formatter := &_Formatter{s:"123"} 49 | we.CheckThat(EqualTo("123").Match(formatter), DidNotMatch) 50 | we.CheckThat(ToString(EqualTo("123")).Match(formatter), Matched) 51 | } 52 | 53 | func Test_ToGoString_onTypesThatImplementGoStringer(t *testing.T) { 54 | we := asserter.Using(t) 55 | gostringer := &_GoStringer{s:"123"} 56 | we.CheckThat(EqualTo("123").Match(gostringer), DidNotMatch) 57 | we.CheckThat(ToGoString(EqualTo("123")).Match(gostringer), Matched) 58 | } 59 | 60 | func Test_ToLower(t *testing.T) { 61 | we := asserter.Using(t) 62 | we.CheckThat(ToLower(EqualTo("shout")).Match("shout"), Matched) 63 | we.CheckThat(ToLower(EqualTo("shout")).Match("SHOUT"), Matched) 64 | we.CheckThat(ToLower(EqualTo("SHOUT")).Match("shout"), DidNotMatch) 65 | we.CheckThat(ToLower(EqualTo("SHOUT")).Match("SHOUT"), DidNotMatch) 66 | we.CheckThat(ToLower(EqualTo("123")).Match("123"), Matched) 67 | we.CheckThat(ToLower(EqualTo("123")).Match(123), DidNotMatch) 68 | } 69 | 70 | func Test_ToUpper(t *testing.T) { 71 | we := asserter.Using(t) 72 | we.CheckThat(ToUpper(EqualTo("shout")).Match("shout"), DidNotMatch) 73 | we.CheckThat(ToUpper(EqualTo("shout")).Match("SHOUT"), DidNotMatch) 74 | we.CheckThat(ToUpper(EqualTo("SHOUT")).Match("shout"), Matched) 75 | we.CheckThat(ToUpper(EqualTo("SHOUT")).Match("SHOUT"), Matched) 76 | we.CheckThat(ToUpper(EqualTo("123")).Match("123"), Matched) 77 | we.CheckThat(ToUpper(EqualTo("123")).Match(123), DidNotMatch) 78 | } 79 | 80 | func Test_ToLen(t *testing.T) { 81 | we := asserter.Using(t) 82 | we.CheckThat(ToLen(EqualTo(5)).Match("SHOUT"), Matched) 83 | we.CheckThat(ToLen(EqualTo(5)).Match("OOPS"), DidNotMatch) 84 | we.CheckThat(ToLen(Anything()).Match(0), DidNotMatch. 85 | Comment("should fail when can't determine length")) 86 | } 87 | 88 | func Test_EqualToIgnoringCase(t *testing.T) { 89 | we := asserter.Using(t) 90 | we.CheckThat(EqualToIgnoringCase("one").Match("one"), Matched) 91 | we.CheckThat(EqualToIgnoringCase("one").Match("ONE"), Matched) 92 | we.CheckThat(EqualToIgnoringCase("ONE").Match("one"), Matched) 93 | we.CheckThat(EqualToIgnoringCase("ONE").Match("ONE"), Matched) 94 | we.CheckThat(EqualToIgnoringCase("oNe").Match("OnE"), Matched) 95 | we.CheckThat(EqualToIgnoringCase("one").Match("two"), DidNotMatch) 96 | we.CheckThat(EqualToIgnoringCase("one").Match(1), DidNotMatch) 97 | we.CheckThat(EqualToIgnoringCase("one").Match(nil), DidNotMatch) 98 | } 99 | 100 | 101 | func Test_Contains(t *testing.T) { 102 | we := asserter.Using(t) 103 | we.CheckThat(Contains("abc").Match("abcde"), Matched.Comment("prefix")) 104 | we.CheckThat(Contains("bcd").Match("abcde"), Matched.Comment("middle")) 105 | we.CheckThat(Contains("cde").Match("abcde"), Matched.Comment("suffix")) 106 | we.CheckThat(Contains("ace").Match("abcde"), DidNotMatch) 107 | we.CheckThat(Contains("123").Match(123), DidNotMatch) 108 | we.CheckThat(Contains("123").Match(nil), DidNotMatch) 109 | } 110 | 111 | var alphabet = "abcdefghijklmnopqrstuvwxyz" 112 | 113 | func Test_HasPrefix(t *testing.T) { 114 | we := asserter.Using(t) 115 | we.CheckThat(HasPrefix("abc").Match(alphabet), Matched) 116 | we.CheckThat(HasPrefix("cde").Match(alphabet), DidNotMatch) 117 | we.CheckThat(HasPrefix("123").Match(123), DidNotMatch) 118 | we.CheckThat(HasPrefix("123").Match(nil), DidNotMatch) 119 | 120 | failResultString := HasPrefix("123").Match(alphabet).String() 121 | we.CheckThat(failResultString, Contains("123")) 122 | we.CheckThat(failResultString, Contains("abcdef")) 123 | we.CheckThat(failResultString, Not(Contains("xyz")). 124 | Comment("Should truncate input on failResult")) 125 | 126 | passResultString := HasPrefix("abc").Match(alphabet).String() 127 | we.CheckThat(passResultString, Contains("abcdef")) 128 | we.CheckThat(passResultString, Not(Contains("xyz")). 129 | Comment("Should truncate input on passResult")) 130 | } 131 | 132 | func Test_HasSuffix(t *testing.T) { 133 | we := asserter.Using(t) 134 | we.CheckThat(HasSuffix("xyz").Match(alphabet), Matched) 135 | we.CheckThat(HasSuffix("wxy").Match(alphabet), DidNotMatch) 136 | we.CheckThat(HasSuffix("123").Match(123), DidNotMatch) 137 | we.CheckThat(HasSuffix("123").Match(nil), DidNotMatch) 138 | 139 | failResultString := HasSuffix("123").Match(alphabet).String() 140 | we.CheckThat(failResultString, Contains("123")) 141 | we.CheckThat(failResultString, Contains("uvwxyz")) 142 | we.CheckThat(failResultString, Not(Contains("abc")). 143 | Comment("Should truncate input on failResult")) 144 | 145 | passResultString := HasSuffix("xyz").Match(alphabet).String() 146 | we.CheckThat(passResultString, Contains("uvwxyz")) 147 | we.CheckThat(passResultString, Not(Contains("abc")). 148 | Comment("Should truncate input on passResult")) 149 | } 150 | 151 | func Test_HasPattern(t *testing.T) { 152 | we := asserter.Using(t) 153 | we.CheckThat(HasPattern("a+b+").Match("abcd"), Matched.Comment("beginning")) 154 | we.CheckThat(HasPattern("b+c+").Match("abcd"), Matched.Comment("middle")) 155 | we.CheckThat(HasPattern("c+d+").Match("abcd"), Matched.Comment("end")) 156 | we.CheckThat(HasPattern("[xy]").Match("abcd"), DidNotMatch) 157 | } 158 | 159 | func Test_EachPattern(t *testing.T) { 160 | we := asserter.Using(t) 161 | eachGoPlusIsGoo := EachPattern("go+")(Is(EqualTo("goo"))) 162 | we.CheckThat(eachGoPlusIsGoo.Match("stop stop stop"), Matched) 163 | we.CheckThat(eachGoPlusIsGoo.Match("goo goo goo"), Matched) 164 | we.CheckThat(eachGoPlusIsGoo.Match("goo go goo"), DidNotMatch) 165 | we.CheckThat(eachGoPlusIsGoo.Match("go go go"), DidNotMatch) 166 | we.CheckThat(eachGoPlusIsGoo.Match(123), DidNotMatch) 167 | we.CheckThat(eachGoPlusIsGoo.Match(nil), DidNotMatch) 168 | 169 | i_before_e := EachPattern("[^aeiou]ei")(HasPrefix("c")) 170 | we.CheckThat("ceiling receipt", i_before_e) 171 | we.CheckThat("deceiver seizure", Not(i_before_e)) 172 | } 173 | 174 | func Test_EachPatternGroup(t *testing.T) { 175 | we := asserter.Using(t) 176 | eachQHasU := EachPatternGroup("([qQ])(.)", 2)(ToLower(EqualTo("u"))) 177 | we.CheckThat(eachQHasU.Match("Quick quack MQ"), Matched) 178 | we.CheckThat(eachQHasU.Match("Quick FAQ for MQ"), DidNotMatch) 179 | we.CheckThat(eachQHasU.Match(123), DidNotMatch) 180 | we.CheckThat(eachQHasU.Match(nil), DidNotMatch) 181 | 182 | ei_after_c := EachPatternGroup("[cC](ei|ie)", 1)(EqualTo("ei")) 183 | we.CheckThat(ei_after_c.Match("Ceiling receipt"), Matched) 184 | we.CheckThat(ei_after_c.Match("receive Cienfuegos"), DidNotMatch) 185 | } 186 | 187 | func Test_AnyPattern(t *testing.T) { 188 | we := asserter.Using(t) 189 | 190 | anyGoPlusIsGoo := AnyPattern("go+")(Is(EqualTo("goo"))) 191 | we.CheckThat(anyGoPlusIsGoo.Match("stop stop stop"), DidNotMatch) 192 | we.CheckThat(anyGoPlusIsGoo.Match("goo goo goo"), Matched) 193 | we.CheckThat(anyGoPlusIsGoo.Match("goo go goo"), Matched) 194 | we.CheckThat(anyGoPlusIsGoo.Match("go go go"), DidNotMatch) 195 | we.CheckThat(anyGoPlusIsGoo.Match(123), DidNotMatch) 196 | we.CheckThat(anyGoPlusIsGoo.Match(nil), DidNotMatch) 197 | 198 | has_cat_word := AnyPattern("[a-z]+at")(HasPrefix("c")) 199 | we.CheckThat("that cravat is phat", has_cat_word) 200 | we.CheckThat("Matt spat at a rat", Not(has_cat_word)) 201 | } 202 | 203 | func Test_AnyPatternGroup(t *testing.T) { 204 | we := asserter.Using(t) 205 | 206 | isHappy := AnyPatternGroup("[:;B]-?(.)", 1)(Is(EqualTo(")"))) 207 | we.CheckThat(isHappy.Match("x :- y+z :-)"), Matched) 208 | we.CheckThat(isHappy.Match(":-P :-/ ;-}"), DidNotMatch) 209 | we.CheckThat(isHappy.Match("<>v<> o rly?"), DidNotMatch) 210 | we.CheckThat(isHappy.Match(123), DidNotMatch) 211 | we.CheckThat(isHappy.Match(nil), DidNotMatch) 212 | } 213 | 214 | func Test_OnPattern(t *testing.T) { 215 | we := asserter.Using(t) 216 | 217 | firstGoPlusIsGoo := OnPattern("Go+")(Is(EqualTo("Goo"))) 218 | we.CheckThat(firstGoPlusIsGoo.Match("take Google to Go"), Matched) 219 | we.CheckThat(firstGoPlusIsGoo.Match("take Go to Google"), DidNotMatch) 220 | we.CheckThat(firstGoPlusIsGoo.Match("Goooooooal"), DidNotMatch) 221 | we.CheckThat(firstGoPlusIsGoo.Match("no big-G goo"), DidNotMatch) 222 | we.CheckThat(firstGoPlusIsGoo.Match(123), DidNotMatch) 223 | we.CheckThat(firstGoPlusIsGoo.Match(nil), DidNotMatch) 224 | 225 | his := OnPattern("h.s")(EqualTo("his")) 226 | we.CheckThat(his.Match("hers and his"), Matched) 227 | we.CheckThat(his.Match("just hers"), DidNotMatch. 228 | Comment("no instances")) 229 | we.CheckThat(his.Match("has chisel"), DidNotMatch. 230 | Comment("second instance matches, but not first")) 231 | } 232 | 233 | func Test_OnPatternGroup(t *testing.T) { 234 | we := asserter.Using(t) 235 | 236 | americanComedy := OnPatternGroup("hum(ou?)r", 1)(Is(EqualTo("o"))) 237 | we.CheckThat(americanComedy.Match("scatological humor"), Matched) 238 | we.CheckThat(americanComedy.Match("spamalot humour"), DidNotMatch) 239 | we.CheckThat(americanComedy.Match("humor I mean humour"), Matched) 240 | we.CheckThat(americanComedy.Match("humour I mean humor"), DidNotMatch) 241 | we.CheckThat(americanComedy.Match("not funny"), DidNotMatch) 242 | we.CheckThat(americanComedy.Match(123), DidNotMatch) 243 | we.CheckThat(americanComedy.Match(nil), DidNotMatch) 244 | } 245 | 246 | --------------------------------------------------------------------------------