From 5a9c4e60bd75ee33b8f63820ed1cdc2b50b07480 Mon Sep 17 00:00:00 2001 From: Jeet Parekh Date: Wed, 29 May 2019 09:41:00 +0530 Subject: [PATCH] added neo4j and esv7 dependencies --- vendor/github.com/golang/mock/LICENSE | 202 ++ vendor/github.com/golang/mock/gomock/call.go | 420 +++ .../golang/mock/gomock/call_test.go | 51 + .../github.com/golang/mock/gomock/callset.go | 108 + .../golang/mock/gomock/callset_test.go | 76 + .../golang/mock/gomock/controller.go | 264 ++ .../golang/mock/gomock/controller_test.go | 739 ++++++ .../internal/mock_gomock/mock_matcher.go | 61 + .../github.com/golang/mock/gomock/matchers.go | 141 ++ .../golang/mock/gomock/matchers_test.go | 119 + .../github.com/neo4j-drivers/gobolt/LICENSE | 201 ++ .../github.com/neo4j-drivers/gobolt/README.md | 3 + .../github.com/neo4j-drivers/gobolt/config.go | 199 ++ .../neo4j-drivers/gobolt/connection.go | 64 + .../gobolt/connection_mock_test.go | 120 + .../gobolt/connection_seabolt.go | 341 +++ .../neo4j-drivers/gobolt/connection_worker.go | 355 +++ .../gobolt/connection_worker_test.go | 698 +++++ .../neo4j-drivers/gobolt/connector.go | 51 + .../neo4j-drivers/gobolt/connector_seabolt.go | 161 ++ .../neo4j-drivers/gobolt/connector_worker.go | 135 + .../github.com/neo4j-drivers/gobolt/error.go | 394 +++ .../neo4j-drivers/gobolt/lifecycle.go | 44 + .../neo4j-drivers/gobolt/logging.go | 121 + .../neo4j-drivers/gobolt/resolver.go | 83 + .../neo4j-drivers/gobolt/seabolt-static.go | 25 + .../neo4j-drivers/gobolt/seabolt.go | 25 + .../github.com/neo4j-drivers/gobolt/stats.go | 36 + .../github.com/neo4j-drivers/gobolt/value.go | 338 +++ .../neo4j-drivers/gobolt/value_handler.go | 52 + .../neo4j-drivers/gobolt/worker_pool.go | 148 ++ .../neo4j-drivers/gobolt/worker_pool_test.go | 167 ++ .../github.com/neo4j/neo4j-go-driver/LICENSE | 201 ++ .../neo4j/neo4j-go-driver/neo4j/Gopkg.lock | 200 ++ .../neo4j/neo4j-go-driver/neo4j/Gopkg.toml | 54 + .../neo4j-go-driver/neo4j/auth_tokens.go | 87 + .../neo4j-go-driver/neo4j/auth_tokens_test.go | 212 ++ .../neo4j/neo4j-go-driver/neo4j/config.go | 130 + .../neo4j-go-driver/neo4j/config_resolver.go | 73 + .../neo4j-go-driver/neo4j/config_test.go | 128 + .../neo4j-go-driver/neo4j/config_trust.go | 62 + .../neo4j/neo4j-go-driver/neo4j/driver.go | 88 + .../neo4j-go-driver/neo4j/driver_test.go | 161 ++ .../neo4j/neo4j-go-driver/neo4j/error.go | 177 ++ .../neo4j/neo4j-go-driver/neo4j/error_test.go | 373 +++ .../neo4j-go-driver/neo4j/ginkgo_test.go | 40 + .../neo4j-go-driver/neo4j/gobolt_driver.go | 130 + .../neo4j/gobolt_driver_test.go | 96 + .../neo4j/neo4j-go-driver/neo4j/logging.go | 75 + .../neo4j-go-driver/neo4j/logging_impl.go | 96 + .../neo4j-go-driver/neo4j/logging_test.go | 137 + .../neo4j/mock_connection_test.go | 288 +++ .../neo4j/mock_connector_test.go | 80 + .../neo4j/mock_factory_test.go | 41 + .../neo4j/mock_logging_test.go | 161 ++ .../neo4j-go-driver/neo4j/mock_pool_test.go | 80 + .../neo4j-go-driver/neo4j/mock_record_test.go | 102 + .../neo4j-go-driver/neo4j/mock_result_test.go | 128 + .../neo4j/mock_resultsummary_test.go | 162 ++ .../neo4j/neo4j-go-driver/neo4j/record.go | 33 + .../neo4j-go-driver/neo4j/record_impl.go | 47 + .../neo4j/neo4j-go-driver/neo4j/result.go | 37 + .../neo4j-go-driver/neo4j/result_helpers.go | 81 + .../neo4j/result_helpers_test.go | 240 ++ .../neo4j-go-driver/neo4j/result_impl.go | 177 ++ .../neo4j/neo4j-go-driver/neo4j/retry.go | 96 + .../neo4j/neo4j-go-driver/neo4j/retry_test.go | 99 + .../neo4j/neo4j-go-driver/neo4j/runner.go | 465 ++++ .../neo4j-go-driver/neo4j/runner_test.go | 1142 +++++++++ .../neo4j/neo4j-go-driver/neo4j/session.go | 40 + .../neo4j-go-driver/neo4j/session_impl.go | 254 ++ .../neo4j/neo4j-go-driver/neo4j/statement.go | 28 + .../neo4j-go-driver/neo4j/statement_impl.go | 42 + .../neo4j/neo4j-go-driver/neo4j/summary.go | 111 + .../neo4j/summary_collection.go | 217 ++ .../neo4j-go-driver/neo4j/summary_counters.go | 120 + .../neo4j/summary_notification.go | 64 + .../neo4j-go-driver/neo4j/summary_plan.go | 64 + .../neo4j-go-driver/neo4j/summary_position.go | 48 + .../neo4j/summary_profiled_plan.go | 74 + .../neo4j/summary_server_info.go | 41 + .../neo4j-go-driver/neo4j/summary_test.go | 849 +++++++ .../neo4j-go-driver/neo4j/transaction.go | 33 + .../neo4j/transaction_config.go | 70 + .../neo4j-go-driver/neo4j/transaction_impl.go | 119 + .../neo4j/neo4j-go-driver/neo4j/utils.go | 38 + .../neo4j/utils/test/gomock_matchers.go | 45 + .../neo4j/utils/test/omega_error_matchers.go | 310 +++ .../neo4j/utils/test/omega_number_matchers.go | 55 + .../neo4j-go-driver/neo4j/values_graph.go | 149 ++ .../neo4j/values_graph_handlers.go | 184 ++ .../neo4j-go-driver/neo4j/values_spatial.go | 86 + .../neo4j/values_spatial_handlers.go | 117 + .../neo4j/values_spatial_test.go | 89 + .../neo4j-go-driver/neo4j/values_temporal.go | 288 +++ .../neo4j/values_temporal_handlers.go | 307 +++ .../neo4j/values_temporal_test.go | 339 +++ .../onsi/ginkgo/extensions/table/table.go | 98 + .../ginkgo/extensions/table/table_entry.go | 81 + .../extensions/table/table_suite_test.go | 13 + .../ginkgo/extensions/table/table_test.go | 64 + vendor/github.com/stretchr/objx/LICENSE | 22 + vendor/github.com/stretchr/objx/README.md | 80 + vendor/github.com/stretchr/objx/Taskfile.yml | 30 + vendor/github.com/stretchr/objx/accessors.go | 179 ++ .../stretchr/objx/accessors_test.go | 220 ++ .../github.com/stretchr/objx/conversions.go | 280 ++ .../stretchr/objx/conversions_test.go | 187 ++ vendor/github.com/stretchr/objx/doc.go | 66 + .../github.com/stretchr/objx/fixture_test.go | 96 + vendor/github.com/stretchr/objx/go.mod | 8 + vendor/github.com/stretchr/objx/go.sum | 8 + vendor/github.com/stretchr/objx/map.go | 228 ++ vendor/github.com/stretchr/objx/map_test.go | 227 ++ vendor/github.com/stretchr/objx/mutations.go | 77 + .../stretchr/objx/mutations_test.go | 106 + vendor/github.com/stretchr/objx/security.go | 12 + .../github.com/stretchr/objx/security_test.go | 12 + .../stretchr/objx/simple_example_test.go | 42 + vendor/github.com/stretchr/objx/tests.go | 17 + vendor/github.com/stretchr/objx/tests_test.go | 25 + .../github.com/stretchr/objx/type_specific.go | 346 +++ .../stretchr/objx/type_specific_codegen.go | 2251 +++++++++++++++++ .../objx/type_specific_codegen_test.go | 2187 ++++++++++++++++ .../stretchr/objx/type_specific_test.go | 459 ++++ vendor/github.com/stretchr/objx/value.go | 159 ++ vendor/github.com/stretchr/objx/value_test.go | 143 ++ .../github.com/stretchr/testify/mock/doc.go | 44 + .../github.com/stretchr/testify/mock/mock.go | 886 +++++++ .../stretchr/testify/mock/mock_test.go | 1499 +++++++++++ vendor/vendor.json | 62 + 131 files changed, 26316 insertions(+) create mode 100644 vendor/github.com/golang/mock/LICENSE create mode 100644 vendor/github.com/golang/mock/gomock/call.go create mode 100644 vendor/github.com/golang/mock/gomock/call_test.go create mode 100644 vendor/github.com/golang/mock/gomock/callset.go create mode 100644 vendor/github.com/golang/mock/gomock/callset_test.go create mode 100644 vendor/github.com/golang/mock/gomock/controller.go create mode 100644 vendor/github.com/golang/mock/gomock/controller_test.go create mode 100644 vendor/github.com/golang/mock/gomock/internal/mock_gomock/mock_matcher.go create mode 100644 vendor/github.com/golang/mock/gomock/matchers.go create mode 100644 vendor/github.com/golang/mock/gomock/matchers_test.go create mode 100644 vendor/github.com/neo4j-drivers/gobolt/LICENSE create mode 100644 vendor/github.com/neo4j-drivers/gobolt/README.md create mode 100644 vendor/github.com/neo4j-drivers/gobolt/config.go create mode 100644 vendor/github.com/neo4j-drivers/gobolt/connection.go create mode 100644 vendor/github.com/neo4j-drivers/gobolt/connection_mock_test.go create mode 100644 vendor/github.com/neo4j-drivers/gobolt/connection_seabolt.go create mode 100644 vendor/github.com/neo4j-drivers/gobolt/connection_worker.go create mode 100644 vendor/github.com/neo4j-drivers/gobolt/connection_worker_test.go create mode 100644 vendor/github.com/neo4j-drivers/gobolt/connector.go create mode 100644 vendor/github.com/neo4j-drivers/gobolt/connector_seabolt.go create mode 100644 vendor/github.com/neo4j-drivers/gobolt/connector_worker.go create mode 100644 vendor/github.com/neo4j-drivers/gobolt/error.go create mode 100644 vendor/github.com/neo4j-drivers/gobolt/lifecycle.go create mode 100644 vendor/github.com/neo4j-drivers/gobolt/logging.go create mode 100644 vendor/github.com/neo4j-drivers/gobolt/resolver.go create mode 100644 vendor/github.com/neo4j-drivers/gobolt/seabolt-static.go create mode 100644 vendor/github.com/neo4j-drivers/gobolt/seabolt.go create mode 100644 vendor/github.com/neo4j-drivers/gobolt/stats.go create mode 100644 vendor/github.com/neo4j-drivers/gobolt/value.go create mode 100644 vendor/github.com/neo4j-drivers/gobolt/value_handler.go create mode 100644 vendor/github.com/neo4j-drivers/gobolt/worker_pool.go create mode 100644 vendor/github.com/neo4j-drivers/gobolt/worker_pool_test.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/LICENSE create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/Gopkg.lock create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/Gopkg.toml create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/auth_tokens.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/auth_tokens_test.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/config.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/config_resolver.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/config_test.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/config_trust.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/driver.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/driver_test.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/error.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/error_test.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/ginkgo_test.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/gobolt_driver.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/gobolt_driver_test.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/logging.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/logging_impl.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/logging_test.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_connection_test.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_connector_test.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_factory_test.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_logging_test.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_pool_test.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_record_test.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_result_test.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_resultsummary_test.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/record.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/record_impl.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/result.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/result_helpers.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/result_helpers_test.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/result_impl.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/retry.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/retry_test.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/runner.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/runner_test.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/session.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/session_impl.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/statement.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/statement_impl.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_collection.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_counters.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_notification.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_plan.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_position.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_profiled_plan.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_server_info.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_test.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/transaction.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/transaction_config.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/transaction_impl.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/utils.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/utils/test/gomock_matchers.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/utils/test/omega_error_matchers.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/utils/test/omega_number_matchers.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_graph.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_graph_handlers.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_spatial.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_spatial_handlers.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_spatial_test.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_temporal.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_temporal_handlers.go create mode 100644 vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_temporal_test.go create mode 100644 vendor/github.com/onsi/ginkgo/extensions/table/table.go create mode 100644 vendor/github.com/onsi/ginkgo/extensions/table/table_entry.go create mode 100644 vendor/github.com/onsi/ginkgo/extensions/table/table_suite_test.go create mode 100644 vendor/github.com/onsi/ginkgo/extensions/table/table_test.go create mode 100644 vendor/github.com/stretchr/objx/LICENSE create mode 100644 vendor/github.com/stretchr/objx/README.md create mode 100644 vendor/github.com/stretchr/objx/Taskfile.yml create mode 100644 vendor/github.com/stretchr/objx/accessors.go create mode 100644 vendor/github.com/stretchr/objx/accessors_test.go create mode 100644 vendor/github.com/stretchr/objx/conversions.go create mode 100644 vendor/github.com/stretchr/objx/conversions_test.go create mode 100644 vendor/github.com/stretchr/objx/doc.go create mode 100644 vendor/github.com/stretchr/objx/fixture_test.go create mode 100644 vendor/github.com/stretchr/objx/go.mod create mode 100644 vendor/github.com/stretchr/objx/go.sum create mode 100644 vendor/github.com/stretchr/objx/map.go create mode 100644 vendor/github.com/stretchr/objx/map_test.go create mode 100644 vendor/github.com/stretchr/objx/mutations.go create mode 100644 vendor/github.com/stretchr/objx/mutations_test.go create mode 100644 vendor/github.com/stretchr/objx/security.go create mode 100644 vendor/github.com/stretchr/objx/security_test.go create mode 100644 vendor/github.com/stretchr/objx/simple_example_test.go create mode 100644 vendor/github.com/stretchr/objx/tests.go create mode 100644 vendor/github.com/stretchr/objx/tests_test.go create mode 100644 vendor/github.com/stretchr/objx/type_specific.go create mode 100644 vendor/github.com/stretchr/objx/type_specific_codegen.go create mode 100644 vendor/github.com/stretchr/objx/type_specific_codegen_test.go create mode 100644 vendor/github.com/stretchr/objx/type_specific_test.go create mode 100644 vendor/github.com/stretchr/objx/value.go create mode 100644 vendor/github.com/stretchr/objx/value_test.go create mode 100644 vendor/github.com/stretchr/testify/mock/doc.go create mode 100644 vendor/github.com/stretchr/testify/mock/mock.go create mode 100644 vendor/github.com/stretchr/testify/mock/mock_test.go diff --git a/vendor/github.com/golang/mock/LICENSE b/vendor/github.com/golang/mock/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/vendor/github.com/golang/mock/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/golang/mock/gomock/call.go b/vendor/github.com/golang/mock/gomock/call.go new file mode 100644 index 0000000..3d54d9f --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/call.go @@ -0,0 +1,420 @@ +// Copyright 2010 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gomock + +import ( + "fmt" + "reflect" + "strconv" + "strings" +) + +// Call represents an expected call to a mock. +type Call struct { + t TestHelper // for triggering test failures on invalid call setup + + receiver interface{} // the receiver of the method call + method string // the name of the method + methodType reflect.Type // the type of the method + args []Matcher // the args + origin string // file and line number of call setup + + preReqs []*Call // prerequisite calls + + // Expectations + minCalls, maxCalls int + + numCalls int // actual number made + + // actions are called when this Call is called. Each action gets the args and + // can set the return values by returning a non-nil slice. Actions run in the + // order they are created. + actions []func([]interface{}) []interface{} +} + +// newCall creates a *Call. It requires the method type in order to support +// unexported methods. +func newCall(t TestHelper, receiver interface{}, method string, methodType reflect.Type, args ...interface{}) *Call { + t.Helper() + + // TODO: check arity, types. + margs := make([]Matcher, len(args)) + for i, arg := range args { + if m, ok := arg.(Matcher); ok { + margs[i] = m + } else if arg == nil { + // Handle nil specially so that passing a nil interface value + // will match the typed nils of concrete args. + margs[i] = Nil() + } else { + margs[i] = Eq(arg) + } + } + + origin := callerInfo(3) + actions := []func([]interface{}) []interface{}{func([]interface{}) []interface{} { + // Synthesize the zero value for each of the return args' types. + rets := make([]interface{}, methodType.NumOut()) + for i := 0; i < methodType.NumOut(); i++ { + rets[i] = reflect.Zero(methodType.Out(i)).Interface() + } + return rets + }} + return &Call{t: t, receiver: receiver, method: method, methodType: methodType, + args: margs, origin: origin, minCalls: 1, maxCalls: 1, actions: actions} +} + +// AnyTimes allows the expectation to be called 0 or more times +func (c *Call) AnyTimes() *Call { + c.minCalls, c.maxCalls = 0, 1e8 // close enough to infinity + return c +} + +// MinTimes requires the call to occur at least n times. If AnyTimes or MaxTimes have not been called, MinTimes also +// sets the maximum number of calls to infinity. +func (c *Call) MinTimes(n int) *Call { + c.minCalls = n + if c.maxCalls == 1 { + c.maxCalls = 1e8 + } + return c +} + +// MaxTimes limits the number of calls to n times. If AnyTimes or MinTimes have not been called, MaxTimes also +// sets the minimum number of calls to 0. +func (c *Call) MaxTimes(n int) *Call { + c.maxCalls = n + if c.minCalls == 1 { + c.minCalls = 0 + } + return c +} + +// DoAndReturn declares the action to run when the call is matched. +// The return values from this function are returned by the mocked function. +// It takes an interface{} argument to support n-arity functions. +func (c *Call) DoAndReturn(f interface{}) *Call { + // TODO: Check arity and types here, rather than dying badly elsewhere. + v := reflect.ValueOf(f) + + c.addAction(func(args []interface{}) []interface{} { + vargs := make([]reflect.Value, len(args)) + ft := v.Type() + for i := 0; i < len(args); i++ { + if args[i] != nil { + vargs[i] = reflect.ValueOf(args[i]) + } else { + // Use the zero value for the arg. + vargs[i] = reflect.Zero(ft.In(i)) + } + } + vrets := v.Call(vargs) + rets := make([]interface{}, len(vrets)) + for i, ret := range vrets { + rets[i] = ret.Interface() + } + return rets + }) + return c +} + +// Do declares the action to run when the call is matched. The function's +// return values are ignored to retain backward compatibility. To use the +// return values call DoAndReturn. +// It takes an interface{} argument to support n-arity functions. +func (c *Call) Do(f interface{}) *Call { + // TODO: Check arity and types here, rather than dying badly elsewhere. + v := reflect.ValueOf(f) + + c.addAction(func(args []interface{}) []interface{} { + vargs := make([]reflect.Value, len(args)) + ft := v.Type() + for i := 0; i < len(args); i++ { + if args[i] != nil { + vargs[i] = reflect.ValueOf(args[i]) + } else { + // Use the zero value for the arg. + vargs[i] = reflect.Zero(ft.In(i)) + } + } + v.Call(vargs) + return nil + }) + return c +} + +// Return declares the values to be returned by the mocked function call. +func (c *Call) Return(rets ...interface{}) *Call { + c.t.Helper() + + mt := c.methodType + if len(rets) != mt.NumOut() { + c.t.Fatalf("wrong number of arguments to Return for %T.%v: got %d, want %d [%s]", + c.receiver, c.method, len(rets), mt.NumOut(), c.origin) + } + for i, ret := range rets { + if got, want := reflect.TypeOf(ret), mt.Out(i); got == want { + // Identical types; nothing to do. + } else if got == nil { + // Nil needs special handling. + switch want.Kind() { + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + // ok + default: + c.t.Fatalf("argument %d to Return for %T.%v is nil, but %v is not nillable [%s]", + i, c.receiver, c.method, want, c.origin) + } + } else if got.AssignableTo(want) { + // Assignable type relation. Make the assignment now so that the generated code + // can return the values with a type assertion. + v := reflect.New(want).Elem() + v.Set(reflect.ValueOf(ret)) + rets[i] = v.Interface() + } else { + c.t.Fatalf("wrong type of argument %d to Return for %T.%v: %v is not assignable to %v [%s]", + i, c.receiver, c.method, got, want, c.origin) + } + } + + c.addAction(func([]interface{}) []interface{} { + return rets + }) + + return c +} + +// Times declares the exact number of times a function call is expected to be executed. +func (c *Call) Times(n int) *Call { + c.minCalls, c.maxCalls = n, n + return c +} + +// SetArg declares an action that will set the nth argument's value, +// indirected through a pointer. Or, in the case of a slice, SetArg +// will copy value's elements into the nth argument. +func (c *Call) SetArg(n int, value interface{}) *Call { + c.t.Helper() + + mt := c.methodType + // TODO: This will break on variadic methods. + // We will need to check those at invocation time. + if n < 0 || n >= mt.NumIn() { + c.t.Fatalf("SetArg(%d, ...) called for a method with %d args [%s]", + n, mt.NumIn(), c.origin) + } + // Permit setting argument through an interface. + // In the interface case, we don't (nay, can't) check the type here. + at := mt.In(n) + switch at.Kind() { + case reflect.Ptr: + dt := at.Elem() + if vt := reflect.TypeOf(value); !vt.AssignableTo(dt) { + c.t.Fatalf("SetArg(%d, ...) argument is a %v, not assignable to %v [%s]", + n, vt, dt, c.origin) + } + case reflect.Interface: + // nothing to do + case reflect.Slice: + // nothing to do + default: + c.t.Fatalf("SetArg(%d, ...) referring to argument of non-pointer non-interface non-slice type %v [%s]", + n, at, c.origin) + } + + c.addAction(func(args []interface{}) []interface{} { + v := reflect.ValueOf(value) + switch reflect.TypeOf(args[n]).Kind() { + case reflect.Slice: + setSlice(args[n], v) + default: + reflect.ValueOf(args[n]).Elem().Set(v) + } + return nil + }) + return c +} + +// isPreReq returns true if other is a direct or indirect prerequisite to c. +func (c *Call) isPreReq(other *Call) bool { + for _, preReq := range c.preReqs { + if other == preReq || preReq.isPreReq(other) { + return true + } + } + return false +} + +// After declares that the call may only match after preReq has been exhausted. +func (c *Call) After(preReq *Call) *Call { + c.t.Helper() + + if c == preReq { + c.t.Fatalf("A call isn't allowed to be its own prerequisite") + } + if preReq.isPreReq(c) { + c.t.Fatalf("Loop in call order: %v is a prerequisite to %v (possibly indirectly).", c, preReq) + } + + c.preReqs = append(c.preReqs, preReq) + return c +} + +// Returns true if the minimum number of calls have been made. +func (c *Call) satisfied() bool { + return c.numCalls >= c.minCalls +} + +// Returns true iff the maximum number of calls have been made. +func (c *Call) exhausted() bool { + return c.numCalls >= c.maxCalls +} + +func (c *Call) String() string { + args := make([]string, len(c.args)) + for i, arg := range c.args { + args[i] = arg.String() + } + arguments := strings.Join(args, ", ") + return fmt.Sprintf("%T.%v(%s) %s", c.receiver, c.method, arguments, c.origin) +} + +// Tests if the given call matches the expected call. +// If yes, returns nil. If no, returns error with message explaining why it does not match. +func (c *Call) matches(args []interface{}) error { + if !c.methodType.IsVariadic() { + if len(args) != len(c.args) { + return fmt.Errorf("Expected call at %s has the wrong number of arguments. Got: %d, want: %d", + c.origin, len(args), len(c.args)) + } + + for i, m := range c.args { + if !m.Matches(args[i]) { + return fmt.Errorf("Expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v", + c.origin, strconv.Itoa(i), args[i], m) + } + } + } else { + if len(c.args) < c.methodType.NumIn()-1 { + return fmt.Errorf("Expected call at %s has the wrong number of matchers. Got: %d, want: %d", + c.origin, len(c.args), c.methodType.NumIn()-1) + } + if len(c.args) != c.methodType.NumIn() && len(args) != len(c.args) { + return fmt.Errorf("Expected call at %s has the wrong number of arguments. Got: %d, want: %d", + c.origin, len(args), len(c.args)) + } + if len(args) < len(c.args)-1 { + return fmt.Errorf("Expected call at %s has the wrong number of arguments. Got: %d, want: greater than or equal to %d", + c.origin, len(args), len(c.args)-1) + } + + for i, m := range c.args { + if i < c.methodType.NumIn()-1 { + // Non-variadic args + if !m.Matches(args[i]) { + return fmt.Errorf("Expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v", + c.origin, strconv.Itoa(i), args[i], m) + } + continue + } + // The last arg has a possibility of a variadic argument, so let it branch + + // sample: Foo(a int, b int, c ...int) + if i < len(c.args) && i < len(args) { + if m.Matches(args[i]) { + // Got Foo(a, b, c) want Foo(matcherA, matcherB, gomock.Any()) + // Got Foo(a, b, c) want Foo(matcherA, matcherB, someSliceMatcher) + // Got Foo(a, b, c) want Foo(matcherA, matcherB, matcherC) + // Got Foo(a, b) want Foo(matcherA, matcherB) + // Got Foo(a, b, c, d) want Foo(matcherA, matcherB, matcherC, matcherD) + continue + } + } + + // The number of actual args don't match the number of matchers, + // or the last matcher is a slice and the last arg is not. + // If this function still matches it is because the last matcher + // matches all the remaining arguments or the lack of any. + // Convert the remaining arguments, if any, into a slice of the + // expected type. + vargsType := c.methodType.In(c.methodType.NumIn() - 1) + vargs := reflect.MakeSlice(vargsType, 0, len(args)-i) + for _, arg := range args[i:] { + vargs = reflect.Append(vargs, reflect.ValueOf(arg)) + } + if m.Matches(vargs.Interface()) { + // Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, gomock.Any()) + // Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, someSliceMatcher) + // Got Foo(a, b) want Foo(matcherA, matcherB, gomock.Any()) + // Got Foo(a, b) want Foo(matcherA, matcherB, someEmptySliceMatcher) + break + } + // Wrong number of matchers or not match. Fail. + // Got Foo(a, b) want Foo(matcherA, matcherB, matcherC, matcherD) + // Got Foo(a, b, c) want Foo(matcherA, matcherB, matcherC, matcherD) + // Got Foo(a, b, c, d) want Foo(matcherA, matcherB, matcherC, matcherD, matcherE) + // Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, matcherC, matcherD) + // Got Foo(a, b, c) want Foo(matcherA, matcherB) + return fmt.Errorf("Expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v", + c.origin, strconv.Itoa(i), args[i:], c.args[i]) + + } + } + + // Check that all prerequisite calls have been satisfied. + for _, preReqCall := range c.preReqs { + if !preReqCall.satisfied() { + return fmt.Errorf("Expected call at %s doesn't have a prerequisite call satisfied:\n%v\nshould be called before:\n%v", + c.origin, preReqCall, c) + } + } + + // Check that the call is not exhausted. + if c.exhausted() { + return fmt.Errorf("Expected call at %s has already been called the max number of times.", c.origin) + } + + return nil +} + +// dropPrereqs tells the expected Call to not re-check prerequisite calls any +// longer, and to return its current set. +func (c *Call) dropPrereqs() (preReqs []*Call) { + preReqs = c.preReqs + c.preReqs = nil + return +} + +func (c *Call) call(args []interface{}) []func([]interface{}) []interface{} { + c.numCalls++ + return c.actions +} + +// InOrder declares that the given calls should occur in order. +func InOrder(calls ...*Call) { + for i := 1; i < len(calls); i++ { + calls[i].After(calls[i-1]) + } +} + +func setSlice(arg interface{}, v reflect.Value) { + va := reflect.ValueOf(arg) + for i := 0; i < v.Len(); i++ { + va.Index(i).Set(v.Index(i)) + } +} + +func (c *Call) addAction(action func([]interface{}) []interface{}) { + c.actions = append(c.actions, action) +} diff --git a/vendor/github.com/golang/mock/gomock/call_test.go b/vendor/github.com/golang/mock/gomock/call_test.go new file mode 100644 index 0000000..3a8315b --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/call_test.go @@ -0,0 +1,51 @@ +package gomock + +import ( + "testing" +) + +type mockTestReporter struct { + errorCalls int + fatalCalls int +} + +func (o *mockTestReporter) Errorf(format string, args ...interface{}) { + o.errorCalls++ +} + +func (o *mockTestReporter) Fatalf(format string, args ...interface{}) { + o.fatalCalls++ +} + +func (o *mockTestReporter) Helper() {} + +func TestCall_After(t *testing.T) { + t.Run("SelfPrereqCallsFatalf", func(t *testing.T) { + tr1 := &mockTestReporter{} + + c := &Call{t: tr1} + c.After(c) + + if tr1.fatalCalls != 1 { + t.Errorf("number of fatal calls == %v, want 1", tr1.fatalCalls) + } + }) + + t.Run("LoopInCallOrderCallsFatalf", func(t *testing.T) { + tr1 := &mockTestReporter{} + tr2 := &mockTestReporter{} + + c1 := &Call{t: tr1} + c2 := &Call{t: tr2} + c1.After(c2) + c2.After(c1) + + if tr1.errorCalls != 0 || tr1.fatalCalls != 0 { + t.Error("unexpected errors") + } + + if tr2.fatalCalls != 1 { + t.Errorf("number of fatal calls == %v, want 1", tr2.fatalCalls) + } + }) +} diff --git a/vendor/github.com/golang/mock/gomock/callset.go b/vendor/github.com/golang/mock/gomock/callset.go new file mode 100644 index 0000000..c44a8a5 --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/callset.go @@ -0,0 +1,108 @@ +// Copyright 2011 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gomock + +import ( + "bytes" + "fmt" +) + +// callSet represents a set of expected calls, indexed by receiver and method +// name. +type callSet struct { + // Calls that are still expected. + expected map[callSetKey][]*Call + // Calls that have been exhausted. + exhausted map[callSetKey][]*Call +} + +// callSetKey is the key in the maps in callSet +type callSetKey struct { + receiver interface{} + fname string +} + +func newCallSet() *callSet { + return &callSet{make(map[callSetKey][]*Call), make(map[callSetKey][]*Call)} +} + +// Add adds a new expected call. +func (cs callSet) Add(call *Call) { + key := callSetKey{call.receiver, call.method} + m := cs.expected + if call.exhausted() { + m = cs.exhausted + } + m[key] = append(m[key], call) +} + +// Remove removes an expected call. +func (cs callSet) Remove(call *Call) { + key := callSetKey{call.receiver, call.method} + calls := cs.expected[key] + for i, c := range calls { + if c == call { + // maintain order for remaining calls + cs.expected[key] = append(calls[:i], calls[i+1:]...) + cs.exhausted[key] = append(cs.exhausted[key], call) + break + } + } +} + +// FindMatch searches for a matching call. Returns error with explanation message if no call matched. +func (cs callSet) FindMatch(receiver interface{}, method string, args []interface{}) (*Call, error) { + key := callSetKey{receiver, method} + + // Search through the expected calls. + expected := cs.expected[key] + var callsErrors bytes.Buffer + for _, call := range expected { + err := call.matches(args) + if err != nil { + fmt.Fprintf(&callsErrors, "\n%v", err) + } else { + return call, nil + } + } + + // If we haven't found a match then search through the exhausted calls so we + // get useful error messages. + exhausted := cs.exhausted[key] + for _, call := range exhausted { + if err := call.matches(args); err != nil { + fmt.Fprintf(&callsErrors, "\n%v", err) + } + } + + if len(expected)+len(exhausted) == 0 { + fmt.Fprintf(&callsErrors, "there are no expected calls of the method %q for that receiver", method) + } + + return nil, fmt.Errorf(callsErrors.String()) +} + +// Failures returns the calls that are not satisfied. +func (cs callSet) Failures() []*Call { + failures := make([]*Call, 0, len(cs.expected)) + for _, calls := range cs.expected { + for _, call := range calls { + if !call.satisfied() { + failures = append(failures, call) + } + } + } + return failures +} diff --git a/vendor/github.com/golang/mock/gomock/callset_test.go b/vendor/github.com/golang/mock/gomock/callset_test.go new file mode 100644 index 0000000..7fc711a --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/callset_test.go @@ -0,0 +1,76 @@ +// Copyright 2011 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gomock + +import ( + "reflect" + "testing" +) + +type receiverType struct{} + +func (receiverType) Func() {} + +func TestCallSetAdd(t *testing.T) { + method := "TestMethod" + var receiver interface{} = "TestReceiver" + cs := newCallSet() + + numCalls := 10 + for i := 0; i < numCalls; i++ { + cs.Add(newCall(t, receiver, method, reflect.TypeOf(receiverType{}.Func))) + } + + call, err := cs.FindMatch(receiver, method, []interface{}{}) + if err != nil { + t.Fatalf("FindMatch: %v", err) + } + if call == nil { + t.Fatalf("FindMatch: Got nil, want non-nil *Call") + } +} + +func TestCallSetRemove(t *testing.T) { + method := "TestMethod" + var receiver interface{} = "TestReceiver" + + cs := newCallSet() + ourCalls := []*Call{} + + numCalls := 10 + for i := 0; i < numCalls; i++ { + // NOTE: abuse the `numCalls` value to convey initial ordering of mocked calls + generatedCall := &Call{receiver: receiver, method: method, numCalls: i} + cs.Add(generatedCall) + ourCalls = append(ourCalls, generatedCall) + } + + // validateOrder validates that the calls in the array are ordered as they were added + validateOrder := func(calls []*Call) { + // lastNum tracks the last `numCalls` (call order) value seen + lastNum := -1 + for _, c := range calls { + if lastNum >= c.numCalls { + t.Errorf("found call %d after call %d", c.numCalls, lastNum) + } + lastNum = c.numCalls + } + } + + for _, c := range ourCalls { + validateOrder(cs.expected[callSetKey{receiver, method}]) + cs.Remove(c) + } +} diff --git a/vendor/github.com/golang/mock/gomock/controller.go b/vendor/github.com/golang/mock/gomock/controller.go new file mode 100644 index 0000000..75f2350 --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/controller.go @@ -0,0 +1,264 @@ +// Copyright 2010 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package gomock is a mock framework for Go. +// +// Standard usage: +// (1) Define an interface that you wish to mock. +// type MyInterface interface { +// SomeMethod(x int64, y string) +// } +// (2) Use mockgen to generate a mock from the interface. +// (3) Use the mock in a test: +// func TestMyThing(t *testing.T) { +// mockCtrl := gomock.NewController(t) +// defer mockCtrl.Finish() +// +// mockObj := something.NewMockMyInterface(mockCtrl) +// mockObj.EXPECT().SomeMethod(4, "blah") +// // pass mockObj to a real object and play with it. +// } +// +// By default, expected calls are not enforced to run in any particular order. +// Call order dependency can be enforced by use of InOrder and/or Call.After. +// Call.After can create more varied call order dependencies, but InOrder is +// often more convenient. +// +// The following examples create equivalent call order dependencies. +// +// Example of using Call.After to chain expected call order: +// +// firstCall := mockObj.EXPECT().SomeMethod(1, "first") +// secondCall := mockObj.EXPECT().SomeMethod(2, "second").After(firstCall) +// mockObj.EXPECT().SomeMethod(3, "third").After(secondCall) +// +// Example of using InOrder to declare expected call order: +// +// gomock.InOrder( +// mockObj.EXPECT().SomeMethod(1, "first"), +// mockObj.EXPECT().SomeMethod(2, "second"), +// mockObj.EXPECT().SomeMethod(3, "third"), +// ) +// +// TODO: +// - Handle different argument/return types (e.g. ..., chan, map, interface). +package gomock + +import ( + "context" + "fmt" + "reflect" + "runtime" + "sync" +) + +// A TestReporter is something that can be used to report test failures. It +// is satisfied by the standard library's *testing.T. +type TestReporter interface { + Errorf(format string, args ...interface{}) + Fatalf(format string, args ...interface{}) +} + +// TestHelper is a TestReporter that has the Helper method. It is satisfied +// by the standard library's *testing.T. +type TestHelper interface { + TestReporter + Helper() +} + +// A Controller represents the top-level control of a mock ecosystem. It +// defines the scope and lifetime of mock objects, as well as their +// expectations. It is safe to call Controller's methods from multiple +// goroutines. Each test should create a new Controller and invoke Finish via +// defer. +// +// func TestFoo(t *testing.T) { +// ctrl := gomock.NewController(t) +// defer ctrl.Finish() +// // .. +// } +// +// func TestBar(t *testing.T) { +// t.Run("Sub-Test-1", st) { +// ctrl := gomock.NewController(st) +// defer ctrl.Finish() +// // .. +// }) +// t.Run("Sub-Test-2", st) { +// ctrl := gomock.NewController(st) +// defer ctrl.Finish() +// // .. +// }) +// }) +type Controller struct { + // T should only be called within a generated mock. It is not intended to + // be used in user code and may be changed in future versions. T is the + // TestReporter passed in when creating the Controller via NewController. + // If the TestReporter does not implement a TestHelper it will be wrapped + // with a nopTestHelper. + T TestHelper + mu sync.Mutex + expectedCalls *callSet + finished bool +} + +// NewController returns a new Controller. It is the preferred way to create a +// Controller. +func NewController(t TestReporter) *Controller { + h, ok := t.(TestHelper) + if !ok { + h = nopTestHelper{t} + } + + return &Controller{ + T: h, + expectedCalls: newCallSet(), + } +} + +type cancelReporter struct { + TestHelper + cancel func() +} + +func (r *cancelReporter) Errorf(format string, args ...interface{}) { + r.TestHelper.Errorf(format, args...) +} +func (r *cancelReporter) Fatalf(format string, args ...interface{}) { + defer r.cancel() + r.TestHelper.Fatalf(format, args...) +} + +// WithContext returns a new Controller and a Context, which is cancelled on any +// fatal failure. +func WithContext(ctx context.Context, t TestReporter) (*Controller, context.Context) { + h, ok := t.(TestHelper) + if !ok { + h = nopTestHelper{t} + } + + ctx, cancel := context.WithCancel(ctx) + return NewController(&cancelReporter{h, cancel}), ctx +} + +type nopTestHelper struct { + TestReporter +} + +func (h nopTestHelper) Helper() {} + +// RecordCall is called by a mock. It should not be called by user code. +func (ctrl *Controller) RecordCall(receiver interface{}, method string, args ...interface{}) *Call { + ctrl.T.Helper() + + recv := reflect.ValueOf(receiver) + for i := 0; i < recv.Type().NumMethod(); i++ { + if recv.Type().Method(i).Name == method { + return ctrl.RecordCallWithMethodType(receiver, method, recv.Method(i).Type(), args...) + } + } + ctrl.T.Fatalf("gomock: failed finding method %s on %T", method, receiver) + panic("unreachable") +} + +// RecordCallWithMethodType is called by a mock. It should not be called by user code. +func (ctrl *Controller) RecordCallWithMethodType(receiver interface{}, method string, methodType reflect.Type, args ...interface{}) *Call { + ctrl.T.Helper() + + call := newCall(ctrl.T, receiver, method, methodType, args...) + + ctrl.mu.Lock() + defer ctrl.mu.Unlock() + ctrl.expectedCalls.Add(call) + + return call +} + +// Call is called by a mock. It should not be called by user code. +func (ctrl *Controller) Call(receiver interface{}, method string, args ...interface{}) []interface{} { + ctrl.T.Helper() + + // Nest this code so we can use defer to make sure the lock is released. + actions := func() []func([]interface{}) []interface{} { + ctrl.T.Helper() + ctrl.mu.Lock() + defer ctrl.mu.Unlock() + + expected, err := ctrl.expectedCalls.FindMatch(receiver, method, args) + if err != nil { + origin := callerInfo(2) + ctrl.T.Fatalf("Unexpected call to %T.%v(%v) at %s because: %s", receiver, method, args, origin, err) + } + + // Two things happen here: + // * the matching call no longer needs to check prerequite calls, + // * and the prerequite calls are no longer expected, so remove them. + preReqCalls := expected.dropPrereqs() + for _, preReqCall := range preReqCalls { + ctrl.expectedCalls.Remove(preReqCall) + } + + actions := expected.call(args) + if expected.exhausted() { + ctrl.expectedCalls.Remove(expected) + } + return actions + }() + + var rets []interface{} + for _, action := range actions { + if r := action(args); r != nil { + rets = r + } + } + + return rets +} + +// Finish checks to see if all the methods that were expected to be called +// were called. It should be invoked for each Controller. It is not idempotent +// and therefore can only be invoked once. +func (ctrl *Controller) Finish() { + ctrl.T.Helper() + + ctrl.mu.Lock() + defer ctrl.mu.Unlock() + + if ctrl.finished { + ctrl.T.Fatalf("Controller.Finish was called more than once. It has to be called exactly once.") + } + ctrl.finished = true + + // If we're currently panicking, probably because this is a deferred call, + // pass through the panic. + if err := recover(); err != nil { + panic(err) + } + + // Check that all remaining expected calls are satisfied. + failures := ctrl.expectedCalls.Failures() + for _, call := range failures { + ctrl.T.Errorf("missing call(s) to %v", call) + } + if len(failures) != 0 { + ctrl.T.Fatalf("aborting test due to missing call(s)") + } +} + +func callerInfo(skip int) string { + if _, file, line, ok := runtime.Caller(skip + 1); ok { + return fmt.Sprintf("%s:%d", file, line) + } + return "unknown file" +} diff --git a/vendor/github.com/golang/mock/gomock/controller_test.go b/vendor/github.com/golang/mock/gomock/controller_test.go new file mode 100644 index 0000000..d85cf9d --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/controller_test.go @@ -0,0 +1,739 @@ +// Copyright 2011 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gomock_test + +import ( + "fmt" + "reflect" + "testing" + + "strings" + + "github.com/golang/mock/gomock" +) + +type ErrorReporter struct { + t *testing.T + log []string + failed bool + fatalToken struct{} +} + +func NewErrorReporter(t *testing.T) *ErrorReporter { + return &ErrorReporter{t: t} +} + +func (e *ErrorReporter) reportLog() { + for _, entry := range e.log { + e.t.Log(entry) + } +} + +func (e *ErrorReporter) assertPass(msg string) { + if e.failed { + e.t.Errorf("Expected pass, but got failure(s): %s", msg) + e.reportLog() + } +} + +func (e *ErrorReporter) assertFail(msg string) { + if !e.failed { + e.t.Errorf("Expected failure, but got pass: %s", msg) + } +} + +// Use to check that code triggers a fatal test failure. +func (e *ErrorReporter) assertFatal(fn func(), expectedErrMsgs ...string) { + defer func() { + err := recover() + if err == nil { + var actual string + if e.failed { + actual = "non-fatal failure" + } else { + actual = "pass" + } + e.t.Error("Expected fatal failure, but got a", actual) + } else if token, ok := err.(*struct{}); ok && token == &e.fatalToken { + // This is okay - the panic is from Fatalf(). + if expectedErrMsgs != nil { + // assert that the actual error message + // contains expectedErrMsgs + + // check the last actualErrMsg, because the previous messages come from previous errors + actualErrMsg := e.log[len(e.log)-1] + for _, expectedErrMsg := range expectedErrMsgs { + if !strings.Contains(actualErrMsg, expectedErrMsg) { + e.t.Errorf("Error message:\ngot: %q\nwant to contain: %q\n", actualErrMsg, expectedErrMsg) + } + } + } + return + } else { + // Some other panic. + panic(err) + } + }() + + fn() +} + +// recoverUnexpectedFatal can be used as a deferred call in test cases to +// recover from and display a call to ErrorReporter.Fatalf(). +func (e *ErrorReporter) recoverUnexpectedFatal() { + err := recover() + if err == nil { + // No panic. + } else if token, ok := err.(*struct{}); ok && token == &e.fatalToken { + // Unexpected fatal error happened. + e.t.Error("Got unexpected fatal error(s). All errors up to this point:") + e.reportLog() + return + } else { + // Some other panic. + panic(err) + } +} + +func (e *ErrorReporter) Logf(format string, args ...interface{}) { + e.log = append(e.log, fmt.Sprintf(format, args...)) +} + +func (e *ErrorReporter) Errorf(format string, args ...interface{}) { + e.Logf(format, args...) + e.failed = true +} + +func (e *ErrorReporter) Fatalf(format string, args ...interface{}) { + e.Logf(format, args...) + e.failed = true + panic(&e.fatalToken) +} + +type HelperReporter struct { + gomock.TestReporter + helper int +} + +func (h *HelperReporter) Helper() { + h.helper++ +} + +// A type purely for use as a receiver in testing the Controller. +type Subject struct{} + +func (s *Subject) FooMethod(arg string) int { + return 0 +} + +func (s *Subject) BarMethod(arg string) int { + return 0 +} + +func (s *Subject) VariadicMethod(arg int, vararg ...string) {} + +// A type purely for ActOnTestStructMethod +type TestStruct struct { + Number int + Message string +} + +func (s *Subject) ActOnTestStructMethod(arg TestStruct, arg1 int) int { + return 0 +} + +func (s *Subject) SetArgMethod(sliceArg []byte, ptrArg *int) {} + +func assertEqual(t *testing.T, expected interface{}, actual interface{}) { + if !reflect.DeepEqual(expected, actual) { + t.Errorf("Expected %+v, but got %+v", expected, actual) + } +} + +func createFixtures(t *testing.T) (reporter *ErrorReporter, ctrl *gomock.Controller) { + // reporter acts as a testing.T-like object that we pass to the + // Controller. We use it to test that the mock considered tests + // successful or failed. + reporter = NewErrorReporter(t) + ctrl = gomock.NewController(reporter) + return +} + +func TestNoCalls(t *testing.T) { + reporter, ctrl := createFixtures(t) + ctrl.Finish() + reporter.assertPass("No calls expected or made.") +} + +func TestNoRecordedCallsForAReceiver(t *testing.T) { + reporter, ctrl := createFixtures(t) + subject := new(Subject) + + reporter.assertFatal(func() { + ctrl.Call(subject, "NotRecordedMethod", "argument") + }, "Unexpected call to", "there are no expected calls of the method \"NotRecordedMethod\" for that receiver") + ctrl.Finish() +} + +func TestNoRecordedMatchingMethodNameForAReceiver(t *testing.T) { + reporter, ctrl := createFixtures(t) + subject := new(Subject) + + ctrl.RecordCall(subject, "FooMethod", "argument") + reporter.assertFatal(func() { + ctrl.Call(subject, "NotRecordedMethod", "argument") + }, "Unexpected call to", "there are no expected calls of the method \"NotRecordedMethod\" for that receiver") + reporter.assertFatal(func() { + // The expected call wasn't made. + ctrl.Finish() + }) +} + +// This tests that a call with an arguments of some primitive type matches a recorded call. +func TestExpectedMethodCall(t *testing.T) { + reporter, ctrl := createFixtures(t) + subject := new(Subject) + + ctrl.RecordCall(subject, "FooMethod", "argument") + ctrl.Call(subject, "FooMethod", "argument") + ctrl.Finish() + + reporter.assertPass("Expected method call made.") +} + +func TestUnexpectedMethodCall(t *testing.T) { + reporter, ctrl := createFixtures(t) + subject := new(Subject) + + reporter.assertFatal(func() { + ctrl.Call(subject, "FooMethod", "argument") + }) + + ctrl.Finish() +} + +func TestRepeatedCall(t *testing.T) { + reporter, ctrl := createFixtures(t) + subject := new(Subject) + + ctrl.RecordCall(subject, "FooMethod", "argument").Times(3) + ctrl.Call(subject, "FooMethod", "argument") + ctrl.Call(subject, "FooMethod", "argument") + ctrl.Call(subject, "FooMethod", "argument") + reporter.assertPass("After expected repeated method calls.") + reporter.assertFatal(func() { + ctrl.Call(subject, "FooMethod", "argument") + }) + ctrl.Finish() + reporter.assertFail("After calling one too many times.") +} + +func TestUnexpectedArgCount(t *testing.T) { + reporter, ctrl := createFixtures(t) + defer reporter.recoverUnexpectedFatal() + subject := new(Subject) + + ctrl.RecordCall(subject, "FooMethod", "argument") + reporter.assertFatal(func() { + // This call is made with the wrong number of arguments... + ctrl.Call(subject, "FooMethod", "argument", "extra_argument") + }, "Unexpected call to", "wrong number of arguments", "Got: 2, want: 1") + reporter.assertFatal(func() { + // ... so is this. + ctrl.Call(subject, "FooMethod") + }, "Unexpected call to", "wrong number of arguments", "Got: 0, want: 1") + reporter.assertFatal(func() { + // The expected call wasn't made. + ctrl.Finish() + }) +} + +// This tests that a call with complex arguments (a struct and some primitive type) matches a recorded call. +func TestExpectedMethodCall_CustomStruct(t *testing.T) { + reporter, ctrl := createFixtures(t) + subject := new(Subject) + + expectedArg0 := TestStruct{Number: 123, Message: "hello"} + ctrl.RecordCall(subject, "ActOnTestStructMethod", expectedArg0, 15) + ctrl.Call(subject, "ActOnTestStructMethod", expectedArg0, 15) + + reporter.assertPass("Expected method call made.") +} + +func TestUnexpectedArgValue_FirstArg(t *testing.T) { + reporter, ctrl := createFixtures(t) + defer reporter.recoverUnexpectedFatal() + subject := new(Subject) + + expectedArg0 := TestStruct{Number: 123, Message: "hello"} + ctrl.RecordCall(subject, "ActOnTestStructMethod", expectedArg0, 15) + + reporter.assertFatal(func() { + // the method argument (of TestStruct type) has 1 unexpected value (for the Message field) + ctrl.Call(subject, "ActOnTestStructMethod", TestStruct{Number: 123, Message: "no message"}, 15) + }, "Unexpected call to", "doesn't match the argument at index 0", + "Got: {123 no message}\nWant: is equal to {123 hello}") + + reporter.assertFatal(func() { + // the method argument (of TestStruct type) has 2 unexpected values (for both fields) + ctrl.Call(subject, "ActOnTestStructMethod", TestStruct{Number: 11, Message: "no message"}, 15) + }, "Unexpected call to", "doesn't match the argument at index 0", + "Got: {11 no message}\nWant: is equal to {123 hello}") + + reporter.assertFatal(func() { + // The expected call wasn't made. + ctrl.Finish() + }) +} + +func TestUnexpectedArgValue_SecondArg(t *testing.T) { + reporter, ctrl := createFixtures(t) + defer reporter.recoverUnexpectedFatal() + subject := new(Subject) + + expectedArg0 := TestStruct{Number: 123, Message: "hello"} + ctrl.RecordCall(subject, "ActOnTestStructMethod", expectedArg0, 15) + + reporter.assertFatal(func() { + ctrl.Call(subject, "ActOnTestStructMethod", TestStruct{Number: 123, Message: "hello"}, 3) + }, "Unexpected call to", "doesn't match the argument at index 1", + "Got: 3\nWant: is equal to 15") + + reporter.assertFatal(func() { + // The expected call wasn't made. + ctrl.Finish() + }) +} + +func TestAnyTimes(t *testing.T) { + reporter, ctrl := createFixtures(t) + subject := new(Subject) + + ctrl.RecordCall(subject, "FooMethod", "argument").AnyTimes() + for i := 0; i < 100; i++ { + ctrl.Call(subject, "FooMethod", "argument") + } + reporter.assertPass("After 100 method calls.") + ctrl.Finish() +} + +func TestMinTimes1(t *testing.T) { + // It fails if there are no calls + reporter, ctrl := createFixtures(t) + subject := new(Subject) + ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(1) + reporter.assertFatal(func() { + ctrl.Finish() + }) + + // It succeeds if there is one call + reporter, ctrl = createFixtures(t) + subject = new(Subject) + ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(1) + ctrl.Call(subject, "FooMethod", "argument") + ctrl.Finish() + + // It succeeds if there are many calls + reporter, ctrl = createFixtures(t) + subject = new(Subject) + ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(1) + for i := 0; i < 100; i++ { + ctrl.Call(subject, "FooMethod", "argument") + } + ctrl.Finish() +} + +func TestMaxTimes1(t *testing.T) { + // It succeeds if there are no calls + _, ctrl := createFixtures(t) + subject := new(Subject) + ctrl.RecordCall(subject, "FooMethod", "argument").MaxTimes(1) + ctrl.Finish() + + // It succeeds if there is one call + _, ctrl = createFixtures(t) + subject = new(Subject) + ctrl.RecordCall(subject, "FooMethod", "argument").MaxTimes(1) + ctrl.Call(subject, "FooMethod", "argument") + ctrl.Finish() + + //It fails if there are more + reporter, ctrl := createFixtures(t) + subject = new(Subject) + ctrl.RecordCall(subject, "FooMethod", "argument").MaxTimes(1) + ctrl.Call(subject, "FooMethod", "argument") + reporter.assertFatal(func() { + ctrl.Call(subject, "FooMethod", "argument") + }) + ctrl.Finish() +} + +func TestMinMaxTimes(t *testing.T) { + // It fails if there are less calls than specified + reporter, ctrl := createFixtures(t) + subject := new(Subject) + ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(2).MaxTimes(2) + ctrl.Call(subject, "FooMethod", "argument") + reporter.assertFatal(func() { + ctrl.Finish() + }) + + // It fails if there are more calls than specified + reporter, ctrl = createFixtures(t) + subject = new(Subject) + ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(2).MaxTimes(2) + ctrl.Call(subject, "FooMethod", "argument") + ctrl.Call(subject, "FooMethod", "argument") + reporter.assertFatal(func() { + ctrl.Call(subject, "FooMethod", "argument") + }) + + // It succeeds if there is just the right number of calls + reporter, ctrl = createFixtures(t) + subject = new(Subject) + ctrl.RecordCall(subject, "FooMethod", "argument").MaxTimes(2).MinTimes(2) + ctrl.Call(subject, "FooMethod", "argument") + ctrl.Call(subject, "FooMethod", "argument") + ctrl.Finish() +} + +func TestDo(t *testing.T) { + _, ctrl := createFixtures(t) + subject := new(Subject) + + doCalled := false + var argument string + ctrl.RecordCall(subject, "FooMethod", "argument").Do( + func(arg string) { + doCalled = true + argument = arg + }) + if doCalled { + t.Error("Do() callback called too early.") + } + + ctrl.Call(subject, "FooMethod", "argument") + + if !doCalled { + t.Error("Do() callback not called.") + } + if "argument" != argument { + t.Error("Do callback received wrong argument.") + } + + ctrl.Finish() +} + +func TestDoAndReturn(t *testing.T) { + _, ctrl := createFixtures(t) + subject := new(Subject) + + doCalled := false + var argument string + ctrl.RecordCall(subject, "FooMethod", "argument").DoAndReturn( + func(arg string) int { + doCalled = true + argument = arg + return 5 + }) + if doCalled { + t.Error("Do() callback called too early.") + } + + rets := ctrl.Call(subject, "FooMethod", "argument") + + if !doCalled { + t.Error("Do() callback not called.") + } + if "argument" != argument { + t.Error("Do callback received wrong argument.") + } + if len(rets) != 1 { + t.Fatalf("Return values from Call: got %d, want 1", len(rets)) + } + if ret, ok := rets[0].(int); !ok { + t.Fatalf("Return value is not an int") + } else if ret != 5 { + t.Errorf("DoAndReturn return value: got %d, want 5", ret) + } + + ctrl.Finish() +} + +func TestSetArgSlice(t *testing.T) { + _, ctrl := createFixtures(t) + subject := new(Subject) + + var in = []byte{4, 5, 6} + var set = []byte{1, 2, 3} + ctrl.RecordCall(subject, "SetArgMethod", in, nil).SetArg(0, set) + ctrl.Call(subject, "SetArgMethod", in, nil) + + if !reflect.DeepEqual(in, set) { + t.Error("Expected SetArg() to modify input slice argument") + } + + ctrl.Finish() +} + +func TestSetArgPtr(t *testing.T) { + _, ctrl := createFixtures(t) + subject := new(Subject) + + var in int = 43 + const set = 42 + ctrl.RecordCall(subject, "SetArgMethod", nil, &in).SetArg(1, set) + ctrl.Call(subject, "SetArgMethod", nil, &in) + + if in != set { + t.Error("Expected SetArg() to modify value pointed to by argument") + } + + ctrl.Finish() +} + +func TestReturn(t *testing.T) { + _, ctrl := createFixtures(t) + subject := new(Subject) + + // Unspecified return should produce "zero" result. + ctrl.RecordCall(subject, "FooMethod", "zero") + ctrl.RecordCall(subject, "FooMethod", "five").Return(5) + + assertEqual( + t, + []interface{}{0}, + ctrl.Call(subject, "FooMethod", "zero")) + + assertEqual( + t, + []interface{}{5}, + ctrl.Call(subject, "FooMethod", "five")) + ctrl.Finish() +} + +func TestUnorderedCalls(t *testing.T) { + reporter, ctrl := createFixtures(t) + defer reporter.recoverUnexpectedFatal() + subjectTwo := new(Subject) + subjectOne := new(Subject) + + ctrl.RecordCall(subjectOne, "FooMethod", "1") + ctrl.RecordCall(subjectOne, "BarMethod", "2") + ctrl.RecordCall(subjectTwo, "FooMethod", "3") + ctrl.RecordCall(subjectTwo, "BarMethod", "4") + + // Make the calls in a different order, which should be fine. + ctrl.Call(subjectOne, "BarMethod", "2") + ctrl.Call(subjectTwo, "FooMethod", "3") + ctrl.Call(subjectTwo, "BarMethod", "4") + ctrl.Call(subjectOne, "FooMethod", "1") + + reporter.assertPass("After making all calls in different order") + + ctrl.Finish() + + reporter.assertPass("After finish") +} + +func commonTestOrderedCalls(t *testing.T) (reporter *ErrorReporter, ctrl *gomock.Controller, subjectOne, subjectTwo *Subject) { + reporter, ctrl = createFixtures(t) + + subjectOne = new(Subject) + subjectTwo = new(Subject) + + gomock.InOrder( + ctrl.RecordCall(subjectOne, "FooMethod", "1").AnyTimes(), + ctrl.RecordCall(subjectTwo, "FooMethod", "2"), + ctrl.RecordCall(subjectTwo, "BarMethod", "3"), + ) + + return +} + +func TestOrderedCallsCorrect(t *testing.T) { + reporter, ctrl, subjectOne, subjectTwo := commonTestOrderedCalls(t) + + ctrl.Call(subjectOne, "FooMethod", "1") + ctrl.Call(subjectTwo, "FooMethod", "2") + ctrl.Call(subjectTwo, "BarMethod", "3") + + ctrl.Finish() + + reporter.assertPass("After finish") +} + +func TestOrderedCallsInCorrect(t *testing.T) { + reporter, ctrl, subjectOne, subjectTwo := commonTestOrderedCalls(t) + + ctrl.Call(subjectOne, "FooMethod", "1") + reporter.assertFatal(func() { + // FooMethod(2) should be called before BarMethod(3) + ctrl.Call(subjectTwo, "BarMethod", "3") + }, "Unexpected call to", "Subject.BarMethod([3])", "doesn't have a prerequisite call satisfied") +} + +// Test that calls that are prerequisites to other calls but have maxCalls > +// minCalls are removed from the expected call set. +func TestOrderedCallsWithPreReqMaxUnbounded(t *testing.T) { + reporter, ctrl, subjectOne, subjectTwo := commonTestOrderedCalls(t) + + // Initially we should be able to call FooMethod("1") as many times as we + // want. + ctrl.Call(subjectOne, "FooMethod", "1") + ctrl.Call(subjectOne, "FooMethod", "1") + + // But calling something that has it as a prerequite should remove it from + // the expected call set. This allows tests to ensure that FooMethod("1") is + // *not* called after FooMethod("2"). + ctrl.Call(subjectTwo, "FooMethod", "2") + + // Therefore this call should fail: + reporter.assertFatal(func() { + ctrl.Call(subjectOne, "FooMethod", "1") + }) +} + +func TestCallAfterLoopPanic(t *testing.T) { + _, ctrl := createFixtures(t) + + subject := new(Subject) + + firstCall := ctrl.RecordCall(subject, "FooMethod", "1") + secondCall := ctrl.RecordCall(subject, "FooMethod", "2") + thirdCall := ctrl.RecordCall(subject, "FooMethod", "3") + + gomock.InOrder(firstCall, secondCall, thirdCall) + + defer func() { + err := recover() + if err == nil { + t.Error("Call.After creation of dependency loop did not panic.") + } + }() + + // This should panic due to dependency loop. + firstCall.After(thirdCall) +} + +func TestPanicOverridesExpectationChecks(t *testing.T) { + ctrl := gomock.NewController(t) + reporter := NewErrorReporter(t) + + reporter.assertFatal(func() { + ctrl.RecordCall(new(Subject), "FooMethod", "1") + defer ctrl.Finish() + reporter.Fatalf("Intentional panic") + }) +} + +func TestSetArgWithBadType(t *testing.T) { + rep, ctrl := createFixtures(t) + defer ctrl.Finish() + + s := new(Subject) + // This should catch a type error: + rep.assertFatal(func() { + ctrl.RecordCall(s, "FooMethod", "1").SetArg(0, "blah") + }) + ctrl.Call(s, "FooMethod", "1") +} + +func TestTimes0(t *testing.T) { + rep, ctrl := createFixtures(t) + defer ctrl.Finish() + + s := new(Subject) + ctrl.RecordCall(s, "FooMethod", "arg").Times(0) + rep.assertFatal(func() { + ctrl.Call(s, "FooMethod", "arg") + }) +} + +func TestVariadicMatching(t *testing.T) { + rep, ctrl := createFixtures(t) + defer rep.recoverUnexpectedFatal() + + s := new(Subject) + ctrl.RecordCall(s, "VariadicMethod", 0, "1", "2") + ctrl.Call(s, "VariadicMethod", 0, "1", "2") + ctrl.Finish() + rep.assertPass("variadic matching works") +} + +func TestVariadicNoMatch(t *testing.T) { + rep, ctrl := createFixtures(t) + defer rep.recoverUnexpectedFatal() + + s := new(Subject) + ctrl.RecordCall(s, "VariadicMethod", 0) + rep.assertFatal(func() { + ctrl.Call(s, "VariadicMethod", 1) + }, "Expected call at", "doesn't match the argument at index 0", + "Got: 1\nWant: is equal to 0") + ctrl.Call(s, "VariadicMethod", 0) + ctrl.Finish() +} + +func TestVariadicMatchingWithSlice(t *testing.T) { + testCases := [][]string{ + {"1"}, + {"1", "2"}, + } + for _, tc := range testCases { + t.Run(fmt.Sprintf("%d arguments", len(tc)), func(t *testing.T) { + rep, ctrl := createFixtures(t) + defer rep.recoverUnexpectedFatal() + + s := new(Subject) + ctrl.RecordCall(s, "VariadicMethod", 1, tc) + args := make([]interface{}, len(tc)+1) + args[0] = 1 + for i, arg := range tc { + args[i+1] = arg + } + ctrl.Call(s, "VariadicMethod", args...) + ctrl.Finish() + rep.assertPass("slices can be used as matchers for variadic arguments") + }) + } +} + +func TestDuplicateFinishCallFails(t *testing.T) { + rep, ctrl := createFixtures(t) + + ctrl.Finish() + rep.assertPass("the first Finish call should succeed") + + rep.assertFatal(ctrl.Finish, "Controller.Finish was called more than once. It has to be called exactly once.") +} + +func TestNoHelper(t *testing.T) { + ctrlNoHelper := gomock.NewController(NewErrorReporter(t)) + + // doesn't panic + ctrlNoHelper.T.Helper() +} + +func TestWithHelper(t *testing.T) { + withHelper := &HelperReporter{TestReporter: NewErrorReporter(t)} + ctrlWithHelper := gomock.NewController(withHelper) + + ctrlWithHelper.T.Helper() + + if withHelper.helper == 0 { + t.Fatal("expected Helper to be invoked") + } +} diff --git a/vendor/github.com/golang/mock/gomock/internal/mock_gomock/mock_matcher.go b/vendor/github.com/golang/mock/gomock/internal/mock_gomock/mock_matcher.go new file mode 100644 index 0000000..5462f4d --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/internal/mock_gomock/mock_matcher.go @@ -0,0 +1,61 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/golang/mock/gomock (interfaces: Matcher) + +// Package mock_gomock is a generated GoMock package. +package mock_gomock + +import ( + gomock "github.com/golang/mock/gomock" + reflect "reflect" +) + +// MockMatcher is a mock of Matcher interface +type MockMatcher struct { + ctrl *gomock.Controller + recorder *MockMatcherMockRecorder +} + +// MockMatcherMockRecorder is the mock recorder for MockMatcher +type MockMatcherMockRecorder struct { + mock *MockMatcher +} + +// NewMockMatcher creates a new mock instance +func NewMockMatcher(ctrl *gomock.Controller) *MockMatcher { + mock := &MockMatcher{ctrl: ctrl} + mock.recorder = &MockMatcherMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockMatcher) EXPECT() *MockMatcherMockRecorder { + return m.recorder +} + +// Matches mocks base method +func (m *MockMatcher) Matches(arg0 interface{}) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Matches", arg0) + ret0, _ := ret[0].(bool) + return ret0 +} + +// Matches indicates an expected call of Matches +func (mr *MockMatcherMockRecorder) Matches(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Matches", reflect.TypeOf((*MockMatcher)(nil).Matches), arg0) +} + +// String mocks base method +func (m *MockMatcher) String() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "String") + ret0, _ := ret[0].(string) + return ret0 +} + +// String indicates an expected call of String +func (mr *MockMatcherMockRecorder) String() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "String", reflect.TypeOf((*MockMatcher)(nil).String)) +} diff --git a/vendor/github.com/golang/mock/gomock/matchers.go b/vendor/github.com/golang/mock/gomock/matchers.go new file mode 100644 index 0000000..fbff060 --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/matchers.go @@ -0,0 +1,141 @@ +// Copyright 2010 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gomock + +import ( + "fmt" + "reflect" +) + +// A Matcher is a representation of a class of values. +// It is used to represent the valid or expected arguments to a mocked method. +type Matcher interface { + // Matches returns whether x is a match. + Matches(x interface{}) bool + + // String describes what the matcher matches. + String() string +} + +type anyMatcher struct{} + +func (anyMatcher) Matches(x interface{}) bool { + return true +} + +func (anyMatcher) String() string { + return "is anything" +} + +type eqMatcher struct { + x interface{} +} + +func (e eqMatcher) Matches(x interface{}) bool { + return reflect.DeepEqual(e.x, x) +} + +func (e eqMatcher) String() string { + return fmt.Sprintf("is equal to %v", e.x) +} + +type nilMatcher struct{} + +func (nilMatcher) Matches(x interface{}) bool { + if x == nil { + return true + } + + v := reflect.ValueOf(x) + switch v.Kind() { + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, + reflect.Ptr, reflect.Slice: + return v.IsNil() + } + + return false +} + +func (nilMatcher) String() string { + return "is nil" +} + +type notMatcher struct { + m Matcher +} + +func (n notMatcher) Matches(x interface{}) bool { + return !n.m.Matches(x) +} + +func (n notMatcher) String() string { + // TODO: Improve this if we add a NotString method to the Matcher interface. + return "not(" + n.m.String() + ")" +} + +type assignableToTypeOfMatcher struct { + targetType reflect.Type +} + +func (m assignableToTypeOfMatcher) Matches(x interface{}) bool { + return reflect.TypeOf(x).AssignableTo(m.targetType) +} + +func (m assignableToTypeOfMatcher) String() string { + return "is assignable to " + m.targetType.Name() +} + +// Constructors +// Any returns a matcher that always matches. +func Any() Matcher { return anyMatcher{} } + +// Eq returns a matcher that matches on equality. +// +// Example usage: +// Eq(5).Matches(5) // returns true +// Eq(5).Matches(4) // returns false +func Eq(x interface{}) Matcher { return eqMatcher{x} } + +// Nil returns a matcher that matches if the received value is nil. +// +// Example usage: +// var x *bytes.Buffer +// Nil().Matches(x) // returns true +// x = &bytes.Buffer{} +// Nil().Matches(x) // returns false +func Nil() Matcher { return nilMatcher{} } + +// Not reverses the results of its given child matcher. +// +// Example usage: +// Not(Eq(5)).Matches(4) // returns true +// Not(Eq(5)).Matches(5) // returns false +func Not(x interface{}) Matcher { + if m, ok := x.(Matcher); ok { + return notMatcher{m} + } + return notMatcher{Eq(x)} +} + +// AssignableToTypeOf is a Matcher that matches if the parameter to the mock +// function is assignable to the type of the parameter to this function. +// +// Example usage: +// var s fmt.Stringer = &bytes.Buffer{} +// AssignableToTypeOf(s).Matches(time.Second) // returns true +// AssignableToTypeOf(s).Matches(99) // returns false +func AssignableToTypeOf(x interface{}) Matcher { + return assignableToTypeOfMatcher{reflect.TypeOf(x)} +} diff --git a/vendor/github.com/golang/mock/gomock/matchers_test.go b/vendor/github.com/golang/mock/gomock/matchers_test.go new file mode 100644 index 0000000..8bb87f7 --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/matchers_test.go @@ -0,0 +1,119 @@ +// Copyright 2010 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:generate mockgen -destination internal/mock_gomock/mock_matcher.go github.com/golang/mock/gomock Matcher + +package gomock_test + +import ( + "errors" + "testing" + + "github.com/golang/mock/gomock" + "github.com/golang/mock/gomock/internal/mock_gomock" +) + +func TestMatchers(t *testing.T) { + type e interface{} + type testCase struct { + matcher gomock.Matcher + yes, no []e + } + tests := []testCase{ + {gomock.Any(), []e{3, nil, "foo"}, nil}, + {gomock.Eq(4), []e{4}, []e{3, "blah", nil, int64(4)}}, + {gomock.Nil(), + []e{nil, (error)(nil), (chan bool)(nil), (*int)(nil)}, + []e{"", 0, make(chan bool), errors.New("err"), new(int)}}, + {gomock.Not(gomock.Eq(4)), []e{3, "blah", nil, int64(4)}, []e{4}}, + } + for i, test := range tests { + for _, x := range test.yes { + if !test.matcher.Matches(x) { + t.Errorf(`test %d: "%v %s" should be true.`, i, x, test.matcher) + } + } + for _, x := range test.no { + if test.matcher.Matches(x) { + t.Errorf(`test %d: "%v %s" should be false.`, i, x, test.matcher) + } + } + } +} + +// A more thorough test of notMatcher +func TestNotMatcher(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockMatcher := mock_gomock.NewMockMatcher(ctrl) + notMatcher := gomock.Not(mockMatcher) + + mockMatcher.EXPECT().Matches(4).Return(true) + if match := notMatcher.Matches(4); match { + t.Errorf("notMatcher should not match 4") + } + + mockMatcher.EXPECT().Matches(5).Return(false) + if match := notMatcher.Matches(5); !match { + t.Errorf("notMatcher should match 5") + } +} + +type Dog struct { + Breed, Name string +} + +// A thorough test of assignableToTypeOfMatcher +func TestAssignableToTypeOfMatcher(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + aStr := "def" + anotherStr := "ghi" + + if match := gomock.AssignableToTypeOf("abc").Matches(4); match { + t.Errorf(`AssignableToTypeOf("abc") should not match 4`) + } + if match := gomock.AssignableToTypeOf("abc").Matches(&aStr); match { + t.Errorf(`AssignableToTypeOf("abc") should not match &aStr (*string)`) + } + if match := gomock.AssignableToTypeOf("abc").Matches("def"); !match { + t.Errorf(`AssignableToTypeOf("abc") should match "def"`) + } + if match := gomock.AssignableToTypeOf(&aStr).Matches("abc"); match { + t.Errorf(`AssignableToTypeOf(&aStr) should not match "abc"`) + } + if match := gomock.AssignableToTypeOf(&aStr).Matches(&anotherStr); !match { + t.Errorf(`AssignableToTypeOf(&aStr) should match &anotherStr`) + } + if match := gomock.AssignableToTypeOf(0).Matches(4); !match { + t.Errorf(`AssignableToTypeOf(0) should match 4`) + } + if match := gomock.AssignableToTypeOf(0).Matches("def"); match { + t.Errorf(`AssignableToTypeOf(0) should not match "def"`) + } + if match := gomock.AssignableToTypeOf(Dog{}).Matches(&Dog{}); match { + t.Errorf(`AssignableToTypeOf(Dog{}) should not match &Dog{}`) + } + if match := gomock.AssignableToTypeOf(Dog{}).Matches(Dog{Breed: "pug", Name: "Fido"}); !match { + t.Errorf(`AssignableToTypeOf(Dog{}) should match Dog{Breed: "pug", Name: "Fido"}`) + } + if match := gomock.AssignableToTypeOf(&Dog{}).Matches(Dog{}); match { + t.Errorf(`AssignableToTypeOf(&Dog{}) should not match Dog{}`) + } + if match := gomock.AssignableToTypeOf(&Dog{}).Matches(&Dog{Breed: "pug", Name: "Fido"}); !match { + t.Errorf(`AssignableToTypeOf(&Dog{}) should match &Dog{Breed: "pug", Name: "Fido"}`) + } +} diff --git a/vendor/github.com/neo4j-drivers/gobolt/LICENSE b/vendor/github.com/neo4j-drivers/gobolt/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/neo4j-drivers/gobolt/README.md b/vendor/github.com/neo4j-drivers/gobolt/README.md new file mode 100644 index 0000000..cd7c6c9 --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/README.md @@ -0,0 +1,3 @@ +# neo4j-go-connector + +This package is an internal dependency being used by [Neo4j Go Driver](https://github.com/neo4j/neo4j-go-driver). \ No newline at end of file diff --git a/vendor/github.com/neo4j-drivers/gobolt/config.go b/vendor/github.com/neo4j-drivers/gobolt/config.go new file mode 100644 index 0000000..76651f1 --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/config.go @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gobolt + +/* +#include + +#include "bolt/bolt.h" +*/ +import "C" +import ( + "bytes" + "crypto/x509" + "encoding/pem" + "net/url" + "time" + "unsafe" +) + +// Config holds the available configurations options applicable to the connector +type Config struct { + Encryption bool + TLSCertificates []*x509.Certificate + TLSSkipVerify bool + TLSSkipVerifyHostname bool + MaxPoolSize int + MaxConnLifetime time.Duration + ConnAcquisitionTimeout time.Duration + SockConnectTimeout time.Duration + SockKeepalive bool + ConnectorErrorFactory func(state, code int, codeText, context, description string) ConnectorError + DatabaseErrorFactory func(classification, code, message string) DatabaseError + GenericErrorFactory func(format string, args ...interface{}) GenericError + Log Logging + AddressResolver URLAddressResolver + ValueHandlers []ValueHandler +} + +func pemEncodeCerts(certs []*x509.Certificate) (*bytes.Buffer, error) { + if len(certs) == 0 { + return nil, nil + } + + var buf = &bytes.Buffer{} + for _, cert := range certs { + if err := pem.Encode(buf, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}); err != nil { + return nil, err + } + } + return buf, nil +} + +func createConfig(key int, uri *url.URL, config *Config, valueSystem *boltValueSystem) (*C.struct_BoltConfig, error) { + var err error + var cTrust *C.struct_BoltTrust + var cSocketOpts *C.struct_BoltSocketOptions + var cRoutingContext *C.struct_BoltValue + var cUserAgent *C.char + var cConfig *C.struct_BoltConfig + + if cTrust, err = createTrust(config); err != nil { + return nil, valueSystem.genericErrorFactory("unable to create trust settings: %v", err) + } + defer C.BoltTrust_destroy(cTrust) + + if cRoutingContext, err = createRoutingContext(uri, valueSystem); err != nil { + return nil, valueSystem.genericErrorFactory("unable to extract routing context: %v", err) + } + defer C.BoltValue_destroy(cRoutingContext) + + cSocketOpts = createSocketOptions(config) + defer C.BoltSocketOptions_destroy(cSocketOpts) + + cUserAgent = C.CString("Go Driver/1.7") + defer C.free(unsafe.Pointer(cUserAgent)) + + var cLogger = registerLogging(key, config.Log) + defer C.BoltLog_destroy(cLogger) + + var cResolver = registerResolver(key, config.AddressResolver) + defer C.BoltAddressResolver_destroy(cResolver) + + cConfig = C.BoltConfig_create() + C.BoltConfig_set_scheme(cConfig, scheme(uri)) + C.BoltConfig_set_transport(cConfig, transport(config)) + C.BoltConfig_set_trust(cConfig, cTrust) + C.BoltConfig_set_user_agent(cConfig, cUserAgent) + C.BoltConfig_set_routing_context(cConfig, cRoutingContext) + C.BoltConfig_set_address_resolver(cConfig, cResolver) + C.BoltConfig_set_log(cConfig, cLogger) + C.BoltConfig_set_max_pool_size(cConfig, C.int32_t(config.MaxPoolSize)) + C.BoltConfig_set_max_connection_life_time(cConfig, C.int32_t(config.MaxConnLifetime/time.Millisecond)) + C.BoltConfig_set_max_connection_acquisition_time(cConfig, C.int32_t(config.ConnAcquisitionTimeout/time.Millisecond)) + C.BoltConfig_set_socket_options(cConfig, cSocketOpts) + return cConfig, nil +} + +func scheme(uri *url.URL) C.BoltScheme { + var mode C.BoltScheme = C.BOLT_SCHEME_DIRECT + if uri.Scheme == "bolt+routing" { + mode = C.BOLT_SCHEME_ROUTING + } + if uri.Scheme == "neo4j" { + mode = C.BOLT_SCHEME_NEO4J + } + + return mode +} + +func transport(config *Config) C.BoltTransport { + var transport C.BoltTransport = C.BOLT_TRANSPORT_PLAINTEXT + if config.Encryption { + transport = C.BOLT_TRANSPORT_ENCRYPTED + } + return transport +} + +func createSocketOptions(config *Config) *C.struct_BoltSocketOptions { + var cSocketOpts = C.BoltSocketOptions_create() + + C.BoltSocketOptions_set_connect_timeout(cSocketOpts, C.int32_t(config.SockConnectTimeout/time.Millisecond)) + C.BoltSocketOptions_set_keep_alive(cSocketOpts, 1) + if !config.SockKeepalive { + C.BoltSocketOptions_set_keep_alive(cSocketOpts, 0) + } + + return cSocketOpts +} + +func createTrust(config *Config) (*C.struct_BoltTrust, error) { + var cTrust = C.BoltTrust_create() + C.BoltTrust_set_certs(cTrust, nil, 0) + C.BoltTrust_set_skip_verify(cTrust, 0) + C.BoltTrust_set_skip_verify_hostname(cTrust, 0) + + certsBuf, err := pemEncodeCerts(config.TLSCertificates) + if err != nil { + C.BoltTrust_destroy(cTrust) + + return nil, err + } + + if certsBuf != nil { + certsBytes := certsBuf.String() + C.BoltTrust_set_certs(cTrust, C.CString(certsBytes), C.uint64_t(certsBuf.Len())) + } + + if config.TLSSkipVerify { + C.BoltTrust_set_skip_verify(cTrust, 1) + } + + if config.TLSSkipVerifyHostname { + C.BoltTrust_set_skip_verify_hostname(cTrust, 1) + } + + return cTrust, nil +} + +func createRoutingContext(source *url.URL, valueSystem *boltValueSystem) (*C.struct_BoltValue, error) { + var err error + var values url.Values + var result map[string]string + + if values, err = url.ParseQuery(source.RawQuery); err != nil { + return nil, valueSystem.genericErrorFactory("unable to parse routing context '%s'", source.RawQuery) + } + + if len(values) == 0 { + return nil, nil + } + + result = make(map[string]string, len(values)) + for key, value := range values { + if len(value) > 1 { + return nil, valueSystem.genericErrorFactory("duplicate value specified for '%s' as routing context", key) + } + + result[key] = value[0] + } + + return valueSystem.valueToConnector(result) +} diff --git a/vendor/github.com/neo4j-drivers/gobolt/connection.go b/vendor/github.com/neo4j-drivers/gobolt/connection.go new file mode 100644 index 0000000..0304441 --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/connection.go @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gobolt + +import ( + "time" +) + +// RequestHandle identifies an individual request sent to server +type RequestHandle int64 + +// FetchType identifies the type of the result fetched via Fetch() call +type FetchType int + +const ( + // FetchTypeRecord tells that fetched data is record + FetchTypeRecord FetchType = 1 + // FetchTypeMetadata tells that fetched data is metadata + FetchTypeMetadata FetchType = 0 + // FetchTypeError tells that fetch was not successful + FetchTypeError FetchType = -1 +) + +// Connection represents an active seabolt connection +type Connection interface { + Id() (string, error) + RemoteAddress() (string, error) + Server() (string, error) + + Begin(bookmarks []string, txTimeout time.Duration, txMetadata map[string]interface{}) (RequestHandle, error) + Commit() (RequestHandle, error) + Rollback() (RequestHandle, error) + Run(cypher string, parameters map[string]interface{}, bookmarks []string, txTimeout time.Duration, txMetadata map[string]interface{}) (RequestHandle, error) + PullAll() (RequestHandle, error) + DiscardAll() (RequestHandle, error) + Reset() (RequestHandle, error) + Flush() error + Fetch(request RequestHandle) (FetchType, error) // return type ? + FetchSummary(request RequestHandle) (int, error) // return type ? + + LastBookmark() (string, error) + Fields() ([]string, error) + Metadata() (map[string]interface{}, error) + Data() ([]interface{}, error) + + Close() error +} diff --git a/vendor/github.com/neo4j-drivers/gobolt/connection_mock_test.go b/vendor/github.com/neo4j-drivers/gobolt/connection_mock_test.go new file mode 100644 index 0000000..73b6e18 --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/connection_mock_test.go @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gobolt + +import ( + "time" + + "github.com/stretchr/testify/mock" +) + +type mockConnection struct { + mock.Mock +} + +func (m *mockConnection) Id() (string, error) { + args := m.Called() + return args.String(0), args.Error(1) +} + +func (m *mockConnection) RemoteAddress() (string, error) { + args := m.Called() + return args.String(0), args.Error(1) +} + +func (m *mockConnection) Server() (string, error) { + args := m.Called() + return args.String(0), args.Error(1) +} + +func (m *mockConnection) Begin(bookmarks []string, txTimeout time.Duration, txMetadata map[string]interface{}) (RequestHandle, error) { + args := m.Called(bookmarks, txTimeout, txMetadata) + return args.Get(0).(RequestHandle), args.Error(1) +} + +func (m *mockConnection) Commit() (RequestHandle, error) { + args := m.Called() + return args.Get(0).(RequestHandle), args.Error(1) +} + +func (m *mockConnection) Rollback() (RequestHandle, error) { + args := m.Called() + return args.Get(0).(RequestHandle), args.Error(1) +} + +func (m *mockConnection) Run(cypher string, parameters map[string]interface{}, bookmarks []string, txTimeout time.Duration, txMetadata map[string]interface{}) (RequestHandle, error) { + args := m.Called(cypher, parameters, bookmarks, txTimeout, txMetadata) + return args.Get(0).(RequestHandle), args.Error(1) +} + +func (m *mockConnection) PullAll() (RequestHandle, error) { + args := m.Called() + return args.Get(0).(RequestHandle), args.Error(1) +} + +func (m *mockConnection) DiscardAll() (RequestHandle, error) { + args := m.Called() + return args.Get(0).(RequestHandle), args.Error(1) +} + +func (m *mockConnection) Reset() (RequestHandle, error) { + args := m.Called() + return args.Get(0).(RequestHandle), args.Error(1) +} + +func (m *mockConnection) Flush() error { + args := m.Called() + return args.Error(0) +} + +func (m *mockConnection) Fetch(request RequestHandle) (FetchType, error) { + args := m.Called(request) + return args.Get(0).(FetchType), args.Error(1) +} + +func (m *mockConnection) FetchSummary(request RequestHandle) (int, error) { + args := m.Called(request) + return args.Int(0), args.Error(1) +} + +func (m *mockConnection) LastBookmark() (string, error) { + args := m.Called() + return args.String(0), args.Error(1) +} + +func (m *mockConnection) Fields() ([]string, error) { + args := m.Called() + return args.Get(0).([]string), args.Error(1) +} + +func (m *mockConnection) Metadata() (map[string]interface{}, error) { + args := m.Called() + return args.Get(0).(map[string]interface{}), args.Error(1) +} + +func (m *mockConnection) Data() ([]interface{}, error) { + args := m.Called() + return args.Get(0).([]interface{}), args.Error(1) +} + +func (m *mockConnection) Close() error { + args := m.Called() + return args.Error(0) +} diff --git a/vendor/github.com/neo4j-drivers/gobolt/connection_seabolt.go b/vendor/github.com/neo4j-drivers/gobolt/connection_seabolt.go new file mode 100644 index 0000000..63edb87 --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/connection_seabolt.go @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gobolt + +/* +#include + +#include "bolt/bolt.h" +*/ +import "C" +import ( + "fmt" + "time" + "unsafe" +) + +type seaboltConnection struct { + connector *seaboltConnector + cInstance *C.struct_BoltConnection + valueSystem *boltValueSystem +} + +var newSeaboltConnection = func(connector *seaboltConnector, mode AccessMode) (*seaboltConnection, error) { + var cMode uint32 = C.BOLT_ACCESS_MODE_WRITE + if mode == AccessModeRead { + cMode = C.BOLT_ACCESS_MODE_READ + } + + cStatus := C.BoltStatus_create() + defer C.BoltStatus_destroy(cStatus) + cConnection := C.BoltConnector_acquire(connector.cInstance, C.BoltAccessMode(cMode), cStatus) + if cConnection == nil { + state := C.BoltStatus_get_state(cStatus) + code := C.BoltStatus_get_error(cStatus) + codeText := C.GoString(C.BoltError_get_string(code)) + context := C.GoString(C.BoltStatus_get_error_context(cStatus)) + + return nil, newConnectorError(int(state), int(code), codeText, context, "unable to acquire connection from connector") + } + + return &seaboltConnection{connector: connector, cInstance: cConnection, valueSystem: connector.valueSystem}, nil +} + +func (connection *seaboltConnection) Id() (string, error) { + return C.GoString(C.BoltConnection_id(connection.cInstance)), nil +} + +func (connection *seaboltConnection) RemoteAddress() (string, error) { + connectedAddress := C.BoltConnection_remote_endpoint(connection.cInstance) + if connectedAddress == nil { + return "UNKNOWN", nil + } + + return fmt.Sprintf("%s:%s", C.GoString(C.BoltAddress_host(connectedAddress)), C.GoString(C.BoltAddress_port(connectedAddress))), nil +} + +func (connection *seaboltConnection) Server() (string, error) { + server := C.BoltConnection_server(connection.cInstance) + if server == nil { + return "UNKNOWN", nil + } + + return C.GoString(server), nil +} + +func (connection *seaboltConnection) Begin(bookmarks []string, txTimeout time.Duration, txMetadata map[string]interface{}) (RequestHandle, error) { + var res C.int32_t + + res = C.BoltConnection_clear_begin(connection.cInstance) + if res != C.BOLT_SUCCESS { + return -1, newError(connection, "unable to clear begin message") + } + + if len(bookmarks) > 0 { + bookmarksValue, err := connection.valueSystem.valueToConnector(bookmarks) + if err != nil { + return -1, connection.valueSystem.genericErrorFactory("unable to convert bookmarks to connector value for begin message: %v", err) + } + res := C.BoltConnection_set_begin_bookmarks(connection.cInstance, bookmarksValue) + C.BoltValue_destroy(bookmarksValue) + if res != C.BOLT_SUCCESS { + return -1, newError(connection, "unable to set bookmarks for begin message") + } + } + + if txTimeout > 0 { + timeOut := C.int64_t(txTimeout / time.Millisecond) + res := C.BoltConnection_set_begin_tx_timeout(connection.cInstance, timeOut) + if res != C.BOLT_SUCCESS { + return -1, newError(connection, "unable to set tx timeout for begin message") + } + } + + if len(txMetadata) > 0 { + metadataValue, err := connection.valueSystem.valueToConnector(txMetadata) + if err != nil { + return -1, connection.valueSystem.genericErrorFactory("unable to convert tx metadata to connector value for begin message: %v", err) + } + res := C.BoltConnection_set_begin_tx_metadata(connection.cInstance, metadataValue) + C.BoltValue_destroy(metadataValue) + if res != C.BOLT_SUCCESS { + return -1, newError(connection, "unable to set tx metadata for begin message") + } + } + + res = C.BoltConnection_load_begin_request(connection.cInstance) + if res != C.BOLT_SUCCESS { + return -1, newError(connection, "unable to generate begin message") + } + + return RequestHandle(C.BoltConnection_last_request(connection.cInstance)), nil +} + +func (connection *seaboltConnection) Commit() (RequestHandle, error) { + res := C.BoltConnection_load_commit_request(connection.cInstance) + if res != C.BOLT_SUCCESS { + return -1, newError(connection, "unable to generate commit message") + } + + return RequestHandle(C.BoltConnection_last_request(connection.cInstance)), nil +} + +func (connection *seaboltConnection) Rollback() (RequestHandle, error) { + res := C.BoltConnection_load_rollback_request(connection.cInstance) + if res != C.BOLT_SUCCESS { + return -1, newError(connection, "unable to generate rollback message") + } + + return RequestHandle(C.BoltConnection_last_request(connection.cInstance)), nil +} + +func (connection *seaboltConnection) Run(cypher string, params map[string]interface{}, bookmarks []string, txTimeout time.Duration, txMetadata map[string]interface{}) (RequestHandle, error) { + var res C.int32_t + + res = C.BoltConnection_clear_run(connection.cInstance) + if res != C.BOLT_SUCCESS { + return -1, newError(connection, "unable to clear run message") + } + + cypherStr := C.CString(cypher) + res = C.BoltConnection_set_run_cypher(connection.cInstance, cypherStr, C.uint64_t(len(cypher)), C.int32_t(len(params))) + C.free(unsafe.Pointer(cypherStr)) + if res != C.BOLT_SUCCESS { + return -1, newError(connection, "unable to set cypher statement") + } + + var index C.int32_t + for paramName, paramValue := range params { + paramNameLen := C.uint64_t(len(paramName)) + paramNameStr := C.CString(paramName) + + boltValue := C.BoltConnection_set_run_cypher_parameter(connection.cInstance, index, paramNameStr, paramNameLen) + C.free(unsafe.Pointer(paramNameStr)) + if boltValue == nil { + return -1, newError(connection, "unable to retrieve reference to cypher statement parameter value") + } + + if err := connection.valueSystem.valueAsConnector(boltValue, paramValue); err != nil { + return -1, connection.valueSystem.genericErrorFactory("unable to convert parameter %q to connector value for run message: %v", paramName, err) + } + + index++ + } + + if len(bookmarks) > 0 { + bookmarksValue, err := connection.valueSystem.valueToConnector(bookmarks) + if err != nil { + return -1, connection.valueSystem.genericErrorFactory("unable to convert bookmarks to connector value for run message: %v", err) + } + res := C.BoltConnection_set_run_bookmarks(connection.cInstance, bookmarksValue) + C.BoltValue_destroy(bookmarksValue) + if res != C.BOLT_SUCCESS { + return -1, newError(connection, "unable to set bookmarks for run message") + } + } + + if txTimeout > 0 { + timeOut := C.int64_t(txTimeout / time.Millisecond) + res := C.BoltConnection_set_run_tx_timeout(connection.cInstance, timeOut) + if res != C.BOLT_SUCCESS { + return -1, newError(connection, "unable to set tx timeout for run message") + } + } + + if len(txMetadata) > 0 { + metadataValue, err := connection.valueSystem.valueToConnector(txMetadata) + if err != nil { + return -1, connection.valueSystem.genericErrorFactory("unable to convert tx metadata to connector value for run message: %v", err) + } + res := C.BoltConnection_set_run_tx_metadata(connection.cInstance, metadataValue) + C.BoltValue_destroy(metadataValue) + if res != C.BOLT_SUCCESS { + return -1, newError(connection, "unable to set tx metadata for run message") + } + } + + res = C.BoltConnection_load_run_request(connection.cInstance) + if res != C.BOLT_SUCCESS { + return -1, newError(connection, "unable to generate run message") + } + + return RequestHandle(C.BoltConnection_last_request(connection.cInstance)), nil +} + +func (connection *seaboltConnection) PullAll() (RequestHandle, error) { + res := C.BoltConnection_load_pull_request(connection.cInstance, -1) + if res != C.BOLT_SUCCESS { + return -1, newError(connection, "unable to generate pullall message") + } + return RequestHandle(C.BoltConnection_last_request(connection.cInstance)), nil +} + +func (connection *seaboltConnection) DiscardAll() (RequestHandle, error) { + res := C.BoltConnection_load_discard_request(connection.cInstance, -1) + if res != C.BOLT_SUCCESS { + return -1, newError(connection, "unable to generate discardall message") + } + return RequestHandle(C.BoltConnection_last_request(connection.cInstance)), nil +} + +func (connection *seaboltConnection) assertReadyState() error { + cStatus := C.BoltConnection_status(connection.cInstance) + + if C.BoltStatus_get_state(cStatus) != C.BOLT_CONNECTION_STATE_READY { + return newError(connection, "unexpected connection state") + } + + return nil +} + +func (connection *seaboltConnection) Flush() error { + res := C.BoltConnection_send(connection.cInstance) + if res < 0 { + return newError(connection, "unable to flush") + } + + return connection.assertReadyState() +} + +func (connection *seaboltConnection) Fetch(request RequestHandle) (FetchType, error) { + res := C.BoltConnection_fetch(connection.cInstance, C.BoltRequest(request)) + + if err := connection.assertReadyState(); err != nil { + return FetchTypeError, err + } + + return FetchType(res), nil +} + +func (connection *seaboltConnection) FetchSummary(request RequestHandle) (int, error) { + res := C.BoltConnection_fetch_summary(connection.cInstance, C.BoltRequest(request)) + if res < 0 { + return -1, newError(connection, "unable to fetch summary") + } + + err := connection.assertReadyState() + if err != nil { + return -1, err + } + + return int(res), nil +} + +func (connection *seaboltConnection) LastBookmark() (string, error) { + bookmark := C.BoltConnection_last_bookmark(connection.cInstance) + if bookmark != nil { + return C.GoString(bookmark), nil + } + + return "", nil +} + +func (connection *seaboltConnection) Fields() ([]string, error) { + fields, err := connection.valueSystem.valueAsGo(C.BoltConnection_field_names(connection.cInstance)) + if err != nil { + return nil, err + } + + if fields != nil { + fieldsAsList := fields.([]interface{}) + fieldsAsStr := make([]string, len(fieldsAsList)) + for i := range fieldsAsList { + fieldsAsStr[i] = fieldsAsList[i].(string) + } + return fieldsAsStr, nil + } + + return nil, connection.valueSystem.genericErrorFactory("field names not available") +} + +func (connection *seaboltConnection) Metadata() (map[string]interface{}, error) { + metadata, err := connection.valueSystem.valueAsGo(C.BoltConnection_metadata(connection.cInstance)) + if err != nil { + return nil, err + } + + if metadataAsGenericMap, ok := metadata.(map[string]interface{}); ok { + return metadataAsGenericMap, nil + } + + return nil, connection.valueSystem.genericErrorFactory("metadata is not of expected type") +} + +func (connection *seaboltConnection) Data() ([]interface{}, error) { + fields, err := connection.valueSystem.valueAsGo(C.BoltConnection_field_values(connection.cInstance)) + if err != nil { + return nil, err + } + + return fields.([]interface{}), nil +} + +func (connection *seaboltConnection) Reset() (RequestHandle, error) { + res := C.BoltConnection_load_reset_request(connection.cInstance) + if res != C.BOLT_SUCCESS { + return -1, newError(connection, "unable to generate reset message") + } + return RequestHandle(C.BoltConnection_last_request(connection.cInstance)), nil +} + +func (connection *seaboltConnection) Close() error { + C.BoltConnector_release(connection.connector.cInstance, connection.cInstance) + return nil +} diff --git a/vendor/github.com/neo4j-drivers/gobolt/connection_worker.go b/vendor/github.com/neo4j-drivers/gobolt/connection_worker.go new file mode 100644 index 0000000..80f4727 --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/connection_worker.go @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gobolt + +import ( + "sync/atomic" + "time" +) + +type job func() + +type workerConnection struct { + connector *workerConnector + pool *workerPool + delegate Connection + active int32 +} + +var newWorkerConnection = func(connector *workerConnector, mode AccessMode) (*workerConnection, error) { + var err error + var startTime time.Time + var delegate *seaboltConnection + var connection *workerConnection + + connection = &workerConnection{ + connector: connector, + pool: connector.pool, + delegate: nil, + active: 0, + } + + for connection.delegate == nil { + if startTime.IsZero() { + startTime = time.Now() + } else if time.Since(startTime) > connector.config.ConnAcquisitionTimeout { + return nil, newConnectionAcquisitionTimedOutError(connector.delegate.valueSystem) + } + + if poolError := connection.queueJob(func() { + delegate, err = newSeaboltConnection(connector.delegate, mode) + }); poolError != nil { + err = poolError + } + + if err != nil { + if isPoolFullError(err) && connector.config.ConnAcquisitionTimeout > 0 { + if waitClosed(connection, connector.config.ConnAcquisitionTimeout-time.Since(startTime)) { + continue + } else { + return nil, newConnectionAcquisitionTimedOutError(connector.delegate.valueSystem) + } + } + + return nil, err + } + + connection.delegate = delegate + } + + return connection, nil +} + +var waitClosed = func(w *workerConnection, timeout time.Duration) bool { + if w.connector != nil { + select { + case <-w.connector.closeSignal: + return true + case <-time.After(timeout): + } + } + + return false +} + +var signalClosed = func(w *workerConnection) { + if w.connector != nil { + select { + case w.connector.closeSignal <- signal{}: + default: + } + } +} + +func (w *workerConnection) queueJob(item job) error { + if atomic.CompareAndSwapInt32(&w.active, 0, 1) { + defer atomic.StoreInt32(&w.active, 0) + + var done = make(chan bool, 1) + defer close(done) + + if err := w.pool.submit(func(stopper <-chan signal) { + item() + done <- true + }); err != nil { + return err + } + + <-done + + return nil + } + + return newGenericError("a connection is not thread-safe and thus should not be used concurrently") +} + +func (w *workerConnection) Id() (string, error) { + var id string + var err error + + if otherErr := w.queueJob(func() { + id, err = w.delegate.Id() + }); otherErr != nil { + err = otherErr + } + + return id, err +} + +func (w *workerConnection) RemoteAddress() (string, error) { + var remoteAddress string + var err error + + if otherErr := w.queueJob(func() { + remoteAddress, err = w.delegate.RemoteAddress() + }); otherErr != nil { + err = otherErr + } + + return remoteAddress, err +} + +func (w *workerConnection) Server() (string, error) { + var server string + var err error + + if otherErr := w.queueJob(func() { + server, err = w.delegate.Server() + }); otherErr != nil { + err = otherErr + } + + return server, err +} + +func (w *workerConnection) Begin(bookmarks []string, txTimeout time.Duration, txMetadata map[string]interface{}) (RequestHandle, error) { + var handle RequestHandle + var err error + + if otherErr := w.queueJob(func() { + handle, err = w.delegate.Begin(bookmarks, txTimeout, txMetadata) + }); otherErr != nil { + err = otherErr + } + + return handle, err +} + +func (w *workerConnection) Commit() (RequestHandle, error) { + var handle RequestHandle + var err error + + if otherErr := w.queueJob(func() { + handle, err = w.delegate.Commit() + }); otherErr != nil { + err = otherErr + } + + return handle, err +} + +func (w *workerConnection) Rollback() (RequestHandle, error) { + var handle RequestHandle + var err error + + if otherErr := w.queueJob(func() { + handle, err = w.delegate.Rollback() + }); otherErr != nil { + err = otherErr + } + + return handle, err +} + +func (w *workerConnection) Run(cypher string, args map[string]interface{}, bookmarks []string, txTimeout time.Duration, txMetadata map[string]interface{}) (RequestHandle, error) { + var handle RequestHandle + var err error + + if otherErr := w.queueJob(func() { + handle, err = w.delegate.Run(cypher, args, bookmarks, txTimeout, txMetadata) + }); otherErr != nil { + err = otherErr + } + + return handle, err +} + +func (w *workerConnection) PullAll() (RequestHandle, error) { + var handle RequestHandle + var err error + + if otherErr := w.queueJob(func() { + handle, err = w.delegate.PullAll() + }); otherErr != nil { + err = otherErr + } + + return handle, err +} + +func (w *workerConnection) DiscardAll() (RequestHandle, error) { + var handle RequestHandle + var err error + + if otherErr := w.queueJob(func() { + handle, err = w.delegate.DiscardAll() + }); otherErr != nil { + err = otherErr + } + + return handle, err +} + +func (w *workerConnection) Reset() (RequestHandle, error) { + var handle RequestHandle + var err error + + if otherErr := w.queueJob(func() { + handle, err = w.delegate.Reset() + }); otherErr != nil { + err = otherErr + } + + return handle, err +} + +func (w *workerConnection) Flush() error { + var err error + + if otherErr := w.queueJob(func() { + err = w.delegate.Flush() + }); otherErr != nil { + err = otherErr + } + + return err +} + +func (w *workerConnection) Fetch(request RequestHandle) (FetchType, error) { + var fetched FetchType + var err error + + if otherErr := w.queueJob(func() { + fetched, err = w.delegate.Fetch(request) + }); otherErr != nil { + err = otherErr + } + + return fetched, err +} + +func (w *workerConnection) FetchSummary(request RequestHandle) (int, error) { + var fetched int + var err error + + if otherErr := w.queueJob(func() { + fetched, err = w.delegate.FetchSummary(request) + }); otherErr != nil { + err = otherErr + } + + return fetched, err +} + +func (w *workerConnection) LastBookmark() (string, error) { + var bookmark string + var err error + + if otherErr := w.queueJob(func() { + bookmark, err = w.delegate.LastBookmark() + }); otherErr != nil { + err = otherErr + } + + return bookmark, err +} + +func (w *workerConnection) Fields() ([]string, error) { + var fields []string + var err error + + if otherErr := w.queueJob(func() { + fields, err = w.delegate.Fields() + }); otherErr != nil { + err = otherErr + } + + return fields, err +} + +func (w *workerConnection) Metadata() (map[string]interface{}, error) { + var metadata map[string]interface{} + var err error + + if otherErr := w.queueJob(func() { + metadata, err = w.delegate.Metadata() + }); otherErr != nil { + err = otherErr + } + + return metadata, err +} + +func (w *workerConnection) Data() ([]interface{}, error) { + var data []interface{} + var err error + + if otherErr := w.queueJob(func() { + data, err = w.delegate.Data() + }); otherErr != nil { + err = otherErr + } + + return data, err +} + +func (w *workerConnection) Close() error { + var err error + + if otherErr := w.queueJob(func() { + err = w.delegate.Close() + }); otherErr != nil { + err = otherErr + } + + signalClosed(w) + + return err +} diff --git a/vendor/github.com/neo4j-drivers/gobolt/connection_worker_test.go b/vendor/github.com/neo4j-drivers/gobolt/connection_worker_test.go new file mode 100644 index 0000000..234b4a5 --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/connection_worker_test.go @@ -0,0 +1,698 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gobolt + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func Test_WorkerConnection(t *testing.T) { + newMockedConnection := func() (*workerConnection, *mockConnection, func()) { + pool := newWorkerPool(1, 1, 1*time.Minute) + delegate := new(mockConnection) + connection := &workerConnection{ + pool: pool, + delegate: delegate, + active: 0, + } + + return connection, delegate, func() { + pool.close() + } + } + + newMockedConnectionInUse := func() (*workerConnection, *mockConnection, func()) { + conn, mocked, cleanup := newMockedConnection() + + conn.active = 1 + + return conn, mocked, cleanup + } + + t.Run("newWorkerConnection", func(t *testing.T) { + var valueSystem = createValueSystem(&Config{}) + var someOtherFailure = fmt.Errorf("some other failure") + var poolFullError = newPoolFullError(valueSystem) + var connectionAcquisitionTimedOutError = newConnectionAcquisitionTimedOutError(valueSystem) + + t.Run("shouldInvokeNewSeaboltConnection", func(t *testing.T) { + var cases = []struct { + name string + timeout time.Duration + }{ + {"AcquisitionTimeout=0", 0}, + {"AcquisitionTimeout=5s", 5 * time.Second}, + } + + for _, testCase := range cases { + t.Run(testCase.name, func(t *testing.T) { + var originalNewSeaboltConnection = newSeaboltConnection + defer func() { + newSeaboltConnection = originalNewSeaboltConnection + }() + + var newSeaboltConnectionCount = 0 + newSeaboltConnection = func(connector *seaboltConnector, mode AccessMode) (*seaboltConnection, error) { + newSeaboltConnectionCount++ + return &seaboltConnection{}, nil + } + + var connector = &workerConnector{ + config: Config{ConnAcquisitionTimeout: testCase.timeout}, + pool: newWorkerPool(1, 1, 1*time.Minute), + } + defer connector.pool.close() + + connection, err := newWorkerConnection(connector, AccessModeRead) + + assert.NoError(t, err) + assert.NotNil(t, connection) + assert.Equal(t, 1, newSeaboltConnectionCount) + }) + } + }) + + t.Run("shouldReturnErrorFromNewSeaboltConnection", func(t *testing.T) { + var originalNewSeaboltConnection = newSeaboltConnection + defer func() { + newSeaboltConnection = originalNewSeaboltConnection + }() + + var newSeaboltConnectionCount = 0 + newSeaboltConnection = func(connector *seaboltConnector, mode AccessMode) (*seaboltConnection, error) { + newSeaboltConnectionCount++ + return nil, someOtherFailure + } + + var connector = &workerConnector{ + config: Config{ConnAcquisitionTimeout: 0}, + pool: newWorkerPool(1, 1, 1*time.Minute), + } + defer connector.pool.close() + + connection, err := newWorkerConnection(connector, AccessModeRead) + + assert.EqualError(t, err, "some other failure") + assert.Nil(t, connection) + assert.Equal(t, 1, newSeaboltConnectionCount) + }) + + t.Run("shouldReturnPoolFullErrorWhenAcquisitionTimeoutIsZero", func(t *testing.T) { + var originalNewSeaboltConnection = newSeaboltConnection + defer func() { + newSeaboltConnection = originalNewSeaboltConnection + }() + + var newSeaboltConnectionCount = 0 + newSeaboltConnection = func(connector *seaboltConnector, mode AccessMode) (*seaboltConnection, error) { + newSeaboltConnectionCount++ + return nil, poolFullError + } + + var connector = &workerConnector{ + config: Config{ConnAcquisitionTimeout: 0}, + pool: newWorkerPool(1, 1, 1*time.Minute), + } + defer connector.pool.close() + + connection, err := newWorkerConnection(connector, AccessModeRead) + + assert.EqualError(t, err, poolFullError.Error()) + assert.Nil(t, connection) + assert.Equal(t, 1, newSeaboltConnectionCount) + }) + + t.Run("shouldInvokeWaitClosedWhenPoolIsFullAndSucceedWhenWaitSucceeds", func(t *testing.T) { + var originalNewSeaboltConnection = newSeaboltConnection + var originalWaitClosed = waitClosed + defer func() { + newSeaboltConnection = originalNewSeaboltConnection + waitClosed = originalWaitClosed + }() + + var newSeaboltConnectionCount = 0 + newSeaboltConnection = func(connector *seaboltConnector, mode AccessMode) (*seaboltConnection, error) { + newSeaboltConnectionCount++ + if newSeaboltConnectionCount > 1 { + return &seaboltConnection{}, nil + } + return nil, poolFullError + } + + var waitClosedCount = 0 + waitClosed = func(w *workerConnection, timeout time.Duration) bool { + waitClosedCount++ + return true + } + + var connector = &workerConnector{ + config: Config{ConnAcquisitionTimeout: 5 * time.Second}, + pool: newWorkerPool(1, 1, 1*time.Minute), + } + defer connector.pool.close() + + connection, err := newWorkerConnection(connector, AccessModeRead) + + assert.NoError(t, err) + assert.NotNil(t, connection) + assert.Equal(t, 1, waitClosedCount) + assert.Equal(t, 2, newSeaboltConnectionCount) + }) + + t.Run("shouldInvokeWaitClosedWhenPoolIsFullAndFailWhenWaitFails", func(t *testing.T) { + var originalNewSeaboltConnection = newSeaboltConnection + var originalWaitClosed = waitClosed + defer func() { + newSeaboltConnection = originalNewSeaboltConnection + waitClosed = originalWaitClosed + }() + + var newSeaboltConnectionCount = 0 + newSeaboltConnection = func(connector *seaboltConnector, mode AccessMode) (*seaboltConnection, error) { + newSeaboltConnectionCount++ + return nil, poolFullError + } + + var waitClosedCount = 0 + waitClosed = func(w *workerConnection, timeout time.Duration) bool { + waitClosedCount++ + return false + } + + var connector = &workerConnector{ + config: Config{ConnAcquisitionTimeout: 5 * time.Second}, + pool: newWorkerPool(1, 1, 1*time.Minute), + delegate: &seaboltConnector{ + valueSystem: valueSystem, + }, + } + defer connector.pool.close() + + connection, err := newWorkerConnection(connector, AccessModeRead) + + assert.EqualError(t, err, connectionAcquisitionTimedOutError.Error()) + assert.Nil(t, connection) + assert.Equal(t, 1, waitClosedCount) + assert.Equal(t, 1, newSeaboltConnectionCount) + }) + }) + + t.Run("shouldInvokeSignalClosedOnClose", func(t *testing.T) { + var originalSignalClosed = signalClosed + defer func() { + signalClosed = originalSignalClosed + }() + + var signalClosedCount = 0 + signalClosed = func(w *workerConnection) { + signalClosedCount++ + } + + conn, delegate, cleanup := newMockedConnection() + defer cleanup() + + delegate.On("Close").Return(nil) + + assert.NoError(t, conn.Close()) + assert.Equal(t, 1, signalClosedCount) + }) + + t.Run("shouldSurfacePoolFullErrorWhenAcquisitionTimeoutIsZero", func(t *testing.T) { + + }) + + t.Run("shouldInterceptPoolFullErrorWhenAcquisitionTimeoutIsNotZero", func(t *testing.T) { + + }) + + t.Run("shouldInvokeDelegate", func(t *testing.T) { + failure := fmt.Errorf("some error") + handle := RequestHandle(500) + + t.Run("Id", func(t *testing.T) { + conn, delegate, cleanup := newMockedConnection() + defer cleanup() + + delegate.On("Id").Return("123", failure) + + id, err := conn.Id() + assert.Equal(t, "123", id) + assert.Equal(t, failure, err) + + delegate.AssertExpectations(t) + }) + + t.Run("RemoteAddress", func(t *testing.T) { + conn, delegate, cleanup := newMockedConnection() + defer cleanup() + + delegate.On("RemoteAddress").Return("localhost:7687", failure) + + remoteAddress, err := conn.RemoteAddress() + assert.Equal(t, "localhost:7687", remoteAddress) + assert.Equal(t, failure, err) + + delegate.AssertExpectations(t) + }) + + t.Run("Server", func(t *testing.T) { + conn, delegate, cleanup := newMockedConnection() + defer cleanup() + + delegate.On("Server").Return("Neo4j/3.5.0", failure) + + server, err := conn.Server() + assert.Equal(t, "Neo4j/3.5.0", server) + assert.Equal(t, failure, err) + + delegate.AssertExpectations(t) + }) + + t.Run("Begin", func(t *testing.T) { + conn, delegate, cleanup := newMockedConnection() + defer cleanup() + + bookmarks := []string{"1", "2", "3"} + txTimeout := 5 * time.Minute + txMetadata := map[string]interface{}{"a": 1, "b": true, "c": "yes"} + delegate.On("Begin", bookmarks, txTimeout, txMetadata).Return(handle, failure) + + beginHandle, err := conn.Begin(bookmarks, txTimeout, txMetadata) + assert.Equal(t, handle, beginHandle) + assert.Equal(t, failure, err) + + delegate.AssertExpectations(t) + }) + + t.Run("Commit", func(t *testing.T) { + conn, delegate, cleanup := newMockedConnection() + defer cleanup() + + delegate.On("Commit").Return(handle, failure) + + commitHandle, err := conn.Commit() + assert.Equal(t, handle, commitHandle) + assert.Equal(t, failure, err) + + delegate.AssertExpectations(t) + }) + + t.Run("Rollback", func(t *testing.T) { + conn, delegate, cleanup := newMockedConnection() + defer cleanup() + + delegate.On("Rollback").Return(handle, failure) + + rollbackHandle, err := conn.Rollback() + assert.Equal(t, handle, rollbackHandle) + assert.Equal(t, failure, err) + + delegate.AssertExpectations(t) + }) + + t.Run("Run", func(t *testing.T) { + conn, delegate, cleanup := newMockedConnection() + defer cleanup() + + cypher := "CREATE (n {id: $x})" + parameters := map[string]interface{}{"id": 5000} + bookmarks := []string{"1", "2", "3"} + txTimeout := 5 * time.Minute + txMetadata := map[string]interface{}{"a": 1, "b": true, "c": "yes"} + delegate.On("Run", cypher, parameters, bookmarks, txTimeout, txMetadata).Return(handle, failure) + + runHandle, err := conn.Run(cypher, parameters, bookmarks, txTimeout, txMetadata) + assert.Equal(t, handle, runHandle) + assert.Equal(t, failure, err) + + delegate.AssertExpectations(t) + }) + + t.Run("PullAll", func(t *testing.T) { + conn, delegate, cleanup := newMockedConnection() + defer cleanup() + + delegate.On("PullAll").Return(handle, failure) + + pullAllHandle, err := conn.PullAll() + assert.Equal(t, handle, pullAllHandle) + assert.Equal(t, failure, err) + + delegate.AssertExpectations(t) + }) + + t.Run("DiscardAll", func(t *testing.T) { + conn, delegate, cleanup := newMockedConnection() + defer cleanup() + + delegate.On("DiscardAll").Return(handle, failure) + + discardAllHandle, err := conn.DiscardAll() + assert.Equal(t, handle, discardAllHandle) + assert.Equal(t, failure, err) + + delegate.AssertExpectations(t) + }) + + t.Run("Reset", func(t *testing.T) { + conn, delegate, cleanup := newMockedConnection() + defer cleanup() + + delegate.On("Reset").Return(handle, failure) + + resetHandle, err := conn.Reset() + assert.Equal(t, handle, resetHandle) + assert.Equal(t, failure, err) + + delegate.AssertExpectations(t) + }) + + t.Run("Flush", func(t *testing.T) { + conn, delegate, cleanup := newMockedConnection() + defer cleanup() + + delegate.On("Flush").Return(failure) + + err := conn.Flush() + assert.Equal(t, failure, err) + + delegate.AssertExpectations(t) + }) + + t.Run("Fetch", func(t *testing.T) { + conn, delegate, cleanup := newMockedConnection() + defer cleanup() + + delegate.On("Fetch", handle).Return(FetchTypeRecord, failure) + + fetched, err := conn.Fetch(handle) + assert.Equal(t, FetchTypeRecord, fetched) + assert.Equal(t, failure, err) + + delegate.AssertExpectations(t) + }) + + t.Run("FetchSummary", func(t *testing.T) { + conn, delegate, cleanup := newMockedConnection() + defer cleanup() + + delegate.On("FetchSummary", handle).Return(50, failure) + + records, err := conn.FetchSummary(handle) + assert.Equal(t, 50, records) + assert.Equal(t, failure, err) + + delegate.AssertExpectations(t) + }) + + t.Run("LastBookmark", func(t *testing.T) { + conn, delegate, cleanup := newMockedConnection() + defer cleanup() + + delegate.On("LastBookmark").Return("bookmark:1234", failure) + + bookmark, err := conn.LastBookmark() + assert.Equal(t, "bookmark:1234", bookmark) + assert.Equal(t, failure, err) + + delegate.AssertExpectations(t) + }) + + t.Run("Fields", func(t *testing.T) { + conn, delegate, cleanup := newMockedConnection() + defer cleanup() + + fields := []string{"x", "y", "z"} + delegate.On("Fields").Return(fields, failure) + + fieldsReturned, err := conn.Fields() + assert.Equal(t, fields, fieldsReturned) + assert.Equal(t, failure, err) + + delegate.AssertExpectations(t) + }) + + t.Run("Metadata", func(t *testing.T) { + conn, delegate, cleanup := newMockedConnection() + defer cleanup() + + metadata := map[string]interface{}{"x": 1, "y": "a", "z": false} + delegate.On("Metadata").Return(metadata, failure) + + metadataReturned, err := conn.Metadata() + assert.Equal(t, metadata, metadataReturned) + assert.Equal(t, failure, err) + + delegate.AssertExpectations(t) + }) + + t.Run("Data", func(t *testing.T) { + conn, delegate, cleanup := newMockedConnection() + defer cleanup() + + data := []interface{}{"1", 2, false} + delegate.On("Data").Return(data, failure) + + dataReturned, err := conn.Data() + assert.Equal(t, data, dataReturned) + assert.Equal(t, failure, err) + + delegate.AssertExpectations(t) + }) + + t.Run("Close", func(t *testing.T) { + conn, delegate, cleanup := newMockedConnection() + defer cleanup() + + delegate.On("Close").Return(failure) + + err := conn.Close() + assert.Equal(t, failure, err) + + delegate.AssertExpectations(t) + }) + + }) + + t.Run("shouldPropagateWorkerError", func(t *testing.T) { + errText := "a connection is not thread-safe and thus should not be used concurrently" + t.Run("Id", func(t *testing.T) { + conn, _, cleanup := newMockedConnectionInUse() + defer cleanup() + + _, err := conn.Id() + assert.EqualError(t, err, errText) + }) + + t.Run("RemoteAddress", func(t *testing.T) { + conn, _, cleanup := newMockedConnectionInUse() + defer cleanup() + + _, err := conn.RemoteAddress() + assert.EqualError(t, err, errText) + }) + + t.Run("Server", func(t *testing.T) { + conn, _, cleanup := newMockedConnectionInUse() + defer cleanup() + + _, err := conn.Server() + assert.EqualError(t, err, errText) + }) + + t.Run("Begin", func(t *testing.T) { + conn, _, cleanup := newMockedConnectionInUse() + defer cleanup() + + _, err := conn.Begin([]string{}, 1*time.Minute, nil) + assert.EqualError(t, err, errText) + }) + + t.Run("Commit", func(t *testing.T) { + conn, _, cleanup := newMockedConnectionInUse() + defer cleanup() + + _, err := conn.Commit() + assert.EqualError(t, err, errText) + }) + + t.Run("Rollback", func(t *testing.T) { + conn, _, cleanup := newMockedConnectionInUse() + defer cleanup() + + _, err := conn.Rollback() + assert.EqualError(t, err, errText) + }) + + t.Run("Run", func(t *testing.T) { + conn, _, cleanup := newMockedConnectionInUse() + defer cleanup() + + _, err := conn.Run("RETURN 1", nil, nil, 1*time.Second, nil) + assert.EqualError(t, err, errText) + }) + + t.Run("PullAll", func(t *testing.T) { + conn, _, cleanup := newMockedConnectionInUse() + defer cleanup() + + _, err := conn.PullAll() + assert.EqualError(t, err, errText) + }) + + t.Run("DiscardAll", func(t *testing.T) { + conn, _, cleanup := newMockedConnectionInUse() + defer cleanup() + + _, err := conn.DiscardAll() + assert.EqualError(t, err, errText) + }) + + t.Run("Reset", func(t *testing.T) { + conn, _, cleanup := newMockedConnectionInUse() + defer cleanup() + + _, err := conn.Reset() + assert.EqualError(t, err, errText) + }) + + t.Run("Flush", func(t *testing.T) { + conn, _, cleanup := newMockedConnectionInUse() + defer cleanup() + + err := conn.Flush() + assert.EqualError(t, err, errText) + }) + + t.Run("Fetch", func(t *testing.T) { + conn, _, cleanup := newMockedConnectionInUse() + defer cleanup() + + _, err := conn.Fetch(RequestHandle(1)) + assert.EqualError(t, err, errText) + }) + + t.Run("FetchSummary", func(t *testing.T) { + conn, _, cleanup := newMockedConnectionInUse() + defer cleanup() + + _, err := conn.FetchSummary(RequestHandle(1)) + assert.EqualError(t, err, errText) + }) + + t.Run("LastBookmark", func(t *testing.T) { + conn, _, cleanup := newMockedConnectionInUse() + defer cleanup() + + _, err := conn.LastBookmark() + assert.EqualError(t, err, errText) + }) + + t.Run("Fields", func(t *testing.T) { + conn, _, cleanup := newMockedConnectionInUse() + defer cleanup() + + _, err := conn.Fields() + assert.EqualError(t, err, errText) + }) + + t.Run("Metadata", func(t *testing.T) { + conn, _, cleanup := newMockedConnectionInUse() + defer cleanup() + + _, err := conn.Metadata() + assert.EqualError(t, err, errText) + }) + + t.Run("Data", func(t *testing.T) { + conn, _, cleanup := newMockedConnectionInUse() + defer cleanup() + + _, err := conn.Data() + assert.EqualError(t, err, errText) + }) + + t.Run("Close", func(t *testing.T) { + conn, _, cleanup := newMockedConnectionInUse() + defer cleanup() + + err := conn.Close() + assert.EqualError(t, err, errText) + }) + + }) + + t.Run("queueJob", func(t *testing.T) { + t.Run("shouldSetReceivingToOneWhenExecuting", func(t *testing.T) { + var startEvent = make(chan bool, 1) + var waitEvent = make(chan bool, 1) + var blockingJob = func() { + startEvent <- true + <-waitEvent + } + + conn, _, cleanup := newMockedConnection() + defer cleanup() + defer close(waitEvent) + defer close(startEvent) + + go conn.queueJob(blockingJob) + + <-startEvent + + assert.Equal(t, int32(1), conn.active) + }) + + t.Run("shouldSetReceivingToZeroWhenExecutionIsComplete", func(t *testing.T) { + conn, _, cleanup := newMockedConnection() + defer cleanup() + + conn.queueJob(func() {}) + + assert.Equal(t, int32(0), conn.active) + }) + + t.Run("shouldCheckForConcurrentAccess", func(t *testing.T) { + var startEvent = make(chan bool, 1) + var waitEvent = make(chan bool, 1) + var blockingJob = func() { + startEvent <- true + <-waitEvent + } + + conn, _, cleanup := newMockedConnection() + defer cleanup() + defer close(waitEvent) + defer close(startEvent) + + go conn.queueJob(blockingJob) + + <-startEvent + + err := conn.queueJob(blockingJob) + + assert.EqualError(t, err, "a connection is not thread-safe and thus should not be used concurrently") + }) + }) +} diff --git a/vendor/github.com/neo4j-drivers/gobolt/connector.go b/vendor/github.com/neo4j-drivers/gobolt/connector.go new file mode 100644 index 0000000..3c242f5 --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/connector.go @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gobolt + +import ( + "net/url" +) + +// AccessMode is used by the routing driver to decide if a transaction should be routed to a write server +// or a read server in a cluster. When running a transaction, a write transaction requires a server that +// supports writes. A read transaction, on the other hand, requires a server that supports read operations. +// This classification is key for routing driver to route transactions to a cluster correctly. +type AccessMode int + +const ( + // AccessModeWrite makes the driver return a session towards a write server + AccessModeWrite AccessMode = 0 + // AccessModeRead makes the driver return a session towards a follower or a read-replica + AccessModeRead AccessMode = 1 +) + +// Connector represents an initialised seabolt connector +type Connector interface { + Acquire(mode AccessMode) (Connection, error) + Close() error +} + +func NewConnector(uri *url.URL, authToken map[string]interface{}, config *Config) (Connector, error) { + if workersEnabled() { + return newWorkerConnector(uri, authToken, config) + } else { + return newSeaboltConnector(uri, authToken, config) + } +} diff --git a/vendor/github.com/neo4j-drivers/gobolt/connector_seabolt.go b/vendor/github.com/neo4j-drivers/gobolt/connector_seabolt.go new file mode 100644 index 0000000..a0b36cd --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/connector_seabolt.go @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gobolt + +/* +#include + +#include "bolt/bolt.h" +*/ +import "C" +import ( + "errors" + "net/url" + "reflect" + "unsafe" +) + +type seaboltConnector struct { + key int + + uri *url.URL + authToken map[string]interface{} + config Config + + cAddress *C.BoltAddress + cInstance *C.BoltConnector + valueSystem *boltValueSystem +} + +func (conn *seaboltConnector) Close() error { + if conn.cInstance != nil { + C.BoltConnector_destroy(conn.cInstance) + conn.cInstance = nil + } + + if conn.cAddress != nil { + C.BoltAddress_destroy(conn.cAddress) + conn.cAddress = nil + } + + unregisterLogging(conn.key) + unregisterResolver(conn.key) + + shutdownLibrary() + + return nil +} + +func (conn *seaboltConnector) Acquire(mode AccessMode) (Connection, error) { + return newSeaboltConnection(conn, mode) +} + +// NewConnector returns a new connector instance with given parameters +func newSeaboltConnector(uri *url.URL, authToken map[string]interface{}, config *Config) (*seaboltConnector, error) { + var err error + var key int + var cAddress *C.struct_BoltAddress + var valueSystem *boltValueSystem + var cAuthToken *C.struct_BoltValue + var cConfig *C.struct_BoltConfig + + if uri == nil { + return nil, errors.New("provided uri should not be nil") + } + + if config == nil { + config = &Config{ + Encryption: true, + MaxPoolSize: 100, + } + } + + valueSystem = createValueSystem(config) + cAddress = createAddress(uri) + key = startupLibrary() + + if cAuthToken, err = valueSystem.valueToConnector(authToken); err != nil { + return nil, valueSystem.genericErrorFactory("unable to convert authentication token: %v", err) + } + defer C.BoltValue_destroy(cAuthToken) + + if cConfig, err = createConfig(key, uri, config, valueSystem); err != nil { + return nil, err + } + defer C.BoltConfig_destroy(cConfig) + + cInstance := C.BoltConnector_create(cAddress, cAuthToken, cConfig) + conn := &seaboltConnector{ + key: key, + uri: uri, + authToken: authToken, + config: *config, + cAddress: cAddress, + valueSystem: valueSystem, + cInstance: cInstance, + } + + return conn, nil +} + +func createValueSystem(config *Config) *boltValueSystem { + valueHandlersBySignature := make(map[int16]ValueHandler, len(config.ValueHandlers)) + valueHandlersByType := make(map[reflect.Type]ValueHandler, len(config.ValueHandlers)) + for _, handler := range config.ValueHandlers { + for _, readSignature := range handler.ReadableStructs() { + valueHandlersBySignature[readSignature] = handler + } + + for _, writeType := range handler.WritableTypes() { + valueHandlersByType[writeType] = handler + } + } + + databaseErrorFactory := newDatabaseError + connectorErrorFactory := newConnectorError + genericErrorFactory := newGenericError + if config.DatabaseErrorFactory != nil { + databaseErrorFactory = config.DatabaseErrorFactory + } + if config.ConnectorErrorFactory != nil { + connectorErrorFactory = config.ConnectorErrorFactory + } + if config.GenericErrorFactory != nil { + genericErrorFactory = config.GenericErrorFactory + } + + return &boltValueSystem{ + valueHandlers: config.ValueHandlers, + valueHandlersBySignature: valueHandlersBySignature, + valueHandlersByType: valueHandlersByType, + connectorErrorFactory: connectorErrorFactory, + databaseErrorFactory: databaseErrorFactory, + genericErrorFactory: genericErrorFactory, + } +} + +func createAddress(uri *url.URL) *C.struct_BoltAddress { + var hostname = C.CString(uri.Hostname()) + var port = C.CString(uri.Port()) + defer C.free(unsafe.Pointer(hostname)) + defer C.free(unsafe.Pointer(port)) + + return C.BoltAddress_create(hostname, port) +} diff --git a/vendor/github.com/neo4j-drivers/gobolt/connector_worker.go b/vendor/github.com/neo4j-drivers/gobolt/connector_worker.go new file mode 100644 index 0000000..799a6a1 --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/connector_worker.go @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gobolt + +import ( + "net/url" + "os" + "strconv" + "time" +) + +type workerConnector struct { + config Config + delegate *seaboltConnector + pool *workerPool + closeSignal chan signal +} + +func (w *workerConnector) Acquire(mode AccessMode) (Connection, error) { + return newWorkerConnection(w, mode) +} + +func (w *workerConnector) Close() error { + var err error + + var done = make(chan bool, 1) + if poolErr := w.pool.submit(func(stopper <-chan signal) { + err = w.delegate.Close() + done <- true + }); poolErr != nil { + err = poolErr + done <- true + } + + <-done + + if err != nil { + return err + } + + w.pool.close() + close(w.closeSignal) + + return nil +} + +func newWorkerConnector(url *url.URL, authToken map[string]interface{}, config *Config) (Connector, error) { + var err error + var connector *seaboltConnector + var pool = newWorkerPool(minWorkers(config), maxWorkers(config), keepAlive(config)) + + var configOverride = *config + configOverride.ConnAcquisitionTimeout = 0 + + var done = make(chan bool, 1) + if poolErr := pool.submit(func(stopper <-chan signal) { + connector, err = newSeaboltConnector(url, authToken, &configOverride) + done <- true + }); poolErr != nil { + err = poolErr + done <- true + } + + // wait for connector creation to complete + <-done + + if err != nil { + defer pool.close() + return nil, err + } + + return &workerConnector{ + config: *config, + delegate: connector, + pool: pool, + closeSignal: make(chan signal, config.MaxPoolSize), + }, nil +} + +func workersEnabled() bool { + var workersEnabled = true + if val, ok := os.LookupEnv("BOLTWORKERS"); ok { + if parsed, err := strconv.ParseBool(val); err == nil { + workersEnabled = parsed + } + } + return workersEnabled +} + +func maxWorkers(config *Config) int { + var workersMax = int(float64(config.MaxPoolSize) * float64(1.2)) + if val, ok := os.LookupEnv("BOLTWORKERSMAX"); ok { + if parsed, err := strconv.ParseInt(val, 10, 32); err == nil { + workersMax = int(parsed) + } + } + return workersMax +} + +func minWorkers(config *Config) int { + var workersMin = 0 + if val, ok := os.LookupEnv("BOLTWORKERSMIN"); ok { + if parsed, err := strconv.ParseInt(val, 10, 32); err == nil { + workersMin = int(parsed) + } + } + return workersMin +} + +func keepAlive(config *Config) time.Duration { + var workersKeepAlive = 5 * time.Minute + if val, ok := os.LookupEnv("BOLTWORKERSKEEPALIVE"); ok { + if parsed, err := time.ParseDuration(val); err == nil { + workersKeepAlive = parsed + } + } + return workersKeepAlive +} diff --git a/vendor/github.com/neo4j-drivers/gobolt/error.go b/vendor/github.com/neo4j-drivers/gobolt/error.go new file mode 100644 index 0000000..26c27c1 --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/error.go @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gobolt + +/* +#include "bolt/bolt.h" +*/ +import "C" +import ( + "fmt" + "strings" +) + +// BoltError is a marker interface to identify neo4j errors +type BoltError interface { + BoltError() bool +} + +// DatabaseError represents errors returned from the server a FAILURE messages +type DatabaseError interface { + // Classification returns classification of the error returned from the database + Classification() string + // Code returns code of the error returned from the database + Code() string + // Message returns message of the error returned from the database + Message() string + // Error returns textual representation of the error returned from the database + Error() string +} + +// ConnectorError represents errors that occur on the connector/client side, like network errors, etc. +type ConnectorError interface { + // State returns the state of the related connection + State() int + // Code returns the error code set on the related connection + Code() int + // Context returns the error context set by the connector + Context() string + // Description returns any additional description set + Description() string + // Error returns textual representation of the connector level error + Error() string +} + +// GenericError represents errors which originates from the connector wrapper itself +type GenericError interface { + // Message returns the underlying error message + Message() string + // Error returns textual representation of the generic error + Error() string +} + +type defaultDatabaseError struct { + classification string + code string + message string +} + +type defaultConnectorError struct { + state int + code int + codeText string + context string + description string +} + +type defaultGenericError struct { + message string +} + +func (failure *defaultDatabaseError) BoltError() bool { + return true +} + +func (failure *defaultDatabaseError) Classification() string { + return failure.classification +} + +func (failure *defaultDatabaseError) Code() string { + return failure.code +} + +func (failure *defaultDatabaseError) Message() string { + return failure.message +} + +func (failure *defaultDatabaseError) Error() string { + return fmt.Sprintf("database returned error [%s]: %s", failure.code, failure.message) +} + +func (failure *defaultConnectorError) BoltError() bool { + return true +} + +func (failure *defaultConnectorError) State() int { + return failure.state +} + +func (failure *defaultConnectorError) Code() int { + return failure.code +} + +func (failure *defaultConnectorError) Context() string { + return failure.context +} + +func (failure *defaultConnectorError) Description() string { + return failure.description +} + +func (failure *defaultConnectorError) Error() string { + if failure.description != "" { + return fmt.Sprintf("%s: error: [%d] %s, state: %d, context: %s", failure.description, failure.code, failure.codeText, failure.state, failure.context) + } + + return fmt.Sprintf("error: [%d] %s, state: %d, context: %s", failure.code, failure.codeText, failure.state, failure.context) +} + +func (failure *defaultGenericError) BoltError() bool { + return true +} + +func (failure *defaultGenericError) Message() string { + return failure.message +} + +func (failure *defaultGenericError) Error() string { + return failure.message +} + +func newError(connection *seaboltConnection, description string) error { + cStatus := C.BoltConnection_status(connection.cInstance) + errorCode := C.BoltStatus_get_error(cStatus) + + if errorCode == C.BOLT_SERVER_FAILURE { + failure, err := connection.valueSystem.valueAsDictionary(C.BoltConnection_failure(connection.cInstance)) + if err != nil { + return connection.valueSystem.genericErrorFactory("unable to construct database error: %s", err.Error()) + } + + var ok bool + var codeInt, messageInt interface{} + var code, message string + + if codeInt, ok = failure["code"]; !ok { + return connection.valueSystem.genericErrorFactory("expected 'code' key to be present in map '%v'", failure) + } + if code, ok = codeInt.(string); !ok { + return connection.valueSystem.genericErrorFactory("expected 'code' value to be of type 'string': '%v'", codeInt) + } + + if messageInt, ok = failure["message"]; !ok { + return connection.valueSystem.genericErrorFactory("expected 'message' key to be present in map '%v'", failure) + } + if message, ok = messageInt.(string); !ok { + return connection.valueSystem.genericErrorFactory("expected 'message' value to be of type 'string': '%v'", messageInt) + } + + classification := "" + if codeParts := strings.Split(code, "."); len(codeParts) >= 2 { + classification = codeParts[1] + } + + return connection.valueSystem.databaseErrorFactory(classification, code, message) + } + + state := C.BoltStatus_get_state(cStatus) + errorText := C.GoString(C.BoltError_get_string(errorCode)) + context := C.GoString(C.BoltStatus_get_error_context(cStatus)) + + return connection.valueSystem.connectorErrorFactory(int(state), int(errorCode), errorText, context, description) +} + +func newGenericError(format string, args ...interface{}) GenericError { + return &defaultGenericError{message: fmt.Sprintf(format, args...)} +} + +func newDatabaseError(classification, code, message string) DatabaseError { + return &defaultDatabaseError{code: code, message: message, classification: classification} +} + +func newConnectorError(state int, code int, codeText, context, description string) ConnectorError { + return &defaultConnectorError{state: state, code: code, codeText: codeText, context: context, description: description} +} + +// IsDatabaseError checkes whether given err is a DatabaseError +func IsDatabaseError(err error) bool { + if _, ok := err.(DatabaseError); !ok { + return false + } + + if _, ok := err.(BoltError); !ok { + return false + } + + return true +} + +// IsConnectorError checkes whether given err is a ConnectorError +func IsConnectorError(err error) bool { + if _, ok := err.(ConnectorError); !ok { + return false + } + + if _, ok := err.(BoltError); !ok { + return false + } + + return true +} + +// IsGenericError checkes whether given err is a GenericError +func IsGenericError(err error) bool { + if _, ok := err.(GenericError); !ok { + return false + } + + if _, ok := err.(BoltError); !ok { + return false + } + + return true +} + +// IsTransientError checks whether given err is a transient error +func IsTransientError(err error) bool { + if _, ok := err.(BoltError); !ok { + return false + } + + if dbErr, ok := err.(DatabaseError); ok { + if dbErr.Classification() == "TransientError" { + switch dbErr.Code() { + case "Neo.TransientError.Transaction.Terminated": + fallthrough + case "Neo.TransientError.Transaction.LockClientStopped": + return false + } + + return true + } + } + + return false +} + +// IsWriteError checks whether given err can be classified as a write error +func IsWriteError(err error) bool { + if _, ok := err.(BoltError); !ok { + return false + } + + if dbErr, ok := err.(DatabaseError); ok { + switch dbErr.Code() { + case "Neo.ClientError.Cluster.NotALeader": + fallthrough + case "Neo.ClientError.General.ForbiddenOnReadOnlyDatabase": + return true + } + } + + return false +} + +// IsServiceUnavailable checkes whether given err represents a service unavailable status +func IsServiceUnavailable(err error) bool { + if _, ok := err.(BoltError); !ok { + return false + } + + if connErr, ok := err.(ConnectorError); ok { + switch connErr.Code() { + case C.BOLT_INTERRUPTED: + fallthrough + case C.BOLT_CONNECTION_RESET: + fallthrough + case C.BOLT_NO_VALID_ADDRESS: + fallthrough + case C.BOLT_TIMED_OUT: + fallthrough + case C.BOLT_CONNECTION_REFUSED: + fallthrough + case C.BOLT_NETWORK_UNREACHABLE: + fallthrough + case C.BOLT_TLS_ERROR: + fallthrough + case C.BOLT_END_OF_TRANSMISSION: + fallthrough + case C.BOLT_POOL_FULL: + fallthrough + case C.BOLT_ADDRESS_NOT_RESOLVED: + fallthrough + case C.BOLT_ROUTING_UNABLE_TO_RETRIEVE_ROUTING_TABLE: + fallthrough + case C.BOLT_ROUTING_UNABLE_TO_REFRESH_ROUTING_TABLE: + fallthrough + case C.BOLT_ROUTING_NO_SERVERS_TO_SELECT: + return true + } + } + + return false +} + +func IsSecurityError(err error) bool { + if _, ok := err.(BoltError); !ok { + return false + } + + if connErr, ok := err.(ConnectorError); ok { + return connErr.Code() == C.BOLT_TLS_ERROR + } + + return IsAuthenticationError(err) +} + +func IsAuthenticationError(err error) bool { + if _, ok := err.(BoltError); !ok { + return false + } + + if connErr, ok := err.(ConnectorError); ok { + return connErr.Code() == C.BOLT_PERMISSION_DENIED + } + + if dbErr, ok := err.(DatabaseError); ok { + return dbErr.Code() == "Neo.ClientError.Security.Unauthorized" + } + + return false +} + +func IsClientError(err error) bool { + if _, ok := err.(BoltError); !ok { + return false + } + + if dbErr, ok := err.(DatabaseError); ok { + if dbErr.Classification() == "ClientError" { + return dbErr.Code() != "Neo.ClientError.Security.Unauthorized" + } + + return false + } + + return IsGenericError(err) +} + +func IsSessionExpired(err error) bool { + if _, ok := err.(BoltError); !ok { + return false + } + + if connErr, ok := err.(ConnectorError); ok { + return connErr.Code() == C.BOLT_ROUTING_NO_SERVERS_TO_SELECT + } + + return false +} + +func isPoolFullError(err error) bool { + if connectorError, ok := err.(ConnectorError); ok { + return connectorError.Code() == C.BOLT_POOL_FULL + } + + return false +} + +func newConnectionAcquisitionTimedOutError(valueSystem *boltValueSystem) error { + return valueSystem.connectorErrorFactory(C.BOLT_CONNECTION_STATE_DISCONNECTED, C.BOLT_POOL_ACQUISITION_TIMED_OUT, C.GoString(C.BoltError_get_string(C.BOLT_POOL_ACQUISITION_TIMED_OUT)), "", "") + +} + +func newPoolFullError(valueSystem *boltValueSystem) error { + return valueSystem.connectorErrorFactory(C.BOLT_CONNECTION_STATE_DISCONNECTED, C.BOLT_POOL_FULL, C.GoString(C.BoltError_get_string(C.BOLT_POOL_FULL)), "", "") + +} diff --git a/vendor/github.com/neo4j-drivers/gobolt/lifecycle.go b/vendor/github.com/neo4j-drivers/gobolt/lifecycle.go new file mode 100644 index 0000000..911073a --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/lifecycle.go @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gobolt + +/* +#include + +#include "bolt/bolt.h" +*/ +import "C" +import "sync/atomic" + +var initCounter int32 + +func startupLibrary() int { + counter := atomic.AddInt32(&initCounter, 1) + if counter == 1 { + C.Bolt_startup() + } + return int(counter) +} + +func shutdownLibrary() { + if atomic.AddInt32(&initCounter, -1) == 0 { + C.Bolt_shutdown() + } +} diff --git a/vendor/github.com/neo4j-drivers/gobolt/logging.go b/vendor/github.com/neo4j-drivers/gobolt/logging.go new file mode 100644 index 0000000..ca70058 --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/logging.go @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gobolt + +/* +#include "bolt/bolt.h" + +extern void go_seabolt_log_error_cb(void* state, char* message); +extern void go_seabolt_log_warning_cb(void* state, char* message); +extern void go_seabolt_log_info_cb(void* state, char* message); +extern void go_seabolt_log_debug_cb(void* state, char* message); +*/ +import "C" +import ( + "sync" + "unsafe" +) + +// Logging is the interface that any provided logging target must satisfy for the connector +// to use +type Logging interface { + ErrorEnabled() bool + WarningEnabled() bool + InfoEnabled() bool + DebugEnabled() bool + + Errorf(message string, args ...interface{}) + Warningf(message string, args ...interface{}) + Infof(message string, args ...interface{}) + Debugf(message string, args ...interface{}) +} + +//export go_seabolt_log_error_cb +func go_seabolt_log_error_cb(state unsafe.Pointer, message *C.char) { + logging := lookupLogging(state) + if logging != nil && logging.ErrorEnabled() { + logging.Errorf(C.GoString(message)) + } +} + +//export go_seabolt_log_warning_cb +func go_seabolt_log_warning_cb(state unsafe.Pointer, message *C.char) { + logging := lookupLogging(state) + if logging != nil && logging.WarningEnabled() { + logging.Warningf(C.GoString(message)) + } +} + +//export go_seabolt_log_info_cb +func go_seabolt_log_info_cb(state unsafe.Pointer, message *C.char) { + logging := lookupLogging(state) + if logging != nil && logging.InfoEnabled() { + logging.Infof(C.GoString(message)) + } +} + +//export go_seabolt_log_debug_cb +func go_seabolt_log_debug_cb(state unsafe.Pointer, message *C.char) { + logging := lookupLogging(state) + if logging != nil && logging.DebugEnabled() { + logging.Debugf(C.GoString(message)) + } +} + +var mapLogging sync.Map + +func registerLogging(key int, logging Logging) *C.struct_BoltLog { + if logging == nil { + return nil + } + + mapLogging.Store(key, logging) + + boltLog := C.BoltLog_create(unsafe.Pointer(&key)) + if logging != nil && logging.ErrorEnabled() { + C.BoltLog_set_error_func(boltLog, C.log_func(C.go_seabolt_log_error_cb)) + } + + if logging != nil && logging.WarningEnabled() { + C.BoltLog_set_warning_func(boltLog, C.log_func(C.go_seabolt_log_warning_cb)) + } + + if logging != nil && logging.InfoEnabled() { + C.BoltLog_set_info_func(boltLog, C.log_func(C.go_seabolt_log_info_cb)) + } + + if logging != nil && logging.DebugEnabled() { + C.BoltLog_set_debug_func(boltLog, C.log_func(C.go_seabolt_log_debug_cb)) + } + + return boltLog +} + +func lookupLogging(key unsafe.Pointer) Logging { + if logging, ok := mapLogging.Load(*(*int)(key)); ok { + return logging.(Logging) + } + + return nil +} + +func unregisterLogging(key int) { + mapLogging.Delete(key) +} diff --git a/vendor/github.com/neo4j-drivers/gobolt/resolver.go b/vendor/github.com/neo4j-drivers/gobolt/resolver.go new file mode 100644 index 0000000..d213160 --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/resolver.go @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gobolt + +/* +#include +#include "bolt/bolt.h" + +extern void go_seabolt_server_address_resolver_cb(void* state, struct BoltAddress *address, struct BoltAddressSet *resolved); +*/ +import "C" +import ( + "fmt" + "net/url" + "sync" + "unsafe" +) + +// URLAddressResolver is the callback function signature that provided custom resolver +// should adhere to +type URLAddressResolver func(address *url.URL) []*url.URL + +//export go_seabolt_server_address_resolver_cb +func go_seabolt_server_address_resolver_cb(state unsafe.Pointer, address *C.struct_BoltAddress, resolved *C.struct_BoltAddressSet) { + resolver := lookupResolver(state) + if resolver != nil { + resolvedAddresses := resolver(&url.URL{Host: fmt.Sprintf("%s:%s", C.GoString(C.BoltAddress_host(address)), C.GoString(C.BoltAddress_port(address)))}) + + for _, addr := range resolvedAddresses { + cHost := C.CString(addr.Hostname()) + cPort := C.CString(addr.Port()) + cAddress := C.BoltAddress_create(cHost, cPort) + + C.BoltAddressSet_add(resolved, cAddress) + + C.BoltAddress_destroy(cAddress) + C.free(unsafe.Pointer(cHost)) + C.free(unsafe.Pointer(cPort)) + } + } +} + +var mapResolver sync.Map + +func registerResolver(key int, resolver URLAddressResolver) *C.struct_BoltAddressResolver { + if resolver == nil { + return nil + } + + mapResolver.Store(key, resolver) + + boltResolver := C.BoltAddressResolver_create(unsafe.Pointer(&key), C.address_resolver_func(C.go_seabolt_server_address_resolver_cb)) + return boltResolver +} + +func lookupResolver(key unsafe.Pointer) URLAddressResolver { + if resolver, ok := mapResolver.Load(*(*int)(key)); ok { + return resolver.(URLAddressResolver) + } + + return nil +} + +func unregisterResolver(key int) { + mapResolver.Delete(key) +} diff --git a/vendor/github.com/neo4j-drivers/gobolt/seabolt-static.go b/vendor/github.com/neo4j-drivers/gobolt/seabolt-static.go new file mode 100644 index 0000000..d347159 --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/seabolt-static.go @@ -0,0 +1,25 @@ +// +build seabolt_static + +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gobolt + +// #cgo pkg-config: seabolt17-static +import "C" diff --git a/vendor/github.com/neo4j-drivers/gobolt/seabolt.go b/vendor/github.com/neo4j-drivers/gobolt/seabolt.go new file mode 100644 index 0000000..4fc9b9e --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/seabolt.go @@ -0,0 +1,25 @@ +// +build !seabolt_static + +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gobolt + +// #cgo pkg-config: seabolt17 +import "C" diff --git a/vendor/github.com/neo4j-drivers/gobolt/stats.go b/vendor/github.com/neo4j-drivers/gobolt/stats.go new file mode 100644 index 0000000..6a2dbf5 --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/stats.go @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gobolt + +/* +#include + +#include "bolt/bolt.h" +*/ +import "C" + +// GetAllocationStats returns statistics about seabolt (C) allocations +func GetAllocationStats() (int64, int64, int64) { + current := C.BoltStat_memory_allocation_current() + peak := C.BoltStat_memory_allocation_peak() + events := C.BoltStat_memory_allocation_events() + + return int64(current), int64(peak), int64(events) +} diff --git a/vendor/github.com/neo4j-drivers/gobolt/value.go b/vendor/github.com/neo4j-drivers/gobolt/value.go new file mode 100644 index 0000000..833c0ed --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/value.go @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gobolt + +/* +#include + +#include "bolt/bolt.h" +*/ +import "C" +import ( + "reflect" + "unsafe" +) + +type boltValueSystem struct { + valueHandlers []ValueHandler + valueHandlersBySignature map[int16]ValueHandler + valueHandlersByType map[reflect.Type]ValueHandler + connectorErrorFactory func(state, code int, codeText, context, description string) ConnectorError + databaseErrorFactory func(classification, code, message string) DatabaseError + genericErrorFactory func(format string, args ...interface{}) GenericError +} + +func (valueSystem *boltValueSystem) valueAsGo(value *C.struct_BoltValue) (interface{}, error) { + valueType := C.BoltValue_type(value) + + switch { + case valueType == C.BOLT_NULL: + return nil, nil + case valueType == C.BOLT_BOOLEAN: + return valueSystem.valueAsBoolean(value), nil + case valueType == C.BOLT_INTEGER: + return valueSystem.valueAsInt(value), nil + case valueType == C.BOLT_FLOAT: + return valueSystem.valueAsFloat(value), nil + case valueType == C.BOLT_STRING: + return valueSystem.valueAsString(value), nil + case valueType == C.BOLT_DICTIONARY: + return valueSystem.valueAsDictionary(value) + case valueType == C.BOLT_LIST: + return valueSystem.valueAsList(value) + case valueType == C.BOLT_BYTES: + return valueSystem.valueAsBytes(value), nil + case valueType == C.BOLT_STRUCTURE: + signature := int16(C.BoltStructure_code(value)) + + if handler, ok := valueSystem.valueHandlersBySignature[signature]; ok { + listValue, err := valueSystem.structAsList(value) + if err != nil { + return nil, err + } + + return handler.Read(signature, listValue) + } + + return nil, valueSystem.genericErrorFactory("unsupported struct type received: %#x", signature) + } + + return nil, valueSystem.genericErrorFactory("unsupported data type") +} + +func (valueSystem *boltValueSystem) valueAsBoolean(value *C.struct_BoltValue) bool { + val := C.BoltBoolean_get(value) + return val == 1 +} + +func (valueSystem *boltValueSystem) valueAsInt(value *C.struct_BoltValue) int64 { + val := C.BoltInteger_get(value) + return int64(val) +} + +func (valueSystem *boltValueSystem) valueAsFloat(value *C.struct_BoltValue) float64 { + val := C.BoltFloat_get(value) + return float64(val) +} + +func (valueSystem *boltValueSystem) valueAsString(value *C.struct_BoltValue) string { + val := C.BoltString_get(value) + return C.GoStringN(val, C.int(C.BoltValue_size(value))) +} + +func (valueSystem *boltValueSystem) valueAsDictionary(value *C.struct_BoltValue) (map[string]interface{}, error) { + size := int(C.BoltValue_size(value)) + dict := make(map[string]interface{}, size) + for i := 0; i < size; i++ { + index := C.int32_t(i) + key := valueSystem.valueAsString(C.BoltDictionary_key(value, index)) + value, err := valueSystem.valueAsGo(C.BoltDictionary_value(value, index)) + if err != nil { + return nil, err + } + + dict[key] = value + } + return dict, nil +} + +func (valueSystem *boltValueSystem) valueAsList(value *C.struct_BoltValue) ([]interface{}, error) { + size := int(C.BoltValue_size(value)) + list := make([]interface{}, size) + for i := 0; i < size; i++ { + index := C.int32_t(i) + value, err := valueSystem.valueAsGo(C.BoltList_value(value, index)) + if err != nil { + return nil, err + } + + list[i] = value + } + return list, nil +} + +func (valueSystem *boltValueSystem) structAsList(value *C.struct_BoltValue) ([]interface{}, error) { + size := int(C.BoltValue_size(value)) + list := make([]interface{}, size) + for i := 0; i < size; i++ { + index := C.int32_t(i) + value, err := valueSystem.valueAsGo(C.BoltStructure_value(value, index)) + if err != nil { + return nil, err + } + + list[i] = value + } + return list, nil +} + +func (valueSystem *boltValueSystem) valueAsBytes(value *C.struct_BoltValue) []byte { + val := C.BoltBytes_get_all(value) + return C.GoBytes(unsafe.Pointer(val), C.int(C.BoltValue_size(value))) +} + +func (valueSystem *boltValueSystem) valueToConnector(value interface{}) (*C.struct_BoltValue, error) { + res := C.BoltValue_create() + err := valueSystem.valueAsConnector(res, value) + return res, err +} + +func (valueSystem *boltValueSystem) valueAsConnector(target *C.struct_BoltValue, value interface{}) error { + if value == nil { + C.BoltValue_format_as_Null(target) + return nil + } + + // try basic types + basic := true + switch bv := value.(type) { + case bool: + valueSystem.boolAsValue(target, bv) + case int: + valueSystem.intAsValue(target, int64(bv)) + case int8: + valueSystem.intAsValue(target, int64(bv)) + case int16: + valueSystem.intAsValue(target, int64(bv)) + case int32: + valueSystem.intAsValue(target, int64(bv)) + case int64: + valueSystem.intAsValue(target, bv) + case uint: + valueSystem.intAsValue(target, int64(bv)) + case uint8: + valueSystem.intAsValue(target, int64(bv)) + case uint16: + valueSystem.intAsValue(target, int64(bv)) + case uint32: + valueSystem.intAsValue(target, int64(bv)) + case uint64: + valueSystem.intAsValue(target, int64(bv)) + case float32: + valueSystem.floatAsValue(target, float64(bv)) + case float64: + valueSystem.floatAsValue(target, bv) + case string: + valueSystem.stringAsValue(target, bv) + case []byte: + valueSystem.bytesAsValue(target, bv) + default: + basic = false + } + if basic { + return nil + } + + vtype := reflect.TypeOf(value) + + // try aliased types + alias := true + switch vtype.Kind() { + case reflect.Bool: + b := reflect.ValueOf(value).Bool() + valueSystem.boolAsValue(target, b) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + i := reflect.ValueOf(value).Int() + valueSystem.intAsValue(target, i) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + i := int64(reflect.ValueOf(value).Uint()) + valueSystem.intAsValue(target, i) + case reflect.Float32, reflect.Float64: + f := reflect.ValueOf(value).Float() + valueSystem.floatAsValue(target, f) + case reflect.String: + s := reflect.ValueOf(value).String() + valueSystem.stringAsValue(target, s) + default: + alias = false + } + if alias { + return nil + } + + // try nested types + switch vtype.Kind() { + case reflect.Ptr: + ptr := reflect.ValueOf(value) + if ptr.IsNil() { + return valueSystem.valueAsConnector(target, nil) + } + return valueSystem.valueAsConnector(target, ptr.Elem().Interface()) + case reflect.Slice: + return valueSystem.listAsValue(target, value) + case reflect.Map: + return valueSystem.mapAsValue(target, value) + } + + // ask for value handlers + if handler, ok := valueSystem.valueHandlersByType[vtype]; ok { + signature, fields, err := handler.Write(value) + if err != nil { + return err + } + + C.BoltValue_format_as_Structure(target, C.int16_t(signature), C.int32_t(len(fields))) + for index, fieldValue := range fields { + t := C.BoltStructure_value(target, C.int32_t(index)) + if err := valueSystem.valueAsConnector(t, fieldValue); err != nil { + return err + } + } + + // custom handler ok + return nil + } + + // nothing worked + return valueSystem.genericErrorFactory("unsupported value for conversion: %v", value) +} + +func (valueSystem *boltValueSystem) boolAsValue(target *C.struct_BoltValue, value bool) { + data := C.char(0) + if value { + data = C.char(1) + } + + C.BoltValue_format_as_Boolean(target, data) +} + +func (valueSystem *boltValueSystem) intAsValue(target *C.struct_BoltValue, value int64) { + C.BoltValue_format_as_Integer(target, C.int64_t(value)) +} + +func (valueSystem *boltValueSystem) floatAsValue(target *C.struct_BoltValue, value float64) { + C.BoltValue_format_as_Float(target, C.double(value)) +} + +func (valueSystem *boltValueSystem) stringAsValue(target *C.struct_BoltValue, value string) { + str := C.CString(value) + C.BoltValue_format_as_String(target, str, C.int32_t(len(value))) + C.free(unsafe.Pointer(str)) +} + +func (valueSystem *boltValueSystem) bytesAsValue(target *C.struct_BoltValue, value []byte) { + bytes := C.CBytes(value) + str := (*C.char)(bytes) + C.BoltValue_format_as_Bytes(target, str, C.int32_t(len(value))) + C.free(bytes) +} + +func (valueSystem *boltValueSystem) listAsValue(target *C.struct_BoltValue, value interface{}) error { + slice := reflect.ValueOf(value) + if slice.Kind() != reflect.Slice { + return valueSystem.genericErrorFactory("listAsValue invoked with a non-slice type: %v", value) + } + + C.BoltValue_format_as_List(target, C.int32_t(slice.Len())) + for i := 0; i < slice.Len(); i++ { + elTarget := C.BoltList_value(target, C.int32_t(i)) + if err := valueSystem.valueAsConnector(elTarget, slice.Index(i).Interface()); err != nil { + return err + } + } + + return nil +} + +func (valueSystem *boltValueSystem) mapAsValue(target *C.struct_BoltValue, value interface{}) error { + dict := reflect.ValueOf(value) + if dict.Kind() != reflect.Map { + return valueSystem.genericErrorFactory("mapAsValue invoked with a non-map type: %v", value) + } + + C.BoltValue_format_as_Dictionary(target, C.int32_t(dict.Len())) + + index := C.int32_t(0) + for _, key := range dict.MapKeys() { + keyTarget := C.BoltDictionary_key(target, index) + elTarget := C.BoltDictionary_value(target, index) + + if err := valueSystem.valueAsConnector(keyTarget, key.Interface()); err != nil { + return err + } + if err := valueSystem.valueAsConnector(elTarget, dict.MapIndex(key).Interface()); err != nil { + return err + } + + index++ + } + + return nil +} diff --git a/vendor/github.com/neo4j-drivers/gobolt/value_handler.go b/vendor/github.com/neo4j-drivers/gobolt/value_handler.go new file mode 100644 index 0000000..5a82760 --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/value_handler.go @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gobolt + +import ( + "fmt" + "reflect" +) + +// ValueHandler is the interface that custom value handlers should implement to +// support reading/writing struct types into custom types +type ValueHandler interface { + ReadableStructs() []int16 + WritableTypes() []reflect.Type + Read(signature int16, values []interface{}) (interface{}, error) + Write(value interface{}) (int16, []interface{}, error) +} + +// ValueHandlerError is the special error that ValueHandlers should return in +// case of unexpected cases +type ValueHandlerError struct { + message string +} + +// NewValueHandlerError constructs a new ValueHandlerError +func NewValueHandlerError(format string, args ...interface{}) *ValueHandlerError { + return &ValueHandlerError{ + message: fmt.Sprintf(format, args...), + } +} + +// Error returns textual representation of the value handler error +func (ns *ValueHandlerError) Error() string { + return ns.message +} diff --git a/vendor/github.com/neo4j-drivers/gobolt/worker_pool.go b/vendor/github.com/neo4j-drivers/gobolt/worker_pool.go new file mode 100644 index 0000000..bdb4354 --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/worker_pool.go @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gobolt + +import ( + "fmt" + "sync" + "sync/atomic" + "time" +) + +type signal struct{} + +type workItem func(stopper <-chan signal) + +type worker func(pool *workerPool) + +type workerPool struct { + minWorkers int + maxWorkers int + keepAlive time.Duration + workerCount int32 + workers chan int + workQueue chan workItem + stopper chan signal + stoppedEvent sync.WaitGroup +} + +func newWorkerPool(minWorkers, maxWorkers int, keepAlive time.Duration) *workerPool { + if minWorkers < 0 { + panic(fmt.Sprintf("%v is an invalid value for minWorkers", minWorkers)) + } + + if maxWorkers == 0 { + panic(fmt.Sprintf("%v is an invalid value for maxWorkers", maxWorkers)) + } + + if maxWorkers < minWorkers { + panic(fmt.Sprintf("maxWorkers[%v] is expected to be larger than or equal to minWorkers[%v]", maxWorkers, minWorkers)) + } + + poolInstance := &workerPool{ + minWorkers: minWorkers, + maxWorkers: maxWorkers, + keepAlive: keepAlive, + workerCount: 0, + workers: make(chan int, maxWorkers), + workQueue: make(chan workItem), + stopper: make(chan signal), + stoppedEvent: sync.WaitGroup{}, + } + + for i := 0; i < minWorkers; i++ { + poolInstance.workers <- 1 + poolInstance.launchWorker() + } + + return poolInstance +} + +func (pool *workerPool) launchWorker() { + pool.stoppedEvent.Add(1) + + var started = make(chan int, 1) + go func(pool *workerPool) { + atomic.AddInt32(&pool.workerCount, 1) + defer func() { + <-pool.workers + atomic.AddInt32(&pool.workerCount, -1) + pool.stoppedEvent.Done() + }() + + started <- 1 + + workerEntryPoint(pool) + }(pool) + + <-started +} + +func workerEntryPoint(pool *workerPool) { + t := time.NewTimer(pool.keepAlive) + for { + select { + case work := <-pool.workQueue: + work(pool.stopper) + if !t.Stop() { + <-t.C + } + t.Reset(pool.keepAlive) + case <-pool.stopper: + return + case <-t.C: + return + } + } +} + +func (pool *workerPool) submit(work workItem) error { + for { + select { + case pool.workQueue <- work: + return nil + default: + } + + select { + case pool.workQueue <- work: + return nil + case <-pool.stopper: + return newGenericError("unable to submit job to a closed worker pool") + case pool.workers <- 1: + pool.launchWorker() + } + } +} + +func (pool *workerPool) isClosed() bool { + select { + case _, ok := <-pool.stopper: + return !ok + default: + return false + } +} + +func (pool *workerPool) close() { + close(pool.stopper) + pool.stoppedEvent.Wait() + close(pool.workQueue) +} diff --git a/vendor/github.com/neo4j-drivers/gobolt/worker_pool_test.go b/vendor/github.com/neo4j-drivers/gobolt/worker_pool_test.go new file mode 100644 index 0000000..65a9694 --- /dev/null +++ b/vendor/github.com/neo4j-drivers/gobolt/worker_pool_test.go @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gobolt + +import ( + "sync/atomic" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func Test_WorkerPool(t *testing.T) { + t.Run("newWorkerPool", func(t *testing.T) { + t.Run("shouldUsePassedInParametersInConstruction", func(t *testing.T) { + pool := newWorkerPool(2, 10, 1*time.Minute) + defer pool.close() + + assert.Equal(t, 2, pool.minWorkers) + assert.Equal(t, 10, pool.maxWorkers) + assert.Equal(t, 1*time.Minute, pool.keepAlive) + }) + + t.Run("shouldPanicOnNegativeMinWorkers", func(t *testing.T) { + assert.Panics(t, func() { + _ = newWorkerPool(-1, 10, 1*time.Minute) + }) + }) + + t.Run("shouldPanicOnZeroMaxWorkers", func(t *testing.T) { + assert.Panics(t, func() { + _ = newWorkerPool(0, 0, 1*time.Minute) + }) + }) + + t.Run("shouldPanicOnInvalidMaxWorkers", func(t *testing.T) { + assert.Panics(t, func() { + _ = newWorkerPool(10, 5, 1*time.Minute) + }) + }) + + t.Run("shouldStartMinWorkers", func(t *testing.T) { + pool := newWorkerPool(20, 50, 1*time.Minute) + defer pool.close() + + assert.Equal(t, int32(20), pool.workerCount) + assert.NotEmpty(t, pool.workers) + }) + }) + + t.Run("close", func(t *testing.T) { + t.Run("shouldSetClosedOnClose", func(t *testing.T) { + pool := newWorkerPool(0, 2, 1*time.Minute) + + assert.False(t, pool.isClosed()) + + pool.close() + + assert.True(t, pool.isClosed()) + }) + + t.Run("shouldWaitForWorkersOnClose", func(t *testing.T) { + pool := newWorkerPool(20, 40, 1*time.Minute) + + assert.Equal(t, int32(20), pool.workerCount) + assert.NotEmpty(t, pool.workers) + + pool.close() + + assert.Equal(t, int32(0), pool.workerCount) + assert.Empty(t, pool.workers) + }) + }) + + t.Run("workerEntryPoint", func(t *testing.T) { + t.Run("shouldDieAfterKeepalive", func(t *testing.T) { + pool := newWorkerPool(4, 8, 3*time.Second) + defer pool.close() + + assert.Equal(t, int32(4), pool.workerCount) + assert.NotEmpty(t, pool.workers) + + <-time.After(5 * time.Second) + + assert.Equal(t, int32(0), pool.workerCount) + assert.Empty(t, pool.workers) + }) + }) + + t.Run("submit", func(t *testing.T) { + t.Run("shouldSucceedWhenThereIsAvailableWorker", func(t *testing.T) { + var workExecutions int32 + var workSignal = make(chan bool, 1) + workFunc := func(stopper <-chan signal) { + atomic.AddInt32(&workExecutions, 1) + workSignal <- true + } + + pool := newWorkerPool(1, 1, 5*time.Minute) + defer pool.close() + + assert.NoError(t, pool.submit(workFunc)) + + <-workSignal + + assert.Equal(t, int32(1), workExecutions) + }) + + t.Run("shouldSucceedBySpawningNewWorker", func(t *testing.T) { + var workExecutions int32 + var workSignal = make(chan bool, 1) + workFunc := func(stopper <-chan signal) { + atomic.AddInt32(&workExecutions, 1) + workSignal <- true + } + + pool := newWorkerPool(0, 1, 5*time.Minute) + defer pool.close() + + assert.NoError(t, pool.submit(workFunc)) + + <-workSignal + + assert.Equal(t, int32(1), workExecutions) + }) + + t.Run("shouldFailWhenClosed", func(t *testing.T) { + var workSignal = make(chan bool, 1) + workFunc := func(stopper <-chan signal) { + <-workSignal + } + + pool := newWorkerPool(1, 5, 5*time.Minute) + pool.submit(workFunc) + + go func() { + pool.close() + }() + + for !pool.isClosed() { + time.Sleep(500 * time.Millisecond) + } + + assert.EqualError(t, pool.submit(workFunc), "unable to submit job to a closed worker pool") + + close(workSignal) + }) + }) + +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/LICENSE b/vendor/github.com/neo4j/neo4j-go-driver/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/Gopkg.lock b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/Gopkg.lock new file mode 100644 index 0000000..721bbf4 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/Gopkg.lock @@ -0,0 +1,200 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec" + name = "github.com/davecgh/go-spew" + packages = ["spew"] + pruneopts = "UT" + revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" + version = "v1.1.1" + +[[projects]] + digest = "1:bc38c7c481812e178d85160472e231c5e1c9a7f5845d67e23ee4e706933c10d8" + name = "github.com/golang/mock" + packages = ["gomock"] + pruneopts = "UT" + revision = "c34cdb4725f4c3844d095133c6e40e448b86589b" + version = "v1.1.1" + +[[projects]] + branch = "master" + digest = "1:59392ed8afb901aab4287d4894df8191722e34f3957716f4350c8c133ce99046" + name = "github.com/hpcloud/tail" + packages = [ + ".", + "ratelimiter", + "util", + "watch", + "winfile", + ] + pruneopts = "UT" + revision = "a1dbeea552b7c8df4b542c66073e393de198a800" + +[[projects]] + digest = "1:1475284f4da1954edf470db7a1a4c02273b575df44e423a70c9252809ceff644" + name = "github.com/neo4j-drivers/gobolt" + packages = ["."] + pruneopts = "UT" + revision = "5c8150e392c88792913393e416a1a63124f03daf" + version = "v1.7.1" + +[[projects]] + digest = "1:f37a92358921891d53d5375ff7fa57739ba65d5b3c311d96a460609bfc1b4999" + name = "github.com/onsi/ginkgo" + packages = [ + ".", + "config", + "extensions/table", + "internal/codelocation", + "internal/containernode", + "internal/failer", + "internal/leafnodes", + "internal/remote", + "internal/spec", + "internal/spec_iterator", + "internal/specrunner", + "internal/suite", + "internal/testingtproxy", + "internal/writer", + "reporters", + "reporters/stenographer", + "reporters/stenographer/support/go-colorable", + "reporters/stenographer/support/go-isatty", + "types", + ] + pruneopts = "UT" + revision = "3774a09d95489ccaa16032e0770d08ea77ba6184" + version = "v1.6.0" + +[[projects]] + digest = "1:ab54eea8d482272009e9e4af07d4d9b5236c27b4d8c54a3f2c99d163be883eca" + name = "github.com/onsi/gomega" + packages = [ + ".", + "format", + "internal/assertion", + "internal/asyncassertion", + "internal/oraclematcher", + "internal/testingtsupport", + "matchers", + "matchers/support/goraph/bipartitegraph", + "matchers/support/goraph/edge", + "matchers/support/goraph/node", + "matchers/support/goraph/util", + "types", + ] + pruneopts = "UT" + revision = "7615b9433f86a8bdf29709bf288bc4fd0636a369" + version = "v1.4.2" + +[[projects]] + digest = "1:40e195917a951a8bf867cd05de2a46aaf1806c50cf92eebf4c16f78cd196f747" + name = "github.com/pkg/errors" + packages = ["."] + pruneopts = "UT" + revision = "645ef00459ed84a119197bfb8d8205042c6df63d" + version = "v0.8.0" + +[[projects]] + digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe" + name = "github.com/pmezard/go-difflib" + packages = ["difflib"] + pruneopts = "UT" + revision = "792786c7400a136282c1664665ae0a8db921c6c2" + version = "v1.0.0" + +[[projects]] + digest = "1:18752d0b95816a1b777505a97f71c7467a8445b8ffb55631a7bf779f6ba4fa83" + name = "github.com/stretchr/testify" + packages = ["assert"] + pruneopts = "UT" + revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686" + version = "v1.2.2" + +[[projects]] + branch = "master" + digest = "1:6d5ed712653ea5321fe3e3475ab2188cf362a4e0d31e9fd3acbd4dfbbca0d680" + name = "golang.org/x/net" + packages = [ + "context", + "html", + "html/atom", + "html/charset", + ] + pruneopts = "UT" + revision = "c44066c5c816ec500d459a2a324a753f78531ae0" + +[[projects]] + branch = "master" + digest = "1:466e5917ea5f69d435d0ab3015dc4b57b80d34a6caf1104097ac82ab462b86e4" + name = "golang.org/x/sys" + packages = ["unix"] + pruneopts = "UT" + revision = "7e31e0c00fa05cb5fbf4347b585621d6709e19a4" + +[[projects]] + digest = "1:aa4d6967a3237f8367b6bf91503964a77183ecf696f1273e8ad3551bb4412b5f" + name = "golang.org/x/text" + packages = [ + "encoding", + "encoding/charmap", + "encoding/htmlindex", + "encoding/internal", + "encoding/internal/identifier", + "encoding/japanese", + "encoding/korean", + "encoding/simplifiedchinese", + "encoding/traditionalchinese", + "encoding/unicode", + "internal/gen", + "internal/tag", + "internal/utf8internal", + "language", + "runes", + "transform", + "unicode/cldr", + ] + pruneopts = "UT" + revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" + version = "v0.3.0" + +[[projects]] + digest = "1:abeb38ade3f32a92943e5be54f55ed6d6e3b6602761d74b4aab4c9dd45c18abd" + name = "gopkg.in/fsnotify/fsnotify.v1" + packages = ["."] + pruneopts = "UT" + revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9" + version = "v1.4.7" + +[[projects]] + digest = "1:3c839a777de0e6da035c9de900b60cbec463b0a89351192c1ea083eaf9e0fce0" + name = "gopkg.in/tomb.v1" + packages = ["."] + pruneopts = "UT" + revision = "c131134a1947e9afd9cecfe11f4c6dff0732ae58" + +[[projects]] + digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202" + name = "gopkg.in/yaml.v2" + packages = ["."] + pruneopts = "UT" + revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" + version = "v2.2.1" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + input-imports = [ + "github.com/golang/mock/gomock", + "github.com/neo4j-drivers/gobolt", + "github.com/onsi/ginkgo", + "github.com/onsi/ginkgo/extensions/table", + "github.com/onsi/ginkgo/reporters", + "github.com/onsi/gomega", + "github.com/onsi/gomega/types", + "github.com/pkg/errors", + "github.com/stretchr/testify/assert", + ] + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/Gopkg.toml b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/Gopkg.toml new file mode 100644 index 0000000..809886a --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/Gopkg.toml @@ -0,0 +1,54 @@ +# Gopkg.toml example +# +# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + + +[[constraint]] + name = "github.com/golang/mock" + version = "1.1.1" + +[[constraint]] + name = "github.com/neo4j-drivers/gobolt" + version = "1.7.x" + +[[constraint]] + name = "github.com/onsi/ginkgo" + version = "1.6.0" + +[[constraint]] + name = "github.com/onsi/gomega" + version = "1.4.2" + +[[constraint]] + name = "github.com/pkg/errors" + version = "0.8.0" + +[prune] + go-tests = true + unused-packages = true + +[[constraint]] + name = "github.com/stretchr/testify" + version = "1.2.2" diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/auth_tokens.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/auth_tokens.go new file mode 100644 index 0000000..99752b3 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/auth_tokens.go @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +// AuthToken contains credentials to be sent over to the neo4j server. +type AuthToken struct { + tokens map[string]interface{} +} + +const keyScheme = "scheme" +const schemeNone = "none" +const schemeBasic = "basic" +const schemeKerberos = "kerberos" +const keyPrincipal = "principal" +const keyCredentials = "credentials" +const keyRealm = "realm" +const keyTicket = "ticket" + +// NoAuth generates an empty authentication token +func NoAuth() AuthToken { + return AuthToken{tokens: map[string]interface{}{ + keyScheme: schemeNone, + }} +} + +// BasicAuth generates a basic authentication token with provided username, password and realm +func BasicAuth(username string, password string, realm string) AuthToken { + tokens := map[string]interface{}{ + keyScheme: schemeBasic, + keyPrincipal: username, + keyCredentials: password, + } + + if realm != "" { + tokens[keyRealm] = realm + } + + return AuthToken{tokens: tokens} +} + +// KerberosAuth generates a kerberos authentication token with provided base-64 encoded kerberos ticket +func KerberosAuth(ticket string) AuthToken { + token := AuthToken{ + tokens: map[string]interface{}{ + keyScheme: schemeKerberos, + keyTicket: ticket, + }, + } + + return token +} + +// CustomAuth generates a custom authentication token with provided parameters +func CustomAuth(scheme string, username string, password string, realm string, parameters map[string]interface{}) AuthToken { + tokens := map[string]interface{}{ + keyScheme: scheme, + keyPrincipal: username, + keyCredentials: password, + } + + if realm != "" { + tokens[keyRealm] = realm + } + + if parameters != nil { + tokens["parameters"] = parameters + } + + return AuthToken{tokens: tokens} +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/auth_tokens_test.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/auth_tokens_test.go new file mode 100644 index 0000000..1fda81d --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/auth_tokens_test.go @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("AuthTokens", func() { + Describe("NoAuth", func() { + When("invoked", func() { + token := NoAuth() + + tokenMap := token.tokens + + Context("the token", func() { + It("should have 1 item", func() { + Expect(tokenMap).To(HaveLen(1)) + }) + + It("should contain scheme=none", func() { + Expect(tokenMap).To(HaveKeyWithValue(keyScheme, schemeNone)) + }) + }) + }) + }) + + Describe("BasicAuth", func() { + When("invoked with username and password only", func() { + token := BasicAuth("test", "1234", "") + + tokenMap := token.tokens + + Context("the token", func() { + It("should have 3 items", func() { + Expect(tokenMap).To(HaveLen(3)) + }) + + It("should contain scheme=basic", func() { + Expect(tokenMap).To(HaveKeyWithValue(keyScheme, schemeBasic)) + }) + + It("should contain principal=test", func() { + Expect(tokenMap).To(HaveKeyWithValue(keyPrincipal, "test")) + }) + + It("should contain credentials=1234", func() { + Expect(tokenMap).To(HaveKeyWithValue(keyCredentials, "1234")) + }) + }) + }) + + When("invoked with username, password and realm", func() { + token := BasicAuth("test", "1234", "a_realm") + + tokenMap := token.tokens + + Context("the token", func() { + It("should have 4 items", func() { + Expect(tokenMap).To(HaveLen(4)) + }) + + It("should contain scheme=basic", func() { + Expect(tokenMap).To(HaveKeyWithValue(keyScheme, schemeBasic)) + }) + + It("should contain principal=test", func() { + Expect(tokenMap).To(HaveKeyWithValue(keyPrincipal, "test")) + }) + + It("should contain credentials=1234", func() { + Expect(tokenMap).To(HaveKeyWithValue(keyCredentials, "1234")) + }) + + It("should contain realm=a_realm", func() { + Expect(tokenMap).To(HaveKeyWithValue(keyRealm, "a_realm")) + }) + }) + }) + }) + + Describe("KerberosAuth", func() { + When("invoked with ticket data", func() { + token := KerberosAuth("ticket_data") + + tokenMap := token.tokens + + Context("the token", func() { + It("should have 2 items", func() { + Expect(tokenMap).To(HaveLen(2)) + }) + + It("should contain scheme=kerberos", func() { + Expect(tokenMap).To(HaveKeyWithValue(keyScheme, schemeKerberos)) + }) + + It("should contain ticket=ticket_data", func() { + Expect(tokenMap).To(HaveKeyWithValue(keyTicket, "ticket_data")) + }) + }) + }) + }) + + Describe("CustomAuth", func() { + When("invoked with scheme, username and password", func() { + token := CustomAuth("custom", "un", "pw", "", nil) + + tokenMap := token.tokens + + Context("the token", func() { + It("should have 3 items", func() { + Expect(tokenMap).To(HaveLen(3)) + }) + + It("should contain scheme=custom", func() { + Expect(tokenMap).To(HaveKeyWithValue(keyScheme, "custom")) + }) + + It("should contain principal=un", func() { + Expect(tokenMap).To(HaveKeyWithValue(keyPrincipal, "un")) + }) + + It("should contain credentials=pw", func() { + Expect(tokenMap).To(HaveKeyWithValue(keyCredentials, "pw")) + }) + }) + }) + + When("invoked with scheme, username, password and realm", func() { + token := CustomAuth("custom", "un", "pw", "realm", nil) + + tokenMap := token.tokens + + Context("the token", func() { + It("should have 4 items", func() { + Expect(tokenMap).To(HaveLen(4)) + }) + + It("should contain scheme=custom", func() { + Expect(tokenMap).To(HaveKeyWithValue(keyScheme, "custom")) + }) + + It("should contain principal=un", func() { + Expect(tokenMap).To(HaveKeyWithValue(keyPrincipal, "un")) + }) + + It("should contain credentials=pw", func() { + Expect(tokenMap).To(HaveKeyWithValue(keyCredentials, "pw")) + }) + + It("should contain realm=realm", func() { + Expect(tokenMap).To(HaveKeyWithValue(keyRealm, "realm")) + }) + }) + }) + + When("invoked with scheme, username, password, realm and parameters", func() { + params := map[string]interface{}{ + "user_id": "1234", + "user_emails": []string{"a@b.com", "b@c.com"}, + } + + token := CustomAuth("custom", "un", "pw", "realm", params) + + tokenMap := token.tokens + + Context("the token", func() { + It("should have 5 items", func() { + Expect(tokenMap).To(HaveLen(5)) + }) + + It("should contain scheme=custom", func() { + Expect(tokenMap).To(HaveKeyWithValue(keyScheme, "custom")) + }) + + It("should contain principal=un", func() { + Expect(tokenMap).To(HaveKeyWithValue(keyPrincipal, "un")) + }) + + It("should contain credentials=pw", func() { + Expect(tokenMap).To(HaveKeyWithValue(keyCredentials, "pw")) + }) + + It("should contain realm=realm", func() { + Expect(tokenMap).To(HaveKeyWithValue(keyRealm, "realm")) + }) + + It("should contain given parameters", func() { + Expect(tokenMap).To(HaveKeyWithValue("parameters", params)) + }) + }) + }) + }) +}) diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/config.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/config.go new file mode 100644 index 0000000..8de3d54 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/config.go @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "math" + "time" +) + +// A Config contains options that can be used to customize certain +// aspects of the driver +type Config struct { + // Whether to turn on/off TLS encryption. + // + // default: true + Encrypted bool + // Sets how the driver establishes trust with the Neo4j instance + // it is connected to. + // + // default: TrustAny(false) + TrustStrategy TrustStrategy + // Logging target the driver will send its log outputs + // + // default: No Op Logger + Log Logging + // Resolver that would be used to resolve initial router address. This may + // be useful if you want to provide more than one URL for initial router. + // If not specified, the provided bolt+routing URL is used as the initial + // router. + // + // default: nil + AddressResolver ServerAddressResolver + // Maximum amount of time a retriable operation would continue retrying. It + // cannot be specified as a negative value. + // + // default: 30 * time.Second + MaxTransactionRetryTime time.Duration + // Maximum number of connections per URL to allow on this driver. It + // cannot be specified as 0 and negative values are interpreted as + // math.MaxInt32. + // + // default: 100 + MaxConnectionPoolSize int + // Maximum connection life time on pooled connections. Values less than + // or equal to 0 disables the lifetime check. + // + // default: 1 * time.Hour + MaxConnectionLifetime time.Duration + // Maximum amount of time to either acquire an idle connection from the pool + // or create a new connection (when the pool is not full). Negative values + // result in an infinite wait time where 0 value results in no timeout which + // results in immediate failure when there are no available connections. + // + // default: 1 * time.Minute + ConnectionAcquisitionTimeout time.Duration + // Connect timeout that will be set on underlying sockets. Values less than + // or equal to 0 results in no timeout being applied. + // + // default: 5 * time.Second + SocketConnectTimeout time.Duration + // Whether to enable TCP keep alive on underlying sockets. + // + // default: true + SocketKeepalive bool +} + +func defaultConfig() *Config { + return &Config{ + Encrypted: true, + TrustStrategy: TrustAny(false), + Log: NoOpLogger(), + AddressResolver: nil, + MaxTransactionRetryTime: 30 * time.Second, + MaxConnectionPoolSize: 100, + MaxConnectionLifetime: 1 * time.Hour, + ConnectionAcquisitionTimeout: 1 * time.Minute, + SocketConnectTimeout: 5 * time.Second, + SocketKeepalive: true, + } +} + +func validateAndNormaliseConfig(config *Config) error { + // Max Transaction Retry Time + if config.MaxTransactionRetryTime < 0 { + return newDriverError("maximum transaction retry time cannot be smaller than 0, but was %v", config.MaxTransactionRetryTime) + } + + // Max Connection Pool Size + if config.MaxConnectionPoolSize == 0 { + return newDriverError("maximum connection pool size cannot be 0") + } + + if config.MaxConnectionPoolSize < 0 { + config.MaxConnectionPoolSize = math.MaxInt32 + } + + // Max Connection Lifetime + if config.MaxConnectionLifetime < 0 { + config.MaxConnectionLifetime = 0 + } + + // Connection Acquisition Timeout + if config.ConnectionAcquisitionTimeout < 0 { + config.ConnectionAcquisitionTimeout = -1 + } + + // Socket Connect Timeout + if config.SocketConnectTimeout < 0 { + config.SocketConnectTimeout = 0 + } + + return nil +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/config_resolver.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/config_resolver.go new file mode 100644 index 0000000..0043b50 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/config_resolver.go @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "net/url" + + "github.com/neo4j-drivers/gobolt" +) + +// ServerAddress represents a host and port. Host can either be an IP address or a DNS name. +// Both IPv4 and IPv6 hosts are supported. +type ServerAddress interface { + // Hostname returns the host portion of this ServerAddress. + Hostname() string + // Port returns the port portion of this ServerAddress. + Port() string +} + +// ServerAddressResolver is a function type that defines the resolver function used by the routing driver to +// resolve the initial address used to create the driver. +type ServerAddressResolver func(address ServerAddress) []ServerAddress + +func newServerAddressURL(hostname string, port string) *url.URL { + if hostname == "" { + return nil + } + + hostAndPort := hostname + if port != "" { + hostAndPort = hostAndPort + ":" + port + } + + return &url.URL{Host: hostAndPort} +} + +// NewServerAddress generates a ServerAddress with provided hostname and port information. +func NewServerAddress(hostname string, port string) ServerAddress { + return newServerAddressURL(hostname, port) +} + +func wrapAddressResolverOrNil(addressResolver ServerAddressResolver) gobolt.URLAddressResolver { + if addressResolver == nil { + return nil + } + + return func(address *url.URL) []*url.URL { + var result []*url.URL + + for _, address := range addressResolver(address) { + result = append(result, newServerAddressURL(address.Hostname(), address.Port())) + } + + return result + } +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/config_test.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/config_test.go new file mode 100644 index 0000000..ebde01f --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/config_test.go @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "math" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Config", func() { + Context("defaultConfig", func() { + config := defaultConfig() + + It("should have encryption turned on", func() { + Expect(config.Encrypted).To(BeTrue()) + }) + + It("should have trust strategy equal to TrustAny(false)", func() { + Expect(config.TrustStrategy).To(Equal(TrustAny(false))) + }) + + It("should have max transaction retry duration as 30s", func() { + Expect(config.MaxTransactionRetryTime).To(BeIdenticalTo(30 * time.Second)) + }) + + It("should have max connection pool size to be 100", func() { + Expect(config.MaxConnectionPoolSize).To(BeEquivalentTo(100)) + }) + + It("should have max connection lifetime to be 1h", func() { + Expect(config.MaxConnectionLifetime).To(BeIdenticalTo(1 * time.Hour)) + }) + + It("should have connection acquisition timeout to be 1m", func() { + Expect(config.ConnectionAcquisitionTimeout).To(BeIdenticalTo(1 * time.Minute)) + }) + + It("should have socket connect timeout to be 5s", func() { + Expect(config.SocketConnectTimeout).To(BeIdenticalTo(5 * time.Second)) + }) + + It("should have socket keep alive enabled", func() { + Expect(config.SocketKeepalive).To(BeTrue()) + }) + + It("should have non-nil logger", func() { + Expect(config.Log).NotTo(BeNil()) + }) + + It("should have an internalLogger logger with level set to 0", func() { + logger, ok := config.Log.(*internalLogger) + Expect(ok).To(BeTrue()) + + Expect(logger.level).To(BeZero()) + }) + }) + + Context("validateAndNormaliseConfig", func() { + It("should return error when MaxTransactionRetryTime is less than 0", func() { + config := defaultConfig() + config.MaxTransactionRetryTime = -1 * time.Second + + err := validateAndNormaliseConfig(config) + Expect(err).NotTo(BeNil()) + Expect(err.Error()).To(ContainSubstring("maximum transaction retry time cannot be smaller than 0")) + }) + + It("should return error when MaxConnectionPoolSize is 0", func() { + config := defaultConfig() + config.MaxConnectionPoolSize = 0 + + err := validateAndNormaliseConfig(config) + Expect(err).NotTo(BeNil()) + Expect(err.Error()).To(ContainSubstring("maximum connection pool size cannot be 0")) + }) + + It("should normalize MaxConnectionPoolSize to MaxInt32 when negative", func() { + config := defaultConfig() + config.MaxConnectionPoolSize = -1 + + err := validateAndNormaliseConfig(config) + Expect(err).To(BeNil()) + + Expect(config.MaxConnectionPoolSize).To(Equal(math.MaxInt32)) + }) + + It("should normalize ConnectionAcquisitionTimeout to -1ns when negative", func() { + config := defaultConfig() + config.ConnectionAcquisitionTimeout = -1 * time.Second + + err := validateAndNormaliseConfig(config) + Expect(err).To(BeNil()) + + Expect(config.ConnectionAcquisitionTimeout).To(Equal(-1 * time.Nanosecond)) + }) + + It("should normalize SocketConnectTimeout to 0 when negative", func() { + config := defaultConfig() + config.SocketConnectTimeout = -1 * time.Second + + err := validateAndNormaliseConfig(config) + Expect(err).To(BeNil()) + + Expect(config.SocketConnectTimeout).To(Equal(0 * time.Nanosecond)) + }) + }) + +}) diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/config_trust.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/config_trust.go new file mode 100644 index 0000000..0a1dbd8 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/config_trust.go @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import "crypto/x509" + +// TrustStrategy defines how the driver will establish trust with the neo4j instance +type TrustStrategy struct { + certificates []*x509.Certificate + skipVerify bool + skipVerifyHostname bool +} + +// TrustAny returns a trust strategy which skips trust verification (trusts any certificate +// provided) and whose hostname verification can be enabled/disabled based on the provided +// parameter +func TrustAny(verifyHostname bool) TrustStrategy { + return TrustStrategy{ + certificates: nil, + skipVerify: true, + skipVerifyHostname: !verifyHostname, + } +} + +// TrustSystem returns a trust strategy which uses system provided certificates for +// trust verification and whose hostname verification can be enabled/disabled based +// on the provided parameter +func TrustSystem(verifyHostname bool) TrustStrategy { + return TrustStrategy{ + certificates: nil, + skipVerify: false, + skipVerifyHostname: !verifyHostname, + } +} + +// TrustOnly returns a trust strategy which uses provided certificates for trust +// verification and whose hostname verification can be enabled/disabled based +// on the provided parameter +func TrustOnly(verifyHostname bool, certs ...*x509.Certificate) TrustStrategy { + return TrustStrategy{ + certificates: certs, + skipVerify: false, + skipVerifyHostname: !verifyHostname, + } +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/driver.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/driver.go new file mode 100644 index 0000000..81ce9a9 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/driver.go @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Package neo4j provides required functionality to connect and execute statements against a Neo4j Database. +package neo4j + +import ( + "net/url" +) + +// AccessMode defines modes that routing driver decides to which cluster member +// a connection should be opened. +type AccessMode int + +const ( + // AccessModeWrite tells the driver to use a connection to 'Leader' + AccessModeWrite AccessMode = 0 + // AccessModeRead tells the driver to use a connection to one of the 'Follower' or 'Read Replica'. + AccessModeRead AccessMode = 1 +) + +// Driver represents a pool(s) of connections to a neo4j server or cluster. It's +// safe for concurrent use. +type Driver interface { + // The url this driver is bootstrapped + Target() url.URL + Session(accessMode AccessMode, bookmarks ...string) (Session, error) + // Close the driver and all underlying connections + Close() error +} + +// NewDriver is the entry point to the neo4j driver to create an instance of a Driver. It is the first function to +// be called in order to establish a connection to a neo4j database. It requires a Bolt URI and an authentication +// token as parameters and can also take optional configuration function(s) as variadic parameters. +// +// In order to connect to a single instance database, you need to pass a URI with scheme 'bolt' +// driver, err = NewDriver("bolt://db.server:7687", BasicAuth(username, password)) +// +// In order to connect to a causal cluster database, you need to pass a URI with scheme 'bolt+routing' or 'neo4j' +// and its host part set to be one of the core cluster members. Please note that 'bolt+routing' scheme will be +// removed with 2.0 series of drivers. +// driver, err = NewDriver("bolt+routing://core.db.server:7687", BasicAuth(username, password)) +// +// You can override default configuration options by providing a configuration function(s) +// driver, err = NewDriver(uri, BasicAuth(username, password), function (config *Config) { +// config.MaxConnectionPoolSize = 10 +// }) +func NewDriver(target string, auth AuthToken, configurers ...func(*Config)) (Driver, error) { + parsed, err := url.Parse(target) + if err != nil { + return nil, err + } + + if parsed.Scheme != "bolt" && parsed.Scheme != "bolt+routing" && parsed.Scheme != "neo4j" { + return nil, newDriverError("url scheme %s is not supported", parsed.Scheme) + } + + if parsed.Scheme == "bolt" && len(parsed.RawQuery) > 0 { + return nil, newDriverError("routing context is not supported for direct driver") + } + + config := defaultConfig() + for _, configurer := range configurers { + configurer(config) + } + + if err := validateAndNormaliseConfig(config); err != nil { + return nil, err + } + + return newGoboltDriver(parsed, auth, config) +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/driver_test.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/driver_test.go new file mode 100644 index 0000000..ec2e370 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/driver_test.go @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + . "github.com/neo4j/neo4j-go-driver/neo4j/utils/test" + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/extensions/table" + . "github.com/onsi/gomega" +) + +var _ = Describe("Driver", func() { + + Context("URI", func() { + It("should support bolt:// scheme", func() { + driver, err := NewDriver("bolt://localhost:7687", NoAuth()) + + Expect(err).To(BeNil()) + Expect(driver).NotTo(BeNil()) + Expect(driver.Target().Scheme).To(BeIdenticalTo("bolt")) + }) + + It("should support bolt+routing:// scheme", func() { + driver, err := NewDriver("bolt+routing://localhost:7687", NoAuth()) + + Expect(err).To(BeNil()) + Expect(driver).NotTo(BeNil()) + Expect(driver.Target().Scheme).To(BeIdenticalTo("bolt+routing")) + }) + + It("should support neo4j:// scheme", func() { + driver, err := NewDriver("neo4j://localhost:7687", NoAuth()) + + Expect(err).To(BeNil()) + Expect(driver).NotTo(BeNil()) + Expect(driver.Target().Scheme).To(BeIdenticalTo("neo4j")) + }) + + It("should error anotherscheme:// scheme", func() { + driver, err := NewDriver("anotherscheme://localhost:7687", NoAuth()) + + Expect(driver).To(BeNil()) + Expect(err).To(BeGenericError(ContainSubstring("url scheme anotherscheme is not supported"))) + }) + }) + + When("constructed with bolt://localhost:7687", func() { + driver, err := NewDriver("bolt://localhost:7687", NoAuth()) + + It("no errors should be returned", func() { + Expect(err).To(BeNil()) + }) + + When("closed", func() { + err := driver.Close() + It("no errors should be returned", func() { + Expect(err).To(BeNil()) + }) + + It("should not allow new read mode sessions", func() { + session, err := driver.Session(AccessModeRead) + Expect(err).NotTo(BeNil()) + Expect(session).To(BeNil()) + }) + + It("should not allow new write mode sessions", func() { + session, err := driver.Session(AccessModeWrite) + Expect(err).NotTo(BeNil()) + Expect(session).To(BeNil()) + }) + + It("should allow more close calls", func() { + err := driver.Close() + Expect(err).To(BeNil()) + }) + }) + + driverTarget := driver.Target() + + Context("driver's", func() { + It("target scheme should be bolt", func() { + Expect(driverTarget.Scheme).To(BeIdenticalTo("bolt")) + }) + + It("target hostname should be localhost", func() { + Expect(driverTarget.Hostname()).To(BeIdenticalTo("localhost")) + }) + + It("target port should be 7687", func() { + Expect(driverTarget.Port()).To(BeIdenticalTo("7687")) + }) + }) + }) + + Describe("Session", func() { + When("constructed", func() { + type SessionTestCase struct { + uri string + mode AccessMode + bookmarks []string + } + + DescribeTable("should conform to given parameters", func(testCase SessionTestCase) { + driver, err := NewDriver(testCase.uri, NoAuth()) + Expect(err).To(BeNil()) + + session, err := driver.Session(testCase.mode, testCase.bookmarks...) + Expect(err).To(BeNil()) + + neoSession := session.(*neoSession) + + Expect(neoSession.accessMode).To(BeIdenticalTo(testCase.mode)) + + Expect(neoSession.bookmarks).To(HaveLen(len(testCase.bookmarks))) + Expect(neoSession.bookmarks).To(ConsistOf(testCase.bookmarks)) + }, Entry("(write, no_bookmark)", SessionTestCase{ + uri: "bolt://localhost:7687", + mode: AccessModeWrite, + bookmarks: []string(nil), + }), Entry("(read, no_bookmark)", SessionTestCase{ + uri: "bolt://localhost:7687", + mode: AccessModeRead, + bookmarks: []string(nil), + }), Entry("(write, one bookmark)", SessionTestCase{ + uri: "bolt://localhost:7687", + mode: AccessModeWrite, + bookmarks: []string{"B1"}, + }), Entry("(read, one bookmark)", SessionTestCase{ + uri: "bolt://localhost:7687", + mode: AccessModeRead, + bookmarks: []string{"B1"}, + }), Entry("(write, multiple bookmarks)", SessionTestCase{ + uri: "bolt://localhost:7687", + mode: AccessModeWrite, + bookmarks: []string{"B1", "B2"}, + }), Entry("(read, multiple bookmarks)", SessionTestCase{ + uri: "bolt://localhost:7687", + mode: AccessModeRead, + bookmarks: []string{"B3", "B4"}, + })) + + }) + }) +}) diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/error.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/error.go new file mode 100644 index 0000000..6fa77ba --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/error.go @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import "C" +import ( + "fmt" + + "github.com/neo4j-drivers/gobolt" +) + +type databaseError struct { + classification string + code string + message string +} + +type connectorError struct { + state int + code int + codeText string + context string + description string +} + +type driverError struct { + message string +} + +type sessionExpiredError struct { + message string +} + +func (failure *databaseError) BoltError() bool { + return true +} + +func (failure *databaseError) Classification() string { + return failure.classification +} + +func (failure *databaseError) Code() string { + return failure.code +} + +func (failure *databaseError) Message() string { + return failure.message +} + +func (failure *databaseError) Error() string { + return fmt.Sprintf("database returned error [%s]: %s", failure.code, failure.message) +} + +func (failure *connectorError) BoltError() bool { + return true +} + +func (failure *connectorError) State() int { + return failure.state +} + +func (failure *connectorError) Code() int { + return failure.code +} + +func (failure *connectorError) Context() string { + return failure.context +} + +func (failure *connectorError) Description() string { + return failure.description +} + +func (failure *connectorError) Error() string { + if failure.description != "" { + return fmt.Sprintf("%s: error: [%d] %s, state: %d, context: %s", failure.description, failure.code, failure.codeText, failure.state, failure.context) + } else { + return fmt.Sprintf("error: [%d] %s, state: %d, context: %s", failure.code, failure.codeText, failure.state, failure.context) + } +} + +func (failure *driverError) BoltError() bool { + return true +} + +func (failure *driverError) Message() string { + return failure.message +} + +func (failure *driverError) Error() string { + return failure.message +} + +func (failure *sessionExpiredError) BoltError() bool { + return true +} + +func (failure *sessionExpiredError) Error() string { + return failure.message +} + +func newDriverError(format string, args ...interface{}) gobolt.GenericError { + return &driverError{message: fmt.Sprintf(format, args...)} +} + +func newSessionExpiredError(format string, args ...interface{}) error { + return &sessionExpiredError{message: fmt.Sprintf(format, args...)} +} + +func newDatabaseError(classification, code, message string) gobolt.DatabaseError { + return &databaseError{code: code, message: message, classification: classification} +} + +func newConnectorError(state int, code int, codeText, context, description string) gobolt.ConnectorError { + return &connectorError{state: state, code: code, codeText: codeText, context: context, description: description} +} + +func isRetriableError(err error) bool { + return gobolt.IsServiceUnavailable(err) || gobolt.IsTransientError(err) || gobolt.IsWriteError(err) +} + +// IsSecurityError is a utility method to check if the provided error is related with any +// TLS failure or authentication issues. +func IsSecurityError(err error) bool { + return gobolt.IsSecurityError(err) +} + +// IsAuthenticationError is a utility method to check if the provided error is related with any +// authentication issues. +func IsAuthenticationError(err error) bool { + return gobolt.IsAuthenticationError(err) +} + +// IsClientError is a utility method to check if the provided error is related with the client +// carrying out an invalid operation. +func IsClientError(err error) bool { + return gobolt.IsClientError(err) +} + +// IsTransientError is a utility method to check if the provided error is related with a temporary +// failure that may be worked around by retrying. +func IsTransientError(err error) bool { + return gobolt.IsTransientError(err) +} + +// IsSessionExpired is a utility method to check if the session no longer satisfy the criteria +// under which it was acquired, e.g. a server no longer accepts write requests. +func IsSessionExpired(err error) bool { + if _, ok := err.(*sessionExpiredError); ok { + return true + } + + return gobolt.IsSessionExpired(err) +} + +// IsServiceUnavailable is a utility method to check if the provided error can be classified +// to be in service unavailable category. +func IsServiceUnavailable(err error) bool { + return gobolt.IsServiceUnavailable(err) +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/error_test.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/error_test.go new file mode 100644 index 0000000..b61acfc --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/error_test.go @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "github.com/pkg/errors" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/extensions/table" + . "github.com/onsi/gomega" +) + +var _ = Describe("Error", func() { + + Context("IsSecurityError", func() { + When("provided with a ConnectorError with BOLT_TLS_ERROR code", func() { + const ( + BOLT_TLS_ERROR = 13 + BOLT_DEFUNCT = 4 + ) + + err := newConnectorError(BOLT_DEFUNCT, BOLT_TLS_ERROR, "BOLT_TLS_ERROR", "some context", "some description") + + It("should return true", func() { + Expect(IsSecurityError(err)).To(BeTrue()) + }) + }) + + When("provided with a DatabaseError with Neo.ClientError.Security.Unauthorized code", func() { + err := newDatabaseError("ClientError", "Neo.ClientError.Security.Unauthorized", "unauthorized") + + It("should return true", func() { + Expect(IsSecurityError(err)).To(BeTrue()) + }) + }) + + When("provided with a ConnectorError with random code", func() { + const ( + BOLT_CONNECTION_RESET = 4 + BOLT_DEFUNCT = 4 + ) + err := newConnectorError(BOLT_DEFUNCT, BOLT_CONNECTION_RESET, "BOLT_CONNECTION_RESET", "some context", "some description") + + It("should return false", func() { + Expect(IsSecurityError(err)).To(BeFalse()) + }) + }) + + When("provided with a DatabaseError with random code", func() { + err := newDatabaseError("TransientError", "Neo.TransientError.Transaction.Terminated", "terminated") + + It("should return false", func() { + Expect(IsSecurityError(err)).To(BeFalse()) + }) + }) + + When("provided with generic error type", func() { + err := newDriverError("some error") + + It("should return false", func() { + Expect(IsSecurityError(err)).To(BeFalse()) + }) + }) + + When("provided with another error type", func() { + err := errors.New("some error") + + It("should return false", func() { + Expect(IsSecurityError(err)).To(BeFalse()) + }) + }) + }) + + Context("IsAuthenticationError", func() { + When("provided with a ConnectorError with BOLT_PERMISSION_DENIED code", func() { + const ( + BOLT_PERMISSION_DENIED = 7 + BOLT_DEFUNCT = 4 + ) + + err := newConnectorError(BOLT_DEFUNCT, BOLT_PERMISSION_DENIED, "BOLT_PERMISSION_DENIED", "some context", "some description") + + It("should return true", func() { + Expect(IsAuthenticationError(err)).To(BeTrue()) + }) + }) + + When("provided with a DatabaseError with Neo.ClientError.Security.Unauthorized code", func() { + err := newDatabaseError("ClientError", "Neo.ClientError.Security.Unauthorized", "unauthorized") + + It("should return true", func() { + Expect(IsAuthenticationError(err)).To(BeTrue()) + }) + }) + + When("provided with a ConnectorError with random code", func() { + const ( + BOLT_CONNECTION_RESET = 4 + BOLT_DEFUNCT = 4 + ) + err := newConnectorError(BOLT_DEFUNCT, BOLT_CONNECTION_RESET, "BOLT_CONNECTION_RESET", "some context", "some description") + + It("should return false", func() { + Expect(IsAuthenticationError(err)).To(BeFalse()) + }) + }) + + When("provided with a DatabaseError with random code", func() { + err := newDatabaseError("TransientError", "Neo.TransientError.Transaction.Terminated", "terminated") + + It("should return false", func() { + Expect(IsAuthenticationError(err)).To(BeFalse()) + }) + }) + + When("provided with generic error type", func() { + err := newDriverError("some error") + + It("should return false", func() { + Expect(IsAuthenticationError(err)).To(BeFalse()) + }) + }) + + When("provided with another error type", func() { + err := errors.New("some error") + + It("should return false", func() { + Expect(IsAuthenticationError(err)).To(BeFalse()) + }) + }) + }) + + Context("IsClientError", func() { + When("provided with a DatabaseError with ClientError classification", func() { + err := newDatabaseError("ClientError", "Neo.ClientError.Statement.Invalid", "invalid statement") + + It("should return true", func() { + Expect(IsClientError(err)).To(BeTrue()) + }) + }) + + When("provided with a generic error", func() { + err := newDriverError("some error") + + It("should return true", func() { + Expect(IsClientError(err)).To(BeTrue()) + }) + }) + + When("provided with a DatabaseError with Neo.ClientError.Security.Unauthorized code", func() { + err := newDatabaseError("ClientError", "Neo.ClientError.Security.Unauthorized", "unauthorized") + + It("should return false", func() { + Expect(IsClientError(err)).To(BeFalse()) + }) + }) + + When("provided with a ConnectorError", func() { + err := newConnectorError(0, 13, "some text", "some context", "some description") + + It("should return false", func() { + Expect(IsClientError(err)).To(BeFalse()) + }) + }) + + When("provided with another error type", func() { + err := errors.New("some error") + + It("should return false", func() { + Expect(IsClientError(err)).To(BeFalse()) + }) + }) + + }) + + Context("IsTransientError", func() { + When("provided with a DatabaseError with TransientError classification", func() { + err := newDatabaseError("TransientError", "Neo.TransientError.Transaction.Timeout", "timeout") + + It("should return true", func() { + Expect(IsTransientError(err)).To(BeTrue()) + }) + }) + + When("provided with a DatabaseError with Neo.TransientError.Transaction.Terminated code", func() { + err := newDatabaseError("TransientError", "Neo.TransientError.Transaction.Terminated", "terminated") + + It("should return false", func() { + Expect(IsTransientError(err)).To(BeFalse()) + }) + }) + + When("provided with a DatabaseError with Neo.TransientError.Transaction.LockClientStopped code", func() { + err := newDatabaseError("TransientError", "Neo.TransientError.Transaction.LockClientStopped", "terminated") + + It("should return false", func() { + Expect(IsTransientError(err)).To(BeFalse()) + }) + }) + + When("provided with a generic error", func() { + err := newDriverError("some error") + + It("should return false", func() { + Expect(IsTransientError(err)).To(BeFalse()) + }) + }) + + When("provided with a ConnectorError", func() { + err := newConnectorError(0, 13, "some text", "some context", "some description") + + It("should return false", func() { + Expect(IsTransientError(err)).To(BeFalse()) + }) + }) + + When("provided with another error type", func() { + err := errors.New("some error") + + It("should return false", func() { + Expect(IsTransientError(err)).To(BeFalse()) + }) + }) + }) + + Context("IsSessionExpired", func() { + When("provided with a sessionExpiredError", func() { + err := &sessionExpiredError{message: "error"} + + It("should return true", func() { + Expect(IsSessionExpired(err)).To(BeTrue()) + }) + }) + + When("provided with a ConnectorError with BOLT_ROUTING_NO_SERVERS_TO_SELECT code", func() { + const ( + BOLT_ROUTING_NO_SERVERS_TO_SELECT = 0x801 + BOLT_DEFUNCT = 4 + ) + + err := newConnectorError(BOLT_DEFUNCT, BOLT_ROUTING_NO_SERVERS_TO_SELECT, "BOLT_ROUTING_NO_SERVERS_TO_SELECT", "some context", "some description") + + It("should return true", func() { + Expect(IsSessionExpired(err)).To(BeTrue()) + }) + }) + + When("provided with a ConnectorError with random code", func() { + const ( + BOLT_TLS_ERROR = 13 + BOLT_DEFUNCT = 4 + ) + + err := newConnectorError(BOLT_DEFUNCT, BOLT_TLS_ERROR, "BOLT_TLS_ERROR", "some context", "some description") + + It("should return true", func() { + Expect(IsSessionExpired(err)).To(BeFalse()) + }) + }) + + When("provided with a database error", func() { + err := newDatabaseError("ClientError", "Neo.TransientError.Transaction.LockClientStopped", "some error") + + It("should return false", func() { + Expect(IsSessionExpired(err)).To(BeFalse()) + }) + }) + + When("provided with a generic error", func() { + err := newDriverError("some error") + + It("should return false", func() { + Expect(IsSessionExpired(err)).To(BeFalse()) + }) + }) + + When("provided with a ConnectorError", func() { + err := newConnectorError(0, 13, "some text", "some context", "some description") + + It("should return false", func() { + Expect(IsSessionExpired(err)).To(BeFalse()) + }) + }) + + When("provided with another error type", func() { + err := errors.New("some error") + + It("should return false", func() { + Expect(IsSessionExpired(err)).To(BeFalse()) + }) + }) + }) + + Context("IsServiceUnavailable", func() { + Context("should return true", func() { + DescribeTable("when provided with a connector error code", + func(code int) { + err := newConnectorError(4, code, "some text", "some context", "some description") + + Expect(IsServiceUnavailable(err)).To(BeTrue()) + }, + Entry("BOLT_INTERRUPTED", 3), + Entry("BOLT_CONNECTION_RESET", 4), + Entry("BOLT_NO_VALID_ADDRESS", 5), + Entry("BOLT_TIMED_OUT", 6), + Entry("BOLT_CONNECTION_REFUSED", 11), + Entry("BOLT_NETWORK_UNREACHABLE", 12), + Entry("BOLT_TLS_ERROR", 13), + Entry("BOLT_END_OF_TRANSMISSION", 15), + Entry("BOLT_POOL_FULL", 0x600), + Entry("BOLT_ADDRESS_NOT_RESOLVED", 0x700), + Entry("BOLT_ROUTING_UNABLE_TO_RETRIEVE_ROUTING_TABLE", 0x800), + Entry("BOLT_ROUTING_UNABLE_TO_REFRESH_ROUTING_TABLE", 0x803), + Entry("BOLT_ROUTING_NO_SERVERS_TO_SELECT", 0x801), + ) + }) + + Context("should return false", func() { + DescribeTable("when provided with an unrelevant connector error code", + func(code int) { + err := newConnectorError(4, code, "some text", "some context", "some description") + + Expect(IsServiceUnavailable(err)).To(BeFalse()) + }, + Entry("BOLT_SERVER_FAILURE", 16), + Entry("BOLT_UNKNOWN_ERROR", 1), + Entry("BOLT_TRANSPORT_UNSUPPORTED", 0x400), + Entry("BOLT_PROTOCOL_VIOLATION", 0x500), + ) + }) + + When("provided with a database error", func() { + err := newDatabaseError("ClientError", "Neo.TransientError.Transaction.LockClientStopped", "some error") + + It("should return false", func() { + Expect(IsServiceUnavailable(err)).To(BeFalse()) + }) + }) + + When("provided with a generic error", func() { + err := newDriverError("some error") + + It("should return false", func() { + Expect(IsServiceUnavailable(err)).To(BeFalse()) + }) + }) + + When("provided with another error type", func() { + err := errors.New("some error") + + It("should return false", func() { + Expect(IsServiceUnavailable(err)).To(BeFalse()) + }) + }) + }) +}) diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/ginkgo_test.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/ginkgo_test.go new file mode 100644 index 0000000..a9c29d8 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/ginkgo_test.go @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "os" + "testing" + + . "github.com/onsi/ginkgo" + "github.com/onsi/ginkgo/reporters" + . "github.com/onsi/gomega" +) + +func TestDriver(t *testing.T) { + RegisterFailHandler(Fail) + + customReporters := []Reporter(nil) + if os.Getenv("TEAMCITY_VERSION") != "" { + customReporters = append(customReporters, reporters.NewTeamCityReporter(os.Stdout)) + } + + RunSpecsWithDefaultAndCustomReporters(t, "Neo4j Go Driver Unit Tests", customReporters) +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/gobolt_driver.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/gobolt_driver.go new file mode 100644 index 0000000..30f5f9e --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/gobolt_driver.go @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "net/url" + "sync/atomic" + + "github.com/neo4j-drivers/gobolt" +) + +type goboltDriver struct { + config *Config + target url.URL + connector gobolt.Connector + + open int32 +} + +func configToGoboltConfig(config *Config) *gobolt.Config { + return &gobolt.Config{ + Encryption: config.Encrypted, + TLSCertificates: config.TrustStrategy.certificates, + TLSSkipVerify: config.TrustStrategy.skipVerify, + TLSSkipVerifyHostname: config.TrustStrategy.skipVerifyHostname, + Log: config.Log, + AddressResolver: wrapAddressResolverOrNil(config.AddressResolver), + MaxPoolSize: config.MaxConnectionPoolSize, + MaxConnLifetime: config.MaxConnectionLifetime, + ConnAcquisitionTimeout: config.ConnectionAcquisitionTimeout, + SockConnectTimeout: config.SocketConnectTimeout, + SockKeepalive: config.SocketKeepalive, + ValueHandlers: []gobolt.ValueHandler{ + &nodeValueHandler{}, + &relationshipValueHandler{}, + &pathValueHandler{}, + &pointValueHandler{}, + &dateValueHandler{}, + &localTimeValueHandler{}, + &offsetTimeValueHandler{}, + &localDateTimeValueHandler{}, + &dateTimeValueHandler{}, + &durationValueHandler{}, + }, + GenericErrorFactory: newDriverError, + ConnectorErrorFactory: newConnectorError, + DatabaseErrorFactory: newDatabaseError, + } +} + +func newGoboltDriver(target *url.URL, token AuthToken, config *Config) (*goboltDriver, error) { + if config == nil { + config = defaultConfig() + } + + connector, err := gobolt.NewConnector(target, token.tokens, configToGoboltConfig(config)) + if err != nil { + return nil, err + } + + driver := goboltDriver{ + config: config, + target: *target, + connector: connector, + open: 1, + } + return &driver, nil +} + +func assertDriverOpen(driver *goboltDriver) error { + if atomic.LoadInt32(&driver.open) == 0 { + return newDriverError("cannot acquire a session on a closed driver") + } + + return nil +} + +func (driver *goboltDriver) Target() url.URL { + return driver.target +} + +func (driver *goboltDriver) Session(accessMode AccessMode, bookmarks ...string) (Session, error) { + if err := assertDriverOpen(driver); err != nil { + return nil, err + } + + return newSession(driver, accessMode, bookmarks), nil +} + +func (driver *goboltDriver) Close() error { + if atomic.CompareAndSwapInt32(&driver.open, 1, 0) { + return driver.connector.Close() + } + + return nil +} + +func (driver *goboltDriver) configuration() *Config { + return driver.config +} + +func (driver *goboltDriver) acquire(mode AccessMode) (gobolt.Connection, error) { + if err := assertDriverOpen(driver); err != nil { + return nil, err + } + + seaboltMode := gobolt.AccessModeWrite + if mode == AccessModeRead { + seaboltMode = gobolt.AccessModeRead + } + + return driver.connector.Acquire(seaboltMode) +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/gobolt_driver_test.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/gobolt_driver_test.go new file mode 100644 index 0000000..1816ca9 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/gobolt_driver_test.go @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "net/url" + + . "github.com/neo4j/neo4j-go-driver/neo4j/utils/test" + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/extensions/table" + . "github.com/onsi/gomega" + + "github.com/neo4j-drivers/gobolt" +) + +var _ = Describe("Driver", func() { + Context("Creation", func() { + Context("Authentication Token", func() { + driverUrl, _ := url.Parse("bolt://localhost") + + It("should fail when an invalid type is passed", func() { + type unsupportedType struct { + } + + var token = AuthToken{ + tokens: map[string]interface{}{ + "unsupported_type": unsupportedType{}, + }, + } + + driver, err := newGoboltDriver(driverUrl, token, nil) + Expect(err).To(BeGenericError(ContainSubstring("unable to convert authentication token:"))) + Expect(driver).To(BeNil()) + }) + }) + + Context("Routing Context", func() { + DescribeTable("should not fail", + func(uri string) { + driverUrl, _ := url.Parse(uri) + + driver, err := newGoboltDriver(driverUrl, NoAuth(), nil) + Expect(err).To(BeNil()) + Expect(driver).NotTo(BeNil()) + }, + Entry("empty query string", "bolt://localhost"), + Entry("query string with empty value", "bolt://localhost?abc"), + Entry("query string with value", "bolt://localhost?abc=def"), + Entry("query string with values", "bolt://localhost?abc=def&def=gef"), + ) + + DescribeTable("should fail", + func(uri string) { + driverUrl, _ := url.Parse(uri) + + driver, err := newGoboltDriver(driverUrl, NoAuth(), nil) + Expect(err).To(BeGenericError(ContainSubstring("unable to extract routing context"))) + Expect(driver).To(BeNil()) + }, + Entry("incorrect query string 1", "bolt://localhost?a%b"), + Entry("incorrect query string 2", "bolt://localhost?abc%d=ef"), + Entry("duplicate values", "bolt://localhost?abc=def&def=gef&abc=hij"), + ) + }) + }) +}) + +func newGoboltWithConnector(target string, connector gobolt.Connector) *goboltDriver { + targetURL, err := url.Parse(target) + if err != nil { + return nil + } + + return &goboltDriver{ + target: *targetURL, + connector: connector, + open: 1, + } +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/logging.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/logging.go new file mode 100644 index 0000000..4b4d753 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/logging.go @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "fmt" + "path/filepath" + "runtime" +) + +// Logging is the interface that any provided logging target must satisfy for the neo4j +// driver to send its logging messages +type Logging interface { + ErrorEnabled() bool + WarningEnabled() bool + InfoEnabled() bool + DebugEnabled() bool + + Errorf(message string, args ...interface{}) + Warningf(message string, args ...interface{}) + Infof(message string, args ...interface{}) + Debugf(message string, args ...interface{}) +} + +func fileAndLineNumberOfCall() string { + _, file, line, ok := runtime.Caller(2) + if !ok { + file = "?" + line = 0 + } + _, file = filepath.Split(file) + + return fmt.Sprintf("%s:%d", file, line) +} + +func errorf(logging Logging, message string, args ...interface{}) { + if logging != nil && logging.ErrorEnabled() { + logging.Errorf(fmt.Sprintf("%s: %s", fileAndLineNumberOfCall(), message), args...) + } +} + +func warningf(logging Logging, message string, args ...interface{}) { + if logging != nil && logging.WarningEnabled() { + logging.Warningf(fmt.Sprintf("%s: %s", fileAndLineNumberOfCall(), message), args...) + } +} + +func infof(logging Logging, message string, args ...interface{}) { + if logging != nil && logging.InfoEnabled() { + logging.Infof(fmt.Sprintf("%s: %s", fileAndLineNumberOfCall(), message), args...) + } +} + +func debugf(logging Logging, message string, args ...interface{}) { + if logging != nil && logging.DebugEnabled() { + logging.Debugf(fmt.Sprintf("%s: %s", fileAndLineNumberOfCall(), message), args...) + } +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/logging_impl.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/logging_impl.go new file mode 100644 index 0000000..9c325eb --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/logging_impl.go @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "log" + "os" +) + +// LogLevel is the type that default logging implementations use for available +// log levels +type LogLevel int + +const ( + // ERROR is the level that error messages are written + ERROR LogLevel = 1 + // WARNING is the level that warning messages are written + WARNING = 2 + // INFO is the level that info messages are written + INFO = 3 + // DEBUG is the level that debug messages are written + DEBUG = 4 +) + +type internalLogger struct { + level LogLevel + errorLogger *log.Logger + warningLogger *log.Logger + infoLogger *log.Logger + debugLogger *log.Logger +} + +// NoOpLogger returns a logger that doesn't generate any output at all +func NoOpLogger() Logging { + return &internalLogger{level: 0} +} + +// ConsoleLogger returns a simple logger that writes its messages to the console +func ConsoleLogger(level LogLevel) Logging { + return &internalLogger{ + level: level, + errorLogger: log.New(os.Stderr, "ERROR : ", log.Ldate|log.Ltime|log.Lmicroseconds), + warningLogger: log.New(os.Stdout, "WARNING: ", log.Ldate|log.Ltime|log.Lmicroseconds), + infoLogger: log.New(os.Stdout, "INFO : ", log.Ldate|log.Ltime|log.Lmicroseconds), + debugLogger: log.New(os.Stdout, "DEBUG : ", log.Ldate|log.Ltime|log.Lmicroseconds), + } +} + +func (logger *internalLogger) ErrorEnabled() bool { + return ERROR <= logger.level +} + +func (logger *internalLogger) WarningEnabled() bool { + return WARNING <= logger.level +} + +func (logger *internalLogger) InfoEnabled() bool { + return INFO <= logger.level +} + +func (logger *internalLogger) DebugEnabled() bool { + return DEBUG <= logger.level +} + +func (logger *internalLogger) Errorf(message string, args ...interface{}) { + logger.errorLogger.Printf(message, args...) +} + +func (logger *internalLogger) Warningf(message string, args ...interface{}) { + logger.warningLogger.Printf(message, args...) +} + +func (logger *internalLogger) Infof(message string, args ...interface{}) { + logger.infoLogger.Printf(message, args...) +} + +func (logger *internalLogger) Debugf(message string, args ...interface{}) { + logger.debugLogger.Printf(message, args...) +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/logging_test.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/logging_test.go new file mode 100644 index 0000000..7a50951 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/logging_test.go @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "github.com/golang/mock/gomock" + "github.com/neo4j/neo4j-go-driver/neo4j/utils/test" + . "github.com/onsi/ginkgo" + "github.com/onsi/gomega" +) + +var _ = Describe("Logging", func() { + var ( + mockCtrl *gomock.Controller + ) + + BeforeEach(func() { + mockCtrl = gomock.NewController(GinkgoT()) + }) + + AfterEach(func() { + mockCtrl.Finish() + }) + + Context("errorf", func() { + When("Error level is not enabled", func() { + It("should not invoke Errorf on logger", func() { + logging := NewMockLogging(mockCtrl) + + logging.EXPECT().ErrorEnabled().Times(1).Return(false) + logging.EXPECT().Errorf(gomock.Any(), gomock.Any()).Times(0) + + errorf(logging, "some error: %s, %d", "str1", 1) + }) + }) + + When("Error level is enabled", func() { + It("should invoke Errorf on logger", func() { + logging := NewMockLogging(mockCtrl) + + logging.EXPECT().ErrorEnabled().Times(1).Return(true) + logging.EXPECT().Errorf(test.WrapMatcher(gomega.ContainSubstring("some error")), "str1", 1).Times(1) + + errorf(logging, "some error", "str1", 1) + }) + }) + }) + + Context("warningf", func() { + When("Warning level is not enabled", func() { + It("should not invoke Warningf on logger", func() { + logging := NewMockLogging(mockCtrl) + + logging.EXPECT().WarningEnabled().Times(1).Return(false) + logging.EXPECT().Warningf(gomock.Any(), gomock.Any()).Times(0) + + warningf(logging, "some warning: %s, %d", "str1", 1) + }) + }) + + When("Warning level is enabled", func() { + It("should invoke Warningf on logger", func() { + logging := NewMockLogging(mockCtrl) + + logging.EXPECT().WarningEnabled().Times(1).Return(true) + logging.EXPECT().Warningf(test.WrapMatcher(gomega.ContainSubstring("some warning")), "str1", 1).Times(1) + + warningf(logging, "some warning", "str1", 1) + }) + }) + }) + + Context("infof", func() { + When("Info level is not enabled", func() { + It("should not invoke Infof on logger", func() { + logging := NewMockLogging(mockCtrl) + + logging.EXPECT().InfoEnabled().Times(1).Return(false) + logging.EXPECT().Infof(gomock.Any(), gomock.Any()).Times(0) + + infof(logging, "some info: %s, %d", "str1", 1) + }) + }) + + When("Info level is enabled", func() { + It("should invoke Infof on logger", func() { + logging := NewMockLogging(mockCtrl) + + logging.EXPECT().InfoEnabled().Times(1).Return(true) + logging.EXPECT().Infof(test.WrapMatcher(gomega.ContainSubstring("some info")), "str1", 1).Times(1) + + infof(logging, "some info", "str1", 1) + }) + }) + }) + + Context("debugf", func() { + When("Debug level is not enabled", func() { + It("should not invoke Debugf on logger", func() { + logging := NewMockLogging(mockCtrl) + + logging.EXPECT().DebugEnabled().Times(1).Return(false) + logging.EXPECT().Debugf(gomock.Any(), gomock.Any()).Times(0) + + debugf(logging, "some debug: %s, %d", "str1", 1) + }) + }) + + When("Debug level is enabled", func() { + It("should invoke Debugf on logger", func() { + logging := NewMockLogging(mockCtrl) + + logging.EXPECT().DebugEnabled().Times(1).Return(true) + logging.EXPECT().Debugf(test.WrapMatcher(gomega.ContainSubstring("some debug")), "str1", 1).Times(1) + + debugf(logging, "some debug", "str1", 1) + }) + }) + }) +}) diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_connection_test.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_connection_test.go new file mode 100644 index 0000000..d295ca3 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_connection_test.go @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Code generated by MockGen. DO NOT EDIT. +// Source: neo4j-go-connector/neo4j (interfaces: Connection) + +// Package connector-mocks is a generated GoMock package. +package neo4j + +import ( + "reflect" + "time" + + "github.com/neo4j-drivers/gobolt" + + "github.com/golang/mock/gomock" +) + +// MockConnection is a mock of Connection interface +type MockConnection struct { + ctrl *gomock.Controller + recorder *MockConnectionMockRecorder +} + +// MockConnectionMockRecorder is the mock recorder for MockConnection +type MockConnectionMockRecorder struct { + mock *MockConnection +} + +// NewMockConnection creates a new mock instance +func NewMockConnection(ctrl *gomock.Controller) *MockConnection { + mock := &MockConnection{ctrl: ctrl} + mock.recorder = &MockConnectionMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockConnection) EXPECT() *MockConnectionMockRecorder { + return m.recorder +} + +// Id connector-mocks base method +func (m *MockConnection) Id() (string, error) { + ret := m.ctrl.Call(m, "Id") + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Id indicates an expected call of Id +func (mr *MockConnectionMockRecorder) Id() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Id", reflect.TypeOf((*MockConnection)(nil).Id)) +} + +// RemoteAddress connector-mocks base method +func (m *MockConnection) RemoteAddress() (string, error) { + ret := m.ctrl.Call(m, "RemoteAddress") + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// RemoteAddress indicates an expected call of RemoteAddress +func (mr *MockConnectionMockRecorder) RemoteAddress() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoteAddress", reflect.TypeOf((*MockConnection)(nil).RemoteAddress)) +} + +// Server connector-mocks base method +func (m *MockConnection) Server() (string, error) { + ret := m.ctrl.Call(m, "Server") + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Server indicates an expected call of Server +func (mr *MockConnectionMockRecorder) Server() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Server", reflect.TypeOf((*MockConnection)(nil).Server)) +} + +// Begin connector-mocks base method +func (m *MockConnection) Begin(arg0 []string, arg1 time.Duration, arg2 map[string]interface{}) (gobolt.RequestHandle, error) { + ret := m.ctrl.Call(m, "Begin", arg0, arg1, arg2) + ret0, _ := ret[0].(gobolt.RequestHandle) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Begin indicates an expected call of Begin +func (mr *MockConnectionMockRecorder) Begin(arg0 interface{}, arg1 interface{}, arg2 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Begin", reflect.TypeOf((*MockConnection)(nil).Begin), arg0, arg1, arg2) +} + +// Close connector-mocks base method +func (m *MockConnection) Close() error { + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close +func (mr *MockConnectionMockRecorder) Close() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockConnection)(nil).Close)) +} + +// Commit connector-mocks base method +func (m *MockConnection) Commit() (gobolt.RequestHandle, error) { + ret := m.ctrl.Call(m, "Commit") + ret0, _ := ret[0].(gobolt.RequestHandle) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Commit indicates an expected call of Commit +func (mr *MockConnectionMockRecorder) Commit() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Commit", reflect.TypeOf((*MockConnection)(nil).Commit)) +} + +// Data connector-mocks base method +func (m *MockConnection) Data() ([]interface{}, error) { + ret := m.ctrl.Call(m, "Data") + ret0, _ := ret[0].([]interface{}) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Data indicates an expected call of Data +func (mr *MockConnectionMockRecorder) Data() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Data", reflect.TypeOf((*MockConnection)(nil).Data)) +} + +// DiscardAll connector-mocks base method +func (m *MockConnection) DiscardAll() (gobolt.RequestHandle, error) { + ret := m.ctrl.Call(m, "DiscardAll") + ret0, _ := ret[0].(gobolt.RequestHandle) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DiscardAll indicates an expected call of DiscardAll +func (mr *MockConnectionMockRecorder) DiscardAll() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DiscardAll", reflect.TypeOf((*MockConnection)(nil).DiscardAll)) +} + +// Fetch connector-mocks base method +func (m *MockConnection) Fetch(arg0 gobolt.RequestHandle) (gobolt.FetchType, error) { + ret := m.ctrl.Call(m, "Fetch", arg0) + ret0, _ := ret[0].(gobolt.FetchType) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Fetch indicates an expected call of Fetch +func (mr *MockConnectionMockRecorder) Fetch(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Fetch", reflect.TypeOf((*MockConnection)(nil).Fetch), arg0) +} + +// FetchSummary connector-mocks base method +func (m *MockConnection) FetchSummary(arg0 gobolt.RequestHandle) (int, error) { + ret := m.ctrl.Call(m, "FetchSummary", arg0) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FetchSummary indicates an expected call of FetchSummary +func (mr *MockConnectionMockRecorder) FetchSummary(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchSummary", reflect.TypeOf((*MockConnection)(nil).FetchSummary), arg0) +} + +// Flush connector-mocks base method +func (m *MockConnection) Flush() error { + ret := m.ctrl.Call(m, "Flush") + ret0, _ := ret[0].(error) + return ret0 +} + +// Flush indicates an expected call of Flush +func (mr *MockConnectionMockRecorder) Flush() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Flush", reflect.TypeOf((*MockConnection)(nil).Flush)) +} + +// LastBookmark connector-mocks base method +func (m *MockConnection) LastBookmark() (string, error) { + ret := m.ctrl.Call(m, "LastBookmark") + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// LastBookmark indicates an expected call of LastBookmark +func (mr *MockConnectionMockRecorder) LastBookmark() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LastBookmark", reflect.TypeOf((*MockConnection)(nil).LastBookmark)) +} + +// Metadata connector-mocks base method +func (m *MockConnection) Fields() ([]string, error) { + ret := m.ctrl.Call(m, "Fields") + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Metadata indicates an expected call of Metadata +func (mr *MockConnectionMockRecorder) Fields() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Fields", reflect.TypeOf((*MockConnection)(nil).Fields)) +} + +// Metadata connector-mocks base method +func (m *MockConnection) Metadata() (map[string]interface{}, error) { + ret := m.ctrl.Call(m, "Metadata") + ret0, _ := ret[0].(map[string]interface{}) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Metadata indicates an expected call of Metadata +func (mr *MockConnectionMockRecorder) Metadata() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Metadata", reflect.TypeOf((*MockConnection)(nil).Metadata)) +} + +// PullAll connector-mocks base method +func (m *MockConnection) PullAll() (gobolt.RequestHandle, error) { + ret := m.ctrl.Call(m, "PullAll") + ret0, _ := ret[0].(gobolt.RequestHandle) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PullAll indicates an expected call of PullAll +func (mr *MockConnectionMockRecorder) PullAll() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PullAll", reflect.TypeOf((*MockConnection)(nil).PullAll)) +} + +// Reset connector-mocks base method +func (m *MockConnection) Reset() (gobolt.RequestHandle, error) { + ret := m.ctrl.Call(m, "Reset") + ret0, _ := ret[0].(gobolt.RequestHandle) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Reset indicates an expected call of Reset +func (mr *MockConnectionMockRecorder) Reset() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Reset", reflect.TypeOf((*MockConnection)(nil).Reset)) +} + +// Rollback connector-mocks base method +func (m *MockConnection) Rollback() (gobolt.RequestHandle, error) { + ret := m.ctrl.Call(m, "Rollback") + ret0, _ := ret[0].(gobolt.RequestHandle) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Rollback indicates an expected call of Rollback +func (mr *MockConnectionMockRecorder) Rollback() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Rollback", reflect.TypeOf((*MockConnection)(nil).Rollback)) +} + +// Run connector-mocks base method +func (m *MockConnection) Run(arg0 string, arg1 map[string]interface{}, arg2 []string, arg3 time.Duration, arg4 map[string]interface{}) (gobolt.RequestHandle, error) { + ret := m.ctrl.Call(m, "Run", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(gobolt.RequestHandle) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Run indicates an expected call of Run +func (mr *MockConnectionMockRecorder) Run(arg0, arg1 interface{}, arg2 interface{}, arg3 interface{}, arg4 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockConnection)(nil).Run), arg0, arg1, arg2, arg3, arg4) +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_connector_test.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_connector_test.go new file mode 100644 index 0000000..a09e090 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_connector_test.go @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Code generated by MockGen. DO NOT EDIT. +// Source: neo4j-go-connector/neo4j (interfaces: Connector) + +// Package connector-mocks is a generated GoMock package. +package neo4j + +import ( + reflect "reflect" + + "github.com/neo4j-drivers/gobolt" + + gomock "github.com/golang/mock/gomock" +) + +// MockConnector is a mock of Connector interface +type MockConnector struct { + ctrl *gomock.Controller + recorder *MockConnectorMockRecorder +} + +// MockConnectorMockRecorder is the mock recorder for MockConnector +type MockConnectorMockRecorder struct { + mock *MockConnector +} + +// NewMockConnector creates a new mock instance +func NewMockConnector(ctrl *gomock.Controller) *MockConnector { + mock := &MockConnector{ctrl: ctrl} + mock.recorder = &MockConnectorMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockConnector) EXPECT() *MockConnectorMockRecorder { + return m.recorder +} + +// Close connector-mocks base method +func (m *MockConnector) Close() error { + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close +func (mr *MockConnectorMockRecorder) Close() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockConnector)(nil).Close)) +} + +// GetPool connector-mocks base method +func (m *MockConnector) Acquire(arg0 gobolt.AccessMode) (gobolt.Connection, error) { + ret := m.ctrl.Call(m, "Acquire", arg0) + ret0, _ := ret[0].(gobolt.Connection) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPool indicates an expected call of GetPool +func (mr *MockConnectorMockRecorder) Acquire(arg0 gobolt.AccessMode) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Acquire", reflect.TypeOf((*MockConnector)(nil).Acquire), arg0) +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_factory_test.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_factory_test.go new file mode 100644 index 0000000..f82ed3b --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_factory_test.go @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import "github.com/neo4j-drivers/gobolt" + +type mockConnector struct { + connection *MockConnection +} + +func (connector *mockConnector) Acquire(mode gobolt.AccessMode) (gobolt.Connection, error) { + return connector.connection, nil +} + +func (connector *mockConnector) Close() error { + return connector.connection.Close() +} + +// MockedConnector returns a mocked connector with the provided mocked connection +func MockedConnector(connection *MockConnection) gobolt.Connector { + return &mockConnector{ + connection: connection, + } +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_logging_test.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_logging_test.go new file mode 100644 index 0000000..8fc8b78 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_logging_test.go @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/neo4j/neo4j-go-driver (interfaces: Logging) + +// Package mocks is a generated GoMock package. +package neo4j + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" +) + +// MockLogging is a mock of Logging interface +type MockLogging struct { + ctrl *gomock.Controller + recorder *MockLoggingMockRecorder +} + +// MockLoggingMockRecorder is the mock recorder for MockLogging +type MockLoggingMockRecorder struct { + mock *MockLogging +} + +// NewMockLogging creates a new mock instance +func NewMockLogging(ctrl *gomock.Controller) *MockLogging { + mock := &MockLogging{ctrl: ctrl} + mock.recorder = &MockLoggingMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockLogging) EXPECT() *MockLoggingMockRecorder { + return m.recorder +} + +// DebugEnabled mocks base method +func (m *MockLogging) DebugEnabled() bool { + ret := m.ctrl.Call(m, "DebugEnabled") + ret0, _ := ret[0].(bool) + return ret0 +} + +// DebugEnabled indicates an expected call of DebugEnabled +func (mr *MockLoggingMockRecorder) DebugEnabled() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DebugEnabled", reflect.TypeOf((*MockLogging)(nil).DebugEnabled)) +} + +// Debugf mocks base method +func (m *MockLogging) Debugf(arg0 string, arg1 ...interface{}) { + varargs := []interface{}{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Debugf", varargs...) +} + +// Debugf indicates an expected call of Debugf +func (mr *MockLoggingMockRecorder) Debugf(arg0 interface{}, arg1 ...interface{}) *gomock.Call { + varargs := append([]interface{}{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debugf", reflect.TypeOf((*MockLogging)(nil).Debugf), varargs...) +} + +// ErrorEnabled mocks base method +func (m *MockLogging) ErrorEnabled() bool { + ret := m.ctrl.Call(m, "ErrorEnabled") + ret0, _ := ret[0].(bool) + return ret0 +} + +// ErrorEnabled indicates an expected call of ErrorEnabled +func (mr *MockLoggingMockRecorder) ErrorEnabled() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ErrorEnabled", reflect.TypeOf((*MockLogging)(nil).ErrorEnabled)) +} + +// Errorf mocks base method +func (m *MockLogging) Errorf(arg0 string, arg1 ...interface{}) { + varargs := []interface{}{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Errorf", varargs...) +} + +// Errorf indicates an expected call of Errorf +func (mr *MockLoggingMockRecorder) Errorf(arg0 interface{}, arg1 ...interface{}) *gomock.Call { + varargs := append([]interface{}{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Errorf", reflect.TypeOf((*MockLogging)(nil).Errorf), varargs...) +} + +// InfoEnabled mocks base method +func (m *MockLogging) InfoEnabled() bool { + ret := m.ctrl.Call(m, "InfoEnabled") + ret0, _ := ret[0].(bool) + return ret0 +} + +// InfoEnabled indicates an expected call of InfoEnabled +func (mr *MockLoggingMockRecorder) InfoEnabled() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InfoEnabled", reflect.TypeOf((*MockLogging)(nil).InfoEnabled)) +} + +// Infof mocks base method +func (m *MockLogging) Infof(arg0 string, arg1 ...interface{}) { + varargs := []interface{}{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Infof", varargs...) +} + +// Infof indicates an expected call of Infof +func (mr *MockLoggingMockRecorder) Infof(arg0 interface{}, arg1 ...interface{}) *gomock.Call { + varargs := append([]interface{}{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Infof", reflect.TypeOf((*MockLogging)(nil).Infof), varargs...) +} + +// WarningEnabled mocks base method +func (m *MockLogging) WarningEnabled() bool { + ret := m.ctrl.Call(m, "WarningEnabled") + ret0, _ := ret[0].(bool) + return ret0 +} + +// WarningEnabled indicates an expected call of WarningEnabled +func (mr *MockLoggingMockRecorder) WarningEnabled() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WarningEnabled", reflect.TypeOf((*MockLogging)(nil).WarningEnabled)) +} + +// Warningf mocks base method +func (m *MockLogging) Warningf(arg0 string, arg1 ...interface{}) { + varargs := []interface{}{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Warningf", varargs...) +} + +// Warningf indicates an expected call of Warningf +func (mr *MockLoggingMockRecorder) Warningf(arg0 interface{}, arg1 ...interface{}) *gomock.Call { + varargs := append([]interface{}{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warningf", reflect.TypeOf((*MockLogging)(nil).Warningf), varargs...) +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_pool_test.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_pool_test.go new file mode 100644 index 0000000..d788016 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_pool_test.go @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Code generated by MockGen. DO NOT EDIT. +// Source: neo4j-go-connector/neo4j (interfaces: Pool) + +// Package connector-mocks is a generated GoMock package. +package neo4j + +import ( + reflect "reflect" + + "github.com/neo4j-drivers/gobolt" + + gomock "github.com/golang/mock/gomock" +) + +// MockPool is a mock of Pool interface +type MockPool struct { + ctrl *gomock.Controller + recorder *MockPoolMockRecorder +} + +// MockPoolMockRecorder is the mock recorder for MockPool +type MockPoolMockRecorder struct { + mock *MockPool +} + +// NewMockPool creates a new mock instance +func NewMockPool(ctrl *gomock.Controller) *MockPool { + mock := &MockPool{ctrl: ctrl} + mock.recorder = &MockPoolMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockPool) EXPECT() *MockPoolMockRecorder { + return m.recorder +} + +// Acquire connector-mocks base method +func (m *MockPool) Acquire() (gobolt.Connection, error) { + ret := m.ctrl.Call(m, "Acquire") + ret0, _ := ret[0].(gobolt.Connection) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Acquire indicates an expected call of Acquire +func (mr *MockPoolMockRecorder) Acquire() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Acquire", reflect.TypeOf((*MockPool)(nil).Acquire)) +} + +// Close connector-mocks base method +func (m *MockPool) Close() error { + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close +func (mr *MockPoolMockRecorder) Close() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockPool)(nil).Close)) +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_record_test.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_record_test.go new file mode 100644 index 0000000..6b6a17e --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_record_test.go @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/neo4j/neo4j-go-driver/neo4j (interfaces: Record) + +// Package mocks is a generated GoMock package. +package neo4j + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" +) + +// MockRecord is a mock of Record interface +type MockRecord struct { + ctrl *gomock.Controller + recorder *MockRecordMockRecorder +} + +// MockRecordMockRecorder is the mock recorder for MockRecord +type MockRecordMockRecorder struct { + mock *MockRecord +} + +// NewMockRecord creates a new mock instance +func NewMockRecord(ctrl *gomock.Controller) *MockRecord { + mock := &MockRecord{ctrl: ctrl} + mock.recorder = &MockRecordMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockRecord) EXPECT() *MockRecordMockRecorder { + return m.recorder +} + +// Get mocks base method +func (m *MockRecord) Get(arg0 string) (interface{}, bool) { + ret := m.ctrl.Call(m, "Get", arg0) + ret0, _ := ret[0].(interface{}) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// Get indicates an expected call of Get +func (mr *MockRecordMockRecorder) Get(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockRecord)(nil).Get), arg0) +} + +// GetByIndex mocks base method +func (m *MockRecord) GetByIndex(arg0 int) interface{} { + ret := m.ctrl.Call(m, "GetByIndex", arg0) + ret0, _ := ret[0].(interface{}) + return ret0 +} + +// GetByIndex indicates an expected call of GetByIndex +func (mr *MockRecordMockRecorder) GetByIndex(arg0 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByIndex", reflect.TypeOf((*MockRecord)(nil).GetByIndex), arg0) +} + +// Keys mocks base method +func (m *MockRecord) Keys() []string { + ret := m.ctrl.Call(m, "Keys") + ret0, _ := ret[0].([]string) + return ret0 +} + +// Keys indicates an expected call of Keys +func (mr *MockRecordMockRecorder) Keys() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Keys", reflect.TypeOf((*MockRecord)(nil).Keys)) +} + +// Values mocks base method +func (m *MockRecord) Values() []interface{} { + ret := m.ctrl.Call(m, "Values") + ret0, _ := ret[0].([]interface{}) + return ret0 +} + +// Values indicates an expected call of Values +func (mr *MockRecordMockRecorder) Values() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Values", reflect.TypeOf((*MockRecord)(nil).Values)) +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_result_test.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_result_test.go new file mode 100644 index 0000000..a62b295 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_result_test.go @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/neo4j/neo4j-go-driver/neo4j (interfaces: Result) + +// Package mock_neo4j is a generated GoMock package. +package neo4j + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" +) + +// MockResult is a mock of Result interface +type MockResult struct { + ctrl *gomock.Controller + recorder *MockResultMockRecorder +} + +// MockResultMockRecorder is the mock recorder for MockResult +type MockResultMockRecorder struct { + mock *MockResult +} + +// NewMockResult creates a new mock instance +func NewMockResult(ctrl *gomock.Controller) *MockResult { + mock := &MockResult{ctrl: ctrl} + mock.recorder = &MockResultMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockResult) EXPECT() *MockResultMockRecorder { + return m.recorder +} + +// Consume mocks base method +func (m *MockResult) Consume() (ResultSummary, error) { + ret := m.ctrl.Call(m, "Consume") + ret0, _ := ret[0].(ResultSummary) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Consume indicates an expected call of Consume +func (mr *MockResultMockRecorder) Consume() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Consume", reflect.TypeOf((*MockResult)(nil).Consume)) +} + +// Err mocks base method +func (m *MockResult) Err() error { + ret := m.ctrl.Call(m, "Err") + ret0, _ := ret[0].(error) + return ret0 +} + +// Err indicates an expected call of Err +func (mr *MockResultMockRecorder) Err() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Err", reflect.TypeOf((*MockResult)(nil).Err)) +} + +// Keys mocks base method +func (m *MockResult) Keys() ([]string, error) { + ret := m.ctrl.Call(m, "Keys") + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Keys indicates an expected call of Keys +func (mr *MockResultMockRecorder) Keys() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Keys", reflect.TypeOf((*MockResult)(nil).Keys)) +} + +// Next mocks base method +func (m *MockResult) Next() bool { + ret := m.ctrl.Call(m, "Next") + ret0, _ := ret[0].(bool) + return ret0 +} + +// Next indicates an expected call of Next +func (mr *MockResultMockRecorder) Next() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Next", reflect.TypeOf((*MockResult)(nil).Next)) +} + +// Record mocks base method +func (m *MockResult) Record() Record { + ret := m.ctrl.Call(m, "Record") + ret0, _ := ret[0].(Record) + return ret0 +} + +// Record indicates an expected call of Record +func (mr *MockResultMockRecorder) Record() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Record", reflect.TypeOf((*MockResult)(nil).Record)) +} + +// Summary mocks base method +func (m *MockResult) Summary() (ResultSummary, error) { + ret := m.ctrl.Call(m, "Summary") + ret0, _ := ret[0].(ResultSummary) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Summary indicates an expected call of Summary +func (mr *MockResultMockRecorder) Summary() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Summary", reflect.TypeOf((*MockResult)(nil).Summary)) +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_resultsummary_test.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_resultsummary_test.go new file mode 100644 index 0000000..4f94cc3 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/mock_resultsummary_test.go @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/neo4j/neo4j-go-driver/neo4j (interfaces: ResultSummary) + +// Package mocks is a generated GoMock package. +package neo4j + +import ( + reflect "reflect" + time "time" + + gomock "github.com/golang/mock/gomock" +) + +// MockResultSummary is a mock of ResultSummary interface +type MockResultSummary struct { + ctrl *gomock.Controller + recorder *MockResultSummaryMockRecorder +} + +// MockResultSummaryMockRecorder is the mock recorder for MockResultSummary +type MockResultSummaryMockRecorder struct { + mock *MockResultSummary +} + +// NewMockResultSummary creates a new mock instance +func NewMockResultSummary(ctrl *gomock.Controller) *MockResultSummary { + mock := &MockResultSummary{ctrl: ctrl} + mock.recorder = &MockResultSummaryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockResultSummary) EXPECT() *MockResultSummaryMockRecorder { + return m.recorder +} + +// Counters mocks base method +func (m *MockResultSummary) Counters() Counters { + ret := m.ctrl.Call(m, "Counters") + ret0, _ := ret[0].(Counters) + return ret0 +} + +// Counters indicates an expected call of Counters +func (mr *MockResultSummaryMockRecorder) Counters() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Counters", reflect.TypeOf((*MockResultSummary)(nil).Counters)) +} + +// Notifications mocks base method +func (m *MockResultSummary) Notifications() []Notification { + ret := m.ctrl.Call(m, "Notifications") + ret0, _ := ret[0].([]Notification) + return ret0 +} + +// Notifications indicates an expected call of Notifications +func (mr *MockResultSummaryMockRecorder) Notifications() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Notifications", reflect.TypeOf((*MockResultSummary)(nil).Notifications)) +} + +// Plan mocks base method +func (m *MockResultSummary) Plan() Plan { + ret := m.ctrl.Call(m, "Plan") + ret0, _ := ret[0].(Plan) + return ret0 +} + +// Plan indicates an expected call of Plan +func (mr *MockResultSummaryMockRecorder) Plan() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Plan", reflect.TypeOf((*MockResultSummary)(nil).Plan)) +} + +// Profile mocks base method +func (m *MockResultSummary) Profile() ProfiledPlan { + ret := m.ctrl.Call(m, "Profile") + ret0, _ := ret[0].(ProfiledPlan) + return ret0 +} + +// Profile indicates an expected call of Profile +func (mr *MockResultSummaryMockRecorder) Profile() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Profile", reflect.TypeOf((*MockResultSummary)(nil).Profile)) +} + +// ResultAvailableAfter mocks base method +func (m *MockResultSummary) ResultAvailableAfter() time.Duration { + ret := m.ctrl.Call(m, "ResultAvailableAfter") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// ResultAvailableAfter indicates an expected call of ResultAvailableAfter +func (mr *MockResultSummaryMockRecorder) ResultAvailableAfter() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResultAvailableAfter", reflect.TypeOf((*MockResultSummary)(nil).ResultAvailableAfter)) +} + +// ResultConsumedAfter mocks base method +func (m *MockResultSummary) ResultConsumedAfter() time.Duration { + ret := m.ctrl.Call(m, "ResultConsumedAfter") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// ResultConsumedAfter indicates an expected call of ResultConsumedAfter +func (mr *MockResultSummaryMockRecorder) ResultConsumedAfter() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResultConsumedAfter", reflect.TypeOf((*MockResultSummary)(nil).ResultConsumedAfter)) +} + +// Server mocks base method +func (m *MockResultSummary) Server() ServerInfo { + ret := m.ctrl.Call(m, "Server") + ret0, _ := ret[0].(ServerInfo) + return ret0 +} + +// Server indicates an expected call of Server +func (mr *MockResultSummaryMockRecorder) Server() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Server", reflect.TypeOf((*MockResultSummary)(nil).Server)) +} + +// Statement mocks base method +func (m *MockResultSummary) Statement() Statement { + ret := m.ctrl.Call(m, "Statement") + ret0, _ := ret[0].(Statement) + return ret0 +} + +// Statement indicates an expected call of Statement +func (mr *MockResultSummaryMockRecorder) Statement() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Statement", reflect.TypeOf((*MockResultSummary)(nil).Statement)) +} + +// StatementType mocks base method +func (m *MockResultSummary) StatementType() StatementType { + ret := m.ctrl.Call(m, "StatementType") + ret0, _ := ret[0].(StatementType) + return ret0 +} + +// StatementType indicates an expected call of StatementType +func (mr *MockResultSummaryMockRecorder) StatementType() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StatementType", reflect.TypeOf((*MockResultSummary)(nil).StatementType)) +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/record.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/record.go new file mode 100644 index 0000000..cba44ec --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/record.go @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +// Record contains ordered keys and values that are returned from a statement executed +// on the server +type Record interface { + // Keys returns the keys available + Keys() []string + // Values returns the values + Values() []interface{} + // Get returns the value (if any) corresponding to the given key + Get(key string) (interface{}, bool) + // GetByIndex returns the value at given index + GetByIndex(index int) interface{} +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/record_impl.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/record_impl.go new file mode 100644 index 0000000..18cd1c7 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/record_impl.go @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +type neoRecord struct { + keys []string + values []interface{} +} + +func (record *neoRecord) Keys() []string { + return record.keys +} + +func (record *neoRecord) Values() []interface{} { + return record.values +} + +func (record *neoRecord) Get(key string) (interface{}, bool) { + for i := range record.keys { + if record.keys[i] == key { + return record.values[i], true + } + } + + return nil, false +} + +func (record *neoRecord) GetByIndex(index int) interface{} { + return record.values[index] +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/result.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/result.go new file mode 100644 index 0000000..a2898ef --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/result.go @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +// Result provides access to the result of the executing statement. +type Result interface { + // Keys returns the keys available on the result set. + Keys() ([]string, error) + // Next returns true only if there is a record to be processed. + Next() bool + // Err returns the latest error that caused this Next to return false. + Err() error + // Record returns the current record. + Record() Record + // Summary returns the summary information about the statement execution. + Summary() (ResultSummary, error) + // Consume consumes the entire result and returns the summary information + // about the statement execution. + Consume() (ResultSummary, error) +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/result_helpers.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/result_helpers.go new file mode 100644 index 0000000..411297b --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/result_helpers.go @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +// Single returns one and only one record from the result stream. Any error passed in +// or reported while navigating the result stream is returned without any conversion. +// If the result stream contains zero or more than one records error is returned. +func Single(from interface{}, err error) (Record, error) { + var result Result + var record Record + var ok bool + + if err != nil { + return nil, err + } + + if result, ok = from.(Result); !ok { + return nil, newDriverError("expected from to be a result but it was '%v'", from) + } + + if result.Next() { + record = result.Record() + } + + if err := result.Err(); err != nil { + return nil, err + } + + if record == nil { + return nil, newDriverError("result contains no records") + } + + if result.Next() { + return nil, newDriverError("result contains more than one record") + } + + return record, nil +} + +// Collect loops through the result stream, collects records into a slice and returns the +// resulting slice. Any error passed in or reported while navigating the result stream is +// returned without any conversion. +func Collect(from interface{}, err error) ([]Record, error) { + var result Result + var list []Record + var ok bool + + if err != nil { + return nil, err + } + + if result, ok = from.(Result); !ok { + return nil, newDriverError("expected from to be a result but it was '%v'", from) + } + + for result.Next() { + list = append(list, result.Record()) + } + if err := result.Err(); err != nil { + return nil, err + } + + return list, nil +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/result_helpers_test.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/result_helpers_test.go new file mode 100644 index 0000000..8129b42 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/result_helpers_test.go @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "github.com/golang/mock/gomock" + . "github.com/neo4j/neo4j-go-driver/neo4j/utils/test" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/pkg/errors" +) + +var _ = Describe("Result Helpers", func() { + var ( + mockCtrl *gomock.Controller + mockResult *MockResult + mockRecord *MockRecord + ) + + BeforeEach(func() { + mockCtrl = gomock.NewController(GinkgoT()) + }) + + AfterEach(func() { + mockCtrl.Finish() + }) + + Context("Single", func() { + var fixedError = errors.New("some error") + + It("should return error when error is passed", func() { + record, err := Single(nil, fixedError) + + Expect(record).To(BeNil()) + Expect(err).To(Equal(fixedError)) + }) + + It("should return error when from is not record", func() { + record, err := Single("i'm not a record", nil) + + Expect(record).To(BeNil()) + Expect(err).To(BeGenericError(ContainSubstring("expected from to be a result but it was 'i'm not a record'"))) + }) + + It("should return error if result returns error", func() { + mockResult = NewMockResult(mockCtrl) + gomock.InOrder( + mockResult.EXPECT().Next().Return(false), + mockResult.EXPECT().Err().Return(fixedError), + ) + + record, err := Single(mockResult, nil) + + Expect(record).To(BeNil()) + Expect(err).To(Equal(fixedError)) + }) + + It("should return error if result returns error after first Next", func() { + mockRecord = NewMockRecord(mockCtrl) + mockResult = NewMockResult(mockCtrl) + + gomock.InOrder( + mockResult.EXPECT().Next().Return(true), + mockResult.EXPECT().Record().Return(mockRecord), + mockResult.EXPECT().Err().Return(fixedError), + ) + + record, err := Single(mockResult, nil) + + Expect(record).To(BeNil()) + Expect(err).To(Equal(fixedError)) + }) + + It("should return nil when there's no elements", func() { + mockResult = NewMockResult(mockCtrl) + + gomock.InOrder( + mockResult.EXPECT().Next().Return(false), + mockResult.EXPECT().Err().Return(nil), + ) + + record, err := Single(mockResult, nil) + + Expect(record).To(BeNil()) + Expect(err).Should(BeGenericError(ContainSubstring("result contains no records"))) + }) + + It("should return record when there's only one element", func() { + mockRecord = NewMockRecord(mockCtrl) + mockResult = NewMockResult(mockCtrl) + + gomock.InOrder( + mockResult.EXPECT().Next().Return(true), + mockResult.EXPECT().Record().Return(mockRecord), + mockResult.EXPECT().Err().Return(nil), + mockResult.EXPECT().Next().Return(false), + ) + + record, err := Single(mockResult, nil) + + Expect(record).To(Equal(mockRecord)) + Expect(err).To(BeNil()) + }) + + It("should return error when there's more than one element", func() { + mockRecord = NewMockRecord(mockCtrl) + mockResult = NewMockResult(mockCtrl) + + gomock.InOrder( + mockResult.EXPECT().Next().Return(true), + mockResult.EXPECT().Record().Return(mockRecord), + mockResult.EXPECT().Err().Return(nil), + mockResult.EXPECT().Next().Return(true), + ) + + record, err := Single(mockResult, nil) + + Expect(record).To(BeNil()) + Expect(err).Should(BeGenericError(ContainSubstring("result contains more than one record"))) + }) + }) + + Context("Collect", func() { + var fixedError = errors.New("some error") + + It("should return error when error is passed", func() { + records, err := Collect(nil, fixedError) + + Expect(records).To(BeNil()) + Expect(err).To(Equal(fixedError)) + }) + + It("should return error when from is not record", func() { + record, err := Collect("i'm not a record", nil) + + Expect(record).To(BeNil()) + Expect(err).To(BeGenericError(ContainSubstring("expected from to be a result but it was 'i'm not a record'"))) + }) + + It("should return error if result returns error", func() { + mockResult = NewMockResult(mockCtrl) + gomock.InOrder( + mockResult.EXPECT().Next().Return(false), + mockResult.EXPECT().Err().Return(fixedError), + ) + + records, err := Collect(mockResult, nil) + + Expect(records).To(BeNil()) + Expect(err).To(Equal(fixedError)) + }) + + It("should return error if result returns error after first Next", func() { + mockRecord = NewMockRecord(mockCtrl) + mockResult = NewMockResult(mockCtrl) + + gomock.InOrder( + mockResult.EXPECT().Next().Return(true), + mockResult.EXPECT().Record().Return(mockRecord), + mockResult.EXPECT().Next().Return(false), + mockResult.EXPECT().Err().Return(fixedError), + ) + + records, err := Collect(mockResult, nil) + + Expect(records).To(BeNil()) + Expect(err).To(Equal(fixedError)) + }) + + It("should return one record", func() { + mockRecord = NewMockRecord(mockCtrl) + mockResult = NewMockResult(mockCtrl) + + gomock.InOrder( + mockResult.EXPECT().Next().Return(true), + mockResult.EXPECT().Record().Return(mockRecord), + mockResult.EXPECT().Next().Return(false), + mockResult.EXPECT().Err().Return(nil), + ) + + records, err := Collect(mockResult, nil) + + Expect(records).To(HaveLen(1)) + Expect(records[0]).To(Equal(mockRecord)) + Expect(err).To(BeNil()) + }) + + It("should return five records", func() { + mockRecord1 := NewMockRecord(mockCtrl) + mockRecord2 := NewMockRecord(mockCtrl) + mockRecord3 := NewMockRecord(mockCtrl) + mockRecord4 := NewMockRecord(mockCtrl) + mockRecord5 := NewMockRecord(mockCtrl) + + mockResult = NewMockResult(mockCtrl) + + gomock.InOrder( + mockResult.EXPECT().Next().Return(true), + mockResult.EXPECT().Record().Return(mockRecord1), + mockResult.EXPECT().Next().Return(true), + mockResult.EXPECT().Record().Return(mockRecord2), + mockResult.EXPECT().Next().Return(true), + mockResult.EXPECT().Record().Return(mockRecord3), + mockResult.EXPECT().Next().Return(true), + mockResult.EXPECT().Record().Return(mockRecord4), + mockResult.EXPECT().Next().Return(true), + mockResult.EXPECT().Record().Return(mockRecord5), + mockResult.EXPECT().Next().Return(false), + mockResult.EXPECT().Err().Return(nil), + ) + + records, err := Collect(mockResult, nil) + + Expect(records).To(HaveLen(5)) + Expect(records[0]).To(Equal(mockRecord1)) + Expect(records[1]).To(Equal(mockRecord2)) + Expect(records[2]).To(Equal(mockRecord3)) + Expect(records[3]).To(Equal(mockRecord4)) + Expect(records[4]).To(Equal(mockRecord5)) + Expect(err).To(BeNil()) + }) + }) +}) diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/result_impl.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/result_impl.go new file mode 100644 index 0000000..8740f0f --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/result_impl.go @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "time" + + "github.com/neo4j-drivers/gobolt" +) + +type neoResult struct { + keys []string + records []Record + current Record + summary *neoResultSummary + runner *statementRunner + err error + runHandle gobolt.RequestHandle + runCompleted bool + resultHandle gobolt.RequestHandle + resultCompleted bool +} + +var collectMetadata = func(result *neoResult, metadata map[string]interface{}) { + if metadata != nil { + if resultAvailabilityTimer, ok := metadata["result_available_after"]; ok { + result.summary.resultAvailableAfter = time.Duration(resultAvailabilityTimer.(int64)) / time.Millisecond + } + + if resultAvailabilityTimer, ok := metadata["t_first"]; ok { + result.summary.resultAvailableAfter = time.Duration(resultAvailabilityTimer.(int64)) / time.Millisecond + } + + if resultConsumptionTimer, ok := metadata["result_consumed_after"]; ok { + result.summary.resultConsumedAfter = time.Duration(resultConsumptionTimer.(int64)) / time.Millisecond + } + + if resultConsumptionTimer, ok := metadata["t_last"]; ok { + result.summary.resultConsumedAfter = time.Duration(resultConsumptionTimer.(int64)) / time.Millisecond + } + + if typeString, ok := metadata["type"]; ok { + switch typeString.(string) { + case "r": + result.summary.statementType = StatementTypeReadOnly + case "rw": + result.summary.statementType = StatementTypeReadWrite + case "w": + result.summary.statementType = StatementTypeWriteOnly + case "s": + result.summary.statementType = StatementTypeSchemaWrite + default: + result.summary.statementType = StatementTypeUnknown + } + } + + if stats, ok := metadata["stats"]; ok { + if statsDict, ok := stats.(map[string]interface{}); ok { + result.summary.counters = collectCounters(&statsDict) + } + } + + if plan, ok := metadata["plan"]; ok { + if plansDict, ok := plan.(map[string]interface{}); ok { + result.summary.plan = collectPlan(&plansDict) + } + } + + if profile, ok := metadata["profile"]; ok { + if profileDict, ok := profile.(map[string]interface{}); ok { + result.summary.profile = collectProfile(&profileDict) + } + } + + if notifications, ok := metadata["notifications"]; ok { + if notificationsList, ok := notifications.([]interface{}); ok { + collectNotification(¬ificationsList, &result.summary.notifications) + } + } + } +} + +var collectRecord = func(result *neoResult, fields []interface{}) { + if fields != nil { + result.records = append(result.records, &neoRecord{keys: result.keys, values: fields}) + } +} + +func (result *neoResult) Keys() ([]string, error) { + for !result.runCompleted { + if currentResult, err := result.runner.receive(); currentResult == result && err != nil { + return nil, err + } + } + + return result.keys, nil +} + +func (result *neoResult) Next() bool { + if result.err != nil { + return false + } + + for !result.runCompleted { + if currentResult, err := result.runner.receive(); currentResult == result && err != nil { + return false + } + } + + for !result.resultCompleted && len(result.records) == 0 { + if currentResult, err := result.runner.receive(); currentResult == result && err != nil { + return false + } + } + + if len(result.records) > 0 { + result.current = result.records[0] + result.records = result.records[1:] + } else { + result.current = nil + } + + return result.current != nil +} + +func (result *neoResult) Err() error { + return result.err +} + +func (result *neoResult) Record() Record { + return result.current +} + +func (result *neoResult) Summary() (ResultSummary, error) { + for result.err == nil && !result.resultCompleted { + if _, err := result.runner.receive(); err != nil { + result.err = err + + break + } + } + + if result.err != nil { + return nil, result.err + } + + return result.summary, nil +} + +func (result *neoResult) Consume() (ResultSummary, error) { + for result.Next() { + + } + + if result.err != nil { + return nil, result.err + } + + return result.summary, nil +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/retry.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/retry.go new file mode 100644 index 0000000..4ea554c --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/retry.go @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "math/rand" + "strings" + "time" +) + +type retryLogic struct { + logging Logging + initialRetryDelay time.Duration + maxRetryTime time.Duration + delayMultiplier float64 + delayJitter float64 +} + +func newRetryLogic(config *Config) *retryLogic { + return &retryLogic{ + logging: config.Log, + initialRetryDelay: 1 * time.Second, + maxRetryTime: config.MaxTransactionRetryTime, + delayMultiplier: 2.0, + delayJitter: 0.2, + } +} + +func computeDelayWithJitter(logic *retryLogic, delay time.Duration) time.Duration { + jitter := time.Duration(float64(delay) * logic.delayJitter) + nextDelay := delay - jitter + time.Duration(2*float64(jitter)*rand.Float64()) + return nextDelay +} + +func (logic *retryLogic) retry(work func() (interface{}, string, error)) (interface{}, error) { + var result interface{} + + count := 0 + result = nil + id := "unknown" + err := error(nil) + suppressedErrors := make([]string, 0) + startTime := time.Time{} + nextDelay := logic.initialRetryDelay + + for true { + count++ + + result, id, err = work() + if err == nil { + return result, nil + } + + if isRetriableError(err) { + suppressedErrors = append(suppressedErrors, err.Error()) + + if startTime.IsZero() { + startTime = time.Now() + } + + elapsed := time.Since(startTime) + if elapsed < logic.maxRetryTime { + delayWithJitter := computeDelayWithJitter(logic, nextDelay) + warningf(logic.logging, "[%s]: retryable operation failed to complete [error: %s] and will be retried in %dms", id, err.Error(), delayWithJitter.Nanoseconds()/int64(time.Millisecond)) + time.Sleep(delayWithJitter) + nextDelay = delayWithJitter + continue + } + } + + break + } + + if count == 1 { + return nil, err + } + + return nil, newDriverError("[%s]: retryable operation failed to complete after %d tries, suppressed errors: [%s]", id, count, strings.Join(suppressedErrors, ", ")) +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/retry_test.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/retry_test.go new file mode 100644 index 0000000..24c8d98 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/retry_test.go @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestRetryLogic(t *testing.T) { + type mockResult struct { + result interface{} + err error + } + + mockWork := func(delay time.Duration, id string, r ...mockResult) func() (interface{}, string, error) { + index := -1 + return func() (interface{}, string, error) { + time.Sleep(delay) + index++ + if index >= len(r) { + index = 0 + } + return r[index].result, id, r[index].err + } + } + + errorNotRetriable := fmt.Errorf("an un-retryable error") + errorRetriable := newDatabaseError("TransientError", "Neo.TransientError.Some.Error", "transient error") + + t.Run("should return result from work if no errors", func(t *testing.T) { + retryLogic := newRetryLogic(&Config{}) + + result, err := retryLogic.retry(mockWork(0, "conn-1", mockResult{12, nil})) + + assert.Equal(t, result, 12) + assert.NoError(t, err) + }) + + t.Run("should return error from work if error is not retriable", func(t *testing.T) { + retryLogic := newRetryLogic(&Config{}) + + result, err := retryLogic.retry(mockWork(0, "conn-1", mockResult{nil, errorNotRetriable})) + + assert.Nil(t, result) + assert.Equal(t, err, errorNotRetriable) + }) + + t.Run("should not return result from work if error", func(t *testing.T) { + retryLogic := newRetryLogic(&Config{}) + + result, err := retryLogic.retry(mockWork(0, "conn-1", mockResult{12, errorNotRetriable})) + + assert.Nil(t, result) + assert.Equal(t, err, errorNotRetriable) + }) + + t.Run("should retry on retriable error and return result upon successful completion", func(t *testing.T) { + retryLogic := newRetryLogic(&Config{MaxTransactionRetryTime: 5 * time.Second}) + + result, err := retryLogic.retry(mockWork(0, "conn-1", mockResult{nil, errorRetriable}, mockResult{12, nil})) + + assert.Equal(t, result, 12) + assert.NoError(t, err) + }) + + t.Run("should return error on successive transient failures", func(t *testing.T) { + retryLogic := newRetryLogic(&Config{MaxTransactionRetryTime: 5 * time.Second}) + + result, err := retryLogic.retry(mockWork(2*time.Second, "conn-1", mockResult{nil, errorRetriable})) + + assert.Nil(t, result) + assert.Error(t, err) + assert.Contains(t, err.Error(), "[conn-1]: retryable operation failed to complete after") + assert.Contains(t, err.Error(), fmt.Sprintf("[%s, %s", errorRetriable.Error(), errorRetriable.Error())) + assert.Contains(t, err.Error(), fmt.Sprintf(", %s]", errorRetriable.Error())) + }) + +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/runner.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/runner.go new file mode 100644 index 0000000..3129fa5 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/runner.go @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://seabolt.com] + * + * This file is part of seabolt. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "github.com/neo4j-drivers/gobolt" +) + +type runnerHandler func(*statementRunner) error +type phaseHandler func(*statementRunner, *neoResult) error +type resultHandler func(*statementRunner) (*neoResult, error) + +type statementRunner struct { + driver *goboltDriver + connection gobolt.Connection + autoClose bool + accessMode AccessMode + lastBookmark string + pendingResults []*neoResult + + closeHandler runnerHandler + receiveHandler resultHandler + receiveAllHandler runnerHandler + receiveAllAndCloseHandler runnerHandler + runPhaseHandler phaseHandler + recordsPhaseHandler phaseHandler +} + +func newRunner(driver *goboltDriver, accessMode AccessMode, autoClose bool) *statementRunner { + return &statementRunner{ + driver: driver, + accessMode: accessMode, + autoClose: autoClose, + } +} + +func (runner *statementRunner) lastSeenBookmark() (string, error) { + if runner.connection != nil { + var err error + var bookmark string + + if bookmark, err = runner.connection.LastBookmark(); err != nil { + runner.driver.config.Log.Errorf("LastBookmark call on connection failed: %v", err) + } + + return bookmark, err + } + + return runner.lastBookmark, nil +} + +func (runner *statementRunner) id() string { + var id = "unknown" + var err error + + if runner.connection != nil { + if id, err = runner.connection.Id(); err != nil { + runner.driver.config.Log.Errorf("Id call on connection failed: %v", err) + id = "unknown[failed to get id]" + } + } + return id +} + +func (runner *statementRunner) remoteAddress() string { + var remoteAddress = "unknown" + var err error + + if runner.connection != nil { + if remoteAddress, err = runner.connection.RemoteAddress(); err != nil { + runner.driver.config.Log.Errorf("RemoteAddress call on connection failed: %v", err) + remoteAddress = "unknown[failed to get remote address]" + } + } + return remoteAddress +} + +func (runner *statementRunner) version() string { + var version = "unknown" + var err error + + if runner.connection != nil { + if version, err = runner.connection.Server(); err != nil { + runner.driver.config.Log.Errorf("Server call on connection failed: %v", err) + version = "unknown[failed to get version text]" + } + } + return version +} + +func (runner *statementRunner) assertConnection() error { + if runner.connection == nil { + return newDriverError("unexpected state: expected an active connection bound to this runner") + } + + return nil +} + +func (runner *statementRunner) assertNoConnection() error { + if runner.connection != nil { + return newDriverError("unexpected state: expected no connection bound to this runner") + } + + return nil +} + +// This ensures that we've a connection to run statements against +func (runner *statementRunner) ensureConnection() error { + if runner.connection == nil { + connection, err := runner.driver.acquire(runner.accessMode) + if err != nil { + return err + } + + runner.connection = connection + } + + return nil +} + +// This receives all pending results and closes the connection +func (runner *statementRunner) receiveAllAndClose() error { + if runner.receiveAllAndCloseHandler != nil { + return runner.receiveAllAndCloseHandler(runner) + } + + return receiveAllAndCloseHandler(runner) +} + +func receiveAllAndCloseHandler(runner *statementRunner) error { + receiveAllErr := runner.receiveAll() + closeErr := runner.close() + if receiveAllErr != nil { + return receiveAllErr + } + return closeErr +} + +// This closes current active connection that's bound to this runner and +// updates bookmark before actual closure +func (runner *statementRunner) close() error { + if runner.closeHandler != nil { + return runner.closeHandler(runner) + } + + return closeHandler(runner) +} + +func closeHandler(runner *statementRunner) error { + if runner.connection != nil { + var bookmark string + var err error + + if bookmark, err = runner.connection.LastBookmark(); err != nil { + runner.driver.config.Log.Errorf("LastBookmark call on connection failed: %v", err) + } else { + runner.lastBookmark = bookmark + } + + if err = runner.connection.Close(); err != nil { + return err + } + + runner.connection = nil + } + + return nil +} + +func (runner *statementRunner) receiveAll() error { + if runner.receiveAllHandler != nil { + return runner.receiveAllHandler(runner) + } + + return receiveAll(runner) +} + +func receiveAll(runner *statementRunner) error { + var errToReturn error = nil + + for len(runner.pendingResults) > 0 { + // we don't care for errors here, because the errors are saved + // into individual result objects + if _, err := runner.receive(); err != nil { + errToReturn = err + } + } + + return errToReturn +} + +func (runner *statementRunner) handleRunPhase(activeResult *neoResult) error { + if runner.runPhaseHandler != nil { + return runner.runPhaseHandler(runner, activeResult) + } + + return handleRunPhase(runner, activeResult) +} + +func handleRunPhase(runner *statementRunner, activeResult *neoResult) error { + if !activeResult.runCompleted { + received, err := runner.connection.Fetch(activeResult.runHandle) + if err != nil { + return err + } + + if received != gobolt.FetchTypeMetadata { + return newDriverError("unexpected response received while waiting for a METADATA") + } + + fields, err := runner.connection.Fields() + if err != nil { + return err + } + activeResult.keys = fields + + metadata, err := runner.connection.Metadata() + if err != nil { + return err + } + + collectMetadata(activeResult, metadata) + activeResult.runCompleted = true + } + + return nil +} + +func (runner *statementRunner) handleRecordsPhase(activeResult *neoResult) error { + if runner.recordsPhaseHandler != nil { + return runner.recordsPhaseHandler(runner, activeResult) + } + + return handleRecordsPhase(runner, activeResult) +} + +func handleRecordsPhase(runner *statementRunner, activeResult *neoResult) error { + if !activeResult.resultCompleted { + received, err := runner.connection.Fetch(activeResult.resultHandle) + if err != nil { + return err + } + + switch received { + case gobolt.FetchTypeMetadata: + metadata, err := runner.connection.Metadata() + if err != nil { + return err + } + + collectMetadata(activeResult, metadata) + activeResult.resultCompleted = true + case gobolt.FetchTypeRecord: + fields, err := runner.connection.Data() + if err != nil { + return err + } + + collectRecord(activeResult, fields) + case gobolt.FetchTypeError: + return newDriverError("unable to fetch from connection") + } + } + + return nil +} + +func transformError(runner *statementRunner, err error) error { + if gobolt.IsWriteError(err) { + if runner.accessMode == AccessModeRead { + return newDriverError("write queries cannot be performed in read access mode") + } + + return newSessionExpiredError("server at %s no longer accepts writes", runner.remoteAddress()) + } + + return err +} + +func (runner *statementRunner) receive() (Result, error) { + if runner.receiveHandler != nil { + return runner.receiveHandler(runner) + } + + return receive(runner) +} + +func receive(runner *statementRunner) (Result, error) { + var err error + + if len(runner.pendingResults) <= 0 { + return nil, newDriverError("unexpected state: no pending results registered on session") + } + + if runner.connection == nil { + return nil, newDriverError("unexpected state: no open connection to perform receive") + } + + activeResult := runner.pendingResults[0] + + if err = runner.handleRunPhase(activeResult); err != nil { + // record error on the result and return error + activeResult.err = transformError(runner, err) + activeResult.runCompleted = true + + return nil, activeResult.err + } + + if err = runner.handleRecordsPhase(activeResult); err != nil { + // just record the error on the result + activeResult.err = transformError(runner, err) + activeResult.resultCompleted = true + } + + if activeResult.resultCompleted { + runner.pendingResults = runner.pendingResults[1:] + } + + if len(runner.pendingResults) == 0 && runner.autoClose { + if err = runner.close(); err != nil { + return nil, err + } + } + + if activeResult.err != nil { + return nil, activeResult.err + } + + return activeResult, nil +} + +func (runner *statementRunner) runStatement(statement *neoStatement, bookmarks []string, txConfig TransactionConfig) (*neoResult, error) { + var runHandle, pullAllHandle gobolt.RequestHandle + var err error + + if err = runner.ensureConnection(); err != nil { + return nil, err + } + + if runHandle, err = runner.connection.Run(statement.text, statement.params, bookmarks, txConfig.Timeout, txConfig.Metadata); err != nil { + return nil, err + } + + if pullAllHandle, err = runner.connection.PullAll(); err != nil { + return nil, err + } + + if err = runner.connection.Flush(); err != nil { + return nil, err + } + + result := &neoResult{ + runner: runner, + runHandle: runHandle, + resultHandle: pullAllHandle, + summary: &neoResultSummary{ + statement: statement, + server: &neoServerInfo{ + address: runner.remoteAddress(), + version: runner.version(), + }, + counters: &neoCounters{}, + }, + } + + runner.pendingResults = append(runner.pendingResults, result) + + return result, nil +} + +func (runner *statementRunner) beginTransaction(bookmarks []string, txConfig TransactionConfig) (*neoResult, error) { + var beginHandle gobolt.RequestHandle + var err error + + if err = runner.assertNoConnection(); err != nil { + return nil, err + } + + if err = runner.ensureConnection(); err != nil { + _ = runner.close() + + return nil, err + } + + if beginHandle, err = runner.connection.Begin(bookmarks, txConfig.Timeout, txConfig.Metadata); err != nil { + _ = runner.close() + + return nil, err + } + + if err = runner.connection.Flush(); err != nil { + _ = runner.close() + + return nil, err + } + + beginResult := &neoResult{runner: runner, runCompleted: true, resultHandle: beginHandle} + + runner.pendingResults = append(runner.pendingResults, beginResult) + + return beginResult, nil +} + +func (runner *statementRunner) commitTransaction() (*neoResult, error) { + var commitHandle gobolt.RequestHandle + var err error + + if err = runner.assertConnection(); err != nil { + return nil, err + } + + if commitHandle, err = runner.connection.Commit(); err != nil { + return nil, err + } + + if err = runner.connection.Flush(); err != nil { + return nil, err + } + + rollbackResult := &neoResult{runner: runner, runCompleted: true, resultHandle: commitHandle} + + runner.pendingResults = append(runner.pendingResults, rollbackResult) + + return rollbackResult, nil +} + +func (runner *statementRunner) rollbackTransaction() (*neoResult, error) { + var rollbackHandle gobolt.RequestHandle + var err error + + if err = runner.assertConnection(); err != nil { + return nil, err + } + + if rollbackHandle, err = runner.connection.Rollback(); err != nil { + return nil, err + } + + if err = runner.connection.Flush(); err != nil { + return nil, err + } + + rollbackResult := &neoResult{runner: runner, runCompleted: true, resultHandle: rollbackHandle} + + runner.pendingResults = append(runner.pendingResults, rollbackResult) + + return rollbackResult, nil +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/runner_test.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/runner_test.go new file mode 100644 index 0000000..5cdf03c --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/runner_test.go @@ -0,0 +1,1142 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "fmt" + "testing" + "time" + + "github.com/neo4j-drivers/gobolt" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" +) + +func TestRunner(t *testing.T) { + createMocksWithParams := func(t *testing.T, mode AccessMode, autoClose bool) (*gomock.Controller, *MockConnection, *statementRunner) { + ctrl := gomock.NewController(t) + connection := NewMockConnection(ctrl) + connector := MockedConnector(connection) + driver := newGoboltWithConnector("bolt://localhost", connector) + runner := newRunner(driver, mode, autoClose) + + connection.EXPECT().RemoteAddress().Return("localhost:7687", nil).AnyTimes() + connection.EXPECT().Server().Return("neo4j/3.5.0", nil).AnyTimes() + + return ctrl, connection, runner + } + + createMocks := func(t *testing.T) (*gomock.Controller, *MockConnection, *statementRunner) { + return createMocksWithParams(t, AccessModeWrite, true) + } + + t.Run("shouldStartWithNilConnection", func(t *testing.T) { + ctrl, _, runner := createMocks(t) + defer ctrl.Finish() + + assert.Nil(t, runner.connection) + }) + + t.Run("shouldStartWithEmptyBookmark", func(t *testing.T) { + ctrl, _, runner := createMocks(t) + defer ctrl.Finish() + + bookmark := runner.lastBookmark + + assert.Empty(t, bookmark) + }) + + t.Run("shouldFailWhenConnectionIsNilOnAssertConnection", func(t *testing.T) { + ctrl, _, runner := createMocks(t) + defer ctrl.Finish() + + err := runner.assertConnection() + + assert.EqualError(t, err, "unexpected state: expected an active connection bound to this runner") + }) + + t.Run("shouldNotFailWhenConnectionIsNotNilOnAssertConnection", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + runner.connection = connection + + assert.NoError(t, runner.assertConnection()) + }) + + t.Run("shouldFailWhenConnectionIsNotNilOnAssertNoConnection", func(t *testing.T) { + ctrl, _, runner := createMocks(t) + defer ctrl.Finish() + + assert.NoError(t, runner.assertNoConnection()) + }) + + t.Run("shouldNotFailWhenConnectionIsNotNilOnAssertNoConnection", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + runner.connection = connection + + err := runner.assertNoConnection() + + assert.EqualError(t, err, "unexpected state: expected no connection bound to this runner") + }) + + t.Run("shouldConstructConnectionOnEnsureConnection", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + err := runner.ensureConnection() + + assert.NoError(t, err) + assert.Equal(t, runner.connection, connection) + }) + + t.Run("shouldPropagateErrorOnEnsureConnection", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + connector := NewMockConnector(mockCtrl) + driver := newGoboltWithConnector("bolt://localhost", connector) + runner := newRunner(driver, AccessModeWrite, true) + + failure := fmt.Errorf("an unexpected error") + + connector.EXPECT().Acquire(gobolt.AccessModeWrite).Return(nil, failure) + + err := runner.ensureConnection() + + assert.Equal(t, err, failure) + }) + + t.Run("shouldNotFailWhenConnectionIsNilOnClose", func(t *testing.T) { + ctrl, _, runner := createMocks(t) + defer ctrl.Finish() + + assert.NoError(t, runner.close()) + }) + + t.Run("shouldQueryLastBookmarkAndCloseConnectionOnClose", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + _ = runner.ensureConnection() + + gomock.InOrder( + connection.EXPECT().LastBookmark().Return("a bookmark", nil), + connection.EXPECT().Close(), + ) + + // When + err := runner.close() + + // Expect + assert.NoError(t, err) + assert.Nil(t, runner.connection) + assert.Equal(t, runner.lastBookmark, "a bookmark") + }) + + t.Run("shouldReturnEmptyWhenInitialisedOnLastSeenBookmark", func(t *testing.T) { + ctrl, _, runner := createMocks(t) + defer ctrl.Finish() + + bookmark, err := runner.lastSeenBookmark() + + assert.NoError(t, err) + assert.Empty(t, bookmark) + }) + + t.Run("shouldReturnStoredBookmarkOnLastSeenBookmark", func(t *testing.T) { + ctrl, _, runner := createMocks(t) + defer ctrl.Finish() + + runner.lastBookmark = "a bookmark" + + bookmark, err := runner.lastSeenBookmark() + + assert.NoError(t, err) + assert.Equal(t, bookmark, "a bookmark") + }) + + t.Run("shouldReturnBookmarkFromConnectionOnLastSeenBookmark", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + _ = runner.ensureConnection() + + runner.lastBookmark = "a bookmark 1" + connection.EXPECT().LastBookmark().Return("a bookmark 2", nil) + + bookmark, err := runner.lastSeenBookmark() + + assert.NoError(t, err) + assert.Equal(t, bookmark, "a bookmark 2") + }) + + t.Run("closeAll", func(t *testing.T) { + failure := fmt.Errorf("an unexpected error") + + t.Run("shouldCallReceiveAll", func(t *testing.T) { + receiveAllCalls := 0 + receiveAllOverride := func(runner *statementRunner) error { + receiveAllCalls++ + return nil + } + + ctrl, _, runner := createMocks(t) + runner.receiveAllHandler = receiveAllOverride + defer ctrl.Finish() + + assert.NoError(t, runner.receiveAllAndClose()) + assert.Equal(t, receiveAllCalls, 1) + }) + + t.Run("shouldCallReceiveAllAndPropogateError", func(t *testing.T) { + receiveAllOverride := func(runner *statementRunner) error { + return failure + } + + ctrl, _, runner := createMocks(t) + runner.receiveAllHandler = receiveAllOverride + defer ctrl.Finish() + + assert.Equal(t, runner.receiveAllAndClose(), failure) + }) + + t.Run("shouldCallCloseConnection", func(t *testing.T) { + closeConnectionCalls := 0 + closeConnectionOverride := func(runner *statementRunner) error { + closeConnectionCalls++ + return nil + } + + ctrl, _, runner := createMocks(t) + runner.closeHandler = closeConnectionOverride + defer ctrl.Finish() + + assert.NoError(t, runner.receiveAllAndClose()) + assert.Equal(t, closeConnectionCalls, 1) + }) + + t.Run("shouldCallCloseConnectionAndPropogateError", func(t *testing.T) { + closeConnectionOverride := func(runner *statementRunner) error { + return failure + } + + ctrl, _, runner := createMocks(t) + runner.closeHandler = closeConnectionOverride + defer ctrl.Finish() + + assert.Equal(t, runner.receiveAllAndClose(), failure) + }) + + t.Run("shouldGivePrecedenceToReceiveAllErrors", func(t *testing.T) { + receiveAllOverride := func(runner *statementRunner) error { + return failure + } + closeConnectionOverride := func(runner *statementRunner) error { + return fmt.Errorf("some other unexpected error") + } + + ctrl, _, runner := createMocks(t) + runner.receiveAllHandler = receiveAllOverride + runner.closeHandler = closeConnectionOverride + defer ctrl.Finish() + + assert.Equal(t, runner.receiveAllAndClose(), failure) + }) + }) + + t.Run("runStatement", func(t *testing.T) { + statementText := "some cypher statement" + statementParams := map[string]interface{}{"param1": 1, "param2": false, "param3": "string"} + statement := neoStatement{text: statementText, params: statementParams} + bookmarks := []string{"bookmark 1", "bookmark 2"} + txTimeout := 1 * time.Minute + txMetadata := map[string]interface{}{"a": 1, "b": true, "c": "something"} + txConfig := TransactionConfig{Timeout: txTimeout, Metadata: txMetadata} + runHandle := gobolt.RequestHandle(1) + pullAllHandle := gobolt.RequestHandle(2) + failure := fmt.Errorf("an unexpected error") + + t.Run("shouldFailWhenEnsureConnectionFails", func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + connector := NewMockConnector(ctrl) + driver := newGoboltWithConnector("bolt://localhost", connector) + runner := newRunner(driver, AccessModeWrite, true) + + connector.EXPECT().Acquire(gobolt.AccessModeWrite).Return(nil, failure) + + result, err := runner.runStatement(&statement, bookmarks, txConfig) + + assert.Equal(t, err, failure) + assert.Nil(t, result) + }) + + t.Run("shouldFailWhenRunFails", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + connection.EXPECT().Run(statementText, statementParams, bookmarks, txTimeout, txMetadata).Return(runHandle, failure) + + result, err := runner.runStatement(&statement, bookmarks, txConfig) + + assert.Equal(t, err, failure) + assert.Nil(t, result) + }) + + t.Run("shouldFailWhenPullAllFails", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + gomock.InOrder( + connection.EXPECT().Run(statementText, statementParams, bookmarks, txTimeout, txMetadata).Return(runHandle, nil), + connection.EXPECT().PullAll().Return(pullAllHandle, failure), + ) + + result, err := runner.runStatement(&statement, bookmarks, txConfig) + + assert.Equal(t, err, failure) + assert.Nil(t, result) + }) + + t.Run("shouldFailWhenFlushFails", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + gomock.InOrder( + connection.EXPECT().Run(statementText, statementParams, bookmarks, txTimeout, txMetadata).Return(runHandle, nil), + connection.EXPECT().PullAll().Return(pullAllHandle, nil), + connection.EXPECT().Flush().Return(failure), + ) + + result, err := runner.runStatement(&statement, bookmarks, txConfig) + + assert.Equal(t, err, failure) + assert.Nil(t, result) + }) + + t.Run("shouldInvokeRunPullAllAndFlush", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + gomock.InOrder( + connection.EXPECT().Run(statementText, statementParams, bookmarks, txTimeout, txMetadata).Return(runHandle, nil), + connection.EXPECT().PullAll().Return(pullAllHandle, nil), + connection.EXPECT().Flush(), + ) + + result, err := runner.runStatement(&statement, bookmarks, txConfig) + + assert.NoError(t, err) + + assert.NotNil(t, result) + assert.Equal(t, result.runHandle, runHandle) + assert.Equal(t, result.resultHandle, pullAllHandle) + assert.Equal(t, result.summary.server.Address(), "localhost:7687") + assert.Equal(t, result.summary.server.Version(), "neo4j/3.5.0") + }) + + }) + + t.Run("beginTransaction", func(t *testing.T) { + bookmarks := []string{"bookmark 1", "bookmark 2"} + txTimeout := 1 * time.Minute + txMetadata := map[string]interface{}{"a": 1, "b": true, "c": "something"} + beginHandle := gobolt.RequestHandle(1) + failure := fmt.Errorf("an unexpected error") + + t.Run("shouldFailWhenThereIsActiveConnection", func(t *testing.T) { + ctrl, _, runner := createMocks(t) + defer ctrl.Finish() + + _ = runner.ensureConnection() + + result, err := runner.beginTransaction(bookmarks, TransactionConfig{Timeout: txTimeout, Metadata: txMetadata}) + + assert.EqualError(t, err, "unexpected state: expected no connection bound to this runner") + assert.Nil(t, result) + }) + + t.Run("shouldFailWhenEnsureConnectionFails", func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + connector := NewMockConnector(ctrl) + driver := newGoboltWithConnector("bolt://localhost", connector) + runner := newRunner(driver, AccessModeWrite, true) + + connector.EXPECT().Acquire(gobolt.AccessModeWrite).Return(nil, failure) + + result, err := runner.beginTransaction(bookmarks, TransactionConfig{Timeout: txTimeout, Metadata: txMetadata}) + + assert.Equal(t, err, failure) + assert.Nil(t, result) + }) + + t.Run("shouldFailWhenBeginFails", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + gomock.InOrder( + connection.EXPECT().Begin(bookmarks, txTimeout, txMetadata).Return(beginHandle, failure), + connection.EXPECT().LastBookmark(), + connection.EXPECT().Close()) + + result, err := runner.beginTransaction(bookmarks, TransactionConfig{Timeout: txTimeout, Metadata: txMetadata}) + + assert.Equal(t, err, failure) + assert.Nil(t, result) + }) + + t.Run("shouldFailWhenFlushFails", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + gomock.InOrder( + connection.EXPECT().Begin(bookmarks, txTimeout, txMetadata).Return(beginHandle, nil), + connection.EXPECT().Flush().Return(failure), + connection.EXPECT().LastBookmark(), + connection.EXPECT().Close()) + + result, err := runner.beginTransaction(bookmarks, TransactionConfig{Timeout: txTimeout, Metadata: txMetadata}) + + assert.Equal(t, err, failure) + assert.Nil(t, result) + }) + + t.Run("shouldInvokeBeginAndFlush", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + gomock.InOrder( + connection.EXPECT().Begin(bookmarks, txTimeout, txMetadata).Return(beginHandle, nil), + connection.EXPECT().Flush()) + + result, err := runner.beginTransaction(bookmarks, TransactionConfig{Timeout: txTimeout, Metadata: txMetadata}) + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, result.resultHandle, beginHandle) + }) + }) + + t.Run("commitTransaction", func(t *testing.T) { + commitHandle := gobolt.RequestHandle(1) + failure := fmt.Errorf("an unexpected error") + + t.Run("shouldFailWhenThereIsNoActiveConnection", func(t *testing.T) { + ctrl, _, runner := createMocks(t) + defer ctrl.Finish() + + result, err := runner.commitTransaction() + + assert.EqualError(t, err, "unexpected state: expected an active connection bound to this runner") + assert.Nil(t, result) + }) + + t.Run("shouldFailWhenCommitFails", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + runner.connection = connection + + connection.EXPECT().Commit().Return(commitHandle, failure) + + result, err := runner.commitTransaction() + + assert.Equal(t, err, failure) + assert.Nil(t, result) + }) + + t.Run("shouldFailWhenFlushFails", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + runner.connection = connection + + gomock.InOrder( + connection.EXPECT().Commit().Return(commitHandle, nil), + connection.EXPECT().Flush().Return(failure), + ) + + result, err := runner.commitTransaction() + + assert.Equal(t, err, failure) + assert.Nil(t, result) + }) + + t.Run("shouldInvokeCommitAndFlush", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + runner.connection = connection + + gomock.InOrder( + connection.EXPECT().Commit().Return(commitHandle, nil), + connection.EXPECT().Flush(), + ) + + result, err := runner.commitTransaction() + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, result.resultHandle, commitHandle) + }) + }) + + t.Run("rollbackTransaction", func(t *testing.T) { + rollbackHandle := gobolt.RequestHandle(1) + failure := fmt.Errorf("an unexpected error") + + t.Run("shouldFailWhenThereIsNoActiveConnection", func(t *testing.T) { + ctrl, _, runner := createMocks(t) + defer ctrl.Finish() + + result, err := runner.rollbackTransaction() + + assert.EqualError(t, err, "unexpected state: expected an active connection bound to this runner") + assert.Nil(t, result) + }) + + t.Run("shouldFailWhenRollbackFails", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + runner.connection = connection + + connection.EXPECT().Rollback().Return(rollbackHandle, failure) + + result, err := runner.rollbackTransaction() + + assert.Equal(t, err, failure) + assert.Nil(t, result) + }) + + t.Run("shouldFailWhenFlushFails", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + runner.connection = connection + + gomock.InOrder( + connection.EXPECT().Rollback().Return(rollbackHandle, nil), + connection.EXPECT().Flush().Return(failure), + ) + + result, err := runner.rollbackTransaction() + + assert.Equal(t, err, failure) + assert.Nil(t, result) + }) + + t.Run("shouldInvokeRollbackAndFlush", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + runner.connection = connection + + gomock.InOrder( + connection.EXPECT().Rollback().Return(rollbackHandle, nil), + connection.EXPECT().Flush(), + ) + + result, err := runner.rollbackTransaction() + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, result.resultHandle, rollbackHandle) + }) + }) + + t.Run("transformError", func(t *testing.T) { + notALeaderError := newDatabaseError("ClientError", "Neo.ClientError.Cluster.NotALeader", "a message") + forbiddenOnReadOnlyDatabaseError := newDatabaseError("ClientError", "Neo.ClientError.General.ForbiddenOnReadOnlyDatabase", "a message") + + t.Run("shouldTransformWriteErrors", func(t *testing.T) { + var errors = []struct { + name string + err error + }{ + {"notALeader", notALeaderError}, + {"forbiddenOnReadOnlyDatabase", forbiddenOnReadOnlyDatabaseError}, + } + + t.Run("readAccessMode", func(t *testing.T) { + for _, testCase := range errors { + t.Run(testCase.name, func(t *testing.T) { + ctrl, _, runner := createMocksWithParams(t, AccessModeRead, true) + defer ctrl.Finish() + + err := transformError(runner, testCase.err) + + assert.EqualError(t, err, "write queries cannot be performed in read access mode") + }) + } + }) + + t.Run("writeAccessMode", func(t *testing.T) { + t.Run("withConnection", func(t *testing.T) { + for _, testCase := range errors { + t.Run(testCase.name, func(t *testing.T) { + ctrl, connection, runner := createMocksWithParams(t, AccessModeWrite, true) + defer ctrl.Finish() + + runner.connection = connection + + err := transformError(runner, testCase.err) + + assert.EqualError(t, err, "server at localhost:7687 no longer accepts writes") + }) + } + }) + + t.Run("withoutConnection", func(t *testing.T) { + for _, testCase := range errors { + t.Run(testCase.name, func(t *testing.T) { + ctrl, _, runner := createMocksWithParams(t, AccessModeWrite, true) + defer ctrl.Finish() + + err := transformError(runner, testCase.err) + + assert.EqualError(t, err, "server at unknown no longer accepts writes") + }) + } + }) + }) + }) + + t.Run("shouldReturnOriginal", func(t *testing.T) { + var errors = []struct { + name string + err error + }{ + {"an ordinary error", fmt.Errorf("an unknown error")}, + {"a driver error", newDriverError("a driver error")}, + {"a session expired error", newSessionExpiredError("a session expired error")}, + {"a connector error", newConnectorError(1, 1, "text", "context", "description")}, + } + + for _, testCase := range errors { + t.Run(testCase.name, func(t *testing.T) { + ctrl, _, runner := createMocksWithParams(t, AccessModeWrite, true) + defer ctrl.Finish() + + err := transformError(runner, testCase.err) + + assert.Equal(t, err, testCase.err) + }) + } + + }) + }) + + createResult := func(runner *statementRunner) *neoResult { + return &neoResult{ + keys: []string{}, + records: []Record{}, + current: nil, + summary: &neoResultSummary{}, + runner: runner, + err: nil, + runHandle: 1, + runCompleted: false, + resultHandle: 2, + resultCompleted: false, + } + } + + createResultWithConn := func(runner *statementRunner) *neoResult { + _ = runner.ensureConnection() + + return createResult(runner) + } + + t.Run("handleRunPhase", func(t *testing.T) { + fields := []string{"Field 1", "Field 2"} + metadata := map[string]interface{}{"type": "r"} + failure := fmt.Errorf("an unexpected error") + + t.Run("shouldSkipIfRunIsCompleted", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + result := createResultWithConn(runner) + result.runCompleted = true + + connection.EXPECT().Fetch(gomock.Any()).Times(0) + connection.EXPECT().Fields().Times(0) + connection.EXPECT().Metadata().Times(0) + + assert.NoError(t, runner.handleRunPhase(result)) + }) + + t.Run("shouldFailWhenFetchFails", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + result := createResultWithConn(runner) + + connection.EXPECT().Fetch(result.runHandle).Return(gobolt.FetchType(0), failure) + connection.EXPECT().Fields().Times(0) + connection.EXPECT().Metadata().Times(0) + + assert.Equal(t, runner.handleRunPhase(result), failure) + }) + + t.Run("shouldFailWhenFetchReturnsRecord", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + result := createResultWithConn(runner) + + connection.EXPECT().Fetch(result.runHandle).Return(gobolt.FetchTypeRecord, nil) + connection.EXPECT().Fields().Times(0) + connection.EXPECT().Metadata().Times(0) + + assert.EqualError(t, runner.handleRunPhase(result), "unexpected response received while waiting for a METADATA") + }) + + t.Run("shouldFailWhenFetchReturnsError", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + result := createResultWithConn(runner) + + connection.EXPECT().Fetch(result.runHandle).Return(gobolt.FetchTypeError, nil) + connection.EXPECT().Fields().Times(0) + connection.EXPECT().Metadata().Times(0) + + assert.EqualError(t, runner.handleRunPhase(result), "unexpected response received while waiting for a METADATA") + }) + + t.Run("shouldFailWhenFieldsReturnsError", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + result := createResultWithConn(runner) + + connection.EXPECT().Fetch(result.runHandle).Return(gobolt.FetchTypeMetadata, nil) + connection.EXPECT().Fields().Return(nil, failure) + connection.EXPECT().Metadata().Times(0) + + assert.Equal(t, runner.handleRunPhase(result), failure) + }) + + t.Run("shouldFailWhenMetadataReturnsError", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + result := createResultWithConn(runner) + + connection.EXPECT().Fetch(result.runHandle).Return(gobolt.FetchTypeMetadata, nil) + connection.EXPECT().Fields().Return([]string{"a"}, nil) + connection.EXPECT().Metadata().Return(nil, failure) + + assert.Equal(t, runner.handleRunPhase(result), failure) + }) + + t.Run("shouldExecuteRunPhase", func(t *testing.T) { + var collectedResult *neoResult + var collectedMetadata map[string]interface{} + collectMetadata = func(result *neoResult, metadata map[string]interface{}) { + collectedResult = result + collectedMetadata = metadata + } + + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + result := createResultWithConn(runner) + + connection.EXPECT().Fetch(result.runHandle).Return(gobolt.FetchTypeMetadata, nil) + connection.EXPECT().Fields().Return(fields, nil) + connection.EXPECT().Metadata().Return(metadata, nil) + + assert.NoError(t, runner.handleRunPhase(result)) + + assert.Equal(t, result.keys, fields) + assert.Equal(t, collectedResult, result) + assert.Equal(t, collectedMetadata, metadata) + assert.True(t, result.runCompleted) + }) + }) + + t.Run("handleRecordsPhase", func(t *testing.T) { + record := []interface{}{true, 1, "data"} + metadata := map[string]interface{}{"result_consumed_after": 1} + failure := fmt.Errorf("an unexpected error") + + t.Run("shouldSkipIfRunIsCompleted", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + result := createResultWithConn(runner) + result.resultCompleted = true + + connection.EXPECT().Fetch(gomock.Any()).Times(0) + connection.EXPECT().Metadata().Times(0) + connection.EXPECT().Data().Times(0) + + assert.NoError(t, runner.handleRecordsPhase(result)) + }) + + t.Run("shouldFailWhenFetchFails", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + result := createResultWithConn(runner) + + connection.EXPECT().Fetch(result.resultHandle).Return(gobolt.FetchType(0), failure) + connection.EXPECT().Metadata().Times(0) + connection.EXPECT().Data().Times(0) + + assert.Equal(t, runner.handleRecordsPhase(result), failure) + }) + + t.Run("shouldFailOnFetchError", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + result := createResultWithConn(runner) + + connection.EXPECT().Fetch(result.resultHandle).Return(gobolt.FetchTypeError, nil) + connection.EXPECT().Metadata().Times(0) + connection.EXPECT().Data().Times(0) + + assert.EqualError(t, runner.handleRecordsPhase(result), "unable to fetch from connection") + }) + + t.Run("shouldFailWhenMetadataFails", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + result := createResultWithConn(runner) + + connection.EXPECT().Fetch(result.resultHandle).Return(gobolt.FetchTypeMetadata, nil) + connection.EXPECT().Metadata().Return(nil, failure) + connection.EXPECT().Data().Times(0) + + assert.Equal(t, runner.handleRecordsPhase(result), failure) + }) + + t.Run("shouldCompleteRecordPhaseOnMetadata", func(t *testing.T) { + var cmResult *neoResult + var cmMetadata map[string]interface{} + collectMetadata = func(result *neoResult, metadata map[string]interface{}) { + cmResult = result + cmMetadata = metadata + } + + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + result := createResultWithConn(runner) + + connection.EXPECT().Fetch(result.resultHandle).Return(gobolt.FetchTypeMetadata, nil) + connection.EXPECT().Metadata().Return(metadata, nil) + + assert.NoError(t, runner.handleRecordsPhase(result)) + + assert.Equal(t, cmResult, result) + assert.Equal(t, cmMetadata, metadata) + assert.True(t, result.resultCompleted) + }) + + t.Run("shouldFailWhenDataFails", func(t *testing.T) { + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + result := createResultWithConn(runner) + + connection.EXPECT().Fetch(result.resultHandle).Return(gobolt.FetchTypeRecord, nil) + connection.EXPECT().Data().Return(nil, failure) + + assert.Equal(t, runner.handleRecordsPhase(result), failure) + }) + + t.Run("shouldCollectRecord", func(t *testing.T) { + var collectedResult *neoResult + var collectedFields []interface{} + collectRecord = func(result *neoResult, fields []interface{}) { + collectedResult = result + collectedFields = fields + } + + ctrl, connection, runner := createMocks(t) + defer ctrl.Finish() + + result := createResultWithConn(runner) + + connection.EXPECT().Fetch(result.resultHandle).Return(gobolt.FetchTypeRecord, nil) + connection.EXPECT().Data().Return(record, nil) + + assert.NoError(t, runner.handleRecordsPhase(result)) + assert.Equal(t, collectedResult, result) + assert.Equal(t, collectedFields, record) + }) + }) + + t.Run("receive", func(t *testing.T) { + failure := fmt.Errorf("an unexpected error") + + t.Run("shouldFailWhenNoPendingResults", func(t *testing.T) { + ctrl, _, runner := createMocks(t) + defer ctrl.Finish() + + result, err := runner.receive() + + assert.EqualError(t, err, "unexpected state: no pending results registered on session") + assert.Nil(t, result) + }) + + t.Run("shouldFailWhenNoActiveConnection", func(t *testing.T) { + ctrl, _, runner := createMocks(t) + defer ctrl.Finish() + + runner.pendingResults = append(runner.pendingResults, createResult(runner)) + + result, err := runner.receive() + + assert.EqualError(t, err, "unexpected state: no open connection to perform receive") + assert.Nil(t, result) + }) + + t.Run("shouldFailWhenRunPhaseFails", func(t *testing.T) { + runPhaseOverride := func(runner *statementRunner, result *neoResult) error { + return failure + } + recordsPhaseOverride := func(runner *statementRunner, result *neoResult) error { + assert.Fail(t, "handleRecordPhase call is not expected") + return nil + } + + ctrl, _, runner := createMocks(t) + runner.runPhaseHandler = runPhaseOverride + runner.recordsPhaseHandler = recordsPhaseOverride + defer ctrl.Finish() + + result := createResultWithConn(runner) + runner.pendingResults = append(runner.pendingResults, result) + + recvdResult, err := runner.receive() + + assert.Equal(t, err, failure) + assert.Nil(t, recvdResult) + assert.True(t, result.runCompleted) + assert.Equal(t, result.err, failure) + }) + + t.Run("shouldFailWhenRecordPhaseFails", func(t *testing.T) { + runPhaseOverride := func(runner *statementRunner, result *neoResult) error { + result.runCompleted = true + return nil + } + recordsPhaseOverride := func(runner *statementRunner, result *neoResult) error { + return failure + } + + var testCases = []struct { + name string + autoClose bool + }{ + {"autoClose=true", true}, + {"autoClose=false", false}, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + ctrl, connection, runner := createMocksWithParams(t, AccessModeWrite, testCase.autoClose) + runner.runPhaseHandler = runPhaseOverride + runner.recordsPhaseHandler = recordsPhaseOverride + defer ctrl.Finish() + + if testCase.autoClose { + // we expect auto-close logic to kick-in + connection.EXPECT().LastBookmark() + connection.EXPECT().Close() + } + + result := createResultWithConn(runner) + runner.pendingResults = append(runner.pendingResults, result) + + recvdResult, err := runner.receive() + + // returned error should be the one from handleRecordsPhase + assert.Equal(t, err, failure) + assert.Nil(t, recvdResult) + + // we should mark the result complete and store the error + assert.True(t, result.resultCompleted) + assert.Equal(t, result.err, failure) + + // we should remove active result from the result queue + assert.Len(t, runner.pendingResults, 0) + }) + } + }) + + t.Run("shouldReturnResult", func(t *testing.T) { + runPhaseOverride := func(runner *statementRunner, result *neoResult) error { + result.runCompleted = true + return nil + } + recordsPhaseOverride := func(runner *statementRunner, result *neoResult) error { + result.resultCompleted = true + return nil + } + + ctrl, _, runner := createMocksWithParams(t, AccessModeRead, false) + runner.runPhaseHandler = runPhaseOverride + runner.recordsPhaseHandler = recordsPhaseOverride + defer ctrl.Finish() + + result := createResultWithConn(runner) + runner.pendingResults = append(runner.pendingResults, result) + + recvdResult, err := runner.receive() + + // we should receive the actual record and no errors + assert.NoError(t, err) + assert.Equal(t, recvdResult, result) + + // we should mark the result complete and store the error + assert.True(t, result.runCompleted) + assert.True(t, result.resultCompleted) + assert.NoError(t, result.err) + + // we should remove active result from the result queue + assert.Len(t, runner.pendingResults, 0) + }) + }) + + t.Run("receiveAll", func(t *testing.T) { + failure := fmt.Errorf("an unexpected error") + + t.Run("shouldNotReceiveIfNoPendingResults", func(t *testing.T) { + receiveOverride := func(runner *statementRunner) (*neoResult, error) { + assert.Fail(t, "receive call unexpected here") + return nil, nil + } + + ctrl, _, runner := createMocksWithParams(t, AccessModeRead, false) + runner.receiveHandler = receiveOverride + defer ctrl.Finish() + + assert.NoError(t, runner.receiveAll()) + }) + + t.Run("shouldReceiveAllResults", func(t *testing.T) { + runPhaseOverride := func(runner *statementRunner, result *neoResult) error { + result.runCompleted = true + return nil + } + recordsPhaseOverride := func(runner *statementRunner, result *neoResult) error { + result.resultCompleted = true + return nil + } + + ctrl, _, runner := createMocksWithParams(t, AccessModeRead, false) + runner.runPhaseHandler = runPhaseOverride + runner.recordsPhaseHandler = recordsPhaseOverride + defer ctrl.Finish() + + resultsPushed := []*neoResult{} + for i := 0; i < 10; i++ { + resultsPushed = append(resultsPushed, createResultWithConn(runner)) + } + + runner.pendingResults = append(runner.pendingResults, resultsPushed...) + + err := runner.receiveAll() + + assert.NoError(t, err) + assert.Empty(t, runner.pendingResults) + }) + + t.Run("shouldReceiveAllResultsEvenSomeResultsFailInRunPhase", func(t *testing.T) { + runs := 0 + runPhaseOverride := func(runner *statementRunner, result *neoResult) error { + runs++ + if runs%4 == 0 { + return failure + } + result.runCompleted = true + return nil + } + recordsPhaseOverride := func(runner *statementRunner, result *neoResult) error { + result.resultCompleted = true + return nil + } + + ctrl, _, runner := createMocksWithParams(t, AccessModeRead, false) + runner.runPhaseHandler = runPhaseOverride + runner.recordsPhaseHandler = recordsPhaseOverride + defer ctrl.Finish() + + resultsPushed := []*neoResult{} + for i := 0; i < 10; i++ { + resultsPushed = append(resultsPushed, createResultWithConn(runner)) + } + + runner.pendingResults = append(runner.pendingResults, resultsPushed...) + + err := runner.receiveAll() + + assert.Equal(t, err, failure) + assert.Empty(t, runner.pendingResults) + }) + + t.Run("shouldReceiveAllResultsEvenSomeResultsFailInRecordsPhase", func(t *testing.T) { + runPhaseOverride := func(runner *statementRunner, result *neoResult) error { + result.runCompleted = true + return nil + } + records := 0 + recordsPhaseOverride := func(runner *statementRunner, result *neoResult) error { + records++ + if records%4 == 0 { + return failure + } + result.resultCompleted = true + return nil + } + + ctrl, _, runner := createMocksWithParams(t, AccessModeRead, false) + runner.runPhaseHandler = runPhaseOverride + runner.recordsPhaseHandler = recordsPhaseOverride + defer ctrl.Finish() + + resultsPushed := []*neoResult{} + for i := 0; i < 10; i++ { + resultsPushed = append(resultsPushed, createResultWithConn(runner)) + } + + runner.pendingResults = append(runner.pendingResults, resultsPushed...) + + err := runner.receiveAll() + + assert.Equal(t, err, failure) + assert.Empty(t, runner.pendingResults) + }) + }) +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/session.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/session.go new file mode 100644 index 0000000..6719da1 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/session.go @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +// Session represents a logical connection (which is not tied to a physical connection) +// to the server +type Session interface { + // LastBookmark returns the bookmark received following the last successfully completed transaction. + // If no bookmark was received or if this transaction was rolled back, the bookmark value will not be changed. + LastBookmark() string + // BeginTransaction starts a new explicit transaction on this session + BeginTransaction(configurers ...func(*TransactionConfig)) (Transaction, error) + // ReadTransaction executes the given unit of work in a AccessModeRead transaction with + // retry logic in place + ReadTransaction(work TransactionWork, configurers ...func(*TransactionConfig)) (interface{}, error) + // WriteTransaction executes the given unit of work in a AccessModeWrite transaction with + // retry logic in place + WriteTransaction(work TransactionWork, configurers ...func(*TransactionConfig)) (interface{}, error) + // Run executes an auto-commit statement and returns a result + Run(cypher string, params map[string]interface{}, configurers ...func(*TransactionConfig)) (Result, error) + // Close closes any open resources and marks this session as unusable + Close() error +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/session_impl.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/session_impl.go new file mode 100644 index 0000000..fc0544e --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/session_impl.go @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "sync/atomic" +) + +type neoSession struct { + driver *goboltDriver + accessMode AccessMode + bookmarks []string + + lastBookmark string + + open int32 + tx *neoTransaction + runner *statementRunner +} + +func newSession(driver *goboltDriver, accessMode AccessMode, bookmarks []string) Session { + // filter out bookmarks with empty string + bookmarks = filter(bookmarks, func(s string) bool { + return len(s) > 0 + }) + + return &neoSession{ + driver: driver, + accessMode: accessMode, + bookmarks: bookmarks, + lastBookmark: "", + open: 1, + tx: nil, + runner: nil, + } +} + +func assertSessionOpen(session *neoSession) error { + if atomic.LoadInt32(&session.open) == 0 { + return newDriverError("session is already closed") + } + + return nil +} + +// This ensures that we're in a good state to run statements on this +// session +func ensureReady(session *neoSession) error { + if err := assertSessionOpen(session); err != nil { + return nil + } + + if session.tx != nil { + return newDriverError("there's already an open transaction on this session") + } + + if session.runner != nil { + if err := session.runner.receiveAll(); err != nil { + return err + } + } + + return nil +} + +// This ensures that we've a connection to run statements against +func ensureRunner(session *neoSession, mode AccessMode, autoClose bool) error { + if session.runner != nil && (session.runner.autoClose != autoClose || session.runner.accessMode != mode) { + closeRunner(session) + } + + if session.runner == nil { + session.runner = newRunner(session.driver, mode, autoClose) + } + + return nil +} + +// This closes any active connection that's bound to this session and +// updates bookmark before actual closure +func closeRunner(session *neoSession) error { + if session.runner != nil { + var err error + var bookmark string + + err = session.runner.receiveAllAndClose() + + if bookmark, err = session.runner.lastSeenBookmark(); err == nil { + session.lastBookmark = bookmark + } + + session.runner = nil + return err + } + + return nil +} + +func (session *neoSession) id() string { + id := "unknown" + if session.runner != nil { + id = session.runner.id() + } + return id +} + +func (session *neoSession) LastBookmark() string { + if session.runner != nil { + var err error + var bookmark string + + if bookmark, err = session.runner.lastSeenBookmark(); err == nil { + return bookmark + } + } + + return session.lastBookmark +} + +func (session *neoSession) BeginTransaction(configurers ...func(*TransactionConfig)) (Transaction, error) { + return beginTransactionInternal(session, session.accessMode, configurers...) +} + +func (session *neoSession) ReadTransaction(work TransactionWork, configurers ...func(*TransactionConfig)) (interface{}, error) { + return runTransaction(session, AccessModeRead, work, configurers...) +} + +func (session *neoSession) WriteTransaction(work TransactionWork, configurers ...func(*TransactionConfig)) (interface{}, error) { + return runTransaction(session, AccessModeWrite, work, configurers...) +} + +func (session *neoSession) Run(cypher string, params map[string]interface{}, configurers ...func(*TransactionConfig)) (Result, error) { + return runStatementOnSession(session, &neoStatement{text: cypher, params: params}, configurers...) +} + +func (session *neoSession) Close() error { + if atomic.CompareAndSwapInt32(&session.open, 1, 0) { + if err := closeRunner(session); err != nil { + return err + } + } + + return nil +} + +func computeTransactionConfig(configurers ...func(config *TransactionConfig)) TransactionConfig { + config := TransactionConfig{Timeout: 0, Metadata: nil} + + for _, configurer := range configurers { + configurer(&config) + } + + return config +} + +func computeBookmarks(session *neoSession) []string { + var computedBookmarks []string + + computedBookmarks = append(computedBookmarks, session.bookmarks...) + if session.lastBookmark != "" { + computedBookmarks = append(computedBookmarks, session.lastBookmark) + } + + return computedBookmarks +} + +func beginTransactionInternal(session *neoSession, mode AccessMode, configurers ...func(*TransactionConfig)) (Transaction, error) { + if err := ensureReady(session); err != nil { + return nil, err + } + + if err := ensureRunner(session, mode, false); err != nil { + return nil, err + } + + beginResult, err := session.runner.beginTransaction(computeBookmarks(session), computeTransactionConfig(configurers...)) + if err != nil { + return nil, err + } + + if _, err := beginResult.Consume(); err != nil { + defer closeRunner(session) + + return nil, err + } + + transaction := &neoTransaction{session: session, beginResult: beginResult} + session.tx = transaction + return transaction, nil +} + +func runStatementOnSession(session *neoSession, statement *neoStatement, configurers ...func(*TransactionConfig)) (Result, error) { + if err := statement.validate(); err != nil { + return nil, err + } + + if err := ensureReady(session); err != nil { + return nil, err + } + + if err := ensureRunner(session, session.accessMode, true); err != nil { + return nil, err + } + + result, err := session.runner.runStatement(statement, computeBookmarks(session), computeTransactionConfig(configurers...)) + if err != nil { + return nil, err + } + + return result, nil +} + +func runTransaction(session *neoSession, mode AccessMode, work TransactionWork, configurers ...func(*TransactionConfig)) (interface{}, error) { + retry := newRetryLogic(session.driver.configuration()) + + result, err := retry.retry(func() (interface{}, string, error) { + tx, errWork := beginTransactionInternal(session, mode, configurers...) + if errWork != nil { + return nil, session.id(), errWork + } + defer tx.Close() + + resultWork, errWork := work(tx) + if errWork != nil { + return nil, session.id(), errWork + } + + errWork = tx.Commit() + if errWork != nil { + return nil, session.id(), errWork + } + + return resultWork, "", nil + }) + + return result, err +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/statement.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/statement.go new file mode 100644 index 0000000..46ef6df --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/statement.go @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +// Statement represents an executable statement, i.e. the statements' text and its parameters. +type Statement interface { + // Text returns the statement's text. + Text() string + // Params returns the statement's parameters. + Params() map[string]interface{} +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/statement_impl.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/statement_impl.go new file mode 100644 index 0000000..b9e3807 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/statement_impl.go @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +// Statement represents a statement along with its parameters (if any) +type neoStatement struct { + text string + params map[string]interface{} +} + +func (statement *neoStatement) Text() string { + return statement.text +} + +func (statement *neoStatement) Params() map[string]interface{} { + return statement.params +} + +func (statement *neoStatement) validate() error { + if len(statement.text) == 0 { + return newDriverError("statement text should not be empty") + } + + return nil +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary.go new file mode 100644 index 0000000..40550e4 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary.go @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "time" +) + +// StatementType defines the type of the statement +type StatementType int + +const ( + // StatementTypeUnknown identifies an unknown statement type + StatementTypeUnknown StatementType = 0 + // StatementTypeReadOnly identifies a read-only statement + StatementTypeReadOnly StatementType = 1 + // StatementTypeReadWrite identifies a read-write statement + StatementTypeReadWrite StatementType = 2 + // StatementTypeWriteOnly identifies a write-only statement + StatementTypeWriteOnly StatementType = 3 + // StatementTypeSchemaWrite identifies a schema-write statement + StatementTypeSchemaWrite StatementType = 4 +) + +// ResultSummary contains information about statement execution. +type ResultSummary interface { + // Server returns basic information about the server where the statement is carried out. + Server() ServerInfo + // Statement returns statement that has been executed. + Statement() Statement + // StatementType returns type of statement that has been executed. + StatementType() StatementType + // Counters returns statistics counts for the statement. + Counters() Counters + // Plan returns statement plan for the executed statement if available, otherwise null. + Plan() Plan + // Profile returns profiled statement plan for the executed statement if available, otherwise null. + Profile() ProfiledPlan + // Notifications returns a slice of notifications produced while executing the statement. + // The list will be empty if no notifications produced while executing the statement. + Notifications() []Notification + // ResultAvailableAfter returns the time it took for the server to make the result available for consumption. + ResultAvailableAfter() time.Duration + // ResultConsumedAfter returns the time it took the server to consume the result. + ResultConsumedAfter() time.Duration +} + +type neoResultSummary struct { + server ServerInfo + statement Statement + statementType StatementType + counters Counters + plan Plan + profile ProfiledPlan + notifications []Notification + resultAvailableAfter time.Duration + resultConsumedAfter time.Duration +} + +func (summary *neoResultSummary) Server() ServerInfo { + return summary.server +} + +func (summary *neoResultSummary) Statement() Statement { + return summary.statement +} + +func (summary *neoResultSummary) StatementType() StatementType { + return summary.statementType +} + +func (summary *neoResultSummary) Counters() Counters { + return summary.counters +} + +func (summary *neoResultSummary) Plan() Plan { + return summary.plan +} + +func (summary *neoResultSummary) Profile() ProfiledPlan { + return summary.profile +} + +func (summary *neoResultSummary) Notifications() []Notification { + return summary.notifications +} + +func (summary *neoResultSummary) ResultAvailableAfter() time.Duration { + return summary.resultAvailableAfter +} + +func (summary *neoResultSummary) ResultConsumedAfter() time.Duration { + return summary.resultConsumedAfter +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_collection.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_collection.go new file mode 100644 index 0000000..793ec1d --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_collection.go @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "fmt" + "strconv" +) + +func extractIntValue(dict *map[string]interface{}, key string, defaultValue int64) int64 { + if dict == nil { + return defaultValue + } + + if value, ok := (*dict)[key]; ok { + if valueAsLong, ok := value.(int64); ok { + return valueAsLong + } + + valueAsLong, err := strconv.ParseInt(fmt.Sprintf("%v", value), 10, 64) + if err != nil { + return defaultValue + } + + return valueAsLong + } + + return defaultValue +} + +func extractStringValue(dict *map[string]interface{}, key string, defaultValue string) string { + if dict == nil { + return defaultValue + } + + if value, ok := (*dict)[key]; ok { + if valueAsStr, ok := value.(string); ok { + return valueAsStr + } + + if isNil(value) { + return defaultValue + } + + return fmt.Sprintf("%v", value) + } + + return defaultValue +} + +func collectCounters(dict *map[string]interface{}) Counters { + counters := &neoCounters{} + + if dict != nil { + counters.nodesCreated = int(extractIntValue(dict, "nodes-created", 0)) + counters.nodesDeleted = int(extractIntValue(dict, "nodes-deleted", 0)) + counters.relationshipsCreated = int(extractIntValue(dict, "relationships-created", 0)) + counters.relationshipsDeleted = int(extractIntValue(dict, "relationships-deleted", 0)) + counters.propertiesSet = int(extractIntValue(dict, "properties-set", 0)) + counters.labelsAdded = int(extractIntValue(dict, "labels-added", 0)) + counters.labelsRemoved = int(extractIntValue(dict, "labels-removed", 0)) + counters.indexesAdded = int(extractIntValue(dict, "indexes-added", 0)) + counters.indexesRemoved = int(extractIntValue(dict, "indexes-removed", 0)) + counters.constraintsAdded = int(extractIntValue(dict, "constraints-added", 0)) + counters.constraintsRemoved = int(extractIntValue(dict, "constraints-removed", 0)) + } + + return counters +} + +func collectNotification(list *[]interface{}, target *[]Notification) { + if list == nil { + return + } + + notificationsList := *list + + notifications := make([]Notification, len(notificationsList)) + for i, notification := range notificationsList { + if notificationDict, ok := notification.(map[string]interface{}); ok { + code := extractStringValue(¬ificationDict, "code", "") + title := extractStringValue(¬ificationDict, "title", "") + description := extractStringValue(¬ificationDict, "description", "") + severity := extractStringValue(¬ificationDict, "severity", "") + + position := &neoInputPosition{} + if positionData, ok := notificationDict["position"]; ok { + if positionDict, ok := positionData.(map[string]interface{}); ok { + position.offset = int(extractIntValue(&positionDict, "offset", 0)) + position.line = int(extractIntValue(&positionDict, "line", 0)) + position.column = int(extractIntValue(&positionDict, "column", 0)) + } + } + + notifications[i] = &neoNotification{ + code: code, + title: title, + description: description, + position: position, + severity: severity, + } + } + } + + *target = notifications +} + +func collectPlan(dict *map[string]interface{}) Plan { + var ( + operationType string + args map[string]interface{} + identifiers []string + children []Plan + ) + + if dict == nil { + return nil + } + + plansDict := *dict + operationType = extractStringValue(dict, "operatorType", "") + + if argsValue, ok := plansDict["args"]; ok { + args = argsValue.(map[string]interface{}) + } + + if identifiersValue, ok := plansDict["identifiers"]; ok { + identifiersList := identifiersValue.([]interface{}) + identifiers = make([]string, len(identifiersList)) + for i, identifier := range identifiersList { + identifiers[i] = identifier.(string) + } + } + + if childrenValue, ok := plansDict["children"]; ok { + childrenList := childrenValue.([]interface{}) + children = make([]Plan, len(childrenList)) + for i, child := range childrenList { + childMap := child.(map[string]interface{}) + children[i] = collectPlan(&childMap) + } + } + + return &neoPlan{ + operator: operationType, + arguments: args, + identifiers: identifiers, + children: children, + } +} + +func collectProfile(dict *map[string]interface{}) ProfiledPlan { + var ( + operationType string + args map[string]interface{} + identifiers []string + dbHits int64 + records int64 + children []ProfiledPlan + ) + + if dict == nil { + return nil + } + + plansDict := *dict + operationType = extractStringValue(dict, "operatorType", "") + dbHits = extractIntValue(dict, "dbHits", 0) + records = extractIntValue(dict, "rows", 0) + + if argsValue, ok := plansDict["args"]; ok { + args = argsValue.(map[string]interface{}) + } + + if identifiersValue, ok := plansDict["identifiers"]; ok { + identifiersList := identifiersValue.([]interface{}) + identifiers = make([]string, len(identifiersList)) + for i, identifier := range identifiersList { + identifiers[i] = identifier.(string) + } + } + + if childrenValue, ok := plansDict["children"]; ok { + childrenList := childrenValue.([]interface{}) + children = make([]ProfiledPlan, len(childrenList)) + for i, child := range childrenList { + childMap := child.(map[string]interface{}) + children[i] = collectProfile(&childMap) + } + } + + return &neoProfiledPlan{ + operator: operationType, + arguments: args, + identifiers: identifiers, + dbHits: dbHits, + records: records, + children: children, + } +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_counters.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_counters.go new file mode 100644 index 0000000..4937e83 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_counters.go @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +// Counters contains statistics about the changes made to the database made as part +// of the statement execution. +type Counters interface { + // Whether there were any updates at all, eg. any of the counters are greater than 0. + ContainsUpdates() bool + // The number of nodes created. + NodesCreated() int + // The number of nodes deleted. + NodesDeleted() int + // The number of relationships created. + RelationshipsCreated() int + // The number of relationships deleted. + RelationshipsDeleted() int + PropertiesSet() int + // The number of labels added to nodes. + LabelsAdded() int + // The number of labels removed from nodes. + LabelsRemoved() int + // The number of indexes added to the schema. + IndexesAdded() int + // The number of indexes removed from the schema. + IndexesRemoved() int + // The number of constraints added to the schema. + ConstraintsAdded() int + // The number of constraints removed from the schema. + ConstraintsRemoved() int +} + +type neoCounters struct { + nodesCreated int + nodesDeleted int + relationshipsCreated int + relationshipsDeleted int + propertiesSet int + labelsAdded int + labelsRemoved int + indexesAdded int + indexesRemoved int + constraintsAdded int + constraintsRemoved int +} + +func (counters *neoCounters) NodesCreated() int { + return counters.nodesCreated +} + +func (counters *neoCounters) NodesDeleted() int { + return counters.nodesDeleted +} + +func (counters *neoCounters) RelationshipsCreated() int { + return counters.relationshipsCreated +} + +func (counters *neoCounters) RelationshipsDeleted() int { + return counters.relationshipsDeleted +} + +func (counters *neoCounters) PropertiesSet() int { + return counters.propertiesSet +} + +func (counters *neoCounters) LabelsAdded() int { + return counters.labelsAdded +} + +func (counters *neoCounters) LabelsRemoved() int { + return counters.labelsRemoved +} + +func (counters *neoCounters) IndexesAdded() int { + return counters.indexesAdded +} + +func (counters *neoCounters) IndexesRemoved() int { + return counters.indexesRemoved +} + +func (counters *neoCounters) ConstraintsAdded() int { + return counters.constraintsAdded +} + +func (counters *neoCounters) ConstraintsRemoved() int { + return counters.constraintsRemoved +} + +func (counters *neoCounters) ContainsUpdates() bool { + return counters.nodesCreated > 0 || + counters.nodesDeleted > 0 || + counters.relationshipsCreated > 0 || + counters.relationshipsDeleted > 0 || + counters.propertiesSet > 0 || + counters.labelsAdded > 0 || + counters.labelsRemoved > 0 || + counters.indexesAdded > 0 || + counters.indexesRemoved > 0 || + counters.constraintsAdded > 0 || + counters.constraintsRemoved > 0 +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_notification.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_notification.go new file mode 100644 index 0000000..51f9182 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_notification.go @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +// Notification represents notifications generated when executing a statement. +// A notification can be visualized in a client pinpointing problems or other information about the statement. +type Notification interface { + // Code returns a notification code for the discovered issue of this notification. + Code() string + // Title returns a short summary of this notification. + Title() string + // Description returns a longer description of this notification. + Description() string + // Position returns the position in the statement where this notification points to. + // Not all notifications have a unique position to point to and in that case the position would be set to nil. + Position() InputPosition + // Severity returns the severity level of this notification. + Severity() string +} + +type neoNotification struct { + code string + title string + description string + position *neoInputPosition + severity string +} + +func (notification *neoNotification) Code() string { + return notification.code +} + +func (notification *neoNotification) Title() string { + return notification.title +} + +func (notification *neoNotification) Description() string { + return notification.description +} + +func (notification *neoNotification) Position() InputPosition { + return notification.position +} + +func (notification *neoNotification) Severity() string { + return notification.severity +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_plan.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_plan.go new file mode 100644 index 0000000..eae9fbd --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_plan.go @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +// Plan describes the actual plan that the database planner produced and used (or will use) to execute your statement. +// This can be extremely helpful in understanding what a statement is doing, and how to optimize it. For more details, +// see the Neo4j Manual. The plan for the statement is a tree of plans - each sub-tree containing zero or more child +// plans. The statement starts with the root plan. Each sub-plan is of a specific operator, which describes what +// that part of the plan does - for instance, perform an index lookup or filter results. +// The Neo4j Manual contains a reference of the available operator types, and these may differ across Neo4j versions. +type Plan interface { + // Operator returns the operation this plan is performing. + Operator() string + // Arguments returns the arguments for the operator used. + // Many operators have arguments defining their specific behavior. This map contains those arguments. + Arguments() map[string]interface{} + // Identifiers returns a list of identifiers used by this plan. Identifiers used by this part of the plan. + // These can be both identifiers introduced by you, or automatically generated. + Identifiers() []string + // Children returns zero or more child plans. A plan is a tree, where each child is another plan. + // The children are where this part of the plan gets its input records - unless this is an operator that + // introduces new records on its own. + Children() []Plan +} + +type neoPlan struct { + operator string + arguments map[string]interface{} + identifiers []string + children []Plan +} + +func (plan *neoPlan) Operator() string { + return plan.operator +} + +func (plan *neoPlan) Arguments() map[string]interface{} { + return plan.arguments +} + +func (plan *neoPlan) Identifiers() []string { + return plan.identifiers +} + +func (plan *neoPlan) Children() []Plan { + return plan.children +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_position.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_position.go new file mode 100644 index 0000000..de1a576 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_position.go @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +// InputPosition contains information about a specific position in a statement +type InputPosition interface { + // Offset returns the character offset referred to by this position; offset numbers start at 0. + Offset() int + // Line returns the line number referred to by this position; line numbers start at 1. + Line() int + // Column returns the column number referred to by this position; column numbers start at 1. + Column() int +} + +type neoInputPosition struct { + offset int + line int + column int +} + +func (pos *neoInputPosition) Offset() int { + return pos.offset +} + +func (pos *neoInputPosition) Line() int { + return pos.line +} + +func (pos *neoInputPosition) Column() int { + return pos.column +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_profiled_plan.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_profiled_plan.go new file mode 100644 index 0000000..8279c4d --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_profiled_plan.go @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +// ProfiledPlan is the same as a regular Plan - except this plan has been executed, meaning it also +// contains detailed information about how much work each step of the plan incurred on the database. +type ProfiledPlan interface { + // Operator returns the operation this plan is performing. + Operator() string + // Arguments returns the arguments for the operator used. + // Many operators have arguments defining their specific behavior. This map contains those arguments. + Arguments() map[string]interface{} + // Identifiers returns a list of identifiers used by this plan. Identifiers used by this part of the plan. + // These can be both identifiers introduced by you, or automatically generated. + Identifiers() []string + // DbHits returns the number of times this part of the plan touched the underlying data stores/ + DbHits() int64 + // Records returns the number of records this part of the plan produced. + Records() int64 + // Children returns zero or more child plans. A plan is a tree, where each child is another plan. + // The children are where this part of the plan gets its input records - unless this is an operator that + // introduces new records on its own. + Children() []ProfiledPlan +} + +type neoProfiledPlan struct { + operator string + arguments map[string]interface{} + identifiers []string + dbHits int64 + records int64 + children []ProfiledPlan +} + +func (plan *neoProfiledPlan) Operator() string { + return plan.operator +} + +func (plan *neoProfiledPlan) Arguments() map[string]interface{} { + return plan.arguments +} + +func (plan *neoProfiledPlan) Identifiers() []string { + return plan.identifiers +} + +func (plan *neoProfiledPlan) DbHits() int64 { + return plan.dbHits +} + +func (plan *neoProfiledPlan) Records() int64 { + return plan.records +} + +func (plan *neoProfiledPlan) Children() []ProfiledPlan { + return plan.children +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_server_info.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_server_info.go new file mode 100644 index 0000000..b0a0330 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_server_info.go @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +// ServerInfo contains basic information of the server. +type ServerInfo interface { + // Address returns the address of the server. + Address() string + // Version returns the version of Neo4j running at the server. + Version() string +} + +type neoServerInfo struct { + address string + version string +} + +func (server *neoServerInfo) Address() string { + return server.address +} + +func (server *neoServerInfo) Version() string { + return server.version +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_test.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_test.go new file mode 100644 index 0000000..fb41261 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/summary_test.go @@ -0,0 +1,849 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Summary", func() { + + Context("extractIntValue", func() { + dict := map[string]interface{}{ + "key1": 123, + "key2": int8(54), + "key3": "456", + "key4": "456.123", + "key5": "some non-number value", + "key6": int64(12456), + } + + When("map is nil", func() { + extracted := extractIntValue(nil, "key", -1) + + It("should return default value", func() { + Expect(extracted).To(BeNumerically("==", -1)) + }) + }) + + When("given key does not exist", func() { + extracted := extractIntValue(&dict, "key", -1) + + It("should return default value if key not found", func() { + Expect(extracted).To(BeNumerically("==", -1)) + }) + }) + + When("given key is mapped to an int value", func() { + extracted := extractIntValue(&dict, "key1", -1) + + It("should return the int value", func() { + Expect(extracted).To(BeNumerically("==", 123)) + }) + }) + + When("given key is mapped to an int64 value", func() { + extracted := extractIntValue(&dict, "key6", -1) + + It("should return the int value", func() { + Expect(extracted).To(BeNumerically("==", 12456)) + }) + }) + + When("given key is mapped to a byte value", func() { + extracted := extractIntValue(&dict, "key2", -1) + + It("should return the int value", func() { + Expect(extracted).To(BeNumerically("==", 54)) + }) + }) + + When("given key is mapped to an int string", func() { + extracted := extractIntValue(&dict, "key3", -1) + + It("should return the int value", func() { + Expect(extracted).To(BeNumerically("==", 456)) + }) + }) + + When("given key is mapped to a float string", func() { + extracted := extractIntValue(&dict, "key4", -1) + + It("should return default value", func() { + Expect(extracted).To(BeNumerically("==", -1)) + }) + }) + + When("given key is mapped to a string", func() { + extracted := extractIntValue(&dict, "key5", -1) + + It("should return default value", func() { + Expect(extracted).To(BeNumerically("==", -1)) + }) + }) + }) + + Context("extractStringValue", func() { + dict := map[string]interface{}{ + "key1": "123", + "key2": 456, + "key3": 3 * time.Second, + "key4": 123.568, + "key5": nil, + } + + When("map is nil", func() { + extracted := extractStringValue(nil, "key", "default") + + It("should return default value", func() { + Expect(extracted).To(Equal("default")) + }) + }) + + When("given key does not exist", func() { + extracted := extractStringValue(&dict, "key", "default") + + It("should return default value", func() { + Expect(extracted).To(Equal("default")) + }) + }) + + When("given key is mapped to nil", func() { + extracted := extractStringValue(&dict, "key5", "default") + + It("should return the default value", func() { + Expect(extracted).To(Equal("default")) + }) + }) + + When("given key is mapped to a string value", func() { + extracted := extractStringValue(&dict, "key1", "default") + + It("should return the string value", func() { + Expect(extracted).To(Equal("123")) + }) + }) + + When("given key is mapped to an int string", func() { + extracted := extractStringValue(&dict, "key2", "default") + + It("should return the converted string value", func() { + Expect(extracted).To(Equal("456")) + }) + }) + + When("given key is mapped to a duration string", func() { + extracted := extractStringValue(&dict, "key3", "default") + + It("should return the converted string value", func() { + Expect(extracted).To(Equal("3s")) + }) + }) + + When("given key is mapped to a float string", func() { + extracted := extractStringValue(&dict, "key4", "default") + + It("should return the converted string value", func() { + Expect(extracted).To(Equal("123.568")) + }) + }) + }) + + Context("collectCounters", func() { + When("map is nil", func() { + It("should not collect anything", func() { + counters := collectCounters(nil) + Expect(counters).To(BeEquivalentTo(&neoCounters{})) + }) + }) + + When("map contains counter values", func() { + dict := map[string]interface{}{ + "nodes-created": 1, + "nodes-deleted": 2, + "relationships-created": 3, + "relationships-deleted": 4, + "properties-set": 5, + "labels-added": 6, + "labels-removed": 7, + "indexes-added": 8, + "indexes-removed": 9, + "constraints-added": 10, + "constraints-removed": 11, + } + + counters := collectCounters(&dict) + + It("should have NodesCreated = 1", func() { + Expect(counters.NodesCreated()).To(BeNumerically("==", 1)) + }) + + It("should have NodesDeleted = 2", func() { + Expect(counters.NodesDeleted()).To(BeNumerically("==", 2)) + }) + + It("should have RelationshipsCreated = 3", func() { + Expect(counters.RelationshipsCreated()).To(BeNumerically("==", 3)) + }) + + It("should have RelationshipsDeleted = 4", func() { + Expect(counters.RelationshipsDeleted()).To(BeNumerically("==", 4)) + }) + + It("should have PropertiesSet = 5", func() { + Expect(counters.PropertiesSet()).To(BeNumerically("==", 5)) + }) + + It("should have LabelsAdded = 6", func() { + Expect(counters.LabelsAdded()).To(BeNumerically("==", 6)) + }) + + It("should have LabelsRemoved = 7", func() { + Expect(counters.LabelsRemoved()).To(BeNumerically("==", 7)) + }) + + It("should have IndexesAdded = 8", func() { + Expect(counters.IndexesAdded()).To(BeNumerically("==", 8)) + }) + + It("should have IndexesRemoved = 9", func() { + Expect(counters.IndexesRemoved()).To(BeNumerically("==", 9)) + }) + + It("should have ConstraintsAdded = 10", func() { + Expect(counters.ConstraintsAdded()).To(BeNumerically("==", 10)) + }) + + It("should have ConstraintsRemoved = 11", func() { + Expect(counters.ConstraintsRemoved()).To(BeNumerically("==", 11)) + }) + }) + }) + + Context("collectNotifications", func() { + When("map is nil", func() { + It("should not collect anything", func() { + var target *[]Notification = nil + collectNotification(nil, target) + Expect(target).To(BeNil()) + }) + }) + + When("map contains one notification", func() { + list := []interface{}{ + map[string]interface{}{ + "code": "c1", + "title": "t1", + "description": "d1", + "position": map[string]interface{}{ + "offset": 1, + "line": 2, + "column": 3, + }, + "severity": "s1", + }, + } + var notifications []Notification + collectNotification(&list, ¬ifications) + + It("should have 1 item", func() { + Expect(notifications).To(HaveLen(1)) + }) + + Context("Item 0", func() { + item := notifications[0] + + It("should have Code = `c1`", func() { + Expect(item.Code()).To(BeIdenticalTo("c1")) + }) + + It("should have Title = `t1`", func() { + Expect(item.Title()).To(BeIdenticalTo("t1")) + }) + + It("should have Description = `d1`", func() { + Expect(item.Description()).To(BeIdenticalTo("d1")) + }) + + Context("Position", func() { + It("should have Offset = 1", func() { + Expect(item.Position().Offset()).To(BeNumerically("==", 1)) + }) + + It("should have Line = 2", func() { + Expect(item.Position().Line()).To(BeNumerically("==", 2)) + }) + + It("should have Column = 3", func() { + Expect(item.Position().Column()).To(BeNumerically("==", 3)) + }) + }) + + It("should have Severity = `s1`", func() { + Expect(item.Severity()).To(BeIdenticalTo("s1")) + }) + }) + }) + + When("map contains two notifications", func() { + list := []interface{}{ + map[string]interface{}{ + "code": "c1", + "title": "t1", + "description": "d1", + "position": map[string]interface{}{ + "offset": 1, + "line": 2, + "column": 3, + }, + "severity": "s1", + }, + map[string]interface{}{ + "code": "c2", + "title": "t2", + "description": "d2", + "position": map[string]interface{}{ + "offset": 4, + "line": 5, + "column": 6, + }, + "severity": "s2", + }, + } + var notifications []Notification + collectNotification(&list, ¬ifications) + + It("should have 2 items", func() { + Expect(notifications).To(HaveLen(2)) + }) + + Context("Item 0", func() { + item := notifications[0] + + It("should have Code = `c1`", func() { + Expect(item.Code()).To(BeIdenticalTo("c1")) + }) + + It("should have Title = `t1`", func() { + Expect(item.Title()).To(BeIdenticalTo("t1")) + }) + + It("should have Description = `d1`", func() { + Expect(item.Description()).To(BeIdenticalTo("d1")) + }) + + Context("Position", func() { + It("should have Offset = 1", func() { + Expect(item.Position().Offset()).To(BeNumerically("==", 1)) + }) + + It("should have Line = 2", func() { + Expect(item.Position().Line()).To(BeNumerically("==", 2)) + }) + + It("should have Column = 3", func() { + Expect(item.Position().Column()).To(BeNumerically("==", 3)) + }) + }) + + It("should have Severity = `s1`", func() { + Expect(item.Severity()).To(BeIdenticalTo("s1")) + }) + }) + + Context("Item 1", func() { + item := notifications[1] + + It("should have Code = `c2`", func() { + Expect(item.Code()).To(BeIdenticalTo("c2")) + }) + + It("should have Title = `t2`", func() { + Expect(item.Title()).To(BeIdenticalTo("t2")) + }) + + It("should have Description = `d2`", func() { + Expect(item.Description()).To(BeIdenticalTo("d2")) + }) + + Context("Position", func() { + It("should have Offset = 4", func() { + Expect(item.Position().Offset()).To(BeNumerically("==", 4)) + }) + + It("should have Line = 5", func() { + Expect(item.Position().Line()).To(BeNumerically("==", 5)) + }) + + It("should have Column = 6", func() { + Expect(item.Position().Column()).To(BeNumerically("==", 6)) + }) + }) + + It("should have Severity = `s2`", func() { + Expect(item.Severity()).To(BeIdenticalTo("s2")) + }) + }) + }) + }) + + Context("collectPlan", func() { + When("given map is nil", func() { + It("should not collect anything", func() { + plan := collectPlan(nil) + Expect(plan).To(BeNil()) + }) + }) + + When("given map contains a plan without children", func() { + dict := map[string]interface{}{ + "operatorType": "XOperator", + "args": map[string]interface{}{ + "x": 1, + "y": "string", + "z": 0.15, + }, + "identifiers": []interface{}{"id1", "id2"}, + } + + planPtr := collectPlan(&dict) + + It("should not be nil", func() { + Expect(planPtr).NotTo(BeNil()) + }) + + It("should have Operator = XOperator", func() { + Expect(planPtr.Operator()).To(BeIdenticalTo("XOperator")) + }) + + Context("Args", func() { + It("should have 3 items", func() { + Expect(planPtr.Arguments()).To(HaveLen(3)) + }) + + It("should contain x = 1", func() { + Expect(planPtr.Arguments()).To(HaveKeyWithValue("x", 1)) + }) + + It("should contain y = string", func() { + Expect(planPtr.Arguments()).To(HaveKeyWithValue("y", "string")) + }) + + It("should contain z = 0.15", func() { + Expect(planPtr.Arguments()).To(HaveKeyWithValue("z", 0.15)) + }) + }) + + Context("Identifiers", func() { + It("should have 2 items", func() { + Expect(planPtr.Identifiers()).To(HaveLen(2)) + }) + + It("should contain id1", func() { + Expect(planPtr.Identifiers()).To(ContainElement("id1")) + }) + + It("should contain id2", func() { + Expect(planPtr.Identifiers()).To(ContainElement("id2")) + }) + }) + + It("should not have any children", func() { + Expect(planPtr.Children()).To(BeEmpty()) + }) + }) + + When("given map contains a plan with children", func() { + dict := map[string]interface{}{ + "operatorType": "XOperator", + "args": map[string]interface{}{ + "x": 1, + "y": "string", + "z": 0.15, + }, + "identifiers": []interface{}{"id1", "id2"}, + "children": []interface{}{ + map[string]interface{}{ + "operatorType": "YOperator", + "args": map[string]interface{}{ + "k": 2, + }, + "identifiers": []interface{}{"id3"}, + }, + map[string]interface{}{ + "operatorType": "ZOperator", + "args": map[string]interface{}{ + "l": 1.35, + }, + }, + }, + } + + plan := collectPlan(&dict) + + It("should not be nil", func() { + Expect(plan).NotTo(BeNil()) + }) + + It("should have Operator = XOperator", func() { + Expect(plan.Operator()).To(BeIdenticalTo("XOperator")) + }) + + Context("Args", func() { + It("should have 3 items", func() { + Expect(plan.Arguments()).To(HaveLen(3)) + }) + + It("should contain x = 1", func() { + Expect(plan.Arguments()).To(HaveKeyWithValue("x", 1)) + }) + + It("should contain y = string", func() { + Expect(plan.Arguments()).To(HaveKeyWithValue("y", "string")) + }) + + It("should contain z = 0.15", func() { + Expect(plan.Arguments()).To(HaveKeyWithValue("z", 0.15)) + }) + }) + + Context("Identifiers", func() { + It("should have 2 items", func() { + Expect(plan.Identifiers()).To(HaveLen(2)) + }) + + It("should contain id1", func() { + Expect(plan.Identifiers()).To(ContainElement("id1")) + }) + + It("should contain id2", func() { + Expect(plan.Identifiers()).To(ContainElement("id2")) + }) + }) + + Context("Children", func() { + It("should have 2 children", func() { + Expect(plan.Children()).To(HaveLen(2)) + }) + + Context("Item 0", func() { + elem := plan.Children()[0] + + It("should have Operator = YOperator", func() { + Expect(elem.Operator()).To(BeIdenticalTo("YOperator")) + }) + + Context("Args", func() { + It("should have 1 item", func() { + Expect(elem.Arguments()).To(HaveLen(1)) + }) + + It("should contain k = 2", func() { + Expect(elem.Arguments()).To(HaveKeyWithValue("k", 2)) + }) + }) + + Context("Identifiers", func() { + It("should have 1 identifier", func() { + Expect(elem.Identifiers()).To(HaveLen(1)) + }) + + It("should contain id3", func() { + Expect(elem.Identifiers()).To(ContainElement("id3")) + }) + }) + + It("should not have any children", func() { + Expect(elem.Children()).To(BeEmpty()) + }) + }) + + Context("Item 1", func() { + elem := plan.Children()[1] + + It("should have Operator = ZOperator", func() { + Expect(elem.Operator()).To(BeIdenticalTo("ZOperator")) + }) + + Context("Args", func() { + It("should have 1 item", func() { + Expect(elem.Arguments()).To(HaveLen(1)) + }) + + It("should contain l = 1.35", func() { + Expect(elem.Arguments()).To(HaveKeyWithValue("l", 1.35)) + }) + }) + + It("should not have any Identifiers", func() { + Expect(elem.Identifiers()).To(BeEmpty()) + }) + + It("should not have any Children", func() { + Expect(elem.Children()).To(BeEmpty()) + }) + }) + }) + }) + }) + + Context("collectProfiledPlan", func() { + When("given map is nil", func() { + It("should not collect anything", func() { + plan := collectProfile(nil) + Expect(plan).To(BeNil()) + }) + }) + + When("given map contains a plan without children", func() { + dict := map[string]interface{}{ + "operatorType": "XOperator", + "rows": 50, + "dbHits": 1000, + "args": map[string]interface{}{ + "x": 1, + "y": "string", + "z": 0.15, + }, + "identifiers": []interface{}{"id1", "id2"}, + } + + planPtr := collectProfile(&dict) + + It("should not be nil", func() { + Expect(planPtr).NotTo(BeNil()) + }) + + It("should have Operator = XOperator", func() { + Expect(planPtr.Operator()).To(BeIdenticalTo("XOperator")) + }) + + It("should have Records = 50", func() { + Expect(planPtr.Records()).To(BeNumerically("==", 50)) + }) + + It("should have DbHits = 1000", func() { + Expect(planPtr.DbHits()).To(BeNumerically("==", 1000)) + }) + + Context("Args", func() { + It("should have 3 items", func() { + Expect(planPtr.Arguments()).To(HaveLen(3)) + }) + + It("should contain x = 1", func() { + Expect(planPtr.Arguments()).To(HaveKeyWithValue("x", 1)) + }) + + It("should contain y = string", func() { + Expect(planPtr.Arguments()).To(HaveKeyWithValue("y", "string")) + }) + + It("should contain z = 0.15", func() { + Expect(planPtr.Arguments()).To(HaveKeyWithValue("z", 0.15)) + }) + }) + + Context("Identifiers", func() { + It("should have 2 items", func() { + Expect(planPtr.Identifiers()).To(HaveLen(2)) + }) + + It("should contain id1", func() { + Expect(planPtr.Identifiers()).To(ContainElement("id1")) + }) + + It("should contain id2", func() { + Expect(planPtr.Identifiers()).To(ContainElement("id2")) + }) + }) + + It("should not have any Children", func() { + Expect(planPtr.Children()).To(BeEmpty()) + }) + }) + + When("given map contains a plan with children", func() { + dict := map[string]interface{}{ + "operatorType": "XOperator", + "rows": 50, + "dbHits": 5000, + "args": map[string]interface{}{ + "x": 1, + "y": "string", + "z": 0.15, + }, + "identifiers": []interface{}{"id1", "id2"}, + "children": []interface{}{ + map[string]interface{}{ + "operatorType": "YOperator", + "rows": 5, + "dbHits": 10, + "args": map[string]interface{}{ + "k": 2, + }, + "identifiers": []interface{}{"id3"}, + }, + map[string]interface{}{ + "operatorType": "ZOperator", + "rows": 10, + "dbHits": 100, + "args": map[string]interface{}{ + "l": 1.35, + }, + }, + }, + } + + plan := collectProfile(&dict) + + It("should not be nil", func() { + Expect(plan).NotTo(BeNil()) + }) + + It("should have Operator = XOperator", func() { + Expect(plan.Operator()).To(BeIdenticalTo("XOperator")) + }) + + It("should have Records = 50", func() { + Expect(plan.Records()).To(BeNumerically("==", 50)) + }) + + It("should have DbHits = 5000", func() { + Expect(plan.DbHits()).To(BeNumerically("==", 5000)) + }) + + Context("Args", func() { + It("should have 3 items", func() { + Expect(plan.Arguments()).To(HaveLen(3)) + }) + + It("should contain x = 1", func() { + Expect(plan.Arguments()).To(HaveKeyWithValue("x", 1)) + }) + + It("should contain y = string", func() { + Expect(plan.Arguments()).To(HaveKeyWithValue("y", "string")) + }) + + It("should contain z = 0.15", func() { + Expect(plan.Arguments()).To(HaveKeyWithValue("z", 0.15)) + }) + }) + + Context("Identifiers", func() { + It("should have 2 items", func() { + Expect(plan.Identifiers()).To(HaveLen(2)) + }) + + It("should contain id1", func() { + Expect(plan.Identifiers()).To(ContainElement("id1")) + }) + + It("should contain id2", func() { + Expect(plan.Identifiers()).To(ContainElement("id2")) + }) + }) + + Context("Children", func() { + It("should have 2 children", func() { + Expect(plan.Children()).To(HaveLen(2)) + }) + + Context("Item 0", func() { + elem := plan.Children()[0] + + It("should have Operator = YOperator", func() { + Expect(elem.Operator()).To(BeIdenticalTo("YOperator")) + }) + + It("should have Records = 5", func() { + Expect(elem.Records()).To(BeNumerically("==", 5)) + }) + + It("should have DbHits = 10", func() { + Expect(elem.DbHits()).To(BeNumerically("==", 10)) + }) + + Context("Args", func() { + It("should have 1 item", func() { + Expect(elem.Arguments()).To(HaveLen(1)) + }) + + It("should contain k = 2", func() { + Expect(elem.Arguments()).To(HaveKeyWithValue("k", 2)) + }) + }) + + Context("Identifiers", func() { + It("should have 1 identifier", func() { + Expect(elem.Identifiers()).To(HaveLen(1)) + }) + + It("should contain id3", func() { + Expect(elem.Identifiers()).To(ContainElement("id3")) + }) + }) + + It("should not have any Children", func() { + Expect(elem.Children()).To(BeEmpty()) + }) + }) + + Context("Item 1", func() { + elem := plan.Children()[1] + + It("should have Operator = ZOperator", func() { + Expect(elem.Operator()).To(BeIdenticalTo("ZOperator")) + }) + + It("should have Records = 5", func() { + Expect(elem.Records()).To(BeNumerically("==", 10)) + }) + + It("should have DbHits = 10", func() { + Expect(elem.DbHits()).To(BeNumerically("==", 100)) + }) + + Context("Args", func() { + It("should have 1 item", func() { + Expect(elem.Arguments()).To(HaveLen(1)) + }) + + It("should contain l = 1.35", func() { + Expect(elem.Arguments()).To(HaveKeyWithValue("l", 1.35)) + }) + }) + + It("should not have any Identifiers", func() { + Expect(elem.Identifiers()).To(BeEmpty()) + }) + + It("should not have any Children", func() { + Expect(elem.Children()).To(BeEmpty()) + }) + }) + }) + }) + }) +}) diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/transaction.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/transaction.go new file mode 100644 index 0000000..6bf8f04 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/transaction.go @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +// Transaction represents a transaction in the Neo4j database +type Transaction interface { + // Run executes a statement on this transaction and returns a result + Run(cypher string, params map[string]interface{}) (Result, error) + // Commit commits the transaction + Commit() error + // Rollback rolls back the transaction + Rollback() error + // Close rolls back the actual transaction if it's not already committed/rolled back + // and closes all resources associated with this transaction + Close() error +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/transaction_config.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/transaction_config.go new file mode 100644 index 0000000..bcc659b --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/transaction_config.go @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import "time" + +// TransactionConfig holds the settings for explicit and auto-commit transactions. Actual configuration is expected +// to be done using configuration functions that are predefined, i.e. 'WithTxTimeout' and 'WithTxMetadata', or one +// that you could write by your own. +type TransactionConfig struct { + // Timeout is the configured transaction timeout. + Timeout time.Duration + // Metadata is the configured transaction metadata that will be attached to the underlying transaction. + Metadata map[string]interface{} +} + +// WithTxTimeout returns a transaction configuration function that applies a timeout to a transaction. +// +// To apply a transaction timeout to an explicit transaction: +// session.BeginTransaction(WithTxTimeout(5*time.Seconds)) +// +// To apply a transaction timeout to an auto-commit transaction: +// session.Run("RETURN 1", nil, WithTxTimeout(5*time.Seconds)) +// +// To apply a transaction timeout to a read transaction function: +// session.ReadTransaction(DoWork, WithTxTimeout(5*time.Seconds)) +// +// To apply a transaction timeout to a write transaction function: +// session.WriteTransaction(DoWork, WithTxTimeout(5*time.Seconds)) +func WithTxTimeout(timeout time.Duration) func(*TransactionConfig) { + return func(config *TransactionConfig) { + config.Timeout = timeout + } +} + +// WithTxMetadata returns a transaction configuration function that attaches metadata to a transaction. +// +// To attach a metadata to an explicit transaction: +// session.BeginTransaction(WithTxMetadata(map[string)interface{}{"work-id": 1})) +// +// To attach a metadata to an auto-commit transaction: +// session.Run("RETURN 1", nil, WithTxMetadata(map[string)interface{}{"work-id": 1})) +// +// To attach a metadata to a read transaction function: +// session.ReadTransaction(DoWork, WithTxMetadata(map[string)interface{}{"work-id": 1})) +// +// To attach a metadata to a write transaction function: +// session.WriteTransaction(DoWork, WithTxMetadata(map[string)interface{}{"work-id": 1})) +func WithTxMetadata(metadata map[string]interface{}) func(*TransactionConfig) { + return func(config *TransactionConfig) { + config.Metadata = metadata + } +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/transaction_impl.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/transaction_impl.go new file mode 100644 index 0000000..b402431 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/transaction_impl.go @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +type neoTransaction struct { + session *neoSession + outcomeApplied bool + beginResult Result +} + +// TransactionWork represents a unit of work that will be executed against the provided +// transaction +type TransactionWork func(tx Transaction) (interface{}, error) + +func ensureTxState(transaction *neoTransaction) error { + if transaction.outcomeApplied { + return newDriverError("transaction is already committed or rolled back") + } + + if transaction.session.runner == nil { + return newDriverError("transaction is closed") + } + + return nil +} + +func (transaction *neoTransaction) Commit() error { + if err := ensureTxState(transaction); err != nil { + return err + } + + commit, err := transaction.session.runner.commitTransaction() + if err != nil { + return err + } + + _, err = commit.Consume() + if err != nil { + return err + } + + transaction.outcomeApplied = true + + return nil +} + +func (transaction *neoTransaction) Rollback() error { + if err := ensureTxState(transaction); err != nil { + return err + } + + rollback, err := transaction.session.runner.rollbackTransaction() + if err != nil { + return err + } + + _, err = rollback.Consume() + if err != nil { + return err + } + + transaction.outcomeApplied = true + + return nil +} + +func (transaction *neoTransaction) Close() error { + if !transaction.outcomeApplied { + if err := transaction.Rollback(); err != nil { + return err + } + } + + if err := closeRunner(transaction.session); err != nil { + return err + } + + transaction.session.tx = nil + + return nil +} + +func (transaction *neoTransaction) Run(cypher string, params map[string]interface{}) (Result, error) { + return runStatementOnTransaction(transaction, &neoStatement{text: cypher, params: params}) +} + +func runStatementOnTransaction(transaction *neoTransaction, statement *neoStatement) (Result, error) { + if err := statement.validate(); err != nil { + return nil, err + } + + if err := ensureTxState(transaction); err != nil { + return nil, err + } + + result, err := transaction.session.runner.runStatement(statement, nil, TransactionConfig{}) + if err != nil { + return nil, err + } + + return result, nil +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/utils.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/utils.go new file mode 100644 index 0000000..dfdaa6b --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/utils.go @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "reflect" +) + +func isNil(value interface{}) bool { + return value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && !reflect.ValueOf(value).IsNil()) +} + +func filter(vs []string, f func(string) bool) []string { + filtered := make([]string, 0) + for _, v := range vs { + if f(v) { + filtered = append(filtered, v) + } + } + return filtered +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/utils/test/gomock_matchers.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/utils/test/gomock_matchers.go new file mode 100644 index 0000000..3c33a14 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/utils/test/gomock_matchers.go @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package test + +import ( + "github.com/golang/mock/gomock" + "github.com/onsi/gomega" +) + +type omegaMatcherWrapper struct { + matcher gomega.OmegaMatcher +} + +func WrapMatcher(matcher gomega.OmegaMatcher) gomock.Matcher { + return &omegaMatcherWrapper{matcher: matcher} +} + +func (wrapper *omegaMatcherWrapper) Matches(actual interface{}) bool { + result, err := wrapper.matcher.Match(actual) + if err != nil { + panic(err) + } + return result +} + +func (wrapper *omegaMatcherWrapper) String() string { + return wrapper.matcher.FailureMessage(nil) +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/utils/test/omega_error_matchers.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/utils/test/omega_error_matchers.go new file mode 100644 index 0000000..403d5b5 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/utils/test/omega_error_matchers.go @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package test + +import ( + "fmt" + + "github.com/neo4j-drivers/gobolt" + "github.com/onsi/gomega" + "github.com/onsi/gomega/types" +) + +func BeGenericError(messageMatcher types.GomegaMatcher) types.GomegaMatcher { + return &genericErrorMatcher{ + messageMatcher: messageMatcher, + } +} + +func BeDatabaseError() types.GomegaMatcher { + return &databaseErrorMatcher{} +} + +func BeTransientError(codeMatcher types.GomegaMatcher, messageMatcher types.GomegaMatcher) types.GomegaMatcher { + return &databaseErrorMatcher{ + classificationMatcher: gomega.BeEquivalentTo("TransientError"), + codeMatcher: codeMatcher, + messageMatcher: messageMatcher, + } +} + +func BeClientError() types.GomegaMatcher { + return &databaseErrorMatcher{ + classificationMatcher: gomega.BeEquivalentTo("ClientError"), + } +} + +func BeArithmeticError() types.GomegaMatcher { + return &databaseErrorMatcher{ + codeMatcher: gomega.ContainSubstring("ArithmeticError"), + } +} + +func BeSyntaxError() types.GomegaMatcher { + return &databaseErrorMatcher{ + codeMatcher: gomega.ContainSubstring("SyntaxError"), + } +} + +func BeServiceUnavailableError() types.GomegaMatcher { + return &serviceUnavailableErrorMatcher{} +} + +func BeConnectorErrorWithState(state uint32) types.GomegaMatcher { + return &connectorErrorMatcher{ + stateMatcher: gomega.BeNumerically("==", state), + } +} + +func BeConnectorErrorWithCode(code uint32) types.GomegaMatcher { + return &connectorErrorMatcher{ + codeMatcher: gomega.BeNumerically("==", code), + } +} + +func BeConnectorErrorWithDescription(description string) types.GomegaMatcher { + return &connectorErrorMatcher{ + descriptionMatcher: gomega.ContainSubstring(description), + } +} + +func BeAuthenticationError() types.GomegaMatcher { + return &connectorErrorMatcher{ + stateMatcher: gomega.BeEquivalentTo(4), + codeMatcher: gomega.BeEquivalentTo(7), + } +} + +func ContainMessage(part string) types.GomegaMatcher { + return &databaseErrorMatcher{ + messageMatcher: gomega.ContainSubstring(part), + } +} + +type genericErrorMatcher struct { + messageMatcher types.GomegaMatcher +} + +type databaseErrorMatcher struct { + classificationMatcher types.GomegaMatcher + codeMatcher types.GomegaMatcher + messageMatcher types.GomegaMatcher +} + +type serviceUnavailableErrorMatcher struct { +} + +type connectorErrorMatcher struct { + stateMatcher types.GomegaMatcher + codeMatcher types.GomegaMatcher + descriptionMatcher types.GomegaMatcher +} + +func (matcher *databaseErrorMatcher) Match(actual interface{}) (success bool, err error) { + databaseError, ok := actual.(gobolt.DatabaseError) + if !ok { + return false, nil + } + + if matcher.classificationMatcher != nil { + return matcher.classificationMatcher.Match(databaseError.Classification()) + } + + if matcher.codeMatcher != nil { + return matcher.codeMatcher.Match(databaseError.Code()) + } + + if matcher.messageMatcher != nil { + return matcher.messageMatcher.Match(databaseError.Message()) + } + + return true, nil +} + +func (matcher *databaseErrorMatcher) FailureMessage(actual interface{}) (message string) { + databaseError, ok := actual.(gobolt.DatabaseError) + if !ok { + return fmt.Sprintf("Expected\n\t%#v\nto be a DatabaseError", actual) + } + + if matcher.classificationMatcher != nil { + return fmt.Sprintf("Expected\n\t%#v\nto have its classification to match %s", actual, matcher.classificationMatcher.FailureMessage(databaseError.Classification())) + } + + if matcher.codeMatcher != nil { + return fmt.Sprintf("Expected\n\t%#v\nto have its code to match %s", actual, matcher.codeMatcher.FailureMessage(databaseError.Code())) + } + + if matcher.messageMatcher != nil { + return fmt.Sprintf("Expected\n\t%#v\nto have its message to match %s", actual, matcher.classificationMatcher.FailureMessage(databaseError.Message())) + } + + return fmt.Sprintf("Unexpected condition in matcher") +} + +func (matcher *databaseErrorMatcher) NegatedFailureMessage(actual interface{}) (message string) { + databaseError, ok := actual.(gobolt.DatabaseError) + if !ok { + return fmt.Sprintf("Expected\n\t%#v\nnot to be a DatabaseError", actual) + } + + if matcher.classificationMatcher != nil { + return fmt.Sprintf("Expected\n\t%#v\nnot to have its classification to match %s", actual, matcher.classificationMatcher.FailureMessage(databaseError.Classification())) + } + + if matcher.codeMatcher != nil { + return fmt.Sprintf("Expected\n\t%#v\nnot to have its code to match %s", actual, matcher.codeMatcher.FailureMessage(databaseError.Code())) + } + + if matcher.messageMatcher != nil { + return fmt.Sprintf("Expected\n\t%#v\nnot to have its message to match %s", actual, matcher.classificationMatcher.FailureMessage(databaseError.Message())) + } + + return fmt.Sprintf("Unexpected condition in matcher") +} + +func (matcher *serviceUnavailableErrorMatcher) Match(actual interface{}) (success bool, err error) { + err, ok := actual.(error) + if !ok { + return false, nil + } + + return gobolt.IsServiceUnavailable(err), nil +} + +func (matcher *serviceUnavailableErrorMatcher) FailureMessage(actual interface{}) (message string) { + _, ok := actual.(error) + if !ok { + return fmt.Sprintf("Expected\n\t%#v\nto be an error", actual) + } + + return fmt.Sprintf("Expected\n\t%#v\nto be a ServiceUnavailableError", actual) +} + +func (matcher *serviceUnavailableErrorMatcher) NegatedFailureMessage(actual interface{}) (message string) { + _, ok := actual.(error) + if !ok { + return fmt.Sprintf("Expected\n\t%#v\nnot to be an error", actual) + } + + return fmt.Sprintf("Expected\n\t%#v\nnot to be a ServiceUnavailableError", actual) +} + +func (matcher *connectorErrorMatcher) Match(actual interface{}) (success bool, err error) { + connectorError, ok := actual.(gobolt.ConnectorError) + if !ok { + return false, nil + } + + if matcher.stateMatcher != nil { + return matcher.stateMatcher.Match(connectorError.State()) + } + + if matcher.codeMatcher != nil { + return matcher.codeMatcher.Match(connectorError.Code()) + } + + if matcher.descriptionMatcher != nil { + return matcher.descriptionMatcher.Match(connectorError.Description()) + } + + return true, nil +} + +func (matcher *connectorErrorMatcher) FailureMessage(actual interface{}) (message string) { + connectorError, ok := actual.(gobolt.ConnectorError) + if !ok { + return fmt.Sprintf("Expected\n\t%#v\nto be a ConnectorError", actual) + } + + if matcher.stateMatcher != nil { + return fmt.Sprintf("Expected\n\t%#v\nto have its state to match %s", actual, matcher.stateMatcher.FailureMessage(connectorError.State())) + } + + if matcher.codeMatcher != nil { + return fmt.Sprintf("Expected\n\t%#v\nto have its code to match %s", actual, matcher.codeMatcher.FailureMessage(connectorError.Code())) + } + + if matcher.descriptionMatcher != nil { + return fmt.Sprintf("Expected\n\t%#v\nto have its description to match %s", actual, matcher.descriptionMatcher.FailureMessage(connectorError.Description())) + } + + return fmt.Sprintf("Unexpected condition in matcher") +} + +func (matcher *connectorErrorMatcher) NegatedFailureMessage(actual interface{}) (message string) { + connectorError, ok := actual.(gobolt.ConnectorError) + if !ok { + return fmt.Sprintf("Expected\n\t%#v\nnot to be a ConnectorError", actual) + } + + if matcher.stateMatcher != nil { + return fmt.Sprintf("Expected\n\t%#v\nnot to have its state to match %s", actual, matcher.stateMatcher.FailureMessage(connectorError.State())) + } + + if matcher.codeMatcher != nil { + return fmt.Sprintf("Expected\n\t%#v\nnot to have its code to match %s", actual, matcher.codeMatcher.FailureMessage(connectorError.Code())) + } + + if matcher.descriptionMatcher != nil { + return fmt.Sprintf("Expected\n\t%#v\nnot to have its description to match %s", actual, matcher.descriptionMatcher.FailureMessage(connectorError.Description())) + } + + return fmt.Sprintf("Unexpected condition in matcher") +} + +func (matcher *genericErrorMatcher) Match(actual interface{}) (success bool, err error) { + genericError, ok := actual.(gobolt.GenericError) + if !ok { + return false, nil + } + + if matcher.messageMatcher != nil { + return matcher.messageMatcher.Match(genericError.Error()) + } + + return true, nil +} + +func (matcher *genericErrorMatcher) FailureMessage(actual interface{}) (message string) { + genericError, ok := actual.(gobolt.GenericError) + if !ok { + return fmt.Sprintf("Expected\n\t%#v\nto be a GenericError", actual) + } + + if matcher.messageMatcher != nil { + return fmt.Sprintf("Expected\n\t%#v\nto have its description to match %s", actual, matcher.messageMatcher.FailureMessage(genericError.Error())) + } + + return fmt.Sprintf("Unexpected condition in matcher") +} + +func (matcher *genericErrorMatcher) NegatedFailureMessage(actual interface{}) (message string) { + genericError, ok := actual.(gobolt.GenericError) + if ok { + return fmt.Sprintf("Expected\n\t%#v\nnot to be a GenericError", actual) + } + + if matcher.messageMatcher != nil { + return fmt.Sprintf("Expected\n\t%#v\nnot to have its description to match %s", actual, matcher.messageMatcher.NegatedFailureMessage(genericError.Error())) + } + + return fmt.Sprintf("Unexpected condition in matcher") +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/utils/test/omega_number_matchers.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/utils/test/omega_number_matchers.go new file mode 100644 index 0000000..2dd9b80 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/utils/test/omega_number_matchers.go @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package test + +import ( + "fmt" + "math" + + "github.com/onsi/gomega/types" +) + +func BeNaN() types.GomegaMatcher { + return &floatNaNMatcher{} +} + +type floatNaNMatcher struct{} + +func (matcher *floatNaNMatcher) Match(actual interface{}) (success bool, err error) { + var f32 float32 + var f64 float64 + var ok bool + + if f32, ok = actual.(float32); ok { + f64 = float64(f32) + } else if f64, ok = actual.(float64); !ok { + return false, fmt.Errorf("expected float32 or float64 values, found: %v", actual) + } + + return math.IsNaN(f64), nil +} + +func (matcher *floatNaNMatcher) FailureMessage(actual interface{}) (message string) { + return fmt.Sprintf("Expected\n\t%#v\nto be NaN", actual) +} + +func (matcher *floatNaNMatcher) NegatedFailureMessage(actual interface{}) (message string) { + return fmt.Sprintf("Expected\n\t%#v\nnot to be NaN", actual) +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_graph.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_graph.go new file mode 100644 index 0000000..9e6b43c --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_graph.go @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +// Node represents a node in the neo4j graph database +type Node interface { + // Id returns the identity of this Node. + Id() int64 + // Labels returns the labels attached to this Node. + Labels() []string + // Props returns the properties of this Node. + Props() map[string]interface{} +} + +// Relationship represents a relationship in the neo4j graph database +type Relationship interface { + // Id returns the identity of this Relationship. + Id() int64 + // StartId returns the identity of the start node of this Relationship. + StartId() int64 + // EndId returns the identity of the end node of this Relationship. + EndId() int64 + // Type returns the type of this Relationship. + Type() string + // Props returns the properties of this Relationship. + Props() map[string]interface{} +} + +type segment interface { + Start() Node + Relationship() Relationship + End() Node +} + +// Path represents a directed sequence of relationships between two nodes. +// This generally represents a traversal or walk through a graph and maintains a direction separate from that of any +// relationships traversed. It is allowed to be of size 0, meaning there are no relationships in it. In this case, +// it contains only a single node which is both the start and the end of the path. +type Path interface { + // Nodes returns all the nodes in the path. + Nodes() []Node + // Relationships returns all the relationships in the path. + Relationships() []Relationship +} + +type relationshipValue struct { + id int64 + startId int64 + endId int64 + relType string + props map[string]interface{} +} + +type nodeValue struct { + id int64 + labels []string + props map[string]interface{} +} + +type segmentValue struct { + start *nodeValue + relationship *relationshipValue + end *nodeValue +} + +type pathValue struct { + segments []segment + nodes []Node + relationships []Relationship +} + +// ID returns id of the node +func (node *nodeValue) Id() int64 { + return node.id +} + +// Labels returns labels of the node +func (node *nodeValue) Labels() []string { + return node.labels +} + +// Props returns properties of the node +func (node *nodeValue) Props() map[string]interface{} { + return node.props +} + +// ID returns id of the relationship +func (rel *relationshipValue) Id() int64 { + return rel.id +} + +// StartID returns the id of the start node +func (rel *relationshipValue) StartId() int64 { + return rel.startId +} + +// EndID returns the id of the end node +func (rel *relationshipValue) EndId() int64 { + return rel.endId +} + +// Type returns the relationship tyoe +func (rel *relationshipValue) Type() string { + return rel.relType +} + +// Props returns properties of the relationship +func (rel *relationshipValue) Props() map[string]interface{} { + return rel.props +} + +func (segment *segmentValue) Start() Node { + return segment.start +} + +func (segment *segmentValue) End() Node { + return segment.end +} + +func (segment *segmentValue) Relationship() Relationship { + return segment.relationship +} + +// Nodes returns the ordered list of nodes available on the path +func (path *pathValue) Nodes() []Node { + return path.nodes +} + +// Relationships returns the ordered list of relationships on the path +func (path *pathValue) Relationships() []Relationship { + return path.relationships +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_graph_handlers.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_graph_handlers.go new file mode 100644 index 0000000..ef8131e --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_graph_handlers.go @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "reflect" + + "github.com/neo4j-drivers/gobolt" +) + +type nodeValueHandler struct { +} + +type relationshipValueHandler struct { +} + +type pathValueHandler struct { +} + +func (handler *nodeValueHandler) ReadableStructs() []int16 { + return []int16{'N'} +} + +func (handler *nodeValueHandler) WritableTypes() []reflect.Type { + return []reflect.Type(nil) +} + +func (handler *nodeValueHandler) Read(signature int16, values []interface{}) (interface{}, error) { + if len(values) != 3 { + return nil, gobolt.NewValueHandlerError("expected node struct to have %d fields but received %d", 3, len(values)) + } + + idValue := values[0].(int64) + labelsValue := values[1].([]interface{}) + props := values[2].(map[string]interface{}) + + labelsSize := len(labelsValue) + labels := make([]string, labelsSize) + for i := 0; i < labelsSize; i++ { + labels[i] = labelsValue[i].(string) + } + + return &nodeValue{ + id: idValue, + labels: labels, + props: props, + }, nil +} + +func (handler *nodeValueHandler) Write(value interface{}) (int16, []interface{}, error) { + return 0, nil, gobolt.NewValueHandlerError("Write is not supported for node values") +} + +func (handler *relationshipValueHandler) ReadableStructs() []int16 { + return []int16{'R', 'r'} +} + +func (handler *relationshipValueHandler) WritableTypes() []reflect.Type { + return []reflect.Type(nil) +} + +func (handler *relationshipValueHandler) Read(signature int16, values []interface{}) (interface{}, error) { + if signature == 'R' { + if len(values) != 5 { + return nil, gobolt.NewValueHandlerError("expected relationship struct to have %d fields but received %d", 5, len(values)) + } + + idValue := values[0].(int64) + startIDValue := values[1].(int64) + endIDValue := values[2].(int64) + relTypeValue := values[3].(string) + propsValue := values[4].(map[string]interface{}) + + return &relationshipValue{ + id: idValue, + startId: startIDValue, + endId: endIDValue, + relType: relTypeValue, + props: propsValue, + }, nil + } + + if len(values) != 3 { + return nil, gobolt.NewValueHandlerError("expected unbound relationship struct to have %d fields but received %d", 3, len(values)) + } + + idValue := values[0].(int64) + relTypeValue := values[1].(string) + propsValue := values[2].(map[string]interface{}) + + return &relationshipValue{ + id: idValue, + startId: int64(-1), + endId: int64(-1), + relType: relTypeValue, + props: propsValue, + }, nil +} + +func (handler *relationshipValueHandler) Write(value interface{}) (int16, []interface{}, error) { + return 0, nil, gobolt.NewValueHandlerError("Write is not supported for relationship values") +} + +func (handler *pathValueHandler) ReadableStructs() []int16 { + return []int16{'P'} +} + +func (handler *pathValueHandler) WritableTypes() []reflect.Type { + return []reflect.Type(nil) +} + +func (handler *pathValueHandler) Read(signature int16, values []interface{}) (interface{}, error) { + if len(values) != 3 { + return nil, gobolt.NewValueHandlerError("expected path struct to have %d fields but received %d", 3, len(values)) + } + + uniqueNodesValue := values[0].([]interface{}) + uniqueRelsValue := values[1].([]interface{}) + segmentsValue := values[2].([]interface{}) + + uniqueNodesSize := len(uniqueNodesValue) + uniqueNodes := make([]Node, uniqueNodesSize) + for i := 0; i < uniqueNodesSize; i++ { + uniqueNodes[i] = uniqueNodesValue[i].(Node) + } + + uniqueRelsSize := len(uniqueRelsValue) + uniqueRels := make([]Relationship, uniqueRelsSize) + for i := 0; i < uniqueRelsSize; i++ { + uniqueRels[i] = uniqueRelsValue[i].(Relationship) + } + + segmentsSize := len(segmentsValue) / 2 + segments := make([]segment, segmentsSize) + nodes := make([]Node, segmentsSize+1) + rels := make([]Relationship, segmentsSize) + + prevNode := uniqueNodes[0] + nodes[0] = prevNode + for i := 0; i < segmentsSize; i++ { + relID := segmentsValue[2*i].(int64) + nextNodeIndex := segmentsValue[2*i+1].(int64) + nextNode := uniqueNodes[nextNodeIndex] + + var rel *relationshipValue + if relID < 0 { + rel = uniqueRels[(-relID)-1].(*relationshipValue) + rel.startId = prevNode.Id() + rel.endId = nextNode.Id() + } else { + rel = uniqueRels[relID-1].(*relationshipValue) + rel.startId = prevNode.Id() + rel.endId = nextNode.Id() + } + + nodes[i+1] = nextNode + rels[i] = rel + segments[i] = &segmentValue{start: prevNode.(*nodeValue), relationship: rel, end: nextNode.(*nodeValue)} + prevNode = nextNode + } + + return &pathValue{segments: segments, nodes: nodes, relationships: rels}, nil +} + +func (handler *pathValueHandler) Write(value interface{}) (int16, []interface{}, error) { + return 0, nil, gobolt.NewValueHandlerError("Write is not supported for path values") +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_spatial.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_spatial.go new file mode 100644 index 0000000..e90089a --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_spatial.go @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "fmt" + "math" +) + +// Point represents a single two or three dimensional point in a particular coordinate reference system. +type Point struct { + dimension int + srId int + x float64 + y float64 + z float64 +} + +// NewPoint2D creates a two dimensional Point with provided coordinates and coordinate reference system. +func NewPoint2D(srId int, x float64, y float64) *Point { + return &Point{ + dimension: 2, + srId: srId, + x: x, + y: y, + z: math.NaN(), + } +} + +// NewPoint3D creates a three dimensional Point with provided coordinates and coordinate reference system. +func NewPoint3D(srId int, x float64, y float64, z float64) *Point { + return &Point{ + dimension: 3, + srId: srId, + x: x, + y: y, + z: z, + } +} + +// SrId returns the Point's coordinate reference system. +func (point *Point) SrId() int { + return point.srId +} + +// X returns the Point's X coordinate. +func (point *Point) X() float64 { + return point.x +} + +// Y returns the Point's Y coordinate. +func (point *Point) Y() float64 { + return point.y +} + +// Z returns the Point's Z coordinate. +// math.NaN is returned when the Point is two dimensional. +func (point *Point) Z() float64 { + return point.z +} + +// String returns the string representation of this Point. +func (point *Point) String() string { + if point.dimension == 2 { + return fmt.Sprintf("Point{srId=%d, x=%f, y=%f}", point.srId, point.x, point.y) + } + + return fmt.Sprintf("Point{srId=%d, x=%f, y=%f, z=%f}", point.srId, point.x, point.y, point.z) +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_spatial_handlers.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_spatial_handlers.go new file mode 100644 index 0000000..c4216b9 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_spatial_handlers.go @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "math" + "reflect" + + "github.com/neo4j-drivers/gobolt" +) + +const ( + point2DSignature int16 = 'X' + point2DSize = 3 + point3DSignature int16 = 'Y' + point3DSize = 4 +) + +type pointValueHandler struct { +} + +func (handler *pointValueHandler) ReadableStructs() []int16 { + return []int16{point2DSignature, point3DSignature} +} + +func (handler *pointValueHandler) WritableTypes() []reflect.Type { + return []reflect.Type{reflect.TypeOf(Point{}), reflect.TypeOf(&Point{})} +} + +func (handler *pointValueHandler) Read(signature int16, values []interface{}) (interface{}, error) { + var ( + dimension int + srId int + x, y, z float64 + ) + + switch signature { + case point2DSignature: + if len(values) != point2DSize { + return nil, gobolt.NewValueHandlerError("expected Point2D struct to have %d fields but received %d", point2DSize, len(values)) + } + + dimension = 2 + srId = int(values[0].(int64)) + x = values[1].(float64) + y = values[2].(float64) + z = math.NaN() + case point3DSignature: + if len(values) != point3DSize { + return nil, gobolt.NewValueHandlerError("expected Point3D struct to have %d fields but received %d", point3DSize, len(values)) + } + + dimension = 3 + srId = int(values[0].(int64)) + x = values[1].(float64) + y = values[2].(float64) + z = values[3].(float64) + default: + return nil, gobolt.NewValueHandlerError("unexpected struct signature provided to PointValueHandler: %#x", signature) + } + + return &Point{ + dimension: dimension, + srId: srId, + x: x, + y: y, + z: z, + }, nil +} + +func (handler *pointValueHandler) Write(value interface{}) (int16, []interface{}, error) { + var point *Point + var ok bool + + if point, ok = value.(*Point); !ok { + if pointVal, ok := value.(Point); ok { + point = &pointVal + } + } + + if point != nil { + switch point.dimension { + case 2: + return point2DSignature, []interface{}{ + point.srId, + point.x, + point.y, + }, nil + case 3: + return point3DSignature, []interface{}{ + point.srId, + point.x, + point.y, + point.z, + }, nil + } + } + + return 0, nil, gobolt.NewValueHandlerError("passed in value %v is not supported by PointValueHandler", value) +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_spatial_test.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_spatial_test.go new file mode 100644 index 0000000..9a01801 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_spatial_test.go @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "math" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Spatial Types", func() { + + Context("Point", func() { + When("constructed with 2 coordinates", func() { + point := NewPoint2D(1, 1.0, 2.0) + + It("should have a dimension of 2", func() { + Expect(point.dimension).To(Equal(2)) + }) + + It("should report provided srId", func() { + Expect(point.SrId()).To(Equal(1)) + }) + + It("should report provided x", func() { + Expect(point.X()).To(Equal(1.0)) + }) + + It("should report provided y", func() { + Expect(point.Y()).To(Equal(2.0)) + }) + + It("should report z as NaN", func() { + Expect(math.IsNaN(point.Z())).To(BeTrue()) + }) + + It("should generate correct string", func() { + Expect(point.String()).To(Equal("Point{srId=1, x=1.000000, y=2.000000}")) + }) + }) + + When("constructed with 3 coordinates", func() { + point := NewPoint3D(1, 1.0, 2.0, 3.0) + + It("should have a dimension of 3", func() { + Expect(point.dimension).To(Equal(3)) + }) + + It("should report provided srId", func() { + Expect(point.SrId()).To(Equal(1)) + }) + + It("should report provided x", func() { + Expect(point.X()).To(Equal(1.0)) + }) + + It("should report provided y", func() { + Expect(point.Y()).To(Equal(2.0)) + }) + + It("should report provided z", func() { + Expect(point.Z()).To(Equal(3.0)) + }) + + It("should generate correct string", func() { + Expect(point.String()).To(Equal("Point{srId=1, x=1.000000, y=2.000000, z=3.000000}")) + }) + }) + }) + +}) diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_temporal.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_temporal.go new file mode 100644 index 0000000..f684e0b --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_temporal.go @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "fmt" + "time" +) + +// Date represents a date value, without a time zone and time related components. +type Date struct { + epochDays int64 +} + +// LocalTime represents a local time value. +type LocalTime struct { + nanosOfDay time.Duration +} + +// OffsetTime represents a time value with a UTC offset. +type OffsetTime struct { + nanosOfDay time.Duration + offset int +} + +// LocalDateTime represents a local date time value, without a time zone. +type LocalDateTime struct { + sec int64 + nsec int +} + +// Duration represents temporal amount containing months, days, seconds and nanoseconds. +type Duration struct { + months int64 + days int64 + seconds int64 + nanos int +} + +const ( + nanosPerDay int64 = 24 * int64(time.Hour) +) + +var ( + epochUtc = time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC) +) + +// DateOf creates a local date from the provided instant by extracting year, month and day fields. +func DateOf(of time.Time) Date { + ofUtc := time.Date(of.Year(), of.Month(), of.Day(), 0, 0, 0, 0, time.UTC) + diffHours := ofUtc.Sub(epochUtc).Hours() + epochDays := diffHours / 24 + + return Date{epochDays: int64(epochDays)} +} + +// Time converts the local date to a time instant with fields other than year, month and day set to 0. +// Returned time's location is time.UTC. +func (date Date) Time() time.Time { + return epochUtc.Add(time.Duration(date.epochDays) * time.Duration(24) * time.Hour) +} + +// Year returns the year component of this instance. +func (date Date) Year() int { + return date.Time().Year() +} + +// Month returns the month component of this instance. +func (date Date) Month() time.Month { + return date.Time().Month() +} + +// Day returns the day component of this instance. +func (date Date) Day() int { + return date.Time().Day() +} + +// String returns the string representation of this Date in ISO-8601 compliant form. +func (date Date) String() string { + return date.Time().Format("2006-01-02") +} + +// LocalTimeOf creates a local time from the provided instant by extracting hour, minute, second and nanosecond +// fields. +func LocalTimeOf(of time.Time) LocalTime { + nanosOfDay := time.Duration(of.Hour())*time.Hour + + time.Duration(of.Minute())*time.Minute + + time.Duration(of.Second())*time.Second + + time.Duration(of.Nanosecond()) + + return LocalTime{nanosOfDay} +} + +// Time converts the local time to a time instant with fields other than hour, minute, second and nanosecond +// set to 0. Returned time's location is time.Local. +func (localTime LocalTime) Time() time.Time { + return time.Date(0, 0, 0, 0, 0, 0, 0, time.Local).Add(localTime.nanosOfDay) +} + +// Hour returns the hour component of this instance. +func (localTime LocalTime) Hour() int { + return localTime.Time().Hour() +} + +// Minute returns the minute component of this instance. +func (localTime LocalTime) Minute() int { + return localTime.Time().Minute() +} + +// Second returns the second component of this instance. +func (localTime LocalTime) Second() int { + return localTime.Time().Second() +} + +// Nanosecond returns the nanosecond component of this instance. +func (localTime LocalTime) Nanosecond() int { + return localTime.Time().Nanosecond() +} + +// String returns the string representation of this LocalTime in ISO-8601 compliant form. +func (localTime LocalTime) String() string { + return localTime.Time().Format("15:04:05.999999999") +} + +// OffsetTimeOf creates an offset time from the provided instant by extracting hour, minute, second and nanosecond +// fields and it's zone offset. +func OffsetTimeOf(of time.Time) OffsetTime { + nanosOfDay := time.Duration(of.Hour())*time.Hour + + time.Duration(of.Minute())*time.Minute + + time.Duration(of.Second())*time.Second + + time.Duration(of.Nanosecond()) + _, offset := of.Zone() + + return OffsetTime{nanosOfDay, offset} +} + +// Time converts the offset time to a time instant with fields other than hour, minute, second and nanosecond +// set to 0. Returned time's location is a fixed zone with name 'Offset' and corresponding offset value. +func (offsetTime OffsetTime) Time() time.Time { + year, month, day := time.Now().Date() + return time.Date(year, month, day, 0, 0, 0, 0, time.FixedZone("Offset", offsetTime.offset)).Add(offsetTime.nanosOfDay) +} + +// Hour returns the hour component of this instance. +func (offsetTime OffsetTime) Hour() int { + return offsetTime.Time().Hour() +} + +// Minute returns the minute component of this instance. +func (offsetTime OffsetTime) Minute() int { + return offsetTime.Time().Minute() +} + +// Second returns the second component of this instance. +func (offsetTime OffsetTime) Second() int { + return offsetTime.Time().Second() +} + +// Nanosecond returns the nanosecond component of this instance. +func (offsetTime OffsetTime) Nanosecond() int { + return offsetTime.Time().Nanosecond() +} + +// Offset returns the offset of this instance in seconds. +func (offsetTime OffsetTime) Offset() int { + return offsetTime.offset +} + +// String returns the string representation of this OffsetTime in ISO-8601 compliant form. +func (offsetTime OffsetTime) String() string { + return offsetTime.Time().Format("15:04:05.999999999Z07:00") +} + +// LocalDateTimeOf creates an local date time from the provided instant by extracting its temporal fields. +func LocalDateTimeOf(of time.Time) LocalDateTime { + utc := time.Date(of.Year(), of.Month(), of.Day(), of.Hour(), of.Minute(), of.Second(), of.Nanosecond(), time.UTC) + return LocalDateTime{utc.Unix(), utc.Nanosecond()} +} + +// Time converts the local date time to a corresponding time instant. +// Returned time's location is time.UTC. +func (localDateTime LocalDateTime) Time() time.Time { + return time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC).Add(time.Second*time.Duration(localDateTime.sec) + time.Duration(localDateTime.nsec)) +} + +// Year returns the year component of this instance. +func (localDateTime LocalDateTime) Year() int { + return localDateTime.Time().Year() +} + +// Month returns the month component of this instance. +func (localDateTime LocalDateTime) Month() time.Month { + return localDateTime.Time().Month() +} + +// Day returns the day component of this instance. +func (localDateTime LocalDateTime) Day() int { + return localDateTime.Time().Day() +} + +// Hour returns the hour component of this instance. +func (localDateTime LocalDateTime) Hour() int { + return localDateTime.Time().Hour() +} + +// Minute returns the minute component of this instance. +func (localDateTime LocalDateTime) Minute() int { + return localDateTime.Time().Minute() +} + +// Second returns the second component of this instance. +func (localDateTime LocalDateTime) Second() int { + return localDateTime.Time().Second() +} + +// Nanosecond returns the nanosecond component of this instance. +func (localDateTime LocalDateTime) Nanosecond() int { + return localDateTime.Time().Nanosecond() +} + +// String returns the string representation of this LocalDateTime in ISO-8601 compliant form. +func (localDateTime LocalDateTime) String() string { + return localDateTime.Time().Format("2006-01-02T15:04:05.999999999") +} + +// DurationOf creates a Duration with provided temporal fields. +func DurationOf(months int64, days int64, seconds int64, nanos int) Duration { + return Duration{months, days, seconds, nanos} +} + +// Months returns the number of months in this duration. +func (duration Duration) Months() int64 { + return duration.months +} + +// Days returns the number of days in this duration. +func (duration Duration) Days() int64 { + return duration.days +} + +// Seconds returns the number of seconds in this duration. +func (duration Duration) Seconds() int64 { + return duration.seconds +} + +// Nanos returns the number of nanoseconds in this duration. +func (duration Duration) Nanos() int { + return duration.nanos +} + +// String returns the string representation of this Duration in ISO-8601 compliant form. +func (duration Duration) String() string { + sign := "" + if duration.seconds < 0 && duration.nanos > 0 { + duration.seconds++ + duration.nanos = int(time.Second) - duration.nanos + + if duration.seconds == 0 { + sign = "-" + } + } + + timePart := "" + if duration.nanos == 0 { + timePart = fmt.Sprintf("%s%d", sign, duration.seconds) + } else { + timePart = fmt.Sprintf("%s%d.%09d", sign, duration.seconds, duration.nanos) + } + + return fmt.Sprintf("P%dM%dDT%sS", duration.months, duration.days, timePart) +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_temporal_handlers.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_temporal_handlers.go new file mode 100644 index 0000000..ac2d37a --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_temporal_handlers.go @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "reflect" + "time" + + "github.com/neo4j-drivers/gobolt" +) + +const ( + dateSignature int16 = 'D' + dateSize = 1 + localTimeSignature int16 = 't' + localTimeSize = 1 + offsetTimeSignature int16 = 'T' + offsetTimeSize = 2 + durationSignature int16 = 'E' + durationSize = 4 + localDateTimeSignature int16 = 'd' + localDateTimeSize int = 2 + dateTimeWithOffsetSignature int16 = 'F' + dateTimeWithZoneIdSignature int16 = 'f' + dateTimeSize int = 3 +) + +type dateTimeValueHandler struct { +} + +type dateValueHandler struct { +} + +type localTimeValueHandler struct { +} + +type offsetTimeValueHandler struct { +} + +type localDateTimeValueHandler struct { +} + +type durationValueHandler struct { +} + +func (handler *dateValueHandler) ReadableStructs() []int16 { + return []int16{dateSignature} +} + +func (handler *dateValueHandler) WritableTypes() []reflect.Type { + return []reflect.Type{reflect.TypeOf(Date{})} +} + +func (handler *dateValueHandler) Read(signature int16, values []interface{}) (interface{}, error) { + switch signature { + case dateSignature: + if len(values) != dateSize { + return nil, gobolt.NewValueHandlerError("expected date struct to have %d fields but received %d", dateSize, len(values)) + } + epochDays := values[0].(int64) + return Date{epochDays}, nil + } + + return nil, gobolt.NewValueHandlerError("unexpected struct signature provided to dateTimeValueHandler: %#x", signature) +} + +func (handler *dateValueHandler) Write(value interface{}) (int16, []interface{}, error) { + var date Date + var ok bool + + if date, ok = value.(Date); !ok { + return 0, nil, gobolt.NewValueHandlerError("passed in value %v is not supported by dateValueHandler", value) + } + + return dateSignature, []interface{}{date.epochDays}, nil +} + +func (handler *localTimeValueHandler) ReadableStructs() []int16 { + return []int16{localTimeSignature} +} + +func (handler *localTimeValueHandler) WritableTypes() []reflect.Type { + return []reflect.Type{reflect.TypeOf(LocalTime{})} +} + +func (handler *localTimeValueHandler) Read(signature int16, values []interface{}) (interface{}, error) { + switch signature { + case localTimeSignature: + if len(values) != localTimeSize { + return nil, gobolt.NewValueHandlerError("expected local time struct to have %d fields but received %d", localTimeSize, len(values)) + } + nanosOfDay := values[0].(int64) + return LocalTime{time.Duration(nanosOfDay)}, nil + } + + return nil, gobolt.NewValueHandlerError("unexpected struct signature provided to localTimeValueHandler: %#x", signature) +} + +func (handler *localTimeValueHandler) Write(value interface{}) (int16, []interface{}, error) { + var localTime LocalTime + var ok bool + + if localTime, ok = value.(LocalTime); !ok { + return 0, nil, gobolt.NewValueHandlerError("passed in value %v is not supported by localTimeValueHandler", value) + } + + return localTimeSignature, []interface{}{int64(localTime.nanosOfDay)}, nil +} + +func (handler *offsetTimeValueHandler) ReadableStructs() []int16 { + return []int16{offsetTimeSignature} +} + +func (handler *offsetTimeValueHandler) WritableTypes() []reflect.Type { + return []reflect.Type{reflect.TypeOf(OffsetTime{})} +} + +func (handler *offsetTimeValueHandler) Read(signature int16, values []interface{}) (interface{}, error) { + switch signature { + case offsetTimeSignature: + if len(values) != offsetTimeSize { + return nil, gobolt.NewValueHandlerError("expected offset time struct to have %d fields but received %d", offsetTimeSize, len(values)) + } + nanosOfDay := values[0].(int64) + offset := values[1].(int64) + return OffsetTime{time.Duration(nanosOfDay), int(offset)}, nil + } + + return nil, gobolt.NewValueHandlerError("unexpected struct signature provided to offsetTimeValueHandler: %#x", signature) +} + +func (handler *offsetTimeValueHandler) Write(value interface{}) (int16, []interface{}, error) { + var offsetTime OffsetTime + var ok bool + + if offsetTime, ok = value.(OffsetTime); !ok { + return 0, nil, gobolt.NewValueHandlerError("passed in value %v is not supported by offsetTimeValueHandler", value) + } + + return offsetTimeSignature, []interface{}{int64(offsetTime.nanosOfDay), offsetTime.offset}, nil +} + +func (handler *durationValueHandler) ReadableStructs() []int16 { + return []int16{durationSignature} +} + +func (handler *durationValueHandler) WritableTypes() []reflect.Type { + return []reflect.Type{reflect.TypeOf(Duration{})} +} + +func (handler *durationValueHandler) Read(signature int16, values []interface{}) (interface{}, error) { + switch signature { + case durationSignature: + if len(values) != durationSize { + return nil, gobolt.NewValueHandlerError("expected duration struct to have %d fields but received %d", durationSize, len(values)) + } + months := values[0].(int64) + days := values[1].(int64) + seconds := values[2].(int64) + nanos := values[3].(int64) + return Duration{months, days, seconds, int(nanos)}, nil + } + + return nil, gobolt.NewValueHandlerError("unexpected struct signature provided to durationValueHandler: %#x", signature) +} + +func (handler *durationValueHandler) Write(value interface{}) (int16, []interface{}, error) { + var duration Duration + var ok bool + + if duration, ok = value.(Duration); !ok { + return 0, nil, gobolt.NewValueHandlerError("passed in value %v is not supported by durationValueHandler", value) + } + + return durationSignature, []interface{}{duration.months, duration.days, duration.seconds, duration.nanos}, nil +} + +func (handler *localDateTimeValueHandler) ReadableStructs() []int16 { + return []int16{localDateTimeSignature} +} + +func (handler *localDateTimeValueHandler) WritableTypes() []reflect.Type { + return []reflect.Type{reflect.TypeOf(LocalDateTime{})} +} + +func (handler *localDateTimeValueHandler) Read(signature int16, values []interface{}) (interface{}, error) { + switch signature { + case localDateTimeSignature: + if len(values) != localDateTimeSize { + return nil, gobolt.NewValueHandlerError("expected local date time struct to have %d fields but received %d", localDateTimeSize, len(values)) + } + + sec := values[0].(int64) + nsec := values[1].(int64) + + return LocalDateTime{sec, int(nsec)}, nil + } + + return nil, gobolt.NewValueHandlerError("unexpected struct signature provided to localDateTimeValueHandler: %#x", signature) +} + +func (handler *localDateTimeValueHandler) Write(value interface{}) (int16, []interface{}, error) { + var localDateTime LocalDateTime + var ok bool + + if localDateTime, ok = value.(LocalDateTime); !ok { + return 0, nil, gobolt.NewValueHandlerError("passed in value %v is not supported by localDateTimeValueHandler", value) + } + + return localDateTimeSignature, []interface{}{ + localDateTime.sec, + localDateTime.nsec, + }, nil +} + +func (handler *dateTimeValueHandler) ReadableStructs() []int16 { + return []int16{dateTimeWithOffsetSignature, dateTimeWithZoneIdSignature} +} + +func (handler *dateTimeValueHandler) WritableTypes() []reflect.Type { + return []reflect.Type{reflect.TypeOf(time.Time{})} +} + +func (handler *dateTimeValueHandler) Read(signature int16, values []interface{}) (interface{}, error) { + switch signature { + case dateTimeWithZoneIdSignature: + if len(values) != dateTimeSize { + return nil, gobolt.NewValueHandlerError("expected date time with zone id struct to have %d fields but received %d", dateTimeSize, len(values)) + } + + sec := values[0].(int64) + nsec := values[1].(int64) + zone := values[2].(string) + location, err := time.LoadLocation(zone) + if err != nil { + return nil, gobolt.NewValueHandlerError("Unable to load time zone '%s'", zone) + } + + utcTime := epochUtc.Add(time.Duration(sec)*time.Second + time.Duration(nsec)) + + return time.Date(utcTime.Year(), utcTime.Month(), utcTime.Day(), utcTime.Hour(), utcTime.Minute(), utcTime.Second(), utcTime.Nanosecond(), location), nil + case dateTimeWithOffsetSignature: + if len(values) != dateTimeSize { + return nil, gobolt.NewValueHandlerError("expected date time with offset struct to have %d fields but received %d", dateTimeSize, len(values)) + } + + sec := values[0].(int64) + nsec := values[1].(int64) + offsec := values[2].(int64) + location := time.FixedZone("Offset", int(offsec)) + + utcTime := epochUtc.Add(time.Duration(sec)*time.Second + time.Duration(nsec)) + + return time.Date(utcTime.Year(), utcTime.Month(), utcTime.Day(), utcTime.Hour(), utcTime.Minute(), utcTime.Second(), utcTime.Nanosecond(), location), nil + } + + return nil, gobolt.NewValueHandlerError("unexpected struct signature provided to dateTimeValueHandler: %#x", signature) +} + +func (handler *dateTimeValueHandler) Write(value interface{}) (int16, []interface{}, error) { + var dateTime time.Time + var ok bool + + if dateTime, ok = value.(time.Time); !ok { + return 0, nil, gobolt.NewValueHandlerError("passed in value %v is not supported by dateTimeValueHandler", value) + } + + location := dateTime.Location() + zoneId, offset := dateTime.Zone() + utcTime := time.Date(dateTime.Year(), dateTime.Month(), dateTime.Day(), dateTime.Hour(), dateTime.Minute(), dateTime.Second(), dateTime.Nanosecond(), time.UTC) + sec := utcTime.Unix() + nsec := utcTime.Nanosecond() + + if zoneId == "Offset" { + // with offset seconds + return dateTimeWithOffsetSignature, []interface{}{ + sec, + nsec, + offset, + }, nil + } + + // with zone id + return dateTimeWithZoneIdSignature, []interface{}{ + sec, + nsec, + location.String(), + }, nil + +} diff --git a/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_temporal_test.go b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_temporal_test.go new file mode 100644 index 0000000..989ad21 --- /dev/null +++ b/vendor/github.com/neo4j/neo4j-go-driver/neo4j/values_temporal_test.go @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2002-2019 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package neo4j + +import ( + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/extensions/table" + . "github.com/onsi/gomega" +) + +var _ = Describe("Temporal Types", func() { + Context("LocalDate", func() { + When("initialized from a Time value", func() { + source := time.Date(2006, time.December, 16, 13, 59, 59, 999999999, time.Local) + value := DateOf(source) + + It("should report year as 2006", func() { + Expect(value.Year()).To(Equal(2006)) + }) + + It("should report month as December", func() { + Expect(value.Month()).To(Equal(time.December)) + }) + + It("should report day as 16", func() { + Expect(value.Day()).To(Equal(16)) + }) + + It("should return an equivalent Time value when converted", func() { + year, month, day := value.Time().Date() + + Expect(year).To(Equal(source.Year())) + Expect(month).To(Equal(source.Month())) + Expect(day).To(Equal(source.Day())) + }) + + It("should generate correct string", func() { + Expect(value.String()).To(Equal("2006-12-16")) + }) + }) + }) + + Context("LocalTime", func() { + When("initialized from a Time value", func() { + source := time.Date(0, 0, 0, 13, 59, 59, 999999999, time.Local) + value := LocalTimeOf(source) + + It("should report hour as 13", func() { + Expect(value.Hour()).To(Equal(13)) + }) + + It("should report minute as 59", func() { + Expect(value.Minute()).To(Equal(59)) + }) + + It("should report second as 59", func() { + Expect(value.Second()).To(Equal(59)) + }) + + It("should report nanosecond as 999999999", func() { + Expect(value.Nanosecond()).To(Equal(999999999)) + }) + + It("should return an equivalent Time value when converted", func() { + converted := value.Time() + + Expect(converted.Hour()).To(Equal(source.Hour())) + Expect(converted.Minute()).To(Equal(source.Minute())) + Expect(converted.Second()).To(Equal(source.Second())) + Expect(converted.Nanosecond()).To(Equal(source.Nanosecond())) + }) + + It("should generate correct string", func() { + Expect(value.String()).To(Equal("13:59:59.999999999")) + }) + }) + }) + + Context("OffsetTime", func() { + When("initialized from a Time value", func() { + year, month, day := time.Now().Date() + location, _ := time.LoadLocation("Europe/Istanbul") + source := time.Date(year, month, day, 13, 59, 59, 999999999, location) + value := OffsetTimeOf(source) + + It("should report hour as 13", func() { + Expect(value.Hour()).To(Equal(13)) + }) + + It("should report minute as 59", func() { + Expect(value.Minute()).To(Equal(59)) + }) + + It("should report second as 59", func() { + Expect(value.Second()).To(Equal(59)) + }) + + It("should report nanosecond as 999999999", func() { + Expect(value.Nanosecond()).To(Equal(999999999)) + }) + + It("should report offset as 3*60*60 (3 hours)", func() { + Expect(value.Offset()).To(Equal(10800)) + }) + + It("should return an equivalent Time value when converted", func() { + converted := value.Time() + + Expect(converted.Hour()).To(Equal(source.Hour())) + Expect(converted.Minute()).To(Equal(source.Minute())) + Expect(converted.Second()).To(Equal(source.Second())) + Expect(converted.Nanosecond()).To(Equal(source.Nanosecond())) + + _, convertedOffset := converted.Zone() + _, offset := source.Zone() + Expect(convertedOffset).To(Equal(offset)) + }) + + It("should generate correct string", func() { + Expect(value.String()).To(Equal("13:59:59.999999999+03:00")) + }) + }) + }) + + Context("LocalDateTime", func() { + When("initialized from a Time value with local time zone", func() { + source := time.Date(1947, 12, 17, 23, 49, 54, 999999999, time.Local) + value := LocalDateTimeOf(source) + + It("should report year as 2006", func() { + Expect(value.Year()).To(Equal(1947)) + }) + + It("should report month as December", func() { + Expect(value.Month()).To(Equal(time.December)) + }) + + It("should report day as 17", func() { + Expect(value.Day()).To(Equal(17)) + }) + + It("should report hour as 23", func() { + Expect(value.Hour()).To(Equal(23)) + }) + + It("should report minute as 49", func() { + Expect(value.Minute()).To(Equal(49)) + }) + + It("should report second as 54", func() { + Expect(value.Second()).To(Equal(54)) + }) + + It("should report nanosecond as 999999999", func() { + Expect(value.Nanosecond()).To(Equal(999999999)) + }) + + It("should return an equivalent Time value when converted", func() { + converted := value.Time() + + Expect(converted.Year()).To(Equal(source.Year())) + Expect(converted.Month()).To(Equal(source.Month())) + Expect(converted.Day()).To(Equal(source.Day())) + Expect(converted.Hour()).To(Equal(source.Hour())) + Expect(converted.Minute()).To(Equal(source.Minute())) + Expect(converted.Second()).To(Equal(source.Second())) + Expect(converted.Nanosecond()).To(Equal(source.Nanosecond())) + }) + + It("should generate correct string", func() { + Expect(value.String()).To(Equal("1947-12-17T23:49:54.999999999")) + }) + }) + + When("initialized from a Time value with UTC time zone", func() { + source := time.Date(1947, 12, 17, 23, 49, 54, 999999999, time.UTC) + value := LocalDateTimeOf(source) + + It("should report year as 2006", func() { + Expect(value.Year()).To(Equal(1947)) + }) + + It("should report month as December", func() { + Expect(value.Month()).To(Equal(time.December)) + }) + + It("should report day as 17", func() { + Expect(value.Day()).To(Equal(17)) + }) + + It("should report hour as 23", func() { + Expect(value.Hour()).To(Equal(23)) + }) + + It("should report minute as 49", func() { + Expect(value.Minute()).To(Equal(49)) + }) + + It("should report second as 54", func() { + Expect(value.Second()).To(Equal(54)) + }) + + It("should report nanosecond as 999999999", func() { + Expect(value.Nanosecond()).To(Equal(999999999)) + }) + + It("should return an equivalent Time value when converted", func() { + converted := value.Time() + + Expect(converted.Year()).To(Equal(source.Year())) + Expect(converted.Month()).To(Equal(source.Month())) + Expect(converted.Day()).To(Equal(source.Day())) + Expect(converted.Hour()).To(Equal(source.Hour())) + Expect(converted.Minute()).To(Equal(source.Minute())) + Expect(converted.Second()).To(Equal(source.Second())) + Expect(converted.Nanosecond()).To(Equal(source.Nanosecond())) + }) + + It("should generate correct string", func() { + Expect(value.String()).To(Equal("1947-12-17T23:49:54.999999999")) + }) + }) + + When("initialized from a Time value with a custom time zone", func() { + location, _ := time.LoadLocation("Europe/Istanbul") + source := time.Date(1947, 12, 17, 23, 49, 54, 999999999, location) + value := LocalDateTimeOf(source) + + It("should report year as 2006", func() { + Expect(value.Year()).To(Equal(1947)) + }) + + It("should report month as December", func() { + Expect(value.Month()).To(Equal(time.December)) + }) + + It("should report day as 17", func() { + Expect(value.Day()).To(Equal(17)) + }) + + It("should report hour as 23", func() { + Expect(value.Hour()).To(Equal(23)) + }) + + It("should report minute as 49", func() { + Expect(value.Minute()).To(Equal(49)) + }) + + It("should report second as 54", func() { + Expect(value.Second()).To(Equal(54)) + }) + + It("should report nanosecond as 999999999", func() { + Expect(value.Nanosecond()).To(Equal(999999999)) + }) + + It("should return an equivalent Time value when converted", func() { + converted := value.Time() + + Expect(converted.Year()).To(Equal(source.Year())) + Expect(converted.Month()).To(Equal(source.Month())) + Expect(converted.Day()).To(Equal(source.Day())) + Expect(converted.Hour()).To(Equal(source.Hour())) + Expect(converted.Minute()).To(Equal(source.Minute())) + Expect(converted.Second()).To(Equal(source.Second())) + Expect(converted.Nanosecond()).To(Equal(source.Nanosecond())) + }) + + It("should generate correct string", func() { + Expect(value.String()).To(Equal("1947-12-17T23:49:54.999999999")) + }) + }) + }) + + Context("Duration", func() { + When("constructed", func() { + value := DurationOf(15, 32, 785, 789215800) + + It("should report months as 15", func() { + Expect(value.Months()).To(BeNumerically("==", 15)) + }) + + It("should report days as 32", func() { + Expect(value.Days()).To(BeNumerically("==", 32)) + }) + + It("should report second as 785", func() { + Expect(value.Seconds()).To(BeNumerically("==", 785)) + }) + + It("should report nanosecond as 789215800", func() { + Expect(value.Nanos()).To(BeNumerically("==", 789215800)) + }) + + It("should generate correct string", func() { + Expect(value.String()).To(Equal("P15M32DT785.789215800S")) + }) + }) + + DescribeTable("should generate correct string", func(months, days, seconds, nanoseconds int, expected string) { + duration := DurationOf(int64(months), int64(days), int64(seconds), nanoseconds) + + Expect(duration.String()).To(Equal(expected)) + }, + Entry("P15M32DT785.789215800S", 15, 32, 785, 789215800, "P15M32DT785.789215800S"), + Entry("P0M32DT785.789215800S", 0, 32, 785, 789215800, "P0M32DT785.789215800S"), + Entry("P0M0DT785.789215800S", 0, 0, 785, 789215800, "P0M0DT785.789215800S"), + Entry("P0M0DT0.789215800S", 0, 0, 0, 789215800, "P0M0DT0.789215800S"), + Entry("P0M0DT-1S", 0, 0, -1, 0, "P0M0DT-1S"), + Entry("P0M0DT0.999999999S", 0, 0, 0, 999999999, "P0M0DT0.999999999S"), + Entry("P0M0DT-0.999999995S", 0, 0, -1, 5, "P0M0DT-0.999999995S"), + Entry("P0M0DT-0.000000001S", 0, 0, -1, 999999999, "P0M0DT-0.000000001S"), + Entry("P500M0DT0S", 500, 0, 0, 0, "P500M0DT0S"), + Entry("P0M0DT0.000000005S", 0, 0, 0, 5, "P0M0DT0.000000005S"), + Entry("P0M0DT-499.999999999S", 0, 0, -500, 1, "P0M0DT-499.999999999S"), + Entry("P0M0DT-500S", 0, 0, -500, 0, "P0M0DT-500S"), + Entry("P-10M5DT-1.999999500S", -10, 5, -2, 500, "P-10M5DT-1.999999500S"), + Entry("P-10M-5DT-1.999999500S", -10, -5, -2, 500, "P-10M-5DT-1.999999500S")) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/extensions/table/table.go b/vendor/github.com/onsi/ginkgo/extensions/table/table.go new file mode 100644 index 0000000..ae8ab7d --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/extensions/table/table.go @@ -0,0 +1,98 @@ +/* + +Table provides a simple DSL for Ginkgo-native Table-Driven Tests + +The godoc documentation describes Table's API. More comprehensive documentation (with examples!) is available at http://onsi.github.io/ginkgo#table-driven-tests + +*/ + +package table + +import ( + "fmt" + "reflect" + + "github.com/onsi/ginkgo" +) + +/* +DescribeTable describes a table-driven test. + +For example: + + DescribeTable("a simple table", + func(x int, y int, expected bool) { + Ω(x > y).Should(Equal(expected)) + }, + Entry("x > y", 1, 0, true), + Entry("x == y", 0, 0, false), + Entry("x < y", 0, 1, false), + ) + +The first argument to `DescribeTable` is a string description. +The second argument is a function that will be run for each table entry. Your assertions go here - the function is equivalent to a Ginkgo It. +The subsequent arguments must be of type `TableEntry`. We recommend using the `Entry` convenience constructors. + +The `Entry` constructor takes a string description followed by an arbitrary set of parameters. These parameters are passed into your function. + +Under the hood, `DescribeTable` simply generates a new Ginkgo `Describe`. Each `Entry` is turned into an `It` within the `Describe`. + +It's important to understand that the `Describe`s and `It`s are generated at evaluation time (i.e. when Ginkgo constructs the tree of tests and before the tests run). + +Individual Entries can be focused (with FEntry) or marked pending (with PEntry or XEntry). In addition, the entire table can be focused or marked pending with FDescribeTable and PDescribeTable/XDescribeTable. +*/ +func DescribeTable(description string, itBody interface{}, entries ...TableEntry) bool { + describeTable(description, itBody, entries, false, false) + return true +} + +/* +You can focus a table with `FDescribeTable`. This is equivalent to `FDescribe`. +*/ +func FDescribeTable(description string, itBody interface{}, entries ...TableEntry) bool { + describeTable(description, itBody, entries, false, true) + return true +} + +/* +You can mark a table as pending with `PDescribeTable`. This is equivalent to `PDescribe`. +*/ +func PDescribeTable(description string, itBody interface{}, entries ...TableEntry) bool { + describeTable(description, itBody, entries, true, false) + return true +} + +/* +You can mark a table as pending with `XDescribeTable`. This is equivalent to `XDescribe`. +*/ +func XDescribeTable(description string, itBody interface{}, entries ...TableEntry) bool { + describeTable(description, itBody, entries, true, false) + return true +} + +func describeTable(description string, itBody interface{}, entries []TableEntry, pending bool, focused bool) { + itBodyValue := reflect.ValueOf(itBody) + if itBodyValue.Kind() != reflect.Func { + panic(fmt.Sprintf("DescribeTable expects a function, got %#v", itBody)) + } + + if pending { + ginkgo.PDescribe(description, func() { + for _, entry := range entries { + entry.generateIt(itBodyValue) + } + }) + } else if focused { + ginkgo.FDescribe(description, func() { + for _, entry := range entries { + entry.generateIt(itBodyValue) + } + }) + } else { + ginkgo.Describe(description, func() { + for _, entry := range entries { + entry.generateIt(itBodyValue) + } + }) + } +} diff --git a/vendor/github.com/onsi/ginkgo/extensions/table/table_entry.go b/vendor/github.com/onsi/ginkgo/extensions/table/table_entry.go new file mode 100644 index 0000000..5fa645b --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/extensions/table/table_entry.go @@ -0,0 +1,81 @@ +package table + +import ( + "reflect" + + "github.com/onsi/ginkgo" +) + +/* +TableEntry represents an entry in a table test. You generally use the `Entry` constructor. +*/ +type TableEntry struct { + Description string + Parameters []interface{} + Pending bool + Focused bool +} + +func (t TableEntry) generateIt(itBody reflect.Value) { + if t.Pending { + ginkgo.PIt(t.Description) + return + } + + values := []reflect.Value{} + for i, param := range t.Parameters { + var value reflect.Value + + if param == nil { + inType := itBody.Type().In(i) + value = reflect.Zero(inType) + } else { + value = reflect.ValueOf(param) + } + + values = append(values, value) + } + + body := func() { + itBody.Call(values) + } + + if t.Focused { + ginkgo.FIt(t.Description, body) + } else { + ginkgo.It(t.Description, body) + } +} + +/* +Entry constructs a TableEntry. + +The first argument is a required description (this becomes the content of the generated Ginkgo `It`). +Subsequent parameters are saved off and sent to the callback passed in to `DescribeTable`. + +Each Entry ends up generating an individual Ginkgo It. +*/ +func Entry(description string, parameters ...interface{}) TableEntry { + return TableEntry{description, parameters, false, false} +} + +/* +You can focus a particular entry with FEntry. This is equivalent to FIt. +*/ +func FEntry(description string, parameters ...interface{}) TableEntry { + return TableEntry{description, parameters, false, true} +} + +/* +You can mark a particular entry as pending with PEntry. This is equivalent to PIt. +*/ +func PEntry(description string, parameters ...interface{}) TableEntry { + return TableEntry{description, parameters, true, false} +} + +/* +You can mark a particular entry as pending with XEntry. This is equivalent to XIt. +*/ +func XEntry(description string, parameters ...interface{}) TableEntry { + return TableEntry{description, parameters, true, false} +} diff --git a/vendor/github.com/onsi/ginkgo/extensions/table/table_suite_test.go b/vendor/github.com/onsi/ginkgo/extensions/table/table_suite_test.go new file mode 100644 index 0000000..f482ec3 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/extensions/table/table_suite_test.go @@ -0,0 +1,13 @@ +package table_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestTable(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Table Suite") +} diff --git a/vendor/github.com/onsi/ginkgo/extensions/table/table_test.go b/vendor/github.com/onsi/ginkgo/extensions/table/table_test.go new file mode 100644 index 0000000..b008e43 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/extensions/table/table_test.go @@ -0,0 +1,64 @@ +package table_test + +import ( + "strings" + + . "github.com/onsi/ginkgo/extensions/table" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Table", func() { + DescribeTable("a simple table", + func(x int, y int, expected bool) { + Ω(x > y).Should(Equal(expected)) + }, + Entry("x > y", 1, 0, true), + Entry("x == y", 0, 0, false), + Entry("x < y", 0, 1, false), + ) + + type ComplicatedThings struct { + Superstructure string + Substructure string + Count int + } + + DescribeTable("a more complicated table", + func(c ComplicatedThings) { + Ω(strings.Count(c.Superstructure, c.Substructure)).Should(BeNumerically("==", c.Count)) + }, + Entry("with no matching substructures", ComplicatedThings{ + Superstructure: "the sixth sheikh's sixth sheep's sick", + Substructure: "emir", + Count: 0, + }), + Entry("with one matching substructure", ComplicatedThings{ + Superstructure: "the sixth sheikh's sixth sheep's sick", + Substructure: "sheep", + Count: 1, + }), + Entry("with many matching substructures", ComplicatedThings{ + Superstructure: "the sixth sheikh's sixth sheep's sick", + Substructure: "si", + Count: 3, + }), + ) + + PDescribeTable("a failure", + func(value bool) { + Ω(value).Should(BeFalse()) + }, + Entry("when true", true), + Entry("when false", false), + Entry("when malformed", 2), + ) + + DescribeTable("an untyped nil as an entry", + func(x interface{}) { + Expect(x).To(BeNil()) + }, + Entry("nil", nil), + ) +}) diff --git a/vendor/github.com/stretchr/objx/LICENSE b/vendor/github.com/stretchr/objx/LICENSE new file mode 100644 index 0000000..44d4d9d --- /dev/null +++ b/vendor/github.com/stretchr/objx/LICENSE @@ -0,0 +1,22 @@ +The MIT License + +Copyright (c) 2014 Stretchr, Inc. +Copyright (c) 2017-2018 objx contributors + +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/stretchr/objx/README.md b/vendor/github.com/stretchr/objx/README.md new file mode 100644 index 0000000..246660b --- /dev/null +++ b/vendor/github.com/stretchr/objx/README.md @@ -0,0 +1,80 @@ +# Objx +[![Build Status](https://travis-ci.org/stretchr/objx.svg?branch=master)](https://travis-ci.org/stretchr/objx) +[![Go Report Card](https://goreportcard.com/badge/github.com/stretchr/objx)](https://goreportcard.com/report/github.com/stretchr/objx) +[![Maintainability](https://api.codeclimate.com/v1/badges/1d64bc6c8474c2074f2b/maintainability)](https://codeclimate.com/github/stretchr/objx/maintainability) +[![Test Coverage](https://api.codeclimate.com/v1/badges/1d64bc6c8474c2074f2b/test_coverage)](https://codeclimate.com/github/stretchr/objx/test_coverage) +[![Sourcegraph](https://sourcegraph.com/github.com/stretchr/objx/-/badge.svg)](https://sourcegraph.com/github.com/stretchr/objx) +[![GoDoc](https://godoc.org/github.com/stretchr/objx?status.svg)](https://godoc.org/github.com/stretchr/objx) + +Objx - Go package for dealing with maps, slices, JSON and other data. + +Get started: + +- Install Objx with [one line of code](#installation), or [update it with another](#staying-up-to-date) +- Check out the API Documentation http://godoc.org/github.com/stretchr/objx + +## Overview +Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes a powerful `Get` method (among others) that allows you to easily and quickly get access to data within the map, without having to worry too much about type assertions, missing data, default values etc. + +### Pattern +Objx uses a preditable pattern to make access data from within `map[string]interface{}` easy. Call one of the `objx.` functions to create your `objx.Map` to get going: + + m, err := objx.FromJSON(json) + +NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong, the rest will be optimistic and try to figure things out without panicking. + +Use `Get` to access the value you're interested in. You can use dot and array +notation too: + + m.Get("places[0].latlng") + +Once you have sought the `Value` you're interested in, you can use the `Is*` methods to determine its type. + + if m.Get("code").IsStr() { // Your code... } + +Or you can just assume the type, and use one of the strong type methods to extract the real value: + + m.Get("code").Int() + +If there's no value there (or if it's the wrong type) then a default value will be returned, or you can be explicit about the default value. + + Get("code").Int(-1) + +If you're dealing with a slice of data as a value, Objx provides many useful methods for iterating, manipulating and selecting that data. You can find out more by exploring the index below. + +### Reading data +A simple example of how to use Objx: + + // Use MustFromJSON to make an objx.Map from some JSON + m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`) + + // Get the details + name := m.Get("name").Str() + age := m.Get("age").Int() + + // Get their nickname (or use their name if they don't have one) + nickname := m.Get("nickname").Str(name) + +### Ranging +Since `objx.Map` is a `map[string]interface{}` you can treat it as such. For example, to `range` the data, do what you would expect: + + m := objx.MustFromJSON(json) + for key, value := range m { + // Your code... + } + +## Installation +To install Objx, use go get: + + go get github.com/stretchr/objx + +### Staying up to date +To update Objx to the latest version, run: + + go get -u github.com/stretchr/objx + +### Supported go versions +We support the lastest three major Go versions, which are 1.10, 1.11 and 1.12 at the moment. + +## Contributing +Please feel free to submit issues, fork the repository and send pull requests! diff --git a/vendor/github.com/stretchr/objx/Taskfile.yml b/vendor/github.com/stretchr/objx/Taskfile.yml new file mode 100644 index 0000000..a749ac5 --- /dev/null +++ b/vendor/github.com/stretchr/objx/Taskfile.yml @@ -0,0 +1,30 @@ +version: '2' + +env: + GOFLAGS: -mod=vendor + +tasks: + default: + deps: [test] + + lint: + desc: Checks code style + cmds: + - gofmt -d -s *.go + - go vet ./... + silent: true + + lint-fix: + desc: Fixes code style + cmds: + - gofmt -w -s *.go + + test: + desc: Runs go tests + cmds: + - go test -race ./... + + test-coverage: + desc: Runs go tests and calucates test coverage + cmds: + - go test -race -coverprofile=c.out ./... diff --git a/vendor/github.com/stretchr/objx/accessors.go b/vendor/github.com/stretchr/objx/accessors.go new file mode 100644 index 0000000..80ad167 --- /dev/null +++ b/vendor/github.com/stretchr/objx/accessors.go @@ -0,0 +1,179 @@ +package objx + +import ( + "reflect" + "regexp" + "strconv" + "strings" +) + +const ( + // PathSeparator is the character used to separate the elements + // of the keypath. + // + // For example, `location.address.city` + PathSeparator string = "." + + // arrayAccesRegexString is the regex used to extract the array number + // from the access path + arrayAccesRegexString = `^(.+)\[([0-9]+)\]$` + + // mapAccessRegexString is the regex used to extract the map key + // from the access path + mapAccessRegexString = `^([^\[]*)\[([^\]]+)\](.*)$` +) + +// arrayAccesRegex is the compiled arrayAccesRegexString +var arrayAccesRegex = regexp.MustCompile(arrayAccesRegexString) + +// mapAccessRegex is the compiled mapAccessRegexString +var mapAccessRegex = regexp.MustCompile(mapAccessRegexString) + +// Get gets the value using the specified selector and +// returns it inside a new Obj object. +// +// If it cannot find the value, Get will return a nil +// value inside an instance of Obj. +// +// Get can only operate directly on map[string]interface{} and []interface. +// +// Example +// +// To access the title of the third chapter of the second book, do: +// +// o.Get("books[1].chapters[2].title") +func (m Map) Get(selector string) *Value { + rawObj := access(m, selector, nil, false) + return &Value{data: rawObj} +} + +// Set sets the value using the specified selector and +// returns the object on which Set was called. +// +// Set can only operate directly on map[string]interface{} and []interface +// +// Example +// +// To set the title of the third chapter of the second book, do: +// +// o.Set("books[1].chapters[2].title","Time to Go") +func (m Map) Set(selector string, value interface{}) Map { + access(m, selector, value, true) + return m +} + +// getIndex returns the index, which is hold in s by two braches. +// It also returns s withour the index part, e.g. name[1] will return (1, name). +// If no index is found, -1 is returned +func getIndex(s string) (int, string) { + arrayMatches := arrayAccesRegex.FindStringSubmatch(s) + if len(arrayMatches) > 0 { + // Get the key into the map + selector := arrayMatches[1] + // Get the index into the array at the key + // We know this cannt fail because arrayMatches[2] is an int for sure + index, _ := strconv.Atoi(arrayMatches[2]) + return index, selector + } + return -1, s +} + +// getKey returns the key which is held in s by two brackets. +// It also returns the next selector. +func getKey(s string) (string, string) { + selSegs := strings.SplitN(s, PathSeparator, 2) + thisSel := selSegs[0] + nextSel := "" + + if len(selSegs) > 1 { + nextSel = selSegs[1] + } + + mapMatches := mapAccessRegex.FindStringSubmatch(s) + if len(mapMatches) > 0 { + if _, err := strconv.Atoi(mapMatches[2]); err != nil { + thisSel = mapMatches[1] + nextSel = "[" + mapMatches[2] + "]" + mapMatches[3] + + if thisSel == "" { + thisSel = mapMatches[2] + nextSel = mapMatches[3] + } + + if nextSel == "" { + selSegs = []string{"", ""} + } else if nextSel[0] == '.' { + nextSel = nextSel[1:] + } + } + } + + return thisSel, nextSel +} + +// access accesses the object using the selector and performs the +// appropriate action. +func access(current interface{}, selector string, value interface{}, isSet bool) interface{} { + thisSel, nextSel := getKey(selector) + + index := -1 + if strings.Contains(thisSel, "[") { + index, thisSel = getIndex(thisSel) + } + + if curMap, ok := current.(Map); ok { + current = map[string]interface{}(curMap) + } + // get the object in question + switch current.(type) { + case map[string]interface{}: + curMSI := current.(map[string]interface{}) + if nextSel == "" && isSet { + curMSI[thisSel] = value + return nil + } + + _, ok := curMSI[thisSel].(map[string]interface{}) + if (curMSI[thisSel] == nil || !ok) && index == -1 && isSet { + curMSI[thisSel] = map[string]interface{}{} + } + + current = curMSI[thisSel] + default: + current = nil + } + + // do we need to access the item of an array? + if index > -1 { + if array, ok := interSlice(current); ok { + if index < len(array) { + current = array[index] + } else { + current = nil + } + } + } + if nextSel != "" { + current = access(current, nextSel, value, isSet) + } + return current +} + +func interSlice(slice interface{}) ([]interface{}, bool) { + if array, ok := slice.([]interface{}); ok { + return array, ok + } + + s := reflect.ValueOf(slice) + if s.Kind() != reflect.Slice { + return nil, false + } + + ret := make([]interface{}, s.Len()) + + for i := 0; i < s.Len(); i++ { + ret[i] = s.Index(i).Interface() + } + + return ret, true +} diff --git a/vendor/github.com/stretchr/objx/accessors_test.go b/vendor/github.com/stretchr/objx/accessors_test.go new file mode 100644 index 0000000..a3ee410 --- /dev/null +++ b/vendor/github.com/stretchr/objx/accessors_test.go @@ -0,0 +1,220 @@ +package objx_test + +import ( + "testing" + + "github.com/stretchr/objx" + "github.com/stretchr/testify/assert" +) + +func TestAccessorsAccessGetSingleField(t *testing.T) { + m := objx.Map{"name": "Tyler"} + + assert.Equal(t, "Tyler", m.Get("name").Data()) +} + +func TestAccessorsAccessGetSingleFieldInt(t *testing.T) { + m := objx.Map{"name": 10} + + assert.Equal(t, 10, m.Get("name").Data()) +} + +func TestAccessorsAccessGetDeep(t *testing.T) { + m := objx.Map{ + "name": objx.Map{ + "first": "Tyler", + "last": "Bunnell", + "friends": []string{ + "Capitol", + "Bollocks", + }, + "ifriends": []interface{}{ + "Capitol", + "Bollocks", + }, + }, + } + + assert.Equal(t, "Tyler", m.Get("name.first").Data()) + assert.Equal(t, "Bunnell", m.Get("name.last").Data()) + assert.Equal(t, "Capitol", m.Get("name.friends[0]").Data()) + assert.Equal(t, "Capitol", m.Get("name.ifriends[0]").Data()) +} + +func TestAccessorsAccessGetDeepDeep(t *testing.T) { + m := objx.Map{ + "one": objx.Map{ + "two": objx.Map{ + "three": objx.Map{ + "four": 4, + }, + }, + }, + } + + assert.Equal(t, 4, m.Get("one.two.three.four").Data()) + assert.Equal(t, 4, m.Get("one[two][three][four]").Data()) +} + +func TestAccessorsGetWithComplexKey(t *testing.T) { + m := objx.Map{ + "domains": objx.Map{ + "example-dot-com": objx.Map{ + "apex": "example", + }, + "example.com": objx.Map{ + "apex": "example", + }, + }, + } + + assert.Equal(t, "example", m.Get("domains.example-dot-com.apex").Data()) + + assert.Equal(t, "example", m.Get("domains[example.com].apex").Data()) + assert.Equal(t, "example", m.Get("domains[example.com][apex]").Data()) +} + +func TestAccessorsAccessGetInsideArray(t *testing.T) { + m := objx.Map{ + "names": []interface{}{ + objx.Map{ + "first": "Tyler", + "last": "Bunnell", + }, + objx.Map{ + "first": "Capitol", + "last": "Bollocks", + }, + }, + } + + assert.Equal(t, "Tyler", m.Get("names[0].first").Data()) + assert.Equal(t, "Bunnell", m.Get("names[0].last").Data()) + assert.Equal(t, "Capitol", m.Get("names[1].first").Data()) + assert.Equal(t, "Bollocks", m.Get("names[1].last").Data()) + + assert.Nil(t, m.Get("names[2]").Data()) + assert.Nil(t, m.Get("names[]").Data()) + assert.Nil(t, m.Get("names1]]").Data()) + assert.Nil(t, m.Get("names[1]]").Data()) + assert.Nil(t, m.Get("names[[1]]").Data()) + assert.Nil(t, m.Get("names[[1]").Data()) + assert.Nil(t, m.Get("names[[1").Data()) +} + +func TestAccessorsGet(t *testing.T) { + m := objx.Map{"name": "Tyler"} + + assert.Equal(t, "Tyler", m.Get("name").Data()) +} + +func TestAccessorsAccessSetSingleField(t *testing.T) { + m := objx.Map{"name": "Tyler"} + + m.Set("name", "Mat") + m.Set("age", 29) + + assert.Equal(t, m.Get("name").Data(), "Mat") + assert.Equal(t, m.Get("age").Data(), 29) +} + +func TestAccessorsAccessSetSingleFieldNotExisting(t *testing.T) { + m := objx.Map{ + "first": "Tyler", + "last": "Bunnell", + } + + m.Set("name", "Mat") + + assert.Equal(t, m.Get("name").Data(), "Mat") +} + +func TestAccessorsAccessSetDeep(t *testing.T) { + m := objx.Map{ + "name": objx.Map{ + "first": "Tyler", + "last": "Bunnell", + }, + } + + m.Set("name.first", "Mat") + m.Set("name.last", "Ryer") + + assert.Equal(t, "Mat", m.Get("name.first").Data()) + assert.Equal(t, "Ryer", m.Get("name.last").Data()) +} + +func TestAccessorsAccessSetDeepDeep(t *testing.T) { + m := objx.Map{ + "one": objx.Map{ + "two": objx.Map{ + "three": objx.Map{ + "four": 4, + }, + }, + }, + } + + m.Set("one.two.three.four", 5) + + assert.Equal(t, 5, m.Get("one.two.three.four").Data()) +} + +func TestAccessorsAccessSetDeepDeepWithoutExisting(t *testing.T) { + m := objx.Map{} + + m.Set("one.two.three.four", 5) + m.Set("one.two.three.five", 6) + + assert.Equal(t, 5, m.Get("one.two.three.four").Data()) + assert.Equal(t, 6, m.Get("one.two.three.five").Data()) + + m.Set("one.two", 7) + assert.Equal(t, 7, m.Get("one.two").Data()) + assert.Equal(t, nil, m.Get("one.two.three.four").Data()) + + m.Set("one.two.three", 8) + assert.Equal(t, 8, m.Get("one.two.three").Data()) +} + +func TestAccessorsAccessSetArray(t *testing.T) { + m := objx.Map{ + "names": []interface{}{"Tyler"}, + } + m.Set("names[0]", "Mat") + + assert.Equal(t, "Mat", m.Get("names[0]").Data()) +} + +func TestAccessorsAccessSetInsideArray(t *testing.T) { + m := objx.Map{ + "names": []interface{}{ + objx.Map{ + "first": "Tyler", + "last": "Bunnell", + }, + objx.Map{ + "first": "Capitol", + "last": "Bollocks", + }, + }, + } + + m.Set("names[0].first", "Mat") + m.Set("names[0].last", "Ryer") + m.Set("names[1].first", "Captain") + m.Set("names[1].last", "Underpants") + + assert.Equal(t, "Mat", m.Get("names[0].first").Data()) + assert.Equal(t, "Ryer", m.Get("names[0].last").Data()) + assert.Equal(t, "Captain", m.Get("names[1].first").Data()) + assert.Equal(t, "Underpants", m.Get("names[1].last").Data()) +} + +func TestAccessorsSet(t *testing.T) { + m := objx.Map{"name": "Tyler"} + + m.Set("name", "Mat") + + assert.Equal(t, "Mat", m.Get("name").Data()) +} diff --git a/vendor/github.com/stretchr/objx/conversions.go b/vendor/github.com/stretchr/objx/conversions.go new file mode 100644 index 0000000..080aa46 --- /dev/null +++ b/vendor/github.com/stretchr/objx/conversions.go @@ -0,0 +1,280 @@ +package objx + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "net/url" + "strconv" +) + +// SignatureSeparator is the character that is used to +// separate the Base64 string from the security signature. +const SignatureSeparator = "_" + +// URLValuesSliceKeySuffix is the character that is used to +// specify a suffic for slices parsed by URLValues. +// If the suffix is set to "[i]", then the index of the slice +// is used in place of i +// Ex: Suffix "[]" would have the form a[]=b&a[]=c +// OR Suffix "[i]" would have the form a[0]=b&a[1]=c +// OR Suffix "" would have the form a=b&a=c +var urlValuesSliceKeySuffix = "[]" + +const ( + URLValuesSliceKeySuffixEmpty = "" + URLValuesSliceKeySuffixArray = "[]" + URLValuesSliceKeySuffixIndex = "[i]" +) + +// SetURLValuesSliceKeySuffix sets the character that is used to +// specify a suffic for slices parsed by URLValues. +// If the suffix is set to "[i]", then the index of the slice +// is used in place of i +// Ex: Suffix "[]" would have the form a[]=b&a[]=c +// OR Suffix "[i]" would have the form a[0]=b&a[1]=c +// OR Suffix "" would have the form a=b&a=c +func SetURLValuesSliceKeySuffix(s string) error { + if s == URLValuesSliceKeySuffixEmpty || s == URLValuesSliceKeySuffixArray || s == URLValuesSliceKeySuffixIndex { + urlValuesSliceKeySuffix = s + return nil + } + + return errors.New("objx: Invalid URLValuesSliceKeySuffix provided.") +} + +// JSON converts the contained object to a JSON string +// representation +func (m Map) JSON() (string, error) { + for k, v := range m { + m[k] = cleanUp(v) + } + + result, err := json.Marshal(m) + if err != nil { + err = errors.New("objx: JSON encode failed with: " + err.Error()) + } + return string(result), err +} + +func cleanUpInterfaceArray(in []interface{}) []interface{} { + result := make([]interface{}, len(in)) + for i, v := range in { + result[i] = cleanUp(v) + } + return result +} + +func cleanUpInterfaceMap(in map[interface{}]interface{}) Map { + result := Map{} + for k, v := range in { + result[fmt.Sprintf("%v", k)] = cleanUp(v) + } + return result +} + +func cleanUpStringMap(in map[string]interface{}) Map { + result := Map{} + for k, v := range in { + result[k] = cleanUp(v) + } + return result +} + +func cleanUpMSIArray(in []map[string]interface{}) []Map { + result := make([]Map, len(in)) + for i, v := range in { + result[i] = cleanUpStringMap(v) + } + return result +} + +func cleanUpMapArray(in []Map) []Map { + result := make([]Map, len(in)) + for i, v := range in { + result[i] = cleanUpStringMap(v) + } + return result +} + +func cleanUp(v interface{}) interface{} { + switch v := v.(type) { + case []interface{}: + return cleanUpInterfaceArray(v) + case []map[string]interface{}: + return cleanUpMSIArray(v) + case map[interface{}]interface{}: + return cleanUpInterfaceMap(v) + case Map: + return cleanUpStringMap(v) + case []Map: + return cleanUpMapArray(v) + default: + return v + } +} + +// MustJSON converts the contained object to a JSON string +// representation and panics if there is an error +func (m Map) MustJSON() string { + result, err := m.JSON() + if err != nil { + panic(err.Error()) + } + return result +} + +// Base64 converts the contained object to a Base64 string +// representation of the JSON string representation +func (m Map) Base64() (string, error) { + var buf bytes.Buffer + + jsonData, err := m.JSON() + if err != nil { + return "", err + } + + encoder := base64.NewEncoder(base64.StdEncoding, &buf) + _, _ = encoder.Write([]byte(jsonData)) + _ = encoder.Close() + + return buf.String(), nil +} + +// MustBase64 converts the contained object to a Base64 string +// representation of the JSON string representation and panics +// if there is an error +func (m Map) MustBase64() string { + result, err := m.Base64() + if err != nil { + panic(err.Error()) + } + return result +} + +// SignedBase64 converts the contained object to a Base64 string +// representation of the JSON string representation and signs it +// using the provided key. +func (m Map) SignedBase64(key string) (string, error) { + base64, err := m.Base64() + if err != nil { + return "", err + } + + sig := HashWithKey(base64, key) + return base64 + SignatureSeparator + sig, nil +} + +// MustSignedBase64 converts the contained object to a Base64 string +// representation of the JSON string representation and signs it +// using the provided key and panics if there is an error +func (m Map) MustSignedBase64(key string) string { + result, err := m.SignedBase64(key) + if err != nil { + panic(err.Error()) + } + return result +} + +/* + URL Query + ------------------------------------------------ +*/ + +// URLValues creates a url.Values object from an Obj. This +// function requires that the wrapped object be a map[string]interface{} +func (m Map) URLValues() url.Values { + vals := make(url.Values) + + m.parseURLValues(m, vals, "") + + return vals +} + +func (m Map) parseURLValues(queryMap Map, vals url.Values, key string) { + useSliceIndex := false + if urlValuesSliceKeySuffix == "[i]" { + useSliceIndex = true + } + + for k, v := range queryMap { + val := &Value{data: v} + switch { + case val.IsObjxMap(): + if key == "" { + m.parseURLValues(val.ObjxMap(), vals, k) + } else { + m.parseURLValues(val.ObjxMap(), vals, key+"["+k+"]") + } + case val.IsObjxMapSlice(): + sliceKey := k + if key != "" { + sliceKey = key + "[" + k + "]" + } + + if useSliceIndex { + for i, sv := range val.MustObjxMapSlice() { + sk := sliceKey + "[" + strconv.FormatInt(int64(i), 10) + "]" + m.parseURLValues(sv, vals, sk) + } + } else { + sliceKey = sliceKey + urlValuesSliceKeySuffix + for _, sv := range val.MustObjxMapSlice() { + m.parseURLValues(sv, vals, sliceKey) + } + } + case val.IsMSISlice(): + sliceKey := k + if key != "" { + sliceKey = key + "[" + k + "]" + } + + if useSliceIndex { + for i, sv := range val.MustMSISlice() { + sk := sliceKey + "[" + strconv.FormatInt(int64(i), 10) + "]" + m.parseURLValues(New(sv), vals, sk) + } + } else { + sliceKey = sliceKey + urlValuesSliceKeySuffix + for _, sv := range val.MustMSISlice() { + m.parseURLValues(New(sv), vals, sliceKey) + } + } + case val.IsStrSlice(), val.IsBoolSlice(), + val.IsFloat32Slice(), val.IsFloat64Slice(), + val.IsIntSlice(), val.IsInt8Slice(), val.IsInt16Slice(), val.IsInt32Slice(), val.IsInt64Slice(), + val.IsUintSlice(), val.IsUint8Slice(), val.IsUint16Slice(), val.IsUint32Slice(), val.IsUint64Slice(): + + sliceKey := k + if key != "" { + sliceKey = key + "[" + k + "]" + } + + if useSliceIndex { + for i, sv := range val.StringSlice() { + sk := sliceKey + "[" + strconv.FormatInt(int64(i), 10) + "]" + vals.Set(sk, sv) + } + } else { + sliceKey = sliceKey + urlValuesSliceKeySuffix + vals[sliceKey] = val.StringSlice() + } + + default: + if key == "" { + vals.Set(k, val.String()) + } else { + vals.Set(key+"["+k+"]", val.String()) + } + } + } +} + +// URLQuery gets an encoded URL query representing the given +// Obj. This function requires that the wrapped object be a +// map[string]interface{} +func (m Map) URLQuery() (string, error) { + return m.URLValues().Encode(), nil +} diff --git a/vendor/github.com/stretchr/objx/conversions_test.go b/vendor/github.com/stretchr/objx/conversions_test.go new file mode 100644 index 0000000..5071225 --- /dev/null +++ b/vendor/github.com/stretchr/objx/conversions_test.go @@ -0,0 +1,187 @@ +package objx_test + +import ( + "net/url" + "testing" + + "github.com/stretchr/objx" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestConversionJSON(t *testing.T) { + jsonString := `{"name":"Mat"}` + o := objx.MustFromJSON(jsonString) + + result, err := o.JSON() + + require.NoError(t, err) + assert.Equal(t, jsonString, result) + assert.Equal(t, jsonString, o.MustJSON()) + + i := objx.Map{ + "a": map[interface{}]interface{}{"b": objx.Map{"c": map[interface{}]interface{}{"d": "e"}}, + "f": []objx.Map{{"g": map[interface{}]interface{}{"h": "i"}}}, + "j": []map[string]interface{}{{"k": map[interface{}]interface{}{"l": "m"}}}, + "n": []interface{}{objx.Map{"o": "p"}}, + }, + } + + jsonString = `{"a":{"b":{"c":{"d":"e"}},"f":[{"g":{"h":"i"}}],"j":[{"k":{"l":"m"}}],"n":[{"o":"p"}]}}` + result, err = i.JSON() + require.NoError(t, err) + assert.Equal(t, jsonString, result) + assert.Equal(t, jsonString, i.MustJSON()) +} + +func TestConversionJSONWithError(t *testing.T) { + o := objx.MSI() + o["test"] = func() {} + + assert.Panics(t, func() { + o.MustJSON() + }) + + _, err := o.JSON() + + assert.Error(t, err) +} + +func TestConversionBase64(t *testing.T) { + o := objx.Map{"name": "Mat"} + + result, err := o.Base64() + + require.NoError(t, err) + assert.Equal(t, "eyJuYW1lIjoiTWF0In0=", result) + assert.Equal(t, "eyJuYW1lIjoiTWF0In0=", o.MustBase64()) +} + +func TestConversionBase64WithError(t *testing.T) { + o := objx.MSI() + o["test"] = func() {} + + assert.Panics(t, func() { + o.MustBase64() + }) + + _, err := o.Base64() + + assert.Error(t, err) +} + +func TestConversionSignedBase64(t *testing.T) { + o := objx.Map{"name": "Mat"} + + result, err := o.SignedBase64("key") + + require.NoError(t, err) + assert.Equal(t, "eyJuYW1lIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6", result) + assert.Equal(t, "eyJuYW1lIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6", o.MustSignedBase64("key")) +} + +func TestConversionSignedBase64WithError(t *testing.T) { + o := objx.MSI() + o["test"] = func() {} + + assert.Panics(t, func() { + o.MustSignedBase64("key") + }) + + _, err := o.SignedBase64("key") + + assert.Error(t, err) +} + +func TestConversionURLValues(t *testing.T) { + m := getURLQueryMap() + u := m.URLValues() + + assert.Equal(t, url.Values{ + "abc": []string{"123"}, + "name": []string{"Mat"}, + "data[age]": []string{"30"}, + "data[height]": []string{"162"}, + "data[arr][]": []string{"1", "2"}, + "stats[]": []string{"1", "2"}, + "bools[]": []string{"true", "false"}, + "mapSlice[][age]": []string{"40"}, + "mapSlice[][height]": []string{"152"}, + "msiData[age]": []string{"30"}, + "msiData[height]": []string{"162"}, + "msiData[arr][]": []string{"1", "2"}, + "msiSlice[][age]": []string{"40"}, + "msiSlice[][height]": []string{"152"}, + }, u) +} + +func TestConversionURLQuery(t *testing.T) { + m := getURLQueryMap() + u, err := m.URLQuery() + + assert.Nil(t, err) + require.NotNil(t, u) + + ue, err := url.QueryUnescape(u) + assert.Nil(t, err) + require.NotNil(t, ue) + + assert.Equal(t, "abc=123&bools[]=true&bools[]=false&data[age]=30&data[arr][]=1&data[arr][]=2&data[height]=162&mapSlice[][age]=40&mapSlice[][height]=152&msiData[age]=30&msiData[arr][]=1&msiData[arr][]=2&msiData[height]=162&msiSlice[][age]=40&msiSlice[][height]=152&name=Mat&stats[]=1&stats[]=2", ue) +} + +func TestConversionURLQueryNoSliceKeySuffix(t *testing.T) { + m := getURLQueryMap() + err := objx.SetURLValuesSliceKeySuffix(objx.URLValuesSliceKeySuffixEmpty) + require.Nil(t, err) + u, err := m.URLQuery() + + assert.Nil(t, err) + require.NotNil(t, u) + + ue, err := url.QueryUnescape(u) + assert.Nil(t, err) + require.NotNil(t, ue) + + assert.Equal(t, "abc=123&bools=true&bools=false&data[age]=30&data[arr]=1&data[arr]=2&data[height]=162&mapSlice[age]=40&mapSlice[height]=152&msiData[age]=30&msiData[arr]=1&msiData[arr]=2&msiData[height]=162&msiSlice[age]=40&msiSlice[height]=152&name=Mat&stats=1&stats=2", ue) +} + +func TestConversionURLQueryIndexSliceKeySuffix(t *testing.T) { + m := getURLQueryMap() + m.Set("mapSlice", []objx.Map{{"age": 40, "sex": "male"}, {"height": 152}}) + err := objx.SetURLValuesSliceKeySuffix(objx.URLValuesSliceKeySuffixIndex) + require.Nil(t, err) + u, err := m.URLQuery() + + assert.Nil(t, err) + require.NotNil(t, u) + + ue, err := url.QueryUnescape(u) + assert.Nil(t, err) + require.NotNil(t, ue) + + assert.Equal(t, "abc=123&bools[0]=true&bools[1]=false&data[age]=30&data[arr][0]=1&data[arr][1]=2&data[height]=162&mapSlice[0][age]=40&mapSlice[0][sex]=male&mapSlice[1][height]=152&msiData[age]=30&msiData[arr][0]=1&msiData[arr][1]=2&msiData[height]=162&msiSlice[0][age]=40&msiSlice[1][height]=152&name=Mat&stats[0]=1&stats[1]=2", ue) +} + +func TestValidityURLQuerySliceKeySuffix(t *testing.T) { + err := objx.SetURLValuesSliceKeySuffix("") + assert.Nil(t, err) + err = objx.SetURLValuesSliceKeySuffix("[]") + assert.Nil(t, err) + err = objx.SetURLValuesSliceKeySuffix("[i]") + assert.Nil(t, err) + err = objx.SetURLValuesSliceKeySuffix("{}") + assert.Error(t, err) +} + +func getURLQueryMap() objx.Map { + return objx.Map{ + "abc": 123, + "name": "Mat", + "data": objx.Map{"age": 30, "height": 162, "arr": []int{1, 2}}, + "mapSlice": []objx.Map{{"age": 40}, {"height": 152}}, + "msiData": map[string]interface{}{"age": 30, "height": 162, "arr": []int{1, 2}}, + "msiSlice": []map[string]interface{}{{"age": 40}, {"height": 152}}, + "stats": []string{"1", "2"}, + "bools": []bool{true, false}, + } +} diff --git a/vendor/github.com/stretchr/objx/doc.go b/vendor/github.com/stretchr/objx/doc.go new file mode 100644 index 0000000..6d6af1a --- /dev/null +++ b/vendor/github.com/stretchr/objx/doc.go @@ -0,0 +1,66 @@ +/* +Objx - Go package for dealing with maps, slices, JSON and other data. + +Overview + +Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes +a powerful `Get` method (among others) that allows you to easily and quickly get +access to data within the map, without having to worry too much about type assertions, +missing data, default values etc. + +Pattern + +Objx uses a preditable pattern to make access data from within `map[string]interface{}` easy. +Call one of the `objx.` functions to create your `objx.Map` to get going: + + m, err := objx.FromJSON(json) + +NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong, +the rest will be optimistic and try to figure things out without panicking. + +Use `Get` to access the value you're interested in. You can use dot and array +notation too: + + m.Get("places[0].latlng") + +Once you have sought the `Value` you're interested in, you can use the `Is*` methods to determine its type. + + if m.Get("code").IsStr() { // Your code... } + +Or you can just assume the type, and use one of the strong type methods to extract the real value: + + m.Get("code").Int() + +If there's no value there (or if it's the wrong type) then a default value will be returned, +or you can be explicit about the default value. + + Get("code").Int(-1) + +If you're dealing with a slice of data as a value, Objx provides many useful methods for iterating, +manipulating and selecting that data. You can find out more by exploring the index below. + +Reading data + +A simple example of how to use Objx: + + // Use MustFromJSON to make an objx.Map from some JSON + m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`) + + // Get the details + name := m.Get("name").Str() + age := m.Get("age").Int() + + // Get their nickname (or use their name if they don't have one) + nickname := m.Get("nickname").Str(name) + +Ranging + +Since `objx.Map` is a `map[string]interface{}` you can treat it as such. +For example, to `range` the data, do what you would expect: + + m := objx.MustFromJSON(json) + for key, value := range m { + // Your code... + } +*/ +package objx diff --git a/vendor/github.com/stretchr/objx/fixture_test.go b/vendor/github.com/stretchr/objx/fixture_test.go new file mode 100644 index 0000000..cefe8cd --- /dev/null +++ b/vendor/github.com/stretchr/objx/fixture_test.go @@ -0,0 +1,96 @@ +package objx_test + +import ( + "testing" + + "github.com/stretchr/objx" + "github.com/stretchr/testify/assert" +) + +var fixtures = []struct { + // name is the name of the fixture (used for reporting + // failures) + name string + // data is the JSON data to be worked on + data string + // get is the argument(s) to pass to Get + get interface{} + // output is the expected output + output interface{} +}{ + { + name: "Simple get", + data: `{"name": "Mat"}`, + get: "name", + output: "Mat", + }, + { + name: "Get with dot notation", + data: `{"address": {"city": "Boulder"}}`, + get: "address.city", + output: "Boulder", + }, + { + name: "Deep get with dot notation", + data: `{"one": {"two": {"three": {"four": "hello"}}}}`, + get: "one.two.three.four", + output: "hello", + }, + { + name: "Get missing with dot notation", + data: `{"one": {"two": {"three": {"four": "hello"}}}}`, + get: "one.ten", + output: nil, + }, + { + name: "Get with array notation", + data: `{"tags": ["one", "two", "three"]}`, + get: "tags[1]", + output: "two", + }, + { + name: "Get with array and dot notation", + data: `{"types": { "tags": ["one", "two", "three"]}}`, + get: "types.tags[1]", + output: "two", + }, + { + name: "Get with array and dot notation - field after array", + data: `{"tags": [{"name":"one"}, {"name":"two"}, {"name":"three"}]}`, + get: "tags[1].name", + output: "two", + }, + { + name: "Complex get with array and dot notation", + data: `{"tags": [{"list": [{"one":"pizza"}]}]}`, + get: "tags[0].list[0].one", + output: "pizza", + }, + { + name: "Get field from within string should be nil", + data: `{"name":"Tyler"}`, + get: "name.something", + output: nil, + }, + { + name: "Get field from within string (using array accessor) should be nil", + data: `{"numbers":["one", "two", "three"]}`, + get: "numbers[0].nope", + output: nil, + }, +} + +func TestFixtures(t *testing.T) { + for _, fixture := range fixtures { + m := objx.MustFromJSON(fixture.data) + + // get the value + t.Logf("Running get fixture: \"%s\" (%v)", fixture.name, fixture) + value := m.Get(fixture.get.(string)) + + // make sure it matches + assert.Equal(t, fixture.output, value.Data(), + "Get fixture \"%s\" failed: %v", fixture.name, fixture, + ) + } +} diff --git a/vendor/github.com/stretchr/objx/go.mod b/vendor/github.com/stretchr/objx/go.mod new file mode 100644 index 0000000..31ec5a7 --- /dev/null +++ b/vendor/github.com/stretchr/objx/go.mod @@ -0,0 +1,8 @@ +module github.com/stretchr/objx + +go 1.12 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/stretchr/testify v1.3.0 +) diff --git a/vendor/github.com/stretchr/objx/go.sum b/vendor/github.com/stretchr/objx/go.sum new file mode 100644 index 0000000..4f89841 --- /dev/null +++ b/vendor/github.com/stretchr/objx/go.sum @@ -0,0 +1,8 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= diff --git a/vendor/github.com/stretchr/objx/map.go b/vendor/github.com/stretchr/objx/map.go new file mode 100644 index 0000000..95149c0 --- /dev/null +++ b/vendor/github.com/stretchr/objx/map.go @@ -0,0 +1,228 @@ +package objx + +import ( + "encoding/base64" + "encoding/json" + "errors" + "io/ioutil" + "net/url" + "strings" +) + +// MSIConvertable is an interface that defines methods for converting your +// custom types to a map[string]interface{} representation. +type MSIConvertable interface { + // MSI gets a map[string]interface{} (msi) representing the + // object. + MSI() map[string]interface{} +} + +// Map provides extended functionality for working with +// untyped data, in particular map[string]interface (msi). +type Map map[string]interface{} + +// Value returns the internal value instance +func (m Map) Value() *Value { + return &Value{data: m} +} + +// Nil represents a nil Map. +var Nil = New(nil) + +// New creates a new Map containing the map[string]interface{} in the data argument. +// If the data argument is not a map[string]interface, New attempts to call the +// MSI() method on the MSIConvertable interface to create one. +func New(data interface{}) Map { + if _, ok := data.(map[string]interface{}); !ok { + if converter, ok := data.(MSIConvertable); ok { + data = converter.MSI() + } else { + return nil + } + } + return Map(data.(map[string]interface{})) +} + +// MSI creates a map[string]interface{} and puts it inside a new Map. +// +// The arguments follow a key, value pattern. +// +// +// Returns nil if any key argument is non-string or if there are an odd number of arguments. +// +// Example +// +// To easily create Maps: +// +// m := objx.MSI("name", "Mat", "age", 29, "subobj", objx.MSI("active", true)) +// +// // creates an Map equivalent to +// m := objx.Map{"name": "Mat", "age": 29, "subobj": objx.Map{"active": true}} +func MSI(keyAndValuePairs ...interface{}) Map { + newMap := Map{} + keyAndValuePairsLen := len(keyAndValuePairs) + if keyAndValuePairsLen%2 != 0 { + return nil + } + for i := 0; i < keyAndValuePairsLen; i = i + 2 { + key := keyAndValuePairs[i] + value := keyAndValuePairs[i+1] + + // make sure the key is a string + keyString, keyStringOK := key.(string) + if !keyStringOK { + return nil + } + newMap[keyString] = value + } + return newMap +} + +// ****** Conversion Constructors + +// MustFromJSON creates a new Map containing the data specified in the +// jsonString. +// +// Panics if the JSON is invalid. +func MustFromJSON(jsonString string) Map { + o, err := FromJSON(jsonString) + if err != nil { + panic("objx: MustFromJSON failed with error: " + err.Error()) + } + return o +} + +// FromJSON creates a new Map containing the data specified in the +// jsonString. +// +// Returns an error if the JSON is invalid. +func FromJSON(jsonString string) (Map, error) { + var m Map + err := json.Unmarshal([]byte(jsonString), &m) + if err != nil { + return Nil, err + } + m.tryConvertFloat64() + return m, nil +} + +func (m Map) tryConvertFloat64() { + for k, v := range m { + switch v.(type) { + case float64: + f := v.(float64) + if float64(int(f)) == f { + m[k] = int(f) + } + case map[string]interface{}: + t := New(v) + t.tryConvertFloat64() + m[k] = t + case []interface{}: + m[k] = tryConvertFloat64InSlice(v.([]interface{})) + } + } +} + +func tryConvertFloat64InSlice(s []interface{}) []interface{} { + for k, v := range s { + switch v.(type) { + case float64: + f := v.(float64) + if float64(int(f)) == f { + s[k] = int(f) + } + case map[string]interface{}: + t := New(v) + t.tryConvertFloat64() + s[k] = t + case []interface{}: + s[k] = tryConvertFloat64InSlice(v.([]interface{})) + } + } + return s +} + +// FromBase64 creates a new Obj containing the data specified +// in the Base64 string. +// +// The string is an encoded JSON string returned by Base64 +func FromBase64(base64String string) (Map, error) { + decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64String)) + decoded, err := ioutil.ReadAll(decoder) + if err != nil { + return nil, err + } + return FromJSON(string(decoded)) +} + +// MustFromBase64 creates a new Obj containing the data specified +// in the Base64 string and panics if there is an error. +// +// The string is an encoded JSON string returned by Base64 +func MustFromBase64(base64String string) Map { + result, err := FromBase64(base64String) + if err != nil { + panic("objx: MustFromBase64 failed with error: " + err.Error()) + } + return result +} + +// FromSignedBase64 creates a new Obj containing the data specified +// in the Base64 string. +// +// The string is an encoded JSON string returned by SignedBase64 +func FromSignedBase64(base64String, key string) (Map, error) { + parts := strings.Split(base64String, SignatureSeparator) + if len(parts) != 2 { + return nil, errors.New("objx: Signed base64 string is malformed") + } + + sig := HashWithKey(parts[0], key) + if parts[1] != sig { + return nil, errors.New("objx: Signature for base64 data does not match") + } + return FromBase64(parts[0]) +} + +// MustFromSignedBase64 creates a new Obj containing the data specified +// in the Base64 string and panics if there is an error. +// +// The string is an encoded JSON string returned by Base64 +func MustFromSignedBase64(base64String, key string) Map { + result, err := FromSignedBase64(base64String, key) + if err != nil { + panic("objx: MustFromSignedBase64 failed with error: " + err.Error()) + } + return result +} + +// FromURLQuery generates a new Obj by parsing the specified +// query. +// +// For queries with multiple values, the first value is selected. +func FromURLQuery(query string) (Map, error) { + vals, err := url.ParseQuery(query) + if err != nil { + return nil, err + } + m := Map{} + for k, vals := range vals { + m[k] = vals[0] + } + return m, nil +} + +// MustFromURLQuery generates a new Obj by parsing the specified +// query. +// +// For queries with multiple values, the first value is selected. +// +// Panics if it encounters an error +func MustFromURLQuery(query string) Map { + o, err := FromURLQuery(query) + if err != nil { + panic("objx: MustFromURLQuery failed with error: " + err.Error()) + } + return o +} diff --git a/vendor/github.com/stretchr/objx/map_test.go b/vendor/github.com/stretchr/objx/map_test.go new file mode 100644 index 0000000..333d519 --- /dev/null +++ b/vendor/github.com/stretchr/objx/map_test.go @@ -0,0 +1,227 @@ +package objx_test + +import ( + "testing" + + "github.com/stretchr/objx" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var TestMap = objx.Map{ + "name": "Tyler", + "address": objx.Map{ + "city": "Salt Lake City", + "state": "UT", + }, + "numbers": []interface{}{"one", "two", "three", "four", "five"}, +} + +type Convertable struct { + name string +} + +type Unconvertable struct { + name string +} + +func (c *Convertable) MSI() map[string]interface{} { + return objx.Map{"name": c.name} +} + +func TestMapCreation(t *testing.T) { + o := objx.New(nil) + assert.Nil(t, o) + + o = objx.New("Tyler") + assert.Nil(t, o) + + unconvertable := &Unconvertable{name: "Tyler"} + o = objx.New(unconvertable) + assert.Nil(t, o) + + convertable := &Convertable{name: "Tyler"} + o = objx.New(convertable) + require.NotNil(t, convertable) + assert.Equal(t, "Tyler", o["name"]) + + o = objx.MSI() + assert.NotNil(t, o) + + o = objx.MSI("name", "Tyler") + require.NotNil(t, o) + assert.Equal(t, o["name"], "Tyler") + + o = objx.MSI(1, "a") + assert.Nil(t, o) + + o = objx.MSI("a") + assert.Nil(t, o) + + o = objx.MSI("a", "b", "c") + assert.Nil(t, o) +} + +func TestMapValure(t *testing.T) { + m := objx.Map{ + "a": 1, + } + v := m.Value() + + assert.Equal(t, m, v.ObjxMap()) +} + +func TestMapMustFromJSONWithError(t *testing.T) { + _, err := objx.FromJSON(`"name":"Mat"}`) + assert.Error(t, err) +} + +func TestMapFromJSON(t *testing.T) { + o := objx.MustFromJSON(`{"name":"Mat"}`) + + require.NotNil(t, o) + assert.Equal(t, "Mat", o["name"]) +} + +func TestMapFromJSONWithError(t *testing.T) { + var m objx.Map + + assert.Panics(t, func() { + m = objx.MustFromJSON(`"name":"Mat"}`) + }) + assert.Nil(t, m) +} + +func TestConversionJSONInt(t *testing.T) { + jsonString := + `{ + "a": 1, + "b": { + "data": 1 + }, + "c": [1], + "d": [[1]] + }` + m, err := objx.FromJSON(jsonString) + + assert.Nil(t, err) + require.NotNil(t, m) + assert.Equal(t, 1, m.Get("a").Int()) + assert.Equal(t, 1, m.Get("b.data").Int()) + + assert.True(t, m.Get("c").IsInterSlice()) + assert.Equal(t, 1, m.Get("c").InterSlice()[0]) + + assert.True(t, m.Get("d").IsInterSlice()) + assert.Equal(t, []interface{}{1}, m.Get("d").InterSlice()[0]) +} + +func TestJSONSliceInt(t *testing.T) { + jsonString := + `{ + "a": [ + {"b": 1}, + {"c": 2} + ] + }` + m, err := objx.FromJSON(jsonString) + + assert.Nil(t, err) + require.NotNil(t, m) + assert.Equal(t, []objx.Map{{"b": 1}, {"c": 2}}, m.Get("a").ObjxMapSlice()) +} + +func TestJSONSliceMixed(t *testing.T) { + jsonString := + `{ + "a": [ + {"b": 1}, + "a" + ] + }` + m, err := objx.FromJSON(jsonString) + + assert.Nil(t, err) + require.NotNil(t, m) + + assert.Nil(t, m.Get("a").ObjxMapSlice()) +} + +func TestMapFromBase64String(t *testing.T) { + base64String := "eyJuYW1lIjoiTWF0In0=" + o, err := objx.FromBase64(base64String) + + require.NoError(t, err) + assert.Equal(t, o.Get("name").Str(), "Mat") + assert.Equal(t, objx.MustFromBase64(base64String).Get("name").Str(), "Mat") +} + +func TestMapFromBase64StringWithError(t *testing.T) { + base64String := "eyJuYW1lIjoiTWFasd0In0=" + _, err := objx.FromBase64(base64String) + + assert.Error(t, err) + assert.Panics(t, func() { + objx.MustFromBase64(base64String) + }) +} + +func TestMapFromSignedBase64String(t *testing.T) { + base64String := "eyJuYW1lIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6" + + o, err := objx.FromSignedBase64(base64String, "key") + + require.NoError(t, err) + assert.Equal(t, o.Get("name").Str(), "Mat") + assert.Equal(t, objx.MustFromSignedBase64(base64String, "key").Get("name").Str(), "Mat") +} + +func TestMapFromSignedBase64StringWithError(t *testing.T) { + base64String := "eyJuYW1lasdIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6" + _, err := objx.FromSignedBase64(base64String, "key") + assert.Error(t, err) + assert.Panics(t, func() { + objx.MustFromSignedBase64(base64String, "key") + }) + + base64String = "eyJuYW1lasdIjoiTWF0In0=67ee82916f90b2c0d68c903266e8998c9ef0c3d6" + _, err = objx.FromSignedBase64(base64String, "key") + assert.Error(t, err) + assert.Panics(t, func() { + objx.MustFromSignedBase64(base64String, "key") + }) + + base64String = "eyJuYW1lIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6_junk" + _, err = objx.FromSignedBase64(base64String, "key") + assert.Error(t, err) + assert.Panics(t, func() { + objx.MustFromSignedBase64(base64String, "key") + }) +} + +func TestMapFromURLQuery(t *testing.T) { + m, err := objx.FromURLQuery("name=tyler&state=UT") + + assert.NoError(t, err) + require.NotNil(t, m) + assert.Equal(t, "tyler", m.Get("name").Str()) + assert.Equal(t, "UT", m.Get("state").Str()) +} + +func TestMapMustFromURLQuery(t *testing.T) { + m := objx.MustFromURLQuery("name=tyler&state=UT") + + require.NotNil(t, m) + assert.Equal(t, "tyler", m.Get("name").Str()) + assert.Equal(t, "UT", m.Get("state").Str()) +} + +func TestMapFromURLQueryWithError(t *testing.T) { + m, err := objx.FromURLQuery("%") + + assert.Error(t, err) + assert.Nil(t, m) + assert.Panics(t, func() { + objx.MustFromURLQuery("%") + }) +} diff --git a/vendor/github.com/stretchr/objx/mutations.go b/vendor/github.com/stretchr/objx/mutations.go new file mode 100644 index 0000000..c3400a3 --- /dev/null +++ b/vendor/github.com/stretchr/objx/mutations.go @@ -0,0 +1,77 @@ +package objx + +// Exclude returns a new Map with the keys in the specified []string +// excluded. +func (m Map) Exclude(exclude []string) Map { + excluded := make(Map) + for k, v := range m { + if !contains(exclude, k) { + excluded[k] = v + } + } + return excluded +} + +// Copy creates a shallow copy of the Obj. +func (m Map) Copy() Map { + copied := Map{} + for k, v := range m { + copied[k] = v + } + return copied +} + +// Merge blends the specified map with a copy of this map and returns the result. +// +// Keys that appear in both will be selected from the specified map. +// This method requires that the wrapped object be a map[string]interface{} +func (m Map) Merge(merge Map) Map { + return m.Copy().MergeHere(merge) +} + +// MergeHere blends the specified map with this map and returns the current map. +// +// Keys that appear in both will be selected from the specified map. The original map +// will be modified. This method requires that +// the wrapped object be a map[string]interface{} +func (m Map) MergeHere(merge Map) Map { + for k, v := range merge { + m[k] = v + } + return m +} + +// Transform builds a new Obj giving the transformer a chance +// to change the keys and values as it goes. This method requires that +// the wrapped object be a map[string]interface{} +func (m Map) Transform(transformer func(key string, value interface{}) (string, interface{})) Map { + newMap := Map{} + for k, v := range m { + modifiedKey, modifiedVal := transformer(k, v) + newMap[modifiedKey] = modifiedVal + } + return newMap +} + +// TransformKeys builds a new map using the specified key mapping. +// +// Unspecified keys will be unaltered. +// This method requires that the wrapped object be a map[string]interface{} +func (m Map) TransformKeys(mapping map[string]string) Map { + return m.Transform(func(key string, value interface{}) (string, interface{}) { + if newKey, ok := mapping[key]; ok { + return newKey, value + } + return key, value + }) +} + +// Checks if a string slice contains a string +func contains(s []string, e string) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} diff --git a/vendor/github.com/stretchr/objx/mutations_test.go b/vendor/github.com/stretchr/objx/mutations_test.go new file mode 100644 index 0000000..40901ce --- /dev/null +++ b/vendor/github.com/stretchr/objx/mutations_test.go @@ -0,0 +1,106 @@ +package objx_test + +import ( + "strings" + "testing" + + "github.com/stretchr/objx" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestExclude(t *testing.T) { + m := objx.Map{ + "name": "Mat", + "age": 29, + "secret": "ABC", + } + + excluded := m.Exclude([]string{"secret"}) + + assert.Equal(t, m["name"], excluded["name"]) + assert.Equal(t, m["age"], excluded["age"]) + assert.False(t, excluded.Has("secret"), "secret should be excluded") +} + +func TestCopy(t *testing.T) { + m1 := objx.Map{ + "name": "Tyler", + "location": "UT", + } + + m2 := m1.Copy() + require.NotNil(t, m2) + m2["name"] = "Mat" + + assert.Equal(t, m1.Get("name").Str(), "Tyler") + assert.Equal(t, m2.Get("name").Str(), "Mat") + +} + +func TestMerge(t *testing.T) { + m1 := objx.Map{ + "name": "Mat", + } + m2 := objx.Map{ + "name": "Tyler", + "location": "UT", + } + + merged := m1.Merge(m2) + + assert.Equal(t, merged.Get("name").Str(), m2.Get("name").Str()) + assert.Equal(t, merged.Get("location").Str(), m2.Get("location").Str()) + assert.Empty(t, m1.Get("location").Str()) +} + +func TestMergeHere(t *testing.T) { + m1 := objx.Map{ + "name": "Mat", + } + m2 := objx.Map{ + "name": "Tyler", + "location": "UT", + } + + merged := m1.MergeHere(m2) + + assert.Equal(t, m1, merged, "With MergeHere, it should return the first modified map") + assert.Equal(t, merged.Get("name").Str(), m2.Get("name").Str()) + assert.Equal(t, merged.Get("location").Str(), m2.Get("location").Str()) + assert.Equal(t, merged.Get("location").Str(), m1.Get("location").Str()) +} + +func TestTransform(t *testing.T) { + m := objx.Map{ + "name": "Mat", + "location": "UK", + } + r := m.Transform(keyToUpper) + assert.Equal(t, objx.Map{ + "NAME": "Mat", + "LOCATION": "UK", + }, r) +} + +func TestTransformKeys(t *testing.T) { + m := objx.Map{ + "a": "1", + "b": "2", + "c": "3", + } + mapping := map[string]string{ + "a": "d", + "b": "e", + } + r := m.TransformKeys(mapping) + assert.Equal(t, objx.Map{ + "c": "3", + "d": "1", + "e": "2", + }, r) +} + +func keyToUpper(s string, v interface{}) (string, interface{}) { + return strings.ToUpper(s), v +} diff --git a/vendor/github.com/stretchr/objx/security.go b/vendor/github.com/stretchr/objx/security.go new file mode 100644 index 0000000..692be8e --- /dev/null +++ b/vendor/github.com/stretchr/objx/security.go @@ -0,0 +1,12 @@ +package objx + +import ( + "crypto/sha1" + "encoding/hex" +) + +// HashWithKey hashes the specified string using the security key +func HashWithKey(data, key string) string { + d := sha1.Sum([]byte(data + ":" + key)) + return hex.EncodeToString(d[:]) +} diff --git a/vendor/github.com/stretchr/objx/security_test.go b/vendor/github.com/stretchr/objx/security_test.go new file mode 100644 index 0000000..8c623db --- /dev/null +++ b/vendor/github.com/stretchr/objx/security_test.go @@ -0,0 +1,12 @@ +package objx_test + +import ( + "testing" + + "github.com/stretchr/objx" + "github.com/stretchr/testify/assert" +) + +func TestHashWithKey(t *testing.T) { + assert.Equal(t, "0ce84d8d01f2c7b6e0882b784429c54d280ea2d9", objx.HashWithKey("abc", "def")) +} diff --git a/vendor/github.com/stretchr/objx/simple_example_test.go b/vendor/github.com/stretchr/objx/simple_example_test.go new file mode 100644 index 0000000..403753d --- /dev/null +++ b/vendor/github.com/stretchr/objx/simple_example_test.go @@ -0,0 +1,42 @@ +package objx_test + +import ( + "testing" + + "github.com/stretchr/objx" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestSimpleExample(t *testing.T) { + // build a map from a JSON object + o := objx.MustFromJSON(`{"name":"Mat","foods":["indian","chinese"], "location":{"county":"hobbiton","city":"the shire"}}`) + + // Map can be used as a straight map[string]interface{} + assert.Equal(t, o["name"], "Mat") + + // Get an Value object + v := o.Get("name") + require.NotNil(t, v) + + // Test the contained value + assert.False(t, v.IsInt()) + assert.False(t, v.IsBool()) + assert.True(t, v.IsStr()) + + // Get the contained value + assert.Equal(t, v.Str(), "Mat") + + // Get a default value if the contained value is not of the expected type or does not exist + assert.Equal(t, 1, v.Int(1)) + + // Get a value by using array notation + assert.Equal(t, "indian", o.Get("foods[0]").Data()) + + // Set a value by using array notation + o.Set("foods[0]", "italian") + assert.Equal(t, "italian", o.Get("foods[0]").Str()) + + // Get a value by using dot notation + assert.Equal(t, "hobbiton", o.Get("location.county").Str()) +} diff --git a/vendor/github.com/stretchr/objx/tests.go b/vendor/github.com/stretchr/objx/tests.go new file mode 100644 index 0000000..d9e0b47 --- /dev/null +++ b/vendor/github.com/stretchr/objx/tests.go @@ -0,0 +1,17 @@ +package objx + +// Has gets whether there is something at the specified selector +// or not. +// +// If m is nil, Has will always return false. +func (m Map) Has(selector string) bool { + if m == nil { + return false + } + return !m.Get(selector).IsNil() +} + +// IsNil gets whether the data is nil or not. +func (v *Value) IsNil() bool { + return v == nil || v.data == nil +} diff --git a/vendor/github.com/stretchr/objx/tests_test.go b/vendor/github.com/stretchr/objx/tests_test.go new file mode 100644 index 0000000..94a8ada --- /dev/null +++ b/vendor/github.com/stretchr/objx/tests_test.go @@ -0,0 +1,25 @@ +package objx_test + +import ( + "testing" + + "github.com/stretchr/objx" + "github.com/stretchr/testify/assert" +) + +func TestHas(t *testing.T) { + m := objx.Map(TestMap) + + assert.True(t, m.Has("name")) + assert.True(t, m.Has("address.state")) + assert.True(t, m.Has("numbers[4]")) + + assert.False(t, m.Has("address.state.nope")) + assert.False(t, m.Has("address.nope")) + assert.False(t, m.Has("nope")) + assert.False(t, m.Has("numbers[5]")) + + m = nil + + assert.False(t, m.Has("nothing")) +} diff --git a/vendor/github.com/stretchr/objx/type_specific.go b/vendor/github.com/stretchr/objx/type_specific.go new file mode 100644 index 0000000..80f88d9 --- /dev/null +++ b/vendor/github.com/stretchr/objx/type_specific.go @@ -0,0 +1,346 @@ +package objx + +/* + MSI (map[string]interface{} and []map[string]interface{}) +*/ + +// MSI gets the value as a map[string]interface{}, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) MSI(optionalDefault ...map[string]interface{}) map[string]interface{} { + if s, ok := v.data.(map[string]interface{}); ok { + return s + } + if s, ok := v.data.(Map); ok { + return map[string]interface{}(s) + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustMSI gets the value as a map[string]interface{}. +// +// Panics if the object is not a map[string]interface{}. +func (v *Value) MustMSI() map[string]interface{} { + if s, ok := v.data.(Map); ok { + return map[string]interface{}(s) + } + return v.data.(map[string]interface{}) +} + +// MSISlice gets the value as a []map[string]interface{}, returns the optionalDefault +// value or nil if the value is not a []map[string]interface{}. +func (v *Value) MSISlice(optionalDefault ...[]map[string]interface{}) []map[string]interface{} { + if s, ok := v.data.([]map[string]interface{}); ok { + return s + } + + s := v.ObjxMapSlice() + if s == nil { + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil + } + + result := make([]map[string]interface{}, len(s)) + for i := range s { + result[i] = s[i].Value().MSI() + } + return result +} + +// MustMSISlice gets the value as a []map[string]interface{}. +// +// Panics if the object is not a []map[string]interface{}. +func (v *Value) MustMSISlice() []map[string]interface{} { + if s := v.MSISlice(); s != nil { + return s + } + + return v.data.([]map[string]interface{}) +} + +// IsMSI gets whether the object contained is a map[string]interface{} or not. +func (v *Value) IsMSI() bool { + _, ok := v.data.(map[string]interface{}) + if !ok { + _, ok = v.data.(Map) + } + return ok +} + +// IsMSISlice gets whether the object contained is a []map[string]interface{} or not. +func (v *Value) IsMSISlice() bool { + _, ok := v.data.([]map[string]interface{}) + if !ok { + _, ok = v.data.([]Map) + if !ok { + s, ok := v.data.([]interface{}) + if ok { + for i := range s { + switch s[i].(type) { + case Map: + case map[string]interface{}: + default: + return false + } + } + return true + } + } + } + return ok +} + +// EachMSI calls the specified callback for each object +// in the []map[string]interface{}. +// +// Panics if the object is the wrong type. +func (v *Value) EachMSI(callback func(int, map[string]interface{}) bool) *Value { + for index, val := range v.MustMSISlice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereMSI uses the specified decider function to select items +// from the []map[string]interface{}. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereMSI(decider func(int, map[string]interface{}) bool) *Value { + var selected []map[string]interface{} + v.EachMSI(func(index int, val map[string]interface{}) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupMSI uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]map[string]interface{}. +func (v *Value) GroupMSI(grouper func(int, map[string]interface{}) string) *Value { + groups := make(map[string][]map[string]interface{}) + v.EachMSI(func(index int, val map[string]interface{}) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]map[string]interface{}, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceMSI uses the specified function to replace each map[string]interface{}s +// by iterating each item. The data in the returned result will be a +// []map[string]interface{} containing the replaced items. +func (v *Value) ReplaceMSI(replacer func(int, map[string]interface{}) map[string]interface{}) *Value { + arr := v.MustMSISlice() + replaced := make([]map[string]interface{}, len(arr)) + v.EachMSI(func(index int, val map[string]interface{}) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectMSI uses the specified collector function to collect a value +// for each of the map[string]interface{}s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectMSI(collector func(int, map[string]interface{}) interface{}) *Value { + arr := v.MustMSISlice() + collected := make([]interface{}, len(arr)) + v.EachMSI(func(index int, val map[string]interface{}) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + ObjxMap ((Map) and [](Map)) +*/ + +// ObjxMap gets the value as a (Map), returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) ObjxMap(optionalDefault ...(Map)) Map { + if s, ok := v.data.((Map)); ok { + return s + } + if s, ok := v.data.(map[string]interface{}); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return New(nil) +} + +// MustObjxMap gets the value as a (Map). +// +// Panics if the object is not a (Map). +func (v *Value) MustObjxMap() Map { + if s, ok := v.data.(map[string]interface{}); ok { + return s + } + return v.data.((Map)) +} + +// ObjxMapSlice gets the value as a [](Map), returns the optionalDefault +// value or nil if the value is not a [](Map). +func (v *Value) ObjxMapSlice(optionalDefault ...[](Map)) [](Map) { + if s, ok := v.data.([]Map); ok { + return s + } + + if s, ok := v.data.([]map[string]interface{}); ok { + result := make([]Map, len(s)) + for i := range s { + result[i] = s[i] + } + return result + } + + s, ok := v.data.([]interface{}) + if !ok { + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil + } + + result := make([]Map, len(s)) + for i := range s { + switch s[i].(type) { + case Map: + result[i] = s[i].(Map) + case map[string]interface{}: + result[i] = New(s[i]) + default: + return nil + } + } + return result +} + +// MustObjxMapSlice gets the value as a [](Map). +// +// Panics if the object is not a [](Map). +func (v *Value) MustObjxMapSlice() [](Map) { + if s := v.ObjxMapSlice(); s != nil { + return s + } + return v.data.([](Map)) +} + +// IsObjxMap gets whether the object contained is a (Map) or not. +func (v *Value) IsObjxMap() bool { + _, ok := v.data.((Map)) + if !ok { + _, ok = v.data.(map[string]interface{}) + } + return ok +} + +// IsObjxMapSlice gets whether the object contained is a [](Map) or not. +func (v *Value) IsObjxMapSlice() bool { + _, ok := v.data.([](Map)) + if !ok { + _, ok = v.data.([]map[string]interface{}) + if !ok { + s, ok := v.data.([]interface{}) + if ok { + for i := range s { + switch s[i].(type) { + case Map: + case map[string]interface{}: + default: + return false + } + } + return true + } + } + } + + return ok +} + +// EachObjxMap calls the specified callback for each object +// in the [](Map). +// +// Panics if the object is the wrong type. +func (v *Value) EachObjxMap(callback func(int, Map) bool) *Value { + for index, val := range v.MustObjxMapSlice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereObjxMap uses the specified decider function to select items +// from the [](Map). The object contained in the result will contain +// only the selected items. +func (v *Value) WhereObjxMap(decider func(int, Map) bool) *Value { + var selected [](Map) + v.EachObjxMap(func(index int, val Map) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupObjxMap uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][](Map). +func (v *Value) GroupObjxMap(grouper func(int, Map) string) *Value { + groups := make(map[string][](Map)) + v.EachObjxMap(func(index int, val Map) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([](Map), 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceObjxMap uses the specified function to replace each (Map)s +// by iterating each item. The data in the returned result will be a +// [](Map) containing the replaced items. +func (v *Value) ReplaceObjxMap(replacer func(int, Map) Map) *Value { + arr := v.MustObjxMapSlice() + replaced := make([](Map), len(arr)) + v.EachObjxMap(func(index int, val Map) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectObjxMap uses the specified collector function to collect a value +// for each of the (Map)s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectObjxMap(collector func(int, Map) interface{}) *Value { + arr := v.MustObjxMapSlice() + collected := make([]interface{}, len(arr)) + v.EachObjxMap(func(index int, val Map) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} diff --git a/vendor/github.com/stretchr/objx/type_specific_codegen.go b/vendor/github.com/stretchr/objx/type_specific_codegen.go new file mode 100644 index 0000000..9859b40 --- /dev/null +++ b/vendor/github.com/stretchr/objx/type_specific_codegen.go @@ -0,0 +1,2251 @@ +package objx + +/* + Inter (interface{} and []interface{}) +*/ + +// Inter gets the value as a interface{}, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Inter(optionalDefault ...interface{}) interface{} { + if s, ok := v.data.(interface{}); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustInter gets the value as a interface{}. +// +// Panics if the object is not a interface{}. +func (v *Value) MustInter() interface{} { + return v.data.(interface{}) +} + +// InterSlice gets the value as a []interface{}, returns the optionalDefault +// value or nil if the value is not a []interface{}. +func (v *Value) InterSlice(optionalDefault ...[]interface{}) []interface{} { + if s, ok := v.data.([]interface{}); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustInterSlice gets the value as a []interface{}. +// +// Panics if the object is not a []interface{}. +func (v *Value) MustInterSlice() []interface{} { + return v.data.([]interface{}) +} + +// IsInter gets whether the object contained is a interface{} or not. +func (v *Value) IsInter() bool { + _, ok := v.data.(interface{}) + return ok +} + +// IsInterSlice gets whether the object contained is a []interface{} or not. +func (v *Value) IsInterSlice() bool { + _, ok := v.data.([]interface{}) + return ok +} + +// EachInter calls the specified callback for each object +// in the []interface{}. +// +// Panics if the object is the wrong type. +func (v *Value) EachInter(callback func(int, interface{}) bool) *Value { + for index, val := range v.MustInterSlice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereInter uses the specified decider function to select items +// from the []interface{}. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereInter(decider func(int, interface{}) bool) *Value { + var selected []interface{} + v.EachInter(func(index int, val interface{}) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupInter uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]interface{}. +func (v *Value) GroupInter(grouper func(int, interface{}) string) *Value { + groups := make(map[string][]interface{}) + v.EachInter(func(index int, val interface{}) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]interface{}, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceInter uses the specified function to replace each interface{}s +// by iterating each item. The data in the returned result will be a +// []interface{} containing the replaced items. +func (v *Value) ReplaceInter(replacer func(int, interface{}) interface{}) *Value { + arr := v.MustInterSlice() + replaced := make([]interface{}, len(arr)) + v.EachInter(func(index int, val interface{}) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectInter uses the specified collector function to collect a value +// for each of the interface{}s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectInter(collector func(int, interface{}) interface{}) *Value { + arr := v.MustInterSlice() + collected := make([]interface{}, len(arr)) + v.EachInter(func(index int, val interface{}) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Bool (bool and []bool) +*/ + +// Bool gets the value as a bool, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Bool(optionalDefault ...bool) bool { + if s, ok := v.data.(bool); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return false +} + +// MustBool gets the value as a bool. +// +// Panics if the object is not a bool. +func (v *Value) MustBool() bool { + return v.data.(bool) +} + +// BoolSlice gets the value as a []bool, returns the optionalDefault +// value or nil if the value is not a []bool. +func (v *Value) BoolSlice(optionalDefault ...[]bool) []bool { + if s, ok := v.data.([]bool); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustBoolSlice gets the value as a []bool. +// +// Panics if the object is not a []bool. +func (v *Value) MustBoolSlice() []bool { + return v.data.([]bool) +} + +// IsBool gets whether the object contained is a bool or not. +func (v *Value) IsBool() bool { + _, ok := v.data.(bool) + return ok +} + +// IsBoolSlice gets whether the object contained is a []bool or not. +func (v *Value) IsBoolSlice() bool { + _, ok := v.data.([]bool) + return ok +} + +// EachBool calls the specified callback for each object +// in the []bool. +// +// Panics if the object is the wrong type. +func (v *Value) EachBool(callback func(int, bool) bool) *Value { + for index, val := range v.MustBoolSlice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereBool uses the specified decider function to select items +// from the []bool. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereBool(decider func(int, bool) bool) *Value { + var selected []bool + v.EachBool(func(index int, val bool) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupBool uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]bool. +func (v *Value) GroupBool(grouper func(int, bool) string) *Value { + groups := make(map[string][]bool) + v.EachBool(func(index int, val bool) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]bool, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceBool uses the specified function to replace each bools +// by iterating each item. The data in the returned result will be a +// []bool containing the replaced items. +func (v *Value) ReplaceBool(replacer func(int, bool) bool) *Value { + arr := v.MustBoolSlice() + replaced := make([]bool, len(arr)) + v.EachBool(func(index int, val bool) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectBool uses the specified collector function to collect a value +// for each of the bools in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectBool(collector func(int, bool) interface{}) *Value { + arr := v.MustBoolSlice() + collected := make([]interface{}, len(arr)) + v.EachBool(func(index int, val bool) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Str (string and []string) +*/ + +// Str gets the value as a string, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Str(optionalDefault ...string) string { + if s, ok := v.data.(string); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return "" +} + +// MustStr gets the value as a string. +// +// Panics if the object is not a string. +func (v *Value) MustStr() string { + return v.data.(string) +} + +// StrSlice gets the value as a []string, returns the optionalDefault +// value or nil if the value is not a []string. +func (v *Value) StrSlice(optionalDefault ...[]string) []string { + if s, ok := v.data.([]string); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustStrSlice gets the value as a []string. +// +// Panics if the object is not a []string. +func (v *Value) MustStrSlice() []string { + return v.data.([]string) +} + +// IsStr gets whether the object contained is a string or not. +func (v *Value) IsStr() bool { + _, ok := v.data.(string) + return ok +} + +// IsStrSlice gets whether the object contained is a []string or not. +func (v *Value) IsStrSlice() bool { + _, ok := v.data.([]string) + return ok +} + +// EachStr calls the specified callback for each object +// in the []string. +// +// Panics if the object is the wrong type. +func (v *Value) EachStr(callback func(int, string) bool) *Value { + for index, val := range v.MustStrSlice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereStr uses the specified decider function to select items +// from the []string. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereStr(decider func(int, string) bool) *Value { + var selected []string + v.EachStr(func(index int, val string) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupStr uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]string. +func (v *Value) GroupStr(grouper func(int, string) string) *Value { + groups := make(map[string][]string) + v.EachStr(func(index int, val string) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]string, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceStr uses the specified function to replace each strings +// by iterating each item. The data in the returned result will be a +// []string containing the replaced items. +func (v *Value) ReplaceStr(replacer func(int, string) string) *Value { + arr := v.MustStrSlice() + replaced := make([]string, len(arr)) + v.EachStr(func(index int, val string) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectStr uses the specified collector function to collect a value +// for each of the strings in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectStr(collector func(int, string) interface{}) *Value { + arr := v.MustStrSlice() + collected := make([]interface{}, len(arr)) + v.EachStr(func(index int, val string) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Int (int and []int) +*/ + +// Int gets the value as a int, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Int(optionalDefault ...int) int { + if s, ok := v.data.(int); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustInt gets the value as a int. +// +// Panics if the object is not a int. +func (v *Value) MustInt() int { + return v.data.(int) +} + +// IntSlice gets the value as a []int, returns the optionalDefault +// value or nil if the value is not a []int. +func (v *Value) IntSlice(optionalDefault ...[]int) []int { + if s, ok := v.data.([]int); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustIntSlice gets the value as a []int. +// +// Panics if the object is not a []int. +func (v *Value) MustIntSlice() []int { + return v.data.([]int) +} + +// IsInt gets whether the object contained is a int or not. +func (v *Value) IsInt() bool { + _, ok := v.data.(int) + return ok +} + +// IsIntSlice gets whether the object contained is a []int or not. +func (v *Value) IsIntSlice() bool { + _, ok := v.data.([]int) + return ok +} + +// EachInt calls the specified callback for each object +// in the []int. +// +// Panics if the object is the wrong type. +func (v *Value) EachInt(callback func(int, int) bool) *Value { + for index, val := range v.MustIntSlice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereInt uses the specified decider function to select items +// from the []int. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereInt(decider func(int, int) bool) *Value { + var selected []int + v.EachInt(func(index int, val int) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupInt uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]int. +func (v *Value) GroupInt(grouper func(int, int) string) *Value { + groups := make(map[string][]int) + v.EachInt(func(index int, val int) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]int, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceInt uses the specified function to replace each ints +// by iterating each item. The data in the returned result will be a +// []int containing the replaced items. +func (v *Value) ReplaceInt(replacer func(int, int) int) *Value { + arr := v.MustIntSlice() + replaced := make([]int, len(arr)) + v.EachInt(func(index int, val int) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectInt uses the specified collector function to collect a value +// for each of the ints in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectInt(collector func(int, int) interface{}) *Value { + arr := v.MustIntSlice() + collected := make([]interface{}, len(arr)) + v.EachInt(func(index int, val int) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Int8 (int8 and []int8) +*/ + +// Int8 gets the value as a int8, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Int8(optionalDefault ...int8) int8 { + if s, ok := v.data.(int8); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustInt8 gets the value as a int8. +// +// Panics if the object is not a int8. +func (v *Value) MustInt8() int8 { + return v.data.(int8) +} + +// Int8Slice gets the value as a []int8, returns the optionalDefault +// value or nil if the value is not a []int8. +func (v *Value) Int8Slice(optionalDefault ...[]int8) []int8 { + if s, ok := v.data.([]int8); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustInt8Slice gets the value as a []int8. +// +// Panics if the object is not a []int8. +func (v *Value) MustInt8Slice() []int8 { + return v.data.([]int8) +} + +// IsInt8 gets whether the object contained is a int8 or not. +func (v *Value) IsInt8() bool { + _, ok := v.data.(int8) + return ok +} + +// IsInt8Slice gets whether the object contained is a []int8 or not. +func (v *Value) IsInt8Slice() bool { + _, ok := v.data.([]int8) + return ok +} + +// EachInt8 calls the specified callback for each object +// in the []int8. +// +// Panics if the object is the wrong type. +func (v *Value) EachInt8(callback func(int, int8) bool) *Value { + for index, val := range v.MustInt8Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereInt8 uses the specified decider function to select items +// from the []int8. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereInt8(decider func(int, int8) bool) *Value { + var selected []int8 + v.EachInt8(func(index int, val int8) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupInt8 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]int8. +func (v *Value) GroupInt8(grouper func(int, int8) string) *Value { + groups := make(map[string][]int8) + v.EachInt8(func(index int, val int8) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]int8, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceInt8 uses the specified function to replace each int8s +// by iterating each item. The data in the returned result will be a +// []int8 containing the replaced items. +func (v *Value) ReplaceInt8(replacer func(int, int8) int8) *Value { + arr := v.MustInt8Slice() + replaced := make([]int8, len(arr)) + v.EachInt8(func(index int, val int8) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectInt8 uses the specified collector function to collect a value +// for each of the int8s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectInt8(collector func(int, int8) interface{}) *Value { + arr := v.MustInt8Slice() + collected := make([]interface{}, len(arr)) + v.EachInt8(func(index int, val int8) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Int16 (int16 and []int16) +*/ + +// Int16 gets the value as a int16, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Int16(optionalDefault ...int16) int16 { + if s, ok := v.data.(int16); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustInt16 gets the value as a int16. +// +// Panics if the object is not a int16. +func (v *Value) MustInt16() int16 { + return v.data.(int16) +} + +// Int16Slice gets the value as a []int16, returns the optionalDefault +// value or nil if the value is not a []int16. +func (v *Value) Int16Slice(optionalDefault ...[]int16) []int16 { + if s, ok := v.data.([]int16); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustInt16Slice gets the value as a []int16. +// +// Panics if the object is not a []int16. +func (v *Value) MustInt16Slice() []int16 { + return v.data.([]int16) +} + +// IsInt16 gets whether the object contained is a int16 or not. +func (v *Value) IsInt16() bool { + _, ok := v.data.(int16) + return ok +} + +// IsInt16Slice gets whether the object contained is a []int16 or not. +func (v *Value) IsInt16Slice() bool { + _, ok := v.data.([]int16) + return ok +} + +// EachInt16 calls the specified callback for each object +// in the []int16. +// +// Panics if the object is the wrong type. +func (v *Value) EachInt16(callback func(int, int16) bool) *Value { + for index, val := range v.MustInt16Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereInt16 uses the specified decider function to select items +// from the []int16. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereInt16(decider func(int, int16) bool) *Value { + var selected []int16 + v.EachInt16(func(index int, val int16) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupInt16 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]int16. +func (v *Value) GroupInt16(grouper func(int, int16) string) *Value { + groups := make(map[string][]int16) + v.EachInt16(func(index int, val int16) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]int16, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceInt16 uses the specified function to replace each int16s +// by iterating each item. The data in the returned result will be a +// []int16 containing the replaced items. +func (v *Value) ReplaceInt16(replacer func(int, int16) int16) *Value { + arr := v.MustInt16Slice() + replaced := make([]int16, len(arr)) + v.EachInt16(func(index int, val int16) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectInt16 uses the specified collector function to collect a value +// for each of the int16s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectInt16(collector func(int, int16) interface{}) *Value { + arr := v.MustInt16Slice() + collected := make([]interface{}, len(arr)) + v.EachInt16(func(index int, val int16) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Int32 (int32 and []int32) +*/ + +// Int32 gets the value as a int32, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Int32(optionalDefault ...int32) int32 { + if s, ok := v.data.(int32); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustInt32 gets the value as a int32. +// +// Panics if the object is not a int32. +func (v *Value) MustInt32() int32 { + return v.data.(int32) +} + +// Int32Slice gets the value as a []int32, returns the optionalDefault +// value or nil if the value is not a []int32. +func (v *Value) Int32Slice(optionalDefault ...[]int32) []int32 { + if s, ok := v.data.([]int32); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustInt32Slice gets the value as a []int32. +// +// Panics if the object is not a []int32. +func (v *Value) MustInt32Slice() []int32 { + return v.data.([]int32) +} + +// IsInt32 gets whether the object contained is a int32 or not. +func (v *Value) IsInt32() bool { + _, ok := v.data.(int32) + return ok +} + +// IsInt32Slice gets whether the object contained is a []int32 or not. +func (v *Value) IsInt32Slice() bool { + _, ok := v.data.([]int32) + return ok +} + +// EachInt32 calls the specified callback for each object +// in the []int32. +// +// Panics if the object is the wrong type. +func (v *Value) EachInt32(callback func(int, int32) bool) *Value { + for index, val := range v.MustInt32Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereInt32 uses the specified decider function to select items +// from the []int32. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereInt32(decider func(int, int32) bool) *Value { + var selected []int32 + v.EachInt32(func(index int, val int32) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupInt32 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]int32. +func (v *Value) GroupInt32(grouper func(int, int32) string) *Value { + groups := make(map[string][]int32) + v.EachInt32(func(index int, val int32) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]int32, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceInt32 uses the specified function to replace each int32s +// by iterating each item. The data in the returned result will be a +// []int32 containing the replaced items. +func (v *Value) ReplaceInt32(replacer func(int, int32) int32) *Value { + arr := v.MustInt32Slice() + replaced := make([]int32, len(arr)) + v.EachInt32(func(index int, val int32) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectInt32 uses the specified collector function to collect a value +// for each of the int32s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectInt32(collector func(int, int32) interface{}) *Value { + arr := v.MustInt32Slice() + collected := make([]interface{}, len(arr)) + v.EachInt32(func(index int, val int32) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Int64 (int64 and []int64) +*/ + +// Int64 gets the value as a int64, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Int64(optionalDefault ...int64) int64 { + if s, ok := v.data.(int64); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustInt64 gets the value as a int64. +// +// Panics if the object is not a int64. +func (v *Value) MustInt64() int64 { + return v.data.(int64) +} + +// Int64Slice gets the value as a []int64, returns the optionalDefault +// value or nil if the value is not a []int64. +func (v *Value) Int64Slice(optionalDefault ...[]int64) []int64 { + if s, ok := v.data.([]int64); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustInt64Slice gets the value as a []int64. +// +// Panics if the object is not a []int64. +func (v *Value) MustInt64Slice() []int64 { + return v.data.([]int64) +} + +// IsInt64 gets whether the object contained is a int64 or not. +func (v *Value) IsInt64() bool { + _, ok := v.data.(int64) + return ok +} + +// IsInt64Slice gets whether the object contained is a []int64 or not. +func (v *Value) IsInt64Slice() bool { + _, ok := v.data.([]int64) + return ok +} + +// EachInt64 calls the specified callback for each object +// in the []int64. +// +// Panics if the object is the wrong type. +func (v *Value) EachInt64(callback func(int, int64) bool) *Value { + for index, val := range v.MustInt64Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereInt64 uses the specified decider function to select items +// from the []int64. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereInt64(decider func(int, int64) bool) *Value { + var selected []int64 + v.EachInt64(func(index int, val int64) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupInt64 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]int64. +func (v *Value) GroupInt64(grouper func(int, int64) string) *Value { + groups := make(map[string][]int64) + v.EachInt64(func(index int, val int64) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]int64, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceInt64 uses the specified function to replace each int64s +// by iterating each item. The data in the returned result will be a +// []int64 containing the replaced items. +func (v *Value) ReplaceInt64(replacer func(int, int64) int64) *Value { + arr := v.MustInt64Slice() + replaced := make([]int64, len(arr)) + v.EachInt64(func(index int, val int64) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectInt64 uses the specified collector function to collect a value +// for each of the int64s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectInt64(collector func(int, int64) interface{}) *Value { + arr := v.MustInt64Slice() + collected := make([]interface{}, len(arr)) + v.EachInt64(func(index int, val int64) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Uint (uint and []uint) +*/ + +// Uint gets the value as a uint, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Uint(optionalDefault ...uint) uint { + if s, ok := v.data.(uint); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustUint gets the value as a uint. +// +// Panics if the object is not a uint. +func (v *Value) MustUint() uint { + return v.data.(uint) +} + +// UintSlice gets the value as a []uint, returns the optionalDefault +// value or nil if the value is not a []uint. +func (v *Value) UintSlice(optionalDefault ...[]uint) []uint { + if s, ok := v.data.([]uint); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustUintSlice gets the value as a []uint. +// +// Panics if the object is not a []uint. +func (v *Value) MustUintSlice() []uint { + return v.data.([]uint) +} + +// IsUint gets whether the object contained is a uint or not. +func (v *Value) IsUint() bool { + _, ok := v.data.(uint) + return ok +} + +// IsUintSlice gets whether the object contained is a []uint or not. +func (v *Value) IsUintSlice() bool { + _, ok := v.data.([]uint) + return ok +} + +// EachUint calls the specified callback for each object +// in the []uint. +// +// Panics if the object is the wrong type. +func (v *Value) EachUint(callback func(int, uint) bool) *Value { + for index, val := range v.MustUintSlice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereUint uses the specified decider function to select items +// from the []uint. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereUint(decider func(int, uint) bool) *Value { + var selected []uint + v.EachUint(func(index int, val uint) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupUint uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]uint. +func (v *Value) GroupUint(grouper func(int, uint) string) *Value { + groups := make(map[string][]uint) + v.EachUint(func(index int, val uint) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]uint, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceUint uses the specified function to replace each uints +// by iterating each item. The data in the returned result will be a +// []uint containing the replaced items. +func (v *Value) ReplaceUint(replacer func(int, uint) uint) *Value { + arr := v.MustUintSlice() + replaced := make([]uint, len(arr)) + v.EachUint(func(index int, val uint) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectUint uses the specified collector function to collect a value +// for each of the uints in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectUint(collector func(int, uint) interface{}) *Value { + arr := v.MustUintSlice() + collected := make([]interface{}, len(arr)) + v.EachUint(func(index int, val uint) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Uint8 (uint8 and []uint8) +*/ + +// Uint8 gets the value as a uint8, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Uint8(optionalDefault ...uint8) uint8 { + if s, ok := v.data.(uint8); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustUint8 gets the value as a uint8. +// +// Panics if the object is not a uint8. +func (v *Value) MustUint8() uint8 { + return v.data.(uint8) +} + +// Uint8Slice gets the value as a []uint8, returns the optionalDefault +// value or nil if the value is not a []uint8. +func (v *Value) Uint8Slice(optionalDefault ...[]uint8) []uint8 { + if s, ok := v.data.([]uint8); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustUint8Slice gets the value as a []uint8. +// +// Panics if the object is not a []uint8. +func (v *Value) MustUint8Slice() []uint8 { + return v.data.([]uint8) +} + +// IsUint8 gets whether the object contained is a uint8 or not. +func (v *Value) IsUint8() bool { + _, ok := v.data.(uint8) + return ok +} + +// IsUint8Slice gets whether the object contained is a []uint8 or not. +func (v *Value) IsUint8Slice() bool { + _, ok := v.data.([]uint8) + return ok +} + +// EachUint8 calls the specified callback for each object +// in the []uint8. +// +// Panics if the object is the wrong type. +func (v *Value) EachUint8(callback func(int, uint8) bool) *Value { + for index, val := range v.MustUint8Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereUint8 uses the specified decider function to select items +// from the []uint8. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereUint8(decider func(int, uint8) bool) *Value { + var selected []uint8 + v.EachUint8(func(index int, val uint8) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupUint8 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]uint8. +func (v *Value) GroupUint8(grouper func(int, uint8) string) *Value { + groups := make(map[string][]uint8) + v.EachUint8(func(index int, val uint8) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]uint8, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceUint8 uses the specified function to replace each uint8s +// by iterating each item. The data in the returned result will be a +// []uint8 containing the replaced items. +func (v *Value) ReplaceUint8(replacer func(int, uint8) uint8) *Value { + arr := v.MustUint8Slice() + replaced := make([]uint8, len(arr)) + v.EachUint8(func(index int, val uint8) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectUint8 uses the specified collector function to collect a value +// for each of the uint8s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectUint8(collector func(int, uint8) interface{}) *Value { + arr := v.MustUint8Slice() + collected := make([]interface{}, len(arr)) + v.EachUint8(func(index int, val uint8) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Uint16 (uint16 and []uint16) +*/ + +// Uint16 gets the value as a uint16, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Uint16(optionalDefault ...uint16) uint16 { + if s, ok := v.data.(uint16); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustUint16 gets the value as a uint16. +// +// Panics if the object is not a uint16. +func (v *Value) MustUint16() uint16 { + return v.data.(uint16) +} + +// Uint16Slice gets the value as a []uint16, returns the optionalDefault +// value or nil if the value is not a []uint16. +func (v *Value) Uint16Slice(optionalDefault ...[]uint16) []uint16 { + if s, ok := v.data.([]uint16); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustUint16Slice gets the value as a []uint16. +// +// Panics if the object is not a []uint16. +func (v *Value) MustUint16Slice() []uint16 { + return v.data.([]uint16) +} + +// IsUint16 gets whether the object contained is a uint16 or not. +func (v *Value) IsUint16() bool { + _, ok := v.data.(uint16) + return ok +} + +// IsUint16Slice gets whether the object contained is a []uint16 or not. +func (v *Value) IsUint16Slice() bool { + _, ok := v.data.([]uint16) + return ok +} + +// EachUint16 calls the specified callback for each object +// in the []uint16. +// +// Panics if the object is the wrong type. +func (v *Value) EachUint16(callback func(int, uint16) bool) *Value { + for index, val := range v.MustUint16Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereUint16 uses the specified decider function to select items +// from the []uint16. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereUint16(decider func(int, uint16) bool) *Value { + var selected []uint16 + v.EachUint16(func(index int, val uint16) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupUint16 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]uint16. +func (v *Value) GroupUint16(grouper func(int, uint16) string) *Value { + groups := make(map[string][]uint16) + v.EachUint16(func(index int, val uint16) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]uint16, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceUint16 uses the specified function to replace each uint16s +// by iterating each item. The data in the returned result will be a +// []uint16 containing the replaced items. +func (v *Value) ReplaceUint16(replacer func(int, uint16) uint16) *Value { + arr := v.MustUint16Slice() + replaced := make([]uint16, len(arr)) + v.EachUint16(func(index int, val uint16) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectUint16 uses the specified collector function to collect a value +// for each of the uint16s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectUint16(collector func(int, uint16) interface{}) *Value { + arr := v.MustUint16Slice() + collected := make([]interface{}, len(arr)) + v.EachUint16(func(index int, val uint16) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Uint32 (uint32 and []uint32) +*/ + +// Uint32 gets the value as a uint32, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Uint32(optionalDefault ...uint32) uint32 { + if s, ok := v.data.(uint32); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustUint32 gets the value as a uint32. +// +// Panics if the object is not a uint32. +func (v *Value) MustUint32() uint32 { + return v.data.(uint32) +} + +// Uint32Slice gets the value as a []uint32, returns the optionalDefault +// value or nil if the value is not a []uint32. +func (v *Value) Uint32Slice(optionalDefault ...[]uint32) []uint32 { + if s, ok := v.data.([]uint32); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustUint32Slice gets the value as a []uint32. +// +// Panics if the object is not a []uint32. +func (v *Value) MustUint32Slice() []uint32 { + return v.data.([]uint32) +} + +// IsUint32 gets whether the object contained is a uint32 or not. +func (v *Value) IsUint32() bool { + _, ok := v.data.(uint32) + return ok +} + +// IsUint32Slice gets whether the object contained is a []uint32 or not. +func (v *Value) IsUint32Slice() bool { + _, ok := v.data.([]uint32) + return ok +} + +// EachUint32 calls the specified callback for each object +// in the []uint32. +// +// Panics if the object is the wrong type. +func (v *Value) EachUint32(callback func(int, uint32) bool) *Value { + for index, val := range v.MustUint32Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereUint32 uses the specified decider function to select items +// from the []uint32. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereUint32(decider func(int, uint32) bool) *Value { + var selected []uint32 + v.EachUint32(func(index int, val uint32) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupUint32 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]uint32. +func (v *Value) GroupUint32(grouper func(int, uint32) string) *Value { + groups := make(map[string][]uint32) + v.EachUint32(func(index int, val uint32) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]uint32, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceUint32 uses the specified function to replace each uint32s +// by iterating each item. The data in the returned result will be a +// []uint32 containing the replaced items. +func (v *Value) ReplaceUint32(replacer func(int, uint32) uint32) *Value { + arr := v.MustUint32Slice() + replaced := make([]uint32, len(arr)) + v.EachUint32(func(index int, val uint32) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectUint32 uses the specified collector function to collect a value +// for each of the uint32s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectUint32(collector func(int, uint32) interface{}) *Value { + arr := v.MustUint32Slice() + collected := make([]interface{}, len(arr)) + v.EachUint32(func(index int, val uint32) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Uint64 (uint64 and []uint64) +*/ + +// Uint64 gets the value as a uint64, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Uint64(optionalDefault ...uint64) uint64 { + if s, ok := v.data.(uint64); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustUint64 gets the value as a uint64. +// +// Panics if the object is not a uint64. +func (v *Value) MustUint64() uint64 { + return v.data.(uint64) +} + +// Uint64Slice gets the value as a []uint64, returns the optionalDefault +// value or nil if the value is not a []uint64. +func (v *Value) Uint64Slice(optionalDefault ...[]uint64) []uint64 { + if s, ok := v.data.([]uint64); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustUint64Slice gets the value as a []uint64. +// +// Panics if the object is not a []uint64. +func (v *Value) MustUint64Slice() []uint64 { + return v.data.([]uint64) +} + +// IsUint64 gets whether the object contained is a uint64 or not. +func (v *Value) IsUint64() bool { + _, ok := v.data.(uint64) + return ok +} + +// IsUint64Slice gets whether the object contained is a []uint64 or not. +func (v *Value) IsUint64Slice() bool { + _, ok := v.data.([]uint64) + return ok +} + +// EachUint64 calls the specified callback for each object +// in the []uint64. +// +// Panics if the object is the wrong type. +func (v *Value) EachUint64(callback func(int, uint64) bool) *Value { + for index, val := range v.MustUint64Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereUint64 uses the specified decider function to select items +// from the []uint64. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereUint64(decider func(int, uint64) bool) *Value { + var selected []uint64 + v.EachUint64(func(index int, val uint64) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupUint64 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]uint64. +func (v *Value) GroupUint64(grouper func(int, uint64) string) *Value { + groups := make(map[string][]uint64) + v.EachUint64(func(index int, val uint64) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]uint64, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceUint64 uses the specified function to replace each uint64s +// by iterating each item. The data in the returned result will be a +// []uint64 containing the replaced items. +func (v *Value) ReplaceUint64(replacer func(int, uint64) uint64) *Value { + arr := v.MustUint64Slice() + replaced := make([]uint64, len(arr)) + v.EachUint64(func(index int, val uint64) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectUint64 uses the specified collector function to collect a value +// for each of the uint64s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectUint64(collector func(int, uint64) interface{}) *Value { + arr := v.MustUint64Slice() + collected := make([]interface{}, len(arr)) + v.EachUint64(func(index int, val uint64) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Uintptr (uintptr and []uintptr) +*/ + +// Uintptr gets the value as a uintptr, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Uintptr(optionalDefault ...uintptr) uintptr { + if s, ok := v.data.(uintptr); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustUintptr gets the value as a uintptr. +// +// Panics if the object is not a uintptr. +func (v *Value) MustUintptr() uintptr { + return v.data.(uintptr) +} + +// UintptrSlice gets the value as a []uintptr, returns the optionalDefault +// value or nil if the value is not a []uintptr. +func (v *Value) UintptrSlice(optionalDefault ...[]uintptr) []uintptr { + if s, ok := v.data.([]uintptr); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustUintptrSlice gets the value as a []uintptr. +// +// Panics if the object is not a []uintptr. +func (v *Value) MustUintptrSlice() []uintptr { + return v.data.([]uintptr) +} + +// IsUintptr gets whether the object contained is a uintptr or not. +func (v *Value) IsUintptr() bool { + _, ok := v.data.(uintptr) + return ok +} + +// IsUintptrSlice gets whether the object contained is a []uintptr or not. +func (v *Value) IsUintptrSlice() bool { + _, ok := v.data.([]uintptr) + return ok +} + +// EachUintptr calls the specified callback for each object +// in the []uintptr. +// +// Panics if the object is the wrong type. +func (v *Value) EachUintptr(callback func(int, uintptr) bool) *Value { + for index, val := range v.MustUintptrSlice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereUintptr uses the specified decider function to select items +// from the []uintptr. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereUintptr(decider func(int, uintptr) bool) *Value { + var selected []uintptr + v.EachUintptr(func(index int, val uintptr) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupUintptr uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]uintptr. +func (v *Value) GroupUintptr(grouper func(int, uintptr) string) *Value { + groups := make(map[string][]uintptr) + v.EachUintptr(func(index int, val uintptr) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]uintptr, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceUintptr uses the specified function to replace each uintptrs +// by iterating each item. The data in the returned result will be a +// []uintptr containing the replaced items. +func (v *Value) ReplaceUintptr(replacer func(int, uintptr) uintptr) *Value { + arr := v.MustUintptrSlice() + replaced := make([]uintptr, len(arr)) + v.EachUintptr(func(index int, val uintptr) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectUintptr uses the specified collector function to collect a value +// for each of the uintptrs in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectUintptr(collector func(int, uintptr) interface{}) *Value { + arr := v.MustUintptrSlice() + collected := make([]interface{}, len(arr)) + v.EachUintptr(func(index int, val uintptr) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Float32 (float32 and []float32) +*/ + +// Float32 gets the value as a float32, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Float32(optionalDefault ...float32) float32 { + if s, ok := v.data.(float32); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustFloat32 gets the value as a float32. +// +// Panics if the object is not a float32. +func (v *Value) MustFloat32() float32 { + return v.data.(float32) +} + +// Float32Slice gets the value as a []float32, returns the optionalDefault +// value or nil if the value is not a []float32. +func (v *Value) Float32Slice(optionalDefault ...[]float32) []float32 { + if s, ok := v.data.([]float32); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustFloat32Slice gets the value as a []float32. +// +// Panics if the object is not a []float32. +func (v *Value) MustFloat32Slice() []float32 { + return v.data.([]float32) +} + +// IsFloat32 gets whether the object contained is a float32 or not. +func (v *Value) IsFloat32() bool { + _, ok := v.data.(float32) + return ok +} + +// IsFloat32Slice gets whether the object contained is a []float32 or not. +func (v *Value) IsFloat32Slice() bool { + _, ok := v.data.([]float32) + return ok +} + +// EachFloat32 calls the specified callback for each object +// in the []float32. +// +// Panics if the object is the wrong type. +func (v *Value) EachFloat32(callback func(int, float32) bool) *Value { + for index, val := range v.MustFloat32Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereFloat32 uses the specified decider function to select items +// from the []float32. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereFloat32(decider func(int, float32) bool) *Value { + var selected []float32 + v.EachFloat32(func(index int, val float32) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupFloat32 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]float32. +func (v *Value) GroupFloat32(grouper func(int, float32) string) *Value { + groups := make(map[string][]float32) + v.EachFloat32(func(index int, val float32) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]float32, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceFloat32 uses the specified function to replace each float32s +// by iterating each item. The data in the returned result will be a +// []float32 containing the replaced items. +func (v *Value) ReplaceFloat32(replacer func(int, float32) float32) *Value { + arr := v.MustFloat32Slice() + replaced := make([]float32, len(arr)) + v.EachFloat32(func(index int, val float32) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectFloat32 uses the specified collector function to collect a value +// for each of the float32s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectFloat32(collector func(int, float32) interface{}) *Value { + arr := v.MustFloat32Slice() + collected := make([]interface{}, len(arr)) + v.EachFloat32(func(index int, val float32) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Float64 (float64 and []float64) +*/ + +// Float64 gets the value as a float64, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Float64(optionalDefault ...float64) float64 { + if s, ok := v.data.(float64); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustFloat64 gets the value as a float64. +// +// Panics if the object is not a float64. +func (v *Value) MustFloat64() float64 { + return v.data.(float64) +} + +// Float64Slice gets the value as a []float64, returns the optionalDefault +// value or nil if the value is not a []float64. +func (v *Value) Float64Slice(optionalDefault ...[]float64) []float64 { + if s, ok := v.data.([]float64); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustFloat64Slice gets the value as a []float64. +// +// Panics if the object is not a []float64. +func (v *Value) MustFloat64Slice() []float64 { + return v.data.([]float64) +} + +// IsFloat64 gets whether the object contained is a float64 or not. +func (v *Value) IsFloat64() bool { + _, ok := v.data.(float64) + return ok +} + +// IsFloat64Slice gets whether the object contained is a []float64 or not. +func (v *Value) IsFloat64Slice() bool { + _, ok := v.data.([]float64) + return ok +} + +// EachFloat64 calls the specified callback for each object +// in the []float64. +// +// Panics if the object is the wrong type. +func (v *Value) EachFloat64(callback func(int, float64) bool) *Value { + for index, val := range v.MustFloat64Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereFloat64 uses the specified decider function to select items +// from the []float64. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereFloat64(decider func(int, float64) bool) *Value { + var selected []float64 + v.EachFloat64(func(index int, val float64) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupFloat64 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]float64. +func (v *Value) GroupFloat64(grouper func(int, float64) string) *Value { + groups := make(map[string][]float64) + v.EachFloat64(func(index int, val float64) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]float64, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceFloat64 uses the specified function to replace each float64s +// by iterating each item. The data in the returned result will be a +// []float64 containing the replaced items. +func (v *Value) ReplaceFloat64(replacer func(int, float64) float64) *Value { + arr := v.MustFloat64Slice() + replaced := make([]float64, len(arr)) + v.EachFloat64(func(index int, val float64) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectFloat64 uses the specified collector function to collect a value +// for each of the float64s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectFloat64(collector func(int, float64) interface{}) *Value { + arr := v.MustFloat64Slice() + collected := make([]interface{}, len(arr)) + v.EachFloat64(func(index int, val float64) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Complex64 (complex64 and []complex64) +*/ + +// Complex64 gets the value as a complex64, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Complex64(optionalDefault ...complex64) complex64 { + if s, ok := v.data.(complex64); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustComplex64 gets the value as a complex64. +// +// Panics if the object is not a complex64. +func (v *Value) MustComplex64() complex64 { + return v.data.(complex64) +} + +// Complex64Slice gets the value as a []complex64, returns the optionalDefault +// value or nil if the value is not a []complex64. +func (v *Value) Complex64Slice(optionalDefault ...[]complex64) []complex64 { + if s, ok := v.data.([]complex64); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustComplex64Slice gets the value as a []complex64. +// +// Panics if the object is not a []complex64. +func (v *Value) MustComplex64Slice() []complex64 { + return v.data.([]complex64) +} + +// IsComplex64 gets whether the object contained is a complex64 or not. +func (v *Value) IsComplex64() bool { + _, ok := v.data.(complex64) + return ok +} + +// IsComplex64Slice gets whether the object contained is a []complex64 or not. +func (v *Value) IsComplex64Slice() bool { + _, ok := v.data.([]complex64) + return ok +} + +// EachComplex64 calls the specified callback for each object +// in the []complex64. +// +// Panics if the object is the wrong type. +func (v *Value) EachComplex64(callback func(int, complex64) bool) *Value { + for index, val := range v.MustComplex64Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereComplex64 uses the specified decider function to select items +// from the []complex64. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereComplex64(decider func(int, complex64) bool) *Value { + var selected []complex64 + v.EachComplex64(func(index int, val complex64) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupComplex64 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]complex64. +func (v *Value) GroupComplex64(grouper func(int, complex64) string) *Value { + groups := make(map[string][]complex64) + v.EachComplex64(func(index int, val complex64) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]complex64, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceComplex64 uses the specified function to replace each complex64s +// by iterating each item. The data in the returned result will be a +// []complex64 containing the replaced items. +func (v *Value) ReplaceComplex64(replacer func(int, complex64) complex64) *Value { + arr := v.MustComplex64Slice() + replaced := make([]complex64, len(arr)) + v.EachComplex64(func(index int, val complex64) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectComplex64 uses the specified collector function to collect a value +// for each of the complex64s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectComplex64(collector func(int, complex64) interface{}) *Value { + arr := v.MustComplex64Slice() + collected := make([]interface{}, len(arr)) + v.EachComplex64(func(index int, val complex64) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Complex128 (complex128 and []complex128) +*/ + +// Complex128 gets the value as a complex128, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Complex128(optionalDefault ...complex128) complex128 { + if s, ok := v.data.(complex128); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustComplex128 gets the value as a complex128. +// +// Panics if the object is not a complex128. +func (v *Value) MustComplex128() complex128 { + return v.data.(complex128) +} + +// Complex128Slice gets the value as a []complex128, returns the optionalDefault +// value or nil if the value is not a []complex128. +func (v *Value) Complex128Slice(optionalDefault ...[]complex128) []complex128 { + if s, ok := v.data.([]complex128); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustComplex128Slice gets the value as a []complex128. +// +// Panics if the object is not a []complex128. +func (v *Value) MustComplex128Slice() []complex128 { + return v.data.([]complex128) +} + +// IsComplex128 gets whether the object contained is a complex128 or not. +func (v *Value) IsComplex128() bool { + _, ok := v.data.(complex128) + return ok +} + +// IsComplex128Slice gets whether the object contained is a []complex128 or not. +func (v *Value) IsComplex128Slice() bool { + _, ok := v.data.([]complex128) + return ok +} + +// EachComplex128 calls the specified callback for each object +// in the []complex128. +// +// Panics if the object is the wrong type. +func (v *Value) EachComplex128(callback func(int, complex128) bool) *Value { + for index, val := range v.MustComplex128Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereComplex128 uses the specified decider function to select items +// from the []complex128. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereComplex128(decider func(int, complex128) bool) *Value { + var selected []complex128 + v.EachComplex128(func(index int, val complex128) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupComplex128 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]complex128. +func (v *Value) GroupComplex128(grouper func(int, complex128) string) *Value { + groups := make(map[string][]complex128) + v.EachComplex128(func(index int, val complex128) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]complex128, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceComplex128 uses the specified function to replace each complex128s +// by iterating each item. The data in the returned result will be a +// []complex128 containing the replaced items. +func (v *Value) ReplaceComplex128(replacer func(int, complex128) complex128) *Value { + arr := v.MustComplex128Slice() + replaced := make([]complex128, len(arr)) + v.EachComplex128(func(index int, val complex128) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectComplex128 uses the specified collector function to collect a value +// for each of the complex128s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectComplex128(collector func(int, complex128) interface{}) *Value { + arr := v.MustComplex128Slice() + collected := make([]interface{}, len(arr)) + v.EachComplex128(func(index int, val complex128) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} diff --git a/vendor/github.com/stretchr/objx/type_specific_codegen_test.go b/vendor/github.com/stretchr/objx/type_specific_codegen_test.go new file mode 100644 index 0000000..72fa8c8 --- /dev/null +++ b/vendor/github.com/stretchr/objx/type_specific_codegen_test.go @@ -0,0 +1,2187 @@ +package objx_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/objx" + "github.com/stretchr/testify/assert" +) + +/* + Tests for Inter (interface{} and []interface{}) +*/ +func TestInter(t *testing.T) { + val := interface{}("something") + m := objx.Map{"value": val, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Inter()) + assert.Equal(t, val, m.Get("value").MustInter()) + assert.Equal(t, interface{}(nil), m.Get("nothing").Inter()) + assert.Equal(t, val, m.Get("nothing").Inter("something")) + assert.Panics(t, func() { + m.Get("age").MustInter() + }) +} + +func TestInterSlice(t *testing.T) { + val := interface{}("something") + m := objx.Map{"value": []interface{}{val}, "nothing": nil} + + assert.Equal(t, val, m.Get("value").InterSlice()[0]) + assert.Equal(t, val, m.Get("value").MustInterSlice()[0]) + assert.Equal(t, []interface{}(nil), m.Get("nothing").InterSlice()) + assert.Equal(t, val, m.Get("nothing").InterSlice([]interface{}{interface{}("something")})[0]) + assert.Panics(t, func() { + m.Get("nothing").MustInterSlice() + }) +} + +func TestIsInter(t *testing.T) { + m := objx.Map{"data": interface{}("something")} + + assert.True(t, m.Get("data").IsInter()) +} + +func TestIsInterSlice(t *testing.T) { + m := objx.Map{"data": []interface{}{interface{}("something")}} + + assert.True(t, m.Get("data").IsInterSlice()) +} + +func TestEachInter(t *testing.T) { + m := objx.Map{"data": []interface{}{interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something")}} + count := 0 + replacedVals := make([]interface{}, 0) + assert.Equal(t, m.Get("data"), m.Get("data").EachInter(func(i int, val interface{}) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + assert.Equal(t, count, 3) + assert.Equal(t, replacedVals[0], m.Get("data").MustInterSlice()[0]) + assert.Equal(t, replacedVals[1], m.Get("data").MustInterSlice()[1]) + assert.Equal(t, replacedVals[2], m.Get("data").MustInterSlice()[2]) +} + +func TestWhereInter(t *testing.T) { + m := objx.Map{"data": []interface{}{interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something")}} + + selected := m.Get("data").WhereInter(func(i int, val interface{}) bool { + return i%2 == 0 + }).MustInterSlice() + + assert.Equal(t, 3, len(selected)) +} + +func TestGroupInter(t *testing.T) { + m := objx.Map{"data": []interface{}{interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something")}} + + grouped := m.Get("data").GroupInter(func(i int, val interface{}) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][]interface{}) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 3, len(grouped["false"])) +} + +func TestReplaceInter(t *testing.T) { + m := objx.Map{"data": []interface{}{interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something")}} + rawArr := m.Get("data").MustInterSlice() + + replaced := m.Get("data").ReplaceInter(func(index int, val interface{}) interface{} { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustInterSlice() + + if assert.Equal(t, 6, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[5]) + assert.Equal(t, replacedArr[5], rawArr[0]) + } +} + +func TestCollectInter(t *testing.T) { + m := objx.Map{"data": []interface{}{interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something"), interface{}("something")}} + + collected := m.Get("data").CollectInter(func(index int, val interface{}) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 6, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + assert.Equal(t, collectedArr[5], 5) + } +} + +/* + Tests for Bool (bool and []bool) +*/ +func TestBool(t *testing.T) { + val := bool(true) + m := objx.Map{"value": val, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Bool()) + assert.Equal(t, val, m.Get("value").MustBool()) + assert.Equal(t, bool(false), m.Get("nothing").Bool()) + assert.Equal(t, val, m.Get("nothing").Bool(true)) + assert.Panics(t, func() { + m.Get("age").MustBool() + }) +} + +func TestBoolSlice(t *testing.T) { + val := bool(true) + m := objx.Map{"value": []bool{val}, "nothing": nil} + + assert.Equal(t, val, m.Get("value").BoolSlice()[0]) + assert.Equal(t, val, m.Get("value").MustBoolSlice()[0]) + assert.Equal(t, []bool(nil), m.Get("nothing").BoolSlice()) + assert.Equal(t, val, m.Get("nothing").BoolSlice([]bool{bool(true)})[0]) + assert.Panics(t, func() { + m.Get("nothing").MustBoolSlice() + }) +} + +func TestIsBool(t *testing.T) { + m := objx.Map{"data": bool(true)} + + assert.True(t, m.Get("data").IsBool()) +} + +func TestIsBoolSlice(t *testing.T) { + m := objx.Map{"data": []bool{bool(true)}} + + assert.True(t, m.Get("data").IsBoolSlice()) +} + +func TestEachBool(t *testing.T) { + m := objx.Map{"data": []bool{bool(true), bool(true), bool(true), bool(true), bool(true)}} + count := 0 + replacedVals := make([]bool, 0) + assert.Equal(t, m.Get("data"), m.Get("data").EachBool(func(i int, val bool) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + assert.Equal(t, count, 3) + assert.Equal(t, replacedVals[0], m.Get("data").MustBoolSlice()[0]) + assert.Equal(t, replacedVals[1], m.Get("data").MustBoolSlice()[1]) + assert.Equal(t, replacedVals[2], m.Get("data").MustBoolSlice()[2]) +} + +func TestWhereBool(t *testing.T) { + m := objx.Map{"data": []bool{bool(true), bool(true), bool(true), bool(true), bool(true), bool(true)}} + + selected := m.Get("data").WhereBool(func(i int, val bool) bool { + return i%2 == 0 + }).MustBoolSlice() + + assert.Equal(t, 3, len(selected)) +} + +func TestGroupBool(t *testing.T) { + m := objx.Map{"data": []bool{bool(true), bool(true), bool(true), bool(true), bool(true), bool(true)}} + + grouped := m.Get("data").GroupBool(func(i int, val bool) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][]bool) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 3, len(grouped["false"])) +} + +func TestReplaceBool(t *testing.T) { + m := objx.Map{"data": []bool{bool(true), bool(true), bool(true), bool(true), bool(true), bool(true)}} + rawArr := m.Get("data").MustBoolSlice() + + replaced := m.Get("data").ReplaceBool(func(index int, val bool) bool { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustBoolSlice() + + if assert.Equal(t, 6, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[5]) + assert.Equal(t, replacedArr[5], rawArr[0]) + } +} + +func TestCollectBool(t *testing.T) { + m := objx.Map{"data": []bool{bool(true), bool(true), bool(true), bool(true), bool(true), bool(true)}} + + collected := m.Get("data").CollectBool(func(index int, val bool) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 6, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + assert.Equal(t, collectedArr[5], 5) + } +} + +/* + Tests for Str (string and []string) +*/ +func TestStr(t *testing.T) { + val := string("hello") + m := objx.Map{"value": val, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Str()) + assert.Equal(t, val, m.Get("value").MustStr()) + assert.Equal(t, string(""), m.Get("nothing").Str()) + assert.Equal(t, val, m.Get("nothing").Str("hello")) + assert.Panics(t, func() { + m.Get("age").MustStr() + }) +} + +func TestStrSlice(t *testing.T) { + val := string("hello") + m := objx.Map{"value": []string{val}, "nothing": nil} + + assert.Equal(t, val, m.Get("value").StrSlice()[0]) + assert.Equal(t, val, m.Get("value").MustStrSlice()[0]) + assert.Equal(t, []string(nil), m.Get("nothing").StrSlice()) + assert.Equal(t, val, m.Get("nothing").StrSlice([]string{string("hello")})[0]) + assert.Panics(t, func() { + m.Get("nothing").MustStrSlice() + }) +} + +func TestIsStr(t *testing.T) { + m := objx.Map{"data": string("hello")} + + assert.True(t, m.Get("data").IsStr()) +} + +func TestIsStrSlice(t *testing.T) { + m := objx.Map{"data": []string{string("hello")}} + + assert.True(t, m.Get("data").IsStrSlice()) +} + +func TestEachStr(t *testing.T) { + m := objx.Map{"data": []string{string("hello"), string("hello"), string("hello"), string("hello"), string("hello")}} + count := 0 + replacedVals := make([]string, 0) + assert.Equal(t, m.Get("data"), m.Get("data").EachStr(func(i int, val string) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + assert.Equal(t, count, 3) + assert.Equal(t, replacedVals[0], m.Get("data").MustStrSlice()[0]) + assert.Equal(t, replacedVals[1], m.Get("data").MustStrSlice()[1]) + assert.Equal(t, replacedVals[2], m.Get("data").MustStrSlice()[2]) +} + +func TestWhereStr(t *testing.T) { + m := objx.Map{"data": []string{string("hello"), string("hello"), string("hello"), string("hello"), string("hello"), string("hello")}} + + selected := m.Get("data").WhereStr(func(i int, val string) bool { + return i%2 == 0 + }).MustStrSlice() + + assert.Equal(t, 3, len(selected)) +} + +func TestGroupStr(t *testing.T) { + m := objx.Map{"data": []string{string("hello"), string("hello"), string("hello"), string("hello"), string("hello"), string("hello")}} + + grouped := m.Get("data").GroupStr(func(i int, val string) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][]string) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 3, len(grouped["false"])) +} + +func TestReplaceStr(t *testing.T) { + m := objx.Map{"data": []string{string("hello"), string("hello"), string("hello"), string("hello"), string("hello"), string("hello")}} + rawArr := m.Get("data").MustStrSlice() + + replaced := m.Get("data").ReplaceStr(func(index int, val string) string { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustStrSlice() + + if assert.Equal(t, 6, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[5]) + assert.Equal(t, replacedArr[5], rawArr[0]) + } +} + +func TestCollectStr(t *testing.T) { + m := objx.Map{"data": []string{string("hello"), string("hello"), string("hello"), string("hello"), string("hello"), string("hello")}} + + collected := m.Get("data").CollectStr(func(index int, val string) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 6, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + assert.Equal(t, collectedArr[5], 5) + } +} + +/* + Tests for Int (int and []int) +*/ +func TestInt(t *testing.T) { + val := int(1) + m := objx.Map{"value": val, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Int()) + assert.Equal(t, val, m.Get("value").MustInt()) + assert.Equal(t, int(0), m.Get("nothing").Int()) + assert.Equal(t, val, m.Get("nothing").Int(1)) + assert.Panics(t, func() { + m.Get("age").MustInt() + }) +} + +func TestIntSlice(t *testing.T) { + val := int(1) + m := objx.Map{"value": []int{val}, "nothing": nil} + + assert.Equal(t, val, m.Get("value").IntSlice()[0]) + assert.Equal(t, val, m.Get("value").MustIntSlice()[0]) + assert.Equal(t, []int(nil), m.Get("nothing").IntSlice()) + assert.Equal(t, val, m.Get("nothing").IntSlice([]int{int(1)})[0]) + assert.Panics(t, func() { + m.Get("nothing").MustIntSlice() + }) +} + +func TestIsInt(t *testing.T) { + m := objx.Map{"data": int(1)} + + assert.True(t, m.Get("data").IsInt()) +} + +func TestIsIntSlice(t *testing.T) { + m := objx.Map{"data": []int{int(1)}} + + assert.True(t, m.Get("data").IsIntSlice()) +} + +func TestEachInt(t *testing.T) { + m := objx.Map{"data": []int{int(1), int(1), int(1), int(1), int(1)}} + count := 0 + replacedVals := make([]int, 0) + assert.Equal(t, m.Get("data"), m.Get("data").EachInt(func(i int, val int) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + assert.Equal(t, count, 3) + assert.Equal(t, replacedVals[0], m.Get("data").MustIntSlice()[0]) + assert.Equal(t, replacedVals[1], m.Get("data").MustIntSlice()[1]) + assert.Equal(t, replacedVals[2], m.Get("data").MustIntSlice()[2]) +} + +func TestWhereInt(t *testing.T) { + m := objx.Map{"data": []int{int(1), int(1), int(1), int(1), int(1), int(1)}} + + selected := m.Get("data").WhereInt(func(i int, val int) bool { + return i%2 == 0 + }).MustIntSlice() + + assert.Equal(t, 3, len(selected)) +} + +func TestGroupInt(t *testing.T) { + m := objx.Map{"data": []int{int(1), int(1), int(1), int(1), int(1), int(1)}} + + grouped := m.Get("data").GroupInt(func(i int, val int) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][]int) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 3, len(grouped["false"])) +} + +func TestReplaceInt(t *testing.T) { + m := objx.Map{"data": []int{int(1), int(1), int(1), int(1), int(1), int(1)}} + rawArr := m.Get("data").MustIntSlice() + + replaced := m.Get("data").ReplaceInt(func(index int, val int) int { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustIntSlice() + + if assert.Equal(t, 6, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[5]) + assert.Equal(t, replacedArr[5], rawArr[0]) + } +} + +func TestCollectInt(t *testing.T) { + m := objx.Map{"data": []int{int(1), int(1), int(1), int(1), int(1), int(1)}} + + collected := m.Get("data").CollectInt(func(index int, val int) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 6, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + assert.Equal(t, collectedArr[5], 5) + } +} + +/* + Tests for Int8 (int8 and []int8) +*/ +func TestInt8(t *testing.T) { + val := int8(1) + m := objx.Map{"value": val, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Int8()) + assert.Equal(t, val, m.Get("value").MustInt8()) + assert.Equal(t, int8(0), m.Get("nothing").Int8()) + assert.Equal(t, val, m.Get("nothing").Int8(1)) + assert.Panics(t, func() { + m.Get("age").MustInt8() + }) +} + +func TestInt8Slice(t *testing.T) { + val := int8(1) + m := objx.Map{"value": []int8{val}, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Int8Slice()[0]) + assert.Equal(t, val, m.Get("value").MustInt8Slice()[0]) + assert.Equal(t, []int8(nil), m.Get("nothing").Int8Slice()) + assert.Equal(t, val, m.Get("nothing").Int8Slice([]int8{int8(1)})[0]) + assert.Panics(t, func() { + m.Get("nothing").MustInt8Slice() + }) +} + +func TestIsInt8(t *testing.T) { + m := objx.Map{"data": int8(1)} + + assert.True(t, m.Get("data").IsInt8()) +} + +func TestIsInt8Slice(t *testing.T) { + m := objx.Map{"data": []int8{int8(1)}} + + assert.True(t, m.Get("data").IsInt8Slice()) +} + +func TestEachInt8(t *testing.T) { + m := objx.Map{"data": []int8{int8(1), int8(1), int8(1), int8(1), int8(1)}} + count := 0 + replacedVals := make([]int8, 0) + assert.Equal(t, m.Get("data"), m.Get("data").EachInt8(func(i int, val int8) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + assert.Equal(t, count, 3) + assert.Equal(t, replacedVals[0], m.Get("data").MustInt8Slice()[0]) + assert.Equal(t, replacedVals[1], m.Get("data").MustInt8Slice()[1]) + assert.Equal(t, replacedVals[2], m.Get("data").MustInt8Slice()[2]) +} + +func TestWhereInt8(t *testing.T) { + m := objx.Map{"data": []int8{int8(1), int8(1), int8(1), int8(1), int8(1), int8(1)}} + + selected := m.Get("data").WhereInt8(func(i int, val int8) bool { + return i%2 == 0 + }).MustInt8Slice() + + assert.Equal(t, 3, len(selected)) +} + +func TestGroupInt8(t *testing.T) { + m := objx.Map{"data": []int8{int8(1), int8(1), int8(1), int8(1), int8(1), int8(1)}} + + grouped := m.Get("data").GroupInt8(func(i int, val int8) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][]int8) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 3, len(grouped["false"])) +} + +func TestReplaceInt8(t *testing.T) { + m := objx.Map{"data": []int8{int8(1), int8(1), int8(1), int8(1), int8(1), int8(1)}} + rawArr := m.Get("data").MustInt8Slice() + + replaced := m.Get("data").ReplaceInt8(func(index int, val int8) int8 { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustInt8Slice() + + if assert.Equal(t, 6, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[5]) + assert.Equal(t, replacedArr[5], rawArr[0]) + } +} + +func TestCollectInt8(t *testing.T) { + m := objx.Map{"data": []int8{int8(1), int8(1), int8(1), int8(1), int8(1), int8(1)}} + + collected := m.Get("data").CollectInt8(func(index int, val int8) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 6, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + assert.Equal(t, collectedArr[5], 5) + } +} + +/* + Tests for Int16 (int16 and []int16) +*/ +func TestInt16(t *testing.T) { + val := int16(1) + m := objx.Map{"value": val, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Int16()) + assert.Equal(t, val, m.Get("value").MustInt16()) + assert.Equal(t, int16(0), m.Get("nothing").Int16()) + assert.Equal(t, val, m.Get("nothing").Int16(1)) + assert.Panics(t, func() { + m.Get("age").MustInt16() + }) +} + +func TestInt16Slice(t *testing.T) { + val := int16(1) + m := objx.Map{"value": []int16{val}, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Int16Slice()[0]) + assert.Equal(t, val, m.Get("value").MustInt16Slice()[0]) + assert.Equal(t, []int16(nil), m.Get("nothing").Int16Slice()) + assert.Equal(t, val, m.Get("nothing").Int16Slice([]int16{int16(1)})[0]) + assert.Panics(t, func() { + m.Get("nothing").MustInt16Slice() + }) +} + +func TestIsInt16(t *testing.T) { + m := objx.Map{"data": int16(1)} + + assert.True(t, m.Get("data").IsInt16()) +} + +func TestIsInt16Slice(t *testing.T) { + m := objx.Map{"data": []int16{int16(1)}} + + assert.True(t, m.Get("data").IsInt16Slice()) +} + +func TestEachInt16(t *testing.T) { + m := objx.Map{"data": []int16{int16(1), int16(1), int16(1), int16(1), int16(1)}} + count := 0 + replacedVals := make([]int16, 0) + assert.Equal(t, m.Get("data"), m.Get("data").EachInt16(func(i int, val int16) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + assert.Equal(t, count, 3) + assert.Equal(t, replacedVals[0], m.Get("data").MustInt16Slice()[0]) + assert.Equal(t, replacedVals[1], m.Get("data").MustInt16Slice()[1]) + assert.Equal(t, replacedVals[2], m.Get("data").MustInt16Slice()[2]) +} + +func TestWhereInt16(t *testing.T) { + m := objx.Map{"data": []int16{int16(1), int16(1), int16(1), int16(1), int16(1), int16(1)}} + + selected := m.Get("data").WhereInt16(func(i int, val int16) bool { + return i%2 == 0 + }).MustInt16Slice() + + assert.Equal(t, 3, len(selected)) +} + +func TestGroupInt16(t *testing.T) { + m := objx.Map{"data": []int16{int16(1), int16(1), int16(1), int16(1), int16(1), int16(1)}} + + grouped := m.Get("data").GroupInt16(func(i int, val int16) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][]int16) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 3, len(grouped["false"])) +} + +func TestReplaceInt16(t *testing.T) { + m := objx.Map{"data": []int16{int16(1), int16(1), int16(1), int16(1), int16(1), int16(1)}} + rawArr := m.Get("data").MustInt16Slice() + + replaced := m.Get("data").ReplaceInt16(func(index int, val int16) int16 { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustInt16Slice() + + if assert.Equal(t, 6, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[5]) + assert.Equal(t, replacedArr[5], rawArr[0]) + } +} + +func TestCollectInt16(t *testing.T) { + m := objx.Map{"data": []int16{int16(1), int16(1), int16(1), int16(1), int16(1), int16(1)}} + + collected := m.Get("data").CollectInt16(func(index int, val int16) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 6, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + assert.Equal(t, collectedArr[5], 5) + } +} + +/* + Tests for Int32 (int32 and []int32) +*/ +func TestInt32(t *testing.T) { + val := int32(1) + m := objx.Map{"value": val, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Int32()) + assert.Equal(t, val, m.Get("value").MustInt32()) + assert.Equal(t, int32(0), m.Get("nothing").Int32()) + assert.Equal(t, val, m.Get("nothing").Int32(1)) + assert.Panics(t, func() { + m.Get("age").MustInt32() + }) +} + +func TestInt32Slice(t *testing.T) { + val := int32(1) + m := objx.Map{"value": []int32{val}, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Int32Slice()[0]) + assert.Equal(t, val, m.Get("value").MustInt32Slice()[0]) + assert.Equal(t, []int32(nil), m.Get("nothing").Int32Slice()) + assert.Equal(t, val, m.Get("nothing").Int32Slice([]int32{int32(1)})[0]) + assert.Panics(t, func() { + m.Get("nothing").MustInt32Slice() + }) +} + +func TestIsInt32(t *testing.T) { + m := objx.Map{"data": int32(1)} + + assert.True(t, m.Get("data").IsInt32()) +} + +func TestIsInt32Slice(t *testing.T) { + m := objx.Map{"data": []int32{int32(1)}} + + assert.True(t, m.Get("data").IsInt32Slice()) +} + +func TestEachInt32(t *testing.T) { + m := objx.Map{"data": []int32{int32(1), int32(1), int32(1), int32(1), int32(1)}} + count := 0 + replacedVals := make([]int32, 0) + assert.Equal(t, m.Get("data"), m.Get("data").EachInt32(func(i int, val int32) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + assert.Equal(t, count, 3) + assert.Equal(t, replacedVals[0], m.Get("data").MustInt32Slice()[0]) + assert.Equal(t, replacedVals[1], m.Get("data").MustInt32Slice()[1]) + assert.Equal(t, replacedVals[2], m.Get("data").MustInt32Slice()[2]) +} + +func TestWhereInt32(t *testing.T) { + m := objx.Map{"data": []int32{int32(1), int32(1), int32(1), int32(1), int32(1), int32(1)}} + + selected := m.Get("data").WhereInt32(func(i int, val int32) bool { + return i%2 == 0 + }).MustInt32Slice() + + assert.Equal(t, 3, len(selected)) +} + +func TestGroupInt32(t *testing.T) { + m := objx.Map{"data": []int32{int32(1), int32(1), int32(1), int32(1), int32(1), int32(1)}} + + grouped := m.Get("data").GroupInt32(func(i int, val int32) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][]int32) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 3, len(grouped["false"])) +} + +func TestReplaceInt32(t *testing.T) { + m := objx.Map{"data": []int32{int32(1), int32(1), int32(1), int32(1), int32(1), int32(1)}} + rawArr := m.Get("data").MustInt32Slice() + + replaced := m.Get("data").ReplaceInt32(func(index int, val int32) int32 { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustInt32Slice() + + if assert.Equal(t, 6, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[5]) + assert.Equal(t, replacedArr[5], rawArr[0]) + } +} + +func TestCollectInt32(t *testing.T) { + m := objx.Map{"data": []int32{int32(1), int32(1), int32(1), int32(1), int32(1), int32(1)}} + + collected := m.Get("data").CollectInt32(func(index int, val int32) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 6, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + assert.Equal(t, collectedArr[5], 5) + } +} + +/* + Tests for Int64 (int64 and []int64) +*/ +func TestInt64(t *testing.T) { + val := int64(1) + m := objx.Map{"value": val, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Int64()) + assert.Equal(t, val, m.Get("value").MustInt64()) + assert.Equal(t, int64(0), m.Get("nothing").Int64()) + assert.Equal(t, val, m.Get("nothing").Int64(1)) + assert.Panics(t, func() { + m.Get("age").MustInt64() + }) +} + +func TestInt64Slice(t *testing.T) { + val := int64(1) + m := objx.Map{"value": []int64{val}, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Int64Slice()[0]) + assert.Equal(t, val, m.Get("value").MustInt64Slice()[0]) + assert.Equal(t, []int64(nil), m.Get("nothing").Int64Slice()) + assert.Equal(t, val, m.Get("nothing").Int64Slice([]int64{int64(1)})[0]) + assert.Panics(t, func() { + m.Get("nothing").MustInt64Slice() + }) +} + +func TestIsInt64(t *testing.T) { + m := objx.Map{"data": int64(1)} + + assert.True(t, m.Get("data").IsInt64()) +} + +func TestIsInt64Slice(t *testing.T) { + m := objx.Map{"data": []int64{int64(1)}} + + assert.True(t, m.Get("data").IsInt64Slice()) +} + +func TestEachInt64(t *testing.T) { + m := objx.Map{"data": []int64{int64(1), int64(1), int64(1), int64(1), int64(1)}} + count := 0 + replacedVals := make([]int64, 0) + assert.Equal(t, m.Get("data"), m.Get("data").EachInt64(func(i int, val int64) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + assert.Equal(t, count, 3) + assert.Equal(t, replacedVals[0], m.Get("data").MustInt64Slice()[0]) + assert.Equal(t, replacedVals[1], m.Get("data").MustInt64Slice()[1]) + assert.Equal(t, replacedVals[2], m.Get("data").MustInt64Slice()[2]) +} + +func TestWhereInt64(t *testing.T) { + m := objx.Map{"data": []int64{int64(1), int64(1), int64(1), int64(1), int64(1), int64(1)}} + + selected := m.Get("data").WhereInt64(func(i int, val int64) bool { + return i%2 == 0 + }).MustInt64Slice() + + assert.Equal(t, 3, len(selected)) +} + +func TestGroupInt64(t *testing.T) { + m := objx.Map{"data": []int64{int64(1), int64(1), int64(1), int64(1), int64(1), int64(1)}} + + grouped := m.Get("data").GroupInt64(func(i int, val int64) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][]int64) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 3, len(grouped["false"])) +} + +func TestReplaceInt64(t *testing.T) { + m := objx.Map{"data": []int64{int64(1), int64(1), int64(1), int64(1), int64(1), int64(1)}} + rawArr := m.Get("data").MustInt64Slice() + + replaced := m.Get("data").ReplaceInt64(func(index int, val int64) int64 { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustInt64Slice() + + if assert.Equal(t, 6, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[5]) + assert.Equal(t, replacedArr[5], rawArr[0]) + } +} + +func TestCollectInt64(t *testing.T) { + m := objx.Map{"data": []int64{int64(1), int64(1), int64(1), int64(1), int64(1), int64(1)}} + + collected := m.Get("data").CollectInt64(func(index int, val int64) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 6, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + assert.Equal(t, collectedArr[5], 5) + } +} + +/* + Tests for Uint (uint and []uint) +*/ +func TestUint(t *testing.T) { + val := uint(1) + m := objx.Map{"value": val, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Uint()) + assert.Equal(t, val, m.Get("value").MustUint()) + assert.Equal(t, uint(0), m.Get("nothing").Uint()) + assert.Equal(t, val, m.Get("nothing").Uint(1)) + assert.Panics(t, func() { + m.Get("age").MustUint() + }) +} + +func TestUintSlice(t *testing.T) { + val := uint(1) + m := objx.Map{"value": []uint{val}, "nothing": nil} + + assert.Equal(t, val, m.Get("value").UintSlice()[0]) + assert.Equal(t, val, m.Get("value").MustUintSlice()[0]) + assert.Equal(t, []uint(nil), m.Get("nothing").UintSlice()) + assert.Equal(t, val, m.Get("nothing").UintSlice([]uint{uint(1)})[0]) + assert.Panics(t, func() { + m.Get("nothing").MustUintSlice() + }) +} + +func TestIsUint(t *testing.T) { + m := objx.Map{"data": uint(1)} + + assert.True(t, m.Get("data").IsUint()) +} + +func TestIsUintSlice(t *testing.T) { + m := objx.Map{"data": []uint{uint(1)}} + + assert.True(t, m.Get("data").IsUintSlice()) +} + +func TestEachUint(t *testing.T) { + m := objx.Map{"data": []uint{uint(1), uint(1), uint(1), uint(1), uint(1)}} + count := 0 + replacedVals := make([]uint, 0) + assert.Equal(t, m.Get("data"), m.Get("data").EachUint(func(i int, val uint) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + assert.Equal(t, count, 3) + assert.Equal(t, replacedVals[0], m.Get("data").MustUintSlice()[0]) + assert.Equal(t, replacedVals[1], m.Get("data").MustUintSlice()[1]) + assert.Equal(t, replacedVals[2], m.Get("data").MustUintSlice()[2]) +} + +func TestWhereUint(t *testing.T) { + m := objx.Map{"data": []uint{uint(1), uint(1), uint(1), uint(1), uint(1), uint(1)}} + + selected := m.Get("data").WhereUint(func(i int, val uint) bool { + return i%2 == 0 + }).MustUintSlice() + + assert.Equal(t, 3, len(selected)) +} + +func TestGroupUint(t *testing.T) { + m := objx.Map{"data": []uint{uint(1), uint(1), uint(1), uint(1), uint(1), uint(1)}} + + grouped := m.Get("data").GroupUint(func(i int, val uint) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][]uint) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 3, len(grouped["false"])) +} + +func TestReplaceUint(t *testing.T) { + m := objx.Map{"data": []uint{uint(1), uint(1), uint(1), uint(1), uint(1), uint(1)}} + rawArr := m.Get("data").MustUintSlice() + + replaced := m.Get("data").ReplaceUint(func(index int, val uint) uint { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustUintSlice() + + if assert.Equal(t, 6, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[5]) + assert.Equal(t, replacedArr[5], rawArr[0]) + } +} + +func TestCollectUint(t *testing.T) { + m := objx.Map{"data": []uint{uint(1), uint(1), uint(1), uint(1), uint(1), uint(1)}} + + collected := m.Get("data").CollectUint(func(index int, val uint) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 6, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + assert.Equal(t, collectedArr[5], 5) + } +} + +/* + Tests for Uint8 (uint8 and []uint8) +*/ +func TestUint8(t *testing.T) { + val := uint8(1) + m := objx.Map{"value": val, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Uint8()) + assert.Equal(t, val, m.Get("value").MustUint8()) + assert.Equal(t, uint8(0), m.Get("nothing").Uint8()) + assert.Equal(t, val, m.Get("nothing").Uint8(1)) + assert.Panics(t, func() { + m.Get("age").MustUint8() + }) +} + +func TestUint8Slice(t *testing.T) { + val := uint8(1) + m := objx.Map{"value": []uint8{val}, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Uint8Slice()[0]) + assert.Equal(t, val, m.Get("value").MustUint8Slice()[0]) + assert.Equal(t, []uint8(nil), m.Get("nothing").Uint8Slice()) + assert.Equal(t, val, m.Get("nothing").Uint8Slice([]uint8{uint8(1)})[0]) + assert.Panics(t, func() { + m.Get("nothing").MustUint8Slice() + }) +} + +func TestIsUint8(t *testing.T) { + m := objx.Map{"data": uint8(1)} + + assert.True(t, m.Get("data").IsUint8()) +} + +func TestIsUint8Slice(t *testing.T) { + m := objx.Map{"data": []uint8{uint8(1)}} + + assert.True(t, m.Get("data").IsUint8Slice()) +} + +func TestEachUint8(t *testing.T) { + m := objx.Map{"data": []uint8{uint8(1), uint8(1), uint8(1), uint8(1), uint8(1)}} + count := 0 + replacedVals := make([]uint8, 0) + assert.Equal(t, m.Get("data"), m.Get("data").EachUint8(func(i int, val uint8) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + assert.Equal(t, count, 3) + assert.Equal(t, replacedVals[0], m.Get("data").MustUint8Slice()[0]) + assert.Equal(t, replacedVals[1], m.Get("data").MustUint8Slice()[1]) + assert.Equal(t, replacedVals[2], m.Get("data").MustUint8Slice()[2]) +} + +func TestWhereUint8(t *testing.T) { + m := objx.Map{"data": []uint8{uint8(1), uint8(1), uint8(1), uint8(1), uint8(1), uint8(1)}} + + selected := m.Get("data").WhereUint8(func(i int, val uint8) bool { + return i%2 == 0 + }).MustUint8Slice() + + assert.Equal(t, 3, len(selected)) +} + +func TestGroupUint8(t *testing.T) { + m := objx.Map{"data": []uint8{uint8(1), uint8(1), uint8(1), uint8(1), uint8(1), uint8(1)}} + + grouped := m.Get("data").GroupUint8(func(i int, val uint8) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][]uint8) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 3, len(grouped["false"])) +} + +func TestReplaceUint8(t *testing.T) { + m := objx.Map{"data": []uint8{uint8(1), uint8(1), uint8(1), uint8(1), uint8(1), uint8(1)}} + rawArr := m.Get("data").MustUint8Slice() + + replaced := m.Get("data").ReplaceUint8(func(index int, val uint8) uint8 { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustUint8Slice() + + if assert.Equal(t, 6, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[5]) + assert.Equal(t, replacedArr[5], rawArr[0]) + } +} + +func TestCollectUint8(t *testing.T) { + m := objx.Map{"data": []uint8{uint8(1), uint8(1), uint8(1), uint8(1), uint8(1), uint8(1)}} + + collected := m.Get("data").CollectUint8(func(index int, val uint8) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 6, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + assert.Equal(t, collectedArr[5], 5) + } +} + +/* + Tests for Uint16 (uint16 and []uint16) +*/ +func TestUint16(t *testing.T) { + val := uint16(1) + m := objx.Map{"value": val, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Uint16()) + assert.Equal(t, val, m.Get("value").MustUint16()) + assert.Equal(t, uint16(0), m.Get("nothing").Uint16()) + assert.Equal(t, val, m.Get("nothing").Uint16(1)) + assert.Panics(t, func() { + m.Get("age").MustUint16() + }) +} + +func TestUint16Slice(t *testing.T) { + val := uint16(1) + m := objx.Map{"value": []uint16{val}, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Uint16Slice()[0]) + assert.Equal(t, val, m.Get("value").MustUint16Slice()[0]) + assert.Equal(t, []uint16(nil), m.Get("nothing").Uint16Slice()) + assert.Equal(t, val, m.Get("nothing").Uint16Slice([]uint16{uint16(1)})[0]) + assert.Panics(t, func() { + m.Get("nothing").MustUint16Slice() + }) +} + +func TestIsUint16(t *testing.T) { + m := objx.Map{"data": uint16(1)} + + assert.True(t, m.Get("data").IsUint16()) +} + +func TestIsUint16Slice(t *testing.T) { + m := objx.Map{"data": []uint16{uint16(1)}} + + assert.True(t, m.Get("data").IsUint16Slice()) +} + +func TestEachUint16(t *testing.T) { + m := objx.Map{"data": []uint16{uint16(1), uint16(1), uint16(1), uint16(1), uint16(1)}} + count := 0 + replacedVals := make([]uint16, 0) + assert.Equal(t, m.Get("data"), m.Get("data").EachUint16(func(i int, val uint16) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + assert.Equal(t, count, 3) + assert.Equal(t, replacedVals[0], m.Get("data").MustUint16Slice()[0]) + assert.Equal(t, replacedVals[1], m.Get("data").MustUint16Slice()[1]) + assert.Equal(t, replacedVals[2], m.Get("data").MustUint16Slice()[2]) +} + +func TestWhereUint16(t *testing.T) { + m := objx.Map{"data": []uint16{uint16(1), uint16(1), uint16(1), uint16(1), uint16(1), uint16(1)}} + + selected := m.Get("data").WhereUint16(func(i int, val uint16) bool { + return i%2 == 0 + }).MustUint16Slice() + + assert.Equal(t, 3, len(selected)) +} + +func TestGroupUint16(t *testing.T) { + m := objx.Map{"data": []uint16{uint16(1), uint16(1), uint16(1), uint16(1), uint16(1), uint16(1)}} + + grouped := m.Get("data").GroupUint16(func(i int, val uint16) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][]uint16) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 3, len(grouped["false"])) +} + +func TestReplaceUint16(t *testing.T) { + m := objx.Map{"data": []uint16{uint16(1), uint16(1), uint16(1), uint16(1), uint16(1), uint16(1)}} + rawArr := m.Get("data").MustUint16Slice() + + replaced := m.Get("data").ReplaceUint16(func(index int, val uint16) uint16 { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustUint16Slice() + + if assert.Equal(t, 6, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[5]) + assert.Equal(t, replacedArr[5], rawArr[0]) + } +} + +func TestCollectUint16(t *testing.T) { + m := objx.Map{"data": []uint16{uint16(1), uint16(1), uint16(1), uint16(1), uint16(1), uint16(1)}} + + collected := m.Get("data").CollectUint16(func(index int, val uint16) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 6, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + assert.Equal(t, collectedArr[5], 5) + } +} + +/* + Tests for Uint32 (uint32 and []uint32) +*/ +func TestUint32(t *testing.T) { + val := uint32(1) + m := objx.Map{"value": val, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Uint32()) + assert.Equal(t, val, m.Get("value").MustUint32()) + assert.Equal(t, uint32(0), m.Get("nothing").Uint32()) + assert.Equal(t, val, m.Get("nothing").Uint32(1)) + assert.Panics(t, func() { + m.Get("age").MustUint32() + }) +} + +func TestUint32Slice(t *testing.T) { + val := uint32(1) + m := objx.Map{"value": []uint32{val}, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Uint32Slice()[0]) + assert.Equal(t, val, m.Get("value").MustUint32Slice()[0]) + assert.Equal(t, []uint32(nil), m.Get("nothing").Uint32Slice()) + assert.Equal(t, val, m.Get("nothing").Uint32Slice([]uint32{uint32(1)})[0]) + assert.Panics(t, func() { + m.Get("nothing").MustUint32Slice() + }) +} + +func TestIsUint32(t *testing.T) { + m := objx.Map{"data": uint32(1)} + + assert.True(t, m.Get("data").IsUint32()) +} + +func TestIsUint32Slice(t *testing.T) { + m := objx.Map{"data": []uint32{uint32(1)}} + + assert.True(t, m.Get("data").IsUint32Slice()) +} + +func TestEachUint32(t *testing.T) { + m := objx.Map{"data": []uint32{uint32(1), uint32(1), uint32(1), uint32(1), uint32(1)}} + count := 0 + replacedVals := make([]uint32, 0) + assert.Equal(t, m.Get("data"), m.Get("data").EachUint32(func(i int, val uint32) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + assert.Equal(t, count, 3) + assert.Equal(t, replacedVals[0], m.Get("data").MustUint32Slice()[0]) + assert.Equal(t, replacedVals[1], m.Get("data").MustUint32Slice()[1]) + assert.Equal(t, replacedVals[2], m.Get("data").MustUint32Slice()[2]) +} + +func TestWhereUint32(t *testing.T) { + m := objx.Map{"data": []uint32{uint32(1), uint32(1), uint32(1), uint32(1), uint32(1), uint32(1)}} + + selected := m.Get("data").WhereUint32(func(i int, val uint32) bool { + return i%2 == 0 + }).MustUint32Slice() + + assert.Equal(t, 3, len(selected)) +} + +func TestGroupUint32(t *testing.T) { + m := objx.Map{"data": []uint32{uint32(1), uint32(1), uint32(1), uint32(1), uint32(1), uint32(1)}} + + grouped := m.Get("data").GroupUint32(func(i int, val uint32) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][]uint32) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 3, len(grouped["false"])) +} + +func TestReplaceUint32(t *testing.T) { + m := objx.Map{"data": []uint32{uint32(1), uint32(1), uint32(1), uint32(1), uint32(1), uint32(1)}} + rawArr := m.Get("data").MustUint32Slice() + + replaced := m.Get("data").ReplaceUint32(func(index int, val uint32) uint32 { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustUint32Slice() + + if assert.Equal(t, 6, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[5]) + assert.Equal(t, replacedArr[5], rawArr[0]) + } +} + +func TestCollectUint32(t *testing.T) { + m := objx.Map{"data": []uint32{uint32(1), uint32(1), uint32(1), uint32(1), uint32(1), uint32(1)}} + + collected := m.Get("data").CollectUint32(func(index int, val uint32) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 6, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + assert.Equal(t, collectedArr[5], 5) + } +} + +/* + Tests for Uint64 (uint64 and []uint64) +*/ +func TestUint64(t *testing.T) { + val := uint64(1) + m := objx.Map{"value": val, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Uint64()) + assert.Equal(t, val, m.Get("value").MustUint64()) + assert.Equal(t, uint64(0), m.Get("nothing").Uint64()) + assert.Equal(t, val, m.Get("nothing").Uint64(1)) + assert.Panics(t, func() { + m.Get("age").MustUint64() + }) +} + +func TestUint64Slice(t *testing.T) { + val := uint64(1) + m := objx.Map{"value": []uint64{val}, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Uint64Slice()[0]) + assert.Equal(t, val, m.Get("value").MustUint64Slice()[0]) + assert.Equal(t, []uint64(nil), m.Get("nothing").Uint64Slice()) + assert.Equal(t, val, m.Get("nothing").Uint64Slice([]uint64{uint64(1)})[0]) + assert.Panics(t, func() { + m.Get("nothing").MustUint64Slice() + }) +} + +func TestIsUint64(t *testing.T) { + m := objx.Map{"data": uint64(1)} + + assert.True(t, m.Get("data").IsUint64()) +} + +func TestIsUint64Slice(t *testing.T) { + m := objx.Map{"data": []uint64{uint64(1)}} + + assert.True(t, m.Get("data").IsUint64Slice()) +} + +func TestEachUint64(t *testing.T) { + m := objx.Map{"data": []uint64{uint64(1), uint64(1), uint64(1), uint64(1), uint64(1)}} + count := 0 + replacedVals := make([]uint64, 0) + assert.Equal(t, m.Get("data"), m.Get("data").EachUint64(func(i int, val uint64) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + assert.Equal(t, count, 3) + assert.Equal(t, replacedVals[0], m.Get("data").MustUint64Slice()[0]) + assert.Equal(t, replacedVals[1], m.Get("data").MustUint64Slice()[1]) + assert.Equal(t, replacedVals[2], m.Get("data").MustUint64Slice()[2]) +} + +func TestWhereUint64(t *testing.T) { + m := objx.Map{"data": []uint64{uint64(1), uint64(1), uint64(1), uint64(1), uint64(1), uint64(1)}} + + selected := m.Get("data").WhereUint64(func(i int, val uint64) bool { + return i%2 == 0 + }).MustUint64Slice() + + assert.Equal(t, 3, len(selected)) +} + +func TestGroupUint64(t *testing.T) { + m := objx.Map{"data": []uint64{uint64(1), uint64(1), uint64(1), uint64(1), uint64(1), uint64(1)}} + + grouped := m.Get("data").GroupUint64(func(i int, val uint64) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][]uint64) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 3, len(grouped["false"])) +} + +func TestReplaceUint64(t *testing.T) { + m := objx.Map{"data": []uint64{uint64(1), uint64(1), uint64(1), uint64(1), uint64(1), uint64(1)}} + rawArr := m.Get("data").MustUint64Slice() + + replaced := m.Get("data").ReplaceUint64(func(index int, val uint64) uint64 { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustUint64Slice() + + if assert.Equal(t, 6, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[5]) + assert.Equal(t, replacedArr[5], rawArr[0]) + } +} + +func TestCollectUint64(t *testing.T) { + m := objx.Map{"data": []uint64{uint64(1), uint64(1), uint64(1), uint64(1), uint64(1), uint64(1)}} + + collected := m.Get("data").CollectUint64(func(index int, val uint64) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 6, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + assert.Equal(t, collectedArr[5], 5) + } +} + +/* + Tests for Uintptr (uintptr and []uintptr) +*/ +func TestUintptr(t *testing.T) { + val := uintptr(1) + m := objx.Map{"value": val, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Uintptr()) + assert.Equal(t, val, m.Get("value").MustUintptr()) + assert.Equal(t, uintptr(0), m.Get("nothing").Uintptr()) + assert.Equal(t, val, m.Get("nothing").Uintptr(1)) + assert.Panics(t, func() { + m.Get("age").MustUintptr() + }) +} + +func TestUintptrSlice(t *testing.T) { + val := uintptr(1) + m := objx.Map{"value": []uintptr{val}, "nothing": nil} + + assert.Equal(t, val, m.Get("value").UintptrSlice()[0]) + assert.Equal(t, val, m.Get("value").MustUintptrSlice()[0]) + assert.Equal(t, []uintptr(nil), m.Get("nothing").UintptrSlice()) + assert.Equal(t, val, m.Get("nothing").UintptrSlice([]uintptr{uintptr(1)})[0]) + assert.Panics(t, func() { + m.Get("nothing").MustUintptrSlice() + }) +} + +func TestIsUintptr(t *testing.T) { + m := objx.Map{"data": uintptr(1)} + + assert.True(t, m.Get("data").IsUintptr()) +} + +func TestIsUintptrSlice(t *testing.T) { + m := objx.Map{"data": []uintptr{uintptr(1)}} + + assert.True(t, m.Get("data").IsUintptrSlice()) +} + +func TestEachUintptr(t *testing.T) { + m := objx.Map{"data": []uintptr{uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1)}} + count := 0 + replacedVals := make([]uintptr, 0) + assert.Equal(t, m.Get("data"), m.Get("data").EachUintptr(func(i int, val uintptr) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + assert.Equal(t, count, 3) + assert.Equal(t, replacedVals[0], m.Get("data").MustUintptrSlice()[0]) + assert.Equal(t, replacedVals[1], m.Get("data").MustUintptrSlice()[1]) + assert.Equal(t, replacedVals[2], m.Get("data").MustUintptrSlice()[2]) +} + +func TestWhereUintptr(t *testing.T) { + m := objx.Map{"data": []uintptr{uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1)}} + + selected := m.Get("data").WhereUintptr(func(i int, val uintptr) bool { + return i%2 == 0 + }).MustUintptrSlice() + + assert.Equal(t, 3, len(selected)) +} + +func TestGroupUintptr(t *testing.T) { + m := objx.Map{"data": []uintptr{uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1)}} + + grouped := m.Get("data").GroupUintptr(func(i int, val uintptr) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][]uintptr) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 3, len(grouped["false"])) +} + +func TestReplaceUintptr(t *testing.T) { + m := objx.Map{"data": []uintptr{uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1)}} + rawArr := m.Get("data").MustUintptrSlice() + + replaced := m.Get("data").ReplaceUintptr(func(index int, val uintptr) uintptr { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustUintptrSlice() + + if assert.Equal(t, 6, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[5]) + assert.Equal(t, replacedArr[5], rawArr[0]) + } +} + +func TestCollectUintptr(t *testing.T) { + m := objx.Map{"data": []uintptr{uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1), uintptr(1)}} + + collected := m.Get("data").CollectUintptr(func(index int, val uintptr) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 6, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + assert.Equal(t, collectedArr[5], 5) + } +} + +/* + Tests for Float32 (float32 and []float32) +*/ +func TestFloat32(t *testing.T) { + val := float32(1) + m := objx.Map{"value": val, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Float32()) + assert.Equal(t, val, m.Get("value").MustFloat32()) + assert.Equal(t, float32(0), m.Get("nothing").Float32()) + assert.Equal(t, val, m.Get("nothing").Float32(1)) + assert.Panics(t, func() { + m.Get("age").MustFloat32() + }) +} + +func TestFloat32Slice(t *testing.T) { + val := float32(1) + m := objx.Map{"value": []float32{val}, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Float32Slice()[0]) + assert.Equal(t, val, m.Get("value").MustFloat32Slice()[0]) + assert.Equal(t, []float32(nil), m.Get("nothing").Float32Slice()) + assert.Equal(t, val, m.Get("nothing").Float32Slice([]float32{float32(1)})[0]) + assert.Panics(t, func() { + m.Get("nothing").MustFloat32Slice() + }) +} + +func TestIsFloat32(t *testing.T) { + m := objx.Map{"data": float32(1)} + + assert.True(t, m.Get("data").IsFloat32()) +} + +func TestIsFloat32Slice(t *testing.T) { + m := objx.Map{"data": []float32{float32(1)}} + + assert.True(t, m.Get("data").IsFloat32Slice()) +} + +func TestEachFloat32(t *testing.T) { + m := objx.Map{"data": []float32{float32(1), float32(1), float32(1), float32(1), float32(1)}} + count := 0 + replacedVals := make([]float32, 0) + assert.Equal(t, m.Get("data"), m.Get("data").EachFloat32(func(i int, val float32) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + assert.Equal(t, count, 3) + assert.Equal(t, replacedVals[0], m.Get("data").MustFloat32Slice()[0]) + assert.Equal(t, replacedVals[1], m.Get("data").MustFloat32Slice()[1]) + assert.Equal(t, replacedVals[2], m.Get("data").MustFloat32Slice()[2]) +} + +func TestWhereFloat32(t *testing.T) { + m := objx.Map{"data": []float32{float32(1), float32(1), float32(1), float32(1), float32(1), float32(1)}} + + selected := m.Get("data").WhereFloat32(func(i int, val float32) bool { + return i%2 == 0 + }).MustFloat32Slice() + + assert.Equal(t, 3, len(selected)) +} + +func TestGroupFloat32(t *testing.T) { + m := objx.Map{"data": []float32{float32(1), float32(1), float32(1), float32(1), float32(1), float32(1)}} + + grouped := m.Get("data").GroupFloat32(func(i int, val float32) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][]float32) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 3, len(grouped["false"])) +} + +func TestReplaceFloat32(t *testing.T) { + m := objx.Map{"data": []float32{float32(1), float32(1), float32(1), float32(1), float32(1), float32(1)}} + rawArr := m.Get("data").MustFloat32Slice() + + replaced := m.Get("data").ReplaceFloat32(func(index int, val float32) float32 { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustFloat32Slice() + + if assert.Equal(t, 6, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[5]) + assert.Equal(t, replacedArr[5], rawArr[0]) + } +} + +func TestCollectFloat32(t *testing.T) { + m := objx.Map{"data": []float32{float32(1), float32(1), float32(1), float32(1), float32(1), float32(1)}} + + collected := m.Get("data").CollectFloat32(func(index int, val float32) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 6, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + assert.Equal(t, collectedArr[5], 5) + } +} + +/* + Tests for Float64 (float64 and []float64) +*/ +func TestFloat64(t *testing.T) { + val := float64(1) + m := objx.Map{"value": val, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Float64()) + assert.Equal(t, val, m.Get("value").MustFloat64()) + assert.Equal(t, float64(0), m.Get("nothing").Float64()) + assert.Equal(t, val, m.Get("nothing").Float64(1)) + assert.Panics(t, func() { + m.Get("age").MustFloat64() + }) +} + +func TestFloat64Slice(t *testing.T) { + val := float64(1) + m := objx.Map{"value": []float64{val}, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Float64Slice()[0]) + assert.Equal(t, val, m.Get("value").MustFloat64Slice()[0]) + assert.Equal(t, []float64(nil), m.Get("nothing").Float64Slice()) + assert.Equal(t, val, m.Get("nothing").Float64Slice([]float64{float64(1)})[0]) + assert.Panics(t, func() { + m.Get("nothing").MustFloat64Slice() + }) +} + +func TestIsFloat64(t *testing.T) { + m := objx.Map{"data": float64(1)} + + assert.True(t, m.Get("data").IsFloat64()) +} + +func TestIsFloat64Slice(t *testing.T) { + m := objx.Map{"data": []float64{float64(1)}} + + assert.True(t, m.Get("data").IsFloat64Slice()) +} + +func TestEachFloat64(t *testing.T) { + m := objx.Map{"data": []float64{float64(1), float64(1), float64(1), float64(1), float64(1)}} + count := 0 + replacedVals := make([]float64, 0) + assert.Equal(t, m.Get("data"), m.Get("data").EachFloat64(func(i int, val float64) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + assert.Equal(t, count, 3) + assert.Equal(t, replacedVals[0], m.Get("data").MustFloat64Slice()[0]) + assert.Equal(t, replacedVals[1], m.Get("data").MustFloat64Slice()[1]) + assert.Equal(t, replacedVals[2], m.Get("data").MustFloat64Slice()[2]) +} + +func TestWhereFloat64(t *testing.T) { + m := objx.Map{"data": []float64{float64(1), float64(1), float64(1), float64(1), float64(1), float64(1)}} + + selected := m.Get("data").WhereFloat64(func(i int, val float64) bool { + return i%2 == 0 + }).MustFloat64Slice() + + assert.Equal(t, 3, len(selected)) +} + +func TestGroupFloat64(t *testing.T) { + m := objx.Map{"data": []float64{float64(1), float64(1), float64(1), float64(1), float64(1), float64(1)}} + + grouped := m.Get("data").GroupFloat64(func(i int, val float64) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][]float64) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 3, len(grouped["false"])) +} + +func TestReplaceFloat64(t *testing.T) { + m := objx.Map{"data": []float64{float64(1), float64(1), float64(1), float64(1), float64(1), float64(1)}} + rawArr := m.Get("data").MustFloat64Slice() + + replaced := m.Get("data").ReplaceFloat64(func(index int, val float64) float64 { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustFloat64Slice() + + if assert.Equal(t, 6, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[5]) + assert.Equal(t, replacedArr[5], rawArr[0]) + } +} + +func TestCollectFloat64(t *testing.T) { + m := objx.Map{"data": []float64{float64(1), float64(1), float64(1), float64(1), float64(1), float64(1)}} + + collected := m.Get("data").CollectFloat64(func(index int, val float64) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 6, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + assert.Equal(t, collectedArr[5], 5) + } +} + +/* + Tests for Complex64 (complex64 and []complex64) +*/ +func TestComplex64(t *testing.T) { + val := complex64(1) + m := objx.Map{"value": val, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Complex64()) + assert.Equal(t, val, m.Get("value").MustComplex64()) + assert.Equal(t, complex64(0), m.Get("nothing").Complex64()) + assert.Equal(t, val, m.Get("nothing").Complex64(1)) + assert.Panics(t, func() { + m.Get("age").MustComplex64() + }) +} + +func TestComplex64Slice(t *testing.T) { + val := complex64(1) + m := objx.Map{"value": []complex64{val}, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Complex64Slice()[0]) + assert.Equal(t, val, m.Get("value").MustComplex64Slice()[0]) + assert.Equal(t, []complex64(nil), m.Get("nothing").Complex64Slice()) + assert.Equal(t, val, m.Get("nothing").Complex64Slice([]complex64{complex64(1)})[0]) + assert.Panics(t, func() { + m.Get("nothing").MustComplex64Slice() + }) +} + +func TestIsComplex64(t *testing.T) { + m := objx.Map{"data": complex64(1)} + + assert.True(t, m.Get("data").IsComplex64()) +} + +func TestIsComplex64Slice(t *testing.T) { + m := objx.Map{"data": []complex64{complex64(1)}} + + assert.True(t, m.Get("data").IsComplex64Slice()) +} + +func TestEachComplex64(t *testing.T) { + m := objx.Map{"data": []complex64{complex64(1), complex64(1), complex64(1), complex64(1), complex64(1)}} + count := 0 + replacedVals := make([]complex64, 0) + assert.Equal(t, m.Get("data"), m.Get("data").EachComplex64(func(i int, val complex64) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + assert.Equal(t, count, 3) + assert.Equal(t, replacedVals[0], m.Get("data").MustComplex64Slice()[0]) + assert.Equal(t, replacedVals[1], m.Get("data").MustComplex64Slice()[1]) + assert.Equal(t, replacedVals[2], m.Get("data").MustComplex64Slice()[2]) +} + +func TestWhereComplex64(t *testing.T) { + m := objx.Map{"data": []complex64{complex64(1), complex64(1), complex64(1), complex64(1), complex64(1), complex64(1)}} + + selected := m.Get("data").WhereComplex64(func(i int, val complex64) bool { + return i%2 == 0 + }).MustComplex64Slice() + + assert.Equal(t, 3, len(selected)) +} + +func TestGroupComplex64(t *testing.T) { + m := objx.Map{"data": []complex64{complex64(1), complex64(1), complex64(1), complex64(1), complex64(1), complex64(1)}} + + grouped := m.Get("data").GroupComplex64(func(i int, val complex64) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][]complex64) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 3, len(grouped["false"])) +} + +func TestReplaceComplex64(t *testing.T) { + m := objx.Map{"data": []complex64{complex64(1), complex64(1), complex64(1), complex64(1), complex64(1), complex64(1)}} + rawArr := m.Get("data").MustComplex64Slice() + + replaced := m.Get("data").ReplaceComplex64(func(index int, val complex64) complex64 { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustComplex64Slice() + + if assert.Equal(t, 6, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[5]) + assert.Equal(t, replacedArr[5], rawArr[0]) + } +} + +func TestCollectComplex64(t *testing.T) { + m := objx.Map{"data": []complex64{complex64(1), complex64(1), complex64(1), complex64(1), complex64(1), complex64(1)}} + + collected := m.Get("data").CollectComplex64(func(index int, val complex64) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 6, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + assert.Equal(t, collectedArr[5], 5) + } +} + +/* + Tests for Complex128 (complex128 and []complex128) +*/ +func TestComplex128(t *testing.T) { + val := complex128(1) + m := objx.Map{"value": val, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Complex128()) + assert.Equal(t, val, m.Get("value").MustComplex128()) + assert.Equal(t, complex128(0), m.Get("nothing").Complex128()) + assert.Equal(t, val, m.Get("nothing").Complex128(1)) + assert.Panics(t, func() { + m.Get("age").MustComplex128() + }) +} + +func TestComplex128Slice(t *testing.T) { + val := complex128(1) + m := objx.Map{"value": []complex128{val}, "nothing": nil} + + assert.Equal(t, val, m.Get("value").Complex128Slice()[0]) + assert.Equal(t, val, m.Get("value").MustComplex128Slice()[0]) + assert.Equal(t, []complex128(nil), m.Get("nothing").Complex128Slice()) + assert.Equal(t, val, m.Get("nothing").Complex128Slice([]complex128{complex128(1)})[0]) + assert.Panics(t, func() { + m.Get("nothing").MustComplex128Slice() + }) +} + +func TestIsComplex128(t *testing.T) { + m := objx.Map{"data": complex128(1)} + + assert.True(t, m.Get("data").IsComplex128()) +} + +func TestIsComplex128Slice(t *testing.T) { + m := objx.Map{"data": []complex128{complex128(1)}} + + assert.True(t, m.Get("data").IsComplex128Slice()) +} + +func TestEachComplex128(t *testing.T) { + m := objx.Map{"data": []complex128{complex128(1), complex128(1), complex128(1), complex128(1), complex128(1)}} + count := 0 + replacedVals := make([]complex128, 0) + assert.Equal(t, m.Get("data"), m.Get("data").EachComplex128(func(i int, val complex128) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + assert.Equal(t, count, 3) + assert.Equal(t, replacedVals[0], m.Get("data").MustComplex128Slice()[0]) + assert.Equal(t, replacedVals[1], m.Get("data").MustComplex128Slice()[1]) + assert.Equal(t, replacedVals[2], m.Get("data").MustComplex128Slice()[2]) +} + +func TestWhereComplex128(t *testing.T) { + m := objx.Map{"data": []complex128{complex128(1), complex128(1), complex128(1), complex128(1), complex128(1), complex128(1)}} + + selected := m.Get("data").WhereComplex128(func(i int, val complex128) bool { + return i%2 == 0 + }).MustComplex128Slice() + + assert.Equal(t, 3, len(selected)) +} + +func TestGroupComplex128(t *testing.T) { + m := objx.Map{"data": []complex128{complex128(1), complex128(1), complex128(1), complex128(1), complex128(1), complex128(1)}} + + grouped := m.Get("data").GroupComplex128(func(i int, val complex128) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][]complex128) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 3, len(grouped["false"])) +} + +func TestReplaceComplex128(t *testing.T) { + m := objx.Map{"data": []complex128{complex128(1), complex128(1), complex128(1), complex128(1), complex128(1), complex128(1)}} + rawArr := m.Get("data").MustComplex128Slice() + + replaced := m.Get("data").ReplaceComplex128(func(index int, val complex128) complex128 { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustComplex128Slice() + + if assert.Equal(t, 6, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[5]) + assert.Equal(t, replacedArr[5], rawArr[0]) + } +} + +func TestCollectComplex128(t *testing.T) { + m := objx.Map{"data": []complex128{complex128(1), complex128(1), complex128(1), complex128(1), complex128(1), complex128(1)}} + + collected := m.Get("data").CollectComplex128(func(index int, val complex128) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 6, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + assert.Equal(t, collectedArr[5], 5) + } +} diff --git a/vendor/github.com/stretchr/objx/type_specific_test.go b/vendor/github.com/stretchr/objx/type_specific_test.go new file mode 100644 index 0000000..7b66847 --- /dev/null +++ b/vendor/github.com/stretchr/objx/type_specific_test.go @@ -0,0 +1,459 @@ +package objx_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/objx" + "github.com/stretchr/testify/assert" +) + +/* + Tests for MSI (map[string]interface{} and []map[string]interface{}) +*/ +func TestMSI(t *testing.T) { + val := map[string]interface{}(map[string]interface{}{"name": "Tyler"}) + m := objx.Map{"value": val, "nothing": nil} + mVal := map[string]interface{}{"value": val, "nothing": nil} + + assert.Equal(t, mVal, m.Value().MSI()) + assert.Equal(t, val, m.Get("value").MSI()) + assert.Equal(t, mVal, m.Value().MustMSI()) + assert.Equal(t, val, m.Get("value").MustMSI()) + assert.Equal(t, map[string]interface{}(nil), m.Get("nothing").MSI()) + assert.Equal(t, val, m.Get("nothing").MSI(map[string]interface{}{"name": "Tyler"})) + assert.Panics(t, func() { + m.Get("age").MustMSI() + }) +} + +func TestMSISlice(t *testing.T) { + val := map[string]interface{}(map[string]interface{}{"name": "Tyler"}) + m := objx.Map{ + "value": []map[string]interface{}{val}, + "value2": []objx.Map{val}, + "value3": []interface{}{val}, + "nothing": nil, + } + + assert.Equal(t, val, m.Get("value").MSISlice()[0]) + assert.Equal(t, val, m.Get("value2").MSISlice()[0]) + assert.Equal(t, val, m.Get("value3").MSISlice()[0]) + assert.Equal(t, val, m.Get("value").MustMSISlice()[0]) + assert.Equal(t, val, m.Get("value2").MustMSISlice()[0]) + assert.Equal(t, val, m.Get("value3").MustMSISlice()[0]) + assert.Equal(t, []map[string]interface{}(nil), m.Get("nothing").MSISlice()) + assert.Equal(t, val, m.Get("nothing").MSISlice([]map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"})})[0]) + assert.Panics(t, func() { + m.Get("nothing").MustMSISlice() + }) + + o := objx.MustFromJSON(`{"d":[{"author":{"displayName":"DemoUser3","id":2},"classes":null,"id":9879,"v":{"code":"","created":"2013-09-19T09:38:50+02:00","published":"0001-01-01T00:00:00Z","updated":"2013-09-19T09:38:50+02:00"}}],"s":200}`) + assert.Equal(t, 9879, o.Get("d").MustMSISlice()[0]["id"]) + assert.Equal(t, 1, len(o.Get("d").MSISlice())) + + i := objx.MustFromJSON(`{"d":[{"author":"abc"},[1]]}`) + assert.Nil(t, i.Get("d").MSISlice()) +} + +func TestIsMSI(t *testing.T) { + m := objx.Map{"data": map[string]interface{}(map[string]interface{}{"name": "Tyler"})} + + assert.True(t, m.Get("data").IsMSI()) + assert.True(t, m.Value().IsMSI()) +} + +func TestIsMSISlice(t *testing.T) { + val := map[string]interface{}(map[string]interface{}{"name": "Tyler"}) + m := objx.Map{"data": []map[string]interface{}{val}, "data2": []objx.Map{val}} + + assert.True(t, m.Get("data").IsMSISlice()) + assert.True(t, m.Get("data2").IsMSISlice()) + + o := objx.MustFromJSON(`{"d":[{"author":{"displayName":"DemoUser3","id":2},"classes":null,"id":9879,"v":{"code":"","created":"2013-09-19T09:38:50+02:00","published":"0001-01-01T00:00:00Z","updated":"2013-09-19T09:38:50+02:00"}}],"s":200}`) + assert.True(t, o.Has("d")) + assert.True(t, o.Get("d").IsMSISlice()) + + o = objx.MustFromJSON(`{"d":[{"author":"abc"},[1]]}`) + assert.True(t, o.Has("d")) + assert.False(t, o.Get("d").IsMSISlice()) +} + +func TestEachMSI(t *testing.T) { + m := objx.Map{"data": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}} + count := 0 + replacedVals := make([]map[string]interface{}, 0) + assert.Equal(t, m.Get("data"), m.Get("data").EachMSI(func(i int, val map[string]interface{}) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + m2 := objx.Map{"data": []objx.Map{{"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}}} + assert.Equal(t, m2.Get("data"), m2.Get("data").EachMSI(func(i int, val map[string]interface{}) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + assert.Equal(t, count, 6) + assert.Equal(t, replacedVals[0], m.Get("data").MustMSISlice()[0]) + assert.Equal(t, replacedVals[1], m.Get("data").MustMSISlice()[1]) + assert.Equal(t, replacedVals[2], m.Get("data").MustMSISlice()[2]) + assert.Equal(t, replacedVals[3], m2.Get("data").MustMSISlice()[0]) + assert.Equal(t, replacedVals[4], m2.Get("data").MustMSISlice()[1]) + assert.Equal(t, replacedVals[5], m2.Get("data").MustMSISlice()[2]) +} + +func TestWhereMSI(t *testing.T) { + m := objx.Map{"data": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}} + + selected := m.Get("data").WhereMSI(func(i int, val map[string]interface{}) bool { + return i%2 == 0 + }).MustMSISlice() + + assert.Equal(t, 3, len(selected)) +} + +func TestWhereMSI2(t *testing.T) { + m := objx.Map{"data": []objx.Map{{"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}}} + + selected := m.Get("data").WhereMSI(func(i int, val map[string]interface{}) bool { + return i%2 == 0 + }).MustMSISlice() + + assert.Equal(t, 2, len(selected)) +} + +func TestGroupMSI(t *testing.T) { + m := objx.Map{"data": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}} + + grouped := m.Get("data").GroupMSI(func(i int, val map[string]interface{}) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][]map[string]interface{}) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 3, len(grouped["false"])) +} + +func TestGroupMSI2(t *testing.T) { + m := objx.Map{"data": []objx.Map{{"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}}} + + grouped := m.Get("data").GroupMSI(func(i int, val map[string]interface{}) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][]map[string]interface{}) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 2, len(grouped["false"])) +} + +func TestReplaceMSI(t *testing.T) { + m := objx.Map{"data": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}} + rawArr := m.Get("data").MustMSISlice() + + replaced := m.Get("data").ReplaceMSI(func(index int, val map[string]interface{}) map[string]interface{} { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustMSISlice() + + if assert.Equal(t, 6, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[5]) + assert.Equal(t, replacedArr[5], rawArr[0]) + } +} + +func TestReplaceMSI2(t *testing.T) { + m := objx.Map{"data": []objx.Map{{"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}}} + rawArr := m.Get("data").MustMSISlice() + + replaced := m.Get("data").ReplaceMSI(func(index int, val map[string]interface{}) map[string]interface{} { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustMSISlice() + + if assert.Equal(t, 5, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[0]) + } +} + +func TestCollectMSI(t *testing.T) { + m := objx.Map{"data": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}} + + collected := m.Get("data").CollectMSI(func(index int, val map[string]interface{}) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 6, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + assert.Equal(t, collectedArr[5], 5) + } +} + +func TestCollectMSI2(t *testing.T) { + m := objx.Map{"data": []objx.Map{{"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}}} + + collected := m.Get("data").CollectMSI(func(index int, val map[string]interface{}) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 5, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + } +} + +/* + Tests for ObjxMap ((objx.Map) and [](objx.Map)) +*/ +func TestObjxMap(t *testing.T) { + val := (objx.Map)(objx.New(1)) + m := objx.Map{"value": val, "value2": map[string]interface{}{"name": "Taylor"}, "nothing": nil} + valMSI := objx.Map{"name": "Taylor"} + + assert.Equal(t, val, m.Get("value").ObjxMap()) + assert.Equal(t, valMSI, m.Get("value2").ObjxMap()) + assert.Equal(t, val, m.Get("value").MustObjxMap()) + assert.Equal(t, valMSI, m.Get("value2").MustObjxMap()) + assert.Equal(t, (objx.Map)(objx.New(nil)), m.Get("nothing").ObjxMap()) + assert.Equal(t, val, m.Get("nothing").ObjxMap(objx.New(1))) + assert.Panics(t, func() { + m.Get("age").MustObjxMap() + }) +} + +func TestObjxMapSlice(t *testing.T) { + val := (objx.Map)(objx.New(1)) + m := objx.Map{ + "value": [](objx.Map){val}, + "value2": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Taylor"})}, + "value3": []interface{}{val}, + "value4": []interface{}{map[string]interface{}(map[string]interface{}{"name": "Taylor"})}, + "nothing": nil, + } + valMSI := objx.Map{"name": "Taylor"} + + assert.Equal(t, val, m.Get("value").ObjxMapSlice()[0]) + assert.Equal(t, valMSI, m.Get("value2").ObjxMapSlice()[0]) + assert.Equal(t, val, m.Get("value3").ObjxMapSlice()[0]) + assert.Equal(t, valMSI, m.Get("value4").ObjxMapSlice()[0]) + assert.Equal(t, val, m.Get("value").MustObjxMapSlice()[0]) + assert.Equal(t, valMSI, m.Get("value2").MustObjxMapSlice()[0]) + assert.Equal(t, val, m.Get("value3").MustObjxMapSlice()[0]) + assert.Equal(t, valMSI, m.Get("value4").MustObjxMapSlice()[0]) + assert.Equal(t, [](objx.Map)(nil), m.Get("nothing").ObjxMapSlice()) + assert.Equal(t, val, m.Get("nothing").ObjxMapSlice([](objx.Map){(objx.Map)(objx.New(1))})[0]) + assert.Panics(t, func() { + m.Get("nothing").MustObjxMapSlice() + }) + + o := objx.MustFromJSON(`{"d":[{"author":{"displayName":"DemoUser3","id":2},"classes":null,"id":9879,"v":{"code":"","created":"2013-09-19T09:38:50+02:00","published":"0001-01-01T00:00:00Z","updated":"2013-09-19T09:38:50+02:00"}}],"s":200}`) + assert.Equal(t, 9879, o.Get("d").MustObjxMapSlice()[0].Get("id").Int()) + assert.Equal(t, 1, len(o.Get("d").ObjxMapSlice())) + + i := objx.MustFromJSON(`{"d":[{"author":"abc"},[1]]}`) + assert.Nil(t, i.Get("d").ObjxMapSlice()) +} + +func TestIsObjxMap(t *testing.T) { + m := objx.Map{"data": (objx.Map)(objx.New(1)), "data2": map[string]interface{}{"name": "Taylor"}} + + assert.True(t, m.Get("data").IsObjxMap()) + assert.True(t, m.Get("data2").IsObjxMap()) +} + +func TestIsObjxMapSlice(t *testing.T) { + m := objx.Map{"data": [](objx.Map){(objx.Map)(objx.New(1))}, "data2": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Taylor"})}} + + assert.True(t, m.Get("data").IsObjxMapSlice()) + assert.True(t, m.Get("data2").IsObjxMapSlice()) + + o := objx.MustFromJSON(`{"d":[{"author":{"displayName":"DemoUser3","id":2},"classes":null,"id":9879,"v":{"code":"","created":"2013-09-19T09:38:50+02:00","published":"0001-01-01T00:00:00Z","updated":"2013-09-19T09:38:50+02:00"}}],"s":200}`) + assert.True(t, o.Has("d")) + assert.True(t, o.Get("d").IsObjxMapSlice()) + + //Valid json but not MSI slice + o = objx.MustFromJSON(`{"d":[{"author":"abc"},[1]]}`) + assert.True(t, o.Has("d")) + assert.False(t, o.Get("d").IsObjxMapSlice()) +} + +func TestEachObjxMap(t *testing.T) { + m := objx.Map{"data": [](objx.Map){(objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1))}} + count := 0 + replacedVals := make([](objx.Map), 0) + assert.Equal(t, m.Get("data"), m.Get("data").EachObjxMap(func(i int, val objx.Map) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + m2 := objx.Map{"data": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}} + assert.Equal(t, m2.Get("data"), m2.Get("data").EachObjxMap(func(i int, val objx.Map) bool { + count++ + replacedVals = append(replacedVals, val) + + // abort early + return i != 2 + })) + + assert.Equal(t, count, 6) + assert.Equal(t, replacedVals[0], m.Get("data").MustObjxMapSlice()[0]) + assert.Equal(t, replacedVals[1], m.Get("data").MustObjxMapSlice()[1]) + assert.Equal(t, replacedVals[2], m.Get("data").MustObjxMapSlice()[2]) + assert.Equal(t, replacedVals[3], m2.Get("data").MustObjxMapSlice()[0]) + assert.Equal(t, replacedVals[4], m2.Get("data").MustObjxMapSlice()[1]) + assert.Equal(t, replacedVals[5], m2.Get("data").MustObjxMapSlice()[2]) +} + +func TestWhereObjxMap(t *testing.T) { + m := objx.Map{"data": [](objx.Map){(objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1))}} + + selected := m.Get("data").WhereObjxMap(func(i int, val objx.Map) bool { + return i%2 == 0 + }).MustObjxMapSlice() + + assert.Equal(t, 3, len(selected)) +} + +func TestWhereObjxMap2(t *testing.T) { + m := objx.Map{"data": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}} + + selected := m.Get("data").WhereObjxMap(func(i int, val objx.Map) bool { + return i%2 == 0 + }).MustObjxMapSlice() + + assert.Equal(t, 2, len(selected)) +} + +func TestGroupObjxMap(t *testing.T) { + m := objx.Map{"data": [](objx.Map){(objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1))}} + + grouped := m.Get("data").GroupObjxMap(func(i int, val objx.Map) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][](objx.Map)) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 3, len(grouped["false"])) +} + +func TestGroupObjxMap2(t *testing.T) { + m := objx.Map{"data": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}} + + grouped := m.Get("data").GroupObjxMap(func(i int, val objx.Map) string { + return fmt.Sprintf("%v", i%2 == 0) + }).Data().(map[string][](objx.Map)) + + assert.Equal(t, 2, len(grouped)) + assert.Equal(t, 3, len(grouped["true"])) + assert.Equal(t, 2, len(grouped["false"])) +} + +func TestReplaceObjxMap(t *testing.T) { + m := objx.Map{"data": [](objx.Map){(objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1))}} + rawArr := m.Get("data").MustObjxMapSlice() + + replaced := m.Get("data").ReplaceObjxMap(func(index int, val objx.Map) objx.Map { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustObjxMapSlice() + + if assert.Equal(t, 6, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[5]) + assert.Equal(t, replacedArr[5], rawArr[0]) + } +} + +func TestReplaceObjxMap2(t *testing.T) { + m := objx.Map{"data": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}} + rawArr := m.Get("data").MustObjxMapSlice() + + replaced := m.Get("data").ReplaceObjxMap(func(index int, val objx.Map) objx.Map { + if index < len(rawArr)-1 { + return rawArr[index+1] + } + return rawArr[0] + }) + replacedArr := replaced.MustObjxMapSlice() + + if assert.Equal(t, 5, len(replacedArr)) { + assert.Equal(t, replacedArr[0], rawArr[1]) + assert.Equal(t, replacedArr[1], rawArr[2]) + assert.Equal(t, replacedArr[2], rawArr[3]) + assert.Equal(t, replacedArr[3], rawArr[4]) + assert.Equal(t, replacedArr[4], rawArr[0]) + } +} + +func TestCollectObjxMap(t *testing.T) { + m := objx.Map{"data": [](objx.Map){(objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1))}} + + collected := m.Get("data").CollectObjxMap(func(index int, val objx.Map) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 6, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + assert.Equal(t, collectedArr[5], 5) + } +} + +func TestCollectObjxMap2(t *testing.T) { + m := objx.Map{"data": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}} + + collected := m.Get("data").CollectObjxMap(func(index int, val objx.Map) interface{} { + return index + }) + collectedArr := collected.MustInterSlice() + + if assert.Equal(t, 5, len(collectedArr)) { + assert.Equal(t, collectedArr[0], 0) + assert.Equal(t, collectedArr[1], 1) + assert.Equal(t, collectedArr[2], 2) + assert.Equal(t, collectedArr[3], 3) + assert.Equal(t, collectedArr[4], 4) + } +} diff --git a/vendor/github.com/stretchr/objx/value.go b/vendor/github.com/stretchr/objx/value.go new file mode 100644 index 0000000..4e5f9b7 --- /dev/null +++ b/vendor/github.com/stretchr/objx/value.go @@ -0,0 +1,159 @@ +package objx + +import ( + "fmt" + "strconv" +) + +// Value provides methods for extracting interface{} data in various +// types. +type Value struct { + // data contains the raw data being managed by this Value + data interface{} +} + +// Data returns the raw data contained by this Value +func (v *Value) Data() interface{} { + return v.data +} + +// String returns the value always as a string +func (v *Value) String() string { + switch { + case v.IsNil(): + return "" + case v.IsStr(): + return v.Str() + case v.IsBool(): + return strconv.FormatBool(v.Bool()) + case v.IsFloat32(): + return strconv.FormatFloat(float64(v.Float32()), 'f', -1, 32) + case v.IsFloat64(): + return strconv.FormatFloat(v.Float64(), 'f', -1, 64) + case v.IsInt(): + return strconv.FormatInt(int64(v.Int()), 10) + case v.IsInt8(): + return strconv.FormatInt(int64(v.Int8()), 10) + case v.IsInt16(): + return strconv.FormatInt(int64(v.Int16()), 10) + case v.IsInt32(): + return strconv.FormatInt(int64(v.Int32()), 10) + case v.IsInt64(): + return strconv.FormatInt(v.Int64(), 10) + case v.IsUint(): + return strconv.FormatUint(uint64(v.Uint()), 10) + case v.IsUint8(): + return strconv.FormatUint(uint64(v.Uint8()), 10) + case v.IsUint16(): + return strconv.FormatUint(uint64(v.Uint16()), 10) + case v.IsUint32(): + return strconv.FormatUint(uint64(v.Uint32()), 10) + case v.IsUint64(): + return strconv.FormatUint(v.Uint64(), 10) + } + return fmt.Sprintf("%#v", v.Data()) +} + +// StringSlice returns the value always as a []string +func (v *Value) StringSlice(optionalDefault ...[]string) []string { + switch { + case v.IsStrSlice(): + return v.MustStrSlice() + case v.IsBoolSlice(): + slice := v.MustBoolSlice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatBool(iv) + } + return vals + case v.IsFloat32Slice(): + slice := v.MustFloat32Slice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatFloat(float64(iv), 'f', -1, 32) + } + return vals + case v.IsFloat64Slice(): + slice := v.MustFloat64Slice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatFloat(iv, 'f', -1, 64) + } + return vals + case v.IsIntSlice(): + slice := v.MustIntSlice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatInt(int64(iv), 10) + } + return vals + case v.IsInt8Slice(): + slice := v.MustInt8Slice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatInt(int64(iv), 10) + } + return vals + case v.IsInt16Slice(): + slice := v.MustInt16Slice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatInt(int64(iv), 10) + } + return vals + case v.IsInt32Slice(): + slice := v.MustInt32Slice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatInt(int64(iv), 10) + } + return vals + case v.IsInt64Slice(): + slice := v.MustInt64Slice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatInt(iv, 10) + } + return vals + case v.IsUintSlice(): + slice := v.MustUintSlice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatUint(uint64(iv), 10) + } + return vals + case v.IsUint8Slice(): + slice := v.MustUint8Slice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatUint(uint64(iv), 10) + } + return vals + case v.IsUint16Slice(): + slice := v.MustUint16Slice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatUint(uint64(iv), 10) + } + return vals + case v.IsUint32Slice(): + slice := v.MustUint32Slice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatUint(uint64(iv), 10) + } + return vals + case v.IsUint64Slice(): + slice := v.MustUint64Slice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatUint(iv, 10) + } + return vals + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + + return []string{} +} diff --git a/vendor/github.com/stretchr/objx/value_test.go b/vendor/github.com/stretchr/objx/value_test.go new file mode 100644 index 0000000..898a59a --- /dev/null +++ b/vendor/github.com/stretchr/objx/value_test.go @@ -0,0 +1,143 @@ +package objx_test + +import ( + "testing" + + "github.com/stretchr/objx" + "github.com/stretchr/testify/assert" +) + +func TestStringTypeString(t *testing.T) { + m := objx.Map{ + "string": "foo", + } + + assert.Equal(t, "foo", m.Get("string").String()) +} + +func TestStringTypeBool(t *testing.T) { + m := objx.Map{ + "bool": true, + } + + assert.Equal(t, "true", m.Get("bool").String()) +} + +func TestStringTypeInt(t *testing.T) { + m := objx.Map{ + "int": int(1), + "int8": int8(8), + "int16": int16(16), + "int32": int32(32), + "int64": int64(64), + } + + assert.Equal(t, "1", m.Get("int").String()) + assert.Equal(t, "8", m.Get("int8").String()) + assert.Equal(t, "16", m.Get("int16").String()) + assert.Equal(t, "32", m.Get("int32").String()) + assert.Equal(t, "64", m.Get("int64").String()) +} + +func TestStringTypeUint(t *testing.T) { + m := objx.Map{ + "uint": uint(1), + "uint8": uint8(8), + "uint16": uint16(16), + "uint32": uint32(32), + "uint64": uint64(64), + } + + assert.Equal(t, "1", m.Get("uint").String()) + assert.Equal(t, "8", m.Get("uint8").String()) + assert.Equal(t, "16", m.Get("uint16").String()) + assert.Equal(t, "32", m.Get("uint32").String()) + assert.Equal(t, "64", m.Get("uint64").String()) +} + +func TestStringTypeFloat(t *testing.T) { + m := objx.Map{ + "float32": float32(32.32), + "float64": float64(64.64), + } + + assert.Equal(t, "32.32", m.Get("float32").String()) + assert.Equal(t, "64.64", m.Get("float64").String()) +} + +func TestStringTypeOther(t *testing.T) { + m := objx.Map{ + "other": []string{"foo", "bar"}, + "nilValue": nil, + } + + assert.Equal(t, "[]string{\"foo\", \"bar\"}", m.Get("other").String()) + assert.Equal(t, "", m.Get("nilValue").String()) +} + +func TestStringSliceTypeString(t *testing.T) { + m := objx.Map{ + "string": []string{"foo", "bar"}, + } + + assert.Equal(t, []string{"foo", "bar"}, m.Get("string").StringSlice()) +} + +func TestStringSliceTypeBool(t *testing.T) { + m := objx.Map{ + "bool": []bool{true, false}, + } + + assert.Equal(t, []string{"true", "false"}, m.Get("bool").StringSlice()) +} + +func TestStringSliceTypeInt(t *testing.T) { + m := objx.Map{ + "int": []int{1, 2}, + "int8": []int8{8, 9}, + "int16": []int16{16, 17}, + "int32": []int32{32, 33}, + "int64": []int64{64, 65}, + } + + assert.Equal(t, []string{"1", "2"}, m.Get("int").StringSlice()) + assert.Equal(t, []string{"8", "9"}, m.Get("int8").StringSlice()) + assert.Equal(t, []string{"16", "17"}, m.Get("int16").StringSlice()) + assert.Equal(t, []string{"32", "33"}, m.Get("int32").StringSlice()) + assert.Equal(t, []string{"64", "65"}, m.Get("int64").StringSlice()) +} + +func TestStringSliceTypeUint(t *testing.T) { + m := objx.Map{ + "uint": []uint{1, 2}, + "uint8": []uint8{8, 9}, + "uint16": []uint16{16, 17}, + "uint32": []uint32{32, 33}, + "uint64": []uint64{64, 65}, + } + + assert.Equal(t, []string{"1", "2"}, m.Get("uint").StringSlice()) + assert.Equal(t, []string{"8", "9"}, m.Get("uint8").StringSlice()) + assert.Equal(t, []string{"16", "17"}, m.Get("uint16").StringSlice()) + assert.Equal(t, []string{"32", "33"}, m.Get("uint32").StringSlice()) + assert.Equal(t, []string{"64", "65"}, m.Get("uint64").StringSlice()) +} + +func TestStringSliceTypeFloat(t *testing.T) { + m := objx.Map{ + "float32": []float32{32.32, 33.33}, + "float64": []float64{64.64, 65.65}, + } + + assert.Equal(t, []string{"32.32", "33.33"}, m.Get("float32").StringSlice()) + assert.Equal(t, []string{"64.64", "65.65"}, m.Get("float64").StringSlice()) +} + +func TestStringSliceTypeOther(t *testing.T) { + m := objx.Map{ + "other": "foo", + } + + assert.Equal(t, []string{}, m.Get("other").StringSlice()) + assert.Equal(t, []string{"bar"}, m.Get("other").StringSlice([]string{"bar"})) +} diff --git a/vendor/github.com/stretchr/testify/mock/doc.go b/vendor/github.com/stretchr/testify/mock/doc.go new file mode 100644 index 0000000..7324128 --- /dev/null +++ b/vendor/github.com/stretchr/testify/mock/doc.go @@ -0,0 +1,44 @@ +// Package mock provides a system by which it is possible to mock your objects +// and verify calls are happening as expected. +// +// Example Usage +// +// The mock package provides an object, Mock, that tracks activity on another object. It is usually +// embedded into a test object as shown below: +// +// type MyTestObject struct { +// // add a Mock object instance +// mock.Mock +// +// // other fields go here as normal +// } +// +// When implementing the methods of an interface, you wire your functions up +// to call the Mock.Called(args...) method, and return the appropriate values. +// +// For example, to mock a method that saves the name and age of a person and returns +// the year of their birth or an error, you might write this: +// +// func (o *MyTestObject) SavePersonDetails(firstname, lastname string, age int) (int, error) { +// args := o.Called(firstname, lastname, age) +// return args.Int(0), args.Error(1) +// } +// +// The Int, Error and Bool methods are examples of strongly typed getters that take the argument +// index position. Given this argument list: +// +// (12, true, "Something") +// +// You could read them out strongly typed like this: +// +// args.Int(0) +// args.Bool(1) +// args.String(2) +// +// For objects of your own type, use the generic Arguments.Get(index) method and make a type assertion: +// +// return args.Get(0).(*MyObject), args.Get(1).(*AnotherObjectOfMine) +// +// This may cause a panic if the object you are getting is nil (the type assertion will fail), in those +// cases you should check for nil first. +package mock diff --git a/vendor/github.com/stretchr/testify/mock/mock.go b/vendor/github.com/stretchr/testify/mock/mock.go new file mode 100644 index 0000000..d6694ed --- /dev/null +++ b/vendor/github.com/stretchr/testify/mock/mock.go @@ -0,0 +1,886 @@ +package mock + +import ( + "errors" + "fmt" + "reflect" + "regexp" + "runtime" + "strings" + "sync" + "time" + + "github.com/davecgh/go-spew/spew" + "github.com/pmezard/go-difflib/difflib" + "github.com/stretchr/objx" + "github.com/stretchr/testify/assert" +) + +// TestingT is an interface wrapper around *testing.T +type TestingT interface { + Logf(format string, args ...interface{}) + Errorf(format string, args ...interface{}) + FailNow() +} + +/* + Call +*/ + +// Call represents a method call and is used for setting expectations, +// as well as recording activity. +type Call struct { + Parent *Mock + + // The name of the method that was or will be called. + Method string + + // Holds the arguments of the method. + Arguments Arguments + + // Holds the arguments that should be returned when + // this method is called. + ReturnArguments Arguments + + // Holds the caller info for the On() call + callerInfo []string + + // The number of times to return the return arguments when setting + // expectations. 0 means to always return the value. + Repeatability int + + // Amount of times this call has been called + totalCalls int + + // Call to this method can be optional + optional bool + + // Holds a channel that will be used to block the Return until it either + // receives a message or is closed. nil means it returns immediately. + WaitFor <-chan time.Time + + waitTime time.Duration + + // Holds a handler used to manipulate arguments content that are passed by + // reference. It's useful when mocking methods such as unmarshalers or + // decoders. + RunFn func(Arguments) +} + +func newCall(parent *Mock, methodName string, callerInfo []string, methodArguments ...interface{}) *Call { + return &Call{ + Parent: parent, + Method: methodName, + Arguments: methodArguments, + ReturnArguments: make([]interface{}, 0), + callerInfo: callerInfo, + Repeatability: 0, + WaitFor: nil, + RunFn: nil, + } +} + +func (c *Call) lock() { + c.Parent.mutex.Lock() +} + +func (c *Call) unlock() { + c.Parent.mutex.Unlock() +} + +// Return specifies the return arguments for the expectation. +// +// Mock.On("DoSomething").Return(errors.New("failed")) +func (c *Call) Return(returnArguments ...interface{}) *Call { + c.lock() + defer c.unlock() + + c.ReturnArguments = returnArguments + + return c +} + +// Once indicates that that the mock should only return the value once. +// +// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once() +func (c *Call) Once() *Call { + return c.Times(1) +} + +// Twice indicates that that the mock should only return the value twice. +// +// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice() +func (c *Call) Twice() *Call { + return c.Times(2) +} + +// Times indicates that that the mock should only return the indicated number +// of times. +// +// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5) +func (c *Call) Times(i int) *Call { + c.lock() + defer c.unlock() + c.Repeatability = i + return c +} + +// WaitUntil sets the channel that will block the mock's return until its closed +// or a message is received. +// +// Mock.On("MyMethod", arg1, arg2).WaitUntil(time.After(time.Second)) +func (c *Call) WaitUntil(w <-chan time.Time) *Call { + c.lock() + defer c.unlock() + c.WaitFor = w + return c +} + +// After sets how long to block until the call returns +// +// Mock.On("MyMethod", arg1, arg2).After(time.Second) +func (c *Call) After(d time.Duration) *Call { + c.lock() + defer c.unlock() + c.waitTime = d + return c +} + +// Run sets a handler to be called before returning. It can be used when +// mocking a method such as unmarshalers that takes a pointer to a struct and +// sets properties in such struct +// +// Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}").Return().Run(func(args Arguments) { +// arg := args.Get(0).(*map[string]interface{}) +// arg["foo"] = "bar" +// }) +func (c *Call) Run(fn func(args Arguments)) *Call { + c.lock() + defer c.unlock() + c.RunFn = fn + return c +} + +// Maybe allows the method call to be optional. Not calling an optional method +// will not cause an error while asserting expectations +func (c *Call) Maybe() *Call { + c.lock() + defer c.unlock() + c.optional = true + return c +} + +// On chains a new expectation description onto the mocked interface. This +// allows syntax like. +// +// Mock. +// On("MyMethod", 1).Return(nil). +// On("MyOtherMethod", 'a', 'b', 'c').Return(errors.New("Some Error")) +//go:noinline +func (c *Call) On(methodName string, arguments ...interface{}) *Call { + return c.Parent.On(methodName, arguments...) +} + +// Mock is the workhorse used to track activity on another object. +// For an example of its usage, refer to the "Example Usage" section at the top +// of this document. +type Mock struct { + // Represents the calls that are expected of + // an object. + ExpectedCalls []*Call + + // Holds the calls that were made to this mocked object. + Calls []Call + + // test is An optional variable that holds the test struct, to be used when an + // invalid mock call was made. + test TestingT + + // TestData holds any data that might be useful for testing. Testify ignores + // this data completely allowing you to do whatever you like with it. + testData objx.Map + + mutex sync.Mutex +} + +// TestData holds any data that might be useful for testing. Testify ignores +// this data completely allowing you to do whatever you like with it. +func (m *Mock) TestData() objx.Map { + + if m.testData == nil { + m.testData = make(objx.Map) + } + + return m.testData +} + +/* + Setting expectations +*/ + +// Test sets the test struct variable of the mock object +func (m *Mock) Test(t TestingT) { + m.mutex.Lock() + defer m.mutex.Unlock() + m.test = t +} + +// fail fails the current test with the given formatted format and args. +// In case that a test was defined, it uses the test APIs for failing a test, +// otherwise it uses panic. +func (m *Mock) fail(format string, args ...interface{}) { + m.mutex.Lock() + defer m.mutex.Unlock() + + if m.test == nil { + panic(fmt.Sprintf(format, args...)) + } + m.test.Errorf(format, args...) + m.test.FailNow() +} + +// On starts a description of an expectation of the specified method +// being called. +// +// Mock.On("MyMethod", arg1, arg2) +func (m *Mock) On(methodName string, arguments ...interface{}) *Call { + for _, arg := range arguments { + if v := reflect.ValueOf(arg); v.Kind() == reflect.Func { + panic(fmt.Sprintf("cannot use Func in expectations. Use mock.AnythingOfType(\"%T\")", arg)) + } + } + + m.mutex.Lock() + defer m.mutex.Unlock() + c := newCall(m, methodName, assert.CallerInfo(), arguments...) + m.ExpectedCalls = append(m.ExpectedCalls, c) + return c +} + +// /* +// Recording and responding to activity +// */ + +func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) { + for i, call := range m.ExpectedCalls { + if call.Method == method && call.Repeatability > -1 { + + _, diffCount := call.Arguments.Diff(arguments) + if diffCount == 0 { + return i, call + } + + } + } + return -1, nil +} + +func (m *Mock) findClosestCall(method string, arguments ...interface{}) (*Call, string) { + var diffCount int + var closestCall *Call + var err string + + for _, call := range m.expectedCalls() { + if call.Method == method { + + errInfo, tempDiffCount := call.Arguments.Diff(arguments) + if tempDiffCount < diffCount || diffCount == 0 { + diffCount = tempDiffCount + closestCall = call + err = errInfo + } + + } + } + + return closestCall, err +} + +func callString(method string, arguments Arguments, includeArgumentValues bool) string { + + var argValsString string + if includeArgumentValues { + var argVals []string + for argIndex, arg := range arguments { + argVals = append(argVals, fmt.Sprintf("%d: %#v", argIndex, arg)) + } + argValsString = fmt.Sprintf("\n\t\t%s", strings.Join(argVals, "\n\t\t")) + } + + return fmt.Sprintf("%s(%s)%s", method, arguments.String(), argValsString) +} + +// Called tells the mock object that a method has been called, and gets an array +// of arguments to return. Panics if the call is unexpected (i.e. not preceded by +// appropriate .On .Return() calls) +// If Call.WaitFor is set, blocks until the channel is closed or receives a message. +func (m *Mock) Called(arguments ...interface{}) Arguments { + // get the calling function's name + pc, _, _, ok := runtime.Caller(1) + if !ok { + panic("Couldn't get the caller information") + } + functionPath := runtime.FuncForPC(pc).Name() + //Next four lines are required to use GCCGO function naming conventions. + //For Ex: github_com_docker_libkv_store_mock.WatchTree.pN39_github_com_docker_libkv_store_mock.Mock + //uses interface information unlike golang github.com/docker/libkv/store/mock.(*Mock).WatchTree + //With GCCGO we need to remove interface information starting from pN
. + re := regexp.MustCompile("\\.pN\\d+_") + if re.MatchString(functionPath) { + functionPath = re.Split(functionPath, -1)[0] + } + parts := strings.Split(functionPath, ".") + functionName := parts[len(parts)-1] + return m.MethodCalled(functionName, arguments...) +} + +// MethodCalled tells the mock object that the given method has been called, and gets +// an array of arguments to return. Panics if the call is unexpected (i.e. not preceded +// by appropriate .On .Return() calls) +// If Call.WaitFor is set, blocks until the channel is closed or receives a message. +func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Arguments { + m.mutex.Lock() + //TODO: could combine expected and closes in single loop + found, call := m.findExpectedCall(methodName, arguments...) + + if found < 0 { + // we have to fail here - because we don't know what to do + // as the return arguments. This is because: + // + // a) this is a totally unexpected call to this method, + // b) the arguments are not what was expected, or + // c) the developer has forgotten to add an accompanying On...Return pair. + + closestCall, mismatch := m.findClosestCall(methodName, arguments...) + m.mutex.Unlock() + + if closestCall != nil { + m.fail("\n\nmock: Unexpected Method Call\n-----------------------------\n\n%s\n\nThe closest call I have is: \n\n%s\n\n%s\nDiff: %s", + callString(methodName, arguments, true), + callString(methodName, closestCall.Arguments, true), + diffArguments(closestCall.Arguments, arguments), + strings.TrimSpace(mismatch), + ) + } else { + m.fail("\nassert: mock: I don't know what to return because the method call was unexpected.\n\tEither do Mock.On(\"%s\").Return(...) first, or remove the %s() call.\n\tThis method was unexpected:\n\t\t%s\n\tat: %s", methodName, methodName, callString(methodName, arguments, true), assert.CallerInfo()) + } + } + + if call.Repeatability == 1 { + call.Repeatability = -1 + } else if call.Repeatability > 1 { + call.Repeatability-- + } + call.totalCalls++ + + // add the call + m.Calls = append(m.Calls, *newCall(m, methodName, assert.CallerInfo(), arguments...)) + m.mutex.Unlock() + + // block if specified + if call.WaitFor != nil { + <-call.WaitFor + } else { + time.Sleep(call.waitTime) + } + + m.mutex.Lock() + runFn := call.RunFn + m.mutex.Unlock() + + if runFn != nil { + runFn(arguments) + } + + m.mutex.Lock() + returnArgs := call.ReturnArguments + m.mutex.Unlock() + + return returnArgs +} + +/* + Assertions +*/ + +type assertExpectationser interface { + AssertExpectations(TestingT) bool +} + +// AssertExpectationsForObjects asserts that everything specified with On and Return +// of the specified objects was in fact called as expected. +// +// Calls may have occurred in any order. +func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + for _, obj := range testObjects { + if m, ok := obj.(Mock); ok { + t.Logf("Deprecated mock.AssertExpectationsForObjects(myMock.Mock) use mock.AssertExpectationsForObjects(myMock)") + obj = &m + } + m := obj.(assertExpectationser) + if !m.AssertExpectations(t) { + t.Logf("Expectations didn't match for Mock: %+v", reflect.TypeOf(m)) + return false + } + } + return true +} + +// AssertExpectations asserts that everything specified with On and Return was +// in fact called as expected. Calls may have occurred in any order. +func (m *Mock) AssertExpectations(t TestingT) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + m.mutex.Lock() + defer m.mutex.Unlock() + var somethingMissing bool + var failedExpectations int + + // iterate through each expectation + expectedCalls := m.expectedCalls() + for _, expectedCall := range expectedCalls { + if !expectedCall.optional && !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments) && expectedCall.totalCalls == 0 { + somethingMissing = true + failedExpectations++ + t.Logf("FAIL:\t%s(%s)\n\t\tat: %s", expectedCall.Method, expectedCall.Arguments.String(), expectedCall.callerInfo) + } else { + if expectedCall.Repeatability > 0 { + somethingMissing = true + failedExpectations++ + t.Logf("FAIL:\t%s(%s)\n\t\tat: %s", expectedCall.Method, expectedCall.Arguments.String(), expectedCall.callerInfo) + } else { + t.Logf("PASS:\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String()) + } + } + } + + if somethingMissing { + t.Errorf("FAIL: %d out of %d expectation(s) were met.\n\tThe code you are testing needs to make %d more call(s).\n\tat: %s", len(expectedCalls)-failedExpectations, len(expectedCalls), failedExpectations, assert.CallerInfo()) + } + + return !somethingMissing +} + +// AssertNumberOfCalls asserts that the method was called expectedCalls times. +func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + m.mutex.Lock() + defer m.mutex.Unlock() + var actualCalls int + for _, call := range m.calls() { + if call.Method == methodName { + actualCalls++ + } + } + return assert.Equal(t, expectedCalls, actualCalls, fmt.Sprintf("Expected number of calls (%d) does not match the actual number of calls (%d).", expectedCalls, actualCalls)) +} + +// AssertCalled asserts that the method was called. +// It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method. +func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + m.mutex.Lock() + defer m.mutex.Unlock() + if !m.methodWasCalled(methodName, arguments) { + var calledWithArgs []string + for _, call := range m.calls() { + calledWithArgs = append(calledWithArgs, fmt.Sprintf("%v", call.Arguments)) + } + if len(calledWithArgs) == 0 { + return assert.Fail(t, "Should have called with given arguments", + fmt.Sprintf("Expected %q to have been called with:\n%v\nbut no actual calls happened", methodName, arguments)) + } + return assert.Fail(t, "Should have called with given arguments", + fmt.Sprintf("Expected %q to have been called with:\n%v\nbut actual calls were:\n %v", methodName, arguments, strings.Join(calledWithArgs, "\n"))) + } + return true +} + +// AssertNotCalled asserts that the method was not called. +// It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method. +func (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + m.mutex.Lock() + defer m.mutex.Unlock() + if m.methodWasCalled(methodName, arguments) { + return assert.Fail(t, "Should not have called with given arguments", + fmt.Sprintf("Expected %q to not have been called with:\n%v\nbut actually it was.", methodName, arguments)) + } + return true +} + +func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool { + for _, call := range m.calls() { + if call.Method == methodName { + + _, differences := Arguments(expected).Diff(call.Arguments) + + if differences == 0 { + // found the expected call + return true + } + + } + } + // we didn't find the expected call + return false +} + +func (m *Mock) expectedCalls() []*Call { + return append([]*Call{}, m.ExpectedCalls...) +} + +func (m *Mock) calls() []Call { + return append([]Call{}, m.Calls...) +} + +/* + Arguments +*/ + +// Arguments holds an array of method arguments or return values. +type Arguments []interface{} + +const ( + // Anything is used in Diff and Assert when the argument being tested + // shouldn't be taken into consideration. + Anything = "mock.Anything" +) + +// AnythingOfTypeArgument is a string that contains the type of an argument +// for use when type checking. Used in Diff and Assert. +type AnythingOfTypeArgument string + +// AnythingOfType returns an AnythingOfTypeArgument object containing the +// name of the type to check for. Used in Diff and Assert. +// +// For example: +// Assert(t, AnythingOfType("string"), AnythingOfType("int")) +func AnythingOfType(t string) AnythingOfTypeArgument { + return AnythingOfTypeArgument(t) +} + +// argumentMatcher performs custom argument matching, returning whether or +// not the argument is matched by the expectation fixture function. +type argumentMatcher struct { + // fn is a function which accepts one argument, and returns a bool. + fn reflect.Value +} + +func (f argumentMatcher) Matches(argument interface{}) bool { + expectType := f.fn.Type().In(0) + expectTypeNilSupported := false + switch expectType.Kind() { + case reflect.Interface, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Ptr: + expectTypeNilSupported = true + } + + argType := reflect.TypeOf(argument) + var arg reflect.Value + if argType == nil { + arg = reflect.New(expectType).Elem() + } else { + arg = reflect.ValueOf(argument) + } + + if argType == nil && !expectTypeNilSupported { + panic(errors.New("attempting to call matcher with nil for non-nil expected type")) + } + if argType == nil || argType.AssignableTo(expectType) { + result := f.fn.Call([]reflect.Value{arg}) + return result[0].Bool() + } + return false +} + +func (f argumentMatcher) String() string { + return fmt.Sprintf("func(%s) bool", f.fn.Type().In(0).Name()) +} + +// MatchedBy can be used to match a mock call based on only certain properties +// from a complex struct or some calculation. It takes a function that will be +// evaluated with the called argument and will return true when there's a match +// and false otherwise. +// +// Example: +// m.On("Do", MatchedBy(func(req *http.Request) bool { return req.Host == "example.com" })) +// +// |fn|, must be a function accepting a single argument (of the expected type) +// which returns a bool. If |fn| doesn't match the required signature, +// MatchedBy() panics. +func MatchedBy(fn interface{}) argumentMatcher { + fnType := reflect.TypeOf(fn) + + if fnType.Kind() != reflect.Func { + panic(fmt.Sprintf("assert: arguments: %s is not a func", fn)) + } + if fnType.NumIn() != 1 { + panic(fmt.Sprintf("assert: arguments: %s does not take exactly one argument", fn)) + } + if fnType.NumOut() != 1 || fnType.Out(0).Kind() != reflect.Bool { + panic(fmt.Sprintf("assert: arguments: %s does not return a bool", fn)) + } + + return argumentMatcher{fn: reflect.ValueOf(fn)} +} + +// Get Returns the argument at the specified index. +func (args Arguments) Get(index int) interface{} { + if index+1 > len(args) { + panic(fmt.Sprintf("assert: arguments: Cannot call Get(%d) because there are %d argument(s).", index, len(args))) + } + return args[index] +} + +// Is gets whether the objects match the arguments specified. +func (args Arguments) Is(objects ...interface{}) bool { + for i, obj := range args { + if obj != objects[i] { + return false + } + } + return true +} + +// Diff gets a string describing the differences between the arguments +// and the specified objects. +// +// Returns the diff string and number of differences found. +func (args Arguments) Diff(objects []interface{}) (string, int) { + //TODO: could return string as error and nil for No difference + + var output = "\n" + var differences int + + var maxArgCount = len(args) + if len(objects) > maxArgCount { + maxArgCount = len(objects) + } + + for i := 0; i < maxArgCount; i++ { + var actual, expected interface{} + var actualFmt, expectedFmt string + + if len(objects) <= i { + actual = "(Missing)" + actualFmt = "(Missing)" + } else { + actual = objects[i] + actualFmt = fmt.Sprintf("(%[1]T=%[1]v)", actual) + } + + if len(args) <= i { + expected = "(Missing)" + expectedFmt = "(Missing)" + } else { + expected = args[i] + expectedFmt = fmt.Sprintf("(%[1]T=%[1]v)", expected) + } + + if matcher, ok := expected.(argumentMatcher); ok { + if matcher.Matches(actual) { + output = fmt.Sprintf("%s\t%d: PASS: %s matched by %s\n", output, i, actualFmt, matcher) + } else { + differences++ + output = fmt.Sprintf("%s\t%d: FAIL: %s not matched by %s\n", output, i, actualFmt, matcher) + } + } else if reflect.TypeOf(expected) == reflect.TypeOf((*AnythingOfTypeArgument)(nil)).Elem() { + + // type checking + if reflect.TypeOf(actual).Name() != string(expected.(AnythingOfTypeArgument)) && reflect.TypeOf(actual).String() != string(expected.(AnythingOfTypeArgument)) { + // not match + differences++ + output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actualFmt) + } + + } else { + + // normal checking + + if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) { + // match + output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, actualFmt, expectedFmt) + } else { + // not match + differences++ + output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, actualFmt, expectedFmt) + } + } + + } + + if differences == 0 { + return "No differences.", differences + } + + return output, differences + +} + +// Assert compares the arguments with the specified objects and fails if +// they do not exactly match. +func (args Arguments) Assert(t TestingT, objects ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + // get the differences + diff, diffCount := args.Diff(objects) + + if diffCount == 0 { + return true + } + + // there are differences... report them... + t.Logf(diff) + t.Errorf("%sArguments do not match.", assert.CallerInfo()) + + return false + +} + +// String gets the argument at the specified index. Panics if there is no argument, or +// if the argument is of the wrong type. +// +// If no index is provided, String() returns a complete string representation +// of the arguments. +func (args Arguments) String(indexOrNil ...int) string { + + if len(indexOrNil) == 0 { + // normal String() method - return a string representation of the args + var argsStr []string + for _, arg := range args { + argsStr = append(argsStr, fmt.Sprintf("%s", reflect.TypeOf(arg))) + } + return strings.Join(argsStr, ",") + } else if len(indexOrNil) == 1 { + // Index has been specified - get the argument at that index + var index = indexOrNil[0] + var s string + var ok bool + if s, ok = args.Get(index).(string); !ok { + panic(fmt.Sprintf("assert: arguments: String(%d) failed because object wasn't correct type: %s", index, args.Get(index))) + } + return s + } + + panic(fmt.Sprintf("assert: arguments: Wrong number of arguments passed to String. Must be 0 or 1, not %d", len(indexOrNil))) + +} + +// Int gets the argument at the specified index. Panics if there is no argument, or +// if the argument is of the wrong type. +func (args Arguments) Int(index int) int { + var s int + var ok bool + if s, ok = args.Get(index).(int); !ok { + panic(fmt.Sprintf("assert: arguments: Int(%d) failed because object wasn't correct type: %v", index, args.Get(index))) + } + return s +} + +// Error gets the argument at the specified index. Panics if there is no argument, or +// if the argument is of the wrong type. +func (args Arguments) Error(index int) error { + obj := args.Get(index) + var s error + var ok bool + if obj == nil { + return nil + } + if s, ok = obj.(error); !ok { + panic(fmt.Sprintf("assert: arguments: Error(%d) failed because object wasn't correct type: %v", index, args.Get(index))) + } + return s +} + +// Bool gets the argument at the specified index. Panics if there is no argument, or +// if the argument is of the wrong type. +func (args Arguments) Bool(index int) bool { + var s bool + var ok bool + if s, ok = args.Get(index).(bool); !ok { + panic(fmt.Sprintf("assert: arguments: Bool(%d) failed because object wasn't correct type: %v", index, args.Get(index))) + } + return s +} + +func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) { + t := reflect.TypeOf(v) + k := t.Kind() + + if k == reflect.Ptr { + t = t.Elem() + k = t.Kind() + } + return t, k +} + +func diffArguments(expected Arguments, actual Arguments) string { + if len(expected) != len(actual) { + return fmt.Sprintf("Provided %v arguments, mocked for %v arguments", len(expected), len(actual)) + } + + for x := range expected { + if diffString := diff(expected[x], actual[x]); diffString != "" { + return fmt.Sprintf("Difference found in argument %v:\n\n%s", x, diffString) + } + } + + return "" +} + +// diff returns a diff of both values as long as both are of the same type and +// are a struct, map, slice or array. Otherwise it returns an empty string. +func diff(expected interface{}, actual interface{}) string { + if expected == nil || actual == nil { + return "" + } + + et, ek := typeAndKind(expected) + at, _ := typeAndKind(actual) + + if et != at { + return "" + } + + if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array { + return "" + } + + e := spewConfig.Sdump(expected) + a := spewConfig.Sdump(actual) + + diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ + A: difflib.SplitLines(e), + B: difflib.SplitLines(a), + FromFile: "Expected", + FromDate: "", + ToFile: "Actual", + ToDate: "", + Context: 1, + }) + + return diff +} + +var spewConfig = spew.ConfigState{ + Indent: " ", + DisablePointerAddresses: true, + DisableCapacities: true, + SortKeys: true, +} + +type tHelper interface { + Helper() +} diff --git a/vendor/github.com/stretchr/testify/mock/mock_test.go b/vendor/github.com/stretchr/testify/mock/mock_test.go new file mode 100644 index 0000000..2608f5a --- /dev/null +++ b/vendor/github.com/stretchr/testify/mock/mock_test.go @@ -0,0 +1,1499 @@ +package mock + +import ( + "errors" + "fmt" + "regexp" + "runtime" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +/* + Test objects +*/ + +// ExampleInterface represents an example interface. +type ExampleInterface interface { + TheExampleMethod(a, b, c int) (int, error) +} + +// TestExampleImplementation is a test implementation of ExampleInterface +type TestExampleImplementation struct { + Mock +} + +func (i *TestExampleImplementation) TheExampleMethod(a, b, c int) (int, error) { + args := i.Called(a, b, c) + return args.Int(0), errors.New("Whoops") +} + +//go:noinline +func (i *TestExampleImplementation) TheExampleMethod2(yesorno bool) { + i.Called(yesorno) +} + +type ExampleType struct { + ran bool +} + +func (i *TestExampleImplementation) TheExampleMethod3(et *ExampleType) error { + args := i.Called(et) + return args.Error(0) +} + +func (i *TestExampleImplementation) TheExampleMethod4(v ExampleInterface) error { + args := i.Called(v) + return args.Error(0) +} + +func (i *TestExampleImplementation) TheExampleMethod5(ch chan struct{}) error { + args := i.Called(ch) + return args.Error(0) +} + +func (i *TestExampleImplementation) TheExampleMethod6(m map[string]bool) error { + args := i.Called(m) + return args.Error(0) +} + +func (i *TestExampleImplementation) TheExampleMethod7(slice []bool) error { + args := i.Called(slice) + return args.Error(0) +} + +func (i *TestExampleImplementation) TheExampleMethodFunc(fn func(string) error) error { + args := i.Called(fn) + return args.Error(0) +} + +func (i *TestExampleImplementation) TheExampleMethodVariadic(a ...int) error { + args := i.Called(a) + return args.Error(0) +} + +func (i *TestExampleImplementation) TheExampleMethodVariadicInterface(a ...interface{}) error { + args := i.Called(a) + return args.Error(0) +} + +func (i *TestExampleImplementation) TheExampleMethodMixedVariadic(a int, b ...int) error { + args := i.Called(a, b) + return args.Error(0) +} + +type ExampleFuncType func(string) error + +func (i *TestExampleImplementation) TheExampleMethodFuncType(fn ExampleFuncType) error { + args := i.Called(fn) + return args.Error(0) +} + +// MockTestingT mocks a test struct +type MockTestingT struct { + logfCount, errorfCount, failNowCount int +} + +const mockTestingTFailNowCalled = "FailNow was called" + +func (m *MockTestingT) Logf(string, ...interface{}) { + m.logfCount++ +} + +func (m *MockTestingT) Errorf(string, ...interface{}) { + m.errorfCount++ +} + +// FailNow mocks the FailNow call. +// It panics in order to mimic the FailNow behavior in the sense that +// the execution stops. +// When expecting this method, the call that invokes it should use the following code: +// +// assert.PanicsWithValue(t, mockTestingTFailNowCalled, func() {...}) +func (m *MockTestingT) FailNow() { + m.failNowCount++ + + // this function should panic now to stop the execution as expected + panic(mockTestingTFailNowCalled) +} + +/* + Mock +*/ + +func Test_Mock_TestData(t *testing.T) { + + var mockedService = new(TestExampleImplementation) + + if assert.NotNil(t, mockedService.TestData()) { + + mockedService.TestData().Set("something", 123) + assert.Equal(t, 123, mockedService.TestData().Get("something").Data()) + } +} + +func Test_Mock_On(t *testing.T) { + + // make a test impl object + var mockedService = new(TestExampleImplementation) + + c := mockedService.On("TheExampleMethod") + assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls) + assert.Equal(t, "TheExampleMethod", c.Method) +} + +func Test_Mock_Chained_On(t *testing.T) { + // make a test impl object + var mockedService = new(TestExampleImplementation) + + // determine our current line number so we can assert the expected calls callerInfo properly + _, _, line, _ := runtime.Caller(0) + mockedService. + On("TheExampleMethod", 1, 2, 3). + Return(0). + On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")). + Return(nil) + + expectedCalls := []*Call{ + { + Parent: &mockedService.Mock, + Method: "TheExampleMethod", + Arguments: []interface{}{1, 2, 3}, + ReturnArguments: []interface{}{0}, + callerInfo: []string{fmt.Sprintf("mock_test.go:%d", line+2)}, + }, + { + Parent: &mockedService.Mock, + Method: "TheExampleMethod3", + Arguments: []interface{}{AnythingOfType("*mock.ExampleType")}, + ReturnArguments: []interface{}{nil}, + callerInfo: []string{fmt.Sprintf("mock_test.go:%d", line+4)}, + }, + } + assert.Equal(t, expectedCalls, mockedService.ExpectedCalls) +} + +func Test_Mock_On_WithArgs(t *testing.T) { + + // make a test impl object + var mockedService = new(TestExampleImplementation) + + c := mockedService.On("TheExampleMethod", 1, 2, 3, 4) + + assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls) + assert.Equal(t, "TheExampleMethod", c.Method) + assert.Equal(t, Arguments{1, 2, 3, 4}, c.Arguments) +} + +func Test_Mock_On_WithFuncArg(t *testing.T) { + + // make a test impl object + var mockedService = new(TestExampleImplementation) + + c := mockedService. + On("TheExampleMethodFunc", AnythingOfType("func(string) error")). + Return(nil) + + assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls) + assert.Equal(t, "TheExampleMethodFunc", c.Method) + assert.Equal(t, 1, len(c.Arguments)) + assert.Equal(t, AnythingOfType("func(string) error"), c.Arguments[0]) + + fn := func(string) error { return nil } + + assert.NotPanics(t, func() { + mockedService.TheExampleMethodFunc(fn) + }) +} + +func Test_Mock_On_WithIntArgMatcher(t *testing.T) { + var mockedService TestExampleImplementation + + mockedService.On("TheExampleMethod", + MatchedBy(func(a int) bool { + return a == 1 + }), MatchedBy(func(b int) bool { + return b == 2 + }), MatchedBy(func(c int) bool { + return c == 3 + })).Return(0, nil) + + assert.Panics(t, func() { + mockedService.TheExampleMethod(1, 2, 4) + }) + assert.Panics(t, func() { + mockedService.TheExampleMethod(2, 2, 3) + }) + assert.NotPanics(t, func() { + mockedService.TheExampleMethod(1, 2, 3) + }) +} + +func TestMock_WithTest(t *testing.T) { + var ( + mockedService TestExampleImplementation + mockedTest MockTestingT + ) + + mockedService.Test(&mockedTest) + mockedService.On("TheExampleMethod", 1, 2, 3).Return(0, nil) + + // Test that on an expected call, the test was not failed + + mockedService.TheExampleMethod(1, 2, 3) + + // Assert that Errorf and FailNow were not called + assert.Equal(t, 0, mockedTest.errorfCount) + assert.Equal(t, 0, mockedTest.failNowCount) + + // Test that on unexpected call, the mocked test was called to fail the test + + assert.PanicsWithValue(t, mockTestingTFailNowCalled, func() { + mockedService.TheExampleMethod(1, 1, 1) + }) + + // Assert that Errorf and FailNow were called once + assert.Equal(t, 1, mockedTest.errorfCount) + assert.Equal(t, 1, mockedTest.failNowCount) +} + +func Test_Mock_On_WithPtrArgMatcher(t *testing.T) { + var mockedService TestExampleImplementation + + mockedService.On("TheExampleMethod3", + MatchedBy(func(a *ExampleType) bool { return a != nil && a.ran == true }), + ).Return(nil) + + mockedService.On("TheExampleMethod3", + MatchedBy(func(a *ExampleType) bool { return a != nil && a.ran == false }), + ).Return(errors.New("error")) + + mockedService.On("TheExampleMethod3", + MatchedBy(func(a *ExampleType) bool { return a == nil }), + ).Return(errors.New("error2")) + + assert.Equal(t, mockedService.TheExampleMethod3(&ExampleType{true}), nil) + assert.EqualError(t, mockedService.TheExampleMethod3(&ExampleType{false}), "error") + assert.EqualError(t, mockedService.TheExampleMethod3(nil), "error2") +} + +func Test_Mock_On_WithFuncArgMatcher(t *testing.T) { + var mockedService TestExampleImplementation + + fixture1, fixture2 := errors.New("fixture1"), errors.New("fixture2") + + mockedService.On("TheExampleMethodFunc", + MatchedBy(func(a func(string) error) bool { return a != nil && a("string") == fixture1 }), + ).Return(errors.New("fixture1")) + + mockedService.On("TheExampleMethodFunc", + MatchedBy(func(a func(string) error) bool { return a != nil && a("string") == fixture2 }), + ).Return(errors.New("fixture2")) + + mockedService.On("TheExampleMethodFunc", + MatchedBy(func(a func(string) error) bool { return a == nil }), + ).Return(errors.New("fixture3")) + + assert.EqualError(t, mockedService.TheExampleMethodFunc( + func(string) error { return fixture1 }), "fixture1") + assert.EqualError(t, mockedService.TheExampleMethodFunc( + func(string) error { return fixture2 }), "fixture2") + assert.EqualError(t, mockedService.TheExampleMethodFunc(nil), "fixture3") +} + +func Test_Mock_On_WithInterfaceArgMatcher(t *testing.T) { + var mockedService TestExampleImplementation + + mockedService.On("TheExampleMethod4", + MatchedBy(func(a ExampleInterface) bool { return a == nil }), + ).Return(errors.New("fixture1")) + + assert.EqualError(t, mockedService.TheExampleMethod4(nil), "fixture1") +} + +func Test_Mock_On_WithChannelArgMatcher(t *testing.T) { + var mockedService TestExampleImplementation + + mockedService.On("TheExampleMethod5", + MatchedBy(func(ch chan struct{}) bool { return ch == nil }), + ).Return(errors.New("fixture1")) + + assert.EqualError(t, mockedService.TheExampleMethod5(nil), "fixture1") +} + +func Test_Mock_On_WithMapArgMatcher(t *testing.T) { + var mockedService TestExampleImplementation + + mockedService.On("TheExampleMethod6", + MatchedBy(func(m map[string]bool) bool { return m == nil }), + ).Return(errors.New("fixture1")) + + assert.EqualError(t, mockedService.TheExampleMethod6(nil), "fixture1") +} + +func Test_Mock_On_WithSliceArgMatcher(t *testing.T) { + var mockedService TestExampleImplementation + + mockedService.On("TheExampleMethod7", + MatchedBy(func(slice []bool) bool { return slice == nil }), + ).Return(errors.New("fixture1")) + + assert.EqualError(t, mockedService.TheExampleMethod7(nil), "fixture1") +} + +func Test_Mock_On_WithVariadicFunc(t *testing.T) { + + // make a test impl object + var mockedService = new(TestExampleImplementation) + + c := mockedService. + On("TheExampleMethodVariadic", []int{1, 2, 3}). + Return(nil) + + assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls) + assert.Equal(t, 1, len(c.Arguments)) + assert.Equal(t, []int{1, 2, 3}, c.Arguments[0]) + + assert.NotPanics(t, func() { + mockedService.TheExampleMethodVariadic(1, 2, 3) + }) + assert.Panics(t, func() { + mockedService.TheExampleMethodVariadic(1, 2) + }) + +} + +func Test_Mock_On_WithMixedVariadicFunc(t *testing.T) { + + // make a test impl object + var mockedService = new(TestExampleImplementation) + + c := mockedService. + On("TheExampleMethodMixedVariadic", 1, []int{2, 3, 4}). + Return(nil) + + assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls) + assert.Equal(t, 2, len(c.Arguments)) + assert.Equal(t, 1, c.Arguments[0]) + assert.Equal(t, []int{2, 3, 4}, c.Arguments[1]) + + assert.NotPanics(t, func() { + mockedService.TheExampleMethodMixedVariadic(1, 2, 3, 4) + }) + assert.Panics(t, func() { + mockedService.TheExampleMethodMixedVariadic(1, 2, 3, 5) + }) + +} + +func Test_Mock_On_WithVariadicFuncWithInterface(t *testing.T) { + + // make a test impl object + var mockedService = new(TestExampleImplementation) + + c := mockedService.On("TheExampleMethodVariadicInterface", []interface{}{1, 2, 3}). + Return(nil) + + assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls) + assert.Equal(t, 1, len(c.Arguments)) + assert.Equal(t, []interface{}{1, 2, 3}, c.Arguments[0]) + + assert.NotPanics(t, func() { + mockedService.TheExampleMethodVariadicInterface(1, 2, 3) + }) + assert.Panics(t, func() { + mockedService.TheExampleMethodVariadicInterface(1, 2) + }) + +} + +func Test_Mock_On_WithVariadicFuncWithEmptyInterfaceArray(t *testing.T) { + + // make a test impl object + var mockedService = new(TestExampleImplementation) + + var expected []interface{} + c := mockedService. + On("TheExampleMethodVariadicInterface", expected). + Return(nil) + + assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls) + assert.Equal(t, 1, len(c.Arguments)) + assert.Equal(t, expected, c.Arguments[0]) + + assert.NotPanics(t, func() { + mockedService.TheExampleMethodVariadicInterface() + }) + assert.Panics(t, func() { + mockedService.TheExampleMethodVariadicInterface(1, 2) + }) + +} + +func Test_Mock_On_WithFuncPanics(t *testing.T) { + // make a test impl object + var mockedService = new(TestExampleImplementation) + + assert.Panics(t, func() { + mockedService.On("TheExampleMethodFunc", func(string) error { return nil }) + }) +} + +func Test_Mock_On_WithFuncTypeArg(t *testing.T) { + + // make a test impl object + var mockedService = new(TestExampleImplementation) + + c := mockedService. + On("TheExampleMethodFuncType", AnythingOfType("mock.ExampleFuncType")). + Return(nil) + + assert.Equal(t, []*Call{c}, mockedService.ExpectedCalls) + assert.Equal(t, 1, len(c.Arguments)) + assert.Equal(t, AnythingOfType("mock.ExampleFuncType"), c.Arguments[0]) + + fn := func(string) error { return nil } + assert.NotPanics(t, func() { + mockedService.TheExampleMethodFuncType(fn) + }) +} + +func Test_Mock_Return(t *testing.T) { + + // make a test impl object + var mockedService = new(TestExampleImplementation) + + c := mockedService. + On("TheExampleMethod", "A", "B", true). + Return(1, "two", true) + + require.Equal(t, []*Call{c}, mockedService.ExpectedCalls) + + call := mockedService.ExpectedCalls[0] + + assert.Equal(t, "TheExampleMethod", call.Method) + assert.Equal(t, "A", call.Arguments[0]) + assert.Equal(t, "B", call.Arguments[1]) + assert.Equal(t, true, call.Arguments[2]) + assert.Equal(t, 1, call.ReturnArguments[0]) + assert.Equal(t, "two", call.ReturnArguments[1]) + assert.Equal(t, true, call.ReturnArguments[2]) + assert.Equal(t, 0, call.Repeatability) + assert.Nil(t, call.WaitFor) +} + +func Test_Mock_Return_WaitUntil(t *testing.T) { + + // make a test impl object + var mockedService = new(TestExampleImplementation) + ch := time.After(time.Second) + + c := mockedService.Mock. + On("TheExampleMethod", "A", "B", true). + WaitUntil(ch). + Return(1, "two", true) + + // assert that the call was created + require.Equal(t, []*Call{c}, mockedService.ExpectedCalls) + + call := mockedService.ExpectedCalls[0] + + assert.Equal(t, "TheExampleMethod", call.Method) + assert.Equal(t, "A", call.Arguments[0]) + assert.Equal(t, "B", call.Arguments[1]) + assert.Equal(t, true, call.Arguments[2]) + assert.Equal(t, 1, call.ReturnArguments[0]) + assert.Equal(t, "two", call.ReturnArguments[1]) + assert.Equal(t, true, call.ReturnArguments[2]) + assert.Equal(t, 0, call.Repeatability) + assert.Equal(t, ch, call.WaitFor) +} + +func Test_Mock_Return_After(t *testing.T) { + + // make a test impl object + var mockedService = new(TestExampleImplementation) + + c := mockedService.Mock. + On("TheExampleMethod", "A", "B", true). + Return(1, "two", true). + After(time.Second) + + require.Equal(t, []*Call{c}, mockedService.ExpectedCalls) + + call := mockedService.Mock.ExpectedCalls[0] + + assert.Equal(t, "TheExampleMethod", call.Method) + assert.Equal(t, "A", call.Arguments[0]) + assert.Equal(t, "B", call.Arguments[1]) + assert.Equal(t, true, call.Arguments[2]) + assert.Equal(t, 1, call.ReturnArguments[0]) + assert.Equal(t, "two", call.ReturnArguments[1]) + assert.Equal(t, true, call.ReturnArguments[2]) + assert.Equal(t, 0, call.Repeatability) + assert.NotEqual(t, nil, call.WaitFor) + +} + +func Test_Mock_Return_Run(t *testing.T) { + + // make a test impl object + var mockedService = new(TestExampleImplementation) + + fn := func(args Arguments) { + arg := args.Get(0).(*ExampleType) + arg.ran = true + } + + c := mockedService.Mock. + On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")). + Return(nil). + Run(fn) + + require.Equal(t, []*Call{c}, mockedService.ExpectedCalls) + + call := mockedService.Mock.ExpectedCalls[0] + + assert.Equal(t, "TheExampleMethod3", call.Method) + assert.Equal(t, AnythingOfType("*mock.ExampleType"), call.Arguments[0]) + assert.Equal(t, nil, call.ReturnArguments[0]) + assert.Equal(t, 0, call.Repeatability) + assert.NotEqual(t, nil, call.WaitFor) + assert.NotNil(t, call.Run) + + et := ExampleType{} + assert.Equal(t, false, et.ran) + mockedService.TheExampleMethod3(&et) + assert.Equal(t, true, et.ran) +} + +func Test_Mock_Return_Run_Out_Of_Order(t *testing.T) { + // make a test impl object + var mockedService = new(TestExampleImplementation) + f := func(args Arguments) { + arg := args.Get(0).(*ExampleType) + arg.ran = true + } + + c := mockedService.Mock. + On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")). + Run(f). + Return(nil) + + require.Equal(t, []*Call{c}, mockedService.ExpectedCalls) + + call := mockedService.Mock.ExpectedCalls[0] + + assert.Equal(t, "TheExampleMethod3", call.Method) + assert.Equal(t, AnythingOfType("*mock.ExampleType"), call.Arguments[0]) + assert.Equal(t, nil, call.ReturnArguments[0]) + assert.Equal(t, 0, call.Repeatability) + assert.NotEqual(t, nil, call.WaitFor) + assert.NotNil(t, call.Run) +} + +func Test_Mock_Return_Once(t *testing.T) { + + // make a test impl object + var mockedService = new(TestExampleImplementation) + + c := mockedService.On("TheExampleMethod", "A", "B", true). + Return(1, "two", true). + Once() + + require.Equal(t, []*Call{c}, mockedService.ExpectedCalls) + + call := mockedService.ExpectedCalls[0] + + assert.Equal(t, "TheExampleMethod", call.Method) + assert.Equal(t, "A", call.Arguments[0]) + assert.Equal(t, "B", call.Arguments[1]) + assert.Equal(t, true, call.Arguments[2]) + assert.Equal(t, 1, call.ReturnArguments[0]) + assert.Equal(t, "two", call.ReturnArguments[1]) + assert.Equal(t, true, call.ReturnArguments[2]) + assert.Equal(t, 1, call.Repeatability) + assert.Nil(t, call.WaitFor) +} + +func Test_Mock_Return_Twice(t *testing.T) { + + // make a test impl object + var mockedService = new(TestExampleImplementation) + + c := mockedService. + On("TheExampleMethod", "A", "B", true). + Return(1, "two", true). + Twice() + + require.Equal(t, []*Call{c}, mockedService.ExpectedCalls) + + call := mockedService.ExpectedCalls[0] + + assert.Equal(t, "TheExampleMethod", call.Method) + assert.Equal(t, "A", call.Arguments[0]) + assert.Equal(t, "B", call.Arguments[1]) + assert.Equal(t, true, call.Arguments[2]) + assert.Equal(t, 1, call.ReturnArguments[0]) + assert.Equal(t, "two", call.ReturnArguments[1]) + assert.Equal(t, true, call.ReturnArguments[2]) + assert.Equal(t, 2, call.Repeatability) + assert.Nil(t, call.WaitFor) +} + +func Test_Mock_Return_Times(t *testing.T) { + + // make a test impl object + var mockedService = new(TestExampleImplementation) + + c := mockedService. + On("TheExampleMethod", "A", "B", true). + Return(1, "two", true). + Times(5) + + require.Equal(t, []*Call{c}, mockedService.ExpectedCalls) + + call := mockedService.ExpectedCalls[0] + + assert.Equal(t, "TheExampleMethod", call.Method) + assert.Equal(t, "A", call.Arguments[0]) + assert.Equal(t, "B", call.Arguments[1]) + assert.Equal(t, true, call.Arguments[2]) + assert.Equal(t, 1, call.ReturnArguments[0]) + assert.Equal(t, "two", call.ReturnArguments[1]) + assert.Equal(t, true, call.ReturnArguments[2]) + assert.Equal(t, 5, call.Repeatability) + assert.Nil(t, call.WaitFor) +} + +func Test_Mock_Return_Nothing(t *testing.T) { + + // make a test impl object + var mockedService = new(TestExampleImplementation) + + c := mockedService. + On("TheExampleMethod", "A", "B", true). + Return() + + require.Equal(t, []*Call{c}, mockedService.ExpectedCalls) + + call := mockedService.ExpectedCalls[0] + + assert.Equal(t, "TheExampleMethod", call.Method) + assert.Equal(t, "A", call.Arguments[0]) + assert.Equal(t, "B", call.Arguments[1]) + assert.Equal(t, true, call.Arguments[2]) + assert.Equal(t, 0, len(call.ReturnArguments)) +} + +func Test_Mock_findExpectedCall(t *testing.T) { + + m := new(Mock) + m.On("One", 1).Return("one") + m.On("Two", 2).Return("two") + m.On("Two", 3).Return("three") + + f, c := m.findExpectedCall("Two", 3) + + if assert.Equal(t, 2, f) { + if assert.NotNil(t, c) { + assert.Equal(t, "Two", c.Method) + assert.Equal(t, 3, c.Arguments[0]) + assert.Equal(t, "three", c.ReturnArguments[0]) + } + } + +} + +func Test_Mock_findExpectedCall_For_Unknown_Method(t *testing.T) { + + m := new(Mock) + m.On("One", 1).Return("one") + m.On("Two", 2).Return("two") + m.On("Two", 3).Return("three") + + f, _ := m.findExpectedCall("Two") + + assert.Equal(t, -1, f) + +} + +func Test_Mock_findExpectedCall_Respects_Repeatability(t *testing.T) { + + m := new(Mock) + m.On("One", 1).Return("one") + m.On("Two", 2).Return("two").Once() + m.On("Two", 3).Return("three").Twice() + m.On("Two", 3).Return("three").Times(8) + + f, c := m.findExpectedCall("Two", 3) + + if assert.Equal(t, 2, f) { + if assert.NotNil(t, c) { + assert.Equal(t, "Two", c.Method) + assert.Equal(t, 3, c.Arguments[0]) + assert.Equal(t, "three", c.ReturnArguments[0]) + } + } + +} + +func Test_callString(t *testing.T) { + + assert.Equal(t, `Method(int,bool,string)`, callString("Method", []interface{}{1, true, "something"}, false)) + +} + +func Test_Mock_Called(t *testing.T) { + + var mockedService = new(TestExampleImplementation) + + mockedService.On("Test_Mock_Called", 1, 2, 3).Return(5, "6", true) + + returnArguments := mockedService.Called(1, 2, 3) + + if assert.Equal(t, 1, len(mockedService.Calls)) { + assert.Equal(t, "Test_Mock_Called", mockedService.Calls[0].Method) + assert.Equal(t, 1, mockedService.Calls[0].Arguments[0]) + assert.Equal(t, 2, mockedService.Calls[0].Arguments[1]) + assert.Equal(t, 3, mockedService.Calls[0].Arguments[2]) + } + + if assert.Equal(t, 3, len(returnArguments)) { + assert.Equal(t, 5, returnArguments[0]) + assert.Equal(t, "6", returnArguments[1]) + assert.Equal(t, true, returnArguments[2]) + } + +} + +func asyncCall(m *Mock, ch chan Arguments) { + ch <- m.Called(1, 2, 3) +} + +func Test_Mock_Called_blocks(t *testing.T) { + + var mockedService = new(TestExampleImplementation) + + mockedService.Mock.On("asyncCall", 1, 2, 3).Return(5, "6", true).After(2 * time.Millisecond) + + ch := make(chan Arguments) + + go asyncCall(&mockedService.Mock, ch) + + select { + case <-ch: + t.Fatal("should have waited") + case <-time.After(1 * time.Millisecond): + } + + returnArguments := <-ch + + if assert.Equal(t, 1, len(mockedService.Mock.Calls)) { + assert.Equal(t, "asyncCall", mockedService.Mock.Calls[0].Method) + assert.Equal(t, 1, mockedService.Mock.Calls[0].Arguments[0]) + assert.Equal(t, 2, mockedService.Mock.Calls[0].Arguments[1]) + assert.Equal(t, 3, mockedService.Mock.Calls[0].Arguments[2]) + } + + if assert.Equal(t, 3, len(returnArguments)) { + assert.Equal(t, 5, returnArguments[0]) + assert.Equal(t, "6", returnArguments[1]) + assert.Equal(t, true, returnArguments[2]) + } + +} + +func Test_Mock_Called_For_Bounded_Repeatability(t *testing.T) { + + var mockedService = new(TestExampleImplementation) + + mockedService. + On("Test_Mock_Called_For_Bounded_Repeatability", 1, 2, 3). + Return(5, "6", true). + Once() + mockedService. + On("Test_Mock_Called_For_Bounded_Repeatability", 1, 2, 3). + Return(-1, "hi", false) + + returnArguments1 := mockedService.Called(1, 2, 3) + returnArguments2 := mockedService.Called(1, 2, 3) + + if assert.Equal(t, 2, len(mockedService.Calls)) { + assert.Equal(t, "Test_Mock_Called_For_Bounded_Repeatability", mockedService.Calls[0].Method) + assert.Equal(t, 1, mockedService.Calls[0].Arguments[0]) + assert.Equal(t, 2, mockedService.Calls[0].Arguments[1]) + assert.Equal(t, 3, mockedService.Calls[0].Arguments[2]) + + assert.Equal(t, "Test_Mock_Called_For_Bounded_Repeatability", mockedService.Calls[1].Method) + assert.Equal(t, 1, mockedService.Calls[1].Arguments[0]) + assert.Equal(t, 2, mockedService.Calls[1].Arguments[1]) + assert.Equal(t, 3, mockedService.Calls[1].Arguments[2]) + } + + if assert.Equal(t, 3, len(returnArguments1)) { + assert.Equal(t, 5, returnArguments1[0]) + assert.Equal(t, "6", returnArguments1[1]) + assert.Equal(t, true, returnArguments1[2]) + } + + if assert.Equal(t, 3, len(returnArguments2)) { + assert.Equal(t, -1, returnArguments2[0]) + assert.Equal(t, "hi", returnArguments2[1]) + assert.Equal(t, false, returnArguments2[2]) + } + +} + +func Test_Mock_Called_For_SetTime_Expectation(t *testing.T) { + + var mockedService = new(TestExampleImplementation) + + mockedService.On("TheExampleMethod", 1, 2, 3).Return(5, "6", true).Times(4) + + mockedService.TheExampleMethod(1, 2, 3) + mockedService.TheExampleMethod(1, 2, 3) + mockedService.TheExampleMethod(1, 2, 3) + mockedService.TheExampleMethod(1, 2, 3) + assert.Panics(t, func() { + mockedService.TheExampleMethod(1, 2, 3) + }) + +} + +func Test_Mock_Called_Unexpected(t *testing.T) { + + var mockedService = new(TestExampleImplementation) + + // make sure it panics if no expectation was made + assert.Panics(t, func() { + mockedService.Called(1, 2, 3) + }, "Calling unexpected method should panic") + +} + +func Test_AssertExpectationsForObjects_Helper(t *testing.T) { + + var mockedService1 = new(TestExampleImplementation) + var mockedService2 = new(TestExampleImplementation) + var mockedService3 = new(TestExampleImplementation) + + mockedService1.On("Test_AssertExpectationsForObjects_Helper", 1).Return() + mockedService2.On("Test_AssertExpectationsForObjects_Helper", 2).Return() + mockedService3.On("Test_AssertExpectationsForObjects_Helper", 3).Return() + + mockedService1.Called(1) + mockedService2.Called(2) + mockedService3.Called(3) + + assert.True(t, AssertExpectationsForObjects(t, &mockedService1.Mock, &mockedService2.Mock, &mockedService3.Mock)) + assert.True(t, AssertExpectationsForObjects(t, mockedService1, mockedService2, mockedService3)) + +} + +func Test_AssertExpectationsForObjects_Helper_Failed(t *testing.T) { + + var mockedService1 = new(TestExampleImplementation) + var mockedService2 = new(TestExampleImplementation) + var mockedService3 = new(TestExampleImplementation) + + mockedService1.On("Test_AssertExpectationsForObjects_Helper_Failed", 1).Return() + mockedService2.On("Test_AssertExpectationsForObjects_Helper_Failed", 2).Return() + mockedService3.On("Test_AssertExpectationsForObjects_Helper_Failed", 3).Return() + + mockedService1.Called(1) + mockedService3.Called(3) + + tt := new(testing.T) + assert.False(t, AssertExpectationsForObjects(tt, &mockedService1.Mock, &mockedService2.Mock, &mockedService3.Mock)) + assert.False(t, AssertExpectationsForObjects(tt, mockedService1, mockedService2, mockedService3)) + +} + +func Test_Mock_AssertExpectations(t *testing.T) { + + var mockedService = new(TestExampleImplementation) + + mockedService.On("Test_Mock_AssertExpectations", 1, 2, 3).Return(5, 6, 7) + + tt := new(testing.T) + assert.False(t, mockedService.AssertExpectations(tt)) + + // make the call now + mockedService.Called(1, 2, 3) + + // now assert expectations + assert.True(t, mockedService.AssertExpectations(tt)) + +} + +func Test_Mock_AssertExpectations_Placeholder_NoArgs(t *testing.T) { + + var mockedService = new(TestExampleImplementation) + + mockedService.On("Test_Mock_AssertExpectations_Placeholder_NoArgs").Return(5, 6, 7).Once() + mockedService.On("Test_Mock_AssertExpectations_Placeholder_NoArgs").Return(7, 6, 5) + + tt := new(testing.T) + assert.False(t, mockedService.AssertExpectations(tt)) + + // make the call now + mockedService.Called() + + // now assert expectations + assert.True(t, mockedService.AssertExpectations(tt)) + +} + +func Test_Mock_AssertExpectations_Placeholder(t *testing.T) { + + var mockedService = new(TestExampleImplementation) + + mockedService.On("Test_Mock_AssertExpectations_Placeholder", 1, 2, 3).Return(5, 6, 7).Once() + mockedService.On("Test_Mock_AssertExpectations_Placeholder", 3, 2, 1).Return(7, 6, 5) + + tt := new(testing.T) + assert.False(t, mockedService.AssertExpectations(tt)) + + // make the call now + mockedService.Called(1, 2, 3) + + // now assert expectations + assert.False(t, mockedService.AssertExpectations(tt)) + + // make call to the second expectation + mockedService.Called(3, 2, 1) + + // now assert expectations again + assert.True(t, mockedService.AssertExpectations(tt)) +} + +func Test_Mock_AssertExpectations_With_Pointers(t *testing.T) { + + var mockedService = new(TestExampleImplementation) + + mockedService.On("Test_Mock_AssertExpectations_With_Pointers", &struct{ Foo int }{1}).Return(1) + mockedService.On("Test_Mock_AssertExpectations_With_Pointers", &struct{ Foo int }{2}).Return(2) + + tt := new(testing.T) + assert.False(t, mockedService.AssertExpectations(tt)) + + s := struct{ Foo int }{1} + // make the calls now + mockedService.Called(&s) + s.Foo = 2 + mockedService.Called(&s) + + // now assert expectations + assert.True(t, mockedService.AssertExpectations(tt)) + +} + +func Test_Mock_AssertExpectationsCustomType(t *testing.T) { + + var mockedService = new(TestExampleImplementation) + + mockedService.On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")).Return(nil).Once() + + tt := new(testing.T) + assert.False(t, mockedService.AssertExpectations(tt)) + + // make the call now + mockedService.TheExampleMethod3(&ExampleType{}) + + // now assert expectations + assert.True(t, mockedService.AssertExpectations(tt)) + +} + +func Test_Mock_AssertExpectations_With_Repeatability(t *testing.T) { + + var mockedService = new(TestExampleImplementation) + + mockedService.On("Test_Mock_AssertExpectations_With_Repeatability", 1, 2, 3).Return(5, 6, 7).Twice() + + tt := new(testing.T) + assert.False(t, mockedService.AssertExpectations(tt)) + + // make the call now + mockedService.Called(1, 2, 3) + + assert.False(t, mockedService.AssertExpectations(tt)) + + mockedService.Called(1, 2, 3) + + // now assert expectations + assert.True(t, mockedService.AssertExpectations(tt)) + +} + +func Test_Mock_TwoCallsWithDifferentArguments(t *testing.T) { + + var mockedService = new(TestExampleImplementation) + + mockedService.On("Test_Mock_TwoCallsWithDifferentArguments", 1, 2, 3).Return(5, 6, 7) + mockedService.On("Test_Mock_TwoCallsWithDifferentArguments", 4, 5, 6).Return(5, 6, 7) + + args1 := mockedService.Called(1, 2, 3) + assert.Equal(t, 5, args1.Int(0)) + assert.Equal(t, 6, args1.Int(1)) + assert.Equal(t, 7, args1.Int(2)) + + args2 := mockedService.Called(4, 5, 6) + assert.Equal(t, 5, args2.Int(0)) + assert.Equal(t, 6, args2.Int(1)) + assert.Equal(t, 7, args2.Int(2)) + +} + +func Test_Mock_AssertNumberOfCalls(t *testing.T) { + + var mockedService = new(TestExampleImplementation) + + mockedService.On("Test_Mock_AssertNumberOfCalls", 1, 2, 3).Return(5, 6, 7) + + mockedService.Called(1, 2, 3) + assert.True(t, mockedService.AssertNumberOfCalls(t, "Test_Mock_AssertNumberOfCalls", 1)) + + mockedService.Called(1, 2, 3) + assert.True(t, mockedService.AssertNumberOfCalls(t, "Test_Mock_AssertNumberOfCalls", 2)) + +} + +func Test_Mock_AssertCalled(t *testing.T) { + + var mockedService = new(TestExampleImplementation) + + mockedService.On("Test_Mock_AssertCalled", 1, 2, 3).Return(5, 6, 7) + + mockedService.Called(1, 2, 3) + + assert.True(t, mockedService.AssertCalled(t, "Test_Mock_AssertCalled", 1, 2, 3)) + +} + +func Test_Mock_AssertCalled_WithAnythingOfTypeArgument(t *testing.T) { + + var mockedService = new(TestExampleImplementation) + + mockedService. + On("Test_Mock_AssertCalled_WithAnythingOfTypeArgument", Anything, Anything, Anything). + Return() + + mockedService.Called(1, "two", []uint8("three")) + + assert.True(t, mockedService.AssertCalled(t, "Test_Mock_AssertCalled_WithAnythingOfTypeArgument", AnythingOfType("int"), AnythingOfType("string"), AnythingOfType("[]uint8"))) + +} + +func Test_Mock_AssertCalled_WithArguments(t *testing.T) { + + var mockedService = new(TestExampleImplementation) + + mockedService.On("Test_Mock_AssertCalled_WithArguments", 1, 2, 3).Return(5, 6, 7) + + mockedService.Called(1, 2, 3) + + tt := new(testing.T) + assert.True(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments", 1, 2, 3)) + assert.False(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments", 2, 3, 4)) + +} + +func Test_Mock_AssertCalled_WithArguments_With_Repeatability(t *testing.T) { + + var mockedService = new(TestExampleImplementation) + + mockedService.On("Test_Mock_AssertCalled_WithArguments_With_Repeatability", 1, 2, 3).Return(5, 6, 7).Once() + mockedService.On("Test_Mock_AssertCalled_WithArguments_With_Repeatability", 2, 3, 4).Return(5, 6, 7).Once() + + mockedService.Called(1, 2, 3) + mockedService.Called(2, 3, 4) + + tt := new(testing.T) + assert.True(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments_With_Repeatability", 1, 2, 3)) + assert.True(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments_With_Repeatability", 2, 3, 4)) + assert.False(t, mockedService.AssertCalled(tt, "Test_Mock_AssertCalled_WithArguments_With_Repeatability", 3, 4, 5)) + +} + +func Test_Mock_AssertNotCalled(t *testing.T) { + + var mockedService = new(TestExampleImplementation) + + mockedService.On("Test_Mock_AssertNotCalled", 1, 2, 3).Return(5, 6, 7) + + mockedService.Called(1, 2, 3) + + assert.True(t, mockedService.AssertNotCalled(t, "Test_Mock_NotCalled")) + +} + +func Test_Mock_AssertOptional(t *testing.T) { + // Optional called + var ms1 = new(TestExampleImplementation) + ms1.On("TheExampleMethod", 1, 2, 3).Maybe().Return(4, nil) + ms1.TheExampleMethod(1, 2, 3) + + tt1 := new(testing.T) + assert.Equal(t, true, ms1.AssertExpectations(tt1)) + + // Optional not called + var ms2 = new(TestExampleImplementation) + ms2.On("TheExampleMethod", 1, 2, 3).Maybe().Return(4, nil) + + tt2 := new(testing.T) + assert.Equal(t, true, ms2.AssertExpectations(tt2)) + + // Non-optional called + var ms3 = new(TestExampleImplementation) + ms3.On("TheExampleMethod", 1, 2, 3).Return(4, nil) + ms3.TheExampleMethod(1, 2, 3) + + tt3 := new(testing.T) + assert.Equal(t, true, ms3.AssertExpectations(tt3)) +} + +/* + Arguments helper methods +*/ +func Test_Arguments_Get(t *testing.T) { + + var args = Arguments([]interface{}{"string", 123, true}) + + assert.Equal(t, "string", args.Get(0).(string)) + assert.Equal(t, 123, args.Get(1).(int)) + assert.Equal(t, true, args.Get(2).(bool)) + +} + +func Test_Arguments_Is(t *testing.T) { + + var args = Arguments([]interface{}{"string", 123, true}) + + assert.True(t, args.Is("string", 123, true)) + assert.False(t, args.Is("wrong", 456, false)) + +} + +func Test_Arguments_Diff(t *testing.T) { + + var args = Arguments([]interface{}{"Hello World", 123, true}) + var diff string + var count int + diff, count = args.Diff([]interface{}{"Hello World", 456, "false"}) + + assert.Equal(t, 2, count) + assert.Contains(t, diff, `(int=456) != (int=123)`) + assert.Contains(t, diff, `(string=false) != (bool=true)`) + +} + +func Test_Arguments_Diff_DifferentNumberOfArgs(t *testing.T) { + + var args = Arguments([]interface{}{"string", 123, true}) + var diff string + var count int + diff, count = args.Diff([]interface{}{"string", 456, "false", "extra"}) + + assert.Equal(t, 3, count) + assert.Contains(t, diff, `(string=extra) != (Missing)`) + +} + +func Test_Arguments_Diff_WithAnythingArgument(t *testing.T) { + + var args = Arguments([]interface{}{"string", 123, true}) + var count int + _, count = args.Diff([]interface{}{"string", Anything, true}) + + assert.Equal(t, 0, count) + +} + +func Test_Arguments_Diff_WithAnythingArgument_InActualToo(t *testing.T) { + + var args = Arguments([]interface{}{"string", Anything, true}) + var count int + _, count = args.Diff([]interface{}{"string", 123, true}) + + assert.Equal(t, 0, count) + +} + +func Test_Arguments_Diff_WithAnythingOfTypeArgument(t *testing.T) { + + var args = Arguments([]interface{}{"string", AnythingOfType("int"), true}) + var count int + _, count = args.Diff([]interface{}{"string", 123, true}) + + assert.Equal(t, 0, count) + +} + +func Test_Arguments_Diff_WithAnythingOfTypeArgument_Failing(t *testing.T) { + + var args = Arguments([]interface{}{"string", AnythingOfType("string"), true}) + var count int + var diff string + diff, count = args.Diff([]interface{}{"string", 123, true}) + + assert.Equal(t, 1, count) + assert.Contains(t, diff, `string != type int - (int=123)`) + +} + +func Test_Arguments_Diff_WithArgMatcher(t *testing.T) { + matchFn := func(a int) bool { + return a == 123 + } + var args = Arguments([]interface{}{"string", MatchedBy(matchFn), true}) + + diff, count := args.Diff([]interface{}{"string", 124, true}) + assert.Equal(t, 1, count) + assert.Contains(t, diff, `(int=124) not matched by func(int) bool`) + + diff, count = args.Diff([]interface{}{"string", false, true}) + assert.Equal(t, 1, count) + assert.Contains(t, diff, `(bool=false) not matched by func(int) bool`) + + diff, count = args.Diff([]interface{}{"string", 123, false}) + assert.Contains(t, diff, `(int=123) matched by func(int) bool`) + + diff, count = args.Diff([]interface{}{"string", 123, true}) + assert.Equal(t, 0, count) + assert.Contains(t, diff, `No differences.`) +} + +func Test_Arguments_Assert(t *testing.T) { + + var args = Arguments([]interface{}{"string", 123, true}) + + assert.True(t, args.Assert(t, "string", 123, true)) + +} + +func Test_Arguments_String_Representation(t *testing.T) { + + var args = Arguments([]interface{}{"string", 123, true}) + assert.Equal(t, `string,int,bool`, args.String()) + +} + +func Test_Arguments_String(t *testing.T) { + + var args = Arguments([]interface{}{"string", 123, true}) + assert.Equal(t, "string", args.String(0)) + +} + +func Test_Arguments_Error(t *testing.T) { + + var err = errors.New("An Error") + var args = Arguments([]interface{}{"string", 123, true, err}) + assert.Equal(t, err, args.Error(3)) + +} + +func Test_Arguments_Error_Nil(t *testing.T) { + + var args = Arguments([]interface{}{"string", 123, true, nil}) + assert.Equal(t, nil, args.Error(3)) + +} + +func Test_Arguments_Int(t *testing.T) { + + var args = Arguments([]interface{}{"string", 123, true}) + assert.Equal(t, 123, args.Int(1)) + +} + +func Test_Arguments_Bool(t *testing.T) { + + var args = Arguments([]interface{}{"string", 123, true}) + assert.Equal(t, true, args.Bool(2)) + +} + +func Test_WaitUntil_Parallel(t *testing.T) { + + // make a test impl object + var mockedService = new(TestExampleImplementation) + + ch1 := make(chan time.Time) + ch2 := make(chan time.Time) + + mockedService.Mock.On("TheExampleMethod2", true).Return().WaitUntil(ch2).Run(func(args Arguments) { + ch1 <- time.Now() + }) + + mockedService.Mock.On("TheExampleMethod2", false).Return().WaitUntil(ch1) + + // Lock both goroutines on the .WaitUntil method + go func() { + mockedService.TheExampleMethod2(false) + }() + go func() { + mockedService.TheExampleMethod2(true) + }() + + // Allow the first call to execute, so the second one executes afterwards + ch2 <- time.Now() +} + +func Test_MockMethodCalled(t *testing.T) { + m := new(Mock) + m.On("foo", "hello").Return("world") + + retArgs := m.MethodCalled("foo", "hello") + require.True(t, len(retArgs) == 1) + require.Equal(t, "world", retArgs[0]) + m.AssertExpectations(t) +} + +// Test to validate fix for racy concurrent call access in MethodCalled() +func Test_MockReturnAndCalledConcurrent(t *testing.T) { + iterations := 1000 + m := &Mock{} + call := m.On("ConcurrencyTestMethod") + + wg := sync.WaitGroup{} + wg.Add(2) + + go func() { + for i := 0; i < iterations; i++ { + call.Return(10) + } + wg.Done() + }() + go func() { + for i := 0; i < iterations; i++ { + ConcurrencyTestMethod(m) + } + wg.Done() + }() + wg.Wait() +} + +type timer struct{ Mock } + +func (s *timer) GetTime(i int) string { + return s.Called(i).Get(0).(string) +} + +type tCustomLogger struct { + *testing.T + logs []string + errs []string +} + +func (tc *tCustomLogger) Logf(format string, args ...interface{}) { + tc.T.Logf(format, args...) + tc.logs = append(tc.logs, fmt.Sprintf(format, args...)) +} + +func (tc *tCustomLogger) Errorf(format string, args ...interface{}) { + tc.errs = append(tc.errs, fmt.Sprintf(format, args...)) +} + +func (tc *tCustomLogger) FailNow() {} + +func TestLoggingAssertExpectations(t *testing.T) { + m := new(timer) + m.On("GetTime", 0).Return("") + tcl := &tCustomLogger{t, []string{}, []string{}} + + AssertExpectationsForObjects(tcl, m, new(TestExampleImplementation)) + + require.Equal(t, 1, len(tcl.errs)) + assert.Regexp(t, regexp.MustCompile("(?s)FAIL: 0 out of 1 expectation\\(s\\) were met.*The code you are testing needs to make 1 more call\\(s\\).*"), tcl.errs[0]) + require.Equal(t, 2, len(tcl.logs)) + assert.Regexp(t, regexp.MustCompile("(?s)FAIL:\tGetTime\\(int\\).*"), tcl.logs[0]) + require.Equal(t, "Expectations didn't match for Mock: *mock.timer", tcl.logs[1]) +} + +func TestAfterTotalWaitTimeWhileExecution(t *testing.T) { + waitDuration := 1 + total, waitMs := 5, time.Millisecond*time.Duration(waitDuration) + aTimer := new(timer) + for i := 0; i < total; i++ { + aTimer.On("GetTime", i).After(waitMs).Return(fmt.Sprintf("Time%d", i)).Once() + } + time.Sleep(waitMs) + start := time.Now() + var results []string + + for i := 0; i < total; i++ { + results = append(results, aTimer.GetTime(i)) + } + + end := time.Now() + elapsedTime := end.Sub(start) + assert.True(t, elapsedTime > waitMs, fmt.Sprintf("Total elapsed time:%v should be atleast greater than %v", elapsedTime, waitMs)) + assert.Equal(t, total, len(results)) + for i := range results { + assert.Equal(t, fmt.Sprintf("Time%d", i), results[i], "Return value of method should be same") + } +} + +func TestArgumentMatcherToPrintMismatch(t *testing.T) { + defer func() { + if r := recover(); r != nil { + matchingExp := regexp.MustCompile( + `\s+mock: Unexpected Method Call\s+-*\s+GetTime\(int\)\s+0: 1\s+The closest call I have is:\s+GetTime\(mock.argumentMatcher\)\s+0: mock.argumentMatcher\{.*?\}\s+Diff:.*\(int=1\) not matched by func\(int\) bool`) + assert.Regexp(t, matchingExp, r) + } + }() + + m := new(timer) + m.On("GetTime", MatchedBy(func(i int) bool { return false })).Return("SomeTime").Once() + + res := m.GetTime(1) + require.Equal(t, "SomeTime", res) + m.AssertExpectations(t) +} + +func TestClosestCallMismatchedArgumentInformationShowsTheClosest(t *testing.T) { + defer func() { + if r := recover(); r != nil { + matchingExp := regexp.MustCompile(unexpectedCallRegex(`TheExampleMethod(int,int,int)`, `0: 1\s+1: 1\s+2: 2`, `0: 1\s+1: 1\s+2: 1`, `0: PASS: \(int=1\) == \(int=1\)\s+1: PASS: \(int=1\) == \(int=1\)\s+2: FAIL: \(int=2\) != \(int=1\)`)) + assert.Regexp(t, matchingExp, r) + } + }() + + m := new(TestExampleImplementation) + m.On("TheExampleMethod", 1, 1, 1).Return(1, nil).Once() + m.On("TheExampleMethod", 2, 2, 2).Return(2, nil).Once() + + m.TheExampleMethod(1, 1, 2) +} + +func TestClosestCallMismatchedArgumentValueInformation(t *testing.T) { + defer func() { + if r := recover(); r != nil { + matchingExp := regexp.MustCompile(unexpectedCallRegex(`GetTime(int)`, "0: 1", "0: 999", `0: FAIL: \(int=1\) != \(int=999\)`)) + assert.Regexp(t, matchingExp, r) + } + }() + + m := new(timer) + m.On("GetTime", 999).Return("SomeTime").Once() + + _ = m.GetTime(1) +} + +func unexpectedCallRegex(method, calledArg, expectedArg, diff string) string { + rMethod := regexp.QuoteMeta(method) + return fmt.Sprintf(`\s+mock: Unexpected Method Call\s+-*\s+%s\s+%s\s+The closest call I have is:\s+%s\s+%s\s+Diff: %s`, + rMethod, calledArg, rMethod, expectedArg, diff) +} + +//go:noinline +func ConcurrencyTestMethod(m *Mock) { + m.Called() +} diff --git a/vendor/vendor.json b/vendor/vendor.json index ecf7017..f2bf10a 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -255,6 +255,18 @@ "revision": "23def4e6c14b4da8ac2ed8007337bc5eb5007998", "revisionTime": "2016-01-25T20:49:56Z" }, + { + "checksumSHA1": "1irnmGLdt0YZ5OuVSzgnUZ/EfhM=", + "path": "github.com/golang/mock/gomock", + "revision": "140ae90f29eaaadc229f8d4b78f074b7f0611c1e", + "revisionTime": "2019-05-17T14:58:38Z" + }, + { + "checksumSHA1": "HuzaMCq8i3gBr/kURLQCcfX6J3I=", + "path": "github.com/golang/mock/gomock/internal/mock_gomock", + "revision": "140ae90f29eaaadc229f8d4b78f074b7f0611c1e", + "revisionTime": "2019-05-17T14:58:38Z" + }, { "checksumSHA1": "5++9mP/Ec3/LuBX8yf0AvveNUlg=", "path": "github.com/golang/protobuf/proto", @@ -471,12 +483,50 @@ "revision": "3fa1c550ffa69b74dc4bfd5109b4e218f32c87cf", "revisionTime": "2019-01-04T16:17:12Z" }, + { + "checksumSHA1": "2PbGxlLhhF4E+0Z1Gy3ryqHiFIE=", + "path": "github.com/neo4j-drivers/gobolt", + "revision": "0b8728e471cbd11fe5ffa3ae65a467886018012e", + "revisionTime": "2019-03-06T10:24:30Z", + "version": "1.7", + "versionExact": "1.7" + }, + { + "checksumSHA1": "jWfYJmAi6KYm02tSfPiWiHggY4M=", + "path": "github.com/neo4j/neo4j-go-driver/neo4j", + "revision": "934739616886b903306e1df80aa58047407a1971", + "revisionTime": "2019-05-08T17:51:40Z", + "version": "1.7", + "versionExact": "1.7" + }, + { + "checksumSHA1": "IFa+ZOnK7JCFfQOqk7EyiaHB8Ww=", + "path": "github.com/neo4j/neo4j-go-driver/neo4j/utils/test", + "revision": "934739616886b903306e1df80aa58047407a1971", + "revisionTime": "2019-05-08T17:51:40Z", + "version": "1.7", + "versionExact": "1.7" + }, { "checksumSHA1": "srxWPDlzsC2TlKJnQsCMSGx/RYg=", "path": "github.com/ogier/pflag", "revision": "45c278ab3607870051a2ea9040bb85fcb8557481", "revisionTime": "2016-01-29T22:01:14Z" }, + { + "path": "github.com/olivere/elastic/v7/config", + "revision": "" + }, + { + "path": "github.com/olivere/elastic/v7/uritemplates", + "revision": "" + }, + { + "checksumSHA1": "OyeP0Sp/PT/Nc5wpA7OlbNJ2XPQ=", + "path": "github.com/onsi/ginkgo/extensions/table", + "revision": "4cb744166b80afeec15fd0b4446c640a7688cd51", + "revisionTime": "2019-05-20T14:44:22Z" + }, { "checksumSHA1": "bnWJ5VK7fHAcqpLqY09k0nX8QNs=", "path": "github.com/pierrec/lz4", @@ -495,6 +545,18 @@ "revision": "8732c616f52954686704c8645fe1a9d59e9df7c1", "revisionTime": "2018-01-25T23:19:41Z" }, + { + "checksumSHA1": "NnsJ7+vqFtYb2DgoI+IXWOshjbU=", + "path": "github.com/stretchr/objx", + "revision": "35313a95ee26395aa17d366c71a2ccf788fa69b6", + "revisionTime": "2019-04-15T11:18:23Z" + }, + { + "checksumSHA1": "zHb8n4J+fZbwB6SBI6NqFL/7l+o=", + "path": "github.com/stretchr/testify/mock", + "revision": "34c6fa2dc70986bccbbffcc6130f6920a924b075", + "revisionTime": "2019-03-04T09:57:49Z" + }, { "checksumSHA1": "Q2NFGh5HlKwYmTu+jjpEd6b18JY=", "path": "go.opencensus.io", -- GitLab