summaryrefslogtreecommitdiff
path: root/vendor/github.com/onsi/gomega
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/onsi/gomega')
-rw-r--r--vendor/github.com/onsi/gomega/.gitignore5
-rw-r--r--vendor/github.com/onsi/gomega/.travis.yml23
-rw-r--r--vendor/github.com/onsi/gomega/CHANGELOG.md125
-rw-r--r--vendor/github.com/onsi/gomega/CONTRIBUTING.md14
-rw-r--r--vendor/github.com/onsi/gomega/LICENSE20
-rw-r--r--vendor/github.com/onsi/gomega/README.md21
-rw-r--r--vendor/github.com/onsi/gomega/RELEASING.md12
-rw-r--r--vendor/github.com/onsi/gomega/format/format.go382
-rw-r--r--vendor/github.com/onsi/gomega/format/format_suite_test.go13
-rw-r--r--vendor/github.com/onsi/gomega/format/format_test.go627
-rw-r--r--vendor/github.com/onsi/gomega/gbytes/buffer.go245
-rw-r--r--vendor/github.com/onsi/gomega/gbytes/buffer_test.go205
-rw-r--r--vendor/github.com/onsi/gomega/gbytes/gbuffer_suite_test.go13
-rw-r--r--vendor/github.com/onsi/gomega/gbytes/io_wrappers.go85
-rw-r--r--vendor/github.com/onsi/gomega/gbytes/io_wrappers_test.go188
-rw-r--r--vendor/github.com/onsi/gomega/gbytes/say_matcher.go104
-rw-r--r--vendor/github.com/onsi/gomega/gbytes/say_matcher_test.go169
-rw-r--r--vendor/github.com/onsi/gomega/gexec/_fixture/firefly/main.go36
-rw-r--r--vendor/github.com/onsi/gomega/gexec/build.go112
-rw-r--r--vendor/github.com/onsi/gomega/gexec/build_test.go112
-rw-r--r--vendor/github.com/onsi/gomega/gexec/exit_matcher.go86
-rw-r--r--vendor/github.com/onsi/gomega/gexec/exit_matcher_test.go114
-rw-r--r--vendor/github.com/onsi/gomega/gexec/gexec_suite_test.go26
-rw-r--r--vendor/github.com/onsi/gomega/gexec/prefixed_writer.go53
-rw-r--r--vendor/github.com/onsi/gomega/gexec/prefixed_writer_test.go43
-rw-r--r--vendor/github.com/onsi/gomega/gexec/session.go303
-rw-r--r--vendor/github.com/onsi/gomega/gexec/session_test.go336
-rw-r--r--vendor/github.com/onsi/gomega/ghttp/handlers.go322
-rw-r--r--vendor/github.com/onsi/gomega/ghttp/protobuf/protobuf.go3
-rw-r--r--vendor/github.com/onsi/gomega/ghttp/protobuf/simple_message.pb.go55
-rw-r--r--vendor/github.com/onsi/gomega/ghttp/protobuf/simple_message.proto9
-rw-r--r--vendor/github.com/onsi/gomega/ghttp/test_server.go422
-rw-r--r--vendor/github.com/onsi/gomega/ghttp/test_server_suite_test.go13
-rw-r--r--vendor/github.com/onsi/gomega/ghttp/test_server_test.go1129
-rw-r--r--vendor/github.com/onsi/gomega/go.mod15
-rw-r--r--vendor/github.com/onsi/gomega/go.sum24
-rw-r--r--vendor/github.com/onsi/gomega/gomega_dsl.go421
-rw-r--r--vendor/github.com/onsi/gomega/gstruct/elements.go159
-rw-r--r--vendor/github.com/onsi/gomega/gstruct/elements_test.go144
-rw-r--r--vendor/github.com/onsi/gomega/gstruct/errors/nested_types.go72
-rw-r--r--vendor/github.com/onsi/gomega/gstruct/fields.go168
-rw-r--r--vendor/github.com/onsi/gomega/gstruct/fields_test.go76
-rw-r--r--vendor/github.com/onsi/gomega/gstruct/gstruct_tests_suite_test.go13
-rw-r--r--vendor/github.com/onsi/gomega/gstruct/ignore.go37
-rw-r--r--vendor/github.com/onsi/gomega/gstruct/ignore_test.go23
-rw-r--r--vendor/github.com/onsi/gomega/gstruct/pointer.go56
-rw-r--r--vendor/github.com/onsi/gomega/gstruct/pointer_test.go33
-rw-r--r--vendor/github.com/onsi/gomega/gstruct/types.go15
-rw-r--r--vendor/github.com/onsi/gomega/internal/assertion/assertion.go105
-rw-r--r--vendor/github.com/onsi/gomega/internal/assertion/assertion_suite_test.go13
-rw-r--r--vendor/github.com/onsi/gomega/internal/assertion/assertion_test.go258
-rw-r--r--vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion.go194
-rw-r--r--vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion_suite_test.go13
-rw-r--r--vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion_test.go351
-rw-r--r--vendor/github.com/onsi/gomega/internal/fakematcher/fake_matcher.go23
-rw-r--r--vendor/github.com/onsi/gomega/internal/oraclematcher/oracle_matcher.go25
-rw-r--r--vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support.go60
-rw-r--r--vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support_test.go92
-rw-r--r--vendor/github.com/onsi/gomega/matchers.go427
-rw-r--r--vendor/github.com/onsi/gomega/matchers/and.go63
-rw-r--r--vendor/github.com/onsi/gomega/matchers/and_test.go103
-rw-r--r--vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher.go35
-rw-r--r--vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher_test.go46
-rw-r--r--vendor/github.com/onsi/gomega/matchers/attributes_slice.go14
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_a_directory.go54
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_a_directory_test.go40
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_a_regular_file.go54
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_a_regular_file_test.go40
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_an_existing_file.go38
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_an_existing_file_test.go40
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_closed_matcher.go46
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_closed_matcher_test.go70
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_empty_matcher.go27
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_empty_matcher_test.go52
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher.go34
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher_test.go50
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_false_matcher.go26
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_false_matcher_test.go20
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_identical_to.go37
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_identical_to_test.go61
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_nil_matcher.go18
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_nil_matcher_test.go28
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_numerically_matcher.go132
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_numerically_matcher_test.go172
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_sent_matcher.go71
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_sent_matcher_test.go107
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_temporally_matcher.go66
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_temporally_matcher_test.go99
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_true_matcher.go26
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_true_matcher_test.go20
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_zero_matcher.go28
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_zero_matcher_test.go40
-rw-r--r--vendor/github.com/onsi/gomega/matchers/consist_of.go80
-rw-r--r--vendor/github.com/onsi/gomega/matchers/consist_of_test.go75
-rw-r--r--vendor/github.com/onsi/gomega/matchers/contain_element_matcher.go56
-rw-r--r--vendor/github.com/onsi/gomega/matchers/contain_element_matcher_test.go76
-rw-r--r--vendor/github.com/onsi/gomega/matchers/contain_substring_matcher.go38
-rw-r--r--vendor/github.com/onsi/gomega/matchers/contain_substring_matcher_test.go36
-rw-r--r--vendor/github.com/onsi/gomega/matchers/equal_matcher.go42
-rw-r--r--vendor/github.com/onsi/gomega/matchers/equal_matcher_test.go80
-rw-r--r--vendor/github.com/onsi/gomega/matchers/have_cap_matcher.go28
-rw-r--r--vendor/github.com/onsi/gomega/matchers/have_cap_matcher_test.go50
-rw-r--r--vendor/github.com/onsi/gomega/matchers/have_key_matcher.go54
-rw-r--r--vendor/github.com/onsi/gomega/matchers/have_key_matcher_test.go73
-rw-r--r--vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher.go74
-rw-r--r--vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher_test.go82
-rw-r--r--vendor/github.com/onsi/gomega/matchers/have_len_matcher.go28
-rw-r--r--vendor/github.com/onsi/gomega/matchers/have_len_matcher_test.go53
-rw-r--r--vendor/github.com/onsi/gomega/matchers/have_occurred_matcher.go33
-rw-r--r--vendor/github.com/onsi/gomega/matchers/have_occurred_matcher_test.go59
-rw-r--r--vendor/github.com/onsi/gomega/matchers/have_prefix_matcher.go36
-rw-r--r--vendor/github.com/onsi/gomega/matchers/have_prefix_matcher_test.go36
-rw-r--r--vendor/github.com/onsi/gomega/matchers/have_suffix_matcher.go36
-rw-r--r--vendor/github.com/onsi/gomega/matchers/have_suffix_matcher_test.go36
-rw-r--r--vendor/github.com/onsi/gomega/matchers/match_error_matcher.go51
-rw-r--r--vendor/github.com/onsi/gomega/matchers/match_error_matcher_test.go107
-rw-r--r--vendor/github.com/onsi/gomega/matchers/match_json_matcher.go65
-rw-r--r--vendor/github.com/onsi/gomega/matchers/match_json_matcher_test.go103
-rw-r--r--vendor/github.com/onsi/gomega/matchers/match_regexp_matcher.go43
-rw-r--r--vendor/github.com/onsi/gomega/matchers/match_regexp_matcher_test.go44
-rw-r--r--vendor/github.com/onsi/gomega/matchers/match_xml_matcher.go134
-rw-r--r--vendor/github.com/onsi/gomega/matchers/match_xml_matcher_test.go97
-rw-r--r--vendor/github.com/onsi/gomega/matchers/match_yaml_matcher.go76
-rw-r--r--vendor/github.com/onsi/gomega/matchers/match_yaml_matcher_test.go101
-rw-r--r--vendor/github.com/onsi/gomega/matchers/matcher_tests_suite_test.go50
-rw-r--r--vendor/github.com/onsi/gomega/matchers/not.go30
-rw-r--r--vendor/github.com/onsi/gomega/matchers/not_test.go64
-rw-r--r--vendor/github.com/onsi/gomega/matchers/or.go67
-rw-r--r--vendor/github.com/onsi/gomega/matchers/or_test.go92
-rw-r--r--vendor/github.com/onsi/gomega/matchers/panic_matcher.go46
-rw-r--r--vendor/github.com/onsi/gomega/matchers/panic_matcher_test.go52
-rw-r--r--vendor/github.com/onsi/gomega/matchers/receive_matcher.go128
-rw-r--r--vendor/github.com/onsi/gomega/matchers/receive_matcher_test.go304
-rw-r--r--vendor/github.com/onsi/gomega/matchers/semi_structured_data_support.go92
-rw-r--r--vendor/github.com/onsi/gomega/matchers/succeed_matcher.go33
-rw-r--r--vendor/github.com/onsi/gomega/matchers/succeed_matcher_test.go72
-rw-r--r--vendor/github.com/onsi/gomega/matchers/support/goraph/MIT.LICENSE20
-rw-r--r--vendor/github.com/onsi/gomega/matchers/support/goraph/bipartitegraph/bipartitegraph.go41
-rw-r--r--vendor/github.com/onsi/gomega/matchers/support/goraph/bipartitegraph/bipartitegraphmatching.go159
-rw-r--r--vendor/github.com/onsi/gomega/matchers/support/goraph/edge/edge.go61
-rw-r--r--vendor/github.com/onsi/gomega/matchers/support/goraph/node/node.go7
-rw-r--r--vendor/github.com/onsi/gomega/matchers/support/goraph/util/util.go7
-rw-r--r--vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_01.xml6
-rw-r--r--vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_02.xml9
-rw-r--r--vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_03.xml1
-rw-r--r--vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_04.xml6
-rw-r--r--vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_05.xml211
-rw-r--r--vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_06.xml13
-rw-r--r--vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_07.xml13
-rw-r--r--vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_08.xml13
-rw-r--r--vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_09.xml4
-rw-r--r--vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_10.xml4
-rw-r--r--vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_11.xml7
-rw-r--r--vendor/github.com/onsi/gomega/matchers/type_support.go179
-rw-r--r--vendor/github.com/onsi/gomega/matchers/with_transform.go72
-rw-r--r--vendor/github.com/onsi/gomega/matchers/with_transform_test.go102
-rw-r--r--vendor/github.com/onsi/gomega/types/types.go26
157 files changed, 13972 insertions, 0 deletions
diff --git a/vendor/github.com/onsi/gomega/.gitignore b/vendor/github.com/onsi/gomega/.gitignore
new file mode 100644
index 000000000..720c13cba
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/.gitignore
@@ -0,0 +1,5 @@
+.DS_Store
+*.test
+.
+.idea
+gomega.iml
diff --git a/vendor/github.com/onsi/gomega/.travis.yml b/vendor/github.com/onsi/gomega/.travis.yml
new file mode 100644
index 000000000..4d71367f6
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/.travis.yml
@@ -0,0 +1,23 @@
+language: go
+
+go:
+ - 1.6.x
+ - 1.7.x
+ - 1.8.x
+ - 1.9.x
+ - 1.10.x
+ - 1.11.x
+
+env:
+ - GO111MODULE=on
+
+install:
+ - go get -v ./...
+ - go build ./...
+ - go get github.com/onsi/ginkgo
+ - go install github.com/onsi/ginkgo/ginkgo
+
+script: |
+ $HOME/gopath/bin/ginkgo -p -r --randomizeAllSpecs --failOnPending --randomizeSuites --race &&
+ go vet &&
+ [ -z "`gofmt -l -e -s -w .`" ]
diff --git a/vendor/github.com/onsi/gomega/CHANGELOG.md b/vendor/github.com/onsi/gomega/CHANGELOG.md
new file mode 100644
index 000000000..9153294f7
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/CHANGELOG.md
@@ -0,0 +1,125 @@
+## 1.4.3
+
+### Fixes:
+
+- ensure file name and line numbers are correctly reported for XUnit [6fff58f]
+- Fixed matcher for content-type (#305) [69d9b43]
+
+## 1.4.2
+
+### Fixes:
+
+- Add go.mod and go.sum files to define the gomega go module [f3de367, a085d30]
+- Work around go vet issue with Go v1.11 (#300) [40dd6ad]
+- Better output when using with go XUnit-style tests, fixes #255 (#297) [29a4b97]
+- Fix MatchJSON fail to parse json.RawMessage (#298) [ae19f1b]
+- show threshold in failure message of BeNumericallyMatcher (#293) [4bbecc8]
+
+## 1.4.1
+
+### Fixes:
+
+- Update documentation formatting and examples (#289) [9be8410]
+- allow 'Receive' matcher to be used with concrete types (#286) [41673fd]
+- Fix data race in ghttp server (#283) [7ac6b01]
+- Travis badge should only show master [cc102ab]
+
+## 1.4.0
+
+### Features
+- Make string pretty diff user configurable (#273) [eb112ce, 649b44d]
+
+### Fixes
+- Use httputil.DumpRequest to pretty-print unhandled requests (#278) [a4ff0fc, b7d1a52]
+- fix typo floa32 > float32 (#272) [041ae3b, 6e33911]
+- Fix link to documentation on adding your own matchers (#270) [bb2c830, fcebc62]
+- Use setters and getters to avoid race condition (#262) [13057c3, a9c79f1]
+- Avoid sending a signal if the process is not alive (#259) [b8043e5, 4fc1762]
+- Improve message from AssignableToTypeOf when expected value is nil (#281) [9c1fb20]
+
+## 1.3.0
+
+Improvements:
+
+- The `Equal` matcher matches byte slices more performantly.
+- Improved how `MatchError` matches error strings.
+- `MatchXML` ignores the order of xml node attributes.
+- Improve support for XUnit style golang tests. ([#254](https://github.com/onsi/gomega/issues/254))
+
+Bug Fixes:
+
+- Diff generation now handles multi-byte sequences correctly.
+- Multiple goroutines can now call `gexec.Build` concurrently.
+
+## 1.2.0
+
+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
+- Added `gbytes.TimeoutCloser`, `gbytes.TimeoutReader`, and `gbytes.TimeoutWriter` - these are convenience wrappers that timeout if the underlying Closer/Reader/Writer does not return within the alloted time.
+- Added `gbytes.BufferReader` - this constructs a `gbytes.Buffer` that asynchronously reads the passed-in `io.Reader` into its buffer.
+
+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`
diff --git a/vendor/github.com/onsi/gomega/CONTRIBUTING.md b/vendor/github.com/onsi/gomega/CONTRIBUTING.md
new file mode 100644
index 000000000..0d7a09928
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/CONTRIBUTING.md
@@ -0,0 +1,14 @@
+# Contributing to Gomega
+
+Your contributions to Gomega are essential for its long-term maintenance and improvement. To make a contribution:
+
+- Please **open an issue first** - describe what problem you are trying to solve and give the community a forum for input and feedback ahead of investing time in writing code!
+- Ensure adequate test coverage:
+ - Make sure to add appropriate unit tests
+ - Please run all tests locally (`ginkgo -r -p`) and make sure they go green before submitting the PR
+ - Please run following linter locally `go vet ./...` and make sure output does not contain any warnings
+- Update the documentation. In addition to standard `godoc` comments Gomega has extensive documentation on the `gh-pages` branch. If relevant, please submit a docs PR to that branch alongside your code PR.
+
+If you're a committer, check out RELEASING.md to learn how to cut a release.
+
+Thanks for supporting Gomega!
diff --git a/vendor/github.com/onsi/gomega/LICENSE b/vendor/github.com/onsi/gomega/LICENSE
new file mode 100644
index 000000000..9415ee72c
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/LICENSE
@@ -0,0 +1,20 @@
+Copyright (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.
diff --git a/vendor/github.com/onsi/gomega/README.md b/vendor/github.com/onsi/gomega/README.md
new file mode 100644
index 000000000..76aa6b558
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/README.md
@@ -0,0 +1,21 @@
+![Gomega: Ginkgo's Preferred Matcher Library](http://onsi.github.io/gomega/images/gomega.png)
+
+[![Build Status](https://travis-ci.org/onsi/gomega.svg?branch=master)](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).
+
+If you have a question, comment, bug report, feature request, etc. please open a GitHub issue.
+
+## [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.
diff --git a/vendor/github.com/onsi/gomega/RELEASING.md b/vendor/github.com/onsi/gomega/RELEASING.md
new file mode 100644
index 000000000..998d64ee7
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/RELEASING.md
@@ -0,0 +1,12 @@
+A Gomega release is a tagged sha and a GitHub release. To cut a release:
+
+1. Ensure CHANGELOG.md is up to date.
+ - Use `git log --pretty=format:'- %s [%h]' HEAD...vX.X.X` to list all the commits since the last release
+ - Categorize the changes into
+ - Breaking Changes (requires a major version)
+ - New Features (minor version)
+ - Fixes (fix version)
+ - Maintenance (which in general should not be mentioned in `CHANGELOG.md` as they have no user impact)
+2. Update GOMEGA_VERSION in `gomega_dsl.go`
+3. Push a commit with the version number as the commit message (e.g. `v1.3.0`)
+4. Create a new [GitHub release](https://help.github.com/articles/creating-releases/) with the version number as the tag (e.g. `v1.3.0`). List the key changes in the release notes.
diff --git a/vendor/github.com/onsi/gomega/format/format.go b/vendor/github.com/onsi/gomega/format/format.go
new file mode 100644
index 000000000..6559525f1
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/format/format.go
@@ -0,0 +1,382 @@
+/*
+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"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// 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
+
+/*
+Print the content of context objects. By default it will be suppressed.
+
+Set PrintContextObjects = true to enable printing of the context internals.
+*/
+var PrintContextObjects = false
+
+// TruncatedDiff choose if we should display a truncated pretty diff or not
+var TruncatedDiff = true
+
+// Ctx interface defined here to keep backwards compatability with go < 1.7
+// It matches the context.Context interface
+type Ctx interface {
+ Deadline() (deadline time.Time, ok bool)
+ Done() <-chan struct{}
+ Err() error
+ Value(key interface{}) interface{}
+}
+
+var contextType = reflect.TypeOf((*Ctx)(nil)).Elem()
+var timeType = reflect.TypeOf(time.Time{})
+
+//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
+ <pretty printed actual>
+ <message>
+ <pretty printed expected>
+
+If expected is omited, then the message looks like:
+
+ Expected
+ <pretty printed actual>
+ <message>
+*/
+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)
+ }
+ return fmt.Sprintf("Expected\n%s\n%s\n%s", Object(actual, 1), message, Object(expected[0], 1))
+}
+
+/*
+
+Generates a nicely formatted matcher success / failure message
+
+Much like Message(...), but it attempts to pretty print diffs in strings
+
+Expected
+ <string>: "...aaaaabaaaaa..."
+to equal |
+ <string>: "...aaaaazaaaaa..."
+
+*/
+
+func MessageWithDiff(actual, message, expected string) string {
+ if TruncatedDiff && len(actual) >= truncateThreshold && len(expected) >= truncateThreshold {
+ diffPoint := findFirstMismatch(actual, expected)
+ formattedActual := truncateAndFormat(actual, diffPoint)
+ formattedExpected := truncateAndFormat(expected, diffPoint)
+
+ spacesBeforeFormattedMismatch := findFirstMismatch(formattedActual, formattedExpected)
+
+ tabLength := 4
+ spaceFromMessageToActual := tabLength + len("<string>: ") - len(message)
+ padding := strings.Repeat(" ", spaceFromMessageToActual+spacesBeforeFormattedMismatch) + "|"
+ return Message(formattedActual, message+padding, formattedExpected)
+ }
+ return Message(actual, message, expected)
+}
+
+func truncateAndFormat(str string, index int) string {
+ leftPadding := `...`
+ rightPadding := `...`
+
+ start := index - charactersAroundMismatchToInclude
+ if start < 0 {
+ start = 0
+ leftPadding = ""
+ }
+
+ // slice index must include the mis-matched character
+ lengthOfMismatchedCharacter := 1
+ end := index + charactersAroundMismatchToInclude + lengthOfMismatchedCharacter
+ if end > len(str) {
+ end = len(str)
+ rightPadding = ""
+
+ }
+ return fmt.Sprintf("\"%s\"", leftPadding+str[start:end]+rightPadding)
+}
+
+func findFirstMismatch(a, b string) int {
+ aSlice := strings.Split(a, "")
+ bSlice := strings.Split(b, "")
+
+ for index, str := range aSlice {
+ if index > len(bSlice)-1 {
+ return index
+ }
+ if str != bSlice[index] {
+ return index
+ }
+ }
+
+ if len(b) > len(a) {
+ return len(a) + 1
+ }
+
+ return 0
+}
+
+const (
+ truncateThreshold = 50
+ charactersAroundMismatchToInclude = 5
+)
+
+/*
+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.
+
+Set PrintContextObjects to true to print the content of objects implementing context.Context
+*/
+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()
+ }
+ }
+ }
+
+ if !PrintContextObjects {
+ if value.Type().Implements(contextType) && indentation > 1 {
+ return "<suppressed context>"
+ }
+ }
+
+ 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:
+ if value.Type() == timeType && value.CanInterface() {
+ t, _ := value.Interface().(time.Time)
+ return t.Format(time.RFC3339Nano)
+ }
+ return formatStruct(value, indentation)
+ case reflect.Interface:
+ return formatValue(value.Elem(), indentation)
+ default:
+ if value.CanInterface() {
+ return fmt.Sprintf("%#v", value.Interface())
+ }
+ 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)
+ }
+ 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, indentation+1), 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)
+ }
+ 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)
+ }
+ 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
+}
diff --git a/vendor/github.com/onsi/gomega/format/format_suite_test.go b/vendor/github.com/onsi/gomega/format/format_suite_test.go
new file mode 100644
index 000000000..8e65a9529
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/format/format_suite_test.go
@@ -0,0 +1,13 @@
+package format_test
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+
+ "testing"
+)
+
+func TestFormat(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Format Suite")
+}
diff --git a/vendor/github.com/onsi/gomega/format/format_test.go b/vendor/github.com/onsi/gomega/format/format_test.go
new file mode 100644
index 000000000..9ea781379
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/format/format_test.go
@@ -0,0 +1,627 @@
+package format_test
+
+import (
+ "fmt"
+ "strings"
+ "time"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/format"
+ "github.com/onsi/gomega/types"
+)
+
+//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"
+}
+
+type ctx struct {
+}
+
+func (c *ctx) Deadline() (deadline time.Time, ok bool) {
+ return time.Time{}, false
+}
+
+func (c *ctx) Done() <-chan struct{} {
+ return nil
+}
+
+func (c *ctx) Err() error {
+ return nil
+}
+
+func (c *ctx) Value(key interface{}) interface{} {
+ return nil
+}
+
+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() {
+ Expect(Message(3, "to be three.")).Should(Equal("Expected\n <int>: 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() {
+ Expect(Message(3, "to equal", 4)).Should(Equal("Expected\n <int>: 3\nto equal\n <int>: 4"))
+ })
+ })
+ })
+
+ Describe("MessageWithDiff", func() {
+ It("shows the exact point where two long strings differ", func() {
+ stringWithB := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ stringWithZ := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+ Expect(MessageWithDiff(stringWithB, "to equal", stringWithZ)).Should(Equal(expectedLongStringFailureMessage))
+ })
+
+ It("truncates the start of long strings that differ only at their end", func() {
+ stringWithB := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"
+ stringWithZ := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaz"
+
+ Expect(MessageWithDiff(stringWithB, "to equal", stringWithZ)).Should(Equal(expectedTruncatedStartStringFailureMessage))
+ })
+
+ It("truncates the start of long strings that differ only in length", func() {
+ smallString := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ largeString := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+ Expect(MessageWithDiff(largeString, "to equal", smallString)).Should(Equal(expectedTruncatedStartSizeFailureMessage))
+ Expect(MessageWithDiff(smallString, "to equal", largeString)).Should(Equal(expectedTruncatedStartSizeSwappedFailureMessage))
+ })
+
+ It("truncates the end of long strings that differ only at their start", func() {
+ stringWithB := "baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ stringWithZ := "zaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+ Expect(MessageWithDiff(stringWithB, "to equal", stringWithZ)).Should(Equal(expectedTruncatedEndStringFailureMessage))
+ })
+
+ It("handles multi-byte sequences correctly", func() {
+ stringA := "• abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz1"
+ stringB := "• abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
+
+ Expect(MessageWithDiff(stringA, "to equal", stringB)).Should(Equal(expectedTruncatedMultiByteFailureMessage))
+ })
+
+ Context("With truncated diff disabled", func() {
+ BeforeEach(func() {
+ TruncatedDiff = false
+ })
+
+ AfterEach(func() {
+ TruncatedDiff = true
+ })
+
+ It("should show the full diff", func() {
+ stringWithB := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ stringWithZ := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+ Expect(MessageWithDiff(stringWithB, "to equal", stringWithZ)).Should(Equal(expectedFullFailureDiff))
+ })
+ })
+ })
+
+ Describe("IndentString", func() {
+ It("should indent the string", func() {
+ Expect(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() {
+ Expect(Object(true, 1)).Should(match("bool", "true"))
+ Expect(Object(false, 1)).Should(match("bool", "false"))
+ })
+ })
+
+ Describe("formatting numbers", func() {
+ It("should give the type and format values correctly", func() {
+ Expect(Object(int(3), 1)).Should(match("int", "3"))
+ Expect(Object(int8(3), 1)).Should(match("int8", "3"))
+ Expect(Object(int16(3), 1)).Should(match("int16", "3"))
+ Expect(Object(int32(3), 1)).Should(match("int32", "3"))
+ Expect(Object(int64(3), 1)).Should(match("int64", "3"))
+
+ Expect(Object(uint(3), 1)).Should(match("uint", "3"))
+ Expect(Object(uint8(3), 1)).Should(match("uint8", "3"))
+ Expect(Object(uint16(3), 1)).Should(match("uint16", "3"))
+ Expect(Object(uint32(3), 1)).Should(match("uint32", "3"))
+ Expect(Object(uint64(3), 1)).Should(match("uint64", "3"))
+ })
+
+ It("should handle uintptr differently", func() {
+ Expect(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
+ Expect(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"
+ Expect(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")
+ Expect(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")
+ Expect(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
+ }
+ Expect(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
+ Expect(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
+
+ Expect(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
+ Expect(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"}
+ Expect(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}
+ Expect(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)
+ Expect(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",
+ ]`
+ Expect(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
+ Expect(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"),
+ }`
+ Expect(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,
+ }
+
+ Expect(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,
+ }
+
+ Expect(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() {
+ Expect(Object(nil, 1)).Should(match("nil", "nil"))
+ var typedNil *AStruct
+ Expect(Object(typedNil, 1)).Should(match("*format_test.AStruct | 0x0", "nil"))
+ var c chan<- bool
+ Expect(Object(c, 1)).Should(match("chan<- bool | len:0, cap:0", "nil"))
+ var s []string
+ Expect(Object(s, 1)).Should(match("[]string | len:0, cap:0", "nil"))
+ var m map[string]bool
+ Expect(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() {
+ Expect(Object(StringAlias("alias"), 1)).Should(match("format_test.StringAlias", `alias`))
+ Expect(Object(ByteAlias("alias"), 1)).Should(matchRegexp(`format_test\.ByteAlias \| len:5, cap:\d+`, `alias`))
+ Expect(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"),
+ },
+ }`
+ Expect(Object(s, 1)).Should(matchRegexp(`format_test\.ComplexStruct`, expected))
+ })
+ })
+
+ Describe("formatting times", func() {
+ It("should format time as RFC3339", func() {
+ t := time.Date(2016, 10, 31, 9, 57, 23, 12345, time.UTC)
+ Expect(Object(t, 1)).Should(match("time.Time", `2016-10-31T09:57:23.000012345Z`))
+ })
+ })
+ })
+
+ 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`))
+
+ Expect(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}`)
+ Expect(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
+ Expect(Object(m, 1)).Should(ContainSubstring("..."))
+ })
+
+ It("really should not go crazy...", func() {
+ type complexKey struct {
+ Value map[interface{}]int
+ }
+
+ complexObject := complexKey{}
+ complexObject.Value = make(map[interface{}]int)
+
+ complexObject.Value[&complexObject] = 2
+ Expect(Object(complexObject, 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() {
+ Expect(Object(GoStringer{}, 1)).Should(ContainSubstring("<format_test.GoStringer>: go-string"))
+ })
+ })
+
+ Context("when passed a stringer", func() {
+ It("should use what String() returns", func() {
+ Expect(Object(Stringer{}, 1)).Should(ContainSubstring("<format_test.Stringer>: string"))
+ })
+ })
+ })
+
+ Describe("Printing a context.Context field", func() {
+
+ type structWithContext struct {
+ Context Ctx
+ Value string
+ }
+
+ context := ctx{}
+ objWithContext := structWithContext{Value: "some-value", Context: &context}
+
+ It("Suppresses the content by default", func() {
+ Expect(Object(objWithContext, 1)).Should(ContainSubstring("<suppressed context>"))
+ })
+
+ It("Doesn't supress the context if it's the object being printed", func() {
+ Expect(Object(context, 1)).ShouldNot(MatchRegexp("^.*<suppressed context>$"))
+ })
+
+ Context("PrintContextObjects is set", func() {
+ BeforeEach(func() {
+ PrintContextObjects = true
+ })
+
+ AfterEach(func() {
+ PrintContextObjects = false
+ })
+
+ It("Prints the context", func() {
+ Expect(Object(objWithContext, 1)).ShouldNot(ContainSubstring("<suppressed context>"))
+ })
+ })
+ })
+})
+
+var expectedLongStringFailureMessage = strings.TrimSpace(`
+Expected
+ <string>: "...aaaaabaaaaa..."
+to equal |
+ <string>: "...aaaaazaaaaa..."
+`)
+var expectedTruncatedEndStringFailureMessage = strings.TrimSpace(`
+Expected
+ <string>: "baaaaa..."
+to equal |
+ <string>: "zaaaaa..."
+`)
+var expectedTruncatedStartStringFailureMessage = strings.TrimSpace(`
+Expected
+ <string>: "...aaaaab"
+to equal |
+ <string>: "...aaaaaz"
+`)
+var expectedTruncatedStartSizeFailureMessage = strings.TrimSpace(`
+Expected
+ <string>: "...aaaaaa"
+to equal |
+ <string>: "...aaaaa"
+`)
+var expectedTruncatedStartSizeSwappedFailureMessage = strings.TrimSpace(`
+Expected
+ <string>: "...aaaa"
+to equal |
+ <string>: "...aaaaa"
+`)
+var expectedTruncatedMultiByteFailureMessage = strings.TrimSpace(`
+Expected
+ <string>: "...tuvwxyz1"
+to equal |
+ <string>: "...tuvwxyz"
+`)
+
+var expectedFullFailureDiff = strings.TrimSpace(`
+Expected
+ <string>: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+to equal
+ <string>: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+`)
diff --git a/vendor/github.com/onsi/gomega/gbytes/buffer.go b/vendor/github.com/onsi/gomega/gbytes/buffer.go
new file mode 100644
index 000000000..336086f4a
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gbytes/buffer.go
@@ -0,0 +1,245 @@
+/*
+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,
+ }
+}
+
+/*
+BufferReader returns a new gbytes.Buffer that wraps a reader. The reader's contents are read into
+the Buffer via io.Copy
+*/
+func BufferReader(reader io.Reader) *Buffer {
+ b := &Buffer{
+ lock: &sync.Mutex{},
+ }
+
+ go func() {
+ io.Copy(b, reader)
+ b.Close()
+ }()
+
+ return b
+}
+
+/*
+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
+ }
+ return false, copyOfUnreadBytes
+}
diff --git a/vendor/github.com/onsi/gomega/gbytes/buffer_test.go b/vendor/github.com/onsi/gomega/gbytes/buffer_test.go
new file mode 100644
index 000000000..9d4e8279d
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gbytes/buffer_test.go
@@ -0,0 +1,205 @@
+package gbytes_test
+
+import (
+ "io"
+ "time"
+
+ . "github.com/onsi/gomega/gbytes"
+
+ "bytes"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+type SlowReader struct {
+ R io.Reader
+ D time.Duration
+}
+
+func (s SlowReader) Read(p []byte) (int, error) {
+ time.Sleep(s.D)
+ return s.R.Read(p)
+}
+
+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"))
+ Expect(buffer.Contents()).Should(Equal([]byte("abcdef")))
+
+ Expect(buffer).Should(Say("bcd"))
+ Expect(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"))
+ Expect(buffer.Contents()).Should(Equal([]byte("abcdef")))
+ Expect(buffer).Should(Say("abc"))
+ Expect(buffer).ShouldNot(Say("abc"))
+ Expect(buffer).Should(Say("def"))
+ })
+ })
+
+ Describe("creating a buffer that wraps a reader", func() {
+ Context("for a well-behaved reader", func() {
+ It("should buffer the contents of the reader", func() {
+ reader := bytes.NewBuffer([]byte("abcdef"))
+ buffer := BufferReader(reader)
+ Eventually(buffer).Should(Say("abc"))
+ Expect(buffer).ShouldNot(Say("abc"))
+ Eventually(buffer).Should(Say("def"))
+ Eventually(buffer.Closed).Should(BeTrue())
+ })
+ })
+
+ Context("for a slow reader", func() {
+ It("should allow Eventually to time out", func() {
+ slowReader := SlowReader{
+ R: bytes.NewBuffer([]byte("abcdef")),
+ D: time.Second,
+ }
+ buffer := BufferReader(slowReader)
+ failures := InterceptGomegaFailures(func() {
+ Eventually(buffer, 100*time.Millisecond).Should(Say("abc"))
+ })
+ Expect(failures).ShouldNot(BeEmpty())
+
+ fastReader := SlowReader{
+ R: bytes.NewBuffer([]byte("abcdef")),
+ D: time.Millisecond,
+ }
+ buffer = BufferReader(fastReader)
+ Eventually(buffer, 100*time.Millisecond).Should(Say("abc"))
+ Eventually(buffer.Closed).Should(BeTrue())
+ })
+ })
+ })
+
+ 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)
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(n).Should(Equal(3))
+ Expect(string(dest)).Should(Equal("abc"))
+
+ dest = make([]byte, 3)
+ n, err = buffer.Read(dest)
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(n).Should(Equal(2))
+ Expect(string(dest[:n])).Should(Equal("de"))
+
+ n, err = buffer.Read(dest)
+ Expect(err).Should(Equal(io.EOF))
+ Expect(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)
+ Expect(err).Should(HaveOccurred())
+ Expect(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")
+ }
+
+ Expect(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")
+ Expect(buffer).ShouldNot(Say("abc"))
+ Expect(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
+ Expect(buffer).Should(Say("abcd"))
+ <-A
+ Expect(buffer).ShouldNot(Say("d"))
+ Expect(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())
+
+ Expect(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"))
+ Expect(err).ShouldNot(HaveOccurred())
+
+ buffer.Close()
+
+ _, err = buffer.Write([]byte("def"))
+ Expect(err).Should(HaveOccurred())
+
+ Expect(buffer.Contents()).Should(Equal([]byte("abc")))
+ })
+
+ It("should be closed", func() {
+ Expect(buffer.Closed()).Should(BeFalse())
+
+ buffer.Close()
+
+ Expect(buffer.Closed()).Should(BeTrue())
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/gbytes/gbuffer_suite_test.go b/vendor/github.com/onsi/gomega/gbytes/gbuffer_suite_test.go
new file mode 100644
index 000000000..3a7dc0612
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gbytes/gbuffer_suite_test.go
@@ -0,0 +1,13 @@
+package gbytes_test
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+
+ "testing"
+)
+
+func TestGbytes(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Gbytes Suite")
+}
diff --git a/vendor/github.com/onsi/gomega/gbytes/io_wrappers.go b/vendor/github.com/onsi/gomega/gbytes/io_wrappers.go
new file mode 100644
index 000000000..3caed8769
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gbytes/io_wrappers.go
@@ -0,0 +1,85 @@
+package gbytes
+
+import (
+ "errors"
+ "io"
+ "time"
+)
+
+// ErrTimeout is returned by TimeoutCloser, TimeoutReader, and TimeoutWriter when the underlying Closer/Reader/Writer does not return within the specified timeout
+var ErrTimeout = errors.New("timeout occurred")
+
+// TimeoutCloser returns an io.Closer that wraps the passed-in io.Closer. If the underlying Closer fails to close within the alloted timeout ErrTimeout is returned.
+func TimeoutCloser(c io.Closer, timeout time.Duration) io.Closer {
+ return timeoutReaderWriterCloser{c: c, d: timeout}
+}
+
+// TimeoutReader returns an io.Reader that wraps the passed-in io.Reader. If the underlying Reader fails to read within the alloted timeout ErrTimeout is returned.
+func TimeoutReader(r io.Reader, timeout time.Duration) io.Reader {
+ return timeoutReaderWriterCloser{r: r, d: timeout}
+}
+
+// TimeoutWriter returns an io.Writer that wraps the passed-in io.Writer. If the underlying Writer fails to write within the alloted timeout ErrTimeout is returned.
+func TimeoutWriter(w io.Writer, timeout time.Duration) io.Writer {
+ return timeoutReaderWriterCloser{w: w, d: timeout}
+}
+
+type timeoutReaderWriterCloser struct {
+ c io.Closer
+ w io.Writer
+ r io.Reader
+ d time.Duration
+}
+
+func (t timeoutReaderWriterCloser) Close() error {
+ done := make(chan struct{})
+ var err error
+
+ go func() {
+ err = t.c.Close()
+ close(done)
+ }()
+
+ select {
+ case <-done:
+ return err
+ case <-time.After(t.d):
+ return ErrTimeout
+ }
+}
+
+func (t timeoutReaderWriterCloser) Read(p []byte) (int, error) {
+ done := make(chan struct{})
+ var n int
+ var err error
+
+ go func() {
+ n, err = t.r.Read(p)
+ close(done)
+ }()
+
+ select {
+ case <-done:
+ return n, err
+ case <-time.After(t.d):
+ return 0, ErrTimeout
+ }
+}
+
+func (t timeoutReaderWriterCloser) Write(p []byte) (int, error) {
+ done := make(chan struct{})
+ var n int
+ var err error
+
+ go func() {
+ n, err = t.w.Write(p)
+ close(done)
+ }()
+
+ select {
+ case <-done:
+ return n, err
+ case <-time.After(t.d):
+ return 0, ErrTimeout
+ }
+}
diff --git a/vendor/github.com/onsi/gomega/gbytes/io_wrappers_test.go b/vendor/github.com/onsi/gomega/gbytes/io_wrappers_test.go
new file mode 100644
index 000000000..3da973498
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gbytes/io_wrappers_test.go
@@ -0,0 +1,188 @@
+package gbytes_test
+
+import (
+ "fmt"
+ "io"
+ "time"
+
+ . "github.com/onsi/gomega/gbytes"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+type FakeCloser struct {
+ err error
+ duration time.Duration
+}
+
+func (f FakeCloser) Close() error {
+ time.Sleep(f.duration)
+ return f.err
+}
+
+type FakeReader struct {
+ err error
+ duration time.Duration
+}
+
+func (f FakeReader) Read(p []byte) (int, error) {
+ time.Sleep(f.duration)
+ if f.err != nil {
+ return 0, f.err
+ }
+
+ for i := 0; i < len(p); i++ {
+ p[i] = 'a'
+ }
+
+ return len(p), nil
+}
+
+type FakeWriter struct {
+ err error
+ duration time.Duration
+}
+
+func (f FakeWriter) Write(p []byte) (int, error) {
+ time.Sleep(f.duration)
+ if f.err != nil {
+ return 0, f.err
+ }
+
+ return len(p), nil
+}
+
+var _ = Describe("Io Wrappers", func() {
+ Describe("TimeoutCloser", func() {
+ var innerCloser io.Closer
+ var timeoutCloser io.Closer
+
+ JustBeforeEach(func() {
+ timeoutCloser = TimeoutCloser(innerCloser, 20*time.Millisecond)
+ })
+
+ Context("when the underlying Closer closes with no error", func() {
+ BeforeEach(func() {
+ innerCloser = FakeCloser{}
+ })
+
+ It("returns with no error", func() {
+ Expect(timeoutCloser.Close()).Should(Succeed())
+ })
+ })
+
+ Context("when the underlying Closer closes with an error", func() {
+ BeforeEach(func() {
+ innerCloser = FakeCloser{err: fmt.Errorf("boom")}
+ })
+
+ It("returns the error", func() {
+ Expect(timeoutCloser.Close()).Should(MatchError("boom"))
+ })
+ })
+
+ Context("when the underlying Closer hangs", func() {
+ BeforeEach(func() {
+ innerCloser = FakeCloser{
+ err: fmt.Errorf("boom"),
+ duration: time.Hour,
+ }
+ })
+
+ It("returns ErrTimeout", func() {
+ Expect(timeoutCloser.Close()).Should(MatchError(ErrTimeout))
+ })
+ })
+ })
+
+ Describe("TimeoutReader", func() {
+ var innerReader io.Reader
+ var timeoutReader io.Reader
+
+ JustBeforeEach(func() {
+ timeoutReader = TimeoutReader(innerReader, 20*time.Millisecond)
+ })
+
+ Context("when the underlying Reader returns no error", func() {
+ BeforeEach(func() {
+ innerReader = FakeReader{}
+ })
+
+ It("returns with no error", func() {
+ p := make([]byte, 5)
+ n, err := timeoutReader.Read(p)
+ Expect(n).Should(Equal(5))
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(p).Should(Equal([]byte("aaaaa")))
+ })
+ })
+
+ Context("when the underlying Reader returns an error", func() {
+ BeforeEach(func() {
+ innerReader = FakeReader{err: fmt.Errorf("boom")}
+ })
+
+ It("returns the error", func() {
+ p := make([]byte, 5)
+ _, err := timeoutReader.Read(p)
+ Expect(err).Should(MatchError("boom"))
+ })
+ })
+
+ Context("when the underlying Reader hangs", func() {
+ BeforeEach(func() {
+ innerReader = FakeReader{err: fmt.Errorf("boom"), duration: time.Hour}
+ })
+
+ It("returns ErrTimeout", func() {
+ p := make([]byte, 5)
+ _, err := timeoutReader.Read(p)
+ Expect(err).Should(MatchError(ErrTimeout))
+ })
+ })
+ })
+
+ Describe("TimeoutWriter", func() {
+ var innerWriter io.Writer
+ var timeoutWriter io.Writer
+
+ JustBeforeEach(func() {
+ timeoutWriter = TimeoutWriter(innerWriter, 20*time.Millisecond)
+ })
+
+ Context("when the underlying Writer returns no error", func() {
+ BeforeEach(func() {
+ innerWriter = FakeWriter{}
+ })
+
+ It("returns with no error", func() {
+ n, err := timeoutWriter.Write([]byte("aaaaa"))
+ Expect(n).Should(Equal(5))
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+ })
+
+ Context("when the underlying Writer returns an error", func() {
+ BeforeEach(func() {
+ innerWriter = FakeWriter{err: fmt.Errorf("boom")}
+ })
+
+ It("returns the error", func() {
+ _, err := timeoutWriter.Write([]byte("aaaaa"))
+ Expect(err).Should(MatchError("boom"))
+ })
+ })
+
+ Context("when the underlying Writer hangs", func() {
+ BeforeEach(func() {
+ innerWriter = FakeWriter{err: fmt.Errorf("boom"), duration: time.Hour}
+ })
+
+ It("returns ErrTimeout", func() {
+ _, err := timeoutWriter.Write([]byte("aaaaa"))
+ Expect(err).Should(MatchError(ErrTimeout))
+ })
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/gbytes/say_matcher.go b/vendor/github.com/onsi/gomega/gbytes/say_matcher.go
new file mode 100644
index 000000000..14317182b
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gbytes/say_matcher.go
@@ -0,0 +1,104 @@
+package 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:
+
+ Expect(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 {
+ if len(args) > 0 {
+ expected = fmt.Sprintf(expected, args...)
+ }
+ return &sayMatcher{
+ re: regexp.MustCompile(expected),
+ }
+}
+
+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
+ }
+}
diff --git a/vendor/github.com/onsi/gomega/gbytes/say_matcher_test.go b/vendor/github.com/onsi/gomega/gbytes/say_matcher_test.go
new file mode 100644
index 000000000..0055d4a1b
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gbytes/say_matcher_test.go
@@ -0,0 +1,169 @@
+package gbytes_test
+
+import (
+ "time"
+
+ . "github.com/onsi/gomega/gbytes"
+
+ . "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() {
+ Expect("foo").Should(Say("foo"))
+ })
+ Expect(failures[0]).Should(ContainSubstring("*gbytes.Buffer"))
+ })
+ })
+
+ Context("when a match is found", func() {
+ It("should succeed", func() {
+ Expect(buffer).Should(Say("abc"))
+ })
+
+ It("should support printf-like formatting", func() {
+ Expect(buffer).Should(Say("a%sc", "b"))
+ })
+
+ It("should match literal %", func() {
+ buffer.Write([]byte("%"))
+ Expect(buffer).Should(Say("abc%"))
+ })
+
+ It("should use a regular expression", func() {
+ Expect(buffer).Should(Say("a.c"))
+ })
+
+ It("should fastforward the buffer", func() {
+ buffer.Write([]byte("def"))
+ Expect(buffer).Should(Say("abcd"))
+ Expect(buffer).Should(Say("ef"))
+ Expect(buffer).ShouldNot(Say("[a-z]"))
+ })
+ })
+
+ Context("when no match is found", func() {
+ It("should not error", func() {
+ Expect(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"))
+ Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond))
+ Expect(failures).Should(HaveLen(1))
+
+ t = time.Now()
+ Eventually(buffer).Should(Say("abc"))
+ Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond))
+ })
+
+ It("should abort a consistently", func() {
+ t := time.Now()
+ Consistently(buffer, 2.0).ShouldNot(Say("def"))
+ Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond))
+ })
+
+ It("should not error with a synchronous matcher", func() {
+ Expect(buffer).ShouldNot(Say("def"))
+ Expect(buffer).Should(Say("abc"))
+ })
+ })
+ })
+
+ Context("when a positive match fails", func() {
+ It("should report where it got stuck", func() {
+ Expect(buffer).Should(Say("abc"))
+ buffer.Write([]byte("def"))
+ failures := InterceptGomegaFailures(func() {
+ Expect(buffer).Should(Say("abc"))
+ })
+ Expect(failures[0]).Should(ContainSubstring("Got stuck at:"))
+ Expect(failures[0]).Should(ContainSubstring("def"))
+ })
+ })
+
+ Context("when a negative match fails", func() {
+ It("should report where it got stuck", func() {
+ failures := InterceptGomegaFailures(func() {
+ Expect(buffer).ShouldNot(Say("abc"))
+ })
+ Expect(failures[0]).Should(ContainSubstring("Saw:"))
+ Expect(failures[0]).Should(ContainSubstring("Which matches the unexpected:"))
+ Expect(failures[0]).Should(ContainSubstring("abc"))
+ })
+ })
+
+ Context("when a match is not found", func() {
+ It("should not fastforward the buffer", func() {
+ Expect(buffer).ShouldNot(Say("def"))
+ Expect(buffer).Should(Say("abc"))
+ })
+ })
+
+ Context("a nice real-life example", func() {
+ It("should behave well", func() {
+ Expect(buffer).Should(Say("abc"))
+ go func() {
+ time.Sleep(10 * time.Millisecond)
+ buffer.Write([]byte("def"))
+ }()
+ Expect(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(),
+ }
+
+ Expect(s).ShouldNot(Say("abc"))
+
+ s.Buffer().Write([]byte("abc"))
+ Expect(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"))
+ })
+ Expect(failures).Should(HaveLen(1))
+ Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond))
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/gexec/_fixture/firefly/main.go b/vendor/github.com/onsi/gomega/gexec/_fixture/firefly/main.go
new file mode 100644
index 000000000..16091c22b
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gexec/_fixture/firefly/main.go
@@ -0,0 +1,36 @@
+package 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)
+ }
+}
diff --git a/vendor/github.com/onsi/gomega/gexec/build.go b/vendor/github.com/onsi/gomega/gexec/build.go
new file mode 100644
index 000000000..869c1ead8
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gexec/build.go
@@ -0,0 +1,112 @@
+package gexec
+
+import (
+ "errors"
+ "fmt"
+ "go/build"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "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. If $GOPATH is not set and you are using Go 1.8+,
+it will use the default GOPATH instead. It passes the variadic args on to `go build`.
+*/
+func Build(packagePath string, args ...string) (compiledPath string, err error) {
+ return doBuild(build.Default.GOPATH, packagePath, nil, args...)
+}
+
+/*
+BuildWithEnvironment is identical to Build but allows you to specify env vars to be set at build time.
+*/
+func BuildWithEnvironment(packagePath string, env []string, args ...string) (compiledPath string, err error) {
+ return doBuild(build.Default.GOPATH, packagePath, env, 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) {
+ return doBuild(gopath, packagePath, nil, args...)
+}
+
+func replaceGoPath(environ []string, newGoPath string) []string {
+ newEnviron := []string{}
+ for _, v := range environ {
+ if !strings.HasPrefix(v, "GOPATH=") {
+ newEnviron = append(newEnviron, v)
+ }
+ }
+ return append(newEnviron, "GOPATH="+newGoPath)
+}
+
+func doBuild(gopath, packagePath string, env []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 = replaceGoPath(os.Environ(), gopath)
+ build.Env = append(build.Env, env...)
+
+ 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")
+}
diff --git a/vendor/github.com/onsi/gomega/gexec/build_test.go b/vendor/github.com/onsi/gomega/gexec/build_test.go
new file mode 100644
index 000000000..295dac8bc
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gexec/build_test.go
@@ -0,0 +1,112 @@
+package gexec_test
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ "github.com/onsi/gomega/gexec"
+)
+
+var packagePath = "./_fixture/firefly"
+
+var _ = Describe(".Build", func() {
+ Context("when there have been previous calls to Build", func() {
+ BeforeEach(func() {
+ _, err := gexec.Build(packagePath)
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+
+ It("compiles the specified package", func() {
+ compiledPath, err := gexec.Build(packagePath)
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(fireflyPath).Should(BeAnExistingFile())
+ })
+ })
+ })
+})
+
+var _ = Describe(".BuildWithEnvironment", func() {
+ var err error
+ env := []string{
+ "GOOS=linux",
+ "GOARCH=amd64",
+ }
+
+ It("compiles the specified package with the specified env vars", func() {
+ compiledPath, err := gexec.BuildWithEnvironment(packagePath, env)
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(compiledPath).Should(BeAnExistingFile())
+ })
+
+ It("returns the environment to a good state", func() {
+ _, err = gexec.BuildWithEnvironment(packagePath, env)
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(os.Environ()).ShouldNot(ContainElement("GOOS=linux"))
+ })
+})
+
+var _ = Describe(".BuildIn", func() {
+ const (
+ target = "github.com/onsi/gomega/gexec/_fixture/firefly/"
+ )
+
+ var (
+ original string
+ gopath string
+ )
+
+ BeforeEach(func() {
+ var err error
+ original = os.Getenv("GOPATH")
+ gopath, err = ioutil.TempDir("", "")
+ Expect(err).NotTo(HaveOccurred())
+ copyFile(filepath.Join("_fixture", "firefly", "main.go"), filepath.Join(gopath, "src", target), "main.go")
+ Expect(os.Setenv("GOPATH", filepath.Join(os.TempDir(), "emptyFakeGopath"))).To(Succeed())
+ Expect(os.Environ()).To(ContainElement(fmt.Sprintf("GOPATH=%s", filepath.Join(os.TempDir(), "emptyFakeGopath"))))
+ })
+
+ AfterEach(func() {
+ if original == "" {
+ Expect(os.Unsetenv("GOPATH")).To(Succeed())
+ } else {
+ Expect(os.Setenv("GOPATH", original)).To(Succeed())
+ }
+ if gopath != "" {
+ os.RemoveAll(gopath)
+ }
+ })
+
+ It("appends the gopath env var", func() {
+ _, err := gexec.BuildIn(gopath, target)
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ It("resets GOPATH to its original value", func() {
+ _, err := gexec.BuildIn(gopath, target)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(os.Getenv("GOPATH")).To(Equal(filepath.Join(os.TempDir(), "emptyFakeGopath")))
+ })
+})
+
+func copyFile(source, directory, basename string) {
+ Expect(os.MkdirAll(directory, 0755)).To(Succeed())
+ content, err := ioutil.ReadFile(source)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(ioutil.WriteFile(filepath.Join(directory, basename), content, 0644)).To(Succeed())
+}
diff --git a/vendor/github.com/onsi/gomega/gexec/exit_matcher.go b/vendor/github.com/onsi/gomega/gexec/exit_matcher.go
new file mode 100644
index 000000000..98a354937
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gexec/exit_matcher.go
@@ -0,0 +1,86 @@
+package gexec
+
+import (
+ "fmt"
+
+ "github.com/onsi/gomega/format"
+)
+
+/*
+The Exit matcher operates on a session:
+
+ Expect(session).Should(Exit(<optional status code>))
+
+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."
+ }
+ 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."
+ }
+ 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
+}
diff --git a/vendor/github.com/onsi/gomega/gexec/exit_matcher_test.go b/vendor/github.com/onsi/gomega/gexec/exit_matcher_test.go
new file mode 100644
index 000000000..9abc3226f
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gexec/exit_matcher_test.go
@@ -0,0 +1,114 @@
+package gexec_test
+
+import (
+ "os/exec"
+ "time"
+
+ . "github.com/onsi/gomega/gexec"
+
+ . "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)
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+
+ Describe("when passed something that is an Exiter", func() {
+ It("should act normally", func() {
+ failures := InterceptGomegaFailures(func() {
+ Expect(NeverExits{}).Should(Exit())
+ })
+
+ Expect(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() {
+ Expect("aardvark").Should(Exit())
+ })
+
+ Expect(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() {
+ Expect(session).ShouldNot(Exit())
+
+ failures := InterceptGomegaFailures(func() {
+ Expect(session).Should(Exit())
+ })
+
+ Expect(failures[0]).Should(ContainSubstring("Expected process to exit. It did not."))
+
+ Eventually(session).Should(Exit())
+
+ Expect(session).Should(Exit())
+
+ failures = InterceptGomegaFailures(func() {
+ Expect(session).ShouldNot(Exit())
+ })
+
+ Expect(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() {
+ Expect(session).ShouldNot(Exit(0))
+ Expect(session).ShouldNot(Exit(1))
+
+ failures := InterceptGomegaFailures(func() {
+ Expect(session).Should(Exit(0))
+ })
+
+ Expect(failures[0]).Should(ContainSubstring("Expected process to exit. It did not."))
+
+ Eventually(session).Should(Exit(0))
+
+ Expect(session).Should(Exit(0))
+
+ failures = InterceptGomegaFailures(func() {
+ Expect(session).Should(Exit(1))
+ })
+
+ Expect(failures[0]).Should(ContainSubstring("to match exit code:"))
+
+ Expect(session).ShouldNot(Exit(1))
+
+ failures = InterceptGomegaFailures(func() {
+ Expect(session).ShouldNot(Exit(0))
+ })
+
+ Expect(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))
+ })
+ Expect(time.Since(t)).Should(BeNumerically("<=", 500*time.Millisecond))
+ Expect(failures).Should(HaveLen(1))
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/gexec/gexec_suite_test.go b/vendor/github.com/onsi/gomega/gexec/gexec_suite_test.go
new file mode 100644
index 000000000..dc8e1f40c
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gexec/gexec_suite_test.go
@@ -0,0 +1,26 @@
+package 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")
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+
+ AfterSuite(func() {
+ gexec.CleanupBuildArtifacts()
+ })
+
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Gexec Suite")
+}
diff --git a/vendor/github.com/onsi/gomega/gexec/prefixed_writer.go b/vendor/github.com/onsi/gomega/gexec/prefixed_writer.go
new file mode 100644
index 000000000..05e695abc
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gexec/prefixed_writer.go
@@ -0,0 +1,53 @@
+package 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
+}
diff --git a/vendor/github.com/onsi/gomega/gexec/prefixed_writer_test.go b/vendor/github.com/onsi/gomega/gexec/prefixed_writer_test.go
new file mode 100644
index 000000000..e847b1501
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gexec/prefixed_writer_test.go
@@ -0,0 +1,43 @@
+package 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"))
+
+ Expect(buffer.String()).Should(Equal(`[p]abcdef
+[p]hij
+[p]
+[p]
+[p]klm
+[p]
+[p]nopqrs
+[p]tuv
+[p]wxyz
+[p]
+`))
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/gexec/session.go b/vendor/github.com/onsi/gomega/gexec/session.go
new file mode 100644
index 000000000..5cb00ca65
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gexec/session.go
@@ -0,0 +1,303 @@
+/*
+Package gexec provides support for testing external processes.
+*/
+package gexec
+
+import (
+ "io"
+ "os"
+ "os/exec"
+ "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:
+
+ Expect(session.Out).Should(gbytes.Say("foo-out"))
+ Expect(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:
+
+ Expect(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:
+
+ Expect(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 {
+ commandOut = io.MultiWriter(commandOut, outWriter)
+ }
+
+ if errWriter != nil {
+ commandErr = io.MultiWriter(commandErr, errWriter)
+ }
+
+ command.Stdout = commandOut
+ command.Stderr = commandErr
+
+ err := command.Start()
+ if err == nil {
+ go session.monitorForExit(exited)
+ trackedSessionsMutex.Lock()
+ defer trackedSessionsMutex.Unlock()
+ trackedSessions = append(trackedSessions, session)
+ }
+
+ 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 {
+ return s.Signal(syscall.SIGKILL)
+}
+
+/*
+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)
+}
+
+/*
+Signal 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.processIsAlive() {
+ 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)
+}
+
+func (s *Session) processIsAlive() bool {
+ return s.ExitCode() == -1 && s.Command.Process != nil
+}
+
+var trackedSessions = []*Session{}
+var trackedSessionsMutex = &sync.Mutex{}
+
+/*
+Kill sends a SIGKILL signal to all the processes started by Run, and waits for them to exit.
+The timeout specified is applied to each process killed.
+
+If any of the processes already exited, KillAndWait returns silently.
+*/
+func KillAndWait(timeout ...interface{}) {
+ trackedSessionsMutex.Lock()
+ defer trackedSessionsMutex.Unlock()
+ for _, session := range trackedSessions {
+ session.Kill().Wait(timeout...)
+ }
+ trackedSessions = []*Session{}
+}
+
+/*
+Kill sends a SIGTERM signal to all the processes started by Run, and waits for them to exit.
+The timeout specified is applied to each process killed.
+
+If any of the processes already exited, TerminateAndWait returns silently.
+*/
+func TerminateAndWait(timeout ...interface{}) {
+ trackedSessionsMutex.Lock()
+ defer trackedSessionsMutex.Unlock()
+ for _, session := range trackedSessions {
+ session.Terminate().Wait(timeout...)
+ }
+}
+
+/*
+Kill sends a SIGKILL signal to all the processes started by Run.
+It does not wait for the processes to exit.
+
+If any of the processes already exited, Kill returns silently.
+*/
+func Kill() {
+ trackedSessionsMutex.Lock()
+ defer trackedSessionsMutex.Unlock()
+ for _, session := range trackedSessions {
+ session.Kill()
+ }
+}
+
+/*
+Terminate sends a SIGTERM signal to all the processes started by Run.
+It does not wait for the processes to exit.
+
+If any of the processes already exited, Terminate returns silently.
+*/
+func Terminate() {
+ trackedSessionsMutex.Lock()
+ defer trackedSessionsMutex.Unlock()
+ for _, session := range trackedSessions {
+ session.Terminate()
+ }
+}
+
+/*
+Signal sends the passed in signal to all the processes started by Run.
+It does not wait for the processes to exit.
+
+If any of the processes already exited, Signal returns silently.
+*/
+func Signal(signal os.Signal) {
+ trackedSessionsMutex.Lock()
+ defer trackedSessionsMutex.Unlock()
+ for _, session := range trackedSessions {
+ session.Signal(signal)
+ }
+}
+
+/*
+Interrupt sends the SIGINT signal to all the processes started by Run.
+It does not wait for the processes to exit.
+
+If any of the processes already exited, Interrupt returns silently.
+*/
+func Interrupt() {
+ trackedSessionsMutex.Lock()
+ defer trackedSessionsMutex.Unlock()
+ for _, session := range trackedSessions {
+ session.Interrupt()
+ }
+}
diff --git a/vendor/github.com/onsi/gomega/gexec/session_test.go b/vendor/github.com/onsi/gomega/gexec/session_test.go
new file mode 100644
index 000000000..6fdf22d21
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gexec/session_test.go
@@ -0,0 +1,336 @@
+package gexec_test
+
+import (
+ "io"
+ "io/ioutil"
+ "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 io.Writer
+
+ BeforeEach(func() {
+ outWriter = nil
+ errWriter = nil
+ })
+
+ JustBeforeEach(func() {
+ command = exec.Command(fireflyPath)
+ var err error
+ session, err = Start(command, outWriter, errWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+
+ Context("running a command", func() {
+ It("should start the process", func() {
+ Expect(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() {
+ Expect(session.ExitCode()).Should(Equal(-1))
+
+ Eventually(session).Should(Exit())
+ Expect(session.ExitCode()).Should(BeNumerically(">=", 0))
+ Expect(session.ExitCode()).Should(BeNumerically("<", 3))
+ })
+ })
+
+ Describe("wait", func() {
+ It("should wait till the command exits", func() {
+ Expect(session.ExitCode()).Should(Equal(-1))
+ Expect(session.Wait().ExitCode()).Should(BeNumerically(">=", 0))
+ Expect(session.Wait().ExitCode()).Should(BeNumerically("<", 3))
+ })
+ })
+
+ Describe("exited", func() {
+ It("should close when the command exits", func() {
+ Eventually(session.Exited).Should(BeClosed())
+ Expect(session.ExitCode()).ShouldNot(Equal(-1))
+ })
+ })
+
+ Describe("kill", func() {
+ It("should kill the command", func() {
+ session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ session.Kill()
+ Eventually(session).Should(Exit(128 + 9))
+ })
+ })
+
+ Describe("interrupt", func() {
+ It("should interrupt the command", func() {
+ session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ session.Interrupt()
+ Eventually(session).Should(Exit(128 + 2))
+ })
+ })
+
+ Describe("terminate", func() {
+ It("should terminate the command", func() {
+ session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ session.Terminate()
+ 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)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ session.Signal(syscall.SIGABRT)
+ Eventually(session).Should(Exit(128 + 6))
+ })
+
+ It("should ignore sending a signal if the command did not start", func() {
+ session, err := Start(exec.Command("notexisting"), GinkgoWriter, GinkgoWriter)
+ Expect(err).To(HaveOccurred())
+
+ Expect(func() { session.Signal(syscall.SIGUSR1) }).NotTo(Panic())
+ })
+ })
+
+ Context("tracking sessions", func() {
+ BeforeEach(func() {
+ KillAndWait()
+ })
+
+ Describe("kill", func() {
+ It("should kill all the started sessions", func() {
+ session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Kill()
+
+ Eventually(session1).Should(Exit(128 + 9))
+ Eventually(session2).Should(Exit(128 + 9))
+ Eventually(session3).Should(Exit(128 + 9))
+ })
+
+ It("should not track unstarted sessions", func() {
+ _, err := Start(exec.Command("does not exist", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).Should(HaveOccurred())
+
+ session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Kill()
+
+ Eventually(session2).Should(Exit(128 + 9))
+ Eventually(session3).Should(Exit(128 + 9))
+ })
+
+ })
+
+ Describe("killAndWait", func() {
+ It("should kill all the started sessions and wait for them to finish", func() {
+ session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ KillAndWait()
+ Expect(session1).Should(Exit(128+9), "Should have exited")
+ Expect(session2).Should(Exit(128+9), "Should have exited")
+ Expect(session3).Should(Exit(128+9), "Should have exited")
+ })
+ })
+
+ Describe("terminate", func() {
+ It("should terminate all the started sessions", func() {
+ session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Terminate()
+
+ Eventually(session1).Should(Exit(128 + 15))
+ Eventually(session2).Should(Exit(128 + 15))
+ Eventually(session3).Should(Exit(128 + 15))
+ })
+ })
+
+ Describe("terminateAndWait", func() {
+ It("should terminate all the started sessions, and wait for them to exit", func() {
+ session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ TerminateAndWait()
+
+ Expect(session1).Should(Exit(128+15), "Should have exited")
+ Expect(session2).Should(Exit(128+15), "Should have exited")
+ Expect(session3).Should(Exit(128+15), "Should have exited")
+ })
+ })
+
+ Describe("signal", func() {
+ It("should signal all the started sessions", func() {
+ session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Signal(syscall.SIGABRT)
+
+ Eventually(session1).Should(Exit(128 + 6))
+ Eventually(session2).Should(Exit(128 + 6))
+ Eventually(session3).Should(Exit(128 + 6))
+ })
+ })
+
+ Describe("interrupt", func() {
+ It("should interrupt all the started sessions, and not wait", func() {
+ session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Interrupt()
+
+ Eventually(session1).Should(Exit(128 + 2))
+ Eventually(session2).Should(Exit(128 + 2))
+ Eventually(session3).Should(Exit(128 + 2))
+ })
+ })
+ })
+
+ Context("when the command exits", func() {
+ It("should close the buffers", func() {
+ Eventually(session).Should(Exit())
+
+ Expect(session.Out.Closed()).Should(BeTrue())
+ Expect(session.Err.Closed()).Should(BeTrue())
+
+ Expect(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"))
+ })
+ Expect(time.Since(t)).Should(BeNumerically("<=", 500*time.Millisecond))
+ Expect(failures).Should(HaveLen(1))
+ })
+ })
+
+ Context("when wrapping out and err", func() {
+ var (
+ outWriterBuffer, errWriterBuffer *Buffer
+ )
+
+ BeforeEach(func() {
+ outWriterBuffer = NewBuffer()
+ outWriter = outWriterBuffer
+ errWriterBuffer = NewBuffer()
+ errWriter = errWriterBuffer
+ })
+
+ 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!"))
+
+ Expect(outWriterBuffer.Contents()).Should(ContainSubstring("We've done the impossible, and that makes us mighty"))
+ Expect(errWriterBuffer.Contents()).Should(ContainSubstring("Ah, curse your sudden but inevitable betrayal!"))
+
+ Eventually(session).Should(Exit())
+
+ Expect(outWriterBuffer.Contents()).Should(Equal(session.Out.Contents()))
+ Expect(errWriterBuffer.Contents()).Should(Equal(session.Err.Contents()))
+ })
+
+ Context("when discarding the output of the command", func() {
+ BeforeEach(func() {
+ outWriter = ioutil.Discard
+ errWriter = ioutil.Discard
+ })
+
+ It("executes succesfuly", func() {
+ Eventually(session).Should(Exit())
+ })
+ })
+ })
+
+ Describe("when the command fails to start", func() {
+ It("should return an error", func() {
+ _, err := Start(exec.Command("agklsjdfas"), nil, nil)
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/ghttp/handlers.go b/vendor/github.com/onsi/gomega/ghttp/handlers.go
new file mode 100644
index 000000000..894eae6d4
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/ghttp/handlers.go
@@ -0,0 +1,322 @@
+package ghttp
+
+import (
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "reflect"
+ "strings"
+
+ "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) {
+ Expect(req.Method).Should(Equal(method), "Method mismatch")
+ switch p := path.(type) {
+ case types.GomegaMatcher:
+ Expect(req.URL.Path).Should(p, "Path mismatch")
+ default:
+ Expect(req.URL.Path).Should(Equal(path), "Path mismatch")
+ }
+ if len(rawQuery) > 0 {
+ values, err := url.ParseQuery(rawQuery[0])
+ Expect(err).ShouldNot(HaveOccurred(), "Expected RawQuery is malformed")
+
+ Expect(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) {
+ Expect(req.Header.Get("Content-Type")).Should(Equal(contentType))
+ }
+}
+
+//VerifyMimeType returns a handler that verifies that a request has a specified mime type set
+//in Content-Type header
+func VerifyMimeType(mimeType string) http.HandlerFunc {
+ return func(w http.ResponseWriter, req *http.Request) {
+ Expect(strings.Split(req.Header.Get("Content-Type"), ";")[0]).Should(Equal(mimeType))
+ }
+}
+
+//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")
+ Expect(auth).ShouldNot(Equal(""), "Authorization header must be specified")
+
+ decoded, err := base64.StdEncoding.DecodeString(auth[6:])
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(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)
+ Expect(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()
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(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(
+ VerifyMimeType("application/json"),
+ func(w http.ResponseWriter, req *http.Request) {
+ body, err := ioutil.ReadAll(req.Body)
+ req.Body.Close()
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(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)
+ Expect(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()
+ Expect(err).ShouldNot(HaveOccurred())
+ for key, vals := range values {
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+ req.Body.Close()
+
+ expectedType := reflect.TypeOf(expected)
+ actualValuePtr := reflect.New(expectedType.Elem())
+
+ actual, ok := actualValuePtr.Interface().(proto.Message)
+ Expect(ok).Should(BeTrue(), "Message value is not a proto.Message")
+
+ err = proto.Unmarshal(body, actual)
+ Expect(err).ShouldNot(HaveOccurred(), "Failed to unmarshal protobuf")
+
+ Expect(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:
+ Expect(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:
+ Expect(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)
+ Expect(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)
+ Expect(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)
+ Expect(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)
+ }
+}
diff --git a/vendor/github.com/onsi/gomega/ghttp/protobuf/protobuf.go b/vendor/github.com/onsi/gomega/ghttp/protobuf/protobuf.go
new file mode 100644
index 000000000..b2972bc9f
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/ghttp/protobuf/protobuf.go
@@ -0,0 +1,3 @@
+package protobuf
+
+//go:generate protoc --go_out=. simple_message.proto
diff --git a/vendor/github.com/onsi/gomega/ghttp/protobuf/simple_message.pb.go b/vendor/github.com/onsi/gomega/ghttp/protobuf/simple_message.pb.go
new file mode 100644
index 000000000..c55a48448
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/ghttp/protobuf/simple_message.pb.go
@@ -0,0 +1,55 @@
+// 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 ""
+}
diff --git a/vendor/github.com/onsi/gomega/ghttp/protobuf/simple_message.proto b/vendor/github.com/onsi/gomega/ghttp/protobuf/simple_message.proto
new file mode 100644
index 000000000..35b7145c2
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/ghttp/protobuf/simple_message.proto
@@ -0,0 +1,9 @@
+syntax = "proto2";
+
+package protobuf;
+
+message SimpleMessage {
+ required string description = 1;
+ required int32 id = 2;
+ optional string metadata = 3;
+}
diff --git a/vendor/github.com/onsi/gomega/ghttp/test_server.go b/vendor/github.com/onsi/gomega/ghttp/test_server.go
new file mode 100644
index 000000000..77535f309
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/ghttp/test_server.go
@@ -0,0 +1,422 @@
+/*
+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() {
+ Expect(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() {
+ Expect(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()
+ Expect(sprockets).Should(BeEmpty())
+ Expect(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()
+ Expect(sprockets).Should(BeEmpty())
+ Expect(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() {
+ Expect(client.Sprockets("food")).Should(Equal(sprockets))
+ })
+ })
+ })
+ })
+*/
+package ghttp
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/http/httptest"
+ "net/http/httputil"
+ "reflect"
+ "regexp"
+ "strings"
+ "sync"
+
+ . "github.com/onsi/gomega"
+)
+
+func new() *Server {
+ return &Server{
+ AllowUnhandledRequests: false,
+ UnhandledRequestStatusCode: http.StatusInternalServerError,
+ rwMutex: &sync.RWMutex{},
+ }
+}
+
+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.
+ //Direct use of this property is deprecated and is likely to be removed, use GetAllowUnhandledRequests and SetAllowUnhandledRequests instead.
+ AllowUnhandledRequests bool
+
+ //The status code returned when receiving an unhandled request.
+ //Defaults to http.StatusInternalServerError.
+ //Only applies if AllowUnhandledRequests is true
+ //Direct use of this property is deprecated and is likely to be removed, use GetUnhandledRequestStatusCode and SetUnhandledRequestStatusCode instead.
+ 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
+
+ rwMutex *sync.RWMutex
+ 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 {
+ s.rwMutex.RLock()
+ defer s.rwMutex.RUnlock()
+ return s.HTTPTestServer.URL
+}
+
+//Addr() returns the address on which the server is listening.
+func (s *Server) Addr() string {
+ s.rwMutex.RLock()
+ defer s.rwMutex.RUnlock()
+ 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.rwMutex.Lock()
+ server := s.HTTPTestServer
+ s.HTTPTestServer = nil
+ s.rwMutex.Unlock()
+
+ 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 set to 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.rwMutex.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()
+ }()
+ Expect(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.rwMutex.Unlock()
+ routedHandler(w, req)
+ } else if s.calls < len(s.requestHandlers) {
+ h := s.requestHandlers[s.calls]
+ s.calls++
+ s.rwMutex.Unlock()
+ h(w, req)
+ } else {
+ s.rwMutex.Unlock()
+ if s.GetAllowUnhandledRequests() {
+ ioutil.ReadAll(req.Body)
+ req.Body.Close()
+ w.WriteHeader(s.GetUnhandledRequestStatusCode())
+ } else {
+ formatted, err := httputil.DumpRequest(req, true)
+ Expect(err).NotTo(HaveOccurred(), "Encountered error while dumping HTTP request")
+ Expect(string(formatted)).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.rwMutex.RLock()
+ defer s.rwMutex.RUnlock()
+
+ 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.rwMutex.Lock()
+ defer s.rwMutex.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.rwMutex.Lock()
+ defer s.rwMutex.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.rwMutex.Lock()
+ defer s.rwMutex.Unlock()
+
+ s.requestHandlers[index] = handler
+}
+
+//GetHandler returns the handler registered at the passed in index.
+func (s *Server) GetHandler(index int) http.HandlerFunc {
+ s.rwMutex.RLock()
+ defer s.rwMutex.RUnlock()
+
+ return s.requestHandlers[index]
+}
+
+func (s *Server) Reset() {
+ s.rwMutex.Lock()
+ defer s.rwMutex.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.rwMutex.Lock()
+ defer s.rwMutex.Unlock()
+
+ s.HTTPTestServer.CloseClientConnections()
+}
+
+//SetAllowUnhandledRequests enables the server to accept unhandled requests.
+func (s *Server) SetAllowUnhandledRequests(allowUnhandledRequests bool) {
+ s.rwMutex.Lock()
+ defer s.rwMutex.Unlock()
+
+ s.AllowUnhandledRequests = allowUnhandledRequests
+}
+
+//GetAllowUnhandledRequests returns true if the server accepts unhandled requests.
+func (s *Server) GetAllowUnhandledRequests() bool {
+ s.rwMutex.RLock()
+ defer s.rwMutex.RUnlock()
+
+ return s.AllowUnhandledRequests
+}
+
+//SetUnhandledRequestStatusCode status code to be returned when the server receives unhandled requests
+func (s *Server) SetUnhandledRequestStatusCode(statusCode int) {
+ s.rwMutex.Lock()
+ defer s.rwMutex.Unlock()
+
+ s.UnhandledRequestStatusCode = statusCode
+}
+
+//GetUnhandledRequestStatusCode returns the current status code being returned for unhandled requests
+func (s *Server) GetUnhandledRequestStatusCode() int {
+ s.rwMutex.RLock()
+ defer s.rwMutex.RUnlock()
+
+ return s.UnhandledRequestStatusCode
+}
diff --git a/vendor/github.com/onsi/gomega/ghttp/test_server_suite_test.go b/vendor/github.com/onsi/gomega/ghttp/test_server_suite_test.go
new file mode 100644
index 000000000..7c1236082
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/ghttp/test_server_suite_test.go
@@ -0,0 +1,13 @@
+package ghttp_test
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+
+ "testing"
+)
+
+func TestGHTTP(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "GHTTP Suite")
+}
diff --git a/vendor/github.com/onsi/gomega/ghttp/test_server_test.go b/vendor/github.com/onsi/gomega/ghttp/test_server_test.go
new file mode 100644
index 000000000..be1c58e82
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/ghttp/test_server_test.go
@@ -0,0 +1,1129 @@
+package 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() + "/")
+
+ Expect(s.ReceivedRequests()).Should(HaveLen(1))
+ })
+
+ It("clears all handlers and call counts", func() {
+ s.Reset()
+ Expect(s.ReceivedRequests()).Should(HaveLen(0))
+ Expect(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())
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(resp.StatusCode).Should(Equal(200))
+
+ body, err := ioutil.ReadAll(resp.Body)
+ resp.Body.Close()
+ Expect(err).ShouldNot(HaveOccurred())
+
+ s.CloseClientConnections()
+
+ resp, err = client.Get(s.URL())
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(resp.StatusCode).Should(Equal(200))
+
+ body2, err := ioutil.ReadAll(resp.Body)
+ resp.Body.Close()
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(body2).ShouldNot(Equal(body))
+ })
+ })
+
+ Describe("closing server mulitple times", func() {
+ It("should not fail", func() {
+ s.Close()
+ Expect(s.Close).ShouldNot(Panic())
+ })
+ })
+
+ Describe("allowing unhandled requests", func() {
+ It("is not permitted by default", func() {
+ Expect(s.GetAllowUnhandledRequests()).To(BeFalse())
+ })
+
+ Context("when true", func() {
+ BeforeEach(func() {
+ s.SetAllowUnhandledRequests(true)
+ s.SetUnhandledRequestStatusCode(http.StatusForbidden)
+ resp, err = http.Get(s.URL() + "/foo")
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should allow unhandled requests and respond with the passed in status code", func() {
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(resp.StatusCode).Should(Equal(http.StatusForbidden))
+
+ data, err := ioutil.ReadAll(resp.Body)
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(data).Should(BeEmpty())
+ })
+
+ It("should record the requests", func() {
+ Expect(s.ReceivedRequests()).Should(HaveLen(1))
+ Expect(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")
+ })
+
+ Expect(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)
+ })
+
+ Expect(failures[0]).Should(ContainSubstring("Received Unhandled Request"))
+ Expect(failures).Should(HaveLen(4))
+
+ http.Post(s.URL()+"/routed3", "application/json", nil)
+
+ Expect(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)
+
+ Expect(called).Should(Equal([]string{"r3", "r4"}))
+ })
+
+ It("should call the appended handlers, in order, as requests come in", func() {
+ http.Get(s.URL() + "/foo")
+ Expect(called).Should(Equal([]string{"A"}))
+
+ http.Get(s.URL() + "/foo")
+ Expect(called).Should(Equal([]string{"A", "B"}))
+
+ failures := InterceptGomegaFailures(func() {
+ http.Get(s.URL() + "/foo")
+ })
+
+ Expect(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")
+ Expect(called).Should(Equal([]string{"C", "B"}))
+ })
+ })
+
+ Describe("Getting an existing handler", func() {
+ It("should return the handler func", func() {
+ s.GetHandler(1)(nil, nil)
+ Expect(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")
+ Expect(called).Should(Equal([]string{"A", "C", "B"}))
+ })
+ })
+ })
+
+ Describe("When a handler fails", func() {
+ BeforeEach(func() {
+ s.SetUnhandledRequestStatusCode(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())
+ })
+
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(resp.StatusCode).Should(Equal(http.StatusInternalServerError))
+ Expect(failures).Should(ConsistOf(ContainSubstring("Handler Panicked")))
+ })
+ })
+
+ Context("because an assertion has failed", func() {
+ BeforeEach(func() {
+ s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) {
+ // Expect(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())
+
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(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")
+ Expect(buf).Should(gbytes.Say("GHTTP Received Request: GET - /foo\n"))
+
+ http.Post(s.URL()+"/bar", "", nil)
+ Expect(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")
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should verify the method, path", func() {
+ failures := InterceptGomegaFailures(func() {
+ http.Get(s.URL() + "/foo2")
+ })
+ Expect(failures).Should(HaveLen(1))
+ })
+
+ It("should verify the method, path", func() {
+ failures := InterceptGomegaFailures(func() {
+ http.Post(s.URL()+"/foo", "application/json", nil)
+ })
+ Expect(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")
+ Expect(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())
+ Expect(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")
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+ req.Header.Set("Content-Type", "application/octet-stream")
+
+ resp, err = http.DefaultClient.Do(req)
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should verify the content type", func() {
+ req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
+ Expect(err).ShouldNot(HaveOccurred())
+ req.Header.Set("Content-Type", "application/json")
+
+ failures := InterceptGomegaFailures(func() {
+ http.DefaultClient.Do(req)
+ })
+ Expect(failures).Should(HaveLen(1))
+ })
+
+ It("should verify the content type", func() {
+ req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
+ Expect(err).ShouldNot(HaveOccurred())
+ req.Header.Set("Content-Type", "application/octet-stream; charset=utf-8")
+
+ failures := InterceptGomegaFailures(func() {
+ http.DefaultClient.Do(req)
+ })
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+ req.SetBasicAuth("bob", "password")
+
+ resp, err = http.DefaultClient.Do(req)
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should verify basic auth", func() {
+ req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
+ Expect(err).ShouldNot(HaveOccurred())
+ req.SetBasicAuth("bob", "bassword")
+
+ failures := InterceptGomegaFailures(func() {
+ http.DefaultClient.Do(req)
+ })
+ Expect(failures).Should(HaveLen(1))
+ })
+
+ It("should require basic auth header", func() {
+ req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ failures := InterceptGomegaFailures(func() {
+ http.DefaultClient.Do(req)
+ })
+ Expect(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)
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should verify the headers", func() {
+ req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
+ Expect(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)
+ })
+ Expect(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)
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should verify the headers", func() {
+ req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
+ Expect(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)
+ })
+ Expect(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")))
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should verify the body", func() {
+ failures := InterceptGomegaFailures(func() {
+ http.Post(s.URL()+"/foo", "", bytes.NewReader([]byte("wrong body")))
+ })
+ Expect(failures).Should(HaveLen(1))
+ })
+ })
+
+ Describe("VerifyMimeType", func() {
+ BeforeEach(func() {
+ s.AppendHandlers(CombineHandlers(
+ VerifyMimeType("application/json"),
+ ))
+ })
+
+ It("should verify the mime type in content-type header", func() {
+ resp, err = http.Post(s.URL()+"/foo", "application/json; charset=utf-8", bytes.NewReader([]byte(`{}`)))
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should verify the mime type in content-type header", func() {
+ failures := InterceptGomegaFailures(func() {
+ http.Post(s.URL()+"/foo", "text/plain", bytes.NewReader([]byte(`{}`)))
+ })
+ Expect(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}`)))
+ Expect(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}`)))
+ })
+ Expect(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}`)))
+ })
+ Expect(failures).Should(HaveLen(1))
+ })
+
+ It("should verify the json body and the content type", func() {
+ resp, err = http.Post(s.URL()+"/foo", "application/json; charset=utf-8", bytes.NewReader([]byte(`{"b":2, "a":3}`)))
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+ })
+
+ 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]`)))
+ Expect(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]`)))
+ })
+ Expect(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())
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should ignore extra values", func() {
+ formValues.Add("extra", "value")
+ resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode())
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+
+ It("fail on missing values", func() {
+ formValues.Del("group")
+ failures := InterceptGomegaFailures(func() {
+ resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode())
+ })
+ Expect(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())
+ })
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should ignore extra values", func() {
+ formValues.Add("extra", "value")
+ resp, err = http.PostForm(s.URL()+"/foo", formValues)
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+
+ It("fail on missing values", func() {
+ formValues.Del("group")
+ failures := InterceptGomegaFailures(func() {
+ resp, err = http.PostForm(s.URL()+"/foo", formValues)
+ })
+ Expect(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)
+ })
+ Expect(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")
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+
+ It("verifies the form value", func() {
+ failures := InterceptGomegaFailures(func() {
+ resp, err = http.Get(s.URL() + "/foo?users=user1")
+ })
+ Expect(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"}})
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+
+ It("verifies the form value", func() {
+ failures := InterceptGomegaFailures(func() {
+ resp, err = http.PostForm(s.URL()+"/foo", url.Values{"users": []string{"user1"}})
+ })
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", bytes.NewReader(serialized))
+ Expect(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"),
+ })
+ Expect(err).ShouldNot(HaveOccurred())
+
+ failures := InterceptGomegaFailures(func() {
+ http.Post(s.URL()+"/proto", "application/x-protobuf", bytes.NewReader(serialized))
+ })
+ Expect(failures).Should(HaveLen(1))
+ })
+
+ It("should verify the proto body and the content type", func() {
+ serialized, err := proto.Marshal(message)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ failures := InterceptGomegaFailures(func() {
+ http.Post(s.URL()+"/proto", "application/not-x-protobuf", bytes.NewReader(serialized))
+ })
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(resp.StatusCode).Should(Equal(http.StatusCreated))
+
+ body, err := ioutil.ReadAll(resp.Body)
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(body).Should(Equal([]byte("sweet")))
+
+ resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(resp.StatusCode).Should(Equal(http.StatusOK))
+
+ body, err = ioutil.ReadAll(resp.Body)
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(resp.StatusCode).Should(Equal(http.StatusCreated))
+ Expect(ioutil.ReadAll(resp.Body)).Should(Equal([]byte("sweet")))
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(resp.StatusCode).Should(Equal(http.StatusCreated))
+
+ body, err := ioutil.ReadAll(resp.Body)
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(body).Should(Equal([]byte("tasty")))
+
+ resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(resp.StatusCode).Should(Equal(http.StatusCreated))
+
+ body, err = ioutil.ReadAll(resp.Body)
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(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)
+
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(resp.StatusCode).Should(Equal(http.StatusOK))
+ body, err := ioutil.ReadAll(resp.Body)
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(body).Should(BeEmpty())
+
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(resp.StatusCode).Should(Equal(http.StatusCreated))
+
+ body, err := ioutil.ReadAll(resp.Body)
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(resp.StatusCode).Should(Equal(http.StatusCreated))
+
+ body, err := ioutil.ReadAll(resp.Body)
+ Expect(err).ShouldNot(HaveOccurred())
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(resp.StatusCode).Should(Equal(http.StatusCreated))
+
+ var received protobuf.SimpleMessage
+ body, err := ioutil.ReadAll(resp.Body)
+ err = proto.Unmarshal(body, &received)
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(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)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ Expect(resp.Header["Content-Type"]).Should(Equal([]string{"not-x-protobuf"}))
+ })
+ })
+ })
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/go.mod b/vendor/github.com/onsi/gomega/go.mod
new file mode 100644
index 000000000..65eedf696
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/go.mod
@@ -0,0 +1,15 @@
+module github.com/onsi/gomega
+
+require (
+ github.com/fsnotify/fsnotify v1.4.7 // indirect
+ github.com/golang/protobuf v1.2.0
+ github.com/hpcloud/tail v1.0.0 // indirect
+ github.com/onsi/ginkgo v1.6.0
+ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd
+ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f // indirect
+ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e // indirect
+ golang.org/x/text v0.3.0 // indirect
+ gopkg.in/fsnotify.v1 v1.4.7 // indirect
+ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
+ gopkg.in/yaml.v2 v2.2.1
+)
diff --git a/vendor/github.com/onsi/gomega/go.sum b/vendor/github.com/onsi/gomega/go.sum
new file mode 100644
index 000000000..b23f6ef02
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/go.sum
@@ -0,0 +1,24 @@
+github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/vendor/github.com/onsi/gomega/gomega_dsl.go b/vendor/github.com/onsi/gomega/gomega_dsl.go
new file mode 100644
index 000000000..471f691a6
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gomega_dsl.go
@@ -0,0 +1,421 @@
+/*
+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.4.3"
+
+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().
+Depending on your vendoring solution you may be inadvertently importing gomega and subpackages (e.g. ghhtp, gexec,...) from different locations.
+`
+
+var globalFailWrapper *types.GomegaFailWrapper
+
+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) {
+ if handler == nil {
+ globalFailWrapper = nil
+ return
+ }
+
+ globalFailWrapper = &types.GomegaFailWrapper{
+ Fail: handler,
+ TWithHelper: testingtsupport.EmptyTWithHelper{},
+ }
+}
+
+func RegisterFailHandlerWithT(t types.TWithHelper, handler types.GomegaFailHandler) {
+ if handler == nil {
+ globalFailWrapper = nil
+ return
+ }
+
+ globalFailWrapper = &types.GomegaFailWrapper{
+ Fail: handler,
+ TWithHelper: t,
+ }
+}
+
+//RegisterTestingT connects Gomega to Golang's XUnit style
+//Testing.T tests. It is now deprecated and you should use NewGomegaWithT() instead.
+//
+//Legacy Documentation:
+//
+//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.
+//
+// NewGomegaWithT() does not have this limitation
+//
+// (As an aside: Ginkgo gets around this limitation by running parallel tests in different *processes*).
+func RegisterTestingT(t types.GomegaTestingT) {
+ tWithHelper, hasHelper := t.(types.TWithHelper)
+ if !hasHelper {
+ RegisterFailHandler(testingtsupport.BuildTestingTGomegaFailWrapper(t).Fail)
+ return
+ }
+ RegisterFailHandlerWithT(tWithHelper, testingtsupport.BuildTestingTGomegaFailWrapper(t).Fail)
+}
+
+//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 := globalFailWrapper.Fail
+ 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 globalFailWrapper == nil {
+ panic(nilFailHandlerPanic)
+ }
+ return assertion.New(actual, globalFailWrapper, 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 globalFailWrapper == 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, globalFailWrapper, 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 globalFailWrapper == 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, globalFailWrapper, 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
+
+//GomegaWithT wraps a *testing.T and provides `Expect`, `Eventually`, and `Consistently` methods. This allows you to leverage
+//Gomega's rich ecosystem of matchers in standard `testing` test suites.
+//
+//Use `NewGomegaWithT` to instantiate a `GomegaWithT`
+type GomegaWithT struct {
+ t types.GomegaTestingT
+}
+
+//NewGomegaWithT takes a *testing.T and returngs a `GomegaWithT` allowing you to use `Expect`, `Eventually`, and `Consistently` along with
+//Gomega's rich ecosystem of matchers in standard `testing` test suits.
+//
+// func TestFarmHasCow(t *testing.T) {
+// g := GomegaWithT(t)
+//
+// f := farm.New([]string{"Cow", "Horse"})
+// g.Expect(f.HasCow()).To(BeTrue(), "Farm should have cow")
+// }
+func NewGomegaWithT(t types.GomegaTestingT) *GomegaWithT {
+ return &GomegaWithT{
+ t: t,
+ }
+}
+
+//See documentation for Expect
+func (g *GomegaWithT) Expect(actual interface{}, extra ...interface{}) GomegaAssertion {
+ return assertion.New(actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), 0, extra...)
+}
+
+//See documentation for Eventually
+func (g *GomegaWithT) Eventually(actual interface{}, intervals ...interface{}) GomegaAsyncAssertion {
+ 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, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), timeoutInterval, pollingInterval, 0)
+}
+
+//See documentation for Consistently
+func (g *GomegaWithT) Consistently(actual interface{}, intervals ...interface{}) GomegaAsyncAssertion {
+ 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, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), timeoutInterval, pollingInterval, 0)
+}
+
+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))
+}
diff --git a/vendor/github.com/onsi/gomega/gstruct/elements.go b/vendor/github.com/onsi/gomega/gstruct/elements.go
new file mode 100644
index 000000000..13bf5b895
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gstruct/elements.go
@@ -0,0 +1,159 @@
+package 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.
+// idFn := func(element interface{}) string {
+// return fmt.Sprintf("%v", element)
+// }
+//
+// Expect([]string{"a", "b"}).To(MatchAllElements(idFn, Elements{
+// "a": Equal("a"),
+// "b": Equal("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.
+// idFn := func(element interface{}) string {
+// return fmt.Sprintf("%v", element)
+// }
+//
+// Expect([]string{"a", "b", "c"}).To(MatchElements(idFn, IgnoreExtras, Elements{
+// "a": Equal("a"),
+// "b": Equal("b"),
+// }))
+// Expect([]string{"a", "c"}).To(MatchElements(idFn, IgnoreMissing, Elements{
+// "a": Equal("a"),
+// "b": Equal("b"),
+// "c": Equal("c"),
+// "d": Equal("d"),
+// }))
+func MatchElements(identifier Identifier, options Options, elements Elements) types.GomegaMatcher {
+ return &ElementsMatcher{
+ Identifier: identifier,
+ Elements: elements,
+ IgnoreExtras: options&IgnoreExtras != 0,
+ IgnoreMissing: options&IgnoreMissing != 0,
+ AllowDuplicates: options&AllowDuplicates != 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
+ // Whether to key duplicates when matching IDs.
+ AllowDuplicates 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)
+ if elements[id] {
+ if !m.AllowDuplicates {
+ 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
+}
diff --git a/vendor/github.com/onsi/gomega/gstruct/elements_test.go b/vendor/github.com/onsi/gomega/gstruct/elements_test.go
new file mode 100644
index 000000000..355d463eb
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gstruct/elements_test.go
@@ -0,0 +1,144 @@
+package 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"),
+ })
+ Expect(allElements).Should(m, "should match all elements")
+ Expect(missingElements).ShouldNot(m, "should fail with missing elements")
+ Expect(extraElements).ShouldNot(m, "should fail with extra elements")
+ Expect(duplicateElements).ShouldNot(m, "should fail with duplicate elements")
+ Expect(nils).ShouldNot(m, "should fail with an uninitialized slice")
+
+ m = MatchAllElements(id, Elements{
+ "a": Equal("a"),
+ "b": Equal("fail"),
+ })
+ Expect(allElements).ShouldNot(m, "should run nested matchers")
+
+ m = MatchAllElements(id, Elements{})
+ Expect(empty).Should(m, "should handle empty slices")
+ Expect(allElements).ShouldNot(m, "should handle only empty slices")
+ Expect(nils).Should(m, "should handle nil slices")
+ })
+
+ It("should ignore extra elements", func() {
+ m := MatchElements(id, IgnoreExtras, Elements{
+ "b": Equal("b"),
+ "a": Equal("a"),
+ })
+ Expect(allElements).Should(m, "should match all elements")
+ Expect(missingElements).ShouldNot(m, "should fail with missing elements")
+ Expect(extraElements).Should(m, "should ignore extra elements")
+ Expect(duplicateElements).ShouldNot(m, "should fail with duplicate elements")
+ Expect(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"),
+ })
+ Expect(allElements).Should(m, "should match all elements")
+ Expect(missingElements).Should(m, "should ignore missing elements")
+ Expect(extraElements).ShouldNot(m, "should fail with extra elements")
+ Expect(duplicateElements).ShouldNot(m, "should fail with duplicate elements")
+ Expect(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"),
+ })
+ Expect(allElements).Should(m, "should match all elements")
+ Expect(missingElements).Should(m, "should ignore missing elements")
+ Expect(extraElements).Should(m, "should ignore extra elements")
+ Expect(duplicateElements).ShouldNot(m, "should fail with duplicate elements")
+ Expect(nils).Should(m, "should ignore an uninitialized slice")
+
+ m = MatchElements(id, IgnoreExtras|IgnoreMissing, Elements{
+ "a": Equal("a"),
+ "b": Equal("fail"),
+ })
+ Expect(allElements).ShouldNot(m, "should run nested matchers")
+ })
+
+ Context("with elements that share a key", func() {
+ nonUniqueID := func(element interface{}) string {
+ return element.(string)[0:1]
+ }
+
+ allElements := []string{"a123", "a213", "b321"}
+ includingBadElements := []string{"a123", "b123", "b5555"}
+ extraElements := []string{"a123", "b1234", "c345"}
+ missingElements := []string{"b123", "b1234", "b1345"}
+
+ It("should strictly allow multiple matches", func() {
+ m := MatchElements(nonUniqueID, AllowDuplicates, Elements{
+ "a": ContainSubstring("1"),
+ "b": ContainSubstring("1"),
+ })
+ Expect(allElements).Should(m, "should match all elements")
+ Expect(includingBadElements).ShouldNot(m, "should reject if a member fails the matcher")
+ Expect(extraElements).ShouldNot(m, "should reject with extra keys")
+ Expect(missingElements).ShouldNot(m, "should reject with missing keys")
+ Expect(nils).ShouldNot(m, "should fail with an uninitialized slice")
+ })
+
+ It("should ignore missing", func() {
+ m := MatchElements(nonUniqueID, AllowDuplicates|IgnoreMissing, Elements{
+ "a": ContainSubstring("1"),
+ "b": ContainSubstring("1"),
+ })
+ Expect(allElements).Should(m, "should match all elements")
+ Expect(includingBadElements).ShouldNot(m, "should reject if a member fails the matcher")
+ Expect(extraElements).ShouldNot(m, "should reject with extra keys")
+ Expect(missingElements).Should(m, "should allow missing keys")
+ Expect(nils).Should(m, "should allow an uninitialized slice")
+ })
+
+ It("should ignore extras", func() {
+ m := MatchElements(nonUniqueID, AllowDuplicates|IgnoreExtras, Elements{
+ "a": ContainSubstring("1"),
+ "b": ContainSubstring("1"),
+ })
+ Expect(allElements).Should(m, "should match all elements")
+ Expect(includingBadElements).ShouldNot(m, "should reject if a member fails the matcher")
+ Expect(extraElements).Should(m, "should allow extra keys")
+ Expect(missingElements).ShouldNot(m, "should reject missing keys")
+ Expect(nils).ShouldNot(m, "should reject an uninitialized slice")
+ })
+
+ It("should ignore missing and extras", func() {
+ m := MatchElements(nonUniqueID, AllowDuplicates|IgnoreExtras|IgnoreMissing, Elements{
+ "a": ContainSubstring("1"),
+ "b": ContainSubstring("1"),
+ })
+ Expect(allElements).Should(m, "should match all elements")
+ Expect(includingBadElements).ShouldNot(m, "should reject if a member fails the matcher")
+ Expect(extraElements).Should(m, "should allow extra keys")
+ Expect(missingElements).Should(m, "should allow missing keys")
+ Expect(nils).Should(m, "should allow an uninitialized slice")
+ })
+ })
+})
+
+func id(element interface{}) string {
+ return element.(string)
+}
diff --git a/vendor/github.com/onsi/gomega/gstruct/errors/nested_types.go b/vendor/github.com/onsi/gomega/gstruct/errors/nested_types.go
new file mode 100644
index 000000000..188492b21
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gstruct/errors/nested_types.go
@@ -0,0 +1,72 @@
+package 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
+}
diff --git a/vendor/github.com/onsi/gomega/gstruct/fields.go b/vendor/github.com/onsi/gomega/gstruct/fields.go
new file mode 100644
index 000000000..2eb2d0887
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gstruct/fields.go
@@ -0,0 +1,168 @@
+package 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.
+// actual := struct{
+// A int
+// B []bool
+// C string
+// }{
+// A: 5,
+// B: []bool{true, false},
+// C: "foo",
+// }
+//
+// Expect(actual).To(MatchAllFields(Fields{
+// "A": Equal(5),
+// "B": ConsistOf(true, false),
+// "C": Equal("foo"),
+// }))
+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.
+// actual := struct{
+// A int
+// B []bool
+// C string
+// }{
+// A: 5,
+// B: []bool{true, false},
+// C: "foo",
+// }
+//
+// Expect(actual).To(MatchFields(IgnoreExtras, Fields{
+// "A": Equal(5),
+// "B": ConsistOf(true, false),
+// }))
+// Expect(actual).To(MatchFields(IgnoreMissing, Fields{
+// "A": Equal(5),
+// "B": ConsistOf(true, false),
+// "C": Equal("foo"),
+// "D": Equal("extra"),
+// }))
+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
+}
diff --git a/vendor/github.com/onsi/gomega/gstruct/fields_test.go b/vendor/github.com/onsi/gomega/gstruct/fields_test.go
new file mode 100644
index 000000000..e4e039e21
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gstruct/fields_test.go
@@ -0,0 +1,76 @@
+package 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"),
+ })
+ Expect(allFields).Should(m, "should match all fields")
+ Expect(missingFields).ShouldNot(m, "should fail with missing fields")
+ Expect(extraFields).ShouldNot(m, "should fail with extra fields")
+ Expect(emptyFields).ShouldNot(m, "should fail with empty fields")
+
+ m = MatchAllFields(Fields{
+ "A": Equal("a"),
+ "B": Equal("fail"),
+ })
+ Expect(allFields).ShouldNot(m, "should run nested matchers")
+ })
+
+ It("should handle empty structs", func() {
+ m := MatchAllFields(Fields{})
+ Expect(struct{}{}).Should(m, "should handle empty structs")
+ Expect(allFields).ShouldNot(m, "should fail with extra fields")
+ })
+
+ It("should ignore missing fields", func() {
+ m := MatchFields(IgnoreMissing, Fields{
+ "B": Equal("b"),
+ "A": Equal("a"),
+ })
+ Expect(allFields).Should(m, "should match all fields")
+ Expect(missingFields).Should(m, "should ignore missing fields")
+ Expect(extraFields).ShouldNot(m, "should fail with extra fields")
+ Expect(emptyFields).ShouldNot(m, "should fail with empty fields")
+ })
+
+ It("should ignore extra fields", func() {
+ m := MatchFields(IgnoreExtras, Fields{
+ "B": Equal("b"),
+ "A": Equal("a"),
+ })
+ Expect(allFields).Should(m, "should match all fields")
+ Expect(missingFields).ShouldNot(m, "should fail with missing fields")
+ Expect(extraFields).Should(m, "should ignore extra fields")
+ Expect(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"),
+ })
+ Expect(allFields).Should(m, "should match all fields")
+ Expect(missingFields).Should(m, "should ignore missing fields")
+ Expect(extraFields).Should(m, "should ignore extra fields")
+ Expect(emptyFields).ShouldNot(m, "should fail with empty fields")
+
+ m = MatchFields(IgnoreMissing|IgnoreExtras, Fields{
+ "A": Equal("a"),
+ "B": Equal("fail"),
+ })
+ Expect(allFields).ShouldNot(m, "should run nested matchers")
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/gstruct/gstruct_tests_suite_test.go b/vendor/github.com/onsi/gomega/gstruct/gstruct_tests_suite_test.go
new file mode 100644
index 000000000..d47566304
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gstruct/gstruct_tests_suite_test.go
@@ -0,0 +1,13 @@
+package gstruct_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+func Test(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Gstruct Suite")
+}
diff --git a/vendor/github.com/onsi/gomega/gstruct/ignore.go b/vendor/github.com/onsi/gomega/gstruct/ignore.go
new file mode 100644
index 000000000..0365f32ad
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gstruct/ignore.go
@@ -0,0 +1,37 @@
+package 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"
+}
diff --git a/vendor/github.com/onsi/gomega/gstruct/ignore_test.go b/vendor/github.com/onsi/gomega/gstruct/ignore_test.go
new file mode 100644
index 000000000..07775e742
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gstruct/ignore_test.go
@@ -0,0 +1,23 @@
+package 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() {
+ Expect(nil).Should(Ignore())
+ Expect(struct{}{}).Should(Ignore())
+ Expect(0).Should(Ignore())
+ Expect(false).Should(Ignore())
+ })
+
+ It("should always fail", func() {
+ Expect(nil).ShouldNot(Reject())
+ Expect(struct{}{}).ShouldNot(Reject())
+ Expect(1).ShouldNot(Reject())
+ Expect(true).ShouldNot(Reject())
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/gstruct/pointer.go b/vendor/github.com/onsi/gomega/gstruct/pointer.go
new file mode 100644
index 000000000..0a2f35de3
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gstruct/pointer.go
@@ -0,0 +1,56 @@
+package 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 <nil>")
+ 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)
+}
diff --git a/vendor/github.com/onsi/gomega/gstruct/pointer_test.go b/vendor/github.com/onsi/gomega/gstruct/pointer_test.go
new file mode 100644
index 000000000..805a92abe
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gstruct/pointer_test.go
@@ -0,0 +1,33 @@
+package 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{}
+ Expect(p).Should(BeNil())
+ })
+
+ It("should succeed when passed non-nil pointer", func() {
+ var s struct{}
+ Expect(&s).Should(PointTo(Ignore()))
+ })
+
+ It("should unwrap the pointee value", func() {
+ i := 1
+ Expect(&i).Should(PointTo(Equal(1)))
+ Expect(&i).ShouldNot(PointTo(Equal(2)))
+ })
+
+ It("should work with nested pointers", func() {
+ i := 1
+ ip := &i
+ ipp := &ip
+ Expect(ipp).Should(PointTo(PointTo(Equal(1))))
+ Expect(ipp).ShouldNot(PointTo(PointTo(Equal(2))))
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/gstruct/types.go b/vendor/github.com/onsi/gomega/gstruct/types.go
new file mode 100644
index 000000000..48cbbe8f6
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gstruct/types.go
@@ -0,0 +1,15 @@
+package 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
+ //AllowDuplicates tells the matcher to permit multiple members of the slice to produce the same ID when
+ //considered by the indentifier function. All members that map to a given key must still match successfully
+ //with the matcher that is provided for that key.
+ AllowDuplicates
+)
diff --git a/vendor/github.com/onsi/gomega/internal/assertion/assertion.go b/vendor/github.com/onsi/gomega/internal/assertion/assertion.go
new file mode 100644
index 000000000..00197b67a
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/internal/assertion/assertion.go
@@ -0,0 +1,105 @@
+package assertion
+
+import (
+ "fmt"
+ "reflect"
+
+ "github.com/onsi/gomega/types"
+)
+
+type Assertion struct {
+ actualInput interface{}
+ failWrapper *types.GomegaFailWrapper
+ offset int
+ extra []interface{}
+}
+
+func New(actualInput interface{}, failWrapper *types.GomegaFailWrapper, offset int, extra ...interface{}) *Assertion {
+ return &Assertion{
+ actualInput: actualInput,
+ failWrapper: failWrapper,
+ offset: offset,
+ extra: extra,
+ }
+}
+
+func (assertion *Assertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
+ assertion.failWrapper.TWithHelper.Helper()
+ return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...)
+}
+
+func (assertion *Assertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
+ assertion.failWrapper.TWithHelper.Helper()
+ return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
+}
+
+func (assertion *Assertion) To(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
+ assertion.failWrapper.TWithHelper.Helper()
+ return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...)
+}
+
+func (assertion *Assertion) ToNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
+ assertion.failWrapper.TWithHelper.Helper()
+ return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
+}
+
+func (assertion *Assertion) NotTo(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
+ assertion.failWrapper.TWithHelper.Helper()
+ 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...)
+ assertion.failWrapper.TWithHelper.Helper()
+ if err != nil {
+ assertion.failWrapper.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.failWrapper.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.failWrapper.TWithHelper.Helper()
+ assertion.failWrapper.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, ""
+}
diff --git a/vendor/github.com/onsi/gomega/internal/assertion/assertion_suite_test.go b/vendor/github.com/onsi/gomega/internal/assertion/assertion_suite_test.go
new file mode 100644
index 000000000..dae47a48b
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/internal/assertion/assertion_suite_test.go
@@ -0,0 +1,13 @@
+package assertion_test
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+
+ "testing"
+)
+
+func TestAssertion(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Assertion Suite")
+}
diff --git a/vendor/github.com/onsi/gomega/internal/assertion/assertion_test.go b/vendor/github.com/onsi/gomega/internal/assertion/assertion_test.go
new file mode 100644
index 000000000..cac0d24c5
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/internal/assertion/assertion_test.go
@@ -0,0 +1,258 @@
+package assertion_test
+
+import (
+ "errors"
+
+ "github.com/onsi/gomega/internal/testingtsupport"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/internal/assertion"
+ "github.com/onsi/gomega/internal/fakematcher"
+ "github.com/onsi/gomega/types"
+)
+
+var _ = Describe("Assertion", func() {
+ var (
+ a *Assertion
+ failureMessage string
+ failureCallerSkip int
+ matcher *fakematcher.FakeMatcher
+ )
+
+ input := "The thing I'm testing"
+
+ var fakeFailWrapper = &types.GomegaFailWrapper{
+ Fail: func(message string, callerSkip ...int) {
+ failureMessage = message
+ if len(callerSkip) == 1 {
+ failureCallerSkip = callerSkip[0]
+ }
+ },
+ TWithHelper: testingtsupport.EmptyTWithHelper{},
+ }
+
+ BeforeEach(func() {
+ matcher = &fakematcher.FakeMatcher{}
+ failureMessage = ""
+ failureCallerSkip = 0
+ a = New(input, fakeFailWrapper, 1)
+ })
+
+ Context("when called", func() {
+ It("should pass the provided input value to the matcher", func() {
+ a.Should(matcher)
+
+ Expect(matcher.ReceivedActual).Should(Equal(input))
+ matcher.ReceivedActual = ""
+
+ a.ShouldNot(matcher)
+
+ Expect(matcher.ReceivedActual).Should(Equal(input))
+ matcher.ReceivedActual = ""
+
+ a.To(matcher)
+
+ Expect(matcher.ReceivedActual).Should(Equal(input))
+ matcher.ReceivedActual = ""
+
+ a.ToNot(matcher)
+
+ Expect(matcher.ReceivedActual).Should(Equal(input))
+ matcher.ReceivedActual = ""
+
+ a.NotTo(matcher)
+
+ Expect(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)
+ Expect(failureMessage).Should(Equal(""))
+ })
+
+ It("should be true", func() {
+ Expect(a.Should(matcher)).Should(BeTrue())
+ })
+ })
+
+ Context("and a negative assertion is being made", func() {
+ It("should call the failure callback", func() {
+ a.ShouldNot(matcher)
+ Expect(failureMessage).Should(Equal("negative: The thing I'm testing"))
+ Expect(failureCallerSkip).Should(Equal(3))
+ })
+
+ It("should be false", func() {
+ Expect(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)
+ Expect(failureMessage).Should(Equal("positive: The thing I'm testing"))
+ Expect(failureCallerSkip).Should(Equal(3))
+ })
+
+ It("should be false", func() {
+ Expect(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)
+ Expect(failureMessage).Should(Equal(""))
+ })
+
+ It("should be true", func() {
+ Expect(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")
+ Expect(failureMessage).Should(Equal("A description\npositive: The thing I'm testing"))
+ Expect(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)
+ Expect(failureMessage).Should(Equal("A description of [3]\npositive: The thing I'm testing"))
+ Expect(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)
+ Expect(failureMessage).Should(Equal("Kaboom!"))
+ Expect(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)
+ Expect(failureMessage).Should(Equal("Kaboom!"))
+ Expect(failureCallerSkip).Should(Equal(3))
+ })
+ })
+
+ It("should always be false", func() {
+ Expect(a.Should(matcher)).Should(BeFalse())
+ Expect(a.ShouldNot(matcher)).Should(BeFalse())
+ })
+ })
+
+ Context("when there are extra parameters", func() {
+ It("(a simple example)", func() {
+ Expect(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, fakeFailWrapper, 1, 0, nil, typedNil)
+
+ result := a.Should(matcher)
+ Expect(result).Should(BeTrue())
+ Expect(matcher.ReceivedActual).Should(Equal(input))
+
+ Expect(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, fakeFailWrapper, 1, errors.New("foo"))
+ result := a.Should(matcher)
+ Expect(result).Should(BeFalse())
+ Expect(matcher.ReceivedActual).Should(BeZero(), "The matcher doesn't even get called")
+ Expect(failureMessage).Should(ContainSubstring("foo"))
+ failureMessage = ""
+
+ a = New(input, fakeFailWrapper, 1, nil, 1)
+ result = a.ShouldNot(matcher)
+ Expect(result).Should(BeFalse())
+ Expect(failureMessage).Should(ContainSubstring("1"))
+ failureMessage = ""
+
+ a = New(input, fakeFailWrapper, 1, nil, 0, []string{"foo"})
+ result = a.To(matcher)
+ Expect(result).Should(BeFalse())
+ Expect(failureMessage).Should(ContainSubstring("foo"))
+ failureMessage = ""
+
+ a = New(input, fakeFailWrapper, 1, nil, 0, []string{"foo"})
+ result = a.ToNot(matcher)
+ Expect(result).Should(BeFalse())
+ Expect(failureMessage).Should(ContainSubstring("foo"))
+ failureMessage = ""
+
+ a = New(input, fakeFailWrapper, 1, nil, 0, []string{"foo"})
+ result = a.NotTo(matcher)
+ Expect(result).Should(BeFalse())
+ Expect(failureMessage).Should(ContainSubstring("foo"))
+ Expect(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)
+ Expect(true).Should(BeTrue())
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion.go b/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion.go
new file mode 100644
index 000000000..cdab233eb
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion.go
@@ -0,0 +1,194 @@
+package 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
+ failWrapper *types.GomegaFailWrapper
+ offset int
+}
+
+func New(asyncType AsyncAssertionType, actualInput interface{}, failWrapper *types.GomegaFailWrapper, 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,
+ failWrapper: failWrapper,
+ timeoutInterval: timeoutInterval,
+ pollingInterval: pollingInterval,
+ offset: offset,
+ }
+}
+
+func (assertion *AsyncAssertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
+ assertion.failWrapper.TWithHelper.Helper()
+ return assertion.match(matcher, true, optionalDescription...)
+}
+
+func (assertion *AsyncAssertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
+ assertion.failWrapper.TWithHelper.Helper()
+ 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)
+ }
+
+ assertion.failWrapper.TWithHelper.Helper()
+
+ 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.failWrapper.TWithHelper.Helper()
+ assertion.failWrapper.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, ""
+}
diff --git a/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion_suite_test.go b/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion_suite_test.go
new file mode 100644
index 000000000..bdb0c3d22
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion_suite_test.go
@@ -0,0 +1,13 @@
+package asyncassertion_test
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+
+ "testing"
+)
+
+func TestAsyncAssertion(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "AsyncAssertion Suite")
+}
diff --git a/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion_test.go b/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion_test.go
new file mode 100644
index 000000000..afd61a7cd
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion_test.go
@@ -0,0 +1,351 @@
+package asyncassertion_test
+
+import (
+ "errors"
+ "time"
+
+ "github.com/onsi/gomega/internal/testingtsupport"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/internal/asyncassertion"
+ "github.com/onsi/gomega/types"
+)
+
+var _ = Describe("Async Assertion", func() {
+ var (
+ failureMessage string
+ callerSkip int
+ )
+
+ var fakeFailWrapper = &types.GomegaFailWrapper{
+ Fail: func(message string, skip ...int) {
+ failureMessage = message
+ callerSkip = skip[0]
+ },
+ TWithHelper: testingtsupport.EmptyTWithHelper{},
+ }
+
+ 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
+ }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.Should(BeNumerically("==", 5))
+ Expect(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
+ }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.Should(BeNumerically("==", 5), "My description %d", 2)
+
+ Expect(failureMessage).Should(ContainSubstring("Timed out after"))
+ Expect(failureMessage).Should(ContainSubstring("My description 2"))
+ Expect(callerSkip).Should(Equal(4))
+ })
+
+ It("should be able to timeout", func() {
+ counter := 0
+ a := New(AsyncAssertionTypeEventually, func() int {
+ counter++
+ return counter
+ }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.Should(BeNumerically(">", 100), "My description %d", 2)
+
+ Expect(counter).Should(BeNumerically(">", 8))
+ Expect(counter).Should(BeNumerically("<=", 10))
+ Expect(failureMessage).Should(ContainSubstring("Timed out after"))
+ Expect(failureMessage).Should(MatchRegexp(`\<int\>: \d`), "Should pass the correct value to the matcher message formatter.")
+ Expect(failureMessage).Should(ContainSubstring("My description 2"))
+ Expect(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
+ }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.ShouldNot(BeNumerically("<", 3))
+
+ Expect(counter).Should(Equal(3))
+ Expect(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
+ }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.ShouldNot(HaveLen(0), "My description %d", 2)
+
+ Expect(failureMessage).Should(ContainSubstring("Timed out after"))
+ Expect(failureMessage).Should(ContainSubstring("Error:"))
+ Expect(failureMessage).Should(ContainSubstring("My description 2"))
+ Expect(callerSkip).Should(Equal(4))
+ })
+
+ It("should be able to timeout", func() {
+ a := New(AsyncAssertionTypeEventually, func() int {
+ return 0
+ }, fakeFailWrapper, time.Duration(0.1*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.ShouldNot(Equal(0), "My description %d", 2)
+
+ Expect(failureMessage).Should(ContainSubstring("Timed out after"))
+ Expect(failureMessage).Should(ContainSubstring("<int>: 0"), "Should pass the correct value to the matcher message formatter.")
+ Expect(failureMessage).Should(ContainSubstring("My description 2"))
+ Expect(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")
+ }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+ a.Should(Equal(2))
+
+ Expect(failureMessage).Should(ContainSubstring("Timed out after"))
+ Expect(failureMessage).Should(ContainSubstring("Error:"))
+ Expect(failureMessage).Should(ContainSubstring("bam"))
+ Expect(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"
+ }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.Should(Equal("foo"))
+ Expect(calls).Should(BeNumerically(">", 8))
+ Expect(calls).Should(BeNumerically("<=", 10))
+ Expect(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"
+ }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.Should(Equal("foo"))
+ Expect(failureMessage).Should(ContainSubstring("to equal"))
+ Expect(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}
+ }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.Should(HaveLen(3))
+ Expect(failureMessage).Should(ContainSubstring("HaveLen matcher expects"))
+ Expect(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, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.ShouldNot(Receive())
+ Expect(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, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.ShouldNot(Receive())
+ Expect(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
+ }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.ShouldNot(BeNumerically(">", 5))
+ Expect(failureMessage).Should(ContainSubstring("not to be >"))
+ Expect(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")
+ }, fakeFailWrapper, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+ a.Should(BeNumerically(">=", 2))
+
+ Expect(failureMessage).Should(ContainSubstring("Error:"))
+ Expect(failureMessage).Should(ContainSubstring("bam"))
+ Expect(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() {
+ Expect(func() {
+ New(AsyncAssertionTypeEventually, func() {}, fakeFailWrapper, 0, 0, 1)
+ }).Should(Panic())
+
+ Expect(func() {
+ New(AsyncAssertionTypeEventually, func(a string) int { return 0 }, fakeFailWrapper, 0, 0, 1)
+ }).Should(Panic())
+
+ Expect(func() {
+ New(AsyncAssertionTypeEventually, func() int { return 0 }, fakeFailWrapper, 0, 0, 1)
+ }).ShouldNot(Panic())
+
+ Expect(func() {
+ New(AsyncAssertionTypeEventually, func() (int, error) { return 0, nil }, fakeFailWrapper, 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())
+ })
+ Expect(time.Since(t)).Should(BeNumerically("<", 90*time.Millisecond))
+
+ Expect(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())
+ })
+ Expect(time.Since(t)).Should(BeNumerically(">=", 90*time.Millisecond))
+
+ Expect(failures).Should(HaveLen(1))
+ })
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/internal/fakematcher/fake_matcher.go b/vendor/github.com/onsi/gomega/internal/fakematcher/fake_matcher.go
new file mode 100644
index 000000000..6e351a7de
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/internal/fakematcher/fake_matcher.go
@@ -0,0 +1,23 @@
+package 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)
+}
diff --git a/vendor/github.com/onsi/gomega/internal/oraclematcher/oracle_matcher.go b/vendor/github.com/onsi/gomega/internal/oraclematcher/oracle_matcher.go
new file mode 100644
index 000000000..66cad88a1
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/internal/oraclematcher/oracle_matcher.go
@@ -0,0 +1,25 @@
+package 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)
+}
diff --git a/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support.go b/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support.go
new file mode 100644
index 000000000..bb27032f6
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support.go
@@ -0,0 +1,60 @@
+package testingtsupport
+
+import (
+ "regexp"
+ "runtime/debug"
+ "strings"
+
+ "github.com/onsi/gomega/types"
+)
+
+var StackTracePruneRE = regexp.MustCompile(`\/gomega\/|\/ginkgo\/|\/pkg\/testing\/|\/pkg\/runtime\/`)
+
+type EmptyTWithHelper struct{}
+
+func (e EmptyTWithHelper) Helper() {}
+
+type gomegaTestingT interface {
+ Fatalf(format string, args ...interface{})
+}
+
+func BuildTestingTGomegaFailWrapper(t gomegaTestingT) *types.GomegaFailWrapper {
+ tWithHelper, hasHelper := t.(types.TWithHelper)
+ if !hasHelper {
+ tWithHelper = EmptyTWithHelper{}
+ }
+
+ fail := func(message string, callerSkip ...int) {
+ if hasHelper {
+ tWithHelper.Helper()
+ t.Fatalf("\n%s", message)
+ } else {
+ skip := 2
+ if len(callerSkip) > 0 {
+ skip += callerSkip[0]
+ }
+ stackTrace := pruneStack(string(debug.Stack()), skip)
+ t.Fatalf("\n%s\n%s\n", stackTrace, message)
+ }
+ }
+
+ return &types.GomegaFailWrapper{
+ Fail: fail,
+ TWithHelper: tWithHelper,
+ }
+}
+
+func pruneStack(fullStackTrace string, skip int) string {
+ stack := strings.Split(fullStackTrace, "\n")[1:]
+ if len(stack) > 2*skip {
+ stack = stack[2*skip:]
+ }
+ prunedStack := []string{}
+ for i := 0; i < len(stack)/2; i++ {
+ if !StackTracePruneRE.Match([]byte(stack[i*2])) {
+ prunedStack = append(prunedStack, stack[i*2])
+ prunedStack = append(prunedStack, stack[i*2+1])
+ }
+ }
+ return strings.Join(prunedStack, "\n")
+}
diff --git a/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support_test.go b/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support_test.go
new file mode 100644
index 000000000..8fd8f0a6c
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support_test.go
@@ -0,0 +1,92 @@
+package testingtsupport_test
+
+import (
+ "regexp"
+ "time"
+
+ "github.com/onsi/gomega/internal/testingtsupport"
+
+ . "github.com/onsi/gomega"
+
+ "fmt"
+ "testing"
+)
+
+func TestTestingT(t *testing.T) {
+ RegisterTestingT(t)
+ Ω(true).Should(BeTrue())
+}
+
+type FakeTWithHelper struct {
+ LastFatal string
+}
+
+func (f *FakeTWithHelper) Fatalf(format string, args ...interface{}) {
+ f.LastFatal = fmt.Sprintf(format, args...)
+}
+
+func TestGomegaWithTWithoutHelper(t *testing.T) {
+ g := NewGomegaWithT(t)
+
+ testingtsupport.StackTracePruneRE = regexp.MustCompile(`\/ginkgo\/`)
+
+ f := &FakeTWithHelper{}
+ testG := NewGomegaWithT(f)
+
+ testG.Expect("foo").To(Equal("foo"))
+ g.Expect(f.LastFatal).To(BeZero())
+
+ testG.Expect("foo").To(Equal("bar"))
+ g.Expect(f.LastFatal).To(ContainSubstring("<string>: foo"))
+ g.Expect(f.LastFatal).To(ContainSubstring("testingtsupport_test"), "It should include a stacktrace")
+
+ testG.Eventually("foo2", time.Millisecond).Should(Equal("bar"))
+ g.Expect(f.LastFatal).To(ContainSubstring("<string>: foo2"))
+
+ testG.Consistently("foo3", time.Millisecond).Should(Equal("bar"))
+ g.Expect(f.LastFatal).To(ContainSubstring("<string>: foo3"))
+}
+
+type FakeTWithoutHelper struct {
+ LastFatal string
+ HelperCount int
+}
+
+func (f *FakeTWithoutHelper) Fatalf(format string, args ...interface{}) {
+ f.LastFatal = fmt.Sprintf(format, args...)
+}
+
+func (f *FakeTWithoutHelper) Helper() {
+ f.HelperCount += 1
+}
+
+func (f *FakeTWithoutHelper) ResetHelper() {
+ f.HelperCount = 0
+}
+
+func TestGomegaWithTWithHelper(t *testing.T) {
+ g := NewGomegaWithT(t)
+
+ f := &FakeTWithoutHelper{}
+ testG := NewGomegaWithT(f)
+
+ testG.Expect("foo").To(Equal("foo"))
+ g.Expect(f.LastFatal).To(BeZero())
+ g.Expect(f.HelperCount).To(BeNumerically(">", 0))
+ f.ResetHelper()
+
+ testG.Expect("foo").To(Equal("bar"))
+ g.Expect(f.LastFatal).To(ContainSubstring("<string>: foo"))
+ g.Expect(f.LastFatal).NotTo(ContainSubstring("testingtsupport_test"), "It should _not_ include a stacktrace")
+ g.Expect(f.HelperCount).To(BeNumerically(">", 0))
+ f.ResetHelper()
+
+ testG.Eventually("foo2", time.Millisecond).Should(Equal("bar"))
+ g.Expect(f.LastFatal).To(ContainSubstring("<string>: foo2"))
+ g.Expect(f.HelperCount).To(BeNumerically(">", 0))
+ f.ResetHelper()
+
+ testG.Consistently("foo3", time.Millisecond).Should(Equal("bar"))
+ g.Expect(f.LastFatal).To(ContainSubstring("<string>: foo3"))
+ g.Expect(f.HelperCount).To(BeNumerically(">", 0))
+}
diff --git a/vendor/github.com/onsi/gomega/matchers.go b/vendor/github.com/onsi/gomega/matchers.go
new file mode 100644
index 000000000..c3a326dd4
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers.go
@@ -0,0 +1,427 @@
+package 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()
+// Expect(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()
+// Expect(err).ShouldNot(HaveOccurred())
+//
+//You can write:
+// Expect(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:
+// Expect(err).Should(MatchError("an error")) //asserts that err.Error() == "an error"
+// Expect(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 Expect(c).Should(Receive()) will fail and Ω(c).ShouldNot(Receive()) will pass.
+//
+//- If the channel `c` is closed then Expect(c).Should(Receive()) will fail and Ω(c).ShouldNot(Receive()) will pass.
+//
+//- If there is something on the channel `c` ready to be read, then Expect(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:
+// Expect(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))
+// Expect(myThing.Sprocket).Should(Equal("foo"))
+// Expect(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 Expect(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 Expect(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 substring. 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,
+ }
+}
+
+//MatchXML succeeds if actual is a string or stringer of XML that matches
+//the expected XML. The XMLs are decoded and the resulting objects are compared via
+//reflect.DeepEqual so things like whitespaces shouldn't matter.
+func MatchXML(xml interface{}) types.GomegaMatcher {
+ return &matchers.MatchXMLMatcher{
+ XMLToMatch: xml,
+ }
+}
+
+//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:
+// Expect([]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 precisely 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:
+//
+// Expect([]string{"Foo", "FooBar"}).Should(ConsistOf("FooBar", "Foo"))
+// Expect([]string{"Foo", "FooBar"}).Should(ConsistOf(ContainSubstring("Bar"), "Foo"))
+// Expect([]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:
+//
+// Expect([]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:
+// Expect(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:
+// Expect(map[string]string{"Foo": "Bar", "BazFoo": "Duck"}).Should(HaveKeyWithValue("Foo", "Bar"))
+// Expect(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 (float32, float64, uint8, etc...).
+//
+//There are six, self-explanatory, supported comparators:
+// Expect(1.0).Should(BeNumerically("==", 1))
+// Expect(1.0).Should(BeNumerically("~", 0.999, 0.01))
+// Expect(1.0).Should(BeNumerically(">", 0.9))
+// Expect(1.0).Should(BeNumerically(">=", 1.0))
+// Expect(1.0).Should(BeNumerically("<", 3))
+// Expect(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
+// Expect(time.Now()).Should(BeTemporally(">", time.Time{}))
+// Expect(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.
+// Expect(0).Should(BeAssignableToTypeOf(0)) // Same values
+// Expect(5).Should(BeAssignableToTypeOf(-1)) // different values same type
+// Expect("foo").Should(BeAssignableToTypeOf("bar")) // different values same type
+// Expect(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 if 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 if 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().
+// Expect("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)
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/and.go b/vendor/github.com/onsi/gomega/matchers/and.go
new file mode 100644
index 000000000..d83a29164
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/and.go
@@ -0,0 +1,63 @@
+package 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
+ }
+ // one of the matchers failed.. it must be able to change in order to affect the result
+ return oraclematcher.MatchMayChangeInTheFuture(m.firstFailedMatcher, actual)
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/and_test.go b/vendor/github.com/onsi/gomega/matchers/and_test.go
new file mode 100644
index 000000000..acf778cd6
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/and_test.go
@@ -0,0 +1,103 @@
+package 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 <string>: " + 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 <string>: hip")
+ verifyFailureMessage(And(true1, true2, false3), input, "to match regular expression\n <string>: 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
+ })
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher.go b/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher.go
new file mode 100644
index 000000000..51f8be6ae
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher.go
@@ -0,0 +1,35 @@
+package 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 <nil> to <nil>.\nBe explicit and use BeNil() instead. This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.")
+ } else if matcher.Expected == nil {
+ return false, fmt.Errorf("Refusing to compare type to <nil>.\nBe explicit and use BeNil() instead. This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.")
+ } else if actual == nil {
+ return false, nil
+ }
+
+ 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))
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher_test.go
new file mode 100644
index 000000000..471a46d97
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher_test.go
@@ -0,0 +1,46 @@
+package 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() {
+ Expect(0).Should(BeAssignableToTypeOf(0))
+ Expect(5).Should(BeAssignableToTypeOf(-1))
+ Expect("foo").Should(BeAssignableToTypeOf("bar"))
+ Expect(struct{ Foo string }{}).Should(BeAssignableToTypeOf(struct{ Foo string }{}))
+
+ Expect(0).ShouldNot(BeAssignableToTypeOf("bar"))
+ Expect(5).ShouldNot(BeAssignableToTypeOf(struct{ Foo string }{}))
+ Expect("foo").ShouldNot(BeAssignableToTypeOf(42))
+ })
+ })
+
+ Context("When asserting nil values", func() {
+ It("should error", func() {
+ success, err := (&AssignableToTypeOfMatcher{Expected: nil}).Match(nil)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+
+ Context("When actual is nil and expected is not nil", func() {
+ It("should return false without error", func() {
+ success, err := (&AssignableToTypeOfMatcher{Expected: 17}).Match(nil)
+ Expect(success).Should(BeFalse())
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+ })
+
+ Context("When actual is not nil and expected is nil", func() {
+ It("should error", func() {
+ success, err := (&AssignableToTypeOfMatcher{Expected: nil}).Match(17)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/attributes_slice.go b/vendor/github.com/onsi/gomega/matchers/attributes_slice.go
new file mode 100644
index 000000000..355b362f4
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/attributes_slice.go
@@ -0,0 +1,14 @@
+package matchers
+
+import (
+ "encoding/xml"
+ "strings"
+)
+
+type attributesSlice []xml.Attr
+
+func (attrs attributesSlice) Len() int { return len(attrs) }
+func (attrs attributesSlice) Less(i, j int) bool {
+ return strings.Compare(attrs[i].Name.Local, attrs[j].Name.Local) == -1
+}
+func (attrs attributesSlice) Swap(i, j int) { attrs[i], attrs[j] = attrs[j], attrs[i] }
diff --git a/vendor/github.com/onsi/gomega/matchers/be_a_directory.go b/vendor/github.com/onsi/gomega/matchers/be_a_directory.go
new file mode 100644
index 000000000..7b6975e41
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_a_directory.go
@@ -0,0 +1,54 @@
+package 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"))
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/be_a_directory_test.go b/vendor/github.com/onsi/gomega/matchers/be_a_directory_test.go
new file mode 100644
index 000000000..bc8742763
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_a_directory_test.go
@@ -0,0 +1,40 @@
+package 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() {
+ Expect("/dne/test").ShouldNot(BeADirectory())
+
+ tmpFile, err := ioutil.TempFile("", "gomega-test-tempfile")
+ Expect(err).ShouldNot(HaveOccurred())
+ defer os.Remove(tmpFile.Name())
+ Expect(tmpFile.Name()).ShouldNot(BeADirectory())
+
+ tmpDir, err := ioutil.TempDir("", "gomega-test-tempdir")
+ Expect(err).ShouldNot(HaveOccurred())
+ defer os.Remove(tmpDir)
+ Expect(tmpDir).Should(BeADirectory())
+ })
+ })
+
+ Context("when passed something else", func() {
+ It("should error", func() {
+ success, err := (&BeADirectoryMatcher{}).Match(nil)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&BeADirectoryMatcher{}).Match(true)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/be_a_regular_file.go b/vendor/github.com/onsi/gomega/matchers/be_a_regular_file.go
new file mode 100644
index 000000000..e239131fb
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_a_regular_file.go
@@ -0,0 +1,54 @@
+package 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"))
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/be_a_regular_file_test.go b/vendor/github.com/onsi/gomega/matchers/be_a_regular_file_test.go
new file mode 100644
index 000000000..eae06a03e
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_a_regular_file_test.go
@@ -0,0 +1,40 @@
+package 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() {
+ Expect("/dne/test").ShouldNot(BeARegularFile())
+
+ tmpFile, err := ioutil.TempFile("", "gomega-test-tempfile")
+ Expect(err).ShouldNot(HaveOccurred())
+ defer os.Remove(tmpFile.Name())
+ Expect(tmpFile.Name()).Should(BeARegularFile())
+
+ tmpDir, err := ioutil.TempDir("", "gomega-test-tempdir")
+ Expect(err).ShouldNot(HaveOccurred())
+ defer os.Remove(tmpDir)
+ Expect(tmpDir).ShouldNot(BeARegularFile())
+ })
+ })
+
+ Context("when passed something else", func() {
+ It("should error", func() {
+ success, err := (&BeARegularFileMatcher{}).Match(nil)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&BeARegularFileMatcher{}).Match(true)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/be_an_existing_file.go b/vendor/github.com/onsi/gomega/matchers/be_an_existing_file.go
new file mode 100644
index 000000000..d42eba223
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_an_existing_file.go
@@ -0,0 +1,38 @@
+package 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"))
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/be_an_existing_file_test.go b/vendor/github.com/onsi/gomega/matchers/be_an_existing_file_test.go
new file mode 100644
index 000000000..e28bd0d65
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_an_existing_file_test.go
@@ -0,0 +1,40 @@
+package 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() {
+ Expect("/dne/test").ShouldNot(BeAnExistingFile())
+
+ tmpFile, err := ioutil.TempFile("", "gomega-test-tempfile")
+ Expect(err).ShouldNot(HaveOccurred())
+ defer os.Remove(tmpFile.Name())
+ Expect(tmpFile.Name()).Should(BeAnExistingFile())
+
+ tmpDir, err := ioutil.TempDir("", "gomega-test-tempdir")
+ Expect(err).ShouldNot(HaveOccurred())
+ defer os.Remove(tmpDir)
+ Expect(tmpDir).Should(BeAnExistingFile())
+ })
+ })
+
+ Context("when passed something else", func() {
+ It("should error", func() {
+ success, err := (&BeAnExistingFileMatcher{}).Match(nil)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&BeAnExistingFileMatcher{}).Match(true)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/be_closed_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_closed_matcher.go
new file mode 100644
index 000000000..80c9c8bb1
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_closed_matcher.go
@@ -0,0 +1,46 @@
+package matchers
+
+import (
+ "fmt"
+ "reflect"
+
+ "github.com/onsi/gomega/format"
+)
+
+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{
+ {Dir: reflect.SelectRecv, Chan: channelValue},
+ {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")
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/be_closed_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_closed_matcher_test.go
new file mode 100644
index 000000000..c2e49ab50
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_closed_matcher_test.go
@@ -0,0 +1,70 @@
+package 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)
+ Expect(openChannel).ShouldNot(BeClosed())
+
+ var openReaderChannel <-chan bool
+ openReaderChannel = openChannel
+ Expect(openReaderChannel).ShouldNot(BeClosed())
+
+ closedChannel := make(chan bool)
+ close(closedChannel)
+
+ Expect(closedChannel).Should(BeClosed())
+
+ var closedReaderChannel <-chan bool
+ closedReaderChannel = closedChannel
+ Expect(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)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ closedChannel := make(chan bool)
+ close(closedChannel)
+
+ var closedWriterChannel chan<- bool
+ closedWriterChannel = closedChannel
+
+ success, err = (&BeClosedMatcher{}).Match(closedWriterChannel)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ })
+ })
+
+ Context("when passed something else", func() {
+ It("should error", func() {
+ var nilChannel chan bool
+
+ success, err := (&BeClosedMatcher{}).Match(nilChannel)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&BeClosedMatcher{}).Match(nil)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&BeClosedMatcher{}).Match(7)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/be_empty_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_empty_matcher.go
new file mode 100644
index 000000000..8b00311b0
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_empty_matcher.go
@@ -0,0 +1,27 @@
+package 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")
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/be_empty_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_empty_matcher_test.go
new file mode 100644
index 000000000..132480cfc
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_empty_matcher_test.go
@@ -0,0 +1,52 @@
+package 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() {
+ Expect("").Should(BeEmpty())
+ Expect(" ").ShouldNot(BeEmpty())
+
+ Expect([0]int{}).Should(BeEmpty())
+ Expect([1]int{1}).ShouldNot(BeEmpty())
+
+ Expect([]int{}).Should(BeEmpty())
+ Expect([]int{1}).ShouldNot(BeEmpty())
+
+ Expect(map[string]int{}).Should(BeEmpty())
+ Expect(map[string]int{"a": 1}).ShouldNot(BeEmpty())
+
+ c := make(chan bool, 1)
+ Expect(c).Should(BeEmpty())
+ c <- true
+ Expect(c).ShouldNot(BeEmpty())
+ })
+ })
+
+ Context("when passed a correctly typed nil", func() {
+ It("should be true", func() {
+ var nilSlice []int
+ Expect(nilSlice).Should(BeEmpty())
+
+ var nilMap map[int]string
+ Expect(nilMap).Should(BeEmpty())
+ })
+ })
+
+ Context("when passed an unsupported type", func() {
+ It("should error", func() {
+ success, err := (&BeEmptyMatcher{}).Match(0)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&BeEmptyMatcher{}).Match(nil)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher.go
new file mode 100644
index 000000000..97ab20a4e
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher.go
@@ -0,0 +1,34 @@
+package matchers
+
+import (
+ "fmt"
+ "reflect"
+
+ "github.com/onsi/gomega/format"
+)
+
+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)
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher_test.go
new file mode 100644
index 000000000..4d9d11d2d
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher_test.go
@@ -0,0 +1,50 @@
+package 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)
+
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("When asserting on nil", func() {
+ It("should do the right thing", func() {
+ Expect("foo").ShouldNot(BeEquivalentTo(nil))
+ Expect(nil).ShouldNot(BeEquivalentTo(3))
+ Expect([]int{1, 2}).ShouldNot(BeEquivalentTo(nil))
+ })
+ })
+
+ Context("When asserting on type aliases", func() {
+ It("should the right thing", func() {
+ Expect(StringAlias("foo")).Should(BeEquivalentTo("foo"))
+ Expect("foo").Should(BeEquivalentTo(StringAlias("foo")))
+ Expect(StringAlias("foo")).ShouldNot(BeEquivalentTo("bar"))
+ Expect("foo").ShouldNot(BeEquivalentTo(StringAlias("bar")))
+ })
+ })
+
+ Context("When asserting on numbers", func() {
+ It("should convert actual to expected and do the right thing", func() {
+ Expect(5).Should(BeEquivalentTo(5))
+ Expect(5.0).Should(BeEquivalentTo(5.0))
+ Expect(5).Should(BeEquivalentTo(5.0))
+
+ Expect(5).ShouldNot(BeEquivalentTo("5"))
+ Expect(5).ShouldNot(BeEquivalentTo(3))
+
+ //Here be dragons!
+ Expect(5.1).Should(BeEquivalentTo(5))
+ Expect(5).ShouldNot(BeEquivalentTo(5.1))
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/be_false_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_false_matcher.go
new file mode 100644
index 000000000..91d3b779e
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_false_matcher.go
@@ -0,0 +1,26 @@
+package 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")
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/be_false_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_false_matcher_test.go
new file mode 100644
index 000000000..25e70633d
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_false_matcher_test.go
@@ -0,0 +1,20 @@
+package 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() {
+ Expect(true).ShouldNot(BeFalse())
+ Expect(false).Should(BeFalse())
+ })
+
+ It("should only support booleans", func() {
+ success, err := (&BeFalseMatcher{}).Match("foo")
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/be_identical_to.go b/vendor/github.com/onsi/gomega/matchers/be_identical_to.go
new file mode 100644
index 000000000..fdcda4d1f
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_identical_to.go
@@ -0,0 +1,37 @@
+package 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 <nil> to <nil>.\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)
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/be_identical_to_test.go b/vendor/github.com/onsi/gomega/matchers/be_identical_to_test.go
new file mode 100644
index 000000000..7fdd56eed
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_identical_to_test.go
@@ -0,0 +1,61 @@
+package 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)
+
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+
+ It("should treat the same pointer to a struct as identical", func() {
+ mySpecialStruct := myCustomType{}
+ Expect(&mySpecialStruct).Should(BeIdenticalTo(&mySpecialStruct))
+ Expect(&myCustomType{}).ShouldNot(BeIdenticalTo(&mySpecialStruct))
+ })
+
+ It("should be strict about types", func() {
+ Expect(5).ShouldNot(BeIdenticalTo("5"))
+ Expect(5).ShouldNot(BeIdenticalTo(5.0))
+ Expect(5).ShouldNot(BeIdenticalTo(3))
+ })
+
+ It("should treat primtives as identical", func() {
+ Expect("5").Should(BeIdenticalTo("5"))
+ Expect("5").ShouldNot(BeIdenticalTo("55"))
+
+ Expect(5.55).Should(BeIdenticalTo(5.55))
+ Expect(5.55).ShouldNot(BeIdenticalTo(6.66))
+
+ Expect(5).Should(BeIdenticalTo(5))
+ Expect(5).ShouldNot(BeIdenticalTo(55))
+ })
+
+ It("should treat the same pointers to a slice as identical", func() {
+ mySlice := []int{1, 2}
+ Expect(&mySlice).Should(BeIdenticalTo(&mySlice))
+ Expect(&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"}
+ Expect(&myMap).Should(BeIdenticalTo(&myMap))
+ Expect(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")
+ Expect(&myError).Should(BeIdenticalTo(&myError))
+ Expect(errors.New("foo")).ShouldNot(BeIdenticalTo(errors.New("bar")))
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/be_nil_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_nil_matcher.go
new file mode 100644
index 000000000..7ee84fe1b
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_nil_matcher.go
@@ -0,0 +1,18 @@
+package 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")
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/be_nil_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_nil_matcher_test.go
new file mode 100644
index 000000000..c35aa3d7c
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_nil_matcher_test.go
@@ -0,0 +1,28 @@
+package matchers_test
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("BeNil", func() {
+ It("should succeed when passed nil", func() {
+ Expect(nil).Should(BeNil())
+ })
+
+ It("should succeed when passed a typed nil", func() {
+ var a []int
+ Expect(a).Should(BeNil())
+ })
+
+ It("should succeed when passing nil pointer", func() {
+ var f *struct{}
+ Expect(f).Should(BeNil())
+ })
+
+ It("should not succeed when not passed nil", func() {
+ Expect(0).ShouldNot(BeNil())
+ Expect(false).ShouldNot(BeNil())
+ Expect("").ShouldNot(BeNil())
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher.go
new file mode 100644
index 000000000..9f4f77eec
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher.go
@@ -0,0 +1,132 @@
+package matchers
+
+import (
+ "fmt"
+ "math"
+
+ "github.com/onsi/gomega/format"
+)
+
+type BeNumericallyMatcher struct {
+ Comparator string
+ CompareTo []interface{}
+}
+
+func (matcher *BeNumericallyMatcher) FailureMessage(actual interface{}) (message string) {
+ return matcher.FormatFailureMessage(actual, false)
+}
+
+func (matcher *BeNumericallyMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ return matcher.FormatFailureMessage(actual, true)
+}
+
+func (matcher *BeNumericallyMatcher) FormatFailureMessage(actual interface{}, negated bool) (message string) {
+ if len(matcher.CompareTo) == 1 {
+ message = fmt.Sprintf("to be %s", matcher.Comparator)
+ } else {
+ message = fmt.Sprintf("to be within %v of %s", matcher.CompareTo[1], matcher.Comparator)
+ }
+ if negated {
+ message = "not " + message
+ }
+ return format.Message(actual, message, 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
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher_test.go
new file mode 100644
index 000000000..a32d2b8b1
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher_test.go
@@ -0,0 +1,172 @@
+package 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() {
+ Expect(uint32(5)).Should(BeNumerically("==", 5))
+ Expect(float64(5.0)).Should(BeNumerically("==", 5))
+ Expect(int8(5)).Should(BeNumerically("==", 5))
+ })
+
+ It("should not have false positives", func() {
+ Expect(5.1).ShouldNot(BeNumerically("==", 5))
+ Expect(5).ShouldNot(BeNumerically("==", 5.1))
+ })
+
+ It("should support >", func() {
+ Expect(uint32(5)).Should(BeNumerically(">", 4))
+ Expect(float64(5.0)).Should(BeNumerically(">", 4.9))
+ Expect(int8(5)).Should(BeNumerically(">", 4))
+
+ Expect(uint32(5)).ShouldNot(BeNumerically(">", 5))
+ Expect(float64(5.0)).ShouldNot(BeNumerically(">", 5.0))
+ Expect(int8(5)).ShouldNot(BeNumerically(">", 5))
+ })
+
+ It("should support <", func() {
+ Expect(uint32(5)).Should(BeNumerically("<", 6))
+ Expect(float64(5.0)).Should(BeNumerically("<", 5.1))
+ Expect(int8(5)).Should(BeNumerically("<", 6))
+
+ Expect(uint32(5)).ShouldNot(BeNumerically("<", 5))
+ Expect(float64(5.0)).ShouldNot(BeNumerically("<", 5.0))
+ Expect(int8(5)).ShouldNot(BeNumerically("<", 5))
+ })
+
+ It("should support >=", func() {
+ Expect(uint32(5)).Should(BeNumerically(">=", 4))
+ Expect(float64(5.0)).Should(BeNumerically(">=", 4.9))
+ Expect(int8(5)).Should(BeNumerically(">=", 4))
+
+ Expect(uint32(5)).Should(BeNumerically(">=", 5))
+ Expect(float64(5.0)).Should(BeNumerically(">=", 5.0))
+ Expect(int8(5)).Should(BeNumerically(">=", 5))
+
+ Expect(uint32(5)).ShouldNot(BeNumerically(">=", 6))
+ Expect(float64(5.0)).ShouldNot(BeNumerically(">=", 5.1))
+ Expect(int8(5)).ShouldNot(BeNumerically(">=", 6))
+ })
+
+ It("should support <=", func() {
+ Expect(uint32(5)).Should(BeNumerically("<=", 6))
+ Expect(float64(5.0)).Should(BeNumerically("<=", 5.1))
+ Expect(int8(5)).Should(BeNumerically("<=", 6))
+
+ Expect(uint32(5)).Should(BeNumerically("<=", 5))
+ Expect(float64(5.0)).Should(BeNumerically("<=", 5.0))
+ Expect(int8(5)).Should(BeNumerically("<=", 5))
+
+ Expect(uint32(5)).ShouldNot(BeNumerically("<=", 4))
+ Expect(float64(5.0)).ShouldNot(BeNumerically("<=", 4.9))
+ Expect(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() {
+ Expect(5.00000001).Should(BeNumerically("~", 5.00000002))
+ Expect(5.00000001).ShouldNot(BeNumerically("~", 5.0000001))
+ })
+
+ It("should show failure message", func() {
+ actual := BeNumerically("~", 4.98).FailureMessage(123)
+ expected := "Expected\n <int>: 123\nto be ~\n <float64>: 4.98"
+ Expect(actual).To(Equal(expected))
+ })
+
+ It("should show negated failure message", func() {
+ actual := BeNumerically("~", 4.98).NegatedFailureMessage(123)
+ expected := "Expected\n <int>: 123\nnot to be ~\n <float64>: 4.98"
+ Expect(actual).To(Equal(expected))
+ })
+ })
+
+ Context("and there is a precision parameter", func() {
+ It("should use the precision parameter", func() {
+ Expect(5.1).Should(BeNumerically("~", 5.19, 0.1))
+ Expect(5.1).Should(BeNumerically("~", 5.01, 0.1))
+ Expect(5.1).ShouldNot(BeNumerically("~", 5.22, 0.1))
+ Expect(5.1).ShouldNot(BeNumerically("~", 4.98, 0.1))
+ })
+
+ It("should show precision in failure message", func() {
+ actual := BeNumerically("~", 4.98, 0.1).FailureMessage(123)
+ expected := "Expected\n <int>: 123\nto be within 0.1 of ~\n <float64>: 4.98"
+ Expect(actual).To(Equal(expected))
+ })
+
+ It("should show precision in negated failure message", func() {
+ actual := BeNumerically("~", 4.98, 0.1).NegatedFailureMessage(123)
+ expected := "Expected\n <int>: 123\nnot to be within 0.1 of ~\n <float64>: 4.98"
+ Expect(actual).To(Equal(expected))
+ })
+ })
+ })
+
+ Context("when passed an int/uint", func() {
+ Context("and there is no precision parameter", func() {
+ It("should just do strict equality", func() {
+ Expect(5).Should(BeNumerically("~", 5))
+ Expect(5).ShouldNot(BeNumerically("~", 6))
+ Expect(uint(5)).ShouldNot(BeNumerically("~", 6))
+ })
+ })
+
+ Context("and there is a precision parameter", func() {
+ It("should use precision paramter", func() {
+ Expect(5).Should(BeNumerically("~", 6, 2))
+ Expect(5).ShouldNot(BeNumerically("~", 8, 2))
+ Expect(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")
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&BeNumericallyMatcher{Comparator: "=="}).Match(5)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&BeNumericallyMatcher{Comparator: "~", CompareTo: []interface{}{3.0, "foo"}}).Match(5.0)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{"bar"}}).Match(5)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{"bar"}}).Match("foo")
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{nil}}).Match(0)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{0}}).Match(nil)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("when passed an unsupported comparator", func() {
+ It("should error", func() {
+ success, err := (&BeNumericallyMatcher{Comparator: "!=", CompareTo: []interface{}{5}}).Match(4)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/be_sent_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_sent_matcher.go
new file mode 100644
index 000000000..302dd1a0a
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_sent_matcher.go
@@ -0,0 +1,71 @@
+package 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{
+ {Dir: reflect.SelectSend, Chan: channelValue, Send: argValue},
+ {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
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/be_sent_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_sent_matcher_test.go
new file mode 100644
index 000000000..68ec72879
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_sent_matcher_test.go
@@ -0,0 +1,107 @@
+package matchers_test
+
+import (
+ "time"
+
+ . "github.com/onsi/gomega/matchers"
+
+ . "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)
+
+ Expect(c).Should(BeSent("foo"))
+ Eventually(d).Should(Receive(Equal("foo")))
+ })
+
+ It("should succeed (with a buffered channel)", func() {
+ c := make(chan string, 1)
+ Expect(c).Should(BeSent("foo"))
+ Expect(<-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)
+ Expect(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)
+ Expect(success).Should(BeFalse())
+ Expect(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"))
+ })
+ Expect(failures).Should(HaveLen(1))
+ Expect(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))
+ Expect(success).Should(BeFalse())
+ Expect(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)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("when passed a nonchannel", func() {
+ It("should error", func() {
+ success, err := (&BeSentMatcher{Arg: "foo"}).Match("bar")
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher.go
new file mode 100644
index 000000000..cb7c038ef
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher.go
@@ -0,0 +1,66 @@
+package matchers
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/onsi/gomega/format"
+)
+
+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
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher_test.go
new file mode 100644
index 000000000..95a3a103e
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher_test.go
@@ -0,0 +1,99 @@
+package matchers_test
+
+import (
+ "time"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/matchers"
+)
+
+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() {
+ Expect(t0).Should(BeTemporally("==", t0))
+ Expect(t1).ShouldNot(BeTemporally("==", t0))
+ Expect(t0).ShouldNot(BeTemporally("==", t1))
+ Expect(t0).ShouldNot(BeTemporally("==", time.Time{}))
+ })
+
+ It("should support >", func() {
+ Expect(t0).Should(BeTemporally(">", t2))
+ Expect(t0).ShouldNot(BeTemporally(">", t0))
+ Expect(t2).ShouldNot(BeTemporally(">", t0))
+ })
+
+ It("should support <", func() {
+ Expect(t0).Should(BeTemporally("<", t1))
+ Expect(t0).ShouldNot(BeTemporally("<", t0))
+ Expect(t1).ShouldNot(BeTemporally("<", t0))
+ })
+
+ It("should support >=", func() {
+ Expect(t0).Should(BeTemporally(">=", t2))
+ Expect(t0).Should(BeTemporally(">=", t0))
+ Expect(t0).ShouldNot(BeTemporally(">=", t1))
+ })
+
+ It("should support <=", func() {
+ Expect(t0).Should(BeTemporally("<=", t1))
+ Expect(t0).Should(BeTemporally("<=", t0))
+ Expect(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() {
+ Expect(t0).Should(BeTemporally("~", t0))
+ Expect(t0).Should(BeTemporally("~", t1))
+ Expect(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
+ Expect(t0).Should(BeTemporally("~", t0, d))
+ Expect(t0).Should(BeTemporally("~", t1, d))
+ Expect(t0).ShouldNot(BeTemporally("~", t2, d))
+ })
+ })
+ })
+ })
+
+ Context("when passed a non-time", func() {
+ It("should error", func() {
+ success, err := (&BeTemporallyMatcher{Comparator: "==", CompareTo: t0}).Match("foo")
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&BeTemporallyMatcher{Comparator: "=="}).Match(nil)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("when passed an unsupported comparator", func() {
+ It("should error", func() {
+ success, err := (&BeTemporallyMatcher{Comparator: "!=", CompareTo: t0}).Match(t2)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/be_true_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_true_matcher.go
new file mode 100644
index 000000000..ec57c5db4
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_true_matcher.go
@@ -0,0 +1,26 @@
+package 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")
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/be_true_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_true_matcher_test.go
new file mode 100644
index 000000000..9eda62c33
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_true_matcher_test.go
@@ -0,0 +1,20 @@
+package 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() {
+ Expect(true).Should(BeTrue())
+ Expect(false).ShouldNot(BeTrue())
+ })
+
+ It("should only support booleans", func() {
+ success, err := (&BeTrueMatcher{}).Match("foo")
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/be_zero_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_zero_matcher.go
new file mode 100644
index 000000000..26196f168
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_zero_matcher.go
@@ -0,0 +1,28 @@
+package matchers
+
+import (
+ "reflect"
+
+ "github.com/onsi/gomega/format"
+)
+
+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")
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/be_zero_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_zero_matcher_test.go
new file mode 100644
index 000000000..c89e10330
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_zero_matcher_test.go
@@ -0,0 +1,40 @@
+package matchers_test
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("BeZero", func() {
+ It("succeeds for zero values for its type", func() {
+ Expect(nil).Should(BeZero())
+
+ Expect("").Should(BeZero())
+ Expect(" ").ShouldNot(BeZero())
+
+ Expect(0).Should(BeZero())
+ Expect(1).ShouldNot(BeZero())
+
+ Expect(0.0).Should(BeZero())
+ Expect(0.1).ShouldNot(BeZero())
+
+ // Expect([]int{}).Should(BeZero())
+ Expect([]int{1}).ShouldNot(BeZero())
+
+ // Expect(map[string]int{}).Should(BeZero())
+ Expect(map[string]int{"a": 1}).ShouldNot(BeZero())
+
+ Expect(myCustomType{}).Should(BeZero())
+ Expect(myCustomType{s: "a"}).ShouldNot(BeZero())
+ })
+
+ It("builds failure message", func() {
+ actual := BeZero().FailureMessage(123)
+ Expect(actual).To(Equal("Expected\n <int>: 123\nto be zero-valued"))
+ })
+
+ It("builds negated failure message", func() {
+ actual := BeZero().NegatedFailureMessage(123)
+ Expect(actual).To(Equal("Expected\n <int>: 123\nnot to be zero-valued"))
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/consist_of.go b/vendor/github.com/onsi/gomega/matchers/consist_of.go
new file mode 100644
index 000000000..7b0e08868
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/consist_of.go
@@ -0,0 +1,80 @@
+package 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)
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/consist_of_test.go b/vendor/github.com/onsi/gomega/matchers/consist_of_test.go
new file mode 100644
index 000000000..f6971c4f5
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/consist_of_test.go
@@ -0,0 +1,75 @@
+package 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() {
+ Expect([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", "bar", "baz"))
+ Expect([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", "bar", "baz"))
+ Expect([]string{"foo", "bar", "baz"}).Should(ConsistOf("baz", "bar", "foo"))
+ Expect([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "bar", "foo", "foo"))
+ Expect([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "foo"))
+ })
+ })
+
+ Context("with an array", func() {
+ It("should do the right thing", func() {
+ Expect([3]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", "bar", "baz"))
+ Expect([3]string{"foo", "bar", "baz"}).Should(ConsistOf("baz", "bar", "foo"))
+ Expect([3]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "bar", "foo", "foo"))
+ Expect([3]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "foo"))
+ })
+ })
+
+ Context("with a map", func() {
+ It("should apply to the values", func() {
+ Expect(map[int]string{1: "foo", 2: "bar", 3: "baz"}).Should(ConsistOf("foo", "bar", "baz"))
+ Expect(map[int]string{1: "foo", 2: "bar", 3: "baz"}).Should(ConsistOf("baz", "bar", "foo"))
+ Expect(map[int]string{1: "foo", 2: "bar", 3: "baz"}).ShouldNot(ConsistOf("baz", "bar", "foo", "foo"))
+ Expect(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() {
+ Expect("foo").Should(ConsistOf("f", "o", "o"))
+ })
+
+ Expect(failures).Should(HaveLen(1))
+ })
+ })
+
+ Context("when passed matchers", func() {
+ It("should pass if the matchers pass", func() {
+ Expect([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", MatchRegexp("^ba"), "baz"))
+ Expect([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("foo", MatchRegexp("^ba")))
+ Expect([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("foo", MatchRegexp("^ba"), MatchRegexp("foo")))
+ Expect([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", MatchRegexp("^ba"), MatchRegexp("^ba")))
+ Expect([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("foo", MatchRegexp("^ba"), MatchRegexp("turducken")))
+ })
+
+ It("should not depend on the order of the matchers", func() {
+ Expect([][]int{{1, 2}, {2}}).Should(ConsistOf(ContainElement(1), ContainElement(2)))
+ Expect([][]int{{1, 2}, {2}}).Should(ConsistOf(ContainElement(2), ContainElement(1)))
+ })
+
+ Context("when a matcher errors", func() {
+ It("should soldier on", func() {
+ Expect([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf(BeFalse(), "foo", "bar"))
+ Expect([]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() {
+ Expect([]string{"foo", "bar", "baz"}).Should(ConsistOf([]string{"foo", "bar", "baz"}))
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/contain_element_matcher.go b/vendor/github.com/onsi/gomega/matchers/contain_element_matcher.go
new file mode 100644
index 000000000..4159335d0
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/contain_element_matcher.go
@@ -0,0 +1,56 @@
+package 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)
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/contain_element_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/contain_element_matcher_test.go
new file mode 100644
index 000000000..60fb55e96
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/contain_element_matcher_test.go
@@ -0,0 +1,76 @@
+package 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() {
+ Expect([2]int{1, 2}).Should(ContainElement(2))
+ Expect([2]int{1, 2}).ShouldNot(ContainElement(3))
+
+ Expect([]int{1, 2}).Should(ContainElement(2))
+ Expect([]int{1, 2}).ShouldNot(ContainElement(3))
+
+ Expect(map[string]int{"foo": 1, "bar": 2}).Should(ContainElement(2))
+ Expect(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"}}
+ Expect(arr).Should(ContainElement(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}))
+ Expect(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() {
+ Expect([]int{1, 2, 3}).Should(ContainElement(BeNumerically(">=", 3)))
+ Expect([]int{1, 2, 3}).ShouldNot(ContainElement(BeNumerically(">", 3)))
+ Expect(map[string]int{"foo": 1, "bar": 2}).Should(ContainElement(BeNumerically(">=", 2)))
+ Expect(map[string]int{"foo": 1, "bar": 2}).ShouldNot(ContainElement(BeNumerically(">", 2)))
+ })
+
+ It("should power through even if the matcher ever fails", func() {
+ Expect([]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)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+ })
+
+ Context("when passed a correctly typed nil", func() {
+ It("should operate succesfully on the passed in value", func() {
+ var nilSlice []int
+ Expect(nilSlice).ShouldNot(ContainElement(1))
+
+ var nilMap map[int]string
+ Expect(nilMap).ShouldNot(ContainElement("foo"))
+ })
+ })
+
+ Context("when passed an unsupported type", func() {
+ It("should error", func() {
+ success, err := (&ContainElementMatcher{Element: 0}).Match(0)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&ContainElementMatcher{Element: 0}).Match("abc")
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&ContainElementMatcher{Element: 0}).Match(nil)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher.go b/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher.go
new file mode 100644
index 000000000..f8dc41e74
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher.go
@@ -0,0 +1,38 @@
+package matchers
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/onsi/gomega/format"
+)
+
+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())
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher_test.go
new file mode 100644
index 000000000..efffb4732
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher_test.go
@@ -0,0 +1,36 @@
+package 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() {
+ Expect("Marvelous").Should(ContainSubstring("rve"))
+ Expect("Marvelous").ShouldNot(ContainSubstring("boo"))
+ })
+ })
+
+ Context("when the matcher is called with multiple arguments", func() {
+ It("should pass the string and arguments to sprintf", func() {
+ Expect("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() {
+ Expect(&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)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/equal_matcher.go b/vendor/github.com/onsi/gomega/matchers/equal_matcher.go
new file mode 100644
index 000000000..befb7bdfd
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/equal_matcher.go
@@ -0,0 +1,42 @@
+package matchers
+
+import (
+ "bytes"
+ "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 <nil> to <nil>.\nBe explicit and use BeNil() instead. This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.")
+ }
+ // Shortcut for byte slices.
+ // Comparing long byte slices with reflect.DeepEqual is very slow,
+ // so use bytes.Equal if actual and expected are both byte slices.
+ if actualByteSlice, ok := actual.([]byte); ok {
+ if expectedByteSlice, ok := matcher.Expected.([]byte); ok {
+ return bytes.Equal(actualByteSlice, expectedByteSlice), nil
+ }
+ }
+ return reflect.DeepEqual(actual, matcher.Expected), nil
+}
+
+func (matcher *EqualMatcher) FailureMessage(actual interface{}) (message string) {
+ actualString, actualOK := actual.(string)
+ expectedString, expectedOK := matcher.Expected.(string)
+ if actualOK && expectedOK {
+ return format.MessageWithDiff(actualString, "to equal", expectedString)
+ }
+
+ 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)
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/equal_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/equal_matcher_test.go
new file mode 100644
index 000000000..3ab991e4f
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/equal_matcher_test.go
@@ -0,0 +1,80 @@
+package matchers_test
+
+import (
+ "errors"
+ "strings"
+
+ . "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)
+
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("When asserting equality between objects", func() {
+ It("should do the right thing", func() {
+ Expect(5).Should(Equal(5))
+ Expect(5.0).Should(Equal(5.0))
+
+ Expect(5).ShouldNot(Equal("5"))
+ Expect(5).ShouldNot(Equal(5.0))
+ Expect(5).ShouldNot(Equal(3))
+
+ Expect("5").Should(Equal("5"))
+ Expect([]int{1, 2}).Should(Equal([]int{1, 2}))
+ Expect([]int{1, 2}).ShouldNot(Equal([]int{2, 1}))
+ Expect([]byte{'f', 'o', 'o'}).Should(Equal([]byte{'f', 'o', 'o'}))
+ Expect([]byte{'f', 'o', 'o'}).ShouldNot(Equal([]byte{'b', 'a', 'r'}))
+ Expect(map[string]string{"a": "b", "c": "d"}).Should(Equal(map[string]string{"a": "b", "c": "d"}))
+ Expect(map[string]string{"a": "b", "c": "d"}).ShouldNot(Equal(map[string]string{"a": "b", "c": "e"}))
+ Expect(errors.New("foo")).Should(Equal(errors.New("foo")))
+ Expect(errors.New("foo")).ShouldNot(Equal(errors.New("bar")))
+
+ Expect(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"}}))
+ Expect(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"}}))
+ Expect(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"}}))
+ Expect(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"}}))
+ Expect(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"}}))
+ })
+ })
+
+ Describe("failure messages", func() {
+ It("shows the two strings simply when they are short", func() {
+ subject := EqualMatcher{Expected: "eric"}
+
+ failureMessage := subject.FailureMessage("tim")
+ Expect(failureMessage).To(BeEquivalentTo(expectedShortStringFailureMessage))
+ })
+
+ It("shows the exact point where two long strings differ", func() {
+ stringWithB := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ stringWithZ := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+ subject := EqualMatcher{Expected: stringWithZ}
+
+ failureMessage := subject.FailureMessage(stringWithB)
+ Expect(failureMessage).To(BeEquivalentTo(expectedLongStringFailureMessage))
+ })
+ })
+})
+
+var expectedShortStringFailureMessage = strings.TrimSpace(`
+Expected
+ <string>: tim
+to equal
+ <string>: eric
+`)
+var expectedLongStringFailureMessage = strings.TrimSpace(`
+Expected
+ <string>: "...aaaaabaaaaa..."
+to equal |
+ <string>: "...aaaaazaaaaa..."
+`)
diff --git a/vendor/github.com/onsi/gomega/matchers/have_cap_matcher.go b/vendor/github.com/onsi/gomega/matchers/have_cap_matcher.go
new file mode 100644
index 000000000..7ace93dc3
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/have_cap_matcher.go
@@ -0,0 +1,28 @@
+package 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)
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/have_cap_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/have_cap_matcher_test.go
new file mode 100644
index 000000000..8a61f2e2c
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/have_cap_matcher_test.go
@@ -0,0 +1,50 @@
+package 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() {
+ Expect([0]int{}).Should(HaveCap(0))
+ Expect([2]int{1}).Should(HaveCap(2))
+
+ Expect([]int{}).Should(HaveCap(0))
+ Expect([]int{1, 2, 3, 4, 5}[:2]).Should(HaveCap(5))
+ Expect(make([]int, 0, 5)).Should(HaveCap(5))
+
+ c := make(chan bool, 3)
+ Expect(c).Should(HaveCap(3))
+ c <- true
+ c <- true
+ Expect(c).Should(HaveCap(3))
+
+ Expect(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
+ Expect(nilSlice).Should(HaveCap(0))
+
+ var nilChan chan int
+ Expect(nilChan).Should(HaveCap(0))
+ })
+ })
+
+ Context("when passed an unsupported type", func() {
+ It("should error", func() {
+ success, err := (&HaveCapMatcher{Count: 0}).Match(0)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&HaveCapMatcher{Count: 0}).Match(nil)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/have_key_matcher.go b/vendor/github.com/onsi/gomega/matchers/have_key_matcher.go
new file mode 100644
index 000000000..ea5b92336
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/have_key_matcher.go
@@ -0,0 +1,54 @@
+package matchers
+
+import (
+ "fmt"
+ "reflect"
+
+ "github.com/onsi/gomega/format"
+)
+
+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)
+ }
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/have_key_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/have_key_matcher_test.go
new file mode 100644
index 000000000..0f1561b7d
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/have_key_matcher_test.go
@@ -0,0 +1,73 @@
+package 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() {
+ Expect(stringKeys).Should(HaveKey("foo"))
+ Expect(stringKeys).ShouldNot(HaveKey("baz"))
+
+ Expect(intKeys).Should(HaveKey(2))
+ Expect(intKeys).ShouldNot(HaveKey(4))
+
+ Expect(objKeys).Should(HaveKey(customA))
+ Expect(objKeys).Should(HaveKey(&myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"cake"}}))
+ Expect(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
+ Expect(nilMap).ShouldNot(HaveKey("foo"))
+ })
+ })
+
+ Context("when the passed in key is actually a matcher", func() {
+ It("should pass each element through the matcher", func() {
+ Expect(stringKeys).Should(HaveKey(ContainSubstring("oo")))
+ Expect(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)
+ Expect(success).Should(BeFalse())
+ Expect(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"})
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&HaveKeyMatcher{Key: "foo"}).Match(nil)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher.go b/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher.go
new file mode 100644
index 000000000..06355b1e9
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher.go
@@ -0,0 +1,74 @@
+package matchers
+
+import (
+ "fmt"
+ "reflect"
+
+ "github.com/onsi/gomega/format"
+)
+
+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)
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher_test.go
new file mode 100644
index 000000000..0a49ec993
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher_test.go
@@ -0,0 +1,82 @@
+package 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() {
+ Expect(stringKeys).Should(HaveKeyWithValue("foo", 2))
+ Expect(stringKeys).ShouldNot(HaveKeyWithValue("foo", 1))
+ Expect(stringKeys).ShouldNot(HaveKeyWithValue("baz", 2))
+ Expect(stringKeys).ShouldNot(HaveKeyWithValue("baz", 1))
+
+ Expect(intKeys).Should(HaveKeyWithValue(2, "foo"))
+ Expect(intKeys).ShouldNot(HaveKeyWithValue(4, "foo"))
+ Expect(intKeys).ShouldNot(HaveKeyWithValue(2, "baz"))
+
+ Expect(objKeys).Should(HaveKeyWithValue(customA, customA))
+ Expect(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"}}))
+ Expect(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
+ Expect(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() {
+ Expect(stringKeys).Should(HaveKeyWithValue(ContainSubstring("oo"), 2))
+ Expect(intKeys).Should(HaveKeyWithValue(2, ContainSubstring("oo")))
+ Expect(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)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ otherActual := map[string]int{"a": 1, "b": 2, "c": 3}
+ success, err = (&HaveKeyWithValueMatcher{Key: "a", Value: ContainSubstring("1")}).Match(otherActual)
+ Expect(success).Should(BeFalse())
+ Expect(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"})
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&HaveKeyWithValueMatcher{Key: "foo", Value: "bar"}).Match(nil)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/have_len_matcher.go b/vendor/github.com/onsi/gomega/matchers/have_len_matcher.go
new file mode 100644
index 000000000..ee4276189
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/have_len_matcher.go
@@ -0,0 +1,28 @@
+package 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)
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/have_len_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/have_len_matcher_test.go
new file mode 100644
index 000000000..c60f63886
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/have_len_matcher_test.go
@@ -0,0 +1,53 @@
+package 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() {
+ Expect("").Should(HaveLen(0))
+ Expect("AA").Should(HaveLen(2))
+
+ Expect([0]int{}).Should(HaveLen(0))
+ Expect([2]int{1, 2}).Should(HaveLen(2))
+
+ Expect([]int{}).Should(HaveLen(0))
+ Expect([]int{1, 2, 3}).Should(HaveLen(3))
+
+ Expect(map[string]int{}).Should(HaveLen(0))
+ Expect(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4}).Should(HaveLen(4))
+
+ c := make(chan bool, 3)
+ Expect(c).Should(HaveLen(0))
+ c <- true
+ c <- true
+ Expect(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
+ Expect(nilSlice).Should(HaveLen(0))
+
+ var nilMap map[int]string
+ Expect(nilMap).Should(HaveLen(0))
+ })
+ })
+
+ Context("when passed an unsupported type", func() {
+ It("should error", func() {
+ success, err := (&HaveLenMatcher{Count: 0}).Match(0)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&HaveLenMatcher{Count: 0}).Match(nil)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/have_occurred_matcher.go b/vendor/github.com/onsi/gomega/matchers/have_occurred_matcher.go
new file mode 100644
index 000000000..ebdd71786
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/have_occurred_matcher.go
@@ -0,0 +1,33 @@
+package 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")
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/have_occurred_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/have_occurred_matcher_test.go
new file mode 100644
index 000000000..0ad632ec1
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/have_occurred_matcher_test.go
@@ -0,0 +1,59 @@
+package 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() {
+ Expect(errors.New("Foo")).Should(HaveOccurred())
+ })
+
+ It("should not succeed with nil", func() {
+ Expect(nil).ShouldNot(HaveOccurred())
+ })
+
+ It("should only support errors and nil", func() {
+ success, err := (&HaveOccurredMatcher{}).Match("foo")
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&HaveOccurredMatcher{}).Match("")
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+
+ It("doesn't support non-error type", func() {
+ success, err := (&HaveOccurredMatcher{}).Match(AnyType{})
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(MatchError("Expected an error-type. Got:\n <matchers_test.AnyType>: {}"))
+ })
+
+ It("doesn't support non-error pointer type", func() {
+ success, err := (&HaveOccurredMatcher{}).Match(&AnyType{})
+ Expect(success).Should(BeFalse())
+ Expect(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"}
+ Expect(err).Should(HaveOccurred())
+ })
+
+ It("should not succeed with nil pointers to types that conform to error interface", func() {
+ var err *CustomErr = nil
+ Expect(err).ShouldNot(HaveOccurred())
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/have_prefix_matcher.go b/vendor/github.com/onsi/gomega/matchers/have_prefix_matcher.go
new file mode 100644
index 000000000..1d8e80270
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/have_prefix_matcher.go
@@ -0,0 +1,36 @@
+package 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())
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/have_prefix_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/have_prefix_matcher_test.go
new file mode 100644
index 000000000..fe29b7b5d
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/have_prefix_matcher_test.go
@@ -0,0 +1,36 @@
+package 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() {
+ Expect("Ab").Should(HavePrefix("A"))
+ Expect("A").ShouldNot(HavePrefix("Ab"))
+ })
+ })
+
+ Context("when the matcher is called with multiple arguments", func() {
+ It("should pass the string and arguments to sprintf", func() {
+ Expect("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() {
+ Expect(&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)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/have_suffix_matcher.go b/vendor/github.com/onsi/gomega/matchers/have_suffix_matcher.go
new file mode 100644
index 000000000..40a3526eb
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/have_suffix_matcher.go
@@ -0,0 +1,36 @@
+package 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())
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/have_suffix_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/have_suffix_matcher_test.go
new file mode 100644
index 000000000..2ae29821a
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/have_suffix_matcher_test.go
@@ -0,0 +1,36 @@
+package 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() {
+ Expect("Ab").Should(HaveSuffix("b"))
+ Expect("A").ShouldNot(HaveSuffix("Ab"))
+ })
+ })
+
+ Context("when the matcher is called with multiple arguments", func() {
+ It("should pass the string and arguments to sprintf", func() {
+ Expect("C3PO").Should(HaveSuffix("%dPO", 3))
+ })
+ })
+
+ Context("when actual is a stringer", func() {
+ It("should call the stringer and match against the returned string", func() {
+ Expect(&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)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/match_error_matcher.go b/vendor/github.com/onsi/gomega/matchers/match_error_matcher.go
new file mode 100644
index 000000000..07499ac95
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/match_error_matcher.go
@@ -0,0 +1,51 @@
+package matchers
+
+import (
+ "fmt"
+ "reflect"
+
+ "github.com/onsi/gomega/format"
+)
+
+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 isError(matcher.Expected) {
+ return reflect.DeepEqual(actualErr, matcher.Expected), nil
+ }
+
+ if isString(matcher.Expected) {
+ return actualErr.Error() == 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)
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/match_error_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/match_error_matcher_test.go
new file mode 100644
index 000000000..9bf89fc46
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/match_error_matcher_test.go
@@ -0,0 +1,107 @@
+package 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{}
+
+ Expect(err).Should(MatchError(errors.New("an error")))
+ Expect(err).ShouldNot(MatchError(errors.New("another error")))
+
+ Expect(fmtErr).Should(MatchError(errors.New("an error")))
+ Expect(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{}
+
+ Expect(err).Should(MatchError("an error"))
+ Expect(err).ShouldNot(MatchError("another error"))
+
+ Expect(fmtErr).Should(MatchError("an error"))
+ Expect(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")
+
+ Expect(err).Should(MatchError(MatchRegexp(`\d{3}`)))
+ })
+
+ It("should fail if the matcher fails against the error string", func() {
+ err := errors.New("no digits")
+ Expect(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)
+ Expect(err).Should(HaveOccurred())
+
+ _, err = (&MatchErrorMatcher{
+ Expected: 3,
+ }).Match(actualErr)
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("when passed nil", func() {
+ It("should fail", func() {
+ _, err := (&MatchErrorMatcher{
+ Expected: "an error",
+ }).Match(nil)
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("when passed a non-error", func() {
+ It("should fail", func() {
+ _, err := (&MatchErrorMatcher{
+ Expected: "an error",
+ }).Match("an error")
+ Expect(err).Should(HaveOccurred())
+
+ _, err = (&MatchErrorMatcher{
+ Expected: "an error",
+ }).Match(3)
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("when passed an error that is also a string", func() {
+ It("should use it as an error", func() {
+ var e mockErr = "mockErr"
+
+ // this fails if the matcher casts e to a string before comparison
+ Expect(e).Should(MatchError(e))
+ })
+ })
+})
+
+type mockErr string
+
+func (m mockErr) Error() string { return string(m) }
diff --git a/vendor/github.com/onsi/gomega/matchers/match_json_matcher.go b/vendor/github.com/onsi/gomega/matchers/match_json_matcher.go
new file mode 100644
index 000000000..f962f139f
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/match_json_matcher.go
@@ -0,0 +1,65 @@
+package matchers
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+
+ "github.com/onsi/gomega/format"
+)
+
+type MatchJSONMatcher struct {
+ JSONToMatch interface{}
+ firstFailurePath []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)
+ var equal bool
+ equal, matcher.firstFailurePath = deepEqual(aval, eval)
+ return equal, nil
+}
+
+func (matcher *MatchJSONMatcher) FailureMessage(actual interface{}) (message string) {
+ actualString, expectedString, _ := matcher.prettyPrint(actual)
+ return formattedMessage(format.Message(actualString, "to match JSON of", expectedString), matcher.firstFailurePath)
+}
+
+func (matcher *MatchJSONMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ actualString, expectedString, _ := matcher.prettyPrint(actual)
+ return formattedMessage(format.Message(actualString, "not to match JSON of", expectedString), matcher.firstFailurePath)
+}
+
+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
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/match_json_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/match_json_matcher_test.go
new file mode 100644
index 000000000..4a1a9db20
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/match_json_matcher_test.go
@@ -0,0 +1,103 @@
+package matchers_test
+
+import (
+ "encoding/json"
+
+ . "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() {
+ Expect("{}").Should(MatchJSON("{}"))
+ Expect(`{"a":1}`).Should(MatchJSON(`{"a":1}`))
+ Expect(`{
+ "a":1
+ }`).Should(MatchJSON(`{"a":1}`))
+ Expect(`{"a":1, "b":2}`).Should(MatchJSON(`{"b":2, "a":1}`))
+ Expect(`{"a":1}`).ShouldNot(MatchJSON(`{"b":2, "a":1}`))
+
+ Expect(`{"a":"a", "b":"b"}`).ShouldNot(MatchJSON(`{"a":"a", "b":"b", "c":"c"}`))
+ Expect(`{"a":"a", "b":"b", "c":"c"}`).ShouldNot(MatchJSON(`{"a":"a", "b":"b"}`))
+
+ Expect(`{"a":null, "b":null}`).ShouldNot(MatchJSON(`{"c":"c", "d":"d"}`))
+ Expect(`{"a":null, "b":null, "c":null}`).ShouldNot(MatchJSON(`{"a":null, "b":null, "d":null}`))
+ })
+
+ It("should work with byte arrays", func() {
+ Expect([]byte("{}")).Should(MatchJSON([]byte("{}")))
+ Expect("{}").Should(MatchJSON([]byte("{}")))
+ Expect([]byte("{}")).Should(MatchJSON("{}"))
+ })
+
+ It("should work with json.RawMessage", func() {
+ Expect([]byte(`{"a": 1}`)).Should(MatchJSON(json.RawMessage(`{"a": 1}`)))
+ })
+ })
+
+ Context("when a key mismatch is found", func() {
+ It("reports the first found mismatch", func() {
+ subject := MatchJSONMatcher{JSONToMatch: `5`}
+ actual := `7`
+ subject.Match(actual)
+
+ failureMessage := subject.FailureMessage(`7`)
+ Expect(failureMessage).ToNot(ContainSubstring("first mismatched key"))
+
+ subject = MatchJSONMatcher{JSONToMatch: `{"a": 1, "b.g": {"c": 2, "1": ["hello", "see ya"]}}`}
+ actual = `{"a": 1, "b.g": {"c": 2, "1": ["hello", "goodbye"]}}`
+ subject.Match(actual)
+
+ failureMessage = subject.FailureMessage(actual)
+ Expect(failureMessage).To(ContainSubstring(`first mismatched key: "b.g"."1"[1]`))
+ })
+ })
+
+ Context("when the expected is not valid JSON", func() {
+ It("should error and explain why", func() {
+ success, err := (&MatchJSONMatcher{JSONToMatch: `{}`}).Match(`oops`)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ Expect(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(`{}`)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ Expect(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("{}")
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ Expect(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got expected:\n <int>: 2"))
+
+ success, err = (&MatchJSONMatcher{JSONToMatch: nil}).Match("{}")
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ Expect(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got expected:\n <nil>: 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)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ Expect(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got actual:\n <int>: 2"))
+
+ success, err = (&MatchJSONMatcher{JSONToMatch: "{}"}).Match(nil)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ Expect(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got actual:\n <nil>: nil"))
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/match_regexp_matcher.go b/vendor/github.com/onsi/gomega/matchers/match_regexp_matcher.go
new file mode 100644
index 000000000..adac5db6b
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/match_regexp_matcher.go
@@ -0,0 +1,43 @@
+package matchers
+
+import (
+ "fmt"
+ "regexp"
+
+ "github.com/onsi/gomega/format"
+)
+
+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
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/match_regexp_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/match_regexp_matcher_test.go
new file mode 100644
index 000000000..ac2538bb4
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/match_regexp_matcher_test.go
@@ -0,0 +1,44 @@
+package 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() {
+ Expect(" a2!bla").Should(MatchRegexp(`\d!`))
+ Expect(" 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() {
+ Expect(&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() {
+ Expect(" 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)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("when the passed in regexp fails to compile", func() {
+ It("should error", func() {
+ success, err := (&MatchRegexpMatcher{Regexp: "("}).Match("Foo")
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/match_xml_matcher.go b/vendor/github.com/onsi/gomega/matchers/match_xml_matcher.go
new file mode 100644
index 000000000..3b412ce81
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/match_xml_matcher.go
@@ -0,0 +1,134 @@
+package matchers
+
+import (
+ "bytes"
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "io"
+ "reflect"
+ "sort"
+ "strings"
+
+ "github.com/onsi/gomega/format"
+ "golang.org/x/net/html/charset"
+)
+
+type MatchXMLMatcher struct {
+ XMLToMatch interface{}
+}
+
+func (matcher *MatchXMLMatcher) Match(actual interface{}) (success bool, err error) {
+ actualString, expectedString, err := matcher.formattedPrint(actual)
+ if err != nil {
+ return false, err
+ }
+
+ aval, err := parseXmlContent(actualString)
+ if err != nil {
+ return false, fmt.Errorf("Actual '%s' should be valid XML, but it is not.\nUnderlying error:%s", actualString, err)
+ }
+
+ eval, err := parseXmlContent(expectedString)
+ if err != nil {
+ return false, fmt.Errorf("Expected '%s' should be valid XML, but it is not.\nUnderlying error:%s", expectedString, err)
+ }
+
+ return reflect.DeepEqual(aval, eval), nil
+}
+
+func (matcher *MatchXMLMatcher) FailureMessage(actual interface{}) (message string) {
+ actualString, expectedString, _ := matcher.formattedPrint(actual)
+ return fmt.Sprintf("Expected\n%s\nto match XML of\n%s", actualString, expectedString)
+}
+
+func (matcher *MatchXMLMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ actualString, expectedString, _ := matcher.formattedPrint(actual)
+ return fmt.Sprintf("Expected\n%s\nnot to match XML of\n%s", actualString, expectedString)
+}
+
+func (matcher *MatchXMLMatcher) formattedPrint(actual interface{}) (actualString, expectedString string, err error) {
+ var ok bool
+ actualString, ok = toString(actual)
+ if !ok {
+ return "", "", fmt.Errorf("MatchXMLMatcher matcher requires a string, stringer, or []byte. Got actual:\n%s", format.Object(actual, 1))
+ }
+ expectedString, ok = toString(matcher.XMLToMatch)
+ if !ok {
+ return "", "", fmt.Errorf("MatchXMLMatcher matcher requires a string, stringer, or []byte. Got expected:\n%s", format.Object(matcher.XMLToMatch, 1))
+ }
+ return actualString, expectedString, nil
+}
+
+func parseXmlContent(content string) (*xmlNode, error) {
+ allNodes := []*xmlNode{}
+
+ dec := newXmlDecoder(strings.NewReader(content))
+ for {
+ tok, err := dec.Token()
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ return nil, fmt.Errorf("failed to decode next token: %v", err)
+ }
+
+ lastNodeIndex := len(allNodes) - 1
+ var lastNode *xmlNode
+ if len(allNodes) > 0 {
+ lastNode = allNodes[lastNodeIndex]
+ } else {
+ lastNode = &xmlNode{}
+ }
+
+ switch tok := tok.(type) {
+ case xml.StartElement:
+ attrs := attributesSlice(tok.Attr)
+ sort.Sort(attrs)
+ allNodes = append(allNodes, &xmlNode{XMLName: tok.Name, XMLAttr: tok.Attr})
+ case xml.EndElement:
+ if len(allNodes) > 1 {
+ allNodes[lastNodeIndex-1].Nodes = append(allNodes[lastNodeIndex-1].Nodes, lastNode)
+ allNodes = allNodes[:lastNodeIndex]
+ }
+ case xml.CharData:
+ lastNode.Content = append(lastNode.Content, tok.Copy()...)
+ case xml.Comment:
+ lastNode.Comments = append(lastNode.Comments, tok.Copy())
+ case xml.ProcInst:
+ lastNode.ProcInsts = append(lastNode.ProcInsts, tok.Copy())
+ }
+ }
+
+ if len(allNodes) == 0 {
+ return nil, errors.New("found no nodes")
+ }
+ firstNode := allNodes[0]
+ trimParentNodesContentSpaces(firstNode)
+
+ return firstNode, nil
+}
+
+func newXmlDecoder(reader io.Reader) *xml.Decoder {
+ dec := xml.NewDecoder(reader)
+ dec.CharsetReader = charset.NewReaderLabel
+ return dec
+}
+
+func trimParentNodesContentSpaces(node *xmlNode) {
+ if len(node.Nodes) > 0 {
+ node.Content = bytes.TrimSpace(node.Content)
+ for _, childNode := range node.Nodes {
+ trimParentNodesContentSpaces(childNode)
+ }
+ }
+}
+
+type xmlNode struct {
+ XMLName xml.Name
+ Comments []xml.Comment
+ ProcInsts []xml.ProcInst
+ XMLAttr []xml.Attr
+ Content []byte
+ Nodes []*xmlNode
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/match_xml_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/match_xml_matcher_test.go
new file mode 100644
index 000000000..0b559b22e
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/match_xml_matcher_test.go
@@ -0,0 +1,97 @@
+package matchers_test
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/matchers"
+)
+
+var _ = Describe("MatchXMLMatcher", func() {
+
+ var (
+ sample_01 = readFileContents("test_data/xml/sample_01.xml")
+ sample_02 = readFileContents("test_data/xml/sample_02.xml")
+ sample_03 = readFileContents("test_data/xml/sample_03.xml")
+ sample_04 = readFileContents("test_data/xml/sample_04.xml")
+ sample_05 = readFileContents("test_data/xml/sample_05.xml")
+ sample_06 = readFileContents("test_data/xml/sample_06.xml")
+ sample_07 = readFileContents("test_data/xml/sample_07.xml")
+ sample_08 = readFileContents("test_data/xml/sample_08.xml")
+ sample_09 = readFileContents("test_data/xml/sample_09.xml")
+ sample_10 = readFileContents("test_data/xml/sample_10.xml")
+ sample_11 = readFileContents("test_data/xml/sample_11.xml")
+ )
+
+ Context("When passed stringifiables", func() {
+ It("matches documents regardless of the attribute order", func() {
+ a := `<a foo="bar" ka="boom"></a>`
+ b := `<a ka="boom" foo="bar"></a>`
+ Expect(b).Should(MatchXML(a))
+ Expect(a).Should(MatchXML(b))
+ })
+
+ It("should succeed if the XML matches", func() {
+ Expect(sample_01).Should(MatchXML(sample_01)) // same XML
+ Expect(sample_01).Should(MatchXML(sample_02)) // same XML with blank lines
+ Expect(sample_01).Should(MatchXML(sample_03)) // same XML with different formatting
+ Expect(sample_01).ShouldNot(MatchXML(sample_04)) // same structures with different values
+ Expect(sample_01).ShouldNot(MatchXML(sample_05)) // different structures
+ Expect(sample_06).ShouldNot(MatchXML(sample_07)) // same xml names with different namespaces
+ Expect(sample_07).ShouldNot(MatchXML(sample_08)) // same structures with different values
+ Expect(sample_09).ShouldNot(MatchXML(sample_10)) // same structures with different attribute values
+ Expect(sample_11).Should(MatchXML(sample_11)) // with non UTF-8 encoding
+ })
+
+ It("should work with byte arrays", func() {
+ Expect([]byte(sample_01)).Should(MatchXML([]byte(sample_01)))
+ Expect([]byte(sample_01)).Should(MatchXML(sample_01))
+ Expect(sample_01).Should(MatchXML([]byte(sample_01)))
+ })
+ })
+
+ Context("when the expected is not valid XML", func() {
+ It("should error and explain why", func() {
+ success, err := (&MatchXMLMatcher{XMLToMatch: sample_01}).Match(`oops`)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ Expect(err.Error()).Should(ContainSubstring("Actual 'oops' should be valid XML"))
+ })
+ })
+
+ Context("when the actual is not valid XML", func() {
+ It("should error and explain why", func() {
+ success, err := (&MatchXMLMatcher{XMLToMatch: `oops`}).Match(sample_01)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ Expect(err.Error()).Should(ContainSubstring("Expected 'oops' should be valid XML"))
+ })
+ })
+
+ Context("when the expected is neither a string nor a stringer nor a byte array", func() {
+ It("should error", func() {
+ success, err := (&MatchXMLMatcher{XMLToMatch: 2}).Match(sample_01)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ Expect(err.Error()).Should(ContainSubstring("MatchXMLMatcher matcher requires a string, stringer, or []byte. Got expected:\n <int>: 2"))
+
+ success, err = (&MatchXMLMatcher{XMLToMatch: nil}).Match(sample_01)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ Expect(err.Error()).Should(ContainSubstring("MatchXMLMatcher matcher requires a string, stringer, or []byte. Got expected:\n <nil>: nil"))
+ })
+ })
+
+ Context("when the actual is neither a string nor a stringer nor a byte array", func() {
+ It("should error", func() {
+ success, err := (&MatchXMLMatcher{XMLToMatch: sample_01}).Match(2)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ Expect(err.Error()).Should(ContainSubstring("MatchXMLMatcher matcher requires a string, stringer, or []byte. Got actual:\n <int>: 2"))
+
+ success, err = (&MatchXMLMatcher{XMLToMatch: sample_01}).Match(nil)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ Expect(err.Error()).Should(ContainSubstring("MatchXMLMatcher matcher requires a string, stringer, or []byte. Got actual:\n <nil>: nil"))
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/match_yaml_matcher.go b/vendor/github.com/onsi/gomega/matchers/match_yaml_matcher.go
new file mode 100644
index 000000000..0c83c2b63
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/match_yaml_matcher.go
@@ -0,0 +1,76 @@
+package matchers
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/onsi/gomega/format"
+ "gopkg.in/yaml.v2"
+)
+
+type MatchYAMLMatcher struct {
+ YAMLToMatch interface{}
+ firstFailurePath []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)
+ }
+
+ var equal bool
+ equal, matcher.firstFailurePath = deepEqual(aval, eval)
+ return equal, nil
+}
+
+func (matcher *MatchYAMLMatcher) FailureMessage(actual interface{}) (message string) {
+ actualString, expectedString, _ := matcher.toNormalisedStrings(actual)
+ return formattedMessage(format.Message(actualString, "to match YAML of", expectedString), matcher.firstFailurePath)
+}
+
+func (matcher *MatchYAMLMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ actualString, expectedString, _ := matcher.toNormalisedStrings(actual)
+ return formattedMessage(format.Message(actualString, "not to match YAML of", expectedString), matcher.firstFailurePath)
+}
+
+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) // unreachable since Match already calls Unmarshal
+ }
+ output, err := yaml.Marshal(val)
+ if err != nil {
+ panic(err) // untested section, unreachable since we Unmarshal above
+ }
+ 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
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/match_yaml_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/match_yaml_matcher_test.go
new file mode 100644
index 000000000..1b0044fd0
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/match_yaml_matcher_test.go
@@ -0,0 +1,101 @@
+package 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+<string>: b: 2\s+to match YAML of\s+<string>: 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+<string>: b: two\s+to match YAML of\s+<string>: 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+<string>: a: 1\s+not to match YAML of\s+<string>: 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+<string>: a: one\s+not to match YAML of\s+<string>: 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"))
+ })
+
+ It("errors when passed directly to Message", func() {
+ Expect(func() {
+ matcher := MatchYAMLMatcher{YAMLToMatch: "good"}
+ matcher.FailureMessage("good:\nbad")
+ }).To(Panic())
+ })
+ })
+
+ 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 <int>: 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>: 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 <int>: 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>: nil"))
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/matcher_tests_suite_test.go b/vendor/github.com/onsi/gomega/matchers/matcher_tests_suite_test.go
new file mode 100644
index 000000000..b5f76c995
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/matcher_tests_suite_test.go
@@ -0,0 +1,50 @@
+package matchers_test
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "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")
+}
+
+func readFileContents(filePath string) []byte {
+ f := openFile(filePath)
+ b, err := ioutil.ReadAll(f)
+ if err != nil {
+ panic(fmt.Errorf("failed to read file contents: %v", err))
+ }
+ return b
+}
+
+func openFile(filePath string) *os.File {
+ f, err := os.Open(filePath)
+ if err != nil {
+ panic(fmt.Errorf("failed to open file: %v", err))
+ }
+ return f
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/not.go b/vendor/github.com/onsi/gomega/matchers/not.go
new file mode 100644
index 000000000..2c91670bd
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/not.go
@@ -0,0 +1,30 @@
+package 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
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/not_test.go b/vendor/github.com/onsi/gomega/matchers/not_test.go
new file mode 100644
index 000000000..06d3ebd17
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/not_test.go
@@ -0,0 +1,64 @@
+package 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))))
+ })
+
+ It("fails on error", func() {
+ failuresMessages := InterceptGomegaFailures(func() {
+ Expect(input).To(Not(Panic()))
+ })
+ Expect(failuresMessages).To(Equal([]string{"PanicMatcher expects a function. Got:\n <string>: hi"}))
+ })
+ })
+
+ 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
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/or.go b/vendor/github.com/onsi/gomega/matchers/or.go
new file mode 100644
index 000000000..3bf799800
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/or.go
@@ -0,0 +1,67 @@
+package 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
+ }
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/or_test.go b/vendor/github.com/onsi/gomega/matchers/or_test.go
new file mode 100644
index 000000000..1f6dfaf61
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/or_test.go
@@ -0,0 +1,92 @@
+package 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("stops on errors", func() {
+ failuresMessages := InterceptGomegaFailures(func() {
+ Expect(input).To(Or(Panic(), true1))
+ })
+ Expect(failuresMessages).To(Equal([]string{"PanicMatcher expects a function. Got:\n <string>: hi"}))
+ })
+
+ 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
+ })
+ })
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/panic_matcher.go b/vendor/github.com/onsi/gomega/matchers/panic_matcher.go
new file mode 100644
index 000000000..640f4db1a
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/panic_matcher.go
@@ -0,0 +1,46 @@
+package matchers
+
+import (
+ "fmt"
+ "reflect"
+
+ "github.com/onsi/gomega/format"
+)
+
+type PanicMatcher struct {
+ object interface{}
+}
+
+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 {
+ matcher.object = e
+ 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, fmt.Sprintf("not to panic, but panicked with\n%s", format.Object(matcher.object, 1)))
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/panic_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/panic_matcher_test.go
new file mode 100644
index 000000000..326bb10a4
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/panic_matcher_test.go
@@ -0,0 +1,52 @@
+package 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")
+ Expect(success).To(BeFalse())
+ Expect(err).To(HaveOccurred())
+
+ success, err = (&PanicMatcher{}).Match(nil)
+ Expect(success).To(BeFalse())
+ Expect(err).To(HaveOccurred())
+
+ success, err = (&PanicMatcher{}).Match(func(foo string) {})
+ Expect(success).To(BeFalse())
+ Expect(err).To(HaveOccurred())
+
+ success, err = (&PanicMatcher{}).Match(func() string { return "bar" })
+ Expect(success).To(BeFalse())
+ Expect(err).To(HaveOccurred())
+ })
+ })
+
+ Context("when passed a function of the correct type", func() {
+ It("should call the function and pass if the function panics", func() {
+ Expect(func() { panic("ack!") }).To(Panic())
+ Expect(func() {}).NotTo(Panic())
+ })
+ })
+
+ Context("when assertion fails", func() {
+ It("prints the object passed to Panic when negative", func() {
+ failuresMessages := InterceptGomegaFailures(func() {
+ Expect(func() { panic("ack!") }).NotTo(Panic())
+ })
+ Expect(failuresMessages).To(ConsistOf(ContainSubstring("not to panic, but panicked with\n <string>: ack!")))
+ })
+
+ It("prints simple message when positive", func() {
+ failuresMessages := InterceptGomegaFailures(func() {
+ Expect(func() {}).To(Panic())
+ })
+ Expect(failuresMessages).To(ConsistOf(MatchRegexp("Expected\n\\s+<func\\(\\)>: .+\nto panic")))
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/receive_matcher.go b/vendor/github.com/onsi/gomega/matchers/receive_matcher.go
new file mode 100644
index 000000000..2018a6128
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/receive_matcher.go
@@ -0,0 +1,128 @@
+package 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))
+ }
+ }
+ }
+
+ winnerIndex, value, open := reflect.Select([]reflect.SelectCase{
+ {Dir: reflect.SelectRecv, Chan: channelValue},
+ {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())
+ }
+ return false, nil
+ }
+
+ if didReceive {
+ if matcher.Arg != nil {
+ outValue := reflect.ValueOf(matcher.Arg)
+
+ if value.Type().AssignableTo(outValue.Elem().Type()) {
+ outValue.Elem().Set(value)
+ return true, nil
+ }
+ if value.Type().Kind() == reflect.Interface && value.Elem().Type().AssignableTo(outValue.Elem().Type()) {
+ outValue.Elem().Set(value.Elem())
+ return true, nil
+ } else {
+ return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nType:\n%s\nTo:\n%s", format.Object(actual, 1), format.Object(value.Interface(), 1), format.Object(matcher.Arg, 1))
+ }
+
+ }
+
+ return true, nil
+ }
+ 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."
+ }
+ 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."
+ }
+ return format.Message(actual, "not to receive anything."+closedAddendum)
+}
+
+func (matcher *ReceiveMatcher) MatchMayChangeInTheFuture(actual interface{}) bool {
+ if !isChan(actual) {
+ return false
+ }
+
+ return !matcher.channelClosed
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/receive_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/receive_matcher_test.go
new file mode 100644
index 000000000..cf04e85dd
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/receive_matcher_test.go
@@ -0,0 +1,304 @@
+package 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
+}
+
+type someError struct{ s string }
+
+func (e *someError) Error() string { return e.s }
+
+var _ = Describe("ReceiveMatcher", func() {
+ Context("with no argument", func() {
+ Context("for a buffered channel", func() {
+ It("should succeed", func() {
+ channel := make(chan bool, 1)
+
+ Expect(channel).ShouldNot(Receive())
+
+ channel <- true
+
+ Expect(channel).Should(Receive())
+ })
+ })
+
+ Context("for an unbuffered channel", func() {
+ It("should succeed (eventually)", func() {
+ channel := make(chan bool)
+
+ Expect(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() {
+ Context("when the channel has an interface type", func() {
+ It("should write the value received on the channel to the pointer", func() {
+ channel := make(chan error, 1)
+
+ var value *someError
+
+ Ω(channel).ShouldNot(Receive(&value))
+ Ω(value).Should(BeZero())
+
+ channel <- &someError{"boooom!"}
+
+ Ω(channel).Should(Receive(&value))
+ Ω(value).Should(MatchError("boooom!"))
+ })
+ })
+ })
+
+ 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
+
+ Expect(channel).ShouldNot(Receive(&value))
+ Expect(value).Should(BeZero())
+
+ channel <- 17
+
+ Expect(channel).Should(Receive(&value))
+ Expect(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
+ Expect(stringChan).Should(Receive(&s))
+ Expect(s).Should(Equal("foo"))
+
+ //channels of slices
+ sliceChan := make(chan []bool, 1)
+ sliceChan <- []bool{true, true, false}
+
+ var sl []bool
+ Expect(sliceChan).Should(Receive(&sl))
+ Expect(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
+ Expect(chanChan).Should(Receive(&receivedC))
+ Expect(receivedC).Should(Equal(c))
+
+ //channels of interfaces
+ jackieChan := make(chan kungFuActor, 1)
+ aJackie := &jackie{name: "Jackie Chan"}
+ jackieChan <- aJackie
+
+ var theJackie kungFuActor
+ Expect(jackieChan).Should(Receive(&theJackie))
+ Expect(theJackie).Should(Equal(aJackie))
+ })
+ })
+
+ Context("of the wrong type", func() {
+ It("should error", func() {
+ channel := make(chan int, 1)
+ channel <- 10
+
+ var incorrectType bool
+
+ success, err := (&ReceiveMatcher{Arg: &incorrectType}).Match(channel)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ var notAPointer int
+ success, err = (&ReceiveMatcher{Arg: notAPointer}).Match(channel)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+ })
+
+ Context("with a matcher", func() {
+ It("should defer to the underlying matcher", func() {
+ intChannel := make(chan int, 1)
+ intChannel <- 3
+ Expect(intChannel).Should(Receive(Equal(3)))
+
+ intChannel <- 2
+ Expect(intChannel).ShouldNot(Receive(Equal(3)))
+
+ stringChannel := make(chan []string, 1)
+ stringChannel <- []string{"foo", "bar", "baz"}
+ Expect(stringChannel).Should(Receive(ContainElement(ContainSubstring("fo"))))
+
+ stringChannel <- []string{"foo", "bar", "baz"}
+ Expect(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)
+ Expect(matcher.FailureMessage(channel)).Should(MatchRegexp(`Expected\s+<int>: 2\s+to equal\s+<int>: 3`))
+
+ channel <- 3
+ matcher.Match(channel)
+ Expect(matcher.NegatedFailureMessage(channel)).Should(MatchRegexp(`Expected\s+<int>: 3\s+not to equal\s+<int>: 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)
+ Expect(success).Should(BeFalse())
+ Expect(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)
+ Expect(success).Should(BeFalse())
+ Expect(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)
+
+ Expect(channel).Should(Receive())
+ Expect(channel).ShouldNot(Receive())
+ })
+ })
+
+ Context("for an unbuffered channel", func() {
+ It("should always fail", func() {
+ channel := make(chan bool)
+ close(channel)
+
+ Expect(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)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("when acutal is a non-channel", func() {
+ It("should error", func() {
+ var nilChannel chan bool
+
+ success, err := (&ReceiveMatcher{}).Match(nilChannel)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&ReceiveMatcher{}).Match(nil)
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(HaveOccurred())
+
+ success, err = (&ReceiveMatcher{}).Match(3)
+ Expect(success).Should(BeFalse())
+ Expect(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")))
+ })
+ Expect(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")))
+ })
+ Expect(failures[0]).Should(ContainSubstring("<string>: 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())
+ })
+ Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond))
+ Expect(failures).Should(HaveLen(1))
+ })
+
+ It("should bail early when passed a non-channel", func() {
+ t := time.Now()
+ failures := InterceptGomegaFailures(func() {
+ Eventually(3).Should(Receive())
+ })
+ Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond))
+ Expect(failures).Should(HaveLen(1))
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/semi_structured_data_support.go b/vendor/github.com/onsi/gomega/matchers/semi_structured_data_support.go
new file mode 100644
index 000000000..639295684
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/semi_structured_data_support.go
@@ -0,0 +1,92 @@
+package matchers
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+)
+
+func formattedMessage(comparisonMessage string, failurePath []interface{}) string {
+ var diffMessage string
+ if len(failurePath) == 0 {
+ diffMessage = ""
+ } else {
+ diffMessage = fmt.Sprintf("\n\nfirst mismatched key: %s", formattedFailurePath(failurePath))
+ }
+ return fmt.Sprintf("%s%s", comparisonMessage, diffMessage)
+}
+
+func formattedFailurePath(failurePath []interface{}) string {
+ formattedPaths := []string{}
+ for i := len(failurePath) - 1; i >= 0; i-- {
+ switch p := failurePath[i].(type) {
+ case int:
+ formattedPaths = append(formattedPaths, fmt.Sprintf(`[%d]`, p))
+ default:
+ if i != len(failurePath)-1 {
+ formattedPaths = append(formattedPaths, ".")
+ }
+ formattedPaths = append(formattedPaths, fmt.Sprintf(`"%s"`, p))
+ }
+ }
+ return strings.Join(formattedPaths, "")
+}
+
+func deepEqual(a interface{}, b interface{}) (bool, []interface{}) {
+ var errorPath []interface{}
+ if reflect.TypeOf(a) != reflect.TypeOf(b) {
+ return false, errorPath
+ }
+
+ switch a.(type) {
+ case []interface{}:
+ if len(a.([]interface{})) != len(b.([]interface{})) {
+ return false, errorPath
+ }
+
+ for i, v := range a.([]interface{}) {
+ elementEqual, keyPath := deepEqual(v, b.([]interface{})[i])
+ if !elementEqual {
+ return false, append(keyPath, i)
+ }
+ }
+ return true, errorPath
+
+ case map[interface{}]interface{}:
+ if len(a.(map[interface{}]interface{})) != len(b.(map[interface{}]interface{})) {
+ return false, errorPath
+ }
+
+ for k, v1 := range a.(map[interface{}]interface{}) {
+ v2, ok := b.(map[interface{}]interface{})[k]
+ if !ok {
+ return false, errorPath
+ }
+ elementEqual, keyPath := deepEqual(v1, v2)
+ if !elementEqual {
+ return false, append(keyPath, k)
+ }
+ }
+ return true, errorPath
+
+ case map[string]interface{}:
+ if len(a.(map[string]interface{})) != len(b.(map[string]interface{})) {
+ return false, errorPath
+ }
+
+ for k, v1 := range a.(map[string]interface{}) {
+ v2, ok := b.(map[string]interface{})[k]
+ if !ok {
+ return false, errorPath
+ }
+ elementEqual, keyPath := deepEqual(v1, v2)
+ if !elementEqual {
+ return false, append(keyPath, k)
+ }
+ }
+ return true, errorPath
+
+ default:
+ return a == b, errorPath
+ }
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/succeed_matcher.go b/vendor/github.com/onsi/gomega/matchers/succeed_matcher.go
new file mode 100644
index 000000000..721ed5529
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/succeed_matcher.go
@@ -0,0 +1,33 @@
+package 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."
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/succeed_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/succeed_matcher_test.go
new file mode 100644
index 000000000..e42dd8a6e
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/succeed_matcher_test.go
@@ -0,0 +1,72 @@
+package matchers_test
+
+import (
+ "errors"
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/matchers"
+ "regexp"
+)
+
+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() {
+ Expect(NotErroring()).Should(Succeed())
+ })
+
+ It("should succeed (in the negated) if the function errored", func() {
+ Expect(Erroring()).ShouldNot(Succeed())
+ })
+
+ It("should not if passed a non-error", func() {
+ success, err := (&SucceedMatcher{}).Match(Invalid())
+ Expect(success).Should(BeFalse())
+ Expect(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{})
+ Expect(success).Should(BeFalse())
+ Expect(err).Should(MatchError("Expected an error-type. Got:\n <matchers_test.AnyType>: {}"))
+ })
+
+ It("doesn't support non-error pointer type", func() {
+ success, err := (&SucceedMatcher{}).Match(&AnyType{})
+ Expect(success).Should(BeFalse())
+ Expect(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"}
+ Expect(err).ShouldNot(Succeed())
+ })
+
+ It("should succeed with nil pointers to types that conform to error interface", func() {
+ var err *CustomErr = nil
+ Expect(err).Should(Succeed())
+ })
+
+ It("builds failure message", func() {
+ actual := Succeed().FailureMessage(errors.New("oops"))
+ actual = regexp.MustCompile(" 0x.*>").ReplaceAllString(actual, " 0x00000000>")
+ Expect(actual).To(Equal("Expected success, but got an error:\n <*errors.errorString | 0x00000000>: {s: \"oops\"}\n oops"))
+ })
+
+ It("builds negated failure message", func() {
+ actual := Succeed().NegatedFailureMessage(123)
+ Expect(actual).To(Equal("Expected failure, but got no error."))
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/matchers/support/goraph/MIT.LICENSE b/vendor/github.com/onsi/gomega/matchers/support/goraph/MIT.LICENSE
new file mode 100644
index 000000000..8edd8175a
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/support/goraph/MIT.LICENSE
@@ -0,0 +1,20 @@
+Copyright (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.
diff --git a/vendor/github.com/onsi/gomega/matchers/support/goraph/bipartitegraph/bipartitegraph.go b/vendor/github.com/onsi/gomega/matchers/support/goraph/bipartitegraph/bipartitegraph.go
new file mode 100644
index 000000000..8aaf8759d
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/support/goraph/bipartitegraph/bipartitegraph.go
@@ -0,0 +1,41 @@
+package 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{Id: i})
+ }
+
+ right := NodeOrderedSet{}
+ for j := range rightValues {
+ right = append(right, Node{Id: 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{Node1: left[i], Node2: right[j]})
+ }
+ }
+ }
+
+ return &BipartiteGraph{left, right, edges}, nil
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/support/goraph/bipartitegraph/bipartitegraphmatching.go b/vendor/github.com/onsi/gomega/matchers/support/goraph/bipartitegraph/bipartitegraphmatching.go
new file mode 100644
index 000000000..8181f43a4
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/support/goraph/bipartitegraph/bipartitegraphmatching.go
@@ -0,0 +1,159 @@
+package 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{}
+ }
+ 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{}
+ }
+ guideLayers = append(guideLayers, currentLayer)
+ }
+
+ return
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/support/goraph/edge/edge.go b/vendor/github.com/onsi/gomega/matchers/support/goraph/edge/edge.go
new file mode 100644
index 000000000..4fd15cc06
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/support/goraph/edge/edge.go
@@ -0,0 +1,61 @@
+package 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
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/support/goraph/node/node.go b/vendor/github.com/onsi/gomega/matchers/support/goraph/node/node.go
new file mode 100644
index 000000000..800c2ea8c
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/support/goraph/node/node.go
@@ -0,0 +1,7 @@
+package node
+
+type Node struct {
+ Id int
+}
+
+type NodeOrderedSet []Node
diff --git a/vendor/github.com/onsi/gomega/matchers/support/goraph/util/util.go b/vendor/github.com/onsi/gomega/matchers/support/goraph/util/util.go
new file mode 100644
index 000000000..d76a1ee00
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/support/goraph/util/util.go
@@ -0,0 +1,7 @@
+package util
+
+import "math"
+
+func Odd(n int) bool {
+ return math.Mod(float64(n), 2.0) == 1.0
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_01.xml b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_01.xml
new file mode 100644
index 000000000..90f0a1b45
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_01.xml
@@ -0,0 +1,6 @@
+<note>
+ <to>Tove</to>
+ <from>Jani</from>
+ <heading>Reminder</heading>
+ <body>Don't forget me this weekend!</body>
+</note> \ No newline at end of file
diff --git a/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_02.xml b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_02.xml
new file mode 100644
index 000000000..3863b83c3
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_02.xml
@@ -0,0 +1,9 @@
+
+
+<note>
+ <to>Tove</to>
+ <from>Jani</from>
+ <heading>Reminder</heading>
+ <body>Don't forget me this weekend!</body>
+</note>
+
diff --git a/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_03.xml b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_03.xml
new file mode 100644
index 000000000..a491c213c
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_03.xml
@@ -0,0 +1 @@
+<note> <to>Tove</to> <from>Jani</from> <heading>Reminder</heading> <body>Don't forget me this weekend!</body> </note>
diff --git a/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_04.xml b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_04.xml
new file mode 100644
index 000000000..dcfd3db03
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_04.xml
@@ -0,0 +1,6 @@
+<note>
+ <to>Tove</to>
+ <from>John</from>
+ <heading>Doe</heading>
+ <body>Don't forget me this weekend!</body>
+</note> \ No newline at end of file
diff --git a/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_05.xml b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_05.xml
new file mode 100644
index 000000000..de15a6a55
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_05.xml
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CATALOG>
+ <CD>
+ <TITLE>Empire Burlesque</TITLE>
+ <ARTIST>Bob Dylan</ARTIST>
+ <COUNTRY>USA</COUNTRY>
+ <COMPANY>Columbia</COMPANY>
+ <PRICE>10.90</PRICE>
+ <YEAR>1985</YEAR>
+ </CD>
+ <CD>
+ <TITLE>Hide your heart</TITLE>
+ <ARTIST>Bonnie Tyler</ARTIST>
+ <COUNTRY>UK</COUNTRY>
+ <COMPANY>CBS Records</COMPANY>
+ <PRICE>9.90</PRICE>
+ <YEAR>1988</YEAR>
+ </CD>
+ <CD>
+ <TITLE>Greatest Hits</TITLE>
+ <ARTIST>Dolly Parton</ARTIST>
+ <COUNTRY>USA</COUNTRY>
+ <COMPANY>RCA</COMPANY>
+ <PRICE>9.90</PRICE>
+ <YEAR>1982</YEAR>
+ </CD>
+ <CD>
+ <TITLE>Still got the blues</TITLE>
+ <ARTIST>Gary Moore</ARTIST>
+ <COUNTRY>UK</COUNTRY>
+ <COMPANY>Virgin records</COMPANY>
+ <PRICE>10.20</PRICE>
+ <YEAR>1990</YEAR>
+ </CD>
+ <CD>
+ <TITLE>Eros</TITLE>
+ <ARTIST>Eros Ramazzotti</ARTIST>
+ <COUNTRY>EU</COUNTRY>
+ <COMPANY>BMG</COMPANY>
+ <PRICE>9.90</PRICE>
+ <YEAR>1997</YEAR>
+ </CD>
+ <CD>
+ <TITLE>One night only</TITLE>
+ <ARTIST>Bee Gees</ARTIST>
+ <COUNTRY>UK</COUNTRY>
+ <COMPANY>Polydor</COMPANY>
+ <PRICE>10.90</PRICE>
+ <YEAR>1998</YEAR>
+ </CD>
+ <CD>
+ <TITLE>Sylvias Mother</TITLE>
+ <ARTIST>Dr.Hook</ARTIST>
+ <COUNTRY>UK</COUNTRY>
+ <COMPANY>CBS</COMPANY>
+ <PRICE>8.10</PRICE>
+ <YEAR>1973</YEAR>
+ </CD>
+ <CD>
+ <TITLE>Maggie May</TITLE>
+ <ARTIST>Rod Stewart</ARTIST>
+ <COUNTRY>UK</COUNTRY>
+ <COMPANY>Pickwick</COMPANY>
+ <PRICE>8.50</PRICE>
+ <YEAR>1990</YEAR>
+ </CD>
+ <CD>
+ <TITLE>Romanza</TITLE>
+ <ARTIST>Andrea Bocelli</ARTIST>
+ <COUNTRY>EU</COUNTRY>
+ <COMPANY>Polydor</COMPANY>
+ <PRICE>10.80</PRICE>
+ <YEAR>1996</YEAR>
+ </CD>
+ <CD>
+ <TITLE>When a man loves a woman</TITLE>
+ <ARTIST>Percy Sledge</ARTIST>
+ <COUNTRY>USA</COUNTRY>
+ <COMPANY>Atlantic</COMPANY>
+ <PRICE>8.70</PRICE>
+ <YEAR>1987</YEAR>
+ </CD>
+ <CD>
+ <TITLE>Black angel</TITLE>
+ <ARTIST>Savage Rose</ARTIST>
+ <COUNTRY>EU</COUNTRY>
+ <COMPANY>Mega</COMPANY>
+ <PRICE>10.90</PRICE>
+ <YEAR>1995</YEAR>
+ </CD>
+ <CD>
+ <TITLE>1999 Grammy Nominees</TITLE>
+ <ARTIST>Many</ARTIST>
+ <COUNTRY>USA</COUNTRY>
+ <COMPANY>Grammy</COMPANY>
+ <PRICE>10.20</PRICE>
+ <YEAR>1999</YEAR>
+ </CD>
+ <CD>
+ <TITLE>For the good times</TITLE>
+ <ARTIST>Kenny Rogers</ARTIST>
+ <COUNTRY>UK</COUNTRY>
+ <COMPANY>Mucik Master</COMPANY>
+ <PRICE>8.70</PRICE>
+ <YEAR>1995</YEAR>
+ </CD>
+ <CD>
+ <TITLE>Big Willie style</TITLE>
+ <ARTIST>Will Smith</ARTIST>
+ <COUNTRY>USA</COUNTRY>
+ <COMPANY>Columbia</COMPANY>
+ <PRICE>9.90</PRICE>
+ <YEAR>1997</YEAR>
+ </CD>
+ <CD>
+ <TITLE>Tupelo Honey</TITLE>
+ <ARTIST>Van Morrison</ARTIST>
+ <COUNTRY>UK</COUNTRY>
+ <COMPANY>Polydor</COMPANY>
+ <PRICE>8.20</PRICE>
+ <YEAR>1971</YEAR>
+ </CD>
+ <CD>
+ <TITLE>Soulsville</TITLE>
+ <ARTIST>Jorn Hoel</ARTIST>
+ <COUNTRY>Norway</COUNTRY>
+ <COMPANY>WEA</COMPANY>
+ <PRICE>7.90</PRICE>
+ <YEAR>1996</YEAR>
+ </CD>
+ <CD>
+ <TITLE>The very best of</TITLE>
+ <ARTIST>Cat Stevens</ARTIST>
+ <COUNTRY>UK</COUNTRY>
+ <COMPANY>Island</COMPANY>
+ <PRICE>8.90</PRICE>
+ <YEAR>1990</YEAR>
+ </CD>
+ <CD>
+ <TITLE>Stop</TITLE>
+ <ARTIST>Sam Brown</ARTIST>
+ <COUNTRY>UK</COUNTRY>
+ <COMPANY>A and M</COMPANY>
+ <PRICE>8.90</PRICE>
+ <YEAR>1988</YEAR>
+ </CD>
+ <CD>
+ <TITLE>Bridge of Spies</TITLE>
+ <ARTIST>T'Pau</ARTIST>
+ <COUNTRY>UK</COUNTRY>
+ <COMPANY>Siren</COMPANY>
+ <PRICE>7.90</PRICE>
+ <YEAR>1987</YEAR>
+ </CD>
+ <CD>
+ <TITLE>Private Dancer</TITLE>
+ <ARTIST>Tina Turner</ARTIST>
+ <COUNTRY>UK</COUNTRY>
+ <COMPANY>Capitol</COMPANY>
+ <PRICE>8.90</PRICE>
+ <YEAR>1983</YEAR>
+ </CD>
+ <CD>
+ <TITLE>Midt om natten</TITLE>
+ <ARTIST>Kim Larsen</ARTIST>
+ <COUNTRY>EU</COUNTRY>
+ <COMPANY>Medley</COMPANY>
+ <PRICE>7.80</PRICE>
+ <YEAR>1983</YEAR>
+ </CD>
+ <CD>
+ <TITLE>Pavarotti Gala Concert</TITLE>
+ <ARTIST>Luciano Pavarotti</ARTIST>
+ <COUNTRY>UK</COUNTRY>
+ <COMPANY>DECCA</COMPANY>
+ <PRICE>9.90</PRICE>
+ <YEAR>1991</YEAR>
+ </CD>
+ <CD>
+ <TITLE>The dock of the bay</TITLE>
+ <ARTIST>Otis Redding</ARTIST>
+ <COUNTRY>USA</COUNTRY>
+ <COMPANY>Stax Records</COMPANY>
+ <PRICE>7.90</PRICE>
+ <YEAR>1968</YEAR>
+ </CD>
+ <CD>
+ <TITLE>Picture book</TITLE>
+ <ARTIST>Simply Red</ARTIST>
+ <COUNTRY>EU</COUNTRY>
+ <COMPANY>Elektra</COMPANY>
+ <PRICE>7.20</PRICE>
+ <YEAR>1985</YEAR>
+ </CD>
+ <CD>
+ <TITLE>Red</TITLE>
+ <ARTIST>The Communards</ARTIST>
+ <COUNTRY>UK</COUNTRY>
+ <COMPANY>London</COMPANY>
+ <PRICE>7.80</PRICE>
+ <YEAR>1987</YEAR>
+ </CD>
+ <CD>
+ <TITLE>Unchain my heart</TITLE>
+ <ARTIST>Joe Cocker</ARTIST>
+ <COUNTRY>USA</COUNTRY>
+ <COMPANY>EMI</COMPANY>
+ <PRICE>8.20</PRICE>
+ <YEAR>1987</YEAR>
+ </CD>
+</CATALOG>
diff --git a/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_06.xml b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_06.xml
new file mode 100644
index 000000000..4ba90fb97
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_06.xml
@@ -0,0 +1,13 @@
+<root>
+ <table>
+ <tr>
+ <td>Apples</td>
+ <td>Bananas</td>
+ </tr>
+ </table>
+ <table>
+ <name>African Coffee Table</name>
+ <width>80</width>
+ <length>120</length>
+ </table>
+</root> \ No newline at end of file
diff --git a/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_07.xml b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_07.xml
new file mode 100644
index 000000000..34b9e9775
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_07.xml
@@ -0,0 +1,13 @@
+<root>
+ <h:table xmlns:h="http://www.w3.org/TR/html4/">
+ <h:tr>
+ <h:td>Apples</h:td>
+ <h:td>Bananas</h:td>
+ </h:tr>
+ </h:table>
+ <f:table xmlns:f="https://www.w3schools.com/furniture">
+ <f:name>African Coffee Table</f:name>
+ <f:width>80</f:width>
+ <f:length>120</f:length>
+ </f:table>
+</root> \ No newline at end of file
diff --git a/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_08.xml b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_08.xml
new file mode 100644
index 000000000..ccaee4e1a
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_08.xml
@@ -0,0 +1,13 @@
+<root>
+ <h:table xmlns:h="http://www.w3.org/TR/html4/">
+ <h:tr>
+ <h:td>Apples</h:td>
+ <h:td>Oranges</h:td>
+ </h:tr>
+ </h:table>
+ <f:table xmlns:f="https://www.w3schools.com/furniture">
+ <f:name>African Coffee Table</f:name>
+ <f:width>80</f:width>
+ <f:length>120</f:length>
+ </f:table>
+</root> \ No newline at end of file
diff --git a/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_09.xml b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_09.xml
new file mode 100644
index 000000000..531f84d3f
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_09.xml
@@ -0,0 +1,4 @@
+<person gender="female">
+ <firstname>Foo</firstname>
+ <lastname>Bar</lastname>
+</person> \ No newline at end of file
diff --git a/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_10.xml b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_10.xml
new file mode 100644
index 000000000..b1e1e1fbe
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_10.xml
@@ -0,0 +1,4 @@
+<person gender="male">
+ <firstname>Foo</firstname>
+ <lastname>Bar</lastname>
+</person> \ No newline at end of file
diff --git a/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_11.xml b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_11.xml
new file mode 100644
index 000000000..3132b0f90
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/test_data/xml/sample_11.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
+<note>
+ <to>Tove</to>
+ <from>Jani</from>
+ <heading>Reminder</heading>
+ <body>Don't forget me this weekend!</body>
+</note>
diff --git a/vendor/github.com/onsi/gomega/matchers/type_support.go b/vendor/github.com/onsi/gomega/matchers/type_support.go
new file mode 100644
index 000000000..75afcd844
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/type_support.go
@@ -0,0 +1,179 @@
+/*
+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 (
+ "encoding/json"
+ "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())
+ }
+ 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())
+ }
+ 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()
+ }
+ 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
+ }
+
+ aJSONRawMessage, isJSONRawMessage := a.(json.RawMessage)
+ if isJSONRawMessage {
+ return string(aJSONRawMessage), 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
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/with_transform.go b/vendor/github.com/onsi/gomega/matchers/with_transform.go
new file mode 100644
index 000000000..8e58d8a0f
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/with_transform.go
@@ -0,0 +1,72 @@
+package 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)
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/with_transform_test.go b/vendor/github.com/onsi/gomega/matchers/with_transform_test.go
new file mode 100644
index 000000000..e52bf8e63
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/with_transform_test.go
@@ -0,0 +1,102 @@
+package 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 <int>: 2\nto equal\n <int>: 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 <int>: 3\nnot to equal\n <int>: 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
+ })
+ })
+})
diff --git a/vendor/github.com/onsi/gomega/types/types.go b/vendor/github.com/onsi/gomega/types/types.go
new file mode 100644
index 000000000..ac59a3a5a
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/types/types.go
@@ -0,0 +1,26 @@
+package types
+
+type TWithHelper interface {
+ Helper()
+}
+
+type GomegaFailHandler func(message string, callerSkip ...int)
+
+type GomegaFailWrapper struct {
+ Fail GomegaFailHandler
+ TWithHelper TWithHelper
+}
+
+//A simple *testing.T interface wrapper
+type GomegaTestingT interface {
+ Fatalf(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)
+}