summaryrefslogtreecommitdiffstats
path: root/vendor/github.com
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com')
-rw-r--r--vendor/github.com/Sirupsen/logrus/.gitignore1
-rw-r--r--vendor/github.com/Sirupsen/logrus/.travis.yml8
-rw-r--r--vendor/github.com/Sirupsen/logrus/CHANGELOG.md94
-rw-r--r--vendor/github.com/Sirupsen/logrus/LICENSE21
-rw-r--r--vendor/github.com/Sirupsen/logrus/README.md476
-rw-r--r--vendor/github.com/Sirupsen/logrus/alt_exit.go64
-rw-r--r--vendor/github.com/Sirupsen/logrus/alt_exit_test.go74
-rw-r--r--vendor/github.com/Sirupsen/logrus/doc.go26
-rw-r--r--vendor/github.com/Sirupsen/logrus/entry.go275
-rw-r--r--vendor/github.com/Sirupsen/logrus/entry_test.go77
-rw-r--r--vendor/github.com/Sirupsen/logrus/examples/basic/basic.go59
-rw-r--r--vendor/github.com/Sirupsen/logrus/examples/hook/hook.go30
-rw-r--r--vendor/github.com/Sirupsen/logrus/exported.go193
-rw-r--r--vendor/github.com/Sirupsen/logrus/formatter.go45
-rw-r--r--vendor/github.com/Sirupsen/logrus/formatter_bench_test.go101
-rw-r--r--vendor/github.com/Sirupsen/logrus/hook_test.go122
-rw-r--r--vendor/github.com/Sirupsen/logrus/hooks.go34
-rw-r--r--vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md39
-rw-r--r--vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go54
-rw-r--r--vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go26
-rw-r--r--vendor/github.com/Sirupsen/logrus/hooks/test/test.go67
-rw-r--r--vendor/github.com/Sirupsen/logrus/hooks/test/test_test.go39
-rw-r--r--vendor/github.com/Sirupsen/logrus/json_formatter.go74
-rw-r--r--vendor/github.com/Sirupsen/logrus/json_formatter_test.go199
-rw-r--r--vendor/github.com/Sirupsen/logrus/logger.go308
-rw-r--r--vendor/github.com/Sirupsen/logrus/logger_bench_test.go61
-rw-r--r--vendor/github.com/Sirupsen/logrus/logrus.go143
-rw-r--r--vendor/github.com/Sirupsen/logrus/logrus_test.go386
-rw-r--r--vendor/github.com/Sirupsen/logrus/terminal_appengine.go10
-rw-r--r--vendor/github.com/Sirupsen/logrus/terminal_bsd.go10
-rw-r--r--vendor/github.com/Sirupsen/logrus/terminal_linux.go14
-rw-r--r--vendor/github.com/Sirupsen/logrus/terminal_notwindows.go28
-rw-r--r--vendor/github.com/Sirupsen/logrus/terminal_solaris.go21
-rw-r--r--vendor/github.com/Sirupsen/logrus/terminal_windows.go33
-rw-r--r--vendor/github.com/Sirupsen/logrus/text_formatter.go189
-rw-r--r--vendor/github.com/Sirupsen/logrus/text_formatter_test.go87
-rw-r--r--vendor/github.com/Sirupsen/logrus/writer.go62
-rw-r--r--vendor/github.com/bennyscetbun/jsongo/.gitignore24
-rw-r--r--vendor/github.com/bennyscetbun/jsongo/LICENSE21
-rw-r--r--vendor/github.com/bennyscetbun/jsongo/README.md574
-rw-r--r--vendor/github.com/bennyscetbun/jsongo/debug.go60
-rw-r--r--vendor/github.com/bennyscetbun/jsongo/jsongo.go472
-rw-r--r--vendor/github.com/bennyscetbun/jsongo/print.go74
-rw-r--r--vendor/github.com/lunixbochs/struc/.travis.yml10
-rw-r--r--vendor/github.com/lunixbochs/struc/LICENSE19
-rw-r--r--vendor/github.com/lunixbochs/struc/README.md103
-rw-r--r--vendor/github.com/lunixbochs/struc/bench_test.go165
-rw-r--r--vendor/github.com/lunixbochs/struc/binary.go52
-rw-r--r--vendor/github.com/lunixbochs/struc/custom.go33
-rw-r--r--vendor/github.com/lunixbochs/struc/custom_float16.go78
-rw-r--r--vendor/github.com/lunixbochs/struc/custom_float16_test.go56
-rw-r--r--vendor/github.com/lunixbochs/struc/custom_test.go97
-rw-r--r--vendor/github.com/lunixbochs/struc/field.go281
-rw-r--r--vendor/github.com/lunixbochs/struc/field_test.go77
-rw-r--r--vendor/github.com/lunixbochs/struc/fields.go169
-rw-r--r--vendor/github.com/lunixbochs/struc/fields_test.go59
-rw-r--r--vendor/github.com/lunixbochs/struc/legacy.go16
-rw-r--r--vendor/github.com/lunixbochs/struc/packable_test.go123
-rw-r--r--vendor/github.com/lunixbochs/struc/packer.go13
-rw-r--r--vendor/github.com/lunixbochs/struc/parse.go217
-rw-r--r--vendor/github.com/lunixbochs/struc/parse_test.go62
-rw-r--r--vendor/github.com/lunixbochs/struc/struc.go117
-rw-r--r--vendor/github.com/lunixbochs/struc/struc_test.go197
-rw-r--r--vendor/github.com/lunixbochs/struc/types.go136
-rw-r--r--vendor/github.com/lunixbochs/struc/types_test.go53
-rw-r--r--vendor/github.com/onsi/gomega/.gitignore5
-rw-r--r--vendor/github.com/onsi/gomega/.travis.yml11
-rw-r--r--vendor/github.com/onsi/gomega/CHANGELOG.md70
-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/format/format.go384
-rw-r--r--vendor/github.com/onsi/gomega/format/format_suite_test.go13
-rw-r--r--vendor/github.com/onsi/gomega/format/format_test.go590
-rw-r--r--vendor/github.com/onsi/gomega/gbytes/buffer.go229
-rw-r--r--vendor/github.com/onsi/gomega/gbytes/buffer_test.go158
-rw-r--r--vendor/github.com/onsi/gomega/gbytes/gbuffer_suite_test.go13
-rw-r--r--vendor/github.com/onsi/gomega/gbytes/say_matcher.go105
-rw-r--r--vendor/github.com/onsi/gomega/gbytes/say_matcher_test.go163
-rw-r--r--vendor/github.com/onsi/gomega/gexec/_fixture/firefly/main.go36
-rw-r--r--vendor/github.com/onsi/gomega/gexec/build.go99
-rw-r--r--vendor/github.com/onsi/gomega/gexec/build_test.go59
-rw-r--r--vendor/github.com/onsi/gomega/gexec/exit_matcher.go88
-rw-r--r--vendor/github.com/onsi/gomega/gexec/exit_matcher_test.go113
-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.go305
-rw-r--r--vendor/github.com/onsi/gomega/gexec/session_test.go351
-rw-r--r--vendor/github.com/onsi/gomega/ghttp/handlers.go313
-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.go381
-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.go1089
-rw-r--r--vendor/github.com/onsi/gomega/gomega_dsl.go335
-rw-r--r--vendor/github.com/onsi/gomega/gstruct/elements.go145
-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.go141
-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.go98
-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.go252
-rw-r--r--vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion.go189
-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.go345
-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.go40
-rw-r--r--vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support_test.go12
-rw-r--r--vendor/github.com/onsi/gomega/matchers.go418
-rw-r--r--vendor/github.com/onsi/gomega/matchers/and.go64
-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.go31
-rw-r--r--vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher_test.go30
-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.go45
-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.go26
-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.go33
-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.go25
-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.go120
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_numerically_matcher_test.go148
-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.go106
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_temporally_matcher.go65
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_temporally_matcher_test.go98
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_true_matcher.go25
-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.go27
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_zero_matcher_test.go30
-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.go37
-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.go33
-rw-r--r--vendor/github.com/onsi/gomega/matchers/equal_matcher_test.go78
-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.go53
-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.go73
-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.go27
-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.go58
-rw-r--r--vendor/github.com/onsi/gomega/matchers/have_prefix_matcher.go35
-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.go35
-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.go50
-rw-r--r--vendor/github.com/onsi/gomega/matchers/match_error_matcher_test.go93
-rw-r--r--vendor/github.com/onsi/gomega/matchers/match_json_matcher.go64
-rw-r--r--vendor/github.com/onsi/gomega/matchers/match_json_matcher_test.go73
-rw-r--r--vendor/github.com/onsi/gomega/matchers/match_regexp_matcher.go42
-rw-r--r--vendor/github.com/onsi/gomega/matchers/match_regexp_matcher_test.go44
-rw-r--r--vendor/github.com/onsi/gomega/matchers/match_yaml_matcher.go74
-rw-r--r--vendor/github.com/onsi/gomega/matchers/match_yaml_matcher_test.go94
-rw-r--r--vendor/github.com/onsi/gomega/matchers/matcher_tests_suite_test.go30
-rw-r--r--vendor/github.com/onsi/gomega/matchers/not.go30
-rw-r--r--vendor/github.com/onsi/gomega/matchers/not_test.go57
-rw-r--r--vendor/github.com/onsi/gomega/matchers/or.go67
-rw-r--r--vendor/github.com/onsi/gomega/matchers/or_test.go85
-rw-r--r--vendor/github.com/onsi/gomega/matchers/panic_matcher.go46
-rw-r--r--vendor/github.com/onsi/gomega/matchers/panic_matcher_test.go45
-rw-r--r--vendor/github.com/onsi/gomega/matchers/receive_matcher.go126
-rw-r--r--vendor/github.com/onsi/gomega/matchers/receive_matcher_test.go280
-rw-r--r--vendor/github.com/onsi/gomega/matchers/succeed_matcher.go33
-rw-r--r--vendor/github.com/onsi/gomega/matchers/succeed_matcher_test.go62
-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.go161
-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/type_support.go176
-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.go17
201 files changed, 19115 insertions, 0 deletions
diff --git a/vendor/github.com/Sirupsen/logrus/.gitignore b/vendor/github.com/Sirupsen/logrus/.gitignore
new file mode 100644
index 0000000..66be63a
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/.gitignore
@@ -0,0 +1 @@
+logrus
diff --git a/vendor/github.com/Sirupsen/logrus/.travis.yml b/vendor/github.com/Sirupsen/logrus/.travis.yml
new file mode 100644
index 0000000..804c569
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/.travis.yml
@@ -0,0 +1,8 @@
+language: go
+go:
+ - 1.6
+ - 1.7
+ - tip
+install:
+ - go get -t ./...
+script: GOMAXPROCS=4 GORACE="halt_on_error=1" go test -race -v ./...
diff --git a/vendor/github.com/Sirupsen/logrus/CHANGELOG.md b/vendor/github.com/Sirupsen/logrus/CHANGELOG.md
new file mode 100644
index 0000000..747e4d8
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/CHANGELOG.md
@@ -0,0 +1,94 @@
+# 0.11.5
+
+* feature: add writer and writerlevel to entry (#372)
+
+# 0.11.4
+
+* bug: fix undefined variable on solaris (#493)
+
+# 0.11.3
+
+* formatter: configure quoting of empty values (#484)
+* formatter: configure quoting character (default is `"`) (#484)
+* bug: fix not importing io correctly in non-linux environments (#481)
+
+# 0.11.2
+
+* bug: fix windows terminal detection (#476)
+
+# 0.11.1
+
+* bug: fix tty detection with custom out (#471)
+
+# 0.11.0
+
+* performance: Use bufferpool to allocate (#370)
+* terminal: terminal detection for app-engine (#343)
+* feature: exit handler (#375)
+
+# 0.10.0
+
+* feature: Add a test hook (#180)
+* feature: `ParseLevel` is now case-insensitive (#326)
+* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308)
+* performance: avoid re-allocations on `WithFields` (#335)
+
+# 0.9.0
+
+* logrus/text_formatter: don't emit empty msg
+* logrus/hooks/airbrake: move out of main repository
+* logrus/hooks/sentry: move out of main repository
+* logrus/hooks/papertrail: move out of main repository
+* logrus/hooks/bugsnag: move out of main repository
+* logrus/core: run tests with `-race`
+* logrus/core: detect TTY based on `stderr`
+* logrus/core: support `WithError` on logger
+* logrus/core: Solaris support
+
+# 0.8.7
+
+* logrus/core: fix possible race (#216)
+* logrus/doc: small typo fixes and doc improvements
+
+
+# 0.8.6
+
+* hooks/raven: allow passing an initialized client
+
+# 0.8.5
+
+* logrus/core: revert #208
+
+# 0.8.4
+
+* formatter/text: fix data race (#218)
+
+# 0.8.3
+
+* logrus/core: fix entry log level (#208)
+* logrus/core: improve performance of text formatter by 40%
+* logrus/core: expose `LevelHooks` type
+* logrus/core: add support for DragonflyBSD and NetBSD
+* formatter/text: print structs more verbosely
+
+# 0.8.2
+
+* logrus: fix more Fatal family functions
+
+# 0.8.1
+
+* logrus: fix not exiting on `Fatalf` and `Fatalln`
+
+# 0.8.0
+
+* logrus: defaults to stderr instead of stdout
+* hooks/sentry: add special field for `*http.Request`
+* formatter/text: ignore Windows for colors
+
+# 0.7.3
+
+* formatter/\*: allow configuration of timestamp layout
+
+# 0.7.2
+
+* formatter/text: Add configuration option for time format (#158)
diff --git a/vendor/github.com/Sirupsen/logrus/LICENSE b/vendor/github.com/Sirupsen/logrus/LICENSE
new file mode 100644
index 0000000..f090cb4
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Simon Eskildsen
+
+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/Sirupsen/logrus/README.md b/vendor/github.com/Sirupsen/logrus/README.md
new file mode 100644
index 0000000..640cf61
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/README.md
@@ -0,0 +1,476 @@
+# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>&nbsp;[![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus)&nbsp;[![GoDoc](https://godoc.org/github.com/Sirupsen/logrus?status.svg)](https://godoc.org/github.com/Sirupsen/logrus)
+
+**Seeing weird case-sensitive problems?** See [this
+issue](https://github.com/sirupsen/logrus/issues/451#issuecomment-264332021).
+This change has been reverted. I apologize for causing this. I greatly
+underestimated the impact this would have. Logrus strives for stability and
+backwards compatibility and failed to provide that.
+
+Logrus is a structured logger for Go (golang), completely API compatible with
+the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
+yet stable (pre 1.0). Logrus itself is completely stable and has been used in
+many large deployments. The core API is unlikely to change much but please
+version control your Logrus to make sure you aren't fetching latest `master` on
+every build.**
+
+Nicely color-coded in development (when a TTY is attached, otherwise just
+plain text):
+
+![Colored](http://i.imgur.com/PY7qMwd.png)
+
+With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash
+or Splunk:
+
+```json
+{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the
+ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
+
+{"level":"warning","msg":"The group's number increased tremendously!",
+"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
+
+{"animal":"walrus","level":"info","msg":"A giant walrus appears!",
+"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
+
+{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.",
+"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
+
+{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,
+"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
+```
+
+With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not
+attached, the output is compatible with the
+[logfmt](http://godoc.org/github.com/kr/logfmt) format:
+
+```text
+time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
+time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
+time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true
+time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
+time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
+time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
+exit status 1
+```
+
+#### Example
+
+The simplest way to use Logrus is simply the package-level exported logger:
+
+```go
+package main
+
+import (
+ log "github.com/Sirupsen/logrus"
+)
+
+func main() {
+ log.WithFields(log.Fields{
+ "animal": "walrus",
+ }).Info("A walrus appears")
+}
+```
+
+Note that it's completely api-compatible with the stdlib logger, so you can
+replace your `log` imports everywhere with `log "github.com/Sirupsen/logrus"`
+and you'll now have the flexibility of Logrus. You can customize it all you
+want:
+
+```go
+package main
+
+import (
+ "os"
+ log "github.com/Sirupsen/logrus"
+)
+
+func init() {
+ // Log as JSON instead of the default ASCII formatter.
+ log.SetFormatter(&log.JSONFormatter{})
+
+ // Output to stdout instead of the default stderr
+ // Can be any io.Writer, see below for File example
+ log.SetOutput(os.Stdout)
+
+ // Only log the warning severity or above.
+ log.SetLevel(log.WarnLevel)
+}
+
+func main() {
+ log.WithFields(log.Fields{
+ "animal": "walrus",
+ "size": 10,
+ }).Info("A group of walrus emerges from the ocean")
+
+ log.WithFields(log.Fields{
+ "omg": true,
+ "number": 122,
+ }).Warn("The group's number increased tremendously!")
+
+ log.WithFields(log.Fields{
+ "omg": true,
+ "number": 100,
+ }).Fatal("The ice breaks!")
+
+ // A common pattern is to re-use fields between logging statements by re-using
+ // the logrus.Entry returned from WithFields()
+ contextLogger := log.WithFields(log.Fields{
+ "common": "this is a common field",
+ "other": "I also should be logged always",
+ })
+
+ contextLogger.Info("I'll be logged with common and other field")
+ contextLogger.Info("Me too")
+}
+```
+
+For more advanced usage such as logging to multiple locations from the same
+application, you can also create an instance of the `logrus` Logger:
+
+```go
+package main
+
+import (
+ "github.com/Sirupsen/logrus"
+)
+
+// Create a new instance of the logger. You can have any number of instances.
+var log = logrus.New()
+
+func main() {
+ // The API for setting attributes is a little different than the package level
+ // exported logger. See Godoc.
+ log.Out = os.Stdout
+
+ // You could set this to any `io.Writer` such as a file
+ // file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666)
+ // if err == nil {
+ // log.Out = file
+ // } else {
+ // log.Info("Failed to log to file, using default stderr")
+ // }
+
+ log.WithFields(logrus.Fields{
+ "animal": "walrus",
+ "size": 10,
+ }).Info("A group of walrus emerges from the ocean")
+}
+```
+
+#### Fields
+
+Logrus encourages careful, structured logging though logging fields instead of
+long, unparseable error messages. For example, instead of: `log.Fatalf("Failed
+to send event %s to topic %s with key %d")`, you should log the much more
+discoverable:
+
+```go
+log.WithFields(log.Fields{
+ "event": event,
+ "topic": topic,
+ "key": key,
+}).Fatal("Failed to send event")
+```
+
+We've found this API forces you to think about logging in a way that produces
+much more useful logging messages. We've been in countless situations where just
+a single added field to a log statement that was already there would've saved us
+hours. The `WithFields` call is optional.
+
+In general, with Logrus using any of the `printf`-family functions should be
+seen as a hint you should add a field, however, you can still use the
+`printf`-family functions with Logrus.
+
+#### Default Fields
+
+Often it's helpful to have fields _always_ attached to log statements in an
+application or parts of one. For example, you may want to always log the
+`request_id` and `user_ip` in the context of a request. Instead of writing
+`log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})` on
+every line, you can create a `logrus.Entry` to pass around instead:
+
+```go
+requestLogger := log.WithFields(log.Fields{"request_id": request_id, user_ip: user_ip})
+requestLogger.Info("something happened on that request") # will log request_id and user_ip
+requestLogger.Warn("something not great happened")
+```
+
+#### Hooks
+
+You can add hooks for logging levels. For example to send errors to an exception
+tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
+multiple places simultaneously, e.g. syslog.
+
+Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
+`init`:
+
+```go
+import (
+ log "github.com/Sirupsen/logrus"
+ "gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake"
+ logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
+ "log/syslog"
+)
+
+func init() {
+
+ // Use the Airbrake hook to report errors that have Error severity or above to
+ // an exception tracker. You can create custom hooks, see the Hooks section.
+ log.AddHook(airbrake.NewHook(123, "xyz", "production"))
+
+ hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
+ if err != nil {
+ log.Error("Unable to connect to local syslog daemon")
+ } else {
+ log.AddHook(hook)
+ }
+}
+```
+Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
+
+| Hook | Description |
+| ----- | ----------- |
+| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
+| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
+| [Amazon Kinesis](https://github.com/evalphobia/logrus_kinesis) | Hook for logging to [Amazon Kinesis](https://aws.amazon.com/kinesis/) |
+| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) |
+| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
+| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
+| [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch|
+| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
+| [Go-Slack](https://github.com/multiplay/go-slack) | Hook for logging to [Slack](https://slack.com) |
+| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) |
+| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
+| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
+| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
+| [Influxus] (http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB] (http://influxdata.com/) |
+| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
+| [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka |
+| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
+| [Logentries](https://github.com/jcftang/logentriesrus) | Hook for logging to [Logentries](https://logentries.com/) |
+| [Logentrus](https://github.com/puddingfactory/logentrus) | Hook for logging to [Logentries](https://logentries.com/) |
+| [Logmatic.io](https://github.com/logmatic/logmatic-go) | Hook for logging to [Logmatic.io](http://logmatic.io/) |
+| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
+| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) |
+| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
+| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
+| [NATS-Hook](https://github.com/rybit/nats_logrus_hook) | Hook for logging to [NATS](https://nats.io) |
+| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
+| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
+| [PostgreSQL](https://github.com/gemnasium/logrus-postgresql-hook) | Send logs to [PostgreSQL](http://postgresql.org) |
+| [Pushover](https://github.com/toorop/logrus_pushover) | Send error via [Pushover](https://pushover.net) |
+| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
+| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
+| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
+| [Scribe](https://github.com/sagar8192/logrus-scribe-hook) | Hook for logging to [Scribe](https://github.com/facebookarchive/scribe)|
+| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. |
+| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
+| [Stackdriver](https://github.com/knq/sdhook) | Hook for logging to [Google Stackdriver](https://cloud.google.com/logging/) |
+| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)|
+| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
+| [TraceView](https://github.com/evalphobia/logrus_appneta) | Hook for logging to [AppNeta TraceView](https://www.appneta.com/products/traceview/) |
+| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
+| [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash |
+
+#### Level logging
+
+Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
+
+```go
+log.Debug("Useful debugging information.")
+log.Info("Something noteworthy happened!")
+log.Warn("You should probably take a look at this.")
+log.Error("Something failed but I'm not quitting.")
+// Calls os.Exit(1) after logging
+log.Fatal("Bye.")
+// Calls panic() after logging
+log.Panic("I'm bailing.")
+```
+
+You can set the logging level on a `Logger`, then it will only log entries with
+that severity or anything above it:
+
+```go
+// Will log anything that is info or above (warn, error, fatal, panic). Default.
+log.SetLevel(log.InfoLevel)
+```
+
+It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose
+environment if your application has that.
+
+#### Entries
+
+Besides the fields added with `WithField` or `WithFields` some fields are
+automatically added to all logging events:
+
+1. `time`. The timestamp when the entry was created.
+2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after
+ the `AddFields` call. E.g. `Failed to send event.`
+3. `level`. The logging level. E.g. `info`.
+
+#### Environments
+
+Logrus has no notion of environment.
+
+If you wish for hooks and formatters to only be used in specific environments,
+you should handle that yourself. For example, if your application has a global
+variable `Environment`, which is a string representation of the environment you
+could do:
+
+```go
+import (
+ log "github.com/Sirupsen/logrus"
+)
+
+init() {
+ // do something here to set environment depending on an environment variable
+ // or command-line flag
+ if Environment == "production" {
+ log.SetFormatter(&log.JSONFormatter{})
+ } else {
+ // The TextFormatter is default, you don't actually have to do this.
+ log.SetFormatter(&log.TextFormatter{})
+ }
+}
+```
+
+This configuration is how `logrus` was intended to be used, but JSON in
+production is mostly only useful if you do log aggregation with tools like
+Splunk or Logstash.
+
+#### Formatters
+
+The built-in logging formatters are:
+
+* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise
+ without colors.
+ * *Note:* to force colored output when there is no TTY, set the `ForceColors`
+ field to `true`. To force no colored output even if there is a TTY set the
+ `DisableColors` field to `true`. For Windows, see
+ [github.com/mattn/go-colorable](https://github.com/mattn/go-colorable).
+ * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter).
+* `logrus.JSONFormatter`. Logs fields as JSON.
+ * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter).
+
+Third party logging formatters:
+
+* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
+* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
+* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
+
+You can define your formatter by implementing the `Formatter` interface,
+requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
+`Fields` type (`map[string]interface{}`) with all your fields as well as the
+default ones (see Entries section above):
+
+```go
+type MyJSONFormatter struct {
+}
+
+log.SetFormatter(new(MyJSONFormatter))
+
+func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) {
+ // Note this doesn't include Time, Level and Message which are available on
+ // the Entry. Consult `godoc` on information about those fields or read the
+ // source of the official loggers.
+ serialized, err := json.Marshal(entry.Data)
+ if err != nil {
+ return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
+ }
+ return append(serialized, '\n'), nil
+}
+```
+
+#### Logger as an `io.Writer`
+
+Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it.
+
+```go
+w := logger.Writer()
+defer w.Close()
+
+srv := http.Server{
+ // create a stdlib log.Logger that writes to
+ // logrus.Logger.
+ ErrorLog: log.New(w, "", 0),
+}
+```
+
+Each line written to that writer will be printed the usual way, using formatters
+and hooks. The level for those entries is `info`.
+
+This means that we can override the standard library logger easily:
+
+```go
+logger := logrus.New()
+logger.Formatter = &logrus.JSONFormatter{}
+
+// Use logrus for standard log output
+// Note that `log` here references stdlib's log
+// Not logrus imported under the name `log`.
+log.SetOutput(logger.Writer())
+```
+
+#### Rotation
+
+Log rotation is not provided with Logrus. Log rotation should be done by an
+external program (like `logrotate(8)`) that can compress and delete old log
+entries. It should not be a feature of the application-level logger.
+
+#### Tools
+
+| Tool | Description |
+| ---- | ----------- |
+|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.|
+|[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper arround Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) |
+
+#### Testing
+
+Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides:
+
+* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook
+* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any):
+
+```go
+logger, hook := NewNullLogger()
+logger.Error("Hello error")
+
+assert.Equal(1, len(hook.Entries))
+assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
+assert.Equal("Hello error", hook.LastEntry().Message)
+
+hook.Reset()
+assert.Nil(hook.LastEntry())
+```
+
+#### Fatal handlers
+
+Logrus can register one or more functions that will be called when any `fatal`
+level message is logged. The registered handlers will be executed before
+logrus performs a `os.Exit(1)`. This behavior may be helpful if callers need
+to gracefully shutdown. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted.
+
+```
+...
+handler := func() {
+ // gracefully shutdown something...
+}
+logrus.RegisterExitHandler(handler)
+...
+```
+
+#### Thread safety
+
+By default Logger is protected by mutex for concurrent writes, this mutex is invoked when calling hooks and writing logs.
+If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking.
+
+Situation when locking is not needed includes:
+
+* You have no hooks registered, or hooks calling is already thread-safe.
+
+* Writing to logger.Out is already thread-safe, for example:
+
+ 1) logger.Out is protected by locks.
+
+ 2) logger.Out is a os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allow multi-thread/multi-process writing)
+
+ (Refer to http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/)
diff --git a/vendor/github.com/Sirupsen/logrus/alt_exit.go b/vendor/github.com/Sirupsen/logrus/alt_exit.go
new file mode 100644
index 0000000..b4c9e84
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/alt_exit.go
@@ -0,0 +1,64 @@
+package logrus
+
+// The following code was sourced and modified from the
+// https://bitbucket.org/tebeka/atexit package governed by the following license:
+//
+// Copyright (c) 2012 Miki Tebeka <miki.tebeka@gmail.com>.
+//
+// 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.
+
+import (
+ "fmt"
+ "os"
+)
+
+var handlers = []func(){}
+
+func runHandler(handler func()) {
+ defer func() {
+ if err := recover(); err != nil {
+ fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err)
+ }
+ }()
+
+ handler()
+}
+
+func runHandlers() {
+ for _, handler := range handlers {
+ runHandler(handler)
+ }
+}
+
+// Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code)
+func Exit(code int) {
+ runHandlers()
+ os.Exit(code)
+}
+
+// RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke
+// all handlers. The handlers will also be invoked when any Fatal log entry is
+// made.
+//
+// This method is useful when a caller wishes to use logrus to log a fatal
+// message but also needs to gracefully shutdown. An example usecase could be
+// closing database connections, or sending a alert that the application is
+// closing.
+func RegisterExitHandler(handler func()) {
+ handlers = append(handlers, handler)
+}
diff --git a/vendor/github.com/Sirupsen/logrus/alt_exit_test.go b/vendor/github.com/Sirupsen/logrus/alt_exit_test.go
new file mode 100644
index 0000000..022b778
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/alt_exit_test.go
@@ -0,0 +1,74 @@
+package logrus
+
+import (
+ "io/ioutil"
+ "os/exec"
+ "testing"
+ "time"
+)
+
+func TestRegister(t *testing.T) {
+ current := len(handlers)
+ RegisterExitHandler(func() {})
+ if len(handlers) != current+1 {
+ t.Fatalf("can't add handler")
+ }
+}
+
+func TestHandler(t *testing.T) {
+ gofile := "/tmp/testprog.go"
+ if err := ioutil.WriteFile(gofile, testprog, 0666); err != nil {
+ t.Fatalf("can't create go file")
+ }
+
+ outfile := "/tmp/testprog.out"
+ arg := time.Now().UTC().String()
+ err := exec.Command("go", "run", gofile, outfile, arg).Run()
+ if err == nil {
+ t.Fatalf("completed normally, should have failed")
+ }
+
+ data, err := ioutil.ReadFile(outfile)
+ if err != nil {
+ t.Fatalf("can't read output file %s", outfile)
+ }
+
+ if string(data) != arg {
+ t.Fatalf("bad data")
+ }
+}
+
+var testprog = []byte(`
+// Test program for atexit, gets output file and data as arguments and writes
+// data to output file in atexit handler.
+package main
+
+import (
+ "github.com/Sirupsen/logrus"
+ "flag"
+ "fmt"
+ "io/ioutil"
+)
+
+var outfile = ""
+var data = ""
+
+func handler() {
+ ioutil.WriteFile(outfile, []byte(data), 0666)
+}
+
+func badHandler() {
+ n := 0
+ fmt.Println(1/n)
+}
+
+func main() {
+ flag.Parse()
+ outfile = flag.Arg(0)
+ data = flag.Arg(1)
+
+ logrus.RegisterExitHandler(handler)
+ logrus.RegisterExitHandler(badHandler)
+ logrus.Fatal("Bye bye")
+}
+`)
diff --git a/vendor/github.com/Sirupsen/logrus/doc.go b/vendor/github.com/Sirupsen/logrus/doc.go
new file mode 100644
index 0000000..dddd5f8
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/doc.go
@@ -0,0 +1,26 @@
+/*
+Package logrus is a structured logger for Go, completely API compatible with the standard library logger.
+
+
+The simplest way to use Logrus is simply the package-level exported logger:
+
+ package main
+
+ import (
+ log "github.com/Sirupsen/logrus"
+ )
+
+ func main() {
+ log.WithFields(log.Fields{
+ "animal": "walrus",
+ "number": 1,
+ "size": 10,
+ }).Info("A walrus appears")
+ }
+
+Output:
+ time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
+
+For a full guide visit https://github.com/Sirupsen/logrus
+*/
+package logrus
diff --git a/vendor/github.com/Sirupsen/logrus/entry.go b/vendor/github.com/Sirupsen/logrus/entry.go
new file mode 100644
index 0000000..4edbe7a
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/entry.go
@@ -0,0 +1,275 @@
+package logrus
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "sync"
+ "time"
+)
+
+var bufferPool *sync.Pool
+
+func init() {
+ bufferPool = &sync.Pool{
+ New: func() interface{} {
+ return new(bytes.Buffer)
+ },
+ }
+}
+
+// Defines the key when adding errors using WithError.
+var ErrorKey = "error"
+
+// An entry is the final or intermediate Logrus logging entry. It contains all
+// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
+// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
+// passed around as much as you wish to avoid field duplication.
+type Entry struct {
+ Logger *Logger
+
+ // Contains all the fields set by the user.
+ Data Fields
+
+ // Time at which the log entry was created
+ Time time.Time
+
+ // Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
+ Level Level
+
+ // Message passed to Debug, Info, Warn, Error, Fatal or Panic
+ Message string
+
+ // When formatter is called in entry.log(), an Buffer may be set to entry
+ Buffer *bytes.Buffer
+}
+
+func NewEntry(logger *Logger) *Entry {
+ return &Entry{
+ Logger: logger,
+ // Default is three fields, give a little extra room
+ Data: make(Fields, 5),
+ }
+}
+
+// Returns the string representation from the reader and ultimately the
+// formatter.
+func (entry *Entry) String() (string, error) {
+ serialized, err := entry.Logger.Formatter.Format(entry)
+ if err != nil {
+ return "", err
+ }
+ str := string(serialized)
+ return str, nil
+}
+
+// Add an error as single field (using the key defined in ErrorKey) to the Entry.
+func (entry *Entry) WithError(err error) *Entry {
+ return entry.WithField(ErrorKey, err)
+}
+
+// Add a single field to the Entry.
+func (entry *Entry) WithField(key string, value interface{}) *Entry {
+ return entry.WithFields(Fields{key: value})
+}
+
+// Add a map of fields to the Entry.
+func (entry *Entry) WithFields(fields Fields) *Entry {
+ data := make(Fields, len(entry.Data)+len(fields))
+ for k, v := range entry.Data {
+ data[k] = v
+ }
+ for k, v := range fields {
+ data[k] = v
+ }
+ return &Entry{Logger: entry.Logger, Data: data}
+}
+
+// This function is not declared with a pointer value because otherwise
+// race conditions will occur when using multiple goroutines
+func (entry Entry) log(level Level, msg string) {
+ var buffer *bytes.Buffer
+ entry.Time = time.Now()
+ entry.Level = level
+ entry.Message = msg
+
+ if err := entry.Logger.Hooks.Fire(level, &entry); err != nil {
+ entry.Logger.mu.Lock()
+ fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
+ entry.Logger.mu.Unlock()
+ }
+ buffer = bufferPool.Get().(*bytes.Buffer)
+ buffer.Reset()
+ defer bufferPool.Put(buffer)
+ entry.Buffer = buffer
+ serialized, err := entry.Logger.Formatter.Format(&entry)
+ entry.Buffer = nil
+ if err != nil {
+ entry.Logger.mu.Lock()
+ fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
+ entry.Logger.mu.Unlock()
+ } else {
+ entry.Logger.mu.Lock()
+ _, err = entry.Logger.Out.Write(serialized)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
+ }
+ entry.Logger.mu.Unlock()
+ }
+
+ // To avoid Entry#log() returning a value that only would make sense for
+ // panic() to use in Entry#Panic(), we avoid the allocation by checking
+ // directly here.
+ if level <= PanicLevel {
+ panic(&entry)
+ }
+}
+
+func (entry *Entry) Debug(args ...interface{}) {
+ if entry.Logger.Level >= DebugLevel {
+ entry.log(DebugLevel, fmt.Sprint(args...))
+ }
+}
+
+func (entry *Entry) Print(args ...interface{}) {
+ entry.Info(args...)
+}
+
+func (entry *Entry) Info(args ...interface{}) {
+ if entry.Logger.Level >= InfoLevel {
+ entry.log(InfoLevel, fmt.Sprint(args...))
+ }
+}
+
+func (entry *Entry) Warn(args ...interface{}) {
+ if entry.Logger.Level >= WarnLevel {
+ entry.log(WarnLevel, fmt.Sprint(args...))
+ }
+}
+
+func (entry *Entry) Warning(args ...interface{}) {
+ entry.Warn(args...)
+}
+
+func (entry *Entry) Error(args ...interface{}) {
+ if entry.Logger.Level >= ErrorLevel {
+ entry.log(ErrorLevel, fmt.Sprint(args...))
+ }
+}
+
+func (entry *Entry) Fatal(args ...interface{}) {
+ if entry.Logger.Level >= FatalLevel {
+ entry.log(FatalLevel, fmt.Sprint(args...))
+ }
+ Exit(1)
+}
+
+func (entry *Entry) Panic(args ...interface{}) {
+ if entry.Logger.Level >= PanicLevel {
+ entry.log(PanicLevel, fmt.Sprint(args...))
+ }
+ panic(fmt.Sprint(args...))
+}
+
+// Entry Printf family functions
+
+func (entry *Entry) Debugf(format string, args ...interface{}) {
+ if entry.Logger.Level >= DebugLevel {
+ entry.Debug(fmt.Sprintf(format, args...))
+ }
+}
+
+func (entry *Entry) Infof(format string, args ...interface{}) {
+ if entry.Logger.Level >= InfoLevel {
+ entry.Info(fmt.Sprintf(format, args...))
+ }
+}
+
+func (entry *Entry) Printf(format string, args ...interface{}) {
+ entry.Infof(format, args...)
+}
+
+func (entry *Entry) Warnf(format string, args ...interface{}) {
+ if entry.Logger.Level >= WarnLevel {
+ entry.Warn(fmt.Sprintf(format, args...))
+ }
+}
+
+func (entry *Entry) Warningf(format string, args ...interface{}) {
+ entry.Warnf(format, args...)
+}
+
+func (entry *Entry) Errorf(format string, args ...interface{}) {
+ if entry.Logger.Level >= ErrorLevel {
+ entry.Error(fmt.Sprintf(format, args...))
+ }
+}
+
+func (entry *Entry) Fatalf(format string, args ...interface{}) {
+ if entry.Logger.Level >= FatalLevel {
+ entry.Fatal(fmt.Sprintf(format, args...))
+ }
+ Exit(1)
+}
+
+func (entry *Entry) Panicf(format string, args ...interface{}) {
+ if entry.Logger.Level >= PanicLevel {
+ entry.Panic(fmt.Sprintf(format, args...))
+ }
+}
+
+// Entry Println family functions
+
+func (entry *Entry) Debugln(args ...interface{}) {
+ if entry.Logger.Level >= DebugLevel {
+ entry.Debug(entry.sprintlnn(args...))
+ }
+}
+
+func (entry *Entry) Infoln(args ...interface{}) {
+ if entry.Logger.Level >= InfoLevel {
+ entry.Info(entry.sprintlnn(args...))
+ }
+}
+
+func (entry *Entry) Println(args ...interface{}) {
+ entry.Infoln(args...)
+}
+
+func (entry *Entry) Warnln(args ...interface{}) {
+ if entry.Logger.Level >= WarnLevel {
+ entry.Warn(entry.sprintlnn(args...))
+ }
+}
+
+func (entry *Entry) Warningln(args ...interface{}) {
+ entry.Warnln(args...)
+}
+
+func (entry *Entry) Errorln(args ...interface{}) {
+ if entry.Logger.Level >= ErrorLevel {
+ entry.Error(entry.sprintlnn(args...))
+ }
+}
+
+func (entry *Entry) Fatalln(args ...interface{}) {
+ if entry.Logger.Level >= FatalLevel {
+ entry.Fatal(entry.sprintlnn(args...))
+ }
+ Exit(1)
+}
+
+func (entry *Entry) Panicln(args ...interface{}) {
+ if entry.Logger.Level >= PanicLevel {
+ entry.Panic(entry.sprintlnn(args...))
+ }
+}
+
+// Sprintlnn => Sprint no newline. This is to get the behavior of how
+// fmt.Sprintln where spaces are always added between operands, regardless of
+// their type. Instead of vendoring the Sprintln implementation to spare a
+// string allocation, we do the simplest thing.
+func (entry *Entry) sprintlnn(args ...interface{}) string {
+ msg := fmt.Sprintln(args...)
+ return msg[:len(msg)-1]
+}
diff --git a/vendor/github.com/Sirupsen/logrus/entry_test.go b/vendor/github.com/Sirupsen/logrus/entry_test.go
new file mode 100644
index 0000000..99c3b41
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/entry_test.go
@@ -0,0 +1,77 @@
+package logrus
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestEntryWithError(t *testing.T) {
+
+ assert := assert.New(t)
+
+ defer func() {
+ ErrorKey = "error"
+ }()
+
+ err := fmt.Errorf("kaboom at layer %d", 4711)
+
+ assert.Equal(err, WithError(err).Data["error"])
+
+ logger := New()
+ logger.Out = &bytes.Buffer{}
+ entry := NewEntry(logger)
+
+ assert.Equal(err, entry.WithError(err).Data["error"])
+
+ ErrorKey = "err"
+
+ assert.Equal(err, entry.WithError(err).Data["err"])
+
+}
+
+func TestEntryPanicln(t *testing.T) {
+ errBoom := fmt.Errorf("boom time")
+
+ defer func() {
+ p := recover()
+ assert.NotNil(t, p)
+
+ switch pVal := p.(type) {
+ case *Entry:
+ assert.Equal(t, "kaboom", pVal.Message)
+ assert.Equal(t, errBoom, pVal.Data["err"])
+ default:
+ t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal)
+ }
+ }()
+
+ logger := New()
+ logger.Out = &bytes.Buffer{}
+ entry := NewEntry(logger)
+ entry.WithField("err", errBoom).Panicln("kaboom")
+}
+
+func TestEntryPanicf(t *testing.T) {
+ errBoom := fmt.Errorf("boom again")
+
+ defer func() {
+ p := recover()
+ assert.NotNil(t, p)
+
+ switch pVal := p.(type) {
+ case *Entry:
+ assert.Equal(t, "kaboom true", pVal.Message)
+ assert.Equal(t, errBoom, pVal.Data["err"])
+ default:
+ t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal)
+ }
+ }()
+
+ logger := New()
+ logger.Out = &bytes.Buffer{}
+ entry := NewEntry(logger)
+ entry.WithField("err", errBoom).Panicf("kaboom %v", true)
+}
diff --git a/vendor/github.com/Sirupsen/logrus/examples/basic/basic.go b/vendor/github.com/Sirupsen/logrus/examples/basic/basic.go
new file mode 100644
index 0000000..ad703fc
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/examples/basic/basic.go
@@ -0,0 +1,59 @@
+package main
+
+import (
+ "github.com/Sirupsen/logrus"
+ // "os"
+)
+
+var log = logrus.New()
+
+func init() {
+ log.Formatter = new(logrus.JSONFormatter)
+ log.Formatter = new(logrus.TextFormatter) // default
+
+ // file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666)
+ // if err == nil {
+ // log.Out = file
+ // } else {
+ // log.Info("Failed to log to file, using default stderr")
+ // }
+
+ log.Level = logrus.DebugLevel
+}
+
+func main() {
+ defer func() {
+ err := recover()
+ if err != nil {
+ log.WithFields(logrus.Fields{
+ "omg": true,
+ "err": err,
+ "number": 100,
+ }).Fatal("The ice breaks!")
+ }
+ }()
+
+ log.WithFields(logrus.Fields{
+ "animal": "walrus",
+ "number": 8,
+ }).Debug("Started observing beach")
+
+ log.WithFields(logrus.Fields{
+ "animal": "walrus",
+ "size": 10,
+ }).Info("A group of walrus emerges from the ocean")
+
+ log.WithFields(logrus.Fields{
+ "omg": true,
+ "number": 122,
+ }).Warn("The group's number increased tremendously!")
+
+ log.WithFields(logrus.Fields{
+ "temperature": -4,
+ }).Debug("Temperature changes")
+
+ log.WithFields(logrus.Fields{
+ "animal": "orca",
+ "size": 9009,
+ }).Panic("It's over 9000!")
+}
diff --git a/vendor/github.com/Sirupsen/logrus/examples/hook/hook.go b/vendor/github.com/Sirupsen/logrus/examples/hook/hook.go
new file mode 100644
index 0000000..3187f6d
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/examples/hook/hook.go
@@ -0,0 +1,30 @@
+package main
+
+import (
+ "github.com/Sirupsen/logrus"
+ "gopkg.in/gemnasium/logrus-airbrake-hook.v2"
+)
+
+var log = logrus.New()
+
+func init() {
+ log.Formatter = new(logrus.TextFormatter) // default
+ log.Hooks.Add(airbrake.NewHook(123, "xyz", "development"))
+}
+
+func main() {
+ log.WithFields(logrus.Fields{
+ "animal": "walrus",
+ "size": 10,
+ }).Info("A group of walrus emerges from the ocean")
+
+ log.WithFields(logrus.Fields{
+ "omg": true,
+ "number": 122,
+ }).Warn("The group's number increased tremendously!")
+
+ log.WithFields(logrus.Fields{
+ "omg": true,
+ "number": 100,
+ }).Fatal("The ice breaks!")
+}
diff --git a/vendor/github.com/Sirupsen/logrus/exported.go b/vendor/github.com/Sirupsen/logrus/exported.go
new file mode 100644
index 0000000..9a0120a
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/exported.go
@@ -0,0 +1,193 @@
+package logrus
+
+import (
+ "io"
+)
+
+var (
+ // std is the name of the standard logger in stdlib `log`
+ std = New()
+)
+
+func StandardLogger() *Logger {
+ return std
+}
+
+// SetOutput sets the standard logger output.
+func SetOutput(out io.Writer) {
+ std.mu.Lock()
+ defer std.mu.Unlock()
+ std.Out = out
+}
+
+// SetFormatter sets the standard logger formatter.
+func SetFormatter(formatter Formatter) {
+ std.mu.Lock()
+ defer std.mu.Unlock()
+ std.Formatter = formatter
+}
+
+// SetLevel sets the standard logger level.
+func SetLevel(level Level) {
+ std.mu.Lock()
+ defer std.mu.Unlock()
+ std.Level = level
+}
+
+// GetLevel returns the standard logger level.
+func GetLevel() Level {
+ std.mu.Lock()
+ defer std.mu.Unlock()
+ return std.Level
+}
+
+// AddHook adds a hook to the standard logger hooks.
+func AddHook(hook Hook) {
+ std.mu.Lock()
+ defer std.mu.Unlock()
+ std.Hooks.Add(hook)
+}
+
+// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
+func WithError(err error) *Entry {
+ return std.WithField(ErrorKey, err)
+}
+
+// WithField creates an entry from the standard logger and adds a field to
+// it. If you want multiple fields, use `WithFields`.
+//
+// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
+// or Panic on the Entry it returns.
+func WithField(key string, value interface{}) *Entry {
+ return std.WithField(key, value)
+}
+
+// WithFields creates an entry from the standard logger and adds multiple
+// fields to it. This is simply a helper for `WithField`, invoking it
+// once for each field.
+//
+// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
+// or Panic on the Entry it returns.
+func WithFields(fields Fields) *Entry {
+ return std.WithFields(fields)
+}
+
+// Debug logs a message at level Debug on the standard logger.
+func Debug(args ...interface{}) {
+ std.Debug(args...)
+}
+
+// Print logs a message at level Info on the standard logger.
+func Print(args ...interface{}) {
+ std.Print(args...)
+}
+
+// Info logs a message at level Info on the standard logger.
+func Info(args ...interface{}) {
+ std.Info(args...)
+}
+
+// Warn logs a message at level Warn on the standard logger.
+func Warn(args ...interface{}) {
+ std.Warn(args...)
+}
+
+// Warning logs a message at level Warn on the standard logger.
+func Warning(args ...interface{}) {
+ std.Warning(args...)
+}
+
+// Error logs a message at level Error on the standard logger.
+func Error(args ...interface{}) {
+ std.Error(args...)
+}
+
+// Panic logs a message at level Panic on the standard logger.
+func Panic(args ...interface{}) {
+ std.Panic(args...)
+}
+
+// Fatal logs a message at level Fatal on the standard logger.
+func Fatal(args ...interface{}) {
+ std.Fatal(args...)
+}
+
+// Debugf logs a message at level Debug on the standard logger.
+func Debugf(format string, args ...interface{}) {
+ std.Debugf(format, args...)
+}
+
+// Printf logs a message at level Info on the standard logger.
+func Printf(format string, args ...interface{}) {
+ std.Printf(format, args...)
+}
+
+// Infof logs a message at level Info on the standard logger.
+func Infof(format string, args ...interface{}) {
+ std.Infof(format, args...)
+}
+
+// Warnf logs a message at level Warn on the standard logger.
+func Warnf(format string, args ...interface{}) {
+ std.Warnf(format, args...)
+}
+
+// Warningf logs a message at level Warn on the standard logger.
+func Warningf(format string, args ...interface{}) {
+ std.Warningf(format, args...)
+}
+
+// Errorf logs a message at level Error on the standard logger.
+func Errorf(format string, args ...interface{}) {
+ std.Errorf(format, args...)
+}
+
+// Panicf logs a message at level Panic on the standard logger.
+func Panicf(format string, args ...interface{}) {
+ std.Panicf(format, args...)
+}
+
+// Fatalf logs a message at level Fatal on the standard logger.
+func Fatalf(format string, args ...interface{}) {
+ std.Fatalf(format, args...)
+}
+
+// Debugln logs a message at level Debug on the standard logger.
+func Debugln(args ...interface{}) {
+ std.Debugln(args...)
+}
+
+// Println logs a message at level Info on the standard logger.
+func Println(args ...interface{}) {
+ std.Println(args...)
+}
+
+// Infoln logs a message at level Info on the standard logger.
+func Infoln(args ...interface{}) {
+ std.Infoln(args...)
+}
+
+// Warnln logs a message at level Warn on the standard logger.
+func Warnln(args ...interface{}) {
+ std.Warnln(args...)
+}
+
+// Warningln logs a message at level Warn on the standard logger.
+func Warningln(args ...interface{}) {
+ std.Warningln(args...)
+}
+
+// Errorln logs a message at level Error on the standard logger.
+func Errorln(args ...interface{}) {
+ std.Errorln(args...)
+}
+
+// Panicln logs a message at level Panic on the standard logger.
+func Panicln(args ...interface{}) {
+ std.Panicln(args...)
+}
+
+// Fatalln logs a message at level Fatal on the standard logger.
+func Fatalln(args ...interface{}) {
+ std.Fatalln(args...)
+}
diff --git a/vendor/github.com/Sirupsen/logrus/formatter.go b/vendor/github.com/Sirupsen/logrus/formatter.go
new file mode 100644
index 0000000..b5fbe93
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/formatter.go
@@ -0,0 +1,45 @@
+package logrus
+
+import "time"
+
+const DefaultTimestampFormat = time.RFC3339
+
+// The Formatter interface is used to implement a custom Formatter. It takes an
+// `Entry`. It exposes all the fields, including the default ones:
+//
+// * `entry.Data["msg"]`. The message passed from Info, Warn, Error ..
+// * `entry.Data["time"]`. The timestamp.
+// * `entry.Data["level"]. The level the entry was logged at.
+//
+// Any additional fields added with `WithField` or `WithFields` are also in
+// `entry.Data`. Format is expected to return an array of bytes which are then
+// logged to `logger.Out`.
+type Formatter interface {
+ Format(*Entry) ([]byte, error)
+}
+
+// This is to not silently overwrite `time`, `msg` and `level` fields when
+// dumping it. If this code wasn't there doing:
+//
+// logrus.WithField("level", 1).Info("hello")
+//
+// Would just silently drop the user provided level. Instead with this code
+// it'll logged as:
+//
+// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
+//
+// It's not exported because it's still using Data in an opinionated way. It's to
+// avoid code duplication between the two default formatters.
+func prefixFieldClashes(data Fields) {
+ if t, ok := data["time"]; ok {
+ data["fields.time"] = t
+ }
+
+ if m, ok := data["msg"]; ok {
+ data["fields.msg"] = m
+ }
+
+ if l, ok := data["level"]; ok {
+ data["fields.level"] = l
+ }
+}
diff --git a/vendor/github.com/Sirupsen/logrus/formatter_bench_test.go b/vendor/github.com/Sirupsen/logrus/formatter_bench_test.go
new file mode 100644
index 0000000..d948158
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/formatter_bench_test.go
@@ -0,0 +1,101 @@
+package logrus
+
+import (
+ "fmt"
+ "testing"
+ "time"
+)
+
+// smallFields is a small size data set for benchmarking
+var smallFields = Fields{
+ "foo": "bar",
+ "baz": "qux",
+ "one": "two",
+ "three": "four",
+}
+
+// largeFields is a large size data set for benchmarking
+var largeFields = Fields{
+ "foo": "bar",
+ "baz": "qux",
+ "one": "two",
+ "three": "four",
+ "five": "six",
+ "seven": "eight",
+ "nine": "ten",
+ "eleven": "twelve",
+ "thirteen": "fourteen",
+ "fifteen": "sixteen",
+ "seventeen": "eighteen",
+ "nineteen": "twenty",
+ "a": "b",
+ "c": "d",
+ "e": "f",
+ "g": "h",
+ "i": "j",
+ "k": "l",
+ "m": "n",
+ "o": "p",
+ "q": "r",
+ "s": "t",
+ "u": "v",
+ "w": "x",
+ "y": "z",
+ "this": "will",
+ "make": "thirty",
+ "entries": "yeah",
+}
+
+var errorFields = Fields{
+ "foo": fmt.Errorf("bar"),
+ "baz": fmt.Errorf("qux"),
+}
+
+func BenchmarkErrorTextFormatter(b *testing.B) {
+ doBenchmark(b, &TextFormatter{DisableColors: true}, errorFields)
+}
+
+func BenchmarkSmallTextFormatter(b *testing.B) {
+ doBenchmark(b, &TextFormatter{DisableColors: true}, smallFields)
+}
+
+func BenchmarkLargeTextFormatter(b *testing.B) {
+ doBenchmark(b, &TextFormatter{DisableColors: true}, largeFields)
+}
+
+func BenchmarkSmallColoredTextFormatter(b *testing.B) {
+ doBenchmark(b, &TextFormatter{ForceColors: true}, smallFields)
+}
+
+func BenchmarkLargeColoredTextFormatter(b *testing.B) {
+ doBenchmark(b, &TextFormatter{ForceColors: true}, largeFields)
+}
+
+func BenchmarkSmallJSONFormatter(b *testing.B) {
+ doBenchmark(b, &JSONFormatter{}, smallFields)
+}
+
+func BenchmarkLargeJSONFormatter(b *testing.B) {
+ doBenchmark(b, &JSONFormatter{}, largeFields)
+}
+
+func doBenchmark(b *testing.B, formatter Formatter, fields Fields) {
+ logger := New()
+
+ entry := &Entry{
+ Time: time.Time{},
+ Level: InfoLevel,
+ Message: "message",
+ Data: fields,
+ Logger: logger,
+ }
+ var d []byte
+ var err error
+ for i := 0; i < b.N; i++ {
+ d, err = formatter.Format(entry)
+ if err != nil {
+ b.Fatal(err)
+ }
+ b.SetBytes(int64(len(d)))
+ }
+}
diff --git a/vendor/github.com/Sirupsen/logrus/hook_test.go b/vendor/github.com/Sirupsen/logrus/hook_test.go
new file mode 100644
index 0000000..13f34cb
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hook_test.go
@@ -0,0 +1,122 @@
+package logrus
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+type TestHook struct {
+ Fired bool
+}
+
+func (hook *TestHook) Fire(entry *Entry) error {
+ hook.Fired = true
+ return nil
+}
+
+func (hook *TestHook) Levels() []Level {
+ return []Level{
+ DebugLevel,
+ InfoLevel,
+ WarnLevel,
+ ErrorLevel,
+ FatalLevel,
+ PanicLevel,
+ }
+}
+
+func TestHookFires(t *testing.T) {
+ hook := new(TestHook)
+
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Hooks.Add(hook)
+ assert.Equal(t, hook.Fired, false)
+
+ log.Print("test")
+ }, func(fields Fields) {
+ assert.Equal(t, hook.Fired, true)
+ })
+}
+
+type ModifyHook struct {
+}
+
+func (hook *ModifyHook) Fire(entry *Entry) error {
+ entry.Data["wow"] = "whale"
+ return nil
+}
+
+func (hook *ModifyHook) Levels() []Level {
+ return []Level{
+ DebugLevel,
+ InfoLevel,
+ WarnLevel,
+ ErrorLevel,
+ FatalLevel,
+ PanicLevel,
+ }
+}
+
+func TestHookCanModifyEntry(t *testing.T) {
+ hook := new(ModifyHook)
+
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Hooks.Add(hook)
+ log.WithField("wow", "elephant").Print("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["wow"], "whale")
+ })
+}
+
+func TestCanFireMultipleHooks(t *testing.T) {
+ hook1 := new(ModifyHook)
+ hook2 := new(TestHook)
+
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Hooks.Add(hook1)
+ log.Hooks.Add(hook2)
+
+ log.WithField("wow", "elephant").Print("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["wow"], "whale")
+ assert.Equal(t, hook2.Fired, true)
+ })
+}
+
+type ErrorHook struct {
+ Fired bool
+}
+
+func (hook *ErrorHook) Fire(entry *Entry) error {
+ hook.Fired = true
+ return nil
+}
+
+func (hook *ErrorHook) Levels() []Level {
+ return []Level{
+ ErrorLevel,
+ }
+}
+
+func TestErrorHookShouldntFireOnInfo(t *testing.T) {
+ hook := new(ErrorHook)
+
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Hooks.Add(hook)
+ log.Info("test")
+ }, func(fields Fields) {
+ assert.Equal(t, hook.Fired, false)
+ })
+}
+
+func TestErrorHookShouldFireOnError(t *testing.T) {
+ hook := new(ErrorHook)
+
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Hooks.Add(hook)
+ log.Error("test")
+ }, func(fields Fields) {
+ assert.Equal(t, hook.Fired, true)
+ })
+}
diff --git a/vendor/github.com/Sirupsen/logrus/hooks.go b/vendor/github.com/Sirupsen/logrus/hooks.go
new file mode 100644
index 0000000..3f151cd
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hooks.go
@@ -0,0 +1,34 @@
+package logrus
+
+// A hook to be fired when logging on the logging levels returned from
+// `Levels()` on your implementation of the interface. Note that this is not
+// fired in a goroutine or a channel with workers, you should handle such
+// functionality yourself if your call is non-blocking and you don't wish for
+// the logging calls for levels returned from `Levels()` to block.
+type Hook interface {
+ Levels() []Level
+ Fire(*Entry) error
+}
+
+// Internal type for storing the hooks on a logger instance.
+type LevelHooks map[Level][]Hook
+
+// Add a hook to an instance of logger. This is called with
+// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface.
+func (hooks LevelHooks) Add(hook Hook) {
+ for _, level := range hook.Levels() {
+ hooks[level] = append(hooks[level], hook)
+ }
+}
+
+// Fire all the hooks for the passed level. Used by `entry.log` to fire
+// appropriate hooks for a log entry.
+func (hooks LevelHooks) Fire(level Level, entry *Entry) error {
+ for _, hook := range hooks[level] {
+ if err := hook.Fire(entry); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md b/vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md
new file mode 100644
index 0000000..066704b
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md
@@ -0,0 +1,39 @@
+# Syslog Hooks for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>
+
+## Usage
+
+```go
+import (
+ "log/syslog"
+ "github.com/Sirupsen/logrus"
+ logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
+)
+
+func main() {
+ log := logrus.New()
+ hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
+
+ if err == nil {
+ log.Hooks.Add(hook)
+ }
+}
+```
+
+If you want to connect to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). Just assign empty string to the first two parameters of `NewSyslogHook`. It should look like the following.
+
+```go
+import (
+ "log/syslog"
+ "github.com/Sirupsen/logrus"
+ logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
+)
+
+func main() {
+ log := logrus.New()
+ hook, err := logrus_syslog.NewSyslogHook("", "", syslog.LOG_INFO, "")
+
+ if err == nil {
+ log.Hooks.Add(hook)
+ }
+}
+``` \ No newline at end of file
diff --git a/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go b/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
new file mode 100644
index 0000000..a36e200
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
@@ -0,0 +1,54 @@
+// +build !windows,!nacl,!plan9
+
+package logrus_syslog
+
+import (
+ "fmt"
+ "github.com/Sirupsen/logrus"
+ "log/syslog"
+ "os"
+)
+
+// SyslogHook to send logs via syslog.
+type SyslogHook struct {
+ Writer *syslog.Writer
+ SyslogNetwork string
+ SyslogRaddr string
+}
+
+// Creates a hook to be added to an instance of logger. This is called with
+// `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")`
+// `if err == nil { log.Hooks.Add(hook) }`
+func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) {
+ w, err := syslog.Dial(network, raddr, priority, tag)
+ return &SyslogHook{w, network, raddr}, err
+}
+
+func (hook *SyslogHook) Fire(entry *logrus.Entry) error {
+ line, err := entry.String()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
+ return err
+ }
+
+ switch entry.Level {
+ case logrus.PanicLevel:
+ return hook.Writer.Crit(line)
+ case logrus.FatalLevel:
+ return hook.Writer.Crit(line)
+ case logrus.ErrorLevel:
+ return hook.Writer.Err(line)
+ case logrus.WarnLevel:
+ return hook.Writer.Warning(line)
+ case logrus.InfoLevel:
+ return hook.Writer.Info(line)
+ case logrus.DebugLevel:
+ return hook.Writer.Debug(line)
+ default:
+ return nil
+ }
+}
+
+func (hook *SyslogHook) Levels() []logrus.Level {
+ return logrus.AllLevels
+}
diff --git a/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go b/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go
new file mode 100644
index 0000000..42762dc
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go
@@ -0,0 +1,26 @@
+package logrus_syslog
+
+import (
+ "github.com/Sirupsen/logrus"
+ "log/syslog"
+ "testing"
+)
+
+func TestLocalhostAddAndPrint(t *testing.T) {
+ log := logrus.New()
+ hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
+
+ if err != nil {
+ t.Errorf("Unable to connect to local syslog.")
+ }
+
+ log.Hooks.Add(hook)
+
+ for _, level := range hook.Levels() {
+ if len(log.Hooks[level]) != 1 {
+ t.Errorf("SyslogHook was not added. The length of log.Hooks[%v]: %v", level, len(log.Hooks[level]))
+ }
+ }
+
+ log.Info("Congratulations!")
+}
diff --git a/vendor/github.com/Sirupsen/logrus/hooks/test/test.go b/vendor/github.com/Sirupsen/logrus/hooks/test/test.go
new file mode 100644
index 0000000..0688125
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hooks/test/test.go
@@ -0,0 +1,67 @@
+package test
+
+import (
+ "io/ioutil"
+
+ "github.com/Sirupsen/logrus"
+)
+
+// test.Hook is a hook designed for dealing with logs in test scenarios.
+type Hook struct {
+ Entries []*logrus.Entry
+}
+
+// Installs a test hook for the global logger.
+func NewGlobal() *Hook {
+
+ hook := new(Hook)
+ logrus.AddHook(hook)
+
+ return hook
+
+}
+
+// Installs a test hook for a given local logger.
+func NewLocal(logger *logrus.Logger) *Hook {
+
+ hook := new(Hook)
+ logger.Hooks.Add(hook)
+
+ return hook
+
+}
+
+// Creates a discarding logger and installs the test hook.
+func NewNullLogger() (*logrus.Logger, *Hook) {
+
+ logger := logrus.New()
+ logger.Out = ioutil.Discard
+
+ return logger, NewLocal(logger)
+
+}
+
+func (t *Hook) Fire(e *logrus.Entry) error {
+ t.Entries = append(t.Entries, e)
+ return nil
+}
+
+func (t *Hook) Levels() []logrus.Level {
+ return logrus.AllLevels
+}
+
+// LastEntry returns the last entry that was logged or nil.
+func (t *Hook) LastEntry() (l *logrus.Entry) {
+
+ if i := len(t.Entries) - 1; i < 0 {
+ return nil
+ } else {
+ return t.Entries[i]
+ }
+
+}
+
+// Reset removes all Entries from this test hook.
+func (t *Hook) Reset() {
+ t.Entries = make([]*logrus.Entry, 0)
+}
diff --git a/vendor/github.com/Sirupsen/logrus/hooks/test/test_test.go b/vendor/github.com/Sirupsen/logrus/hooks/test/test_test.go
new file mode 100644
index 0000000..d69455b
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hooks/test/test_test.go
@@ -0,0 +1,39 @@
+package test
+
+import (
+ "testing"
+
+ "github.com/Sirupsen/logrus"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestAllHooks(t *testing.T) {
+
+ assert := assert.New(t)
+
+ logger, hook := NewNullLogger()
+ assert.Nil(hook.LastEntry())
+ assert.Equal(0, len(hook.Entries))
+
+ logger.Error("Hello error")
+ assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
+ assert.Equal("Hello error", hook.LastEntry().Message)
+ assert.Equal(1, len(hook.Entries))
+
+ logger.Warn("Hello warning")
+ assert.Equal(logrus.WarnLevel, hook.LastEntry().Level)
+ assert.Equal("Hello warning", hook.LastEntry().Message)
+ assert.Equal(2, len(hook.Entries))
+
+ hook.Reset()
+ assert.Nil(hook.LastEntry())
+ assert.Equal(0, len(hook.Entries))
+
+ hook = NewGlobal()
+
+ logrus.Error("Hello error")
+ assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
+ assert.Equal("Hello error", hook.LastEntry().Message)
+ assert.Equal(1, len(hook.Entries))
+
+}
diff --git a/vendor/github.com/Sirupsen/logrus/json_formatter.go b/vendor/github.com/Sirupsen/logrus/json_formatter.go
new file mode 100644
index 0000000..266554e
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/json_formatter.go
@@ -0,0 +1,74 @@
+package logrus
+
+import (
+ "encoding/json"
+ "fmt"
+)
+
+type fieldKey string
+type FieldMap map[fieldKey]string
+
+const (
+ FieldKeyMsg = "msg"
+ FieldKeyLevel = "level"
+ FieldKeyTime = "time"
+)
+
+func (f FieldMap) resolve(key fieldKey) string {
+ if k, ok := f[key]; ok {
+ return k
+ }
+
+ return string(key)
+}
+
+type JSONFormatter struct {
+ // TimestampFormat sets the format used for marshaling timestamps.
+ TimestampFormat string
+
+ // DisableTimestamp allows disabling automatic timestamps in output
+ DisableTimestamp bool
+
+ // FieldMap allows users to customize the names of keys for various fields.
+ // As an example:
+ // formatter := &JSONFormatter{
+ // FieldMap: FieldMap{
+ // FieldKeyTime: "@timestamp",
+ // FieldKeyLevel: "@level",
+ // FieldKeyLevel: "@message",
+ // },
+ // }
+ FieldMap FieldMap
+}
+
+func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
+ data := make(Fields, len(entry.Data)+3)
+ for k, v := range entry.Data {
+ switch v := v.(type) {
+ case error:
+ // Otherwise errors are ignored by `encoding/json`
+ // https://github.com/Sirupsen/logrus/issues/137
+ data[k] = v.Error()
+ default:
+ data[k] = v
+ }
+ }
+ prefixFieldClashes(data)
+
+ timestampFormat := f.TimestampFormat
+ if timestampFormat == "" {
+ timestampFormat = DefaultTimestampFormat
+ }
+
+ if !f.DisableTimestamp {
+ data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
+ }
+ data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
+ data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
+
+ serialized, err := json.Marshal(data)
+ if err != nil {
+ return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
+ }
+ return append(serialized, '\n'), nil
+}
diff --git a/vendor/github.com/Sirupsen/logrus/json_formatter_test.go b/vendor/github.com/Sirupsen/logrus/json_formatter_test.go
new file mode 100644
index 0000000..51093a7
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/json_formatter_test.go
@@ -0,0 +1,199 @@
+package logrus
+
+import (
+ "encoding/json"
+ "errors"
+ "strings"
+ "testing"
+)
+
+func TestErrorNotLost(t *testing.T) {
+ formatter := &JSONFormatter{}
+
+ b, err := formatter.Format(WithField("error", errors.New("wild walrus")))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+
+ entry := make(map[string]interface{})
+ err = json.Unmarshal(b, &entry)
+ if err != nil {
+ t.Fatal("Unable to unmarshal formatted entry: ", err)
+ }
+
+ if entry["error"] != "wild walrus" {
+ t.Fatal("Error field not set")
+ }
+}
+
+func TestErrorNotLostOnFieldNotNamedError(t *testing.T) {
+ formatter := &JSONFormatter{}
+
+ b, err := formatter.Format(WithField("omg", errors.New("wild walrus")))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+
+ entry := make(map[string]interface{})
+ err = json.Unmarshal(b, &entry)
+ if err != nil {
+ t.Fatal("Unable to unmarshal formatted entry: ", err)
+ }
+
+ if entry["omg"] != "wild walrus" {
+ t.Fatal("Error field not set")
+ }
+}
+
+func TestFieldClashWithTime(t *testing.T) {
+ formatter := &JSONFormatter{}
+
+ b, err := formatter.Format(WithField("time", "right now!"))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+
+ entry := make(map[string]interface{})
+ err = json.Unmarshal(b, &entry)
+ if err != nil {
+ t.Fatal("Unable to unmarshal formatted entry: ", err)
+ }
+
+ if entry["fields.time"] != "right now!" {
+ t.Fatal("fields.time not set to original time field")
+ }
+
+ if entry["time"] != "0001-01-01T00:00:00Z" {
+ t.Fatal("time field not set to current time, was: ", entry["time"])
+ }
+}
+
+func TestFieldClashWithMsg(t *testing.T) {
+ formatter := &JSONFormatter{}
+
+ b, err := formatter.Format(WithField("msg", "something"))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+
+ entry := make(map[string]interface{})
+ err = json.Unmarshal(b, &entry)
+ if err != nil {
+ t.Fatal("Unable to unmarshal formatted entry: ", err)
+ }
+
+ if entry["fields.msg"] != "something" {
+ t.Fatal("fields.msg not set to original msg field")
+ }
+}
+
+func TestFieldClashWithLevel(t *testing.T) {
+ formatter := &JSONFormatter{}
+
+ b, err := formatter.Format(WithField("level", "something"))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+
+ entry := make(map[string]interface{})
+ err = json.Unmarshal(b, &entry)
+ if err != nil {
+ t.Fatal("Unable to unmarshal formatted entry: ", err)
+ }
+
+ if entry["fields.level"] != "something" {
+ t.Fatal("fields.level not set to original level field")
+ }
+}
+
+func TestJSONEntryEndsWithNewline(t *testing.T) {
+ formatter := &JSONFormatter{}
+
+ b, err := formatter.Format(WithField("level", "something"))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+
+ if b[len(b)-1] != '\n' {
+ t.Fatal("Expected JSON log entry to end with a newline")
+ }
+}
+
+func TestJSONMessageKey(t *testing.T) {
+ formatter := &JSONFormatter{
+ FieldMap: FieldMap{
+ FieldKeyMsg: "message",
+ },
+ }
+
+ b, err := formatter.Format(&Entry{Message: "oh hai"})
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+ s := string(b)
+ if !(strings.Contains(s, "message") && strings.Contains(s, "oh hai")) {
+ t.Fatal("Expected JSON to format message key")
+ }
+}
+
+func TestJSONLevelKey(t *testing.T) {
+ formatter := &JSONFormatter{
+ FieldMap: FieldMap{
+ FieldKeyLevel: "somelevel",
+ },
+ }
+
+ b, err := formatter.Format(WithField("level", "something"))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+ s := string(b)
+ if !strings.Contains(s, "somelevel") {
+ t.Fatal("Expected JSON to format level key")
+ }
+}
+
+func TestJSONTimeKey(t *testing.T) {
+ formatter := &JSONFormatter{
+ FieldMap: FieldMap{
+ FieldKeyTime: "timeywimey",
+ },
+ }
+
+ b, err := formatter.Format(WithField("level", "something"))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+ s := string(b)
+ if !strings.Contains(s, "timeywimey") {
+ t.Fatal("Expected JSON to format time key")
+ }
+}
+
+func TestJSONDisableTimestamp(t *testing.T) {
+ formatter := &JSONFormatter{
+ DisableTimestamp: true,
+ }
+
+ b, err := formatter.Format(WithField("level", "something"))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+ s := string(b)
+ if strings.Contains(s, FieldKeyTime) {
+ t.Error("Did not prevent timestamp", s)
+ }
+}
+
+func TestJSONEnableTimestamp(t *testing.T) {
+ formatter := &JSONFormatter{}
+
+ b, err := formatter.Format(WithField("level", "something"))
+ if err != nil {
+ t.Fatal("Unable to format entry: ", err)
+ }
+ s := string(b)
+ if !strings.Contains(s, FieldKeyTime) {
+ t.Error("Timestamp not present", s)
+ }
+}
diff --git a/vendor/github.com/Sirupsen/logrus/logger.go b/vendor/github.com/Sirupsen/logrus/logger.go
new file mode 100644
index 0000000..b769f3d
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/logger.go
@@ -0,0 +1,308 @@
+package logrus
+
+import (
+ "io"
+ "os"
+ "sync"
+)
+
+type Logger struct {
+ // The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
+ // file, or leave it default which is `os.Stderr`. You can also set this to
+ // something more adventorous, such as logging to Kafka.
+ Out io.Writer
+ // Hooks for the logger instance. These allow firing events based on logging
+ // levels and log entries. For example, to send errors to an error tracking
+ // service, log to StatsD or dump the core on fatal errors.
+ Hooks LevelHooks
+ // All log entries pass through the formatter before logged to Out. The
+ // included formatters are `TextFormatter` and `JSONFormatter` for which
+ // TextFormatter is the default. In development (when a TTY is attached) it
+ // logs with colors, but to a file it wouldn't. You can easily implement your
+ // own that implements the `Formatter` interface, see the `README` or included
+ // formatters for examples.
+ Formatter Formatter
+ // The logging level the logger should log at. This is typically (and defaults
+ // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
+ // logged. `logrus.Debug` is useful in
+ Level Level
+ // Used to sync writing to the log. Locking is enabled by Default
+ mu MutexWrap
+ // Reusable empty entry
+ entryPool sync.Pool
+}
+
+type MutexWrap struct {
+ lock sync.Mutex
+ disabled bool
+}
+
+func (mw *MutexWrap) Lock() {
+ if !mw.disabled {
+ mw.lock.Lock()
+ }
+}
+
+func (mw *MutexWrap) Unlock() {
+ if !mw.disabled {
+ mw.lock.Unlock()
+ }
+}
+
+func (mw *MutexWrap) Disable() {
+ mw.disabled = true
+}
+
+// Creates a new logger. Configuration should be set by changing `Formatter`,
+// `Out` and `Hooks` directly on the default logger instance. You can also just
+// instantiate your own:
+//
+// var log = &Logger{
+// Out: os.Stderr,
+// Formatter: new(JSONFormatter),
+// Hooks: make(LevelHooks),
+// Level: logrus.DebugLevel,
+// }
+//
+// It's recommended to make this a global instance called `log`.
+func New() *Logger {
+ return &Logger{
+ Out: os.Stderr,
+ Formatter: new(TextFormatter),
+ Hooks: make(LevelHooks),
+ Level: InfoLevel,
+ }
+}
+
+func (logger *Logger) newEntry() *Entry {
+ entry, ok := logger.entryPool.Get().(*Entry)
+ if ok {
+ return entry
+ }
+ return NewEntry(logger)
+}
+
+func (logger *Logger) releaseEntry(entry *Entry) {
+ logger.entryPool.Put(entry)
+}
+
+// Adds a field to the log entry, note that it doesn't log until you call
+// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
+// If you want multiple fields, use `WithFields`.
+func (logger *Logger) WithField(key string, value interface{}) *Entry {
+ entry := logger.newEntry()
+ defer logger.releaseEntry(entry)
+ return entry.WithField(key, value)
+}
+
+// Adds a struct of fields to the log entry. All it does is call `WithField` for
+// each `Field`.
+func (logger *Logger) WithFields(fields Fields) *Entry {
+ entry := logger.newEntry()
+ defer logger.releaseEntry(entry)
+ return entry.WithFields(fields)
+}
+
+// Add an error as single field to the log entry. All it does is call
+// `WithError` for the given `error`.
+func (logger *Logger) WithError(err error) *Entry {
+ entry := logger.newEntry()
+ defer logger.releaseEntry(entry)
+ return entry.WithError(err)
+}
+
+func (logger *Logger) Debugf(format string, args ...interface{}) {
+ if logger.Level >= DebugLevel {
+ entry := logger.newEntry()
+ entry.Debugf(format, args...)
+ logger.releaseEntry(entry)
+ }
+}
+
+func (logger *Logger) Infof(format string, args ...interface{}) {
+ if logger.Level >= InfoLevel {
+ entry := logger.newEntry()
+ entry.Infof(format, args...)
+ logger.releaseEntry(entry)
+ }
+}
+
+func (logger *Logger) Printf(format string, args ...interface{}) {
+ entry := logger.newEntry()
+ entry.Printf(format, args...)
+ logger.releaseEntry(entry)
+}
+
+func (logger *Logger) Warnf(format string, args ...interface{}) {
+ if logger.Level >= WarnLevel {
+ entry := logger.newEntry()
+ entry.Warnf(format, args...)
+ logger.releaseEntry(entry)
+ }
+}
+
+func (logger *Logger) Warningf(format string, args ...interface{}) {
+ if logger.Level >= WarnLevel {
+ entry := logger.newEntry()
+ entry.Warnf(format, args...)
+ logger.releaseEntry(entry)
+ }
+}
+
+func (logger *Logger) Errorf(format string, args ...interface{}) {
+ if logger.Level >= ErrorLevel {
+ entry := logger.newEntry()
+ entry.Errorf(format, args...)
+ logger.releaseEntry(entry)
+ }
+}
+
+func (logger *Logger) Fatalf(format string, args ...interface{}) {
+ if logger.Level >= FatalLevel {
+ entry := logger.newEntry()
+ entry.Fatalf(format, args...)
+ logger.releaseEntry(entry)
+ }
+ Exit(1)
+}
+
+func (logger *Logger) Panicf(format string, args ...interface{}) {
+ if logger.Level >= PanicLevel {
+ entry := logger.newEntry()
+ entry.Panicf(format, args...)
+ logger.releaseEntry(entry)
+ }
+}
+
+func (logger *Logger) Debug(args ...interface{}) {
+ if logger.Level >= DebugLevel {
+ entry := logger.newEntry()
+ entry.Debug(args...)
+ logger.releaseEntry(entry)
+ }
+}
+
+func (logger *Logger) Info(args ...interface{}) {
+ if logger.Level >= InfoLevel {
+ entry := logger.newEntry()
+ entry.Info(args...)
+ logger.releaseEntry(entry)
+ }
+}
+
+func (logger *Logger) Print(args ...interface{}) {
+ entry := logger.newEntry()
+ entry.Info(args...)
+ logger.releaseEntry(entry)
+}
+
+func (logger *Logger) Warn(args ...interface{}) {
+ if logger.Level >= WarnLevel {
+ entry := logger.newEntry()
+ entry.Warn(args...)
+ logger.releaseEntry(entry)
+ }
+}
+
+func (logger *Logger) Warning(args ...interface{}) {
+ if logger.Level >= WarnLevel {
+ entry := logger.newEntry()
+ entry.Warn(args...)
+ logger.releaseEntry(entry)
+ }
+}
+
+func (logger *Logger) Error(args ...interface{}) {
+ if logger.Level >= ErrorLevel {
+ entry := logger.newEntry()
+ entry.Error(args...)
+ logger.releaseEntry(entry)
+ }
+}
+
+func (logger *Logger) Fatal(args ...interface{}) {
+ if logger.Level >= FatalLevel {
+ entry := logger.newEntry()
+ entry.Fatal(args...)
+ logger.releaseEntry(entry)
+ }
+ Exit(1)
+}
+
+func (logger *Logger) Panic(args ...interface{}) {
+ if logger.Level >= PanicLevel {
+ entry := logger.newEntry()
+ entry.Panic(args...)
+ logger.releaseEntry(entry)
+ }
+}
+
+func (logger *Logger) Debugln(args ...interface{}) {
+ if logger.Level >= DebugLevel {
+ entry := logger.newEntry()
+ entry.Debugln(args...)
+ logger.releaseEntry(entry)
+ }
+}
+
+func (logger *Logger) Infoln(args ...interface{}) {
+ if logger.Level >= InfoLevel {
+ entry := logger.newEntry()
+ entry.Infoln(args...)
+ logger.releaseEntry(entry)
+ }
+}
+
+func (logger *Logger) Println(args ...interface{}) {
+ entry := logger.newEntry()
+ entry.Println(args...)
+ logger.releaseEntry(entry)
+}
+
+func (logger *Logger) Warnln(args ...interface{}) {
+ if logger.Level >= WarnLevel {
+ entry := logger.newEntry()
+ entry.Warnln(args...)
+ logger.releaseEntry(entry)
+ }
+}
+
+func (logger *Logger) Warningln(args ...interface{}) {
+ if logger.Level >= WarnLevel {
+ entry := logger.newEntry()
+ entry.Warnln(args...)
+ logger.releaseEntry(entry)
+ }
+}
+
+func (logger *Logger) Errorln(args ...interface{}) {
+ if logger.Level >= ErrorLevel {
+ entry := logger.newEntry()
+ entry.Errorln(args...)
+ logger.releaseEntry(entry)
+ }
+}
+
+func (logger *Logger) Fatalln(args ...interface{}) {
+ if logger.Level >= FatalLevel {
+ entry := logger.newEntry()
+ entry.Fatalln(args...)
+ logger.releaseEntry(entry)
+ }
+ Exit(1)
+}
+
+func (logger *Logger) Panicln(args ...interface{}) {
+ if logger.Level >= PanicLevel {
+ entry := logger.newEntry()
+ entry.Panicln(args...)
+ logger.releaseEntry(entry)
+ }
+}
+
+//When file is opened with appending mode, it's safe to
+//write concurrently to a file (within 4k message on Linux).
+//In these cases user can choose to disable the lock.
+func (logger *Logger) SetNoLock() {
+ logger.mu.Disable()
+}
diff --git a/vendor/github.com/Sirupsen/logrus/logger_bench_test.go b/vendor/github.com/Sirupsen/logrus/logger_bench_test.go
new file mode 100644
index 0000000..dd23a35
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/logger_bench_test.go
@@ -0,0 +1,61 @@
+package logrus
+
+import (
+ "os"
+ "testing"
+)
+
+// smallFields is a small size data set for benchmarking
+var loggerFields = Fields{
+ "foo": "bar",
+ "baz": "qux",
+ "one": "two",
+ "three": "four",
+}
+
+func BenchmarkDummyLogger(b *testing.B) {
+ nullf, err := os.OpenFile("/dev/null", os.O_WRONLY, 0666)
+ if err != nil {
+ b.Fatalf("%v", err)
+ }
+ defer nullf.Close()
+ doLoggerBenchmark(b, nullf, &TextFormatter{DisableColors: true}, smallFields)
+}
+
+func BenchmarkDummyLoggerNoLock(b *testing.B) {
+ nullf, err := os.OpenFile("/dev/null", os.O_WRONLY|os.O_APPEND, 0666)
+ if err != nil {
+ b.Fatalf("%v", err)
+ }
+ defer nullf.Close()
+ doLoggerBenchmarkNoLock(b, nullf, &TextFormatter{DisableColors: true}, smallFields)
+}
+
+func doLoggerBenchmark(b *testing.B, out *os.File, formatter Formatter, fields Fields) {
+ logger := Logger{
+ Out: out,
+ Level: InfoLevel,
+ Formatter: formatter,
+ }
+ entry := logger.WithFields(fields)
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ entry.Info("aaa")
+ }
+ })
+}
+
+func doLoggerBenchmarkNoLock(b *testing.B, out *os.File, formatter Formatter, fields Fields) {
+ logger := Logger{
+ Out: out,
+ Level: InfoLevel,
+ Formatter: formatter,
+ }
+ logger.SetNoLock()
+ entry := logger.WithFields(fields)
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ entry.Info("aaa")
+ }
+ })
+}
diff --git a/vendor/github.com/Sirupsen/logrus/logrus.go b/vendor/github.com/Sirupsen/logrus/logrus.go
new file mode 100644
index 0000000..e596691
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/logrus.go
@@ -0,0 +1,143 @@
+package logrus
+
+import (
+ "fmt"
+ "log"
+ "strings"
+)
+
+// Fields type, used to pass to `WithFields`.
+type Fields map[string]interface{}
+
+// Level type
+type Level uint8
+
+// Convert the Level to a string. E.g. PanicLevel becomes "panic".
+func (level Level) String() string {
+ switch level {
+ case DebugLevel:
+ return "debug"
+ case InfoLevel:
+ return "info"
+ case WarnLevel:
+ return "warning"
+ case ErrorLevel:
+ return "error"
+ case FatalLevel:
+ return "fatal"
+ case PanicLevel:
+ return "panic"
+ }
+
+ return "unknown"
+}
+
+// ParseLevel takes a string level and returns the Logrus log level constant.
+func ParseLevel(lvl string) (Level, error) {
+ switch strings.ToLower(lvl) {
+ case "panic":
+ return PanicLevel, nil
+ case "fatal":
+ return FatalLevel, nil
+ case "error":
+ return ErrorLevel, nil
+ case "warn", "warning":
+ return WarnLevel, nil
+ case "info":
+ return InfoLevel, nil
+ case "debug":
+ return DebugLevel, nil
+ }
+
+ var l Level
+ return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
+}
+
+// A constant exposing all logging levels
+var AllLevels = []Level{
+ PanicLevel,
+ FatalLevel,
+ ErrorLevel,
+ WarnLevel,
+ InfoLevel,
+ DebugLevel,
+}
+
+// These are the different logging levels. You can set the logging level to log
+// on your instance of logger, obtained with `logrus.New()`.
+const (
+ // PanicLevel level, highest level of severity. Logs and then calls panic with the
+ // message passed to Debug, Info, ...
+ PanicLevel Level = iota
+ // FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
+ // logging level is set to Panic.
+ FatalLevel
+ // ErrorLevel level. Logs. Used for errors that should definitely be noted.
+ // Commonly used for hooks to send errors to an error tracking service.
+ ErrorLevel
+ // WarnLevel level. Non-critical entries that deserve eyes.
+ WarnLevel
+ // InfoLevel level. General operational entries about what's going on inside the
+ // application.
+ InfoLevel
+ // DebugLevel level. Usually only enabled when debugging. Very verbose logging.
+ DebugLevel
+)
+
+// Won't compile if StdLogger can't be realized by a log.Logger
+var (
+ _ StdLogger = &log.Logger{}
+ _ StdLogger = &Entry{}
+ _ StdLogger = &Logger{}
+)
+
+// StdLogger is what your logrus-enabled library should take, that way
+// it'll accept a stdlib logger and a logrus logger. There's no standard
+// interface, this is the closest we get, unfortunately.
+type StdLogger interface {
+ Print(...interface{})
+ Printf(string, ...interface{})
+ Println(...interface{})
+
+ Fatal(...interface{})
+ Fatalf(string, ...interface{})
+ Fatalln(...interface{})
+
+ Panic(...interface{})
+ Panicf(string, ...interface{})
+ Panicln(...interface{})
+}
+
+// The FieldLogger interface generalizes the Entry and Logger types
+type FieldLogger interface {
+ WithField(key string, value interface{}) *Entry
+ WithFields(fields Fields) *Entry
+ WithError(err error) *Entry
+
+ Debugf(format string, args ...interface{})
+ Infof(format string, args ...interface{})
+ Printf(format string, args ...interface{})
+ Warnf(format string, args ...interface{})
+ Warningf(format string, args ...interface{})
+ Errorf(format string, args ...interface{})
+ Fatalf(format string, args ...interface{})
+ Panicf(format string, args ...interface{})
+
+ Debug(args ...interface{})
+ Info(args ...interface{})
+ Print(args ...interface{})
+ Warn(args ...interface{})
+ Warning(args ...interface{})
+ Error(args ...interface{})
+ Fatal(args ...interface{})
+ Panic(args ...interface{})
+
+ Debugln(args ...interface{})
+ Infoln(args ...interface{})
+ Println(args ...interface{})
+ Warnln(args ...interface{})
+ Warningln(args ...interface{})
+ Errorln(args ...interface{})
+ Fatalln(args ...interface{})
+ Panicln(args ...interface{})
+}
diff --git a/vendor/github.com/Sirupsen/logrus/logrus_test.go b/vendor/github.com/Sirupsen/logrus/logrus_test.go
new file mode 100644
index 0000000..78cbc28
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/logrus_test.go
@@ -0,0 +1,386 @@
+package logrus
+
+import (
+ "bytes"
+ "encoding/json"
+ "strconv"
+ "strings"
+ "sync"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func LogAndAssertJSON(t *testing.T, log func(*Logger), assertions func(fields Fields)) {
+ var buffer bytes.Buffer
+ var fields Fields
+
+ logger := New()
+ logger.Out = &buffer
+ logger.Formatter = new(JSONFormatter)
+
+ log(logger)
+
+ err := json.Unmarshal(buffer.Bytes(), &fields)
+ assert.Nil(t, err)
+
+ assertions(fields)
+}
+
+func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields map[string]string)) {
+ var buffer bytes.Buffer
+
+ logger := New()
+ logger.Out = &buffer
+ logger.Formatter = &TextFormatter{
+ DisableColors: true,
+ }
+
+ log(logger)
+
+ fields := make(map[string]string)
+ for _, kv := range strings.Split(buffer.String(), " ") {
+ if !strings.Contains(kv, "=") {
+ continue
+ }
+ kvArr := strings.Split(kv, "=")
+ key := strings.TrimSpace(kvArr[0])
+ val := kvArr[1]
+ if kvArr[1][0] == '"' {
+ var err error
+ val, err = strconv.Unquote(val)
+ assert.NoError(t, err)
+ }
+ fields[key] = val
+ }
+ assertions(fields)
+}
+
+func TestPrint(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Print("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test")
+ assert.Equal(t, fields["level"], "info")
+ })
+}
+
+func TestInfo(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Info("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test")
+ assert.Equal(t, fields["level"], "info")
+ })
+}
+
+func TestWarn(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Warn("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test")
+ assert.Equal(t, fields["level"], "warning")
+ })
+}
+
+func TestInfolnShouldAddSpacesBetweenStrings(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Infoln("test", "test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test test")
+ })
+}
+
+func TestInfolnShouldAddSpacesBetweenStringAndNonstring(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Infoln("test", 10)
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test 10")
+ })
+}
+
+func TestInfolnShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Infoln(10, 10)
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "10 10")
+ })
+}
+
+func TestInfoShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Infoln(10, 10)
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "10 10")
+ })
+}
+
+func TestInfoShouldNotAddSpacesBetweenStringAndNonstring(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Info("test", 10)
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test10")
+ })
+}
+
+func TestInfoShouldNotAddSpacesBetweenStrings(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.Info("test", "test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "testtest")
+ })
+}
+
+func TestWithFieldsShouldAllowAssignments(t *testing.T) {
+ var buffer bytes.Buffer
+ var fields Fields
+
+ logger := New()
+ logger.Out = &buffer
+ logger.Formatter = new(JSONFormatter)
+
+ localLog := logger.WithFields(Fields{
+ "key1": "value1",
+ })
+
+ localLog.WithField("key2", "value2").Info("test")
+ err := json.Unmarshal(buffer.Bytes(), &fields)
+ assert.Nil(t, err)
+
+ assert.Equal(t, "value2", fields["key2"])
+ assert.Equal(t, "value1", fields["key1"])
+
+ buffer = bytes.Buffer{}
+ fields = Fields{}
+ localLog.Info("test")
+ err = json.Unmarshal(buffer.Bytes(), &fields)
+ assert.Nil(t, err)
+
+ _, ok := fields["key2"]
+ assert.Equal(t, false, ok)
+ assert.Equal(t, "value1", fields["key1"])
+}
+
+func TestUserSuppliedFieldDoesNotOverwriteDefaults(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.WithField("msg", "hello").Info("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test")
+ })
+}
+
+func TestUserSuppliedMsgFieldHasPrefix(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.WithField("msg", "hello").Info("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["msg"], "test")
+ assert.Equal(t, fields["fields.msg"], "hello")
+ })
+}
+
+func TestUserSuppliedTimeFieldHasPrefix(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.WithField("time", "hello").Info("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["fields.time"], "hello")
+ })
+}
+
+func TestUserSuppliedLevelFieldHasPrefix(t *testing.T) {
+ LogAndAssertJSON(t, func(log *Logger) {
+ log.WithField("level", 1).Info("test")
+ }, func(fields Fields) {
+ assert.Equal(t, fields["level"], "info")
+ assert.Equal(t, fields["fields.level"], 1.0) // JSON has floats only
+ })
+}
+
+func TestDefaultFieldsAreNotPrefixed(t *testing.T) {
+ LogAndAssertText(t, func(log *Logger) {
+ ll := log.WithField("herp", "derp")
+ ll.Info("hello")
+ ll.Info("bye")
+ }, func(fields map[string]string) {
+ for _, fieldName := range []string{"fields.level", "fields.time", "fields.msg"} {
+ if _, ok := fields[fieldName]; ok {
+ t.Fatalf("should not have prefixed %q: %v", fieldName, fields)
+ }
+ }
+ })
+}
+
+func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) {
+
+ var buffer bytes.Buffer
+ var fields Fields
+
+ logger := New()
+ logger.Out = &buffer
+ logger.Formatter = new(JSONFormatter)
+
+ llog := logger.WithField("context", "eating raw fish")
+
+ llog.Info("looks delicious")
+
+ err := json.Unmarshal(buffer.Bytes(), &fields)
+ assert.NoError(t, err, "should have decoded first message")
+ assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
+ assert.Equal(t, fields["msg"], "looks delicious")
+ assert.Equal(t, fields["context"], "eating raw fish")
+
+ buffer.Reset()
+
+ llog.Warn("omg it is!")
+
+ err = json.Unmarshal(buffer.Bytes(), &fields)
+ assert.NoError(t, err, "should have decoded second message")
+ assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
+ assert.Equal(t, fields["msg"], "omg it is!")
+ assert.Equal(t, fields["context"], "eating raw fish")
+ assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry")
+
+}
+
+func TestConvertLevelToString(t *testing.T) {
+ assert.Equal(t, "debug", DebugLevel.String())
+ assert.Equal(t, "info", InfoLevel.String())
+ assert.Equal(t, "warning", WarnLevel.String())
+ assert.Equal(t, "error", ErrorLevel.String())
+ assert.Equal(t, "fatal", FatalLevel.String())
+ assert.Equal(t, "panic", PanicLevel.String())
+}
+
+func TestParseLevel(t *testing.T) {
+ l, err := ParseLevel("panic")
+ assert.Nil(t, err)
+ assert.Equal(t, PanicLevel, l)
+
+ l, err = ParseLevel("PANIC")
+ assert.Nil(t, err)
+ assert.Equal(t, PanicLevel, l)
+
+ l, err = ParseLevel("fatal")
+ assert.Nil(t, err)
+ assert.Equal(t, FatalLevel, l)
+
+ l, err = ParseLevel("FATAL")
+ assert.Nil(t, err)
+ assert.Equal(t, FatalLevel, l)
+
+ l, err = ParseLevel("error")
+ assert.Nil(t, err)
+ assert.Equal(t, ErrorLevel, l)
+
+ l, err = ParseLevel("ERROR")
+ assert.Nil(t, err)
+ assert.Equal(t, ErrorLevel, l)
+
+ l, err = ParseLevel("warn")
+ assert.Nil(t, err)
+ assert.Equal(t, WarnLevel, l)
+
+ l, err = ParseLevel("WARN")
+ assert.Nil(t, err)
+ assert.Equal(t, WarnLevel, l)
+
+ l, err = ParseLevel("warning")
+ assert.Nil(t, err)
+ assert.Equal(t, WarnLevel, l)
+
+ l, err = ParseLevel("WARNING")
+ assert.Nil(t, err)
+ assert.Equal(t, WarnLevel, l)
+
+ l, err = ParseLevel("info")
+ assert.Nil(t, err)
+ assert.Equal(t, InfoLevel, l)
+
+ l, err = ParseLevel("INFO")
+ assert.Nil(t, err)
+ assert.Equal(t, InfoLevel, l)
+
+ l, err = ParseLevel("debug")
+ assert.Nil(t, err)
+ assert.Equal(t, DebugLevel, l)
+
+ l, err = ParseLevel("DEBUG")
+ assert.Nil(t, err)
+ assert.Equal(t, DebugLevel, l)
+
+ l, err = ParseLevel("invalid")
+ assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error())
+}
+
+func TestGetSetLevelRace(t *testing.T) {
+ wg := sync.WaitGroup{}
+ for i := 0; i < 100; i++ {
+ wg.Add(1)
+ go func(i int) {
+ defer wg.Done()
+ if i%2 == 0 {
+ SetLevel(InfoLevel)
+ } else {
+ GetLevel()
+ }
+ }(i)
+
+ }
+ wg.Wait()
+}
+
+func TestLoggingRace(t *testing.T) {
+ logger := New()
+
+ var wg sync.WaitGroup
+ wg.Add(100)
+
+ for i := 0; i < 100; i++ {
+ go func() {
+ logger.Info("info")
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+}
+
+// Compile test
+func TestLogrusInterface(t *testing.T) {
+ var buffer bytes.Buffer
+ fn := func(l FieldLogger) {
+ b := l.WithField("key", "value")
+ b.Debug("Test")
+ }
+ // test logger
+ logger := New()
+ logger.Out = &buffer
+ fn(logger)
+
+ // test Entry
+ e := logger.WithField("another", "value")
+ fn(e)
+}
+
+// Implements io.Writer using channels for synchronization, so we can wait on
+// the Entry.Writer goroutine to write in a non-racey way. This does assume that
+// there is a single call to Logger.Out for each message.
+type channelWriter chan []byte
+
+func (cw channelWriter) Write(p []byte) (int, error) {
+ cw <- p
+ return len(p), nil
+}
+
+func TestEntryWriter(t *testing.T) {
+ cw := channelWriter(make(chan []byte, 1))
+ log := New()
+ log.Out = cw
+ log.Formatter = new(JSONFormatter)
+ log.WithField("foo", "bar").WriterLevel(WarnLevel).Write([]byte("hello\n"))
+
+ bs := <-cw
+ var fields Fields
+ err := json.Unmarshal(bs, &fields)
+ assert.Nil(t, err)
+ assert.Equal(t, fields["foo"], "bar")
+ assert.Equal(t, fields["level"], "warning")
+}
diff --git a/vendor/github.com/Sirupsen/logrus/terminal_appengine.go b/vendor/github.com/Sirupsen/logrus/terminal_appengine.go
new file mode 100644
index 0000000..e011a86
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/terminal_appengine.go
@@ -0,0 +1,10 @@
+// +build appengine
+
+package logrus
+
+import "io"
+
+// IsTerminal returns true if stderr's file descriptor is a terminal.
+func IsTerminal(f io.Writer) bool {
+ return true
+}
diff --git a/vendor/github.com/Sirupsen/logrus/terminal_bsd.go b/vendor/github.com/Sirupsen/logrus/terminal_bsd.go
new file mode 100644
index 0000000..5f6be4d
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/terminal_bsd.go
@@ -0,0 +1,10 @@
+// +build darwin freebsd openbsd netbsd dragonfly
+// +build !appengine
+
+package logrus
+
+import "syscall"
+
+const ioctlReadTermios = syscall.TIOCGETA
+
+type Termios syscall.Termios
diff --git a/vendor/github.com/Sirupsen/logrus/terminal_linux.go b/vendor/github.com/Sirupsen/logrus/terminal_linux.go
new file mode 100644
index 0000000..308160c
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/terminal_linux.go
@@ -0,0 +1,14 @@
+// Based on ssh/terminal:
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !appengine
+
+package logrus
+
+import "syscall"
+
+const ioctlReadTermios = syscall.TCGETS
+
+type Termios syscall.Termios
diff --git a/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go b/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
new file mode 100644
index 0000000..190297a
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
@@ -0,0 +1,28 @@
+// Based on ssh/terminal:
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux darwin freebsd openbsd netbsd dragonfly
+// +build !appengine
+
+package logrus
+
+import (
+ "io"
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+// IsTerminal returns true if stderr's file descriptor is a terminal.
+func IsTerminal(f io.Writer) bool {
+ var termios Termios
+ switch v := f.(type) {
+ case *os.File:
+ _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(v.Fd()), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
+ return err == 0
+ default:
+ return false
+ }
+}
diff --git a/vendor/github.com/Sirupsen/logrus/terminal_solaris.go b/vendor/github.com/Sirupsen/logrus/terminal_solaris.go
new file mode 100644
index 0000000..3c86b1a
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/terminal_solaris.go
@@ -0,0 +1,21 @@
+// +build solaris,!appengine
+
+package logrus
+
+import (
+ "io"
+ "os"
+
+ "golang.org/x/sys/unix"
+)
+
+// IsTerminal returns true if the given file descriptor is a terminal.
+func IsTerminal(f io.Writer) bool {
+ switch v := f.(type) {
+ case *os.File:
+ _, err := unix.IoctlGetTermios(int(v.Fd()), unix.TCGETA)
+ return err == nil
+ default:
+ return false
+ }
+}
diff --git a/vendor/github.com/Sirupsen/logrus/terminal_windows.go b/vendor/github.com/Sirupsen/logrus/terminal_windows.go
new file mode 100644
index 0000000..05d2f91
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/terminal_windows.go
@@ -0,0 +1,33 @@
+// Based on ssh/terminal:
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows,!appengine
+
+package logrus
+
+import (
+ "io"
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+var kernel32 = syscall.NewLazyDLL("kernel32.dll")
+
+var (
+ procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
+)
+
+// IsTerminal returns true if stderr's file descriptor is a terminal.
+func IsTerminal(f io.Writer) bool {
+ switch v := f.(type) {
+ case *os.File:
+ var st uint32
+ r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(v.Fd()), uintptr(unsafe.Pointer(&st)), 0)
+ return r != 0 && e == 0
+ default:
+ return false
+ }
+}
diff --git a/vendor/github.com/Sirupsen/logrus/text_formatter.go b/vendor/github.com/Sirupsen/logrus/text_formatter.go
new file mode 100644
index 0000000..ba88854
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/text_formatter.go
@@ -0,0 +1,189 @@
+package logrus
+
+import (
+ "bytes"
+ "fmt"
+ "sort"
+ "strings"
+ "sync"
+ "time"
+)
+
+const (
+ nocolor = 0
+ red = 31
+ green = 32
+ yellow = 33
+ blue = 34
+ gray = 37
+)
+
+var (
+ baseTimestamp time.Time
+)
+
+func init() {
+ baseTimestamp = time.Now()
+}
+
+type TextFormatter struct {
+ // Set to true to bypass checking for a TTY before outputting colors.
+ ForceColors bool
+
+ // Force disabling colors.
+ DisableColors bool
+
+ // Disable timestamp logging. useful when output is redirected to logging
+ // system that already adds timestamps.
+ DisableTimestamp bool
+
+ // Enable logging the full timestamp when a TTY is attached instead of just
+ // the time passed since beginning of execution.
+ FullTimestamp bool
+
+ // TimestampFormat to use for display when a full timestamp is printed
+ TimestampFormat string
+
+ // The fields are sorted by default for a consistent output. For applications
+ // that log extremely frequently and don't use the JSON formatter this may not
+ // be desired.
+ DisableSorting bool
+
+ // QuoteEmptyFields will wrap empty fields in quotes if true
+ QuoteEmptyFields bool
+
+ // QuoteCharacter can be set to the override the default quoting character "
+ // with something else. For example: ', or `.
+ QuoteCharacter string
+
+ // Whether the logger's out is to a terminal
+ isTerminal bool
+
+ sync.Once
+}
+
+func (f *TextFormatter) init(entry *Entry) {
+ if len(f.QuoteCharacter) == 0 {
+ f.QuoteCharacter = "\""
+ }
+ if entry.Logger != nil {
+ f.isTerminal = IsTerminal(entry.Logger.Out)
+ }
+}
+
+func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
+ var b *bytes.Buffer
+ keys := make([]string, 0, len(entry.Data))
+ for k := range entry.Data {
+ keys = append(keys, k)
+ }
+
+ if !f.DisableSorting {
+ sort.Strings(keys)
+ }
+ if entry.Buffer != nil {
+ b = entry.Buffer
+ } else {
+ b = &bytes.Buffer{}
+ }
+
+ prefixFieldClashes(entry.Data)
+
+ f.Do(func() { f.init(entry) })
+
+ isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors
+
+ timestampFormat := f.TimestampFormat
+ if timestampFormat == "" {
+ timestampFormat = DefaultTimestampFormat
+ }
+ if isColored {
+ f.printColored(b, entry, keys, timestampFormat)
+ } else {
+ if !f.DisableTimestamp {
+ f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat))
+ }
+ f.appendKeyValue(b, "level", entry.Level.String())
+ if entry.Message != "" {
+ f.appendKeyValue(b, "msg", entry.Message)
+ }
+ for _, key := range keys {
+ f.appendKeyValue(b, key, entry.Data[key])
+ }
+ }
+
+ b.WriteByte('\n')
+ return b.Bytes(), nil
+}
+
+func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
+ var levelColor int
+ switch entry.Level {
+ case DebugLevel:
+ levelColor = gray
+ case WarnLevel:
+ levelColor = yellow
+ case ErrorLevel, FatalLevel, PanicLevel:
+ levelColor = red
+ default:
+ levelColor = blue
+ }
+
+ levelText := strings.ToUpper(entry.Level.String())[0:4]
+
+ if f.DisableTimestamp {
+ fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message)
+ } else if !f.FullTimestamp {
+ fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), entry.Message)
+ } else {
+ fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
+ }
+ for _, k := range keys {
+ v := entry.Data[k]
+ fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k)
+ f.appendValue(b, v)
+ }
+}
+
+func (f *TextFormatter) needsQuoting(text string) bool {
+ if f.QuoteEmptyFields && len(text) == 0 {
+ return true
+ }
+ for _, ch := range text {
+ if !((ch >= 'a' && ch <= 'z') ||
+ (ch >= 'A' && ch <= 'Z') ||
+ (ch >= '0' && ch <= '9') ||
+ ch == '-' || ch == '.') {
+ return true
+ }
+ }
+ return false
+}
+
+func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
+
+ b.WriteString(key)
+ b.WriteByte('=')
+ f.appendValue(b, value)
+ b.WriteByte(' ')
+}
+
+func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
+ switch value := value.(type) {
+ case string:
+ if !f.needsQuoting(value) {
+ b.WriteString(value)
+ } else {
+ fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, value, f.QuoteCharacter)
+ }
+ case error:
+ errmsg := value.Error()
+ if !f.needsQuoting(errmsg) {
+ b.WriteString(errmsg)
+ } else {
+ fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, errmsg, f.QuoteCharacter)
+ }
+ default:
+ fmt.Fprint(b, value)
+ }
+}
diff --git a/vendor/github.com/Sirupsen/logrus/text_formatter_test.go b/vendor/github.com/Sirupsen/logrus/text_formatter_test.go
new file mode 100644
index 0000000..9793b5f
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/text_formatter_test.go
@@ -0,0 +1,87 @@
+package logrus
+
+import (
+ "bytes"
+ "errors"
+ "strings"
+ "testing"
+ "time"
+)
+
+func TestQuoting(t *testing.T) {
+ tf := &TextFormatter{DisableColors: true}
+
+ checkQuoting := func(q bool, value interface{}) {
+ b, _ := tf.Format(WithField("test", value))
+ idx := bytes.Index(b, ([]byte)("test="))
+ cont := bytes.Contains(b[idx+5:], []byte(tf.QuoteCharacter))
+ if cont != q {
+ if q {
+ t.Errorf("quoting expected for: %#v", value)
+ } else {
+ t.Errorf("quoting not expected for: %#v", value)
+ }
+ }
+ }
+
+ checkQuoting(false, "")
+ checkQuoting(false, "abcd")
+ checkQuoting(false, "v1.0")
+ checkQuoting(false, "1234567890")
+ checkQuoting(true, "/foobar")
+ checkQuoting(true, "x y")
+ checkQuoting(true, "x,y")
+ checkQuoting(false, errors.New("invalid"))
+ checkQuoting(true, errors.New("invalid argument"))
+
+ // Test for custom quote character.
+ tf.QuoteCharacter = "`"
+ checkQuoting(false, "")
+ checkQuoting(false, "abcd")
+ checkQuoting(true, "/foobar")
+ checkQuoting(true, errors.New("invalid argument"))
+
+ // Test for multi-character quotes.
+ tf.QuoteCharacter = "§~±"
+ checkQuoting(false, "abcd")
+ checkQuoting(true, errors.New("invalid argument"))
+
+ // Test for quoting empty fields.
+ tf.QuoteEmptyFields = true
+ checkQuoting(true, "")
+ checkQuoting(false, "abcd")
+ checkQuoting(true, errors.New("invalid argument"))
+}
+
+func TestTimestampFormat(t *testing.T) {
+ checkTimeStr := func(format string) {
+ customFormatter := &TextFormatter{DisableColors: true, TimestampFormat: format}
+ customStr, _ := customFormatter.Format(WithField("test", "test"))
+ timeStart := bytes.Index(customStr, ([]byte)("time="))
+ timeEnd := bytes.Index(customStr, ([]byte)("level="))
+ timeStr := customStr[timeStart+5+len(customFormatter.QuoteCharacter) : timeEnd-1-len(customFormatter.QuoteCharacter)]
+ if format == "" {
+ format = time.RFC3339
+ }
+ _, e := time.Parse(format, (string)(timeStr))
+ if e != nil {
+ t.Errorf("time string \"%s\" did not match provided time format \"%s\": %s", timeStr, format, e)
+ }
+ }
+
+ checkTimeStr("2006-01-02T15:04:05.000000000Z07:00")
+ checkTimeStr("Mon Jan _2 15:04:05 2006")
+ checkTimeStr("")
+}
+
+func TestDisableTimestampWithColoredOutput(t *testing.T) {
+ tf := &TextFormatter{DisableTimestamp: true, ForceColors: true}
+
+ b, _ := tf.Format(WithField("test", "test"))
+ if strings.Contains(string(b), "[0000]") {
+ t.Error("timestamp not expected when DisableTimestamp is true")
+ }
+}
+
+// TODO add tests for sorting etc., this requires a parser for the text
+// formatter output.
diff --git a/vendor/github.com/Sirupsen/logrus/writer.go b/vendor/github.com/Sirupsen/logrus/writer.go
new file mode 100644
index 0000000..7bdebed
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/writer.go
@@ -0,0 +1,62 @@
+package logrus
+
+import (
+ "bufio"
+ "io"
+ "runtime"
+)
+
+func (logger *Logger) Writer() *io.PipeWriter {
+ return logger.WriterLevel(InfoLevel)
+}
+
+func (logger *Logger) WriterLevel(level Level) *io.PipeWriter {
+ return NewEntry(logger).WriterLevel(level)
+}
+
+func (entry *Entry) Writer() *io.PipeWriter {
+ return entry.WriterLevel(InfoLevel)
+}
+
+func (entry *Entry) WriterLevel(level Level) *io.PipeWriter {
+ reader, writer := io.Pipe()
+
+ var printFunc func(args ...interface{})
+
+ switch level {
+ case DebugLevel:
+ printFunc = entry.Debug
+ case InfoLevel:
+ printFunc = entry.Info
+ case WarnLevel:
+ printFunc = entry.Warn
+ case ErrorLevel:
+ printFunc = entry.Error
+ case FatalLevel:
+ printFunc = entry.Fatal
+ case PanicLevel:
+ printFunc = entry.Panic
+ default:
+ printFunc = entry.Print
+ }
+
+ go entry.writerScanner(reader, printFunc)
+ runtime.SetFinalizer(writer, writerFinalizer)
+
+ return writer
+}
+
+func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) {
+ scanner := bufio.NewScanner(reader)
+ for scanner.Scan() {
+ printFunc(scanner.Text())
+ }
+ if err := scanner.Err(); err != nil {
+ entry.Errorf("Error while reading from Writer: %s", err)
+ }
+ reader.Close()
+}
+
+func writerFinalizer(writer *io.PipeWriter) {
+ writer.Close()
+}
diff --git a/vendor/github.com/bennyscetbun/jsongo/.gitignore b/vendor/github.com/bennyscetbun/jsongo/.gitignore
new file mode 100644
index 0000000..32678c7
--- /dev/null
+++ b/vendor/github.com/bennyscetbun/jsongo/.gitignore
@@ -0,0 +1,24 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*~
diff --git a/vendor/github.com/bennyscetbun/jsongo/LICENSE b/vendor/github.com/bennyscetbun/jsongo/LICENSE
new file mode 100644
index 0000000..aab88ef
--- /dev/null
+++ b/vendor/github.com/bennyscetbun/jsongo/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Benny Scetbun
+
+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/bennyscetbun/jsongo/README.md b/vendor/github.com/bennyscetbun/jsongo/README.md
new file mode 100644
index 0000000..ebc81c6
--- /dev/null
+++ b/vendor/github.com/bennyscetbun/jsongo/README.md
@@ -0,0 +1,574 @@
+jsongo
+======
+
+**Jsongo is a simple library for golang to help you build Json without static struct or map[string]interface**
+
+[json.Marshal](http://golang.org/pkg/encoding/json/#Marshal) and [json.Unmarshal](http://golang.org/pkg/encoding/json/#Unmarshal) have never been that easy
+
+**If you had only one function to look at, look at the "[At](#at)" function**
+
+***If you want an easy way to turn your json into a structure you should use the "[Print](#print)" function after unmarshalling json in a JSONNODE***
+
+You can find the doc on godoc.org [![GoDoc](https://godoc.org/github.com/bennyscetbun/jsongo?status.png)](https://godoc.org/github.com/bennyscetbun/jsongo)
+
+
+##JsonNode
+
+JsonNode is the basic Structure that you must use when using jsongo. It can either be a:
+- Map (jsongo.TypeMap)
+- Array (jsongo.TypeArray)
+- Value (jsongo.TypeValue) *Precisely a pointer store in an interface{}*
+- Undefined (jsongo.TypeUndefined) *default type*
+
+*When a JSONNode Type is set you cant change it without using Unset() first*
+____
+###Val
+####Synopsis:
+turn this JSONNode to TypeValue and set that value
+```go
+func (that *JSONNode) Val(val interface{})
+```
+
+####Examples
+#####code:
+```go
+package main
+
+import (
+ "github.com/bennyscetbun/jsongo"
+)
+
+func main() {
+ root := jsongo.JSONNode{}
+ root.Val(42)
+ root.DebugPrint("")
+}
+```
+#####output:
+```
+42
+```
+#####code:
+```go
+package main
+
+import (
+ "github.com/bennyscetbun/jsongo"
+)
+type MyStruct struct {
+ Member1 string
+ Member2 int
+}
+
+func main() {
+ root := jsongo.JSONNode{}
+ root.Val(MyStruct{"The answer", 42})
+ root.DebugPrint("")
+}
+```
+#####output:
+```
+{
+ "Member1": "The answer",
+ "Member2": 42
+}
+```
+_____
+###Array
+####Synopsis:
+ Turn this JSONNode to a TypeArray and/or set the array size (reducing size will make you loose data)
+```go
+func (that *JSONNode) Array(size int) *[]JSONNode
+```
+
+####Examples
+#####code:
+```go
+package main
+
+import (
+ "github.com/bennyscetbun/jsongo"
+)
+
+func main() {
+ root := jsongo.JSONNode{}
+ a := root.Array(4)
+ for i := 0; i < 4; i++ {
+ (*a)[i].Val(i)
+ }
+ root.DebugPrint("")
+}
+```
+#####output:
+```
+[
+ 0,
+ 1,
+ 2,
+ 3
+]
+```
+#####code:
+```go
+package main
+
+import (
+ "github.com/bennyscetbun/jsongo"
+)
+
+func main() {
+ root := jsongo.JSONNode{}
+ a := root.Array(4)
+ for i := 0; i < 4; i++ {
+ (*a)[i].Val(i)
+ }
+ root.Array(2) //Here we reduce the size and we loose some data
+ root.DebugPrint("")
+}
+```
+#####output:
+```
+[
+ 0,
+ 1
+]
+```
+____
+###Map
+####Synopsis:
+Turn this JSONNode to a TypeMap and/or Create a new element for key if necessary and return it
+```go
+func (that *JSONNode) Map(key string) *JSONNode
+```
+
+####Examples
+#####code:
+```go
+package main
+
+import (
+ "github.com/bennyscetbun/jsongo"
+)
+
+func main() {
+ root := jsongo.JSONNode{}
+ root.Map("there").Val("you are")
+ root.Map("here").Val("you should be")
+ root.DebugPrint("")
+}
+```
+#####output:
+```
+{
+ "here": "you should be",
+ "there": "you are"
+}
+```
+____
+###At
+####Synopsis:
+Helps you move through your node by building them on the fly
+
+*val can be string or int only*
+
+*strings are keys for TypeMap*
+
+*ints are index in TypeArray (it will make array grow on the fly, so you should start to populate with the biggest index first)*
+```go
+func (that *JSONNode) At(val ...interface{}) *JSONNode
+```
+
+####Examples
+#####code:
+```go
+package main
+
+import (
+ "github.com/bennyscetbun/jsongo"
+)
+
+func main() {
+ root := jsongo.JSONNode{}
+ root.At(4, "Who").Val("Let the dog out") //is equivalent to (*root.Array(5))[4].Map("Who").Val("Let the dog out")
+ root.DebugPrint("")
+}
+```
+#####output:
+```
+[
+ null,
+ null,
+ null,
+ null,
+ {
+ "Who": "Let the dog out"
+ }
+]
+```
+#####code:
+```go
+package main
+
+import (
+ "github.com/bennyscetbun/jsongo"
+)
+
+func main() {
+ root := jsongo.JSONNode{}
+ root.At(4, "Who").Val("Let the dog out")
+ //to win some time you can even even save a certain JSONNode
+ node := root.At(2, "What")
+ node.At("Can", "You").Val("do with that?")
+ node.At("Do", "You", "Think").Val("Of that")
+ root.DebugPrint("")
+}
+```
+#####output:
+```
+[
+ null,
+ null,
+ {
+ "What": {
+ "Can": {
+ "You": "do with that?"
+ },
+ "Do": {
+ "You": {
+ "Think": "Of that"
+ }
+ }
+ }
+ },
+ null,
+ {
+ "Who": "Let the dog out"
+ }
+]
+```
+____
+###Print
+####Synopsis:
+Helps you build your code by printing a go structure from the json you ve just unmarshaled
+
+```go
+func (that *JSONNode) Print()
+```
+
+____
+###Other Function
+There is plenty of other function, you should check the complete doc [![GoDoc](https://godoc.org/github.com/bennyscetbun/jsongo?status.png)](https://godoc.org/github.com/bennyscetbun/jsongo)
+
+####A last Example for fun
+#####code:
+```go
+package main
+
+import (
+ "github.com/bennyscetbun/jsongo"
+)
+
+func ShowOnlyValue(current *jsongo.JSONNode) {
+ switch current.GetType() {
+ case jsongo.TypeValue:
+ println(current.Get().(string))
+ case jsongo.TypeMap:
+ for _, key := range current.GetKeys() {
+ ShowOnlyValue(current.At(key))
+ }
+ case jsongo.TypeArray:
+ for _, key := range current.GetKeys() {
+ ShowOnlyValue(current.At(key))
+ }
+ }
+}
+
+func main() {
+ root := jsongo.JSONNode{}
+ root.At(4, "Who").Val("Let the dog out")
+ node := root.At(2, "What")
+ node.At("Can", "You").Val("do with that?")
+ node.At("Do", "You", "Think").Val("Of that")
+ ShowOnlyValue(&root)
+}
+```
+#####output:
+```
+Of that
+do with that?
+Let the dog out
+```
+_____
+_____
+##Json Marshal/Unmarshal
+
+One of the main purpose of jsongo was to create Json from data without using static structure or map[string]interface.
+
+You can use the full power of the [encoding/json](http://golang.org/pkg/encoding/json/) package with jsongo.
+
+###Marshal
+####Example
+#####code:
+```go
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "github.com/bennyscetbun/jsongo"
+)
+
+type Test struct {
+ Static string `json:"static"`
+ Over int `json:"over"`
+}
+
+func main() {
+ root := jsongo.JSONNode{}
+ root.At("A", "AA", "AAA").Val(42)
+
+ node := root.At("A", "AB")
+ node.At(1).Val("Peace")
+ node.At(0).Val(Test{"struct suck when you build json", 9000})
+ root.At("B").Val("Oh Yeah")
+
+ tojson, err := json.MarshalIndent(&root, "", " ")
+ if err != nil {
+ fmt.Printf("%s\n", err.Error())
+ return
+ }
+ fmt.Printf("%s\n", tojson)
+}
+```
+#####output:
+```
+{
+ "A": {
+ "AA": {
+ "AAA": 42
+ },
+ "AB": [
+ {
+ "static": "struct suck when you build json",
+ "over": 9000
+ },
+ "Peace"
+ ]
+ },
+ "B": "Oh Yeah"
+}
+```
+____
+###Unmarshal
+Unmarshal using JSONNode follow some simple rules:
+- Any TypeUndefined JSONNode will be set to the right type, any other type wont be changed
+- Array will grow if necessary
+- New keys will be added to Map
+- Values set to nil "*.Val(nil)*" will be turn into the type decide by Json
+- It will respect any current mapping and will return errors if needed
+
+You can set a node as "DontExpand" with the UnmarshalDontExpand function and thoose rules will apply:
+- The type wont be change for any type
+- Array wont grow
+- New keys wont be added to Map
+- Values set to nil "*.Val(nil)*" will be turn into the type decide by Json
+- It will respect any current mapping and will return errors if needed
+
+####Example of full expand
+#####code:
+```go
+package main
+
+import (
+ "encoding/json"
+ "github.com/bennyscetbun/jsongo"
+ "fmt"
+)
+
+func main() {
+ root := jsongo.JSONNode{}
+ fromjson := `{
+ "A": {
+ "AA": {
+ "AAA": 42
+ },
+ "AB": [
+ {
+ "static": "struct suck when you build json",
+ "over": 9000
+ },
+ "Peace"
+ ]
+ },
+ "B": "Oh Yeah"
+ }`
+ err := json.Unmarshal([]byte(fromjson), &root)
+ if err != nil {
+ fmt.Printf("%s\n", err.Error())
+ return
+ }
+ root.DebugProspect(0, "\t")
+}
+```
+#####output:
+```
+Is of Type: TypeMap
+A:
+ Is of Type: TypeMap
+ AA:
+ Is of Type: TypeMap
+ AAA:
+ Is of Type: TypeValue
+ Value of type: float64
+ 42
+ AB:
+ Is of Type: TypeArray
+ [0]:
+ Is of Type: TypeMap
+ static:
+ Is of Type: TypeValue
+ Value of type: string
+ struct suck when you build json
+ over:
+ Is of Type: TypeValue
+ Value of type: float64
+ 9000
+ [1]:
+ Is of Type: TypeValue
+ Value of type: string
+ Peace
+B:
+ Is of Type: TypeValue
+ Value of type: string
+ Oh Yeah
+```
+####Example expand with mapping
+#####code:
+```go
+package main
+
+import (
+ "encoding/json"
+ "github.com/bennyscetbun/jsongo"
+ "fmt"
+)
+type Test struct {
+ Static string `json:"static"`
+ Over int `json:"over"`
+}
+
+func main() {
+ root := jsongo.JSONNode{}
+ fromjson := `{
+ "A": {
+ "AA": {
+ "AAA": 42
+ },
+ "AB": [
+ {
+ "static": "struct suck when you build json",
+ "over": 9000
+ },
+ "Peace"
+ ]
+ },
+ "B": "Oh Yeah"
+ }`
+ root.At("A", "AB", 0).Val(Test{})
+ err := json.Unmarshal([]byte(fromjson), &root)
+ if err != nil {
+ fmt.Printf("%s\n", err.Error())
+ return
+ }
+ root.DebugProspect(0, "\t")
+}
+```
+#####output:
+```
+Is of Type: TypeMap
+A:
+ Is of Type: TypeMap
+ AB:
+ Is of Type: TypeArray
+ [0]:
+ Is of Type: TypeValue
+ Value of type: main.Test
+ {Static:struct suck when you build json Over:9000}
+ [1]:
+ Is of Type: TypeValue
+ Value of type: string
+ Peace
+ AA:
+ Is of Type: TypeMap
+ AAA:
+ Is of Type: TypeValue
+ Value of type: float64
+ 42
+B:
+ Is of Type: TypeValue
+ Value of type: string
+ Oh Yeah
+```
+####Example expand with some UnmarshalDontExpand
+#####code:
+```go
+package main
+
+import (
+ "encoding/json"
+ "github.com/bennyscetbun/jsongo"
+ "fmt"
+)
+type Test struct {
+ Static string `json:"static"`
+ Over int `json:"over"`
+}
+
+func main() {
+ root := jsongo.JSONNode{}
+ fromjson := `{
+ "A": {
+ "AA": {
+ "AAA": 42
+ },
+ "AB": [
+ {
+ "static": "struct suck when you build json",
+ "over": 9000
+ },
+ "Peace"
+ ]
+ },
+ "B": "Oh Yeah"
+ }`
+ root.At("A", "AB").UnmarshalDontExpand(true, false).At(0).Val(Test{})
+ err := json.Unmarshal([]byte(fromjson), &root)
+ if err != nil {
+ fmt.Printf("%s\n", err.Error())
+ return
+ }
+ root.DebugProspect(0, "\t")
+}
+```
+#####output:
+```
+Is of Type: TypeMap
+A:
+ Is of Type: TypeMap
+ AB:
+ Is of Type: TypeArray
+ [0]:
+ Is of Type: TypeValue
+ Value of type: main.Test
+ {Static:struct suck when you build json Over:9000}
+ AA:
+ Is of Type: TypeMap
+ AAA:
+ Is of Type: TypeValue
+ Value of type: float64
+ 42
+B:
+ Is of Type: TypeValue
+ Value of type: string
+ Oh Yeah
+```
diff --git a/vendor/github.com/bennyscetbun/jsongo/debug.go b/vendor/github.com/bennyscetbun/jsongo/debug.go
new file mode 100644
index 0000000..a1aa425
--- /dev/null
+++ b/vendor/github.com/bennyscetbun/jsongo/debug.go
@@ -0,0 +1,60 @@
+package jsongo
+
+import (
+ "encoding/json"
+ "fmt"
+ "os"
+)
+
+//DebugPrint Print a JSONNode as json withindent
+func (that *JSONNode) DebugPrint(prefix string) {
+ asJSON, err := json.MarshalIndent(that, "", " ")
+ if err != nil {
+ fmt.Printf("%s\n", err.Error())
+ os.Exit(-1)
+ }
+ fmt.Printf("%s%s\n", prefix, asJSON)
+}
+
+func printfindent(indentlevel int, indentchar string, format string, args ...interface{}) {
+ for i := 0; i < indentlevel; i++ {
+ fmt.Printf("%s", indentchar)
+ }
+ fmt.Printf(format, args...)
+}
+
+func (that *JSONNode) debugProspectValue(indentlevel int, indentchar string) {
+ printfindent(indentlevel, indentchar, "Is of Type: TypeValue\n")
+ printfindent(indentlevel, indentchar, "Value of type: %T\n", that.Get())
+ printfindent(indentlevel, indentchar, "%+v\n", that.Get())
+}
+
+func (that *JSONNode) debugProspectMap(indentlevel int, indentchar string) {
+ printfindent(indentlevel, indentchar, "Is of Type: TypeMap\n")
+ for key := range that.m {
+ printfindent(indentlevel, indentchar, "%s:\n", key)
+ that.m[key].DebugProspect(indentlevel+1, indentchar)
+ }
+}
+
+func (that *JSONNode) debugProspectArray(indentlevel int, indentchar string) {
+ printfindent(indentlevel, indentchar, "Is of Type: TypeArray\n")
+ for key := range that.a {
+ printfindent(indentlevel, indentchar, "[%d]:\n", key)
+ that.a[key].DebugProspect(indentlevel+1, indentchar)
+ }
+}
+
+//DebugProspect Print all the data the we ve got on a node and all it s children
+func (that *JSONNode) DebugProspect(indentlevel int, indentchar string) {
+ switch that.t {
+ case TypeValue:
+ that.debugProspectValue(indentlevel, indentchar)
+ case TypeMap:
+ that.debugProspectMap(indentlevel, indentchar)
+ case TypeArray:
+ that.debugProspectArray(indentlevel, indentchar)
+ case TypeUndefined:
+ printfindent(indentlevel, indentchar, "Is of Type: TypeUndefined\n")
+ }
+}
diff --git a/vendor/github.com/bennyscetbun/jsongo/jsongo.go b/vendor/github.com/bennyscetbun/jsongo/jsongo.go
new file mode 100644
index 0000000..d661931
--- /dev/null
+++ b/vendor/github.com/bennyscetbun/jsongo/jsongo.go
@@ -0,0 +1,472 @@
+// Copyright 2014 Benny Scetbun. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+// Package Jsongo is a simple library to help you build Json without static struct
+//
+// Source code and project home:
+// https://github.com/benny-deluxe/jsongo
+//
+
+package jsongo
+
+import (
+ "encoding/json"
+ "errors"
+ "reflect"
+ //"fmt"
+)
+
+//ErrorKeyAlreadyExist error if a key already exist in current JSONNode
+var ErrorKeyAlreadyExist = errors.New("jsongo key already exist")
+
+//ErrorMultipleType error if a JSONNode already got a different type of value
+var ErrorMultipleType = errors.New("jsongo this node is already set to a different jsonNodeType")
+
+//ErrorArrayNegativeValue error if you ask for a negative index in an array
+var ErrorArrayNegativeValue = errors.New("jsongo negative index for array")
+
+//ErrorArrayNegativeValue error if you ask for a negative index in an array
+var ErrorAtUnsupportedType = errors.New("jsongo Unsupported Type as At argument")
+
+//ErrorRetrieveUserValue error if you ask the value of a node that is not a value node
+var ErrorRetrieveUserValue = errors.New("jsongo Cannot retrieve node's value which is not of type value")
+
+//ErrorTypeUnmarshaling error if you try to unmarshal something in the wrong type
+var ErrorTypeUnmarshaling = errors.New("jsongo Wrong type when Unmarshaling")
+
+//ErrorUnknowType error if you try to use an unknow JSONNodeType
+var ErrorUnknowType = errors.New("jsongo Unknow JSONNodeType")
+
+//ErrorValNotPointer error if you try to use Val without a valid pointer
+var ErrorValNotPointer = errors.New("jsongo: Val: arguments must be a pointer and not nil")
+
+//ErrorGetKeys error if you try to get the keys from a JSONNode that isnt a TypeMap or a TypeArray
+var ErrorGetKeys = errors.New("jsongo: GetKeys: JSONNode is not a TypeMap or TypeArray")
+
+//ErrorDeleteKey error if you try to call DelKey on a JSONNode that isnt a TypeMap
+var ErrorDeleteKey = errors.New("jsongo: DelKey: This JSONNode is not a TypeMap")
+
+//ErrorCopyType error if you try to call Copy on a JSONNode that isnt a TypeUndefined
+var ErrorCopyType = errors.New("jsongo: Copy: This JSONNode is not a TypeUndefined")
+
+//JSONNode Datastructure to build and maintain Nodes
+type JSONNode struct {
+ m map[string]*JSONNode
+ a []JSONNode
+ v interface{}
+ vChanged bool //True if we changed the type of the value
+ t JSONNodeType //Type of that JSONNode 0: Not defined, 1: map, 2: array, 3: value
+ dontExpand bool //dont expand while Unmarshal
+}
+
+//JSONNodeType is used to set, check and get the inner type of a JSONNode
+type JSONNodeType uint
+
+const (
+ //TypeUndefined is set by default for empty JSONNode
+ TypeUndefined JSONNodeType = iota
+ //TypeMap is set when a JSONNode is a Map
+ TypeMap
+ //TypeArray is set when a JSONNode is an Array
+ TypeArray
+ //TypeValue is set when a JSONNode is a Value Node
+ TypeValue
+ //typeError help us detect errors
+ typeError
+)
+
+//At helps you move through your node by building them on the fly
+//
+//val can be string or int only
+//
+//strings are keys for TypeMap
+//
+//ints are index in TypeArray (it will make array grow on the fly, so you should start to populate with the biggest index first)*
+func (that *JSONNode) At(val ...interface{}) *JSONNode {
+ if len(val) == 0 {
+ return that
+ }
+ switch vv := val[0].(type) {
+ case string:
+ return that.atMap(vv, val[1:]...)
+ case int:
+ return that.atArray(vv, val[1:]...)
+ }
+ panic(ErrorAtUnsupportedType)
+}
+
+//atMap return the JSONNode in current map
+func (that *JSONNode) atMap(key string, val ...interface{}) *JSONNode {
+ if that.t != TypeUndefined && that.t != TypeMap {
+ panic(ErrorMultipleType)
+ }
+ if that.m == nil {
+ that.m = make(map[string]*JSONNode)
+ that.t = TypeMap
+ }
+ if next, ok := that.m[key]; ok {
+ return next.At(val...)
+ }
+ that.m[key] = new(JSONNode)
+ return that.m[key].At(val...)
+}
+
+//atArray return the JSONNode in current TypeArray (and make it grow if necessary)
+func (that *JSONNode) atArray(key int, val ...interface{}) *JSONNode {
+ if that.t == TypeUndefined {
+ that.t = TypeArray
+ } else if that.t != TypeArray {
+ panic(ErrorMultipleType)
+ }
+ if key < 0 {
+ panic(ErrorArrayNegativeValue)
+ }
+ if key >= len(that.a) {
+ newa := make([]JSONNode, key+1)
+ for i := 0; i < len(that.a); i++ {
+ newa[i] = that.a[i]
+ }
+ that.a = newa
+ }
+ return that.a[key].At(val...)
+}
+
+//Map Turn this JSONNode to a TypeMap and/or Create a new element for key if necessary and return it
+func (that *JSONNode) Map(key string) *JSONNode {
+ if that.t != TypeUndefined && that.t != TypeMap {
+ panic(ErrorMultipleType)
+ }
+ if that.m == nil {
+ that.m = make(map[string]*JSONNode)
+ that.t = TypeMap
+ }
+ if _, ok := that.m[key]; ok {
+ return that.m[key]
+ }
+ that.m[key] = &JSONNode{}
+ return that.m[key]
+}
+
+//Array Turn this JSONNode to a TypeArray and/or set the array size (reducing size will make you loose data)
+func (that *JSONNode) Array(size int) *[]JSONNode {
+ if that.t == TypeUndefined {
+ that.t = TypeArray
+ } else if that.t != TypeArray {
+ panic(ErrorMultipleType)
+ }
+ if size < 0 {
+ panic(ErrorArrayNegativeValue)
+ }
+ var min int
+ if size < len(that.a) {
+ min = size
+ } else {
+ min = len(that.a)
+ }
+ newa := make([]JSONNode, size)
+ for i := 0; i < min; i++ {
+ newa[i] = that.a[i]
+ }
+ that.a = newa
+ return &(that.a)
+}
+
+//Val Turn this JSONNode to Value type and/or set that value to val
+func (that *JSONNode) Val(val interface{}) {
+ if that.t == TypeUndefined {
+ that.t = TypeValue
+ } else if that.t != TypeValue {
+ panic(ErrorMultipleType)
+ }
+ rt := reflect.TypeOf(val)
+ var finalval interface{}
+ if val == nil {
+ finalval = &val
+ that.vChanged = true
+ } else if rt.Kind() != reflect.Ptr {
+ rv := reflect.ValueOf(val)
+ var tmp reflect.Value
+ if rv.CanAddr() {
+ tmp = rv.Addr()
+ } else {
+ tmp = reflect.New(rt)
+ tmp.Elem().Set(rv)
+ }
+ finalval = tmp.Interface()
+ that.vChanged = true
+ } else {
+ finalval = val
+ }
+ that.v = finalval
+}
+
+//Get Return value of a TypeValue as interface{}
+func (that *JSONNode) Get() interface{} {
+ if that.t != TypeValue {
+ panic(ErrorRetrieveUserValue)
+ }
+ if that.vChanged {
+ rv := reflect.ValueOf(that.v)
+ return rv.Elem().Interface()
+ }
+ return that.v
+}
+
+//GetKeys Return a slice interface that represent the keys to use with the At fonction (Works only on TypeMap and TypeArray)
+func (that *JSONNode) GetKeys() []interface{} {
+ var ret []interface{}
+ switch that.t {
+ case TypeMap:
+ nb := len(that.m)
+ ret = make([]interface{}, nb)
+ for key := range that.m {
+ nb--
+ ret[nb] = key
+ }
+ case TypeArray:
+ nb := len(that.a)
+ ret = make([]interface{}, nb)
+ for nb > 0 {
+ nb--
+ ret[nb] = nb
+ }
+ default:
+ panic(ErrorGetKeys)
+ }
+ return ret
+}
+
+//Len Return the length of the current Node
+//
+// if TypeUndefined return 0
+//
+// if TypeValue return 1
+//
+// if TypeArray return the size of the array
+//
+// if TypeMap return the size of the map
+func (that *JSONNode) Len() int {
+ var ret int
+ switch that.t {
+ case TypeMap:
+ ret = len(that.m)
+ case TypeArray:
+ ret = len(that.a)
+ case TypeValue:
+ ret = 1
+ }
+ return ret
+}
+
+//SetType Is use to set the Type of a node and return the current Node you are working on
+func (that *JSONNode) SetType(t JSONNodeType) *JSONNode {
+ if that.t != TypeUndefined && that.t != t {
+ panic(ErrorMultipleType)
+ }
+ if t >= typeError {
+ panic(ErrorUnknowType)
+ }
+ that.t = t
+ switch t {
+ case TypeMap:
+ that.m = make(map[string]*JSONNode, 0)
+ case TypeArray:
+ that.a = make([]JSONNode, 0)
+ case TypeValue:
+ that.Val(nil)
+ }
+ return that
+}
+
+//GetType Is use to Get the Type of a node
+func (that *JSONNode) GetType() JSONNodeType {
+ return that.t
+}
+
+//Copy Will set this node like the one in argument. this node must be of type TypeUndefined
+//
+//if deepCopy is true we will copy all the children recursively else we will share the children
+//
+//return the current JSONNode
+func (that *JSONNode) Copy(other *JSONNode, deepCopy bool) *JSONNode {
+ if that.t != TypeUndefined {
+ panic(ErrorCopyType)
+ }
+
+ if other.t == TypeValue {
+ *that = *other
+ } else if other.t == TypeArray {
+ if !deepCopy {
+ *that = *other
+ } else {
+ that.Array(len(other.a))
+ for i := range other.a {
+ that.At(i).Copy(other.At(i), deepCopy)
+ }
+ }
+ } else if other.t == TypeMap {
+ that.SetType(other.t)
+ if !deepCopy {
+ for val := range other.m {
+ that.m[val] = other.m[val]
+ }
+ } else {
+ for val := range other.m {
+ that.Map(val).Copy(other.At(val), deepCopy)
+ }
+ }
+ }
+ return that
+}
+
+
+//Unset Will unset everything in the JSONnode. All the children data will be lost
+func (that *JSONNode) Unset() {
+ *that = JSONNode{}
+}
+
+//DelKey will remove a key in the map.
+//
+//return the current JSONNode.
+func (that *JSONNode) DelKey(key string) *JSONNode {
+ if that.t != TypeMap {
+ panic(ErrorDeleteKey)
+ }
+ delete(that.m, key)
+ return that
+}
+
+//UnmarshalDontExpand set or not if Unmarshall will generate anything in that JSONNode and its children
+//
+//val: will change the expanding rules for this node
+//
+//- The type wont be change for any type
+//
+//- Array wont grow
+//
+//- New keys wont be added to Map
+//
+//- Values set to nil "*.Val(nil)*" will be turn into the type decide by Json
+//
+//- It will respect any current mapping and will return errors if needed
+//
+//recurse: if true, it will set all the children of that JSONNode with val
+func (that *JSONNode) UnmarshalDontExpand(val bool, recurse bool) *JSONNode {
+ that.dontExpand = val
+ if recurse {
+ switch that.t {
+ case TypeMap:
+ for k := range that.m {
+ that.m[k].UnmarshalDontExpand(val, recurse)
+ }
+ case TypeArray:
+ for k := range that.a {
+ that.a[k].UnmarshalDontExpand(val, recurse)
+ }
+ }
+ }
+ return that
+}
+
+//MarshalJSON Make JSONNode a Marshaler Interface compatible
+func (that *JSONNode) MarshalJSON() ([]byte, error) {
+ var ret []byte
+ var err error
+ switch that.t {
+ case TypeMap:
+ ret, err = json.Marshal(that.m)
+ case TypeArray:
+ ret, err = json.Marshal(that.a)
+ case TypeValue:
+ ret, err = json.Marshal(that.v)
+ default:
+ ret, err = json.Marshal(nil)
+ }
+ if err != nil {
+ return nil, err
+ }
+ return ret, err
+}
+
+func (that *JSONNode) unmarshalMap(data []byte) error {
+ tmp := make(map[string]json.RawMessage)
+ err := json.Unmarshal(data, &tmp)
+ if err != nil {
+ return err
+ }
+ for k := range tmp {
+ if _, ok := that.m[k]; ok {
+ err := json.Unmarshal(tmp[k], that.m[k])
+ if err != nil {
+ return err
+ }
+ } else if !that.dontExpand {
+ err := json.Unmarshal(tmp[k], that.Map(k))
+ if err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func (that *JSONNode) unmarshalArray(data []byte) error {
+ var tmp []json.RawMessage
+ err := json.Unmarshal(data, &tmp)
+ if err != nil {
+ return err
+ }
+ for i := len(tmp) - 1; i >= 0; i-- {
+ if !that.dontExpand || i < len(that.a) {
+ err := json.Unmarshal(tmp[i], that.At(i))
+ if err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func (that *JSONNode) unmarshalValue(data []byte) error {
+ if that.v != nil {
+ return json.Unmarshal(data, that.v)
+ }
+ var tmp interface{}
+ err := json.Unmarshal(data, &tmp)
+ if err != nil {
+ return err
+ }
+ that.Val(tmp)
+ return nil
+}
+
+//UnmarshalJSON Make JSONNode a Unmarshaler Interface compatible
+func (that *JSONNode) UnmarshalJSON(data []byte) error {
+ if len(data) == 0 {
+ return nil
+ }
+ if that.dontExpand && that.t == TypeUndefined {
+ return nil
+ }
+ if that.t == TypeValue {
+ return that.unmarshalValue(data)
+ }
+ if data[0] == '{' {
+ if that.t != TypeMap && that.t != TypeUndefined {
+ return ErrorTypeUnmarshaling
+ }
+ return that.unmarshalMap(data)
+ }
+ if data[0] == '[' {
+ if that.t != TypeArray && that.t != TypeUndefined {
+ return ErrorTypeUnmarshaling
+ }
+ return that.unmarshalArray(data)
+
+ }
+ if that.t == TypeUndefined {
+ return that.unmarshalValue(data)
+ }
+ return ErrorTypeUnmarshaling
+}
diff --git a/vendor/github.com/bennyscetbun/jsongo/print.go b/vendor/github.com/bennyscetbun/jsongo/print.go
new file mode 100644
index 0000000..6869918
--- /dev/null
+++ b/vendor/github.com/bennyscetbun/jsongo/print.go
@@ -0,0 +1,74 @@
+package jsongo
+
+import (
+ "fmt"
+ "regexp"
+ "strings"
+)
+
+//Thanks https://github.com/chuckpreslar/inflect for the UpperCamelCase
+
+// Split's a string so that it can be converted to a different casing.
+// Splits on underscores, hyphens, spaces and camel casing.
+func split(str string) []string {
+ // FIXME: This isn't a perfect solution.
+ // ex. WEiRD CaSINg (Support for 13 year old developers)
+ return strings.Split(regexp.MustCompile(`-|_|([a-z])([A-Z])`).ReplaceAllString(strings.Trim(str, `-|_| `), `$1 $2`), ` `)
+}
+
+// UpperCamelCase converts a string to it's upper camel case version.
+func UpperCamelCase(str string) string {
+ pieces := split(str)
+
+ for index, s := range pieces {
+ pieces[index] = fmt.Sprintf(`%v%v`, strings.ToUpper(string(s[0])), strings.ToLower(s[1:]))
+ }
+
+ return strings.Join(pieces, ``)
+}
+
+func (that *JSONNode) printValue(indentlevel int, indentchar string) {
+ fmt.Printf(" %T ", that.Get())
+}
+
+func (that *JSONNode) printMap(indentlevel int, indentchar string) {
+ fmt.Printf(" struct {\n")
+ for key := range that.m {
+ printfindent(indentlevel+1, indentchar, "%s", UpperCamelCase(key))
+ that.m[key].print(indentlevel+1, indentchar)
+ fmt.Printf(" `json:\"%s\"`\n", key)
+ }
+ printfindent(indentlevel, indentchar, "}")
+}
+
+func (that *JSONNode) printArray(indentlevel int, indentchar string) {
+ if len(that.a) == 0 {
+ fmt.Printf(" []interface{} ")
+ return
+ }
+ fmt.Printf(" [] ")
+ for key := range that.a {
+ that.a[key].print(indentlevel+1, indentchar)
+ break
+ }
+}
+
+//DebugProspect Print all the data the we ve got on a node and all it s children
+func (that *JSONNode) print(indentlevel int, indentchar string) {
+ switch that.t {
+ case TypeValue:
+ that.printValue(indentlevel, indentchar)
+ case TypeMap:
+ that.printMap(indentlevel, indentchar)
+ case TypeArray:
+ that.printArray(indentlevel, indentchar)
+ case TypeUndefined:
+ printfindent(indentlevel, indentchar, "Is of Type: TypeUndefined\n")
+ }
+}
+
+//Print Print all the data the we ve got on a node and all it s children as a go struct :) (FOR DEV PURPOSE)
+func (that *JSONNode) Print() {
+ that.print(0, "\t")
+ fmt.Printf("\n")
+}
diff --git a/vendor/github.com/lunixbochs/struc/.travis.yml b/vendor/github.com/lunixbochs/struc/.travis.yml
new file mode 100644
index 0000000..8316e89
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/.travis.yml
@@ -0,0 +1,10 @@
+language: go
+sudo: false
+
+script: go test -v
+
+go:
+ - 1.2
+ - 1.3
+ - 1.4
+ - tip
diff --git a/vendor/github.com/lunixbochs/struc/LICENSE b/vendor/github.com/lunixbochs/struc/LICENSE
new file mode 100644
index 0000000..42e8263
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2015 Ryan Hileman
+
+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/lunixbochs/struc/README.md b/vendor/github.com/lunixbochs/struc/README.md
new file mode 100644
index 0000000..c813497
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/README.md
@@ -0,0 +1,103 @@
+[![Build Status](https://travis-ci.org/lunixbochs/struc.svg?branch=master)](https://travis-ci.org/lunixbochs/struc)
+
+struc
+====
+
+Struc exists to pack and unpack C-style structures from bytes, which is useful for binary files and network protocols. It could be considered an alternative to `encoding/binary`, which requires massive boilerplate for some similar operations.
+
+Take a look at an [example comparing `struc` and `encoding/binary`](https://bochs.info/p/cxvm9)
+
+Struc considers usability first. That said, it does cache reflection data and aims to be competitive with `encoding/binary` struct packing in every way, including performance.
+
+Example struct
+----
+
+```Go
+type Example struct {
+ Var int `struc:"int32,sizeof=Str"`
+ Str string
+ Weird []byte `struc:"[8]int64"`
+ Var []int `struc:"[]int32,little"`
+}
+```
+
+Struct tag format
+----
+
+ - ```Var []int `struc:"[]int32,little,sizeof=StringField"` ``` will pack Var as a slice of little-endian int32, and link it as the size of `StringField`.
+ - `sizeof=`: Indicates this field is a number used to track the length of a another field. `sizeof` fields are automatically updated on `Pack()` based on the current length of the tracked field, and are used to size the target field during `Unpack()`.
+ - Bare values will be parsed as type and endianness.
+
+Endian formats
+----
+
+ - `big` (default)
+ - `little`
+
+Recognized types
+----
+
+ - `pad` - this type ignores field contents and is backed by a `[length]byte` containing nulls
+ - `bool`
+ - `byte`
+ - `int8`, `uint8`
+ - `int16`, `uint16`
+ - `int32`, `uint32`
+ - `int64`, `uint64`
+ - `float32`
+ - `float64`
+
+Types can be indicated as arrays/slices using `[]` syntax. Example: `[]int64`, `[8]int32`.
+
+Bare slice types (those with no `[size]`) must have a linked `Sizeof` field.
+
+Private fields are ignored when packing and unpacking.
+
+Example code
+----
+
+```Go
+package main
+
+import (
+ "bytes"
+ "github.com/lunixbochs/struc"
+)
+
+type Example struct {
+ A int `struc:"big"`
+
+ // B will be encoded/decoded as a 16-bit int (a "short")
+ // but is stored as a native int in the struct
+ B int `struc:"int16"`
+
+ // the sizeof key links a buffer's size to any int field
+ Size int `struc:"int8,little,sizeof=Str"`
+ Str string
+
+ // you can get freaky if you want
+ Str2 string `struc:"[5]int64"`
+}
+
+func main() {
+ var buf bytes.Buffer
+ t := &Example{1, 2, 0, "test", "test2"}
+ err := struc.Pack(&buf, t)
+ o := &Example{}
+ err = struc.Unpack(&buf, o)
+}
+```
+
+Benchmark
+----
+
+`BenchmarkEncode` uses struc. `Stdlib` benchmarks use equivalent `encoding/binary` code. `Manual` encodes without any reflection, and should be considered an upper bound on performance (which generated code based on struc definitions should be able to achieve).
+
+```
+BenchmarkEncode 1000000 1265 ns/op
+BenchmarkStdlibEncode 1000000 1855 ns/op
+BenchmarkManualEncode 5000000 284 ns/op
+BenchmarkDecode 1000000 1259 ns/op
+BenchmarkStdlibDecode 1000000 1656 ns/op
+BenchmarkManualDecode 20000000 89.0 ns/op
+```
diff --git a/vendor/github.com/lunixbochs/struc/bench_test.go b/vendor/github.com/lunixbochs/struc/bench_test.go
new file mode 100644
index 0000000..d73c110
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/bench_test.go
@@ -0,0 +1,165 @@
+package struc
+
+import (
+ "bytes"
+ "encoding/binary"
+ "testing"
+)
+
+type BenchExample struct {
+ Test [5]byte
+ A int32
+ B, C, D int16
+ Test2 [4]byte
+ Length int32
+}
+
+type BenchStrucExample struct {
+ Test [5]byte `struc:"[5]byte"`
+ A int `struc:"int32"`
+ B, C, D int `struc:"int16"`
+ Test2 [4]byte `struc:"[4]byte"`
+ Length int `struc:"int32,sizeof=Data"`
+ Data []byte
+}
+
+var benchRef = &BenchExample{
+ [5]byte{1, 2, 3, 4, 5},
+ 1, 2, 3, 4,
+ [4]byte{1, 2, 3, 4},
+ 8,
+}
+
+var eightBytes = []byte("8bytestr")
+
+var benchStrucRef = &BenchStrucExample{
+ [5]byte{1, 2, 3, 4, 5},
+ 1, 2, 3, 4,
+ [4]byte{1, 2, 3, 4},
+ 8, eightBytes,
+}
+
+func BenchmarkEncode(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var buf bytes.Buffer
+ err := Pack(&buf, benchStrucRef)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
+func BenchmarkStdlibEncode(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var buf bytes.Buffer
+ err := binary.Write(&buf, binary.BigEndian, benchRef)
+ if err != nil {
+ b.Fatal(err)
+ }
+ _, err = buf.Write(eightBytes)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
+func BenchmarkManualEncode(b *testing.B) {
+ order := binary.BigEndian
+ s := benchStrucRef
+ for i := 0; i < b.N; i++ {
+ var buf bytes.Buffer
+ tmp := make([]byte, 29)
+ copy(tmp[0:5], s.Test[:])
+ order.PutUint32(tmp[5:9], uint32(s.A))
+ order.PutUint16(tmp[9:11], uint16(s.B))
+ order.PutUint16(tmp[11:13], uint16(s.C))
+ order.PutUint16(tmp[13:15], uint16(s.D))
+ copy(tmp[15:19], s.Test2[:])
+ order.PutUint32(tmp[19:23], uint32(s.Length))
+ copy(tmp[23:], s.Data)
+ _, err := buf.Write(tmp)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
+func BenchmarkDecode(b *testing.B) {
+ var out BenchStrucExample
+ var buf bytes.Buffer
+ if err := Pack(&buf, benchStrucRef); err != nil {
+ b.Fatal(err)
+ }
+ bufBytes := buf.Bytes()
+ for i := 0; i < b.N; i++ {
+ buf := bytes.NewReader(bufBytes)
+ err := Unpack(buf, &out)
+ if err != nil {
+ b.Fatal(err)
+ }
+ out.Data = nil
+ }
+}
+
+func BenchmarkStdlibDecode(b *testing.B) {
+ var out BenchExample
+ var buf bytes.Buffer
+ binary.Write(&buf, binary.BigEndian, *benchRef)
+ _, err := buf.Write(eightBytes)
+ if err != nil {
+ b.Fatal(err)
+ }
+ bufBytes := buf.Bytes()
+ for i := 0; i < b.N; i++ {
+ buf := bytes.NewReader(bufBytes)
+ err := binary.Read(buf, binary.BigEndian, &out)
+ if err != nil {
+ b.Fatal(err)
+ }
+ tmp := make([]byte, out.Length)
+ _, err = buf.Read(tmp)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
+func BenchmarkManualDecode(b *testing.B) {
+ var o BenchStrucExample
+ var buf bytes.Buffer
+ if err := Pack(&buf, benchStrucRef); err != nil {
+ b.Fatal(err)
+ }
+ tmp := buf.Bytes()
+ order := binary.BigEndian
+ for i := 0; i < b.N; i++ {
+ copy(o.Test[:], tmp[0:5])
+ o.A = int(order.Uint32(tmp[5:9]))
+ o.B = int(order.Uint16(tmp[9:11]))
+ o.C = int(order.Uint16(tmp[11:13]))
+ o.D = int(order.Uint16(tmp[13:15]))
+ copy(o.Test2[:], tmp[15:19])
+ o.Length = int(order.Uint32(tmp[19:23]))
+ o.Data = make([]byte, o.Length)
+ copy(o.Data, tmp[23:])
+ }
+}
+
+func BenchmarkFullEncode(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var buf bytes.Buffer
+ if err := Pack(&buf, reference); err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
+func BenchmarkFullDecode(b *testing.B) {
+ var out Example
+ for i := 0; i < b.N; i++ {
+ buf := bytes.NewBuffer(referenceBytes)
+ if err := Unpack(buf, &out); err != nil {
+ b.Fatal(err)
+ }
+ }
+}
diff --git a/vendor/github.com/lunixbochs/struc/binary.go b/vendor/github.com/lunixbochs/struc/binary.go
new file mode 100644
index 0000000..4899d08
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/binary.go
@@ -0,0 +1,52 @@
+package struc
+
+import (
+ "encoding/binary"
+ "io"
+ "reflect"
+)
+
+type byteWriter struct {
+ buf []byte
+ pos int
+}
+
+func (b byteWriter) Write(p []byte) (int, error) {
+ capacity := len(b.buf) - b.pos
+ if capacity < len(p) {
+ p = p[:capacity]
+ }
+ if len(p) > 0 {
+ copy(b.buf[b.pos:], p)
+ b.pos += len(p)
+ }
+ return len(p), nil
+}
+
+type binaryFallback reflect.Value
+
+func (b binaryFallback) String() string {
+ return b.String()
+}
+
+func (b binaryFallback) Sizeof(val reflect.Value, options *Options) int {
+ return binary.Size(val.Interface())
+}
+
+func (b binaryFallback) Pack(buf []byte, val reflect.Value, options *Options) (int, error) {
+ tmp := byteWriter{buf: buf}
+ var order binary.ByteOrder = binary.BigEndian
+ if options.Order != nil {
+ order = options.Order
+ }
+ err := binary.Write(tmp, order, val.Interface())
+ return tmp.pos, err
+}
+
+func (b binaryFallback) Unpack(r io.Reader, val reflect.Value, options *Options) error {
+ var order binary.ByteOrder = binary.BigEndian
+ if options.Order != nil {
+ order = options.Order
+ }
+ return binary.Read(r, order, val.Interface())
+}
diff --git a/vendor/github.com/lunixbochs/struc/custom.go b/vendor/github.com/lunixbochs/struc/custom.go
new file mode 100644
index 0000000..c468dce
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/custom.go
@@ -0,0 +1,33 @@
+package struc
+
+import (
+ "io"
+ "reflect"
+)
+
+type Custom interface {
+ Pack(p []byte, opt *Options) (int, error)
+ Unpack(r io.Reader, length int, opt *Options) error
+ Size(opt *Options) int
+ String() string
+}
+
+type customFallback struct {
+ custom Custom
+}
+
+func (c customFallback) Pack(p []byte, val reflect.Value, opt *Options) (int, error) {
+ return c.custom.Pack(p, opt)
+}
+
+func (c customFallback) Unpack(r io.Reader, val reflect.Value, opt *Options) error {
+ return c.custom.Unpack(r, 1, opt)
+}
+
+func (c customFallback) Sizeof(val reflect.Value, opt *Options) int {
+ return c.custom.Size(opt)
+}
+
+func (c customFallback) String() string {
+ return c.custom.String()
+}
diff --git a/vendor/github.com/lunixbochs/struc/custom_float16.go b/vendor/github.com/lunixbochs/struc/custom_float16.go
new file mode 100644
index 0000000..722be76
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/custom_float16.go
@@ -0,0 +1,78 @@
+package struc
+
+import (
+ "encoding/binary"
+ "io"
+ "math"
+ "strconv"
+)
+
+type Float16 float64
+
+func (f *Float16) Pack(p []byte, opt *Options) (int, error) {
+ order := opt.Order
+ if order == nil {
+ order = binary.BigEndian
+ }
+ sign := uint16(0)
+ if *f < 0 {
+ sign = 1
+ }
+ var frac, exp uint16
+ if math.IsInf(float64(*f), 0) {
+ exp = 0x1f
+ frac = 0
+ } else if math.IsNaN(float64(*f)) {
+ exp = 0x1f
+ frac = 1
+ } else {
+ bits := math.Float64bits(float64(*f))
+ exp64 := (bits >> 52) & 0x7ff
+ if exp64 != 0 {
+ exp = uint16((exp64 - 1023 + 15) & 0x1f)
+ }
+ frac = uint16((bits >> 42) & 0x3ff)
+ }
+ var out uint16
+ out |= sign << 15
+ out |= exp << 10
+ out |= frac & 0x3ff
+ order.PutUint16(p, out)
+ return 2, nil
+}
+func (f *Float16) Unpack(r io.Reader, length int, opt *Options) error {
+ order := opt.Order
+ if order == nil {
+ order = binary.BigEndian
+ }
+ var tmp [2]byte
+ if _, err := r.Read(tmp[:]); err != nil {
+ return err
+ }
+ val := order.Uint16(tmp[:2])
+ sign := (val >> 15) & 1
+ exp := int16((val >> 10) & 0x1f)
+ frac := val & 0x3ff
+ if exp == 0x1f {
+ if frac != 0 {
+ *f = Float16(math.NaN())
+ } else {
+ *f = Float16(math.Inf(int(sign)*-2 + 1))
+ }
+ } else {
+ var bits uint64
+ bits |= uint64(sign) << 63
+ bits |= uint64(frac) << 42
+ if exp > 0 {
+ bits |= uint64(exp-15+1023) << 52
+ }
+ *f = Float16(math.Float64frombits(bits))
+ }
+ return nil
+}
+func (f *Float16) Size(opt *Options) int {
+ return 2
+}
+func (f *Float16) String() string {
+ return strconv.FormatFloat(float64(*f), 'g', -1, 32)
+}
diff --git a/vendor/github.com/lunixbochs/struc/custom_float16_test.go b/vendor/github.com/lunixbochs/struc/custom_float16_test.go
new file mode 100644
index 0000000..11f73cb
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/custom_float16_test.go
@@ -0,0 +1,56 @@
+package struc
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "math"
+ "strconv"
+ "strings"
+ "testing"
+)
+
+func TestFloat16(t *testing.T) {
+ // test cases from https://en.wikipedia.org/wiki/Half-precision_floating-point_format#Half_precision_examples
+ tests := []struct {
+ B string
+ F float64
+ }{
+ //s expnt significand
+ {"0 01111 0000000000", 1},
+ {"0 01111 0000000001", 1.0009765625},
+ {"1 10000 0000000000", -2},
+ {"0 11110 1111111111", 65504},
+ // {"0 00001 0000000000", 0.0000610352},
+ // {"0 00000 1111111111", 0.0000609756},
+ // {"0 00000 0000000001", 0.0000000596046},
+ {"0 00000 0000000000", 0},
+ // {"1 00000 0000000000", -0},
+ {"0 11111 0000000000", math.Inf(1)},
+ {"1 11111 0000000000", math.Inf(-1)},
+ {"0 01101 0101010101", 0.333251953125},
+ }
+ for _, test := range tests {
+ var buf bytes.Buffer
+ f := Float16(test.F)
+ if err := Pack(&buf, &f); err != nil {
+ t.Error("pack failed:", err)
+ continue
+ }
+ bitval, _ := strconv.ParseUint(strings.Replace(test.B, " ", "", -1), 2, 16)
+ tmp := binary.BigEndian.Uint16(buf.Bytes())
+ if tmp != uint16(bitval) {
+ t.Errorf("incorrect pack: %s != %016b (%f)", test.B, tmp, test.F)
+ continue
+ }
+ var f2 Float16
+ if err := Unpack(&buf, &f2); err != nil {
+ t.Error("unpack failed:", err)
+ continue
+ }
+ // let sprintf deal with (im)precision for me here
+ if fmt.Sprintf("%f", f) != fmt.Sprintf("%f", f2) {
+ t.Errorf("incorrect unpack: %016b %f != %f", bitval, f, f2)
+ }
+ }
+}
diff --git a/vendor/github.com/lunixbochs/struc/custom_test.go b/vendor/github.com/lunixbochs/struc/custom_test.go
new file mode 100644
index 0000000..e601166
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/custom_test.go
@@ -0,0 +1,97 @@
+package struc
+
+import (
+ "bytes"
+ "encoding/binary"
+ "io"
+ "strconv"
+ "testing"
+)
+
+type Int3 uint32
+
+func (i *Int3) Pack(p []byte, opt *Options) (int, error) {
+ var tmp [4]byte
+ binary.BigEndian.PutUint32(tmp[:], uint32(*i))
+ copy(p, tmp[1:])
+ return 3, nil
+}
+func (i *Int3) Unpack(r io.Reader, length int, opt *Options) error {
+ var tmp [4]byte
+ if _, err := r.Read(tmp[1:]); err != nil {
+ return err
+ }
+ *i = Int3(binary.BigEndian.Uint32(tmp[:]))
+ return nil
+}
+func (i *Int3) Size(opt *Options) int {
+ return 3
+}
+func (i *Int3) String() string {
+ return strconv.FormatUint(uint64(*i), 10)
+}
+
+func TestCustom(t *testing.T) {
+ var buf bytes.Buffer
+ var i Int3 = 3
+ if err := Pack(&buf, &i); err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(buf.Bytes(), []byte{0, 0, 3}) {
+ t.Fatal("error packing custom int")
+ }
+ var i2 Int3
+ if err := Unpack(&buf, &i2); err != nil {
+ t.Fatal(err)
+ }
+ if i2 != 3 {
+ t.Fatal("error unpacking custom int")
+ }
+}
+
+type Int3Struct struct {
+ I Int3
+}
+
+func TestCustomStruct(t *testing.T) {
+ var buf bytes.Buffer
+ i := Int3Struct{3}
+ if err := Pack(&buf, &i); err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(buf.Bytes(), []byte{0, 0, 3}) {
+ t.Fatal("error packing custom int struct")
+ }
+ var i2 Int3Struct
+ if err := Unpack(&buf, &i2); err != nil {
+ t.Fatal(err)
+ }
+ if i2.I != 3 {
+ t.Fatal("error unpacking custom int struct")
+ }
+}
+
+// TODO: slices of custom types don't work yet
+/*
+type Int3SliceStruct struct {
+ I [2]Int3
+}
+
+func TestCustomSliceStruct(t *testing.T) {
+ var buf bytes.Buffer
+ i := Int3SliceStruct{[2]Int3{3, 4}}
+ if err := Pack(&buf, &i); err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(buf.Bytes(), []byte{0, 0, 3}) {
+ t.Fatal("error packing custom int struct")
+ }
+ var i2 Int3SliceStruct
+ if err := Unpack(&buf, &i2); err != nil {
+ t.Fatal(err)
+ }
+ if i2.I[0] != 3 && i2.I[1] != 4 {
+ t.Fatal("error unpacking custom int struct")
+ }
+}
+*/
diff --git a/vendor/github.com/lunixbochs/struc/field.go b/vendor/github.com/lunixbochs/struc/field.go
new file mode 100644
index 0000000..4af10a7
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/field.go
@@ -0,0 +1,281 @@
+package struc
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "math"
+ "reflect"
+)
+
+type Field struct {
+ Name string
+ CanSet bool
+ Ptr bool
+ Index int
+ Type Type
+ defType Type
+ Array bool
+ Slice bool
+ Len int
+ Order binary.ByteOrder
+ Sizeof []int
+ Sizefrom []int
+ Fields Fields
+ kind reflect.Kind
+}
+
+func (f *Field) String() string {
+ var out string
+ if f.Type == Pad {
+ return fmt.Sprintf("{type: Pad, len: %d}", f.Len)
+ } else {
+ out = fmt.Sprintf("type: %s, order: %v", f.Type.String(), f.Order)
+ }
+ if f.Sizefrom != nil {
+ out += fmt.Sprintf(", sizefrom: %v", f.Sizefrom)
+ } else if f.Len > 0 {
+ out += fmt.Sprintf(", len: %d", f.Len)
+ }
+ if f.Sizeof != nil {
+ out += fmt.Sprintf(", sizeof: %v", f.Sizeof)
+ }
+ return "{" + out + "}"
+}
+
+func (f *Field) Size(val reflect.Value, options *Options) int {
+ typ := f.Type.Resolve(options)
+ size := 0
+ if typ == Struct {
+ vals := []reflect.Value{val}
+ if f.Slice {
+ vals = make([]reflect.Value, val.Len())
+ for i := 0; i < val.Len(); i++ {
+ vals[i] = val.Index(i)
+ }
+ }
+ for _, val := range vals {
+ size += f.Fields.Sizeof(val, options)
+ }
+ } else if typ == Pad {
+ size = f.Len
+ } else if f.Slice || f.kind == reflect.String {
+ length := val.Len()
+ if f.Len > 1 {
+ length = f.Len
+ }
+ size = length * typ.Size()
+ } else if typ == CustomType {
+ return val.Addr().Interface().(Custom).Size(options)
+ } else {
+ size = typ.Size()
+ }
+ align := options.ByteAlign
+ if align > 0 && size < align {
+ size = align
+ }
+ return size
+}
+
+func (f *Field) packVal(buf []byte, val reflect.Value, length int, options *Options) (size int, err error) {
+ order := f.Order
+ if options.Order != nil {
+ order = options.Order
+ }
+ if f.Ptr {
+ val = val.Elem()
+ }
+ typ := f.Type.Resolve(options)
+ switch typ {
+ case Struct:
+ return f.Fields.Pack(buf, val, options)
+ case Bool, Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64:
+ size = typ.Size()
+ var n uint64
+ switch f.kind {
+ case reflect.Bool:
+ if val.Bool() {
+ n = 1
+ } else {
+ n = 0
+ }
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ n = uint64(val.Int())
+ default:
+ n = val.Uint()
+ }
+ switch typ {
+ case Bool:
+ if n != 0 {
+ buf[0] = 1
+ } else {
+ buf[0] = 0
+ }
+ case Int8, Uint8:
+ buf[0] = byte(n)
+ case Int16, Uint16:
+ order.PutUint16(buf, uint16(n))
+ case Int32, Uint32:
+ order.PutUint32(buf, uint32(n))
+ case Int64, Uint64:
+ order.PutUint64(buf, uint64(n))
+ }
+ case Float32, Float64:
+ size = typ.Size()
+ n := val.Float()
+ switch typ {
+ case Float32:
+ order.PutUint32(buf, math.Float32bits(float32(n)))
+ case Float64:
+ order.PutUint64(buf, math.Float64bits(n))
+ }
+ case String:
+ switch f.kind {
+ case reflect.String:
+ size = val.Len()
+ copy(buf, []byte(val.String()))
+ default:
+ // TODO: handle kind != bytes here
+ size = val.Len()
+ copy(buf, val.Bytes())
+ }
+ case CustomType:
+ return val.Addr().Interface().(Custom).Pack(buf, options)
+ default:
+ panic(fmt.Sprintf("no pack handler for type: %s", typ))
+ }
+ return
+}
+
+func (f *Field) Pack(buf []byte, val reflect.Value, length int, options *Options) (int, error) {
+ typ := f.Type.Resolve(options)
+ if typ == Pad {
+ for i := 0; i < length; i++ {
+ buf[i] = 0
+ }
+ return length, nil
+ }
+ if f.Slice {
+ // special case strings and byte slices for performance
+ end := val.Len()
+ if !f.Array && typ == Uint8 && (f.defType == Uint8 || f.kind == reflect.String) {
+ var tmp []byte
+ if f.kind == reflect.String {
+ tmp = []byte(val.String())
+ } else {
+ tmp = val.Bytes()
+ }
+ copy(buf, tmp)
+ if end < length {
+ // TODO: allow configuring pad byte?
+ rep := bytes.Repeat([]byte{0}, length-end)
+ copy(buf[end:], rep)
+ return length, nil
+ }
+ return val.Len(), nil
+ }
+ pos := 0
+ var zero reflect.Value
+ if end < length {
+ zero = reflect.Zero(val.Type().Elem())
+ }
+ for i := 0; i < length; i++ {
+ cur := zero
+ if i < end {
+ cur = val.Index(i)
+ }
+ if n, err := f.packVal(buf[pos:], cur, 1, options); err != nil {
+ return pos, err
+ } else {
+ pos += n
+ }
+ }
+ return pos, nil
+ } else {
+ return f.packVal(buf, val, length, options)
+ }
+}
+
+func (f *Field) unpackVal(buf []byte, val reflect.Value, length int, options *Options) error {
+ order := f.Order
+ if options.Order != nil {
+ order = options.Order
+ }
+ if f.Ptr {
+ val = val.Elem()
+ }
+ typ := f.Type.Resolve(options)
+ switch typ {
+ case Float32, Float64:
+ var n float64
+ switch typ {
+ case Float32:
+ n = float64(math.Float32frombits(order.Uint32(buf)))
+ case Float64:
+ n = math.Float64frombits(order.Uint64(buf))
+ }
+ switch f.kind {
+ case reflect.Float32, reflect.Float64:
+ val.SetFloat(n)
+ default:
+ return fmt.Errorf("struc: refusing to unpack float into field %s of type %s", f.Name, f.kind.String())
+ }
+ case Bool, Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64:
+ var n uint64
+ switch typ {
+ case Bool, Int8, Uint8:
+ n = uint64(buf[0])
+ case Int16, Uint16:
+ n = uint64(order.Uint16(buf))
+ case Int32, Uint32:
+ n = uint64(order.Uint32(buf))
+ case Int64, Uint64:
+ n = uint64(order.Uint64(buf))
+ }
+ switch f.kind {
+ case reflect.Bool:
+ val.SetBool(n != 0)
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ val.SetInt(int64(n))
+ default:
+ val.SetUint(n)
+ }
+ default:
+ panic(fmt.Sprintf("no unpack handler for type: %s", typ))
+ }
+ return nil
+}
+
+func (f *Field) Unpack(buf []byte, val reflect.Value, length int, options *Options) error {
+ typ := f.Type.Resolve(options)
+ if typ == Pad || f.kind == reflect.String {
+ if typ == Pad {
+ return nil
+ } else {
+ val.SetString(string(buf))
+ return nil
+ }
+ } else if f.Slice {
+ if val.Cap() < length {
+ val.Set(reflect.MakeSlice(val.Type(), length, length))
+ } else if val.Len() < length {
+ val.Set(val.Slice(0, length))
+ }
+ // special case byte slices for performance
+ if !f.Array && typ == Uint8 && f.defType == Uint8 {
+ copy(val.Bytes(), buf[:length])
+ return nil
+ }
+ pos := 0
+ size := typ.Size()
+ for i := 0; i < length; i++ {
+ if err := f.unpackVal(buf[pos:pos+size], val.Index(i), 1, options); err != nil {
+ return err
+ }
+ pos += size
+ }
+ return nil
+ } else {
+ return f.unpackVal(buf, val, length, options)
+ }
+}
diff --git a/vendor/github.com/lunixbochs/struc/field_test.go b/vendor/github.com/lunixbochs/struc/field_test.go
new file mode 100644
index 0000000..45a07b2
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/field_test.go
@@ -0,0 +1,77 @@
+package struc
+
+import (
+ "bytes"
+ "testing"
+)
+
+type badFloat struct {
+ BadFloat int `struc:"float64"`
+}
+
+func TestBadFloatField(t *testing.T) {
+ buf := bytes.NewReader([]byte("00000000"))
+ err := Unpack(buf, &badFloat{})
+ if err == nil {
+ t.Fatal("failed to error on bad float unpack")
+ }
+}
+
+type emptyLengthField struct {
+ Strlen int `struc:"sizeof=Str"`
+ Str []byte
+}
+
+func TestEmptyLengthField(t *testing.T) {
+ var buf bytes.Buffer
+ s := &emptyLengthField{0, []byte("test")}
+ o := &emptyLengthField{}
+ if err := Pack(&buf, s); err != nil {
+ t.Fatal(err)
+ }
+ if err := Unpack(&buf, o); err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(s.Str, o.Str) {
+ t.Fatal("empty length field encode failed")
+ }
+}
+
+type fixedSlicePad struct {
+ Field []byte `struc:"[4]byte"`
+}
+
+func TestFixedSlicePad(t *testing.T) {
+ var buf bytes.Buffer
+ ref := []byte{0, 0, 0, 0}
+ s := &fixedSlicePad{}
+ if err := Pack(&buf, s); err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(buf.Bytes(), ref) {
+ t.Fatal("implicit fixed slice pack failed")
+ }
+ if err := Unpack(&buf, s); err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(s.Field, ref) {
+ t.Fatal("implicit fixed slice unpack failed")
+ }
+}
+
+type sliceCap struct {
+ Len int `struc:"sizeof=Field"`
+ Field []byte
+}
+
+func TestSliceCap(t *testing.T) {
+ var buf bytes.Buffer
+ tmp := &sliceCap{0, []byte("1234")}
+ if err := Pack(&buf, tmp); err != nil {
+ t.Fatal(err)
+ }
+ tmp.Field = make([]byte, 0, 4)
+ if err := Unpack(&buf, tmp); err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/vendor/github.com/lunixbochs/struc/fields.go b/vendor/github.com/lunixbochs/struc/fields.go
new file mode 100644
index 0000000..80e2045
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/fields.go
@@ -0,0 +1,169 @@
+package struc
+
+import (
+ "encoding/binary"
+ "fmt"
+ "io"
+ "reflect"
+ "strings"
+)
+
+type Fields []*Field
+
+func (f Fields) SetByteOrder(order binary.ByteOrder) {
+ for _, field := range f {
+ field.Order = order
+ }
+}
+
+func (f Fields) String() string {
+ fields := make([]string, len(f))
+ for i, field := range f {
+ fields[i] = field.String()
+ }
+ return "{" + strings.Join(fields, ", ") + "}"
+}
+
+func (f Fields) Sizeof(val reflect.Value, options *Options) int {
+ for val.Kind() == reflect.Ptr {
+ val = val.Elem()
+ }
+ size := 0
+ for i, field := range f {
+ v := val.Field(i)
+ if v.CanSet() {
+ size += field.Size(v, options)
+ }
+ }
+ return size
+}
+
+func (f Fields) sizefrom(val reflect.Value, index []int) int {
+ field := val.FieldByIndex(index)
+ switch field.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return int(field.Int())
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ n := int(field.Uint())
+ // all the builtin array length types are native int
+ // so this guards against weird truncation
+ if n < 0 {
+ return 0
+ }
+ return n
+ default:
+ name := val.Type().FieldByIndex(index).Name
+ panic(fmt.Sprintf("sizeof field %T.%s not an integer type", val.Interface(), name))
+ }
+}
+
+func (f Fields) Pack(buf []byte, val reflect.Value, options *Options) (int, error) {
+ for val.Kind() == reflect.Ptr {
+ val = val.Elem()
+ }
+ pos := 0
+ for i, field := range f {
+ if !field.CanSet {
+ continue
+ }
+ v := val.Field(i)
+ length := field.Len
+ if field.Sizefrom != nil {
+ length = f.sizefrom(val, field.Sizefrom)
+ }
+ if length <= 0 && field.Slice {
+ length = v.Len()
+ }
+ if field.Sizeof != nil {
+ length := val.FieldByIndex(field.Sizeof).Len()
+ switch field.kind {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ // allocating a new int here has fewer side effects (doesn't update the original struct)
+ // but it's a wasteful allocation
+ // the old method might work if we just cast the temporary int/uint to the target type
+ v = reflect.New(v.Type()).Elem()
+ v.SetInt(int64(length))
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ v = reflect.New(v.Type()).Elem()
+ v.SetUint(uint64(length))
+ default:
+ panic(fmt.Sprintf("sizeof field is not int or uint type: %s, %s", field.Name, v.Type()))
+ }
+ }
+ if n, err := field.Pack(buf[pos:], v, length, options); err != nil {
+ return n, err
+ } else {
+ pos += n
+ }
+ }
+ return pos, nil
+}
+
+func (f Fields) Unpack(r io.Reader, val reflect.Value, options *Options) error {
+ for val.Kind() == reflect.Ptr {
+ val = val.Elem()
+ }
+ var tmp [8]byte
+ var buf []byte
+ for i, field := range f {
+ if !field.CanSet {
+ continue
+ }
+ v := val.Field(i)
+ length := field.Len
+ if field.Sizefrom != nil {
+ length = f.sizefrom(val, field.Sizefrom)
+ }
+ if v.Kind() == reflect.Ptr && !v.Elem().IsValid() {
+ v.Set(reflect.New(v.Type().Elem()))
+ }
+ if field.Type == Struct {
+ if field.Slice {
+ vals := reflect.MakeSlice(v.Type(), length, length)
+ for i := 0; i < length; i++ {
+ v := vals.Index(i)
+ fields, err := parseFields(v)
+ if err != nil {
+ return err
+ }
+ if err := fields.Unpack(r, v, options); err != nil {
+ return err
+ }
+ }
+ v.Set(vals)
+ } else {
+ // TODO: DRY (we repeat the inner loop above)
+ fields, err := parseFields(v)
+ if err != nil {
+ return err
+ }
+ if err := fields.Unpack(r, v, options); err != nil {
+ return err
+ }
+ }
+ continue
+ } else {
+ typ := field.Type.Resolve(options)
+ if typ == CustomType {
+ if err := v.Addr().Interface().(Custom).Unpack(r, length, options); err != nil {
+ return err
+ }
+ } else {
+ size := length * field.Type.Resolve(options).Size()
+ if size < 8 {
+ buf = tmp[:size]
+ } else {
+ buf = make([]byte, size)
+ }
+ if _, err := io.ReadFull(r, buf); err != nil {
+ return err
+ }
+ err := field.Unpack(buf[:size], v, length, options)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/lunixbochs/struc/fields_test.go b/vendor/github.com/lunixbochs/struc/fields_test.go
new file mode 100644
index 0000000..850e377
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/fields_test.go
@@ -0,0 +1,59 @@
+package struc
+
+import (
+ "bytes"
+ "reflect"
+ "testing"
+)
+
+var refVal = reflect.ValueOf(reference)
+
+func TestFieldsParse(t *testing.T) {
+ if _, err := parseFields(refVal); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestFieldsString(t *testing.T) {
+ fields, _ := parseFields(refVal)
+ fields.String()
+}
+
+type sizefromStruct struct {
+ Size1 uint `struc:"sizeof=Var1"`
+ Var1 []byte
+ Size2 int `struc:"sizeof=Var2"`
+ Var2 []byte
+}
+
+func TestFieldsSizefrom(t *testing.T) {
+ var test = sizefromStruct{
+ Var1: []byte{1, 2, 3},
+ Var2: []byte{4, 5, 6},
+ }
+ var buf bytes.Buffer
+ err := Pack(&buf, &test)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = Unpack(&buf, &test)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+type sizefromStructBad struct {
+ Size1 string `struc:"sizeof=Var1"`
+ Var1 []byte
+}
+
+func TestFieldsSizefromBad(t *testing.T) {
+ var test = &sizefromStructBad{Var1: []byte{1, 2, 3}}
+ var buf bytes.Buffer
+ defer func() {
+ if err := recover(); err == nil {
+ t.Fatal("failed to panic on bad sizeof type")
+ }
+ }()
+ Pack(&buf, &test)
+}
diff --git a/vendor/github.com/lunixbochs/struc/legacy.go b/vendor/github.com/lunixbochs/struc/legacy.go
new file mode 100644
index 0000000..5baf70d
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/legacy.go
@@ -0,0 +1,16 @@
+package struc
+
+import (
+ "encoding/binary"
+ "io"
+)
+
+// Deprecated. Use PackWithOptions.
+func PackWithOrder(w io.Writer, data interface{}, order binary.ByteOrder) error {
+ return PackWithOptions(w, data, &Options{Order: order})
+}
+
+// Deprecated. Use UnpackWithOptions.
+func UnpackWithOrder(r io.Reader, data interface{}, order binary.ByteOrder) error {
+ return UnpackWithOptions(r, data, &Options{Order: order})
+}
diff --git a/vendor/github.com/lunixbochs/struc/packable_test.go b/vendor/github.com/lunixbochs/struc/packable_test.go
new file mode 100644
index 0000000..ec2bed9
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/packable_test.go
@@ -0,0 +1,123 @@
+package struc
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+)
+
+var packableReference = []byte{
+ 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 5, 0, 6, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16,
+ 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24,
+}
+
+func TestPackable(t *testing.T) {
+ var (
+ buf bytes.Buffer
+
+ i8 int8 = 1
+ i16 int16 = 2
+ i32 int32 = 3
+ i64 int64 = 4
+ u8 uint8 = 5
+ u16 uint16 = 6
+ u32 uint32 = 7
+ u64 uint64 = 8
+
+ u8a = [8]uint8{9, 10, 11, 12, 13, 14, 15, 16}
+ u16a = [8]uint16{17, 18, 19, 20, 21, 22, 23, 24}
+ )
+ // pack tests
+ if err := Pack(&buf, i8); err != nil {
+ t.Fatal(err)
+ }
+ if err := Pack(&buf, i16); err != nil {
+ t.Fatal(err)
+ }
+ if err := Pack(&buf, i32); err != nil {
+ t.Fatal(err)
+ }
+ if err := Pack(&buf, i64); err != nil {
+ t.Fatal(err)
+ }
+ if err := Pack(&buf, u8); err != nil {
+ t.Fatal(err)
+ }
+ if err := Pack(&buf, u16); err != nil {
+ t.Fatal(err)
+ }
+ if err := Pack(&buf, u32); err != nil {
+ t.Fatal(err)
+ }
+ if err := Pack(&buf, u64); err != nil {
+ t.Fatal(err)
+ }
+ if err := Pack(&buf, u8a[:]); err != nil {
+ t.Fatal(err)
+ }
+ if err := Pack(&buf, u16a[:]); err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(buf.Bytes(), packableReference) {
+ fmt.Println(buf.Bytes())
+ fmt.Println(packableReference)
+ t.Fatal("Packable Pack() did not match reference.")
+ }
+ // unpack tests
+ i8 = 0
+ i16 = 0
+ i32 = 0
+ i64 = 0
+ u8 = 0
+ u16 = 0
+ u32 = 0
+ u64 = 0
+ if err := Unpack(&buf, &i8); err != nil {
+ t.Fatal(err)
+ }
+ if err := Unpack(&buf, &i16); err != nil {
+ t.Fatal(err)
+ }
+ if err := Unpack(&buf, &i32); err != nil {
+ t.Fatal(err)
+ }
+ if err := Unpack(&buf, &i64); err != nil {
+ t.Fatal(err)
+ }
+ if err := Unpack(&buf, &u8); err != nil {
+ t.Fatal(err)
+ }
+ if err := Unpack(&buf, &u16); err != nil {
+ t.Fatal(err)
+ }
+ if err := Unpack(&buf, &u32); err != nil {
+ t.Fatal(err)
+ }
+ if err := Unpack(&buf, &u64); err != nil {
+ t.Fatal(err)
+ }
+ if err := Unpack(&buf, u8a[:]); err != nil {
+ t.Fatal(err)
+ }
+ if err := Unpack(&buf, u16a[:]); err != nil {
+ t.Fatal(err)
+ }
+ // unpack checks
+ if i8 != 1 || i16 != 2 || i32 != 3 || i64 != 4 {
+ t.Fatal("Signed integer unpack failed.")
+ }
+ if u8 != 5 || u16 != 6 || u32 != 7 || u64 != 8 {
+ t.Fatal("Unsigned integer unpack failed.")
+ }
+ for i := 0; i < 8; i++ {
+ if u8a[i] != uint8(i+9) {
+ t.Fatal("uint8 array unpack failed.")
+ }
+ }
+ for i := 0; i < 8; i++ {
+ if u16a[i] != uint16(i+17) {
+ t.Fatal("uint16 array unpack failed.")
+ }
+ }
+}
diff --git a/vendor/github.com/lunixbochs/struc/packer.go b/vendor/github.com/lunixbochs/struc/packer.go
new file mode 100644
index 0000000..a3a91a2
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/packer.go
@@ -0,0 +1,13 @@
+package struc
+
+import (
+ "io"
+ "reflect"
+)
+
+type Packer interface {
+ Pack(buf []byte, val reflect.Value, options *Options) (int, error)
+ Unpack(r io.Reader, val reflect.Value, options *Options) error
+ Sizeof(val reflect.Value, options *Options) int
+ String() string
+}
diff --git a/vendor/github.com/lunixbochs/struc/parse.go b/vendor/github.com/lunixbochs/struc/parse.go
new file mode 100644
index 0000000..5a30d53
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/parse.go
@@ -0,0 +1,217 @@
+package struc
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "reflect"
+ "regexp"
+ "strconv"
+ "strings"
+ "sync"
+)
+
+// struc:"int32,big,sizeof=Data"
+
+var tagWordsRe = regexp.MustCompile(`(\[|\b)[^"]+\b+$`)
+
+type strucTag struct {
+ Type string
+ Order binary.ByteOrder
+ Sizeof string
+}
+
+func parseStrucTag(tag reflect.StructTag) *strucTag {
+ t := &strucTag{
+ Order: binary.BigEndian,
+ }
+ tagStr := tag.Get("struc")
+ if tagStr == "" {
+ // someone's going to typo this (I already did once)
+ // sorry if you made a module actually using this tag
+ // and you're mad at me now
+ tagStr = tag.Get("struct")
+ }
+ for _, s := range strings.Split(tagStr, ",") {
+ if strings.HasPrefix(s, "sizeof=") {
+ tmp := strings.SplitN(s, "=", 2)
+ t.Sizeof = tmp[1]
+ } else if s == "big" {
+ t.Order = binary.BigEndian
+ } else if s == "little" {
+ t.Order = binary.LittleEndian
+ } else {
+ t.Type = s
+ }
+ }
+ return t
+}
+
+var typeLenRe = regexp.MustCompile(`^\[(\d*)\]`)
+
+func parseField(f reflect.StructField) (fd *Field, err error) {
+ tag := parseStrucTag(f.Tag)
+ var ok bool
+ fd = &Field{
+ Name: f.Name,
+ Len: 1,
+ Order: tag.Order,
+ Slice: false,
+ kind: f.Type.Kind(),
+ }
+ switch fd.kind {
+ case reflect.Array:
+ fd.Slice = true
+ fd.Array = true
+ fd.Len = f.Type.Len()
+ fd.kind = f.Type.Elem().Kind()
+ case reflect.Slice:
+ fd.Slice = true
+ fd.Len = -1
+ fd.kind = f.Type.Elem().Kind()
+ case reflect.Ptr:
+ fd.Ptr = true
+ fd.kind = f.Type.Elem().Kind()
+ }
+ // check for custom types
+ tmp := reflect.New(f.Type)
+ if _, ok := tmp.Interface().(Custom); ok {
+ fd.Type = CustomType
+ return
+ }
+ var defTypeOk bool
+ fd.defType, defTypeOk = reflectTypeMap[fd.kind]
+ // find a type in the struct tag
+ pureType := typeLenRe.ReplaceAllLiteralString(tag.Type, "")
+ if fd.Type, ok = typeLookup[pureType]; ok {
+ fd.Len = 1
+ match := typeLenRe.FindAllStringSubmatch(tag.Type, -1)
+ if len(match) > 0 && len(match[0]) > 1 {
+ fd.Slice = true
+ first := match[0][1]
+ // Field.Len = -1 indicates a []slice
+ if first == "" {
+ fd.Len = -1
+ } else {
+ fd.Len, err = strconv.Atoi(first)
+ }
+ }
+ return
+ }
+ // the user didn't specify a type
+ switch f.Type {
+ case reflect.TypeOf(Size_t(0)):
+ fd.Type = SizeType
+ case reflect.TypeOf(Off_t(0)):
+ fd.Type = OffType
+ default:
+ if defTypeOk {
+ fd.Type = fd.defType
+ } else {
+ err = errors.New("struc: Could not find field type.")
+ }
+ }
+ return
+}
+
+func parseFieldsLocked(v reflect.Value) (Fields, error) {
+ // we need to repeat this logic because parseFields() below can't be recursively called due to locking
+ for v.Kind() == reflect.Ptr {
+ v = v.Elem()
+ }
+ t := v.Type()
+ if v.NumField() < 1 {
+ return nil, errors.New("struc: Struct has no fields.")
+ }
+ sizeofMap := make(map[string][]int)
+ fields := make(Fields, 0, v.NumField())
+ for i := 0; i < t.NumField(); i++ {
+ field := t.Field(i)
+ f, err := parseField(field)
+ if err != nil {
+ return nil, err
+ }
+ f.CanSet = v.Field(i).CanSet()
+ if !f.CanSet {
+ continue
+ }
+ f.Index = i
+ tag := parseStrucTag(field.Tag)
+ if tag.Sizeof != "" {
+ target, ok := t.FieldByName(tag.Sizeof)
+ if !ok {
+ return nil, fmt.Errorf("struc: `sizeof=%s` field does not exist", tag.Sizeof)
+ }
+ f.Sizeof = target.Index
+ sizeofMap[tag.Sizeof] = field.Index
+ }
+ if sizefrom, ok := sizeofMap[field.Name]; ok {
+ f.Sizefrom = sizefrom
+ }
+ if f.Len == -1 && f.Sizefrom == nil {
+ return nil, fmt.Errorf("struc: field `%s` is a slice with no length or sizeof field", field.Name)
+ }
+ // recurse into nested structs
+ // TODO: handle loops (probably by indirecting the []Field and putting pointer in cache)
+ if f.Type == Struct {
+ typ := field.Type
+ if f.Ptr {
+ typ = typ.Elem()
+ }
+ if f.Slice {
+ typ = typ.Elem()
+ }
+ f.Fields, err = parseFieldsLocked(reflect.New(typ))
+ if err != nil {
+ return nil, err
+ }
+ }
+ fields = append(fields, f)
+ }
+ return fields, nil
+}
+
+var fieldCache = make(map[reflect.Type]Fields)
+var fieldCacheLock sync.RWMutex
+var parseLock sync.Mutex
+
+func fieldCacheLookup(t reflect.Type) Fields {
+ fieldCacheLock.RLock()
+ defer fieldCacheLock.RUnlock()
+ if cached, ok := fieldCache[t]; ok {
+ return cached
+ }
+ return nil
+}
+
+func parseFields(v reflect.Value) (Fields, error) {
+ for v.Kind() == reflect.Ptr {
+ v = v.Elem()
+ }
+ t := v.Type()
+
+ // fast path: hopefully the field parsing is already cached
+ if cached := fieldCacheLookup(t); cached != nil {
+ return cached, nil
+ }
+
+ // hold a global lock so multiple goroutines can't parse (the same) fields at once
+ parseLock.Lock()
+ defer parseLock.Unlock()
+
+ // check cache a second time, in case parseLock was just released by
+ // another thread who filled the cache for us
+ if cached := fieldCacheLookup(t); cached != nil {
+ return cached, nil
+ }
+
+ // no luck, time to parse and fill the cache ourselves
+ fields, err := parseFieldsLocked(v)
+ if err != nil {
+ return nil, err
+ }
+ fieldCacheLock.Lock()
+ fieldCache[t] = fields
+ fieldCacheLock.Unlock()
+ return fields, nil
+}
diff --git a/vendor/github.com/lunixbochs/struc/parse_test.go b/vendor/github.com/lunixbochs/struc/parse_test.go
new file mode 100644
index 0000000..861fdd1
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/parse_test.go
@@ -0,0 +1,62 @@
+package struc
+
+import (
+ "bytes"
+ "reflect"
+ "testing"
+)
+
+func parseTest(data interface{}) error {
+ _, err := parseFields(reflect.ValueOf(data))
+ return err
+}
+
+type empty struct{}
+
+func TestEmptyStruc(t *testing.T) {
+ if err := parseTest(&empty{}); err == nil {
+ t.Fatal("failed to error on empty struct")
+ }
+}
+
+type chanStruct struct {
+ Test chan int
+}
+
+func TestChanError(t *testing.T) {
+ if err := parseTest(&chanStruct{}); err == nil {
+ // TODO: should probably ignore channel fields
+ t.Fatal("failed to error on struct containing channel")
+ }
+}
+
+type badSizeof struct {
+ Size int `struc:"sizeof=Bad"`
+}
+
+func TestBadSizeof(t *testing.T) {
+ if err := parseTest(&badSizeof{}); err == nil {
+ t.Fatal("failed to error on missing Sizeof target")
+ }
+}
+
+type missingSize struct {
+ Test []byte
+}
+
+func TestMissingSize(t *testing.T) {
+ if err := parseTest(&missingSize{}); err == nil {
+ t.Fatal("failed to error on missing field size")
+ }
+}
+
+type badNested struct {
+ Empty empty
+}
+
+func TestNestedParseError(t *testing.T) {
+ var buf bytes.Buffer
+ if err := Pack(&buf, &badNested{}); err == nil {
+ t.Fatal("failed to error on bad nested struct")
+ }
+}
diff --git a/vendor/github.com/lunixbochs/struc/struc.go b/vendor/github.com/lunixbochs/struc/struc.go
new file mode 100644
index 0000000..3d85fe3
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/struc.go
@@ -0,0 +1,117 @@
+package struc
+
+import (
+ "encoding/binary"
+ "fmt"
+ "io"
+ "reflect"
+)
+
+type Options struct {
+ ByteAlign int
+ PtrSize int
+ Order binary.ByteOrder
+}
+
+func (o *Options) Validate() error {
+ if o.PtrSize == 0 {
+ o.PtrSize = 32
+ } else {
+ switch o.PtrSize {
+ case 8, 16, 32, 64:
+ default:
+ return fmt.Errorf("Invalid Options.PtrSize: %d. Must be in (8, 16, 32, 64)", o.PtrSize)
+ }
+ }
+ return nil
+}
+
+var emptyOptions = &Options{}
+
+func prep(data interface{}) (reflect.Value, Packer, error) {
+ value := reflect.ValueOf(data)
+ for value.Kind() == reflect.Ptr {
+ next := value.Elem().Kind()
+ if next == reflect.Struct || next == reflect.Ptr {
+ value = value.Elem()
+ } else {
+ break
+ }
+ }
+ switch value.Kind() {
+ case reflect.Struct:
+ fields, err := parseFields(value)
+ return value, fields, err
+ default:
+ if !value.IsValid() {
+ return reflect.Value{}, nil, fmt.Errorf("Invalid reflect.Value for %+v", data)
+ }
+ if c, ok := data.(Custom); ok {
+ return value, customFallback{c}, nil
+ }
+ return value, binaryFallback(value), nil
+ }
+}
+
+func Pack(w io.Writer, data interface{}) error {
+ return PackWithOptions(w, data, nil)
+}
+
+func PackWithOptions(w io.Writer, data interface{}, options *Options) error {
+ if options == nil {
+ options = emptyOptions
+ }
+ if err := options.Validate(); err != nil {
+ return err
+ }
+ val, packer, err := prep(data)
+ if err != nil {
+ return err
+ }
+ if val.Type().Kind() == reflect.String {
+ val = val.Convert(reflect.TypeOf([]byte{}))
+ }
+ size := packer.Sizeof(val, options)
+ buf := make([]byte, size)
+ if _, err := packer.Pack(buf, val, options); err != nil {
+ return err
+ }
+ _, err = w.Write(buf)
+ return err
+}
+
+func Unpack(r io.Reader, data interface{}) error {
+ return UnpackWithOptions(r, data, nil)
+}
+
+func UnpackWithOptions(r io.Reader, data interface{}, options *Options) error {
+ if options == nil {
+ options = emptyOptions
+ }
+ if err := options.Validate(); err != nil {
+ return err
+ }
+ val, packer, err := prep(data)
+ if err != nil {
+ return err
+ }
+ return packer.Unpack(r, val, options)
+}
+
+func Sizeof(data interface{}) (int, error) {
+ return SizeofWithOptions(data, nil)
+}
+
+func SizeofWithOptions(data interface{}, options *Options) (int, error) {
+ if options == nil {
+ options = emptyOptions
+ }
+ if err := options.Validate(); err != nil {
+ return 0, err
+ }
+ val, packer, err := prep(data)
+ if err != nil {
+ return 0, err
+ }
+ return packer.Sizeof(val, options), nil
+}
diff --git a/vendor/github.com/lunixbochs/struc/struc_test.go b/vendor/github.com/lunixbochs/struc/struc_test.go
new file mode 100644
index 0000000..939c3e3
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/struc_test.go
@@ -0,0 +1,197 @@
+package struc
+
+import (
+ "bytes"
+ "encoding/binary"
+ "reflect"
+ "testing"
+)
+
+type Nested struct {
+ Test2 int `struc:"int8"`
+}
+
+type Example struct {
+ Pad []byte `struc:"[5]pad"` // 00 00 00 00 00
+ I8f int `struc:"int8"` // 01
+ I16f int `struc:"int16"` // 00 02
+ I32f int `struc:"int32"` // 00 00 00 03
+ I64f int `struc:"int64"` // 00 00 00 00 00 00 00 04
+ U8f int `struc:"uint8,little"` // 05
+ U16f int `struc:"uint16,little"` // 06 00
+ U32f int `struc:"uint32,little"` // 07 00 00 00
+ U64f int `struc:"uint64,little"` // 08 00 00 00 00 00 00 00
+ Boolf int `struc:"bool"` // 01
+ Byte4f []byte `struc:"[4]byte"` // "abcd"
+
+ I8 int8 // 09
+ I16 int16 // 00 0a
+ I32 int32 // 00 00 00 0b
+ I64 int64 // 00 00 00 00 00 00 00 0c
+ U8 uint8 `struc:"little"` // 0d
+ U16 uint16 `struc:"little"` // 0e 00
+ U32 uint32 `struc:"little"` // 0f 00 00 00
+ U64 uint64 `struc:"little"` // 10 00 00 00 00 00 00 00
+ BoolT bool // 01
+ BoolF bool // 00
+ Byte4 [4]byte // "efgh"
+ Float1 float32 // 41 a0 00 00
+ Float2 float64 // 41 35 00 00 00 00 00 00
+
+ Size int `struc:"sizeof=Str,little"` // 0a 00 00 00
+ Str string `struc:"[]byte"` // "ijklmnopqr"
+ Strb string `struc:"[4]byte"` // "stuv"
+
+ Size2 int `struc:"uint8,sizeof=Str2"` // 04
+ Str2 string // "1234"
+
+ Size3 int `struc:"uint8,sizeof=Bstr"` // 04
+ Bstr []byte // "5678"
+
+ Nested Nested // 00 00 00 01
+ NestedP *Nested // 00 00 00 02
+ TestP64 *int `struc:"int64"` // 00 00 00 05
+
+ NestedSize int `struc:"sizeof=NestedA"` // 00 00 00 02
+ NestedA []Nested // [00 00 00 03, 00 00 00 04]
+
+ CustomTypeSize Int3 `struc:"sizeof=CustomTypeSizeArr"` // 00 00 00 04
+ CustomTypeSizeArr []byte // "ABCD"
+}
+
+var five = 5
+
+var reference = &Example{
+ nil,
+ 1, 2, 3, 4, 5, 6, 7, 8, 0, []byte{'a', 'b', 'c', 'd'},
+ 9, 10, 11, 12, 13, 14, 15, 16, true, false, [4]byte{'e', 'f', 'g', 'h'},
+ 20, 21,
+ 10, "ijklmnopqr", "stuv",
+ 4, "1234",
+ 4, []byte("5678"),
+ Nested{1}, &Nested{2}, &five,
+ 6, []Nested{{3}, {4}, {5}, {6}, {7}, {8}},
+ Int3(4), []byte("ABCD"),
+}
+
+var referenceBytes = []byte{
+ 0, 0, 0, 0, 0, // pad(5)
+ 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, // fake int8-int64(1-4)
+ 5, 6, 0, 7, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, // fake little-endian uint8-uint64(5-8)
+ 0, // fake bool(0)
+ 'a', 'b', 'c', 'd', // fake [4]byte
+
+ 9, 0, 10, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 12, // real int8-int64(9-12)
+ 13, 14, 0, 15, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, // real little-endian uint8-uint64(13-16)
+ 1, 0, // real bool(1), bool(0)
+ 'e', 'f', 'g', 'h', // real [4]byte
+ 65, 160, 0, 0, // real float32(20)
+ 64, 53, 0, 0, 0, 0, 0, 0, // real float64(21)
+
+ 10, 0, 0, 0, // little-endian int32(10) sizeof=Str
+ 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', // Str
+ 's', 't', 'u', 'v', // fake string([4]byte)
+ 04, '1', '2', '3', '4', // real string
+ 04, '5', '6', '7', '8', // fake []byte(string)
+
+ 1, 2, // Nested{1}, Nested{2}
+ 0, 0, 0, 0, 0, 0, 0, 5, // &five
+
+ 0, 0, 0, 6, // int32(6)
+ 3, 4, 5, 6, 7, 8, // [Nested{3}, ...Nested{8}]
+
+ 0, 0, 4, 'A', 'B', 'C', 'D', // Int3(4), []byte("ABCD")
+}
+
+func TestCodec(t *testing.T) {
+ var buf bytes.Buffer
+ if err := Pack(&buf, reference); err != nil {
+ t.Fatal(err)
+ }
+ out := &Example{}
+ if err := Unpack(&buf, out); err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(reference, out) {
+ t.Fatal("encode/decode failed")
+ }
+}
+
+func TestEncode(t *testing.T) {
+ var buf bytes.Buffer
+ if err := Pack(&buf, reference); err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(buf.Bytes(), referenceBytes) {
+ t.Fatal("encode failed")
+ }
+}
+
+func TestDecode(t *testing.T) {
+ buf := bytes.NewReader(referenceBytes)
+ out := &Example{}
+ if err := Unpack(buf, out); err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(reference, out) {
+ t.Fatal("decode failed")
+ }
+}
+
+func TestSizeof(t *testing.T) {
+ size, err := Sizeof(reference)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if size != len(referenceBytes) {
+ t.Fatal("sizeof failed")
+ }
+}
+
+type ExampleEndian struct {
+ T int `struc:"int16,big"`
+}
+
+func TestEndianSwap(t *testing.T) {
+ var buf bytes.Buffer
+ big := &ExampleEndian{1}
+ if err := PackWithOrder(&buf, big, binary.BigEndian); err != nil {
+ t.Fatal(err)
+ }
+ little := &ExampleEndian{}
+ if err := UnpackWithOrder(&buf, little, binary.LittleEndian); err != nil {
+ t.Fatal(err)
+ }
+ if little.T != 256 {
+ t.Fatal("big -> little conversion failed")
+ }
+}
+
+func TestNilValue(t *testing.T) {
+ var buf bytes.Buffer
+ if err := Pack(&buf, nil); err == nil {
+ t.Fatal("failed throw error for bad struct value")
+ }
+ if err := Unpack(&buf, nil); err == nil {
+ t.Fatal("failed throw error for bad struct value")
+ }
+ if _, err := Sizeof(nil); err == nil {
+ t.Fatal("failed to throw error for bad struct value")
+ }
+}
+
+type sliceUnderrun struct {
+ Str string `struc:"[10]byte"`
+ Arr []uint16 `struc:"[10]uint16"`
+}
+
+func TestSliceUnderrun(t *testing.T) {
+ var buf bytes.Buffer
+ v := sliceUnderrun{
+ Str: "foo",
+ Arr: []uint16{1, 2, 3},
+ }
+ if err := Pack(&buf, &v); err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/vendor/github.com/lunixbochs/struc/types.go b/vendor/github.com/lunixbochs/struc/types.go
new file mode 100644
index 0000000..6ca97f4
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/types.go
@@ -0,0 +1,136 @@
+package struc
+
+import (
+ "fmt"
+ "reflect"
+)
+
+type Type int
+
+const (
+ Invalid Type = iota
+ Pad
+ Bool
+ Int
+ Int8
+ Uint8
+ Int16
+ Uint16
+ Int32
+ Uint32
+ Int64
+ Uint64
+ Float32
+ Float64
+ String
+ Struct
+ Ptr
+
+ SizeType
+ OffType
+ CustomType
+)
+
+func (t Type) Resolve(options *Options) Type {
+ switch t {
+ case OffType:
+ switch options.PtrSize {
+ case 8:
+ return Int8
+ case 16:
+ return Int16
+ case 32:
+ return Int32
+ case 64:
+ return Int64
+ default:
+ panic(fmt.Sprintf("unsupported ptr bits: %d", options.PtrSize))
+ }
+ case SizeType:
+ switch options.PtrSize {
+ case 8:
+ return Uint8
+ case 16:
+ return Uint16
+ case 32:
+ return Uint32
+ case 64:
+ return Uint64
+ default:
+ panic(fmt.Sprintf("unsupported ptr bits: %d", options.PtrSize))
+ }
+ }
+ return t
+}
+
+func (t Type) String() string {
+ return typeNames[t]
+}
+
+func (t Type) Size() int {
+ switch t {
+ case SizeType, OffType:
+ panic("Size_t/Off_t types must be converted to another type using options.PtrSize")
+ case Pad, String, Int8, Uint8, Bool:
+ return 1
+ case Int16, Uint16:
+ return 2
+ case Int32, Uint32, Float32:
+ return 4
+ case Int64, Uint64, Float64:
+ return 8
+ default:
+ panic("Cannot resolve size of type:" + t.String())
+ }
+}
+
+var typeLookup = map[string]Type{
+ "pad": Pad,
+ "bool": Bool,
+ "byte": Uint8,
+ "int8": Int8,
+ "uint8": Uint8,
+ "int16": Int16,
+ "uint16": Uint16,
+ "int32": Int32,
+ "uint32": Uint32,
+ "int64": Int64,
+ "uint64": Uint64,
+ "float32": Float32,
+ "float64": Float64,
+
+ "size_t": SizeType,
+ "off_t": OffType,
+}
+
+var typeNames = map[Type]string{
+ CustomType: "Custom",
+}
+
+func init() {
+ for name, enum := range typeLookup {
+ typeNames[enum] = name
+ }
+}
+
+type Size_t uint64
+type Off_t int64
+
+var reflectTypeMap = map[reflect.Kind]Type{
+ reflect.Bool: Bool,
+ reflect.Int8: Int8,
+ reflect.Int16: Int16,
+ reflect.Int: Int32,
+ reflect.Int32: Int32,
+ reflect.Int64: Int64,
+ reflect.Uint8: Uint8,
+ reflect.Uint16: Uint16,
+ reflect.Uint: Uint32,
+ reflect.Uint32: Uint32,
+ reflect.Uint64: Uint64,
+ reflect.Float32: Float32,
+ reflect.Float64: Float64,
+ reflect.String: String,
+ reflect.Struct: Struct,
+ reflect.Ptr: Ptr,
+}
diff --git a/vendor/github.com/lunixbochs/struc/types_test.go b/vendor/github.com/lunixbochs/struc/types_test.go
new file mode 100644
index 0000000..3b33e8f
--- /dev/null
+++ b/vendor/github.com/lunixbochs/struc/types_test.go
@@ -0,0 +1,53 @@
+package struc
+
+import (
+ "bytes"
+ "testing"
+)
+
+func TestBadType(t *testing.T) {
+ defer func() { recover() }()
+ Type(-1).Size()
+ t.Fatal("failed to panic for invalid Type.Size()")
+}
+
+func TestTypeString(t *testing.T) {
+ if Pad.String() != "pad" {
+ t.Fatal("type string representation failed")
+ }
+}
+
+type sizeOffTest struct {
+ Size Size_t
+ Off Off_t
+}
+
+func TestSizeOffTypes(t *testing.T) {
+ bits := []int{8, 16, 32, 64}
+ var buf bytes.Buffer
+ test := &sizeOffTest{1, 2}
+ for _, b := range bits {
+ if err := PackWithOptions(&buf, test, &Options{PtrSize: b}); err != nil {
+ t.Fatal(err)
+ }
+ }
+ reference := []byte{
+ 1, 2,
+ 0, 1, 0, 2,
+ 0, 0, 0, 1, 0, 0, 0, 2,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2,
+ }
+ if !bytes.Equal(reference, buf.Bytes()) {
+ t.Errorf("reference != bytes: %v", reference, buf.Bytes())
+ }
+ reader := bytes.NewReader(buf.Bytes())
+ for _, b := range bits {
+ out := &sizeOffTest{}
+ if err := UnpackWithOptions(reader, out, &Options{PtrSize: b}); err != nil {
+ t.Fatal(err)
+ }
+ if out.Size != 1 || out.Off != 2 {
+ t.Errorf("Size_t/Off_t mismatch: {%d, %d}\n%v", out.Size, out.Off, buf.Bytes())
+ }
+ }
+}
diff --git a/vendor/github.com/onsi/gomega/.gitignore b/vendor/github.com/onsi/gomega/.gitignore
new file mode 100644
index 0000000..720c13c
--- /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 0000000..9bc3fd0
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/.travis.yml
@@ -0,0 +1,11 @@
+language: go
+go:
+ - 1.6
+ - 1.7
+
+install:
+ - go get -v ./...
+ - go get github.com/onsi/ginkgo
+ - go install github.com/onsi/ginkgo/ginkgo
+
+script: $HOME/gopath/bin/ginkgo -r --randomizeAllSpecs --failOnPending --randomizeSuites --race
diff --git a/vendor/github.com/onsi/gomega/CHANGELOG.md b/vendor/github.com/onsi/gomega/CHANGELOG.md
new file mode 100644
index 0000000..0c5ede5
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/CHANGELOG.md
@@ -0,0 +1,70 @@
+## HEAD
+
+Improvements:
+
+- Added `BeSent` which attempts to send a value down a channel and fails if the attempt blocks. Can be paired with `Eventually` to safely send a value down a channel with a timeout.
+- `Ω`, `Expect`, `Eventually`, and `Consistently` now immediately `panic` if there is no registered fail handler. This is always a mistake that can hide failing tests.
+- `Receive()` no longer errors when passed a closed channel, it's perfectly fine to attempt to read from a closed channel so Ω(c).Should(Receive()) always fails and Ω(c).ShoudlNot(Receive()) always passes with a closed channel.
+- Added `HavePrefix` and `HaveSuffix` matchers.
+- `ghttp` can now handle concurrent requests.
+- Added `Succeed` which allows one to write `Ω(MyFunction()).Should(Succeed())`.
+- Improved `ghttp`'s behavior around failing assertions and panics:
+ - If a registered handler makes a failing assertion `ghttp` will return `500`.
+ - If a registered handler panics, `ghttp` will return `500` *and* fail the test. This is new behavior that may cause existing code to break. This code is almost certainly incorrect and creating a false positive.
+- `ghttp` servers can take an `io.Writer`. `ghttp` will write a line to the writer when each request arrives.
+- Added `WithTransform` matcher to allow munging input data before feeding into the relevant matcher
+- Added boolean `And`, `Or`, and `Not` matchers to allow creating composite matchers
+
+Bug Fixes:
+- gexec: `session.Wait` now uses `EventuallyWithOffset` to get the right line number in the failure.
+- `ContainElement` no longer bails if a passed-in matcher errors.
+
+## 1.0 (8/2/2014)
+
+No changes. Dropping "beta" from the version number.
+
+## 1.0.0-beta (7/8/2014)
+Breaking Changes:
+
+- Changed OmegaMatcher interface. Instead of having `Match` return failure messages, two new methods `FailureMessage` and `NegatedFailureMessage` are called instead.
+- Moved and renamed OmegaFailHandler to types.GomegaFailHandler and OmegaMatcher to types.GomegaMatcher. Any references to OmegaMatcher in any custom matchers will need to be changed to point to types.GomegaMatcher
+
+New Test-Support Features:
+
+- `ghttp`: supports testing http clients
+ - Provides a flexible fake http server
+ - Provides a collection of chainable http handlers that perform assertions.
+- `gbytes`: supports making ordered assertions against streams of data
+ - Provides a `gbytes.Buffer`
+ - Provides a `Say` matcher to perform ordered assertions against output data
+- `gexec`: supports testing external processes
+ - Provides support for building Go binaries
+ - Wraps and starts `exec.Cmd` commands
+ - Makes it easy to assert against stdout and stderr
+ - Makes it easy to send signals and wait for processes to exit
+ - Provides an `Exit` matcher to assert against exit code.
+
+DSL Changes:
+
+- `Eventually` and `Consistently` can accept `time.Duration` interval and polling inputs.
+- The default timeouts for `Eventually` and `Consistently` are now configurable.
+
+New Matchers:
+
+- `ConsistOf`: order-independent assertion against the elements of an array/slice or keys of a map.
+- `BeTemporally`: like `BeNumerically` but for `time.Time`
+- `HaveKeyWithValue`: asserts a map has a given key with the given value.
+
+Updated Matchers:
+
+- `Receive` matcher can take a matcher as an argument and passes only if the channel under test receives an objet that satisfies the passed-in matcher.
+- Matchers that implement `MatchMayChangeInTheFuture(actual interface{}) bool` can inform `Eventually` and/or `Consistently` when a match has no chance of changing status in the future. For example, `Receive` returns `false` when a channel is closed.
+
+Misc:
+
+- Start using semantic versioning
+- Start maintaining changelog
+
+Major refactor:
+
+- Pull out Gomega's internal to `internal`
diff --git a/vendor/github.com/onsi/gomega/LICENSE b/vendor/github.com/onsi/gomega/LICENSE
new file mode 100644
index 0000000..9415ee7
--- /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 0000000..9714f67
--- /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)](https://travis-ci.org/onsi/gomega)
+
+Jump straight to the [docs](http://onsi.github.io/gomega/) to learn about Gomega, including a list of [all available matchers](http://onsi.github.io/gomega/#provided-matchers).
+
+To discuss Gomega and get updates, join the [google group](https://groups.google.com/d/forum/ginkgo-and-gomega).
+
+## [Ginkgo](http://github.com/onsi/ginkgo): a BDD Testing Framework for Golang
+
+Learn more about Ginkgo [here](http://onsi.github.io/ginkgo/)
+
+## Community Matchers
+
+A collection of community matchers is available on the [wiki](https://github.com/onsi/gomega/wiki).
+
+## License
+
+Gomega is MIT-Licensed
+
+The `ConsistOf` matcher uses [goraph](https://github.com/amitkgupta/goraph) which is embedded in the source to simplify distribution. goraph has an MIT license.
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 0000000..a9d2651
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/format/format.go
@@ -0,0 +1,384 @@
+/*
+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
+
+// 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)
+ } else {
+ 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 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(b) - 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())
+ } else {
+ return fmt.Sprintf("%#v", value)
+ }
+ }
+}
+
+func formatString(object interface{}, indentation uint) string {
+ if indentation == 1 {
+ s := fmt.Sprintf("%s", object)
+ components := strings.Split(s, "\n")
+ result := ""
+ for i, component := range components {
+ if i == 0 {
+ result += component
+ } else {
+ result += Indent + component
+ }
+ if i < len(components)-1 {
+ result += "\n"
+ }
+ }
+
+ return fmt.Sprintf("%s", result)
+ } else {
+ return fmt.Sprintf("%q", object)
+ }
+}
+
+func formatSlice(v reflect.Value, indentation uint) string {
+ if v.Kind() == reflect.Slice && v.Type().Elem().Kind() == reflect.Uint8 && isPrintableString(string(v.Bytes())) {
+ return formatString(v.Bytes(), indentation)
+ }
+
+ l := v.Len()
+ result := make([]string, l)
+ longest := 0
+ for i := 0; i < l; i++ {
+ result[i] = formatValue(v.Index(i), indentation+1)
+ if len(result[i]) > longest {
+ longest = len(result[i])
+ }
+ }
+
+ if longest > longFormThreshold {
+ indenter := strings.Repeat(Indent, int(indentation))
+ return fmt.Sprintf("[\n%s%s,\n%s]", indenter+Indent, strings.Join(result, ",\n"+indenter+Indent), indenter)
+ } else {
+ return fmt.Sprintf("[%s]", strings.Join(result, ", "))
+ }
+}
+
+func formatMap(v reflect.Value, indentation uint) string {
+ l := v.Len()
+ result := make([]string, l)
+
+ longest := 0
+ for i, key := range v.MapKeys() {
+ value := v.MapIndex(key)
+ result[i] = fmt.Sprintf("%s: %s", formatValue(key, 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)
+ } else {
+ return fmt.Sprintf("{%s}", strings.Join(result, ", "))
+ }
+}
+
+func formatStruct(v reflect.Value, indentation uint) string {
+ t := v.Type()
+
+ l := v.NumField()
+ result := []string{}
+ longest := 0
+ for i := 0; i < l; i++ {
+ structField := t.Field(i)
+ fieldEntry := v.Field(i)
+ representation := fmt.Sprintf("%s: %s", structField.Name, formatValue(fieldEntry, indentation+1))
+ result = append(result, representation)
+ if len(representation) > longest {
+ longest = len(representation)
+ }
+ }
+ if longest > longFormThreshold {
+ indenter := strings.Repeat(Indent, int(indentation))
+ return fmt.Sprintf("{\n%s%s,\n%s}", indenter+Indent, strings.Join(result, ",\n"+indenter+Indent), indenter)
+ } else {
+ return fmt.Sprintf("{%s}", strings.Join(result, ", "))
+ }
+}
+
+func isNilValue(a reflect.Value) bool {
+ switch a.Kind() {
+ case reflect.Invalid:
+ return true
+ case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
+ return a.IsNil()
+ }
+
+ return false
+}
+
+/*
+Returns true when the string is entirely made of printable runes, false otherwise.
+*/
+func isPrintableString(str string) bool {
+ for _, runeValue := range str {
+ if !strconv.IsPrint(runeValue) {
+ return false
+ }
+ }
+ return true
+}
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 0000000..8e65a95
--- /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 0000000..a1a9031
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/format/format_test.go
@@ -0,0 +1,590 @@
+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() {
+ Ω(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() {
+ Ω(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"
+
+ Ω(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"
+
+ Ω(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"
+
+ Ω(MessageWithDiff(largeString, "to equal", smallString)).Should(Equal(expectedTruncatedStartSizeFailureMessage))
+ Ω(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"
+
+ Ω(MessageWithDiff(stringWithB, "to equal", stringWithZ)).Should(Equal(expectedTruncatedEndStringFailureMessage))
+ })
+ })
+
+ Describe("IndentString", func() {
+ It("should indent the string", func() {
+ Ω(IndentString("foo\n bar\nbaz", 2)).Should(Equal(" foo\n bar\n baz"))
+ })
+ })
+
+ Describe("Object", func() {
+ Describe("formatting boolean values", func() {
+ It("should give the type and format values correctly", func() {
+ Ω(Object(true, 1)).Should(match("bool", "true"))
+ Ω(Object(false, 1)).Should(match("bool", "false"))
+ })
+ })
+
+ Describe("formatting numbers", func() {
+ It("should give the type and format values correctly", func() {
+ Ω(Object(int(3), 1)).Should(match("int", "3"))
+ Ω(Object(int8(3), 1)).Should(match("int8", "3"))
+ Ω(Object(int16(3), 1)).Should(match("int16", "3"))
+ Ω(Object(int32(3), 1)).Should(match("int32", "3"))
+ Ω(Object(int64(3), 1)).Should(match("int64", "3"))
+
+ Ω(Object(uint(3), 1)).Should(match("uint", "3"))
+ Ω(Object(uint8(3), 1)).Should(match("uint8", "3"))
+ Ω(Object(uint16(3), 1)).Should(match("uint16", "3"))
+ Ω(Object(uint32(3), 1)).Should(match("uint32", "3"))
+ Ω(Object(uint64(3), 1)).Should(match("uint64", "3"))
+ })
+
+ It("should handle uintptr differently", func() {
+ Ω(Object(uintptr(3), 1)).Should(match("uintptr", "0x3"))
+ })
+ })
+
+ Describe("formatting channels", func() {
+ It("should give the type and format values correctly", func() {
+ c := make(chan<- bool, 3)
+ c <- true
+ c <- false
+ Ω(Object(c, 1)).Should(match("chan<- bool | len:2, cap:3", "%v", c))
+ })
+ })
+
+ Describe("formatting strings", func() {
+ It("should give the type and format values correctly", func() {
+ s := "a\nb\nc"
+ Ω(Object(s, 1)).Should(match("string", `a
+ b
+ c`))
+ })
+ })
+
+ Describe("formatting []byte slices", func() {
+ Context("when the slice is made of printable bytes", func() {
+ It("should present it as string", func() {
+ b := []byte("a b c")
+ Ω(Object(b, 1)).Should(matchRegexp(`\[\]uint8 \| len:5, cap:\d+`, `a b c`))
+ })
+ })
+ Context("when the slice contains non-printable bytes", func() {
+ It("should present it as slice", func() {
+ b := []byte("a b c\n\x01\x02\x03\xff\x1bH")
+ Ω(Object(b, 1)).Should(matchRegexp(`\[\]uint8 \| len:12, cap:\d+`, `\[97, 32, 98, 32, 99, 10, 1, 2, 3, 255, 27, 72\]`))
+ })
+ })
+ })
+
+ Describe("formatting functions", func() {
+ It("should give the type and format values correctly", func() {
+ f := func(a string, b []int) ([]byte, error) {
+ return []byte("abc"), nil
+ }
+ Ω(Object(f, 1)).Should(match("func(string, []int) ([]uint8, error)", "%v", f))
+ })
+ })
+
+ Describe("formatting pointers", func() {
+ It("should give the type and dereference the value to format it correctly", func() {
+ a := 3
+ Ω(Object(&a, 1)).Should(match(fmt.Sprintf("*int | %p", &a), "3"))
+ })
+
+ Context("when there are pointers to pointers...", func() {
+ It("should recursively deference the pointer until it gets to a value", func() {
+ a := 3
+ var b *int
+ var c **int
+ var d ***int
+ b = &a
+ c = &b
+ d = &c
+
+ Ω(Object(d, 1)).Should(match(fmt.Sprintf("***int | %p", d), "3"))
+ })
+ })
+
+ Context("when the pointer points to nil", func() {
+ It("should say nil and not explode", func() {
+ var a *AStruct
+ Ω(Object(a, 1)).Should(match("*format_test.AStruct | 0x0", "nil"))
+ })
+ })
+ })
+
+ Describe("formatting arrays", func() {
+ It("should give the type and format values correctly", func() {
+ w := [3]string{"Jed Bartlet", "Toby Ziegler", "CJ Cregg"}
+ Ω(Object(w, 1)).Should(match("[3]string", `["Jed Bartlet", "Toby Ziegler", "CJ Cregg"]`))
+ })
+
+ Context("with byte arrays", func() {
+ It("should give the type and format values correctly", func() {
+ w := [3]byte{17, 28, 19}
+ Ω(Object(w, 1)).Should(match("[3]uint8", `[17, 28, 19]`))
+ })
+ })
+ })
+
+ Describe("formatting slices", func() {
+ It("should include the length and capacity in the type information", func() {
+ s := make([]bool, 3, 4)
+ Ω(Object(s, 1)).Should(match("[]bool | len:3, cap:4", "[false, false, false]"))
+ })
+
+ Context("when the slice contains long entries", func() {
+ It("should format the entries with newlines", func() {
+ w := []string{"Josiah Edward Bartlet", "Toby Ziegler", "CJ Cregg"}
+ expected := `[
+ "Josiah Edward Bartlet",
+ "Toby Ziegler",
+ "CJ Cregg",
+ ]`
+ Ω(Object(w, 1)).Should(match("[]string | len:3, cap:3", expected))
+ })
+ })
+ })
+
+ Describe("formatting maps", func() {
+ It("should include the length in the type information", func() {
+ m := make(map[int]bool, 5)
+ m[3] = true
+ m[4] = false
+ Ω(Object(m, 1)).Should(matchRegexp(`map\[int\]bool \| len:2`, hashMatchingRegexp("3: true", "4: false")))
+ })
+
+ Context("when the slice contains long entries", func() {
+ It("should format the entries with newlines", func() {
+ m := map[string][]byte{}
+ m["Josiah Edward Bartlet"] = []byte("Martin Sheen")
+ m["Toby Ziegler"] = []byte("Richard Schiff")
+ m["CJ Cregg"] = []byte("Allison Janney")
+ expected := `{
+ ("Josiah Edward Bartlet": "Martin Sheen"|"Toby Ziegler": "Richard Schiff"|"CJ Cregg": "Allison Janney"),
+ ("Josiah Edward Bartlet": "Martin Sheen"|"Toby Ziegler": "Richard Schiff"|"CJ Cregg": "Allison Janney"),
+ ("Josiah Edward Bartlet": "Martin Sheen"|"Toby Ziegler": "Richard Schiff"|"CJ Cregg": "Allison Janney"),
+ }`
+ Ω(Object(m, 1)).Should(matchRegexp(`map\[string\]\[\]uint8 \| len:3`, expected))
+ })
+ })
+ })
+
+ Describe("formatting structs", func() {
+ It("should include the struct name and the field names", func() {
+ s := SimpleStruct{
+ Name: "Oswald",
+ Enumeration: 17,
+ Veritas: true,
+ Data: []byte("datum"),
+ secret: 1983,
+ }
+
+ Ω(Object(s, 1)).Should(match("format_test.SimpleStruct", `{Name: "Oswald", Enumeration: 17, Veritas: true, Data: "datum", secret: 1983}`))
+ })
+
+ Context("when the struct contains long entries", func() {
+ It("should format the entries with new lines", func() {
+ s := &SimpleStruct{
+ Name: "Mithrandir Gandalf Greyhame",
+ Enumeration: 2021,
+ Veritas: true,
+ Data: []byte("wizard"),
+ secret: 3,
+ }
+
+ Ω(Object(s, 1)).Should(match(fmt.Sprintf("*format_test.SimpleStruct | %p", s), `{
+ Name: "Mithrandir Gandalf Greyhame",
+ Enumeration: 2021,
+ Veritas: true,
+ Data: "wizard",
+ secret: 3,
+ }`))
+ })
+ })
+ })
+
+ Describe("formatting nil values", func() {
+ It("should print out nil", func() {
+ Ω(Object(nil, 1)).Should(match("nil", "nil"))
+ var typedNil *AStruct
+ Ω(Object(typedNil, 1)).Should(match("*format_test.AStruct | 0x0", "nil"))
+ var c chan<- bool
+ Ω(Object(c, 1)).Should(match("chan<- bool | len:0, cap:0", "nil"))
+ var s []string
+ Ω(Object(s, 1)).Should(match("[]string | len:0, cap:0", "nil"))
+ var m map[string]bool
+ Ω(Object(m, 1)).Should(match("map[string]bool | len:0", "nil"))
+ })
+ })
+
+ Describe("formatting aliased types", func() {
+ It("should print out the correct alias type", func() {
+ Ω(Object(StringAlias("alias"), 1)).Should(match("format_test.StringAlias", `alias`))
+ Ω(Object(ByteAlias("alias"), 1)).Should(matchRegexp(`format_test\.ByteAlias \| len:5, cap:\d+`, `alias`))
+ Ω(Object(IntAlias(3), 1)).Should(match("format_test.IntAlias", "3"))
+ })
+ })
+
+ Describe("handling nested things", func() {
+ It("should produce a correctly nested representation", func() {
+ s := ComplexStruct{
+ Strings: []string{"lots", "of", "short", "strings"},
+ SimpleThings: []*SimpleStruct{
+ {"short", 7, true, []byte("succinct"), 17},
+ {"something longer", 427, true, []byte("designed to wrap around nicely"), 30},
+ },
+ DataMaps: map[int]ByteAlias{
+ 17: ByteAlias("some substantially longer chunks of data"),
+ 1138: ByteAlias("that should make things wrap"),
+ },
+ }
+ expected := `{
+ Strings: \["lots", "of", "short", "strings"\],
+ SimpleThings: \[
+ {Name: "short", Enumeration: 7, Veritas: true, Data: "succinct", secret: 17},
+ {
+ Name: "something longer",
+ Enumeration: 427,
+ Veritas: true,
+ Data: "designed to wrap around nicely",
+ secret: 30,
+ },
+ \],
+ DataMaps: {
+ (17: "some substantially longer chunks of data"|1138: "that should make things wrap"),
+ (17: "some substantially longer chunks of data"|1138: "that should make things wrap"),
+ },
+ }`
+ Ω(Object(s, 1)).Should(matchRegexp(`format_test\.ComplexStruct`, expected))
+ })
+ })
+
+ Describe("formatting times", func() {
+ It("should format time as RFC3339", func() {
+ t := time.Date(2016, 10, 31, 9, 57, 23, 12345, time.UTC)
+ Ω(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`))
+
+ Ω(Object(s, 1)).Should(matchRegexp(`format_test\.SecretiveStruct`, expected))
+ })
+ })
+
+ Describe("Handling interfaces", func() {
+ It("should unpack the interface", func() {
+ outerHash := map[string]interface{}{}
+ innerHash := map[string]int{}
+
+ innerHash["inner"] = 3
+ outerHash["integer"] = 2
+ outerHash["map"] = innerHash
+
+ expected := hashMatchingRegexp(`"integer": 2`, `"map": {"inner": 3}`)
+ Ω(Object(outerHash, 1)).Should(matchRegexp(`map\[string\]interface {} \| len:2`, expected))
+ })
+ })
+
+ Describe("Handling recursive things", func() {
+ It("should not go crazy...", func() {
+ m := map[string]interface{}{}
+ m["integer"] = 2
+ m["map"] = m
+ Ω(Object(m, 1)).Should(ContainSubstring("..."))
+ })
+
+ 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
+ Ω(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() {
+ Ω(Object(GoStringer{}, 1)).Should(ContainSubstring("<format_test.GoStringer>: go-string"))
+ })
+ })
+
+ Context("when passed a stringer", func() {
+ It("should use what String() returns", func() {
+ Ω(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() {
+ Ω(Object(objWithContext, 1)).Should(ContainSubstring("<suppressed context>"))
+ })
+
+ It("Doesn't supress the context if it's the object being printed", func() {
+ Ω(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() {
+ Ω(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"
+`)
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 0000000..8775b86
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gbytes/buffer.go
@@ -0,0 +1,229 @@
+/*
+Package gbytes provides a buffer that supports incrementally detecting input.
+
+You use gbytes.Buffer with the gbytes.Say matcher. When Say finds a match, it fastforwards the buffer's read cursor to the end of that match.
+
+Subsequent matches against the buffer will only operate against data that appears *after* the read cursor.
+
+The read cursor is an opaque implementation detail that you cannot access. You should use the Say matcher to sift through the buffer. You can always
+access the entire buffer's contents with Contents().
+
+*/
+package gbytes
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "regexp"
+ "sync"
+ "time"
+)
+
+/*
+gbytes.Buffer implements an io.Writer and can be used with the gbytes.Say matcher.
+
+You should only use a gbytes.Buffer in test code. It stores all writes in an in-memory buffer - behavior that is inappropriate for production code!
+*/
+type Buffer struct {
+ contents []byte
+ readCursor uint64
+ lock *sync.Mutex
+ detectCloser chan interface{}
+ closed bool
+}
+
+/*
+NewBuffer returns a new gbytes.Buffer
+*/
+func NewBuffer() *Buffer {
+ return &Buffer{
+ lock: &sync.Mutex{},
+ }
+}
+
+/*
+BufferWithBytes returns a new gbytes.Buffer seeded with the passed in bytes
+*/
+func BufferWithBytes(bytes []byte) *Buffer {
+ return &Buffer{
+ lock: &sync.Mutex{},
+ contents: bytes,
+ }
+}
+
+/*
+Write implements the io.Writer interface
+*/
+func (b *Buffer) Write(p []byte) (n int, err error) {
+ b.lock.Lock()
+ defer b.lock.Unlock()
+
+ if b.closed {
+ return 0, errors.New("attempt to write to closed buffer")
+ }
+
+ b.contents = append(b.contents, p...)
+ return len(p), nil
+}
+
+/*
+Read implements the io.Reader interface. It advances the
+cursor as it reads.
+
+Returns an error if called after Close.
+*/
+func (b *Buffer) Read(d []byte) (int, error) {
+ b.lock.Lock()
+ defer b.lock.Unlock()
+
+ if b.closed {
+ return 0, errors.New("attempt to read from closed buffer")
+ }
+
+ if uint64(len(b.contents)) <= b.readCursor {
+ return 0, io.EOF
+ }
+
+ n := copy(d, b.contents[b.readCursor:])
+ b.readCursor += uint64(n)
+
+ return n, nil
+}
+
+/*
+Close signifies that the buffer will no longer be written to
+*/
+func (b *Buffer) Close() error {
+ b.lock.Lock()
+ defer b.lock.Unlock()
+
+ b.closed = true
+
+ return nil
+}
+
+/*
+Closed returns true if the buffer has been closed
+*/
+func (b *Buffer) Closed() bool {
+ b.lock.Lock()
+ defer b.lock.Unlock()
+
+ return b.closed
+}
+
+/*
+Contents returns all data ever written to the buffer.
+*/
+func (b *Buffer) Contents() []byte {
+ b.lock.Lock()
+ defer b.lock.Unlock()
+
+ contents := make([]byte, len(b.contents))
+ copy(contents, b.contents)
+ return contents
+}
+
+/*
+Detect takes a regular expression and returns a channel.
+
+The channel will receive true the first time data matching the regular expression is written to the buffer.
+The channel is subsequently closed and the buffer's read-cursor is fast-forwarded to just after the matching region.
+
+You typically don't need to use Detect and should use the ghttp.Say matcher instead. Detect is useful, however, in cases where your code must
+be branch and handle different outputs written to the buffer.
+
+For example, consider a buffer hooked up to the stdout of a client library. You may (or may not, depending on state outside of your control) need to authenticate the client library.
+
+You could do something like:
+
+select {
+case <-buffer.Detect("You are not logged in"):
+ //log in
+case <-buffer.Detect("Success"):
+ //carry on
+case <-time.After(time.Second):
+ //welp
+}
+buffer.CancelDetects()
+
+You should always call CancelDetects after using Detect. This will close any channels that have not detected and clean up the goroutines that were spawned to support them.
+
+Finally, you can pass detect a format string followed by variadic arguments. This will construct the regexp using fmt.Sprintf.
+*/
+func (b *Buffer) Detect(desired string, args ...interface{}) chan bool {
+ formattedRegexp := desired
+ if len(args) > 0 {
+ formattedRegexp = fmt.Sprintf(desired, args...)
+ }
+ re := regexp.MustCompile(formattedRegexp)
+
+ b.lock.Lock()
+ defer b.lock.Unlock()
+
+ if b.detectCloser == nil {
+ b.detectCloser = make(chan interface{})
+ }
+
+ closer := b.detectCloser
+ response := make(chan bool)
+ go func() {
+ ticker := time.NewTicker(10 * time.Millisecond)
+ defer ticker.Stop()
+ defer close(response)
+ for {
+ select {
+ case <-ticker.C:
+ b.lock.Lock()
+ data, cursor := b.contents[b.readCursor:], b.readCursor
+ loc := re.FindIndex(data)
+ b.lock.Unlock()
+
+ if loc != nil {
+ response <- true
+ b.lock.Lock()
+ newCursorPosition := cursor + uint64(loc[1])
+ if newCursorPosition >= b.readCursor {
+ b.readCursor = newCursorPosition
+ }
+ b.lock.Unlock()
+ return
+ }
+ case <-closer:
+ return
+ }
+ }
+ }()
+
+ return response
+}
+
+/*
+CancelDetects cancels any pending detects and cleans up their goroutines. You should always call this when you're done with a set of Detect channels.
+*/
+func (b *Buffer) CancelDetects() {
+ b.lock.Lock()
+ defer b.lock.Unlock()
+
+ close(b.detectCloser)
+ b.detectCloser = nil
+}
+
+func (b *Buffer) didSay(re *regexp.Regexp) (bool, []byte) {
+ b.lock.Lock()
+ defer b.lock.Unlock()
+
+ unreadBytes := b.contents[b.readCursor:]
+ copyOfUnreadBytes := make([]byte, len(unreadBytes))
+ copy(copyOfUnreadBytes, unreadBytes)
+
+ loc := re.FindIndex(unreadBytes)
+
+ if loc != nil {
+ b.readCursor += uint64(loc[1])
+ return true, copyOfUnreadBytes
+ } else {
+ return false, copyOfUnreadBytes
+ }
+}
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 0000000..b111138
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gbytes/buffer_test.go
@@ -0,0 +1,158 @@
+package gbytes_test
+
+import (
+ "io"
+ "time"
+
+ . "github.com/onsi/gomega/gbytes"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("Buffer", func() {
+ var buffer *Buffer
+
+ BeforeEach(func() {
+ buffer = NewBuffer()
+ })
+
+ Describe("dumping the entire contents of the buffer", func() {
+ It("should return everything that's been written", func() {
+ buffer.Write([]byte("abc"))
+ buffer.Write([]byte("def"))
+ Ω(buffer.Contents()).Should(Equal([]byte("abcdef")))
+
+ Ω(buffer).Should(Say("bcd"))
+ Ω(buffer.Contents()).Should(Equal([]byte("abcdef")))
+ })
+ })
+
+ Describe("creating a buffer with bytes", func() {
+ It("should create the buffer with the cursor set to the beginning", func() {
+ buffer := BufferWithBytes([]byte("abcdef"))
+ Ω(buffer.Contents()).Should(Equal([]byte("abcdef")))
+ Ω(buffer).Should(Say("abc"))
+ Ω(buffer).ShouldNot(Say("abc"))
+ Ω(buffer).Should(Say("def"))
+ })
+ })
+
+ Describe("reading from a buffer", func() {
+ It("should read the current contents of the buffer", func() {
+ buffer := BufferWithBytes([]byte("abcde"))
+
+ dest := make([]byte, 3)
+ n, err := buffer.Read(dest)
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(n).Should(Equal(3))
+ Ω(string(dest)).Should(Equal("abc"))
+
+ dest = make([]byte, 3)
+ n, err = buffer.Read(dest)
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(n).Should(Equal(2))
+ Ω(string(dest[:n])).Should(Equal("de"))
+
+ n, err = buffer.Read(dest)
+ Ω(err).Should(Equal(io.EOF))
+ Ω(n).Should(Equal(0))
+ })
+
+ Context("after the buffer has been closed", func() {
+ It("returns an error", func() {
+ buffer := BufferWithBytes([]byte("abcde"))
+
+ buffer.Close()
+
+ dest := make([]byte, 3)
+ n, err := buffer.Read(dest)
+ Ω(err).Should(HaveOccurred())
+ Ω(n).Should(Equal(0))
+ })
+ })
+ })
+
+ Describe("detecting regular expressions", func() {
+ It("should fire the appropriate channel when the passed in pattern matches, then close it", func(done Done) {
+ go func() {
+ time.Sleep(10 * time.Millisecond)
+ buffer.Write([]byte("abcde"))
+ }()
+
+ A := buffer.Detect("%s", "a.c")
+ B := buffer.Detect("def")
+
+ var gotIt bool
+ select {
+ case gotIt = <-A:
+ case <-B:
+ Fail("should not have gotten here")
+ }
+
+ Ω(gotIt).Should(BeTrue())
+ Eventually(A).Should(BeClosed())
+
+ buffer.Write([]byte("f"))
+ Eventually(B).Should(Receive())
+ Eventually(B).Should(BeClosed())
+
+ close(done)
+ })
+
+ It("should fast-forward the buffer upon detection", func(done Done) {
+ buffer.Write([]byte("abcde"))
+ <-buffer.Detect("abc")
+ Ω(buffer).ShouldNot(Say("abc"))
+ Ω(buffer).Should(Say("de"))
+ close(done)
+ })
+
+ It("should only fast-forward the buffer when the channel is read, and only if doing so would not rewind it", func(done Done) {
+ buffer.Write([]byte("abcde"))
+ A := buffer.Detect("abc")
+ time.Sleep(20 * time.Millisecond) //give the goroutine a chance to detect and write to the channel
+ Ω(buffer).Should(Say("abcd"))
+ <-A
+ Ω(buffer).ShouldNot(Say("d"))
+ Ω(buffer).Should(Say("e"))
+ Eventually(A).Should(BeClosed())
+ close(done)
+ })
+
+ It("should be possible to cancel a detection", func(done Done) {
+ A := buffer.Detect("abc")
+ B := buffer.Detect("def")
+ buffer.CancelDetects()
+ buffer.Write([]byte("abcdef"))
+ Eventually(A).Should(BeClosed())
+ Eventually(B).Should(BeClosed())
+
+ Ω(buffer).Should(Say("bcde"))
+ <-buffer.Detect("f")
+ close(done)
+ })
+ })
+
+ Describe("closing the buffer", func() {
+ It("should error when further write attempts are made", func() {
+ _, err := buffer.Write([]byte("abc"))
+ Ω(err).ShouldNot(HaveOccurred())
+
+ buffer.Close()
+
+ _, err = buffer.Write([]byte("def"))
+ Ω(err).Should(HaveOccurred())
+
+ Ω(buffer.Contents()).Should(Equal([]byte("abc")))
+ })
+
+ It("should be closed", func() {
+ Ω(buffer.Closed()).Should(BeFalse())
+
+ buffer.Close()
+
+ Ω(buffer.Closed()).Should(BeTrue())
+ })
+ })
+})
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 0000000..3a7dc06
--- /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/say_matcher.go b/vendor/github.com/onsi/gomega/gbytes/say_matcher.go
new file mode 100644
index 0000000..cbc266c
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gbytes/say_matcher.go
@@ -0,0 +1,105 @@
+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:
+
+ Ω(buffer).Should(Say("something"))
+
+will succeed if the unread portion of the buffer matches the regular expression "something".
+
+When Say succeeds, it fast forwards the gbytes.Buffer's read cursor to just after the succesful match.
+Thus, subsequent calls to Say will only match against the unread portion of the buffer
+
+Say pairs very well with Eventually. To assert that a buffer eventually receives data matching "[123]-star" within 3 seconds you can:
+
+ Eventually(buffer, 3).Should(Say("[123]-star"))
+
+Ditto with consistently. To assert that a buffer does not receive data matching "never-see-this" for 1 second you can:
+
+ Consistently(buffer, 1).ShouldNot(Say("never-see-this"))
+
+In addition to bytes.Buffers, Say can operate on objects that implement the gbytes.BufferProvider interface.
+In such cases, Say simply operates on the *gbytes.Buffer returned by Buffer()
+
+If the buffer is closed, the Say matcher will tell Eventually to abort.
+*/
+func Say(expected string, args ...interface{}) *sayMatcher {
+ formattedRegexp := expected
+ if len(args) > 0 {
+ formattedRegexp = fmt.Sprintf(expected, args...)
+ }
+ return &sayMatcher{
+ re: regexp.MustCompile(formattedRegexp),
+ }
+}
+
+type sayMatcher struct {
+ re *regexp.Regexp
+ receivedSayings []byte
+}
+
+func (m *sayMatcher) buffer(actual interface{}) (*Buffer, bool) {
+ var buffer *Buffer
+
+ switch x := actual.(type) {
+ case *Buffer:
+ buffer = x
+ case BufferProvider:
+ buffer = x.Buffer()
+ default:
+ return nil, false
+ }
+
+ return buffer, true
+}
+
+func (m *sayMatcher) Match(actual interface{}) (success bool, err error) {
+ buffer, ok := m.buffer(actual)
+ if !ok {
+ return false, fmt.Errorf("Say must be passed a *gbytes.Buffer or BufferProvider. Got:\n%s", format.Object(actual, 1))
+ }
+
+ didSay, sayings := buffer.didSay(m.re)
+ m.receivedSayings = sayings
+
+ return didSay, nil
+}
+
+func (m *sayMatcher) FailureMessage(actual interface{}) (message string) {
+ return fmt.Sprintf(
+ "Got stuck at:\n%s\nWaiting for:\n%s",
+ format.IndentString(string(m.receivedSayings), 1),
+ format.IndentString(m.re.String(), 1),
+ )
+}
+
+func (m *sayMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ return fmt.Sprintf(
+ "Saw:\n%s\nWhich matches the unexpected:\n%s",
+ format.IndentString(string(m.receivedSayings), 1),
+ format.IndentString(m.re.String(), 1),
+ )
+}
+
+func (m *sayMatcher) MatchMayChangeInTheFuture(actual interface{}) bool {
+ switch x := actual.(type) {
+ case *Buffer:
+ return !x.Closed()
+ case BufferProvider:
+ return !x.Buffer().Closed()
+ default:
+ return true
+ }
+}
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 0000000..63fb3b3
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gbytes/say_matcher_test.go
@@ -0,0 +1,163 @@
+package gbytes_test
+
+import (
+ . "github.com/onsi/gomega/gbytes"
+ "time"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+type speaker struct {
+ buffer *Buffer
+}
+
+func (s *speaker) Buffer() *Buffer {
+ return s.buffer
+}
+
+var _ = Describe("SayMatcher", func() {
+ var buffer *Buffer
+
+ BeforeEach(func() {
+ buffer = NewBuffer()
+ buffer.Write([]byte("abc"))
+ })
+
+ Context("when actual is not a gexec Buffer, or a BufferProvider", func() {
+ It("should error", func() {
+ failures := InterceptGomegaFailures(func() {
+ Ω("foo").Should(Say("foo"))
+ })
+ Ω(failures[0]).Should(ContainSubstring("*gbytes.Buffer"))
+ })
+ })
+
+ Context("when a match is found", func() {
+ It("should succeed", func() {
+ Ω(buffer).Should(Say("abc"))
+ })
+
+ It("should support printf-like formatting", func() {
+ Ω(buffer).Should(Say("a%sc", "b"))
+ })
+
+ It("should use a regular expression", func() {
+ Ω(buffer).Should(Say("a.c"))
+ })
+
+ It("should fastforward the buffer", func() {
+ buffer.Write([]byte("def"))
+ Ω(buffer).Should(Say("abcd"))
+ Ω(buffer).Should(Say("ef"))
+ Ω(buffer).ShouldNot(Say("[a-z]"))
+ })
+ })
+
+ Context("when no match is found", func() {
+ It("should not error", func() {
+ Ω(buffer).ShouldNot(Say("def"))
+ })
+
+ Context("when the buffer is closed", func() {
+ BeforeEach(func() {
+ buffer.Close()
+ })
+
+ It("should abort an eventually", func() {
+ t := time.Now()
+ failures := InterceptGomegaFailures(func() {
+ Eventually(buffer).Should(Say("def"))
+ })
+ Eventually(buffer).ShouldNot(Say("def"))
+ Ω(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond))
+ Ω(failures).Should(HaveLen(1))
+
+ t = time.Now()
+ Eventually(buffer).Should(Say("abc"))
+ Ω(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond))
+ })
+
+ It("should abort a consistently", func() {
+ t := time.Now()
+ Consistently(buffer, 2.0).ShouldNot(Say("def"))
+ Ω(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond))
+ })
+
+ It("should not error with a synchronous matcher", func() {
+ Ω(buffer).ShouldNot(Say("def"))
+ Ω(buffer).Should(Say("abc"))
+ })
+ })
+ })
+
+ Context("when a positive match fails", func() {
+ It("should report where it got stuck", func() {
+ Ω(buffer).Should(Say("abc"))
+ buffer.Write([]byte("def"))
+ failures := InterceptGomegaFailures(func() {
+ Ω(buffer).Should(Say("abc"))
+ })
+ Ω(failures[0]).Should(ContainSubstring("Got stuck at:"))
+ Ω(failures[0]).Should(ContainSubstring("def"))
+ })
+ })
+
+ Context("when a negative match fails", func() {
+ It("should report where it got stuck", func() {
+ failures := InterceptGomegaFailures(func() {
+ Ω(buffer).ShouldNot(Say("abc"))
+ })
+ Ω(failures[0]).Should(ContainSubstring("Saw:"))
+ Ω(failures[0]).Should(ContainSubstring("Which matches the unexpected:"))
+ Ω(failures[0]).Should(ContainSubstring("abc"))
+ })
+ })
+
+ Context("when a match is not found", func() {
+ It("should not fastforward the buffer", func() {
+ Ω(buffer).ShouldNot(Say("def"))
+ Ω(buffer).Should(Say("abc"))
+ })
+ })
+
+ Context("a nice real-life example", func() {
+ It("should behave well", func() {
+ Ω(buffer).Should(Say("abc"))
+ go func() {
+ time.Sleep(10 * time.Millisecond)
+ buffer.Write([]byte("def"))
+ }()
+ Ω(buffer).ShouldNot(Say("def"))
+ Eventually(buffer).Should(Say("def"))
+ })
+ })
+
+ Context("when actual is a BufferProvider", func() {
+ It("should use actual's buffer", func() {
+ s := &speaker{
+ buffer: NewBuffer(),
+ }
+
+ Ω(s).ShouldNot(Say("abc"))
+
+ s.Buffer().Write([]byte("abc"))
+ Ω(s).Should(Say("abc"))
+ })
+
+ It("should abort an eventually", func() {
+ s := &speaker{
+ buffer: NewBuffer(),
+ }
+
+ s.buffer.Close()
+
+ t := time.Now()
+ failures := InterceptGomegaFailures(func() {
+ Eventually(s).Should(Say("def"))
+ })
+ Ω(failures).Should(HaveLen(1))
+ Ω(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond))
+ })
+ })
+})
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 0000000..16091c2
--- /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 0000000..d11b2fd
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gexec/build.go
@@ -0,0 +1,99 @@
+package gexec
+
+import (
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path"
+ "path/filepath"
+ "runtime"
+ "sync"
+)
+
+var (
+ mu sync.Mutex
+ tmpDir string
+)
+
+/*
+Build uses go build to compile the package at packagePath. The resulting binary is saved off in a temporary directory.
+A path pointing to this binary is returned.
+
+Build uses the $GOPATH set in your environment. It passes the variadic args on to `go build`.
+*/
+func Build(packagePath string, args ...string) (compiledPath string, err error) {
+ return doBuild(os.Getenv("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(os.Getenv("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 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 = append([]string{"GOPATH=" + gopath}, os.Environ()...)
+ 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 0000000..8df0790
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gexec/build_test.go
@@ -0,0 +1,59 @@
+package gexec_test
+
+import (
+ "os"
+
+ . "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)
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+
+ It("compiles the specified package", func() {
+ compiledPath, err := gexec.Build(packagePath)
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(compiledPath).Should(BeAnExistingFile())
+ })
+
+ Context("and CleanupBuildArtifacts has been called", func() {
+ BeforeEach(func() {
+ gexec.CleanupBuildArtifacts()
+ })
+
+ It("compiles the specified package", func() {
+ var err error
+ fireflyPath, err = gexec.Build(packagePath)
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(fireflyPath).Should(BeAnExistingFile())
+ })
+ })
+ })
+})
+
+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)
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(compiledPath).Should(BeAnExistingFile())
+ })
+
+ It("returns the environment to a good state", func() {
+ _, err = gexec.BuildWithEnvironment(packagePath, env)
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(os.Environ()).ShouldNot(ContainElement("GOOS=linux"))
+ })
+})
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 0000000..e6f4329
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gexec/exit_matcher.go
@@ -0,0 +1,88 @@
+package gexec
+
+import (
+ "fmt"
+
+ "github.com/onsi/gomega/format"
+)
+
+/*
+The Exit matcher operates on a session:
+
+ Ω(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."
+ } else {
+ return format.Message(m.actualExitCode, "to match exit code:", m.exitCode)
+ }
+}
+
+func (m *exitMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ if m.actualExitCode == -1 {
+ return "you really shouldn't be able to see this!"
+ } else {
+ if m.exitCode == -1 {
+ return "Expected process not to exit. It did."
+ } else {
+ return format.Message(m.actualExitCode, "not to match exit code:", m.exitCode)
+ }
+ }
+}
+
+func (m *exitMatcher) MatchMayChangeInTheFuture(actual interface{}) bool {
+ session, ok := actual.(*Session)
+ if ok {
+ return session.ExitCode() == -1
+ }
+ return true
+}
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 0000000..79615dd
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gexec/exit_matcher_test.go
@@ -0,0 +1,113 @@
+package gexec_test
+
+import (
+ . "github.com/onsi/gomega/gexec"
+ "os/exec"
+ "time"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+type NeverExits struct{}
+
+func (e NeverExits) ExitCode() int {
+ return -1
+}
+
+var _ = Describe("ExitMatcher", func() {
+ var command *exec.Cmd
+ var session *Session
+
+ BeforeEach(func() {
+ var err error
+ command = exec.Command(fireflyPath, "0")
+ session, err = Start(command, nil, nil)
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+
+ Describe("when passed something that is an Exiter", func() {
+ It("should act normally", func() {
+ failures := InterceptGomegaFailures(func() {
+ Ω(NeverExits{}).Should(Exit())
+ })
+
+ Ω(failures[0]).Should(ContainSubstring("Expected process to exit. It did not."))
+ })
+ })
+
+ Describe("when passed something that is not an Exiter", func() {
+ It("should error", func() {
+ failures := InterceptGomegaFailures(func() {
+ Ω("aardvark").Should(Exit())
+ })
+
+ Ω(failures[0]).Should(ContainSubstring("Exit must be passed a gexec.Exiter"))
+ })
+ })
+
+ Context("with no exit code", func() {
+ It("should say the right things when it fails", func() {
+ Ω(session).ShouldNot(Exit())
+
+ failures := InterceptGomegaFailures(func() {
+ Ω(session).Should(Exit())
+ })
+
+ Ω(failures[0]).Should(ContainSubstring("Expected process to exit. It did not."))
+
+ Eventually(session).Should(Exit())
+
+ Ω(session).Should(Exit())
+
+ failures = InterceptGomegaFailures(func() {
+ Ω(session).ShouldNot(Exit())
+ })
+
+ Ω(failures[0]).Should(ContainSubstring("Expected process not to exit. It did."))
+ })
+ })
+
+ Context("with an exit code", func() {
+ It("should say the right things when it fails", func() {
+ Ω(session).ShouldNot(Exit(0))
+ Ω(session).ShouldNot(Exit(1))
+
+ failures := InterceptGomegaFailures(func() {
+ Ω(session).Should(Exit(0))
+ })
+
+ Ω(failures[0]).Should(ContainSubstring("Expected process to exit. It did not."))
+
+ Eventually(session).Should(Exit(0))
+
+ Ω(session).Should(Exit(0))
+
+ failures = InterceptGomegaFailures(func() {
+ Ω(session).Should(Exit(1))
+ })
+
+ Ω(failures[0]).Should(ContainSubstring("to match exit code:"))
+
+ Ω(session).ShouldNot(Exit(1))
+
+ failures = InterceptGomegaFailures(func() {
+ Ω(session).ShouldNot(Exit(0))
+ })
+
+ Ω(failures[0]).Should(ContainSubstring("not to match exit code:"))
+ })
+ })
+
+ Describe("bailing out early", func() {
+ It("should bail out early once the process exits", func() {
+ t := time.Now()
+
+ failures := InterceptGomegaFailures(func() {
+ Eventually(session).Should(Exit(1))
+ })
+ Ω(time.Since(t)).Should(BeNumerically("<=", 500*time.Millisecond))
+ Ω(failures).Should(HaveLen(1))
+ })
+ })
+})
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 0000000..87672aa
--- /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")
+ Ω(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 0000000..05e695a
--- /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 0000000..8657d0c
--- /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"))
+
+ Ω(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 0000000..387a72c
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gexec/session.go
@@ -0,0 +1,305 @@
+/*
+Package gexec provides support for testing external processes.
+*/
+package gexec
+
+import (
+ "io"
+ "os"
+ "os/exec"
+ "reflect"
+ "sync"
+ "syscall"
+
+ . "github.com/onsi/gomega"
+ "github.com/onsi/gomega/gbytes"
+)
+
+const INVALID_EXIT_CODE = 254
+
+type Session struct {
+ //The wrapped command
+ Command *exec.Cmd
+
+ //A *gbytes.Buffer connected to the command's stdout
+ Out *gbytes.Buffer
+
+ //A *gbytes.Buffer connected to the command's stderr
+ Err *gbytes.Buffer
+
+ //A channel that will close when the command exits
+ Exited <-chan struct{}
+
+ lock *sync.Mutex
+ exitCode int
+}
+
+/*
+Start starts the passed-in *exec.Cmd command. It wraps the command in a *gexec.Session.
+
+The session pipes the command's stdout and stderr to two *gbytes.Buffers available as properties on the session: session.Out and session.Err.
+These buffers can be used with the gbytes.Say matcher to match against unread output:
+
+ Ω(session.Out).Should(gbytes.Say("foo-out"))
+ Ω(session.Err).Should(gbytes.Say("foo-err"))
+
+In addition, Session satisfies the gbytes.BufferProvider interface and provides the stdout *gbytes.Buffer. This allows you to replace the first line, above, with:
+
+ Ω(session).Should(gbytes.Say("foo-out"))
+
+When outWriter and/or errWriter are non-nil, the session will pipe stdout and/or stderr output both into the session *gybtes.Buffers and to the passed-in outWriter/errWriter.
+This is useful for capturing the process's output or logging it to screen. In particular, when using Ginkgo it can be convenient to direct output to the GinkgoWriter:
+
+ session, err := Start(command, GinkgoWriter, GinkgoWriter)
+
+This will log output when running tests in verbose mode, but - otherwise - will only log output when a test fails.
+
+The session wrapper is responsible for waiting on the *exec.Cmd command. You *should not* call command.Wait() yourself.
+Instead, to assert that the command has exited you can use the gexec.Exit matcher:
+
+ Ω(session).Should(gexec.Exit())
+
+When the session exits it closes the stdout and stderr gbytes buffers. This will short circuit any
+Eventuallys waiting for the buffers to Say something.
+*/
+func Start(command *exec.Cmd, outWriter io.Writer, errWriter io.Writer) (*Session, error) {
+ exited := make(chan struct{})
+
+ session := &Session{
+ Command: command,
+ Out: gbytes.NewBuffer(),
+ Err: gbytes.NewBuffer(),
+ Exited: exited,
+ lock: &sync.Mutex{},
+ exitCode: -1,
+ }
+
+ var commandOut, commandErr io.Writer
+
+ commandOut, commandErr = session.Out, session.Err
+
+ if outWriter != nil && !reflect.ValueOf(outWriter).IsNil() {
+ commandOut = io.MultiWriter(commandOut, outWriter)
+ }
+
+ if errWriter != nil && !reflect.ValueOf(errWriter).IsNil() {
+ commandErr = io.MultiWriter(commandErr, errWriter)
+ }
+
+ command.Stdout = commandOut
+ command.Stderr = commandErr
+
+ err := command.Start()
+ if err == nil {
+ go session.monitorForExit(exited)
+ 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 {
+ if s.ExitCode() != -1 {
+ return s
+ }
+ s.Command.Process.Kill()
+ return s
+}
+
+/*
+Interrupt sends the running command a SIGINT signal. It does not wait for the process to exit.
+
+If the command has already exited, Interrupt returns silently.
+
+The session is returned to enable chaining.
+*/
+func (s *Session) Interrupt() *Session {
+ return s.Signal(syscall.SIGINT)
+}
+
+/*
+Terminate sends the running command a SIGTERM signal. It does not wait for the process to exit.
+
+If the command has already exited, Terminate returns silently.
+
+The session is returned to enable chaining.
+*/
+func (s *Session) Terminate() *Session {
+ return s.Signal(syscall.SIGTERM)
+}
+
+/*
+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.ExitCode() != -1 {
+ return s
+ }
+ s.Command.Process.Signal(signal)
+ return s
+}
+
+func (s *Session) monitorForExit(exited chan<- struct{}) {
+ err := s.Command.Wait()
+ s.lock.Lock()
+ s.Out.Close()
+ s.Err.Close()
+ status := s.Command.ProcessState.Sys().(syscall.WaitStatus)
+ if status.Signaled() {
+ s.exitCode = 128 + int(status.Signal())
+ } else {
+ exitStatus := status.ExitStatus()
+ if exitStatus == -1 && err != nil {
+ s.exitCode = INVALID_EXIT_CODE
+ }
+ s.exitCode = exitStatus
+ }
+ s.lock.Unlock()
+
+ close(exited)
+}
+
+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 0000000..b7841a0
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gexec/session_test.go
@@ -0,0 +1,351 @@
+package gexec_test
+
+import (
+ "os/exec"
+ "syscall"
+ "time"
+
+ . "github.com/onsi/gomega/gbytes"
+ . "github.com/onsi/gomega/gexec"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("Session", func() {
+ var command *exec.Cmd
+ var session *Session
+
+ var outWriter, errWriter *Buffer
+
+ BeforeEach(func() {
+ outWriter = nil
+ errWriter = nil
+ })
+
+ JustBeforeEach(func() {
+ command = exec.Command(fireflyPath)
+ var err error
+ session, err = Start(command, outWriter, errWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+
+ Context("running a command", func() {
+ It("should start the process", func() {
+ Ω(command.Process).ShouldNot(BeNil())
+ })
+
+ It("should wrap the process's stdout and stderr with gbytes buffers", func(done Done) {
+ Eventually(session.Out).Should(Say("We've done the impossible, and that makes us mighty"))
+ Eventually(session.Err).Should(Say("Ah, curse your sudden but inevitable betrayal!"))
+ defer session.Out.CancelDetects()
+
+ select {
+ case <-session.Out.Detect("Can we maybe vote on the whole murdering people issue"):
+ Eventually(session).Should(Exit(0))
+ case <-session.Out.Detect("I swear by my pretty floral bonnet, I will end you."):
+ Eventually(session).Should(Exit(1))
+ case <-session.Out.Detect("My work's illegal, but at least it's honest."):
+ Eventually(session).Should(Exit(2))
+ }
+
+ close(done)
+ })
+
+ It("should satisfy the gbytes.BufferProvider interface, passing Stdout", func() {
+ Eventually(session).Should(Say("We've done the impossible, and that makes us mighty"))
+ Eventually(session).Should(Exit())
+ })
+ })
+
+ Describe("providing the exit code", func() {
+ It("should provide the app's exit code", func() {
+ Ω(session.ExitCode()).Should(Equal(-1))
+
+ Eventually(session).Should(Exit())
+ Ω(session.ExitCode()).Should(BeNumerically(">=", 0))
+ Ω(session.ExitCode()).Should(BeNumerically("<", 3))
+ })
+ })
+
+ Describe("wait", func() {
+ It("should wait till the command exits", func() {
+ Ω(session.ExitCode()).Should(Equal(-1))
+ Ω(session.Wait().ExitCode()).Should(BeNumerically(">=", 0))
+ Ω(session.Wait().ExitCode()).Should(BeNumerically("<", 3))
+ })
+ })
+
+ Describe("exited", func() {
+ It("should close when the command exits", func() {
+ Eventually(session.Exited).Should(BeClosed())
+ Ω(session.ExitCode()).ShouldNot(Equal(-1))
+ })
+ })
+
+ Describe("kill", func() {
+ It("should kill the command and don't wait for it to exit", func() {
+ session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ session.Kill()
+ Ω(session).ShouldNot(Exit(), "Should not exit immediately...")
+ Eventually(session).Should(Exit(128 + 9))
+ })
+ })
+
+ Describe("interrupt", func() {
+ It("should interrupt the command", func() {
+ session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ session.Interrupt()
+ Ω(session).ShouldNot(Exit(), "Should not exit immediately...")
+ Eventually(session).Should(Exit(128 + 2))
+ })
+ })
+
+ Describe("terminate", func() {
+ It("should terminate the command", func() {
+ session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ session.Terminate()
+ Ω(session).ShouldNot(Exit(), "Should not exit immediately...")
+ Eventually(session).Should(Exit(128 + 15))
+ })
+ })
+
+ Describe("signal", func() {
+ It("should send the signal to the command", func() {
+ session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ session.Signal(syscall.SIGABRT)
+ Ω(session).ShouldNot(Exit(), "Should not exit immediately...")
+ Eventually(session).Should(Exit(128 + 6))
+ })
+ })
+
+ Context("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)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(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 wait for exit", func() {
+ session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Kill()
+ Ω(session1).ShouldNot(Exit(), "Should not exit immediately...")
+
+ Eventually(session1).Should(Exit(128 + 9))
+ })
+
+ It("should not track unstarted sessions", func() {
+ _, err := Start(exec.Command("does not exist", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).Should(HaveOccurred())
+
+ session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(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)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ KillAndWait()
+ Ω(session1).Should(Exit(128+9), "Should have exited")
+ Ω(session2).Should(Exit(128+9), "Should have exited")
+ Ω(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)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Terminate()
+
+ Eventually(session1).Should(Exit(128 + 15))
+ Eventually(session2).Should(Exit(128 + 15))
+ Eventually(session3).Should(Exit(128 + 15))
+ })
+
+ It("should not wait for exit", func() {
+ session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Terminate()
+
+ Ω(session1).ShouldNot(Exit(), "Should not exit immediately...")
+ })
+ })
+
+ 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)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ TerminateAndWait()
+
+ Ω(session1).Should(Exit(128+15), "Should have exited")
+ Ω(session2).Should(Exit(128+15), "Should have exited")
+ Ω(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)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Signal(syscall.SIGABRT)
+
+ Eventually(session1).Should(Exit(128 + 6))
+ Eventually(session2).Should(Exit(128 + 6))
+ Eventually(session3).Should(Exit(128 + 6))
+ })
+
+ It("should not wait", func() {
+ session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Signal(syscall.SIGABRT)
+
+ Ω(session1).ShouldNot(Exit(), "Should not exit immediately...")
+ })
+ })
+
+ Describe("interrupt", func() {
+ It("should interrupt all the started sessions, and not wait", func() {
+ session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Interrupt()
+
+ Eventually(session1).Should(Exit(128 + 2))
+ Eventually(session2).Should(Exit(128 + 2))
+ Eventually(session3).Should(Exit(128 + 2))
+ })
+
+ It("should not wait", func() {
+ session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Interrupt()
+
+ Ω(session1).ShouldNot(Exit(), "Should not exit immediately...")
+ })
+ })
+ })
+
+ Context("when the command exits", func() {
+ It("should close the buffers", func() {
+ Eventually(session).Should(Exit())
+
+ Ω(session.Out.Closed()).Should(BeTrue())
+ Ω(session.Err.Closed()).Should(BeTrue())
+
+ Ω(session.Out).Should(Say("We've done the impossible, and that makes us mighty"))
+ })
+
+ var So = It
+
+ So("this means that eventually should short circuit", func() {
+ t := time.Now()
+ failures := InterceptGomegaFailures(func() {
+ Eventually(session).Should(Say("blah blah blah blah blah"))
+ })
+ Ω(time.Since(t)).Should(BeNumerically("<=", 500*time.Millisecond))
+ Ω(failures).Should(HaveLen(1))
+ })
+ })
+
+ Context("when wrapping out and err", func() {
+ BeforeEach(func() {
+ outWriter = NewBuffer()
+ errWriter = NewBuffer()
+ })
+
+ It("should route to both the provided writers and the gbytes buffers", func() {
+ Eventually(session.Out).Should(Say("We've done the impossible, and that makes us mighty"))
+ Eventually(session.Err).Should(Say("Ah, curse your sudden but inevitable betrayal!"))
+
+ Ω(outWriter.Contents()).Should(ContainSubstring("We've done the impossible, and that makes us mighty"))
+ Ω(errWriter.Contents()).Should(ContainSubstring("Ah, curse your sudden but inevitable betrayal!"))
+
+ Eventually(session).Should(Exit())
+
+ Ω(outWriter.Contents()).Should(Equal(session.Out.Contents()))
+ Ω(errWriter.Contents()).Should(Equal(session.Err.Contents()))
+ })
+ })
+
+ Describe("when the command fails to start", func() {
+ It("should return an error", func() {
+ _, err := Start(exec.Command("agklsjdfas"), nil, nil)
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+})
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 0000000..63ff691
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/ghttp/handlers.go
@@ -0,0 +1,313 @@
+package ghttp
+
+import (
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "reflect"
+
+ "github.com/golang/protobuf/proto"
+ . "github.com/onsi/gomega"
+ "github.com/onsi/gomega/types"
+)
+
+//CombineHandler takes variadic list of handlers and produces one handler
+//that calls each handler in order.
+func CombineHandlers(handlers ...http.HandlerFunc) http.HandlerFunc {
+ return func(w http.ResponseWriter, req *http.Request) {
+ for _, handler := range handlers {
+ handler(w, req)
+ }
+ }
+}
+
+//VerifyRequest returns a handler that verifies that a request uses the specified method to connect to the specified path
+//You may also pass in an optional rawQuery string which is tested against the request's `req.URL.RawQuery`
+//
+//For path, you may pass in a string, in which case strict equality will be applied
+//Alternatively you can pass in a matcher (ContainSubstring("/foo") and MatchRegexp("/foo/[a-f0-9]+") for example)
+func VerifyRequest(method string, path interface{}, rawQuery ...string) http.HandlerFunc {
+ return func(w http.ResponseWriter, req *http.Request) {
+ Ω(req.Method).Should(Equal(method), "Method mismatch")
+ switch p := path.(type) {
+ case types.GomegaMatcher:
+ Ω(req.URL.Path).Should(p, "Path mismatch")
+ default:
+ Ω(req.URL.Path).Should(Equal(path), "Path mismatch")
+ }
+ if len(rawQuery) > 0 {
+ values, err := url.ParseQuery(rawQuery[0])
+ Ω(err).ShouldNot(HaveOccurred(), "Expected RawQuery is malformed")
+
+ Ω(req.URL.Query()).Should(Equal(values), "RawQuery mismatch")
+ }
+ }
+}
+
+//VerifyContentType returns a handler that verifies that a request has a Content-Type header set to the
+//specified value
+func VerifyContentType(contentType string) http.HandlerFunc {
+ return func(w http.ResponseWriter, req *http.Request) {
+ Ω(req.Header.Get("Content-Type")).Should(Equal(contentType))
+ }
+}
+
+//VerifyBasicAuth returns a handler that verifies the request contains a BasicAuth Authorization header
+//matching the passed in username and password
+func VerifyBasicAuth(username string, password string) http.HandlerFunc {
+ return func(w http.ResponseWriter, req *http.Request) {
+ auth := req.Header.Get("Authorization")
+ Ω(auth).ShouldNot(Equal(""), "Authorization header must be specified")
+
+ decoded, err := base64.StdEncoding.DecodeString(auth[6:])
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(string(decoded)).Should(Equal(fmt.Sprintf("%s:%s", username, password)), "Authorization mismatch")
+ }
+}
+
+//VerifyHeader returns a handler that verifies the request contains the passed in headers.
+//The passed in header keys are first canonicalized via http.CanonicalHeaderKey.
+//
+//The request must contain *all* the passed in headers, but it is allowed to have additional headers
+//beyond the passed in set.
+func VerifyHeader(header http.Header) http.HandlerFunc {
+ return func(w http.ResponseWriter, req *http.Request) {
+ for key, values := range header {
+ key = http.CanonicalHeaderKey(key)
+ Ω(req.Header[key]).Should(Equal(values), "Header mismatch for key: %s", key)
+ }
+ }
+}
+
+//VerifyHeaderKV returns a handler that verifies the request contains a header matching the passed in key and values
+//(recall that a `http.Header` is a mapping from string (key) to []string (values))
+//It is a convenience wrapper around `VerifyHeader` that allows you to avoid having to create an `http.Header` object.
+func VerifyHeaderKV(key string, values ...string) http.HandlerFunc {
+ return VerifyHeader(http.Header{key: values})
+}
+
+//VerifyBody returns a handler that verifies that the body of the request matches the passed in byte array.
+//It does this using Equal().
+func VerifyBody(expectedBody []byte) http.HandlerFunc {
+ return CombineHandlers(
+ func(w http.ResponseWriter, req *http.Request) {
+ body, err := ioutil.ReadAll(req.Body)
+ req.Body.Close()
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(body).Should(Equal(expectedBody), "Body Mismatch")
+ },
+ )
+}
+
+//VerifyJSON returns a handler that verifies that the body of the request is a valid JSON representation
+//matching the passed in JSON string. It does this using Gomega's MatchJSON method
+//
+//VerifyJSON also verifies that the request's content type is application/json
+func VerifyJSON(expectedJSON string) http.HandlerFunc {
+ return CombineHandlers(
+ VerifyContentType("application/json"),
+ func(w http.ResponseWriter, req *http.Request) {
+ body, err := ioutil.ReadAll(req.Body)
+ req.Body.Close()
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(body).Should(MatchJSON(expectedJSON), "JSON Mismatch")
+ },
+ )
+}
+
+//VerifyJSONRepresenting is similar to VerifyJSON. Instead of taking a JSON string, however, it
+//takes an arbitrary JSON-encodable object and verifies that the requests's body is a JSON representation
+//that matches the object
+func VerifyJSONRepresenting(object interface{}) http.HandlerFunc {
+ data, err := json.Marshal(object)
+ Ω(err).ShouldNot(HaveOccurred())
+ return CombineHandlers(
+ VerifyContentType("application/json"),
+ VerifyJSON(string(data)),
+ )
+}
+
+//VerifyForm returns a handler that verifies a request contains the specified form values.
+//
+//The request must contain *all* of the specified values, but it is allowed to have additional
+//form values beyond the passed in set.
+func VerifyForm(values url.Values) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ err := r.ParseForm()
+ Ω(err).ShouldNot(HaveOccurred())
+ for key, vals := range values {
+ Ω(r.Form[key]).Should(Equal(vals), "Form mismatch for key: %s", key)
+ }
+ }
+}
+
+//VerifyFormKV returns a handler that verifies a request contains a form key with the specified values.
+//
+//It is a convenience wrapper around `VerifyForm` that lets you avoid having to create a `url.Values` object.
+func VerifyFormKV(key string, values ...string) http.HandlerFunc {
+ return VerifyForm(url.Values{key: values})
+}
+
+//VerifyProtoRepresenting returns a handler that verifies that the body of the request is a valid protobuf
+//representation of the passed message.
+//
+//VerifyProtoRepresenting also verifies that the request's content type is application/x-protobuf
+func VerifyProtoRepresenting(expected proto.Message) http.HandlerFunc {
+ return CombineHandlers(
+ VerifyContentType("application/x-protobuf"),
+ func(w http.ResponseWriter, req *http.Request) {
+ body, err := ioutil.ReadAll(req.Body)
+ Ω(err).ShouldNot(HaveOccurred())
+ req.Body.Close()
+
+ expectedType := reflect.TypeOf(expected)
+ actualValuePtr := reflect.New(expectedType.Elem())
+
+ actual, ok := actualValuePtr.Interface().(proto.Message)
+ Ω(ok).Should(BeTrue(), "Message value is not a proto.Message")
+
+ err = proto.Unmarshal(body, actual)
+ Ω(err).ShouldNot(HaveOccurred(), "Failed to unmarshal protobuf")
+
+ Ω(actual).Should(Equal(expected), "ProtoBuf Mismatch")
+ },
+ )
+}
+
+func copyHeader(src http.Header, dst http.Header) {
+ for key, value := range src {
+ dst[key] = value
+ }
+}
+
+/*
+RespondWith returns a handler that responds to a request with the specified status code and body
+
+Body may be a string or []byte
+
+Also, RespondWith can be given an optional http.Header. The headers defined therein will be added to the response headers.
+*/
+func RespondWith(statusCode int, body interface{}, optionalHeader ...http.Header) http.HandlerFunc {
+ return func(w http.ResponseWriter, req *http.Request) {
+ if len(optionalHeader) == 1 {
+ copyHeader(optionalHeader[0], w.Header())
+ }
+ w.WriteHeader(statusCode)
+ switch x := body.(type) {
+ case string:
+ w.Write([]byte(x))
+ case []byte:
+ w.Write(x)
+ default:
+ Ω(body).Should(BeNil(), "Invalid type for body. Should be string or []byte.")
+ }
+ }
+}
+
+/*
+RespondWithPtr returns a handler that responds to a request with the specified status code and body
+
+Unlike RespondWith, you pass RepondWithPtr a pointer to the status code and body allowing different tests
+to share the same setup but specify different status codes and bodies.
+
+Also, RespondWithPtr can be given an optional http.Header. The headers defined therein will be added to the response headers.
+Since the http.Header can be mutated after the fact you don't need to pass in a pointer.
+*/
+func RespondWithPtr(statusCode *int, body interface{}, optionalHeader ...http.Header) http.HandlerFunc {
+ return func(w http.ResponseWriter, req *http.Request) {
+ if len(optionalHeader) == 1 {
+ copyHeader(optionalHeader[0], w.Header())
+ }
+ w.WriteHeader(*statusCode)
+ if body != nil {
+ switch x := (body).(type) {
+ case *string:
+ w.Write([]byte(*x))
+ case *[]byte:
+ w.Write(*x)
+ default:
+ Ω(body).Should(BeNil(), "Invalid type for body. Should be string or []byte.")
+ }
+ }
+ }
+}
+
+/*
+RespondWithJSONEncoded returns a handler that responds to a request with the specified status code and a body
+containing the JSON-encoding of the passed in object
+
+Also, RespondWithJSONEncoded can be given an optional http.Header. The headers defined therein will be added to the response headers.
+*/
+func RespondWithJSONEncoded(statusCode int, object interface{}, optionalHeader ...http.Header) http.HandlerFunc {
+ data, err := json.Marshal(object)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ var headers http.Header
+ if len(optionalHeader) == 1 {
+ headers = optionalHeader[0]
+ } else {
+ headers = make(http.Header)
+ }
+ if _, found := headers["Content-Type"]; !found {
+ headers["Content-Type"] = []string{"application/json"}
+ }
+ return RespondWith(statusCode, string(data), headers)
+}
+
+/*
+RespondWithJSONEncodedPtr behaves like RespondWithJSONEncoded but takes a pointer
+to a status code and object.
+
+This allows different tests to share the same setup but specify different status codes and JSON-encoded
+objects.
+
+Also, RespondWithJSONEncodedPtr can be given an optional http.Header. The headers defined therein will be added to the response headers.
+Since the http.Header can be mutated after the fact you don't need to pass in a pointer.
+*/
+func RespondWithJSONEncodedPtr(statusCode *int, object interface{}, optionalHeader ...http.Header) http.HandlerFunc {
+ return func(w http.ResponseWriter, req *http.Request) {
+ data, err := json.Marshal(object)
+ Ω(err).ShouldNot(HaveOccurred())
+ var headers http.Header
+ if len(optionalHeader) == 1 {
+ headers = optionalHeader[0]
+ } else {
+ headers = make(http.Header)
+ }
+ if _, found := headers["Content-Type"]; !found {
+ headers["Content-Type"] = []string{"application/json"}
+ }
+ copyHeader(headers, w.Header())
+ w.WriteHeader(*statusCode)
+ w.Write(data)
+ }
+}
+
+//RespondWithProto returns a handler that responds to a request with the specified status code and a body
+//containing the protobuf serialization of the provided message.
+//
+//Also, RespondWithProto can be given an optional http.Header. The headers defined therein will be added to the response headers.
+func RespondWithProto(statusCode int, message proto.Message, optionalHeader ...http.Header) http.HandlerFunc {
+ return func(w http.ResponseWriter, req *http.Request) {
+ data, err := proto.Marshal(message)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ var headers http.Header
+ if len(optionalHeader) == 1 {
+ headers = optionalHeader[0]
+ } else {
+ headers = make(http.Header)
+ }
+ if _, found := headers["Content-Type"]; !found {
+ headers["Content-Type"] = []string{"application/x-protobuf"}
+ }
+ copyHeader(headers, w.Header())
+
+ w.WriteHeader(statusCode)
+ w.Write(data)
+ }
+}
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 0000000..b2972bc
--- /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 0000000..c55a484
--- /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 0000000..35b7145
--- /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 0000000..40d92de
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/ghttp/test_server.go
@@ -0,0 +1,381 @@
+/*
+Package ghttp supports testing HTTP clients by providing a test server (simply a thin wrapper around httptest's server) that supports
+registering multiple handlers. Incoming requests are not routed between the different handlers
+- rather it is merely the order of the handlers that matters. The first request is handled by the first
+registered handler, the second request by the second handler, etc.
+
+The intent here is to have each handler *verify* that the incoming request is valid. To accomplish, ghttp
+also provides a collection of bite-size handlers that each perform one aspect of request verification. These can
+be composed together and registered with a ghttp server. The result is an expressive language for describing
+the requests generated by the client under test.
+
+Here's a simple example, note that the server handler is only defined in one BeforeEach and then modified, as required, by the nested BeforeEaches.
+A more comprehensive example is available at https://onsi.github.io/gomega/#_testing_http_clients
+
+ var _ = Describe("A Sprockets Client", func() {
+ var server *ghttp.Server
+ var client *SprocketClient
+ BeforeEach(func() {
+ server = ghttp.NewServer()
+ client = NewSprocketClient(server.URL(), "skywalker", "tk427")
+ })
+
+ AfterEach(func() {
+ server.Close()
+ })
+
+ Describe("fetching sprockets", func() {
+ var statusCode int
+ var sprockets []Sprocket
+ BeforeEach(func() {
+ statusCode = http.StatusOK
+ sprockets = []Sprocket{}
+ server.AppendHandlers(ghttp.CombineHandlers(
+ ghttp.VerifyRequest("GET", "/sprockets"),
+ ghttp.VerifyBasicAuth("skywalker", "tk427"),
+ ghttp.RespondWithJSONEncodedPtr(&statusCode, &sprockets),
+ ))
+ })
+
+ Context("when requesting all sprockets", func() {
+ Context("when the response is succesful", func() {
+ BeforeEach(func() {
+ sprockets = []Sprocket{
+ NewSprocket("Alfalfa"),
+ NewSprocket("Banana"),
+ }
+ })
+
+ It("should return the returned sprockets", func() {
+ Ω(client.Sprockets()).Should(Equal(sprockets))
+ })
+ })
+
+ Context("when the response is missing", func() {
+ BeforeEach(func() {
+ statusCode = http.StatusNotFound
+ })
+
+ It("should return an empty list of sprockets", func() {
+ Ω(client.Sprockets()).Should(BeEmpty())
+ })
+ })
+
+ Context("when the response fails to authenticate", func() {
+ BeforeEach(func() {
+ statusCode = http.StatusUnauthorized
+ })
+
+ It("should return an AuthenticationError error", func() {
+ sprockets, err := client.Sprockets()
+ Ω(sprockets).Should(BeEmpty())
+ Ω(err).Should(MatchError(AuthenticationError))
+ })
+ })
+
+ Context("when the response is a server failure", func() {
+ BeforeEach(func() {
+ statusCode = http.StatusInternalServerError
+ })
+
+ It("should return an InternalError error", func() {
+ sprockets, err := client.Sprockets()
+ Ω(sprockets).Should(BeEmpty())
+ Ω(err).Should(MatchError(InternalError))
+ })
+ })
+ })
+
+ Context("when requesting some sprockets", func() {
+ BeforeEach(func() {
+ sprockets = []Sprocket{
+ NewSprocket("Alfalfa"),
+ NewSprocket("Banana"),
+ }
+
+ server.WrapHandler(0, ghttp.VerifyRequest("GET", "/sprockets", "filter=FOOD"))
+ })
+
+ It("should make the request with a filter", func() {
+ Ω(client.Sprockets("food")).Should(Equal(sprockets))
+ })
+ })
+ })
+ })
+*/
+package ghttp
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/http/httptest"
+ "reflect"
+ "regexp"
+ "strings"
+ "sync"
+
+ . "github.com/onsi/gomega"
+)
+
+func new() *Server {
+ return &Server{
+ AllowUnhandledRequests: false,
+ UnhandledRequestStatusCode: http.StatusInternalServerError,
+ writeLock: &sync.Mutex{},
+ }
+}
+
+type routedHandler struct {
+ method string
+ pathRegexp *regexp.Regexp
+ path string
+ handler http.HandlerFunc
+}
+
+// NewServer returns a new `*ghttp.Server` that wraps an `httptest` server. The server is started automatically.
+func NewServer() *Server {
+ s := new()
+ s.HTTPTestServer = httptest.NewServer(s)
+ return s
+}
+
+// NewUnstartedServer return a new, unstarted, `*ghttp.Server`. Useful for specifying a custom listener on `server.HTTPTestServer`.
+func NewUnstartedServer() *Server {
+ s := new()
+ s.HTTPTestServer = httptest.NewUnstartedServer(s)
+ return s
+}
+
+// NewTLSServer returns a new `*ghttp.Server` that wraps an `httptest` TLS server. The server is started automatically.
+func NewTLSServer() *Server {
+ s := new()
+ s.HTTPTestServer = httptest.NewTLSServer(s)
+ return s
+}
+
+type Server struct {
+ //The underlying httptest server
+ HTTPTestServer *httptest.Server
+
+ //Defaults to false. If set to true, the Server will allow more requests than there are registered handlers.
+ AllowUnhandledRequests bool
+
+ //The status code returned when receiving an unhandled request.
+ //Defaults to http.StatusInternalServerError.
+ //Only applies if AllowUnhandledRequests is true
+ UnhandledRequestStatusCode int
+
+ //If provided, ghttp will log about each request received to the provided io.Writer
+ //Defaults to nil
+ //If you're using Ginkgo, set this to GinkgoWriter to get improved output during failures
+ Writer io.Writer
+
+ receivedRequests []*http.Request
+ requestHandlers []http.HandlerFunc
+ routedHandlers []routedHandler
+
+ writeLock *sync.Mutex
+ calls int
+}
+
+//Start() starts an unstarted ghttp server. It is a catastrophic error to call Start more than once (thanks, httptest).
+func (s *Server) Start() {
+ s.HTTPTestServer.Start()
+}
+
+//URL() returns a url that will hit the server
+func (s *Server) URL() string {
+ return s.HTTPTestServer.URL
+}
+
+//Addr() returns the address on which the server is listening.
+func (s *Server) Addr() string {
+ return s.HTTPTestServer.Listener.Addr().String()
+}
+
+//Close() should be called at the end of each test. It spins down and cleans up the test server.
+func (s *Server) Close() {
+ s.writeLock.Lock()
+ server := s.HTTPTestServer
+ s.HTTPTestServer = nil
+ s.writeLock.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 true, the request will be handled with response code of UnhandledRequestStatusCode
+// b) If AllowUnhandledRequests is false, the request will not be handled and the current test will be marked as failed.
+func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ s.writeLock.Lock()
+ defer func() {
+ e := recover()
+ if e != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ }
+
+ //If the handler panics GHTTP will silently succeed. This is bad™.
+ //To catch this case we need to fail the test if the handler has panicked.
+ //However, if the handler is panicking because Ginkgo's causing it to panic (i.e. an assertion failed)
+ //then we shouldn't double-report the error as this will confuse people.
+
+ //So: step 1, if this is a Ginkgo panic - do nothing, Ginkgo's aware of the failure
+ eAsString, ok := e.(string)
+ if ok && strings.Contains(eAsString, "defer GinkgoRecover()") {
+ return
+ }
+
+ //If we're here, we have to do step 2: assert that the error is nil. This assertion will
+ //allow us to fail the test suite (note: we can't call Fail since Gomega is not allowed to import Ginkgo).
+ //Since a failed assertion throws a panic, and we are likely in a goroutine, we need to defer within our defer!
+ defer func() {
+ recover()
+ }()
+ Ω(e).Should(BeNil(), "Handler Panicked")
+ }()
+
+ if s.Writer != nil {
+ s.Writer.Write([]byte(fmt.Sprintf("GHTTP Received Request: %s - %s\n", req.Method, req.URL)))
+ }
+
+ s.receivedRequests = append(s.receivedRequests, req)
+ if routedHandler, ok := s.handlerForRoute(req.Method, req.URL.Path); ok {
+ s.writeLock.Unlock()
+ routedHandler(w, req)
+ } else if s.calls < len(s.requestHandlers) {
+ h := s.requestHandlers[s.calls]
+ s.calls++
+ s.writeLock.Unlock()
+ h(w, req)
+ } else {
+ s.writeLock.Unlock()
+ if s.AllowUnhandledRequests {
+ ioutil.ReadAll(req.Body)
+ req.Body.Close()
+ w.WriteHeader(s.UnhandledRequestStatusCode)
+ } else {
+ Ω(req).Should(BeNil(), "Received Unhandled Request")
+ }
+ }
+}
+
+//ReceivedRequests is an array containing all requests received by the server (both handled and unhandled requests)
+func (s *Server) ReceivedRequests() []*http.Request {
+ s.writeLock.Lock()
+ defer s.writeLock.Unlock()
+
+ return s.receivedRequests
+}
+
+//RouteToHandler can be used to register handlers that will always handle requests that match
+//the passed in method and path.
+//
+//The path may be either a string object or a *regexp.Regexp.
+func (s *Server) RouteToHandler(method string, path interface{}, handler http.HandlerFunc) {
+ s.writeLock.Lock()
+ defer s.writeLock.Unlock()
+
+ rh := routedHandler{
+ method: method,
+ handler: handler,
+ }
+
+ switch p := path.(type) {
+ case *regexp.Regexp:
+ rh.pathRegexp = p
+ case string:
+ rh.path = p
+ default:
+ panic("path must be a string or a regular expression")
+ }
+
+ for i, existingRH := range s.routedHandlers {
+ if existingRH.method == method &&
+ reflect.DeepEqual(existingRH.pathRegexp, rh.pathRegexp) &&
+ existingRH.path == rh.path {
+ s.routedHandlers[i] = rh
+ return
+ }
+ }
+ s.routedHandlers = append(s.routedHandlers, rh)
+}
+
+func (s *Server) handlerForRoute(method string, path string) (http.HandlerFunc, bool) {
+ for _, rh := range s.routedHandlers {
+ if rh.method == method {
+ if rh.pathRegexp != nil {
+ if rh.pathRegexp.Match([]byte(path)) {
+ return rh.handler, true
+ }
+ } else if rh.path == path {
+ return rh.handler, true
+ }
+ }
+ }
+
+ return nil, false
+}
+
+//AppendHandlers will appends http.HandlerFuncs to the server's list of registered handlers. The first incoming request is handled by the first handler, the second by the second, etc...
+func (s *Server) AppendHandlers(handlers ...http.HandlerFunc) {
+ s.writeLock.Lock()
+ defer s.writeLock.Unlock()
+
+ s.requestHandlers = append(s.requestHandlers, handlers...)
+}
+
+//SetHandler overrides the registered handler at the passed in index with the passed in handler
+//This is useful, for example, when a server has been set up in a shared context, but must be tweaked
+//for a particular test.
+func (s *Server) SetHandler(index int, handler http.HandlerFunc) {
+ s.writeLock.Lock()
+ defer s.writeLock.Unlock()
+
+ s.requestHandlers[index] = handler
+}
+
+//GetHandler returns the handler registered at the passed in index.
+func (s *Server) GetHandler(index int) http.HandlerFunc {
+ s.writeLock.Lock()
+ defer s.writeLock.Unlock()
+
+ return s.requestHandlers[index]
+}
+
+func (s *Server) Reset() {
+ s.writeLock.Lock()
+ defer s.writeLock.Unlock()
+
+ s.HTTPTestServer.CloseClientConnections()
+ s.calls = 0
+ s.receivedRequests = nil
+ s.requestHandlers = nil
+ s.routedHandlers = nil
+}
+
+//WrapHandler combines the passed in handler with the handler registered at the passed in index.
+//This is useful, for example, when a server has been set up in a shared context but must be tweaked
+//for a particular test.
+//
+//If the currently registered handler is A, and the new passed in handler is B then
+//WrapHandler will generate a new handler that first calls A, then calls B, and assign it to index
+func (s *Server) WrapHandler(index int, handler http.HandlerFunc) {
+ existingHandler := s.GetHandler(index)
+ s.SetHandler(index, CombineHandlers(existingHandler, handler))
+}
+
+func (s *Server) CloseClientConnections() {
+ s.writeLock.Lock()
+ defer s.writeLock.Unlock()
+
+ s.HTTPTestServer.CloseClientConnections()
+}
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 0000000..7c12360
--- /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 0000000..88b3246
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/ghttp/test_server_test.go
@@ -0,0 +1,1089 @@
+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() + "/")
+
+ Ω(s.ReceivedRequests()).Should(HaveLen(1))
+ })
+
+ It("clears all handlers and call counts", func() {
+ s.Reset()
+ Ω(s.ReceivedRequests()).Should(HaveLen(0))
+ Ω(func() { s.GetHandler(0) }).Should(Panic())
+ })
+ })
+
+ Describe("closing client connections", func() {
+ It("closes", func() {
+ s.RouteToHandler("GET", "/",
+ func(w http.ResponseWriter, req *http.Request) {
+ io.WriteString(w, req.RemoteAddr)
+ },
+ )
+ client := http.Client{Transport: &http.Transport{DisableKeepAlives: true}}
+ resp, err := client.Get(s.URL())
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(resp.StatusCode).Should(Equal(200))
+
+ body, err := ioutil.ReadAll(resp.Body)
+ resp.Body.Close()
+ Ω(err).ShouldNot(HaveOccurred())
+
+ s.CloseClientConnections()
+
+ resp, err = client.Get(s.URL())
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(resp.StatusCode).Should(Equal(200))
+
+ body2, err := ioutil.ReadAll(resp.Body)
+ resp.Body.Close()
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(body2).ShouldNot(Equal(body))
+ })
+ })
+
+ Describe("closing server mulitple times", func() {
+ It("should not fail", func() {
+ s.Close()
+ Ω(s.Close).ShouldNot(Panic())
+ })
+ })
+
+ Describe("allowing unhandled requests", func() {
+ Context("when true", func() {
+ BeforeEach(func() {
+ s.AllowUnhandledRequests = true
+ s.UnhandledRequestStatusCode = http.StatusForbidden
+ resp, err = http.Get(s.URL() + "/foo")
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should allow unhandled requests and respond with the passed in status code", func() {
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(resp.StatusCode).Should(Equal(http.StatusForbidden))
+
+ data, err := ioutil.ReadAll(resp.Body)
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(data).Should(BeEmpty())
+ })
+
+ It("should record the requests", func() {
+ Ω(s.ReceivedRequests()).Should(HaveLen(1))
+ Ω(s.ReceivedRequests()[0].URL.Path).Should(Equal("/foo"))
+ })
+ })
+
+ Context("when false", func() {
+ It("should fail when attempting a request", func() {
+ failures := InterceptGomegaFailures(func() {
+ http.Get(s.URL() + "/foo")
+ })
+
+ Ω(failures[0]).Should(ContainSubstring("Received Unhandled Request"))
+ })
+ })
+ })
+
+ Describe("Managing Handlers", func() {
+ var called []string
+ BeforeEach(func() {
+ called = []string{}
+ s.RouteToHandler("GET", "/routed", func(w http.ResponseWriter, req *http.Request) {
+ called = append(called, "r1")
+ })
+ s.RouteToHandler("POST", regexp.MustCompile(`/routed\d`), func(w http.ResponseWriter, req *http.Request) {
+ called = append(called, "r2")
+ })
+ s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) {
+ called = append(called, "A")
+ }, func(w http.ResponseWriter, req *http.Request) {
+ called = append(called, "B")
+ })
+ })
+
+ It("should prefer routed handlers if there is a match", func() {
+ http.Get(s.URL() + "/routed")
+ http.Post(s.URL()+"/routed7", "application/json", nil)
+ http.Get(s.URL() + "/foo")
+ http.Get(s.URL() + "/routed")
+ http.Post(s.URL()+"/routed9", "application/json", nil)
+ http.Get(s.URL() + "/bar")
+
+ failures := InterceptGomegaFailures(func() {
+ http.Get(s.URL() + "/foo")
+ http.Get(s.URL() + "/routed/not/a/match")
+ http.Get(s.URL() + "/routed7")
+ http.Post(s.URL()+"/routed", "application/json", nil)
+ })
+
+ Ω(failures[0]).Should(ContainSubstring("Received Unhandled Request"))
+ Ω(failures).Should(HaveLen(4))
+
+ http.Post(s.URL()+"/routed3", "application/json", nil)
+
+ Ω(called).Should(Equal([]string{"r1", "r2", "A", "r1", "r2", "B", "r2"}))
+ })
+
+ It("should override routed handlers when reregistered", func() {
+ s.RouteToHandler("GET", "/routed", func(w http.ResponseWriter, req *http.Request) {
+ called = append(called, "r3")
+ })
+ s.RouteToHandler("POST", regexp.MustCompile(`/routed\d`), func(w http.ResponseWriter, req *http.Request) {
+ called = append(called, "r4")
+ })
+
+ http.Get(s.URL() + "/routed")
+ http.Post(s.URL()+"/routed7", "application/json", nil)
+
+ Ω(called).Should(Equal([]string{"r3", "r4"}))
+ })
+
+ It("should call the appended handlers, in order, as requests come in", func() {
+ http.Get(s.URL() + "/foo")
+ Ω(called).Should(Equal([]string{"A"}))
+
+ http.Get(s.URL() + "/foo")
+ Ω(called).Should(Equal([]string{"A", "B"}))
+
+ failures := InterceptGomegaFailures(func() {
+ http.Get(s.URL() + "/foo")
+ })
+
+ Ω(failures[0]).Should(ContainSubstring("Received Unhandled Request"))
+ })
+
+ Describe("Overwriting an existing handler", func() {
+ BeforeEach(func() {
+ s.SetHandler(0, func(w http.ResponseWriter, req *http.Request) {
+ called = append(called, "C")
+ })
+ })
+
+ It("should override the specified handler", func() {
+ http.Get(s.URL() + "/foo")
+ http.Get(s.URL() + "/foo")
+ Ω(called).Should(Equal([]string{"C", "B"}))
+ })
+ })
+
+ Describe("Getting an existing handler", func() {
+ It("should return the handler func", func() {
+ s.GetHandler(1)(nil, nil)
+ Ω(called).Should(Equal([]string{"B"}))
+ })
+ })
+
+ Describe("Wrapping an existing handler", func() {
+ BeforeEach(func() {
+ s.WrapHandler(0, func(w http.ResponseWriter, req *http.Request) {
+ called = append(called, "C")
+ })
+ })
+
+ It("should wrap the existing handler in a new handler", func() {
+ http.Get(s.URL() + "/foo")
+ http.Get(s.URL() + "/foo")
+ Ω(called).Should(Equal([]string{"A", "C", "B"}))
+ })
+ })
+ })
+
+ Describe("When a handler fails", func() {
+ BeforeEach(func() {
+ s.UnhandledRequestStatusCode = http.StatusForbidden //just to be clear that 500s aren't coming from unhandled requests
+ })
+
+ Context("because the handler has panicked", func() {
+ BeforeEach(func() {
+ s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) {
+ panic("bam")
+ })
+ })
+
+ It("should respond with a 500 and make a failing assertion", func() {
+ var resp *http.Response
+ var err error
+
+ failures := InterceptGomegaFailures(func() {
+ resp, err = http.Get(s.URL())
+ })
+
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(resp.StatusCode).Should(Equal(http.StatusInternalServerError))
+ Ω(failures).Should(ConsistOf(ContainSubstring("Handler Panicked")))
+ })
+ })
+
+ Context("because an assertion has failed", func() {
+ BeforeEach(func() {
+ s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) {
+ // Ω(true).Should(BeFalse()) <-- would be nice to do it this way, but the test just can't be written this way
+
+ By("We're cheating a bit here -- we're throwing a GINKGO_PANIC which simulates a failed assertion")
+ panic(GINKGO_PANIC)
+ })
+ })
+
+ It("should respond with a 500 and *not* make a failing assertion, instead relying on Ginkgo to have already been notified of the error", func() {
+ resp, err := http.Get(s.URL())
+
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(resp.StatusCode).Should(Equal(http.StatusInternalServerError))
+ })
+ })
+ })
+
+ Describe("Logging to the Writer", func() {
+ var buf *gbytes.Buffer
+ BeforeEach(func() {
+ buf = gbytes.NewBuffer()
+ s.Writer = buf
+ s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) {})
+ s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) {})
+ })
+
+ It("should write to the buffer when a request comes in", func() {
+ http.Get(s.URL() + "/foo")
+ Ω(buf).Should(gbytes.Say("GHTTP Received Request: GET - /foo\n"))
+
+ http.Post(s.URL()+"/bar", "", nil)
+ Ω(buf).Should(gbytes.Say("GHTTP Received Request: POST - /bar\n"))
+ })
+ })
+
+ Describe("Request Handlers", func() {
+ Describe("VerifyRequest", func() {
+ BeforeEach(func() {
+ s.AppendHandlers(VerifyRequest("GET", "/foo"))
+ })
+
+ It("should verify the method, path", func() {
+ resp, err = http.Get(s.URL() + "/foo?baz=bar")
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should verify the method, path", func() {
+ failures := InterceptGomegaFailures(func() {
+ http.Get(s.URL() + "/foo2")
+ })
+ Ω(failures).Should(HaveLen(1))
+ })
+
+ It("should verify the method, path", func() {
+ failures := InterceptGomegaFailures(func() {
+ http.Post(s.URL()+"/foo", "application/json", nil)
+ })
+ Ω(failures).Should(HaveLen(1))
+ })
+
+ Context("when passed a rawQuery", func() {
+ It("should also be possible to verify the rawQuery", func() {
+ s.SetHandler(0, VerifyRequest("GET", "/foo", "baz=bar"))
+ resp, err = http.Get(s.URL() + "/foo?baz=bar")
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should match irregardless of query parameter ordering", func() {
+ s.SetHandler(0, VerifyRequest("GET", "/foo", "type=get&name=money"))
+ u, _ := url.Parse(s.URL() + "/foo")
+ u.RawQuery = url.Values{
+ "type": []string{"get"},
+ "name": []string{"money"},
+ }.Encode()
+
+ resp, err = http.Get(u.String())
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+ })
+
+ Context("when passed a matcher for path", func() {
+ It("should apply the matcher", func() {
+ s.SetHandler(0, VerifyRequest("GET", MatchRegexp(`/foo/[a-f]*/3`)))
+ resp, err = http.Get(s.URL() + "/foo/abcdefa/3")
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+ })
+ })
+
+ Describe("VerifyContentType", func() {
+ BeforeEach(func() {
+ s.AppendHandlers(CombineHandlers(
+ VerifyRequest("GET", "/foo"),
+ VerifyContentType("application/octet-stream"),
+ ))
+ })
+
+ It("should verify the content type", func() {
+ req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+ req.Header.Set("Content-Type", "application/octet-stream")
+
+ resp, err = http.DefaultClient.Do(req)
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should verify the content type", func() {
+ req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+ req.Header.Set("Content-Type", "application/json")
+
+ failures := InterceptGomegaFailures(func() {
+ http.DefaultClient.Do(req)
+ })
+ Ω(failures).Should(HaveLen(1))
+ })
+ })
+
+ Describe("Verify BasicAuth", func() {
+ BeforeEach(func() {
+ s.AppendHandlers(CombineHandlers(
+ VerifyRequest("GET", "/foo"),
+ VerifyBasicAuth("bob", "password"),
+ ))
+ })
+
+ It("should verify basic auth", func() {
+ req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+ req.SetBasicAuth("bob", "password")
+
+ resp, err = http.DefaultClient.Do(req)
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should verify basic auth", func() {
+ req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+ req.SetBasicAuth("bob", "bassword")
+
+ failures := InterceptGomegaFailures(func() {
+ http.DefaultClient.Do(req)
+ })
+ Ω(failures).Should(HaveLen(1))
+ })
+
+ It("should require basic auth header", func() {
+ req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ failures := InterceptGomegaFailures(func() {
+ http.DefaultClient.Do(req)
+ })
+ Ω(failures).Should(ContainElement(ContainSubstring("Authorization header must be specified")))
+ })
+ })
+
+ Describe("VerifyHeader", func() {
+ BeforeEach(func() {
+ s.AppendHandlers(CombineHandlers(
+ VerifyRequest("GET", "/foo"),
+ VerifyHeader(http.Header{
+ "accept": []string{"jpeg", "png"},
+ "cache-control": []string{"omicron"},
+ "Return-Path": []string{"hobbiton"},
+ }),
+ ))
+ })
+
+ It("should verify the headers", func() {
+ req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+ req.Header.Add("Accept", "jpeg")
+ req.Header.Add("Accept", "png")
+ req.Header.Add("Cache-Control", "omicron")
+ req.Header.Add("return-path", "hobbiton")
+
+ resp, err = http.DefaultClient.Do(req)
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should verify the headers", func() {
+ req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+ req.Header.Add("Schmaccept", "jpeg")
+ req.Header.Add("Schmaccept", "png")
+ req.Header.Add("Cache-Control", "omicron")
+ req.Header.Add("return-path", "hobbiton")
+
+ failures := InterceptGomegaFailures(func() {
+ http.DefaultClient.Do(req)
+ })
+ Ω(failures).Should(HaveLen(1))
+ })
+ })
+
+ Describe("VerifyHeaderKV", func() {
+ BeforeEach(func() {
+ s.AppendHandlers(CombineHandlers(
+ VerifyRequest("GET", "/foo"),
+ VerifyHeaderKV("accept", "jpeg", "png"),
+ VerifyHeaderKV("cache-control", "omicron"),
+ VerifyHeaderKV("Return-Path", "hobbiton"),
+ ))
+ })
+
+ It("should verify the headers", func() {
+ req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+ req.Header.Add("Accept", "jpeg")
+ req.Header.Add("Accept", "png")
+ req.Header.Add("Cache-Control", "omicron")
+ req.Header.Add("return-path", "hobbiton")
+
+ resp, err = http.DefaultClient.Do(req)
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should verify the headers", func() {
+ req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+ req.Header.Add("Accept", "jpeg")
+ req.Header.Add("Cache-Control", "omicron")
+ req.Header.Add("return-path", "hobbiton")
+
+ failures := InterceptGomegaFailures(func() {
+ http.DefaultClient.Do(req)
+ })
+ Ω(failures).Should(HaveLen(1))
+ })
+ })
+
+ Describe("VerifyBody", func() {
+ BeforeEach(func() {
+ s.AppendHandlers(CombineHandlers(
+ VerifyRequest("POST", "/foo"),
+ VerifyBody([]byte("some body")),
+ ))
+ })
+
+ It("should verify the body", func() {
+ resp, err = http.Post(s.URL()+"/foo", "", bytes.NewReader([]byte("some body")))
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should verify the body", func() {
+ failures := InterceptGomegaFailures(func() {
+ http.Post(s.URL()+"/foo", "", bytes.NewReader([]byte("wrong body")))
+ })
+ Ω(failures).Should(HaveLen(1))
+ })
+ })
+
+ Describe("VerifyJSON", func() {
+ BeforeEach(func() {
+ s.AppendHandlers(CombineHandlers(
+ VerifyRequest("POST", "/foo"),
+ VerifyJSON(`{"a":3, "b":2}`),
+ ))
+ })
+
+ It("should verify the json body and the content type", func() {
+ resp, err = http.Post(s.URL()+"/foo", "application/json", bytes.NewReader([]byte(`{"b":2, "a":3}`)))
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should verify the json body and the content type", func() {
+ failures := InterceptGomegaFailures(func() {
+ http.Post(s.URL()+"/foo", "application/json", bytes.NewReader([]byte(`{"b":2, "a":4}`)))
+ })
+ Ω(failures).Should(HaveLen(1))
+ })
+
+ It("should verify the json body and the content type", func() {
+ failures := InterceptGomegaFailures(func() {
+ http.Post(s.URL()+"/foo", "application/not-json", bytes.NewReader([]byte(`{"b":2, "a":3}`)))
+ })
+ Ω(failures).Should(HaveLen(1))
+ })
+ })
+
+ Describe("VerifyJSONRepresenting", func() {
+ BeforeEach(func() {
+ s.AppendHandlers(CombineHandlers(
+ VerifyRequest("POST", "/foo"),
+ VerifyJSONRepresenting([]int{1, 3, 5}),
+ ))
+ })
+
+ It("should verify the json body and the content type", func() {
+ resp, err = http.Post(s.URL()+"/foo", "application/json", bytes.NewReader([]byte(`[1,3,5]`)))
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should verify the json body and the content type", func() {
+ failures := InterceptGomegaFailures(func() {
+ http.Post(s.URL()+"/foo", "application/json", bytes.NewReader([]byte(`[1,3]`)))
+ })
+ Ω(failures).Should(HaveLen(1))
+ })
+ })
+
+ Describe("VerifyForm", func() {
+ var formValues url.Values
+
+ BeforeEach(func() {
+ formValues = make(url.Values)
+ formValues.Add("users", "user1")
+ formValues.Add("users", "user2")
+ formValues.Add("group", "users")
+ })
+
+ Context("when encoded in the URL", func() {
+ BeforeEach(func() {
+ s.AppendHandlers(CombineHandlers(
+ VerifyRequest("GET", "/foo"),
+ VerifyForm(url.Values{
+ "users": []string{"user1", "user2"},
+ "group": []string{"users"},
+ }),
+ ))
+ })
+
+ It("should verify form values", func() {
+ resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode())
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should ignore extra values", func() {
+ formValues.Add("extra", "value")
+ resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode())
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+
+ It("fail on missing values", func() {
+ formValues.Del("group")
+ failures := InterceptGomegaFailures(func() {
+ resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode())
+ })
+ Ω(failures).Should(HaveLen(1))
+ })
+
+ It("fail on incorrect values", func() {
+ formValues.Set("group", "wheel")
+ failures := InterceptGomegaFailures(func() {
+ resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode())
+ })
+ Ω(failures).Should(HaveLen(1))
+ })
+ })
+
+ Context("when present in the body", func() {
+ BeforeEach(func() {
+ s.AppendHandlers(CombineHandlers(
+ VerifyRequest("POST", "/foo"),
+ VerifyForm(url.Values{
+ "users": []string{"user1", "user2"},
+ "group": []string{"users"},
+ }),
+ ))
+ })
+
+ It("should verify form values", func() {
+ resp, err = http.PostForm(s.URL()+"/foo", formValues)
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should ignore extra values", func() {
+ formValues.Add("extra", "value")
+ resp, err = http.PostForm(s.URL()+"/foo", formValues)
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+
+ It("fail on missing values", func() {
+ formValues.Del("group")
+ failures := InterceptGomegaFailures(func() {
+ resp, err = http.PostForm(s.URL()+"/foo", formValues)
+ })
+ Ω(failures).Should(HaveLen(1))
+ })
+
+ It("fail on incorrect values", func() {
+ formValues.Set("group", "wheel")
+ failures := InterceptGomegaFailures(func() {
+ resp, err = http.PostForm(s.URL()+"/foo", formValues)
+ })
+ Ω(failures).Should(HaveLen(1))
+ })
+ })
+ })
+
+ Describe("VerifyFormKV", func() {
+ Context("when encoded in the URL", func() {
+ BeforeEach(func() {
+ s.AppendHandlers(CombineHandlers(
+ VerifyRequest("GET", "/foo"),
+ VerifyFormKV("users", "user1", "user2"),
+ ))
+ })
+
+ It("verifies the form value", func() {
+ resp, err = http.Get(s.URL() + "/foo?users=user1&users=user2")
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+
+ It("verifies the form value", func() {
+ failures := InterceptGomegaFailures(func() {
+ resp, err = http.Get(s.URL() + "/foo?users=user1")
+ })
+ Ω(failures).Should(HaveLen(1))
+ })
+ })
+
+ Context("when present in the body", func() {
+ BeforeEach(func() {
+ s.AppendHandlers(CombineHandlers(
+ VerifyRequest("POST", "/foo"),
+ VerifyFormKV("users", "user1", "user2"),
+ ))
+ })
+
+ It("verifies the form value", func() {
+ resp, err = http.PostForm(s.URL()+"/foo", url.Values{"users": []string{"user1", "user2"}})
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+
+ It("verifies the form value", func() {
+ failures := InterceptGomegaFailures(func() {
+ resp, err = http.PostForm(s.URL()+"/foo", url.Values{"users": []string{"user1"}})
+ })
+ Ω(failures).Should(HaveLen(1))
+ })
+ })
+ })
+
+ Describe("VerifyProtoRepresenting", func() {
+ var message *protobuf.SimpleMessage
+
+ BeforeEach(func() {
+ message = new(protobuf.SimpleMessage)
+ message.Description = proto.String("A description")
+ message.Id = proto.Int32(0)
+
+ s.AppendHandlers(CombineHandlers(
+ VerifyRequest("POST", "/proto"),
+ VerifyProtoRepresenting(message),
+ ))
+ })
+
+ It("verifies the proto body and the content type", func() {
+ serialized, err := proto.Marshal(message)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", bytes.NewReader(serialized))
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should verify the proto body and the content type", func() {
+ serialized, err := proto.Marshal(&protobuf.SimpleMessage{
+ Description: proto.String("A description"),
+ Id: proto.Int32(0),
+ Metadata: proto.String("some metadata"),
+ })
+ Ω(err).ShouldNot(HaveOccurred())
+
+ failures := InterceptGomegaFailures(func() {
+ http.Post(s.URL()+"/proto", "application/x-protobuf", bytes.NewReader(serialized))
+ })
+ Ω(failures).Should(HaveLen(1))
+ })
+
+ It("should verify the proto body and the content type", func() {
+ serialized, err := proto.Marshal(message)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ failures := InterceptGomegaFailures(func() {
+ http.Post(s.URL()+"/proto", "application/not-x-protobuf", bytes.NewReader(serialized))
+ })
+ Ω(failures).Should(HaveLen(1))
+ })
+ })
+
+ Describe("RespondWith", func() {
+ Context("without headers", func() {
+ BeforeEach(func() {
+ s.AppendHandlers(CombineHandlers(
+ VerifyRequest("POST", "/foo"),
+ RespondWith(http.StatusCreated, "sweet"),
+ ), CombineHandlers(
+ VerifyRequest("POST", "/foo"),
+ RespondWith(http.StatusOK, []byte("sour")),
+ ))
+ })
+
+ It("should return the response", func() {
+ resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(resp.StatusCode).Should(Equal(http.StatusCreated))
+
+ body, err := ioutil.ReadAll(resp.Body)
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(body).Should(Equal([]byte("sweet")))
+
+ resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(resp.StatusCode).Should(Equal(http.StatusOK))
+
+ body, err = ioutil.ReadAll(resp.Body)
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(body).Should(Equal([]byte("sour")))
+ })
+ })
+
+ Context("with headers", func() {
+ BeforeEach(func() {
+ s.AppendHandlers(CombineHandlers(
+ VerifyRequest("POST", "/foo"),
+ RespondWith(http.StatusCreated, "sweet", http.Header{"X-Custom-Header": []string{"my header"}}),
+ ))
+ })
+
+ It("should return the headers too", func() {
+ resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(resp.StatusCode).Should(Equal(http.StatusCreated))
+ Ω(ioutil.ReadAll(resp.Body)).Should(Equal([]byte("sweet")))
+ Ω(resp.Header.Get("X-Custom-Header")).Should(Equal("my header"))
+ })
+ })
+ })
+
+ Describe("RespondWithPtr", func() {
+ var code int
+ var byteBody []byte
+ var stringBody string
+ BeforeEach(func() {
+ code = http.StatusOK
+ byteBody = []byte("sweet")
+ stringBody = "sour"
+
+ s.AppendHandlers(CombineHandlers(
+ VerifyRequest("POST", "/foo"),
+ RespondWithPtr(&code, &byteBody),
+ ), CombineHandlers(
+ VerifyRequest("POST", "/foo"),
+ RespondWithPtr(&code, &stringBody),
+ ))
+ })
+
+ It("should return the response", func() {
+ code = http.StatusCreated
+ byteBody = []byte("tasty")
+ stringBody = "treat"
+
+ resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(resp.StatusCode).Should(Equal(http.StatusCreated))
+
+ body, err := ioutil.ReadAll(resp.Body)
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(body).Should(Equal([]byte("tasty")))
+
+ resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(resp.StatusCode).Should(Equal(http.StatusCreated))
+
+ body, err = ioutil.ReadAll(resp.Body)
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(body).Should(Equal([]byte("treat")))
+ })
+
+ Context("when passed a nil body", func() {
+ BeforeEach(func() {
+ s.SetHandler(0, CombineHandlers(
+ VerifyRequest("POST", "/foo"),
+ RespondWithPtr(&code, nil),
+ ))
+ })
+
+ It("should return an empty body and not explode", func() {
+ resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
+
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(resp.StatusCode).Should(Equal(http.StatusOK))
+ body, err := ioutil.ReadAll(resp.Body)
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(body).Should(BeEmpty())
+
+ Ω(s.ReceivedRequests()).Should(HaveLen(1))
+ })
+ })
+ })
+
+ Describe("RespondWithJSON", func() {
+ Context("when no optional headers are set", func() {
+ BeforeEach(func() {
+ s.AppendHandlers(CombineHandlers(
+ VerifyRequest("POST", "/foo"),
+ RespondWithJSONEncoded(http.StatusCreated, []int{1, 2, 3}),
+ ))
+ })
+
+ It("should return the response", func() {
+ resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(resp.StatusCode).Should(Equal(http.StatusCreated))
+
+ body, err := ioutil.ReadAll(resp.Body)
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(body).Should(MatchJSON("[1,2,3]"))
+ })
+
+ It("should set the Content-Type header to application/json", func() {
+ resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"}))
+ })
+ })
+
+ Context("when optional headers are set", func() {
+ var headers http.Header
+ BeforeEach(func() {
+ headers = http.Header{"Stuff": []string{"things"}}
+ })
+
+ JustBeforeEach(func() {
+ s.AppendHandlers(CombineHandlers(
+ VerifyRequest("POST", "/foo"),
+ RespondWithJSONEncoded(http.StatusCreated, []int{1, 2, 3}, headers),
+ ))
+ })
+
+ It("should preserve those headers", func() {
+ resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(resp.Header["Stuff"]).Should(Equal([]string{"things"}))
+ })
+
+ It("should set the Content-Type header to application/json", func() {
+ resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"}))
+ })
+
+ Context("when setting the Content-Type explicitly", func() {
+ BeforeEach(func() {
+ headers["Content-Type"] = []string{"not-json"}
+ })
+
+ It("should use the Content-Type header that was explicitly set", func() {
+ resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(resp.Header["Content-Type"]).Should(Equal([]string{"not-json"}))
+ })
+ })
+ })
+ })
+
+ Describe("RespondWithJSONPtr", func() {
+ type testObject struct {
+ Key string
+ Value string
+ }
+
+ var code int
+ var object testObject
+
+ Context("when no optional headers are set", func() {
+ BeforeEach(func() {
+ code = http.StatusOK
+ object = testObject{}
+ s.AppendHandlers(CombineHandlers(
+ VerifyRequest("POST", "/foo"),
+ RespondWithJSONEncodedPtr(&code, &object),
+ ))
+ })
+
+ It("should return the response", func() {
+ code = http.StatusCreated
+ object = testObject{
+ Key: "Jim",
+ Value: "Codes",
+ }
+ resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(resp.StatusCode).Should(Equal(http.StatusCreated))
+
+ body, err := ioutil.ReadAll(resp.Body)
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(body).Should(MatchJSON(`{"Key": "Jim", "Value": "Codes"}`))
+ })
+
+ It("should set the Content-Type header to application/json", func() {
+ resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"}))
+ })
+ })
+
+ Context("when optional headers are set", func() {
+ var headers http.Header
+ BeforeEach(func() {
+ headers = http.Header{"Stuff": []string{"things"}}
+ })
+
+ JustBeforeEach(func() {
+ code = http.StatusOK
+ object = testObject{}
+ s.AppendHandlers(CombineHandlers(
+ VerifyRequest("POST", "/foo"),
+ RespondWithJSONEncodedPtr(&code, &object, headers),
+ ))
+ })
+
+ It("should preserve those headers", func() {
+ resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(resp.Header["Stuff"]).Should(Equal([]string{"things"}))
+ })
+
+ It("should set the Content-Type header to application/json", func() {
+ resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"}))
+ })
+
+ Context("when setting the Content-Type explicitly", func() {
+ BeforeEach(func() {
+ headers["Content-Type"] = []string{"not-json"}
+ })
+
+ It("should use the Content-Type header that was explicitly set", func() {
+ resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(resp.Header["Content-Type"]).Should(Equal([]string{"not-json"}))
+ })
+ })
+ })
+ })
+
+ Describe("RespondWithProto", func() {
+ var message *protobuf.SimpleMessage
+
+ BeforeEach(func() {
+ message = new(protobuf.SimpleMessage)
+ message.Description = proto.String("A description")
+ message.Id = proto.Int32(99)
+ })
+
+ Context("when no optional headers are set", func() {
+ BeforeEach(func() {
+ s.AppendHandlers(CombineHandlers(
+ VerifyRequest("POST", "/proto"),
+ RespondWithProto(http.StatusCreated, message),
+ ))
+ })
+
+ It("should return the response", func() {
+ resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(resp.StatusCode).Should(Equal(http.StatusCreated))
+
+ var received protobuf.SimpleMessage
+ body, err := ioutil.ReadAll(resp.Body)
+ err = proto.Unmarshal(body, &received)
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+
+ It("should set the Content-Type header to application/x-protobuf", func() {
+ resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/x-protobuf"}))
+ })
+ })
+
+ Context("when optional headers are set", func() {
+ var headers http.Header
+ BeforeEach(func() {
+ headers = http.Header{"Stuff": []string{"things"}}
+ })
+
+ JustBeforeEach(func() {
+ s.AppendHandlers(CombineHandlers(
+ VerifyRequest("POST", "/proto"),
+ RespondWithProto(http.StatusCreated, message, headers),
+ ))
+ })
+
+ It("should preserve those headers", func() {
+ resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(resp.Header["Stuff"]).Should(Equal([]string{"things"}))
+ })
+
+ It("should set the Content-Type header to application/x-protobuf", func() {
+ resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/x-protobuf"}))
+ })
+
+ Context("when setting the Content-Type explicitly", func() {
+ BeforeEach(func() {
+ headers["Content-Type"] = []string{"not-x-protobuf"}
+ })
+
+ It("should use the Content-Type header that was explicitly set", func() {
+ resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(resp.Header["Content-Type"]).Should(Equal([]string{"not-x-protobuf"}))
+ })
+ })
+ })
+ })
+ })
+})
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 0000000..78bd188
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gomega_dsl.go
@@ -0,0 +1,335 @@
+/*
+Gomega is the Ginkgo BDD-style testing framework's preferred matcher library.
+
+The godoc documentation describes Gomega's API. More comprehensive documentation (with examples!) is available at http://onsi.github.io/gomega/
+
+Gomega on Github: http://github.com/onsi/gomega
+
+Learn more about Ginkgo online: http://onsi.github.io/ginkgo
+
+Ginkgo on Github: http://github.com/onsi/ginkgo
+
+Gomega is MIT-Licensed
+*/
+package gomega
+
+import (
+ "fmt"
+ "reflect"
+ "time"
+
+ "github.com/onsi/gomega/internal/assertion"
+ "github.com/onsi/gomega/internal/asyncassertion"
+ "github.com/onsi/gomega/internal/testingtsupport"
+ "github.com/onsi/gomega/types"
+)
+
+const GOMEGA_VERSION = "1.0"
+
+const nilFailHandlerPanic = `You are trying to make an assertion, but Gomega's fail handler is nil.
+If you're using Ginkgo then you probably forgot to put your assertion in an It().
+Alternatively, you may have forgotten to register a fail handler with RegisterFailHandler() or RegisterTestingT().
+`
+
+var globalFailHandler types.GomegaFailHandler
+
+var defaultEventuallyTimeout = time.Second
+var defaultEventuallyPollingInterval = 10 * time.Millisecond
+var defaultConsistentlyDuration = 100 * time.Millisecond
+var defaultConsistentlyPollingInterval = 10 * time.Millisecond
+
+//RegisterFailHandler connects Ginkgo to Gomega. When a matcher fails
+//the fail handler passed into RegisterFailHandler is called.
+func RegisterFailHandler(handler types.GomegaFailHandler) {
+ globalFailHandler = handler
+}
+
+//RegisterTestingT connects Gomega to Golang's XUnit style
+//Testing.T tests. You'll need to call this at the top of each XUnit style test:
+//
+// func TestFarmHasCow(t *testing.T) {
+// RegisterTestingT(t)
+//
+// f := farm.New([]string{"Cow", "Horse"})
+// Expect(f.HasCow()).To(BeTrue(), "Farm should have cow")
+// }
+//
+// Note that this *testing.T is registered *globally* by Gomega (this is why you don't have to
+// pass `t` down to the matcher itself). This means that you cannot run the XUnit style tests
+// in parallel as the global fail handler cannot point to more than one testing.T at a time.
+//
+// (As an aside: Ginkgo gets around this limitation by running parallel tests in different *processes*).
+func RegisterTestingT(t types.GomegaTestingT) {
+ RegisterFailHandler(testingtsupport.BuildTestingTGomegaFailHandler(t))
+}
+
+//InterceptGomegaHandlers runs a given callback and returns an array of
+//failure messages generated by any Gomega assertions within the callback.
+//
+//This is accomplished by temporarily replacing the *global* fail handler
+//with a fail handler that simply annotates failures. The original fail handler
+//is reset when InterceptGomegaFailures returns.
+//
+//This is most useful when testing custom matchers, but can also be used to check
+//on a value using a Gomega assertion without causing a test failure.
+func InterceptGomegaFailures(f func()) []string {
+ originalHandler := globalFailHandler
+ failures := []string{}
+ RegisterFailHandler(func(message string, callerSkip ...int) {
+ failures = append(failures, message)
+ })
+ f()
+ RegisterFailHandler(originalHandler)
+ return failures
+}
+
+//Ω wraps an actual value allowing assertions to be made on it:
+// Ω("foo").Should(Equal("foo"))
+//
+//If Ω is passed more than one argument it will pass the *first* argument to the matcher.
+//All subsequent arguments will be required to be nil/zero.
+//
+//This is convenient if you want to make an assertion on a method/function that returns
+//a value and an error - a common patter in Go.
+//
+//For example, given a function with signature:
+// func MyAmazingThing() (int, error)
+//
+//Then:
+// Ω(MyAmazingThing()).Should(Equal(3))
+//Will succeed only if `MyAmazingThing()` returns `(3, nil)`
+//
+//Ω and Expect are identical
+func Ω(actual interface{}, extra ...interface{}) GomegaAssertion {
+ return ExpectWithOffset(0, actual, extra...)
+}
+
+//Expect wraps an actual value allowing assertions to be made on it:
+// Expect("foo").To(Equal("foo"))
+//
+//If Expect is passed more than one argument it will pass the *first* argument to the matcher.
+//All subsequent arguments will be required to be nil/zero.
+//
+//This is convenient if you want to make an assertion on a method/function that returns
+//a value and an error - a common patter in Go.
+//
+//For example, given a function with signature:
+// func MyAmazingThing() (int, error)
+//
+//Then:
+// Expect(MyAmazingThing()).Should(Equal(3))
+//Will succeed only if `MyAmazingThing()` returns `(3, nil)`
+//
+//Expect and Ω are identical
+func Expect(actual interface{}, extra ...interface{}) GomegaAssertion {
+ return ExpectWithOffset(0, actual, extra...)
+}
+
+//ExpectWithOffset wraps an actual value allowing assertions to be made on it:
+// ExpectWithOffset(1, "foo").To(Equal("foo"))
+//
+//Unlike `Expect` and `Ω`, `ExpectWithOffset` takes an additional integer argument
+//this is used to modify the call-stack offset when computing line numbers.
+//
+//This is most useful in helper functions that make assertions. If you want Gomega's
+//error message to refer to the calling line in the test (as opposed to the line in the helper function)
+//set the first argument of `ExpectWithOffset` appropriately.
+func ExpectWithOffset(offset int, actual interface{}, extra ...interface{}) GomegaAssertion {
+ if globalFailHandler == nil {
+ panic(nilFailHandlerPanic)
+ }
+ return assertion.New(actual, globalFailHandler, offset, extra...)
+}
+
+//Eventually wraps an actual value allowing assertions to be made on it.
+//The assertion is tried periodically until it passes or a timeout occurs.
+//
+//Both the timeout and polling interval are configurable as optional arguments:
+//The first optional argument is the timeout
+//The second optional argument is the polling interval
+//
+//Both intervals can either be specified as time.Duration, parsable duration strings or as floats/integers. In the
+//last case they are interpreted as seconds.
+//
+//If Eventually is passed an actual that is a function taking no arguments and returning at least one value,
+//then Eventually will call the function periodically and try the matcher against the function's first return value.
+//
+//Example:
+//
+// Eventually(func() int {
+// return thingImPolling.Count()
+// }).Should(BeNumerically(">=", 17))
+//
+//Note that this example could be rewritten:
+//
+// Eventually(thingImPolling.Count).Should(BeNumerically(">=", 17))
+//
+//If the function returns more than one value, then Eventually will pass the first value to the matcher and
+//assert that all other values are nil/zero.
+//This allows you to pass Eventually a function that returns a value and an error - a common pattern in Go.
+//
+//For example, consider a method that returns a value and an error:
+// func FetchFromDB() (string, error)
+//
+//Then
+// Eventually(FetchFromDB).Should(Equal("hasselhoff"))
+//
+//Will pass only if the the returned error is nil and the returned string passes the matcher.
+//
+//Eventually's default timeout is 1 second, and its default polling interval is 10ms
+func Eventually(actual interface{}, intervals ...interface{}) GomegaAsyncAssertion {
+ return EventuallyWithOffset(0, actual, intervals...)
+}
+
+//EventuallyWithOffset operates like Eventually but takes an additional
+//initial argument to indicate an offset in the call stack. This is useful when building helper
+//functions that contain matchers. To learn more, read about `ExpectWithOffset`.
+func EventuallyWithOffset(offset int, actual interface{}, intervals ...interface{}) GomegaAsyncAssertion {
+ if globalFailHandler == nil {
+ panic(nilFailHandlerPanic)
+ }
+ timeoutInterval := defaultEventuallyTimeout
+ pollingInterval := defaultEventuallyPollingInterval
+ if len(intervals) > 0 {
+ timeoutInterval = toDuration(intervals[0])
+ }
+ if len(intervals) > 1 {
+ pollingInterval = toDuration(intervals[1])
+ }
+ return asyncassertion.New(asyncassertion.AsyncAssertionTypeEventually, actual, globalFailHandler, timeoutInterval, pollingInterval, offset)
+}
+
+//Consistently wraps an actual value allowing assertions to be made on it.
+//The assertion is tried periodically and is required to pass for a period of time.
+//
+//Both the total time and polling interval are configurable as optional arguments:
+//The first optional argument is the duration that Consistently will run for
+//The second optional argument is the polling interval
+//
+//Both intervals can either be specified as time.Duration, parsable duration strings or as floats/integers. In the
+//last case they are interpreted as seconds.
+//
+//If Consistently is passed an actual that is a function taking no arguments and returning at least one value,
+//then Consistently will call the function periodically and try the matcher against the function's first return value.
+//
+//If the function returns more than one value, then Consistently will pass the first value to the matcher and
+//assert that all other values are nil/zero.
+//This allows you to pass Consistently a function that returns a value and an error - a common pattern in Go.
+//
+//Consistently is useful in cases where you want to assert that something *does not happen* over a period of tiem.
+//For example, you want to assert that a goroutine does *not* send data down a channel. In this case, you could:
+//
+// Consistently(channel).ShouldNot(Receive())
+//
+//Consistently's default duration is 100ms, and its default polling interval is 10ms
+func Consistently(actual interface{}, intervals ...interface{}) GomegaAsyncAssertion {
+ return ConsistentlyWithOffset(0, actual, intervals...)
+}
+
+//ConsistentlyWithOffset operates like Consistnetly but takes an additional
+//initial argument to indicate an offset in the call stack. This is useful when building helper
+//functions that contain matchers. To learn more, read about `ExpectWithOffset`.
+func ConsistentlyWithOffset(offset int, actual interface{}, intervals ...interface{}) GomegaAsyncAssertion {
+ if globalFailHandler == nil {
+ panic(nilFailHandlerPanic)
+ }
+ timeoutInterval := defaultConsistentlyDuration
+ pollingInterval := defaultConsistentlyPollingInterval
+ if len(intervals) > 0 {
+ timeoutInterval = toDuration(intervals[0])
+ }
+ if len(intervals) > 1 {
+ pollingInterval = toDuration(intervals[1])
+ }
+ return asyncassertion.New(asyncassertion.AsyncAssertionTypeConsistently, actual, globalFailHandler, timeoutInterval, pollingInterval, offset)
+}
+
+//Set the default timeout duration for Eventually. Eventually will repeatedly poll your condition until it succeeds, or until this timeout elapses.
+func SetDefaultEventuallyTimeout(t time.Duration) {
+ defaultEventuallyTimeout = t
+}
+
+//Set the default polling interval for Eventually.
+func SetDefaultEventuallyPollingInterval(t time.Duration) {
+ defaultEventuallyPollingInterval = t
+}
+
+//Set the default duration for Consistently. Consistently will verify that your condition is satsified for this long.
+func SetDefaultConsistentlyDuration(t time.Duration) {
+ defaultConsistentlyDuration = t
+}
+
+//Set the default polling interval for Consistently.
+func SetDefaultConsistentlyPollingInterval(t time.Duration) {
+ defaultConsistentlyPollingInterval = t
+}
+
+//GomegaAsyncAssertion is returned by Eventually and Consistently and polls the actual value passed into Eventually against
+//the matcher passed to the Should and ShouldNot methods.
+//
+//Both Should and ShouldNot take a variadic optionalDescription argument. This is passed on to
+//fmt.Sprintf() and is used to annotate failure messages. This allows you to make your failure messages more
+//descriptive
+//
+//Both Should and ShouldNot return a boolean that is true if the assertion passed and false if it failed.
+//
+//Example:
+//
+// Eventually(myChannel).Should(Receive(), "Something should have come down the pipe.")
+// Consistently(myChannel).ShouldNot(Receive(), "Nothing should have come down the pipe.")
+type GomegaAsyncAssertion interface {
+ Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool
+ ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool
+}
+
+//GomegaAssertion is returned by Ω and Expect and compares the actual value to the matcher
+//passed to the Should/ShouldNot and To/ToNot/NotTo methods.
+//
+//Typically Should/ShouldNot are used with Ω and To/ToNot/NotTo are used with Expect
+//though this is not enforced.
+//
+//All methods take a variadic optionalDescription argument. This is passed on to fmt.Sprintf()
+//and is used to annotate failure messages.
+//
+//All methods return a bool that is true if hte assertion passed and false if it failed.
+//
+//Example:
+//
+// Ω(farm.HasCow()).Should(BeTrue(), "Farm %v should have a cow", farm)
+type GomegaAssertion interface {
+ Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool
+ ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool
+
+ To(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool
+ ToNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool
+ NotTo(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool
+}
+
+//OmegaMatcher is deprecated in favor of the better-named and better-organized types.GomegaMatcher but sticks around to support existing code that uses it
+type OmegaMatcher types.GomegaMatcher
+
+func toDuration(input interface{}) time.Duration {
+ duration, ok := input.(time.Duration)
+ if ok {
+ return duration
+ }
+
+ value := reflect.ValueOf(input)
+ kind := reflect.TypeOf(input).Kind()
+
+ if reflect.Int <= kind && kind <= reflect.Int64 {
+ return time.Duration(value.Int()) * time.Second
+ } else if reflect.Uint <= kind && kind <= reflect.Uint64 {
+ return time.Duration(value.Uint()) * time.Second
+ } else if reflect.Float32 <= kind && kind <= reflect.Float64 {
+ return time.Duration(value.Float() * float64(time.Second))
+ } else if reflect.String == kind {
+ duration, err := time.ParseDuration(value.String())
+ if err != nil {
+ panic(fmt.Sprintf("%#v is not a valid parsable duration string.", input))
+ }
+ return duration
+ }
+
+ panic(fmt.Sprintf("%v is not a valid interval. Must be time.Duration, parsable duration string or a number.", input))
+}
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 0000000..a315fa1
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gstruct/elements.go
@@ -0,0 +1,145 @@
+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.
+// Expect([]string{"a", "b"}).To(MatchAllElements(idFn, matchers.Elements{
+// "a": BeEqual("a"),
+// "b": BeEqual("b"),
+// })
+func MatchAllElements(identifier Identifier, elements Elements) types.GomegaMatcher {
+ return &ElementsMatcher{
+ Identifier: identifier,
+ Elements: elements,
+ }
+}
+
+//MatchElements succeeds if each element of a slice matches the element matcher it maps to
+//through the id function. It can ignore extra elements and/or missing elements.
+// Expect([]string{"a", "c"}).To(MatchElements(idFn, IgnoreMissing|IgnoreExtra, matchers.Elements{
+// "a": BeEqual("a")
+// "b": BeEqual("b"),
+// })
+func MatchElements(identifier Identifier, options Options, elements Elements) types.GomegaMatcher {
+ return &ElementsMatcher{
+ Identifier: identifier,
+ Elements: elements,
+ IgnoreExtras: options&IgnoreExtras != 0,
+ IgnoreMissing: options&IgnoreMissing != 0,
+ 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 0000000..8ba78cb
--- /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"),
+ })
+ Ω(allElements).Should(m, "should match all elements")
+ Ω(missingElements).ShouldNot(m, "should fail with missing elements")
+ Ω(extraElements).ShouldNot(m, "should fail with extra elements")
+ Ω(duplicateElements).ShouldNot(m, "should fail with duplicate elements")
+ Ω(nils).ShouldNot(m, "should fail with an uninitialized slice")
+
+ m = MatchAllElements(id, Elements{
+ "a": Equal("a"),
+ "b": Equal("fail"),
+ })
+ Ω(allElements).ShouldNot(m, "should run nested matchers")
+
+ m = MatchAllElements(id, Elements{})
+ Ω(empty).Should(m, "should handle empty slices")
+ Ω(allElements).ShouldNot(m, "should handle only empty slices")
+ Ω(nils).Should(m, "should handle nil slices")
+ })
+
+ It("should ignore extra elements", func() {
+ m := MatchElements(id, IgnoreExtras, Elements{
+ "b": Equal("b"),
+ "a": Equal("a"),
+ })
+ Ω(allElements).Should(m, "should match all elements")
+ Ω(missingElements).ShouldNot(m, "should fail with missing elements")
+ Ω(extraElements).Should(m, "should ignore extra elements")
+ Ω(duplicateElements).ShouldNot(m, "should fail with duplicate elements")
+ Ω(nils).ShouldNot(m, "should fail with an uninitialized slice")
+ })
+
+ It("should ignore missing elements", func() {
+ m := MatchElements(id, IgnoreMissing, Elements{
+ "a": Equal("a"),
+ "b": Equal("b"),
+ })
+ Ω(allElements).Should(m, "should match all elements")
+ Ω(missingElements).Should(m, "should ignore missing elements")
+ Ω(extraElements).ShouldNot(m, "should fail with extra elements")
+ Ω(duplicateElements).ShouldNot(m, "should fail with duplicate elements")
+ Ω(nils).Should(m, "should ignore an uninitialized slice")
+ })
+
+ It("should ignore missing and extra elements", func() {
+ m := MatchElements(id, IgnoreMissing|IgnoreExtras, Elements{
+ "a": Equal("a"),
+ "b": Equal("b"),
+ })
+ Ω(allElements).Should(m, "should match all elements")
+ Ω(missingElements).Should(m, "should ignore missing elements")
+ Ω(extraElements).Should(m, "should ignore extra elements")
+ Ω(duplicateElements).ShouldNot(m, "should fail with duplicate elements")
+ Ω(nils).Should(m, "should ignore an uninitialized slice")
+
+ m = MatchElements(id, IgnoreExtras|IgnoreMissing, Elements{
+ "a": Equal("a"),
+ "b": Equal("fail"),
+ })
+ Ω(allElements).ShouldNot(m, "should run nested matchers")
+ })
+
+ 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"),
+ })
+ Ω(allElements).Should(m, "should match all elements")
+ Ω(includingBadElements).ShouldNot(m, "should reject if a member fails the matcher")
+ Ω(extraElements).ShouldNot(m, "should reject with extra keys")
+ Ω(missingElements).ShouldNot(m, "should reject with missing keys")
+ Ω(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"),
+ })
+ Ω(allElements).Should(m, "should match all elements")
+ Ω(includingBadElements).ShouldNot(m, "should reject if a member fails the matcher")
+ Ω(extraElements).ShouldNot(m, "should reject with extra keys")
+ Ω(missingElements).Should(m, "should allow missing keys")
+ Ω(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"),
+ })
+ Ω(allElements).Should(m, "should match all elements")
+ Ω(includingBadElements).ShouldNot(m, "should reject if a member fails the matcher")
+ Ω(extraElements).Should(m, "should allow extra keys")
+ Ω(missingElements).ShouldNot(m, "should reject missing keys")
+ Ω(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"),
+ })
+ Ω(allElements).Should(m, "should match all elements")
+ Ω(includingBadElements).ShouldNot(m, "should reject if a member fails the matcher")
+ Ω(extraElements).Should(m, "should allow extra keys")
+ Ω(missingElements).Should(m, "should allow missing keys")
+ Ω(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 0000000..188492b
--- /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 0000000..f3c1575
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/gstruct/fields.go
@@ -0,0 +1,141 @@
+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.
+// Expect([]string{"a", "b"}).To(MatchAllFields(idFn, gstruct.Fields{
+// "a": BeEqual("a"),
+// "b": BeEqual("b"),
+// })
+func MatchAllFields(fields Fields) types.GomegaMatcher {
+ return &FieldsMatcher{
+ Fields: fields,
+ }
+}
+
+//MatchFields succeeds if each element of a struct matches the field matcher associated with
+//it. It can ignore extra fields and/or missing fields.
+// Expect([]string{"a", "c"}).To(MatchFields(idFn, IgnoreMissing|IgnoreExtra, gstruct.Fields{
+// "a": BeEqual("a")
+// "b": BeEqual("b"),
+// })
+func MatchFields(options Options, fields Fields) types.GomegaMatcher {
+ return &FieldsMatcher{
+ Fields: fields,
+ IgnoreExtras: options&IgnoreExtras != 0,
+ IgnoreMissing: options&IgnoreMissing != 0,
+ }
+}
+
+type FieldsMatcher struct {
+ // Matchers for each field.
+ Fields Fields
+
+ // Whether to ignore extra elements or consider it an error.
+ IgnoreExtras bool
+ // Whether to ignore missing elements or consider it an error.
+ IgnoreMissing bool
+
+ // State.
+ failures []error
+}
+
+// Field name to matcher.
+type Fields map[string]types.GomegaMatcher
+
+func (m *FieldsMatcher) Match(actual interface{}) (success bool, err error) {
+ if reflect.TypeOf(actual).Kind() != reflect.Struct {
+ return false, fmt.Errorf("%v is type %T, expected struct", actual, actual)
+ }
+
+ m.failures = m.matchFields(actual)
+ if len(m.failures) > 0 {
+ return false, nil
+ }
+ return true, nil
+}
+
+func (m *FieldsMatcher) matchFields(actual interface{}) (errs []error) {
+ val := reflect.ValueOf(actual)
+ typ := val.Type()
+ fields := map[string]bool{}
+ for i := 0; i < val.NumField(); i++ {
+ fieldName := typ.Field(i).Name
+ fields[fieldName] = true
+
+ err := func() (err error) {
+ // This test relies heavily on reflect, which tends to panic.
+ // Recover here to provide more useful error messages in that case.
+ defer func() {
+ if r := recover(); r != nil {
+ err = fmt.Errorf("panic checking %+v: %v\n%s", actual, r, debug.Stack())
+ }
+ }()
+
+ matcher, expected := m.Fields[fieldName]
+ if !expected {
+ if !m.IgnoreExtras {
+ return fmt.Errorf("unexpected field %s: %+v", fieldName, actual)
+ }
+ return nil
+ }
+
+ var field interface{}
+ if val.Field(i).IsValid() {
+ field = val.Field(i).Interface()
+ } else {
+ field = reflect.Zero(typ.Field(i).Type)
+ }
+
+ match, err := matcher.Match(field)
+ if err != nil {
+ return err
+ } else if !match {
+ if nesting, ok := matcher.(errorsutil.NestingMatcher); ok {
+ return errorsutil.AggregateError(nesting.Failures())
+ }
+ return errors.New(matcher.FailureMessage(field))
+ }
+ return nil
+ }()
+ if err != nil {
+ errs = append(errs, errorsutil.Nest("."+fieldName, err))
+ }
+ }
+
+ for field := range m.Fields {
+ if !fields[field] && !m.IgnoreMissing {
+ errs = append(errs, fmt.Errorf("missing expected field %s", field))
+ }
+ }
+
+ return errs
+}
+
+func (m *FieldsMatcher) FailureMessage(actual interface{}) (message string) {
+ failures := make([]string, len(m.failures))
+ for i := range m.failures {
+ failures[i] = m.failures[i].Error()
+ }
+ return format.Message(reflect.TypeOf(actual).Name(),
+ fmt.Sprintf("to match fields: {\n%v\n}\n", strings.Join(failures, "\n")))
+}
+
+func (m *FieldsMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, "not to match fields")
+}
+
+func (m *FieldsMatcher) Failures() []error {
+ return m.failures
+}
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 0000000..61f4afc
--- /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"),
+ })
+ Ω(allFields).Should(m, "should match all fields")
+ Ω(missingFields).ShouldNot(m, "should fail with missing fields")
+ Ω(extraFields).ShouldNot(m, "should fail with extra fields")
+ Ω(emptyFields).ShouldNot(m, "should fail with empty fields")
+
+ m = MatchAllFields(Fields{
+ "A": Equal("a"),
+ "B": Equal("fail"),
+ })
+ Ω(allFields).ShouldNot(m, "should run nested matchers")
+ })
+
+ It("should handle empty structs", func() {
+ m := MatchAllFields(Fields{})
+ Ω(struct{}{}).Should(m, "should handle empty structs")
+ Ω(allFields).ShouldNot(m, "should fail with extra fields")
+ })
+
+ It("should ignore missing fields", func() {
+ m := MatchFields(IgnoreMissing, Fields{
+ "B": Equal("b"),
+ "A": Equal("a"),
+ })
+ Ω(allFields).Should(m, "should match all fields")
+ Ω(missingFields).Should(m, "should ignore missing fields")
+ Ω(extraFields).ShouldNot(m, "should fail with extra fields")
+ Ω(emptyFields).ShouldNot(m, "should fail with empty fields")
+ })
+
+ It("should ignore extra fields", func() {
+ m := MatchFields(IgnoreExtras, Fields{
+ "B": Equal("b"),
+ "A": Equal("a"),
+ })
+ Ω(allFields).Should(m, "should match all fields")
+ Ω(missingFields).ShouldNot(m, "should fail with missing fields")
+ Ω(extraFields).Should(m, "should ignore extra fields")
+ Ω(emptyFields).ShouldNot(m, "should fail with empty fields")
+ })
+
+ It("should ignore missing and extra fields", func() {
+ m := MatchFields(IgnoreMissing|IgnoreExtras, Fields{
+ "B": Equal("b"),
+ "A": Equal("a"),
+ })
+ Ω(allFields).Should(m, "should match all fields")
+ Ω(missingFields).Should(m, "should ignore missing fields")
+ Ω(extraFields).Should(m, "should ignore extra fields")
+ Ω(emptyFields).ShouldNot(m, "should fail with empty fields")
+
+ m = MatchFields(IgnoreMissing|IgnoreExtras, Fields{
+ "A": Equal("a"),
+ "B": Equal("fail"),
+ })
+ Ω(allFields).ShouldNot(m, "should run nested matchers")
+ })
+})
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 0000000..d475663
--- /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 0000000..0365f32
--- /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 0000000..70e1d40
--- /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() {
+ Ω(nil).Should(Ignore())
+ Ω(struct{}{}).Should(Ignore())
+ Ω(0).Should(Ignore())
+ Ω(false).Should(Ignore())
+ })
+
+ It("should always fail", func() {
+ Ω(nil).ShouldNot(Reject())
+ Ω(struct{}{}).ShouldNot(Reject())
+ Ω(1).ShouldNot(Reject())
+ Ω(true).ShouldNot(Reject())
+ })
+})
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 0000000..0a2f35d
--- /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 0000000..b02081c
--- /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{}
+ Ω(p).Should(BeNil())
+ })
+
+ It("should succeed when passed non-nil pointer", func() {
+ var s struct{}
+ Ω(&s).Should(PointTo(Ignore()))
+ })
+
+ It("should unwrap the pointee value", func() {
+ i := 1
+ Ω(&i).Should(PointTo(Equal(1)))
+ Ω(&i).ShouldNot(PointTo(Equal(2)))
+ })
+
+ It("should work with nested pointers", func() {
+ i := 1
+ ip := &i
+ ipp := &ip
+ Ω(ipp).Should(PointTo(PointTo(Equal(1))))
+ Ω(ipp).ShouldNot(PointTo(PointTo(Equal(2))))
+ })
+})
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 0000000..48cbbe8
--- /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 0000000..b73673f
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/internal/assertion/assertion.go
@@ -0,0 +1,98 @@
+package assertion
+
+import (
+ "fmt"
+ "reflect"
+
+ "github.com/onsi/gomega/types"
+)
+
+type Assertion struct {
+ actualInput interface{}
+ fail types.GomegaFailHandler
+ offset int
+ extra []interface{}
+}
+
+func New(actualInput interface{}, fail types.GomegaFailHandler, offset int, extra ...interface{}) *Assertion {
+ return &Assertion{
+ actualInput: actualInput,
+ fail: fail,
+ offset: offset,
+ extra: extra,
+ }
+}
+
+func (assertion *Assertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
+ return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...)
+}
+
+func (assertion *Assertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
+ return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
+}
+
+func (assertion *Assertion) To(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
+ return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...)
+}
+
+func (assertion *Assertion) ToNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
+ return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
+}
+
+func (assertion *Assertion) NotTo(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
+ return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
+}
+
+func (assertion *Assertion) buildDescription(optionalDescription ...interface{}) string {
+ switch len(optionalDescription) {
+ case 0:
+ return ""
+ default:
+ return fmt.Sprintf(optionalDescription[0].(string), optionalDescription[1:]...) + "\n"
+ }
+}
+
+func (assertion *Assertion) match(matcher types.GomegaMatcher, desiredMatch bool, optionalDescription ...interface{}) bool {
+ matches, err := matcher.Match(assertion.actualInput)
+ description := assertion.buildDescription(optionalDescription...)
+ if err != nil {
+ assertion.fail(description+err.Error(), 2+assertion.offset)
+ return false
+ }
+ if matches != desiredMatch {
+ var message string
+ if desiredMatch {
+ message = matcher.FailureMessage(assertion.actualInput)
+ } else {
+ message = matcher.NegatedFailureMessage(assertion.actualInput)
+ }
+ assertion.fail(description+message, 2+assertion.offset)
+ return false
+ }
+
+ return true
+}
+
+func (assertion *Assertion) vetExtras(optionalDescription ...interface{}) bool {
+ success, message := vetExtras(assertion.extra)
+ if success {
+ return true
+ }
+
+ description := assertion.buildDescription(optionalDescription...)
+ assertion.fail(description+message, 2+assertion.offset)
+ return false
+}
+
+func vetExtras(extras []interface{}) (bool, string) {
+ for i, extra := range extras {
+ if extra != nil {
+ zeroValue := reflect.Zero(reflect.TypeOf(extra)).Interface()
+ if !reflect.DeepEqual(zeroValue, extra) {
+ message := fmt.Sprintf("Unexpected non-nil/non-zero extra argument at index %d:\n\t<%T>: %#v", i+1, extra, extra)
+ return false, message
+ }
+ }
+ }
+ return true, ""
+}
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 0000000..dae47a4
--- /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 0000000..c03b7a3
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/internal/assertion/assertion_test.go
@@ -0,0 +1,252 @@
+package assertion_test
+
+import (
+ "errors"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/internal/assertion"
+ "github.com/onsi/gomega/internal/fakematcher"
+)
+
+var _ = Describe("Assertion", func() {
+ var (
+ a *Assertion
+ failureMessage string
+ failureCallerSkip int
+ matcher *fakematcher.FakeMatcher
+ )
+
+ input := "The thing I'm testing"
+
+ var fakeFailHandler = func(message string, callerSkip ...int) {
+ failureMessage = message
+ if len(callerSkip) == 1 {
+ failureCallerSkip = callerSkip[0]
+ }
+ }
+
+ BeforeEach(func() {
+ matcher = &fakematcher.FakeMatcher{}
+ failureMessage = ""
+ failureCallerSkip = 0
+ a = New(input, fakeFailHandler, 1)
+ })
+
+ Context("when called", func() {
+ It("should pass the provided input value to the matcher", func() {
+ a.Should(matcher)
+
+ Ω(matcher.ReceivedActual).Should(Equal(input))
+ matcher.ReceivedActual = ""
+
+ a.ShouldNot(matcher)
+
+ Ω(matcher.ReceivedActual).Should(Equal(input))
+ matcher.ReceivedActual = ""
+
+ a.To(matcher)
+
+ Ω(matcher.ReceivedActual).Should(Equal(input))
+ matcher.ReceivedActual = ""
+
+ a.ToNot(matcher)
+
+ Ω(matcher.ReceivedActual).Should(Equal(input))
+ matcher.ReceivedActual = ""
+
+ a.NotTo(matcher)
+
+ Ω(matcher.ReceivedActual).Should(Equal(input))
+ })
+ })
+
+ Context("when the matcher succeeds", func() {
+ BeforeEach(func() {
+ matcher.MatchesToReturn = true
+ matcher.ErrToReturn = nil
+ })
+
+ Context("and a positive assertion is being made", func() {
+ It("should not call the failure callback", func() {
+ a.Should(matcher)
+ Ω(failureMessage).Should(Equal(""))
+ })
+
+ It("should be true", func() {
+ Ω(a.Should(matcher)).Should(BeTrue())
+ })
+ })
+
+ Context("and a negative assertion is being made", func() {
+ It("should call the failure callback", func() {
+ a.ShouldNot(matcher)
+ Ω(failureMessage).Should(Equal("negative: The thing I'm testing"))
+ Ω(failureCallerSkip).Should(Equal(3))
+ })
+
+ It("should be false", func() {
+ Ω(a.ShouldNot(matcher)).Should(BeFalse())
+ })
+ })
+ })
+
+ Context("when the matcher fails", func() {
+ BeforeEach(func() {
+ matcher.MatchesToReturn = false
+ matcher.ErrToReturn = nil
+ })
+
+ Context("and a positive assertion is being made", func() {
+ It("should call the failure callback", func() {
+ a.Should(matcher)
+ Ω(failureMessage).Should(Equal("positive: The thing I'm testing"))
+ Ω(failureCallerSkip).Should(Equal(3))
+ })
+
+ It("should be false", func() {
+ Ω(a.Should(matcher)).Should(BeFalse())
+ })
+ })
+
+ Context("and a negative assertion is being made", func() {
+ It("should not call the failure callback", func() {
+ a.ShouldNot(matcher)
+ Ω(failureMessage).Should(Equal(""))
+ })
+
+ It("should be true", func() {
+ Ω(a.ShouldNot(matcher)).Should(BeTrue())
+ })
+ })
+ })
+
+ Context("When reporting a failure", func() {
+ BeforeEach(func() {
+ matcher.MatchesToReturn = false
+ matcher.ErrToReturn = nil
+ })
+
+ Context("and there is an optional description", func() {
+ It("should append the description to the failure message", func() {
+ a.Should(matcher, "A description")
+ Ω(failureMessage).Should(Equal("A description\npositive: The thing I'm testing"))
+ Ω(failureCallerSkip).Should(Equal(3))
+ })
+ })
+
+ Context("and there are multiple arguments to the optional description", func() {
+ It("should append the formatted description to the failure message", func() {
+ a.Should(matcher, "A description of [%d]", 3)
+ Ω(failureMessage).Should(Equal("A description of [3]\npositive: The thing I'm testing"))
+ Ω(failureCallerSkip).Should(Equal(3))
+ })
+ })
+ })
+
+ Context("When the matcher returns an error", func() {
+ BeforeEach(func() {
+ matcher.ErrToReturn = errors.New("Kaboom!")
+ })
+
+ Context("and a positive assertion is being made", func() {
+ It("should call the failure callback", func() {
+ matcher.MatchesToReturn = true
+ a.Should(matcher)
+ Ω(failureMessage).Should(Equal("Kaboom!"))
+ Ω(failureCallerSkip).Should(Equal(3))
+ })
+ })
+
+ Context("and a negative assertion is being made", func() {
+ It("should call the failure callback", func() {
+ matcher.MatchesToReturn = false
+ a.ShouldNot(matcher)
+ Ω(failureMessage).Should(Equal("Kaboom!"))
+ Ω(failureCallerSkip).Should(Equal(3))
+ })
+ })
+
+ It("should always be false", func() {
+ Ω(a.Should(matcher)).Should(BeFalse())
+ Ω(a.ShouldNot(matcher)).Should(BeFalse())
+ })
+ })
+
+ Context("when there are extra parameters", func() {
+ It("(a simple example)", func() {
+ Ω(func() (string, int, error) {
+ return "foo", 0, nil
+ }()).Should(Equal("foo"))
+ })
+
+ Context("when the parameters are all nil or zero", func() {
+ It("should invoke the matcher", func() {
+ matcher.MatchesToReturn = true
+ matcher.ErrToReturn = nil
+
+ var typedNil []string
+ a = New(input, fakeFailHandler, 1, 0, nil, typedNil)
+
+ result := a.Should(matcher)
+ Ω(result).Should(BeTrue())
+ Ω(matcher.ReceivedActual).Should(Equal(input))
+
+ Ω(failureMessage).Should(BeZero())
+ })
+ })
+
+ Context("when any of the parameters are not nil or zero", func() {
+ It("should call the failure callback", func() {
+ matcher.MatchesToReturn = false
+ matcher.ErrToReturn = nil
+
+ a = New(input, fakeFailHandler, 1, errors.New("foo"))
+ result := a.Should(matcher)
+ Ω(result).Should(BeFalse())
+ Ω(matcher.ReceivedActual).Should(BeZero(), "The matcher doesn't even get called")
+ Ω(failureMessage).Should(ContainSubstring("foo"))
+ failureMessage = ""
+
+ a = New(input, fakeFailHandler, 1, nil, 1)
+ result = a.ShouldNot(matcher)
+ Ω(result).Should(BeFalse())
+ Ω(failureMessage).Should(ContainSubstring("1"))
+ failureMessage = ""
+
+ a = New(input, fakeFailHandler, 1, nil, 0, []string{"foo"})
+ result = a.To(matcher)
+ Ω(result).Should(BeFalse())
+ Ω(failureMessage).Should(ContainSubstring("foo"))
+ failureMessage = ""
+
+ a = New(input, fakeFailHandler, 1, nil, 0, []string{"foo"})
+ result = a.ToNot(matcher)
+ Ω(result).Should(BeFalse())
+ Ω(failureMessage).Should(ContainSubstring("foo"))
+ failureMessage = ""
+
+ a = New(input, fakeFailHandler, 1, nil, 0, []string{"foo"})
+ result = a.NotTo(matcher)
+ Ω(result).Should(BeFalse())
+ Ω(failureMessage).Should(ContainSubstring("foo"))
+ Ω(failureCallerSkip).Should(Equal(3))
+ })
+ })
+ })
+
+ Context("Making an assertion without a registered fail handler", func() {
+ It("should panic", func() {
+ defer func() {
+ e := recover()
+ RegisterFailHandler(Fail)
+ if e == nil {
+ Fail("expected a panic to have occurred")
+ }
+ }()
+
+ RegisterFailHandler(nil)
+ Ω(true).Should(BeTrue())
+ })
+ })
+})
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 0000000..bce0853
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion.go
@@ -0,0 +1,189 @@
+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
+ fail types.GomegaFailHandler
+ offset int
+}
+
+func New(asyncType AsyncAssertionType, actualInput interface{}, fail types.GomegaFailHandler, timeoutInterval time.Duration, pollingInterval time.Duration, offset int) *AsyncAssertion {
+ actualType := reflect.TypeOf(actualInput)
+ if actualType.Kind() == reflect.Func {
+ if actualType.NumIn() != 0 || actualType.NumOut() == 0 {
+ panic("Expected a function with no arguments and one or more return values.")
+ }
+ }
+
+ return &AsyncAssertion{
+ asyncType: asyncType,
+ actualInput: actualInput,
+ fail: fail,
+ timeoutInterval: timeoutInterval,
+ pollingInterval: pollingInterval,
+ offset: offset,
+ }
+}
+
+func (assertion *AsyncAssertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
+ return assertion.match(matcher, true, optionalDescription...)
+}
+
+func (assertion *AsyncAssertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
+ return assertion.match(matcher, false, optionalDescription...)
+}
+
+func (assertion *AsyncAssertion) buildDescription(optionalDescription ...interface{}) string {
+ switch len(optionalDescription) {
+ case 0:
+ return ""
+ default:
+ return fmt.Sprintf(optionalDescription[0].(string), optionalDescription[1:]...) + "\n"
+ }
+}
+
+func (assertion *AsyncAssertion) actualInputIsAFunction() bool {
+ actualType := reflect.TypeOf(assertion.actualInput)
+ return actualType.Kind() == reflect.Func && actualType.NumIn() == 0 && actualType.NumOut() > 0
+}
+
+func (assertion *AsyncAssertion) pollActual() (interface{}, error) {
+ if assertion.actualInputIsAFunction() {
+ values := reflect.ValueOf(assertion.actualInput).Call([]reflect.Value{})
+
+ extras := []interface{}{}
+ for _, value := range values[1:] {
+ extras = append(extras, value.Interface())
+ }
+
+ success, message := vetExtras(extras)
+
+ if !success {
+ return nil, errors.New(message)
+ }
+
+ return values[0].Interface(), nil
+ }
+
+ return assertion.actualInput, nil
+}
+
+func (assertion *AsyncAssertion) matcherMayChange(matcher types.GomegaMatcher, value interface{}) bool {
+ if assertion.actualInputIsAFunction() {
+ return true
+ }
+
+ return oraclematcher.MatchMayChangeInTheFuture(matcher, value)
+}
+
+func (assertion *AsyncAssertion) match(matcher types.GomegaMatcher, desiredMatch bool, optionalDescription ...interface{}) bool {
+ timer := time.Now()
+ timeout := time.After(assertion.timeoutInterval)
+
+ description := assertion.buildDescription(optionalDescription...)
+
+ var matches bool
+ var err error
+ mayChange := true
+ value, err := assertion.pollActual()
+ if err == nil {
+ mayChange = assertion.matcherMayChange(matcher, value)
+ matches, err = matcher.Match(value)
+ }
+
+ fail := func(preamble string) {
+ errMsg := ""
+ message := ""
+ if err != nil {
+ errMsg = "Error: " + err.Error()
+ } else {
+ if desiredMatch {
+ message = matcher.FailureMessage(value)
+ } else {
+ message = matcher.NegatedFailureMessage(value)
+ }
+ }
+ assertion.fail(fmt.Sprintf("%s after %.3fs.\n%s%s%s", preamble, time.Since(timer).Seconds(), description, message, errMsg), 3+assertion.offset)
+ }
+
+ if assertion.asyncType == AsyncAssertionTypeEventually {
+ for {
+ if err == nil && matches == desiredMatch {
+ return true
+ }
+
+ if !mayChange {
+ fail("No future change is possible. Bailing out early")
+ return false
+ }
+
+ select {
+ case <-time.After(assertion.pollingInterval):
+ value, err = assertion.pollActual()
+ if err == nil {
+ mayChange = assertion.matcherMayChange(matcher, value)
+ matches, err = matcher.Match(value)
+ }
+ case <-timeout:
+ fail("Timed out")
+ return false
+ }
+ }
+ } else if assertion.asyncType == AsyncAssertionTypeConsistently {
+ for {
+ if !(err == nil && matches == desiredMatch) {
+ fail("Failed")
+ return false
+ }
+
+ if !mayChange {
+ return true
+ }
+
+ select {
+ case <-time.After(assertion.pollingInterval):
+ value, err = assertion.pollActual()
+ if err == nil {
+ mayChange = assertion.matcherMayChange(matcher, value)
+ matches, err = matcher.Match(value)
+ }
+ case <-timeout:
+ return true
+ }
+ }
+ }
+
+ return false
+}
+
+func vetExtras(extras []interface{}) (bool, string) {
+ for i, extra := range extras {
+ if extra != nil {
+ zeroValue := reflect.Zero(reflect.TypeOf(extra)).Interface()
+ if !reflect.DeepEqual(zeroValue, extra) {
+ message := fmt.Sprintf("Unexpected non-nil/non-zero extra argument at index %d:\n\t<%T>: %#v", i+1, extra, extra)
+ return false, message
+ }
+ }
+ }
+ return true, ""
+}
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 0000000..bdb0c3d
--- /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 0000000..3d7e348
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion_test.go
@@ -0,0 +1,345 @@
+package asyncassertion_test
+
+import (
+ "errors"
+ "time"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/internal/asyncassertion"
+)
+
+var _ = Describe("Async Assertion", func() {
+ var (
+ failureMessage string
+ callerSkip int
+ )
+
+ var fakeFailHandler = func(message string, skip ...int) {
+ failureMessage = message
+ callerSkip = skip[0]
+ }
+
+ BeforeEach(func() {
+ failureMessage = ""
+ callerSkip = 0
+ })
+
+ Describe("Eventually", func() {
+ Context("the positive case", func() {
+ It("should poll the function and matcher", func() {
+ counter := 0
+ a := New(AsyncAssertionTypeEventually, func() int {
+ counter++
+ return counter
+ }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.Should(BeNumerically("==", 5))
+ Ω(failureMessage).Should(BeZero())
+ })
+
+ It("should continue when the matcher errors", func() {
+ counter := 0
+ a := New(AsyncAssertionTypeEventually, func() interface{} {
+ counter++
+ if counter == 5 {
+ return "not-a-number" //this should cause the matcher to error
+ }
+ return counter
+ }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.Should(BeNumerically("==", 5), "My description %d", 2)
+
+ Ω(failureMessage).Should(ContainSubstring("Timed out after"))
+ Ω(failureMessage).Should(ContainSubstring("My description 2"))
+ Ω(callerSkip).Should(Equal(4))
+ })
+
+ It("should be able to timeout", func() {
+ counter := 0
+ a := New(AsyncAssertionTypeEventually, func() int {
+ counter++
+ return counter
+ }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.Should(BeNumerically(">", 100), "My description %d", 2)
+
+ Ω(counter).Should(BeNumerically(">", 8))
+ Ω(counter).Should(BeNumerically("<=", 10))
+ Ω(failureMessage).Should(ContainSubstring("Timed out after"))
+ Ω(failureMessage).Should(MatchRegexp(`\<int\>: \d`), "Should pass the correct value to the matcher message formatter.")
+ Ω(failureMessage).Should(ContainSubstring("My description 2"))
+ Ω(callerSkip).Should(Equal(4))
+ })
+ })
+
+ Context("the negative case", func() {
+ It("should poll the function and matcher", func() {
+ counter := 0
+ a := New(AsyncAssertionTypeEventually, func() int {
+ counter += 1
+ return counter
+ }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.ShouldNot(BeNumerically("<", 3))
+
+ Ω(counter).Should(Equal(3))
+ Ω(failureMessage).Should(BeZero())
+ })
+
+ It("should timeout when the matcher errors", func() {
+ a := New(AsyncAssertionTypeEventually, func() interface{} {
+ return 0 //this should cause the matcher to error
+ }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.ShouldNot(HaveLen(0), "My description %d", 2)
+
+ Ω(failureMessage).Should(ContainSubstring("Timed out after"))
+ Ω(failureMessage).Should(ContainSubstring("Error:"))
+ Ω(failureMessage).Should(ContainSubstring("My description 2"))
+ Ω(callerSkip).Should(Equal(4))
+ })
+
+ It("should be able to timeout", func() {
+ a := New(AsyncAssertionTypeEventually, func() int {
+ return 0
+ }, fakeFailHandler, time.Duration(0.1*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.ShouldNot(Equal(0), "My description %d", 2)
+
+ Ω(failureMessage).Should(ContainSubstring("Timed out after"))
+ Ω(failureMessage).Should(ContainSubstring("<int>: 0"), "Should pass the correct value to the matcher message formatter.")
+ Ω(failureMessage).Should(ContainSubstring("My description 2"))
+ Ω(callerSkip).Should(Equal(4))
+ })
+ })
+
+ Context("with a function that returns multiple values", func() {
+ It("should eventually succeed if the additional arguments are nil", func() {
+ i := 0
+ Eventually(func() (int, error) {
+ i++
+ return i, nil
+ }).Should(Equal(10))
+ })
+
+ It("should eventually timeout if the additional arguments are not nil", func() {
+ i := 0
+ a := New(AsyncAssertionTypeEventually, func() (int, error) {
+ i++
+ return i, errors.New("bam")
+ }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+ a.Should(Equal(2))
+
+ Ω(failureMessage).Should(ContainSubstring("Timed out after"))
+ Ω(failureMessage).Should(ContainSubstring("Error:"))
+ Ω(failureMessage).Should(ContainSubstring("bam"))
+ Ω(callerSkip).Should(Equal(4))
+ })
+ })
+
+ Context("Making an assertion without a registered fail handler", func() {
+ It("should panic", func() {
+ defer func() {
+ e := recover()
+ RegisterFailHandler(Fail)
+ if e == nil {
+ Fail("expected a panic to have occurred")
+ }
+ }()
+
+ RegisterFailHandler(nil)
+ c := make(chan bool, 1)
+ c <- true
+ Eventually(c).Should(Receive())
+ })
+ })
+ })
+
+ Describe("Consistently", func() {
+ Describe("The positive case", func() {
+ Context("when the matcher consistently passes for the duration", func() {
+ It("should pass", func() {
+ calls := 0
+ a := New(AsyncAssertionTypeConsistently, func() string {
+ calls++
+ return "foo"
+ }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.Should(Equal("foo"))
+ Ω(calls).Should(BeNumerically(">", 8))
+ Ω(calls).Should(BeNumerically("<=", 10))
+ Ω(failureMessage).Should(BeZero())
+ })
+ })
+
+ Context("when the matcher fails at some point", func() {
+ It("should fail", func() {
+ calls := 0
+ a := New(AsyncAssertionTypeConsistently, func() interface{} {
+ calls++
+ if calls > 5 {
+ return "bar"
+ }
+ return "foo"
+ }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.Should(Equal("foo"))
+ Ω(failureMessage).Should(ContainSubstring("to equal"))
+ Ω(callerSkip).Should(Equal(4))
+ })
+ })
+
+ Context("when the matcher errors at some point", func() {
+ It("should fail", func() {
+ calls := 0
+ a := New(AsyncAssertionTypeConsistently, func() interface{} {
+ calls++
+ if calls > 5 {
+ return 3
+ }
+ return []int{1, 2, 3}
+ }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.Should(HaveLen(3))
+ Ω(failureMessage).Should(ContainSubstring("HaveLen matcher expects"))
+ Ω(callerSkip).Should(Equal(4))
+ })
+ })
+ })
+
+ Describe("The negative case", func() {
+ Context("when the matcher consistently passes for the duration", func() {
+ It("should pass", func() {
+ c := make(chan bool)
+ a := New(AsyncAssertionTypeConsistently, c, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.ShouldNot(Receive())
+ Ω(failureMessage).Should(BeZero())
+ })
+ })
+
+ Context("when the matcher fails at some point", func() {
+ It("should fail", func() {
+ c := make(chan bool)
+ go func() {
+ time.Sleep(time.Duration(100 * time.Millisecond))
+ c <- true
+ }()
+
+ a := New(AsyncAssertionTypeConsistently, c, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.ShouldNot(Receive())
+ Ω(failureMessage).Should(ContainSubstring("not to receive anything"))
+ })
+ })
+
+ Context("when the matcher errors at some point", func() {
+ It("should fail", func() {
+ calls := 0
+ a := New(AsyncAssertionTypeConsistently, func() interface{} {
+ calls++
+ return calls
+ }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+
+ a.ShouldNot(BeNumerically(">", 5))
+ Ω(failureMessage).Should(ContainSubstring("not to be >"))
+ Ω(callerSkip).Should(Equal(4))
+ })
+ })
+ })
+
+ Context("with a function that returns multiple values", func() {
+ It("should consistently succeed if the additional arguments are nil", func() {
+ i := 2
+ Consistently(func() (int, error) {
+ i++
+ return i, nil
+ }).Should(BeNumerically(">=", 2))
+ })
+
+ It("should eventually timeout if the additional arguments are not nil", func() {
+ i := 2
+ a := New(AsyncAssertionTypeEventually, func() (int, error) {
+ i++
+ return i, errors.New("bam")
+ }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1)
+ a.Should(BeNumerically(">=", 2))
+
+ Ω(failureMessage).Should(ContainSubstring("Error:"))
+ Ω(failureMessage).Should(ContainSubstring("bam"))
+ Ω(callerSkip).Should(Equal(4))
+ })
+ })
+
+ Context("Making an assertion without a registered fail handler", func() {
+ It("should panic", func() {
+ defer func() {
+ e := recover()
+ RegisterFailHandler(Fail)
+ if e == nil {
+ Fail("expected a panic to have occurred")
+ }
+ }()
+
+ RegisterFailHandler(nil)
+ c := make(chan bool)
+ Consistently(c).ShouldNot(Receive())
+ })
+ })
+ })
+
+ Context("when passed a function with the wrong # or arguments & returns", func() {
+ It("should panic", func() {
+ Ω(func() {
+ New(AsyncAssertionTypeEventually, func() {}, fakeFailHandler, 0, 0, 1)
+ }).Should(Panic())
+
+ Ω(func() {
+ New(AsyncAssertionTypeEventually, func(a string) int { return 0 }, fakeFailHandler, 0, 0, 1)
+ }).Should(Panic())
+
+ Ω(func() {
+ New(AsyncAssertionTypeEventually, func() int { return 0 }, fakeFailHandler, 0, 0, 1)
+ }).ShouldNot(Panic())
+
+ Ω(func() {
+ New(AsyncAssertionTypeEventually, func() (int, error) { return 0, nil }, fakeFailHandler, 0, 0, 1)
+ }).ShouldNot(Panic())
+ })
+ })
+
+ Describe("bailing early", func() {
+ Context("when actual is a value", func() {
+ It("Eventually should bail out and fail early if the matcher says to", func() {
+ c := make(chan bool)
+ close(c)
+
+ t := time.Now()
+ failures := InterceptGomegaFailures(func() {
+ Eventually(c, 0.1).Should(Receive())
+ })
+ Ω(time.Since(t)).Should(BeNumerically("<", 90*time.Millisecond))
+
+ Ω(failures).Should(HaveLen(1))
+ })
+ })
+
+ Context("when actual is a function", func() {
+ It("should never bail early", func() {
+ c := make(chan bool)
+ close(c)
+
+ t := time.Now()
+ failures := InterceptGomegaFailures(func() {
+ Eventually(func() chan bool {
+ return c
+ }, 0.1).Should(Receive())
+ })
+ Ω(time.Since(t)).Should(BeNumerically(">=", 90*time.Millisecond))
+
+ Ω(failures).Should(HaveLen(1))
+ })
+ })
+ })
+})
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 0000000..6e351a7
--- /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 0000000..66cad88
--- /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 0000000..7871fd4
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support.go
@@ -0,0 +1,40 @@
+package testingtsupport
+
+import (
+ "regexp"
+ "runtime/debug"
+ "strings"
+
+ "github.com/onsi/gomega/types"
+)
+
+type gomegaTestingT interface {
+ Errorf(format string, args ...interface{})
+}
+
+func BuildTestingTGomegaFailHandler(t gomegaTestingT) types.GomegaFailHandler {
+ return func(message string, callerSkip ...int) {
+ skip := 1
+ if len(callerSkip) > 0 {
+ skip = callerSkip[0]
+ }
+ stackTrace := pruneStack(string(debug.Stack()), skip)
+ t.Errorf("\n%s\n%s", stackTrace, message)
+ }
+}
+
+func pruneStack(fullStackTrace string, skip int) string {
+ stack := strings.Split(fullStackTrace, "\n")
+ if len(stack) > 2*(skip+1) {
+ stack = stack[2*(skip+1):]
+ }
+ prunedStack := []string{}
+ re := regexp.MustCompile(`\/ginkgo\/|\/pkg\/testing\/|\/pkg\/runtime\/`)
+ for i := 0; i < len(stack)/2; i++ {
+ if !re.Match([]byte(stack[i*2])) {
+ prunedStack = append(prunedStack, stack[i*2])
+ prunedStack = append(prunedStack, stack[i*2+1])
+ }
+ }
+ return strings.Join(prunedStack, "\n")
+}
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 0000000..b9fbd6c
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support_test.go
@@ -0,0 +1,12 @@
+package testingtsupport_test
+
+import (
+ . "github.com/onsi/gomega"
+
+ "testing"
+)
+
+func TestTestingT(t *testing.T) {
+ RegisterTestingT(t)
+ Ω(true).Should(BeTrue())
+}
diff --git a/vendor/github.com/onsi/gomega/matchers.go b/vendor/github.com/onsi/gomega/matchers.go
new file mode 100644
index 0000000..ad04ab6
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers.go
@@ -0,0 +1,418 @@
+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()
+// Ω(err).ShouldNot(HaveOccurred())
+func HaveOccurred() types.GomegaMatcher {
+ return &matchers.HaveOccurredMatcher{}
+}
+
+//Succeed passes if actual is a nil error
+//Succeed is intended to be used with functions that return a single error value. Instead of
+// err := SomethingThatMightFail()
+// Ω(err).ShouldNot(HaveOccurred())
+//
+//You can write:
+// Ω(SomethingThatMightFail()).Should(Succeed())
+//
+//It is a mistake to use Succeed with a function that has multiple return values. Gomega's Ω and Expect
+//functions automatically trigger failure if any return values after the first return value are non-zero/non-nil.
+//This means that Ω(MultiReturnFunc()).ShouldNot(Succeed()) can never pass.
+func Succeed() types.GomegaMatcher {
+ return &matchers.SucceedMatcher{}
+}
+
+//MatchError succeeds if actual is a non-nil error that matches the passed in string/error.
+//
+//These are valid use-cases:
+// Ω(err).Should(MatchError("an error")) //asserts that err.Error() == "an error"
+// Ω(err).Should(MatchError(SomeError)) //asserts that err == SomeError (via reflect.DeepEqual)
+//
+//It is an error for err to be nil or an object that does not implement the Error interface
+func MatchError(expected interface{}) types.GomegaMatcher {
+ return &matchers.MatchErrorMatcher{
+ Expected: expected,
+ }
+}
+
+//BeClosed succeeds if actual is a closed channel.
+//It is an error to pass a non-channel to BeClosed, it is also an error to pass nil
+//
+//In order to check whether or not the channel is closed, Gomega must try to read from the channel
+//(even in the `ShouldNot(BeClosed())` case). You should keep this in mind if you wish to make subsequent assertions about
+//values coming down the channel.
+//
+//Also, if you are testing that a *buffered* channel is closed you must first read all values out of the channel before
+//asserting that it is closed (it is not possible to detect that a buffered-channel has been closed until all its buffered values are read).
+//
+//Finally, as a corollary: it is an error to check whether or not a send-only channel is closed.
+func BeClosed() types.GomegaMatcher {
+ return &matchers.BeClosedMatcher{}
+}
+
+//Receive succeeds if there is a value to be received on actual.
+//Actual must be a channel (and cannot be a send-only channel) -- anything else is an error.
+//
+//Receive returns immediately and never blocks:
+//
+//- If there is nothing on the channel `c` then Ω(c).Should(Receive()) will fail and Ω(c).ShouldNot(Receive()) will pass.
+//
+//- If the channel `c` is closed then Ω(c).Should(Receive()) will fail and Ω(c).ShouldNot(Receive()) will pass.
+//
+//- If there is something on the channel `c` ready to be read, then Ω(c).Should(Receive()) will pass and Ω(c).ShouldNot(Receive()) will fail.
+//
+//If you have a go-routine running in the background that will write to channel `c` you can:
+// Eventually(c).Should(Receive())
+//
+//This will timeout if nothing gets sent to `c` (you can modify the timeout interval as you normally do with `Eventually`)
+//
+//A similar use-case is to assert that no go-routine writes to a channel (for a period of time). You can do this with `Consistently`:
+// Consistently(c).ShouldNot(Receive())
+//
+//You can pass `Receive` a matcher. If you do so, it will match the received object against the matcher. For example:
+// Ω(c).Should(Receive(Equal("foo")))
+//
+//When given a matcher, `Receive` will always fail if there is nothing to be received on the channel.
+//
+//Passing Receive a matcher is especially useful when paired with Eventually:
+//
+// Eventually(c).Should(Receive(ContainSubstring("bar")))
+//
+//will repeatedly attempt to pull values out of `c` until a value matching "bar" is received.
+//
+//Finally, if you want to have a reference to the value *sent* to the channel you can pass the `Receive` matcher a pointer to a variable of the appropriate type:
+// var myThing thing
+// Eventually(thingChan).Should(Receive(&myThing))
+// Ω(myThing.Sprocket).Should(Equal("foo"))
+// Ω(myThing.IsValid()).Should(BeTrue())
+func Receive(args ...interface{}) types.GomegaMatcher {
+ var arg interface{}
+ if len(args) > 0 {
+ arg = args[0]
+ }
+
+ return &matchers.ReceiveMatcher{
+ Arg: arg,
+ }
+}
+
+//BeSent succeeds if a value can be sent to actual.
+//Actual must be a channel (and cannot be a receive-only channel) that can sent the type of the value passed into BeSent -- anything else is an error.
+//In addition, actual must not be closed.
+//
+//BeSent never blocks:
+//
+//- If the channel `c` is not ready to receive then Ω(c).Should(BeSent("foo")) will fail immediately
+//- If the channel `c` is eventually ready to receive then Eventually(c).Should(BeSent("foo")) will succeed.. presuming the channel becomes ready to receive before Eventually's timeout
+//- If the channel `c` is closed then Ω(c).Should(BeSent("foo")) and Ω(c).ShouldNot(BeSent("foo")) will both fail immediately
+//
+//Of course, the value is actually sent to the channel. The point of `BeSent` is less to make an assertion about the availability of the channel (which is typically an implementation detail that your test should not be concerned with).
+//Rather, the point of `BeSent` is to make it possible to easily and expressively write tests that can timeout on blocked channel sends.
+func BeSent(arg interface{}) types.GomegaMatcher {
+ return &matchers.BeSentMatcher{
+ Arg: arg,
+ }
+}
+
+//MatchRegexp succeeds if actual is a string or stringer that matches the
+//passed-in regexp. Optional arguments can be provided to construct a regexp
+//via fmt.Sprintf().
+func MatchRegexp(regexp string, args ...interface{}) types.GomegaMatcher {
+ return &matchers.MatchRegexpMatcher{
+ Regexp: regexp,
+ Args: args,
+ }
+}
+
+//ContainSubstring succeeds if actual is a string or stringer that contains the
+//passed-in 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,
+ }
+}
+
+//MatchYAML succeeds if actual is a string or stringer of YAML that matches
+//the expected YAML. The YAML's are decoded and the resulting objects are compared via
+//reflect.DeepEqual so things like key-ordering and whitespace shouldn't matter.
+func MatchYAML(yaml interface{}) types.GomegaMatcher {
+ return &matchers.MatchYAMLMatcher{
+ YAMLToMatch: yaml,
+ }
+}
+
+//BeEmpty succeeds if actual is empty. Actual must be of type string, array, map, chan, or slice.
+func BeEmpty() types.GomegaMatcher {
+ return &matchers.BeEmptyMatcher{}
+}
+
+//HaveLen succeeds if actual has the passed-in length. Actual must be of type string, array, map, chan, or slice.
+func HaveLen(count int) types.GomegaMatcher {
+ return &matchers.HaveLenMatcher{
+ Count: count,
+ }
+}
+
+//HaveCap succeeds if actual has the passed-in capacity. Actual must be of type array, chan, or slice.
+func HaveCap(count int) types.GomegaMatcher {
+ return &matchers.HaveCapMatcher{
+ Count: count,
+ }
+}
+
+//BeZero succeeds if actual is the zero value for its type or if actual is nil.
+func BeZero() types.GomegaMatcher {
+ return &matchers.BeZeroMatcher{}
+}
+
+//ContainElement succeeds if actual contains the passed in element.
+//By default ContainElement() uses Equal() to perform the match, however a
+//matcher can be passed in instead:
+// Ω([]string{"Foo", "FooBar"}).Should(ContainElement(ContainSubstring("Bar")))
+//
+//Actual must be an array, slice or map.
+//For maps, ContainElement searches through the map's values.
+func ContainElement(element interface{}) types.GomegaMatcher {
+ return &matchers.ContainElementMatcher{
+ Element: element,
+ }
+}
+
+//ConsistOf succeeds if actual contains preciely the elements passed into the matcher. The ordering of the elements does not matter.
+//By default ConsistOf() uses Equal() to match the elements, however custom matchers can be passed in instead. Here are some examples:
+//
+// Ω([]string{"Foo", "FooBar"}).Should(ConsistOf("FooBar", "Foo"))
+// Ω([]string{"Foo", "FooBar"}).Should(ConsistOf(ContainSubstring("Bar"), "Foo"))
+// Ω([]string{"Foo", "FooBar"}).Should(ConsistOf(ContainSubstring("Foo"), ContainSubstring("Foo")))
+//
+//Actual must be an array, slice or map. For maps, ConsistOf matches against the map's values.
+//
+//You typically pass variadic arguments to ConsistOf (as in the examples above). However, if you need to pass in a slice you can provided that it
+//is the only element passed in to ConsistOf:
+//
+// Ω([]string{"Foo", "FooBar"}).Should(ConsistOf([]string{"FooBar", "Foo"}))
+//
+//Note that Go's type system does not allow you to write this as ConsistOf([]string{"FooBar", "Foo"}...) as []string and []interface{} are different types - hence the need for this special rule.
+func ConsistOf(elements ...interface{}) types.GomegaMatcher {
+ return &matchers.ConsistOfMatcher{
+ Elements: elements,
+ }
+}
+
+//HaveKey succeeds if actual is a map with the passed in key.
+//By default HaveKey uses Equal() to perform the match, however a
+//matcher can be passed in instead:
+// Ω(map[string]string{"Foo": "Bar", "BazFoo": "Duck"}).Should(HaveKey(MatchRegexp(`.+Foo$`)))
+func HaveKey(key interface{}) types.GomegaMatcher {
+ return &matchers.HaveKeyMatcher{
+ Key: key,
+ }
+}
+
+//HaveKeyWithValue succeeds if actual is a map with the passed in key and value.
+//By default HaveKeyWithValue uses Equal() to perform the match, however a
+//matcher can be passed in instead:
+// Ω(map[string]string{"Foo": "Bar", "BazFoo": "Duck"}).Should(HaveKeyWithValue("Foo", "Bar"))
+// Ω(map[string]string{"Foo": "Bar", "BazFoo": "Duck"}).Should(HaveKeyWithValue(MatchRegexp(`.+Foo$`), "Bar"))
+func HaveKeyWithValue(key interface{}, value interface{}) types.GomegaMatcher {
+ return &matchers.HaveKeyWithValueMatcher{
+ Key: key,
+ Value: value,
+ }
+}
+
+//BeNumerically performs numerical assertions in a type-agnostic way.
+//Actual and expected should be numbers, though the specific type of
+//number is irrelevant (floa32, float64, uint8, etc...).
+//
+//There are six, self-explanatory, supported comparators:
+// Ω(1.0).Should(BeNumerically("==", 1))
+// Ω(1.0).Should(BeNumerically("~", 0.999, 0.01))
+// Ω(1.0).Should(BeNumerically(">", 0.9))
+// Ω(1.0).Should(BeNumerically(">=", 1.0))
+// Ω(1.0).Should(BeNumerically("<", 3))
+// Ω(1.0).Should(BeNumerically("<=", 1.0))
+func BeNumerically(comparator string, compareTo ...interface{}) types.GomegaMatcher {
+ return &matchers.BeNumericallyMatcher{
+ Comparator: comparator,
+ CompareTo: compareTo,
+ }
+}
+
+//BeTemporally compares time.Time's like BeNumerically
+//Actual and expected must be time.Time. The comparators are the same as for BeNumerically
+// Ω(time.Now()).Should(BeTemporally(">", time.Time{}))
+// Ω(time.Now()).Should(BeTemporally("~", time.Now(), time.Second))
+func BeTemporally(comparator string, compareTo time.Time, threshold ...time.Duration) types.GomegaMatcher {
+ return &matchers.BeTemporallyMatcher{
+ Comparator: comparator,
+ CompareTo: compareTo,
+ Threshold: threshold,
+ }
+}
+
+//BeAssignableToTypeOf succeeds if actual is assignable to the type of expected.
+//It will return an error when one of the values is nil.
+// Ω(0).Should(BeAssignableToTypeOf(0)) // Same values
+// Ω(5).Should(BeAssignableToTypeOf(-1)) // different values same type
+// Ω("foo").Should(BeAssignableToTypeOf("bar")) // different values same type
+// Ω(struct{ Foo string }{}).Should(BeAssignableToTypeOf(struct{ Foo string }{}))
+func BeAssignableToTypeOf(expected interface{}) types.GomegaMatcher {
+ return &matchers.AssignableToTypeOfMatcher{
+ Expected: expected,
+ }
+}
+
+//Panic succeeds if actual is a function that, when invoked, panics.
+//Actual must be a function that takes no arguments and returns no results.
+func Panic() types.GomegaMatcher {
+ return &matchers.PanicMatcher{}
+}
+
+//BeAnExistingFile succeeds if a file exists.
+//Actual must be a string representing the abs path to the file being checked.
+func BeAnExistingFile() types.GomegaMatcher {
+ return &matchers.BeAnExistingFileMatcher{}
+}
+
+//BeARegularFile succeeds iff a file exists and is a regular file.
+//Actual must be a string representing the abs path to the file being checked.
+func BeARegularFile() types.GomegaMatcher {
+ return &matchers.BeARegularFileMatcher{}
+}
+
+//BeADirectory succeeds iff a file exists and is a directory.
+//Actual must be a string representing the abs path to the file being checked.
+func BeADirectory() types.GomegaMatcher {
+ return &matchers.BeADirectoryMatcher{}
+}
+
+//And succeeds only if all of the given matchers succeed.
+//The matchers are tried in order, and will fail-fast if one doesn't succeed.
+// Expect("hi").To(And(HaveLen(2), Equal("hi"))
+//
+//And(), Or(), Not() and WithTransform() allow matchers to be composed into complex expressions.
+func And(ms ...types.GomegaMatcher) types.GomegaMatcher {
+ return &matchers.AndMatcher{Matchers: ms}
+}
+
+//SatisfyAll is an alias for And().
+// Ω("hi").Should(SatisfyAll(HaveLen(2), Equal("hi")))
+func SatisfyAll(matchers ...types.GomegaMatcher) types.GomegaMatcher {
+ return And(matchers...)
+}
+
+//Or succeeds if any of the given matchers succeed.
+//The matchers are tried in order and will return immediately upon the first successful match.
+// Expect("hi").To(Or(HaveLen(3), HaveLen(2))
+//
+//And(), Or(), Not() and WithTransform() allow matchers to be composed into complex expressions.
+func Or(ms ...types.GomegaMatcher) types.GomegaMatcher {
+ return &matchers.OrMatcher{Matchers: ms}
+}
+
+//SatisfyAny is an alias for Or().
+// Expect("hi").SatisfyAny(Or(HaveLen(3), HaveLen(2))
+func SatisfyAny(matchers ...types.GomegaMatcher) types.GomegaMatcher {
+ return Or(matchers...)
+}
+
+//Not negates the given matcher; it succeeds if the given matcher fails.
+// Expect(1).To(Not(Equal(2))
+//
+//And(), Or(), Not() and WithTransform() allow matchers to be composed into complex expressions.
+func Not(matcher types.GomegaMatcher) types.GomegaMatcher {
+ return &matchers.NotMatcher{Matcher: matcher}
+}
+
+//WithTransform applies the `transform` to the actual value and matches it against `matcher`.
+//The given transform must be a function of one parameter that returns one value.
+// var plus1 = func(i int) int { return i + 1 }
+// Expect(1).To(WithTransform(plus1, Equal(2))
+//
+//And(), Or(), Not() and WithTransform() allow matchers to be composed into complex expressions.
+func WithTransform(transform interface{}, matcher types.GomegaMatcher) types.GomegaMatcher {
+ return matchers.NewWithTransformMatcher(transform, matcher)
+}
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 0000000..94c42a7
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/and.go
@@ -0,0 +1,64 @@
+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
+ } else {
+ // 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 0000000..acf778c
--- /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 0000000..89a1fc2
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher.go
@@ -0,0 +1,31 @@
+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.")
+ }
+
+ 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 0000000..d2280e0
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher_test.go
@@ -0,0 +1,30 @@
+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() {
+ Ω(0).Should(BeAssignableToTypeOf(0))
+ Ω(5).Should(BeAssignableToTypeOf(-1))
+ Ω("foo").Should(BeAssignableToTypeOf("bar"))
+ Ω(struct{ Foo string }{}).Should(BeAssignableToTypeOf(struct{ Foo string }{}))
+
+ Ω(0).ShouldNot(BeAssignableToTypeOf("bar"))
+ Ω(5).ShouldNot(BeAssignableToTypeOf(struct{ Foo string }{}))
+ Ω("foo").ShouldNot(BeAssignableToTypeOf(42))
+ })
+ })
+
+ Context("When asserting nil values", func() {
+ It("should error", func() {
+ success, err := (&AssignableToTypeOfMatcher{Expected: nil}).Match(nil)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+})
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 0000000..7b6975e
--- /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 0000000..e59d769
--- /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() {
+ Ω("/dne/test").ShouldNot(BeADirectory())
+
+ tmpFile, err := ioutil.TempFile("", "gomega-test-tempfile")
+ Ω(err).ShouldNot(HaveOccurred())
+ defer os.Remove(tmpFile.Name())
+ Ω(tmpFile.Name()).ShouldNot(BeADirectory())
+
+ tmpDir, err := ioutil.TempDir("", "gomega-test-tempdir")
+ Ω(err).ShouldNot(HaveOccurred())
+ defer os.Remove(tmpDir)
+ Ω(tmpDir).Should(BeADirectory())
+ })
+ })
+
+ Context("when passed something else", func() {
+ It("should error", func() {
+ success, err := (&BeADirectoryMatcher{}).Match(nil)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&BeADirectoryMatcher{}).Match(true)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+})
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 0000000..e239131
--- /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 0000000..951e750
--- /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() {
+ Ω("/dne/test").ShouldNot(BeARegularFile())
+
+ tmpFile, err := ioutil.TempFile("", "gomega-test-tempfile")
+ Ω(err).ShouldNot(HaveOccurred())
+ defer os.Remove(tmpFile.Name())
+ Ω(tmpFile.Name()).Should(BeARegularFile())
+
+ tmpDir, err := ioutil.TempDir("", "gomega-test-tempdir")
+ Ω(err).ShouldNot(HaveOccurred())
+ defer os.Remove(tmpDir)
+ Ω(tmpDir).ShouldNot(BeARegularFile())
+ })
+ })
+
+ Context("when passed something else", func() {
+ It("should error", func() {
+ success, err := (&BeARegularFileMatcher{}).Match(nil)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&BeARegularFileMatcher{}).Match(true)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+})
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 0000000..d42eba2
--- /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 0000000..775f7b6
--- /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() {
+ Ω("/dne/test").ShouldNot(BeAnExistingFile())
+
+ tmpFile, err := ioutil.TempFile("", "gomega-test-tempfile")
+ Ω(err).ShouldNot(HaveOccurred())
+ defer os.Remove(tmpFile.Name())
+ Ω(tmpFile.Name()).Should(BeAnExistingFile())
+
+ tmpDir, err := ioutil.TempDir("", "gomega-test-tempdir")
+ Ω(err).ShouldNot(HaveOccurred())
+ defer os.Remove(tmpDir)
+ Ω(tmpDir).Should(BeAnExistingFile())
+ })
+ })
+
+ Context("when passed something else", func() {
+ It("should error", func() {
+ success, err := (&BeAnExistingFileMatcher{}).Match(nil)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&BeAnExistingFileMatcher{}).Match(true)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+})
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 0000000..c1b4995
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_closed_matcher.go
@@ -0,0 +1,45 @@
+package matchers
+
+import (
+ "fmt"
+ "github.com/onsi/gomega/format"
+ "reflect"
+)
+
+type BeClosedMatcher struct {
+}
+
+func (matcher *BeClosedMatcher) Match(actual interface{}) (success bool, err error) {
+ if !isChan(actual) {
+ return false, fmt.Errorf("BeClosed matcher expects a channel. Got:\n%s", format.Object(actual, 1))
+ }
+
+ channelType := reflect.TypeOf(actual)
+ channelValue := reflect.ValueOf(actual)
+
+ if channelType.ChanDir() == reflect.SendDir {
+ return false, fmt.Errorf("BeClosed matcher cannot determine if a send-only channel is closed or open. Got:\n%s", format.Object(actual, 1))
+ }
+
+ winnerIndex, _, open := reflect.Select([]reflect.SelectCase{
+ reflect.SelectCase{Dir: reflect.SelectRecv, Chan: channelValue},
+ reflect.SelectCase{Dir: reflect.SelectDefault},
+ })
+
+ var closed bool
+ if winnerIndex == 0 {
+ closed = !open
+ } else if winnerIndex == 1 {
+ closed = false
+ }
+
+ return closed, nil
+}
+
+func (matcher *BeClosedMatcher) FailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, "to be closed")
+}
+
+func (matcher *BeClosedMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, "to be open")
+}
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 0000000..b2c40c9
--- /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)
+ Ω(openChannel).ShouldNot(BeClosed())
+
+ var openReaderChannel <-chan bool
+ openReaderChannel = openChannel
+ Ω(openReaderChannel).ShouldNot(BeClosed())
+
+ closedChannel := make(chan bool)
+ close(closedChannel)
+
+ Ω(closedChannel).Should(BeClosed())
+
+ var closedReaderChannel <-chan bool
+ closedReaderChannel = closedChannel
+ Ω(closedReaderChannel).Should(BeClosed())
+ })
+ })
+
+ Context("when passed a send-only channel", func() {
+ It("should error", func() {
+ openChannel := make(chan bool)
+ var openWriterChannel chan<- bool
+ openWriterChannel = openChannel
+
+ success, err := (&BeClosedMatcher{}).Match(openWriterChannel)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ closedChannel := make(chan bool)
+ close(closedChannel)
+
+ var closedWriterChannel chan<- bool
+ closedWriterChannel = closedChannel
+
+ success, err = (&BeClosedMatcher{}).Match(closedWriterChannel)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ })
+ })
+
+ Context("when passed something else", func() {
+ It("should error", func() {
+ var nilChannel chan bool
+
+ success, err := (&BeClosedMatcher{}).Match(nilChannel)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&BeClosedMatcher{}).Match(nil)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&BeClosedMatcher{}).Match(7)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+})
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 0000000..55bdd7d
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_empty_matcher.go
@@ -0,0 +1,26 @@
+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 0000000..541c1b9
--- /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() {
+ Ω("").Should(BeEmpty())
+ Ω(" ").ShouldNot(BeEmpty())
+
+ Ω([0]int{}).Should(BeEmpty())
+ Ω([1]int{1}).ShouldNot(BeEmpty())
+
+ Ω([]int{}).Should(BeEmpty())
+ Ω([]int{1}).ShouldNot(BeEmpty())
+
+ Ω(map[string]int{}).Should(BeEmpty())
+ Ω(map[string]int{"a": 1}).ShouldNot(BeEmpty())
+
+ c := make(chan bool, 1)
+ Ω(c).Should(BeEmpty())
+ c <- true
+ Ω(c).ShouldNot(BeEmpty())
+ })
+ })
+
+ Context("when passed a correctly typed nil", func() {
+ It("should be true", func() {
+ var nilSlice []int
+ Ω(nilSlice).Should(BeEmpty())
+
+ var nilMap map[int]string
+ Ω(nilMap).Should(BeEmpty())
+ })
+ })
+
+ Context("when passed an unsupported type", func() {
+ It("should error", func() {
+ success, err := (&BeEmptyMatcher{}).Match(0)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&BeEmptyMatcher{}).Match(nil)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+})
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 0000000..32a0c31
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher.go
@@ -0,0 +1,33 @@
+package matchers
+
+import (
+ "fmt"
+ "github.com/onsi/gomega/format"
+ "reflect"
+)
+
+type BeEquivalentToMatcher struct {
+ Expected interface{}
+}
+
+func (matcher *BeEquivalentToMatcher) Match(actual interface{}) (success bool, err error) {
+ if actual == nil && matcher.Expected == nil {
+ return false, fmt.Errorf("Both actual and expected must not be nil.")
+ }
+
+ convertedActual := actual
+
+ if actual != nil && matcher.Expected != nil && reflect.TypeOf(actual).ConvertibleTo(reflect.TypeOf(matcher.Expected)) {
+ convertedActual = reflect.ValueOf(actual).Convert(reflect.TypeOf(matcher.Expected)).Interface()
+ }
+
+ return reflect.DeepEqual(convertedActual, matcher.Expected), nil
+}
+
+func (matcher *BeEquivalentToMatcher) FailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, "to be equivalent to", matcher.Expected)
+}
+
+func (matcher *BeEquivalentToMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, "not to be equivalent to", matcher.Expected)
+}
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 0000000..def5104
--- /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)
+
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("When asserting on nil", func() {
+ It("should do the right thing", func() {
+ Ω("foo").ShouldNot(BeEquivalentTo(nil))
+ Ω(nil).ShouldNot(BeEquivalentTo(3))
+ Ω([]int{1, 2}).ShouldNot(BeEquivalentTo(nil))
+ })
+ })
+
+ Context("When asserting on type aliases", func() {
+ It("should the right thing", func() {
+ Ω(StringAlias("foo")).Should(BeEquivalentTo("foo"))
+ Ω("foo").Should(BeEquivalentTo(StringAlias("foo")))
+ Ω(StringAlias("foo")).ShouldNot(BeEquivalentTo("bar"))
+ Ω("foo").ShouldNot(BeEquivalentTo(StringAlias("bar")))
+ })
+ })
+
+ Context("When asserting on numbers", func() {
+ It("should convert actual to expected and do the right thing", func() {
+ Ω(5).Should(BeEquivalentTo(5))
+ Ω(5.0).Should(BeEquivalentTo(5.0))
+ Ω(5).Should(BeEquivalentTo(5.0))
+
+ Ω(5).ShouldNot(BeEquivalentTo("5"))
+ Ω(5).ShouldNot(BeEquivalentTo(3))
+
+ //Here be dragons!
+ Ω(5.1).Should(BeEquivalentTo(5))
+ Ω(5).ShouldNot(BeEquivalentTo(5.1))
+ })
+ })
+})
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 0000000..0b224cb
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_false_matcher.go
@@ -0,0 +1,25 @@
+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 0000000..3965a2c
--- /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() {
+ Ω(true).ShouldNot(BeFalse())
+ Ω(false).Should(BeFalse())
+ })
+
+ It("should only support booleans", func() {
+ success, err := (&BeFalseMatcher{}).Match("foo")
+ Ω(success).Should(BeFalse())
+ Ω(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 0000000..fdcda4d
--- /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 0000000..8b90a1a
--- /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)
+
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+
+ It("should treat the same pointer to a struct as identical", func() {
+ mySpecialStruct := myCustomType{}
+ Ω(&mySpecialStruct).Should(BeIdenticalTo(&mySpecialStruct))
+ Ω(&myCustomType{}).ShouldNot(BeIdenticalTo(&mySpecialStruct))
+ })
+
+ It("should be strict about types", func() {
+ Ω(5).ShouldNot(BeIdenticalTo("5"))
+ Ω(5).ShouldNot(BeIdenticalTo(5.0))
+ Ω(5).ShouldNot(BeIdenticalTo(3))
+ })
+
+ It("should treat primtives as identical", func() {
+ Ω("5").Should(BeIdenticalTo("5"))
+ Ω("5").ShouldNot(BeIdenticalTo("55"))
+
+ Ω(5.55).Should(BeIdenticalTo(5.55))
+ Ω(5.55).ShouldNot(BeIdenticalTo(6.66))
+
+ Ω(5).Should(BeIdenticalTo(5))
+ Ω(5).ShouldNot(BeIdenticalTo(55))
+ })
+
+ It("should treat the same pointers to a slice as identical", func() {
+ mySlice := []int{1, 2}
+ Ω(&mySlice).Should(BeIdenticalTo(&mySlice))
+ Ω(&mySlice).ShouldNot(BeIdenticalTo(&[]int{1, 2}))
+ })
+
+ It("should treat the same pointers to a map as identical", func() {
+ myMap := map[string]string{"a": "b", "c": "d"}
+ Ω(&myMap).Should(BeIdenticalTo(&myMap))
+ Ω(myMap).ShouldNot(BeIdenticalTo(map[string]string{"a": "b", "c": "d"}))
+ })
+
+ It("should treat the same pointers to an error as identical", func() {
+ myError := errors.New("foo")
+ Ω(&myError).Should(BeIdenticalTo(&myError))
+ Ω(errors.New("foo")).ShouldNot(BeIdenticalTo(errors.New("bar")))
+ })
+})
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 0000000..7ee84fe
--- /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 0000000..7533253
--- /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() {
+ Ω(nil).Should(BeNil())
+ })
+
+ It("should succeed when passed a typed nil", func() {
+ var a []int
+ Ω(a).Should(BeNil())
+ })
+
+ It("should succeed when passing nil pointer", func() {
+ var f *struct{}
+ Ω(f).Should(BeNil())
+ })
+
+ It("should not succeed when not passed nil", func() {
+ Ω(0).ShouldNot(BeNil())
+ Ω(false).ShouldNot(BeNil())
+ Ω("").ShouldNot(BeNil())
+ })
+})
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 0000000..0c157f6
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher.go
@@ -0,0 +1,120 @@
+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 format.Message(actual, fmt.Sprintf("to be %s", matcher.Comparator), matcher.CompareTo[0])
+}
+
+func (matcher *BeNumericallyMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, fmt.Sprintf("not to be %s", matcher.Comparator), matcher.CompareTo[0])
+}
+
+func (matcher *BeNumericallyMatcher) Match(actual interface{}) (success bool, err error) {
+ if len(matcher.CompareTo) == 0 || len(matcher.CompareTo) > 2 {
+ return false, fmt.Errorf("BeNumerically requires 1 or 2 CompareTo arguments. Got:\n%s", format.Object(matcher.CompareTo, 1))
+ }
+ if !isNumber(actual) {
+ return false, fmt.Errorf("Expected a number. Got:\n%s", format.Object(actual, 1))
+ }
+ if !isNumber(matcher.CompareTo[0]) {
+ return false, fmt.Errorf("Expected a number. Got:\n%s", format.Object(matcher.CompareTo[0], 1))
+ }
+ if len(matcher.CompareTo) == 2 && !isNumber(matcher.CompareTo[1]) {
+ return false, fmt.Errorf("Expected a number. Got:\n%s", format.Object(matcher.CompareTo[0], 1))
+ }
+
+ switch matcher.Comparator {
+ case "==", "~", ">", ">=", "<", "<=":
+ default:
+ return false, fmt.Errorf("Unknown comparator: %s", matcher.Comparator)
+ }
+
+ if isFloat(actual) || isFloat(matcher.CompareTo[0]) {
+ var secondOperand float64 = 1e-8
+ if len(matcher.CompareTo) == 2 {
+ secondOperand = toFloat(matcher.CompareTo[1])
+ }
+ success = matcher.matchFloats(toFloat(actual), toFloat(matcher.CompareTo[0]), secondOperand)
+ } else if isInteger(actual) {
+ var secondOperand int64 = 0
+ if len(matcher.CompareTo) == 2 {
+ secondOperand = toInteger(matcher.CompareTo[1])
+ }
+ success = matcher.matchIntegers(toInteger(actual), toInteger(matcher.CompareTo[0]), secondOperand)
+ } else if isUnsignedInteger(actual) {
+ var secondOperand uint64 = 0
+ if len(matcher.CompareTo) == 2 {
+ secondOperand = toUnsignedInteger(matcher.CompareTo[1])
+ }
+ success = matcher.matchUnsignedIntegers(toUnsignedInteger(actual), toUnsignedInteger(matcher.CompareTo[0]), secondOperand)
+ } else {
+ return false, fmt.Errorf("Failed to compare:\n%s\n%s:\n%s", format.Object(actual, 1), matcher.Comparator, format.Object(matcher.CompareTo[0], 1))
+ }
+
+ return success, nil
+}
+
+func (matcher *BeNumericallyMatcher) matchIntegers(actual, compareTo, threshold int64) (success bool) {
+ switch matcher.Comparator {
+ case "==", "~":
+ diff := actual - compareTo
+ return -threshold <= diff && diff <= threshold
+ case ">":
+ return (actual > compareTo)
+ case ">=":
+ return (actual >= compareTo)
+ case "<":
+ return (actual < compareTo)
+ case "<=":
+ return (actual <= compareTo)
+ }
+ return false
+}
+
+func (matcher *BeNumericallyMatcher) matchUnsignedIntegers(actual, compareTo, threshold uint64) (success bool) {
+ switch matcher.Comparator {
+ case "==", "~":
+ if actual < compareTo {
+ actual, compareTo = compareTo, actual
+ }
+ return actual-compareTo <= threshold
+ case ">":
+ return (actual > compareTo)
+ case ">=":
+ return (actual >= compareTo)
+ case "<":
+ return (actual < compareTo)
+ case "<=":
+ return (actual <= compareTo)
+ }
+ return false
+}
+
+func (matcher *BeNumericallyMatcher) matchFloats(actual, compareTo, threshold float64) (success bool) {
+ switch matcher.Comparator {
+ case "~":
+ return math.Abs(actual-compareTo) <= threshold
+ case "==":
+ return (actual == compareTo)
+ case ">":
+ return (actual > compareTo)
+ case ">=":
+ return (actual >= compareTo)
+ case "<":
+ return (actual < compareTo)
+ case "<=":
+ return (actual <= compareTo)
+ }
+ return false
+}
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 0000000..43fdb1f
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher_test.go
@@ -0,0 +1,148 @@
+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() {
+ Ω(uint32(5)).Should(BeNumerically("==", 5))
+ Ω(float64(5.0)).Should(BeNumerically("==", 5))
+ Ω(int8(5)).Should(BeNumerically("==", 5))
+ })
+
+ It("should not have false positives", func() {
+ Ω(5.1).ShouldNot(BeNumerically("==", 5))
+ Ω(5).ShouldNot(BeNumerically("==", 5.1))
+ })
+
+ It("should support >", func() {
+ Ω(uint32(5)).Should(BeNumerically(">", 4))
+ Ω(float64(5.0)).Should(BeNumerically(">", 4.9))
+ Ω(int8(5)).Should(BeNumerically(">", 4))
+
+ Ω(uint32(5)).ShouldNot(BeNumerically(">", 5))
+ Ω(float64(5.0)).ShouldNot(BeNumerically(">", 5.0))
+ Ω(int8(5)).ShouldNot(BeNumerically(">", 5))
+ })
+
+ It("should support <", func() {
+ Ω(uint32(5)).Should(BeNumerically("<", 6))
+ Ω(float64(5.0)).Should(BeNumerically("<", 5.1))
+ Ω(int8(5)).Should(BeNumerically("<", 6))
+
+ Ω(uint32(5)).ShouldNot(BeNumerically("<", 5))
+ Ω(float64(5.0)).ShouldNot(BeNumerically("<", 5.0))
+ Ω(int8(5)).ShouldNot(BeNumerically("<", 5))
+ })
+
+ It("should support >=", func() {
+ Ω(uint32(5)).Should(BeNumerically(">=", 4))
+ Ω(float64(5.0)).Should(BeNumerically(">=", 4.9))
+ Ω(int8(5)).Should(BeNumerically(">=", 4))
+
+ Ω(uint32(5)).Should(BeNumerically(">=", 5))
+ Ω(float64(5.0)).Should(BeNumerically(">=", 5.0))
+ Ω(int8(5)).Should(BeNumerically(">=", 5))
+
+ Ω(uint32(5)).ShouldNot(BeNumerically(">=", 6))
+ Ω(float64(5.0)).ShouldNot(BeNumerically(">=", 5.1))
+ Ω(int8(5)).ShouldNot(BeNumerically(">=", 6))
+ })
+
+ It("should support <=", func() {
+ Ω(uint32(5)).Should(BeNumerically("<=", 6))
+ Ω(float64(5.0)).Should(BeNumerically("<=", 5.1))
+ Ω(int8(5)).Should(BeNumerically("<=", 6))
+
+ Ω(uint32(5)).Should(BeNumerically("<=", 5))
+ Ω(float64(5.0)).Should(BeNumerically("<=", 5.0))
+ Ω(int8(5)).Should(BeNumerically("<=", 5))
+
+ Ω(uint32(5)).ShouldNot(BeNumerically("<=", 4))
+ Ω(float64(5.0)).ShouldNot(BeNumerically("<=", 4.9))
+ Ω(int8(5)).Should(BeNumerically("<=", 5))
+ })
+
+ Context("when passed ~", func() {
+ Context("when passed a float", func() {
+ Context("and there is no precision parameter", func() {
+ It("should default to 1e-8", func() {
+ Ω(5.00000001).Should(BeNumerically("~", 5.00000002))
+ Ω(5.00000001).ShouldNot(BeNumerically("~", 5.0000001))
+ })
+ })
+
+ Context("and there is a precision parameter", func() {
+ It("should use the precision parameter", func() {
+ Ω(5.1).Should(BeNumerically("~", 5.19, 0.1))
+ Ω(5.1).Should(BeNumerically("~", 5.01, 0.1))
+ Ω(5.1).ShouldNot(BeNumerically("~", 5.22, 0.1))
+ Ω(5.1).ShouldNot(BeNumerically("~", 4.98, 0.1))
+ })
+ })
+ })
+
+ Context("when passed an int/uint", func() {
+ Context("and there is no precision parameter", func() {
+ It("should just do strict equality", func() {
+ Ω(5).Should(BeNumerically("~", 5))
+ Ω(5).ShouldNot(BeNumerically("~", 6))
+ Ω(uint(5)).ShouldNot(BeNumerically("~", 6))
+ })
+ })
+
+ Context("and there is a precision parameter", func() {
+ It("should use precision paramter", func() {
+ Ω(5).Should(BeNumerically("~", 6, 2))
+ Ω(5).ShouldNot(BeNumerically("~", 8, 2))
+ Ω(uint(5)).Should(BeNumerically("~", 6, 1))
+ })
+ })
+ })
+ })
+ })
+
+ Context("when passed a non-number", func() {
+ It("should error", func() {
+ success, err := (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{5}}).Match("foo")
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&BeNumericallyMatcher{Comparator: "=="}).Match(5)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&BeNumericallyMatcher{Comparator: "~", CompareTo: []interface{}{3.0, "foo"}}).Match(5.0)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{"bar"}}).Match(5)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{"bar"}}).Match("foo")
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{nil}}).Match(0)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{0}}).Match(nil)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("when passed an unsupported comparator", func() {
+ It("should error", func() {
+ success, err := (&BeNumericallyMatcher{Comparator: "!=", CompareTo: []interface{}{5}}).Match(4)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+})
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 0000000..d7c3223
--- /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{
+ reflect.SelectCase{Dir: reflect.SelectSend, Chan: channelValue, Send: argValue},
+ reflect.SelectCase{Dir: reflect.SelectDefault},
+ })
+
+ var didSend bool
+ if winnerIndex == 0 {
+ didSend = true
+ }
+
+ return didSend, nil
+}
+
+func (matcher *BeSentMatcher) FailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, "to send:", matcher.Arg)
+}
+
+func (matcher *BeSentMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, "not to send:", matcher.Arg)
+}
+
+func (matcher *BeSentMatcher) MatchMayChangeInTheFuture(actual interface{}) bool {
+ if !isChan(actual) {
+ return false
+ }
+
+ return !matcher.channelClosed
+}
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 0000000..205d71f
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_sent_matcher_test.go
@@ -0,0 +1,106 @@
+package matchers_test
+
+import (
+ . "github.com/onsi/gomega/matchers"
+ "time"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("BeSent", func() {
+ Context("when passed a channel and a matching type", func() {
+ Context("when the channel is ready to receive", func() {
+ It("should succeed and send the value down the channel", func() {
+ c := make(chan string)
+ d := make(chan string)
+ go func() {
+ val := <-c
+ d <- val
+ }()
+
+ time.Sleep(10 * time.Millisecond)
+
+ Ω(c).Should(BeSent("foo"))
+ Eventually(d).Should(Receive(Equal("foo")))
+ })
+
+ It("should succeed (with a buffered channel)", func() {
+ c := make(chan string, 1)
+ Ω(c).Should(BeSent("foo"))
+ Ω(<-c).Should(Equal("foo"))
+ })
+ })
+
+ Context("when the channel is not ready to receive", func() {
+ It("should fail and not send down the channel", func() {
+ c := make(chan string)
+ Ω(c).ShouldNot(BeSent("foo"))
+ Consistently(c).ShouldNot(Receive())
+ })
+ })
+
+ Context("when the channel is eventually ready to receive", func() {
+ It("should succeed", func() {
+ c := make(chan string)
+ d := make(chan string)
+ go func() {
+ time.Sleep(30 * time.Millisecond)
+ val := <-c
+ d <- val
+ }()
+
+ Eventually(c).Should(BeSent("foo"))
+ Eventually(d).Should(Receive(Equal("foo")))
+ })
+ })
+
+ Context("when the channel is closed", func() {
+ It("should error", func() {
+ c := make(chan string)
+ close(c)
+ success, err := (&BeSentMatcher{Arg: "foo"}).Match(c)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+
+ It("should short-circuit Eventually", func() {
+ c := make(chan string)
+ close(c)
+
+ t := time.Now()
+ failures := InterceptGomegaFailures(func() {
+ Eventually(c, 10.0).Should(BeSent("foo"))
+ })
+ Ω(failures).Should(HaveLen(1))
+ Ω(time.Since(t)).Should(BeNumerically("<", time.Second))
+ })
+ })
+ })
+
+ Context("when passed a channel and a non-matching type", func() {
+ It("should error", func() {
+ success, err := (&BeSentMatcher{Arg: "foo"}).Match(make(chan int, 1))
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("when passed a receive-only channel", func() {
+ It("should error", func() {
+ var c <-chan string
+ c = make(chan string, 1)
+ success, err := (&BeSentMatcher{Arg: "foo"}).Match(c)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("when passed a nonchannel", func() {
+ It("should error", func() {
+ success, err := (&BeSentMatcher{Arg: "foo"}).Match("bar")
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+})
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 0000000..abda4eb
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher.go
@@ -0,0 +1,65 @@
+package matchers
+
+import (
+ "fmt"
+ "github.com/onsi/gomega/format"
+ "time"
+)
+
+type BeTemporallyMatcher struct {
+ Comparator string
+ CompareTo time.Time
+ Threshold []time.Duration
+}
+
+func (matcher *BeTemporallyMatcher) FailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, fmt.Sprintf("to be %s", matcher.Comparator), matcher.CompareTo)
+}
+
+func (matcher *BeTemporallyMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, fmt.Sprintf("not to be %s", matcher.Comparator), matcher.CompareTo)
+}
+
+func (matcher *BeTemporallyMatcher) Match(actual interface{}) (bool, error) {
+ // predicate to test for time.Time type
+ isTime := func(t interface{}) bool {
+ _, ok := t.(time.Time)
+ return ok
+ }
+
+ if !isTime(actual) {
+ return false, fmt.Errorf("Expected a time.Time. Got:\n%s", format.Object(actual, 1))
+ }
+
+ switch matcher.Comparator {
+ case "==", "~", ">", ">=", "<", "<=":
+ default:
+ return false, fmt.Errorf("Unknown comparator: %s", matcher.Comparator)
+ }
+
+ var threshold = time.Millisecond
+ if len(matcher.Threshold) == 1 {
+ threshold = matcher.Threshold[0]
+ }
+
+ return matcher.matchTimes(actual.(time.Time), matcher.CompareTo, threshold), nil
+}
+
+func (matcher *BeTemporallyMatcher) matchTimes(actual, compareTo time.Time, threshold time.Duration) (success bool) {
+ switch matcher.Comparator {
+ case "==":
+ return actual.Equal(compareTo)
+ case "~":
+ diff := actual.Sub(compareTo)
+ return -threshold <= diff && diff <= threshold
+ case ">":
+ return actual.After(compareTo)
+ case ">=":
+ return !actual.Before(compareTo)
+ case "<":
+ return actual.Before(compareTo)
+ case "<=":
+ return !actual.After(compareTo)
+ }
+ return false
+}
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 0000000..feb33e5
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher_test.go
@@ -0,0 +1,98 @@
+package matchers_test
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/matchers"
+ "time"
+)
+
+var _ = Describe("BeTemporally", func() {
+
+ var t0, t1, t2 time.Time
+ BeforeEach(func() {
+ t0 = time.Now()
+ t1 = t0.Add(time.Second)
+ t2 = t0.Add(-time.Second)
+ })
+
+ Context("When comparing times", func() {
+
+ It("should support ==", func() {
+ Ω(t0).Should(BeTemporally("==", t0))
+ Ω(t1).ShouldNot(BeTemporally("==", t0))
+ Ω(t0).ShouldNot(BeTemporally("==", t1))
+ Ω(t0).ShouldNot(BeTemporally("==", time.Time{}))
+ })
+
+ It("should support >", func() {
+ Ω(t0).Should(BeTemporally(">", t2))
+ Ω(t0).ShouldNot(BeTemporally(">", t0))
+ Ω(t2).ShouldNot(BeTemporally(">", t0))
+ })
+
+ It("should support <", func() {
+ Ω(t0).Should(BeTemporally("<", t1))
+ Ω(t0).ShouldNot(BeTemporally("<", t0))
+ Ω(t1).ShouldNot(BeTemporally("<", t0))
+ })
+
+ It("should support >=", func() {
+ Ω(t0).Should(BeTemporally(">=", t2))
+ Ω(t0).Should(BeTemporally(">=", t0))
+ Ω(t0).ShouldNot(BeTemporally(">=", t1))
+ })
+
+ It("should support <=", func() {
+ Ω(t0).Should(BeTemporally("<=", t1))
+ Ω(t0).Should(BeTemporally("<=", t0))
+ Ω(t0).ShouldNot(BeTemporally("<=", t2))
+ })
+
+ Context("when passed ~", func() {
+ Context("and there is no precision parameter", func() {
+ BeforeEach(func() {
+ t1 = t0.Add(time.Millisecond / 2)
+ t2 = t0.Add(-2 * time.Millisecond)
+ })
+ It("should approximate", func() {
+ Ω(t0).Should(BeTemporally("~", t0))
+ Ω(t0).Should(BeTemporally("~", t1))
+ Ω(t0).ShouldNot(BeTemporally("~", t2))
+ })
+ })
+
+ Context("and there is a precision parameter", func() {
+ BeforeEach(func() {
+ t2 = t0.Add(3 * time.Second)
+ })
+ It("should use precision paramter", func() {
+ d := 2 * time.Second
+ Ω(t0).Should(BeTemporally("~", t0, d))
+ Ω(t0).Should(BeTemporally("~", t1, d))
+ Ω(t0).ShouldNot(BeTemporally("~", t2, d))
+ })
+ })
+ })
+ })
+
+ Context("when passed a non-time", func() {
+ It("should error", func() {
+ success, err := (&BeTemporallyMatcher{Comparator: "==", CompareTo: t0}).Match("foo")
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&BeTemporallyMatcher{Comparator: "=="}).Match(nil)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("when passed an unsupported comparator", func() {
+ It("should error", func() {
+ success, err := (&BeTemporallyMatcher{Comparator: "!=", CompareTo: t0}).Match(t2)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+})
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 0000000..1275e5f
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_true_matcher.go
@@ -0,0 +1,25 @@
+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 0000000..ca32e56
--- /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() {
+ Ω(true).Should(BeTrue())
+ Ω(false).ShouldNot(BeTrue())
+ })
+
+ It("should only support booleans", func() {
+ success, err := (&BeTrueMatcher{}).Match("foo")
+ Ω(success).Should(BeFalse())
+ Ω(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 0000000..b39c914
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_zero_matcher.go
@@ -0,0 +1,27 @@
+package matchers
+
+import (
+ "github.com/onsi/gomega/format"
+ "reflect"
+)
+
+type BeZeroMatcher struct {
+}
+
+func (matcher *BeZeroMatcher) Match(actual interface{}) (success bool, err error) {
+ if actual == nil {
+ return true, nil
+ }
+ zeroValue := reflect.Zero(reflect.TypeOf(actual)).Interface()
+
+ return reflect.DeepEqual(zeroValue, actual), nil
+
+}
+
+func (matcher *BeZeroMatcher) FailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, "to be zero-valued")
+}
+
+func (matcher *BeZeroMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, "not to be zero-valued")
+}
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 0000000..8ec3643
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/be_zero_matcher_test.go
@@ -0,0 +1,30 @@
+package matchers_test
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("BeZero", func() {
+ It("should succeed if the passed in object is the zero value for its type", func() {
+ Ω(nil).Should(BeZero())
+
+ Ω("").Should(BeZero())
+ Ω(" ").ShouldNot(BeZero())
+
+ Ω(0).Should(BeZero())
+ Ω(1).ShouldNot(BeZero())
+
+ Ω(0.0).Should(BeZero())
+ Ω(0.1).ShouldNot(BeZero())
+
+ // Ω([]int{}).Should(BeZero())
+ Ω([]int{1}).ShouldNot(BeZero())
+
+ // Ω(map[string]int{}).Should(BeZero())
+ Ω(map[string]int{"a": 1}).ShouldNot(BeZero())
+
+ Ω(myCustomType{}).Should(BeZero())
+ Ω(myCustomType{s: "a"}).ShouldNot(BeZero())
+ })
+})
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 0000000..7b0e088
--- /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 0000000..dcd1afe
--- /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() {
+ Ω([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", "bar", "baz"))
+ Ω([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", "bar", "baz"))
+ Ω([]string{"foo", "bar", "baz"}).Should(ConsistOf("baz", "bar", "foo"))
+ Ω([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "bar", "foo", "foo"))
+ Ω([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "foo"))
+ })
+ })
+
+ Context("with an array", func() {
+ It("should do the right thing", func() {
+ Ω([3]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", "bar", "baz"))
+ Ω([3]string{"foo", "bar", "baz"}).Should(ConsistOf("baz", "bar", "foo"))
+ Ω([3]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "bar", "foo", "foo"))
+ Ω([3]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "foo"))
+ })
+ })
+
+ Context("with a map", func() {
+ It("should apply to the values", func() {
+ Ω(map[int]string{1: "foo", 2: "bar", 3: "baz"}).Should(ConsistOf("foo", "bar", "baz"))
+ Ω(map[int]string{1: "foo", 2: "bar", 3: "baz"}).Should(ConsistOf("baz", "bar", "foo"))
+ Ω(map[int]string{1: "foo", 2: "bar", 3: "baz"}).ShouldNot(ConsistOf("baz", "bar", "foo", "foo"))
+ Ω(map[int]string{1: "foo", 2: "bar", 3: "baz"}).ShouldNot(ConsistOf("baz", "foo"))
+ })
+
+ })
+
+ Context("with anything else", func() {
+ It("should error", func() {
+ failures := InterceptGomegaFailures(func() {
+ Ω("foo").Should(ConsistOf("f", "o", "o"))
+ })
+
+ Ω(failures).Should(HaveLen(1))
+ })
+ })
+
+ Context("when passed matchers", func() {
+ It("should pass if the matchers pass", func() {
+ Ω([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", MatchRegexp("^ba"), "baz"))
+ Ω([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("foo", MatchRegexp("^ba")))
+ Ω([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("foo", MatchRegexp("^ba"), MatchRegexp("foo")))
+ Ω([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", MatchRegexp("^ba"), MatchRegexp("^ba")))
+ Ω([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("foo", MatchRegexp("^ba"), MatchRegexp("turducken")))
+ })
+
+ It("should not depend on the order of the matchers", func() {
+ Ω([][]int{[]int{1, 2}, []int{2}}).Should(ConsistOf(ContainElement(1), ContainElement(2)))
+ Ω([][]int{[]int{1, 2}, []int{2}}).Should(ConsistOf(ContainElement(2), ContainElement(1)))
+ })
+
+ Context("when a matcher errors", func() {
+ It("should soldier on", func() {
+ Ω([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf(BeFalse(), "foo", "bar"))
+ Ω([]interface{}{"foo", "bar", false}).Should(ConsistOf(BeFalse(), ContainSubstring("foo"), "bar"))
+ })
+ })
+ })
+
+ Context("when passed exactly one argument, and that argument is a slice", func() {
+ It("should match against the elements of that argument", func() {
+ Ω([]string{"foo", "bar", "baz"}).Should(ConsistOf([]string{"foo", "bar", "baz"}))
+ })
+ })
+})
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 0000000..4159335
--- /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 0000000..38ee518
--- /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() {
+ Ω([2]int{1, 2}).Should(ContainElement(2))
+ Ω([2]int{1, 2}).ShouldNot(ContainElement(3))
+
+ Ω([]int{1, 2}).Should(ContainElement(2))
+ Ω([]int{1, 2}).ShouldNot(ContainElement(3))
+
+ Ω(map[string]int{"foo": 1, "bar": 2}).Should(ContainElement(2))
+ Ω(map[int]int{3: 1, 4: 2}).ShouldNot(ContainElement(3))
+
+ arr := make([]myCustomType, 2)
+ arr[0] = myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}
+ arr[1] = myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "c"}}
+ Ω(arr).Should(ContainElement(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}))
+ Ω(arr).ShouldNot(ContainElement(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"b", "c"}}))
+ })
+ })
+
+ Context("and expecting a matcher", func() {
+ It("should pass each element through the matcher", func() {
+ Ω([]int{1, 2, 3}).Should(ContainElement(BeNumerically(">=", 3)))
+ Ω([]int{1, 2, 3}).ShouldNot(ContainElement(BeNumerically(">", 3)))
+ Ω(map[string]int{"foo": 1, "bar": 2}).Should(ContainElement(BeNumerically(">=", 2)))
+ Ω(map[string]int{"foo": 1, "bar": 2}).ShouldNot(ContainElement(BeNumerically(">", 2)))
+ })
+
+ It("should power through even if the matcher ever fails", func() {
+ Ω([]interface{}{1, 2, "3", 4}).Should(ContainElement(BeNumerically(">=", 3)))
+ })
+
+ It("should fail if the matcher fails", func() {
+ actual := []interface{}{1, 2, "3", "4"}
+ success, err := (&ContainElementMatcher{Element: BeNumerically(">=", 3)}).Match(actual)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+ })
+
+ Context("when passed a correctly typed nil", func() {
+ It("should operate succesfully on the passed in value", func() {
+ var nilSlice []int
+ Ω(nilSlice).ShouldNot(ContainElement(1))
+
+ var nilMap map[int]string
+ Ω(nilMap).ShouldNot(ContainElement("foo"))
+ })
+ })
+
+ Context("when passed an unsupported type", func() {
+ It("should error", func() {
+ success, err := (&ContainElementMatcher{Element: 0}).Match(0)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&ContainElementMatcher{Element: 0}).Match("abc")
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&ContainElementMatcher{Element: 0}).Match(nil)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+})
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 0000000..2e76089
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher.go
@@ -0,0 +1,37 @@
+package matchers
+
+import (
+ "fmt"
+ "github.com/onsi/gomega/format"
+ "strings"
+)
+
+type ContainSubstringMatcher struct {
+ Substr string
+ Args []interface{}
+}
+
+func (matcher *ContainSubstringMatcher) Match(actual interface{}) (success bool, err error) {
+ actualString, ok := toString(actual)
+ if !ok {
+ return false, fmt.Errorf("ContainSubstring matcher requires a string or stringer. Got:\n%s", format.Object(actual, 1))
+ }
+
+ return strings.Contains(actualString, matcher.stringToMatch()), nil
+}
+
+func (matcher *ContainSubstringMatcher) stringToMatch() string {
+ stringToMatch := matcher.Substr
+ if len(matcher.Args) > 0 {
+ stringToMatch = fmt.Sprintf(matcher.Substr, matcher.Args...)
+ }
+ return stringToMatch
+}
+
+func (matcher *ContainSubstringMatcher) FailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, "to contain substring", matcher.stringToMatch())
+}
+
+func (matcher *ContainSubstringMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, "not to contain substring", matcher.stringToMatch())
+}
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 0000000..6935168
--- /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() {
+ Ω("Marvelous").Should(ContainSubstring("rve"))
+ Ω("Marvelous").ShouldNot(ContainSubstring("boo"))
+ })
+ })
+
+ Context("when the matcher is called with multiple arguments", func() {
+ It("should pass the string and arguments to sprintf", func() {
+ Ω("Marvelous3").Should(ContainSubstring("velous%d", 3))
+ })
+ })
+
+ Context("when actual is a stringer", func() {
+ It("should call the stringer and match agains the returned string", func() {
+ Ω(&myStringer{a: "Abc3"}).Should(ContainSubstring("bc3"))
+ })
+ })
+
+ Context("when actual is neither a string nor a stringer", func() {
+ It("should error", func() {
+ success, err := (&ContainSubstringMatcher{Substr: "2"}).Match(2)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+})
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 0000000..874e6a6
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/equal_matcher.go
@@ -0,0 +1,33 @@
+package matchers
+
+import (
+ "fmt"
+ "reflect"
+
+ "github.com/onsi/gomega/format"
+)
+
+type EqualMatcher struct {
+ Expected interface{}
+}
+
+func (matcher *EqualMatcher) Match(actual interface{}) (success bool, err error) {
+ if actual == nil && matcher.Expected == nil {
+ return false, fmt.Errorf("Refusing to compare <nil> to <nil>.\nBe explicit and use BeNil() instead. This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.")
+ }
+ return reflect.DeepEqual(actual, matcher.Expected), nil
+}
+
+func (matcher *EqualMatcher) FailureMessage(actual interface{}) (message string) {
+ 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 0000000..2add0b7
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/equal_matcher_test.go
@@ -0,0 +1,78 @@
+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)
+
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("When asserting equality between objects", func() {
+ It("should do the right thing", func() {
+ Ω(5).Should(Equal(5))
+ Ω(5.0).Should(Equal(5.0))
+
+ Ω(5).ShouldNot(Equal("5"))
+ Ω(5).ShouldNot(Equal(5.0))
+ Ω(5).ShouldNot(Equal(3))
+
+ Ω("5").Should(Equal("5"))
+ Ω([]int{1, 2}).Should(Equal([]int{1, 2}))
+ Ω([]int{1, 2}).ShouldNot(Equal([]int{2, 1}))
+ Ω(map[string]string{"a": "b", "c": "d"}).Should(Equal(map[string]string{"a": "b", "c": "d"}))
+ Ω(map[string]string{"a": "b", "c": "d"}).ShouldNot(Equal(map[string]string{"a": "b", "c": "e"}))
+ Ω(errors.New("foo")).Should(Equal(errors.New("foo")))
+ Ω(errors.New("foo")).ShouldNot(Equal(errors.New("bar")))
+
+ Ω(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).Should(Equal(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}))
+ Ω(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Equal(myCustomType{s: "bar", n: 3, f: 2.0, arr: []string{"a", "b"}}))
+ Ω(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Equal(myCustomType{s: "foo", n: 2, f: 2.0, arr: []string{"a", "b"}}))
+ Ω(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Equal(myCustomType{s: "foo", n: 3, f: 3.0, arr: []string{"a", "b"}}))
+ Ω(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Equal(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b", "c"}}))
+ })
+ })
+
+ Describe("failure messages", func() {
+ It("shows the two strings simply when they are short", func() {
+ subject := EqualMatcher{Expected: "eric"}
+
+ failureMessage := subject.FailureMessage("tim")
+ Ω(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)
+ Ω(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 0000000..7ace93d
--- /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 0000000..a92a177
--- /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() {
+ Ω([0]int{}).Should(HaveCap(0))
+ Ω([2]int{1}).Should(HaveCap(2))
+
+ Ω([]int{}).Should(HaveCap(0))
+ Ω([]int{1, 2, 3, 4, 5}[:2]).Should(HaveCap(5))
+ Ω(make([]int, 0, 5)).Should(HaveCap(5))
+
+ c := make(chan bool, 3)
+ Ω(c).Should(HaveCap(3))
+ c <- true
+ c <- true
+ Ω(c).Should(HaveCap(3))
+
+ Ω(make(chan bool)).Should(HaveCap(0))
+ })
+ })
+
+ Context("when passed a correctly typed nil", func() {
+ It("should operate succesfully on the passed in value", func() {
+ var nilSlice []int
+ Ω(nilSlice).Should(HaveCap(0))
+
+ var nilChan chan int
+ Ω(nilChan).Should(HaveCap(0))
+ })
+ })
+
+ Context("when passed an unsupported type", func() {
+ It("should error", func() {
+ success, err := (&HaveCapMatcher{Count: 0}).Match(0)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&HaveCapMatcher{Count: 0}).Match(nil)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+})
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 0000000..5701ba6
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/have_key_matcher.go
@@ -0,0 +1,53 @@
+package matchers
+
+import (
+ "fmt"
+ "github.com/onsi/gomega/format"
+ "reflect"
+)
+
+type HaveKeyMatcher struct {
+ Key interface{}
+}
+
+func (matcher *HaveKeyMatcher) Match(actual interface{}) (success bool, err error) {
+ if !isMap(actual) {
+ return false, fmt.Errorf("HaveKey matcher expects a map. Got:%s", format.Object(actual, 1))
+ }
+
+ keyMatcher, keyIsMatcher := matcher.Key.(omegaMatcher)
+ if !keyIsMatcher {
+ keyMatcher = &EqualMatcher{Expected: matcher.Key}
+ }
+
+ keys := reflect.ValueOf(actual).MapKeys()
+ for i := 0; i < len(keys); i++ {
+ success, err := keyMatcher.Match(keys[i].Interface())
+ if err != nil {
+ return false, fmt.Errorf("HaveKey's key matcher failed with:\n%s%s", format.Indent, err.Error())
+ }
+ if success {
+ return true, nil
+ }
+ }
+
+ return false, nil
+}
+
+func (matcher *HaveKeyMatcher) FailureMessage(actual interface{}) (message string) {
+ switch matcher.Key.(type) {
+ case omegaMatcher:
+ return format.Message(actual, "to have key matching", matcher.Key)
+ default:
+ return format.Message(actual, "to have key", matcher.Key)
+ }
+}
+
+func (matcher *HaveKeyMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ switch matcher.Key.(type) {
+ case omegaMatcher:
+ return format.Message(actual, "not to have key matching", matcher.Key)
+ default:
+ return format.Message(actual, "not to have key", matcher.Key)
+ }
+}
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 0000000..c663e30
--- /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() {
+ Ω(stringKeys).Should(HaveKey("foo"))
+ Ω(stringKeys).ShouldNot(HaveKey("baz"))
+
+ Ω(intKeys).Should(HaveKey(2))
+ Ω(intKeys).ShouldNot(HaveKey(4))
+
+ Ω(objKeys).Should(HaveKey(customA))
+ Ω(objKeys).Should(HaveKey(&myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"cake"}}))
+ Ω(objKeys).ShouldNot(HaveKey(&myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"apple", "pie"}}))
+ })
+ })
+
+ Context("when passed a correctly typed nil", func() {
+ It("should operate succesfully on the passed in value", func() {
+ var nilMap map[int]string
+ Ω(nilMap).ShouldNot(HaveKey("foo"))
+ })
+ })
+
+ Context("when the passed in key is actually a matcher", func() {
+ It("should pass each element through the matcher", func() {
+ Ω(stringKeys).Should(HaveKey(ContainSubstring("oo")))
+ Ω(stringKeys).ShouldNot(HaveKey(ContainSubstring("foobar")))
+ })
+
+ It("should fail if the matcher ever fails", func() {
+ actual := map[int]string{1: "a", 3: "b", 2: "c"}
+ success, err := (&HaveKeyMatcher{Key: ContainSubstring("ar")}).Match(actual)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("when passed something that is not a map", func() {
+ It("should error", func() {
+ success, err := (&HaveKeyMatcher{Key: "foo"}).Match([]string{"foo"})
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&HaveKeyMatcher{Key: "foo"}).Match(nil)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+})
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 0000000..464ac18
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher.go
@@ -0,0 +1,73 @@
+package matchers
+
+import (
+ "fmt"
+ "github.com/onsi/gomega/format"
+ "reflect"
+)
+
+type HaveKeyWithValueMatcher struct {
+ Key interface{}
+ Value interface{}
+}
+
+func (matcher *HaveKeyWithValueMatcher) Match(actual interface{}) (success bool, err error) {
+ if !isMap(actual) {
+ return false, fmt.Errorf("HaveKeyWithValue matcher expects a map. Got:%s", format.Object(actual, 1))
+ }
+
+ keyMatcher, keyIsMatcher := matcher.Key.(omegaMatcher)
+ if !keyIsMatcher {
+ keyMatcher = &EqualMatcher{Expected: matcher.Key}
+ }
+
+ valueMatcher, valueIsMatcher := matcher.Value.(omegaMatcher)
+ if !valueIsMatcher {
+ valueMatcher = &EqualMatcher{Expected: matcher.Value}
+ }
+
+ keys := reflect.ValueOf(actual).MapKeys()
+ for i := 0; i < len(keys); i++ {
+ success, err := keyMatcher.Match(keys[i].Interface())
+ if err != nil {
+ return false, fmt.Errorf("HaveKeyWithValue's key matcher failed with:\n%s%s", format.Indent, err.Error())
+ }
+ if success {
+ actualValue := reflect.ValueOf(actual).MapIndex(keys[i])
+ success, err := valueMatcher.Match(actualValue.Interface())
+ if err != nil {
+ return false, fmt.Errorf("HaveKeyWithValue's value matcher failed with:\n%s%s", format.Indent, err.Error())
+ }
+ return success, nil
+ }
+ }
+
+ return false, nil
+}
+
+func (matcher *HaveKeyWithValueMatcher) FailureMessage(actual interface{}) (message string) {
+ str := "to have {key: value}"
+ if _, ok := matcher.Key.(omegaMatcher); ok {
+ str += " matching"
+ } else if _, ok := matcher.Value.(omegaMatcher); ok {
+ str += " matching"
+ }
+
+ expect := make(map[interface{}]interface{}, 1)
+ expect[matcher.Key] = matcher.Value
+ return format.Message(actual, str, expect)
+}
+
+func (matcher *HaveKeyWithValueMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ kStr := "not to have key"
+ if _, ok := matcher.Key.(omegaMatcher); ok {
+ kStr = "not to have key matching"
+ }
+
+ vStr := "or that key's value not be"
+ if _, ok := matcher.Value.(omegaMatcher); ok {
+ vStr = "or to have that key's value not matching"
+ }
+
+ return format.Message(actual, kStr, matcher.Key, vStr, matcher.Value)
+}
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 0000000..06a2242
--- /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() {
+ Ω(stringKeys).Should(HaveKeyWithValue("foo", 2))
+ Ω(stringKeys).ShouldNot(HaveKeyWithValue("foo", 1))
+ Ω(stringKeys).ShouldNot(HaveKeyWithValue("baz", 2))
+ Ω(stringKeys).ShouldNot(HaveKeyWithValue("baz", 1))
+
+ Ω(intKeys).Should(HaveKeyWithValue(2, "foo"))
+ Ω(intKeys).ShouldNot(HaveKeyWithValue(4, "foo"))
+ Ω(intKeys).ShouldNot(HaveKeyWithValue(2, "baz"))
+
+ Ω(objKeys).Should(HaveKeyWithValue(customA, customA))
+ Ω(objKeys).Should(HaveKeyWithValue(&myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"cake"}}, &myCustomType{s: "a", n: 2, f: 2.3, arr: []string{"ice", "cream"}}))
+ Ω(objKeys).ShouldNot(HaveKeyWithValue(&myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"apple", "pie"}}, customA))
+ })
+ })
+
+ Context("when passed a correctly typed nil", func() {
+ It("should operate succesfully on the passed in value", func() {
+ var nilMap map[int]string
+ Ω(nilMap).ShouldNot(HaveKeyWithValue("foo", "bar"))
+ })
+ })
+
+ Context("when the passed in key or value is actually a matcher", func() {
+ It("should pass each element through the matcher", func() {
+ Ω(stringKeys).Should(HaveKeyWithValue(ContainSubstring("oo"), 2))
+ Ω(intKeys).Should(HaveKeyWithValue(2, ContainSubstring("oo")))
+ Ω(stringKeys).ShouldNot(HaveKeyWithValue(ContainSubstring("foobar"), 2))
+ })
+
+ It("should fail if the matcher ever fails", func() {
+ actual := map[int]string{1: "a", 3: "b", 2: "c"}
+ success, err := (&HaveKeyWithValueMatcher{Key: ContainSubstring("ar"), Value: 2}).Match(actual)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ otherActual := map[string]int{"a": 1, "b": 2, "c": 3}
+ success, err = (&HaveKeyWithValueMatcher{Key: "a", Value: ContainSubstring("1")}).Match(otherActual)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("when passed something that is not a map", func() {
+ It("should error", func() {
+ success, err := (&HaveKeyWithValueMatcher{Key: "foo", Value: "bar"}).Match([]string{"foo"})
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&HaveKeyWithValueMatcher{Key: "foo", Value: "bar"}).Match(nil)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+})
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 0000000..a183775
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/have_len_matcher.go
@@ -0,0 +1,27 @@
+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 0000000..1e6aa69
--- /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() {
+ Ω("").Should(HaveLen(0))
+ Ω("AA").Should(HaveLen(2))
+
+ Ω([0]int{}).Should(HaveLen(0))
+ Ω([2]int{1, 2}).Should(HaveLen(2))
+
+ Ω([]int{}).Should(HaveLen(0))
+ Ω([]int{1, 2, 3}).Should(HaveLen(3))
+
+ Ω(map[string]int{}).Should(HaveLen(0))
+ Ω(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4}).Should(HaveLen(4))
+
+ c := make(chan bool, 3)
+ Ω(c).Should(HaveLen(0))
+ c <- true
+ c <- true
+ Ω(c).Should(HaveLen(2))
+ })
+ })
+
+ Context("when passed a correctly typed nil", func() {
+ It("should operate succesfully on the passed in value", func() {
+ var nilSlice []int
+ Ω(nilSlice).Should(HaveLen(0))
+
+ var nilMap map[int]string
+ Ω(nilMap).Should(HaveLen(0))
+ })
+ })
+
+ Context("when passed an unsupported type", func() {
+ It("should error", func() {
+ success, err := (&HaveLenMatcher{Count: 0}).Match(0)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&HaveLenMatcher{Count: 0}).Match(nil)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+})
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 0000000..ebdd717
--- /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 0000000..009e23e
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/have_occurred_matcher_test.go
@@ -0,0 +1,58 @@
+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() {
+ Ω(errors.New("Foo")).Should(HaveOccurred())
+ })
+
+ It("should not succeed with nil", func() {
+ Ω(nil).ShouldNot(HaveOccurred())
+ })
+
+ It("should only support errors and nil", func() {
+ success, err := (&HaveOccurredMatcher{}).Match("foo")
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&HaveOccurredMatcher{}).Match("")
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+
+ It("doesn't support non-error type", func() {
+ success, err := (&HaveOccurredMatcher{}).Match(AnyType{})
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(MatchError("Expected an error-type. Got:\n <matchers_test.AnyType>: {}"))
+ })
+
+ It("doesn't support non-error pointer type", func() {
+ success, err := (&HaveOccurredMatcher{}).Match(&AnyType{})
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(MatchError(MatchRegexp(`Expected an error-type. Got:\n <*matchers_test.AnyType | 0x[[:xdigit:]]+>: {}`)))
+ })
+
+ It("should succeed with pointer types that conform to error interface", func() {
+ err := &CustomErr{"ohai"}
+ Ω(err).Should(HaveOccurred())
+ })
+
+ It("should not succeed with nil pointers to types that conform to error interface", func() {
+ var err *CustomErr = nil
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+})
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 0000000..8b63a89
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/have_prefix_matcher.go
@@ -0,0 +1,35 @@
+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 0000000..bec3f97
--- /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() {
+ Ω("Ab").Should(HavePrefix("A"))
+ Ω("A").ShouldNot(HavePrefix("Ab"))
+ })
+ })
+
+ Context("when the matcher is called with multiple arguments", func() {
+ It("should pass the string and arguments to sprintf", func() {
+ Ω("C3PO").Should(HavePrefix("C%dP", 3))
+ })
+ })
+
+ Context("when actual is a stringer", func() {
+ It("should call the stringer and match against the returned string", func() {
+ Ω(&myStringer{a: "Ab"}).Should(HavePrefix("A"))
+ })
+ })
+
+ Context("when actual is neither a string nor a stringer", func() {
+ It("should error", func() {
+ success, err := (&HavePrefixMatcher{Prefix: "2"}).Match(2)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+})
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 0000000..afc78fc
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/have_suffix_matcher.go
@@ -0,0 +1,35 @@
+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 0000000..72e8975
--- /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() {
+ Ω("Ab").Should(HaveSuffix("b"))
+ Ω("A").ShouldNot(HaveSuffix("Ab"))
+ })
+ })
+
+ Context("when the matcher is called with multiple arguments", func() {
+ It("should pass the string and arguments to sprintf", func() {
+ Ω("C3PO").Should(HaveSuffix("%dPO", 3))
+ })
+ })
+
+ Context("when actual is a stringer", func() {
+ It("should call the stringer and match against the returned string", func() {
+ Ω(&myStringer{a: "Ab"}).Should(HaveSuffix("b"))
+ })
+ })
+
+ Context("when actual is neither a string nor a stringer", func() {
+ It("should error", func() {
+ success, err := (&HaveSuffixMatcher{Suffix: "2"}).Match(2)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+})
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 0000000..03cdf04
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/match_error_matcher.go
@@ -0,0 +1,50 @@
+package matchers
+
+import (
+ "fmt"
+ "github.com/onsi/gomega/format"
+ "reflect"
+)
+
+type MatchErrorMatcher struct {
+ Expected interface{}
+}
+
+func (matcher *MatchErrorMatcher) Match(actual interface{}) (success bool, err error) {
+ if isNil(actual) {
+ return false, fmt.Errorf("Expected an error, got nil")
+ }
+
+ if !isError(actual) {
+ return false, fmt.Errorf("Expected an error. Got:\n%s", format.Object(actual, 1))
+ }
+
+ actualErr := actual.(error)
+
+ if isString(matcher.Expected) {
+ return reflect.DeepEqual(actualErr.Error(), matcher.Expected), nil
+ }
+
+ if isError(matcher.Expected) {
+ return reflect.DeepEqual(actualErr, matcher.Expected), nil
+ }
+
+ var subMatcher omegaMatcher
+ var hasSubMatcher bool
+ if matcher.Expected != nil {
+ subMatcher, hasSubMatcher = (matcher.Expected).(omegaMatcher)
+ if hasSubMatcher {
+ return subMatcher.Match(actualErr.Error())
+ }
+ }
+
+ return false, fmt.Errorf("MatchError must be passed an error, string, or Matcher that can match on strings. Got:\n%s", format.Object(matcher.Expected, 1))
+}
+
+func (matcher *MatchErrorMatcher) FailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, "to match error", matcher.Expected)
+}
+
+func (matcher *MatchErrorMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, "not to match error", matcher.Expected)
+}
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 0000000..338b512
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/match_error_matcher_test.go
@@ -0,0 +1,93 @@
+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{}
+
+ Ω(err).Should(MatchError(errors.New("an error")))
+ Ω(err).ShouldNot(MatchError(errors.New("another error")))
+
+ Ω(fmtErr).Should(MatchError(errors.New("an error")))
+ Ω(customErr).Should(MatchError(CustomError{}))
+ })
+
+ It("should succeed when matching with a string", func() {
+ err := errors.New("an error")
+ fmtErr := fmt.Errorf("an error")
+ customErr := CustomError{}
+
+ Ω(err).Should(MatchError("an error"))
+ Ω(err).ShouldNot(MatchError("another error"))
+
+ Ω(fmtErr).Should(MatchError("an error"))
+ Ω(customErr).Should(MatchError("an error"))
+ })
+
+ Context("when passed a matcher", func() {
+ It("should pass if the matcher passes against the error string", func() {
+ err := errors.New("error 123 abc")
+
+ Ω(err).Should(MatchError(MatchRegexp(`\d{3}`)))
+ })
+
+ It("should fail if the matcher fails against the error string", func() {
+ err := errors.New("no digits")
+ Ω(err).ShouldNot(MatchError(MatchRegexp(`\d`)))
+ })
+ })
+
+ It("should fail when passed anything else", func() {
+ actualErr := errors.New("an error")
+ _, err := (&MatchErrorMatcher{
+ Expected: []byte("an error"),
+ }).Match(actualErr)
+ Ω(err).Should(HaveOccurred())
+
+ _, err = (&MatchErrorMatcher{
+ Expected: 3,
+ }).Match(actualErr)
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("when passed nil", func() {
+ It("should fail", func() {
+ _, err := (&MatchErrorMatcher{
+ Expected: "an error",
+ }).Match(nil)
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("when passed a non-error", func() {
+ It("should fail", func() {
+ _, err := (&MatchErrorMatcher{
+ Expected: "an error",
+ }).Match("an error")
+ Ω(err).Should(HaveOccurred())
+
+ _, err = (&MatchErrorMatcher{
+ Expected: "an error",
+ }).Match(3)
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+})
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 0000000..e61978a
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/match_json_matcher.go
@@ -0,0 +1,64 @@
+package matchers
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "reflect"
+
+ "github.com/onsi/gomega/format"
+)
+
+type MatchJSONMatcher struct {
+ JSONToMatch interface{}
+}
+
+func (matcher *MatchJSONMatcher) Match(actual interface{}) (success bool, err error) {
+ actualString, expectedString, err := matcher.prettyPrint(actual)
+ if err != nil {
+ return false, err
+ }
+
+ var aval interface{}
+ var eval interface{}
+
+ // this is guarded by prettyPrint
+ json.Unmarshal([]byte(actualString), &aval)
+ json.Unmarshal([]byte(expectedString), &eval)
+
+ return reflect.DeepEqual(aval, eval), nil
+}
+
+func (matcher *MatchJSONMatcher) FailureMessage(actual interface{}) (message string) {
+ actualString, expectedString, _ := matcher.prettyPrint(actual)
+ return format.Message(actualString, "to match JSON of", expectedString)
+}
+
+func (matcher *MatchJSONMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ actualString, expectedString, _ := matcher.prettyPrint(actual)
+ return format.Message(actualString, "not to match JSON of", expectedString)
+}
+
+func (matcher *MatchJSONMatcher) prettyPrint(actual interface{}) (actualFormatted, expectedFormatted string, err error) {
+ actualString, ok := toString(actual)
+ if !ok {
+ return "", "", fmt.Errorf("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got actual:\n%s", format.Object(actual, 1))
+ }
+ expectedString, ok := toString(matcher.JSONToMatch)
+ if !ok {
+ return "", "", fmt.Errorf("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got expected:\n%s", format.Object(matcher.JSONToMatch, 1))
+ }
+
+ abuf := new(bytes.Buffer)
+ ebuf := new(bytes.Buffer)
+
+ if err := json.Indent(abuf, []byte(actualString), "", " "); err != nil {
+ return "", "", fmt.Errorf("Actual '%s' should be valid JSON, but it is not.\nUnderlying error:%s", actualString, err)
+ }
+
+ if err := json.Indent(ebuf, []byte(expectedString), "", " "); err != nil {
+ return "", "", fmt.Errorf("Expected '%s' should be valid JSON, but it is not.\nUnderlying error:%s", expectedString, err)
+ }
+
+ return abuf.String(), ebuf.String(), nil
+}
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 0000000..755c4ad
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/match_json_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("MatchJSONMatcher", func() {
+ Context("When passed stringifiables", func() {
+ It("should succeed if the JSON matches", func() {
+ Ω("{}").Should(MatchJSON("{}"))
+ Ω(`{"a":1}`).Should(MatchJSON(`{"a":1}`))
+ Ω(`{
+ "a":1
+ }`).Should(MatchJSON(`{"a":1}`))
+ Ω(`{"a":1, "b":2}`).Should(MatchJSON(`{"b":2, "a":1}`))
+ Ω(`{"a":1}`).ShouldNot(MatchJSON(`{"b":2, "a":1}`))
+ })
+
+ It("should work with byte arrays", func() {
+ Ω([]byte("{}")).Should(MatchJSON([]byte("{}")))
+ Ω("{}").Should(MatchJSON([]byte("{}")))
+ Ω([]byte("{}")).Should(MatchJSON("{}"))
+ })
+ })
+
+ Context("when the expected is not valid JSON", func() {
+ It("should error and explain why", func() {
+ success, err := (&MatchJSONMatcher{JSONToMatch: `{}`}).Match(`oops`)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ Ω(err.Error()).Should(ContainSubstring("Actual 'oops' should be valid JSON"))
+ })
+ })
+
+ Context("when the actual is not valid JSON", func() {
+ It("should error and explain why", func() {
+ success, err := (&MatchJSONMatcher{JSONToMatch: `oops`}).Match(`{}`)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ Ω(err.Error()).Should(ContainSubstring("Expected 'oops' should be valid JSON"))
+ })
+ })
+
+ Context("when the expected is neither a string nor a stringer nor a byte array", func() {
+ It("should error", func() {
+ success, err := (&MatchJSONMatcher{JSONToMatch: 2}).Match("{}")
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ Ω(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got expected:\n <int>: 2"))
+
+ success, err = (&MatchJSONMatcher{JSONToMatch: nil}).Match("{}")
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ Ω(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got expected:\n <nil>: nil"))
+ })
+ })
+
+ Context("when the actual is neither a string nor a stringer nor a byte array", func() {
+ It("should error", func() {
+ success, err := (&MatchJSONMatcher{JSONToMatch: "{}"}).Match(2)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ Ω(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got actual:\n <int>: 2"))
+
+ success, err = (&MatchJSONMatcher{JSONToMatch: "{}"}).Match(nil)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ Ω(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got actual:\n <nil>: 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 0000000..7ca79a1
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/match_regexp_matcher.go
@@ -0,0 +1,42 @@
+package matchers
+
+import (
+ "fmt"
+ "github.com/onsi/gomega/format"
+ "regexp"
+)
+
+type MatchRegexpMatcher struct {
+ Regexp string
+ Args []interface{}
+}
+
+func (matcher *MatchRegexpMatcher) Match(actual interface{}) (success bool, err error) {
+ actualString, ok := toString(actual)
+ if !ok {
+ return false, fmt.Errorf("RegExp matcher requires a string or stringer.\nGot:%s", format.Object(actual, 1))
+ }
+
+ match, err := regexp.Match(matcher.regexp(), []byte(actualString))
+ if err != nil {
+ return false, fmt.Errorf("RegExp match failed to compile with error:\n\t%s", err.Error())
+ }
+
+ return match, nil
+}
+
+func (matcher *MatchRegexpMatcher) FailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, "to match regular expression", matcher.regexp())
+}
+
+func (matcher *MatchRegexpMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, "not to match regular expression", matcher.regexp())
+}
+
+func (matcher *MatchRegexpMatcher) regexp() string {
+ re := matcher.Regexp
+ if len(matcher.Args) > 0 {
+ re = fmt.Sprintf(matcher.Regexp, matcher.Args...)
+ }
+ return re
+}
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 0000000..bb521cc
--- /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() {
+ Ω(" a2!bla").Should(MatchRegexp(`\d!`))
+ Ω(" a2!bla").ShouldNot(MatchRegexp(`[A-Z]`))
+ })
+ })
+
+ Context("when actual is a stringer", func() {
+ It("should call the stringer and match agains the returned string", func() {
+ Ω(&myStringer{a: "Abc3"}).Should(MatchRegexp(`[A-Z][a-z]+\d`))
+ })
+ })
+
+ Context("when the matcher is called with multiple arguments", func() {
+ It("should pass the string and arguments to sprintf", func() {
+ Ω(" a23!bla").Should(MatchRegexp(`\d%d!`, 3))
+ })
+ })
+
+ Context("when actual is neither a string nor a stringer", func() {
+ It("should error", func() {
+ success, err := (&MatchRegexpMatcher{Regexp: `\d`}).Match(2)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("when the passed in regexp fails to compile", func() {
+ It("should error", func() {
+ success, err := (&MatchRegexpMatcher{Regexp: "("}).Match("Foo")
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+})
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 0000000..69fb51a
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/match_yaml_matcher.go
@@ -0,0 +1,74 @@
+package matchers
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+
+ "github.com/onsi/gomega/format"
+ "gopkg.in/yaml.v2"
+)
+
+type MatchYAMLMatcher struct {
+ YAMLToMatch interface{}
+}
+
+func (matcher *MatchYAMLMatcher) Match(actual interface{}) (success bool, err error) {
+ actualString, expectedString, err := matcher.toStrings(actual)
+ if err != nil {
+ return false, err
+ }
+
+ var aval interface{}
+ var eval interface{}
+
+ if err := yaml.Unmarshal([]byte(actualString), &aval); err != nil {
+ return false, fmt.Errorf("Actual '%s' should be valid YAML, but it is not.\nUnderlying error:%s", actualString, err)
+ }
+ if err := yaml.Unmarshal([]byte(expectedString), &eval); err != nil {
+ return false, fmt.Errorf("Expected '%s' should be valid YAML, but it is not.\nUnderlying error:%s", expectedString, err)
+ }
+
+ return reflect.DeepEqual(aval, eval), nil
+}
+
+func (matcher *MatchYAMLMatcher) FailureMessage(actual interface{}) (message string) {
+ actualString, expectedString, _ := matcher.toNormalisedStrings(actual)
+ return format.Message(actualString, "to match YAML of", expectedString)
+}
+
+func (matcher *MatchYAMLMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ actualString, expectedString, _ := matcher.toNormalisedStrings(actual)
+ return format.Message(actualString, "not to match YAML of", expectedString)
+}
+
+func (matcher *MatchYAMLMatcher) toNormalisedStrings(actual interface{}) (actualFormatted, expectedFormatted string, err error) {
+ actualString, expectedString, err := matcher.toStrings(actual)
+ return normalise(actualString), normalise(expectedString), err
+}
+
+func normalise(input string) string {
+ var val interface{}
+ err := yaml.Unmarshal([]byte(input), &val)
+ if err != nil {
+ panic(err) // guarded by Match
+ }
+ output, err := yaml.Marshal(val)
+ if err != nil {
+ panic(err) // guarded by Unmarshal
+ }
+ return strings.TrimSpace(string(output))
+}
+
+func (matcher *MatchYAMLMatcher) toStrings(actual interface{}) (actualFormatted, expectedFormatted string, err error) {
+ actualString, ok := toString(actual)
+ if !ok {
+ return "", "", fmt.Errorf("MatchYAMLMatcher matcher requires a string, stringer, or []byte. Got actual:\n%s", format.Object(actual, 1))
+ }
+ expectedString, ok := toString(matcher.YAMLToMatch)
+ if !ok {
+ return "", "", fmt.Errorf("MatchYAMLMatcher matcher requires a string, stringer, or []byte. Got expected:\n%s", format.Object(matcher.YAMLToMatch, 1))
+ }
+
+ return actualString, expectedString, nil
+}
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 0000000..8e63de1
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/match_yaml_matcher_test.go
@@ -0,0 +1,94 @@
+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"))
+ })
+ })
+
+ 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 0000000..01b11b9
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/matcher_tests_suite_test.go
@@ -0,0 +1,30 @@
+package matchers_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+type myStringer struct {
+ a string
+}
+
+func (s *myStringer) String() string {
+ return s.a
+}
+
+type StringAlias string
+
+type myCustomType struct {
+ s string
+ n int
+ f float32
+ arr []string
+}
+
+func Test(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Gomega Matchers")
+}
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 0000000..2c91670
--- /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 0000000..b3c1fdb
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/not_test.go
@@ -0,0 +1,57 @@
+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))))
+ })
+ })
+
+ 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 0000000..3bf7998
--- /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 0000000..9589a17
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/or_test.go
@@ -0,0 +1,85 @@
+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("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 0000000..640f4db
--- /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 0000000..6b859a7
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/panic_matcher_test.go
@@ -0,0 +1,45 @@
+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")
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&PanicMatcher{}).Match(nil)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&PanicMatcher{}).Match(func(foo string) {})
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&PanicMatcher{}).Match(func() string { return "bar" })
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("when passed a function of the correct type", func() {
+ It("should call the function and pass if the function panics", func() {
+ Ω(func() { panic("ack!") }).Should(Panic())
+ Ω(func() {}).ShouldNot(Panic())
+ })
+ })
+
+ Context("when assertion fails", func() {
+ It("should print the object passed to Panic", func() {
+ failuresMessages := InterceptGomegaFailures(func() {
+ Ω(func() { panic("ack!") }).ShouldNot(Panic())
+ })
+ Ω(failuresMessages).Should(ConsistOf(MatchRegexp("not to panic, but panicked with\\s*<string>: ack!")))
+ })
+ })
+})
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 0000000..7a8c2cd
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/receive_matcher.go
@@ -0,0 +1,126 @@
+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))
+ }
+
+ assignable := channelType.Elem().AssignableTo(argType.Elem())
+ if !assignable {
+ return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nTo:\n%s", format.Object(actual, 1), format.Object(matcher.Arg, 1))
+ }
+ }
+ }
+
+ winnerIndex, value, open := reflect.Select([]reflect.SelectCase{
+ reflect.SelectCase{Dir: reflect.SelectRecv, Chan: channelValue},
+ reflect.SelectCase{Dir: reflect.SelectDefault},
+ })
+
+ var closed bool
+ var didReceive bool
+ if winnerIndex == 0 {
+ closed = !open
+ didReceive = open
+ }
+ matcher.channelClosed = closed
+
+ if closed {
+ return false, nil
+ }
+
+ if hasSubMatcher {
+ if didReceive {
+ matcher.receivedValue = value
+ return subMatcher.Match(matcher.receivedValue.Interface())
+ } else {
+ return false, nil
+ }
+ }
+
+ if didReceive {
+ if matcher.Arg != nil {
+ outValue := reflect.ValueOf(matcher.Arg)
+ reflect.Indirect(outValue).Set(value)
+ }
+
+ return true, nil
+ } else {
+ return false, nil
+ }
+}
+
+func (matcher *ReceiveMatcher) FailureMessage(actual interface{}) (message string) {
+ subMatcher, hasSubMatcher := (matcher.Arg).(omegaMatcher)
+
+ closedAddendum := ""
+ if matcher.channelClosed {
+ closedAddendum = " The channel is closed."
+ }
+
+ if hasSubMatcher {
+ if matcher.receivedValue.IsValid() {
+ return subMatcher.FailureMessage(matcher.receivedValue.Interface())
+ }
+ return "When passed a matcher, ReceiveMatcher's channel *must* receive something."
+ } else {
+ return format.Message(actual, "to receive something."+closedAddendum)
+ }
+}
+
+func (matcher *ReceiveMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ subMatcher, hasSubMatcher := (matcher.Arg).(omegaMatcher)
+
+ closedAddendum := ""
+ if matcher.channelClosed {
+ closedAddendum = " The channel is closed."
+ }
+
+ if hasSubMatcher {
+ if matcher.receivedValue.IsValid() {
+ return subMatcher.NegatedFailureMessage(matcher.receivedValue.Interface())
+ }
+ return "When passed a matcher, ReceiveMatcher's channel *must* receive something."
+ } else {
+ return format.Message(actual, "not to receive anything."+closedAddendum)
+ }
+}
+
+func (matcher *ReceiveMatcher) MatchMayChangeInTheFuture(actual interface{}) bool {
+ if !isChan(actual) {
+ return false
+ }
+
+ return !matcher.channelClosed
+}
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 0000000..938c078
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/receive_matcher_test.go
@@ -0,0 +1,280 @@
+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
+}
+
+var _ = Describe("ReceiveMatcher", func() {
+ Context("with no argument", func() {
+ Context("for a buffered channel", func() {
+ It("should succeed", func() {
+ channel := make(chan bool, 1)
+
+ Ω(channel).ShouldNot(Receive())
+
+ channel <- true
+
+ Ω(channel).Should(Receive())
+ })
+ })
+
+ Context("for an unbuffered channel", func() {
+ It("should succeed (eventually)", func() {
+ channel := make(chan bool)
+
+ Ω(channel).ShouldNot(Receive())
+
+ go func() {
+ time.Sleep(10 * time.Millisecond)
+ channel <- true
+ }()
+
+ Eventually(channel).Should(Receive())
+ })
+ })
+ })
+
+ Context("with a pointer argument", func() {
+ Context("of the correct type", func() {
+ It("should write the value received on the channel to the pointer", func() {
+ channel := make(chan int, 1)
+
+ var value int
+
+ Ω(channel).ShouldNot(Receive(&value))
+ Ω(value).Should(BeZero())
+
+ channel <- 17
+
+ Ω(channel).Should(Receive(&value))
+ Ω(value).Should(Equal(17))
+ })
+ })
+
+ Context("to various types of objects", func() {
+ It("should work", func() {
+ //channels of strings
+ stringChan := make(chan string, 1)
+ stringChan <- "foo"
+
+ var s string
+ Ω(stringChan).Should(Receive(&s))
+ Ω(s).Should(Equal("foo"))
+
+ //channels of slices
+ sliceChan := make(chan []bool, 1)
+ sliceChan <- []bool{true, true, false}
+
+ var sl []bool
+ Ω(sliceChan).Should(Receive(&sl))
+ Ω(sl).Should(Equal([]bool{true, true, false}))
+
+ //channels of channels
+ chanChan := make(chan chan bool, 1)
+ c := make(chan bool)
+ chanChan <- c
+
+ var receivedC chan bool
+ Ω(chanChan).Should(Receive(&receivedC))
+ Ω(receivedC).Should(Equal(c))
+
+ //channels of interfaces
+ jackieChan := make(chan kungFuActor, 1)
+ aJackie := &jackie{name: "Jackie Chan"}
+ jackieChan <- aJackie
+
+ var theJackie kungFuActor
+ Ω(jackieChan).Should(Receive(&theJackie))
+ Ω(theJackie).Should(Equal(aJackie))
+ })
+ })
+
+ Context("of the wrong type", func() {
+ It("should error", func() {
+ channel := make(chan int)
+ var incorrectType bool
+
+ success, err := (&ReceiveMatcher{Arg: &incorrectType}).Match(channel)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ var notAPointer int
+ success, err = (&ReceiveMatcher{Arg: notAPointer}).Match(channel)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+ })
+
+ Context("with a matcher", func() {
+ It("should defer to the underlying matcher", func() {
+ intChannel := make(chan int, 1)
+ intChannel <- 3
+ Ω(intChannel).Should(Receive(Equal(3)))
+
+ intChannel <- 2
+ Ω(intChannel).ShouldNot(Receive(Equal(3)))
+
+ stringChannel := make(chan []string, 1)
+ stringChannel <- []string{"foo", "bar", "baz"}
+ Ω(stringChannel).Should(Receive(ContainElement(ContainSubstring("fo"))))
+
+ stringChannel <- []string{"foo", "bar", "baz"}
+ Ω(stringChannel).ShouldNot(Receive(ContainElement(ContainSubstring("archipelago"))))
+ })
+
+ It("should defer to the underlying matcher for the message", func() {
+ matcher := Receive(Equal(3))
+ channel := make(chan int, 1)
+ channel <- 2
+ matcher.Match(channel)
+ Ω(matcher.FailureMessage(channel)).Should(MatchRegexp(`Expected\s+<int>: 2\s+to equal\s+<int>: 3`))
+
+ channel <- 3
+ matcher.Match(channel)
+ Ω(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)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("if nothing is received", func() {
+ It("should fail", func() {
+ channel := make(chan int, 1)
+ success, err := (&ReceiveMatcher{Arg: Equal(1)}).Match(channel)
+ Ω(success).Should(BeFalse())
+ Ω(err).ShouldNot(HaveOccurred())
+ })
+ })
+ })
+
+ Context("When actual is a *closed* channel", func() {
+ Context("for a buffered channel", func() {
+ It("should work until it hits the end of the buffer", func() {
+ channel := make(chan bool, 1)
+ channel <- true
+
+ close(channel)
+
+ Ω(channel).Should(Receive())
+ Ω(channel).ShouldNot(Receive())
+ })
+ })
+
+ Context("for an unbuffered channel", func() {
+ It("should always fail", func() {
+ channel := make(chan bool)
+ close(channel)
+
+ Ω(channel).ShouldNot(Receive())
+ })
+ })
+ })
+
+ Context("When actual is a send-only channel", func() {
+ It("should error", func() {
+ channel := make(chan bool)
+
+ var writerChannel chan<- bool
+ writerChannel = channel
+
+ success, err := (&ReceiveMatcher{}).Match(writerChannel)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+
+ Context("when acutal is a non-channel", func() {
+ It("should error", func() {
+ var nilChannel chan bool
+
+ success, err := (&ReceiveMatcher{}).Match(nilChannel)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&ReceiveMatcher{}).Match(nil)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+
+ success, err = (&ReceiveMatcher{}).Match(3)
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(HaveOccurred())
+ })
+ })
+
+ Describe("when used with eventually and a custom matcher", func() {
+ It("should return the matcher's error when a failing value is received on the channel, instead of the must receive something failure", func() {
+ failures := InterceptGomegaFailures(func() {
+ c := make(chan string, 0)
+ Eventually(c, 0.01).Should(Receive(Equal("hello")))
+ })
+ Ω(failures[0]).Should(ContainSubstring("When passed a matcher, ReceiveMatcher's channel *must* receive something."))
+
+ failures = InterceptGomegaFailures(func() {
+ c := make(chan string, 1)
+ c <- "hi"
+ Eventually(c, 0.01).Should(Receive(Equal("hello")))
+ })
+ Ω(failures[0]).Should(ContainSubstring("<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())
+ })
+ Ω(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond))
+ Ω(failures).Should(HaveLen(1))
+ })
+
+ It("should bail early when passed a non-channel", func() {
+ t := time.Now()
+ failures := InterceptGomegaFailures(func() {
+ Eventually(3).Should(Receive())
+ })
+ Ω(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond))
+ Ω(failures).Should(HaveLen(1))
+ })
+ })
+})
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 0000000..721ed55
--- /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 0000000..6b62c8b
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/succeed_matcher_test.go
@@ -0,0 +1,62 @@
+package matchers_test
+
+import (
+ "errors"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/matchers"
+)
+
+func Erroring() error {
+ return errors.New("bam")
+}
+
+func NotErroring() error {
+ return nil
+}
+
+type AnyType struct{}
+
+func Invalid() *AnyType {
+ return nil
+}
+
+var _ = Describe("Succeed", func() {
+ It("should succeed if the function succeeds", func() {
+ Ω(NotErroring()).Should(Succeed())
+ })
+
+ It("should succeed (in the negated) if the function errored", func() {
+ Ω(Erroring()).ShouldNot(Succeed())
+ })
+
+ It("should not if passed a non-error", func() {
+ success, err := (&SucceedMatcher{}).Match(Invalid())
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(MatchError("Expected an error-type. Got:\n <*matchers_test.AnyType | 0x0>: nil"))
+ })
+
+ It("doesn't support non-error type", func() {
+ success, err := (&SucceedMatcher{}).Match(AnyType{})
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(MatchError("Expected an error-type. Got:\n <matchers_test.AnyType>: {}"))
+ })
+
+ It("doesn't support non-error pointer type", func() {
+ success, err := (&SucceedMatcher{}).Match(&AnyType{})
+ Ω(success).Should(BeFalse())
+ Ω(err).Should(MatchError(MatchRegexp(`Expected an error-type. Got:\n <*matchers_test.AnyType | 0x[[:xdigit:]]+>: {}`)))
+ })
+
+ It("should not succeed with pointer types that conform to error interface", func() {
+ err := &CustomErr{"ohai"}
+ Ω(err).ShouldNot(Succeed())
+ })
+
+ It("should succeed with nil pointers to types that conform to error interface", func() {
+ var err *CustomErr = nil
+ Ω(err).Should(Succeed())
+ })
+
+})
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 0000000..8edd817
--- /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 0000000..119d21e
--- /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{i})
+ }
+
+ right := NodeOrderedSet{}
+ for j, _ := range rightValues {
+ right = append(right, Node{j + len(left)})
+ }
+
+ edges := EdgeSet{}
+ for i, leftValue := range leftValues {
+ for j, rightValue := range rightValues {
+ neighbours, err := neighbours(leftValue, rightValue)
+ if err != nil {
+ return nil, errors.New(fmt.Sprintf("error determining adjacency for %v and %v: %s", leftValue, rightValue, err.Error()))
+ }
+
+ if neighbours {
+ edges = append(edges, Edge{left[i], right[j]})
+ }
+ }
+ }
+
+ return &BipartiteGraph{left, right, edges}, nil
+}
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 0000000..32529c5
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/support/goraph/bipartitegraph/bipartitegraphmatching.go
@@ -0,0 +1,161 @@
+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{}
+ } else {
+ guideLayers = append(guideLayers, currentLayer)
+ }
+
+ done := false
+
+ for !done {
+ lastLayer := currentLayer
+ currentLayer = NodeOrderedSet{}
+
+ if util.Odd(len(guideLayers)) {
+ for _, leftNode := range lastLayer {
+ for _, rightNode := range bg.Right {
+ if used[rightNode] {
+ continue
+ }
+
+ edge, found := bg.Edges.FindByNodes(leftNode, rightNode)
+ if !found || matching.Contains(edge) {
+ continue
+ }
+
+ currentLayer = append(currentLayer, rightNode)
+ used[rightNode] = true
+
+ if matching.Free(rightNode) {
+ done = true
+ }
+ }
+ }
+ } else {
+ for _, rightNode := range lastLayer {
+ for _, leftNode := range bg.Left {
+ if used[leftNode] {
+ continue
+ }
+
+ edge, found := bg.Edges.FindByNodes(leftNode, rightNode)
+ if !found || !matching.Contains(edge) {
+ continue
+ }
+
+ currentLayer = append(currentLayer, leftNode)
+ used[leftNode] = true
+ }
+ }
+
+ }
+
+ if len(currentLayer) == 0 {
+ return []NodeOrderedSet{}
+ } else {
+ guideLayers = append(guideLayers, currentLayer)
+ }
+ }
+
+ return
+}
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 0000000..4fd15cc
--- /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 0000000..800c2ea
--- /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 0000000..d76a1ee
--- /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/type_support.go b/vendor/github.com/onsi/gomega/matchers/type_support.go
new file mode 100644
index 0000000..04020f0
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/type_support.go
@@ -0,0 +1,176 @@
+/*
+Gomega matchers
+
+This package implements the Gomega matchers and does not typically need to be imported.
+See the docs for Gomega for documentation on the matchers
+
+http://onsi.github.io/gomega/
+*/
+package matchers
+
+import (
+ "fmt"
+ "reflect"
+)
+
+type omegaMatcher interface {
+ Match(actual interface{}) (success bool, err error)
+ FailureMessage(actual interface{}) (message string)
+ NegatedFailureMessage(actual interface{}) (message string)
+}
+
+func isBool(a interface{}) bool {
+ return reflect.TypeOf(a).Kind() == reflect.Bool
+}
+
+func isNumber(a interface{}) bool {
+ if a == nil {
+ return false
+ }
+ kind := reflect.TypeOf(a).Kind()
+ return reflect.Int <= kind && kind <= reflect.Float64
+}
+
+func isInteger(a interface{}) bool {
+ kind := reflect.TypeOf(a).Kind()
+ return reflect.Int <= kind && kind <= reflect.Int64
+}
+
+func isUnsignedInteger(a interface{}) bool {
+ kind := reflect.TypeOf(a).Kind()
+ return reflect.Uint <= kind && kind <= reflect.Uint64
+}
+
+func isFloat(a interface{}) bool {
+ kind := reflect.TypeOf(a).Kind()
+ return reflect.Float32 <= kind && kind <= reflect.Float64
+}
+
+func toInteger(a interface{}) int64 {
+ if isInteger(a) {
+ return reflect.ValueOf(a).Int()
+ } else if isUnsignedInteger(a) {
+ return int64(reflect.ValueOf(a).Uint())
+ } else if isFloat(a) {
+ return int64(reflect.ValueOf(a).Float())
+ } else {
+ panic(fmt.Sprintf("Expected a number! Got <%T> %#v", a, a))
+ }
+}
+
+func toUnsignedInteger(a interface{}) uint64 {
+ if isInteger(a) {
+ return uint64(reflect.ValueOf(a).Int())
+ } else if isUnsignedInteger(a) {
+ return reflect.ValueOf(a).Uint()
+ } else if isFloat(a) {
+ return uint64(reflect.ValueOf(a).Float())
+ } else {
+ panic(fmt.Sprintf("Expected a number! Got <%T> %#v", a, a))
+ }
+}
+
+func toFloat(a interface{}) float64 {
+ if isInteger(a) {
+ return float64(reflect.ValueOf(a).Int())
+ } else if isUnsignedInteger(a) {
+ return float64(reflect.ValueOf(a).Uint())
+ } else if isFloat(a) {
+ return reflect.ValueOf(a).Float()
+ } else {
+ panic(fmt.Sprintf("Expected a number! Got <%T> %#v", a, a))
+ }
+}
+
+func isError(a interface{}) bool {
+ _, ok := a.(error)
+ return ok
+}
+
+func isChan(a interface{}) bool {
+ if isNil(a) {
+ return false
+ }
+ return reflect.TypeOf(a).Kind() == reflect.Chan
+}
+
+func isMap(a interface{}) bool {
+ if a == nil {
+ return false
+ }
+ return reflect.TypeOf(a).Kind() == reflect.Map
+}
+
+func isArrayOrSlice(a interface{}) bool {
+ if a == nil {
+ return false
+ }
+ switch reflect.TypeOf(a).Kind() {
+ case reflect.Array, reflect.Slice:
+ return true
+ default:
+ return false
+ }
+}
+
+func isString(a interface{}) bool {
+ if a == nil {
+ return false
+ }
+ return reflect.TypeOf(a).Kind() == reflect.String
+}
+
+func toString(a interface{}) (string, bool) {
+ aString, isString := a.(string)
+ if isString {
+ return aString, true
+ }
+
+ aBytes, isBytes := a.([]byte)
+ if isBytes {
+ return string(aBytes), true
+ }
+
+ aStringer, isStringer := a.(fmt.Stringer)
+ if isStringer {
+ return aStringer.String(), true
+ }
+
+ return "", false
+}
+
+func lengthOf(a interface{}) (int, bool) {
+ if a == nil {
+ return 0, false
+ }
+ switch reflect.TypeOf(a).Kind() {
+ case reflect.Map, reflect.Array, reflect.String, reflect.Chan, reflect.Slice:
+ return reflect.ValueOf(a).Len(), true
+ default:
+ return 0, false
+ }
+}
+func capOf(a interface{}) (int, bool) {
+ if a == nil {
+ return 0, false
+ }
+ switch reflect.TypeOf(a).Kind() {
+ case reflect.Array, reflect.Chan, reflect.Slice:
+ return reflect.ValueOf(a).Cap(), true
+ default:
+ return 0, false
+ }
+}
+
+func isNil(a interface{}) bool {
+ if a == nil {
+ return true
+ }
+
+ switch reflect.TypeOf(a).Kind() {
+ case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
+ return reflect.ValueOf(a).IsNil()
+ }
+
+ return false
+}
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 0000000..8e58d8a
--- /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 0000000..e52bf8e
--- /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 0000000..1c632ad
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/types/types.go
@@ -0,0 +1,17 @@
+package types
+
+type GomegaFailHandler func(message string, callerSkip ...int)
+
+//A simple *testing.T interface wrapper
+type GomegaTestingT interface {
+ Errorf(format string, args ...interface{})
+}
+
+//All Gomega matchers must implement the GomegaMatcher interface
+//
+//For details on writing custom matchers, check out: http://onsi.github.io/gomega/#adding_your_own_matchers
+type GomegaMatcher interface {
+ Match(actual interface{}) (success bool, err error)
+ FailureMessage(actual interface{}) (message string)
+ NegatedFailureMessage(actual interface{}) (message string)
+}