pax_global_header00006660000000000000000000000064127651634770014534gustar00rootroot0000000000000052 comment=d59fa0ac68bb5dd932ee8d24eed631cdd519efc3 golang-gomega-1.0+git20160910.d59fa0a/000077500000000000000000000000001276516347700166325ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/.gitignore000066400000000000000000000000441276516347700206200ustar00rootroot00000000000000.DS_Store *.test . .idea gomega.iml golang-gomega-1.0+git20160910.d59fa0a/.travis.yml000066400000000000000000000003741276516347700207470ustar00rootroot00000000000000language: go go: - 1.5 - 1.6.2 - stable install: - go get -v ./... - go get github.com/onsi/ginkgo - go install github.com/onsi/ginkgo/ginkgo script: $HOME/gopath/bin/ginkgo -r --randomizeAllSpecs --failOnPending --randomizeSuites --race golang-gomega-1.0+git20160910.d59fa0a/CHANGELOG.md000066400000000000000000000073561276516347700204560ustar00rootroot00000000000000## HEAD Improvements: - Added `BeSent` which attempts to send a value down a channel and fails if the attempt blocks. Can be paired with `Eventually` to safely send a value down a channel with a timeout. - `Ω`, `Expect`, `Eventually`, and `Consistently` now immediately `panic` if there is no registered fail handler. This is always a mistake that can hide failing tests. - `Receive()` no longer errors when passed a closed channel, it's perfectly fine to attempt to read from a closed channel so Ω(c).Should(Receive()) always fails and Ω(c).ShoudlNot(Receive()) always passes with a closed channel. - Added `HavePrefix` and `HaveSuffix` matchers. - `ghttp` can now handle concurrent requests. - Added `Succeed` which allows one to write `Ω(MyFunction()).Should(Succeed())`. - Improved `ghttp`'s behavior around failing assertions and panics: - If a registered handler makes a failing assertion `ghttp` will return `500`. - If a registered handler panics, `ghttp` will return `500` *and* fail the test. This is new behavior that may cause existing code to break. This code is almost certainly incorrect and creating a false positive. - `ghttp` servers can take an `io.Writer`. `ghttp` will write a line to the writer when each request arrives. - Added `WithTransform` matcher to allow munging input data before feeding into the relevant matcher - Added boolean `And`, `Or`, and `Not` matchers to allow creating composite matchers Bug Fixes: - gexec: `session.Wait` now uses `EventuallyWithOffset` to get the right line number in the failure. - `ContainElement` no longer bails if a passed-in matcher errors. ## 1.0 (8/2/2014) No changes. Dropping "beta" from the version number. ## 1.0.0-beta (7/8/2014) Breaking Changes: - Changed OmegaMatcher interface. Instead of having `Match` return failure messages, two new methods `FailureMessage` and `NegatedFailureMessage` are called instead. - Moved and renamed OmegaFailHandler to types.GomegaFailHandler and OmegaMatcher to types.GomegaMatcher. Any references to OmegaMatcher in any custom matchers will need to be changed to point to types.GomegaMatcher New Test-Support Features: - `ghttp`: supports testing http clients - Provides a flexible fake http server - Provides a collection of chainable http handlers that perform assertions. - `gbytes`: supports making ordered assertions against streams of data - Provides a `gbytes.Buffer` - Provides a `Say` matcher to perform ordered assertions against output data - `gexec`: supports testing external processes - Provides support for building Go binaries - Wraps and starts `exec.Cmd` commands - Makes it easy to assert against stdout and stderr - Makes it easy to send signals and wait for processes to exit - Provides an `Exit` matcher to assert against exit code. DSL Changes: - `Eventually` and `Consistently` can accept `time.Duration` interval and polling inputs. - The default timeouts for `Eventually` and `Consistently` are now configurable. New Matchers: - `ConsistOf`: order-independent assertion against the elements of an array/slice or keys of a map. - `BeTemporally`: like `BeNumerically` but for `time.Time` - `HaveKeyWithValue`: asserts a map has a given key with the given value. Updated Matchers: - `Receive` matcher can take a matcher as an argument and passes only if the channel under test receives an objet that satisfies the passed-in matcher. - Matchers that implement `MatchMayChangeInTheFuture(actual interface{}) bool` can inform `Eventually` and/or `Consistently` when a match has no chance of changing status in the future. For example, `Receive` returns `false` when a channel is closed. Misc: - Start using semantic versioning - Start maintaining changelog Major refactor: - Pull out Gomega's internal to `internal` golang-gomega-1.0+git20160910.d59fa0a/LICENSE000066400000000000000000000020461276516347700176410ustar00rootroot00000000000000Copyright (c) 2013-2014 Onsi Fakhouri Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. golang-gomega-1.0+git20160910.d59fa0a/README.md000066400000000000000000000016611276516347700201150ustar00rootroot00000000000000![Gomega: Ginkgo's Preferred Matcher Library](http://onsi.github.io/gomega/images/gomega.png) [![Build Status](https://travis-ci.org/onsi/gomega.png)](https://travis-ci.org/onsi/gomega) Jump straight to the [docs](http://onsi.github.io/gomega/) to learn about Gomega, including a list of [all available matchers](http://onsi.github.io/gomega/#provided-matchers). To discuss Gomega and get updates, join the [google group](https://groups.google.com/d/forum/ginkgo-and-gomega). ## [Ginkgo](http://github.com/onsi/ginkgo): a BDD Testing Framework for Golang Learn more about Ginkgo [here](http://onsi.github.io/ginkgo/) ## Community Matchers A collection of community matchers is available on the [wiki](https://github.com/onsi/gomega/wiki). ## License Gomega is MIT-Licensed The `ConsistOf` matcher uses [goraph](https://github.com/amitkgupta/goraph) which is embedded in the source to simplify distribution. goraph has an MIT license. golang-gomega-1.0+git20160910.d59fa0a/format/000077500000000000000000000000001276516347700201225ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/format/format.go000066400000000000000000000166771276516347700217620ustar00rootroot00000000000000/* Gomega's format package pretty-prints objects. It explores input objects recursively and generates formatted, indented output with type information. */ package format import ( "fmt" "reflect" "strings" "strconv" ) // Use MaxDepth to set the maximum recursion depth when printing deeply nested objects var MaxDepth = uint(10) /* By default, all objects (even those that implement fmt.Stringer and fmt.GoStringer) are recursively inspected to generate output. Set UseStringerRepresentation = true to use GoString (for fmt.GoStringers) or String (for fmt.Stringer) instead. Note that GoString and String don't always have all the information you need to understand why a test failed! */ var UseStringerRepresentation = false //The default indentation string emitted by the format package var Indent = " " var longFormThreshold = 20 /* Generates a formatted matcher success/failure message of the form: Expected If expected is omited, then the message looks like: Expected */ func Message(actual interface{}, message string, expected ...interface{}) string { if len(expected) == 0 { return fmt.Sprintf("Expected\n%s\n%s", Object(actual, 1), message) } else { return fmt.Sprintf("Expected\n%s\n%s\n%s", Object(actual, 1), message, Object(expected[0], 1)) } } /* Pretty prints the passed in object at the passed in indentation level. Object recurses into deeply nested objects emitting pretty-printed representations of their components. Modify format.MaxDepth to control how deep the recursion is allowed to go Set format.UseStringerRepresentation to true to return object.GoString() or object.String() when available instead of recursing into the object. */ func Object(object interface{}, indentation uint) string { indent := strings.Repeat(Indent, int(indentation)) value := reflect.ValueOf(object) return fmt.Sprintf("%s<%s>: %s", indent, formatType(object), formatValue(value, indentation)) } /* IndentString takes a string and indents each line by the specified amount. */ func IndentString(s string, indentation uint) string { components := strings.Split(s, "\n") result := "" indent := strings.Repeat(Indent, int(indentation)) for i, component := range components { result += indent + component if i < len(components)-1 { result += "\n" } } return result } func formatType(object interface{}) string { t := reflect.TypeOf(object) if t == nil { return "nil" } switch t.Kind() { case reflect.Chan: v := reflect.ValueOf(object) return fmt.Sprintf("%T | len:%d, cap:%d", object, v.Len(), v.Cap()) case reflect.Ptr: return fmt.Sprintf("%T | %p", object, object) case reflect.Slice: v := reflect.ValueOf(object) return fmt.Sprintf("%T | len:%d, cap:%d", object, v.Len(), v.Cap()) case reflect.Map: v := reflect.ValueOf(object) return fmt.Sprintf("%T | len:%d", object, v.Len()) default: return fmt.Sprintf("%T", object) } } func formatValue(value reflect.Value, indentation uint) string { if indentation > MaxDepth { return "..." } if isNilValue(value) { return "nil" } if UseStringerRepresentation { if value.CanInterface() { obj := value.Interface() switch x := obj.(type) { case fmt.GoStringer: return x.GoString() case fmt.Stringer: return x.String() } } } switch value.Kind() { case reflect.Bool: return fmt.Sprintf("%v", value.Bool()) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return fmt.Sprintf("%v", value.Int()) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return fmt.Sprintf("%v", value.Uint()) case reflect.Uintptr: return fmt.Sprintf("0x%x", value.Uint()) case reflect.Float32, reflect.Float64: return fmt.Sprintf("%v", value.Float()) case reflect.Complex64, reflect.Complex128: return fmt.Sprintf("%v", value.Complex()) case reflect.Chan: return fmt.Sprintf("0x%x", value.Pointer()) case reflect.Func: return fmt.Sprintf("0x%x", value.Pointer()) case reflect.Ptr: return formatValue(value.Elem(), indentation) case reflect.Slice: return formatSlice(value, indentation) case reflect.String: return formatString(value.String(), indentation) case reflect.Array: return formatSlice(value, indentation) case reflect.Map: return formatMap(value, indentation) case reflect.Struct: return formatStruct(value, indentation) case reflect.Interface: return formatValue(value.Elem(), indentation) default: if value.CanInterface() { return fmt.Sprintf("%#v", value.Interface()) } else { return fmt.Sprintf("%#v", value) } } } func formatString(object interface{}, indentation uint) string { if indentation == 1 { s := fmt.Sprintf("%s", object) components := strings.Split(s, "\n") result := "" for i, component := range components { if i == 0 { result += component } else { result += Indent + component } if i < len(components)-1 { result += "\n" } } return fmt.Sprintf("%s", result) } else { return fmt.Sprintf("%q", object) } } func formatSlice(v reflect.Value, indentation uint) string { if v.Kind() == reflect.Slice && v.Type().Elem().Kind() == reflect.Uint8 && isPrintableString(string(v.Bytes())){ return formatString(v.Bytes(), indentation) } l := v.Len() result := make([]string, l) longest := 0 for i := 0; i < l; i++ { result[i] = formatValue(v.Index(i), indentation+1) if len(result[i]) > longest { longest = len(result[i]) } } if longest > longFormThreshold { indenter := strings.Repeat(Indent, int(indentation)) return fmt.Sprintf("[\n%s%s,\n%s]", indenter+Indent, strings.Join(result, ",\n"+indenter+Indent), indenter) } else { return fmt.Sprintf("[%s]", strings.Join(result, ", ")) } } func formatMap(v reflect.Value, indentation uint) string { l := v.Len() result := make([]string, l) longest := 0 for i, key := range v.MapKeys() { value := v.MapIndex(key) result[i] = fmt.Sprintf("%s: %s", formatValue(key, 0), formatValue(value, indentation+1)) if len(result[i]) > longest { longest = len(result[i]) } } if longest > longFormThreshold { indenter := strings.Repeat(Indent, int(indentation)) return fmt.Sprintf("{\n%s%s,\n%s}", indenter+Indent, strings.Join(result, ",\n"+indenter+Indent), indenter) } else { return fmt.Sprintf("{%s}", strings.Join(result, ", ")) } } func formatStruct(v reflect.Value, indentation uint) string { t := v.Type() l := v.NumField() result := []string{} longest := 0 for i := 0; i < l; i++ { structField := t.Field(i) fieldEntry := v.Field(i) representation := fmt.Sprintf("%s: %s", structField.Name, formatValue(fieldEntry, indentation+1)) result = append(result, representation) if len(representation) > longest { longest = len(representation) } } if longest > longFormThreshold { indenter := strings.Repeat(Indent, int(indentation)) return fmt.Sprintf("{\n%s%s,\n%s}", indenter+Indent, strings.Join(result, ",\n"+indenter+Indent), indenter) } else { return fmt.Sprintf("{%s}", strings.Join(result, ", ")) } } func isNilValue(a reflect.Value) bool { switch a.Kind() { case reflect.Invalid: return true case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: return a.IsNil() } return false } /* Returns true when the string is entirely made of printable runes, false otherwise. */ func isPrintableString(str string) bool { for _, runeValue := range str { if !strconv.IsPrint(runeValue) { return false } } return true } golang-gomega-1.0+git20160910.d59fa0a/format/format_suite_test.go000066400000000000000000000002771276516347700242170ustar00rootroot00000000000000package format_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestFormat(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Format Suite") } golang-gomega-1.0+git20160910.d59fa0a/format/format_test.go000066400000000000000000000336321276516347700230070ustar00rootroot00000000000000package format_test import ( "fmt" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/format" "github.com/onsi/gomega/types" "strings" ) //recursive struct type StringAlias string type ByteAlias []byte type IntAlias int type AStruct struct { Exported string } type SimpleStruct struct { Name string Enumeration int Veritas bool Data []byte secret uint32 } type ComplexStruct struct { Strings []string SimpleThings []*SimpleStruct DataMaps map[int]ByteAlias } type SecretiveStruct struct { boolValue bool intValue int uintValue uint uintptrValue uintptr floatValue float32 complexValue complex64 chanValue chan bool funcValue func() pointerValue *int sliceValue []string byteSliceValue []byte stringValue string arrValue [3]int byteArrValue [3]byte mapValue map[string]int structValue AStruct interfaceValue interface{} } type GoStringer struct { } func (g GoStringer) GoString() string { return "go-string" } func (g GoStringer) String() string { return "string" } type Stringer struct { } func (g Stringer) String() string { return "string" } var _ = Describe("Format", func() { match := func(typeRepresentation string, valueRepresentation string, args ...interface{}) types.GomegaMatcher { if len(args) > 0 { valueRepresentation = fmt.Sprintf(valueRepresentation, args...) } return Equal(fmt.Sprintf("%s<%s>: %s", Indent, typeRepresentation, valueRepresentation)) } matchRegexp := func(typeRepresentation string, valueRepresentation string, args ...interface{}) types.GomegaMatcher { if len(args) > 0 { valueRepresentation = fmt.Sprintf(valueRepresentation, args...) } return MatchRegexp(fmt.Sprintf("%s<%s>: %s", Indent, typeRepresentation, valueRepresentation)) } hashMatchingRegexp := func(entries ...string) string { entriesSwitch := "(" + strings.Join(entries, "|") + ")" arr := make([]string, len(entries)) for i := range arr { arr[i] = entriesSwitch } return "{" + strings.Join(arr, ", ") + "}" } Describe("Message", func() { Context("with only an actual value", func() { It("should print out an indented formatted representation of the value and the message", func() { Ω(Message(3, "to be three.")).Should(Equal("Expected\n : 3\nto be three.")) }) }) Context("with an actual and an expected value", func() { It("should print out an indented formatted representatino of both values, and the message", func() { Ω(Message(3, "to equal", 4)).Should(Equal("Expected\n : 3\nto equal\n : 4")) }) }) }) Describe("IndentString", func() { It("should indent the string", func() { Ω(IndentString("foo\n bar\nbaz", 2)).Should(Equal(" foo\n bar\n baz")) }) }) Describe("Object", func() { Describe("formatting boolean values", func() { It("should give the type and format values correctly", func() { Ω(Object(true, 1)).Should(match("bool", "true")) Ω(Object(false, 1)).Should(match("bool", "false")) }) }) Describe("formatting numbers", func() { It("should give the type and format values correctly", func() { Ω(Object(int(3), 1)).Should(match("int", "3")) Ω(Object(int8(3), 1)).Should(match("int8", "3")) Ω(Object(int16(3), 1)).Should(match("int16", "3")) Ω(Object(int32(3), 1)).Should(match("int32", "3")) Ω(Object(int64(3), 1)).Should(match("int64", "3")) Ω(Object(uint(3), 1)).Should(match("uint", "3")) Ω(Object(uint8(3), 1)).Should(match("uint8", "3")) Ω(Object(uint16(3), 1)).Should(match("uint16", "3")) Ω(Object(uint32(3), 1)).Should(match("uint32", "3")) Ω(Object(uint64(3), 1)).Should(match("uint64", "3")) }) It("should handle uintptr differently", func() { Ω(Object(uintptr(3), 1)).Should(match("uintptr", "0x3")) }) }) Describe("formatting channels", func() { It("should give the type and format values correctly", func() { c := make(chan<- bool, 3) c <- true c <- false Ω(Object(c, 1)).Should(match("chan<- bool | len:2, cap:3", "%v", c)) }) }) Describe("formatting strings", func() { It("should give the type and format values correctly", func() { s := "a\nb\nc" Ω(Object(s, 1)).Should(match("string", `a b c`)) }) }) Describe("formatting []byte slices", func() { Context("when the slice is made of printable bytes", func () { It("should present it as string", func() { b := []byte("a b c") Ω(Object(b, 1)).Should(matchRegexp(`\[\]uint8 \| len:5, cap:\d+`, `a b c`)) }) }) Context("when the slice contains non-printable bytes", func () { It("should present it as slice", func() { b := []byte("a b c\n\x01\x02\x03\xff\x1bH") Ω(Object(b, 1)).Should(matchRegexp(`\[\]uint8 \| len:12, cap:\d+`, `\[97, 32, 98, 32, 99, 10, 1, 2, 3, 255, 27, 72\]`)) }) }) }) Describe("formatting functions", func() { It("should give the type and format values correctly", func() { f := func(a string, b []int) ([]byte, error) { return []byte("abc"), nil } Ω(Object(f, 1)).Should(match("func(string, []int) ([]uint8, error)", "%v", f)) }) }) Describe("formatting pointers", func() { It("should give the type and dereference the value to format it correctly", func() { a := 3 Ω(Object(&a, 1)).Should(match(fmt.Sprintf("*int | %p", &a), "3")) }) Context("when there are pointers to pointers...", func() { It("should recursively deference the pointer until it gets to a value", func() { a := 3 var b *int var c **int var d ***int b = &a c = &b d = &c Ω(Object(d, 1)).Should(match(fmt.Sprintf("***int | %p", d), "3")) }) }) Context("when the pointer points to nil", func() { It("should say nil and not explode", func() { var a *AStruct Ω(Object(a, 1)).Should(match("*format_test.AStruct | 0x0", "nil")) }) }) }) Describe("formatting arrays", func() { It("should give the type and format values correctly", func() { w := [3]string{"Jed Bartlet", "Toby Ziegler", "CJ Cregg"} Ω(Object(w, 1)).Should(match("[3]string", `["Jed Bartlet", "Toby Ziegler", "CJ Cregg"]`)) }) Context("with byte arrays", func() { It("should give the type and format values correctly", func() { w := [3]byte{17, 28, 19} Ω(Object(w, 1)).Should(match("[3]uint8", `[17, 28, 19]`)) }) }) }) Describe("formatting slices", func() { It("should include the length and capacity in the type information", func() { s := make([]bool, 3, 4) Ω(Object(s, 1)).Should(match("[]bool | len:3, cap:4", "[false, false, false]")) }) Context("when the slice contains long entries", func() { It("should format the entries with newlines", func() { w := []string{"Josiah Edward Bartlet", "Toby Ziegler", "CJ Cregg"} expected := `[ "Josiah Edward Bartlet", "Toby Ziegler", "CJ Cregg", ]` Ω(Object(w, 1)).Should(match("[]string | len:3, cap:3", expected)) }) }) }) Describe("formatting maps", func() { It("should include the length in the type information", func() { m := make(map[int]bool, 5) m[3] = true m[4] = false Ω(Object(m, 1)).Should(matchRegexp(`map\[int\]bool \| len:2`, hashMatchingRegexp("3: true", "4: false"))) }) Context("when the slice contains long entries", func() { It("should format the entries with newlines", func() { m := map[string][]byte{} m["Josiah Edward Bartlet"] = []byte("Martin Sheen") m["Toby Ziegler"] = []byte("Richard Schiff") m["CJ Cregg"] = []byte("Allison Janney") expected := `{ ("Josiah Edward Bartlet": "Martin Sheen"|"Toby Ziegler": "Richard Schiff"|"CJ Cregg": "Allison Janney"), ("Josiah Edward Bartlet": "Martin Sheen"|"Toby Ziegler": "Richard Schiff"|"CJ Cregg": "Allison Janney"), ("Josiah Edward Bartlet": "Martin Sheen"|"Toby Ziegler": "Richard Schiff"|"CJ Cregg": "Allison Janney"), }` Ω(Object(m, 1)).Should(matchRegexp(`map\[string\]\[\]uint8 \| len:3`, expected)) }) }) }) Describe("formatting structs", func() { It("should include the struct name and the field names", func() { s := SimpleStruct{ Name: "Oswald", Enumeration: 17, Veritas: true, Data: []byte("datum"), secret: 1983, } Ω(Object(s, 1)).Should(match("format_test.SimpleStruct", `{Name: "Oswald", Enumeration: 17, Veritas: true, Data: "datum", secret: 1983}`)) }) Context("when the struct contains long entries", func() { It("should format the entries with new lines", func() { s := &SimpleStruct{ Name: "Mithrandir Gandalf Greyhame", Enumeration: 2021, Veritas: true, Data: []byte("wizard"), secret: 3, } Ω(Object(s, 1)).Should(match(fmt.Sprintf("*format_test.SimpleStruct | %p", s), `{ Name: "Mithrandir Gandalf Greyhame", Enumeration: 2021, Veritas: true, Data: "wizard", secret: 3, }`)) }) }) }) Describe("formatting nil values", func() { It("should print out nil", func() { Ω(Object(nil, 1)).Should(match("nil", "nil")) var typedNil *AStruct Ω(Object(typedNil, 1)).Should(match("*format_test.AStruct | 0x0", "nil")) var c chan<- bool Ω(Object(c, 1)).Should(match("chan<- bool | len:0, cap:0", "nil")) var s []string Ω(Object(s, 1)).Should(match("[]string | len:0, cap:0", "nil")) var m map[string]bool Ω(Object(m, 1)).Should(match("map[string]bool | len:0", "nil")) }) }) Describe("formatting aliased types", func() { It("should print out the correct alias type", func() { Ω(Object(StringAlias("alias"), 1)).Should(match("format_test.StringAlias", `alias`)) Ω(Object(ByteAlias("alias"), 1)).Should(matchRegexp(`format_test\.ByteAlias \| len:5, cap:\d+`, `alias`)) Ω(Object(IntAlias(3), 1)).Should(match("format_test.IntAlias", "3")) }) }) Describe("handling nested things", func() { It("should produce a correctly nested representation", func() { s := ComplexStruct{ Strings: []string{"lots", "of", "short", "strings"}, SimpleThings: []*SimpleStruct{ {"short", 7, true, []byte("succinct"), 17}, {"something longer", 427, true, []byte("designed to wrap around nicely"), 30}, }, DataMaps: map[int]ByteAlias{ 17: ByteAlias("some substantially longer chunks of data"), 1138: ByteAlias("that should make things wrap"), }, } expected := `{ Strings: \["lots", "of", "short", "strings"\], SimpleThings: \[ {Name: "short", Enumeration: 7, Veritas: true, Data: "succinct", secret: 17}, { Name: "something longer", Enumeration: 427, Veritas: true, Data: "designed to wrap around nicely", secret: 30, }, \], DataMaps: { (17: "some substantially longer chunks of data"|1138: "that should make things wrap"), (17: "some substantially longer chunks of data"|1138: "that should make things wrap"), }, }` Ω(Object(s, 1)).Should(matchRegexp(`format_test\.ComplexStruct`, expected)) }) }) }) Describe("Handling unexported fields in structs", func() { It("should handle all the various types correctly", func() { a := int(5) s := SecretiveStruct{ boolValue: true, intValue: 3, uintValue: 4, uintptrValue: 5, floatValue: 6.0, complexValue: complex(5.0, 3.0), chanValue: make(chan bool, 2), funcValue: func() {}, pointerValue: &a, sliceValue: []string{"string", "slice"}, byteSliceValue: []byte("bytes"), stringValue: "a string", arrValue: [3]int{11, 12, 13}, byteArrValue: [3]byte{17, 20, 32}, mapValue: map[string]int{"a key": 20, "b key": 30}, structValue: AStruct{"exported"}, interfaceValue: map[string]int{"a key": 17}, } expected := fmt.Sprintf(`{ boolValue: true, intValue: 3, uintValue: 4, uintptrValue: 0x5, floatValue: 6, complexValue: \(5\+3i\), chanValue: %p, funcValue: %p, pointerValue: 5, sliceValue: \["string", "slice"\], byteSliceValue: "bytes", stringValue: "a string", arrValue: \[11, 12, 13\], byteArrValue: \[17, 20, 32\], mapValue: %s, structValue: {Exported: "exported"}, interfaceValue: {"a key": 17}, }`, s.chanValue, s.funcValue, hashMatchingRegexp(`"a key": 20`, `"b key": 30`)) Ω(Object(s, 1)).Should(matchRegexp(`format_test\.SecretiveStruct`, expected)) }) }) Describe("Handling interfaces", func() { It("should unpack the interface", func() { outerHash := map[string]interface{}{} innerHash := map[string]int{} innerHash["inner"] = 3 outerHash["integer"] = 2 outerHash["map"] = innerHash expected := hashMatchingRegexp(`"integer": 2`, `"map": {"inner": 3}`) Ω(Object(outerHash, 1)).Should(matchRegexp(`map\[string\]interface {} \| len:2`, expected)) }) }) Describe("Handling recursive things", func() { It("should not go crazy...", func() { m := map[string]interface{}{} m["integer"] = 2 m["map"] = m Ω(Object(m, 1)).Should(ContainSubstring("...")) }) }) Describe("When instructed to use the Stringer representation", func() { BeforeEach(func() { UseStringerRepresentation = true }) AfterEach(func() { UseStringerRepresentation = false }) Context("when passed a GoStringer", func() { It("should use what GoString() returns", func() { Ω(Object(GoStringer{}, 1)).Should(ContainSubstring(": go-string")) }) }) Context("when passed a stringer", func() { It("should use what String() returns", func() { Ω(Object(Stringer{}, 1)).Should(ContainSubstring(": string")) }) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/gbytes/000077500000000000000000000000001276516347700201275ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/gbytes/buffer.go000066400000000000000000000124571276516347700217400ustar00rootroot00000000000000/* Package gbytes provides a buffer that supports incrementally detecting input. You use gbytes.Buffer with the gbytes.Say matcher. When Say finds a match, it fastforwards the buffer's read cursor to the end of that match. Subsequent matches against the buffer will only operate against data that appears *after* the read cursor. The read cursor is an opaque implementation detail that you cannot access. You should use the Say matcher to sift through the buffer. You can always access the entire buffer's contents with Contents(). */ package gbytes import ( "errors" "fmt" "io" "regexp" "sync" "time" ) /* gbytes.Buffer implements an io.Writer and can be used with the gbytes.Say matcher. You should only use a gbytes.Buffer in test code. It stores all writes in an in-memory buffer - behavior that is inappropriate for production code! */ type Buffer struct { contents []byte readCursor uint64 lock *sync.Mutex detectCloser chan interface{} closed bool } /* NewBuffer returns a new gbytes.Buffer */ func NewBuffer() *Buffer { return &Buffer{ lock: &sync.Mutex{}, } } /* BufferWithBytes returns a new gbytes.Buffer seeded with the passed in bytes */ func BufferWithBytes(bytes []byte) *Buffer { return &Buffer{ lock: &sync.Mutex{}, contents: bytes, } } /* Write implements the io.Writer interface */ func (b *Buffer) Write(p []byte) (n int, err error) { b.lock.Lock() defer b.lock.Unlock() if b.closed { return 0, errors.New("attempt to write to closed buffer") } b.contents = append(b.contents, p...) return len(p), nil } /* Read implements the io.Reader interface. It advances the cursor as it reads. Returns an error if called after Close. */ func (b *Buffer) Read(d []byte) (int, error) { b.lock.Lock() defer b.lock.Unlock() if b.closed { return 0, errors.New("attempt to read from closed buffer") } if uint64(len(b.contents)) <= b.readCursor { return 0, io.EOF } n := copy(d, b.contents[b.readCursor:]) b.readCursor += uint64(n) return n, nil } /* Close signifies that the buffer will no longer be written to */ func (b *Buffer) Close() error { b.lock.Lock() defer b.lock.Unlock() b.closed = true return nil } /* Closed returns true if the buffer has been closed */ func (b *Buffer) Closed() bool { b.lock.Lock() defer b.lock.Unlock() return b.closed } /* Contents returns all data ever written to the buffer. */ func (b *Buffer) Contents() []byte { b.lock.Lock() defer b.lock.Unlock() contents := make([]byte, len(b.contents)) copy(contents, b.contents) return contents } /* Detect takes a regular expression and returns a channel. The channel will receive true the first time data matching the regular expression is written to the buffer. The channel is subsequently closed and the buffer's read-cursor is fast-forwarded to just after the matching region. You typically don't need to use Detect and should use the ghttp.Say matcher instead. Detect is useful, however, in cases where your code must be branch and handle different outputs written to the buffer. For example, consider a buffer hooked up to the stdout of a client library. You may (or may not, depending on state outside of your control) need to authenticate the client library. You could do something like: select { case <-buffer.Detect("You are not logged in"): //log in case <-buffer.Detect("Success"): //carry on case <-time.After(time.Second): //welp } buffer.CancelDetects() You should always call CancelDetects after using Detect. This will close any channels that have not detected and clean up the goroutines that were spawned to support them. Finally, you can pass detect a format string followed by variadic arguments. This will construct the regexp using fmt.Sprintf. */ func (b *Buffer) Detect(desired string, args ...interface{}) chan bool { formattedRegexp := desired if len(args) > 0 { formattedRegexp = fmt.Sprintf(desired, args...) } re := regexp.MustCompile(formattedRegexp) b.lock.Lock() defer b.lock.Unlock() if b.detectCloser == nil { b.detectCloser = make(chan interface{}) } closer := b.detectCloser response := make(chan bool) go func() { ticker := time.NewTicker(10 * time.Millisecond) defer ticker.Stop() defer close(response) for { select { case <-ticker.C: b.lock.Lock() data, cursor := b.contents[b.readCursor:], b.readCursor loc := re.FindIndex(data) b.lock.Unlock() if loc != nil { response <- true b.lock.Lock() newCursorPosition := cursor + uint64(loc[1]) if newCursorPosition >= b.readCursor { b.readCursor = newCursorPosition } b.lock.Unlock() return } case <-closer: return } } }() return response } /* CancelDetects cancels any pending detects and cleans up their goroutines. You should always call this when you're done with a set of Detect channels. */ func (b *Buffer) CancelDetects() { b.lock.Lock() defer b.lock.Unlock() close(b.detectCloser) b.detectCloser = nil } func (b *Buffer) didSay(re *regexp.Regexp) (bool, []byte) { b.lock.Lock() defer b.lock.Unlock() unreadBytes := b.contents[b.readCursor:] copyOfUnreadBytes := make([]byte, len(unreadBytes)) copy(copyOfUnreadBytes, unreadBytes) loc := re.FindIndex(unreadBytes) if loc != nil { b.readCursor += uint64(loc[1]) return true, copyOfUnreadBytes } else { return false, copyOfUnreadBytes } } golang-gomega-1.0+git20160910.d59fa0a/gbytes/buffer_test.go000066400000000000000000000075431276516347700227770ustar00rootroot00000000000000package gbytes_test import ( "io" "time" . "github.com/onsi/gomega/gbytes" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Buffer", func() { var buffer *Buffer BeforeEach(func() { buffer = NewBuffer() }) Describe("dumping the entire contents of the buffer", func() { It("should return everything that's been written", func() { buffer.Write([]byte("abc")) buffer.Write([]byte("def")) Ω(buffer.Contents()).Should(Equal([]byte("abcdef"))) Ω(buffer).Should(Say("bcd")) Ω(buffer.Contents()).Should(Equal([]byte("abcdef"))) }) }) Describe("creating a buffer with bytes", func() { It("should create the buffer with the cursor set to the beginning", func() { buffer := BufferWithBytes([]byte("abcdef")) Ω(buffer.Contents()).Should(Equal([]byte("abcdef"))) Ω(buffer).Should(Say("abc")) Ω(buffer).ShouldNot(Say("abc")) Ω(buffer).Should(Say("def")) }) }) Describe("reading from a buffer", func() { It("should read the current contents of the buffer", func() { buffer := BufferWithBytes([]byte("abcde")) dest := make([]byte, 3) n, err := buffer.Read(dest) Ω(err).ShouldNot(HaveOccurred()) Ω(n).Should(Equal(3)) Ω(string(dest)).Should(Equal("abc")) dest = make([]byte, 3) n, err = buffer.Read(dest) Ω(err).ShouldNot(HaveOccurred()) Ω(n).Should(Equal(2)) Ω(string(dest[:n])).Should(Equal("de")) n, err = buffer.Read(dest) Ω(err).Should(Equal(io.EOF)) Ω(n).Should(Equal(0)) }) Context("after the buffer has been closed", func() { It("returns an error", func() { buffer := BufferWithBytes([]byte("abcde")) buffer.Close() dest := make([]byte, 3) n, err := buffer.Read(dest) Ω(err).Should(HaveOccurred()) Ω(n).Should(Equal(0)) }) }) }) Describe("detecting regular expressions", func() { It("should fire the appropriate channel when the passed in pattern matches, then close it", func(done Done) { go func() { time.Sleep(10 * time.Millisecond) buffer.Write([]byte("abcde")) }() A := buffer.Detect("%s", "a.c") B := buffer.Detect("def") var gotIt bool select { case gotIt = <-A: case <-B: Fail("should not have gotten here") } Ω(gotIt).Should(BeTrue()) Eventually(A).Should(BeClosed()) buffer.Write([]byte("f")) Eventually(B).Should(Receive()) Eventually(B).Should(BeClosed()) close(done) }) It("should fast-forward the buffer upon detection", func(done Done) { buffer.Write([]byte("abcde")) <-buffer.Detect("abc") Ω(buffer).ShouldNot(Say("abc")) Ω(buffer).Should(Say("de")) close(done) }) It("should only fast-forward the buffer when the channel is read, and only if doing so would not rewind it", func(done Done) { buffer.Write([]byte("abcde")) A := buffer.Detect("abc") time.Sleep(20 * time.Millisecond) //give the goroutine a chance to detect and write to the channel Ω(buffer).Should(Say("abcd")) <-A Ω(buffer).ShouldNot(Say("d")) Ω(buffer).Should(Say("e")) Eventually(A).Should(BeClosed()) close(done) }) It("should be possible to cancel a detection", func(done Done) { A := buffer.Detect("abc") B := buffer.Detect("def") buffer.CancelDetects() buffer.Write([]byte("abcdef")) Eventually(A).Should(BeClosed()) Eventually(B).Should(BeClosed()) Ω(buffer).Should(Say("bcde")) <-buffer.Detect("f") close(done) }) }) Describe("closing the buffer", func() { It("should error when further write attempts are made", func() { _, err := buffer.Write([]byte("abc")) Ω(err).ShouldNot(HaveOccurred()) buffer.Close() _, err = buffer.Write([]byte("def")) Ω(err).Should(HaveOccurred()) Ω(buffer.Contents()).Should(Equal([]byte("abc"))) }) It("should be closed", func() { Ω(buffer.Closed()).Should(BeFalse()) buffer.Close() Ω(buffer.Closed()).Should(BeTrue()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/gbytes/gbuffer_suite_test.go000066400000000000000000000002771276516347700243540ustar00rootroot00000000000000package gbytes_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestGbytes(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Gbytes Suite") } golang-gomega-1.0+git20160910.d59fa0a/gbytes/say_matcher.go000066400000000000000000000054131276516347700227600ustar00rootroot00000000000000package gbytes import ( "fmt" "regexp" "github.com/onsi/gomega/format" ) //Objects satisfying the BufferProvider can be used with the Say matcher. type BufferProvider interface { Buffer() *Buffer } /* Say is a Gomega matcher that operates on gbytes.Buffers: Ω(buffer).Should(Say("something")) will succeed if the unread portion of the buffer matches the regular expression "something". When Say succeeds, it fast forwards the gbytes.Buffer's read cursor to just after the succesful match. Thus, subsequent calls to Say will only match against the unread portion of the buffer Say pairs very well with Eventually. To assert that a buffer eventually receives data matching "[123]-star" within 3 seconds you can: Eventually(buffer, 3).Should(Say("[123]-star")) Ditto with consistently. To assert that a buffer does not receive data matching "never-see-this" for 1 second you can: Consistently(buffer, 1).ShouldNot(Say("never-see-this")) In addition to bytes.Buffers, Say can operate on objects that implement the gbytes.BufferProvider interface. In such cases, Say simply operates on the *gbytes.Buffer returned by Buffer() If the buffer is closed, the Say matcher will tell Eventually to abort. */ func Say(expected string, args ...interface{}) *sayMatcher { formattedRegexp := expected if len(args) > 0 { formattedRegexp = fmt.Sprintf(expected, args...) } return &sayMatcher{ re: regexp.MustCompile(formattedRegexp), } } type sayMatcher struct { re *regexp.Regexp receivedSayings []byte } func (m *sayMatcher) buffer(actual interface{}) (*Buffer, bool) { var buffer *Buffer switch x := actual.(type) { case *Buffer: buffer = x case BufferProvider: buffer = x.Buffer() default: return nil, false } return buffer, true } func (m *sayMatcher) Match(actual interface{}) (success bool, err error) { buffer, ok := m.buffer(actual) if !ok { return false, fmt.Errorf("Say must be passed a *gbytes.Buffer or BufferProvider. Got:\n%s", format.Object(actual, 1)) } didSay, sayings := buffer.didSay(m.re) m.receivedSayings = sayings return didSay, nil } func (m *sayMatcher) FailureMessage(actual interface{}) (message string) { return fmt.Sprintf( "Got stuck at:\n%s\nWaiting for:\n%s", format.IndentString(string(m.receivedSayings), 1), format.IndentString(m.re.String(), 1), ) } func (m *sayMatcher) NegatedFailureMessage(actual interface{}) (message string) { return fmt.Sprintf( "Saw:\n%s\nWhich matches the unexpected:\n%s", format.IndentString(string(m.receivedSayings), 1), format.IndentString(m.re.String(), 1), ) } func (m *sayMatcher) MatchMayChangeInTheFuture(actual interface{}) bool { switch x := actual.(type) { case *Buffer: return !x.Closed() case BufferProvider: return !x.Buffer().Closed() default: return true } } golang-gomega-1.0+git20160910.d59fa0a/gbytes/say_matcher_test.go000066400000000000000000000075701276516347700240250ustar00rootroot00000000000000package gbytes_test import ( . "github.com/onsi/gomega/gbytes" "time" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) type speaker struct { buffer *Buffer } func (s *speaker) Buffer() *Buffer { return s.buffer } var _ = Describe("SayMatcher", func() { var buffer *Buffer BeforeEach(func() { buffer = NewBuffer() buffer.Write([]byte("abc")) }) Context("when actual is not a gexec Buffer, or a BufferProvider", func() { It("should error", func() { failures := InterceptGomegaFailures(func() { Ω("foo").Should(Say("foo")) }) Ω(failures[0]).Should(ContainSubstring("*gbytes.Buffer")) }) }) Context("when a match is found", func() { It("should succeed", func() { Ω(buffer).Should(Say("abc")) }) It("should support printf-like formatting", func() { Ω(buffer).Should(Say("a%sc", "b")) }) It("should use a regular expression", func() { Ω(buffer).Should(Say("a.c")) }) It("should fastforward the buffer", func() { buffer.Write([]byte("def")) Ω(buffer).Should(Say("abcd")) Ω(buffer).Should(Say("ef")) Ω(buffer).ShouldNot(Say("[a-z]")) }) }) Context("when no match is found", func() { It("should not error", func() { Ω(buffer).ShouldNot(Say("def")) }) Context("when the buffer is closed", func() { BeforeEach(func() { buffer.Close() }) It("should abort an eventually", func() { t := time.Now() failures := InterceptGomegaFailures(func() { Eventually(buffer).Should(Say("def")) }) Eventually(buffer).ShouldNot(Say("def")) Ω(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) Ω(failures).Should(HaveLen(1)) t = time.Now() Eventually(buffer).Should(Say("abc")) Ω(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) }) It("should abort a consistently", func() { t := time.Now() Consistently(buffer, 2.0).ShouldNot(Say("def")) Ω(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) }) It("should not error with a synchronous matcher", func() { Ω(buffer).ShouldNot(Say("def")) Ω(buffer).Should(Say("abc")) }) }) }) Context("when a positive match fails", func() { It("should report where it got stuck", func() { Ω(buffer).Should(Say("abc")) buffer.Write([]byte("def")) failures := InterceptGomegaFailures(func() { Ω(buffer).Should(Say("abc")) }) Ω(failures[0]).Should(ContainSubstring("Got stuck at:")) Ω(failures[0]).Should(ContainSubstring("def")) }) }) Context("when a negative match fails", func() { It("should report where it got stuck", func() { failures := InterceptGomegaFailures(func() { Ω(buffer).ShouldNot(Say("abc")) }) Ω(failures[0]).Should(ContainSubstring("Saw:")) Ω(failures[0]).Should(ContainSubstring("Which matches the unexpected:")) Ω(failures[0]).Should(ContainSubstring("abc")) }) }) Context("when a match is not found", func() { It("should not fastforward the buffer", func() { Ω(buffer).ShouldNot(Say("def")) Ω(buffer).Should(Say("abc")) }) }) Context("a nice real-life example", func() { It("should behave well", func() { Ω(buffer).Should(Say("abc")) go func() { time.Sleep(10 * time.Millisecond) buffer.Write([]byte("def")) }() Ω(buffer).ShouldNot(Say("def")) Eventually(buffer).Should(Say("def")) }) }) Context("when actual is a BufferProvider", func() { It("should use actual's buffer", func() { s := &speaker{ buffer: NewBuffer(), } Ω(s).ShouldNot(Say("abc")) s.Buffer().Write([]byte("abc")) Ω(s).Should(Say("abc")) }) It("should abort an eventually", func() { s := &speaker{ buffer: NewBuffer(), } s.buffer.Close() t := time.Now() failures := InterceptGomegaFailures(func() { Eventually(s).Should(Say("def")) }) Ω(failures).Should(HaveLen(1)) Ω(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/gexec/000077500000000000000000000000001276516347700177255ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/gexec/_fixture/000077500000000000000000000000001276516347700215525ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/gexec/_fixture/firefly/000077500000000000000000000000001276516347700232125ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/gexec/_fixture/firefly/main.go000066400000000000000000000014261276516347700244700ustar00rootroot00000000000000package main import ( "fmt" "math/rand" "os" "strconv" "time" ) var outQuote = "We've done the impossible, and that makes us mighty." var errQuote = "Ah, curse your sudden but inevitable betrayal!" var randomQuotes = []string{ "Can we maybe vote on the whole murdering people issue?", "I swear by my pretty floral bonnet, I will end you.", "My work's illegal, but at least it's honest.", } func main() { fmt.Fprintln(os.Stdout, outQuote) fmt.Fprintln(os.Stderr, errQuote) randomIndex := rand.New(rand.NewSource(time.Now().UnixNano())).Intn(len(randomQuotes)) time.Sleep(100 * time.Millisecond) fmt.Fprintln(os.Stdout, randomQuotes[randomIndex]) if len(os.Args) == 2 { exitCode, _ := strconv.Atoi(os.Args[1]) os.Exit(exitCode) } else { os.Exit(randomIndex) } } golang-gomega-1.0+git20160910.d59fa0a/gexec/build.go000066400000000000000000000037731276516347700213650ustar00rootroot00000000000000package gexec import ( "errors" "fmt" "io/ioutil" "os" "os/exec" "path" "path/filepath" "runtime" "sync" ) var ( mu sync.Mutex tmpDir string ) /* Build uses go build to compile the package at packagePath. The resulting binary is saved off in a temporary directory. A path pointing to this binary is returned. Build uses the $GOPATH set in your environment. It passes the variadic args on to `go build`. */ func Build(packagePath string, args ...string) (compiledPath string, err error) { return BuildIn(os.Getenv("GOPATH"), packagePath, args...) } /* BuildIn is identical to Build but allows you to specify a custom $GOPATH (the first argument). */ func BuildIn(gopath string, packagePath string, args ...string) (compiledPath string, err error) { tmpDir, err := temporaryDirectory() if err != nil { return "", err } if len(gopath) == 0 { return "", errors.New("$GOPATH not provided when building " + packagePath) } executable := filepath.Join(tmpDir, path.Base(packagePath)) if runtime.GOOS == "windows" { executable = executable + ".exe" } cmdArgs := append([]string{"build"}, args...) cmdArgs = append(cmdArgs, "-o", executable, packagePath) build := exec.Command("go", cmdArgs...) build.Env = append([]string{"GOPATH=" + gopath}, os.Environ()...) output, err := build.CombinedOutput() if err != nil { return "", fmt.Errorf("Failed to build %s:\n\nError:\n%s\n\nOutput:\n%s", packagePath, err, string(output)) } return executable, nil } /* You should call CleanupBuildArtifacts before your test ends to clean up any temporary artifacts generated by gexec. In Ginkgo this is typically done in an AfterSuite callback. */ func CleanupBuildArtifacts() { mu.Lock() defer mu.Unlock() if tmpDir != "" { os.RemoveAll(tmpDir) tmpDir = "" } } func temporaryDirectory() (string, error) { var err error mu.Lock() defer mu.Unlock() if tmpDir == "" { tmpDir, err = ioutil.TempDir("", "gexec_artifacts") if err != nil { return "", err } } return ioutil.TempDir(tmpDir, "g") } golang-gomega-1.0+git20160910.d59fa0a/gexec/build_test.go000066400000000000000000000016031276516347700224120ustar00rootroot00000000000000package gexec_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" ) var _ = Describe(".Build", func() { var packagePath = "./_fixture/firefly" Context("when there have been previous calls to Build", func() { BeforeEach(func() { _, err := gexec.Build(packagePath) Ω(err).ShouldNot(HaveOccurred()) }) It("compiles the specified package", func() { compiledPath, err := gexec.Build(packagePath) Ω(err).ShouldNot(HaveOccurred()) Ω(compiledPath).Should(BeAnExistingFile()) }) Context("and CleanupBuildArtifacts has been called", func() { BeforeEach(func() { gexec.CleanupBuildArtifacts() }) It("compiles the specified package", func() { var err error fireflyPath, err = gexec.Build(packagePath) Ω(err).ShouldNot(HaveOccurred()) Ω(fireflyPath).Should(BeAnExistingFile()) }) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/gexec/exit_matcher.go000066400000000000000000000040321276516347700227270ustar00rootroot00000000000000package gexec import ( "fmt" "github.com/onsi/gomega/format" ) /* The Exit matcher operates on a session: Ω(session).Should(Exit()) Exit passes if the session has already exited. If no status code is provided, then Exit will succeed if the session has exited regardless of exit code. Otherwise, Exit will only succeed if the process has exited with the provided status code. Note that the process must have already exited. To wait for a process to exit, use Eventually: Eventually(session, 3).Should(Exit(0)) */ func Exit(optionalExitCode ...int) *exitMatcher { exitCode := -1 if len(optionalExitCode) > 0 { exitCode = optionalExitCode[0] } return &exitMatcher{ exitCode: exitCode, } } type exitMatcher struct { exitCode int didExit bool actualExitCode int } type Exiter interface { ExitCode() int } func (m *exitMatcher) Match(actual interface{}) (success bool, err error) { exiter, ok := actual.(Exiter) if !ok { return false, fmt.Errorf("Exit must be passed a gexec.Exiter (Missing method ExitCode() int) Got:\n%s", format.Object(actual, 1)) } m.actualExitCode = exiter.ExitCode() if m.actualExitCode == -1 { return false, nil } if m.exitCode == -1 { return true, nil } return m.exitCode == m.actualExitCode, nil } func (m *exitMatcher) FailureMessage(actual interface{}) (message string) { if m.actualExitCode == -1 { return "Expected process to exit. It did not." } else { return format.Message(m.actualExitCode, "to match exit code:", m.exitCode) } } func (m *exitMatcher) NegatedFailureMessage(actual interface{}) (message string) { if m.actualExitCode == -1 { return "you really shouldn't be able to see this!" } else { if m.exitCode == -1 { return "Expected process not to exit. It did." } else { return format.Message(m.actualExitCode, "not to match exit code:", m.exitCode) } } } func (m *exitMatcher) MatchMayChangeInTheFuture(actual interface{}) bool { session, ok := actual.(*Session) if ok { return session.ExitCode() == -1 } return true } golang-gomega-1.0+git20160910.d59fa0a/gexec/exit_matcher_test.go000066400000000000000000000052111276516347700237660ustar00rootroot00000000000000package gexec_test import ( . "github.com/onsi/gomega/gexec" "os/exec" "time" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) type NeverExits struct{} func (e NeverExits) ExitCode() int { return -1 } var _ = Describe("ExitMatcher", func() { var command *exec.Cmd var session *Session BeforeEach(func() { var err error command = exec.Command(fireflyPath, "0") session, err = Start(command, nil, nil) Ω(err).ShouldNot(HaveOccurred()) }) Describe("when passed something that is an Exiter", func() { It("should act normally", func() { failures := InterceptGomegaFailures(func() { Ω(NeverExits{}).Should(Exit()) }) Ω(failures[0]).Should(ContainSubstring("Expected process to exit. It did not.")) }) }) Describe("when passed something that is not an Exiter", func() { It("should error", func() { failures := InterceptGomegaFailures(func() { Ω("aardvark").Should(Exit()) }) Ω(failures[0]).Should(ContainSubstring("Exit must be passed a gexec.Exiter")) }) }) Context("with no exit code", func() { It("should say the right things when it fails", func() { Ω(session).ShouldNot(Exit()) failures := InterceptGomegaFailures(func() { Ω(session).Should(Exit()) }) Ω(failures[0]).Should(ContainSubstring("Expected process to exit. It did not.")) Eventually(session).Should(Exit()) Ω(session).Should(Exit()) failures = InterceptGomegaFailures(func() { Ω(session).ShouldNot(Exit()) }) Ω(failures[0]).Should(ContainSubstring("Expected process not to exit. It did.")) }) }) Context("with an exit code", func() { It("should say the right things when it fails", func() { Ω(session).ShouldNot(Exit(0)) Ω(session).ShouldNot(Exit(1)) failures := InterceptGomegaFailures(func() { Ω(session).Should(Exit(0)) }) Ω(failures[0]).Should(ContainSubstring("Expected process to exit. It did not.")) Eventually(session).Should(Exit(0)) Ω(session).Should(Exit(0)) failures = InterceptGomegaFailures(func() { Ω(session).Should(Exit(1)) }) Ω(failures[0]).Should(ContainSubstring("to match exit code:")) Ω(session).ShouldNot(Exit(1)) failures = InterceptGomegaFailures(func() { Ω(session).ShouldNot(Exit(0)) }) Ω(failures[0]).Should(ContainSubstring("not to match exit code:")) }) }) Describe("bailing out early", func() { It("should bail out early once the process exits", func() { t := time.Now() failures := InterceptGomegaFailures(func() { Eventually(session).Should(Exit(1)) }) Ω(time.Since(t)).Should(BeNumerically("<=", 500*time.Millisecond)) Ω(failures).Should(HaveLen(1)) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/gexec/gexec_suite_test.go000066400000000000000000000006641276516347700236250ustar00rootroot00000000000000package gexec_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" "testing" ) var fireflyPath string func TestGexec(t *testing.T) { BeforeSuite(func() { var err error fireflyPath, err = gexec.Build("./_fixture/firefly") Ω(err).ShouldNot(HaveOccurred()) }) AfterSuite(func() { gexec.CleanupBuildArtifacts() }) RegisterFailHandler(Fail) RunSpecs(t, "Gexec Suite") } golang-gomega-1.0+git20160910.d59fa0a/gexec/prefixed_writer.go000066400000000000000000000021371276516347700234610ustar00rootroot00000000000000package gexec import ( "io" "sync" ) /* PrefixedWriter wraps an io.Writer, emiting the passed in prefix at the beginning of each new line. This can be useful when running multiple gexec.Sessions concurrently - you can prefix the log output of each session by passing in a PrefixedWriter: gexec.Start(cmd, NewPrefixedWriter("[my-cmd] ", GinkgoWriter), NewPrefixedWriter("[my-cmd] ", GinkgoWriter)) */ type PrefixedWriter struct { prefix []byte writer io.Writer lock *sync.Mutex atStartOfLine bool } func NewPrefixedWriter(prefix string, writer io.Writer) *PrefixedWriter { return &PrefixedWriter{ prefix: []byte(prefix), writer: writer, lock: &sync.Mutex{}, atStartOfLine: true, } } func (w *PrefixedWriter) Write(b []byte) (int, error) { w.lock.Lock() defer w.lock.Unlock() toWrite := []byte{} for _, c := range b { if w.atStartOfLine { toWrite = append(toWrite, w.prefix...) } toWrite = append(toWrite, c) w.atStartOfLine = c == '\n' } _, err := w.writer.Write(toWrite) if err != nil { return 0, err } return len(b), nil } golang-gomega-1.0+git20160910.d59fa0a/gexec/prefixed_writer_test.go000066400000000000000000000014141276516347700245150ustar00rootroot00000000000000package gexec_test import ( "bytes" . "github.com/onsi/gomega/gexec" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("PrefixedWriter", func() { var buffer *bytes.Buffer var writer *PrefixedWriter BeforeEach(func() { buffer = &bytes.Buffer{} writer = NewPrefixedWriter("[p]", buffer) }) It("should emit the prefix on newlines", func() { writer.Write([]byte("abc")) writer.Write([]byte("def\n")) writer.Write([]byte("hij\n")) writer.Write([]byte("\n\n")) writer.Write([]byte("klm\n\nnop")) writer.Write([]byte("")) writer.Write([]byte("qrs")) writer.Write([]byte("\ntuv\nwx")) writer.Write([]byte("yz\n\n")) Ω(buffer.String()).Should(Equal(`[p]abcdef [p]hij [p] [p] [p]klm [p] [p]nopqrs [p]tuv [p]wxyz [p] `)) }) }) golang-gomega-1.0+git20160910.d59fa0a/gexec/session.go000066400000000000000000000135661276516347700217520ustar00rootroot00000000000000/* Package gexec provides support for testing external processes. */ package gexec import ( "io" "os" "os/exec" "reflect" "sync" "syscall" . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" ) const INVALID_EXIT_CODE = 254 type Session struct { //The wrapped command Command *exec.Cmd //A *gbytes.Buffer connected to the command's stdout Out *gbytes.Buffer //A *gbytes.Buffer connected to the command's stderr Err *gbytes.Buffer //A channel that will close when the command exits Exited <-chan struct{} lock *sync.Mutex exitCode int } /* Start starts the passed-in *exec.Cmd command. It wraps the command in a *gexec.Session. The session pipes the command's stdout and stderr to two *gbytes.Buffers available as properties on the session: session.Out and session.Err. These buffers can be used with the gbytes.Say matcher to match against unread output: Ω(session.Out).Should(gbytes.Say("foo-out")) Ω(session.Err).Should(gbytes.Say("foo-err")) In addition, Session satisfies the gbytes.BufferProvider interface and provides the stdout *gbytes.Buffer. This allows you to replace the first line, above, with: Ω(session).Should(gbytes.Say("foo-out")) When outWriter and/or errWriter are non-nil, the session will pipe stdout and/or stderr output both into the session *gybtes.Buffers and to the passed-in outWriter/errWriter. This is useful for capturing the process's output or logging it to screen. In particular, when using Ginkgo it can be convenient to direct output to the GinkgoWriter: session, err := Start(command, GinkgoWriter, GinkgoWriter) This will log output when running tests in verbose mode, but - otherwise - will only log output when a test fails. The session wrapper is responsible for waiting on the *exec.Cmd command. You *should not* call command.Wait() yourself. Instead, to assert that the command has exited you can use the gexec.Exit matcher: Ω(session).Should(gexec.Exit()) When the session exits it closes the stdout and stderr gbytes buffers. This will short circuit any Eventuallys waiting for the buffers to Say something. */ func Start(command *exec.Cmd, outWriter io.Writer, errWriter io.Writer) (*Session, error) { exited := make(chan struct{}) session := &Session{ Command: command, Out: gbytes.NewBuffer(), Err: gbytes.NewBuffer(), Exited: exited, lock: &sync.Mutex{}, exitCode: -1, } var commandOut, commandErr io.Writer commandOut, commandErr = session.Out, session.Err if outWriter != nil && !reflect.ValueOf(outWriter).IsNil() { commandOut = io.MultiWriter(commandOut, outWriter) } if errWriter != nil && !reflect.ValueOf(errWriter).IsNil() { commandErr = io.MultiWriter(commandErr, errWriter) } command.Stdout = commandOut command.Stderr = commandErr err := command.Start() if err == nil { go session.monitorForExit(exited) } return session, err } /* Buffer implements the gbytes.BufferProvider interface and returns s.Out This allows you to make gbytes.Say matcher assertions against stdout without having to reference .Out: Eventually(session).Should(gbytes.Say("foo")) */ func (s *Session) Buffer() *gbytes.Buffer { return s.Out } /* ExitCode returns the wrapped command's exit code. If the command hasn't exited yet, ExitCode returns -1. To assert that the command has exited it is more convenient to use the Exit matcher: Eventually(s).Should(gexec.Exit()) When the process exits because it has received a particular signal, the exit code will be 128+signal-value (See http://www.tldp.org/LDP/abs/html/exitcodes.html and http://man7.org/linux/man-pages/man7/signal.7.html) */ func (s *Session) ExitCode() int { s.lock.Lock() defer s.lock.Unlock() return s.exitCode } /* Wait waits until the wrapped command exits. It can be passed an optional timeout. If the command does not exit within the timeout, Wait will trigger a test failure. Wait returns the session, making it possible to chain: session.Wait().Out.Contents() will wait for the command to exit then return the entirety of Out's contents. Wait uses eventually under the hood and accepts the same timeout/polling intervals that eventually does. */ func (s *Session) Wait(timeout ...interface{}) *Session { EventuallyWithOffset(1, s, timeout...).Should(Exit()) return s } /* Kill sends the running command a SIGKILL signal. It does not wait for the process to exit. If the command has already exited, Kill returns silently. The session is returned to enable chaining. */ func (s *Session) Kill() *Session { if s.ExitCode() != -1 { return s } s.Command.Process.Kill() return s } /* Interrupt sends the running command a SIGINT signal. It does not wait for the process to exit. If the command has already exited, Interrupt returns silently. The session is returned to enable chaining. */ func (s *Session) Interrupt() *Session { return s.Signal(syscall.SIGINT) } /* Terminate sends the running command a SIGTERM signal. It does not wait for the process to exit. If the command has already exited, Terminate returns silently. The session is returned to enable chaining. */ func (s *Session) Terminate() *Session { return s.Signal(syscall.SIGTERM) } /* Terminate sends the running command the passed in signal. It does not wait for the process to exit. If the command has already exited, Signal returns silently. The session is returned to enable chaining. */ func (s *Session) Signal(signal os.Signal) *Session { if s.ExitCode() != -1 { return s } s.Command.Process.Signal(signal) return s } func (s *Session) monitorForExit(exited chan<- struct{}) { err := s.Command.Wait() s.lock.Lock() s.Out.Close() s.Err.Close() status := s.Command.ProcessState.Sys().(syscall.WaitStatus) if status.Signaled() { s.exitCode = 128 + int(status.Signal()) } else { exitStatus := status.ExitStatus() if exitStatus == -1 && err != nil { s.exitCode = INVALID_EXIT_CODE } s.exitCode = exitStatus } s.lock.Unlock() close(exited) } golang-gomega-1.0+git20160910.d59fa0a/gexec/session_test.go000066400000000000000000000124501276516347700230000ustar00rootroot00000000000000package gexec_test import ( "os/exec" "syscall" "time" . "github.com/onsi/gomega/gbytes" . "github.com/onsi/gomega/gexec" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Session", func() { var command *exec.Cmd var session *Session var outWriter, errWriter *Buffer BeforeEach(func() { outWriter = nil errWriter = nil }) JustBeforeEach(func() { command = exec.Command(fireflyPath) var err error session, err = Start(command, outWriter, errWriter) Ω(err).ShouldNot(HaveOccurred()) }) Context("running a command", func() { It("should start the process", func() { Ω(command.Process).ShouldNot(BeNil()) }) It("should wrap the process's stdout and stderr with gbytes buffers", func(done Done) { Eventually(session.Out).Should(Say("We've done the impossible, and that makes us mighty")) Eventually(session.Err).Should(Say("Ah, curse your sudden but inevitable betrayal!")) defer session.Out.CancelDetects() select { case <-session.Out.Detect("Can we maybe vote on the whole murdering people issue"): Eventually(session).Should(Exit(0)) case <-session.Out.Detect("I swear by my pretty floral bonnet, I will end you."): Eventually(session).Should(Exit(1)) case <-session.Out.Detect("My work's illegal, but at least it's honest."): Eventually(session).Should(Exit(2)) } close(done) }) It("should satisfy the gbytes.BufferProvider interface, passing Stdout", func() { Eventually(session).Should(Say("We've done the impossible, and that makes us mighty")) Eventually(session).Should(Exit()) }) }) Describe("providing the exit code", func() { It("should provide the app's exit code", func() { Ω(session.ExitCode()).Should(Equal(-1)) Eventually(session).Should(Exit()) Ω(session.ExitCode()).Should(BeNumerically(">=", 0)) Ω(session.ExitCode()).Should(BeNumerically("<", 3)) }) }) Describe("wait", func() { It("should wait till the command exits", func() { Ω(session.ExitCode()).Should(Equal(-1)) Ω(session.Wait().ExitCode()).Should(BeNumerically(">=", 0)) Ω(session.Wait().ExitCode()).Should(BeNumerically("<", 3)) }) }) Describe("exited", func() { It("should close when the command exits", func() { Eventually(session.Exited).Should(BeClosed()) Ω(session.ExitCode()).ShouldNot(Equal(-1)) }) }) Describe("kill", func() { It("should kill the command and wait for it to exit", func() { session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) Ω(err).ShouldNot(HaveOccurred()) session.Kill() Ω(session).ShouldNot(Exit(), "Should not exit immediately...") Eventually(session).Should(Exit(128 + 9)) }) }) Describe("interrupt", func() { It("should interrupt the command", func() { session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) Ω(err).ShouldNot(HaveOccurred()) session.Interrupt() Ω(session).ShouldNot(Exit(), "Should not exit immediately...") Eventually(session).Should(Exit(128 + 2)) }) }) Describe("terminate", func() { It("should terminate the command", func() { session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) Ω(err).ShouldNot(HaveOccurred()) session.Terminate() Ω(session).ShouldNot(Exit(), "Should not exit immediately...") Eventually(session).Should(Exit(128 + 15)) }) }) Describe("signal", func() { It("should send the signal to the command", func() { session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) Ω(err).ShouldNot(HaveOccurred()) session.Signal(syscall.SIGABRT) Ω(session).ShouldNot(Exit(), "Should not exit immediately...") Eventually(session).Should(Exit(128 + 6)) }) }) Context("when the command exits", func() { It("should close the buffers", func() { Eventually(session).Should(Exit()) Ω(session.Out.Closed()).Should(BeTrue()) Ω(session.Err.Closed()).Should(BeTrue()) Ω(session.Out).Should(Say("We've done the impossible, and that makes us mighty")) }) var So = It So("this means that eventually should short circuit", func() { t := time.Now() failures := InterceptGomegaFailures(func() { Eventually(session).Should(Say("blah blah blah blah blah")) }) Ω(time.Since(t)).Should(BeNumerically("<=", 500*time.Millisecond)) Ω(failures).Should(HaveLen(1)) }) }) Context("when wrapping out and err", func() { BeforeEach(func() { outWriter = NewBuffer() errWriter = NewBuffer() }) It("should route to both the provided writers and the gbytes buffers", func() { Eventually(session.Out).Should(Say("We've done the impossible, and that makes us mighty")) Eventually(session.Err).Should(Say("Ah, curse your sudden but inevitable betrayal!")) Ω(outWriter.Contents()).Should(ContainSubstring("We've done the impossible, and that makes us mighty")) Ω(errWriter.Contents()).Should(ContainSubstring("Ah, curse your sudden but inevitable betrayal!")) Eventually(session).Should(Exit()) Ω(outWriter.Contents()).Should(Equal(session.Out.Contents())) Ω(errWriter.Contents()).Should(Equal(session.Err.Contents())) }) }) Describe("when the command fails to start", func() { It("should return an error", func() { _, err := Start(exec.Command("agklsjdfas"), nil, nil) Ω(err).Should(HaveOccurred()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/ghttp/000077500000000000000000000000001276516347700177605ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/ghttp/handlers.go000066400000000000000000000261261276516347700221160ustar00rootroot00000000000000package ghttp import ( "encoding/base64" "encoding/json" "fmt" "io/ioutil" "net/http" "net/url" "reflect" "github.com/golang/protobuf/proto" . "github.com/onsi/gomega" "github.com/onsi/gomega/types" ) //CombineHandler takes variadic list of handlers and produces one handler //that calls each handler in order. func CombineHandlers(handlers ...http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { for _, handler := range handlers { handler(w, req) } } } //VerifyRequest returns a handler that verifies that a request uses the specified method to connect to the specified path //You may also pass in an optional rawQuery string which is tested against the request's `req.URL.RawQuery` // //For path, you may pass in a string, in which case strict equality will be applied //Alternatively you can pass in a matcher (ContainSubstring("/foo") and MatchRegexp("/foo/[a-f0-9]+") for example) func VerifyRequest(method string, path interface{}, rawQuery ...string) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { Ω(req.Method).Should(Equal(method), "Method mismatch") switch p := path.(type) { case types.GomegaMatcher: Ω(req.URL.Path).Should(p, "Path mismatch") default: Ω(req.URL.Path).Should(Equal(path), "Path mismatch") } if len(rawQuery) > 0 { values, err := url.ParseQuery(rawQuery[0]) Ω(err).ShouldNot(HaveOccurred(), "Expected RawQuery is malformed") Ω(req.URL.Query()).Should(Equal(values), "RawQuery mismatch") } } } //VerifyContentType returns a handler that verifies that a request has a Content-Type header set to the //specified value func VerifyContentType(contentType string) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { Ω(req.Header.Get("Content-Type")).Should(Equal(contentType)) } } //VerifyBasicAuth returns a handler that verifies the request contains a BasicAuth Authorization header //matching the passed in username and password func VerifyBasicAuth(username string, password string) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { auth := req.Header.Get("Authorization") Ω(auth).ShouldNot(Equal(""), "Authorization header must be specified") decoded, err := base64.StdEncoding.DecodeString(auth[6:]) Ω(err).ShouldNot(HaveOccurred()) Ω(string(decoded)).Should(Equal(fmt.Sprintf("%s:%s", username, password)), "Authorization mismatch") } } //VerifyHeader returns a handler that verifies the request contains the passed in headers. //The passed in header keys are first canonicalized via http.CanonicalHeaderKey. // //The request must contain *all* the passed in headers, but it is allowed to have additional headers //beyond the passed in set. func VerifyHeader(header http.Header) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { for key, values := range header { key = http.CanonicalHeaderKey(key) Ω(req.Header[key]).Should(Equal(values), "Header mismatch for key: %s", key) } } } //VerifyHeaderKV returns a handler that verifies the request contains a header matching the passed in key and values //(recall that a `http.Header` is a mapping from string (key) to []string (values)) //It is a convenience wrapper around `VerifyHeader` that allows you to avoid having to create an `http.Header` object. func VerifyHeaderKV(key string, values ...string) http.HandlerFunc { return VerifyHeader(http.Header{key: values}) } //VerifyBody returns a handler that verifies that the body of the request matches the passed in byte array. //It does this using Equal(). func VerifyBody(expectedBody []byte) http.HandlerFunc { return CombineHandlers( func(w http.ResponseWriter, req *http.Request) { body, err := ioutil.ReadAll(req.Body) req.Body.Close() Ω(err).ShouldNot(HaveOccurred()) Ω(body).Should(Equal(expectedBody), "Body Mismatch") }, ) } //VerifyJSON returns a handler that verifies that the body of the request is a valid JSON representation //matching the passed in JSON string. It does this using Gomega's MatchJSON method // //VerifyJSON also verifies that the request's content type is application/json func VerifyJSON(expectedJSON string) http.HandlerFunc { return CombineHandlers( VerifyContentType("application/json"), func(w http.ResponseWriter, req *http.Request) { body, err := ioutil.ReadAll(req.Body) req.Body.Close() Ω(err).ShouldNot(HaveOccurred()) Ω(body).Should(MatchJSON(expectedJSON), "JSON Mismatch") }, ) } //VerifyJSONRepresenting is similar to VerifyJSON. Instead of taking a JSON string, however, it //takes an arbitrary JSON-encodable object and verifies that the requests's body is a JSON representation //that matches the object func VerifyJSONRepresenting(object interface{}) http.HandlerFunc { data, err := json.Marshal(object) Ω(err).ShouldNot(HaveOccurred()) return CombineHandlers( VerifyContentType("application/json"), VerifyJSON(string(data)), ) } //VerifyForm returns a handler that verifies a request contains the specified form values. // //The request must contain *all* of the specified values, but it is allowed to have additional //form values beyond the passed in set. func VerifyForm(values url.Values) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() Ω(err).ShouldNot(HaveOccurred()) for key, vals := range values { Ω(r.Form[key]).Should(Equal(vals), "Form mismatch for key: %s", key) } } } //VerifyFormKV returns a handler that verifies a request contains a form key with the specified values. // //It is a convenience wrapper around `VerifyForm` that lets you avoid having to create a `url.Values` object. func VerifyFormKV(key string, values ...string) http.HandlerFunc { return VerifyForm(url.Values{key: values}) } //VerifyProtoRepresenting returns a handler that verifies that the body of the request is a valid protobuf //representation of the passed message. // //VerifyProtoRepresenting also verifies that the request's content type is application/x-protobuf func VerifyProtoRepresenting(expected proto.Message) http.HandlerFunc { return CombineHandlers( VerifyContentType("application/x-protobuf"), func(w http.ResponseWriter, req *http.Request) { body, err := ioutil.ReadAll(req.Body) Ω(err).ShouldNot(HaveOccurred()) req.Body.Close() expectedType := reflect.TypeOf(expected) actualValuePtr := reflect.New(expectedType.Elem()) actual, ok := actualValuePtr.Interface().(proto.Message) Ω(ok).Should(BeTrue(), "Message value is not a proto.Message") err = proto.Unmarshal(body, actual) Ω(err).ShouldNot(HaveOccurred(), "Failed to unmarshal protobuf") Ω(actual).Should(Equal(expected), "ProtoBuf Mismatch") }, ) } func copyHeader(src http.Header, dst http.Header) { for key, value := range src { dst[key] = value } } /* RespondWith returns a handler that responds to a request with the specified status code and body Body may be a string or []byte Also, RespondWith can be given an optional http.Header. The headers defined therein will be added to the response headers. */ func RespondWith(statusCode int, body interface{}, optionalHeader ...http.Header) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { if len(optionalHeader) == 1 { copyHeader(optionalHeader[0], w.Header()) } w.WriteHeader(statusCode) switch x := body.(type) { case string: w.Write([]byte(x)) case []byte: w.Write(x) default: Ω(body).Should(BeNil(), "Invalid type for body. Should be string or []byte.") } } } /* RespondWithPtr returns a handler that responds to a request with the specified status code and body Unlike RespondWith, you pass RepondWithPtr a pointer to the status code and body allowing different tests to share the same setup but specify different status codes and bodies. Also, RespondWithPtr can be given an optional http.Header. The headers defined therein will be added to the response headers. Since the http.Header can be mutated after the fact you don't need to pass in a pointer. */ func RespondWithPtr(statusCode *int, body interface{}, optionalHeader ...http.Header) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { if len(optionalHeader) == 1 { copyHeader(optionalHeader[0], w.Header()) } w.WriteHeader(*statusCode) if body != nil { switch x := (body).(type) { case *string: w.Write([]byte(*x)) case *[]byte: w.Write(*x) default: Ω(body).Should(BeNil(), "Invalid type for body. Should be string or []byte.") } } } } /* RespondWithJSONEncoded returns a handler that responds to a request with the specified status code and a body containing the JSON-encoding of the passed in object Also, RespondWithJSONEncoded can be given an optional http.Header. The headers defined therein will be added to the response headers. */ func RespondWithJSONEncoded(statusCode int, object interface{}, optionalHeader ...http.Header) http.HandlerFunc { data, err := json.Marshal(object) Ω(err).ShouldNot(HaveOccurred()) var headers http.Header if len(optionalHeader) == 1 { headers = optionalHeader[0] } else { headers = make(http.Header) } if _, found := headers["Content-Type"]; !found { headers["Content-Type"] = []string{"application/json"} } return RespondWith(statusCode, string(data), headers) } /* RespondWithJSONEncodedPtr behaves like RespondWithJSONEncoded but takes a pointer to a status code and object. This allows different tests to share the same setup but specify different status codes and JSON-encoded objects. Also, RespondWithJSONEncodedPtr can be given an optional http.Header. The headers defined therein will be added to the response headers. Since the http.Header can be mutated after the fact you don't need to pass in a pointer. */ func RespondWithJSONEncodedPtr(statusCode *int, object interface{}, optionalHeader ...http.Header) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { data, err := json.Marshal(object) Ω(err).ShouldNot(HaveOccurred()) var headers http.Header if len(optionalHeader) == 1 { headers = optionalHeader[0] } else { headers = make(http.Header) } if _, found := headers["Content-Type"]; !found { headers["Content-Type"] = []string{"application/json"} } copyHeader(headers, w.Header()) w.WriteHeader(*statusCode) w.Write(data) } } //RespondWithProto returns a handler that responds to a request with the specified status code and a body //containing the protobuf serialization of the provided message. // //Also, RespondWithProto can be given an optional http.Header. The headers defined therein will be added to the response headers. func RespondWithProto(statusCode int, message proto.Message, optionalHeader ...http.Header) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { data, err := proto.Marshal(message) Ω(err).ShouldNot(HaveOccurred()) var headers http.Header if len(optionalHeader) == 1 { headers = optionalHeader[0] } else { headers = make(http.Header) } if _, found := headers["Content-Type"]; !found { headers["Content-Type"] = []string{"application/x-protobuf"} } copyHeader(headers, w.Header()) w.WriteHeader(statusCode) w.Write(data) } } golang-gomega-1.0+git20160910.d59fa0a/ghttp/protobuf/000077500000000000000000000000001276516347700216205ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/ghttp/protobuf/protobuf.go000066400000000000000000000001071276516347700240050ustar00rootroot00000000000000package protobuf //go:generate protoc --go_out=. simple_message.proto golang-gomega-1.0+git20160910.d59fa0a/ghttp/protobuf/simple_message.pb.go000066400000000000000000000025221276516347700255450ustar00rootroot00000000000000// Code generated by protoc-gen-go. // source: simple_message.proto // DO NOT EDIT! /* Package protobuf is a generated protocol buffer package. It is generated from these files: simple_message.proto It has these top-level messages: SimpleMessage */ package protobuf import proto "github.com/golang/protobuf/proto" import fmt "fmt" import math "math" // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf type SimpleMessage struct { Description *string `protobuf:"bytes,1,req,name=description" json:"description,omitempty"` Id *int32 `protobuf:"varint,2,req,name=id" json:"id,omitempty"` Metadata *string `protobuf:"bytes,3,opt,name=metadata" json:"metadata,omitempty"` XXX_unrecognized []byte `json:"-"` } func (m *SimpleMessage) Reset() { *m = SimpleMessage{} } func (m *SimpleMessage) String() string { return proto.CompactTextString(m) } func (*SimpleMessage) ProtoMessage() {} func (m *SimpleMessage) GetDescription() string { if m != nil && m.Description != nil { return *m.Description } return "" } func (m *SimpleMessage) GetId() int32 { if m != nil && m.Id != nil { return *m.Id } return 0 } func (m *SimpleMessage) GetMetadata() string { if m != nil && m.Metadata != nil { return *m.Metadata } return "" } golang-gomega-1.0+git20160910.d59fa0a/ghttp/protobuf/simple_message.proto000066400000000000000000000002431276516347700257010ustar00rootroot00000000000000syntax = "proto2"; package protobuf; message SimpleMessage { required string description = 1; required int32 id = 2; optional string metadata = 3; } golang-gomega-1.0+git20160910.d59fa0a/ghttp/test_server.go000066400000000000000000000270471276516347700226660ustar00rootroot00000000000000/* Package ghttp supports testing HTTP clients by providing a test server (simply a thin wrapper around httptest's server) that supports registering multiple handlers. Incoming requests are not routed between the different handlers - rather it is merely the order of the handlers that matters. The first request is handled by the first registered handler, the second request by the second handler, etc. The intent here is to have each handler *verify* that the incoming request is valid. To accomplish, ghttp also provides a collection of bite-size handlers that each perform one aspect of request verification. These can be composed together and registered with a ghttp server. The result is an expressive language for describing the requests generated by the client under test. Here's a simple example, note that the server handler is only defined in one BeforeEach and then modified, as required, by the nested BeforeEaches. A more comprehensive example is available at https://onsi.github.io/gomega/#_testing_http_clients var _ = Describe("A Sprockets Client", func() { var server *ghttp.Server var client *SprocketClient BeforeEach(func() { server = ghttp.NewServer() client = NewSprocketClient(server.URL(), "skywalker", "tk427") }) AfterEach(func() { server.Close() }) Describe("fetching sprockets", func() { var statusCode int var sprockets []Sprocket BeforeEach(func() { statusCode = http.StatusOK sprockets = []Sprocket{} server.AppendHandlers(ghttp.CombineHandlers( ghttp.VerifyRequest("GET", "/sprockets"), ghttp.VerifyBasicAuth("skywalker", "tk427"), ghttp.RespondWithJSONEncodedPtr(&statusCode, &sprockets), )) }) Context("when requesting all sprockets", func() { Context("when the response is succesful", func() { BeforeEach(func() { sprockets = []Sprocket{ NewSprocket("Alfalfa"), NewSprocket("Banana"), } }) It("should return the returned sprockets", func() { Ω(client.Sprockets()).Should(Equal(sprockets)) }) }) Context("when the response is missing", func() { BeforeEach(func() { statusCode = http.StatusNotFound }) It("should return an empty list of sprockets", func() { Ω(client.Sprockets()).Should(BeEmpty()) }) }) Context("when the response fails to authenticate", func() { BeforeEach(func() { statusCode = http.StatusUnauthorized }) It("should return an AuthenticationError error", func() { sprockets, err := client.Sprockets() Ω(sprockets).Should(BeEmpty()) Ω(err).Should(MatchError(AuthenticationError)) }) }) Context("when the response is a server failure", func() { BeforeEach(func() { statusCode = http.StatusInternalServerError }) It("should return an InternalError error", func() { sprockets, err := client.Sprockets() Ω(sprockets).Should(BeEmpty()) Ω(err).Should(MatchError(InternalError)) }) }) }) Context("when requesting some sprockets", func() { BeforeEach(func() { sprockets = []Sprocket{ NewSprocket("Alfalfa"), NewSprocket("Banana"), } server.WrapHandler(0, ghttp.VerifyRequest("GET", "/sprockets", "filter=FOOD")) }) It("should make the request with a filter", func() { Ω(client.Sprockets("food")).Should(Equal(sprockets)) }) }) }) }) */ package ghttp import ( "fmt" "io" "io/ioutil" "net/http" "net/http/httptest" "reflect" "regexp" "strings" "sync" . "github.com/onsi/gomega" ) func new() *Server { return &Server{ AllowUnhandledRequests: false, UnhandledRequestStatusCode: http.StatusInternalServerError, writeLock: &sync.Mutex{}, } } type routedHandler struct { method string pathRegexp *regexp.Regexp path string handler http.HandlerFunc } // NewServer returns a new `*ghttp.Server` that wraps an `httptest` server. The server is started automatically. func NewServer() *Server { s := new() s.HTTPTestServer = httptest.NewServer(s) return s } // NewUnstartedServer return a new, unstarted, `*ghttp.Server`. Useful for specifying a custom listener on `server.HTTPTestServer`. func NewUnstartedServer() *Server { s := new() s.HTTPTestServer = httptest.NewUnstartedServer(s) return s } // NewTLSServer returns a new `*ghttp.Server` that wraps an `httptest` TLS server. The server is started automatically. func NewTLSServer() *Server { s := new() s.HTTPTestServer = httptest.NewTLSServer(s) return s } type Server struct { //The underlying httptest server HTTPTestServer *httptest.Server //Defaults to false. If set to true, the Server will allow more requests than there are registered handlers. AllowUnhandledRequests bool //The status code returned when receiving an unhandled request. //Defaults to http.StatusInternalServerError. //Only applies if AllowUnhandledRequests is true UnhandledRequestStatusCode int //If provided, ghttp will log about each request received to the provided io.Writer //Defaults to nil //If you're using Ginkgo, set this to GinkgoWriter to get improved output during failures Writer io.Writer receivedRequests []*http.Request requestHandlers []http.HandlerFunc routedHandlers []routedHandler writeLock *sync.Mutex calls int } //Start() starts an unstarted ghttp server. It is a catastrophic error to call Start more than once (thanks, httptest). func (s *Server) Start() { s.HTTPTestServer.Start() } //URL() returns a url that will hit the server func (s *Server) URL() string { return s.HTTPTestServer.URL } //Addr() returns the address on which the server is listening. func (s *Server) Addr() string { return s.HTTPTestServer.Listener.Addr().String() } //Close() should be called at the end of each test. It spins down and cleans up the test server. func (s *Server) Close() { s.writeLock.Lock() defer s.writeLock.Unlock() server := s.HTTPTestServer s.HTTPTestServer = nil if server != nil { server.Close() } } //ServeHTTP() makes Server an http.Handler //When the server receives a request it handles the request in the following order: // //1. If the request matches a handler registered with RouteToHandler, that handler is called. //2. Otherwise, if there are handlers registered via AppendHandlers, those handlers are called in order. //3. If all registered handlers have been called then: // a) If AllowUnhandledRequests is true, the request will be handled with response code of UnhandledRequestStatusCode // b) If AllowUnhandledRequests is false, the request will not be handled and the current test will be marked as failed. func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) { s.writeLock.Lock() defer func() { e := recover() if e != nil { w.WriteHeader(http.StatusInternalServerError) } //If the handler panics GHTTP will silently succeed. This is bad™. //To catch this case we need to fail the test if the handler has panicked. //However, if the handler is panicking because Ginkgo's causing it to panic (i.e. an assertion failed) //then we shouldn't double-report the error as this will confuse people. //So: step 1, if this is a Ginkgo panic - do nothing, Ginkgo's aware of the failure eAsString, ok := e.(string) if ok && strings.Contains(eAsString, "defer GinkgoRecover()") { return } //If we're here, we have to do step 2: assert that the error is nil. This assertion will //allow us to fail the test suite (note: we can't call Fail since Gomega is not allowed to import Ginkgo). //Since a failed assertion throws a panic, and we are likely in a goroutine, we need to defer within our defer! defer func() { recover() }() Ω(e).Should(BeNil(), "Handler Panicked") }() if s.Writer != nil { s.Writer.Write([]byte(fmt.Sprintf("GHTTP Received Request: %s - %s\n", req.Method, req.URL))) } s.receivedRequests = append(s.receivedRequests, req) if routedHandler, ok := s.handlerForRoute(req.Method, req.URL.Path); ok { s.writeLock.Unlock() routedHandler(w, req) } else if s.calls < len(s.requestHandlers) { h := s.requestHandlers[s.calls] s.calls++ s.writeLock.Unlock() h(w, req) } else { s.writeLock.Unlock() if s.AllowUnhandledRequests { ioutil.ReadAll(req.Body) req.Body.Close() w.WriteHeader(s.UnhandledRequestStatusCode) } else { Ω(req).Should(BeNil(), "Received Unhandled Request") } } } //ReceivedRequests is an array containing all requests received by the server (both handled and unhandled requests) func (s *Server) ReceivedRequests() []*http.Request { s.writeLock.Lock() defer s.writeLock.Unlock() return s.receivedRequests } //RouteToHandler can be used to register handlers that will always handle requests that match //the passed in method and path. // //The path may be either a string object or a *regexp.Regexp. func (s *Server) RouteToHandler(method string, path interface{}, handler http.HandlerFunc) { s.writeLock.Lock() defer s.writeLock.Unlock() rh := routedHandler{ method: method, handler: handler, } switch p := path.(type) { case *regexp.Regexp: rh.pathRegexp = p case string: rh.path = p default: panic("path must be a string or a regular expression") } for i, existingRH := range s.routedHandlers { if existingRH.method == method && reflect.DeepEqual(existingRH.pathRegexp, rh.pathRegexp) && existingRH.path == rh.path { s.routedHandlers[i] = rh return } } s.routedHandlers = append(s.routedHandlers, rh) } func (s *Server) handlerForRoute(method string, path string) (http.HandlerFunc, bool) { for _, rh := range s.routedHandlers { if rh.method == method { if rh.pathRegexp != nil { if rh.pathRegexp.Match([]byte(path)) { return rh.handler, true } } else if rh.path == path { return rh.handler, true } } } return nil, false } //AppendHandlers will appends http.HandlerFuncs to the server's list of registered handlers. The first incoming request is handled by the first handler, the second by the second, etc... func (s *Server) AppendHandlers(handlers ...http.HandlerFunc) { s.writeLock.Lock() defer s.writeLock.Unlock() s.requestHandlers = append(s.requestHandlers, handlers...) } //SetHandler overrides the registered handler at the passed in index with the passed in handler //This is useful, for example, when a server has been set up in a shared context, but must be tweaked //for a particular test. func (s *Server) SetHandler(index int, handler http.HandlerFunc) { s.writeLock.Lock() defer s.writeLock.Unlock() s.requestHandlers[index] = handler } //GetHandler returns the handler registered at the passed in index. func (s *Server) GetHandler(index int) http.HandlerFunc { s.writeLock.Lock() defer s.writeLock.Unlock() return s.requestHandlers[index] } func (s *Server) Reset() { s.writeLock.Lock() defer s.writeLock.Unlock() s.HTTPTestServer.CloseClientConnections() s.calls = 0 s.receivedRequests = nil s.requestHandlers = nil s.routedHandlers = nil } //WrapHandler combines the passed in handler with the handler registered at the passed in index. //This is useful, for example, when a server has been set up in a shared context but must be tweaked //for a particular test. // //If the currently registered handler is A, and the new passed in handler is B then //WrapHandler will generate a new handler that first calls A, then calls B, and assign it to index func (s *Server) WrapHandler(index int, handler http.HandlerFunc) { existingHandler := s.GetHandler(index) s.SetHandler(index, CombineHandlers(existingHandler, handler)) } func (s *Server) CloseClientConnections() { s.writeLock.Lock() defer s.writeLock.Unlock() s.HTTPTestServer.CloseClientConnections() } golang-gomega-1.0+git20160910.d59fa0a/ghttp/test_server_suite_test.go000066400000000000000000000002741276516347700251270ustar00rootroot00000000000000package ghttp_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestGHTTP(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "GHTTP Suite") } golang-gomega-1.0+git20160910.d59fa0a/ghttp/test_server_test.go000066400000000000000000000765701276516347700237320ustar00rootroot00000000000000package ghttp_test import ( "bytes" "io" "io/ioutil" "net/http" "net/url" "regexp" "github.com/golang/protobuf/proto" "github.com/onsi/gomega/gbytes" "github.com/onsi/gomega/ghttp/protobuf" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/ghttp" ) var _ = Describe("TestServer", func() { var ( resp *http.Response err error s *Server ) BeforeEach(func() { s = NewServer() }) AfterEach(func() { s.Close() }) Describe("Resetting the server", func() { BeforeEach(func() { s.RouteToHandler("GET", "/", func(w http.ResponseWriter, req *http.Request) {}) s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) {}) http.Get(s.URL() + "/") Ω(s.ReceivedRequests()).Should(HaveLen(1)) }) It("clears all handlers and call counts", func() { s.Reset() Ω(s.ReceivedRequests()).Should(HaveLen(0)) Ω(func() { s.GetHandler(0) }).Should(Panic()) }) }) Describe("closing client connections", func() { It("closes", func() { s.RouteToHandler("GET", "/", func(w http.ResponseWriter, req *http.Request) { io.WriteString(w, req.RemoteAddr) }, ) client := http.Client{Transport: &http.Transport{DisableKeepAlives: true}} resp, err := client.Get(s.URL()) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.StatusCode).Should(Equal(200)) body, err := ioutil.ReadAll(resp.Body) resp.Body.Close() Ω(err).ShouldNot(HaveOccurred()) s.CloseClientConnections() resp, err = client.Get(s.URL()) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.StatusCode).Should(Equal(200)) body2, err := ioutil.ReadAll(resp.Body) resp.Body.Close() Ω(err).ShouldNot(HaveOccurred()) Ω(body2).ShouldNot(Equal(body)) }) }) Describe("closing server mulitple times", func() { It("should not fail", func() { s.Close() Ω(s.Close).ShouldNot(Panic()) }) }) Describe("allowing unhandled requests", func() { Context("when true", func() { BeforeEach(func() { s.AllowUnhandledRequests = true s.UnhandledRequestStatusCode = http.StatusForbidden resp, err = http.Get(s.URL() + "/foo") Ω(err).ShouldNot(HaveOccurred()) }) It("should allow unhandled requests and respond with the passed in status code", func() { Ω(err).ShouldNot(HaveOccurred()) Ω(resp.StatusCode).Should(Equal(http.StatusForbidden)) data, err := ioutil.ReadAll(resp.Body) Ω(err).ShouldNot(HaveOccurred()) Ω(data).Should(BeEmpty()) }) It("should record the requests", func() { Ω(s.ReceivedRequests()).Should(HaveLen(1)) Ω(s.ReceivedRequests()[0].URL.Path).Should(Equal("/foo")) }) }) Context("when false", func() { It("should fail when attempting a request", func() { failures := InterceptGomegaFailures(func() { http.Get(s.URL() + "/foo") }) Ω(failures[0]).Should(ContainSubstring("Received Unhandled Request")) }) }) }) Describe("Managing Handlers", func() { var called []string BeforeEach(func() { called = []string{} s.RouteToHandler("GET", "/routed", func(w http.ResponseWriter, req *http.Request) { called = append(called, "r1") }) s.RouteToHandler("POST", regexp.MustCompile(`/routed\d`), func(w http.ResponseWriter, req *http.Request) { called = append(called, "r2") }) s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) { called = append(called, "A") }, func(w http.ResponseWriter, req *http.Request) { called = append(called, "B") }) }) It("should prefer routed handlers if there is a match", func() { http.Get(s.URL() + "/routed") http.Post(s.URL()+"/routed7", "application/json", nil) http.Get(s.URL() + "/foo") http.Get(s.URL() + "/routed") http.Post(s.URL()+"/routed9", "application/json", nil) http.Get(s.URL() + "/bar") failures := InterceptGomegaFailures(func() { http.Get(s.URL() + "/foo") http.Get(s.URL() + "/routed/not/a/match") http.Get(s.URL() + "/routed7") http.Post(s.URL()+"/routed", "application/json", nil) }) Ω(failures[0]).Should(ContainSubstring("Received Unhandled Request")) Ω(failures).Should(HaveLen(4)) http.Post(s.URL()+"/routed3", "application/json", nil) Ω(called).Should(Equal([]string{"r1", "r2", "A", "r1", "r2", "B", "r2"})) }) It("should override routed handlers when reregistered", func() { s.RouteToHandler("GET", "/routed", func(w http.ResponseWriter, req *http.Request) { called = append(called, "r3") }) s.RouteToHandler("POST", regexp.MustCompile(`/routed\d`), func(w http.ResponseWriter, req *http.Request) { called = append(called, "r4") }) http.Get(s.URL() + "/routed") http.Post(s.URL()+"/routed7", "application/json", nil) Ω(called).Should(Equal([]string{"r3", "r4"})) }) It("should call the appended handlers, in order, as requests come in", func() { http.Get(s.URL() + "/foo") Ω(called).Should(Equal([]string{"A"})) http.Get(s.URL() + "/foo") Ω(called).Should(Equal([]string{"A", "B"})) failures := InterceptGomegaFailures(func() { http.Get(s.URL() + "/foo") }) Ω(failures[0]).Should(ContainSubstring("Received Unhandled Request")) }) Describe("Overwriting an existing handler", func() { BeforeEach(func() { s.SetHandler(0, func(w http.ResponseWriter, req *http.Request) { called = append(called, "C") }) }) It("should override the specified handler", func() { http.Get(s.URL() + "/foo") http.Get(s.URL() + "/foo") Ω(called).Should(Equal([]string{"C", "B"})) }) }) Describe("Getting an existing handler", func() { It("should return the handler func", func() { s.GetHandler(1)(nil, nil) Ω(called).Should(Equal([]string{"B"})) }) }) Describe("Wrapping an existing handler", func() { BeforeEach(func() { s.WrapHandler(0, func(w http.ResponseWriter, req *http.Request) { called = append(called, "C") }) }) It("should wrap the existing handler in a new handler", func() { http.Get(s.URL() + "/foo") http.Get(s.URL() + "/foo") Ω(called).Should(Equal([]string{"A", "C", "B"})) }) }) }) Describe("When a handler fails", func() { BeforeEach(func() { s.UnhandledRequestStatusCode = http.StatusForbidden //just to be clear that 500s aren't coming from unhandled requests }) Context("because the handler has panicked", func() { BeforeEach(func() { s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) { panic("bam") }) }) It("should respond with a 500 and make a failing assertion", func() { var resp *http.Response var err error failures := InterceptGomegaFailures(func() { resp, err = http.Get(s.URL()) }) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.StatusCode).Should(Equal(http.StatusInternalServerError)) Ω(failures).Should(ConsistOf(ContainSubstring("Handler Panicked"))) }) }) Context("because an assertion has failed", func() { BeforeEach(func() { s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) { // Ω(true).Should(BeFalse()) <-- would be nice to do it this way, but the test just can't be written this way By("We're cheating a bit here -- we're throwing a GINKGO_PANIC which simulates a failed assertion") panic(GINKGO_PANIC) }) }) It("should respond with a 500 and *not* make a failing assertion, instead relying on Ginkgo to have already been notified of the error", func() { resp, err := http.Get(s.URL()) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.StatusCode).Should(Equal(http.StatusInternalServerError)) }) }) }) Describe("Logging to the Writer", func() { var buf *gbytes.Buffer BeforeEach(func() { buf = gbytes.NewBuffer() s.Writer = buf s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) {}) s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) {}) }) It("should write to the buffer when a request comes in", func() { http.Get(s.URL() + "/foo") Ω(buf).Should(gbytes.Say("GHTTP Received Request: GET - /foo\n")) http.Post(s.URL()+"/bar", "", nil) Ω(buf).Should(gbytes.Say("GHTTP Received Request: POST - /bar\n")) }) }) Describe("Request Handlers", func() { Describe("VerifyRequest", func() { BeforeEach(func() { s.AppendHandlers(VerifyRequest("GET", "/foo")) }) It("should verify the method, path", func() { resp, err = http.Get(s.URL() + "/foo?baz=bar") Ω(err).ShouldNot(HaveOccurred()) }) It("should verify the method, path", func() { failures := InterceptGomegaFailures(func() { http.Get(s.URL() + "/foo2") }) Ω(failures).Should(HaveLen(1)) }) It("should verify the method, path", func() { failures := InterceptGomegaFailures(func() { http.Post(s.URL()+"/foo", "application/json", nil) }) Ω(failures).Should(HaveLen(1)) }) Context("when passed a rawQuery", func() { It("should also be possible to verify the rawQuery", func() { s.SetHandler(0, VerifyRequest("GET", "/foo", "baz=bar")) resp, err = http.Get(s.URL() + "/foo?baz=bar") Ω(err).ShouldNot(HaveOccurred()) }) It("should match irregardless of query parameter ordering", func() { s.SetHandler(0, VerifyRequest("GET", "/foo", "type=get&name=money")) u, _ := url.Parse(s.URL() + "/foo") u.RawQuery = url.Values{ "type": []string{"get"}, "name": []string{"money"}, }.Encode() resp, err = http.Get(u.String()) Ω(err).ShouldNot(HaveOccurred()) }) }) Context("when passed a matcher for path", func() { It("should apply the matcher", func() { s.SetHandler(0, VerifyRequest("GET", MatchRegexp(`/foo/[a-f]*/3`))) resp, err = http.Get(s.URL() + "/foo/abcdefa/3") Ω(err).ShouldNot(HaveOccurred()) }) }) }) Describe("VerifyContentType", func() { BeforeEach(func() { s.AppendHandlers(CombineHandlers( VerifyRequest("GET", "/foo"), VerifyContentType("application/octet-stream"), )) }) It("should verify the content type", func() { req, err := http.NewRequest("GET", s.URL()+"/foo", nil) Ω(err).ShouldNot(HaveOccurred()) req.Header.Set("Content-Type", "application/octet-stream") resp, err = http.DefaultClient.Do(req) Ω(err).ShouldNot(HaveOccurred()) }) It("should verify the content type", func() { req, err := http.NewRequest("GET", s.URL()+"/foo", nil) Ω(err).ShouldNot(HaveOccurred()) req.Header.Set("Content-Type", "application/json") failures := InterceptGomegaFailures(func() { http.DefaultClient.Do(req) }) Ω(failures).Should(HaveLen(1)) }) }) Describe("Verify BasicAuth", func() { BeforeEach(func() { s.AppendHandlers(CombineHandlers( VerifyRequest("GET", "/foo"), VerifyBasicAuth("bob", "password"), )) }) It("should verify basic auth", func() { req, err := http.NewRequest("GET", s.URL()+"/foo", nil) Ω(err).ShouldNot(HaveOccurred()) req.SetBasicAuth("bob", "password") resp, err = http.DefaultClient.Do(req) Ω(err).ShouldNot(HaveOccurred()) }) It("should verify basic auth", func() { req, err := http.NewRequest("GET", s.URL()+"/foo", nil) Ω(err).ShouldNot(HaveOccurred()) req.SetBasicAuth("bob", "bassword") failures := InterceptGomegaFailures(func() { http.DefaultClient.Do(req) }) Ω(failures).Should(HaveLen(1)) }) It("should require basic auth header", func() { req, err := http.NewRequest("GET", s.URL()+"/foo", nil) Ω(err).ShouldNot(HaveOccurred()) failures := InterceptGomegaFailures(func() { http.DefaultClient.Do(req) }) Ω(failures).Should(ContainElement(ContainSubstring("Authorization header must be specified"))) }) }) Describe("VerifyHeader", func() { BeforeEach(func() { s.AppendHandlers(CombineHandlers( VerifyRequest("GET", "/foo"), VerifyHeader(http.Header{ "accept": []string{"jpeg", "png"}, "cache-control": []string{"omicron"}, "Return-Path": []string{"hobbiton"}, }), )) }) It("should verify the headers", func() { req, err := http.NewRequest("GET", s.URL()+"/foo", nil) Ω(err).ShouldNot(HaveOccurred()) req.Header.Add("Accept", "jpeg") req.Header.Add("Accept", "png") req.Header.Add("Cache-Control", "omicron") req.Header.Add("return-path", "hobbiton") resp, err = http.DefaultClient.Do(req) Ω(err).ShouldNot(HaveOccurred()) }) It("should verify the headers", func() { req, err := http.NewRequest("GET", s.URL()+"/foo", nil) Ω(err).ShouldNot(HaveOccurred()) req.Header.Add("Schmaccept", "jpeg") req.Header.Add("Schmaccept", "png") req.Header.Add("Cache-Control", "omicron") req.Header.Add("return-path", "hobbiton") failures := InterceptGomegaFailures(func() { http.DefaultClient.Do(req) }) Ω(failures).Should(HaveLen(1)) }) }) Describe("VerifyHeaderKV", func() { BeforeEach(func() { s.AppendHandlers(CombineHandlers( VerifyRequest("GET", "/foo"), VerifyHeaderKV("accept", "jpeg", "png"), VerifyHeaderKV("cache-control", "omicron"), VerifyHeaderKV("Return-Path", "hobbiton"), )) }) It("should verify the headers", func() { req, err := http.NewRequest("GET", s.URL()+"/foo", nil) Ω(err).ShouldNot(HaveOccurred()) req.Header.Add("Accept", "jpeg") req.Header.Add("Accept", "png") req.Header.Add("Cache-Control", "omicron") req.Header.Add("return-path", "hobbiton") resp, err = http.DefaultClient.Do(req) Ω(err).ShouldNot(HaveOccurred()) }) It("should verify the headers", func() { req, err := http.NewRequest("GET", s.URL()+"/foo", nil) Ω(err).ShouldNot(HaveOccurred()) req.Header.Add("Accept", "jpeg") req.Header.Add("Cache-Control", "omicron") req.Header.Add("return-path", "hobbiton") failures := InterceptGomegaFailures(func() { http.DefaultClient.Do(req) }) Ω(failures).Should(HaveLen(1)) }) }) Describe("VerifyBody", func() { BeforeEach(func() { s.AppendHandlers(CombineHandlers( VerifyRequest("POST", "/foo"), VerifyBody([]byte("some body")), )) }) It("should verify the body", func() { resp, err = http.Post(s.URL()+"/foo", "", bytes.NewReader([]byte("some body"))) Ω(err).ShouldNot(HaveOccurred()) }) It("should verify the body", func() { failures := InterceptGomegaFailures(func() { http.Post(s.URL()+"/foo", "", bytes.NewReader([]byte("wrong body"))) }) Ω(failures).Should(HaveLen(1)) }) }) Describe("VerifyJSON", func() { BeforeEach(func() { s.AppendHandlers(CombineHandlers( VerifyRequest("POST", "/foo"), VerifyJSON(`{"a":3, "b":2}`), )) }) It("should verify the json body and the content type", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", bytes.NewReader([]byte(`{"b":2, "a":3}`))) Ω(err).ShouldNot(HaveOccurred()) }) It("should verify the json body and the content type", func() { failures := InterceptGomegaFailures(func() { http.Post(s.URL()+"/foo", "application/json", bytes.NewReader([]byte(`{"b":2, "a":4}`))) }) Ω(failures).Should(HaveLen(1)) }) It("should verify the json body and the content type", func() { failures := InterceptGomegaFailures(func() { http.Post(s.URL()+"/foo", "application/not-json", bytes.NewReader([]byte(`{"b":2, "a":3}`))) }) Ω(failures).Should(HaveLen(1)) }) }) Describe("VerifyJSONRepresenting", func() { BeforeEach(func() { s.AppendHandlers(CombineHandlers( VerifyRequest("POST", "/foo"), VerifyJSONRepresenting([]int{1, 3, 5}), )) }) It("should verify the json body and the content type", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", bytes.NewReader([]byte(`[1,3,5]`))) Ω(err).ShouldNot(HaveOccurred()) }) It("should verify the json body and the content type", func() { failures := InterceptGomegaFailures(func() { http.Post(s.URL()+"/foo", "application/json", bytes.NewReader([]byte(`[1,3]`))) }) Ω(failures).Should(HaveLen(1)) }) }) Describe("VerifyForm", func() { var formValues url.Values BeforeEach(func() { formValues = make(url.Values) formValues.Add("users", "user1") formValues.Add("users", "user2") formValues.Add("group", "users") }) Context("when encoded in the URL", func() { BeforeEach(func() { s.AppendHandlers(CombineHandlers( VerifyRequest("GET", "/foo"), VerifyForm(url.Values{ "users": []string{"user1", "user2"}, "group": []string{"users"}, }), )) }) It("should verify form values", func() { resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode()) Ω(err).ShouldNot(HaveOccurred()) }) It("should ignore extra values", func() { formValues.Add("extra", "value") resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode()) Ω(err).ShouldNot(HaveOccurred()) }) It("fail on missing values", func() { formValues.Del("group") failures := InterceptGomegaFailures(func() { resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode()) }) Ω(failures).Should(HaveLen(1)) }) It("fail on incorrect values", func() { formValues.Set("group", "wheel") failures := InterceptGomegaFailures(func() { resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode()) }) Ω(failures).Should(HaveLen(1)) }) }) Context("when present in the body", func() { BeforeEach(func() { s.AppendHandlers(CombineHandlers( VerifyRequest("POST", "/foo"), VerifyForm(url.Values{ "users": []string{"user1", "user2"}, "group": []string{"users"}, }), )) }) It("should verify form values", func() { resp, err = http.PostForm(s.URL()+"/foo", formValues) Ω(err).ShouldNot(HaveOccurred()) }) It("should ignore extra values", func() { formValues.Add("extra", "value") resp, err = http.PostForm(s.URL()+"/foo", formValues) Ω(err).ShouldNot(HaveOccurred()) }) It("fail on missing values", func() { formValues.Del("group") failures := InterceptGomegaFailures(func() { resp, err = http.PostForm(s.URL()+"/foo", formValues) }) Ω(failures).Should(HaveLen(1)) }) It("fail on incorrect values", func() { formValues.Set("group", "wheel") failures := InterceptGomegaFailures(func() { resp, err = http.PostForm(s.URL()+"/foo", formValues) }) Ω(failures).Should(HaveLen(1)) }) }) }) Describe("VerifyFormKV", func() { Context("when encoded in the URL", func() { BeforeEach(func() { s.AppendHandlers(CombineHandlers( VerifyRequest("GET", "/foo"), VerifyFormKV("users", "user1", "user2"), )) }) It("verifies the form value", func() { resp, err = http.Get(s.URL() + "/foo?users=user1&users=user2") Ω(err).ShouldNot(HaveOccurred()) }) It("verifies the form value", func() { failures := InterceptGomegaFailures(func() { resp, err = http.Get(s.URL() + "/foo?users=user1") }) Ω(failures).Should(HaveLen(1)) }) }) Context("when present in the body", func() { BeforeEach(func() { s.AppendHandlers(CombineHandlers( VerifyRequest("POST", "/foo"), VerifyFormKV("users", "user1", "user2"), )) }) It("verifies the form value", func() { resp, err = http.PostForm(s.URL()+"/foo", url.Values{"users": []string{"user1", "user2"}}) Ω(err).ShouldNot(HaveOccurred()) }) It("verifies the form value", func() { failures := InterceptGomegaFailures(func() { resp, err = http.PostForm(s.URL()+"/foo", url.Values{"users": []string{"user1"}}) }) Ω(failures).Should(HaveLen(1)) }) }) }) Describe("VerifyProtoRepresenting", func() { var message *protobuf.SimpleMessage BeforeEach(func() { message = new(protobuf.SimpleMessage) message.Description = proto.String("A description") message.Id = proto.Int32(0) s.AppendHandlers(CombineHandlers( VerifyRequest("POST", "/proto"), VerifyProtoRepresenting(message), )) }) It("verifies the proto body and the content type", func() { serialized, err := proto.Marshal(message) Ω(err).ShouldNot(HaveOccurred()) resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", bytes.NewReader(serialized)) Ω(err).ShouldNot(HaveOccurred()) }) It("should verify the proto body and the content type", func() { serialized, err := proto.Marshal(&protobuf.SimpleMessage{ Description: proto.String("A description"), Id: proto.Int32(0), Metadata: proto.String("some metadata"), }) Ω(err).ShouldNot(HaveOccurred()) failures := InterceptGomegaFailures(func() { http.Post(s.URL()+"/proto", "application/x-protobuf", bytes.NewReader(serialized)) }) Ω(failures).Should(HaveLen(1)) }) It("should verify the proto body and the content type", func() { serialized, err := proto.Marshal(message) Ω(err).ShouldNot(HaveOccurred()) failures := InterceptGomegaFailures(func() { http.Post(s.URL()+"/proto", "application/not-x-protobuf", bytes.NewReader(serialized)) }) Ω(failures).Should(HaveLen(1)) }) }) Describe("RespondWith", func() { Context("without headers", func() { BeforeEach(func() { s.AppendHandlers(CombineHandlers( VerifyRequest("POST", "/foo"), RespondWith(http.StatusCreated, "sweet"), ), CombineHandlers( VerifyRequest("POST", "/foo"), RespondWith(http.StatusOK, []byte("sour")), )) }) It("should return the response", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.StatusCode).Should(Equal(http.StatusCreated)) body, err := ioutil.ReadAll(resp.Body) Ω(err).ShouldNot(HaveOccurred()) Ω(body).Should(Equal([]byte("sweet"))) resp, err = http.Post(s.URL()+"/foo", "application/json", nil) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.StatusCode).Should(Equal(http.StatusOK)) body, err = ioutil.ReadAll(resp.Body) Ω(err).ShouldNot(HaveOccurred()) Ω(body).Should(Equal([]byte("sour"))) }) }) Context("with headers", func() { BeforeEach(func() { s.AppendHandlers(CombineHandlers( VerifyRequest("POST", "/foo"), RespondWith(http.StatusCreated, "sweet", http.Header{"X-Custom-Header": []string{"my header"}}), )) }) It("should return the headers too", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.StatusCode).Should(Equal(http.StatusCreated)) Ω(ioutil.ReadAll(resp.Body)).Should(Equal([]byte("sweet"))) Ω(resp.Header.Get("X-Custom-Header")).Should(Equal("my header")) }) }) }) Describe("RespondWithPtr", func() { var code int var byteBody []byte var stringBody string BeforeEach(func() { code = http.StatusOK byteBody = []byte("sweet") stringBody = "sour" s.AppendHandlers(CombineHandlers( VerifyRequest("POST", "/foo"), RespondWithPtr(&code, &byteBody), ), CombineHandlers( VerifyRequest("POST", "/foo"), RespondWithPtr(&code, &stringBody), )) }) It("should return the response", func() { code = http.StatusCreated byteBody = []byte("tasty") stringBody = "treat" resp, err = http.Post(s.URL()+"/foo", "application/json", nil) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.StatusCode).Should(Equal(http.StatusCreated)) body, err := ioutil.ReadAll(resp.Body) Ω(err).ShouldNot(HaveOccurred()) Ω(body).Should(Equal([]byte("tasty"))) resp, err = http.Post(s.URL()+"/foo", "application/json", nil) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.StatusCode).Should(Equal(http.StatusCreated)) body, err = ioutil.ReadAll(resp.Body) Ω(err).ShouldNot(HaveOccurred()) Ω(body).Should(Equal([]byte("treat"))) }) Context("when passed a nil body", func() { BeforeEach(func() { s.SetHandler(0, CombineHandlers( VerifyRequest("POST", "/foo"), RespondWithPtr(&code, nil), )) }) It("should return an empty body and not explode", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.StatusCode).Should(Equal(http.StatusOK)) body, err := ioutil.ReadAll(resp.Body) Ω(err).ShouldNot(HaveOccurred()) Ω(body).Should(BeEmpty()) Ω(s.ReceivedRequests()).Should(HaveLen(1)) }) }) }) Describe("RespondWithJSON", func() { Context("when no optional headers are set", func() { BeforeEach(func() { s.AppendHandlers(CombineHandlers( VerifyRequest("POST", "/foo"), RespondWithJSONEncoded(http.StatusCreated, []int{1, 2, 3}), )) }) It("should return the response", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.StatusCode).Should(Equal(http.StatusCreated)) body, err := ioutil.ReadAll(resp.Body) Ω(err).ShouldNot(HaveOccurred()) Ω(body).Should(MatchJSON("[1,2,3]")) }) It("should set the Content-Type header to application/json", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"})) }) }) Context("when optional headers are set", func() { var headers http.Header BeforeEach(func() { headers = http.Header{"Stuff": []string{"things"}} }) JustBeforeEach(func() { s.AppendHandlers(CombineHandlers( VerifyRequest("POST", "/foo"), RespondWithJSONEncoded(http.StatusCreated, []int{1, 2, 3}, headers), )) }) It("should preserve those headers", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.Header["Stuff"]).Should(Equal([]string{"things"})) }) It("should set the Content-Type header to application/json", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"})) }) Context("when setting the Content-Type explicitly", func() { BeforeEach(func() { headers["Content-Type"] = []string{"not-json"} }) It("should use the Content-Type header that was explicitly set", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.Header["Content-Type"]).Should(Equal([]string{"not-json"})) }) }) }) }) Describe("RespondWithJSONPtr", func() { type testObject struct { Key string Value string } var code int var object testObject Context("when no optional headers are set", func() { BeforeEach(func() { code = http.StatusOK object = testObject{} s.AppendHandlers(CombineHandlers( VerifyRequest("POST", "/foo"), RespondWithJSONEncodedPtr(&code, &object), )) }) It("should return the response", func() { code = http.StatusCreated object = testObject{ Key: "Jim", Value: "Codes", } resp, err = http.Post(s.URL()+"/foo", "application/json", nil) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.StatusCode).Should(Equal(http.StatusCreated)) body, err := ioutil.ReadAll(resp.Body) Ω(err).ShouldNot(HaveOccurred()) Ω(body).Should(MatchJSON(`{"Key": "Jim", "Value": "Codes"}`)) }) It("should set the Content-Type header to application/json", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"})) }) }) Context("when optional headers are set", func() { var headers http.Header BeforeEach(func() { headers = http.Header{"Stuff": []string{"things"}} }) JustBeforeEach(func() { code = http.StatusOK object = testObject{} s.AppendHandlers(CombineHandlers( VerifyRequest("POST", "/foo"), RespondWithJSONEncodedPtr(&code, &object, headers), )) }) It("should preserve those headers", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.Header["Stuff"]).Should(Equal([]string{"things"})) }) It("should set the Content-Type header to application/json", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"})) }) Context("when setting the Content-Type explicitly", func() { BeforeEach(func() { headers["Content-Type"] = []string{"not-json"} }) It("should use the Content-Type header that was explicitly set", func() { resp, err = http.Post(s.URL()+"/foo", "application/json", nil) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.Header["Content-Type"]).Should(Equal([]string{"not-json"})) }) }) }) }) Describe("RespondWithProto", func() { var message *protobuf.SimpleMessage BeforeEach(func() { message = new(protobuf.SimpleMessage) message.Description = proto.String("A description") message.Id = proto.Int32(99) }) Context("when no optional headers are set", func() { BeforeEach(func() { s.AppendHandlers(CombineHandlers( VerifyRequest("POST", "/proto"), RespondWithProto(http.StatusCreated, message), )) }) It("should return the response", func() { resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.StatusCode).Should(Equal(http.StatusCreated)) var received protobuf.SimpleMessage body, err := ioutil.ReadAll(resp.Body) err = proto.Unmarshal(body, &received) Ω(err).ShouldNot(HaveOccurred()) }) It("should set the Content-Type header to application/x-protobuf", func() { resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/x-protobuf"})) }) }) Context("when optional headers are set", func() { var headers http.Header BeforeEach(func() { headers = http.Header{"Stuff": []string{"things"}} }) JustBeforeEach(func() { s.AppendHandlers(CombineHandlers( VerifyRequest("POST", "/proto"), RespondWithProto(http.StatusCreated, message, headers), )) }) It("should preserve those headers", func() { resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.Header["Stuff"]).Should(Equal([]string{"things"})) }) It("should set the Content-Type header to application/x-protobuf", func() { resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/x-protobuf"})) }) Context("when setting the Content-Type explicitly", func() { BeforeEach(func() { headers["Content-Type"] = []string{"not-x-protobuf"} }) It("should use the Content-Type header that was explicitly set", func() { resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil) Ω(err).ShouldNot(HaveOccurred()) Ω(resp.Header["Content-Type"]).Should(Equal([]string{"not-x-protobuf"})) }) }) }) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/gomega_dsl.go000066400000000000000000000333741276516347700212740ustar00rootroot00000000000000/* Gomega is the Ginkgo BDD-style testing framework's preferred matcher library. The godoc documentation describes Gomega's API. More comprehensive documentation (with examples!) is available at http://onsi.github.io/gomega/ Gomega on Github: http://github.com/onsi/gomega Learn more about Ginkgo online: http://onsi.github.io/ginkgo Ginkgo on Github: http://github.com/onsi/ginkgo Gomega is MIT-Licensed */ package gomega import ( "fmt" "reflect" "time" "github.com/onsi/gomega/internal/assertion" "github.com/onsi/gomega/internal/asyncassertion" "github.com/onsi/gomega/internal/testingtsupport" "github.com/onsi/gomega/types" ) const GOMEGA_VERSION = "1.0" const nilFailHandlerPanic = `You are trying to make an assertion, but Gomega's fail handler is nil. If you're using Ginkgo then you probably forgot to put your assertion in an It(). Alternatively, you may have forgotten to register a fail handler with RegisterFailHandler() or RegisterTestingT(). ` var globalFailHandler types.GomegaFailHandler var defaultEventuallyTimeout = time.Second var defaultEventuallyPollingInterval = 10 * time.Millisecond var defaultConsistentlyDuration = 100 * time.Millisecond var defaultConsistentlyPollingInterval = 10 * time.Millisecond //RegisterFailHandler connects Ginkgo to Gomega. When a matcher fails //the fail handler passed into RegisterFailHandler is called. func RegisterFailHandler(handler types.GomegaFailHandler) { globalFailHandler = handler } //RegisterTestingT connects Gomega to Golang's XUnit style //Testing.T tests. You'll need to call this at the top of each XUnit style test: // // func TestFarmHasCow(t *testing.T) { // RegisterTestingT(t) // // f := farm.New([]string{"Cow", "Horse"}) // Expect(f.HasCow()).To(BeTrue(), "Farm should have cow") // } // // Note that this *testing.T is registered *globally* by Gomega (this is why you don't have to // pass `t` down to the matcher itself). This means that you cannot run the XUnit style tests // in parallel as the global fail handler cannot point to more than one testing.T at a time. // // (As an aside: Ginkgo gets around this limitation by running parallel tests in different *processes*). func RegisterTestingT(t types.GomegaTestingT) { RegisterFailHandler(testingtsupport.BuildTestingTGomegaFailHandler(t)) } //InterceptGomegaHandlers runs a given callback and returns an array of //failure messages generated by any Gomega assertions within the callback. // //This is accomplished by temporarily replacing the *global* fail handler //with a fail handler that simply annotates failures. The original fail handler //is reset when InterceptGomegaFailures returns. // //This is most useful when testing custom matchers, but can also be used to check //on a value using a Gomega assertion without causing a test failure. func InterceptGomegaFailures(f func()) []string { originalHandler := globalFailHandler failures := []string{} RegisterFailHandler(func(message string, callerSkip ...int) { failures = append(failures, message) }) f() RegisterFailHandler(originalHandler) return failures } //Ω wraps an actual value allowing assertions to be made on it: // Ω("foo").Should(Equal("foo")) // //If Ω is passed more than one argument it will pass the *first* argument to the matcher. //All subsequent arguments will be required to be nil/zero. // //This is convenient if you want to make an assertion on a method/function that returns //a value and an error - a common patter in Go. // //For example, given a function with signature: // func MyAmazingThing() (int, error) // //Then: // Ω(MyAmazingThing()).Should(Equal(3)) //Will succeed only if `MyAmazingThing()` returns `(3, nil)` // //Ω and Expect are identical func Ω(actual interface{}, extra ...interface{}) GomegaAssertion { return ExpectWithOffset(0, actual, extra...) } //Expect wraps an actual value allowing assertions to be made on it: // Expect("foo").To(Equal("foo")) // //If Expect is passed more than one argument it will pass the *first* argument to the matcher. //All subsequent arguments will be required to be nil/zero. // //This is convenient if you want to make an assertion on a method/function that returns //a value and an error - a common patter in Go. // //For example, given a function with signature: // func MyAmazingThing() (int, error) // //Then: // Expect(MyAmazingThing()).Should(Equal(3)) //Will succeed only if `MyAmazingThing()` returns `(3, nil)` // //Expect and Ω are identical func Expect(actual interface{}, extra ...interface{}) GomegaAssertion { return ExpectWithOffset(0, actual, extra...) } //ExpectWithOffset wraps an actual value allowing assertions to be made on it: // ExpectWithOffset(1, "foo").To(Equal("foo")) // //Unlike `Expect` and `Ω`, `ExpectWithOffset` takes an additional integer argument //this is used to modify the call-stack offset when computing line numbers. // //This is most useful in helper functions that make assertions. If you want Gomega's //error message to refer to the calling line in the test (as opposed to the line in the helper function) //set the first argument of `ExpectWithOffset` appropriately. func ExpectWithOffset(offset int, actual interface{}, extra ...interface{}) GomegaAssertion { if globalFailHandler == nil { panic(nilFailHandlerPanic) } return assertion.New(actual, globalFailHandler, offset, extra...) } //Eventually wraps an actual value allowing assertions to be made on it. //The assertion is tried periodically until it passes or a timeout occurs. // //Both the timeout and polling interval are configurable as optional arguments: //The first optional argument is the timeout //The second optional argument is the polling interval // //Both intervals can either be specified as time.Duration, parsable duration strings or as floats/integers. In the //last case they are interpreted as seconds. // //If Eventually is passed an actual that is a function taking no arguments and returning at least one value, //then Eventually will call the function periodically and try the matcher against the function's first return value. // //Example: // // Eventually(func() int { // return thingImPolling.Count() // }).Should(BeNumerically(">=", 17)) // //Note that this example could be rewritten: // // Eventually(thingImPolling.Count).Should(BeNumerically(">=", 17)) // //If the function returns more than one value, then Eventually will pass the first value to the matcher and //assert that all other values are nil/zero. //This allows you to pass Eventually a function that returns a value and an error - a common pattern in Go. // //For example, consider a method that returns a value and an error: // func FetchFromDB() (string, error) // //Then // Eventually(FetchFromDB).Should(Equal("hasselhoff")) // //Will pass only if the the returned error is nil and the returned string passes the matcher. // //Eventually's default timeout is 1 second, and its default polling interval is 10ms func Eventually(actual interface{}, intervals ...interface{}) GomegaAsyncAssertion { return EventuallyWithOffset(0, actual, intervals...) } //EventuallyWithOffset operates like Eventually but takes an additional //initial argument to indicate an offset in the call stack. This is useful when building helper //functions that contain matchers. To learn more, read about `ExpectWithOffset`. func EventuallyWithOffset(offset int, actual interface{}, intervals ...interface{}) GomegaAsyncAssertion { if globalFailHandler == nil { panic(nilFailHandlerPanic) } timeoutInterval := defaultEventuallyTimeout pollingInterval := defaultEventuallyPollingInterval if len(intervals) > 0 { timeoutInterval = toDuration(intervals[0]) } if len(intervals) > 1 { pollingInterval = toDuration(intervals[1]) } return asyncassertion.New(asyncassertion.AsyncAssertionTypeEventually, actual, globalFailHandler, timeoutInterval, pollingInterval, offset) } //Consistently wraps an actual value allowing assertions to be made on it. //The assertion is tried periodically and is required to pass for a period of time. // //Both the total time and polling interval are configurable as optional arguments: //The first optional argument is the duration that Consistently will run for //The second optional argument is the polling interval // //Both intervals can either be specified as time.Duration, parsable duration strings or as floats/integers. In the //last case they are interpreted as seconds. // //If Consistently is passed an actual that is a function taking no arguments and returning at least one value, //then Consistently will call the function periodically and try the matcher against the function's first return value. // //If the function returns more than one value, then Consistently will pass the first value to the matcher and //assert that all other values are nil/zero. //This allows you to pass Consistently a function that returns a value and an error - a common pattern in Go. // //Consistently is useful in cases where you want to assert that something *does not happen* over a period of tiem. //For example, you want to assert that a goroutine does *not* send data down a channel. In this case, you could: // // Consistently(channel).ShouldNot(Receive()) // //Consistently's default duration is 100ms, and its default polling interval is 10ms func Consistently(actual interface{}, intervals ...interface{}) GomegaAsyncAssertion { return ConsistentlyWithOffset(0, actual, intervals...) } //ConsistentlyWithOffset operates like Consistnetly but takes an additional //initial argument to indicate an offset in the call stack. This is useful when building helper //functions that contain matchers. To learn more, read about `ExpectWithOffset`. func ConsistentlyWithOffset(offset int, actual interface{}, intervals ...interface{}) GomegaAsyncAssertion { if globalFailHandler == nil { panic(nilFailHandlerPanic) } timeoutInterval := defaultConsistentlyDuration pollingInterval := defaultConsistentlyPollingInterval if len(intervals) > 0 { timeoutInterval = toDuration(intervals[0]) } if len(intervals) > 1 { pollingInterval = toDuration(intervals[1]) } return asyncassertion.New(asyncassertion.AsyncAssertionTypeConsistently, actual, globalFailHandler, timeoutInterval, pollingInterval, offset) } //Set the default timeout duration for Eventually. Eventually will repeatedly poll your condition until it succeeds, or until this timeout elapses. func SetDefaultEventuallyTimeout(t time.Duration) { defaultEventuallyTimeout = t } //Set the default polling interval for Eventually. func SetDefaultEventuallyPollingInterval(t time.Duration) { defaultEventuallyPollingInterval = t } //Set the default duration for Consistently. Consistently will verify that your condition is satsified for this long. func SetDefaultConsistentlyDuration(t time.Duration) { defaultConsistentlyDuration = t } //Set the default polling interval for Consistently. func SetDefaultConsistentlyPollingInterval(t time.Duration) { defaultConsistentlyPollingInterval = t } //GomegaAsyncAssertion is returned by Eventually and Consistently and polls the actual value passed into Eventually against //the matcher passed to the Should and ShouldNot methods. // //Both Should and ShouldNot take a variadic optionalDescription argument. This is passed on to //fmt.Sprintf() and is used to annotate failure messages. This allows you to make your failure messages more //descriptive // //Both Should and ShouldNot return a boolean that is true if the assertion passed and false if it failed. // //Example: // // Eventually(myChannel).Should(Receive(), "Something should have come down the pipe.") // Consistently(myChannel).ShouldNot(Receive(), "Nothing should have come down the pipe.") type GomegaAsyncAssertion interface { Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool } //GomegaAssertion is returned by Ω and Expect and compares the actual value to the matcher //passed to the Should/ShouldNot and To/ToNot/NotTo methods. // //Typically Should/ShouldNot are used with Ω and To/ToNot/NotTo are used with Expect //though this is not enforced. // //All methods take a variadic optionalDescription argument. This is passed on to fmt.Sprintf() //and is used to annotate failure messages. // //All methods return a bool that is true if hte assertion passed and false if it failed. // //Example: // // Ω(farm.HasCow()).Should(BeTrue(), "Farm %v should have a cow", farm) type GomegaAssertion interface { Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool To(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool ToNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool NotTo(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool } //OmegaMatcher is deprecated in favor of the better-named and better-organized types.GomegaMatcher but sticks around to support existing code that uses it type OmegaMatcher types.GomegaMatcher func toDuration(input interface{}) time.Duration { duration, ok := input.(time.Duration) if ok { return duration } value := reflect.ValueOf(input) kind := reflect.TypeOf(input).Kind() if reflect.Int <= kind && kind <= reflect.Int64 { return time.Duration(value.Int()) * time.Second } else if reflect.Uint <= kind && kind <= reflect.Uint64 { return time.Duration(value.Uint()) * time.Second } else if reflect.Float32 <= kind && kind <= reflect.Float64 { return time.Duration(value.Float() * float64(time.Second)) } else if reflect.String == kind { duration, err := time.ParseDuration(value.String()) if err != nil { panic(fmt.Sprintf("%#v is not a valid parsable duration string.", input)) } return duration } panic(fmt.Sprintf("%v is not a valid interval. Must be time.Duration, parsable duration string or a number.", input)) } golang-gomega-1.0+git20160910.d59fa0a/gstruct/000077500000000000000000000000001276516347700203255ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/gstruct/elements.go000066400000000000000000000077741276516347700225070ustar00rootroot00000000000000package gstruct import ( "errors" "fmt" "reflect" "runtime/debug" "github.com/onsi/gomega/format" errorsutil "github.com/onsi/gomega/gstruct/errors" "github.com/onsi/gomega/types" ) //MatchAllElements succeeds if every element of a slice matches the element matcher it maps to //through the id function, and every element matcher is matched. // Expect([]string{"a", "b"}).To(MatchAllElements(idFn, matchers.Elements{ // "a": BeEqual("a"), // "b": BeEqual("b"), // }) func MatchAllElements(identifier Identifier, elements Elements) types.GomegaMatcher { return &ElementsMatcher{ Identifier: identifier, Elements: elements, } } //MatchElements succeeds if each element of a slice matches the element matcher it maps to //through the id function. It can ignore extra elements and/or missing elements. // Expect([]string{"a", "c"}).To(MatchElements(idFn, IgnoreMissing|IgnoreExtra, matchers.Elements{ // "a": BeEqual("a") // "b": BeEqual("b"), // }) func MatchElements(identifier Identifier, options Options, elements Elements) types.GomegaMatcher { return &ElementsMatcher{ Identifier: identifier, Elements: elements, IgnoreExtras: options&IgnoreExtras != 0, IgnoreMissing: options&IgnoreMissing != 0, } } // ElementsMatcher is a NestingMatcher that applies custom matchers to each element of a slice mapped // by the Identifier function. // TODO: Extend this to work with arrays & maps (map the key) as well. type ElementsMatcher struct { // Matchers for each element. Elements Elements // Function mapping an element to the string key identifying its matcher. Identifier Identifier // Whether to ignore extra elements or consider it an error. IgnoreExtras bool // Whether to ignore missing elements or consider it an error. IgnoreMissing bool // State. failures []error } // Element ID to matcher. type Elements map[string]types.GomegaMatcher // Function for identifying (mapping) elements. type Identifier func(element interface{}) string func (m *ElementsMatcher) Match(actual interface{}) (success bool, err error) { if reflect.TypeOf(actual).Kind() != reflect.Slice { return false, fmt.Errorf("%v is type %T, expected slice", actual, actual) } m.failures = m.matchElements(actual) if len(m.failures) > 0 { return false, nil } return true, nil } func (m *ElementsMatcher) matchElements(actual interface{}) (errs []error) { // Provide more useful error messages in the case of a panic. defer func() { if err := recover(); err != nil { errs = append(errs, fmt.Errorf("panic checking %+v: %v\n%s", actual, err, debug.Stack())) } }() val := reflect.ValueOf(actual) elements := map[string]bool{} for i := 0; i < val.Len(); i++ { element := val.Index(i).Interface() id := m.Identifier(element) // TODO: Add options to ignore & match duplicates. if elements[id] { errs = append(errs, fmt.Errorf("found duplicate element ID %s", id)) continue } elements[id] = true matcher, expected := m.Elements[id] if !expected { if !m.IgnoreExtras { errs = append(errs, fmt.Errorf("unexpected element %s", id)) } continue } match, err := matcher.Match(element) if match { continue } if err == nil { if nesting, ok := matcher.(errorsutil.NestingMatcher); ok { err = errorsutil.AggregateError(nesting.Failures()) } else { err = errors.New(matcher.FailureMessage(element)) } } errs = append(errs, errorsutil.Nest(fmt.Sprintf("[%s]", id), err)) } for id := range m.Elements { if !elements[id] && !m.IgnoreMissing { errs = append(errs, fmt.Errorf("missing expected element %s", id)) } } return errs } func (m *ElementsMatcher) FailureMessage(actual interface{}) (message string) { failure := errorsutil.AggregateError(m.failures) return format.Message(actual, fmt.Sprintf("to match elements: %v", failure)) } func (m *ElementsMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, "not to match elements") } func (m *ElementsMatcher) Failures() []error { return m.failures } golang-gomega-1.0+git20160910.d59fa0a/gstruct/elements_test.go000066400000000000000000000054751276516347700235420ustar00rootroot00000000000000package gstruct_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/gstruct" ) var _ = Describe("Slice", func() { allElements := []string{"a", "b"} missingElements := []string{"a"} extraElements := []string{"a", "b", "c"} duplicateElements := []string{"a", "a", "b"} empty := []string{} var nils []string It("should strictly match all elements", func() { m := MatchAllElements(id, Elements{ "b": Equal("b"), "a": Equal("a"), }) Ω(allElements).Should(m, "should match all elements") Ω(missingElements).ShouldNot(m, "should fail with missing elements") Ω(extraElements).ShouldNot(m, "should fail with extra elements") Ω(duplicateElements).ShouldNot(m, "should fail with duplicate elements") Ω(nils).ShouldNot(m, "should fail with an uninitialized slice") m = MatchAllElements(id, Elements{ "a": Equal("a"), "b": Equal("fail"), }) Ω(allElements).ShouldNot(m, "should run nested matchers") m = MatchAllElements(id, Elements{}) Ω(empty).Should(m, "should handle empty slices") Ω(allElements).ShouldNot(m, "should handle only empty slices") Ω(nils).Should(m, "should handle nil slices") }) It("should ignore extra elements", func() { m := MatchElements(id, IgnoreExtras, Elements{ "b": Equal("b"), "a": Equal("a"), }) Ω(allElements).Should(m, "should match all elements") Ω(missingElements).ShouldNot(m, "should fail with missing elements") Ω(extraElements).Should(m, "should ignore extra elements") Ω(duplicateElements).ShouldNot(m, "should fail with duplicate elements") Ω(nils).ShouldNot(m, "should fail with an uninitialized slice") }) It("should ignore missing elements", func() { m := MatchElements(id, IgnoreMissing, Elements{ "a": Equal("a"), "b": Equal("b"), }) Ω(allElements).Should(m, "should match all elements") Ω(missingElements).Should(m, "should ignore missing elements") Ω(extraElements).ShouldNot(m, "should fail with extra elements") Ω(duplicateElements).ShouldNot(m, "should fail with duplicate elements") Ω(nils).Should(m, "should ignore an uninitialized slice") }) It("should ignore missing and extra elements", func() { m := MatchElements(id, IgnoreMissing|IgnoreExtras, Elements{ "a": Equal("a"), "b": Equal("b"), }) Ω(allElements).Should(m, "should match all elements") Ω(missingElements).Should(m, "should ignore missing elements") Ω(extraElements).Should(m, "should ignore extra elements") Ω(duplicateElements).ShouldNot(m, "should fail with duplicate elements") Ω(nils).Should(m, "should ignore an uninitialized slice") m = MatchElements(id, IgnoreExtras|IgnoreMissing, Elements{ "a": Equal("a"), "b": Equal("fail"), }) Ω(allElements).ShouldNot(m, "should run nested matchers") }) }) func id(element interface{}) string { return element.(string) } golang-gomega-1.0+git20160910.d59fa0a/gstruct/errors/000077500000000000000000000000001276516347700216415ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/gstruct/errors/nested_types.go000066400000000000000000000030721276516347700247000ustar00rootroot00000000000000package errors import ( "fmt" "strings" "github.com/onsi/gomega/types" ) // A stateful matcher that nests other matchers within it and preserves the error types of the // nested matcher failures. type NestingMatcher interface { types.GomegaMatcher // Returns the failures of nested matchers. Failures() []error } // An error type for labeling errors on deeply nested matchers. type NestedError struct { Path string Err error } func (e *NestedError) Error() string { // Indent Errors. indented := strings.Replace(e.Err.Error(), "\n", "\n\t", -1) return fmt.Sprintf("%s:\n\t%v", e.Path, indented) } // Create a NestedError with the given path. // If err is a NestedError, prepend the path to it. // If err is an AggregateError, recursively Nest each error. func Nest(path string, err error) error { if ag, ok := err.(AggregateError); ok { var errs AggregateError for _, e := range ag { errs = append(errs, Nest(path, e)) } return errs } if ne, ok := err.(*NestedError); ok { return &NestedError{ Path: path + ne.Path, Err: ne.Err, } } return &NestedError{ Path: path, Err: err, } } // An error type for treating multiple errors as a single error. type AggregateError []error // Error is part of the error interface. func (err AggregateError) Error() string { if len(err) == 0 { // This should never happen, really. return "" } if len(err) == 1 { return err[0].Error() } result := fmt.Sprintf("[%s", err[0].Error()) for i := 1; i < len(err); i++ { result += fmt.Sprintf(", %s", err[i].Error()) } result += "]" return result } golang-gomega-1.0+git20160910.d59fa0a/gstruct/fields.go000066400000000000000000000072441276516347700221310ustar00rootroot00000000000000package gstruct import ( "errors" "fmt" "reflect" "runtime/debug" "strings" "github.com/onsi/gomega/format" errorsutil "github.com/onsi/gomega/gstruct/errors" "github.com/onsi/gomega/types" ) //MatchAllFields succeeds if every field of a struct matches the field matcher associated with //it, and every element matcher is matched. // Expect([]string{"a", "b"}).To(MatchAllFields(idFn, gstruct.Fields{ // "a": BeEqual("a"), // "b": BeEqual("b"), // }) func MatchAllFields(fields Fields) types.GomegaMatcher { return &FieldsMatcher{ Fields: fields, } } //MatchFields succeeds if each element of a struct matches the field matcher associated with //it. It can ignore extra fields and/or missing fields. // Expect([]string{"a", "c"}).To(MatchFields(idFn, IgnoreMissing|IgnoreExtra, gstruct.Fields{ // "a": BeEqual("a") // "b": BeEqual("b"), // }) func MatchFields(options Options, fields Fields) types.GomegaMatcher { return &FieldsMatcher{ Fields: fields, IgnoreExtras: options&IgnoreExtras != 0, IgnoreMissing: options&IgnoreMissing != 0, } } type FieldsMatcher struct { // Matchers for each field. Fields Fields // Whether to ignore extra elements or consider it an error. IgnoreExtras bool // Whether to ignore missing elements or consider it an error. IgnoreMissing bool // State. failures []error } // Field name to matcher. type Fields map[string]types.GomegaMatcher func (m *FieldsMatcher) Match(actual interface{}) (success bool, err error) { if reflect.TypeOf(actual).Kind() != reflect.Struct { return false, fmt.Errorf("%v is type %T, expected struct", actual, actual) } m.failures = m.matchFields(actual) if len(m.failures) > 0 { return false, nil } return true, nil } func (m *FieldsMatcher) matchFields(actual interface{}) (errs []error) { val := reflect.ValueOf(actual) typ := val.Type() fields := map[string]bool{} for i := 0; i < val.NumField(); i++ { fieldName := typ.Field(i).Name fields[fieldName] = true err := func() (err error) { // This test relies heavily on reflect, which tends to panic. // Recover here to provide more useful error messages in that case. defer func() { if r := recover(); r != nil { err = fmt.Errorf("panic checking %+v: %v\n%s", actual, r, debug.Stack()) } }() matcher, expected := m.Fields[fieldName] if !expected { if !m.IgnoreExtras { return fmt.Errorf("unexpected field %s: %+v", fieldName, actual) } return nil } var field interface{} if val.Field(i).IsValid() { field = val.Field(i).Interface() } else { field = reflect.Zero(typ.Field(i).Type) } match, err := matcher.Match(field) if err != nil { return err } else if !match { if nesting, ok := matcher.(errorsutil.NestingMatcher); ok { return errorsutil.AggregateError(nesting.Failures()) } return errors.New(matcher.FailureMessage(field)) } return nil }() if err != nil { errs = append(errs, errorsutil.Nest("."+fieldName, err)) } } for field := range m.Fields { if !fields[field] && !m.IgnoreMissing { errs = append(errs, fmt.Errorf("missing expected field %s", field)) } } return errs } func (m *FieldsMatcher) FailureMessage(actual interface{}) (message string) { failures := make([]string, len(m.failures)) for i := range m.failures { failures[i] = m.failures[i].Error() } return format.Message(reflect.TypeOf(actual).Name(), fmt.Sprintf("to match fields: {\n%v\n}\n", strings.Join(failures, "\n"))) } func (m *FieldsMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, "not to match fields") } func (m *FieldsMatcher) Failures() []error { return m.failures } golang-gomega-1.0+git20160910.d59fa0a/gstruct/fields_test.go000066400000000000000000000045151276516347700231660ustar00rootroot00000000000000package gstruct_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/gstruct" ) var _ = Describe("Struct", func() { allFields := struct{ A, B string }{"a", "b"} missingFields := struct{ A string }{"a"} extraFields := struct{ A, B, C string }{"a", "b", "c"} emptyFields := struct{ A, B string }{} It("should strictly match all fields", func() { m := MatchAllFields(Fields{ "B": Equal("b"), "A": Equal("a"), }) Ω(allFields).Should(m, "should match all fields") Ω(missingFields).ShouldNot(m, "should fail with missing fields") Ω(extraFields).ShouldNot(m, "should fail with extra fields") Ω(emptyFields).ShouldNot(m, "should fail with empty fields") m = MatchAllFields(Fields{ "A": Equal("a"), "B": Equal("fail"), }) Ω(allFields).ShouldNot(m, "should run nested matchers") }) It("should handle empty structs", func() { m := MatchAllFields(Fields{}) Ω(struct{}{}).Should(m, "should handle empty structs") Ω(allFields).ShouldNot(m, "should fail with extra fields") }) It("should ignore missing fields", func() { m := MatchFields(IgnoreMissing, Fields{ "B": Equal("b"), "A": Equal("a"), }) Ω(allFields).Should(m, "should match all fields") Ω(missingFields).Should(m, "should ignore missing fields") Ω(extraFields).ShouldNot(m, "should fail with extra fields") Ω(emptyFields).ShouldNot(m, "should fail with empty fields") }) It("should ignore extra fields", func() { m := MatchFields(IgnoreExtras, Fields{ "B": Equal("b"), "A": Equal("a"), }) Ω(allFields).Should(m, "should match all fields") Ω(missingFields).ShouldNot(m, "should fail with missing fields") Ω(extraFields).Should(m, "should ignore extra fields") Ω(emptyFields).ShouldNot(m, "should fail with empty fields") }) It("should ignore missing and extra fields", func() { m := MatchFields(IgnoreMissing|IgnoreExtras, Fields{ "B": Equal("b"), "A": Equal("a"), }) Ω(allFields).Should(m, "should match all fields") Ω(missingFields).Should(m, "should ignore missing fields") Ω(extraFields).Should(m, "should ignore extra fields") Ω(emptyFields).ShouldNot(m, "should fail with empty fields") m = MatchFields(IgnoreMissing|IgnoreExtras, Fields{ "A": Equal("a"), "B": Equal("fail"), }) Ω(allFields).ShouldNot(m, "should run nested matchers") }) }) golang-gomega-1.0+git20160910.d59fa0a/gstruct/gstruct_tests_suite_test.go000066400000000000000000000002731276516347700260430ustar00rootroot00000000000000package gstruct_test import ( "testing" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) func Test(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Gstruct Suite") } golang-gomega-1.0+git20160910.d59fa0a/gstruct/ignore.go000066400000000000000000000017001276516347700221350ustar00rootroot00000000000000package gstruct import ( "github.com/onsi/gomega/types" ) //Ignore ignores the actual value and always succeeds. // Expect(nil).To(Ignore()) // Expect(true).To(Ignore()) func Ignore() types.GomegaMatcher { return &IgnoreMatcher{true} } //Reject ignores the actual value and always fails. It can be used in conjunction with IgnoreMissing //to catch problematic elements, or to verify tests are running. // Expect(nil).NotTo(Reject()) // Expect(true).NotTo(Reject()) func Reject() types.GomegaMatcher { return &IgnoreMatcher{false} } // A matcher that either always succeeds or always fails. type IgnoreMatcher struct { Succeed bool } func (m *IgnoreMatcher) Match(actual interface{}) (bool, error) { return m.Succeed, nil } func (m *IgnoreMatcher) FailureMessage(_ interface{}) (message string) { return "Unconditional failure" } func (m *IgnoreMatcher) NegatedFailureMessage(_ interface{}) (message string) { return "Unconditional success" } golang-gomega-1.0+git20160910.d59fa0a/gstruct/ignore_test.go000066400000000000000000000007501276516347700232000ustar00rootroot00000000000000package gstruct_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/gstruct" ) var _ = Describe("Ignore", func() { It("should always succeed", func() { Ω(nil).Should(Ignore()) Ω(struct{}{}).Should(Ignore()) Ω(0).Should(Ignore()) Ω(false).Should(Ignore()) }) It("should always fail", func() { Ω(nil).ShouldNot(Reject()) Ω(struct{}{}).ShouldNot(Reject()) Ω(1).ShouldNot(Reject()) Ω(true).ShouldNot(Reject()) }) }) golang-gomega-1.0+git20160910.d59fa0a/gstruct/pointer.go000066400000000000000000000024111276516347700223320ustar00rootroot00000000000000package gstruct import ( "fmt" "reflect" "github.com/onsi/gomega/format" "github.com/onsi/gomega/types" ) //PointTo applies the given matcher to the value pointed to by actual. It fails if the pointer is //nil. // actual := 5 // Expect(&actual).To(PointTo(Equal(5))) func PointTo(matcher types.GomegaMatcher) types.GomegaMatcher { return &PointerMatcher{ Matcher: matcher, } } type PointerMatcher struct { Matcher types.GomegaMatcher // Failure message. failure string } func (m *PointerMatcher) Match(actual interface{}) (bool, error) { val := reflect.ValueOf(actual) // return error if actual type is not a pointer if val.Kind() != reflect.Ptr { return false, fmt.Errorf("PointerMatcher expects a pointer but we have '%s'", val.Kind()) } if !val.IsValid() || val.IsNil() { m.failure = format.Message(actual, "not to be ") return false, nil } // Forward the value. elem := val.Elem().Interface() match, err := m.Matcher.Match(elem) if !match { m.failure = m.Matcher.FailureMessage(elem) } return match, err } func (m *PointerMatcher) FailureMessage(_ interface{}) (message string) { return m.failure } func (m *PointerMatcher) NegatedFailureMessage(actual interface{}) (message string) { return m.Matcher.NegatedFailureMessage(actual) } golang-gomega-1.0+git20160910.d59fa0a/gstruct/pointer_test.go000066400000000000000000000012571276516347700234000ustar00rootroot00000000000000package gstruct_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/gstruct" ) var _ = Describe("PointTo", func() { It("should fail when passed nil", func() { var p *struct{} Ω(p).Should(BeNil()) }) It("should succeed when passed non-nil pointer", func() { var s struct{} Ω(&s).Should(PointTo(Ignore())) }) It("should unwrap the pointee value", func() { i := 1 Ω(&i).Should(PointTo(Equal(1))) Ω(&i).ShouldNot(PointTo(Equal(2))) }) It("should work with nested pointers", func() { i := 1 ip := &i ipp := &ip Ω(ipp).Should(PointTo(PointTo(Equal(1)))) Ω(ipp).ShouldNot(PointTo(PointTo(Equal(2)))) }) }) golang-gomega-1.0+git20160910.d59fa0a/gstruct/types.go000066400000000000000000000005541276516347700220240ustar00rootroot00000000000000package gstruct //Options is the type for options passed to some matchers. type Options int const ( //IgnoreExtras tells the matcher to ignore extra elements or fields, rather than triggering a failure. IgnoreExtras Options = 1 << iota //IgnoreMissing tells the matcher to ignore missing elements or fields, rather than triggering a failure. IgnoreMissing ) golang-gomega-1.0+git20160910.d59fa0a/internal/000077500000000000000000000000001276516347700204465ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/internal/assertion/000077500000000000000000000000001276516347700224555ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/internal/assertion/assertion.go000066400000000000000000000061001276516347700250100ustar00rootroot00000000000000package assertion import ( "fmt" "reflect" "github.com/onsi/gomega/types" ) type Assertion struct { actualInput interface{} fail types.GomegaFailHandler offset int extra []interface{} } func New(actualInput interface{}, fail types.GomegaFailHandler, offset int, extra ...interface{}) *Assertion { return &Assertion{ actualInput: actualInput, fail: fail, offset: offset, extra: extra, } } func (assertion *Assertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...) } func (assertion *Assertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...) } func (assertion *Assertion) To(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...) } func (assertion *Assertion) ToNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...) } func (assertion *Assertion) NotTo(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...) } func (assertion *Assertion) buildDescription(optionalDescription ...interface{}) string { switch len(optionalDescription) { case 0: return "" default: return fmt.Sprintf(optionalDescription[0].(string), optionalDescription[1:]...) + "\n" } } func (assertion *Assertion) match(matcher types.GomegaMatcher, desiredMatch bool, optionalDescription ...interface{}) bool { matches, err := matcher.Match(assertion.actualInput) description := assertion.buildDescription(optionalDescription...) if err != nil { assertion.fail(description+err.Error(), 2+assertion.offset) return false } if matches != desiredMatch { var message string if desiredMatch { message = matcher.FailureMessage(assertion.actualInput) } else { message = matcher.NegatedFailureMessage(assertion.actualInput) } assertion.fail(description+message, 2+assertion.offset) return false } return true } func (assertion *Assertion) vetExtras(optionalDescription ...interface{}) bool { success, message := vetExtras(assertion.extra) if success { return true } description := assertion.buildDescription(optionalDescription...) assertion.fail(description+message, 2+assertion.offset) return false } func vetExtras(extras []interface{}) (bool, string) { for i, extra := range extras { if extra != nil { zeroValue := reflect.Zero(reflect.TypeOf(extra)).Interface() if !reflect.DeepEqual(zeroValue, extra) { message := fmt.Sprintf("Unexpected non-nil/non-zero extra argument at index %d:\n\t<%T>: %#v", i+1, extra, extra) return false, message } } } return true, "" } golang-gomega-1.0+git20160910.d59fa0a/internal/assertion/assertion_suite_test.go000066400000000000000000000003101276516347700272550ustar00rootroot00000000000000package assertion_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestAssertion(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Assertion Suite") } golang-gomega-1.0+git20160910.d59fa0a/internal/assertion/assertion_test.go000066400000000000000000000151261276516347700260570ustar00rootroot00000000000000package assertion_test import ( "errors" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/internal/assertion" "github.com/onsi/gomega/internal/fakematcher" ) var _ = Describe("Assertion", func() { var ( a *Assertion failureMessage string failureCallerSkip int matcher *fakematcher.FakeMatcher ) input := "The thing I'm testing" var fakeFailHandler = func(message string, callerSkip ...int) { failureMessage = message if len(callerSkip) == 1 { failureCallerSkip = callerSkip[0] } } BeforeEach(func() { matcher = &fakematcher.FakeMatcher{} failureMessage = "" failureCallerSkip = 0 a = New(input, fakeFailHandler, 1) }) Context("when called", func() { It("should pass the provided input value to the matcher", func() { a.Should(matcher) Ω(matcher.ReceivedActual).Should(Equal(input)) matcher.ReceivedActual = "" a.ShouldNot(matcher) Ω(matcher.ReceivedActual).Should(Equal(input)) matcher.ReceivedActual = "" a.To(matcher) Ω(matcher.ReceivedActual).Should(Equal(input)) matcher.ReceivedActual = "" a.ToNot(matcher) Ω(matcher.ReceivedActual).Should(Equal(input)) matcher.ReceivedActual = "" a.NotTo(matcher) Ω(matcher.ReceivedActual).Should(Equal(input)) }) }) Context("when the matcher succeeds", func() { BeforeEach(func() { matcher.MatchesToReturn = true matcher.ErrToReturn = nil }) Context("and a positive assertion is being made", func() { It("should not call the failure callback", func() { a.Should(matcher) Ω(failureMessage).Should(Equal("")) }) It("should be true", func() { Ω(a.Should(matcher)).Should(BeTrue()) }) }) Context("and a negative assertion is being made", func() { It("should call the failure callback", func() { a.ShouldNot(matcher) Ω(failureMessage).Should(Equal("negative: The thing I'm testing")) Ω(failureCallerSkip).Should(Equal(3)) }) It("should be false", func() { Ω(a.ShouldNot(matcher)).Should(BeFalse()) }) }) }) Context("when the matcher fails", func() { BeforeEach(func() { matcher.MatchesToReturn = false matcher.ErrToReturn = nil }) Context("and a positive assertion is being made", func() { It("should call the failure callback", func() { a.Should(matcher) Ω(failureMessage).Should(Equal("positive: The thing I'm testing")) Ω(failureCallerSkip).Should(Equal(3)) }) It("should be false", func() { Ω(a.Should(matcher)).Should(BeFalse()) }) }) Context("and a negative assertion is being made", func() { It("should not call the failure callback", func() { a.ShouldNot(matcher) Ω(failureMessage).Should(Equal("")) }) It("should be true", func() { Ω(a.ShouldNot(matcher)).Should(BeTrue()) }) }) }) Context("When reporting a failure", func() { BeforeEach(func() { matcher.MatchesToReturn = false matcher.ErrToReturn = nil }) Context("and there is an optional description", func() { It("should append the description to the failure message", func() { a.Should(matcher, "A description") Ω(failureMessage).Should(Equal("A description\npositive: The thing I'm testing")) Ω(failureCallerSkip).Should(Equal(3)) }) }) Context("and there are multiple arguments to the optional description", func() { It("should append the formatted description to the failure message", func() { a.Should(matcher, "A description of [%d]", 3) Ω(failureMessage).Should(Equal("A description of [3]\npositive: The thing I'm testing")) Ω(failureCallerSkip).Should(Equal(3)) }) }) }) Context("When the matcher returns an error", func() { BeforeEach(func() { matcher.ErrToReturn = errors.New("Kaboom!") }) Context("and a positive assertion is being made", func() { It("should call the failure callback", func() { matcher.MatchesToReturn = true a.Should(matcher) Ω(failureMessage).Should(Equal("Kaboom!")) Ω(failureCallerSkip).Should(Equal(3)) }) }) Context("and a negative assertion is being made", func() { It("should call the failure callback", func() { matcher.MatchesToReturn = false a.ShouldNot(matcher) Ω(failureMessage).Should(Equal("Kaboom!")) Ω(failureCallerSkip).Should(Equal(3)) }) }) It("should always be false", func() { Ω(a.Should(matcher)).Should(BeFalse()) Ω(a.ShouldNot(matcher)).Should(BeFalse()) }) }) Context("when there are extra parameters", func() { It("(a simple example)", func() { Ω(func() (string, int, error) { return "foo", 0, nil }()).Should(Equal("foo")) }) Context("when the parameters are all nil or zero", func() { It("should invoke the matcher", func() { matcher.MatchesToReturn = true matcher.ErrToReturn = nil var typedNil []string a = New(input, fakeFailHandler, 1, 0, nil, typedNil) result := a.Should(matcher) Ω(result).Should(BeTrue()) Ω(matcher.ReceivedActual).Should(Equal(input)) Ω(failureMessage).Should(BeZero()) }) }) Context("when any of the parameters are not nil or zero", func() { It("should call the failure callback", func() { matcher.MatchesToReturn = false matcher.ErrToReturn = nil a = New(input, fakeFailHandler, 1, errors.New("foo")) result := a.Should(matcher) Ω(result).Should(BeFalse()) Ω(matcher.ReceivedActual).Should(BeZero(), "The matcher doesn't even get called") Ω(failureMessage).Should(ContainSubstring("foo")) failureMessage = "" a = New(input, fakeFailHandler, 1, nil, 1) result = a.ShouldNot(matcher) Ω(result).Should(BeFalse()) Ω(failureMessage).Should(ContainSubstring("1")) failureMessage = "" a = New(input, fakeFailHandler, 1, nil, 0, []string{"foo"}) result = a.To(matcher) Ω(result).Should(BeFalse()) Ω(failureMessage).Should(ContainSubstring("foo")) failureMessage = "" a = New(input, fakeFailHandler, 1, nil, 0, []string{"foo"}) result = a.ToNot(matcher) Ω(result).Should(BeFalse()) Ω(failureMessage).Should(ContainSubstring("foo")) failureMessage = "" a = New(input, fakeFailHandler, 1, nil, 0, []string{"foo"}) result = a.NotTo(matcher) Ω(result).Should(BeFalse()) Ω(failureMessage).Should(ContainSubstring("foo")) Ω(failureCallerSkip).Should(Equal(3)) }) }) }) Context("Making an assertion without a registered fail handler", func() { It("should panic", func() { defer func() { e := recover() RegisterFailHandler(Fail) if e == nil { Fail("expected a panic to have occurred") } }() RegisterFailHandler(nil) Ω(true).Should(BeTrue()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/internal/asyncassertion/000077500000000000000000000000001276516347700235135ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/internal/asyncassertion/async_assertion.go000066400000000000000000000116011276516347700272450ustar00rootroot00000000000000package asyncassertion import ( "errors" "fmt" "reflect" "time" "github.com/onsi/gomega/internal/oraclematcher" "github.com/onsi/gomega/types" ) type AsyncAssertionType uint const ( AsyncAssertionTypeEventually AsyncAssertionType = iota AsyncAssertionTypeConsistently ) type AsyncAssertion struct { asyncType AsyncAssertionType actualInput interface{} timeoutInterval time.Duration pollingInterval time.Duration fail types.GomegaFailHandler offset int } func New(asyncType AsyncAssertionType, actualInput interface{}, fail types.GomegaFailHandler, timeoutInterval time.Duration, pollingInterval time.Duration, offset int) *AsyncAssertion { actualType := reflect.TypeOf(actualInput) if actualType.Kind() == reflect.Func { if actualType.NumIn() != 0 || actualType.NumOut() == 0 { panic("Expected a function with no arguments and one or more return values.") } } return &AsyncAssertion{ asyncType: asyncType, actualInput: actualInput, fail: fail, timeoutInterval: timeoutInterval, pollingInterval: pollingInterval, offset: offset, } } func (assertion *AsyncAssertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { return assertion.match(matcher, true, optionalDescription...) } func (assertion *AsyncAssertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { return assertion.match(matcher, false, optionalDescription...) } func (assertion *AsyncAssertion) buildDescription(optionalDescription ...interface{}) string { switch len(optionalDescription) { case 0: return "" default: return fmt.Sprintf(optionalDescription[0].(string), optionalDescription[1:]...) + "\n" } } func (assertion *AsyncAssertion) actualInputIsAFunction() bool { actualType := reflect.TypeOf(assertion.actualInput) return actualType.Kind() == reflect.Func && actualType.NumIn() == 0 && actualType.NumOut() > 0 } func (assertion *AsyncAssertion) pollActual() (interface{}, error) { if assertion.actualInputIsAFunction() { values := reflect.ValueOf(assertion.actualInput).Call([]reflect.Value{}) extras := []interface{}{} for _, value := range values[1:] { extras = append(extras, value.Interface()) } success, message := vetExtras(extras) if !success { return nil, errors.New(message) } return values[0].Interface(), nil } return assertion.actualInput, nil } func (assertion *AsyncAssertion) matcherMayChange(matcher types.GomegaMatcher, value interface{}) bool { if assertion.actualInputIsAFunction() { return true } return oraclematcher.MatchMayChangeInTheFuture(matcher, value) } func (assertion *AsyncAssertion) match(matcher types.GomegaMatcher, desiredMatch bool, optionalDescription ...interface{}) bool { timer := time.Now() timeout := time.After(assertion.timeoutInterval) description := assertion.buildDescription(optionalDescription...) var matches bool var err error mayChange := true value, err := assertion.pollActual() if err == nil { mayChange = assertion.matcherMayChange(matcher, value) matches, err = matcher.Match(value) } fail := func(preamble string) { errMsg := "" message := "" if err != nil { errMsg = "Error: " + err.Error() } else { if desiredMatch { message = matcher.FailureMessage(value) } else { message = matcher.NegatedFailureMessage(value) } } assertion.fail(fmt.Sprintf("%s after %.3fs.\n%s%s%s", preamble, time.Since(timer).Seconds(), description, message, errMsg), 3+assertion.offset) } if assertion.asyncType == AsyncAssertionTypeEventually { for { if err == nil && matches == desiredMatch { return true } if !mayChange { fail("No future change is possible. Bailing out early") return false } select { case <-time.After(assertion.pollingInterval): value, err = assertion.pollActual() if err == nil { mayChange = assertion.matcherMayChange(matcher, value) matches, err = matcher.Match(value) } case <-timeout: fail("Timed out") return false } } } else if assertion.asyncType == AsyncAssertionTypeConsistently { for { if !(err == nil && matches == desiredMatch) { fail("Failed") return false } if !mayChange { return true } select { case <-time.After(assertion.pollingInterval): value, err = assertion.pollActual() if err == nil { mayChange = assertion.matcherMayChange(matcher, value) matches, err = matcher.Match(value) } case <-timeout: return true } } } return false } func vetExtras(extras []interface{}) (bool, string) { for i, extra := range extras { if extra != nil { zeroValue := reflect.Zero(reflect.TypeOf(extra)).Interface() if !reflect.DeepEqual(zeroValue, extra) { message := fmt.Sprintf("Unexpected non-nil/non-zero extra argument at index %d:\n\t<%T>: %#v", i+1, extra, extra) return false, message } } } return true, "" } golang-gomega-1.0+git20160910.d59fa0a/internal/asyncassertion/async_assertion_suite_test.go000066400000000000000000000003271276516347700315200ustar00rootroot00000000000000package asyncassertion_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestAsyncAssertion(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "AsyncAssertion Suite") } golang-gomega-1.0+git20160910.d59fa0a/internal/asyncassertion/async_assertion_test.go000066400000000000000000000246721276516347700303200ustar00rootroot00000000000000package asyncassertion_test import ( "errors" "time" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/internal/asyncassertion" ) var _ = Describe("Async Assertion", func() { var ( failureMessage string callerSkip int ) var fakeFailHandler = func(message string, skip ...int) { failureMessage = message callerSkip = skip[0] } BeforeEach(func() { failureMessage = "" callerSkip = 0 }) Describe("Eventually", func() { Context("the positive case", func() { It("should poll the function and matcher", func() { counter := 0 a := New(AsyncAssertionTypeEventually, func() int { counter++ return counter }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.Should(BeNumerically("==", 5)) Ω(failureMessage).Should(BeZero()) }) It("should continue when the matcher errors", func() { counter := 0 a := New(AsyncAssertionTypeEventually, func() interface{} { counter++ if counter == 5 { return "not-a-number" //this should cause the matcher to error } return counter }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.Should(BeNumerically("==", 5), "My description %d", 2) Ω(failureMessage).Should(ContainSubstring("Timed out after")) Ω(failureMessage).Should(ContainSubstring("My description 2")) Ω(callerSkip).Should(Equal(4)) }) It("should be able to timeout", func() { counter := 0 a := New(AsyncAssertionTypeEventually, func() int { counter++ return counter }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.Should(BeNumerically(">", 100), "My description %d", 2) Ω(counter).Should(BeNumerically(">", 8)) Ω(counter).Should(BeNumerically("<=", 10)) Ω(failureMessage).Should(ContainSubstring("Timed out after")) Ω(failureMessage).Should(MatchRegexp(`\: \d`), "Should pass the correct value to the matcher message formatter.") Ω(failureMessage).Should(ContainSubstring("My description 2")) Ω(callerSkip).Should(Equal(4)) }) }) Context("the negative case", func() { It("should poll the function and matcher", func() { counter := 0 a := New(AsyncAssertionTypeEventually, func() int { counter += 1 return counter }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.ShouldNot(BeNumerically("<", 3)) Ω(counter).Should(Equal(3)) Ω(failureMessage).Should(BeZero()) }) It("should timeout when the matcher errors", func() { a := New(AsyncAssertionTypeEventually, func() interface{} { return 0 //this should cause the matcher to error }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.ShouldNot(HaveLen(0), "My description %d", 2) Ω(failureMessage).Should(ContainSubstring("Timed out after")) Ω(failureMessage).Should(ContainSubstring("Error:")) Ω(failureMessage).Should(ContainSubstring("My description 2")) Ω(callerSkip).Should(Equal(4)) }) It("should be able to timeout", func() { a := New(AsyncAssertionTypeEventually, func() int { return 0 }, fakeFailHandler, time.Duration(0.1*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.ShouldNot(Equal(0), "My description %d", 2) Ω(failureMessage).Should(ContainSubstring("Timed out after")) Ω(failureMessage).Should(ContainSubstring(": 0"), "Should pass the correct value to the matcher message formatter.") Ω(failureMessage).Should(ContainSubstring("My description 2")) Ω(callerSkip).Should(Equal(4)) }) }) Context("with a function that returns multiple values", func() { It("should eventually succeed if the additional arguments are nil", func() { i := 0 Eventually(func() (int, error) { i++ return i, nil }).Should(Equal(10)) }) It("should eventually timeout if the additional arguments are not nil", func() { i := 0 a := New(AsyncAssertionTypeEventually, func() (int, error) { i++ return i, errors.New("bam") }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.Should(Equal(2)) Ω(failureMessage).Should(ContainSubstring("Timed out after")) Ω(failureMessage).Should(ContainSubstring("Error:")) Ω(failureMessage).Should(ContainSubstring("bam")) Ω(callerSkip).Should(Equal(4)) }) }) Context("Making an assertion without a registered fail handler", func() { It("should panic", func() { defer func() { e := recover() RegisterFailHandler(Fail) if e == nil { Fail("expected a panic to have occurred") } }() RegisterFailHandler(nil) c := make(chan bool, 1) c <- true Eventually(c).Should(Receive()) }) }) }) Describe("Consistently", func() { Describe("The positive case", func() { Context("when the matcher consistently passes for the duration", func() { It("should pass", func() { calls := 0 a := New(AsyncAssertionTypeConsistently, func() string { calls++ return "foo" }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.Should(Equal("foo")) Ω(calls).Should(BeNumerically(">", 8)) Ω(calls).Should(BeNumerically("<=", 10)) Ω(failureMessage).Should(BeZero()) }) }) Context("when the matcher fails at some point", func() { It("should fail", func() { calls := 0 a := New(AsyncAssertionTypeConsistently, func() interface{} { calls++ if calls > 5 { return "bar" } return "foo" }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.Should(Equal("foo")) Ω(failureMessage).Should(ContainSubstring("to equal")) Ω(callerSkip).Should(Equal(4)) }) }) Context("when the matcher errors at some point", func() { It("should fail", func() { calls := 0 a := New(AsyncAssertionTypeConsistently, func() interface{} { calls++ if calls > 5 { return 3 } return []int{1, 2, 3} }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.Should(HaveLen(3)) Ω(failureMessage).Should(ContainSubstring("HaveLen matcher expects")) Ω(callerSkip).Should(Equal(4)) }) }) }) Describe("The negative case", func() { Context("when the matcher consistently passes for the duration", func() { It("should pass", func() { c := make(chan bool) a := New(AsyncAssertionTypeConsistently, c, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.ShouldNot(Receive()) Ω(failureMessage).Should(BeZero()) }) }) Context("when the matcher fails at some point", func() { It("should fail", func() { c := make(chan bool) go func() { time.Sleep(time.Duration(100 * time.Millisecond)) c <- true }() a := New(AsyncAssertionTypeConsistently, c, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.ShouldNot(Receive()) Ω(failureMessage).Should(ContainSubstring("not to receive anything")) }) }) Context("when the matcher errors at some point", func() { It("should fail", func() { calls := 0 a := New(AsyncAssertionTypeConsistently, func() interface{} { calls++ return calls }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.ShouldNot(BeNumerically(">", 5)) Ω(failureMessage).Should(ContainSubstring("not to be >")) Ω(callerSkip).Should(Equal(4)) }) }) }) Context("with a function that returns multiple values", func() { It("should consistently succeed if the additional arguments are nil", func() { i := 2 Consistently(func() (int, error) { i++ return i, nil }).Should(BeNumerically(">=", 2)) }) It("should eventually timeout if the additional arguments are not nil", func() { i := 2 a := New(AsyncAssertionTypeEventually, func() (int, error) { i++ return i, errors.New("bam") }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) a.Should(BeNumerically(">=", 2)) Ω(failureMessage).Should(ContainSubstring("Error:")) Ω(failureMessage).Should(ContainSubstring("bam")) Ω(callerSkip).Should(Equal(4)) }) }) Context("Making an assertion without a registered fail handler", func() { It("should panic", func() { defer func() { e := recover() RegisterFailHandler(Fail) if e == nil { Fail("expected a panic to have occurred") } }() RegisterFailHandler(nil) c := make(chan bool) Consistently(c).ShouldNot(Receive()) }) }) }) Context("when passed a function with the wrong # or arguments & returns", func() { It("should panic", func() { Ω(func() { New(AsyncAssertionTypeEventually, func() {}, fakeFailHandler, 0, 0, 1) }).Should(Panic()) Ω(func() { New(AsyncAssertionTypeEventually, func(a string) int { return 0 }, fakeFailHandler, 0, 0, 1) }).Should(Panic()) Ω(func() { New(AsyncAssertionTypeEventually, func() int { return 0 }, fakeFailHandler, 0, 0, 1) }).ShouldNot(Panic()) Ω(func() { New(AsyncAssertionTypeEventually, func() (int, error) { return 0, nil }, fakeFailHandler, 0, 0, 1) }).ShouldNot(Panic()) }) }) Describe("bailing early", func() { Context("when actual is a value", func() { It("Eventually should bail out and fail early if the matcher says to", func() { c := make(chan bool) close(c) t := time.Now() failures := InterceptGomegaFailures(func() { Eventually(c, 0.1).Should(Receive()) }) Ω(time.Since(t)).Should(BeNumerically("<", 90*time.Millisecond)) Ω(failures).Should(HaveLen(1)) }) }) Context("when actual is a function", func() { It("should never bail early", func() { c := make(chan bool) close(c) t := time.Now() failures := InterceptGomegaFailures(func() { Eventually(func() chan bool { return c }, 0.1).Should(Receive()) }) Ω(time.Since(t)).Should(BeNumerically(">=", 90*time.Millisecond)) Ω(failures).Should(HaveLen(1)) }) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/internal/fakematcher/000077500000000000000000000000001276516347700227205ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/internal/fakematcher/fake_matcher.go000066400000000000000000000010361276516347700256600ustar00rootroot00000000000000package fakematcher import "fmt" type FakeMatcher struct { ReceivedActual interface{} MatchesToReturn bool ErrToReturn error } func (matcher *FakeMatcher) Match(actual interface{}) (bool, error) { matcher.ReceivedActual = actual return matcher.MatchesToReturn, matcher.ErrToReturn } func (matcher *FakeMatcher) FailureMessage(actual interface{}) string { return fmt.Sprintf("positive: %v", actual) } func (matcher *FakeMatcher) NegatedFailureMessage(actual interface{}) string { return fmt.Sprintf("negative: %v", actual) } golang-gomega-1.0+git20160910.d59fa0a/internal/oraclematcher/000077500000000000000000000000001276516347700232575ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/internal/oraclematcher/oracle_matcher.go000066400000000000000000000014541276516347700265620ustar00rootroot00000000000000package oraclematcher import "github.com/onsi/gomega/types" /* GomegaMatchers that also match the OracleMatcher interface can convey information about whether or not their result will change upon future attempts. This allows `Eventually` and `Consistently` to short circuit if success becomes impossible. For example, a process' exit code can never change. So, gexec's Exit matcher returns `true` for `MatchMayChangeInTheFuture` until the process exits, at which point it returns `false` forevermore. */ type OracleMatcher interface { MatchMayChangeInTheFuture(actual interface{}) bool } func MatchMayChangeInTheFuture(matcher types.GomegaMatcher, value interface{}) bool { oracleMatcher, ok := matcher.(OracleMatcher) if !ok { return true } return oracleMatcher.MatchMayChangeInTheFuture(value) } golang-gomega-1.0+git20160910.d59fa0a/internal/testingtsupport/000077500000000000000000000000001276516347700237445ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/internal/testingtsupport/testing_t_support.go000066400000000000000000000017241276516347700300730ustar00rootroot00000000000000package testingtsupport import ( "regexp" "runtime/debug" "strings" "github.com/onsi/gomega/types" ) type gomegaTestingT interface { Errorf(format string, args ...interface{}) } func BuildTestingTGomegaFailHandler(t gomegaTestingT) types.GomegaFailHandler { return func(message string, callerSkip ...int) { skip := 1 if len(callerSkip) > 0 { skip = callerSkip[0] } stackTrace := pruneStack(string(debug.Stack()), skip) t.Errorf("\n%s\n%s", stackTrace, message) } } func pruneStack(fullStackTrace string, skip int) string { stack := strings.Split(fullStackTrace, "\n") if len(stack) > 2*(skip+1) { stack = stack[2*(skip+1):] } prunedStack := []string{} re := regexp.MustCompile(`\/ginkgo\/|\/pkg\/testing\/|\/pkg\/runtime\/`) for i := 0; i < len(stack)/2; i++ { if !re.Match([]byte(stack[i*2])) { prunedStack = append(prunedStack, stack[i*2]) prunedStack = append(prunedStack, stack[i*2+1]) } } return strings.Join(prunedStack, "\n") } golang-gomega-1.0+git20160910.d59fa0a/internal/testingtsupport/testing_t_support_test.go000066400000000000000000000002461276516347700311300ustar00rootroot00000000000000package testingtsupport_test import ( . "github.com/onsi/gomega" "testing" ) func TestTestingT(t *testing.T) { RegisterTestingT(t) Ω(true).Should(BeTrue()) } golang-gomega-1.0+git20160910.d59fa0a/matchers.go000066400000000000000000000415051276516347700207740ustar00rootroot00000000000000package gomega import ( "time" "github.com/onsi/gomega/matchers" "github.com/onsi/gomega/types" ) //Equal uses reflect.DeepEqual to compare actual with expected. Equal is strict about //types when performing comparisons. //It is an error for both actual and expected to be nil. Use BeNil() instead. func Equal(expected interface{}) types.GomegaMatcher { return &matchers.EqualMatcher{ Expected: expected, } } //BeEquivalentTo is more lax than Equal, allowing equality between different types. //This is done by converting actual to have the type of expected before //attempting equality with reflect.DeepEqual. //It is an error for actual and expected to be nil. Use BeNil() instead. func BeEquivalentTo(expected interface{}) types.GomegaMatcher { return &matchers.BeEquivalentToMatcher{ Expected: expected, } } //BeIdenticalTo uses the == operator to compare actual with expected. //BeIdenticalTo is strict about types when performing comparisons. //It is an error for both actual and expected to be nil. Use BeNil() instead. func BeIdenticalTo(expected interface{}) types.GomegaMatcher { return &matchers.BeIdenticalToMatcher{ Expected: expected, } } //BeNil succeeds if actual is nil func BeNil() types.GomegaMatcher { return &matchers.BeNilMatcher{} } //BeTrue succeeds if actual is true func BeTrue() types.GomegaMatcher { return &matchers.BeTrueMatcher{} } //BeFalse succeeds if actual is false func BeFalse() types.GomegaMatcher { return &matchers.BeFalseMatcher{} } //HaveOccurred succeeds if actual is a non-nil error //The typical Go error checking pattern looks like: // err := SomethingThatMightFail() // Ω(err).ShouldNot(HaveOccurred()) func HaveOccurred() types.GomegaMatcher { return &matchers.HaveOccurredMatcher{} } //Succeed passes if actual is a nil error //Succeed is intended to be used with functions that return a single error value. Instead of // err := SomethingThatMightFail() // Ω(err).ShouldNot(HaveOccurred()) // //You can write: // Ω(SomethingThatMightFail()).Should(Succeed()) // //It is a mistake to use Succeed with a function that has multiple return values. Gomega's Ω and Expect //functions automatically trigger failure if any return values after the first return value are non-zero/non-nil. //This means that Ω(MultiReturnFunc()).ShouldNot(Succeed()) can never pass. func Succeed() types.GomegaMatcher { return &matchers.SucceedMatcher{} } //MatchError succeeds if actual is a non-nil error that matches the passed in string/error. // //These are valid use-cases: // Ω(err).Should(MatchError("an error")) //asserts that err.Error() == "an error" // Ω(err).Should(MatchError(SomeError)) //asserts that err == SomeError (via reflect.DeepEqual) // //It is an error for err to be nil or an object that does not implement the Error interface func MatchError(expected interface{}) types.GomegaMatcher { return &matchers.MatchErrorMatcher{ Expected: expected, } } //BeClosed succeeds if actual is a closed channel. //It is an error to pass a non-channel to BeClosed, it is also an error to pass nil // //In order to check whether or not the channel is closed, Gomega must try to read from the channel //(even in the `ShouldNot(BeClosed())` case). You should keep this in mind if you wish to make subsequent assertions about //values coming down the channel. // //Also, if you are testing that a *buffered* channel is closed you must first read all values out of the channel before //asserting that it is closed (it is not possible to detect that a buffered-channel has been closed until all its buffered values are read). // //Finally, as a corollary: it is an error to check whether or not a send-only channel is closed. func BeClosed() types.GomegaMatcher { return &matchers.BeClosedMatcher{} } //Receive succeeds if there is a value to be received on actual. //Actual must be a channel (and cannot be a send-only channel) -- anything else is an error. // //Receive returns immediately and never blocks: // //- If there is nothing on the channel `c` then Ω(c).Should(Receive()) will fail and Ω(c).ShouldNot(Receive()) will pass. // //- If the channel `c` is closed then Ω(c).Should(Receive()) will fail and Ω(c).ShouldNot(Receive()) will pass. // //- If there is something on the channel `c` ready to be read, then Ω(c).Should(Receive()) will pass and Ω(c).ShouldNot(Receive()) will fail. // //If you have a go-routine running in the background that will write to channel `c` you can: // Eventually(c).Should(Receive()) // //This will timeout if nothing gets sent to `c` (you can modify the timeout interval as you normally do with `Eventually`) // //A similar use-case is to assert that no go-routine writes to a channel (for a period of time). You can do this with `Consistently`: // Consistently(c).ShouldNot(Receive()) // //You can pass `Receive` a matcher. If you do so, it will match the received object against the matcher. For example: // Ω(c).Should(Receive(Equal("foo"))) // //When given a matcher, `Receive` will always fail if there is nothing to be received on the channel. // //Passing Receive a matcher is especially useful when paired with Eventually: // // Eventually(c).Should(Receive(ContainSubstring("bar"))) // //will repeatedly attempt to pull values out of `c` until a value matching "bar" is received. // //Finally, if you want to have a reference to the value *sent* to the channel you can pass the `Receive` matcher a pointer to a variable of the appropriate type: // var myThing thing // Eventually(thingChan).Should(Receive(&myThing)) // Ω(myThing.Sprocket).Should(Equal("foo")) // Ω(myThing.IsValid()).Should(BeTrue()) func Receive(args ...interface{}) types.GomegaMatcher { var arg interface{} if len(args) > 0 { arg = args[0] } return &matchers.ReceiveMatcher{ Arg: arg, } } //BeSent succeeds if a value can be sent to actual. //Actual must be a channel (and cannot be a receive-only channel) that can sent the type of the value passed into BeSent -- anything else is an error. //In addition, actual must not be closed. // //BeSent never blocks: // //- If the channel `c` is not ready to receive then Ω(c).Should(BeSent("foo")) will fail immediately //- If the channel `c` is eventually ready to receive then Eventually(c).Should(BeSent("foo")) will succeed.. presuming the channel becomes ready to receive before Eventually's timeout //- If the channel `c` is closed then Ω(c).Should(BeSent("foo")) and Ω(c).ShouldNot(BeSent("foo")) will both fail immediately // //Of course, the value is actually sent to the channel. The point of `BeSent` is less to make an assertion about the availability of the channel (which is typically an implementation detail that your test should not be concerned with). //Rather, the point of `BeSent` is to make it possible to easily and expressively write tests that can timeout on blocked channel sends. func BeSent(arg interface{}) types.GomegaMatcher { return &matchers.BeSentMatcher{ Arg: arg, } } //MatchRegexp succeeds if actual is a string or stringer that matches the //passed-in regexp. Optional arguments can be provided to construct a regexp //via fmt.Sprintf(). func MatchRegexp(regexp string, args ...interface{}) types.GomegaMatcher { return &matchers.MatchRegexpMatcher{ Regexp: regexp, Args: args, } } //ContainSubstring succeeds if actual is a string or stringer that contains the //passed-in regexp. Optional arguments can be provided to construct the substring //via fmt.Sprintf(). func ContainSubstring(substr string, args ...interface{}) types.GomegaMatcher { return &matchers.ContainSubstringMatcher{ Substr: substr, Args: args, } } //HavePrefix succeeds if actual is a string or stringer that contains the //passed-in string as a prefix. Optional arguments can be provided to construct //via fmt.Sprintf(). func HavePrefix(prefix string, args ...interface{}) types.GomegaMatcher { return &matchers.HavePrefixMatcher{ Prefix: prefix, Args: args, } } //HaveSuffix succeeds if actual is a string or stringer that contains the //passed-in string as a suffix. Optional arguments can be provided to construct //via fmt.Sprintf(). func HaveSuffix(suffix string, args ...interface{}) types.GomegaMatcher { return &matchers.HaveSuffixMatcher{ Suffix: suffix, Args: args, } } //MatchJSON succeeds if actual is a string or stringer of JSON that matches //the expected JSON. The JSONs are decoded and the resulting objects are compared via //reflect.DeepEqual so things like key-ordering and whitespace shouldn't matter. func MatchJSON(json interface{}) types.GomegaMatcher { return &matchers.MatchJSONMatcher{ JSONToMatch: json, } } //MatchYAML succeeds if actual is a string or stringer of YAML that matches //the expected YAML. The YAML's are decoded and the resulting objects are compared via //reflect.DeepEqual so things like key-ordering and whitespace shouldn't matter. func MatchYAML(yaml interface{}) types.GomegaMatcher { return &matchers.MatchYAMLMatcher{ YAMLToMatch: yaml, } } //BeEmpty succeeds if actual is empty. Actual must be of type string, array, map, chan, or slice. func BeEmpty() types.GomegaMatcher { return &matchers.BeEmptyMatcher{} } //HaveLen succeeds if actual has the passed-in length. Actual must be of type string, array, map, chan, or slice. func HaveLen(count int) types.GomegaMatcher { return &matchers.HaveLenMatcher{ Count: count, } } //HaveCap succeeds if actual has the passed-in capacity. Actual must be of type array, chan, or slice. func HaveCap(count int) types.GomegaMatcher { return &matchers.HaveCapMatcher{ Count: count, } } //BeZero succeeds if actual is the zero value for its type or if actual is nil. func BeZero() types.GomegaMatcher { return &matchers.BeZeroMatcher{} } //ContainElement succeeds if actual contains the passed in element. //By default ContainElement() uses Equal() to perform the match, however a //matcher can be passed in instead: // Ω([]string{"Foo", "FooBar"}).Should(ContainElement(ContainSubstring("Bar"))) // //Actual must be an array, slice or map. //For maps, ContainElement searches through the map's values. func ContainElement(element interface{}) types.GomegaMatcher { return &matchers.ContainElementMatcher{ Element: element, } } //ConsistOf succeeds if actual contains preciely the elements passed into the matcher. The ordering of the elements does not matter. //By default ConsistOf() uses Equal() to match the elements, however custom matchers can be passed in instead. Here are some examples: // // Ω([]string{"Foo", "FooBar"}).Should(ConsistOf("FooBar", "Foo")) // Ω([]string{"Foo", "FooBar"}).Should(ConsistOf(ContainSubstring("Bar"), "Foo")) // Ω([]string{"Foo", "FooBar"}).Should(ConsistOf(ContainSubstring("Foo"), ContainSubstring("Foo"))) // //Actual must be an array, slice or map. For maps, ConsistOf matches against the map's values. // //You typically pass variadic arguments to ConsistOf (as in the examples above). However, if you need to pass in a slice you can provided that it //is the only element passed in to ConsistOf: // // Ω([]string{"Foo", "FooBar"}).Should(ConsistOf([]string{"FooBar", "Foo"})) // //Note that Go's type system does not allow you to write this as ConsistOf([]string{"FooBar", "Foo"}...) as []string and []interface{} are different types - hence the need for this special rule. func ConsistOf(elements ...interface{}) types.GomegaMatcher { return &matchers.ConsistOfMatcher{ Elements: elements, } } //HaveKey succeeds if actual is a map with the passed in key. //By default HaveKey uses Equal() to perform the match, however a //matcher can be passed in instead: // Ω(map[string]string{"Foo": "Bar", "BazFoo": "Duck"}).Should(HaveKey(MatchRegexp(`.+Foo$`))) func HaveKey(key interface{}) types.GomegaMatcher { return &matchers.HaveKeyMatcher{ Key: key, } } //HaveKeyWithValue succeeds if actual is a map with the passed in key and value. //By default HaveKeyWithValue uses Equal() to perform the match, however a //matcher can be passed in instead: // Ω(map[string]string{"Foo": "Bar", "BazFoo": "Duck"}).Should(HaveKeyWithValue("Foo", "Bar")) // Ω(map[string]string{"Foo": "Bar", "BazFoo": "Duck"}).Should(HaveKeyWithValue(MatchRegexp(`.+Foo$`), "Bar")) func HaveKeyWithValue(key interface{}, value interface{}) types.GomegaMatcher { return &matchers.HaveKeyWithValueMatcher{ Key: key, Value: value, } } //BeNumerically performs numerical assertions in a type-agnostic way. //Actual and expected should be numbers, though the specific type of //number is irrelevant (floa32, float64, uint8, etc...). // //There are six, self-explanatory, supported comparators: // Ω(1.0).Should(BeNumerically("==", 1)) // Ω(1.0).Should(BeNumerically("~", 0.999, 0.01)) // Ω(1.0).Should(BeNumerically(">", 0.9)) // Ω(1.0).Should(BeNumerically(">=", 1.0)) // Ω(1.0).Should(BeNumerically("<", 3)) // Ω(1.0).Should(BeNumerically("<=", 1.0)) func BeNumerically(comparator string, compareTo ...interface{}) types.GomegaMatcher { return &matchers.BeNumericallyMatcher{ Comparator: comparator, CompareTo: compareTo, } } //BeTemporally compares time.Time's like BeNumerically //Actual and expected must be time.Time. The comparators are the same as for BeNumerically // Ω(time.Now()).Should(BeTemporally(">", time.Time{})) // Ω(time.Now()).Should(BeTemporally("~", time.Now(), time.Second)) func BeTemporally(comparator string, compareTo time.Time, threshold ...time.Duration) types.GomegaMatcher { return &matchers.BeTemporallyMatcher{ Comparator: comparator, CompareTo: compareTo, Threshold: threshold, } } //BeAssignableToTypeOf succeeds if actual is assignable to the type of expected. //It will return an error when one of the values is nil. // Ω(0).Should(BeAssignableToTypeOf(0)) // Same values // Ω(5).Should(BeAssignableToTypeOf(-1)) // different values same type // Ω("foo").Should(BeAssignableToTypeOf("bar")) // different values same type // Ω(struct{ Foo string }{}).Should(BeAssignableToTypeOf(struct{ Foo string }{})) func BeAssignableToTypeOf(expected interface{}) types.GomegaMatcher { return &matchers.AssignableToTypeOfMatcher{ Expected: expected, } } //Panic succeeds if actual is a function that, when invoked, panics. //Actual must be a function that takes no arguments and returns no results. func Panic() types.GomegaMatcher { return &matchers.PanicMatcher{} } //BeAnExistingFile succeeds if a file exists. //Actual must be a string representing the abs path to the file being checked. func BeAnExistingFile() types.GomegaMatcher { return &matchers.BeAnExistingFileMatcher{} } //BeARegularFile succeeds iff a file exists and is a regular file. //Actual must be a string representing the abs path to the file being checked. func BeARegularFile() types.GomegaMatcher { return &matchers.BeARegularFileMatcher{} } //BeADirectory succeeds iff a file exists and is a directory. //Actual must be a string representing the abs path to the file being checked. func BeADirectory() types.GomegaMatcher { return &matchers.BeADirectoryMatcher{} } //And succeeds only if all of the given matchers succeed. //The matchers are tried in order, and will fail-fast if one doesn't succeed. // Expect("hi").To(And(HaveLen(2), Equal("hi")) // //And(), Or(), Not() and WithTransform() allow matchers to be composed into complex expressions. func And(ms ...types.GomegaMatcher) types.GomegaMatcher { return &matchers.AndMatcher{Matchers: ms} } //SatisfyAll is an alias for And(). // Ω("hi").Should(SatisfyAll(HaveLen(2), Equal("hi"))) func SatisfyAll(matchers ...types.GomegaMatcher) types.GomegaMatcher { return And(matchers...) } //Or succeeds if any of the given matchers succeed. //The matchers are tried in order and will return immediately upon the first successful match. // Expect("hi").To(Or(HaveLen(3), HaveLen(2)) // //And(), Or(), Not() and WithTransform() allow matchers to be composed into complex expressions. func Or(ms ...types.GomegaMatcher) types.GomegaMatcher { return &matchers.OrMatcher{Matchers: ms} } //SatisfyAny is an alias for Or(). // Expect("hi").SatisfyAny(Or(HaveLen(3), HaveLen(2)) func SatisfyAny(matchers ...types.GomegaMatcher) types.GomegaMatcher { return Or(matchers...) } //Not negates the given matcher; it succeeds if the given matcher fails. // Expect(1).To(Not(Equal(2)) // //And(), Or(), Not() and WithTransform() allow matchers to be composed into complex expressions. func Not(matcher types.GomegaMatcher) types.GomegaMatcher { return &matchers.NotMatcher{Matcher: matcher} } //WithTransform applies the `transform` to the actual value and matches it against `matcher`. //The given transform must be a function of one parameter that returns one value. // var plus1 = func(i int) int { return i + 1 } // Expect(1).To(WithTransform(plus1, Equal(2)) // //And(), Or(), Not() and WithTransform() allow matchers to be composed into complex expressions. func WithTransform(transform interface{}, matcher types.GomegaMatcher) types.GomegaMatcher { return matchers.NewWithTransformMatcher(transform, matcher) } golang-gomega-1.0+git20160910.d59fa0a/matchers/000077500000000000000000000000001276516347700204405ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/matchers/and.go000066400000000000000000000035671276516347700215440ustar00rootroot00000000000000package matchers import ( "fmt" "github.com/onsi/gomega/format" "github.com/onsi/gomega/internal/oraclematcher" "github.com/onsi/gomega/types" ) type AndMatcher struct { Matchers []types.GomegaMatcher // state firstFailedMatcher types.GomegaMatcher } func (m *AndMatcher) Match(actual interface{}) (success bool, err error) { m.firstFailedMatcher = nil for _, matcher := range m.Matchers { success, err := matcher.Match(actual) if !success || err != nil { m.firstFailedMatcher = matcher return false, err } } return true, nil } func (m *AndMatcher) FailureMessage(actual interface{}) (message string) { return m.firstFailedMatcher.FailureMessage(actual) } func (m *AndMatcher) NegatedFailureMessage(actual interface{}) (message string) { // not the most beautiful list of matchers, but not bad either... return format.Message(actual, fmt.Sprintf("To not satisfy all of these matchers: %s", m.Matchers)) } func (m *AndMatcher) MatchMayChangeInTheFuture(actual interface{}) bool { /* Example with 3 matchers: A, B, C Match evaluates them: T, F, => F So match is currently F, what should MatchMayChangeInTheFuture() return? Seems like it only depends on B, since currently B MUST change to allow the result to become T Match eval: T, T, T => T So match is currently T, what should MatchMayChangeInTheFuture() return? Seems to depend on ANY of them being able to change to F. */ if m.firstFailedMatcher == nil { // so all matchers succeeded.. Any one of them changing would change the result. for _, matcher := range m.Matchers { if oraclematcher.MatchMayChangeInTheFuture(matcher, actual) { return true } } return false // none of were going to change } else { // one of the matchers failed.. it must be able to change in order to affect the result return oraclematcher.MatchMayChangeInTheFuture(m.firstFailedMatcher, actual) } } golang-gomega-1.0+git20160910.d59fa0a/matchers/and_test.go000066400000000000000000000075601276516347700226000ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" "github.com/onsi/gomega/types" ) // sample data var ( // example input input = "hi" // some matchers that succeed against the input true1 = HaveLen(2) true2 = Equal("hi") true3 = MatchRegexp("hi") // some matchers that fail against the input. false1 = HaveLen(1) false2 = Equal("hip") false3 = MatchRegexp("hope") ) // verifyFailureMessage expects the matcher to fail with the given input, and verifies the failure message. func verifyFailureMessage(m types.GomegaMatcher, input string, expectedFailureMsgFragment string) { Expect(m.Match(input)).To(BeFalse()) Expect(m.FailureMessage(input)).To(Equal( "Expected\n : " + input + "\n" + expectedFailureMsgFragment)) } var _ = Describe("AndMatcher", func() { It("works with positive cases", func() { Expect(input).To(And()) Expect(input).To(And(true1)) Expect(input).To(And(true1, true2)) Expect(input).To(And(true1, true2, true3)) // use alias Expect(input).To(SatisfyAll(true1, true2, true3)) }) It("works with negative cases", func() { Expect(input).ToNot(And(false1, false2)) Expect(input).ToNot(And(true1, true2, false3)) Expect(input).ToNot(And(true1, false2, false3)) Expect(input).ToNot(And(false1, true1, true2)) }) Context("failure messages", func() { Context("when match fails", func() { It("gives a descriptive message", func() { verifyFailureMessage(And(false1, true1), input, "to have length 1") verifyFailureMessage(And(true1, false2), input, "to equal\n : hip") verifyFailureMessage(And(true1, true2, false3), input, "to match regular expression\n : hope") }) }) Context("when match succeeds, but expected it to fail", func() { It("gives a descriptive message", func() { verifyFailureMessage(Not(And(true1, true2)), input, `To not satisfy all of these matchers: [%!s(*matchers.HaveLenMatcher=&{2}) %!s(*matchers.EqualMatcher=&{hi})]`) }) }) }) Context("MatchMayChangeInTheFuture", func() { Context("Match returned false", func() { Context("returns value of the failed matcher", func() { It("false if failed matcher not going to change", func() { // 3 matchers: 1st returns true, 2nd returns false and is not going to change, 3rd is never called m := And(Not(BeNil()), Or(), Equal(1)) Expect(m.Match("hi")).To(BeFalse()) Expect(m.(*AndMatcher).MatchMayChangeInTheFuture("hi")).To(BeFalse()) // empty Or() indicates not going to change }) It("true if failed matcher indicates it might change", func() { // 3 matchers: 1st returns true, 2nd returns false and "might" change, 3rd is never called m := And(Not(BeNil()), Equal(5), Equal(1)) Expect(m.Match("hi")).To(BeFalse()) Expect(m.(*AndMatcher).MatchMayChangeInTheFuture("hi")).To(BeTrue()) // Equal(5) indicates it might change }) }) }) Context("Match returned true", func() { It("returns true if any of the matchers could change", func() { // 3 matchers, all return true, and all could change m := And(Not(BeNil()), Equal("hi"), HaveLen(2)) Expect(m.Match("hi")).To(BeTrue()) Expect(m.(*AndMatcher).MatchMayChangeInTheFuture("hi")).To(BeTrue()) // all 3 of these matchers default to 'true' }) It("returns false if none of the matchers could change", func() { // empty And() has the property of always matching, and never can change since there are no sub-matchers that could change m := And() Expect(m.Match("anything")).To(BeTrue()) Expect(m.(*AndMatcher).MatchMayChangeInTheFuture("anything")).To(BeFalse()) // And() with 3 sub-matchers that return true, and can't change m = And(And(), And(), And()) Expect(m.Match("hi")).To(BeTrue()) Expect(m.(*AndMatcher).MatchMayChangeInTheFuture("hi")).To(BeFalse()) // the 3 empty And()'s won't change }) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/assignable_to_type_of_matcher.go000066400000000000000000000017701276516347700270360ustar00rootroot00000000000000package matchers import ( "fmt" "reflect" "github.com/onsi/gomega/format" ) type AssignableToTypeOfMatcher struct { Expected interface{} } func (matcher *AssignableToTypeOfMatcher) Match(actual interface{}) (success bool, err error) { if actual == nil || matcher.Expected == nil { return false, fmt.Errorf("Refusing to compare to .\nBe explicit and use BeNil() instead. This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.") } actualType := reflect.TypeOf(actual) expectedType := reflect.TypeOf(matcher.Expected) return actualType.AssignableTo(expectedType), nil } func (matcher *AssignableToTypeOfMatcher) FailureMessage(actual interface{}) string { return format.Message(actual, fmt.Sprintf("to be assignable to the type: %T", matcher.Expected)) } func (matcher *AssignableToTypeOfMatcher) NegatedFailureMessage(actual interface{}) string { return format.Message(actual, fmt.Sprintf("not to be assignable to the type: %T", matcher.Expected)) } golang-gomega-1.0+git20160910.d59fa0a/matchers/assignable_to_type_of_matcher_test.go000066400000000000000000000016051276516347700300720ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("AssignableToTypeOf", func() { Context("When asserting assignability between types", func() { It("should do the right thing", func() { Ω(0).Should(BeAssignableToTypeOf(0)) Ω(5).Should(BeAssignableToTypeOf(-1)) Ω("foo").Should(BeAssignableToTypeOf("bar")) Ω(struct{ Foo string }{}).Should(BeAssignableToTypeOf(struct{ Foo string }{})) Ω(0).ShouldNot(BeAssignableToTypeOf("bar")) Ω(5).ShouldNot(BeAssignableToTypeOf(struct{ Foo string }{})) Ω("foo").ShouldNot(BeAssignableToTypeOf(42)) }) }) Context("When asserting nil values", func() { It("should error", func() { success, err := (&AssignableToTypeOfMatcher{Expected: nil}).Match(nil) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/be_a_directory.go000066400000000000000000000023041276516347700237400ustar00rootroot00000000000000package matchers import ( "fmt" "os" "github.com/onsi/gomega/format" ) type notADirectoryError struct { os.FileInfo } func (t notADirectoryError) Error() string { fileInfo := os.FileInfo(t) switch { case fileInfo.Mode().IsRegular(): return "file is a regular file" default: return fmt.Sprintf("file mode is: %s", fileInfo.Mode().String()) } } type BeADirectoryMatcher struct { expected interface{} err error } func (matcher *BeADirectoryMatcher) Match(actual interface{}) (success bool, err error) { actualFilename, ok := actual.(string) if !ok { return false, fmt.Errorf("BeADirectoryMatcher matcher expects a file path") } fileInfo, err := os.Stat(actualFilename) if err != nil { matcher.err = err return false, nil } if !fileInfo.Mode().IsDir() { matcher.err = notADirectoryError{fileInfo} return false, nil } return true, nil } func (matcher *BeADirectoryMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, fmt.Sprintf("to be a directory: %s", matcher.err)) } func (matcher *BeADirectoryMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, fmt.Sprintf("not be a directory")) } golang-gomega-1.0+git20160910.d59fa0a/matchers/be_a_directory_test.go000066400000000000000000000017721276516347700250070ustar00rootroot00000000000000package matchers_test import ( "io/ioutil" "os" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("BeADirectoryMatcher", func() { Context("when passed a string", func() { It("should do the right thing", func() { Ω("/dne/test").ShouldNot(BeADirectory()) tmpFile, err := ioutil.TempFile("", "gomega-test-tempfile") Ω(err).ShouldNot(HaveOccurred()) defer os.Remove(tmpFile.Name()) Ω(tmpFile.Name()).ShouldNot(BeADirectory()) tmpDir, err := ioutil.TempDir("", "gomega-test-tempdir") Ω(err).ShouldNot(HaveOccurred()) defer os.Remove(tmpDir) Ω(tmpDir).Should(BeADirectory()) }) }) Context("when passed something else", func() { It("should error", func() { success, err := (&BeADirectoryMatcher{}).Match(nil) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&BeADirectoryMatcher{}).Match(true) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/be_a_regular_file.go000066400000000000000000000023201276516347700243720ustar00rootroot00000000000000package matchers import ( "fmt" "os" "github.com/onsi/gomega/format" ) type notARegularFileError struct { os.FileInfo } func (t notARegularFileError) Error() string { fileInfo := os.FileInfo(t) switch { case fileInfo.IsDir(): return "file is a directory" default: return fmt.Sprintf("file mode is: %s", fileInfo.Mode().String()) } } type BeARegularFileMatcher struct { expected interface{} err error } func (matcher *BeARegularFileMatcher) Match(actual interface{}) (success bool, err error) { actualFilename, ok := actual.(string) if !ok { return false, fmt.Errorf("BeARegularFileMatcher matcher expects a file path") } fileInfo, err := os.Stat(actualFilename) if err != nil { matcher.err = err return false, nil } if !fileInfo.Mode().IsRegular() { matcher.err = notARegularFileError{fileInfo} return false, nil } return true, nil } func (matcher *BeARegularFileMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, fmt.Sprintf("to be a regular file: %s", matcher.err)) } func (matcher *BeARegularFileMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, fmt.Sprintf("not be a regular file")) } golang-gomega-1.0+git20160910.d59fa0a/matchers/be_a_regular_file_test.go000066400000000000000000000020061276516347700254320ustar00rootroot00000000000000package matchers_test import ( "io/ioutil" "os" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("BeARegularFileMatcher", func() { Context("when passed a string", func() { It("should do the right thing", func() { Ω("/dne/test").ShouldNot(BeARegularFile()) tmpFile, err := ioutil.TempFile("", "gomega-test-tempfile") Ω(err).ShouldNot(HaveOccurred()) defer os.Remove(tmpFile.Name()) Ω(tmpFile.Name()).Should(BeARegularFile()) tmpDir, err := ioutil.TempDir("", "gomega-test-tempdir") Ω(err).ShouldNot(HaveOccurred()) defer os.Remove(tmpDir) Ω(tmpDir).ShouldNot(BeARegularFile()) }) }) Context("when passed something else", func() { It("should error", func() { success, err := (&BeARegularFileMatcher{}).Match(nil) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&BeARegularFileMatcher{}).Match(true) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/be_an_existing_file.go000066400000000000000000000015301276516347700247430ustar00rootroot00000000000000package matchers import ( "fmt" "os" "github.com/onsi/gomega/format" ) type BeAnExistingFileMatcher struct { expected interface{} } func (matcher *BeAnExistingFileMatcher) Match(actual interface{}) (success bool, err error) { actualFilename, ok := actual.(string) if !ok { return false, fmt.Errorf("BeAnExistingFileMatcher matcher expects a file path") } if _, err = os.Stat(actualFilename); err != nil { switch { case os.IsNotExist(err): return false, nil default: return false, err } } return true, nil } func (matcher *BeAnExistingFileMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, fmt.Sprintf("to exist")) } func (matcher *BeAnExistingFileMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, fmt.Sprintf("not to exist")) } golang-gomega-1.0+git20160910.d59fa0a/matchers/be_an_existing_file_test.go000066400000000000000000000020171276516347700260030ustar00rootroot00000000000000package matchers_test import ( "io/ioutil" "os" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("BeAnExistingFileMatcher", func() { Context("when passed a string", func() { It("should do the right thing", func() { Ω("/dne/test").ShouldNot(BeAnExistingFile()) tmpFile, err := ioutil.TempFile("", "gomega-test-tempfile") Ω(err).ShouldNot(HaveOccurred()) defer os.Remove(tmpFile.Name()) Ω(tmpFile.Name()).Should(BeAnExistingFile()) tmpDir, err := ioutil.TempDir("", "gomega-test-tempdir") Ω(err).ShouldNot(HaveOccurred()) defer os.Remove(tmpDir) Ω(tmpDir).Should(BeAnExistingFile()) }) }) Context("when passed something else", func() { It("should error", func() { success, err := (&BeAnExistingFileMatcher{}).Match(nil) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&BeAnExistingFileMatcher{}).Match(true) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/be_closed_matcher.go000066400000000000000000000022511276516347700244110ustar00rootroot00000000000000package matchers import ( "fmt" "github.com/onsi/gomega/format" "reflect" ) type BeClosedMatcher struct { } func (matcher *BeClosedMatcher) Match(actual interface{}) (success bool, err error) { if !isChan(actual) { return false, fmt.Errorf("BeClosed matcher expects a channel. Got:\n%s", format.Object(actual, 1)) } channelType := reflect.TypeOf(actual) channelValue := reflect.ValueOf(actual) if channelType.ChanDir() == reflect.SendDir { return false, fmt.Errorf("BeClosed matcher cannot determine if a send-only channel is closed or open. Got:\n%s", format.Object(actual, 1)) } winnerIndex, _, open := reflect.Select([]reflect.SelectCase{ reflect.SelectCase{Dir: reflect.SelectRecv, Chan: channelValue}, reflect.SelectCase{Dir: reflect.SelectDefault}, }) var closed bool if winnerIndex == 0 { closed = !open } else if winnerIndex == 1 { closed = false } return closed, nil } func (matcher *BeClosedMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, "to be closed") } func (matcher *BeClosedMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, "to be open") } golang-gomega-1.0+git20160910.d59fa0a/matchers/be_closed_matcher_test.go000066400000000000000000000033601276516347700254520ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("BeClosedMatcher", func() { Context("when passed a channel", func() { It("should do the right thing", func() { openChannel := make(chan bool) Ω(openChannel).ShouldNot(BeClosed()) var openReaderChannel <-chan bool openReaderChannel = openChannel Ω(openReaderChannel).ShouldNot(BeClosed()) closedChannel := make(chan bool) close(closedChannel) Ω(closedChannel).Should(BeClosed()) var closedReaderChannel <-chan bool closedReaderChannel = closedChannel Ω(closedReaderChannel).Should(BeClosed()) }) }) Context("when passed a send-only channel", func() { It("should error", func() { openChannel := make(chan bool) var openWriterChannel chan<- bool openWriterChannel = openChannel success, err := (&BeClosedMatcher{}).Match(openWriterChannel) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) closedChannel := make(chan bool) close(closedChannel) var closedWriterChannel chan<- bool closedWriterChannel = closedChannel success, err = (&BeClosedMatcher{}).Match(closedWriterChannel) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) Context("when passed something else", func() { It("should error", func() { var nilChannel chan bool success, err := (&BeClosedMatcher{}).Match(nilChannel) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&BeClosedMatcher{}).Match(nil) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&BeClosedMatcher{}).Match(7) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/be_empty_matcher.go000066400000000000000000000012271276516347700243000ustar00rootroot00000000000000package matchers import ( "fmt" "github.com/onsi/gomega/format" ) type BeEmptyMatcher struct { } func (matcher *BeEmptyMatcher) Match(actual interface{}) (success bool, err error) { length, ok := lengthOf(actual) if !ok { return false, fmt.Errorf("BeEmpty matcher expects a string/array/map/channel/slice. Got:\n%s", format.Object(actual, 1)) } return length == 0, nil } func (matcher *BeEmptyMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, "to be empty") } func (matcher *BeEmptyMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, "not to be empty") } golang-gomega-1.0+git20160910.d59fa0a/matchers/be_empty_matcher_test.go000066400000000000000000000022661276516347700253430ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("BeEmpty", func() { Context("when passed a supported type", func() { It("should do the right thing", func() { Ω("").Should(BeEmpty()) Ω(" ").ShouldNot(BeEmpty()) Ω([0]int{}).Should(BeEmpty()) Ω([1]int{1}).ShouldNot(BeEmpty()) Ω([]int{}).Should(BeEmpty()) Ω([]int{1}).ShouldNot(BeEmpty()) Ω(map[string]int{}).Should(BeEmpty()) Ω(map[string]int{"a": 1}).ShouldNot(BeEmpty()) c := make(chan bool, 1) Ω(c).Should(BeEmpty()) c <- true Ω(c).ShouldNot(BeEmpty()) }) }) Context("when passed a correctly typed nil", func() { It("should be true", func() { var nilSlice []int Ω(nilSlice).Should(BeEmpty()) var nilMap map[int]string Ω(nilMap).Should(BeEmpty()) }) }) Context("when passed an unsupported type", func() { It("should error", func() { success, err := (&BeEmptyMatcher{}).Match(0) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&BeEmptyMatcher{}).Match(nil) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/be_equivalent_to_matcher.go000066400000000000000000000017751276516347700260310ustar00rootroot00000000000000package matchers import ( "fmt" "github.com/onsi/gomega/format" "reflect" ) type BeEquivalentToMatcher struct { Expected interface{} } func (matcher *BeEquivalentToMatcher) Match(actual interface{}) (success bool, err error) { if actual == nil && matcher.Expected == nil { return false, fmt.Errorf("Both actual and expected must not be nil.") } convertedActual := actual if actual != nil && matcher.Expected != nil && reflect.TypeOf(actual).ConvertibleTo(reflect.TypeOf(matcher.Expected)) { convertedActual = reflect.ValueOf(actual).Convert(reflect.TypeOf(matcher.Expected)).Interface() } return reflect.DeepEqual(convertedActual, matcher.Expected), nil } func (matcher *BeEquivalentToMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, "to be equivalent to", matcher.Expected) } func (matcher *BeEquivalentToMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, "not to be equivalent to", matcher.Expected) } golang-gomega-1.0+git20160910.d59fa0a/matchers/be_equivalent_to_matcher_test.go000066400000000000000000000025711276516347700270630ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("BeEquivalentTo", func() { Context("when asserting that nil is equivalent to nil", func() { It("should error", func() { success, err := (&BeEquivalentToMatcher{Expected: nil}).Match(nil) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) Context("When asserting on nil", func() { It("should do the right thing", func() { Ω("foo").ShouldNot(BeEquivalentTo(nil)) Ω(nil).ShouldNot(BeEquivalentTo(3)) Ω([]int{1, 2}).ShouldNot(BeEquivalentTo(nil)) }) }) Context("When asserting on type aliases", func() { It("should the right thing", func() { Ω(StringAlias("foo")).Should(BeEquivalentTo("foo")) Ω("foo").Should(BeEquivalentTo(StringAlias("foo"))) Ω(StringAlias("foo")).ShouldNot(BeEquivalentTo("bar")) Ω("foo").ShouldNot(BeEquivalentTo(StringAlias("bar"))) }) }) Context("When asserting on numbers", func() { It("should convert actual to expected and do the right thing", func() { Ω(5).Should(BeEquivalentTo(5)) Ω(5.0).Should(BeEquivalentTo(5.0)) Ω(5).Should(BeEquivalentTo(5.0)) Ω(5).ShouldNot(BeEquivalentTo("5")) Ω(5).ShouldNot(BeEquivalentTo(3)) //Here be dragons! Ω(5.1).Should(BeEquivalentTo(5)) Ω(5).ShouldNot(BeEquivalentTo(5.1)) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/be_false_matcher.go000066400000000000000000000011411276516347700242270ustar00rootroot00000000000000package matchers import ( "fmt" "github.com/onsi/gomega/format" ) type BeFalseMatcher struct { } func (matcher *BeFalseMatcher) Match(actual interface{}) (success bool, err error) { if !isBool(actual) { return false, fmt.Errorf("Expected a boolean. Got:\n%s", format.Object(actual, 1)) } return actual == false, nil } func (matcher *BeFalseMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, "to be false") } func (matcher *BeFalseMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, "not to be false") } golang-gomega-1.0+git20160910.d59fa0a/matchers/be_false_matcher_test.go000066400000000000000000000007071276516347700252750ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("BeFalse", func() { It("should handle true and false correctly", func() { Ω(true).ShouldNot(BeFalse()) Ω(false).Should(BeFalse()) }) It("should only support booleans", func() { success, err := (&BeFalseMatcher{}).Match("foo") Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/be_identical_to.go000066400000000000000000000017341276516347700241000ustar00rootroot00000000000000package matchers import ( "fmt" "runtime" "github.com/onsi/gomega/format" ) type BeIdenticalToMatcher struct { Expected interface{} } func (matcher *BeIdenticalToMatcher) Match(actual interface{}) (success bool, matchErr error) { if actual == nil && matcher.Expected == nil { return false, fmt.Errorf("Refusing to compare to .\nBe explicit and use BeNil() instead. This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.") } defer func() { if r := recover(); r != nil { if _, ok := r.(runtime.Error); ok { success = false matchErr = nil } } }() return actual == matcher.Expected, nil } func (matcher *BeIdenticalToMatcher) FailureMessage(actual interface{}) string { return format.Message(actual, "to be identical to", matcher.Expected) } func (matcher *BeIdenticalToMatcher) NegatedFailureMessage(actual interface{}) string { return format.Message(actual, "not to be identical to", matcher.Expected) } golang-gomega-1.0+git20160910.d59fa0a/matchers/be_identical_to_test.go000066400000000000000000000033561276516347700251410ustar00rootroot00000000000000package matchers_test import ( "errors" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("BeIdenticalTo", func() { Context("when asserting that nil equals nil", func() { It("should error", func() { success, err := (&BeIdenticalToMatcher{Expected: nil}).Match(nil) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) It("should treat the same pointer to a struct as identical", func() { mySpecialStruct := myCustomType{} Ω(&mySpecialStruct).Should(BeIdenticalTo(&mySpecialStruct)) Ω(&myCustomType{}).ShouldNot(BeIdenticalTo(&mySpecialStruct)) }) It("should be strict about types", func() { Ω(5).ShouldNot(BeIdenticalTo("5")) Ω(5).ShouldNot(BeIdenticalTo(5.0)) Ω(5).ShouldNot(BeIdenticalTo(3)) }) It("should treat primtives as identical", func() { Ω("5").Should(BeIdenticalTo("5")) Ω("5").ShouldNot(BeIdenticalTo("55")) Ω(5.55).Should(BeIdenticalTo(5.55)) Ω(5.55).ShouldNot(BeIdenticalTo(6.66)) Ω(5).Should(BeIdenticalTo(5)) Ω(5).ShouldNot(BeIdenticalTo(55)) }) It("should treat the same pointers to a slice as identical", func() { mySlice := []int{1, 2} Ω(&mySlice).Should(BeIdenticalTo(&mySlice)) Ω(&mySlice).ShouldNot(BeIdenticalTo(&[]int{1, 2})) }) It("should treat the same pointers to a map as identical", func() { myMap := map[string]string{"a": "b", "c": "d"} Ω(&myMap).Should(BeIdenticalTo(&myMap)) Ω(myMap).ShouldNot(BeIdenticalTo(map[string]string{"a": "b", "c": "d"})) }) It("should treat the same pointers to an error as identical", func() { myError := errors.New("foo") Ω(&myError).Should(BeIdenticalTo(&myError)) Ω(errors.New("foo")).ShouldNot(BeIdenticalTo(errors.New("bar"))) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/be_nil_matcher.go000066400000000000000000000007271276516347700237300ustar00rootroot00000000000000package matchers import "github.com/onsi/gomega/format" type BeNilMatcher struct { } func (matcher *BeNilMatcher) Match(actual interface{}) (success bool, err error) { return isNil(actual), nil } func (matcher *BeNilMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, "to be nil") } func (matcher *BeNilMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, "not to be nil") } golang-gomega-1.0+git20160910.d59fa0a/matchers/be_nil_matcher_test.go000066400000000000000000000010511276516347700247560ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("BeNil", func() { It("should succeed when passed nil", func() { Ω(nil).Should(BeNil()) }) It("should succeed when passed a typed nil", func() { var a []int Ω(a).Should(BeNil()) }) It("should succeed when passing nil pointer", func() { var f *struct{} Ω(f).Should(BeNil()) }) It("should not succeed when not passed nil", func() { Ω(0).ShouldNot(BeNil()) Ω(false).ShouldNot(BeNil()) Ω("").ShouldNot(BeNil()) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/be_numerically_matcher.go000066400000000000000000000072111276516347700254650ustar00rootroot00000000000000package matchers import ( "fmt" "github.com/onsi/gomega/format" "math" ) type BeNumericallyMatcher struct { Comparator string CompareTo []interface{} } func (matcher *BeNumericallyMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, fmt.Sprintf("to be %s", matcher.Comparator), matcher.CompareTo[0]) } func (matcher *BeNumericallyMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, fmt.Sprintf("not to be %s", matcher.Comparator), matcher.CompareTo[0]) } func (matcher *BeNumericallyMatcher) Match(actual interface{}) (success bool, err error) { if len(matcher.CompareTo) == 0 || len(matcher.CompareTo) > 2 { return false, fmt.Errorf("BeNumerically requires 1 or 2 CompareTo arguments. Got:\n%s", format.Object(matcher.CompareTo, 1)) } if !isNumber(actual) { return false, fmt.Errorf("Expected a number. Got:\n%s", format.Object(actual, 1)) } if !isNumber(matcher.CompareTo[0]) { return false, fmt.Errorf("Expected a number. Got:\n%s", format.Object(matcher.CompareTo[0], 1)) } if len(matcher.CompareTo) == 2 && !isNumber(matcher.CompareTo[1]) { return false, fmt.Errorf("Expected a number. Got:\n%s", format.Object(matcher.CompareTo[0], 1)) } switch matcher.Comparator { case "==", "~", ">", ">=", "<", "<=": default: return false, fmt.Errorf("Unknown comparator: %s", matcher.Comparator) } if isFloat(actual) || isFloat(matcher.CompareTo[0]) { var secondOperand float64 = 1e-8 if len(matcher.CompareTo) == 2 { secondOperand = toFloat(matcher.CompareTo[1]) } success = matcher.matchFloats(toFloat(actual), toFloat(matcher.CompareTo[0]), secondOperand) } else if isInteger(actual) { var secondOperand int64 = 0 if len(matcher.CompareTo) == 2 { secondOperand = toInteger(matcher.CompareTo[1]) } success = matcher.matchIntegers(toInteger(actual), toInteger(matcher.CompareTo[0]), secondOperand) } else if isUnsignedInteger(actual) { var secondOperand uint64 = 0 if len(matcher.CompareTo) == 2 { secondOperand = toUnsignedInteger(matcher.CompareTo[1]) } success = matcher.matchUnsignedIntegers(toUnsignedInteger(actual), toUnsignedInteger(matcher.CompareTo[0]), secondOperand) } else { return false, fmt.Errorf("Failed to compare:\n%s\n%s:\n%s", format.Object(actual, 1), matcher.Comparator, format.Object(matcher.CompareTo[0], 1)) } return success, nil } func (matcher *BeNumericallyMatcher) matchIntegers(actual, compareTo, threshold int64) (success bool) { switch matcher.Comparator { case "==", "~": diff := actual - compareTo return -threshold <= diff && diff <= threshold case ">": return (actual > compareTo) case ">=": return (actual >= compareTo) case "<": return (actual < compareTo) case "<=": return (actual <= compareTo) } return false } func (matcher *BeNumericallyMatcher) matchUnsignedIntegers(actual, compareTo, threshold uint64) (success bool) { switch matcher.Comparator { case "==", "~": if actual < compareTo { actual, compareTo = compareTo, actual } return actual-compareTo <= threshold case ">": return (actual > compareTo) case ">=": return (actual >= compareTo) case "<": return (actual < compareTo) case "<=": return (actual <= compareTo) } return false } func (matcher *BeNumericallyMatcher) matchFloats(actual, compareTo, threshold float64) (success bool) { switch matcher.Comparator { case "~": return math.Abs(actual-compareTo) <= threshold case "==": return (actual == compareTo) case ">": return (actual > compareTo) case ">=": return (actual >= compareTo) case "<": return (actual < compareTo) case "<=": return (actual <= compareTo) } return false } golang-gomega-1.0+git20160910.d59fa0a/matchers/be_numerically_matcher_test.go000066400000000000000000000115711276516347700265300ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("BeNumerically", func() { Context("when passed a number", func() { It("should support ==", func() { Ω(uint32(5)).Should(BeNumerically("==", 5)) Ω(float64(5.0)).Should(BeNumerically("==", 5)) Ω(int8(5)).Should(BeNumerically("==", 5)) }) It("should not have false positives", func() { Ω(5.1).ShouldNot(BeNumerically("==", 5)) Ω(5).ShouldNot(BeNumerically("==", 5.1)) }) It("should support >", func() { Ω(uint32(5)).Should(BeNumerically(">", 4)) Ω(float64(5.0)).Should(BeNumerically(">", 4.9)) Ω(int8(5)).Should(BeNumerically(">", 4)) Ω(uint32(5)).ShouldNot(BeNumerically(">", 5)) Ω(float64(5.0)).ShouldNot(BeNumerically(">", 5.0)) Ω(int8(5)).ShouldNot(BeNumerically(">", 5)) }) It("should support <", func() { Ω(uint32(5)).Should(BeNumerically("<", 6)) Ω(float64(5.0)).Should(BeNumerically("<", 5.1)) Ω(int8(5)).Should(BeNumerically("<", 6)) Ω(uint32(5)).ShouldNot(BeNumerically("<", 5)) Ω(float64(5.0)).ShouldNot(BeNumerically("<", 5.0)) Ω(int8(5)).ShouldNot(BeNumerically("<", 5)) }) It("should support >=", func() { Ω(uint32(5)).Should(BeNumerically(">=", 4)) Ω(float64(5.0)).Should(BeNumerically(">=", 4.9)) Ω(int8(5)).Should(BeNumerically(">=", 4)) Ω(uint32(5)).Should(BeNumerically(">=", 5)) Ω(float64(5.0)).Should(BeNumerically(">=", 5.0)) Ω(int8(5)).Should(BeNumerically(">=", 5)) Ω(uint32(5)).ShouldNot(BeNumerically(">=", 6)) Ω(float64(5.0)).ShouldNot(BeNumerically(">=", 5.1)) Ω(int8(5)).ShouldNot(BeNumerically(">=", 6)) }) It("should support <=", func() { Ω(uint32(5)).Should(BeNumerically("<=", 6)) Ω(float64(5.0)).Should(BeNumerically("<=", 5.1)) Ω(int8(5)).Should(BeNumerically("<=", 6)) Ω(uint32(5)).Should(BeNumerically("<=", 5)) Ω(float64(5.0)).Should(BeNumerically("<=", 5.0)) Ω(int8(5)).Should(BeNumerically("<=", 5)) Ω(uint32(5)).ShouldNot(BeNumerically("<=", 4)) Ω(float64(5.0)).ShouldNot(BeNumerically("<=", 4.9)) Ω(int8(5)).Should(BeNumerically("<=", 5)) }) Context("when passed ~", func() { Context("when passed a float", func() { Context("and there is no precision parameter", func() { It("should default to 1e-8", func() { Ω(5.00000001).Should(BeNumerically("~", 5.00000002)) Ω(5.00000001).ShouldNot(BeNumerically("~", 5.0000001)) }) }) Context("and there is a precision parameter", func() { It("should use the precision parameter", func() { Ω(5.1).Should(BeNumerically("~", 5.19, 0.1)) Ω(5.1).Should(BeNumerically("~", 5.01, 0.1)) Ω(5.1).ShouldNot(BeNumerically("~", 5.22, 0.1)) Ω(5.1).ShouldNot(BeNumerically("~", 4.98, 0.1)) }) }) }) Context("when passed an int/uint", func() { Context("and there is no precision parameter", func() { It("should just do strict equality", func() { Ω(5).Should(BeNumerically("~", 5)) Ω(5).ShouldNot(BeNumerically("~", 6)) Ω(uint(5)).ShouldNot(BeNumerically("~", 6)) }) }) Context("and there is a precision parameter", func() { It("should use precision paramter", func() { Ω(5).Should(BeNumerically("~", 6, 2)) Ω(5).ShouldNot(BeNumerically("~", 8, 2)) Ω(uint(5)).Should(BeNumerically("~", 6, 1)) }) }) }) }) }) Context("when passed a non-number", func() { It("should error", func() { success, err := (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{5}}).Match("foo") Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&BeNumericallyMatcher{Comparator: "=="}).Match(5) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&BeNumericallyMatcher{Comparator: "~", CompareTo: []interface{}{3.0, "foo"}}).Match(5.0) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{"bar"}}).Match(5) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{"bar"}}).Match("foo") Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{nil}}).Match(0) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{0}}).Match(nil) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) Context("when passed an unsupported comparator", func() { It("should error", func() { success, err := (&BeNumericallyMatcher{Comparator: "!=", CompareTo: []interface{}{5}}).Match(4) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/be_sent_matcher.go000066400000000000000000000034431276516347700241150ustar00rootroot00000000000000package matchers import ( "fmt" "reflect" "github.com/onsi/gomega/format" ) type BeSentMatcher struct { Arg interface{} channelClosed bool } func (matcher *BeSentMatcher) Match(actual interface{}) (success bool, err error) { if !isChan(actual) { return false, fmt.Errorf("BeSent expects a channel. Got:\n%s", format.Object(actual, 1)) } channelType := reflect.TypeOf(actual) channelValue := reflect.ValueOf(actual) if channelType.ChanDir() == reflect.RecvDir { return false, fmt.Errorf("BeSent matcher cannot be passed a receive-only channel. Got:\n%s", format.Object(actual, 1)) } argType := reflect.TypeOf(matcher.Arg) assignable := argType.AssignableTo(channelType.Elem()) if !assignable { return false, fmt.Errorf("Cannot pass:\n%s to the channel:\n%s\nThe types don't match.", format.Object(matcher.Arg, 1), format.Object(actual, 1)) } argValue := reflect.ValueOf(matcher.Arg) defer func() { if e := recover(); e != nil { success = false err = fmt.Errorf("Cannot send to a closed channel") matcher.channelClosed = true } }() winnerIndex, _, _ := reflect.Select([]reflect.SelectCase{ reflect.SelectCase{Dir: reflect.SelectSend, Chan: channelValue, Send: argValue}, reflect.SelectCase{Dir: reflect.SelectDefault}, }) var didSend bool if winnerIndex == 0 { didSend = true } return didSend, nil } func (matcher *BeSentMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, "to send:", matcher.Arg) } func (matcher *BeSentMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, "not to send:", matcher.Arg) } func (matcher *BeSentMatcher) MatchMayChangeInTheFuture(actual interface{}) bool { if !isChan(actual) { return false } return !matcher.channelClosed } golang-gomega-1.0+git20160910.d59fa0a/matchers/be_sent_matcher_test.go000066400000000000000000000051561276516347700251570ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/gomega/matchers" "time" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("BeSent", func() { Context("when passed a channel and a matching type", func() { Context("when the channel is ready to receive", func() { It("should succeed and send the value down the channel", func() { c := make(chan string) d := make(chan string) go func() { val := <-c d <- val }() time.Sleep(10 * time.Millisecond) Ω(c).Should(BeSent("foo")) Eventually(d).Should(Receive(Equal("foo"))) }) It("should succeed (with a buffered channel)", func() { c := make(chan string, 1) Ω(c).Should(BeSent("foo")) Ω(<-c).Should(Equal("foo")) }) }) Context("when the channel is not ready to receive", func() { It("should fail and not send down the channel", func() { c := make(chan string) Ω(c).ShouldNot(BeSent("foo")) Consistently(c).ShouldNot(Receive()) }) }) Context("when the channel is eventually ready to receive", func() { It("should succeed", func() { c := make(chan string) d := make(chan string) go func() { time.Sleep(30 * time.Millisecond) val := <-c d <- val }() Eventually(c).Should(BeSent("foo")) Eventually(d).Should(Receive(Equal("foo"))) }) }) Context("when the channel is closed", func() { It("should error", func() { c := make(chan string) close(c) success, err := (&BeSentMatcher{Arg: "foo"}).Match(c) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) It("should short-circuit Eventually", func() { c := make(chan string) close(c) t := time.Now() failures := InterceptGomegaFailures(func() { Eventually(c, 10.0).Should(BeSent("foo")) }) Ω(failures).Should(HaveLen(1)) Ω(time.Since(t)).Should(BeNumerically("<", time.Second)) }) }) }) Context("when passed a channel and a non-matching type", func() { It("should error", func() { success, err := (&BeSentMatcher{Arg: "foo"}).Match(make(chan int, 1)) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) Context("when passed a receive-only channel", func() { It("should error", func() { var c <-chan string c = make(chan string, 1) success, err := (&BeSentMatcher{Arg: "foo"}).Match(c) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) Context("when passed a nonchannel", func() { It("should error", func() { success, err := (&BeSentMatcher{Arg: "foo"}).Match("bar") Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/be_temporally_matcher.go000066400000000000000000000032631276516347700253340ustar00rootroot00000000000000package matchers import ( "fmt" "github.com/onsi/gomega/format" "time" ) type BeTemporallyMatcher struct { Comparator string CompareTo time.Time Threshold []time.Duration } func (matcher *BeTemporallyMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, fmt.Sprintf("to be %s", matcher.Comparator), matcher.CompareTo) } func (matcher *BeTemporallyMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, fmt.Sprintf("not to be %s", matcher.Comparator), matcher.CompareTo) } func (matcher *BeTemporallyMatcher) Match(actual interface{}) (bool, error) { // predicate to test for time.Time type isTime := func(t interface{}) bool { _, ok := t.(time.Time) return ok } if !isTime(actual) { return false, fmt.Errorf("Expected a time.Time. Got:\n%s", format.Object(actual, 1)) } switch matcher.Comparator { case "==", "~", ">", ">=", "<", "<=": default: return false, fmt.Errorf("Unknown comparator: %s", matcher.Comparator) } var threshold = time.Millisecond if len(matcher.Threshold) == 1 { threshold = matcher.Threshold[0] } return matcher.matchTimes(actual.(time.Time), matcher.CompareTo, threshold), nil } func (matcher *BeTemporallyMatcher) matchTimes(actual, compareTo time.Time, threshold time.Duration) (success bool) { switch matcher.Comparator { case "==": return actual.Equal(compareTo) case "~": diff := actual.Sub(compareTo) return -threshold <= diff && diff <= threshold case ">": return actual.After(compareTo) case ">=": return !actual.Before(compareTo) case "<": return actual.Before(compareTo) case "<=": return !actual.After(compareTo) } return false } golang-gomega-1.0+git20160910.d59fa0a/matchers/be_temporally_matcher_test.go000066400000000000000000000050631276516347700263730ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" "time" ) var _ = Describe("BeTemporally", func() { var t0, t1, t2 time.Time BeforeEach(func() { t0 = time.Now() t1 = t0.Add(time.Second) t2 = t0.Add(-time.Second) }) Context("When comparing times", func() { It("should support ==", func() { Ω(t0).Should(BeTemporally("==", t0)) Ω(t1).ShouldNot(BeTemporally("==", t0)) Ω(t0).ShouldNot(BeTemporally("==", t1)) Ω(t0).ShouldNot(BeTemporally("==", time.Time{})) }) It("should support >", func() { Ω(t0).Should(BeTemporally(">", t2)) Ω(t0).ShouldNot(BeTemporally(">", t0)) Ω(t2).ShouldNot(BeTemporally(">", t0)) }) It("should support <", func() { Ω(t0).Should(BeTemporally("<", t1)) Ω(t0).ShouldNot(BeTemporally("<", t0)) Ω(t1).ShouldNot(BeTemporally("<", t0)) }) It("should support >=", func() { Ω(t0).Should(BeTemporally(">=", t2)) Ω(t0).Should(BeTemporally(">=", t0)) Ω(t0).ShouldNot(BeTemporally(">=", t1)) }) It("should support <=", func() { Ω(t0).Should(BeTemporally("<=", t1)) Ω(t0).Should(BeTemporally("<=", t0)) Ω(t0).ShouldNot(BeTemporally("<=", t2)) }) Context("when passed ~", func() { Context("and there is no precision parameter", func() { BeforeEach(func() { t1 = t0.Add(time.Millisecond / 2) t2 = t0.Add(-2 * time.Millisecond) }) It("should approximate", func() { Ω(t0).Should(BeTemporally("~", t0)) Ω(t0).Should(BeTemporally("~", t1)) Ω(t0).ShouldNot(BeTemporally("~", t2)) }) }) Context("and there is a precision parameter", func() { BeforeEach(func() { t2 = t0.Add(3 * time.Second) }) It("should use precision paramter", func() { d := 2 * time.Second Ω(t0).Should(BeTemporally("~", t0, d)) Ω(t0).Should(BeTemporally("~", t1, d)) Ω(t0).ShouldNot(BeTemporally("~", t2, d)) }) }) }) }) Context("when passed a non-time", func() { It("should error", func() { success, err := (&BeTemporallyMatcher{Comparator: "==", CompareTo: t0}).Match("foo") Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&BeTemporallyMatcher{Comparator: "=="}).Match(nil) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) Context("when passed an unsupported comparator", func() { It("should error", func() { success, err := (&BeTemporallyMatcher{Comparator: "!=", CompareTo: t0}).Match(t2) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/be_true_matcher.go000066400000000000000000000011311276516347700241130ustar00rootroot00000000000000package matchers import ( "fmt" "github.com/onsi/gomega/format" ) type BeTrueMatcher struct { } func (matcher *BeTrueMatcher) Match(actual interface{}) (success bool, err error) { if !isBool(actual) { return false, fmt.Errorf("Expected a boolean. Got:\n%s", format.Object(actual, 1)) } return actual.(bool), nil } func (matcher *BeTrueMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, "to be true") } func (matcher *BeTrueMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, "not to be true") } golang-gomega-1.0+git20160910.d59fa0a/matchers/be_true_matcher_test.go000066400000000000000000000007031276516347700251560ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("BeTrue", func() { It("should handle true and false correctly", func() { Ω(true).Should(BeTrue()) Ω(false).ShouldNot(BeTrue()) }) It("should only support booleans", func() { success, err := (&BeTrueMatcher{}).Match("foo") Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/be_zero_matcher.go000066400000000000000000000011751276516347700241230ustar00rootroot00000000000000package matchers import ( "github.com/onsi/gomega/format" "reflect" ) type BeZeroMatcher struct { } func (matcher *BeZeroMatcher) Match(actual interface{}) (success bool, err error) { if actual == nil { return true, nil } zeroValue := reflect.Zero(reflect.TypeOf(actual)).Interface() return reflect.DeepEqual(zeroValue, actual), nil } func (matcher *BeZeroMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, "to be zero-valued") } func (matcher *BeZeroMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, "not to be zero-valued") } golang-gomega-1.0+git20160910.d59fa0a/matchers/be_zero_matcher_test.go000066400000000000000000000012311276516347700251530ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("BeZero", func() { It("should succeed if the passed in object is the zero value for its type", func() { Ω(nil).Should(BeZero()) Ω("").Should(BeZero()) Ω(" ").ShouldNot(BeZero()) Ω(0).Should(BeZero()) Ω(1).ShouldNot(BeZero()) Ω(0.0).Should(BeZero()) Ω(0.1).ShouldNot(BeZero()) // Ω([]int{}).Should(BeZero()) Ω([]int{1}).ShouldNot(BeZero()) // Ω(map[string]int{}).Should(BeZero()) Ω(map[string]int{"a": 1}).ShouldNot(BeZero()) Ω(myCustomType{}).Should(BeZero()) Ω(myCustomType{s: "a"}).ShouldNot(BeZero()) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/consist_of.go000066400000000000000000000041211276516347700231330ustar00rootroot00000000000000package matchers import ( "fmt" "reflect" "github.com/onsi/gomega/format" "github.com/onsi/gomega/matchers/support/goraph/bipartitegraph" ) type ConsistOfMatcher struct { Elements []interface{} } func (matcher *ConsistOfMatcher) Match(actual interface{}) (success bool, err error) { if !isArrayOrSlice(actual) && !isMap(actual) { return false, fmt.Errorf("ConsistOf matcher expects an array/slice/map. Got:\n%s", format.Object(actual, 1)) } elements := matcher.Elements if len(matcher.Elements) == 1 && isArrayOrSlice(matcher.Elements[0]) { elements = []interface{}{} value := reflect.ValueOf(matcher.Elements[0]) for i := 0; i < value.Len(); i++ { elements = append(elements, value.Index(i).Interface()) } } matchers := []interface{}{} for _, element := range elements { matcher, isMatcher := element.(omegaMatcher) if !isMatcher { matcher = &EqualMatcher{Expected: element} } matchers = append(matchers, matcher) } values := matcher.valuesOf(actual) if len(values) != len(matchers) { return false, nil } neighbours := func(v, m interface{}) (bool, error) { match, err := m.(omegaMatcher).Match(v) return match && err == nil, nil } bipartiteGraph, err := bipartitegraph.NewBipartiteGraph(values, matchers, neighbours) if err != nil { return false, err } return len(bipartiteGraph.LargestMatching()) == len(values), nil } func (matcher *ConsistOfMatcher) valuesOf(actual interface{}) []interface{} { value := reflect.ValueOf(actual) values := []interface{}{} if isMap(actual) { keys := value.MapKeys() for i := 0; i < value.Len(); i++ { values = append(values, value.MapIndex(keys[i]).Interface()) } } else { for i := 0; i < value.Len(); i++ { values = append(values, value.Index(i).Interface()) } } return values } func (matcher *ConsistOfMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, "to consist of", matcher.Elements) } func (matcher *ConsistOfMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, "not to consist of", matcher.Elements) } golang-gomega-1.0+git20160910.d59fa0a/matchers/consist_of_test.go000066400000000000000000000057651276516347700242110ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("ConsistOf", func() { Context("with a slice", func() { It("should do the right thing", func() { Ω([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", "bar", "baz")) Ω([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", "bar", "baz")) Ω([]string{"foo", "bar", "baz"}).Should(ConsistOf("baz", "bar", "foo")) Ω([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "bar", "foo", "foo")) Ω([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "foo")) }) }) Context("with an array", func() { It("should do the right thing", func() { Ω([3]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", "bar", "baz")) Ω([3]string{"foo", "bar", "baz"}).Should(ConsistOf("baz", "bar", "foo")) Ω([3]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "bar", "foo", "foo")) Ω([3]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "foo")) }) }) Context("with a map", func() { It("should apply to the values", func() { Ω(map[int]string{1: "foo", 2: "bar", 3: "baz"}).Should(ConsistOf("foo", "bar", "baz")) Ω(map[int]string{1: "foo", 2: "bar", 3: "baz"}).Should(ConsistOf("baz", "bar", "foo")) Ω(map[int]string{1: "foo", 2: "bar", 3: "baz"}).ShouldNot(ConsistOf("baz", "bar", "foo", "foo")) Ω(map[int]string{1: "foo", 2: "bar", 3: "baz"}).ShouldNot(ConsistOf("baz", "foo")) }) }) Context("with anything else", func() { It("should error", func() { failures := InterceptGomegaFailures(func() { Ω("foo").Should(ConsistOf("f", "o", "o")) }) Ω(failures).Should(HaveLen(1)) }) }) Context("when passed matchers", func() { It("should pass if the matchers pass", func() { Ω([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", MatchRegexp("^ba"), "baz")) Ω([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("foo", MatchRegexp("^ba"))) Ω([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("foo", MatchRegexp("^ba"), MatchRegexp("foo"))) Ω([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", MatchRegexp("^ba"), MatchRegexp("^ba"))) Ω([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("foo", MatchRegexp("^ba"), MatchRegexp("turducken"))) }) It("should not depend on the order of the matchers", func() { Ω([][]int{[]int{1, 2}, []int{2}}).Should(ConsistOf(ContainElement(1), ContainElement(2))) Ω([][]int{[]int{1, 2}, []int{2}}).Should(ConsistOf(ContainElement(2), ContainElement(1))) }) Context("when a matcher errors", func() { It("should soldier on", func() { Ω([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf(BeFalse(), "foo", "bar")) Ω([]interface{}{"foo", "bar", false}).Should(ConsistOf(BeFalse(), ContainSubstring("foo"), "bar")) }) }) }) Context("when passed exactly one argument, and that argument is a slice", func() { It("should match against the elements of that argument", func() { Ω([]string{"foo", "bar", "baz"}).Should(ConsistOf([]string{"foo", "bar", "baz"})) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/contain_element_matcher.go000066400000000000000000000026001276516347700256340ustar00rootroot00000000000000package matchers import ( "fmt" "reflect" "github.com/onsi/gomega/format" ) type ContainElementMatcher struct { Element interface{} } func (matcher *ContainElementMatcher) Match(actual interface{}) (success bool, err error) { if !isArrayOrSlice(actual) && !isMap(actual) { return false, fmt.Errorf("ContainElement matcher expects an array/slice/map. Got:\n%s", format.Object(actual, 1)) } elemMatcher, elementIsMatcher := matcher.Element.(omegaMatcher) if !elementIsMatcher { elemMatcher = &EqualMatcher{Expected: matcher.Element} } value := reflect.ValueOf(actual) var keys []reflect.Value if isMap(actual) { keys = value.MapKeys() } var lastError error for i := 0; i < value.Len(); i++ { var success bool var err error if isMap(actual) { success, err = elemMatcher.Match(value.MapIndex(keys[i]).Interface()) } else { success, err = elemMatcher.Match(value.Index(i).Interface()) } if err != nil { lastError = err continue } if success { return true, nil } } return false, lastError } func (matcher *ContainElementMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, "to contain element matching", matcher.Element) } func (matcher *ContainElementMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, "not to contain element matching", matcher.Element) } golang-gomega-1.0+git20160910.d59fa0a/matchers/contain_element_matcher_test.go000066400000000000000000000051721276516347700267020ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("ContainElement", func() { Context("when passed a supported type", func() { Context("and expecting a non-matcher", func() { It("should do the right thing", func() { Ω([2]int{1, 2}).Should(ContainElement(2)) Ω([2]int{1, 2}).ShouldNot(ContainElement(3)) Ω([]int{1, 2}).Should(ContainElement(2)) Ω([]int{1, 2}).ShouldNot(ContainElement(3)) Ω(map[string]int{"foo": 1, "bar": 2}).Should(ContainElement(2)) Ω(map[int]int{3: 1, 4: 2}).ShouldNot(ContainElement(3)) arr := make([]myCustomType, 2) arr[0] = myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}} arr[1] = myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "c"}} Ω(arr).Should(ContainElement(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}})) Ω(arr).ShouldNot(ContainElement(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"b", "c"}})) }) }) Context("and expecting a matcher", func() { It("should pass each element through the matcher", func() { Ω([]int{1, 2, 3}).Should(ContainElement(BeNumerically(">=", 3))) Ω([]int{1, 2, 3}).ShouldNot(ContainElement(BeNumerically(">", 3))) Ω(map[string]int{"foo": 1, "bar": 2}).Should(ContainElement(BeNumerically(">=", 2))) Ω(map[string]int{"foo": 1, "bar": 2}).ShouldNot(ContainElement(BeNumerically(">", 2))) }) It("should power through even if the matcher ever fails", func() { Ω([]interface{}{1, 2, "3", 4}).Should(ContainElement(BeNumerically(">=", 3))) }) It("should fail if the matcher fails", func() { actual := []interface{}{1, 2, "3", "4"} success, err := (&ContainElementMatcher{Element: BeNumerically(">=", 3)}).Match(actual) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) }) Context("when passed a correctly typed nil", func() { It("should operate succesfully on the passed in value", func() { var nilSlice []int Ω(nilSlice).ShouldNot(ContainElement(1)) var nilMap map[int]string Ω(nilMap).ShouldNot(ContainElement("foo")) }) }) Context("when passed an unsupported type", func() { It("should error", func() { success, err := (&ContainElementMatcher{Element: 0}).Match(0) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&ContainElementMatcher{Element: 0}).Match("abc") Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&ContainElementMatcher{Element: 0}).Match(nil) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/contain_substring_matcher.go000066400000000000000000000020701276516347700262240ustar00rootroot00000000000000package matchers import ( "fmt" "github.com/onsi/gomega/format" "strings" ) type ContainSubstringMatcher struct { Substr string Args []interface{} } func (matcher *ContainSubstringMatcher) Match(actual interface{}) (success bool, err error) { actualString, ok := toString(actual) if !ok { return false, fmt.Errorf("ContainSubstring matcher requires a string or stringer. Got:\n%s", format.Object(actual, 1)) } return strings.Contains(actualString, matcher.stringToMatch()), nil } func (matcher *ContainSubstringMatcher) stringToMatch() string { stringToMatch := matcher.Substr if len(matcher.Args) > 0 { stringToMatch = fmt.Sprintf(matcher.Substr, matcher.Args...) } return stringToMatch } func (matcher *ContainSubstringMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, "to contain substring", matcher.stringToMatch()) } func (matcher *ContainSubstringMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, "not to contain substring", matcher.stringToMatch()) } golang-gomega-1.0+git20160910.d59fa0a/matchers/contain_substring_matcher_test.go000066400000000000000000000020201276516347700272560ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("ContainSubstringMatcher", func() { Context("when actual is a string", func() { It("should match against the string", func() { Ω("Marvelous").Should(ContainSubstring("rve")) Ω("Marvelous").ShouldNot(ContainSubstring("boo")) }) }) Context("when the matcher is called with multiple arguments", func() { It("should pass the string and arguments to sprintf", func() { Ω("Marvelous3").Should(ContainSubstring("velous%d", 3)) }) }) Context("when actual is a stringer", func() { It("should call the stringer and match agains the returned string", func() { Ω(&myStringer{a: "Abc3"}).Should(ContainSubstring("bc3")) }) }) Context("when actual is neither a string nor a stringer", func() { It("should error", func() { success, err := (&ContainSubstringMatcher{Substr: "2"}).Match(2) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/equal_matcher.go000066400000000000000000000014721276516347700236050ustar00rootroot00000000000000package matchers import ( "fmt" "reflect" "github.com/onsi/gomega/format" ) type EqualMatcher struct { Expected interface{} } func (matcher *EqualMatcher) Match(actual interface{}) (success bool, err error) { if actual == nil && matcher.Expected == nil { return false, fmt.Errorf("Refusing to compare to .\nBe explicit and use BeNil() instead. This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.") } return reflect.DeepEqual(actual, matcher.Expected), nil } func (matcher *EqualMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, "to equal", matcher.Expected) } func (matcher *EqualMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, "not to equal", matcher.Expected) } golang-gomega-1.0+git20160910.d59fa0a/matchers/equal_matcher_test.go000066400000000000000000000034761276516347700246520ustar00rootroot00000000000000package matchers_test import ( "errors" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("Equal", func() { Context("when asserting that nil equals nil", func() { It("should error", func() { success, err := (&EqualMatcher{Expected: nil}).Match(nil) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) Context("When asserting equality between objects", func() { It("should do the right thing", func() { Ω(5).Should(Equal(5)) Ω(5.0).Should(Equal(5.0)) Ω(5).ShouldNot(Equal("5")) Ω(5).ShouldNot(Equal(5.0)) Ω(5).ShouldNot(Equal(3)) Ω("5").Should(Equal("5")) Ω([]int{1, 2}).Should(Equal([]int{1, 2})) Ω([]int{1, 2}).ShouldNot(Equal([]int{2, 1})) Ω(map[string]string{"a": "b", "c": "d"}).Should(Equal(map[string]string{"a": "b", "c": "d"})) Ω(map[string]string{"a": "b", "c": "d"}).ShouldNot(Equal(map[string]string{"a": "b", "c": "e"})) Ω(errors.New("foo")).Should(Equal(errors.New("foo"))) Ω(errors.New("foo")).ShouldNot(Equal(errors.New("bar"))) Ω(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).Should(Equal(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}})) Ω(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Equal(myCustomType{s: "bar", n: 3, f: 2.0, arr: []string{"a", "b"}})) Ω(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Equal(myCustomType{s: "foo", n: 2, f: 2.0, arr: []string{"a", "b"}})) Ω(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Equal(myCustomType{s: "foo", n: 3, f: 3.0, arr: []string{"a", "b"}})) Ω(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Equal(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b", "c"}})) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/have_cap_matcher.go000066400000000000000000000014111276516347700242350ustar00rootroot00000000000000package matchers import ( "fmt" "github.com/onsi/gomega/format" ) type HaveCapMatcher struct { Count int } func (matcher *HaveCapMatcher) Match(actual interface{}) (success bool, err error) { length, ok := capOf(actual) if !ok { return false, fmt.Errorf("HaveCap matcher expects a array/channel/slice. Got:\n%s", format.Object(actual, 1)) } return length == matcher.Count, nil } func (matcher *HaveCapMatcher) FailureMessage(actual interface{}) (message string) { return fmt.Sprintf("Expected\n%s\nto have capacity %d", format.Object(actual, 1), matcher.Count) } func (matcher *HaveCapMatcher) NegatedFailureMessage(actual interface{}) (message string) { return fmt.Sprintf("Expected\n%s\nnot to have capacity %d", format.Object(actual, 1), matcher.Count) } golang-gomega-1.0+git20160910.d59fa0a/matchers/have_cap_matcher_test.go000066400000000000000000000022751276516347700253050ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("HaveCap", func() { Context("when passed a supported type", func() { It("should do the right thing", func() { Ω([0]int{}).Should(HaveCap(0)) Ω([2]int{1}).Should(HaveCap(2)) Ω([]int{}).Should(HaveCap(0)) Ω([]int{1, 2, 3, 4, 5}[:2]).Should(HaveCap(5)) Ω(make([]int, 0, 5)).Should(HaveCap(5)) c := make(chan bool, 3) Ω(c).Should(HaveCap(3)) c <- true c <- true Ω(c).Should(HaveCap(3)) Ω(make(chan bool)).Should(HaveCap(0)) }) }) Context("when passed a correctly typed nil", func() { It("should operate succesfully on the passed in value", func() { var nilSlice []int Ω(nilSlice).Should(HaveCap(0)) var nilChan chan int Ω(nilChan).Should(HaveCap(0)) }) }) Context("when passed an unsupported type", func() { It("should error", func() { success, err := (&HaveCapMatcher{Count: 0}).Match(0) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&HaveCapMatcher{Count: 0}).Match(nil) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/have_key_matcher.go000066400000000000000000000025171276516347700242720ustar00rootroot00000000000000package matchers import ( "fmt" "github.com/onsi/gomega/format" "reflect" ) type HaveKeyMatcher struct { Key interface{} } func (matcher *HaveKeyMatcher) Match(actual interface{}) (success bool, err error) { if !isMap(actual) { return false, fmt.Errorf("HaveKey matcher expects a map. Got:%s", format.Object(actual, 1)) } keyMatcher, keyIsMatcher := matcher.Key.(omegaMatcher) if !keyIsMatcher { keyMatcher = &EqualMatcher{Expected: matcher.Key} } keys := reflect.ValueOf(actual).MapKeys() for i := 0; i < len(keys); i++ { success, err := keyMatcher.Match(keys[i].Interface()) if err != nil { return false, fmt.Errorf("HaveKey's key matcher failed with:\n%s%s", format.Indent, err.Error()) } if success { return true, nil } } return false, nil } func (matcher *HaveKeyMatcher) FailureMessage(actual interface{}) (message string) { switch matcher.Key.(type) { case omegaMatcher: return format.Message(actual, "to have key matching", matcher.Key) default: return format.Message(actual, "to have key", matcher.Key) } } func (matcher *HaveKeyMatcher) NegatedFailureMessage(actual interface{}) (message string) { switch matcher.Key.(type) { case omegaMatcher: return format.Message(actual, "not to have key matching", matcher.Key) default: return format.Message(actual, "not to have key", matcher.Key) } } golang-gomega-1.0+git20160910.d59fa0a/matchers/have_key_matcher_test.go000066400000000000000000000043051276516347700253260ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("HaveKey", func() { var ( stringKeys map[string]int intKeys map[int]string objKeys map[*myCustomType]string customA *myCustomType customB *myCustomType ) BeforeEach(func() { stringKeys = map[string]int{"foo": 2, "bar": 3} intKeys = map[int]string{2: "foo", 3: "bar"} customA = &myCustomType{s: "a", n: 2, f: 2.3, arr: []string{"ice", "cream"}} customB = &myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"cake"}} objKeys = map[*myCustomType]string{customA: "aardvark", customB: "kangaroo"} }) Context("when passed a map", func() { It("should do the right thing", func() { Ω(stringKeys).Should(HaveKey("foo")) Ω(stringKeys).ShouldNot(HaveKey("baz")) Ω(intKeys).Should(HaveKey(2)) Ω(intKeys).ShouldNot(HaveKey(4)) Ω(objKeys).Should(HaveKey(customA)) Ω(objKeys).Should(HaveKey(&myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"cake"}})) Ω(objKeys).ShouldNot(HaveKey(&myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"apple", "pie"}})) }) }) Context("when passed a correctly typed nil", func() { It("should operate succesfully on the passed in value", func() { var nilMap map[int]string Ω(nilMap).ShouldNot(HaveKey("foo")) }) }) Context("when the passed in key is actually a matcher", func() { It("should pass each element through the matcher", func() { Ω(stringKeys).Should(HaveKey(ContainSubstring("oo"))) Ω(stringKeys).ShouldNot(HaveKey(ContainSubstring("foobar"))) }) It("should fail if the matcher ever fails", func() { actual := map[int]string{1: "a", 3: "b", 2: "c"} success, err := (&HaveKeyMatcher{Key: ContainSubstring("ar")}).Match(actual) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) Context("when passed something that is not a map", func() { It("should error", func() { success, err := (&HaveKeyMatcher{Key: "foo"}).Match([]string{"foo"}) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&HaveKeyMatcher{Key: "foo"}).Match(nil) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/have_key_with_value_matcher.go000066400000000000000000000040431276516347700265150ustar00rootroot00000000000000package matchers import ( "fmt" "github.com/onsi/gomega/format" "reflect" ) type HaveKeyWithValueMatcher struct { Key interface{} Value interface{} } func (matcher *HaveKeyWithValueMatcher) Match(actual interface{}) (success bool, err error) { if !isMap(actual) { return false, fmt.Errorf("HaveKeyWithValue matcher expects a map. Got:%s", format.Object(actual, 1)) } keyMatcher, keyIsMatcher := matcher.Key.(omegaMatcher) if !keyIsMatcher { keyMatcher = &EqualMatcher{Expected: matcher.Key} } valueMatcher, valueIsMatcher := matcher.Value.(omegaMatcher) if !valueIsMatcher { valueMatcher = &EqualMatcher{Expected: matcher.Value} } keys := reflect.ValueOf(actual).MapKeys() for i := 0; i < len(keys); i++ { success, err := keyMatcher.Match(keys[i].Interface()) if err != nil { return false, fmt.Errorf("HaveKeyWithValue's key matcher failed with:\n%s%s", format.Indent, err.Error()) } if success { actualValue := reflect.ValueOf(actual).MapIndex(keys[i]) success, err := valueMatcher.Match(actualValue.Interface()) if err != nil { return false, fmt.Errorf("HaveKeyWithValue's value matcher failed with:\n%s%s", format.Indent, err.Error()) } return success, nil } } return false, nil } func (matcher *HaveKeyWithValueMatcher) FailureMessage(actual interface{}) (message string) { str := "to have {key: value}" if _, ok := matcher.Key.(omegaMatcher); ok { str += " matching" } else if _, ok := matcher.Value.(omegaMatcher); ok { str += " matching" } expect := make(map[interface{}]interface{}, 1) expect[matcher.Key] = matcher.Value return format.Message(actual, str, expect) } func (matcher *HaveKeyWithValueMatcher) NegatedFailureMessage(actual interface{}) (message string) { kStr := "not to have key" if _, ok := matcher.Key.(omegaMatcher); ok { kStr = "not to have key matching" } vStr := "or that key's value not be" if _, ok := matcher.Value.(omegaMatcher); ok { vStr = "or to have that key's value not matching" } return format.Message(actual, kStr, matcher.Key, vStr, matcher.Value) } golang-gomega-1.0+git20160910.d59fa0a/matchers/have_key_with_value_matcher_test.go000066400000000000000000000056761276516347700275710ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("HaveKeyWithValue", func() { var ( stringKeys map[string]int intKeys map[int]string objKeys map[*myCustomType]*myCustomType customA *myCustomType customB *myCustomType ) BeforeEach(func() { stringKeys = map[string]int{"foo": 2, "bar": 3} intKeys = map[int]string{2: "foo", 3: "bar"} customA = &myCustomType{s: "a", n: 2, f: 2.3, arr: []string{"ice", "cream"}} customB = &myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"cake"}} objKeys = map[*myCustomType]*myCustomType{customA: customA, customB: customA} }) Context("when passed a map", func() { It("should do the right thing", func() { Ω(stringKeys).Should(HaveKeyWithValue("foo", 2)) Ω(stringKeys).ShouldNot(HaveKeyWithValue("foo", 1)) Ω(stringKeys).ShouldNot(HaveKeyWithValue("baz", 2)) Ω(stringKeys).ShouldNot(HaveKeyWithValue("baz", 1)) Ω(intKeys).Should(HaveKeyWithValue(2, "foo")) Ω(intKeys).ShouldNot(HaveKeyWithValue(4, "foo")) Ω(intKeys).ShouldNot(HaveKeyWithValue(2, "baz")) Ω(objKeys).Should(HaveKeyWithValue(customA, customA)) Ω(objKeys).Should(HaveKeyWithValue(&myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"cake"}}, &myCustomType{s: "a", n: 2, f: 2.3, arr: []string{"ice", "cream"}})) Ω(objKeys).ShouldNot(HaveKeyWithValue(&myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"apple", "pie"}}, customA)) }) }) Context("when passed a correctly typed nil", func() { It("should operate succesfully on the passed in value", func() { var nilMap map[int]string Ω(nilMap).ShouldNot(HaveKeyWithValue("foo", "bar")) }) }) Context("when the passed in key or value is actually a matcher", func() { It("should pass each element through the matcher", func() { Ω(stringKeys).Should(HaveKeyWithValue(ContainSubstring("oo"), 2)) Ω(intKeys).Should(HaveKeyWithValue(2, ContainSubstring("oo"))) Ω(stringKeys).ShouldNot(HaveKeyWithValue(ContainSubstring("foobar"), 2)) }) It("should fail if the matcher ever fails", func() { actual := map[int]string{1: "a", 3: "b", 2: "c"} success, err := (&HaveKeyWithValueMatcher{Key: ContainSubstring("ar"), Value: 2}).Match(actual) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) otherActual := map[string]int{"a": 1, "b": 2, "c": 3} success, err = (&HaveKeyWithValueMatcher{Key: "a", Value: ContainSubstring("1")}).Match(otherActual) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) Context("when passed something that is not a map", func() { It("should error", func() { success, err := (&HaveKeyWithValueMatcher{Key: "foo", Value: "bar"}).Match([]string{"foo"}) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&HaveKeyWithValueMatcher{Key: "foo", Value: "bar"}).Match(nil) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/have_len_matcher.go000066400000000000000000000014221276516347700242520ustar00rootroot00000000000000package matchers import ( "fmt" "github.com/onsi/gomega/format" ) type HaveLenMatcher struct { Count int } func (matcher *HaveLenMatcher) Match(actual interface{}) (success bool, err error) { length, ok := lengthOf(actual) if !ok { return false, fmt.Errorf("HaveLen matcher expects a string/array/map/channel/slice. Got:\n%s", format.Object(actual, 1)) } return length == matcher.Count, nil } func (matcher *HaveLenMatcher) FailureMessage(actual interface{}) (message string) { return fmt.Sprintf("Expected\n%s\nto have length %d", format.Object(actual, 1), matcher.Count) } func (matcher *HaveLenMatcher) NegatedFailureMessage(actual interface{}) (message string) { return fmt.Sprintf("Expected\n%s\nnot to have length %d", format.Object(actual, 1), matcher.Count) } golang-gomega-1.0+git20160910.d59fa0a/matchers/have_len_matcher_test.go000066400000000000000000000024251276516347700253150ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("HaveLen", func() { Context("when passed a supported type", func() { It("should do the right thing", func() { Ω("").Should(HaveLen(0)) Ω("AA").Should(HaveLen(2)) Ω([0]int{}).Should(HaveLen(0)) Ω([2]int{1, 2}).Should(HaveLen(2)) Ω([]int{}).Should(HaveLen(0)) Ω([]int{1, 2, 3}).Should(HaveLen(3)) Ω(map[string]int{}).Should(HaveLen(0)) Ω(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4}).Should(HaveLen(4)) c := make(chan bool, 3) Ω(c).Should(HaveLen(0)) c <- true c <- true Ω(c).Should(HaveLen(2)) }) }) Context("when passed a correctly typed nil", func() { It("should operate succesfully on the passed in value", func() { var nilSlice []int Ω(nilSlice).Should(HaveLen(0)) var nilMap map[int]string Ω(nilMap).Should(HaveLen(0)) }) }) Context("when passed an unsupported type", func() { It("should error", func() { success, err := (&HaveLenMatcher{Count: 0}).Match(0) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&HaveLenMatcher{Count: 0}).Match(nil) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/have_occurred_matcher.go000066400000000000000000000016311276516347700253040ustar00rootroot00000000000000package matchers import ( "fmt" "github.com/onsi/gomega/format" ) type HaveOccurredMatcher struct { } func (matcher *HaveOccurredMatcher) Match(actual interface{}) (success bool, err error) { // is purely nil? if actual == nil { return false, nil } // must be an 'error' type if !isError(actual) { return false, fmt.Errorf("Expected an error-type. Got:\n%s", format.Object(actual, 1)) } // must be non-nil (or a pointer to a non-nil) return !isNil(actual), nil } func (matcher *HaveOccurredMatcher) FailureMessage(actual interface{}) (message string) { return fmt.Sprintf("Expected an error to have occurred. Got:\n%s", format.Object(actual, 1)) } func (matcher *HaveOccurredMatcher) NegatedFailureMessage(actual interface{}) (message string) { return fmt.Sprintf("Expected error:\n%s\n%s\n%s", format.Object(actual, 1), format.IndentString(actual.(error).Error(), 1), "not to have occurred") } golang-gomega-1.0+git20160910.d59fa0a/matchers/have_occurred_matcher_test.go000066400000000000000000000030641276516347700263450ustar00rootroot00000000000000package matchers_test import ( "errors" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) type CustomErr struct { msg string } func (e *CustomErr) Error() string { return e.msg } var _ = Describe("HaveOccurred", func() { It("should succeed if matching an error", func() { Ω(errors.New("Foo")).Should(HaveOccurred()) }) It("should not succeed with nil", func() { Ω(nil).ShouldNot(HaveOccurred()) }) It("should only support errors and nil", func() { success, err := (&HaveOccurredMatcher{}).Match("foo") Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&HaveOccurredMatcher{}).Match("") Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) It("doesn't support non-error type", func() { success, err := (&HaveOccurredMatcher{}).Match(AnyType{}) Ω(success).Should(BeFalse()) Ω(err).Should(MatchError("Expected an error-type. Got:\n : {}")) }) It("doesn't support non-error pointer type", func() { success, err := (&HaveOccurredMatcher{}).Match(&AnyType{}) Ω(success).Should(BeFalse()) Ω(err).Should(MatchError(MatchRegexp(`Expected an error-type. Got:\n <*matchers_test.AnyType | 0x[[:xdigit:]]+>: {}`))) }) It("should succeed with pointer types that conform to error interface", func() { err := &CustomErr{"ohai"} Ω(err).Should(HaveOccurred()) }) It("should not succeed with nil pointers to types that conform to error interface", func() { var err *CustomErr = nil Ω(err).ShouldNot(HaveOccurred()) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/have_prefix_matcher.go000066400000000000000000000017541276516347700250010ustar00rootroot00000000000000package matchers import ( "fmt" "github.com/onsi/gomega/format" ) type HavePrefixMatcher struct { Prefix string Args []interface{} } func (matcher *HavePrefixMatcher) Match(actual interface{}) (success bool, err error) { actualString, ok := toString(actual) if !ok { return false, fmt.Errorf("HavePrefix matcher requires a string or stringer. Got:\n%s", format.Object(actual, 1)) } prefix := matcher.prefix() return len(actualString) >= len(prefix) && actualString[0:len(prefix)] == prefix, nil } func (matcher *HavePrefixMatcher) prefix() string { if len(matcher.Args) > 0 { return fmt.Sprintf(matcher.Prefix, matcher.Args...) } return matcher.Prefix } func (matcher *HavePrefixMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, "to have prefix", matcher.prefix()) } func (matcher *HavePrefixMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, "not to have prefix", matcher.prefix()) } golang-gomega-1.0+git20160910.d59fa0a/matchers/have_prefix_matcher_test.go000066400000000000000000000017121276516347700260320ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("HavePrefixMatcher", func() { Context("when actual is a string", func() { It("should match a string prefix", func() { Ω("Ab").Should(HavePrefix("A")) Ω("A").ShouldNot(HavePrefix("Ab")) }) }) Context("when the matcher is called with multiple arguments", func() { It("should pass the string and arguments to sprintf", func() { Ω("C3PO").Should(HavePrefix("C%dP", 3)) }) }) Context("when actual is a stringer", func() { It("should call the stringer and match against the returned string", func() { Ω(&myStringer{a: "Ab"}).Should(HavePrefix("A")) }) }) Context("when actual is neither a string nor a stringer", func() { It("should error", func() { success, err := (&HavePrefixMatcher{Prefix: "2"}).Match(2) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/have_suffix_matcher.go000066400000000000000000000017751276516347700250130ustar00rootroot00000000000000package matchers import ( "fmt" "github.com/onsi/gomega/format" ) type HaveSuffixMatcher struct { Suffix string Args []interface{} } func (matcher *HaveSuffixMatcher) Match(actual interface{}) (success bool, err error) { actualString, ok := toString(actual) if !ok { return false, fmt.Errorf("HaveSuffix matcher requires a string or stringer. Got:\n%s", format.Object(actual, 1)) } suffix := matcher.suffix() return len(actualString) >= len(suffix) && actualString[len(actualString)-len(suffix):] == suffix, nil } func (matcher *HaveSuffixMatcher) suffix() string { if len(matcher.Args) > 0 { return fmt.Sprintf(matcher.Suffix, matcher.Args...) } return matcher.Suffix } func (matcher *HaveSuffixMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, "to have suffix", matcher.suffix()) } func (matcher *HaveSuffixMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, "not to have suffix", matcher.suffix()) } golang-gomega-1.0+git20160910.d59fa0a/matchers/have_suffix_matcher_test.go000066400000000000000000000017121276516347700260410ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("HaveSuffixMatcher", func() { Context("when actual is a string", func() { It("should match a string suffix", func() { Ω("Ab").Should(HaveSuffix("b")) Ω("A").ShouldNot(HaveSuffix("Ab")) }) }) Context("when the matcher is called with multiple arguments", func() { It("should pass the string and arguments to sprintf", func() { Ω("C3PO").Should(HaveSuffix("%dPO", 3)) }) }) Context("when actual is a stringer", func() { It("should call the stringer and match against the returned string", func() { Ω(&myStringer{a: "Ab"}).Should(HaveSuffix("b")) }) }) Context("when actual is neither a string nor a stringer", func() { It("should error", func() { success, err := (&HaveSuffixMatcher{Suffix: "2"}).Match(2) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/match_error_matcher.go000066400000000000000000000025201276516347700247760ustar00rootroot00000000000000package matchers import ( "fmt" "github.com/onsi/gomega/format" "reflect" ) type MatchErrorMatcher struct { Expected interface{} } func (matcher *MatchErrorMatcher) Match(actual interface{}) (success bool, err error) { if isNil(actual) { return false, fmt.Errorf("Expected an error, got nil") } if !isError(actual) { return false, fmt.Errorf("Expected an error. Got:\n%s", format.Object(actual, 1)) } actualErr := actual.(error) if isString(matcher.Expected) { return reflect.DeepEqual(actualErr.Error(), matcher.Expected), nil } if isError(matcher.Expected) { return reflect.DeepEqual(actualErr, matcher.Expected), nil } var subMatcher omegaMatcher var hasSubMatcher bool if matcher.Expected != nil { subMatcher, hasSubMatcher = (matcher.Expected).(omegaMatcher) if hasSubMatcher { return subMatcher.Match(actualErr.Error()) } } return false, fmt.Errorf("MatchError must be passed an error, string, or Matcher that can match on strings. Got:\n%s", format.Object(matcher.Expected, 1)) } func (matcher *MatchErrorMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, "to match error", matcher.Expected) } func (matcher *MatchErrorMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, "not to match error", matcher.Expected) } golang-gomega-1.0+git20160910.d59fa0a/matchers/match_error_matcher_test.go000066400000000000000000000044071276516347700260430ustar00rootroot00000000000000package matchers_test import ( "errors" "fmt" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) type CustomError struct { } func (c CustomError) Error() string { return "an error" } var _ = Describe("MatchErrorMatcher", func() { Context("When asserting against an error", func() { It("should succeed when matching with an error", func() { err := errors.New("an error") fmtErr := fmt.Errorf("an error") customErr := CustomError{} Ω(err).Should(MatchError(errors.New("an error"))) Ω(err).ShouldNot(MatchError(errors.New("another error"))) Ω(fmtErr).Should(MatchError(errors.New("an error"))) Ω(customErr).Should(MatchError(CustomError{})) }) It("should succeed when matching with a string", func() { err := errors.New("an error") fmtErr := fmt.Errorf("an error") customErr := CustomError{} Ω(err).Should(MatchError("an error")) Ω(err).ShouldNot(MatchError("another error")) Ω(fmtErr).Should(MatchError("an error")) Ω(customErr).Should(MatchError("an error")) }) Context("when passed a matcher", func() { It("should pass if the matcher passes against the error string", func() { err := errors.New("error 123 abc") Ω(err).Should(MatchError(MatchRegexp(`\d{3}`))) }) It("should fail if the matcher fails against the error string", func() { err := errors.New("no digits") Ω(err).ShouldNot(MatchError(MatchRegexp(`\d`))) }) }) It("should fail when passed anything else", func() { actualErr := errors.New("an error") _, err := (&MatchErrorMatcher{ Expected: []byte("an error"), }).Match(actualErr) Ω(err).Should(HaveOccurred()) _, err = (&MatchErrorMatcher{ Expected: 3, }).Match(actualErr) Ω(err).Should(HaveOccurred()) }) }) Context("when passed nil", func() { It("should fail", func() { _, err := (&MatchErrorMatcher{ Expected: "an error", }).Match(nil) Ω(err).Should(HaveOccurred()) }) }) Context("when passed a non-error", func() { It("should fail", func() { _, err := (&MatchErrorMatcher{ Expected: "an error", }).Match("an error") Ω(err).Should(HaveOccurred()) _, err = (&MatchErrorMatcher{ Expected: "an error", }).Match(3) Ω(err).Should(HaveOccurred()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/match_json_matcher.go000066400000000000000000000040411276516347700246160ustar00rootroot00000000000000package matchers import ( "bytes" "encoding/json" "fmt" "reflect" "github.com/onsi/gomega/format" ) type MatchJSONMatcher struct { JSONToMatch interface{} } func (matcher *MatchJSONMatcher) Match(actual interface{}) (success bool, err error) { actualString, expectedString, err := matcher.prettyPrint(actual) if err != nil { return false, err } var aval interface{} var eval interface{} // this is guarded by prettyPrint json.Unmarshal([]byte(actualString), &aval) json.Unmarshal([]byte(expectedString), &eval) return reflect.DeepEqual(aval, eval), nil } func (matcher *MatchJSONMatcher) FailureMessage(actual interface{}) (message string) { actualString, expectedString, _ := matcher.prettyPrint(actual) return format.Message(actualString, "to match JSON of", expectedString) } func (matcher *MatchJSONMatcher) NegatedFailureMessage(actual interface{}) (message string) { actualString, expectedString, _ := matcher.prettyPrint(actual) return format.Message(actualString, "not to match JSON of", expectedString) } func (matcher *MatchJSONMatcher) prettyPrint(actual interface{}) (actualFormatted, expectedFormatted string, err error) { actualString, ok := toString(actual) if !ok { return "", "", fmt.Errorf("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got actual:\n%s", format.Object(actual, 1)) } expectedString, ok := toString(matcher.JSONToMatch) if !ok { return "", "", fmt.Errorf("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got expected:\n%s", format.Object(matcher.JSONToMatch, 1)) } abuf := new(bytes.Buffer) ebuf := new(bytes.Buffer) if err := json.Indent(abuf, []byte(actualString), "", " "); err != nil { return "", "", fmt.Errorf("Actual '%s' should be valid JSON, but it is not.\nUnderlying error:%s", actualString, err) } if err := json.Indent(ebuf, []byte(expectedString), "", " "); err != nil { return "", "", fmt.Errorf("Expected '%s' should be valid JSON, but it is not.\nUnderlying error:%s", expectedString, err) } return abuf.String(), ebuf.String(), nil } golang-gomega-1.0+git20160910.d59fa0a/matchers/match_json_matcher_test.go000066400000000000000000000053401276516347700256600ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("MatchJSONMatcher", func() { Context("When passed stringifiables", func() { It("should succeed if the JSON matches", func() { Ω("{}").Should(MatchJSON("{}")) Ω(`{"a":1}`).Should(MatchJSON(`{"a":1}`)) Ω(`{ "a":1 }`).Should(MatchJSON(`{"a":1}`)) Ω(`{"a":1, "b":2}`).Should(MatchJSON(`{"b":2, "a":1}`)) Ω(`{"a":1}`).ShouldNot(MatchJSON(`{"b":2, "a":1}`)) }) It("should work with byte arrays", func() { Ω([]byte("{}")).Should(MatchJSON([]byte("{}"))) Ω("{}").Should(MatchJSON([]byte("{}"))) Ω([]byte("{}")).Should(MatchJSON("{}")) }) }) Context("when the expected is not valid JSON", func() { It("should error and explain why", func() { success, err := (&MatchJSONMatcher{JSONToMatch: `{}`}).Match(`oops`) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) Ω(err.Error()).Should(ContainSubstring("Actual 'oops' should be valid JSON")) }) }) Context("when the actual is not valid JSON", func() { It("should error and explain why", func() { success, err := (&MatchJSONMatcher{JSONToMatch: `oops`}).Match(`{}`) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) Ω(err.Error()).Should(ContainSubstring("Expected 'oops' should be valid JSON")) }) }) Context("when the expected is neither a string nor a stringer nor a byte array", func() { It("should error", func() { success, err := (&MatchJSONMatcher{JSONToMatch: 2}).Match("{}") Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) Ω(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got expected:\n : 2")) success, err = (&MatchJSONMatcher{JSONToMatch: nil}).Match("{}") Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) Ω(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got expected:\n : nil")) }) }) Context("when the actual is neither a string nor a stringer nor a byte array", func() { It("should error", func() { success, err := (&MatchJSONMatcher{JSONToMatch: "{}"}).Match(2) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) Ω(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got actual:\n : 2")) success, err = (&MatchJSONMatcher{JSONToMatch: "{}"}).Match(nil) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) Ω(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got actual:\n : nil")) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/match_regexp_matcher.go000066400000000000000000000021551276516347700251430ustar00rootroot00000000000000package matchers import ( "fmt" "github.com/onsi/gomega/format" "regexp" ) type MatchRegexpMatcher struct { Regexp string Args []interface{} } func (matcher *MatchRegexpMatcher) Match(actual interface{}) (success bool, err error) { actualString, ok := toString(actual) if !ok { return false, fmt.Errorf("RegExp matcher requires a string or stringer.\nGot:%s", format.Object(actual, 1)) } match, err := regexp.Match(matcher.regexp(), []byte(actualString)) if err != nil { return false, fmt.Errorf("RegExp match failed to compile with error:\n\t%s", err.Error()) } return match, nil } func (matcher *MatchRegexpMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, "to match regular expression", matcher.regexp()) } func (matcher *MatchRegexpMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, "not to match regular expression", matcher.regexp()) } func (matcher *MatchRegexpMatcher) regexp() string { re := matcher.Regexp if len(matcher.Args) > 0 { re = fmt.Sprintf(matcher.Regexp, matcher.Args...) } return re } golang-gomega-1.0+git20160910.d59fa0a/matchers/match_regexp_matcher_test.go000066400000000000000000000023351276516347700262020ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("MatchRegexp", func() { Context("when actual is a string", func() { It("should match against the string", func() { Ω(" a2!bla").Should(MatchRegexp(`\d!`)) Ω(" a2!bla").ShouldNot(MatchRegexp(`[A-Z]`)) }) }) Context("when actual is a stringer", func() { It("should call the stringer and match agains the returned string", func() { Ω(&myStringer{a: "Abc3"}).Should(MatchRegexp(`[A-Z][a-z]+\d`)) }) }) Context("when the matcher is called with multiple arguments", func() { It("should pass the string and arguments to sprintf", func() { Ω(" a23!bla").Should(MatchRegexp(`\d%d!`, 3)) }) }) Context("when actual is neither a string nor a stringer", func() { It("should error", func() { success, err := (&MatchRegexpMatcher{Regexp: `\d`}).Match(2) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) Context("when the passed in regexp fails to compile", func() { It("should error", func() { success, err := (&MatchRegexpMatcher{Regexp: "("}).Match("Foo") Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/match_yaml_matcher.go000066400000000000000000000046251276516347700246170ustar00rootroot00000000000000package matchers import ( "fmt" "reflect" "strings" "github.com/onsi/gomega/format" "gopkg.in/yaml.v2" ) type MatchYAMLMatcher struct { YAMLToMatch interface{} } func (matcher *MatchYAMLMatcher) Match(actual interface{}) (success bool, err error) { actualString, expectedString, err := matcher.toStrings(actual) if err != nil { return false, err } var aval interface{} var eval interface{} if err := yaml.Unmarshal([]byte(actualString), &aval); err != nil { return false, fmt.Errorf("Actual '%s' should be valid YAML, but it is not.\nUnderlying error:%s", actualString, err) } if err := yaml.Unmarshal([]byte(expectedString), &eval); err != nil { return false, fmt.Errorf("Expected '%s' should be valid YAML, but it is not.\nUnderlying error:%s", expectedString, err) } return reflect.DeepEqual(aval, eval), nil } func (matcher *MatchYAMLMatcher) FailureMessage(actual interface{}) (message string) { actualString, expectedString, _ := matcher.toNormalisedStrings(actual) return format.Message(actualString, "to match YAML of", expectedString) } func (matcher *MatchYAMLMatcher) NegatedFailureMessage(actual interface{}) (message string) { actualString, expectedString, _ := matcher.toNormalisedStrings(actual) return format.Message(actualString, "not to match YAML of", expectedString) } func (matcher *MatchYAMLMatcher) toNormalisedStrings(actual interface{}) (actualFormatted, expectedFormatted string, err error) { actualString, expectedString, err := matcher.toStrings(actual) return normalise(actualString), normalise(expectedString), err } func normalise(input string) string { var val interface{} err := yaml.Unmarshal([]byte(input), &val) if err != nil { panic(err) // guarded by Match } output, err := yaml.Marshal(val) if err != nil { panic(err) // guarded by Unmarshal } return strings.TrimSpace(string(output)) } func (matcher *MatchYAMLMatcher) toStrings(actual interface{}) (actualFormatted, expectedFormatted string, err error) { actualString, ok := toString(actual) if !ok { return "", "", fmt.Errorf("MatchYAMLMatcher matcher requires a string, stringer, or []byte. Got actual:\n%s", format.Object(actual, 1)) } expectedString, ok := toString(matcher.YAMLToMatch) if !ok { return "", "", fmt.Errorf("MatchYAMLMatcher matcher requires a string, stringer, or []byte. Got expected:\n%s", format.Object(matcher.YAMLToMatch, 1)) } return actualString, expectedString, nil } golang-gomega-1.0+git20160910.d59fa0a/matchers/match_yaml_matcher_test.go000066400000000000000000000077101276516347700256540ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("MatchYAMLMatcher", func() { Context("When passed stringifiables", func() { It("should succeed if the YAML matches", func() { Expect("---").Should(MatchYAML("")) Expect("a: 1").Should(MatchYAML(`{"a":1}`)) Expect("a: 1\nb: 2").Should(MatchYAML(`{"b":2, "a":1}`)) }) It("should explain if the YAML does not match when it should", func() { message := (&MatchYAMLMatcher{YAMLToMatch: "a: 1"}).FailureMessage("b: 2") Expect(message).To(MatchRegexp(`Expected\s+: b: 2\s+to match YAML of\s+: a: 1`)) }) It("should normalise the expected and actual when explaining if the YAML does not match when it should", func() { message := (&MatchYAMLMatcher{YAMLToMatch: "a: 'one'"}).FailureMessage("{b: two}") Expect(message).To(MatchRegexp(`Expected\s+: b: two\s+to match YAML of\s+: a: one`)) }) It("should explain if the YAML matches when it should not", func() { message := (&MatchYAMLMatcher{YAMLToMatch: "a: 1"}).NegatedFailureMessage("a: 1") Expect(message).To(MatchRegexp(`Expected\s+: a: 1\s+not to match YAML of\s+: a: 1`)) }) It("should normalise the expected and actual when explaining if the YAML matches when it should not", func() { message := (&MatchYAMLMatcher{YAMLToMatch: "a: 'one'"}).NegatedFailureMessage("{a: one}") Expect(message).To(MatchRegexp(`Expected\s+: a: one\s+not to match YAML of\s+: a: one`)) }) It("should fail if the YAML does not match", func() { Expect("a: 1").ShouldNot(MatchYAML(`{"b":2, "a":1}`)) }) It("should work with byte arrays", func() { Expect([]byte("a: 1")).Should(MatchYAML([]byte("a: 1"))) Expect("a: 1").Should(MatchYAML([]byte("a: 1"))) Expect([]byte("a: 1")).Should(MatchYAML("a: 1")) }) }) Context("when the expected is not valid YAML", func() { It("should error and explain why", func() { success, err := (&MatchYAMLMatcher{YAMLToMatch: ""}).Match("good:\nbad") Expect(success).Should(BeFalse()) Expect(err).Should(HaveOccurred()) Expect(err.Error()).Should(ContainSubstring("Actual 'good:\nbad' should be valid YAML")) }) }) Context("when the actual is not valid YAML", func() { It("should error and explain why", func() { success, err := (&MatchYAMLMatcher{YAMLToMatch: "good:\nbad"}).Match("") Expect(success).Should(BeFalse()) Expect(err).Should(HaveOccurred()) Expect(err.Error()).Should(ContainSubstring("Expected 'good:\nbad' should be valid YAML")) }) }) Context("when the expected is neither a string nor a stringer nor a byte array", func() { It("should error", func() { success, err := (&MatchYAMLMatcher{YAMLToMatch: 2}).Match("") Expect(success).Should(BeFalse()) Expect(err).Should(HaveOccurred()) Expect(err.Error()).Should(ContainSubstring("MatchYAMLMatcher matcher requires a string, stringer, or []byte. Got expected:\n : 2")) success, err = (&MatchYAMLMatcher{YAMLToMatch: nil}).Match("") Expect(success).Should(BeFalse()) Expect(err).Should(HaveOccurred()) Expect(err.Error()).Should(ContainSubstring("MatchYAMLMatcher matcher requires a string, stringer, or []byte. Got expected:\n : nil")) }) }) Context("when the actual is neither a string nor a stringer nor a byte array", func() { It("should error", func() { success, err := (&MatchYAMLMatcher{YAMLToMatch: ""}).Match(2) Expect(success).Should(BeFalse()) Expect(err).Should(HaveOccurred()) Expect(err.Error()).Should(ContainSubstring("MatchYAMLMatcher matcher requires a string, stringer, or []byte. Got actual:\n : 2")) success, err = (&MatchYAMLMatcher{YAMLToMatch: ""}).Match(nil) Expect(success).Should(BeFalse()) Expect(err).Should(HaveOccurred()) Expect(err.Error()).Should(ContainSubstring("MatchYAMLMatcher matcher requires a string, stringer, or []byte. Got actual:\n : nil")) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/matcher_tests_suite_test.go000066400000000000000000000006011276516347700261010ustar00rootroot00000000000000package matchers_test import ( "testing" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) type myStringer struct { a string } func (s *myStringer) String() string { return s.a } type StringAlias string type myCustomType struct { s string n int f float32 arr []string } func Test(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Gomega Matchers") } golang-gomega-1.0+git20160910.d59fa0a/matchers/not.go000066400000000000000000000014471276516347700215750ustar00rootroot00000000000000package matchers import ( "github.com/onsi/gomega/internal/oraclematcher" "github.com/onsi/gomega/types" ) type NotMatcher struct { Matcher types.GomegaMatcher } func (m *NotMatcher) Match(actual interface{}) (bool, error) { success, err := m.Matcher.Match(actual) if err != nil { return false, err } return !success, nil } func (m *NotMatcher) FailureMessage(actual interface{}) (message string) { return m.Matcher.NegatedFailureMessage(actual) // works beautifully } func (m *NotMatcher) NegatedFailureMessage(actual interface{}) (message string) { return m.Matcher.FailureMessage(actual) // works beautifully } func (m *NotMatcher) MatchMayChangeInTheFuture(actual interface{}) bool { return oraclematcher.MatchMayChangeInTheFuture(m.Matcher, actual) // just return m.Matcher's value } golang-gomega-1.0+git20160910.d59fa0a/matchers/not_test.go000066400000000000000000000033371276516347700226340ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("NotMatcher", func() { Context("basic examples", func() { It("works", func() { Expect(input).To(Not(false1)) Expect(input).To(Not(Not(true2))) Expect(input).ToNot(Not(true3)) Expect(input).ToNot(Not(Not(false1))) Expect(input).To(Not(Not(Not(false2)))) }) }) Context("De Morgan's laws", func() { It("~(A && B) == ~A || ~B", func() { Expect(input).To(Not(And(false1, false2))) Expect(input).To(Or(Not(false1), Not(false2))) }) It("~(A || B) == ~A && ~B", func() { Expect(input).To(Not(Or(false1, false2))) Expect(input).To(And(Not(false1), Not(false2))) }) }) Context("failure messages are opposite of original matchers' failure messages", func() { Context("when match fails", func() { It("gives a descriptive message", func() { verifyFailureMessage(Not(HaveLen(2)), input, "not to have length 2") }) }) Context("when match succeeds, but expected it to fail", func() { It("gives a descriptive message", func() { verifyFailureMessage(Not(Not(HaveLen(3))), input, "to have length 3") }) }) }) Context("MatchMayChangeInTheFuture()", func() { It("Propagates value from wrapped matcher", func() { m := Not(Or()) // an empty Or() always returns false, and indicates it cannot change Expect(m.Match("anything")).To(BeTrue()) Expect(m.(*NotMatcher).MatchMayChangeInTheFuture("anything")).To(BeFalse()) }) It("Defaults to true", func() { m := Not(Equal(1)) // Equal does not have this method Expect(m.Match(2)).To(BeTrue()) Expect(m.(*NotMatcher).MatchMayChangeInTheFuture(2)).To(BeTrue()) // defaults to true }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/or.go000066400000000000000000000036621276516347700214160ustar00rootroot00000000000000package matchers import ( "fmt" "github.com/onsi/gomega/format" "github.com/onsi/gomega/internal/oraclematcher" "github.com/onsi/gomega/types" ) type OrMatcher struct { Matchers []types.GomegaMatcher // state firstSuccessfulMatcher types.GomegaMatcher } func (m *OrMatcher) Match(actual interface{}) (success bool, err error) { m.firstSuccessfulMatcher = nil for _, matcher := range m.Matchers { success, err := matcher.Match(actual) if err != nil { return false, err } if success { m.firstSuccessfulMatcher = matcher return true, nil } } return false, nil } func (m *OrMatcher) FailureMessage(actual interface{}) (message string) { // not the most beautiful list of matchers, but not bad either... return format.Message(actual, fmt.Sprintf("To satisfy at least one of these matchers: %s", m.Matchers)) } func (m *OrMatcher) NegatedFailureMessage(actual interface{}) (message string) { return m.firstSuccessfulMatcher.NegatedFailureMessage(actual) } func (m *OrMatcher) MatchMayChangeInTheFuture(actual interface{}) bool { /* Example with 3 matchers: A, B, C Match evaluates them: F, T, => T So match is currently T, what should MatchMayChangeInTheFuture() return? Seems like it only depends on B, since currently B MUST change to allow the result to become F Match eval: F, F, F => F So match is currently F, what should MatchMayChangeInTheFuture() return? Seems to depend on ANY of them being able to change to T. */ if m.firstSuccessfulMatcher != nil { // one of the matchers succeeded.. it must be able to change in order to affect the result return oraclematcher.MatchMayChangeInTheFuture(m.firstSuccessfulMatcher, actual) } else { // so all matchers failed.. Any one of them changing would change the result. for _, matcher := range m.Matchers { if oraclematcher.MatchMayChangeInTheFuture(matcher, actual) { return true } } return false // none of were going to change } } golang-gomega-1.0+git20160910.d59fa0a/matchers/or_test.go000066400000000000000000000063011276516347700224460ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("OrMatcher", func() { It("works with positive cases", func() { Expect(input).To(Or(true1)) Expect(input).To(Or(true1, true2)) Expect(input).To(Or(true1, false1)) Expect(input).To(Or(false1, true2)) Expect(input).To(Or(true1, true2, true3)) Expect(input).To(Or(true1, true2, false3)) Expect(input).To(Or(true1, false2, true3)) Expect(input).To(Or(false1, true2, true3)) Expect(input).To(Or(true1, false2, false3)) Expect(input).To(Or(false1, false2, true3)) // use alias Expect(input).To(SatisfyAny(false1, false2, true3)) }) It("works with negative cases", func() { Expect(input).ToNot(Or()) Expect(input).ToNot(Or(false1)) Expect(input).ToNot(Or(false1, false2)) Expect(input).ToNot(Or(false1, false2, false3)) }) Context("failure messages", func() { Context("when match fails", func() { It("gives a descriptive message", func() { verifyFailureMessage(Or(false1, false2), input, "To satisfy at least one of these matchers: [%!s(*matchers.HaveLenMatcher=&{1}) %!s(*matchers.EqualMatcher=&{hip})]") }) }) Context("when match succeeds, but expected it to fail", func() { It("gives a descriptive message", func() { verifyFailureMessage(Not(Or(true1, true2)), input, `not to have length 2`) }) }) }) Context("MatchMayChangeInTheFuture", func() { Context("Match returned false", func() { It("returns true if any of the matchers could change", func() { // 3 matchers, all return false, and all could change m := Or(BeNil(), Equal("hip"), HaveLen(1)) Expect(m.Match("hi")).To(BeFalse()) Expect(m.(*OrMatcher).MatchMayChangeInTheFuture("hi")).To(BeTrue()) // all 3 of these matchers default to 'true' }) It("returns false if none of the matchers could change", func() { // empty Or() has the property of never matching, and never can change since there are no sub-matchers that could change m := Or() Expect(m.Match("anything")).To(BeFalse()) Expect(m.(*OrMatcher).MatchMayChangeInTheFuture("anything")).To(BeFalse()) // Or() with 3 sub-matchers that return false, and can't change m = Or(Or(), Or(), Or()) Expect(m.Match("hi")).To(BeFalse()) Expect(m.(*OrMatcher).MatchMayChangeInTheFuture("hi")).To(BeFalse()) // the 3 empty Or()'s won't change }) }) Context("Match returned true", func() { Context("returns value of the successful matcher", func() { It("false if successful matcher not going to change", func() { // 3 matchers: 1st returns false, 2nd returns true and is not going to change, 3rd is never called m := Or(BeNil(), And(), Equal(1)) Expect(m.Match("hi")).To(BeTrue()) Expect(m.(*OrMatcher).MatchMayChangeInTheFuture("hi")).To(BeFalse()) }) It("true if successful matcher indicates it might change", func() { // 3 matchers: 1st returns false, 2nd returns true and "might" change, 3rd is never called m := Or(Not(BeNil()), Equal("hi"), Equal(1)) Expect(m.Match("hi")).To(BeTrue()) Expect(m.(*OrMatcher).MatchMayChangeInTheFuture("hi")).To(BeTrue()) // Equal("hi") indicates it might change }) }) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/panic_matcher.go000066400000000000000000000021011276516347700235560ustar00rootroot00000000000000package matchers import ( "fmt" "github.com/onsi/gomega/format" "reflect" ) type PanicMatcher struct{} func (matcher *PanicMatcher) Match(actual interface{}) (success bool, err error) { if actual == nil { return false, fmt.Errorf("PanicMatcher expects a non-nil actual.") } actualType := reflect.TypeOf(actual) if actualType.Kind() != reflect.Func { return false, fmt.Errorf("PanicMatcher expects a function. Got:\n%s", format.Object(actual, 1)) } if !(actualType.NumIn() == 0 && actualType.NumOut() == 0) { return false, fmt.Errorf("PanicMatcher expects a function with no arguments and no return value. Got:\n%s", format.Object(actual, 1)) } success = false defer func() { if e := recover(); e != nil { success = true } }() reflect.ValueOf(actual).Call([]reflect.Value{}) return } func (matcher *PanicMatcher) FailureMessage(actual interface{}) (message string) { return format.Message(actual, "to panic") } func (matcher *PanicMatcher) NegatedFailureMessage(actual interface{}) (message string) { return format.Message(actual, "not to panic") } golang-gomega-1.0+git20160910.d59fa0a/matchers/panic_matcher_test.go000066400000000000000000000020351276516347700246230ustar00rootroot00000000000000package matchers_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("Panic", func() { Context("when passed something that's not a function that takes zero arguments and returns nothing", func() { It("should error", func() { success, err := (&PanicMatcher{}).Match("foo") Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&PanicMatcher{}).Match(nil) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&PanicMatcher{}).Match(func(foo string) {}) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&PanicMatcher{}).Match(func() string { return "bar" }) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) Context("when passed a function of the correct type", func() { It("should call the function and pass if the function panics", func() { Ω(func() { panic("ack!") }).Should(Panic()) Ω(func() {}).ShouldNot(Panic()) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/receive_matcher.go000066400000000000000000000063621276516347700241230ustar00rootroot00000000000000package matchers import ( "fmt" "reflect" "github.com/onsi/gomega/format" ) type ReceiveMatcher struct { Arg interface{} receivedValue reflect.Value channelClosed bool } func (matcher *ReceiveMatcher) Match(actual interface{}) (success bool, err error) { if !isChan(actual) { return false, fmt.Errorf("ReceiveMatcher expects a channel. Got:\n%s", format.Object(actual, 1)) } channelType := reflect.TypeOf(actual) channelValue := reflect.ValueOf(actual) if channelType.ChanDir() == reflect.SendDir { return false, fmt.Errorf("ReceiveMatcher matcher cannot be passed a send-only channel. Got:\n%s", format.Object(actual, 1)) } var subMatcher omegaMatcher var hasSubMatcher bool if matcher.Arg != nil { subMatcher, hasSubMatcher = (matcher.Arg).(omegaMatcher) if !hasSubMatcher { argType := reflect.TypeOf(matcher.Arg) if argType.Kind() != reflect.Ptr { return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nTo:\n%s\nYou need to pass a pointer!", format.Object(actual, 1), format.Object(matcher.Arg, 1)) } assignable := channelType.Elem().AssignableTo(argType.Elem()) if !assignable { return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nTo:\n%s", format.Object(actual, 1), format.Object(matcher.Arg, 1)) } } } winnerIndex, value, open := reflect.Select([]reflect.SelectCase{ reflect.SelectCase{Dir: reflect.SelectRecv, Chan: channelValue}, reflect.SelectCase{Dir: reflect.SelectDefault}, }) var closed bool var didReceive bool if winnerIndex == 0 { closed = !open didReceive = open } matcher.channelClosed = closed if closed { return false, nil } if hasSubMatcher { if didReceive { matcher.receivedValue = value return subMatcher.Match(matcher.receivedValue.Interface()) } else { return false, nil } } if didReceive { if matcher.Arg != nil { outValue := reflect.ValueOf(matcher.Arg) reflect.Indirect(outValue).Set(value) } return true, nil } else { return false, nil } } func (matcher *ReceiveMatcher) FailureMessage(actual interface{}) (message string) { subMatcher, hasSubMatcher := (matcher.Arg).(omegaMatcher) closedAddendum := "" if matcher.channelClosed { closedAddendum = " The channel is closed." } if hasSubMatcher { if matcher.receivedValue.IsValid() { return subMatcher.FailureMessage(matcher.receivedValue.Interface()) } return "When passed a matcher, ReceiveMatcher's channel *must* receive something." } else { return format.Message(actual, "to receive something."+closedAddendum) } } func (matcher *ReceiveMatcher) NegatedFailureMessage(actual interface{}) (message string) { subMatcher, hasSubMatcher := (matcher.Arg).(omegaMatcher) closedAddendum := "" if matcher.channelClosed { closedAddendum = " The channel is closed." } if hasSubMatcher { if matcher.receivedValue.IsValid() { return subMatcher.NegatedFailureMessage(matcher.receivedValue.Interface()) } return "When passed a matcher, ReceiveMatcher's channel *must* receive something." } else { return format.Message(actual, "not to receive anything."+closedAddendum) } } func (matcher *ReceiveMatcher) MatchMayChangeInTheFuture(actual interface{}) bool { if !isChan(actual) { return false } return !matcher.channelClosed } golang-gomega-1.0+git20160910.d59fa0a/matchers/receive_matcher_test.go000066400000000000000000000161071276516347700251600ustar00rootroot00000000000000package matchers_test import ( "time" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) type kungFuActor interface { DrunkenMaster() bool } type jackie struct { name string } func (j *jackie) DrunkenMaster() bool { return true } var _ = Describe("ReceiveMatcher", func() { Context("with no argument", func() { Context("for a buffered channel", func() { It("should succeed", func() { channel := make(chan bool, 1) Ω(channel).ShouldNot(Receive()) channel <- true Ω(channel).Should(Receive()) }) }) Context("for an unbuffered channel", func() { It("should succeed (eventually)", func() { channel := make(chan bool) Ω(channel).ShouldNot(Receive()) go func() { time.Sleep(10 * time.Millisecond) channel <- true }() Eventually(channel).Should(Receive()) }) }) }) Context("with a pointer argument", func() { Context("of the correct type", func() { It("should write the value received on the channel to the pointer", func() { channel := make(chan int, 1) var value int Ω(channel).ShouldNot(Receive(&value)) Ω(value).Should(BeZero()) channel <- 17 Ω(channel).Should(Receive(&value)) Ω(value).Should(Equal(17)) }) }) Context("to various types of objects", func() { It("should work", func() { //channels of strings stringChan := make(chan string, 1) stringChan <- "foo" var s string Ω(stringChan).Should(Receive(&s)) Ω(s).Should(Equal("foo")) //channels of slices sliceChan := make(chan []bool, 1) sliceChan <- []bool{true, true, false} var sl []bool Ω(sliceChan).Should(Receive(&sl)) Ω(sl).Should(Equal([]bool{true, true, false})) //channels of channels chanChan := make(chan chan bool, 1) c := make(chan bool) chanChan <- c var receivedC chan bool Ω(chanChan).Should(Receive(&receivedC)) Ω(receivedC).Should(Equal(c)) //channels of interfaces jackieChan := make(chan kungFuActor, 1) aJackie := &jackie{name: "Jackie Chan"} jackieChan <- aJackie var theJackie kungFuActor Ω(jackieChan).Should(Receive(&theJackie)) Ω(theJackie).Should(Equal(aJackie)) }) }) Context("of the wrong type", func() { It("should error", func() { channel := make(chan int) var incorrectType bool success, err := (&ReceiveMatcher{Arg: &incorrectType}).Match(channel) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) var notAPointer int success, err = (&ReceiveMatcher{Arg: notAPointer}).Match(channel) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) }) Context("with a matcher", func() { It("should defer to the underlying matcher", func() { intChannel := make(chan int, 1) intChannel <- 3 Ω(intChannel).Should(Receive(Equal(3))) intChannel <- 2 Ω(intChannel).ShouldNot(Receive(Equal(3))) stringChannel := make(chan []string, 1) stringChannel <- []string{"foo", "bar", "baz"} Ω(stringChannel).Should(Receive(ContainElement(ContainSubstring("fo")))) stringChannel <- []string{"foo", "bar", "baz"} Ω(stringChannel).ShouldNot(Receive(ContainElement(ContainSubstring("archipelago")))) }) It("should defer to the underlying matcher for the message", func() { matcher := Receive(Equal(3)) channel := make(chan int, 1) channel <- 2 matcher.Match(channel) Ω(matcher.FailureMessage(channel)).Should(MatchRegexp(`Expected\s+: 2\s+to equal\s+: 3`)) channel <- 3 matcher.Match(channel) Ω(matcher.NegatedFailureMessage(channel)).Should(MatchRegexp(`Expected\s+: 3\s+not to equal\s+: 3`)) }) It("should work just fine with Eventually", func() { stringChannel := make(chan string) go func() { time.Sleep(5 * time.Millisecond) stringChannel <- "A" time.Sleep(5 * time.Millisecond) stringChannel <- "B" }() Eventually(stringChannel).Should(Receive(Equal("B"))) }) Context("if the matcher errors", func() { It("should error", func() { channel := make(chan int, 1) channel <- 3 success, err := (&ReceiveMatcher{Arg: ContainSubstring("three")}).Match(channel) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) Context("if nothing is received", func() { It("should fail", func() { channel := make(chan int, 1) success, err := (&ReceiveMatcher{Arg: Equal(1)}).Match(channel) Ω(success).Should(BeFalse()) Ω(err).ShouldNot(HaveOccurred()) }) }) }) Context("When actual is a *closed* channel", func() { Context("for a buffered channel", func() { It("should work until it hits the end of the buffer", func() { channel := make(chan bool, 1) channel <- true close(channel) Ω(channel).Should(Receive()) Ω(channel).ShouldNot(Receive()) }) }) Context("for an unbuffered channel", func() { It("should always fail", func() { channel := make(chan bool) close(channel) Ω(channel).ShouldNot(Receive()) }) }) }) Context("When actual is a send-only channel", func() { It("should error", func() { channel := make(chan bool) var writerChannel chan<- bool writerChannel = channel success, err := (&ReceiveMatcher{}).Match(writerChannel) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) Context("when acutal is a non-channel", func() { It("should error", func() { var nilChannel chan bool success, err := (&ReceiveMatcher{}).Match(nilChannel) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&ReceiveMatcher{}).Match(nil) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) success, err = (&ReceiveMatcher{}).Match(3) Ω(success).Should(BeFalse()) Ω(err).Should(HaveOccurred()) }) }) Describe("when used with eventually and a custom matcher", func() { It("should return the matcher's error when a failing value is received on the channel, instead of the must receive something failure", func() { failures := InterceptGomegaFailures(func() { c := make(chan string, 0) Eventually(c, 0.01).Should(Receive(Equal("hello"))) }) Ω(failures[0]).Should(ContainSubstring("When passed a matcher, ReceiveMatcher's channel *must* receive something.")) failures = InterceptGomegaFailures(func() { c := make(chan string, 1) c <- "hi" Eventually(c, 0.01).Should(Receive(Equal("hello"))) }) Ω(failures[0]).Should(ContainSubstring(": hello")) }) }) Describe("Bailing early", func() { It("should bail early when passed a closed channel", func() { c := make(chan bool) close(c) t := time.Now() failures := InterceptGomegaFailures(func() { Eventually(c).Should(Receive()) }) Ω(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) Ω(failures).Should(HaveLen(1)) }) It("should bail early when passed a non-channel", func() { t := time.Now() failures := InterceptGomegaFailures(func() { Eventually(3).Should(Receive()) }) Ω(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) Ω(failures).Should(HaveLen(1)) }) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/succeed_matcher.go000066400000000000000000000015021276516347700241030ustar00rootroot00000000000000package matchers import ( "fmt" "github.com/onsi/gomega/format" ) type SucceedMatcher struct { } func (matcher *SucceedMatcher) Match(actual interface{}) (success bool, err error) { // is purely nil? if actual == nil { return true, nil } // must be an 'error' type if !isError(actual) { return false, fmt.Errorf("Expected an error-type. Got:\n%s", format.Object(actual, 1)) } // must be nil (or a pointer to a nil) return isNil(actual), nil } func (matcher *SucceedMatcher) FailureMessage(actual interface{}) (message string) { return fmt.Sprintf("Expected success, but got an error:\n%s\n%s", format.Object(actual, 1), format.IndentString(actual.(error).Error(), 1)) } func (matcher *SucceedMatcher) NegatedFailureMessage(actual interface{}) (message string) { return "Expected failure, but got no error." } golang-gomega-1.0+git20160910.d59fa0a/matchers/succeed_matcher_test.go000066400000000000000000000031051276516347700251430ustar00rootroot00000000000000package matchers_test import ( "errors" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) func Erroring() error { return errors.New("bam") } func NotErroring() error { return nil } type AnyType struct{} func Invalid() *AnyType { return nil } var _ = Describe("Succeed", func() { It("should succeed if the function succeeds", func() { Ω(NotErroring()).Should(Succeed()) }) It("should succeed (in the negated) if the function errored", func() { Ω(Erroring()).ShouldNot(Succeed()) }) It("should not if passed a non-error", func() { success, err := (&SucceedMatcher{}).Match(Invalid()) Ω(success).Should(BeFalse()) Ω(err).Should(MatchError("Expected an error-type. Got:\n <*matchers_test.AnyType | 0x0>: nil")) }) It("doesn't support non-error type", func() { success, err := (&SucceedMatcher{}).Match(AnyType{}) Ω(success).Should(BeFalse()) Ω(err).Should(MatchError("Expected an error-type. Got:\n : {}")) }) It("doesn't support non-error pointer type", func() { success, err := (&SucceedMatcher{}).Match(&AnyType{}) Ω(success).Should(BeFalse()) Ω(err).Should(MatchError(MatchRegexp(`Expected an error-type. Got:\n <*matchers_test.AnyType | 0x[[:xdigit:]]+>: {}`))) }) It("should not succeed with pointer types that conform to error interface", func() { err := &CustomErr{"ohai"} Ω(err).ShouldNot(Succeed()) }) It("should succeed with nil pointers to types that conform to error interface", func() { var err *CustomErr = nil Ω(err).Should(Succeed()) }) }) golang-gomega-1.0+git20160910.d59fa0a/matchers/support/000077500000000000000000000000001276516347700221545ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/matchers/support/goraph/000077500000000000000000000000001276516347700234345ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/matchers/support/goraph/MIT.LICENSE000066400000000000000000000020441276516347700250710ustar00rootroot00000000000000Copyright (c) 2014 Amit Kumar Gupta Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. golang-gomega-1.0+git20160910.d59fa0a/matchers/support/goraph/bipartitegraph/000077500000000000000000000000001276516347700264415ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/matchers/support/goraph/bipartitegraph/bipartitegraph.go000066400000000000000000000020471276516347700320000ustar00rootroot00000000000000package bipartitegraph import "errors" import "fmt" import . "github.com/onsi/gomega/matchers/support/goraph/node" import . "github.com/onsi/gomega/matchers/support/goraph/edge" type BipartiteGraph struct { Left NodeOrderedSet Right NodeOrderedSet Edges EdgeSet } func NewBipartiteGraph(leftValues, rightValues []interface{}, neighbours func(interface{}, interface{}) (bool, error)) (*BipartiteGraph, error) { left := NodeOrderedSet{} for i, _ := range leftValues { left = append(left, Node{i}) } right := NodeOrderedSet{} for j, _ := range rightValues { right = append(right, Node{j + len(left)}) } edges := EdgeSet{} for i, leftValue := range leftValues { for j, rightValue := range rightValues { neighbours, err := neighbours(leftValue, rightValue) if err != nil { return nil, errors.New(fmt.Sprintf("error determining adjacency for %v and %v: %s", leftValue, rightValue, err.Error())) } if neighbours { edges = append(edges, Edge{left[i], right[j]}) } } } return &BipartiteGraph{left, right, edges}, nil } bipartitegraphmatching.go000066400000000000000000000067321276516347700334410ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/matchers/support/goraph/bipartitegraphpackage bipartitegraph import . "github.com/onsi/gomega/matchers/support/goraph/node" import . "github.com/onsi/gomega/matchers/support/goraph/edge" import "github.com/onsi/gomega/matchers/support/goraph/util" func (bg *BipartiteGraph) LargestMatching() (matching EdgeSet) { paths := bg.maximalDisjointSLAPCollection(matching) for len(paths) > 0 { for _, path := range paths { matching = matching.SymmetricDifference(path) } paths = bg.maximalDisjointSLAPCollection(matching) } return } func (bg *BipartiteGraph) maximalDisjointSLAPCollection(matching EdgeSet) (result []EdgeSet) { guideLayers := bg.createSLAPGuideLayers(matching) if len(guideLayers) == 0 { return } used := make(map[Node]bool) for _, u := range guideLayers[len(guideLayers)-1] { slap, found := bg.findDisjointSLAP(u, matching, guideLayers, used) if found { for _, edge := range slap { used[edge.Node1] = true used[edge.Node2] = true } result = append(result, slap) } } return } func (bg *BipartiteGraph) findDisjointSLAP( start Node, matching EdgeSet, guideLayers []NodeOrderedSet, used map[Node]bool, ) ([]Edge, bool) { return bg.findDisjointSLAPHelper(start, EdgeSet{}, len(guideLayers)-1, matching, guideLayers, used) } func (bg *BipartiteGraph) findDisjointSLAPHelper( currentNode Node, currentSLAP EdgeSet, currentLevel int, matching EdgeSet, guideLayers []NodeOrderedSet, used map[Node]bool, ) (EdgeSet, bool) { used[currentNode] = true if currentLevel == 0 { return currentSLAP, true } for _, nextNode := range guideLayers[currentLevel-1] { if used[nextNode] { continue } edge, found := bg.Edges.FindByNodes(currentNode, nextNode) if !found { continue } if matching.Contains(edge) == util.Odd(currentLevel) { continue } currentSLAP = append(currentSLAP, edge) slap, found := bg.findDisjointSLAPHelper(nextNode, currentSLAP, currentLevel-1, matching, guideLayers, used) if found { return slap, true } currentSLAP = currentSLAP[:len(currentSLAP)-1] } used[currentNode] = false return nil, false } func (bg *BipartiteGraph) createSLAPGuideLayers(matching EdgeSet) (guideLayers []NodeOrderedSet) { used := make(map[Node]bool) currentLayer := NodeOrderedSet{} for _, node := range bg.Left { if matching.Free(node) { used[node] = true currentLayer = append(currentLayer, node) } } if len(currentLayer) == 0 { return []NodeOrderedSet{} } else { guideLayers = append(guideLayers, currentLayer) } done := false for !done { lastLayer := currentLayer currentLayer = NodeOrderedSet{} if util.Odd(len(guideLayers)) { for _, leftNode := range lastLayer { for _, rightNode := range bg.Right { if used[rightNode] { continue } edge, found := bg.Edges.FindByNodes(leftNode, rightNode) if !found || matching.Contains(edge) { continue } currentLayer = append(currentLayer, rightNode) used[rightNode] = true if matching.Free(rightNode) { done = true } } } } else { for _, rightNode := range lastLayer { for _, leftNode := range bg.Left { if used[leftNode] { continue } edge, found := bg.Edges.FindByNodes(leftNode, rightNode) if !found || !matching.Contains(edge) { continue } currentLayer = append(currentLayer, leftNode) used[leftNode] = true } } } if len(currentLayer) == 0 { return []NodeOrderedSet{} } else { guideLayers = append(guideLayers, currentLayer) } } return } golang-gomega-1.0+git20160910.d59fa0a/matchers/support/goraph/edge/000077500000000000000000000000001276516347700243405ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/matchers/support/goraph/edge/edge.go000066400000000000000000000017541276516347700256020ustar00rootroot00000000000000package edge import . "github.com/onsi/gomega/matchers/support/goraph/node" type Edge struct { Node1 Node Node2 Node } type EdgeSet []Edge func (ec EdgeSet) Free(node Node) bool { for _, e := range ec { if e.Node1 == node || e.Node2 == node { return false } } return true } func (ec EdgeSet) Contains(edge Edge) bool { for _, e := range ec { if e == edge { return true } } return false } func (ec EdgeSet) FindByNodes(node1, node2 Node) (Edge, bool) { for _, e := range ec { if (e.Node1 == node1 && e.Node2 == node2) || (e.Node1 == node2 && e.Node2 == node1) { return e, true } } return Edge{}, false } func (ec EdgeSet) SymmetricDifference(ec2 EdgeSet) EdgeSet { edgesToInclude := make(map[Edge]bool) for _, e := range ec { edgesToInclude[e] = true } for _, e := range ec2 { edgesToInclude[e] = !edgesToInclude[e] } result := EdgeSet{} for e, include := range edgesToInclude { if include { result = append(result, e) } } return result } golang-gomega-1.0+git20160910.d59fa0a/matchers/support/goraph/node/000077500000000000000000000000001276516347700243615ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/matchers/support/goraph/node/node.go000066400000000000000000000001071276516347700256330ustar00rootroot00000000000000package node type Node struct { Id int } type NodeOrderedSet []Node golang-gomega-1.0+git20160910.d59fa0a/matchers/support/goraph/util/000077500000000000000000000000001276516347700244115ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/matchers/support/goraph/util/util.go000066400000000000000000000001371276516347700257160ustar00rootroot00000000000000package util import "math" func Odd(n int) bool { return math.Mod(float64(n), 2.0) == 1.0 } golang-gomega-1.0+git20160910.d59fa0a/matchers/type_support.go000066400000000000000000000072251276516347700235520ustar00rootroot00000000000000/* Gomega matchers This package implements the Gomega matchers and does not typically need to be imported. See the docs for Gomega for documentation on the matchers http://onsi.github.io/gomega/ */ package matchers import ( "fmt" "reflect" ) type omegaMatcher interface { Match(actual interface{}) (success bool, err error) FailureMessage(actual interface{}) (message string) NegatedFailureMessage(actual interface{}) (message string) } func isBool(a interface{}) bool { return reflect.TypeOf(a).Kind() == reflect.Bool } func isNumber(a interface{}) bool { if a == nil { return false } kind := reflect.TypeOf(a).Kind() return reflect.Int <= kind && kind <= reflect.Float64 } func isInteger(a interface{}) bool { kind := reflect.TypeOf(a).Kind() return reflect.Int <= kind && kind <= reflect.Int64 } func isUnsignedInteger(a interface{}) bool { kind := reflect.TypeOf(a).Kind() return reflect.Uint <= kind && kind <= reflect.Uint64 } func isFloat(a interface{}) bool { kind := reflect.TypeOf(a).Kind() return reflect.Float32 <= kind && kind <= reflect.Float64 } func toInteger(a interface{}) int64 { if isInteger(a) { return reflect.ValueOf(a).Int() } else if isUnsignedInteger(a) { return int64(reflect.ValueOf(a).Uint()) } else if isFloat(a) { return int64(reflect.ValueOf(a).Float()) } else { panic(fmt.Sprintf("Expected a number! Got <%T> %#v", a, a)) } } func toUnsignedInteger(a interface{}) uint64 { if isInteger(a) { return uint64(reflect.ValueOf(a).Int()) } else if isUnsignedInteger(a) { return reflect.ValueOf(a).Uint() } else if isFloat(a) { return uint64(reflect.ValueOf(a).Float()) } else { panic(fmt.Sprintf("Expected a number! Got <%T> %#v", a, a)) } } func toFloat(a interface{}) float64 { if isInteger(a) { return float64(reflect.ValueOf(a).Int()) } else if isUnsignedInteger(a) { return float64(reflect.ValueOf(a).Uint()) } else if isFloat(a) { return reflect.ValueOf(a).Float() } else { panic(fmt.Sprintf("Expected a number! Got <%T> %#v", a, a)) } } func isError(a interface{}) bool { _, ok := a.(error) return ok } func isChan(a interface{}) bool { if isNil(a) { return false } return reflect.TypeOf(a).Kind() == reflect.Chan } func isMap(a interface{}) bool { if a == nil { return false } return reflect.TypeOf(a).Kind() == reflect.Map } func isArrayOrSlice(a interface{}) bool { if a == nil { return false } switch reflect.TypeOf(a).Kind() { case reflect.Array, reflect.Slice: return true default: return false } } func isString(a interface{}) bool { if a == nil { return false } return reflect.TypeOf(a).Kind() == reflect.String } func toString(a interface{}) (string, bool) { aString, isString := a.(string) if isString { return aString, true } aBytes, isBytes := a.([]byte) if isBytes { return string(aBytes), true } aStringer, isStringer := a.(fmt.Stringer) if isStringer { return aStringer.String(), true } return "", false } func lengthOf(a interface{}) (int, bool) { if a == nil { return 0, false } switch reflect.TypeOf(a).Kind() { case reflect.Map, reflect.Array, reflect.String, reflect.Chan, reflect.Slice: return reflect.ValueOf(a).Len(), true default: return 0, false } } func capOf(a interface{}) (int, bool) { if a == nil { return 0, false } switch reflect.TypeOf(a).Kind() { case reflect.Array, reflect.Chan, reflect.Slice: return reflect.ValueOf(a).Cap(), true default: return 0, false } } func isNil(a interface{}) bool { if a == nil { return true } switch reflect.TypeOf(a).Kind() { case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: return reflect.ValueOf(a).IsNil() } return false } golang-gomega-1.0+git20160910.d59fa0a/matchers/with_transform.go000066400000000000000000000045301276516347700240370ustar00rootroot00000000000000package matchers import ( "fmt" "reflect" "github.com/onsi/gomega/internal/oraclematcher" "github.com/onsi/gomega/types" ) type WithTransformMatcher struct { // input Transform interface{} // must be a function of one parameter that returns one value Matcher types.GomegaMatcher // cached value transformArgType reflect.Type // state transformedValue interface{} } func NewWithTransformMatcher(transform interface{}, matcher types.GomegaMatcher) *WithTransformMatcher { if transform == nil { panic("transform function cannot be nil") } txType := reflect.TypeOf(transform) if txType.NumIn() != 1 { panic("transform function must have 1 argument") } if txType.NumOut() != 1 { panic("transform function must have 1 return value") } return &WithTransformMatcher{ Transform: transform, Matcher: matcher, transformArgType: reflect.TypeOf(transform).In(0), } } func (m *WithTransformMatcher) Match(actual interface{}) (bool, error) { // return error if actual's type is incompatible with Transform function's argument type actualType := reflect.TypeOf(actual) if !actualType.AssignableTo(m.transformArgType) { return false, fmt.Errorf("Transform function expects '%s' but we have '%s'", m.transformArgType, actualType) } // call the Transform function with `actual` fn := reflect.ValueOf(m.Transform) result := fn.Call([]reflect.Value{reflect.ValueOf(actual)}) m.transformedValue = result[0].Interface() // expect exactly one value return m.Matcher.Match(m.transformedValue) } func (m *WithTransformMatcher) FailureMessage(_ interface{}) (message string) { return m.Matcher.FailureMessage(m.transformedValue) } func (m *WithTransformMatcher) NegatedFailureMessage(_ interface{}) (message string) { return m.Matcher.NegatedFailureMessage(m.transformedValue) } func (m *WithTransformMatcher) MatchMayChangeInTheFuture(_ interface{}) bool { // TODO: Maybe this should always just return true? (Only an issue for non-deterministic transformers.) // // Querying the next matcher is fine if the transformer always will return the same value. // But if the transformer is non-deterministic and returns a different value each time, then there // is no point in querying the next matcher, since it can only comment on the last transformed value. return oraclematcher.MatchMayChangeInTheFuture(m.Matcher, m.transformedValue) } golang-gomega-1.0+git20160910.d59fa0a/matchers/with_transform_test.go000066400000000000000000000065621276516347700251050ustar00rootroot00000000000000package matchers_test import ( "errors" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/matchers" ) var _ = Describe("WithTransformMatcher", func() { var plus1 = func(i int) int { return i + 1 } Context("Panic if transform function invalid", func() { panicsWithTransformer := func(transform interface{}) { ExpectWithOffset(1, func() { WithTransform(transform, nil) }).To(Panic()) } It("nil", func() { panicsWithTransformer(nil) }) Context("Invalid number of args, but correct return value count", func() { It("zero", func() { panicsWithTransformer(func() int { return 5 }) }) It("two", func() { panicsWithTransformer(func(i, j int) int { return 5 }) }) }) Context("Invalid number of return values, but correct number of arguments", func() { It("zero", func() { panicsWithTransformer(func(i int) {}) }) It("two", func() { panicsWithTransformer(func(i int) (int, int) { return 5, 6 }) }) }) }) It("works with positive cases", func() { Expect(1).To(WithTransform(plus1, Equal(2))) Expect(1).To(WithTransform(plus1, WithTransform(plus1, Equal(3)))) Expect(1).To(WithTransform(plus1, And(Equal(2), BeNumerically(">", 1)))) // transform expects custom type type S struct { A int B string } transformer := func(s S) string { return s.B } Expect(S{1, "hi"}).To(WithTransform(transformer, Equal("hi"))) // transform expects interface errString := func(e error) string { return e.Error() } Expect(errors.New("abc")).To(WithTransform(errString, Equal("abc"))) }) It("works with negative cases", func() { Expect(1).ToNot(WithTransform(plus1, Equal(3))) Expect(1).ToNot(WithTransform(plus1, WithTransform(plus1, Equal(2)))) }) Context("failure messages", func() { Context("when match fails", func() { It("gives a descriptive message", func() { m := WithTransform(plus1, Equal(3)) Expect(m.Match(1)).To(BeFalse()) Expect(m.FailureMessage(1)).To(Equal("Expected\n : 2\nto equal\n : 3")) }) }) Context("when match succeeds, but expected it to fail", func() { It("gives a descriptive message", func() { m := Not(WithTransform(plus1, Equal(3))) Expect(m.Match(2)).To(BeFalse()) Expect(m.FailureMessage(2)).To(Equal("Expected\n : 3\nnot to equal\n : 3")) }) }) Context("actual value is incompatible with transform function's argument type", func() { It("gracefully fails if transform cannot be performed", func() { m := WithTransform(plus1, Equal(3)) result, err := m.Match("hi") // give it a string but transform expects int; doesn't panic Expect(result).To(BeFalse()) Expect(err).To(MatchError("Transform function expects 'int' but we have 'string'")) }) }) }) Context("MatchMayChangeInTheFuture()", func() { It("Propagates value from wrapped matcher on the transformed value", func() { m := WithTransform(plus1, Or()) // empty Or() always returns false, and indicates it cannot change Expect(m.Match(1)).To(BeFalse()) Expect(m.(*WithTransformMatcher).MatchMayChangeInTheFuture(1)).To(BeFalse()) // empty Or() indicates cannot change }) It("Defaults to true", func() { m := WithTransform(plus1, Equal(2)) // Equal does not have this method Expect(m.Match(1)).To(BeTrue()) Expect(m.(*WithTransformMatcher).MatchMayChangeInTheFuture(1)).To(BeTrue()) // defaults to true }) }) }) golang-gomega-1.0+git20160910.d59fa0a/types/000077500000000000000000000000001276516347700177765ustar00rootroot00000000000000golang-gomega-1.0+git20160910.d59fa0a/types/types.go000066400000000000000000000010751276516347700214740ustar00rootroot00000000000000package types type GomegaFailHandler func(message string, callerSkip ...int) //A simple *testing.T interface wrapper type GomegaTestingT interface { Errorf(format string, args ...interface{}) } //All Gomega matchers must implement the GomegaMatcher interface // //For details on writing custom matchers, check out: http://onsi.github.io/gomega/#adding_your_own_matchers type GomegaMatcher interface { Match(actual interface{}) (success bool, err error) FailureMessage(actual interface{}) (message string) NegatedFailureMessage(actual interface{}) (message string) }