From 1d78a41e4115a891b99ad32ee60c583e87bafb5c Mon Sep 17 00:00:00 2001 From: tidwall Date: Thu, 2 Aug 2018 19:57:11 -0700 Subject: [PATCH] Added BoxTree --- BACKERS.md | 19 - Gopkg.lock | 225 ++- Gopkg.toml | 5 +- README.md | 1 - pkg/index/index.go | 39 +- pkg/index/rtree/.gitignore | 1 - pkg/index/rtree/base.go | 660 --------- pkg/index/rtree/base_test.go | 554 -------- pkg/index/rtree/knn.go | 101 -- pkg/index/rtree/load.go | 102 -- .../github.com/pmezard/go-difflib/.travis.yml | 5 - vendor/github.com/pmezard/go-difflib/LICENSE | 27 - .../github.com/pmezard/go-difflib/README.md | 50 - .../pmezard/go-difflib/difflib/difflib.go | 772 ----------- .../go-difflib/difflib/difflib_test.go | 426 ------ vendor/github.com/stretchr/testify/.gitignore | 24 - .../github.com/stretchr/testify/.travis.yml | 16 - .../stretchr/testify/Godeps/Godeps.json | 23 - .../github.com/stretchr/testify/Godeps/Readme | 5 - .../github.com/stretchr/testify/LICENCE.txt | 22 - vendor/github.com/stretchr/testify/LICENSE | 22 - vendor/github.com/stretchr/testify/README.md | 332 ----- .../stretchr/testify/_codegen/main.go | 287 ---- .../testify/assert/assertion_forward.go | 387 ------ .../testify/assert/assertion_forward.go.tmpl | 4 - .../stretchr/testify/assert/assertions.go | 1052 -------------- .../testify/assert/assertions_test.go | 1210 ----------------- .../github.com/stretchr/testify/assert/doc.go | 45 - .../stretchr/testify/assert/errors.go | 10 - .../testify/assert/forward_assertions.go | 16 - .../testify/assert/forward_assertions_test.go | 611 --------- .../testify/assert/http_assertions.go | 106 -- .../testify/assert/http_assertions_test.go | 86 -- vendor/github.com/stretchr/testify/doc.go | 22 - .../github.com/stretchr/testify/http/doc.go | 2 - .../testify/http/test_response_writer.go | 49 - .../testify/http/test_round_tripper.go | 17 - .../github.com/stretchr/testify/mock/doc.go | 44 - .../github.com/stretchr/testify/mock/mock.go | 763 ----------- .../stretchr/testify/mock/mock_test.go | 1132 --------------- .../stretchr/testify/package_test.go | 12 - .../stretchr/testify/require/doc.go | 28 - .../testify/require/forward_requirements.go | 16 - .../require/forward_requirements_test.go | 385 ------ .../stretchr/testify/require/require.go | 464 ------- .../stretchr/testify/require/require.go.tmpl | 6 - .../testify/require/require_forward.go | 388 ------ .../testify/require/require_forward.go.tmpl | 4 - .../stretchr/testify/require/requirements.go | 9 - .../testify/require/requirements_test.go | 369 ----- .../github.com/stretchr/testify/suite/doc.go | 65 - .../stretchr/testify/suite/interfaces.go | 34 - .../stretchr/testify/suite/suite.go | 115 -- .../stretchr/testify/suite/suite_test.go | 239 ---- vendor/github.com/tidwall/boxtree/LICENSE | 19 + vendor/github.com/tidwall/boxtree/README.md | 94 ++ vendor/github.com/tidwall/boxtree/boxtree.go | 36 + .../tidwall/boxtree/boxtree_test.go | 125 ++ .../github.com/tidwall/boxtree/d2/boxtree.go | 707 ++++++++++ .../tidwall/boxtree/d2/boxtree_test.go | 379 ++++++ .../github.com/tidwall/boxtree/d3/boxtree.go | 707 ++++++++++ .../tidwall/boxtree/d3/boxtree_test.go | 379 ++++++ .../github.com/tidwall/boxtree/res/cities.png | Bin 0 -> 344308 bytes .../tidwall/boxtree/res/cities/main.go | 17 + .../tidwall/boxtree/res/gen/main.go | 33 + .../tidwall/boxtree/res/tools/tools.go | 112 ++ vendor/github.com/tidwall/tinyqueue/LICENSE | 15 - vendor/github.com/tidwall/tinyqueue/README.md | 7 - .../github.com/tidwall/tinyqueue/tinyqueue.go | 86 -- .../tidwall/tinyqueue/tinyqueue_test.go | 65 - 70 files changed, 2836 insertions(+), 11353 deletions(-) delete mode 100644 BACKERS.md delete mode 100644 pkg/index/rtree/.gitignore delete mode 100644 pkg/index/rtree/base.go delete mode 100644 pkg/index/rtree/base_test.go delete mode 100644 pkg/index/rtree/knn.go delete mode 100644 pkg/index/rtree/load.go delete mode 100644 vendor/github.com/pmezard/go-difflib/.travis.yml delete mode 100644 vendor/github.com/pmezard/go-difflib/LICENSE delete mode 100644 vendor/github.com/pmezard/go-difflib/README.md delete mode 100644 vendor/github.com/pmezard/go-difflib/difflib/difflib.go delete mode 100644 vendor/github.com/pmezard/go-difflib/difflib/difflib_test.go delete mode 100644 vendor/github.com/stretchr/testify/.gitignore delete mode 100644 vendor/github.com/stretchr/testify/.travis.yml delete mode 100644 vendor/github.com/stretchr/testify/Godeps/Godeps.json delete mode 100644 vendor/github.com/stretchr/testify/Godeps/Readme delete mode 100644 vendor/github.com/stretchr/testify/LICENCE.txt delete mode 100644 vendor/github.com/stretchr/testify/LICENSE delete mode 100644 vendor/github.com/stretchr/testify/README.md delete mode 100644 vendor/github.com/stretchr/testify/_codegen/main.go delete mode 100644 vendor/github.com/stretchr/testify/assert/assertion_forward.go delete mode 100644 vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl delete mode 100644 vendor/github.com/stretchr/testify/assert/assertions.go delete mode 100644 vendor/github.com/stretchr/testify/assert/assertions_test.go delete mode 100644 vendor/github.com/stretchr/testify/assert/doc.go delete mode 100644 vendor/github.com/stretchr/testify/assert/errors.go delete mode 100644 vendor/github.com/stretchr/testify/assert/forward_assertions.go delete mode 100644 vendor/github.com/stretchr/testify/assert/forward_assertions_test.go delete mode 100644 vendor/github.com/stretchr/testify/assert/http_assertions.go delete mode 100644 vendor/github.com/stretchr/testify/assert/http_assertions_test.go delete mode 100644 vendor/github.com/stretchr/testify/doc.go delete mode 100644 vendor/github.com/stretchr/testify/http/doc.go delete mode 100644 vendor/github.com/stretchr/testify/http/test_response_writer.go delete mode 100644 vendor/github.com/stretchr/testify/http/test_round_tripper.go delete mode 100644 vendor/github.com/stretchr/testify/mock/doc.go delete mode 100644 vendor/github.com/stretchr/testify/mock/mock.go delete mode 100644 vendor/github.com/stretchr/testify/mock/mock_test.go delete mode 100644 vendor/github.com/stretchr/testify/package_test.go delete mode 100644 vendor/github.com/stretchr/testify/require/doc.go delete mode 100644 vendor/github.com/stretchr/testify/require/forward_requirements.go delete mode 100644 vendor/github.com/stretchr/testify/require/forward_requirements_test.go delete mode 100644 vendor/github.com/stretchr/testify/require/require.go delete mode 100644 vendor/github.com/stretchr/testify/require/require.go.tmpl delete mode 100644 vendor/github.com/stretchr/testify/require/require_forward.go delete mode 100644 vendor/github.com/stretchr/testify/require/require_forward.go.tmpl delete mode 100644 vendor/github.com/stretchr/testify/require/requirements.go delete mode 100644 vendor/github.com/stretchr/testify/require/requirements_test.go delete mode 100644 vendor/github.com/stretchr/testify/suite/doc.go delete mode 100644 vendor/github.com/stretchr/testify/suite/interfaces.go delete mode 100644 vendor/github.com/stretchr/testify/suite/suite.go delete mode 100644 vendor/github.com/stretchr/testify/suite/suite_test.go create mode 100644 vendor/github.com/tidwall/boxtree/LICENSE create mode 100644 vendor/github.com/tidwall/boxtree/README.md create mode 100644 vendor/github.com/tidwall/boxtree/boxtree.go create mode 100644 vendor/github.com/tidwall/boxtree/boxtree_test.go create mode 100644 vendor/github.com/tidwall/boxtree/d2/boxtree.go create mode 100644 vendor/github.com/tidwall/boxtree/d2/boxtree_test.go create mode 100644 vendor/github.com/tidwall/boxtree/d3/boxtree.go create mode 100644 vendor/github.com/tidwall/boxtree/d3/boxtree_test.go create mode 100644 vendor/github.com/tidwall/boxtree/res/cities.png create mode 100644 vendor/github.com/tidwall/boxtree/res/cities/main.go create mode 100644 vendor/github.com/tidwall/boxtree/res/gen/main.go create mode 100644 vendor/github.com/tidwall/boxtree/res/tools/tools.go delete mode 100644 vendor/github.com/tidwall/tinyqueue/LICENSE delete mode 100644 vendor/github.com/tidwall/tinyqueue/README.md delete mode 100644 vendor/github.com/tidwall/tinyqueue/tinyqueue.go delete mode 100644 vendor/github.com/tidwall/tinyqueue/tinyqueue_test.go diff --git a/BACKERS.md b/BACKERS.md deleted file mode 100644 index 02ca47af..00000000 --- a/BACKERS.md +++ /dev/null @@ -1,19 +0,0 @@ -## Sponsors & Backers - -Tile38 is an MIT-licensed open source project. - -It's an independent project with its ongoing development made possible thanks to the support by these awesome [backers](https://github.com/tidwall/tile38/blob/master/BACKERS.md). -If you'd like to join them, please consider: - -- [Become a backer or sponsor on Patreon](https://www.patreon.com/tidwall). - -## Generous Backers via Patreon ($50+) - -- gmonk63 - -## Backers via Patreon - -- Aviv Klasquin Komissar -- Coen B -- Melbatoast -- Richard Law diff --git a/Gopkg.lock b/Gopkg.lock index d3f891af..1ddea21c 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -2,241 +2,414 @@ [[projects]] + digest = "1:db7100aae319b808f819ee6d1d2e400d234b0a335bff2b70392f1e3a79ccd63d" name = "github.com/Shopify/sarama" packages = ["."] + pruneopts = "" revision = "bbdbe644099b7fdc8327d5cc69c030945188b2e9" version = "v1.13.0" [[projects]] + digest = "1:11c577e4f8478a8b397adb7976f1f201b31951a5473d7e794c6423a1224dab80" name = "github.com/aws/aws-sdk-go" - packages = ["aws","aws/awserr","aws/awsutil","aws/client","aws/client/metadata","aws/corehandlers","aws/credentials","aws/credentials/ec2rolecreds","aws/credentials/endpointcreds","aws/credentials/stscreds","aws/defaults","aws/ec2metadata","aws/endpoints","aws/request","aws/session","aws/signer/v4","internal/shareddefaults","private/protocol","private/protocol/query","private/protocol/query/queryutil","private/protocol/rest","private/protocol/xml/xmlutil","service/sqs","service/sts"] + packages = [ + "aws", + "aws/awserr", + "aws/awsutil", + "aws/client", + "aws/client/metadata", + "aws/corehandlers", + "aws/credentials", + "aws/credentials/ec2rolecreds", + "aws/credentials/endpointcreds", + "aws/credentials/stscreds", + "aws/defaults", + "aws/ec2metadata", + "aws/endpoints", + "aws/request", + "aws/session", + "aws/signer/v4", + "internal/shareddefaults", + "private/protocol", + "private/protocol/query", + "private/protocol/query/queryutil", + "private/protocol/rest", + "private/protocol/xml/xmlutil", + "service/sqs", + "service/sts", + ] + pruneopts = "" revision = "da415b5fa0ff3f91d4707348a8ea1be53f700c22" version = "v1.12.6" [[projects]] + digest = "1:56c130d885a4aacae1dd9c7b71cfe39912c7ebc1ff7d2b46083c8812996dc43b" name = "github.com/davecgh/go-spew" packages = ["spew"] + pruneopts = "" revision = "346938d642f2ec3594ed81d874461961cd0faa76" version = "v1.1.0" [[projects]] + digest = "1:f714fa0ab4449a2fe13d156446ac1c1e16bc85334e9be320d42bf8bee362ba45" name = "github.com/eapache/go-resiliency" packages = ["breaker"] + pruneopts = "" revision = "6800482f2c813e689c88b7ed3282262385011890" version = "v1.0.0" [[projects]] branch = "master" + digest = "1:1f7503fa58a852a1416556ae2ddb219b49a1304fd408391948e2e3676514c48d" name = "github.com/eapache/go-xerial-snappy" packages = ["."] + pruneopts = "" revision = "bb955e01b9346ac19dc29eb16586c90ded99a98c" [[projects]] + digest = "1:c05dc14dd75a9697b8410ea13445ceb40669448f789afe955351ad34bc998cd0" name = "github.com/eapache/queue" packages = ["."] + pruneopts = "" revision = "ded5959c0d4e360646dc9e9908cff48666781367" version = "v1.0.2" [[projects]] + digest = "1:eecb3e6cef98036972582ffff7d3e340aef15f075236da353aa3e7fb798fdb21" name = "github.com/eclipse/paho.mqtt.golang" - packages = [".","packets"] + packages = [ + ".", + "packets", + ] + pruneopts = "" revision = "aff15770515e3c57fc6109da73d42b0d46f7f483" version = "v1.1.0" [[projects]] + digest = "1:c955959498f5eb42652958ac60bcd9a7fde78b8d6886f2e5b88513114c902a9c" name = "github.com/garyburd/redigo" - packages = ["internal","redis"] + packages = [ + "internal", + "redis", + ] + pruneopts = "" revision = "433969511232c397de61b1442f9fd49ec06ae9ba" version = "v1.1.0" [[projects]] + digest = "1:e26d0f8ccaf4087b93306d5e20e4816258116868ad6c6da0f2b4926c72fb92fa" name = "github.com/go-ini/ini" packages = ["."] + pruneopts = "" revision = "20b96f641a5ea98f2f8619ff4f3e061cff4833bd" version = "v1.28.2" [[projects]] branch = "master" + digest = "1:27854310d59099f8dcc61dd8af4a69f0a3597f001154b2fb4d1c41baf2e31ec1" name = "github.com/golang/protobuf" - packages = ["proto","ptypes","ptypes/any","ptypes/duration","ptypes/timestamp"] + packages = [ + "proto", + "ptypes", + "ptypes/any", + "ptypes/duration", + "ptypes/timestamp", + ] + pruneopts = "" revision = "130e6b02ab059e7b717a096f397c5b60111cae74" [[projects]] branch = "master" + digest = "1:09307dfb1aa3f49a2bf869dcfa4c6c06ecd3c207221bd1c1a1141f0e51f209eb" name = "github.com/golang/snappy" packages = ["."] + pruneopts = "" revision = "553a641470496b2327abcac10b36396bd98e45c9" [[projects]] + digest = "1:6f49eae0c1e5dab1dafafee34b207aeb7a42303105960944828c2079b92fc88e" name = "github.com/jmespath/go-jmespath" packages = ["."] + pruneopts = "" revision = "0b12d6b5" [[projects]] branch = "master" + digest = "1:30f72985e574101b71666d6e601e7564bd02d95164da59ca17363ad194137969" name = "github.com/peterh/liner" packages = ["."] + pruneopts = "" revision = "a37ad39843113264dae84a5d89fcee28f50b35c6" [[projects]] + digest = "1:2118aac9bc7ff09544626d5d1c7f7d4fb92a558702b00da5572ccc80ae7caf2b" name = "github.com/pierrec/lz4" packages = ["."] + pruneopts = "" revision = "08c27939df1bd95e881e2c2367a749964ad1fceb" version = "v1.0.1" [[projects]] + digest = "1:ff95a6c61f34f32e57833783059c80274d84e9c74e6e315c3dc2e93e9bf3dab9" name = "github.com/pierrec/xxHash" packages = ["xxHash32"] + pruneopts = "" revision = "f051bb7f1d1aaf1b5a665d74fb6b0217712c69f7" version = "v0.1.1" -[[projects]] - name = "github.com/pmezard/go-difflib" - packages = ["difflib"] - revision = "792786c7400a136282c1664665ae0a8db921c6c2" - version = "v1.0.0" - [[projects]] branch = "master" + digest = "1:5e3f4c2357e1e95ede9f36dc027b4b5a2cca463c8899344c22ebeb7c0abab8d5" name = "github.com/rcrowley/go-metrics" packages = ["."] + pruneopts = "" revision = "1f30fe9094a513ce4c700b9a54458bbb0c96996c" [[projects]] branch = "master" + digest = "1:10332fc7c87ee09af278e9c1899f1349f5c54dd22843ad2030e6556d05c5983e" name = "github.com/streadway/amqp" packages = ["."] + pruneopts = "" revision = "cefed15a0bd808d13947f228770a81b06ebe8e45" [[projects]] - name = "github.com/stretchr/testify" - packages = ["assert"] - revision = "69483b4bd14f5845b5a1e55bca19e954e827f1d0" - version = "v1.1.4" + branch = "master" + digest = "1:6e319cc90f8432f0ac3f78e6bb7be410e6939b6405e1ba84ae4e920de15476f3" + name = "github.com/tidwall/boxtree" + packages = ["d2"] + pruneopts = "" + revision = "a570caa42c5e4c65f50e6f7ca0e7fa1c5084981c" [[projects]] branch = "master" + digest = "1:b28f2f9253cbb1bf2bcb3c0ab7421d2f88a245386199a6668b0a66eb09ce3e1f" name = "github.com/tidwall/btree" packages = ["."] + pruneopts = "" revision = "9876f1454cf0993a53d74c27196993e345f50dd1" [[projects]] branch = "master" + digest = "1:2fef6390e8d9118debd4937a699afad9e1629f2d5d3c965a58fc33afe04f9b46" name = "github.com/tidwall/buntdb" packages = ["."] + pruneopts = "" revision = "b67b1b8c1658cb01502801c14e33c61e6c4cbb95" [[projects]] + digest = "1:211773b67c5594aa92b1e8389c59558fa4927614507ea38237265e00c0ba6b81" name = "github.com/tidwall/gjson" packages = ["."] + pruneopts = "" revision = "5a69e67cfd8f6f9b0044ed49f5079d0eeed28653" version = "v1.0.1" [[projects]] branch = "master" + digest = "1:bf59f997bab72b8ecd044aed35d706edb6abd6128afe0502c94398b2374f1f3f" name = "github.com/tidwall/grect" packages = ["."] + pruneopts = "" revision = "ba9a043346eba55344e40d66a5e74cfda3a9d293" [[projects]] branch = "master" + digest = "1:96eb1cfd440166e1313d61021adba328e0dfeeac426abf9cc8c9879019b99b59" name = "github.com/tidwall/lotsa" packages = ["."] + pruneopts = "" revision = "a03631ac7f1cd37f159fca01ff6d600b3536d3cf" [[projects]] branch = "master" + digest = "1:4db4f92bb9cb04cfc4fccb36aba2598b02a988008c4cc0692b241214ad8ac96e" name = "github.com/tidwall/match" packages = ["."] + pruneopts = "" revision = "1731857f09b1f38450e2c12409748407822dc6be" [[projects]] branch = "master" + digest = "1:630381558bc538e831db8468dd0dc2702d81789f79b8ddf665eeebc729e2a055" name = "github.com/tidwall/redbench" packages = ["."] + pruneopts = "" revision = "637a608ebec1acbf049c2e4a5eda6c2d72aa3af1" [[projects]] branch = "master" + digest = "1:3d97df307101403f6647217a1af92bdb1dc15d7d4c2c92280faeeb98c4fce0f2" name = "github.com/tidwall/redcon" packages = ["."] + pruneopts = "" revision = "3df12143a4fe57c9f0d7f0f37e29ad95bc37f9a7" [[projects]] branch = "master" + digest = "1:f0bb37e804b0c1901995b54f51a63f23ff0bb67747a1f8d37a666f394025bbc8" name = "github.com/tidwall/resp" packages = ["."] + pruneopts = "" revision = "b2b1a7ca20e34ad839fdb81f78e67522c99959f0" [[projects]] branch = "master" + digest = "1:9384bff0cadcd196d5981923a738898c36d4ce049781152b9a9816791c8221b4" name = "github.com/tidwall/rtree" packages = ["."] + pruneopts = "" revision = "d4a8a3d30d5729f85edfba1745241f3a621d0359" [[projects]] + digest = "1:ed6a1c415a0bd35c9c18eec74bfd460a57ba21fb3bc0da629afc275096edffa4" name = "github.com/tidwall/sjson" packages = ["."] + pruneopts = "" revision = "6a22caf2fd45d5e2119bfc3717e984f15a7eb7ee" version = "v1.0.0" [[projects]] branch = "master" - name = "github.com/tidwall/tinyqueue" - packages = ["."] - revision = "1feaf062ef04a231c9126f99a68eaa579fd0e390" - -[[projects]] - branch = "master" + digest = "1:9d71091ff8756d88318a4334be685d311b10e1a01c0290ce743187b3bfb1b3f6" name = "github.com/yuin/gopher-lua" - packages = [".","ast","parse","pm"] + packages = [ + ".", + "ast", + "parse", + "pm", + ] + pruneopts = "" revision = "eb1c7299435cc746b72514f37f74a5154dfe460f" [[projects]] branch = "master" + digest = "1:d2438f1c85d855408197edcbac2ba137513738ccefbd12396b0af99d5449880b" name = "golang.org/x/crypto" packages = ["ssh/terminal"] + pruneopts = "" revision = "9419663f5a44be8b34ca85f08abc5fe1be11f8a3" [[projects]] branch = "master" + digest = "1:898bc7c802c1e0c20cecd65811e90b7b9bc5651b4a07aefd159451bfb200b2b3" name = "golang.org/x/net" - packages = ["context","http2","http2/hpack","idna","internal/timeseries","lex/httplex","proxy","trace","websocket"] + packages = [ + "context", + "http2", + "http2/hpack", + "idna", + "internal/timeseries", + "lex/httplex", + "proxy", + "trace", + "websocket", + ] + pruneopts = "" revision = "a04bdaca5b32abe1c069418fb7088ae607de5bd0" [[projects]] branch = "master" + digest = "1:e9f555036bb1a2f61074131371313348581fa1b643c0e5f8c0a436bf7ce6db69" name = "golang.org/x/sys" - packages = ["unix","windows"] + packages = [ + "unix", + "windows", + ] + pruneopts = "" revision = "314a259e304ff91bd6985da2a7149bbf91237993" [[projects]] branch = "master" + digest = "1:de5f2b854c46e933cd32e9c6e1f4bcf79d38587037f9a35178dde028779d9067" name = "golang.org/x/text" - packages = ["collate","collate/build","internal/colltab","internal/gen","internal/tag","internal/triegen","internal/ucd","language","secure/bidirule","transform","unicode/bidi","unicode/cldr","unicode/norm","unicode/rangetable"] + packages = [ + "collate", + "collate/build", + "internal/colltab", + "internal/gen", + "internal/tag", + "internal/triegen", + "internal/ucd", + "language", + "secure/bidirule", + "transform", + "unicode/bidi", + "unicode/cldr", + "unicode/norm", + "unicode/rangetable", + ] + pruneopts = "" revision = "d82c1812e304abfeeabd31e995a115a2855bf642" [[projects]] branch = "master" + digest = "1:180913ea45cbe0072abce387a686b929908f8213106a735fe1d1273ae5239648" name = "google.golang.org/genproto" packages = ["googleapis/rpc/status"] + pruneopts = "" revision = "f676e0f3ac6395ff1a529ae59a6670878a8371a6" [[projects]] + digest = "1:b3c989821c14a572c49a8091fd1e832a5e53d3ae2fbf90ed3ea46cef4863aad9" name = "google.golang.org/grpc" - packages = [".","codes","connectivity","credentials","grpclb/grpc_lb_v1/messages","grpclog","internal","keepalive","metadata","naming","peer","stats","status","tap","transport"] + packages = [ + ".", + "codes", + "connectivity", + "credentials", + "grpclb/grpc_lb_v1/messages", + "grpclog", + "internal", + "keepalive", + "metadata", + "naming", + "peer", + "stats", + "status", + "tap", + "transport", + ] + pruneopts = "" revision = "f92cdcd7dcdc69e81b2d7b338479a19a8723cfa3" version = "v1.6.0" [[projects]] branch = "master" + digest = "1:d14d9e6f479cbbac36f556199034db558ec5755b59dcf9b44fa373611e97c7be" name = "layeh.com/gopher-json" packages = ["."] + pruneopts = "" revision = "c128cc74278be889c4381681712931976fe0d88b" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "815f293904a566198a4157c81abad0db57c378fad869347de42c2201795b2158" + input-imports = [ + "github.com/Shopify/sarama", + "github.com/aws/aws-sdk-go/aws", + "github.com/aws/aws-sdk-go/aws/credentials", + "github.com/aws/aws-sdk-go/aws/session", + "github.com/aws/aws-sdk-go/service/sqs", + "github.com/eclipse/paho.mqtt.golang", + "github.com/garyburd/redigo/redis", + "github.com/golang/protobuf/proto", + "github.com/peterh/liner", + "github.com/streadway/amqp", + "github.com/tidwall/boxtree/d2", + "github.com/tidwall/btree", + "github.com/tidwall/buntdb", + "github.com/tidwall/gjson", + "github.com/tidwall/lotsa", + "github.com/tidwall/redbench", + "github.com/tidwall/redcon", + "github.com/tidwall/resp", + "github.com/tidwall/sjson", + "github.com/yuin/gopher-lua", + "golang.org/x/crypto/ssh/terminal", + "golang.org/x/net/context", + "google.golang.org/grpc", + "layeh.com/gopher-json", + ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 4fc657ec..b5843b77 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -20,9 +20,12 @@ # name = "github.com/x/y" # version = "2.4.0" - required = ["github.com/tidwall/lotsa"] +[[constraint]] + branch = "master" + name = "github.com/tidwall/boxtree" + [[constraint]] name = "github.com/Shopify/sarama" version = "1.13.0" diff --git a/README.md b/README.md index 3db73f44..ae452302 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,6 @@ Tile38 is an open source (MIT licensed), in-memory geolocation data store, spati - Leader / follower [replication](#replication). - In-memory database that persists on disk. - All coordinates are in [WGS 84 Web Mercator / EPSG:3857](#coordinate-system) -- Fast R-Tree indexes based on the [RBush](https://github.com/mourner/rbush) library by [Vladimir Agafonkin](https://github.com/mourner) ## Components - `tile38-server ` - The server diff --git a/pkg/index/index.go b/pkg/index/index.go index 200d8618..020d0d89 100644 --- a/pkg/index/index.go +++ b/pkg/index/index.go @@ -1,19 +1,17 @@ package index import ( - rtree "github.com/tidwall/tile38/pkg/index/rtree" + "github.com/tidwall/boxtree/d2" ) // Index is a geospatial index type Index struct { - r *rtree.RTree + r d2.BoxTree } // New create a new index func New() *Index { - return &Index{ - r: rtree.New(), - } + return &Index{} } // Item represents an index item. @@ -40,13 +38,13 @@ func (item *FlexItem) Point() (x, y float64) { // Insert inserts an item into the index func (ix *Index) Insert(item Item) { minX, minY, maxX, maxY := item.Rect() - ix.r.Insert([2]float64{minX, minY}, [2]float64{maxX, maxY}, item) + ix.r.Insert([]float64{minX, minY}, []float64{maxX, maxY}, item) } // Remove removed an item from the index func (ix *Index) Remove(item Item) { minX, minY, maxX, maxY := item.Rect() - ix.r.Remove([2]float64{minX, minY}, [2]float64{maxX, maxY}, item) + ix.r.Delete([]float64{minX, minY}, []float64{maxX, maxY}, item) } // Count counts all items in the index. @@ -63,22 +61,35 @@ func (ix *Index) Bounds() (MinX, MinY, MaxX, MaxY float64) { // RemoveAll removes all items from the index. func (ix *Index) RemoveAll() { - ix.r = rtree.New() + ix.r = d2.BoxTree{} } +// KNN returns the nearsest neighbors func (ix *Index) KNN(x, y float64, iterator func(item interface{}) bool) bool { - return ix.r.KNN([2]float64{x, y}, [2]float64{x, y}, true, - func(item interface{}, dist float64) bool { - return iterator(item) + res := true + ix.r.Nearby([]float64{x, y}, []float64{x, y}, + func(_, _ []float64, item interface{}) bool { + if !iterator(item) { + res = false + return false + } + return true }) + return res } // Search returns all items that intersect the bounding box. func (ix *Index) Search(minX, minY, maxX, maxY float64, iterator func(item interface{}) bool, ) bool { - return ix.r.Search([2]float64{minX, minY}, [2]float64{maxX, maxY}, - func(item interface{}) bool { - return iterator(item) + res := true + ix.r.Search([]float64{minX, minY}, []float64{maxX, maxY}, + func(_, _ []float64, item interface{}) bool { + if !iterator(item) { + res = false + return false + } + return true }) + return res } diff --git a/pkg/index/rtree/.gitignore b/pkg/index/rtree/.gitignore deleted file mode 100644 index e33609d2..00000000 --- a/pkg/index/rtree/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.png diff --git a/pkg/index/rtree/base.go b/pkg/index/rtree/base.go deleted file mode 100644 index de5d603f..00000000 --- a/pkg/index/rtree/base.go +++ /dev/null @@ -1,660 +0,0 @@ -// This package is adapted from the RBush project by Vladimir Agafonkin. -// https://github.com/mourner/rbush - -package rtree - -import ( - "math" - "unsafe" -) - -// D is the number of dimensions -const D = 2 -const M = 13 - -// precalculate infinity -var mathInfNeg = math.Inf(-1) -var mathInfPos = math.Inf(+1) - -type treeNode struct { - min, max [D]float64 - children [M + 1]*treeNode - count int - height int - leaf bool -} - -func (node *treeNode) unsafeItem() *treeItem { - return (*treeItem)(unsafe.Pointer(node)) -} - -func createNode(children []*treeNode) *treeNode { - n := &treeNode{ - height: 1, - leaf: true, - } - if len(children) > 0 { - n.count = len(children) - copy(n.children[:n.count], children) - } - - for i := 0; i < D; i++ { - n.min[i] = mathInfPos - n.max[i] = mathInfNeg - } - return n -} - -func (node *treeNode) extend(b *treeNode) { - for i := 0; i < len(node.min); i++ { - if b.min[i] < node.min[i] { - node.min[i] = b.min[i] - } - if b.max[i] > node.max[i] { - node.max[i] = b.max[i] - } - } -} - -func (node *treeNode) area() float64 { - area := node.max[0] - node.min[0] - for i := 1; i < len(node.min); i++ { - area *= node.max[i] - node.min[i] - } - return area -} - -func (node *treeNode) enlargedAreaAxis(b *treeNode, axis int) float64 { - var max, min float64 - if b.max[axis] > node.max[axis] { - max = b.max[axis] - } else { - max = node.max[axis] - } - if b.min[axis] < node.min[axis] { - min = b.min[axis] - } else { - min = node.min[axis] - } - return max - min -} - -func (node *treeNode) enlargedArea(b *treeNode) float64 { - area := node.enlargedAreaAxis(b, 0) - for i := 1; i < len(node.min); i++ { - area *= node.enlargedAreaAxis(b, i) - } - return area -} - -func (node *treeNode) intersectionAreaAxis(b *treeNode, axis int) float64 { - var max, min float64 - if node.max[axis] < b.max[axis] { - max = node.max[axis] - } else { - max = b.max[axis] - } - if node.min[axis] > b.min[axis] { - min = node.min[axis] - } else { - min = b.min[axis] - } - if max > min { - return max - min - } - return 0 -} -func (node *treeNode) intersectionArea(b *treeNode) float64 { - area := node.intersectionAreaAxis(b, 0) - for i := 1; i < len(node.min); i++ { - area *= node.intersectionAreaAxis(b, i) - } - return area -} -func (node *treeNode) margin() float64 { - margin := node.max[0] - node.min[0] - for i := 1; i < len(node.min); i++ { - margin += node.max[i] - node.min[i] - } - return margin -} - -type result int - -const ( - not result = 0 - intersects result = 1 - contains result = 2 -) - -func (node *treeNode) overlaps(b *treeNode) result { - for i := 0; i < len(node.min); i++ { - if b.min[i] > node.max[i] || b.max[i] < node.min[i] { - return not - } - if node.min[i] > b.min[i] || b.max[i] > node.max[i] { - i++ - for ; i < len(node.min); i++ { - if b.min[i] > node.max[i] || b.max[i] < node.min[i] { - return not - } - } - return intersects - } - } - return contains -} - -func (node *treeNode) intersects(b *treeNode) bool { - for i := 0; i < len(node.min); i++ { - if b.min[i] > node.max[i] || b.max[i] < node.min[i] { - return false - } - } - return true -} - -func (node *treeNode) findItem(item interface{}) int { - for i := 0; i < node.count; i++ { - if node.children[i].unsafeItem().item == item { - return i - } - } - return -1 -} - -func (node *treeNode) contains(b *treeNode) bool { - for i := 0; i < len(node.min); i++ { - if node.min[i] > b.min[i] || b.max[i] > node.max[i] { - return false - } - } - return true -} - -func (node *treeNode) childCount() int { - if node.leaf { - return node.count - } - var n int - for i := 0; i < node.count; i++ { - n += node.children[i].childCount() - } - return n -} - -type treeItem struct { - min, max [D]float64 - item interface{} -} - -func (item *treeItem) unsafeNode() *treeNode { - return (*treeNode)(unsafe.Pointer(item)) -} - -// RTree is an R-tree -type RTree struct { - maxEntries int - minEntries int - data *treeNode // root node - // resusable fields, these help performance of common mutable operations. - reuse struct { - path []*treeNode // for reinsertion path - indexes []int // for remove function - stack []int // for bulk loading - } -} - -// New creates a new R-tree -func New() *RTree { - tr := &RTree{} - tr.maxEntries = int(math.Max(4, float64(M))) - tr.minEntries = int(math.Max(2, math.Ceil(float64(tr.maxEntries)*0.4))) - tr.data = createNode(nil) - return tr -} - -// Insert inserts an item -func (tr *RTree) Insert(min, max [D]float64, item interface{}) { - if item == nil { - panic("nil item") - } - bbox := treeNode{min: min, max: max} - tr.insert(&bbox, item, tr.data.height-1, false) -} - -func (tr *RTree) insert(bbox *treeNode, item interface{}, level int, isNode bool) { - tr.reuse.path = tr.reuse.path[:0] - node, insertPath := tr.chooseSubtree(bbox, tr.data, level, tr.reuse.path) - if item == nil { - // item is only nil when bulk loading a node - if node.leaf { - panic("loading node into leaf") - } - node.children[node.count] = bbox - node.count++ - } else { - ti := &treeItem{min: bbox.min, max: bbox.max, item: item} - node.children[node.count] = ti.unsafeNode() - node.count++ - } - node.extend(bbox) - for level >= 0 { - if insertPath[level].count > tr.maxEntries { - insertPath = tr.split(insertPath, level) - level-- - } else { - break - } - } - tr.adjustParentBBoxes(bbox, insertPath, level) - tr.reuse.path = insertPath -} - -func (tr *RTree) adjustParentBBoxes(bbox *treeNode, path []*treeNode, level int) { - // adjust bboxes along the given tree path - for i := level; i >= 0; i-- { - path[i].extend(bbox) - } -} - -func (tr *RTree) chooseSubtree(bbox, node *treeNode, level int, path []*treeNode) (*treeNode, []*treeNode) { - var targetNode *treeNode - var area, enlargement, minArea, minEnlargement float64 - for { - path = append(path, node) - if node.leaf || len(path)-1 == level { - break - } - minEnlargement = mathInfPos - minArea = minEnlargement - for i := 0; i < node.count; i++ { - child := node.children[i] - area = child.area() - enlargement = bbox.enlargedArea(child) - area - if enlargement < minEnlargement { - minEnlargement = enlargement - if area < minArea { - minArea = area - } - targetNode = child - } else if enlargement == minEnlargement { - if area < minArea { - minArea = area - targetNode = child - } - } - } - if targetNode != nil { - node = targetNode - } else if node.count > 0 { - node = (*treeNode)(node.children[0]) - } else { - node = nil - } - } - return node, path -} -func (tr *RTree) split(insertPath []*treeNode, level int) []*treeNode { - var node = insertPath[level] - var M = node.count - var m = tr.minEntries - - tr.chooseSplitAxis(node, m, M) - splitIndex := tr.chooseSplitIndex(node, m, M) - - spliced := make([]*treeNode, node.count-splitIndex) - copy(spliced, node.children[splitIndex:]) - node.count = splitIndex - - newNode := createNode(spliced) - newNode.height = node.height - newNode.leaf = node.leaf - - tr.calcBBox(node) - tr.calcBBox(newNode) - - if level != 0 { - insertPath[level-1].children[insertPath[level-1].count] = newNode - insertPath[level-1].count++ - } else { - tr.splitRoot(node, newNode) - } - return insertPath -} -func (tr *RTree) chooseSplitIndex(node *treeNode, m, M int) int { - var i int - var bbox1, bbox2 *treeNode - var overlap, area, minOverlap, minArea float64 - var index int - - minArea = mathInfPos - minOverlap = minArea - - for i = m; i <= M-m; i++ { - bbox1 = tr.distBBox(node, 0, i, nil) - bbox2 = tr.distBBox(node, i, M, nil) - - overlap = bbox1.intersectionArea(bbox2) - area = bbox1.area() + bbox2.area() - - // choose distribution with minimum overlap - if overlap < minOverlap { - minOverlap = overlap - index = i - - if area < minArea { - minArea = area - } - } else if overlap == minOverlap { - // otherwise choose distribution with minimum area - if area < minArea { - minArea = area - index = i - } - } - } - return index -} -func (tr *RTree) calcBBox(node *treeNode) { - tr.distBBox(node, 0, node.count, node) -} -func (tr *RTree) chooseSplitAxis(node *treeNode, m, M int) { - minMargin := tr.allDistMargin(node, m, M, 0) - var minAxis int - for axis := 1; axis < D; axis++ { - margin := tr.allDistMargin(node, m, M, axis) - if margin < minMargin { - minMargin = margin - minAxis = axis - } - } - if minAxis < D { - tr.sortNodes(node, minAxis) - } -} -func (tr *RTree) splitRoot(node, newNode *treeNode) { - tr.data = createNode([]*treeNode{node, newNode}) - tr.data.height = node.height + 1 - tr.data.leaf = false - tr.calcBBox(tr.data) -} -func (tr *RTree) distBBox(node *treeNode, k, p int, destNode *treeNode) *treeNode { - if destNode == nil { - destNode = createNode(nil) - } else { - for i := 0; i < D; i++ { - destNode.min[i] = mathInfPos - destNode.max[i] = mathInfNeg - } - } - for i := k; i < p; i++ { - if node.leaf { - destNode.extend(node.children[i]) - } else { - destNode.extend((*treeNode)(node.children[i])) - } - } - return destNode -} -func (tr *RTree) allDistMargin(node *treeNode, m, M int, axis int) float64 { - tr.sortNodes(node, axis) - - var leftBBox = tr.distBBox(node, 0, m, nil) - var rightBBox = tr.distBBox(node, M-m, M, nil) - var margin = leftBBox.margin() + rightBBox.margin() - - var i int - - if node.leaf { - for i = m; i < M-m; i++ { - leftBBox.extend(node.children[i]) - margin += leftBBox.margin() - } - for i = M - m - 1; i >= m; i-- { - leftBBox.extend(node.children[i]) - margin += rightBBox.margin() - } - } else { - for i = m; i < M-m; i++ { - child := (*treeNode)(node.children[i]) - leftBBox.extend(child) - margin += leftBBox.margin() - } - for i = M - m - 1; i >= m; i-- { - child := (*treeNode)(node.children[i]) - leftBBox.extend(child) - margin += rightBBox.margin() - } - } - return margin -} -func (tr *RTree) sortNodes(node *treeNode, axis int) { - sortByAxis(node.children[:node.count], axis) -} - -func sortByAxis(items []*treeNode, axis int) { - if len(items) < 2 { - return - } - left, right := 0, len(items)-1 - pivotIndex := len(items) / 2 - items[pivotIndex], items[right] = items[right], items[pivotIndex] - for i := range items { - if items[i].min[axis] < items[right].min[axis] { - items[i], items[left] = items[left], items[i] - left++ - } - } - items[left], items[right] = items[right], items[left] - sortByAxis(items[:left], axis) - sortByAxis(items[left+1:], axis) -} - -// Search searches the tree for items in the input rectangle -func (tr *RTree) Search(min, max [D]float64, iter func(item interface{}) bool) bool { - bbox := &treeNode{min: min, max: max} - if !tr.data.intersects(bbox) { - return true - } - return tr.search(tr.data, bbox, iter) -} - -func (tr *RTree) search(node, bbox *treeNode, iter func(item interface{}) bool) bool { - if node.leaf { - for i := 0; i < node.count; i++ { - if bbox.intersects(node.children[i]) { - if !iter(node.children[i].unsafeItem().item) { - return false - } - } - } - } else { - for i := 0; i < node.count; i++ { - r := bbox.overlaps(node.children[i]) - if r == intersects { - if !tr.search(node.children[i], bbox, iter) { - return false - } - } else if r == contains { - if !scan(node.children[i], iter) { - return false - } - } - } - } - return true -} - -// Remove removes an item from the R-tree. -func (tr *RTree) Remove(min, max [D]float64, item interface{}) { - bbox := &treeNode{min: min, max: max} - tr.remove(bbox, item) -} - -func (tr *RTree) remove(bbox *treeNode, item interface{}) { - path := tr.reuse.path[:0] - indexes := tr.reuse.indexes[:0] - - var node = tr.data - var i int - var parent *treeNode - var index int - var goingUp bool - - for node != nil || len(path) != 0 { - if node == nil { - node = path[len(path)-1] - path = path[:len(path)-1] - if len(path) == 0 { - parent = nil - } else { - parent = path[len(path)-1] - } - i = indexes[len(indexes)-1] - indexes = indexes[:len(indexes)-1] - goingUp = true - } - - if node.leaf { - index = node.findItem(item) - if index != -1 { - // item found, remove the item and condense tree upwards - copy(node.children[index:], node.children[index+1:]) - node.children[node.count-1] = nil - node.count-- - path = append(path, node) - tr.condense(path) - goto done - } - } - if !goingUp && !node.leaf && node.contains(bbox) { // go down - path = append(path, node) - indexes = append(indexes, i) - i = 0 - parent = node - node = (*treeNode)(node.children[0]) - } else if parent != nil { // go right - i++ - if i == parent.count { - node = nil - } else { - node = (*treeNode)(parent.children[i]) - } - goingUp = false - } else { - node = nil - } - } -done: - tr.reuse.path = path - tr.reuse.indexes = indexes - return -} -func (tr *RTree) condense(path []*treeNode) { - // go through the path, removing empty nodes and updating bboxes - var siblings []*treeNode - for i := len(path) - 1; i >= 0; i-- { - if path[i].count == 0 { - if i > 0 { - siblings = path[i-1].children[:path[i-1].count] - index := -1 - for j := 0; j < len(siblings); j++ { - if siblings[j] == path[i] { - index = j - break - } - } - copy(siblings[index:], siblings[index+1:]) - siblings[len(siblings)-1] = nil - path[i-1].count-- - //siblings = siblings[:len(siblings)-1] - //path[i-1].children = siblings - } else { - tr.data = createNode(nil) // clear tree - } - } else { - tr.calcBBox(path[i]) - } - } -} - -// Count returns the number of items in the R-tree. -func (tr *RTree) Count() int { - return tr.data.childCount() -} - -// Traverse iterates over the entire R-tree and includes all nodes and items. -func (tr *RTree) Traverse(iter func(min, max [D]float64, level int, item interface{}) bool) bool { - return tr.traverse(tr.data, iter) -} - -func (tr *RTree) traverse(node *treeNode, iter func(min, max [D]float64, level int, item interface{}) bool) bool { - if !iter(node.min, node.max, int(node.height), nil) { - return false - } - if node.leaf { - for i := 0; i < node.count; i++ { - child := node.children[i] - if !iter(child.min, child.max, 0, child.unsafeItem().item) { - return false - } - } - } else { - for i := 0; i < node.count; i++ { - child := node.children[i] - if !tr.traverse(child, iter) { - return false - } - } - } - return true -} - -// Scan iterates over the entire R-tree -func (tr *RTree) Scan(iter func(item interface{}) bool) bool { - return scan(tr.data, iter) -} - -func scan(node *treeNode, iter func(item interface{}) bool) bool { - if node.leaf { - for i := 0; i < node.count; i++ { - child := node.children[i] - if !iter(child.unsafeItem().item) { - return false - } - } - } else { - for i := 0; i < node.count; i++ { - child := node.children[i] - if !scan(child, iter) { - return false - } - } - } - return true -} - -// Bounds returns the bounding box of the entire R-tree -func (tr *RTree) Bounds() (min, max [D]float64) { - if tr.data.count > 0 { - min, max = tr.data.min, tr.data.max - } - return -} - -// Complexity returns the complexity of the R-tree. The higher the value, the -// more complex the tree. The value of 1 is the lowest. -func (tr *RTree) Complexity() float64 { - var nodeCount int - var itemCount int - tr.Traverse(func(_, _ [D]float64, level int, _ interface{}) bool { - if level == 0 { - itemCount++ - } else { - nodeCount++ - } - return true - }) - return float64(tr.maxEntries*nodeCount) / float64(itemCount) -} diff --git a/pkg/index/rtree/base_test.go b/pkg/index/rtree/base_test.go deleted file mode 100644 index f020fca2..00000000 --- a/pkg/index/rtree/base_test.go +++ /dev/null @@ -1,554 +0,0 @@ -package rtree - -import ( - "fmt" - "log" - "math" - "math/rand" - "runtime" - "sort" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -type Rect struct { - min, max [D]float64 - item interface{} -} - -func ptrMakePoint(vals ...float64) *Rect { - var r Rect - for i := 0; i < D && i < len(vals); i++ { - r.min[i] = vals[i] - r.max[i] = vals[i] - } - r.item = &r - return &r -} - -func ptrMakeRect(vals ...float64) *Rect { - var r Rect - for i := 0; i < D && i < len(vals); i++ { - r.min[i] = vals[i] - r.max[i] = vals[i+D] - } - r.item = &r - return &r -} - -func TestRTree(t *testing.T) { - tr := New() - p := ptrMakePoint(10, 10) - tr.Insert(p.min, p.max, p.item) -} - -func TestPtrBasic2D(t *testing.T) { - if D != 2 { - return - } - tr := New() - p1 := ptrMakePoint(-115, 33) - p2 := ptrMakePoint(-113, 35) - tr.Insert(p1.min, p1.max, p1.item) - tr.Insert(p2.min, p2.max, p2.item) - assert.Equal(t, 2, tr.Count()) - - var points []*Rect - bbox := ptrMakeRect(-116, 32, -114, 34) - tr.Search(bbox.min, bbox.max, func(item interface{}) bool { - points = append(points, item.(*Rect)) - return true - }) - assert.Equal(t, 1, len(points)) - tr.Remove(p1.min, p1.max, p1.item) - assert.Equal(t, 1, tr.Count()) - - points = nil - bbox = ptrMakeRect(-116, 33, -114, 34) - tr.Search(bbox.min, bbox.max, func(item interface{}) bool { - points = append(points, item.(*Rect)) - return true - }) - assert.Equal(t, 0, len(points)) - tr.Remove(p2.min, p2.max, p2.item) - assert.Equal(t, 0, tr.Count()) -} - -func getMemStats() runtime.MemStats { - runtime.GC() - time.Sleep(time.Millisecond) - runtime.GC() - var ms runtime.MemStats - runtime.ReadMemStats(&ms) - return ms -} - -func ptrMakeRandom(what string) *Rect { - if what == "point" { - vals := make([]float64, D) - for i := 0; i < D; i++ { - if i == 0 { - vals[i] = rand.Float64()*360 - 180 - } else if i == 1 { - vals[i] = rand.Float64()*180 - 90 - } else { - vals[i] = rand.Float64()*100 - 50 - } - } - return ptrMakePoint(vals...) - } else if what == "rect" { - vals := make([]float64, D) - for i := 0; i < D; i++ { - if i == 0 { - vals[i] = rand.Float64()*340 - 170 - } else if i == 1 { - vals[i] = rand.Float64()*160 - 80 - } else { - vals[i] = rand.Float64()*80 - 30 - } - } - rvals := make([]float64, D*2) - for i := 0; i < D; i++ { - rvals[i] = vals[i] - rand.Float64()*10 - rvals[D+i] = vals[i] + rand.Float64()*10 - } - return ptrMakeRect(rvals...) - } - panic("??") -} - -func TestPtrRandom(t *testing.T) { - t.Run(fmt.Sprintf("%dD", D), func(t *testing.T) { - t.Run("point", func(t *testing.T) { ptrTestRandom(t, "point", 10000) }) - t.Run("rect", func(t *testing.T) { ptrTestRandom(t, "rect", 10000) }) - }) -} - -func ptrTestRandom(t *testing.T, which string, n int) { - fmt.Println("-------------------------------------------------") - fmt.Printf("Testing Random %dD %ss\n", D, which) - fmt.Println("-------------------------------------------------") - rand.Seed(time.Now().UnixNano()) - tr := New() - min, max := tr.Bounds() - assert.Equal(t, make([]float64, D), min[:]) - assert.Equal(t, make([]float64, D), max[:]) - - // create random objects - m1 := getMemStats() - objs := make([]*Rect, n) - for i := 0; i < n; i++ { - objs[i] = ptrMakeRandom(which) - } - - // insert the objects into tree - m2 := getMemStats() - start := time.Now() - for _, r := range objs { - tr.Insert(r.min, r.max, r.item) - } - durInsert := time.Since(start) - m3 := getMemStats() - assert.Equal(t, len(objs), tr.Count()) - fmt.Printf("Inserted %d random %ss in %dms -- %d ops/sec\n", - len(objs), which, int(durInsert.Seconds()*1000), - int(float64(len(objs))/durInsert.Seconds())) - fmt.Printf(" total cost is %d bytes/%s\n", int(m3.HeapAlloc-m1.HeapAlloc)/len(objs), which) - fmt.Printf(" tree cost is %d bytes/%s\n", int(m3.HeapAlloc-m2.HeapAlloc)/len(objs), which) - fmt.Printf(" tree overhead %d%%\n", int((float64(m3.HeapAlloc-m2.HeapAlloc)/float64(len(objs)))/(float64(m3.HeapAlloc-m1.HeapAlloc)/float64(len(objs)))*100)) - fmt.Printf(" complexity %f\n", tr.Complexity()) - - start = time.Now() - // count all nodes and leaves - var nodes int - var leaves int - var maxLevel int - tr.Traverse(func(min, max [D]float64, level int, item interface{}) bool { - if level != 0 { - nodes++ - } - if level == 1 { - leaves++ - } - if level > maxLevel { - maxLevel = level - } - return true - }) - fmt.Printf(" nodes: %d, leaves: %d, level: %d\n", nodes, leaves, maxLevel) - - // verify mbr - for i := 0; i < D; i++ { - min[i] = math.Inf(+1) - max[i] = math.Inf(-1) - } - for _, o := range objs { - for i := 0; i < D; i++ { - if o.min[i] < min[i] { - min[i] = o.min[i] - } - if o.max[i] > max[i] { - max[i] = o.max[i] - } - } - } - minb, maxb := tr.Bounds() - assert.Equal(t, min, minb) - assert.Equal(t, max, maxb) - - // scan - var arr []*Rect - tr.Scan(func(item interface{}) bool { - arr = append(arr, item.(*Rect)) - return true - }) - assert.True(t, ptrTestHasSameItems(objs, arr)) - - // search - ptrTestSearch(t, tr, objs, 0.10, true) - ptrTestSearch(t, tr, objs, 0.50, true) - ptrTestSearch(t, tr, objs, 1.00, true) - - // knn - ptrTestKNN(t, tr, objs, int(float64(len(objs))*0.01), true) - ptrTestKNN(t, tr, objs, int(float64(len(objs))*0.50), true) - ptrTestKNN(t, tr, objs, int(float64(len(objs))*1.00), true) - - // remove all objects - indexes := rand.Perm(len(objs)) - start = time.Now() - for _, i := range indexes { - tr.Remove(objs[i].min, objs[i].max, objs[i].item) - } - durRemove := time.Since(start) - assert.Equal(t, 0, tr.Count()) - fmt.Printf("Removed %d random %ss in %dms -- %d ops/sec\n", - len(objs), which, int(durRemove.Seconds()*1000), - int(float64(len(objs))/durRemove.Seconds())) - - min, max = tr.Bounds() - assert.Equal(t, make([]float64, D), min[:]) - assert.Equal(t, make([]float64, D), max[:]) -} - -func ptrTestHasSameItems(a1, a2 []*Rect) bool { - if len(a1) != len(a2) { - return false - } - for _, p1 := range a1 { - var found bool - for _, p2 := range a2 { - if *p1 == *p2 { - found = true - break - } - } - if !found { - return false - } - } - return true -} - -func ptrTestSearch(t *testing.T, tr *RTree, objs []*Rect, percent float64, check bool) { - var found int - var start time.Time - var stop time.Time - defer func() { - dur := stop.Sub(start) - fmt.Printf("Searched %.0f%% (%d/%d items) in %dms -- %d ops/sec\n", - percent*100, found, len(objs), int(dur.Seconds()*1000), - int(float64(1)/dur.Seconds()), - ) - }() - min, max := tr.Bounds() - vals := make([]float64, D*2) - for i := 0; i < D; i++ { - vals[i] = ((max[i]+min[i])/2 - ((max[i]-min[i])*percent)/2) - vals[D+i] = ((max[i]+min[i])/2 + ((max[i]-min[i])*percent)/2) - } - var arr1 []*Rect - var box *Rect - if percent == 1 { - box = ptrMakeRect(append(append([]float64{}, min[:]...), max[:]...)...) - } else { - box = ptrMakeRect(vals...) - } - start = time.Now() - tr.Search(box.min, box.max, func(item interface{}) bool { - if check { - arr1 = append(arr1, item.(*Rect)) - } - found++ - return true - }) - stop = time.Now() - if !check { - return - } - var arr2 []*Rect - for _, obj := range objs { - if ptrTestIntersects(obj, box) { - arr2 = append(arr2, obj) - } - } - assert.Equal(t, len(arr1), len(arr2)) - for _, o1 := range arr1 { - var found bool - for _, o2 := range arr2 { - if *o2 == *o1 { - found = true - break - } - } - if !found { - t.Fatalf("not found") - } - } -} - -func ptrTestKNN(t *testing.T, tr *RTree, objs []*Rect, n int, check bool) { - var start time.Time - var stop time.Time - defer func() { - dur := stop.Sub(start) - fmt.Printf("KNN %d items in %dms -- %d ops/sec\n", - n, int(dur.Seconds()*1000), - int(float64(1)/dur.Seconds()), - ) - }() - min, max := tr.Bounds() - pvals := make([]float64, D) - for i := 0; i < D; i++ { - pvals[i] = (max[i] + min[i]) / 2 - } - point := ptrMakePoint(pvals...) - - // gather the results, make sure that is matches exactly - var arr1 []Rect - var dists1 []float64 - pdist := math.Inf(-1) - start = time.Now() - tr.KNN(point.min, point.max, false, func(item interface{}, dist float64) bool { - if len(arr1) == n { - return false - } - arr1 = append(arr1, Rect{min: min, max: max, item: item}) - dists1 = append(dists1, dist) - if dist < pdist { - panic("dist out of order") - } - pdist = dist - return true - }) - stop = time.Now() - assert.True(t, n > len(objs) || n == len(arr1)) - - // get the KNN for the original array - nobjs := make([]*Rect, len(objs)) - copy(nobjs, objs) - sort.Slice(nobjs, func(i, j int) bool { - idist := ptrTestBoxDist(pvals, nobjs[i].min, nobjs[i].max) - jdist := ptrTestBoxDist(pvals, nobjs[j].min, nobjs[j].max) - return idist < jdist - }) - arr2 := nobjs[:len(arr1)] - var dists2 []float64 - for i := 0; i < len(arr2); i++ { - dist := ptrTestBoxDist(pvals, arr2[i].min, arr2[i].max) - dists2 = append(dists2, dist) - } - // only compare the distances, not the objects because rectangles with - // a dist of zero will not be ordered. - assert.Equal(t, dists1, dists2) - -} - -func ptrTestBoxDist(point []float64, min, max [D]float64) float64 { - var dist float64 - for i := 0; i < len(point); i++ { - d := ptrTestAxisDist(point[i], min[i], max[i]) - dist += d * d - } - return dist -} -func ptrTestAxisDist(k, min, max float64) float64 { - if k < min { - return min - k - } - if k <= max { - return 0 - } - return k - max -} -func ptrTestIntersects(obj, box *Rect) bool { - for i := 0; i < D; i++ { - if box.min[i] > obj.max[i] || box.max[i] < obj.min[i] { - return false - } - } - return true -} - -// func TestPtrInsertFlatPNG2D(t *testing.T) { -// fmt.Println("-------------------------------------------------") -// fmt.Println("Generating Cities PNG 2D (flat-insert-2d.png)") -// fmt.Println("-------------------------------------------------") -// tr := New() -// var items []*Rect -// c := cities.Cities -// for i := 0; i < len(c); i++ { -// x := c[i].Longitude -// y := c[i].Latitude -// items = append(items, ptrMakePoint(x, y)) -// } -// start := time.Now() -// for _, item := range items { -// tr.Insert(item.min, item.max, item.item) -// } -// dur := time.Since(start) -// fmt.Printf("wrote %d cities (flat) in %s (%.0f/ops)\n", len(c), dur, float64(len(c))/dur.Seconds()) -// withGIF := os.Getenv("GIFOUTPUT") != "" -// if err := tr.SavePNG("ptr-flat-insert-2d.png", 1000, 1000, 1.25/360.0, 0, true, withGIF, os.Stdout); err != nil { -// t.Fatal(err) -// } -// if !withGIF { -// fmt.Println("use GIFOUTPUT=1 for animated gif") -// } -// } - -// func TestPtrLoadFlatPNG2D(t *testing.T) { -// fmt.Println("-------------------------------------------------") -// fmt.Println("Generating Cities 2D PNG (flat-load-2d.png)") -// fmt.Println("-------------------------------------------------") -// tr := New() -// var items []*Rect -// c := cities.Cities -// for i := 0; i < len(c); i++ { -// x := c[i].Longitude -// y := c[i].Latitude -// items = append(items, ptrMakePoint(x, y)) -// } - -// var mins [][D]float64 -// var maxs [][D]float64 -// var ifs []interface{} -// for i := 0; i < len(items); i++ { -// mins = append(mins, items[i].min) -// maxs = append(maxs, items[i].max) -// ifs = append(ifs, items[i].item) -// } - -// start := time.Now() -// tr.Load(mins, maxs, ifs) -// dur := time.Since(start) - -// if true { -// var all []*Rect -// tr.Scan(func(min, max [D]float64, item interface{}) bool { -// all = append(all, &Rect{min: min, max: max, item: item}) -// return true -// }) -// assert.Equal(t, len(all), len(items)) - -// for len(all) > 0 { -// item := all[0] -// var found bool -// for _, city := range items { -// if *city == *item { -// found = true -// break -// } -// } -// if !found { -// t.Fatal("item not found") -// } -// all = all[1:] -// } -// } -// fmt.Printf("wrote %d cities (flat) in %s (%.0f/ops)\n", len(c), dur, float64(len(c))/dur.Seconds()) -// withGIF := os.Getenv("GIFOUTPUT") != "" -// if err := tr.SavePNG("ptr-flat-load-2d.png", 1000, 1000, 1.25/360.0, 0, true, withGIF, os.Stdout); err != nil { -// t.Fatal(err) -// } -// if !withGIF { -// fmt.Println("use GIFOUTPUT=1 for animated gif") -// } -// } - -func TestBenchmarks(t *testing.T) { - var points []*Rect - for i := 0; i < 2000000; i++ { - x := rand.Float64()*360 - 180 - y := rand.Float64()*180 - 90 - points = append(points, ptrMakePoint(x, y)) - } - tr := New() - start := time.Now() - for i := len(points) / 2; i < len(points); i++ { - tr.Insert(points[i].min, points[i].max, points[i].item) - } - dur := time.Since(start) - log.Printf("insert 1M items one by one: %.3fs", dur.Seconds()) - //// - rarr := rand.Perm(len(points) / 2) - start = time.Now() - for i := 0; i < len(points)/2; i++ { - a := points[rarr[i]+len(points)/2] - b := points[rarr[i]] - tr.Remove(a.min, a.max, a.item) - tr.Insert(b.min, b.max, b.item) - } - dur = time.Since(start) - log.Printf("replaced 1M items one by one: %.3fs", dur.Seconds()) - points = points[:len(points)/2] - //// - start = time.Now() - for i := 0; i < 1000; i++ { - tr.Remove(points[i].min, points[i].max, points[i].item) - } - dur = time.Since(start) - log.Printf("remove 100 items one by one: %.3fs", dur.Seconds()) - //// - bbox := ptrMakeRect(0, 0, 0+(360*0.0001), 0+(180*0.0001)) - start = time.Now() - for i := 0; i < 1000; i++ { - tr.Search(bbox.min, bbox.max, func(_ interface{}) bool { return true }) - } - dur = time.Since(start) - log.Printf("1000 searches of 0.01%% area: %.3fs", dur.Seconds()) - //// - bbox = ptrMakeRect(0, 0, 0+(360*0.01), 0+(180*0.01)) - start = time.Now() - for i := 0; i < 1000; i++ { - tr.Search(bbox.min, bbox.max, func(_ interface{}) bool { return true }) - } - dur = time.Since(start) - log.Printf("1000 searches of 1%% area: %.3fs", dur.Seconds()) - //// - bbox = ptrMakeRect(0, 0, 0+(360*0.10), 0+(180*0.10)) - start = time.Now() - for i := 0; i < 1000; i++ { - tr.Search(bbox.min, bbox.max, func(_ interface{}) bool { return true }) - } - dur = time.Since(start) - log.Printf("1000 searches of 10%% area: %.3fs", dur.Seconds()) - /// - - var mins [][D]float64 - var maxs [][D]float64 - var items []interface{} - for i := 0; i < len(points); i++ { - mins = append(mins, points[i].min) - maxs = append(maxs, points[i].max) - items = append(items, points[i].item) - } - - tr = New() - start = time.Now() - tr.Load(mins, maxs, items) - dur = time.Since(start) - log.Printf("bulk-insert 1M items: %.3fs", dur.Seconds()) -} diff --git a/pkg/index/rtree/knn.go b/pkg/index/rtree/knn.go deleted file mode 100644 index fa55a646..00000000 --- a/pkg/index/rtree/knn.go +++ /dev/null @@ -1,101 +0,0 @@ -// This package is adapted from the RBush project by Vladimir Agafonkin. -// https://github.com/mourner/rbush - -package rtree - -import ( - "github.com/tidwall/tinyqueue" -) - -type queueItem struct { - node *treeNode - isItem bool - dist float64 -} - -func (item *queueItem) Less(b tinyqueue.Item) bool { - return item.dist < b.(*queueItem).dist -} - -// KNN returns items nearest to farthest. The dist param is the "box distance". -func (tr *RTree) KNN(min, max [D]float64, center bool, iter func(item interface{}, dist float64) bool) bool { - var isBox bool - var knnPoint [D]float64 - - bbox := &treeNode{min: min, max: max} - - for i := 0; i < D; i++ { - knnPoint[i] = (bbox.min[i] + bbox.max[i]) / 2 - if !isBox && bbox.min[i] != bbox.max[i] { - isBox = true - } - } - node := tr.data - queue := tinyqueue.New(nil) - for node != nil { - for i := 0; i < node.count; i++ { - child := node.children[i] - var dist float64 - if isBox { - dist = boxDistRect(bbox, child) - } else { - dist = boxDistPoint(knnPoint, child) - } - queue.Push(&queueItem{node: child, isItem: node.leaf, dist: dist}) - } - for queue.Len() > 0 && queue.Peek().(*queueItem).isItem { - item := queue.Pop().(*queueItem) - if !iter(item.node.unsafeItem().item, item.dist) { - return false - } - } - last := queue.Pop() - if last != nil { - node = (*treeNode)(last.(*queueItem).node) - } else { - node = nil - } - } - return true -} - -func boxDistRect(a, b *treeNode) float64 { - var dist float64 - for i := 0; i < len(a.min); i++ { - var min, max float64 - if a.min[i] > b.min[i] { - min = a.min[i] - } else { - min = b.min[i] - } - if a.max[i] < b.max[i] { - max = a.max[i] - } else { - max = b.max[i] - } - squared := min - max - if squared > 0 { - dist += squared * squared - } - } - return dist -} - -func boxDistPoint(point [D]float64, childBox *treeNode) float64 { - var dist float64 - for i := 0; i < len(point); i++ { - d := axisDist(point[i], childBox.min[i], childBox.max[i]) - dist += d * d - } - return dist -} - -func axisDist(k, min, max float64) float64 { - if k < min { - return min - k - } - if k <= max { - return 0 - } - return k - max -} diff --git a/pkg/index/rtree/load.go b/pkg/index/rtree/load.go deleted file mode 100644 index f5550c5c..00000000 --- a/pkg/index/rtree/load.go +++ /dev/null @@ -1,102 +0,0 @@ -// This package is adapted from the RBush project by Vladimir Agafonkin. -// https://github.com/mourner/rbush - -package rtree - -import ( - "math" -) - -// Load bulk load items into the R-tree. -func (tr *RTree) Load(mins, maxs [][D]float64, items []interface{}) { - if len(items) < tr.minEntries { - for i := 0; i < len(items); i++ { - tr.Insert(mins[i], maxs[i], items[i]) - } - return - } - - // prefill the items - fitems := make([]*treeNode, len(items)) - for i := 0; i < len(items); i++ { - item := &treeItem{min: mins[i], max: maxs[i], item: items[i]} - fitems[i] = item.unsafeNode() - } - - // following equations are defined in the paper describing OMT - N := len(fitems) - M := tr.maxEntries - h := int(math.Ceil(math.Log(float64(N)) / math.Log(float64(M)))) - Nsubtree := int(math.Pow(float64(M), float64(h-1))) - S := int(math.Ceil(math.Sqrt(float64(N) / float64(Nsubtree)))) - - // sort by the initial axis - axis := 0 - sortByAxis(fitems, axis) - - // build the root node. it's split differently from the subtrees. - children := make([]*treeNode, 0, S) - for i := 0; i < S; i++ { - var part []*treeNode - if i == S-1 { - // last split - part = fitems[len(fitems)/S*i:] - } else { - part = fitems[len(fitems)/S*i : len(fitems)/S*(i+1)] - } - children = append(children, tr.omt(part, h-1, axis+1)) - } - - node := createNode(children) - node.leaf = false - node.height = h - tr.calcBBox(node) - - if tr.data.count == 0 { - // save as is if tree is empty - tr.data = node - } else if tr.data.height == node.height { - // split root if trees have the same height - tr.splitRoot(tr.data, node) - } else { - if tr.data.height < node.height { - // swap trees if inserted one is bigger - tr.data, node = node, tr.data - } - - // insert the small tree into the large tree at appropriate level - tr.insert(node, nil, tr.data.height-node.height-1, true) - } -} - -func (tr *RTree) omt(fitems []*treeNode, h, axis int) *treeNode { - if len(fitems) <= tr.maxEntries { - // reached leaf level; return leaf - children := make([]*treeNode, len(fitems)) - copy(children, fitems) - node := createNode(children) - node.height = h - tr.calcBBox(node) - return node - } - - // sort the items on a different axis than the previous level. - sortByAxis(fitems, axis%D) - children := make([]*treeNode, 0, tr.maxEntries) - partsz := len(fitems) / tr.maxEntries - for i := 0; i < tr.maxEntries; i++ { - var part []*treeNode - if i == tr.maxEntries-1 { - // last part - part = fitems[partsz*i:] - } else { - part = fitems[partsz*i : partsz*(i+1)] - } - children = append(children, tr.omt(part, h-1, axis+1)) - } - node := createNode(children) - node.height = h - node.leaf = false - tr.calcBBox(node) - return node -} diff --git a/vendor/github.com/pmezard/go-difflib/.travis.yml b/vendor/github.com/pmezard/go-difflib/.travis.yml deleted file mode 100644 index 90c9c6f9..00000000 --- a/vendor/github.com/pmezard/go-difflib/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -language: go -go: - - 1.5 - - tip - diff --git a/vendor/github.com/pmezard/go-difflib/LICENSE b/vendor/github.com/pmezard/go-difflib/LICENSE deleted file mode 100644 index c67dad61..00000000 --- a/vendor/github.com/pmezard/go-difflib/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2013, Patrick Mezard -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - The names of its contributors may not be used to endorse or promote -products derived from this software without specific prior written -permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/pmezard/go-difflib/README.md b/vendor/github.com/pmezard/go-difflib/README.md deleted file mode 100644 index e87f307e..00000000 --- a/vendor/github.com/pmezard/go-difflib/README.md +++ /dev/null @@ -1,50 +0,0 @@ -go-difflib -========== - -[![Build Status](https://travis-ci.org/pmezard/go-difflib.png?branch=master)](https://travis-ci.org/pmezard/go-difflib) -[![GoDoc](https://godoc.org/github.com/pmezard/go-difflib/difflib?status.svg)](https://godoc.org/github.com/pmezard/go-difflib/difflib) - -Go-difflib is a partial port of python 3 difflib package. Its main goal -was to make unified and context diff available in pure Go, mostly for -testing purposes. - -The following class and functions (and related tests) have be ported: - -* `SequenceMatcher` -* `unified_diff()` -* `context_diff()` - -## Installation - -```bash -$ go get github.com/pmezard/go-difflib/difflib -``` - -### Quick Start - -Diffs are configured with Unified (or ContextDiff) structures, and can -be output to an io.Writer or returned as a string. - -```Go -diff := UnifiedDiff{ - A: difflib.SplitLines("foo\nbar\n"), - B: difflib.SplitLines("foo\nbaz\n"), - FromFile: "Original", - ToFile: "Current", - Context: 3, -} -text, _ := GetUnifiedDiffString(diff) -fmt.Printf(text) -``` - -would output: - -``` ---- Original -+++ Current -@@ -1,3 +1,3 @@ - foo --bar -+baz -``` - diff --git a/vendor/github.com/pmezard/go-difflib/difflib/difflib.go b/vendor/github.com/pmezard/go-difflib/difflib/difflib.go deleted file mode 100644 index 003e99fa..00000000 --- a/vendor/github.com/pmezard/go-difflib/difflib/difflib.go +++ /dev/null @@ -1,772 +0,0 @@ -// Package difflib is a partial port of Python difflib module. -// -// It provides tools to compare sequences of strings and generate textual diffs. -// -// The following class and functions have been ported: -// -// - SequenceMatcher -// -// - unified_diff -// -// - context_diff -// -// Getting unified diffs was the main goal of the port. Keep in mind this code -// is mostly suitable to output text differences in a human friendly way, there -// are no guarantees generated diffs are consumable by patch(1). -package difflib - -import ( - "bufio" - "bytes" - "fmt" - "io" - "strings" -) - -func min(a, b int) int { - if a < b { - return a - } - return b -} - -func max(a, b int) int { - if a > b { - return a - } - return b -} - -func calculateRatio(matches, length int) float64 { - if length > 0 { - return 2.0 * float64(matches) / float64(length) - } - return 1.0 -} - -type Match struct { - A int - B int - Size int -} - -type OpCode struct { - Tag byte - I1 int - I2 int - J1 int - J2 int -} - -// SequenceMatcher compares sequence of strings. The basic -// algorithm predates, and is a little fancier than, an algorithm -// published in the late 1980's by Ratcliff and Obershelp under the -// hyperbolic name "gestalt pattern matching". The basic idea is to find -// the longest contiguous matching subsequence that contains no "junk" -// elements (R-O doesn't address junk). The same idea is then applied -// recursively to the pieces of the sequences to the left and to the right -// of the matching subsequence. This does not yield minimal edit -// sequences, but does tend to yield matches that "look right" to people. -// -// SequenceMatcher tries to compute a "human-friendly diff" between two -// sequences. Unlike e.g. UNIX(tm) diff, the fundamental notion is the -// longest *contiguous* & junk-free matching subsequence. That's what -// catches peoples' eyes. The Windows(tm) windiff has another interesting -// notion, pairing up elements that appear uniquely in each sequence. -// That, and the method here, appear to yield more intuitive difference -// reports than does diff. This method appears to be the least vulnerable -// to synching up on blocks of "junk lines", though (like blank lines in -// ordinary text files, or maybe "

" lines in HTML files). That may be -// because this is the only method of the 3 that has a *concept* of -// "junk" . -// -// Timing: Basic R-O is cubic time worst case and quadratic time expected -// case. SequenceMatcher is quadratic time for the worst case and has -// expected-case behavior dependent in a complicated way on how many -// elements the sequences have in common; best case time is linear. -type SequenceMatcher struct { - a []string - b []string - b2j map[string][]int - IsJunk func(string) bool - autoJunk bool - bJunk map[string]struct{} - matchingBlocks []Match - fullBCount map[string]int - bPopular map[string]struct{} - opCodes []OpCode -} - -func NewMatcher(a, b []string) *SequenceMatcher { - m := SequenceMatcher{autoJunk: true} - m.SetSeqs(a, b) - return &m -} - -func NewMatcherWithJunk(a, b []string, autoJunk bool, - isJunk func(string) bool) *SequenceMatcher { - - m := SequenceMatcher{IsJunk: isJunk, autoJunk: autoJunk} - m.SetSeqs(a, b) - return &m -} - -// Set two sequences to be compared. -func (m *SequenceMatcher) SetSeqs(a, b []string) { - m.SetSeq1(a) - m.SetSeq2(b) -} - -// Set the first sequence to be compared. The second sequence to be compared is -// not changed. -// -// SequenceMatcher computes and caches detailed information about the second -// sequence, so if you want to compare one sequence S against many sequences, -// use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other -// sequences. -// -// See also SetSeqs() and SetSeq2(). -func (m *SequenceMatcher) SetSeq1(a []string) { - if &a == &m.a { - return - } - m.a = a - m.matchingBlocks = nil - m.opCodes = nil -} - -// Set the second sequence to be compared. The first sequence to be compared is -// not changed. -func (m *SequenceMatcher) SetSeq2(b []string) { - if &b == &m.b { - return - } - m.b = b - m.matchingBlocks = nil - m.opCodes = nil - m.fullBCount = nil - m.chainB() -} - -func (m *SequenceMatcher) chainB() { - // Populate line -> index mapping - b2j := map[string][]int{} - for i, s := range m.b { - indices := b2j[s] - indices = append(indices, i) - b2j[s] = indices - } - - // Purge junk elements - m.bJunk = map[string]struct{}{} - if m.IsJunk != nil { - junk := m.bJunk - for s, _ := range b2j { - if m.IsJunk(s) { - junk[s] = struct{}{} - } - } - for s, _ := range junk { - delete(b2j, s) - } - } - - // Purge remaining popular elements - popular := map[string]struct{}{} - n := len(m.b) - if m.autoJunk && n >= 200 { - ntest := n/100 + 1 - for s, indices := range b2j { - if len(indices) > ntest { - popular[s] = struct{}{} - } - } - for s, _ := range popular { - delete(b2j, s) - } - } - m.bPopular = popular - m.b2j = b2j -} - -func (m *SequenceMatcher) isBJunk(s string) bool { - _, ok := m.bJunk[s] - return ok -} - -// Find longest matching block in a[alo:ahi] and b[blo:bhi]. -// -// If IsJunk is not defined: -// -// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where -// alo <= i <= i+k <= ahi -// blo <= j <= j+k <= bhi -// and for all (i',j',k') meeting those conditions, -// k >= k' -// i <= i' -// and if i == i', j <= j' -// -// In other words, of all maximal matching blocks, return one that -// starts earliest in a, and of all those maximal matching blocks that -// start earliest in a, return the one that starts earliest in b. -// -// If IsJunk is defined, first the longest matching block is -// determined as above, but with the additional restriction that no -// junk element appears in the block. Then that block is extended as -// far as possible by matching (only) junk elements on both sides. So -// the resulting block never matches on junk except as identical junk -// happens to be adjacent to an "interesting" match. -// -// If no blocks match, return (alo, blo, 0). -func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match { - // CAUTION: stripping common prefix or suffix would be incorrect. - // E.g., - // ab - // acab - // Longest matching block is "ab", but if common prefix is - // stripped, it's "a" (tied with "b"). UNIX(tm) diff does so - // strip, so ends up claiming that ab is changed to acab by - // inserting "ca" in the middle. That's minimal but unintuitive: - // "it's obvious" that someone inserted "ac" at the front. - // Windiff ends up at the same place as diff, but by pairing up - // the unique 'b's and then matching the first two 'a's. - besti, bestj, bestsize := alo, blo, 0 - - // find longest junk-free match - // during an iteration of the loop, j2len[j] = length of longest - // junk-free match ending with a[i-1] and b[j] - j2len := map[int]int{} - for i := alo; i != ahi; i++ { - // look at all instances of a[i] in b; note that because - // b2j has no junk keys, the loop is skipped if a[i] is junk - newj2len := map[int]int{} - for _, j := range m.b2j[m.a[i]] { - // a[i] matches b[j] - if j < blo { - continue - } - if j >= bhi { - break - } - k := j2len[j-1] + 1 - newj2len[j] = k - if k > bestsize { - besti, bestj, bestsize = i-k+1, j-k+1, k - } - } - j2len = newj2len - } - - // Extend the best by non-junk elements on each end. In particular, - // "popular" non-junk elements aren't in b2j, which greatly speeds - // the inner loop above, but also means "the best" match so far - // doesn't contain any junk *or* popular non-junk elements. - for besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) && - m.a[besti-1] == m.b[bestj-1] { - besti, bestj, bestsize = besti-1, bestj-1, bestsize+1 - } - for besti+bestsize < ahi && bestj+bestsize < bhi && - !m.isBJunk(m.b[bestj+bestsize]) && - m.a[besti+bestsize] == m.b[bestj+bestsize] { - bestsize += 1 - } - - // Now that we have a wholly interesting match (albeit possibly - // empty!), we may as well suck up the matching junk on each - // side of it too. Can't think of a good reason not to, and it - // saves post-processing the (possibly considerable) expense of - // figuring out what to do with it. In the case of an empty - // interesting match, this is clearly the right thing to do, - // because no other kind of match is possible in the regions. - for besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) && - m.a[besti-1] == m.b[bestj-1] { - besti, bestj, bestsize = besti-1, bestj-1, bestsize+1 - } - for besti+bestsize < ahi && bestj+bestsize < bhi && - m.isBJunk(m.b[bestj+bestsize]) && - m.a[besti+bestsize] == m.b[bestj+bestsize] { - bestsize += 1 - } - - return Match{A: besti, B: bestj, Size: bestsize} -} - -// Return list of triples describing matching subsequences. -// -// Each triple is of the form (i, j, n), and means that -// a[i:i+n] == b[j:j+n]. The triples are monotonically increasing in -// i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are -// adjacent triples in the list, and the second is not the last triple in the -// list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe -// adjacent equal blocks. -// -// The last triple is a dummy, (len(a), len(b), 0), and is the only -// triple with n==0. -func (m *SequenceMatcher) GetMatchingBlocks() []Match { - if m.matchingBlocks != nil { - return m.matchingBlocks - } - - var matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match - matchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match { - match := m.findLongestMatch(alo, ahi, blo, bhi) - i, j, k := match.A, match.B, match.Size - if match.Size > 0 { - if alo < i && blo < j { - matched = matchBlocks(alo, i, blo, j, matched) - } - matched = append(matched, match) - if i+k < ahi && j+k < bhi { - matched = matchBlocks(i+k, ahi, j+k, bhi, matched) - } - } - return matched - } - matched := matchBlocks(0, len(m.a), 0, len(m.b), nil) - - // It's possible that we have adjacent equal blocks in the - // matching_blocks list now. - nonAdjacent := []Match{} - i1, j1, k1 := 0, 0, 0 - for _, b := range matched { - // Is this block adjacent to i1, j1, k1? - i2, j2, k2 := b.A, b.B, b.Size - if i1+k1 == i2 && j1+k1 == j2 { - // Yes, so collapse them -- this just increases the length of - // the first block by the length of the second, and the first - // block so lengthened remains the block to compare against. - k1 += k2 - } else { - // Not adjacent. Remember the first block (k1==0 means it's - // the dummy we started with), and make the second block the - // new block to compare against. - if k1 > 0 { - nonAdjacent = append(nonAdjacent, Match{i1, j1, k1}) - } - i1, j1, k1 = i2, j2, k2 - } - } - if k1 > 0 { - nonAdjacent = append(nonAdjacent, Match{i1, j1, k1}) - } - - nonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0}) - m.matchingBlocks = nonAdjacent - return m.matchingBlocks -} - -// Return list of 5-tuples describing how to turn a into b. -// -// Each tuple is of the form (tag, i1, i2, j1, j2). The first tuple -// has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the -// tuple preceding it, and likewise for j1 == the previous j2. -// -// The tags are characters, with these meanings: -// -// 'r' (replace): a[i1:i2] should be replaced by b[j1:j2] -// -// 'd' (delete): a[i1:i2] should be deleted, j1==j2 in this case. -// -// 'i' (insert): b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case. -// -// 'e' (equal): a[i1:i2] == b[j1:j2] -func (m *SequenceMatcher) GetOpCodes() []OpCode { - if m.opCodes != nil { - return m.opCodes - } - i, j := 0, 0 - matching := m.GetMatchingBlocks() - opCodes := make([]OpCode, 0, len(matching)) - for _, m := range matching { - // invariant: we've pumped out correct diffs to change - // a[:i] into b[:j], and the next matching block is - // a[ai:ai+size] == b[bj:bj+size]. So we need to pump - // out a diff to change a[i:ai] into b[j:bj], pump out - // the matching block, and move (i,j) beyond the match - ai, bj, size := m.A, m.B, m.Size - tag := byte(0) - if i < ai && j < bj { - tag = 'r' - } else if i < ai { - tag = 'd' - } else if j < bj { - tag = 'i' - } - if tag > 0 { - opCodes = append(opCodes, OpCode{tag, i, ai, j, bj}) - } - i, j = ai+size, bj+size - // the list of matching blocks is terminated by a - // sentinel with size 0 - if size > 0 { - opCodes = append(opCodes, OpCode{'e', ai, i, bj, j}) - } - } - m.opCodes = opCodes - return m.opCodes -} - -// Isolate change clusters by eliminating ranges with no changes. -// -// Return a generator of groups with up to n lines of context. -// Each group is in the same format as returned by GetOpCodes(). -func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode { - if n < 0 { - n = 3 - } - codes := m.GetOpCodes() - if len(codes) == 0 { - codes = []OpCode{OpCode{'e', 0, 1, 0, 1}} - } - // Fixup leading and trailing groups if they show no changes. - if codes[0].Tag == 'e' { - c := codes[0] - i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 - codes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2} - } - if codes[len(codes)-1].Tag == 'e' { - c := codes[len(codes)-1] - i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 - codes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)} - } - nn := n + n - groups := [][]OpCode{} - group := []OpCode{} - for _, c := range codes { - i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 - // End the current group and start a new one whenever - // there is a large range with no changes. - if c.Tag == 'e' && i2-i1 > nn { - group = append(group, OpCode{c.Tag, i1, min(i2, i1+n), - j1, min(j2, j1+n)}) - groups = append(groups, group) - group = []OpCode{} - i1, j1 = max(i1, i2-n), max(j1, j2-n) - } - group = append(group, OpCode{c.Tag, i1, i2, j1, j2}) - } - if len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') { - groups = append(groups, group) - } - return groups -} - -// Return a measure of the sequences' similarity (float in [0,1]). -// -// Where T is the total number of elements in both sequences, and -// M is the number of matches, this is 2.0*M / T. -// Note that this is 1 if the sequences are identical, and 0 if -// they have nothing in common. -// -// .Ratio() is expensive to compute if you haven't already computed -// .GetMatchingBlocks() or .GetOpCodes(), in which case you may -// want to try .QuickRatio() or .RealQuickRation() first to get an -// upper bound. -func (m *SequenceMatcher) Ratio() float64 { - matches := 0 - for _, m := range m.GetMatchingBlocks() { - matches += m.Size - } - return calculateRatio(matches, len(m.a)+len(m.b)) -} - -// Return an upper bound on ratio() relatively quickly. -// -// This isn't defined beyond that it is an upper bound on .Ratio(), and -// is faster to compute. -func (m *SequenceMatcher) QuickRatio() float64 { - // viewing a and b as multisets, set matches to the cardinality - // of their intersection; this counts the number of matches - // without regard to order, so is clearly an upper bound - if m.fullBCount == nil { - m.fullBCount = map[string]int{} - for _, s := range m.b { - m.fullBCount[s] = m.fullBCount[s] + 1 - } - } - - // avail[x] is the number of times x appears in 'b' less the - // number of times we've seen it in 'a' so far ... kinda - avail := map[string]int{} - matches := 0 - for _, s := range m.a { - n, ok := avail[s] - if !ok { - n = m.fullBCount[s] - } - avail[s] = n - 1 - if n > 0 { - matches += 1 - } - } - return calculateRatio(matches, len(m.a)+len(m.b)) -} - -// Return an upper bound on ratio() very quickly. -// -// This isn't defined beyond that it is an upper bound on .Ratio(), and -// is faster to compute than either .Ratio() or .QuickRatio(). -func (m *SequenceMatcher) RealQuickRatio() float64 { - la, lb := len(m.a), len(m.b) - return calculateRatio(min(la, lb), la+lb) -} - -// Convert range to the "ed" format -func formatRangeUnified(start, stop int) string { - // Per the diff spec at http://www.unix.org/single_unix_specification/ - beginning := start + 1 // lines start numbering with one - length := stop - start - if length == 1 { - return fmt.Sprintf("%d", beginning) - } - if length == 0 { - beginning -= 1 // empty ranges begin at line just before the range - } - return fmt.Sprintf("%d,%d", beginning, length) -} - -// Unified diff parameters -type UnifiedDiff struct { - A []string // First sequence lines - FromFile string // First file name - FromDate string // First file time - B []string // Second sequence lines - ToFile string // Second file name - ToDate string // Second file time - Eol string // Headers end of line, defaults to LF - Context int // Number of context lines -} - -// Compare two sequences of lines; generate the delta as a unified diff. -// -// Unified diffs are a compact way of showing line changes and a few -// lines of context. The number of context lines is set by 'n' which -// defaults to three. -// -// By default, the diff control lines (those with ---, +++, or @@) are -// created with a trailing newline. This is helpful so that inputs -// created from file.readlines() result in diffs that are suitable for -// file.writelines() since both the inputs and outputs have trailing -// newlines. -// -// For inputs that do not have trailing newlines, set the lineterm -// argument to "" so that the output will be uniformly newline free. -// -// The unidiff format normally has a header for filenames and modification -// times. Any or all of these may be specified using strings for -// 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'. -// The modification times are normally expressed in the ISO 8601 format. -func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error { - buf := bufio.NewWriter(writer) - defer buf.Flush() - wf := func(format string, args ...interface{}) error { - _, err := buf.WriteString(fmt.Sprintf(format, args...)) - return err - } - ws := func(s string) error { - _, err := buf.WriteString(s) - return err - } - - if len(diff.Eol) == 0 { - diff.Eol = "\n" - } - - started := false - m := NewMatcher(diff.A, diff.B) - for _, g := range m.GetGroupedOpCodes(diff.Context) { - if !started { - started = true - fromDate := "" - if len(diff.FromDate) > 0 { - fromDate = "\t" + diff.FromDate - } - toDate := "" - if len(diff.ToDate) > 0 { - toDate = "\t" + diff.ToDate - } - if diff.FromFile != "" || diff.ToFile != "" { - err := wf("--- %s%s%s", diff.FromFile, fromDate, diff.Eol) - if err != nil { - return err - } - err = wf("+++ %s%s%s", diff.ToFile, toDate, diff.Eol) - if err != nil { - return err - } - } - } - first, last := g[0], g[len(g)-1] - range1 := formatRangeUnified(first.I1, last.I2) - range2 := formatRangeUnified(first.J1, last.J2) - if err := wf("@@ -%s +%s @@%s", range1, range2, diff.Eol); err != nil { - return err - } - for _, c := range g { - i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 - if c.Tag == 'e' { - for _, line := range diff.A[i1:i2] { - if err := ws(" " + line); err != nil { - return err - } - } - continue - } - if c.Tag == 'r' || c.Tag == 'd' { - for _, line := range diff.A[i1:i2] { - if err := ws("-" + line); err != nil { - return err - } - } - } - if c.Tag == 'r' || c.Tag == 'i' { - for _, line := range diff.B[j1:j2] { - if err := ws("+" + line); err != nil { - return err - } - } - } - } - } - return nil -} - -// Like WriteUnifiedDiff but returns the diff a string. -func GetUnifiedDiffString(diff UnifiedDiff) (string, error) { - w := &bytes.Buffer{} - err := WriteUnifiedDiff(w, diff) - return string(w.Bytes()), err -} - -// Convert range to the "ed" format. -func formatRangeContext(start, stop int) string { - // Per the diff spec at http://www.unix.org/single_unix_specification/ - beginning := start + 1 // lines start numbering with one - length := stop - start - if length == 0 { - beginning -= 1 // empty ranges begin at line just before the range - } - if length <= 1 { - return fmt.Sprintf("%d", beginning) - } - return fmt.Sprintf("%d,%d", beginning, beginning+length-1) -} - -type ContextDiff UnifiedDiff - -// Compare two sequences of lines; generate the delta as a context diff. -// -// Context diffs are a compact way of showing line changes and a few -// lines of context. The number of context lines is set by diff.Context -// which defaults to three. -// -// By default, the diff control lines (those with *** or ---) are -// created with a trailing newline. -// -// For inputs that do not have trailing newlines, set the diff.Eol -// argument to "" so that the output will be uniformly newline free. -// -// The context diff format normally has a header for filenames and -// modification times. Any or all of these may be specified using -// strings for diff.FromFile, diff.ToFile, diff.FromDate, diff.ToDate. -// The modification times are normally expressed in the ISO 8601 format. -// If not specified, the strings default to blanks. -func WriteContextDiff(writer io.Writer, diff ContextDiff) error { - buf := bufio.NewWriter(writer) - defer buf.Flush() - var diffErr error - wf := func(format string, args ...interface{}) { - _, err := buf.WriteString(fmt.Sprintf(format, args...)) - if diffErr == nil && err != nil { - diffErr = err - } - } - ws := func(s string) { - _, err := buf.WriteString(s) - if diffErr == nil && err != nil { - diffErr = err - } - } - - if len(diff.Eol) == 0 { - diff.Eol = "\n" - } - - prefix := map[byte]string{ - 'i': "+ ", - 'd': "- ", - 'r': "! ", - 'e': " ", - } - - started := false - m := NewMatcher(diff.A, diff.B) - for _, g := range m.GetGroupedOpCodes(diff.Context) { - if !started { - started = true - fromDate := "" - if len(diff.FromDate) > 0 { - fromDate = "\t" + diff.FromDate - } - toDate := "" - if len(diff.ToDate) > 0 { - toDate = "\t" + diff.ToDate - } - if diff.FromFile != "" || diff.ToFile != "" { - wf("*** %s%s%s", diff.FromFile, fromDate, diff.Eol) - wf("--- %s%s%s", diff.ToFile, toDate, diff.Eol) - } - } - - first, last := g[0], g[len(g)-1] - ws("***************" + diff.Eol) - - range1 := formatRangeContext(first.I1, last.I2) - wf("*** %s ****%s", range1, diff.Eol) - for _, c := range g { - if c.Tag == 'r' || c.Tag == 'd' { - for _, cc := range g { - if cc.Tag == 'i' { - continue - } - for _, line := range diff.A[cc.I1:cc.I2] { - ws(prefix[cc.Tag] + line) - } - } - break - } - } - - range2 := formatRangeContext(first.J1, last.J2) - wf("--- %s ----%s", range2, diff.Eol) - for _, c := range g { - if c.Tag == 'r' || c.Tag == 'i' { - for _, cc := range g { - if cc.Tag == 'd' { - continue - } - for _, line := range diff.B[cc.J1:cc.J2] { - ws(prefix[cc.Tag] + line) - } - } - break - } - } - } - return diffErr -} - -// Like WriteContextDiff but returns the diff a string. -func GetContextDiffString(diff ContextDiff) (string, error) { - w := &bytes.Buffer{} - err := WriteContextDiff(w, diff) - return string(w.Bytes()), err -} - -// Split a string on "\n" while preserving them. The output can be used -// as input for UnifiedDiff and ContextDiff structures. -func SplitLines(s string) []string { - lines := strings.SplitAfter(s, "\n") - lines[len(lines)-1] += "\n" - return lines -} diff --git a/vendor/github.com/pmezard/go-difflib/difflib/difflib_test.go b/vendor/github.com/pmezard/go-difflib/difflib/difflib_test.go deleted file mode 100644 index d7251196..00000000 --- a/vendor/github.com/pmezard/go-difflib/difflib/difflib_test.go +++ /dev/null @@ -1,426 +0,0 @@ -package difflib - -import ( - "bytes" - "fmt" - "math" - "reflect" - "strings" - "testing" -) - -func assertAlmostEqual(t *testing.T, a, b float64, places int) { - if math.Abs(a-b) > math.Pow10(-places) { - t.Errorf("%.7f != %.7f", a, b) - } -} - -func assertEqual(t *testing.T, a, b interface{}) { - if !reflect.DeepEqual(a, b) { - t.Errorf("%v != %v", a, b) - } -} - -func splitChars(s string) []string { - chars := make([]string, 0, len(s)) - // Assume ASCII inputs - for i := 0; i != len(s); i++ { - chars = append(chars, string(s[i])) - } - return chars -} - -func TestSequenceMatcherRatio(t *testing.T) { - s := NewMatcher(splitChars("abcd"), splitChars("bcde")) - assertEqual(t, s.Ratio(), 0.75) - assertEqual(t, s.QuickRatio(), 0.75) - assertEqual(t, s.RealQuickRatio(), 1.0) -} - -func TestGetOptCodes(t *testing.T) { - a := "qabxcd" - b := "abycdf" - s := NewMatcher(splitChars(a), splitChars(b)) - w := &bytes.Buffer{} - for _, op := range s.GetOpCodes() { - fmt.Fprintf(w, "%s a[%d:%d], (%s) b[%d:%d] (%s)\n", string(op.Tag), - op.I1, op.I2, a[op.I1:op.I2], op.J1, op.J2, b[op.J1:op.J2]) - } - result := string(w.Bytes()) - expected := `d a[0:1], (q) b[0:0] () -e a[1:3], (ab) b[0:2] (ab) -r a[3:4], (x) b[2:3] (y) -e a[4:6], (cd) b[3:5] (cd) -i a[6:6], () b[5:6] (f) -` - if expected != result { - t.Errorf("unexpected op codes: \n%s", result) - } -} - -func TestGroupedOpCodes(t *testing.T) { - a := []string{} - for i := 0; i != 39; i++ { - a = append(a, fmt.Sprintf("%02d", i)) - } - b := []string{} - b = append(b, a[:8]...) - b = append(b, " i") - b = append(b, a[8:19]...) - b = append(b, " x") - b = append(b, a[20:22]...) - b = append(b, a[27:34]...) - b = append(b, " y") - b = append(b, a[35:]...) - s := NewMatcher(a, b) - w := &bytes.Buffer{} - for _, g := range s.GetGroupedOpCodes(-1) { - fmt.Fprintf(w, "group\n") - for _, op := range g { - fmt.Fprintf(w, " %s, %d, %d, %d, %d\n", string(op.Tag), - op.I1, op.I2, op.J1, op.J2) - } - } - result := string(w.Bytes()) - expected := `group - e, 5, 8, 5, 8 - i, 8, 8, 8, 9 - e, 8, 11, 9, 12 -group - e, 16, 19, 17, 20 - r, 19, 20, 20, 21 - e, 20, 22, 21, 23 - d, 22, 27, 23, 23 - e, 27, 30, 23, 26 -group - e, 31, 34, 27, 30 - r, 34, 35, 30, 31 - e, 35, 38, 31, 34 -` - if expected != result { - t.Errorf("unexpected op codes: \n%s", result) - } -} - -func ExampleGetUnifiedDiffCode() { - a := `one -two -three -four -fmt.Printf("%s,%T",a,b)` - b := `zero -one -three -four` - diff := UnifiedDiff{ - A: SplitLines(a), - B: SplitLines(b), - FromFile: "Original", - FromDate: "2005-01-26 23:30:50", - ToFile: "Current", - ToDate: "2010-04-02 10:20:52", - Context: 3, - } - result, _ := GetUnifiedDiffString(diff) - fmt.Println(strings.Replace(result, "\t", " ", -1)) - // Output: - // --- Original 2005-01-26 23:30:50 - // +++ Current 2010-04-02 10:20:52 - // @@ -1,5 +1,4 @@ - // +zero - // one - // -two - // three - // four - // -fmt.Printf("%s,%T",a,b) -} - -func ExampleGetContextDiffCode() { - a := `one -two -three -four -fmt.Printf("%s,%T",a,b)` - b := `zero -one -tree -four` - diff := ContextDiff{ - A: SplitLines(a), - B: SplitLines(b), - FromFile: "Original", - ToFile: "Current", - Context: 3, - Eol: "\n", - } - result, _ := GetContextDiffString(diff) - fmt.Print(strings.Replace(result, "\t", " ", -1)) - // Output: - // *** Original - // --- Current - // *************** - // *** 1,5 **** - // one - // ! two - // ! three - // four - // - fmt.Printf("%s,%T",a,b) - // --- 1,4 ---- - // + zero - // one - // ! tree - // four -} - -func ExampleGetContextDiffString() { - a := `one -two -three -four` - b := `zero -one -tree -four` - diff := ContextDiff{ - A: SplitLines(a), - B: SplitLines(b), - FromFile: "Original", - ToFile: "Current", - Context: 3, - Eol: "\n", - } - result, _ := GetContextDiffString(diff) - fmt.Printf(strings.Replace(result, "\t", " ", -1)) - // Output: - // *** Original - // --- Current - // *************** - // *** 1,4 **** - // one - // ! two - // ! three - // four - // --- 1,4 ---- - // + zero - // one - // ! tree - // four -} - -func rep(s string, count int) string { - return strings.Repeat(s, count) -} - -func TestWithAsciiOneInsert(t *testing.T) { - sm := NewMatcher(splitChars(rep("b", 100)), - splitChars("a"+rep("b", 100))) - assertAlmostEqual(t, sm.Ratio(), 0.995, 3) - assertEqual(t, sm.GetOpCodes(), - []OpCode{{'i', 0, 0, 0, 1}, {'e', 0, 100, 1, 101}}) - assertEqual(t, len(sm.bPopular), 0) - - sm = NewMatcher(splitChars(rep("b", 100)), - splitChars(rep("b", 50)+"a"+rep("b", 50))) - assertAlmostEqual(t, sm.Ratio(), 0.995, 3) - assertEqual(t, sm.GetOpCodes(), - []OpCode{{'e', 0, 50, 0, 50}, {'i', 50, 50, 50, 51}, {'e', 50, 100, 51, 101}}) - assertEqual(t, len(sm.bPopular), 0) -} - -func TestWithAsciiOnDelete(t *testing.T) { - sm := NewMatcher(splitChars(rep("a", 40)+"c"+rep("b", 40)), - splitChars(rep("a", 40)+rep("b", 40))) - assertAlmostEqual(t, sm.Ratio(), 0.994, 3) - assertEqual(t, sm.GetOpCodes(), - []OpCode{{'e', 0, 40, 0, 40}, {'d', 40, 41, 40, 40}, {'e', 41, 81, 40, 80}}) -} - -func TestWithAsciiBJunk(t *testing.T) { - isJunk := func(s string) bool { - return s == " " - } - sm := NewMatcherWithJunk(splitChars(rep("a", 40)+rep("b", 40)), - splitChars(rep("a", 44)+rep("b", 40)), true, isJunk) - assertEqual(t, sm.bJunk, map[string]struct{}{}) - - sm = NewMatcherWithJunk(splitChars(rep("a", 40)+rep("b", 40)), - splitChars(rep("a", 44)+rep("b", 40)+rep(" ", 20)), false, isJunk) - assertEqual(t, sm.bJunk, map[string]struct{}{" ": struct{}{}}) - - isJunk = func(s string) bool { - return s == " " || s == "b" - } - sm = NewMatcherWithJunk(splitChars(rep("a", 40)+rep("b", 40)), - splitChars(rep("a", 44)+rep("b", 40)+rep(" ", 20)), false, isJunk) - assertEqual(t, sm.bJunk, map[string]struct{}{" ": struct{}{}, "b": struct{}{}}) -} - -func TestSFBugsRatioForNullSeqn(t *testing.T) { - sm := NewMatcher(nil, nil) - assertEqual(t, sm.Ratio(), 1.0) - assertEqual(t, sm.QuickRatio(), 1.0) - assertEqual(t, sm.RealQuickRatio(), 1.0) -} - -func TestSFBugsComparingEmptyLists(t *testing.T) { - groups := NewMatcher(nil, nil).GetGroupedOpCodes(-1) - assertEqual(t, len(groups), 0) - diff := UnifiedDiff{ - FromFile: "Original", - ToFile: "Current", - Context: 3, - } - result, err := GetUnifiedDiffString(diff) - assertEqual(t, err, nil) - assertEqual(t, result, "") -} - -func TestOutputFormatRangeFormatUnified(t *testing.T) { - // Per the diff spec at http://www.unix.org/single_unix_specification/ - // - // Each field shall be of the form: - // %1d", if the range contains exactly one line, - // and: - // "%1d,%1d", , otherwise. - // If a range is empty, its beginning line number shall be the number of - // the line just before the range, or 0 if the empty range starts the file. - fm := formatRangeUnified - assertEqual(t, fm(3, 3), "3,0") - assertEqual(t, fm(3, 4), "4") - assertEqual(t, fm(3, 5), "4,2") - assertEqual(t, fm(3, 6), "4,3") - assertEqual(t, fm(0, 0), "0,0") -} - -func TestOutputFormatRangeFormatContext(t *testing.T) { - // Per the diff spec at http://www.unix.org/single_unix_specification/ - // - // The range of lines in file1 shall be written in the following format - // if the range contains two or more lines: - // "*** %d,%d ****\n", , - // and the following format otherwise: - // "*** %d ****\n", - // The ending line number of an empty range shall be the number of the preceding line, - // or 0 if the range is at the start of the file. - // - // Next, the range of lines in file2 shall be written in the following format - // if the range contains two or more lines: - // "--- %d,%d ----\n", , - // and the following format otherwise: - // "--- %d ----\n", - fm := formatRangeContext - assertEqual(t, fm(3, 3), "3") - assertEqual(t, fm(3, 4), "4") - assertEqual(t, fm(3, 5), "4,5") - assertEqual(t, fm(3, 6), "4,6") - assertEqual(t, fm(0, 0), "0") -} - -func TestOutputFormatTabDelimiter(t *testing.T) { - diff := UnifiedDiff{ - A: splitChars("one"), - B: splitChars("two"), - FromFile: "Original", - FromDate: "2005-01-26 23:30:50", - ToFile: "Current", - ToDate: "2010-04-12 10:20:52", - Eol: "\n", - } - ud, err := GetUnifiedDiffString(diff) - assertEqual(t, err, nil) - assertEqual(t, SplitLines(ud)[:2], []string{ - "--- Original\t2005-01-26 23:30:50\n", - "+++ Current\t2010-04-12 10:20:52\n", - }) - cd, err := GetContextDiffString(ContextDiff(diff)) - assertEqual(t, err, nil) - assertEqual(t, SplitLines(cd)[:2], []string{ - "*** Original\t2005-01-26 23:30:50\n", - "--- Current\t2010-04-12 10:20:52\n", - }) -} - -func TestOutputFormatNoTrailingTabOnEmptyFiledate(t *testing.T) { - diff := UnifiedDiff{ - A: splitChars("one"), - B: splitChars("two"), - FromFile: "Original", - ToFile: "Current", - Eol: "\n", - } - ud, err := GetUnifiedDiffString(diff) - assertEqual(t, err, nil) - assertEqual(t, SplitLines(ud)[:2], []string{"--- Original\n", "+++ Current\n"}) - - cd, err := GetContextDiffString(ContextDiff(diff)) - assertEqual(t, err, nil) - assertEqual(t, SplitLines(cd)[:2], []string{"*** Original\n", "--- Current\n"}) -} - -func TestOmitFilenames(t *testing.T) { - diff := UnifiedDiff{ - A: SplitLines("o\nn\ne\n"), - B: SplitLines("t\nw\no\n"), - Eol: "\n", - } - ud, err := GetUnifiedDiffString(diff) - assertEqual(t, err, nil) - assertEqual(t, SplitLines(ud), []string{ - "@@ -0,0 +1,2 @@\n", - "+t\n", - "+w\n", - "@@ -2,2 +3,0 @@\n", - "-n\n", - "-e\n", - "\n", - }) - - cd, err := GetContextDiffString(ContextDiff(diff)) - assertEqual(t, err, nil) - assertEqual(t, SplitLines(cd), []string{ - "***************\n", - "*** 0 ****\n", - "--- 1,2 ----\n", - "+ t\n", - "+ w\n", - "***************\n", - "*** 2,3 ****\n", - "- n\n", - "- e\n", - "--- 3 ----\n", - "\n", - }) -} - -func TestSplitLines(t *testing.T) { - allTests := []struct { - input string - want []string - }{ - {"foo", []string{"foo\n"}}, - {"foo\nbar", []string{"foo\n", "bar\n"}}, - {"foo\nbar\n", []string{"foo\n", "bar\n", "\n"}}, - } - for _, test := range allTests { - assertEqual(t, SplitLines(test.input), test.want) - } -} - -func benchmarkSplitLines(b *testing.B, count int) { - str := strings.Repeat("foo\n", count) - - b.ResetTimer() - - n := 0 - for i := 0; i < b.N; i++ { - n += len(SplitLines(str)) - } -} - -func BenchmarkSplitLines100(b *testing.B) { - benchmarkSplitLines(b, 100) -} - -func BenchmarkSplitLines10000(b *testing.B) { - benchmarkSplitLines(b, 10000) -} diff --git a/vendor/github.com/stretchr/testify/.gitignore b/vendor/github.com/stretchr/testify/.gitignore deleted file mode 100644 index 5aacdb7c..00000000 --- a/vendor/github.com/stretchr/testify/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe - -.DS_Store diff --git a/vendor/github.com/stretchr/testify/.travis.yml b/vendor/github.com/stretchr/testify/.travis.yml deleted file mode 100644 index ffb9e0dd..00000000 --- a/vendor/github.com/stretchr/testify/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -language: go - -sudo: false - -go: - - 1.1 - - 1.2 - - 1.3 - - 1.4 - - 1.5 - - 1.6 - - 1.7 - - tip - -script: - - go test -v ./... diff --git a/vendor/github.com/stretchr/testify/Godeps/Godeps.json b/vendor/github.com/stretchr/testify/Godeps/Godeps.json deleted file mode 100644 index df032ac3..00000000 --- a/vendor/github.com/stretchr/testify/Godeps/Godeps.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "ImportPath": "github.com/stretchr/testify", - "GoVersion": "go1.5", - "GodepVersion": "v74", - "Packages": [ - "./..." - ], - "Deps": [ - { - "ImportPath": "github.com/davecgh/go-spew/spew", - "Comment": "v1.0.0-3-g6d21280", - "Rev": "6d212800a42e8ab5c146b8ace3490ee17e5225f9" - }, - { - "ImportPath": "github.com/pmezard/go-difflib/difflib", - "Rev": "d8ed2627bdf02c080bf22230dbb337003b7aba2d" - }, - { - "ImportPath": "github.com/stretchr/objx", - "Rev": "cbeaeb16a013161a98496fad62933b1d21786672" - } - ] -} diff --git a/vendor/github.com/stretchr/testify/Godeps/Readme b/vendor/github.com/stretchr/testify/Godeps/Readme deleted file mode 100644 index 4cdaa53d..00000000 --- a/vendor/github.com/stretchr/testify/Godeps/Readme +++ /dev/null @@ -1,5 +0,0 @@ -This directory tree is generated automatically by godep. - -Please do not edit. - -See https://github.com/tools/godep for more information. diff --git a/vendor/github.com/stretchr/testify/LICENCE.txt b/vendor/github.com/stretchr/testify/LICENCE.txt deleted file mode 100644 index 473b670a..00000000 --- a/vendor/github.com/stretchr/testify/LICENCE.txt +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell - -Please consider promoting this project if you find it useful. - -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/testify/LICENSE b/vendor/github.com/stretchr/testify/LICENSE deleted file mode 100644 index 473b670a..00000000 --- a/vendor/github.com/stretchr/testify/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell - -Please consider promoting this project if you find it useful. - -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/testify/README.md b/vendor/github.com/stretchr/testify/README.md deleted file mode 100644 index e57b1811..00000000 --- a/vendor/github.com/stretchr/testify/README.md +++ /dev/null @@ -1,332 +0,0 @@ -Testify - Thou Shalt Write Tests -================================ - -[![Build Status](https://travis-ci.org/stretchr/testify.svg)](https://travis-ci.org/stretchr/testify) [![Go Report Card](https://goreportcard.com/badge/github.com/stretchr/testify)](https://goreportcard.com/report/github.com/stretchr/testify) [![GoDoc](https://godoc.org/github.com/stretchr/testify?status.svg)](https://godoc.org/github.com/stretchr/testify) - -Go code (golang) set of packages that provide many tools for testifying that your code will behave as you intend. - -Features include: - - * [Easy assertions](#assert-package) - * [Mocking](#mock-package) - * [HTTP response trapping](#http-package) - * [Testing suite interfaces and functions](#suite-package) - -Get started: - - * Install testify with [one line of code](#installation), or [update it with another](#staying-up-to-date) - * For an introduction to writing test code in Go, see http://golang.org/doc/code.html#Testing - * Check out the API Documentation http://godoc.org/github.com/stretchr/testify - * To make your testing life easier, check out our other project, [gorc](http://github.com/stretchr/gorc) - * A little about [Test-Driven Development (TDD)](http://en.wikipedia.org/wiki/Test-driven_development) - - - -[`assert`](http://godoc.org/github.com/stretchr/testify/assert "API documentation") package -------------------------------------------------------------------------------------------- - -The `assert` package provides some helpful methods that allow you to write better test code in Go. - - * Prints friendly, easy to read failure descriptions - * Allows for very readable code - * Optionally annotate each assertion with a message - -See it in action: - -```go -package yours - -import ( - "testing" - "github.com/stretchr/testify/assert" -) - -func TestSomething(t *testing.T) { - - // assert equality - assert.Equal(t, 123, 123, "they should be equal") - - // assert inequality - assert.NotEqual(t, 123, 456, "they should not be equal") - - // assert for nil (good for errors) - assert.Nil(t, object) - - // assert for not nil (good when you expect something) - if assert.NotNil(t, object) { - - // now we know that object isn't nil, we are safe to make - // further assertions without causing any errors - assert.Equal(t, "Something", object.Value) - - } - -} -``` - - * Every assert func takes the `testing.T` object as the first argument. This is how it writes the errors out through the normal `go test` capabilities. - * Every assert func returns a bool indicating whether the assertion was successful or not, this is useful for if you want to go on making further assertions under certain conditions. - -if you assert many times, use the below: - -```go -package yours - -import ( - "testing" - "github.com/stretchr/testify/assert" -) - -func TestSomething(t *testing.T) { - assert := assert.New(t) - - // assert equality - assert.Equal(123, 123, "they should be equal") - - // assert inequality - assert.NotEqual(123, 456, "they should not be equal") - - // assert for nil (good for errors) - assert.Nil(object) - - // assert for not nil (good when you expect something) - if assert.NotNil(object) { - - // now we know that object isn't nil, we are safe to make - // further assertions without causing any errors - assert.Equal("Something", object.Value) - } -} -``` - -[`require`](http://godoc.org/github.com/stretchr/testify/require "API documentation") package ---------------------------------------------------------------------------------------------- - -The `require` package provides same global functions as the `assert` package, but instead of returning a boolean result they terminate current test. - -See [t.FailNow](http://golang.org/pkg/testing/#T.FailNow) for details. - - -[`http`](http://godoc.org/github.com/stretchr/testify/http "API documentation") package ---------------------------------------------------------------------------------------- - -The `http` package contains test objects useful for testing code that relies on the `net/http` package. Check out the [(deprecated) API documentation for the `http` package](http://godoc.org/github.com/stretchr/testify/http). - -We recommend you use [httptest](http://golang.org/pkg/net/http/httptest) instead. - -[`mock`](http://godoc.org/github.com/stretchr/testify/mock "API documentation") package ----------------------------------------------------------------------------------------- - -The `mock` package provides a mechanism for easily writing mock objects that can be used in place of real objects when writing test code. - -An example test function that tests a piece of code that relies on an external object `testObj`, can setup expectations (testify) and assert that they indeed happened: - -```go -package yours - -import ( - "testing" - "github.com/stretchr/testify/mock" -) - -/* - Test objects -*/ - -// MyMockedObject is a mocked object that implements an interface -// that describes an object that the code I am testing relies on. -type MyMockedObject struct{ - mock.Mock -} - -// DoSomething is a method on MyMockedObject that implements some interface -// and just records the activity, and returns what the Mock object tells it to. -// -// In the real object, this method would do something useful, but since this -// is a mocked object - we're just going to stub it out. -// -// NOTE: This method is not being tested here, code that uses this object is. -func (m *MyMockedObject) DoSomething(number int) (bool, error) { - - args := m.Called(number) - return args.Bool(0), args.Error(1) - -} - -/* - Actual test functions -*/ - -// TestSomething is an example of how to use our test object to -// make assertions about some target code we are testing. -func TestSomething(t *testing.T) { - - // create an instance of our test object - testObj := new(MyMockedObject) - - // setup expectations - testObj.On("DoSomething", 123).Return(true, nil) - - // call the code we are testing - targetFuncThatDoesSomethingWithObj(testObj) - - // assert that the expectations were met - testObj.AssertExpectations(t) - -} -``` - -For more information on how to write mock code, check out the [API documentation for the `mock` package](http://godoc.org/github.com/stretchr/testify/mock). - -You can use the [mockery tool](http://github.com/vektra/mockery) to autogenerate the mock code against an interface as well, making using mocks much quicker. - -[`suite`](http://godoc.org/github.com/stretchr/testify/suite "API documentation") package ------------------------------------------------------------------------------------------ - -The `suite` package provides functionality that you might be used to from more common object oriented languages. With it, you can build a testing suite as a struct, build setup/teardown methods and testing methods on your struct, and run them with 'go test' as per normal. - -An example suite is shown below: - -```go -// Basic imports -import ( - "testing" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -// Define the suite, and absorb the built-in basic suite -// functionality from testify - including a T() method which -// returns the current testing context -type ExampleTestSuite struct { - suite.Suite - VariableThatShouldStartAtFive int -} - -// Make sure that VariableThatShouldStartAtFive is set to five -// before each test -func (suite *ExampleTestSuite) SetupTest() { - suite.VariableThatShouldStartAtFive = 5 -} - -// All methods that begin with "Test" are run as tests within a -// suite. -func (suite *ExampleTestSuite) TestExample() { - assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive) -} - -// In order for 'go test' to run this suite, we need to create -// a normal test function and pass our suite to suite.Run -func TestExampleTestSuite(t *testing.T) { - suite.Run(t, new(ExampleTestSuite)) -} -``` - -For a more complete example, using all of the functionality provided by the suite package, look at our [example testing suite](https://github.com/stretchr/testify/blob/master/suite/suite_test.go) - -For more information on writing suites, check out the [API documentation for the `suite` package](http://godoc.org/github.com/stretchr/testify/suite). - -`Suite` object has assertion methods: - -```go -// Basic imports -import ( - "testing" - "github.com/stretchr/testify/suite" -) - -// Define the suite, and absorb the built-in basic suite -// functionality from testify - including assertion methods. -type ExampleTestSuite struct { - suite.Suite - VariableThatShouldStartAtFive int -} - -// Make sure that VariableThatShouldStartAtFive is set to five -// before each test -func (suite *ExampleTestSuite) SetupTest() { - suite.VariableThatShouldStartAtFive = 5 -} - -// All methods that begin with "Test" are run as tests within a -// suite. -func (suite *ExampleTestSuite) TestExample() { - suite.Equal(suite.VariableThatShouldStartAtFive, 5) -} - -// In order for 'go test' to run this suite, we need to create -// a normal test function and pass our suite to suite.Run -func TestExampleTestSuite(t *testing.T) { - suite.Run(t, new(ExampleTestSuite)) -} -``` - ------- - -Installation -============ - -To install Testify, use `go get`: - - * Latest version: go get github.com/stretchr/testify - * Specific version: go get gopkg.in/stretchr/testify.v1 - -This will then make the following packages available to you: - - github.com/stretchr/testify/assert - github.com/stretchr/testify/mock - github.com/stretchr/testify/http - -Import the `testify/assert` package into your code using this template: - -```go -package yours - -import ( - "testing" - "github.com/stretchr/testify/assert" -) - -func TestSomething(t *testing.T) { - - assert.True(t, true, "True is true!") - -} -``` - ------- - -Staying up to date -================== - -To update Testify to the latest version, use `go get -u github.com/stretchr/testify`. - ------- - -Version History -=============== - - * 1.0 - New package versioning strategy adopted. - ------- - -Contributing -============ - -Please feel free to submit issues, fork the repository and send pull requests! - -When submitting an issue, we ask that you please include a complete test function that demonstrates the issue. Extra credit for those using Testify to write the test code that demonstrates it. - ------- - -Licence -======= -Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell - -Please consider promoting this project if you find it useful. - -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/testify/_codegen/main.go b/vendor/github.com/stretchr/testify/_codegen/main.go deleted file mode 100644 index 328009f8..00000000 --- a/vendor/github.com/stretchr/testify/_codegen/main.go +++ /dev/null @@ -1,287 +0,0 @@ -// This program reads all assertion functions from the assert package and -// automatically generates the corersponding requires and forwarded assertions - -package main - -import ( - "bytes" - "flag" - "fmt" - "go/ast" - "go/build" - "go/doc" - "go/importer" - "go/parser" - "go/token" - "go/types" - "io" - "io/ioutil" - "log" - "os" - "path" - "strings" - "text/template" - - "github.com/ernesto-jimenez/gogen/imports" -) - -var ( - pkg = flag.String("assert-path", "github.com/stretchr/testify/assert", "Path to the assert package") - outputPkg = flag.String("output-package", "", "package for the resulting code") - tmplFile = flag.String("template", "", "What file to load the function template from") - out = flag.String("out", "", "What file to write the source code to") -) - -func main() { - flag.Parse() - - scope, docs, err := parsePackageSource(*pkg) - if err != nil { - log.Fatal(err) - } - - importer, funcs, err := analyzeCode(scope, docs) - if err != nil { - log.Fatal(err) - } - - if err := generateCode(importer, funcs); err != nil { - log.Fatal(err) - } -} - -func generateCode(importer imports.Importer, funcs []testFunc) error { - buff := bytes.NewBuffer(nil) - - tmplHead, tmplFunc, err := parseTemplates() - if err != nil { - return err - } - - // Generate header - if err := tmplHead.Execute(buff, struct { - Name string - Imports map[string]string - }{ - *outputPkg, - importer.Imports(), - }); err != nil { - return err - } - - // Generate funcs - for _, fn := range funcs { - buff.Write([]byte("\n\n")) - if err := tmplFunc.Execute(buff, &fn); err != nil { - return err - } - } - - // Write file - output, err := outputFile() - if err != nil { - return err - } - defer output.Close() - _, err = io.Copy(output, buff) - return err -} - -func parseTemplates() (*template.Template, *template.Template, error) { - tmplHead, err := template.New("header").Parse(headerTemplate) - if err != nil { - return nil, nil, err - } - if *tmplFile != "" { - f, err := ioutil.ReadFile(*tmplFile) - if err != nil { - return nil, nil, err - } - funcTemplate = string(f) - } - tmpl, err := template.New("function").Parse(funcTemplate) - if err != nil { - return nil, nil, err - } - return tmplHead, tmpl, nil -} - -func outputFile() (*os.File, error) { - filename := *out - if filename == "-" || (filename == "" && *tmplFile == "") { - return os.Stdout, nil - } - if filename == "" { - filename = strings.TrimSuffix(strings.TrimSuffix(*tmplFile, ".tmpl"), ".go") + ".go" - } - return os.Create(filename) -} - -// analyzeCode takes the types scope and the docs and returns the import -// information and information about all the assertion functions. -func analyzeCode(scope *types.Scope, docs *doc.Package) (imports.Importer, []testFunc, error) { - testingT := scope.Lookup("TestingT").Type().Underlying().(*types.Interface) - - importer := imports.New(*outputPkg) - var funcs []testFunc - // Go through all the top level functions - for _, fdocs := range docs.Funcs { - // Find the function - obj := scope.Lookup(fdocs.Name) - - fn, ok := obj.(*types.Func) - if !ok { - continue - } - // Check function signatuer has at least two arguments - sig := fn.Type().(*types.Signature) - if sig.Params().Len() < 2 { - continue - } - // Check first argument is of type testingT - first, ok := sig.Params().At(0).Type().(*types.Named) - if !ok { - continue - } - firstType, ok := first.Underlying().(*types.Interface) - if !ok { - continue - } - if !types.Implements(firstType, testingT) { - continue - } - - funcs = append(funcs, testFunc{*outputPkg, fdocs, fn}) - importer.AddImportsFrom(sig.Params()) - } - return importer, funcs, nil -} - -// parsePackageSource returns the types scope and the package documentation from the pa -func parsePackageSource(pkg string) (*types.Scope, *doc.Package, error) { - pd, err := build.Import(pkg, ".", 0) - if err != nil { - return nil, nil, err - } - - fset := token.NewFileSet() - files := make(map[string]*ast.File) - fileList := make([]*ast.File, len(pd.GoFiles)) - for i, fname := range pd.GoFiles { - src, err := ioutil.ReadFile(path.Join(pd.SrcRoot, pd.ImportPath, fname)) - if err != nil { - return nil, nil, err - } - f, err := parser.ParseFile(fset, fname, src, parser.ParseComments|parser.AllErrors) - if err != nil { - return nil, nil, err - } - files[fname] = f - fileList[i] = f - } - - cfg := types.Config{ - Importer: importer.Default(), - } - info := types.Info{ - Defs: make(map[*ast.Ident]types.Object), - } - tp, err := cfg.Check(pkg, fset, fileList, &info) - if err != nil { - return nil, nil, err - } - - scope := tp.Scope() - - ap, _ := ast.NewPackage(fset, files, nil, nil) - docs := doc.New(ap, pkg, 0) - - return scope, docs, nil -} - -type testFunc struct { - CurrentPkg string - DocInfo *doc.Func - TypeInfo *types.Func -} - -func (f *testFunc) Qualifier(p *types.Package) string { - if p == nil || p.Name() == f.CurrentPkg { - return "" - } - return p.Name() -} - -func (f *testFunc) Params() string { - sig := f.TypeInfo.Type().(*types.Signature) - params := sig.Params() - p := "" - comma := "" - to := params.Len() - var i int - - if sig.Variadic() { - to-- - } - for i = 1; i < to; i++ { - param := params.At(i) - p += fmt.Sprintf("%s%s %s", comma, param.Name(), types.TypeString(param.Type(), f.Qualifier)) - comma = ", " - } - if sig.Variadic() { - param := params.At(params.Len() - 1) - p += fmt.Sprintf("%s%s ...%s", comma, param.Name(), types.TypeString(param.Type().(*types.Slice).Elem(), f.Qualifier)) - } - return p -} - -func (f *testFunc) ForwardedParams() string { - sig := f.TypeInfo.Type().(*types.Signature) - params := sig.Params() - p := "" - comma := "" - to := params.Len() - var i int - - if sig.Variadic() { - to-- - } - for i = 1; i < to; i++ { - param := params.At(i) - p += fmt.Sprintf("%s%s", comma, param.Name()) - comma = ", " - } - if sig.Variadic() { - param := params.At(params.Len() - 1) - p += fmt.Sprintf("%s%s...", comma, param.Name()) - } - return p -} - -func (f *testFunc) Comment() string { - return "// " + strings.Replace(strings.TrimSpace(f.DocInfo.Doc), "\n", "\n// ", -1) -} - -func (f *testFunc) CommentWithoutT(receiver string) string { - search := fmt.Sprintf("assert.%s(t, ", f.DocInfo.Name) - replace := fmt.Sprintf("%s.%s(", receiver, f.DocInfo.Name) - return strings.Replace(f.Comment(), search, replace, -1) -} - -var headerTemplate = `/* -* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen -* THIS FILE MUST NOT BE EDITED BY HAND -*/ - -package {{.Name}} - -import ( -{{range $path, $name := .Imports}} - {{$name}} "{{$path}}"{{end}} -) -` - -var funcTemplate = `{{.Comment}} -func (fwd *AssertionsForwarder) {{.DocInfo.Name}}({{.Params}}) bool { - return assert.{{.DocInfo.Name}}({{.ForwardedParams}}) -}` diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go b/vendor/github.com/stretchr/testify/assert/assertion_forward.go deleted file mode 100644 index e6a79604..00000000 --- a/vendor/github.com/stretchr/testify/assert/assertion_forward.go +++ /dev/null @@ -1,387 +0,0 @@ -/* -* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen -* THIS FILE MUST NOT BE EDITED BY HAND -*/ - -package assert - -import ( - - http "net/http" - url "net/url" - time "time" -) - - -// Condition uses a Comparison to assert a complex condition. -func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool { - return Condition(a.t, comp, msgAndArgs...) -} - - -// Contains asserts that the specified string, list(array, slice...) or map contains the -// specified substring or element. -// -// a.Contains("Hello World", "World", "But 'Hello World' does contain 'World'") -// a.Contains(["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'") -// a.Contains({"Hello": "World"}, "Hello", "But {'Hello': 'World'} does contain 'Hello'") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool { - return Contains(a.t, s, contains, msgAndArgs...) -} - - -// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either -// a slice or a channel with len == 0. -// -// a.Empty(obj) -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool { - return Empty(a.t, object, msgAndArgs...) -} - - -// Equal asserts that two objects are equal. -// -// a.Equal(123, 123, "123 and 123 should be equal") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { - return Equal(a.t, expected, actual, msgAndArgs...) -} - - -// EqualError asserts that a function returned an error (i.e. not `nil`) -// and that it is equal to the provided error. -// -// actualObj, err := SomeFunction() -// if assert.Error(t, err, "An error was expected") { -// assert.Equal(t, err, expectedError) -// } -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool { - return EqualError(a.t, theError, errString, msgAndArgs...) -} - - -// EqualValues asserts that two objects are equal or convertable to the same types -// and equal. -// -// a.EqualValues(uint32(123), int32(123), "123 and 123 should be equal") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { - return EqualValues(a.t, expected, actual, msgAndArgs...) -} - - -// Error asserts that a function returned an error (i.e. not `nil`). -// -// actualObj, err := SomeFunction() -// if a.Error(err, "An error was expected") { -// assert.Equal(t, err, expectedError) -// } -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool { - return Error(a.t, err, msgAndArgs...) -} - - -// Exactly asserts that two objects are equal is value and type. -// -// a.Exactly(int32(123), int64(123), "123 and 123 should NOT be equal") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { - return Exactly(a.t, expected, actual, msgAndArgs...) -} - - -// Fail reports a failure through -func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool { - return Fail(a.t, failureMessage, msgAndArgs...) -} - - -// FailNow fails test -func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) bool { - return FailNow(a.t, failureMessage, msgAndArgs...) -} - - -// False asserts that the specified value is false. -// -// a.False(myBool, "myBool should be false") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool { - return False(a.t, value, msgAndArgs...) -} - - -// HTTPBodyContains asserts that a specified handler returns a -// body that contains a string. -// -// a.HTTPBodyContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) bool { - return HTTPBodyContains(a.t, handler, method, url, values, str) -} - - -// HTTPBodyNotContains asserts that a specified handler returns a -// body that does not contain a string. -// -// a.HTTPBodyNotContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) bool { - return HTTPBodyNotContains(a.t, handler, method, url, values, str) -} - - -// HTTPError asserts that a specified handler returns an error status code. -// -// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values) bool { - return HTTPError(a.t, handler, method, url, values) -} - - -// HTTPRedirect asserts that a specified handler returns a redirect status code. -// -// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values) bool { - return HTTPRedirect(a.t, handler, method, url, values) -} - - -// HTTPSuccess asserts that a specified handler returns a success status code. -// -// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values) bool { - return HTTPSuccess(a.t, handler, method, url, values) -} - - -// Implements asserts that an object is implemented by the specified interface. -// -// a.Implements((*MyInterface)(nil), new(MyObject), "MyObject") -func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { - return Implements(a.t, interfaceObject, object, msgAndArgs...) -} - - -// InDelta asserts that the two numerals are within delta of each other. -// -// a.InDelta(math.Pi, (22 / 7.0), 0.01) -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { - return InDelta(a.t, expected, actual, delta, msgAndArgs...) -} - - -// InDeltaSlice is the same as InDelta, except it compares two slices. -func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { - return InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...) -} - - -// InEpsilon asserts that expected and actual have a relative error less than epsilon -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { - return InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...) -} - - -// InEpsilonSlice is the same as InEpsilon, except it compares two slices. -func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { - return InEpsilonSlice(a.t, expected, actual, delta, msgAndArgs...) -} - - -// IsType asserts that the specified objects are of the same type. -func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool { - return IsType(a.t, expectedType, object, msgAndArgs...) -} - - -// JSONEq asserts that two JSON strings are equivalent. -// -// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool { - return JSONEq(a.t, expected, actual, msgAndArgs...) -} - - -// Len asserts that the specified object has specific length. -// Len also fails if the object has a type that len() not accept. -// -// a.Len(mySlice, 3, "The size of slice is not 3") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool { - return Len(a.t, object, length, msgAndArgs...) -} - - -// Nil asserts that the specified object is nil. -// -// a.Nil(err, "err should be nothing") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool { - return Nil(a.t, object, msgAndArgs...) -} - - -// NoError asserts that a function returned no error (i.e. `nil`). -// -// actualObj, err := SomeFunction() -// if a.NoError(err) { -// assert.Equal(t, actualObj, expectedObj) -// } -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool { - return NoError(a.t, err, msgAndArgs...) -} - - -// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the -// specified substring or element. -// -// a.NotContains("Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'") -// a.NotContains(["Hello", "World"], "Earth", "But ['Hello', 'World'] does NOT contain 'Earth'") -// a.NotContains({"Hello": "World"}, "Earth", "But {'Hello': 'World'} does NOT contain 'Earth'") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool { - return NotContains(a.t, s, contains, msgAndArgs...) -} - - -// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either -// a slice or a channel with len == 0. -// -// if a.NotEmpty(obj) { -// assert.Equal(t, "two", obj[1]) -// } -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool { - return NotEmpty(a.t, object, msgAndArgs...) -} - - -// NotEqual asserts that the specified values are NOT equal. -// -// a.NotEqual(obj1, obj2, "two objects shouldn't be equal") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { - return NotEqual(a.t, expected, actual, msgAndArgs...) -} - - -// NotNil asserts that the specified object is not nil. -// -// a.NotNil(err, "err should be something") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool { - return NotNil(a.t, object, msgAndArgs...) -} - - -// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. -// -// a.NotPanics(func(){ -// RemainCalm() -// }, "Calling RemainCalm() should NOT panic") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool { - return NotPanics(a.t, f, msgAndArgs...) -} - - -// NotRegexp asserts that a specified regexp does not match a string. -// -// a.NotRegexp(regexp.MustCompile("starts"), "it's starting") -// a.NotRegexp("^start", "it's not starting") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { - return NotRegexp(a.t, rx, str, msgAndArgs...) -} - - -// NotZero asserts that i is not the zero value for its type and returns the truth. -func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool { - return NotZero(a.t, i, msgAndArgs...) -} - - -// Panics asserts that the code inside the specified PanicTestFunc panics. -// -// a.Panics(func(){ -// GoCrazy() -// }, "Calling GoCrazy() should panic") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool { - return Panics(a.t, f, msgAndArgs...) -} - - -// Regexp asserts that a specified regexp matches a string. -// -// a.Regexp(regexp.MustCompile("start"), "it's starting") -// a.Regexp("start...$", "it's not starting") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { - return Regexp(a.t, rx, str, msgAndArgs...) -} - - -// True asserts that the specified value is true. -// -// a.True(myBool, "myBool should be true") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool { - return True(a.t, value, msgAndArgs...) -} - - -// WithinDuration asserts that the two times are within duration delta of each other. -// -// a.WithinDuration(time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool { - return WithinDuration(a.t, expected, actual, delta, msgAndArgs...) -} - - -// Zero asserts that i is the zero value for its type and returns the truth. -func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool { - return Zero(a.t, i, msgAndArgs...) -} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl b/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl deleted file mode 100644 index 99f9acfb..00000000 --- a/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl +++ /dev/null @@ -1,4 +0,0 @@ -{{.CommentWithoutT "a"}} -func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool { - return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) -} diff --git a/vendor/github.com/stretchr/testify/assert/assertions.go b/vendor/github.com/stretchr/testify/assert/assertions.go deleted file mode 100644 index b3f4e170..00000000 --- a/vendor/github.com/stretchr/testify/assert/assertions.go +++ /dev/null @@ -1,1052 +0,0 @@ -package assert - -import ( - "bufio" - "bytes" - "encoding/json" - "fmt" - "math" - "reflect" - "regexp" - "runtime" - "strings" - "time" - "unicode" - "unicode/utf8" - - "github.com/davecgh/go-spew/spew" - "github.com/pmezard/go-difflib/difflib" -) - -func init() { - spew.Config.SortKeys = true -} - -// TestingT is an interface wrapper around *testing.T -type TestingT interface { - Errorf(format string, args ...interface{}) -} - -// Comparison a custom function that returns true on success and false on failure -type Comparison func() (success bool) - -/* - Helper functions -*/ - -// ObjectsAreEqual determines if two objects are considered equal. -// -// This function does no assertion of any kind. -func ObjectsAreEqual(expected, actual interface{}) bool { - - if expected == nil || actual == nil { - return expected == actual - } - - return reflect.DeepEqual(expected, actual) - -} - -// ObjectsAreEqualValues gets whether two objects are equal, or if their -// values are equal. -func ObjectsAreEqualValues(expected, actual interface{}) bool { - if ObjectsAreEqual(expected, actual) { - return true - } - - actualType := reflect.TypeOf(actual) - if actualType == nil { - return false - } - expectedValue := reflect.ValueOf(expected) - if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) { - // Attempt comparison after type conversion - return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual) - } - - return false -} - -/* CallerInfo is necessary because the assert functions use the testing object -internally, causing it to print the file:line of the assert method, rather than where -the problem actually occurred in calling code.*/ - -// CallerInfo returns an array of strings containing the file and line number -// of each stack frame leading from the current test to the assert call that -// failed. -func CallerInfo() []string { - - pc := uintptr(0) - file := "" - line := 0 - ok := false - name := "" - - callers := []string{} - for i := 0; ; i++ { - pc, file, line, ok = runtime.Caller(i) - if !ok { - // The breaks below failed to terminate the loop, and we ran off the - // end of the call stack. - break - } - - // This is a huge edge case, but it will panic if this is the case, see #180 - if file == "" { - break - } - - f := runtime.FuncForPC(pc) - if f == nil { - break - } - name = f.Name() - - // testing.tRunner is the standard library function that calls - // tests. Subtests are called directly by tRunner, without going through - // the Test/Benchmark/Example function that contains the t.Run calls, so - // with subtests we should break when we hit tRunner, without adding it - // to the list of callers. - if name == "testing.tRunner" { - break - } - - parts := strings.Split(file, "/") - dir := parts[len(parts)-2] - file = parts[len(parts)-1] - if (dir != "assert" && dir != "mock" && dir != "require") || file == "mock_test.go" { - callers = append(callers, fmt.Sprintf("%s:%d", file, line)) - } - - // Drop the package - segments := strings.Split(name, ".") - name = segments[len(segments)-1] - if isTest(name, "Test") || - isTest(name, "Benchmark") || - isTest(name, "Example") { - break - } - } - - return callers -} - -// Stolen from the `go test` tool. -// isTest tells whether name looks like a test (or benchmark, according to prefix). -// It is a Test (say) if there is a character after Test that is not a lower-case letter. -// We don't want TesticularCancer. -func isTest(name, prefix string) bool { - if !strings.HasPrefix(name, prefix) { - return false - } - if len(name) == len(prefix) { // "Test" is ok - return true - } - rune, _ := utf8.DecodeRuneInString(name[len(prefix):]) - return !unicode.IsLower(rune) -} - -// getWhitespaceString returns a string that is long enough to overwrite the default -// output from the go testing framework. -func getWhitespaceString() string { - - _, file, line, ok := runtime.Caller(1) - if !ok { - return "" - } - parts := strings.Split(file, "/") - file = parts[len(parts)-1] - - return strings.Repeat(" ", len(fmt.Sprintf("%s:%d: ", file, line))) - -} - -func messageFromMsgAndArgs(msgAndArgs ...interface{}) string { - if len(msgAndArgs) == 0 || msgAndArgs == nil { - return "" - } - if len(msgAndArgs) == 1 { - return msgAndArgs[0].(string) - } - if len(msgAndArgs) > 1 { - return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...) - } - return "" -} - -// Indents all lines of the message by appending a number of tabs to each line, in an output format compatible with Go's -// test printing (see inner comment for specifics) -func indentMessageLines(message string, tabs int) string { - outBuf := new(bytes.Buffer) - - for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ { - if i != 0 { - outBuf.WriteRune('\n') - } - for ii := 0; ii < tabs; ii++ { - outBuf.WriteRune('\t') - // Bizarrely, all lines except the first need one fewer tabs prepended, so deliberately advance the counter - // by 1 prematurely. - if ii == 0 && i > 0 { - ii++ - } - } - outBuf.WriteString(scanner.Text()) - } - - return outBuf.String() -} - -type failNower interface { - FailNow() -} - -// FailNow fails test -func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool { - Fail(t, failureMessage, msgAndArgs...) - - // We cannot extend TestingT with FailNow() and - // maintain backwards compatibility, so we fallback - // to panicking when FailNow is not available in - // TestingT. - // See issue #263 - - if t, ok := t.(failNower); ok { - t.FailNow() - } else { - panic("test failed and t is missing `FailNow()`") - } - return false -} - -// Fail reports a failure through -func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool { - - message := messageFromMsgAndArgs(msgAndArgs...) - - errorTrace := strings.Join(CallerInfo(), "\n\r\t\t\t") - if len(message) > 0 { - t.Errorf("\r%s\r\tError Trace:\t%s\n"+ - "\r\tError:%s\n"+ - "\r\tMessages:\t%s\n\r", - getWhitespaceString(), - errorTrace, - indentMessageLines(failureMessage, 2), - message) - } else { - t.Errorf("\r%s\r\tError Trace:\t%s\n"+ - "\r\tError:%s\n\r", - getWhitespaceString(), - errorTrace, - indentMessageLines(failureMessage, 2)) - } - - return false -} - -// Implements asserts that an object is implemented by the specified interface. -// -// assert.Implements(t, (*MyInterface)(nil), new(MyObject), "MyObject") -func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { - - interfaceType := reflect.TypeOf(interfaceObject).Elem() - - if !reflect.TypeOf(object).Implements(interfaceType) { - return Fail(t, fmt.Sprintf("%T must implement %v", object, interfaceType), msgAndArgs...) - } - - return true - -} - -// IsType asserts that the specified objects are of the same type. -func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool { - - if !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) { - return Fail(t, fmt.Sprintf("Object expected to be of type %v, but was %v", reflect.TypeOf(expectedType), reflect.TypeOf(object)), msgAndArgs...) - } - - return true -} - -// Equal asserts that two objects are equal. -// -// assert.Equal(t, 123, 123, "123 and 123 should be equal") -// -// Returns whether the assertion was successful (true) or not (false). -func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { - - if !ObjectsAreEqual(expected, actual) { - diff := diff(expected, actual) - expected, actual = formatUnequalValues(expected, actual) - return Fail(t, fmt.Sprintf("Not equal: %s (expected)\n"+ - " != %s (actual)%s", expected, actual, diff), msgAndArgs...) - } - - return true - -} - -// formatUnequalValues takes two values of arbitrary types and returns string -// representations appropriate to be presented to the user. -// -// If the values are not of like type, the returned strings will be prefixed -// with the type name, and the value will be enclosed in parenthesis similar -// to a type conversion in the Go grammar. -func formatUnequalValues(expected, actual interface{}) (e string, a string) { - aType := reflect.TypeOf(expected) - bType := reflect.TypeOf(actual) - - if aType != bType && isNumericType(aType) && isNumericType(bType) { - return fmt.Sprintf("%v(%#v)", aType, expected), - fmt.Sprintf("%v(%#v)", bType, actual) - } - - return fmt.Sprintf("%#v", expected), - fmt.Sprintf("%#v", actual) -} - -func isNumericType(t reflect.Type) bool { - switch t.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return true - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return true - case reflect.Float32, reflect.Float64: - return true - } - - return false -} - -// EqualValues asserts that two objects are equal or convertable to the same types -// and equal. -// -// assert.EqualValues(t, uint32(123), int32(123), "123 and 123 should be equal") -// -// Returns whether the assertion was successful (true) or not (false). -func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { - - if !ObjectsAreEqualValues(expected, actual) { - return Fail(t, fmt.Sprintf("Not equal: %#v (expected)\n"+ - " != %#v (actual)", expected, actual), msgAndArgs...) - } - - return true - -} - -// Exactly asserts that two objects are equal is value and type. -// -// assert.Exactly(t, int32(123), int64(123), "123 and 123 should NOT be equal") -// -// Returns whether the assertion was successful (true) or not (false). -func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { - - aType := reflect.TypeOf(expected) - bType := reflect.TypeOf(actual) - - if aType != bType { - return Fail(t, fmt.Sprintf("Types expected to match exactly\n\r\t%v != %v", aType, bType), msgAndArgs...) - } - - return Equal(t, expected, actual, msgAndArgs...) - -} - -// NotNil asserts that the specified object is not nil. -// -// assert.NotNil(t, err, "err should be something") -// -// Returns whether the assertion was successful (true) or not (false). -func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { - if !isNil(object) { - return true - } - return Fail(t, "Expected value not to be nil.", msgAndArgs...) -} - -// isNil checks if a specified object is nil or not, without Failing. -func isNil(object interface{}) bool { - if object == nil { - return true - } - - value := reflect.ValueOf(object) - kind := value.Kind() - if kind >= reflect.Chan && kind <= reflect.Slice && value.IsNil() { - return true - } - - return false -} - -// Nil asserts that the specified object is nil. -// -// assert.Nil(t, err, "err should be nothing") -// -// Returns whether the assertion was successful (true) or not (false). -func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { - if isNil(object) { - return true - } - return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...) -} - -var numericZeros = []interface{}{ - int(0), - int8(0), - int16(0), - int32(0), - int64(0), - uint(0), - uint8(0), - uint16(0), - uint32(0), - uint64(0), - float32(0), - float64(0), -} - -// isEmpty gets whether the specified object is considered empty or not. -func isEmpty(object interface{}) bool { - - if object == nil { - return true - } else if object == "" { - return true - } else if object == false { - return true - } - - for _, v := range numericZeros { - if object == v { - return true - } - } - - objValue := reflect.ValueOf(object) - - switch objValue.Kind() { - case reflect.Map: - fallthrough - case reflect.Slice, reflect.Chan: - { - return (objValue.Len() == 0) - } - case reflect.Struct: - switch object.(type) { - case time.Time: - return object.(time.Time).IsZero() - } - case reflect.Ptr: - { - if objValue.IsNil() { - return true - } - switch object.(type) { - case *time.Time: - return object.(*time.Time).IsZero() - default: - return false - } - } - } - return false -} - -// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either -// a slice or a channel with len == 0. -// -// assert.Empty(t, obj) -// -// Returns whether the assertion was successful (true) or not (false). -func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { - - pass := isEmpty(object) - if !pass { - Fail(t, fmt.Sprintf("Should be empty, but was %v", object), msgAndArgs...) - } - - return pass - -} - -// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either -// a slice or a channel with len == 0. -// -// if assert.NotEmpty(t, obj) { -// assert.Equal(t, "two", obj[1]) -// } -// -// Returns whether the assertion was successful (true) or not (false). -func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { - - pass := !isEmpty(object) - if !pass { - Fail(t, fmt.Sprintf("Should NOT be empty, but was %v", object), msgAndArgs...) - } - - return pass - -} - -// getLen try to get length of object. -// return (false, 0) if impossible. -func getLen(x interface{}) (ok bool, length int) { - v := reflect.ValueOf(x) - defer func() { - if e := recover(); e != nil { - ok = false - } - }() - return true, v.Len() -} - -// Len asserts that the specified object has specific length. -// Len also fails if the object has a type that len() not accept. -// -// assert.Len(t, mySlice, 3, "The size of slice is not 3") -// -// Returns whether the assertion was successful (true) or not (false). -func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool { - ok, l := getLen(object) - if !ok { - return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", object), msgAndArgs...) - } - - if l != length { - return Fail(t, fmt.Sprintf("\"%s\" should have %d item(s), but has %d", object, length, l), msgAndArgs...) - } - return true -} - -// True asserts that the specified value is true. -// -// assert.True(t, myBool, "myBool should be true") -// -// Returns whether the assertion was successful (true) or not (false). -func True(t TestingT, value bool, msgAndArgs ...interface{}) bool { - - if value != true { - return Fail(t, "Should be true", msgAndArgs...) - } - - return true - -} - -// False asserts that the specified value is false. -// -// assert.False(t, myBool, "myBool should be false") -// -// Returns whether the assertion was successful (true) or not (false). -func False(t TestingT, value bool, msgAndArgs ...interface{}) bool { - - if value != false { - return Fail(t, "Should be false", msgAndArgs...) - } - - return true - -} - -// NotEqual asserts that the specified values are NOT equal. -// -// assert.NotEqual(t, obj1, obj2, "two objects shouldn't be equal") -// -// Returns whether the assertion was successful (true) or not (false). -func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { - - if ObjectsAreEqual(expected, actual) { - return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...) - } - - return true - -} - -// containsElement try loop over the list check if the list includes the element. -// return (false, false) if impossible. -// return (true, false) if element was not found. -// return (true, true) if element was found. -func includeElement(list interface{}, element interface{}) (ok, found bool) { - - listValue := reflect.ValueOf(list) - elementValue := reflect.ValueOf(element) - defer func() { - if e := recover(); e != nil { - ok = false - found = false - } - }() - - if reflect.TypeOf(list).Kind() == reflect.String { - return true, strings.Contains(listValue.String(), elementValue.String()) - } - - if reflect.TypeOf(list).Kind() == reflect.Map { - mapKeys := listValue.MapKeys() - for i := 0; i < len(mapKeys); i++ { - if ObjectsAreEqual(mapKeys[i].Interface(), element) { - return true, true - } - } - return true, false - } - - for i := 0; i < listValue.Len(); i++ { - if ObjectsAreEqual(listValue.Index(i).Interface(), element) { - return true, true - } - } - return true, false - -} - -// Contains asserts that the specified string, list(array, slice...) or map contains the -// specified substring or element. -// -// assert.Contains(t, "Hello World", "World", "But 'Hello World' does contain 'World'") -// assert.Contains(t, ["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'") -// assert.Contains(t, {"Hello": "World"}, "Hello", "But {'Hello': 'World'} does contain 'Hello'") -// -// Returns whether the assertion was successful (true) or not (false). -func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool { - - ok, found := includeElement(s, contains) - if !ok { - return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...) - } - if !found { - return Fail(t, fmt.Sprintf("\"%s\" does not contain \"%s\"", s, contains), msgAndArgs...) - } - - return true - -} - -// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the -// specified substring or element. -// -// assert.NotContains(t, "Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'") -// assert.NotContains(t, ["Hello", "World"], "Earth", "But ['Hello', 'World'] does NOT contain 'Earth'") -// assert.NotContains(t, {"Hello": "World"}, "Earth", "But {'Hello': 'World'} does NOT contain 'Earth'") -// -// Returns whether the assertion was successful (true) or not (false). -func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool { - - ok, found := includeElement(s, contains) - if !ok { - return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...) - } - if found { - return Fail(t, fmt.Sprintf("\"%s\" should not contain \"%s\"", s, contains), msgAndArgs...) - } - - return true - -} - -// Condition uses a Comparison to assert a complex condition. -func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool { - result := comp() - if !result { - Fail(t, "Condition failed!", msgAndArgs...) - } - return result -} - -// PanicTestFunc defines a func that should be passed to the assert.Panics and assert.NotPanics -// methods, and represents a simple func that takes no arguments, and returns nothing. -type PanicTestFunc func() - -// didPanic returns true if the function passed to it panics. Otherwise, it returns false. -func didPanic(f PanicTestFunc) (bool, interface{}) { - - didPanic := false - var message interface{} - func() { - - defer func() { - if message = recover(); message != nil { - didPanic = true - } - }() - - // call the target function - f() - - }() - - return didPanic, message - -} - -// Panics asserts that the code inside the specified PanicTestFunc panics. -// -// assert.Panics(t, func(){ -// GoCrazy() -// }, "Calling GoCrazy() should panic") -// -// Returns whether the assertion was successful (true) or not (false). -func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { - - if funcDidPanic, panicValue := didPanic(f); !funcDidPanic { - return Fail(t, fmt.Sprintf("func %#v should panic\n\r\tPanic value:\t%v", f, panicValue), msgAndArgs...) - } - - return true -} - -// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. -// -// assert.NotPanics(t, func(){ -// RemainCalm() -// }, "Calling RemainCalm() should NOT panic") -// -// Returns whether the assertion was successful (true) or not (false). -func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { - - if funcDidPanic, panicValue := didPanic(f); funcDidPanic { - return Fail(t, fmt.Sprintf("func %#v should not panic\n\r\tPanic value:\t%v", f, panicValue), msgAndArgs...) - } - - return true -} - -// WithinDuration asserts that the two times are within duration delta of each other. -// -// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s") -// -// Returns whether the assertion was successful (true) or not (false). -func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool { - - dt := expected.Sub(actual) - if dt < -delta || dt > delta { - return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...) - } - - return true -} - -func toFloat(x interface{}) (float64, bool) { - var xf float64 - xok := true - - switch xn := x.(type) { - case uint8: - xf = float64(xn) - case uint16: - xf = float64(xn) - case uint32: - xf = float64(xn) - case uint64: - xf = float64(xn) - case int: - xf = float64(xn) - case int8: - xf = float64(xn) - case int16: - xf = float64(xn) - case int32: - xf = float64(xn) - case int64: - xf = float64(xn) - case float32: - xf = float64(xn) - case float64: - xf = float64(xn) - default: - xok = false - } - - return xf, xok -} - -// InDelta asserts that the two numerals are within delta of each other. -// -// assert.InDelta(t, math.Pi, (22 / 7.0), 0.01) -// -// Returns whether the assertion was successful (true) or not (false). -func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { - - af, aok := toFloat(expected) - bf, bok := toFloat(actual) - - if !aok || !bok { - return Fail(t, fmt.Sprintf("Parameters must be numerical"), msgAndArgs...) - } - - if math.IsNaN(af) { - return Fail(t, fmt.Sprintf("Actual must not be NaN"), msgAndArgs...) - } - - if math.IsNaN(bf) { - return Fail(t, fmt.Sprintf("Expected %v with delta %v, but was NaN", expected, delta), msgAndArgs...) - } - - dt := af - bf - if dt < -delta || dt > delta { - return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...) - } - - return true -} - -// InDeltaSlice is the same as InDelta, except it compares two slices. -func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { - if expected == nil || actual == nil || - reflect.TypeOf(actual).Kind() != reflect.Slice || - reflect.TypeOf(expected).Kind() != reflect.Slice { - return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...) - } - - actualSlice := reflect.ValueOf(actual) - expectedSlice := reflect.ValueOf(expected) - - for i := 0; i < actualSlice.Len(); i++ { - result := InDelta(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta) - if !result { - return result - } - } - - return true -} - -func calcRelativeError(expected, actual interface{}) (float64, error) { - af, aok := toFloat(expected) - if !aok { - return 0, fmt.Errorf("expected value %q cannot be converted to float", expected) - } - if af == 0 { - return 0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error") - } - bf, bok := toFloat(actual) - if !bok { - return 0, fmt.Errorf("expected value %q cannot be converted to float", actual) - } - - return math.Abs(af-bf) / math.Abs(af), nil -} - -// InEpsilon asserts that expected and actual have a relative error less than epsilon -// -// Returns whether the assertion was successful (true) or not (false). -func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { - actualEpsilon, err := calcRelativeError(expected, actual) - if err != nil { - return Fail(t, err.Error(), msgAndArgs...) - } - if actualEpsilon > epsilon { - return Fail(t, fmt.Sprintf("Relative error is too high: %#v (expected)\n"+ - " < %#v (actual)", actualEpsilon, epsilon), msgAndArgs...) - } - - return true -} - -// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. -func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { - if expected == nil || actual == nil || - reflect.TypeOf(actual).Kind() != reflect.Slice || - reflect.TypeOf(expected).Kind() != reflect.Slice { - return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...) - } - - actualSlice := reflect.ValueOf(actual) - expectedSlice := reflect.ValueOf(expected) - - for i := 0; i < actualSlice.Len(); i++ { - result := InEpsilon(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), epsilon) - if !result { - return result - } - } - - return true -} - -/* - Errors -*/ - -// NoError asserts that a function returned no error (i.e. `nil`). -// -// actualObj, err := SomeFunction() -// if assert.NoError(t, err) { -// assert.Equal(t, actualObj, expectedObj) -// } -// -// Returns whether the assertion was successful (true) or not (false). -func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool { - if err != nil { - return Fail(t, fmt.Sprintf("Received unexpected error %+v", err), msgAndArgs...) - } - - return true -} - -// Error asserts that a function returned an error (i.e. not `nil`). -// -// actualObj, err := SomeFunction() -// if assert.Error(t, err, "An error was expected") { -// assert.Equal(t, err, expectedError) -// } -// -// Returns whether the assertion was successful (true) or not (false). -func Error(t TestingT, err error, msgAndArgs ...interface{}) bool { - - if err == nil { - return Fail(t, "An error is expected but got nil.", msgAndArgs...) - } - - return true -} - -// EqualError asserts that a function returned an error (i.e. not `nil`) -// and that it is equal to the provided error. -// -// actualObj, err := SomeFunction() -// assert.EqualError(t, err, expectedErrorString, "An error was expected") -// -// Returns whether the assertion was successful (true) or not (false). -func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool { - - message := messageFromMsgAndArgs(msgAndArgs...) - if !NotNil(t, theError, "An error is expected but got nil. %s", message) { - return false - } - s := "An error with value \"%s\" is expected but got \"%s\". %s" - return Equal(t, errString, theError.Error(), - s, errString, theError.Error(), message) -} - -// matchRegexp return true if a specified regexp matches a string. -func matchRegexp(rx interface{}, str interface{}) bool { - - var r *regexp.Regexp - if rr, ok := rx.(*regexp.Regexp); ok { - r = rr - } else { - r = regexp.MustCompile(fmt.Sprint(rx)) - } - - return (r.FindStringIndex(fmt.Sprint(str)) != nil) - -} - -// Regexp asserts that a specified regexp matches a string. -// -// assert.Regexp(t, regexp.MustCompile("start"), "it's starting") -// assert.Regexp(t, "start...$", "it's not starting") -// -// Returns whether the assertion was successful (true) or not (false). -func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { - - match := matchRegexp(rx, str) - - if !match { - Fail(t, fmt.Sprintf("Expect \"%v\" to match \"%v\"", str, rx), msgAndArgs...) - } - - return match -} - -// NotRegexp asserts that a specified regexp does not match a string. -// -// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") -// assert.NotRegexp(t, "^start", "it's not starting") -// -// Returns whether the assertion was successful (true) or not (false). -func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { - match := matchRegexp(rx, str) - - if match { - Fail(t, fmt.Sprintf("Expect \"%v\" to NOT match \"%v\"", str, rx), msgAndArgs...) - } - - return !match - -} - -// Zero asserts that i is the zero value for its type and returns the truth. -func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool { - if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) { - return Fail(t, fmt.Sprintf("Should be zero, but was %v", i), msgAndArgs...) - } - return true -} - -// NotZero asserts that i is not the zero value for its type and returns the truth. -func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool { - if i == nil || reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) { - return Fail(t, fmt.Sprintf("Should not be zero, but was %v", i), msgAndArgs...) - } - return true -} - -// JSONEq asserts that two JSON strings are equivalent. -// -// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) -// -// Returns whether the assertion was successful (true) or not (false). -func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool { - var expectedJSONAsInterface, actualJSONAsInterface interface{} - - if err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil { - return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid json.\nJSON parsing error: '%s'", expected, err.Error()), msgAndArgs...) - } - - if err := json.Unmarshal([]byte(actual), &actualJSONAsInterface); err != nil { - return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid json.\nJSON parsing error: '%s'", actual, err.Error()), msgAndArgs...) - } - - return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...) -} - -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 -} - -// 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 := spew.Sdump(expected) - a := spew.Sdump(actual) - - diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ - A: difflib.SplitLines(e), - B: difflib.SplitLines(a), - FromFile: "Expected", - FromDate: "", - ToFile: "Actual", - ToDate: "", - Context: 1, - }) - - return "\n\nDiff:\n" + diff -} diff --git a/vendor/github.com/stretchr/testify/assert/assertions_test.go b/vendor/github.com/stretchr/testify/assert/assertions_test.go deleted file mode 100644 index ac9b7017..00000000 --- a/vendor/github.com/stretchr/testify/assert/assertions_test.go +++ /dev/null @@ -1,1210 +0,0 @@ -package assert - -import ( - "errors" - "io" - "math" - "os" - "reflect" - "regexp" - "testing" - "time" -) - -var ( - i interface{} - zeros = []interface{}{ - false, - byte(0), - complex64(0), - complex128(0), - float32(0), - float64(0), - int(0), - int8(0), - int16(0), - int32(0), - int64(0), - rune(0), - uint(0), - uint8(0), - uint16(0), - uint32(0), - uint64(0), - uintptr(0), - "", - [0]interface{}{}, - []interface{}(nil), - struct{ x int }{}, - (*interface{})(nil), - (func())(nil), - nil, - interface{}(nil), - map[interface{}]interface{}(nil), - (chan interface{})(nil), - (<-chan interface{})(nil), - (chan<- interface{})(nil), - } - nonZeros = []interface{}{ - true, - byte(1), - complex64(1), - complex128(1), - float32(1), - float64(1), - int(1), - int8(1), - int16(1), - int32(1), - int64(1), - rune(1), - uint(1), - uint8(1), - uint16(1), - uint32(1), - uint64(1), - uintptr(1), - "s", - [1]interface{}{1}, - []interface{}{}, - struct{ x int }{1}, - (*interface{})(&i), - (func())(func() {}), - interface{}(1), - map[interface{}]interface{}{}, - (chan interface{})(make(chan interface{})), - (<-chan interface{})(make(chan interface{})), - (chan<- interface{})(make(chan interface{})), - } -) - -// AssertionTesterInterface defines an interface to be used for testing assertion methods -type AssertionTesterInterface interface { - TestMethod() -} - -// AssertionTesterConformingObject is an object that conforms to the AssertionTesterInterface interface -type AssertionTesterConformingObject struct { -} - -func (a *AssertionTesterConformingObject) TestMethod() { -} - -// AssertionTesterNonConformingObject is an object that does not conform to the AssertionTesterInterface interface -type AssertionTesterNonConformingObject struct { -} - -func TestObjectsAreEqual(t *testing.T) { - - if !ObjectsAreEqual("Hello World", "Hello World") { - t.Error("objectsAreEqual should return true") - } - if !ObjectsAreEqual(123, 123) { - t.Error("objectsAreEqual should return true") - } - if !ObjectsAreEqual(123.5, 123.5) { - t.Error("objectsAreEqual should return true") - } - if !ObjectsAreEqual([]byte("Hello World"), []byte("Hello World")) { - t.Error("objectsAreEqual should return true") - } - if !ObjectsAreEqual(nil, nil) { - t.Error("objectsAreEqual should return true") - } - if ObjectsAreEqual(map[int]int{5: 10}, map[int]int{10: 20}) { - t.Error("objectsAreEqual should return false") - } - if ObjectsAreEqual('x', "x") { - t.Error("objectsAreEqual should return false") - } - if ObjectsAreEqual("x", 'x') { - t.Error("objectsAreEqual should return false") - } - if ObjectsAreEqual(0, 0.1) { - t.Error("objectsAreEqual should return false") - } - if ObjectsAreEqual(0.1, 0) { - t.Error("objectsAreEqual should return false") - } - if ObjectsAreEqual(uint32(10), int32(10)) { - t.Error("objectsAreEqual should return false") - } - if !ObjectsAreEqualValues(uint32(10), int32(10)) { - t.Error("ObjectsAreEqualValues should return true") - } - if ObjectsAreEqualValues(0, nil) { - t.Fail() - } - if ObjectsAreEqualValues(nil, 0) { - t.Fail() - } - -} - -func TestImplements(t *testing.T) { - - mockT := new(testing.T) - - if !Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) { - t.Error("Implements method should return true: AssertionTesterConformingObject implements AssertionTesterInterface") - } - if Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) { - t.Error("Implements method should return false: AssertionTesterNonConformingObject does not implements AssertionTesterInterface") - } - -} - -func TestIsType(t *testing.T) { - - mockT := new(testing.T) - - if !IsType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) { - t.Error("IsType should return true: AssertionTesterConformingObject is the same type as AssertionTesterConformingObject") - } - if IsType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) { - t.Error("IsType should return false: AssertionTesterConformingObject is not the same type as AssertionTesterNonConformingObject") - } - -} - -func TestEqual(t *testing.T) { - - mockT := new(testing.T) - - if !Equal(mockT, "Hello World", "Hello World") { - t.Error("Equal should return true") - } - if !Equal(mockT, 123, 123) { - t.Error("Equal should return true") - } - if !Equal(mockT, 123.5, 123.5) { - t.Error("Equal should return true") - } - if !Equal(mockT, []byte("Hello World"), []byte("Hello World")) { - t.Error("Equal should return true") - } - if !Equal(mockT, nil, nil) { - t.Error("Equal should return true") - } - if !Equal(mockT, int32(123), int32(123)) { - t.Error("Equal should return true") - } - if !Equal(mockT, uint64(123), uint64(123)) { - t.Error("Equal should return true") - } - -} - -func TestFormatUnequalValues(t *testing.T) { - expected, actual := formatUnequalValues("foo", "bar") - Equal(t, `"foo"`, expected, "value should not include type") - Equal(t, `"bar"`, actual, "value should not include type") - - expected, actual = formatUnequalValues(123, 123) - Equal(t, `123`, expected, "value should not include type") - Equal(t, `123`, actual, "value should not include type") - - expected, actual = formatUnequalValues(int64(123), int32(123)) - Equal(t, `int64(123)`, expected, "value should include type") - Equal(t, `int32(123)`, actual, "value should include type") - - type testStructType struct { - Val string - } - - expected, actual = formatUnequalValues(&testStructType{Val: "test"}, &testStructType{Val: "test"}) - Equal(t, `&assert.testStructType{Val:"test"}`, expected, "value should not include type annotation") - Equal(t, `&assert.testStructType{Val:"test"}`, actual, "value should not include type annotation") -} - -func TestNotNil(t *testing.T) { - - mockT := new(testing.T) - - if !NotNil(mockT, new(AssertionTesterConformingObject)) { - t.Error("NotNil should return true: object is not nil") - } - if NotNil(mockT, nil) { - t.Error("NotNil should return false: object is nil") - } - if NotNil(mockT, (*struct{})(nil)) { - t.Error("NotNil should return false: object is (*struct{})(nil)") - } - -} - -func TestNil(t *testing.T) { - - mockT := new(testing.T) - - if !Nil(mockT, nil) { - t.Error("Nil should return true: object is nil") - } - if !Nil(mockT, (*struct{})(nil)) { - t.Error("Nil should return true: object is (*struct{})(nil)") - } - if Nil(mockT, new(AssertionTesterConformingObject)) { - t.Error("Nil should return false: object is not nil") - } - -} - -func TestTrue(t *testing.T) { - - mockT := new(testing.T) - - if !True(mockT, true) { - t.Error("True should return true") - } - if True(mockT, false) { - t.Error("True should return false") - } - -} - -func TestFalse(t *testing.T) { - - mockT := new(testing.T) - - if !False(mockT, false) { - t.Error("False should return true") - } - if False(mockT, true) { - t.Error("False should return false") - } - -} - -func TestExactly(t *testing.T) { - - mockT := new(testing.T) - - a := float32(1) - b := float64(1) - c := float32(1) - d := float32(2) - - if Exactly(mockT, a, b) { - t.Error("Exactly should return false") - } - if Exactly(mockT, a, d) { - t.Error("Exactly should return false") - } - if !Exactly(mockT, a, c) { - t.Error("Exactly should return true") - } - - if Exactly(mockT, nil, a) { - t.Error("Exactly should return false") - } - if Exactly(mockT, a, nil) { - t.Error("Exactly should return false") - } - -} - -func TestNotEqual(t *testing.T) { - - mockT := new(testing.T) - - if !NotEqual(mockT, "Hello World", "Hello World!") { - t.Error("NotEqual should return true") - } - if !NotEqual(mockT, 123, 1234) { - t.Error("NotEqual should return true") - } - if !NotEqual(mockT, 123.5, 123.55) { - t.Error("NotEqual should return true") - } - if !NotEqual(mockT, []byte("Hello World"), []byte("Hello World!")) { - t.Error("NotEqual should return true") - } - if !NotEqual(mockT, nil, new(AssertionTesterConformingObject)) { - t.Error("NotEqual should return true") - } - funcA := func() int { return 23 } - funcB := func() int { return 42 } - if !NotEqual(mockT, funcA, funcB) { - t.Error("NotEqual should return true") - } - - if NotEqual(mockT, "Hello World", "Hello World") { - t.Error("NotEqual should return false") - } - if NotEqual(mockT, 123, 123) { - t.Error("NotEqual should return false") - } - if NotEqual(mockT, 123.5, 123.5) { - t.Error("NotEqual should return false") - } - if NotEqual(mockT, []byte("Hello World"), []byte("Hello World")) { - t.Error("NotEqual should return false") - } - if NotEqual(mockT, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) { - t.Error("NotEqual should return false") - } -} - -type A struct { - Name, Value string -} - -func TestContains(t *testing.T) { - - mockT := new(testing.T) - list := []string{"Foo", "Bar"} - complexList := []*A{ - {"b", "c"}, - {"d", "e"}, - {"g", "h"}, - {"j", "k"}, - } - simpleMap := map[interface{}]interface{}{"Foo": "Bar"} - - if !Contains(mockT, "Hello World", "Hello") { - t.Error("Contains should return true: \"Hello World\" contains \"Hello\"") - } - if Contains(mockT, "Hello World", "Salut") { - t.Error("Contains should return false: \"Hello World\" does not contain \"Salut\"") - } - - if !Contains(mockT, list, "Bar") { - t.Error("Contains should return true: \"[\"Foo\", \"Bar\"]\" contains \"Bar\"") - } - if Contains(mockT, list, "Salut") { - t.Error("Contains should return false: \"[\"Foo\", \"Bar\"]\" does not contain \"Salut\"") - } - if !Contains(mockT, complexList, &A{"g", "h"}) { - t.Error("Contains should return true: complexList contains {\"g\", \"h\"}") - } - if Contains(mockT, complexList, &A{"g", "e"}) { - t.Error("Contains should return false: complexList contains {\"g\", \"e\"}") - } - if Contains(mockT, complexList, &A{"g", "e"}) { - t.Error("Contains should return false: complexList contains {\"g\", \"e\"}") - } - if !Contains(mockT, simpleMap, "Foo") { - t.Error("Contains should return true: \"{\"Foo\": \"Bar\"}\" contains \"Foo\"") - } - if Contains(mockT, simpleMap, "Bar") { - t.Error("Contains should return false: \"{\"Foo\": \"Bar\"}\" does not contains \"Bar\"") - } -} - -func TestNotContains(t *testing.T) { - - mockT := new(testing.T) - list := []string{"Foo", "Bar"} - simpleMap := map[interface{}]interface{}{"Foo": "Bar"} - - if !NotContains(mockT, "Hello World", "Hello!") { - t.Error("NotContains should return true: \"Hello World\" does not contain \"Hello!\"") - } - if NotContains(mockT, "Hello World", "Hello") { - t.Error("NotContains should return false: \"Hello World\" contains \"Hello\"") - } - - if !NotContains(mockT, list, "Foo!") { - t.Error("NotContains should return true: \"[\"Foo\", \"Bar\"]\" does not contain \"Foo!\"") - } - if NotContains(mockT, list, "Foo") { - t.Error("NotContains should return false: \"[\"Foo\", \"Bar\"]\" contains \"Foo\"") - } - if NotContains(mockT, simpleMap, "Foo") { - t.Error("Contains should return true: \"{\"Foo\": \"Bar\"}\" contains \"Foo\"") - } - if !NotContains(mockT, simpleMap, "Bar") { - t.Error("Contains should return false: \"{\"Foo\": \"Bar\"}\" does not contains \"Bar\"") - } -} - -func Test_includeElement(t *testing.T) { - - list1 := []string{"Foo", "Bar"} - list2 := []int{1, 2} - simpleMap := map[interface{}]interface{}{"Foo": "Bar"} - - ok, found := includeElement("Hello World", "World") - True(t, ok) - True(t, found) - - ok, found = includeElement(list1, "Foo") - True(t, ok) - True(t, found) - - ok, found = includeElement(list1, "Bar") - True(t, ok) - True(t, found) - - ok, found = includeElement(list2, 1) - True(t, ok) - True(t, found) - - ok, found = includeElement(list2, 2) - True(t, ok) - True(t, found) - - ok, found = includeElement(list1, "Foo!") - True(t, ok) - False(t, found) - - ok, found = includeElement(list2, 3) - True(t, ok) - False(t, found) - - ok, found = includeElement(list2, "1") - True(t, ok) - False(t, found) - - ok, found = includeElement(simpleMap, "Foo") - True(t, ok) - True(t, found) - - ok, found = includeElement(simpleMap, "Bar") - True(t, ok) - False(t, found) - - ok, found = includeElement(1433, "1") - False(t, ok) - False(t, found) -} - -func TestCondition(t *testing.T) { - mockT := new(testing.T) - - if !Condition(mockT, func() bool { return true }, "Truth") { - t.Error("Condition should return true") - } - - if Condition(mockT, func() bool { return false }, "Lie") { - t.Error("Condition should return false") - } - -} - -func TestDidPanic(t *testing.T) { - - if funcDidPanic, _ := didPanic(func() { - panic("Panic!") - }); !funcDidPanic { - t.Error("didPanic should return true") - } - - if funcDidPanic, _ := didPanic(func() { - }); funcDidPanic { - t.Error("didPanic should return false") - } - -} - -func TestPanics(t *testing.T) { - - mockT := new(testing.T) - - if !Panics(mockT, func() { - panic("Panic!") - }) { - t.Error("Panics should return true") - } - - if Panics(mockT, func() { - }) { - t.Error("Panics should return false") - } - -} - -func TestNotPanics(t *testing.T) { - - mockT := new(testing.T) - - if !NotPanics(mockT, func() { - }) { - t.Error("NotPanics should return true") - } - - if NotPanics(mockT, func() { - panic("Panic!") - }) { - t.Error("NotPanics should return false") - } - -} - -func TestNoError(t *testing.T) { - - mockT := new(testing.T) - - // start with a nil error - var err error - - True(t, NoError(mockT, err), "NoError should return True for nil arg") - - // now set an error - err = errors.New("some error") - - False(t, NoError(mockT, err), "NoError with error should return False") - - // returning an empty error interface - err = func() error { - var err *customError - if err != nil { - t.Fatal("err should be nil here") - } - return err - }() - - if err == nil { // err is not nil here! - t.Errorf("Error should be nil due to empty interface", err) - } - - False(t, NoError(mockT, err), "NoError should fail with empty error interface") -} - -type customError struct{} - -func (*customError) Error() string { return "fail" } - -func TestError(t *testing.T) { - - mockT := new(testing.T) - - // start with a nil error - var err error - - False(t, Error(mockT, err), "Error should return False for nil arg") - - // now set an error - err = errors.New("some error") - - True(t, Error(mockT, err), "Error with error should return True") - - // returning an empty error interface - err = func() error { - var err *customError - if err != nil { - t.Fatal("err should be nil here") - } - return err - }() - - if err == nil { // err is not nil here! - t.Errorf("Error should be nil due to empty interface", err) - } - - True(t, Error(mockT, err), "Error should pass with empty error interface") -} - -func TestEqualError(t *testing.T) { - mockT := new(testing.T) - - // start with a nil error - var err error - False(t, EqualError(mockT, err, ""), - "EqualError should return false for nil arg") - - // now set an error - err = errors.New("some error") - False(t, EqualError(mockT, err, "Not some error"), - "EqualError should return false for different error string") - True(t, EqualError(mockT, err, "some error"), - "EqualError should return true") -} - -func Test_isEmpty(t *testing.T) { - - chWithValue := make(chan struct{}, 1) - chWithValue <- struct{}{} - - True(t, isEmpty("")) - True(t, isEmpty(nil)) - True(t, isEmpty([]string{})) - True(t, isEmpty(0)) - True(t, isEmpty(int32(0))) - True(t, isEmpty(int64(0))) - True(t, isEmpty(false)) - True(t, isEmpty(map[string]string{})) - True(t, isEmpty(new(time.Time))) - True(t, isEmpty(time.Time{})) - True(t, isEmpty(make(chan struct{}))) - False(t, isEmpty("something")) - False(t, isEmpty(errors.New("something"))) - False(t, isEmpty([]string{"something"})) - False(t, isEmpty(1)) - False(t, isEmpty(true)) - False(t, isEmpty(map[string]string{"Hello": "World"})) - False(t, isEmpty(chWithValue)) - -} - -func TestEmpty(t *testing.T) { - - mockT := new(testing.T) - chWithValue := make(chan struct{}, 1) - chWithValue <- struct{}{} - var tiP *time.Time - var tiNP time.Time - var s *string - var f *os.File - - True(t, Empty(mockT, ""), "Empty string is empty") - True(t, Empty(mockT, nil), "Nil is empty") - True(t, Empty(mockT, []string{}), "Empty string array is empty") - True(t, Empty(mockT, 0), "Zero int value is empty") - True(t, Empty(mockT, false), "False value is empty") - True(t, Empty(mockT, make(chan struct{})), "Channel without values is empty") - True(t, Empty(mockT, s), "Nil string pointer is empty") - True(t, Empty(mockT, f), "Nil os.File pointer is empty") - True(t, Empty(mockT, tiP), "Nil time.Time pointer is empty") - True(t, Empty(mockT, tiNP), "time.Time is empty") - - False(t, Empty(mockT, "something"), "Non Empty string is not empty") - False(t, Empty(mockT, errors.New("something")), "Non nil object is not empty") - False(t, Empty(mockT, []string{"something"}), "Non empty string array is not empty") - False(t, Empty(mockT, 1), "Non-zero int value is not empty") - False(t, Empty(mockT, true), "True value is not empty") - False(t, Empty(mockT, chWithValue), "Channel with values is not empty") -} - -func TestNotEmpty(t *testing.T) { - - mockT := new(testing.T) - chWithValue := make(chan struct{}, 1) - chWithValue <- struct{}{} - - False(t, NotEmpty(mockT, ""), "Empty string is empty") - False(t, NotEmpty(mockT, nil), "Nil is empty") - False(t, NotEmpty(mockT, []string{}), "Empty string array is empty") - False(t, NotEmpty(mockT, 0), "Zero int value is empty") - False(t, NotEmpty(mockT, false), "False value is empty") - False(t, NotEmpty(mockT, make(chan struct{})), "Channel without values is empty") - - True(t, NotEmpty(mockT, "something"), "Non Empty string is not empty") - True(t, NotEmpty(mockT, errors.New("something")), "Non nil object is not empty") - True(t, NotEmpty(mockT, []string{"something"}), "Non empty string array is not empty") - True(t, NotEmpty(mockT, 1), "Non-zero int value is not empty") - True(t, NotEmpty(mockT, true), "True value is not empty") - True(t, NotEmpty(mockT, chWithValue), "Channel with values is not empty") -} - -func Test_getLen(t *testing.T) { - falseCases := []interface{}{ - nil, - 0, - true, - false, - 'A', - struct{}{}, - } - for _, v := range falseCases { - ok, l := getLen(v) - False(t, ok, "Expected getLen fail to get length of %#v", v) - Equal(t, 0, l, "getLen should return 0 for %#v", v) - } - - ch := make(chan int, 5) - ch <- 1 - ch <- 2 - ch <- 3 - trueCases := []struct { - v interface{} - l int - }{ - {[]int{1, 2, 3}, 3}, - {[...]int{1, 2, 3}, 3}, - {"ABC", 3}, - {map[int]int{1: 2, 2: 4, 3: 6}, 3}, - {ch, 3}, - - {[]int{}, 0}, - {map[int]int{}, 0}, - {make(chan int), 0}, - - {[]int(nil), 0}, - {map[int]int(nil), 0}, - {(chan int)(nil), 0}, - } - - for _, c := range trueCases { - ok, l := getLen(c.v) - True(t, ok, "Expected getLen success to get length of %#v", c.v) - Equal(t, c.l, l) - } -} - -func TestLen(t *testing.T) { - mockT := new(testing.T) - - False(t, Len(mockT, nil, 0), "nil does not have length") - False(t, Len(mockT, 0, 0), "int does not have length") - False(t, Len(mockT, true, 0), "true does not have length") - False(t, Len(mockT, false, 0), "false does not have length") - False(t, Len(mockT, 'A', 0), "Rune does not have length") - False(t, Len(mockT, struct{}{}, 0), "Struct does not have length") - - ch := make(chan int, 5) - ch <- 1 - ch <- 2 - ch <- 3 - - cases := []struct { - v interface{} - l int - }{ - {[]int{1, 2, 3}, 3}, - {[...]int{1, 2, 3}, 3}, - {"ABC", 3}, - {map[int]int{1: 2, 2: 4, 3: 6}, 3}, - {ch, 3}, - - {[]int{}, 0}, - {map[int]int{}, 0}, - {make(chan int), 0}, - - {[]int(nil), 0}, - {map[int]int(nil), 0}, - {(chan int)(nil), 0}, - } - - for _, c := range cases { - True(t, Len(mockT, c.v, c.l), "%#v have %d items", c.v, c.l) - } - - cases = []struct { - v interface{} - l int - }{ - {[]int{1, 2, 3}, 4}, - {[...]int{1, 2, 3}, 2}, - {"ABC", 2}, - {map[int]int{1: 2, 2: 4, 3: 6}, 4}, - {ch, 2}, - - {[]int{}, 1}, - {map[int]int{}, 1}, - {make(chan int), 1}, - - {[]int(nil), 1}, - {map[int]int(nil), 1}, - {(chan int)(nil), 1}, - } - - for _, c := range cases { - False(t, Len(mockT, c.v, c.l), "%#v have %d items", c.v, c.l) - } -} - -func TestWithinDuration(t *testing.T) { - - mockT := new(testing.T) - a := time.Now() - b := a.Add(10 * time.Second) - - True(t, WithinDuration(mockT, a, b, 10*time.Second), "A 10s difference is within a 10s time difference") - True(t, WithinDuration(mockT, b, a, 10*time.Second), "A 10s difference is within a 10s time difference") - - False(t, WithinDuration(mockT, a, b, 9*time.Second), "A 10s difference is not within a 9s time difference") - False(t, WithinDuration(mockT, b, a, 9*time.Second), "A 10s difference is not within a 9s time difference") - - False(t, WithinDuration(mockT, a, b, -9*time.Second), "A 10s difference is not within a 9s time difference") - False(t, WithinDuration(mockT, b, a, -9*time.Second), "A 10s difference is not within a 9s time difference") - - False(t, WithinDuration(mockT, a, b, -11*time.Second), "A 10s difference is not within a 9s time difference") - False(t, WithinDuration(mockT, b, a, -11*time.Second), "A 10s difference is not within a 9s time difference") -} - -func TestInDelta(t *testing.T) { - mockT := new(testing.T) - - True(t, InDelta(mockT, 1.001, 1, 0.01), "|1.001 - 1| <= 0.01") - True(t, InDelta(mockT, 1, 1.001, 0.01), "|1 - 1.001| <= 0.01") - True(t, InDelta(mockT, 1, 2, 1), "|1 - 2| <= 1") - False(t, InDelta(mockT, 1, 2, 0.5), "Expected |1 - 2| <= 0.5 to fail") - False(t, InDelta(mockT, 2, 1, 0.5), "Expected |2 - 1| <= 0.5 to fail") - False(t, InDelta(mockT, "", nil, 1), "Expected non numerals to fail") - False(t, InDelta(mockT, 42, math.NaN(), 0.01), "Expected NaN for actual to fail") - False(t, InDelta(mockT, math.NaN(), 42, 0.01), "Expected NaN for expected to fail") - - cases := []struct { - a, b interface{} - delta float64 - }{ - {uint8(2), uint8(1), 1}, - {uint16(2), uint16(1), 1}, - {uint32(2), uint32(1), 1}, - {uint64(2), uint64(1), 1}, - - {int(2), int(1), 1}, - {int8(2), int8(1), 1}, - {int16(2), int16(1), 1}, - {int32(2), int32(1), 1}, - {int64(2), int64(1), 1}, - - {float32(2), float32(1), 1}, - {float64(2), float64(1), 1}, - } - - for _, tc := range cases { - True(t, InDelta(mockT, tc.a, tc.b, tc.delta), "Expected |%V - %V| <= %v", tc.a, tc.b, tc.delta) - } -} - -func TestInDeltaSlice(t *testing.T) { - mockT := new(testing.T) - - True(t, InDeltaSlice(mockT, - []float64{1.001, 0.999}, - []float64{1, 1}, - 0.1), "{1.001, 0.009} is element-wise close to {1, 1} in delta=0.1") - - True(t, InDeltaSlice(mockT, - []float64{1, 2}, - []float64{0, 3}, - 1), "{1, 2} is element-wise close to {0, 3} in delta=1") - - False(t, InDeltaSlice(mockT, - []float64{1, 2}, - []float64{0, 3}, - 0.1), "{1, 2} is not element-wise close to {0, 3} in delta=0.1") - - False(t, InDeltaSlice(mockT, "", nil, 1), "Expected non numeral slices to fail") -} - -func TestInEpsilon(t *testing.T) { - mockT := new(testing.T) - - cases := []struct { - a, b interface{} - epsilon float64 - }{ - {uint8(2), uint16(2), .001}, - {2.1, 2.2, 0.1}, - {2.2, 2.1, 0.1}, - {-2.1, -2.2, 0.1}, - {-2.2, -2.1, 0.1}, - {uint64(100), uint8(101), 0.01}, - {0.1, -0.1, 2}, - {0.1, 0, 2}, - } - - for _, tc := range cases { - True(t, InEpsilon(t, tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon), "test: %q", tc) - } - - cases = []struct { - a, b interface{} - epsilon float64 - }{ - {uint8(2), int16(-2), .001}, - {uint64(100), uint8(102), 0.01}, - {2.1, 2.2, 0.001}, - {2.2, 2.1, 0.001}, - {2.1, -2.2, 1}, - {2.1, "bla-bla", 0}, - {0.1, -0.1, 1.99}, - {0, 0.1, 2}, // expected must be different to zero - } - - for _, tc := range cases { - False(t, InEpsilon(mockT, tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon)) - } - -} - -func TestInEpsilonSlice(t *testing.T) { - mockT := new(testing.T) - - True(t, InEpsilonSlice(mockT, - []float64{2.2, 2.0}, - []float64{2.1, 2.1}, - 0.06), "{2.2, 2.0} is element-wise close to {2.1, 2.1} in espilon=0.06") - - False(t, InEpsilonSlice(mockT, - []float64{2.2, 2.0}, - []float64{2.1, 2.1}, - 0.04), "{2.2, 2.0} is not element-wise close to {2.1, 2.1} in espilon=0.04") - - False(t, InEpsilonSlice(mockT, "", nil, 1), "Expected non numeral slices to fail") -} - -func TestRegexp(t *testing.T) { - mockT := new(testing.T) - - cases := []struct { - rx, str string - }{ - {"^start", "start of the line"}, - {"end$", "in the end"}, - {"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12.34"}, - } - - for _, tc := range cases { - True(t, Regexp(mockT, tc.rx, tc.str)) - True(t, Regexp(mockT, regexp.MustCompile(tc.rx), tc.str)) - False(t, NotRegexp(mockT, tc.rx, tc.str)) - False(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str)) - } - - cases = []struct { - rx, str string - }{ - {"^asdfastart", "Not the start of the line"}, - {"end$", "in the end."}, - {"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12a.34"}, - } - - for _, tc := range cases { - False(t, Regexp(mockT, tc.rx, tc.str), "Expected \"%s\" to not match \"%s\"", tc.rx, tc.str) - False(t, Regexp(mockT, regexp.MustCompile(tc.rx), tc.str)) - True(t, NotRegexp(mockT, tc.rx, tc.str)) - True(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str)) - } -} - -func testAutogeneratedFunction() { - defer func() { - if err := recover(); err == nil { - panic("did not panic") - } - CallerInfo() - }() - t := struct { - io.Closer - }{} - var c io.Closer - c = t - c.Close() -} - -func TestCallerInfoWithAutogeneratedFunctions(t *testing.T) { - NotPanics(t, func() { - testAutogeneratedFunction() - }) -} - -func TestZero(t *testing.T) { - mockT := new(testing.T) - - for _, test := range zeros { - True(t, Zero(mockT, test, "%#v is not the %v zero value", test, reflect.TypeOf(test))) - } - - for _, test := range nonZeros { - False(t, Zero(mockT, test, "%#v is not the %v zero value", test, reflect.TypeOf(test))) - } -} - -func TestNotZero(t *testing.T) { - mockT := new(testing.T) - - for _, test := range zeros { - False(t, NotZero(mockT, test, "%#v is not the %v zero value", test, reflect.TypeOf(test))) - } - - for _, test := range nonZeros { - True(t, NotZero(mockT, test, "%#v is not the %v zero value", test, reflect.TypeOf(test))) - } -} - -func TestJSONEq_EqualSONString(t *testing.T) { - mockT := new(testing.T) - True(t, JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`)) -} - -func TestJSONEq_EquivalentButNotEqual(t *testing.T) { - mockT := new(testing.T) - True(t, JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)) -} - -func TestJSONEq_HashOfArraysAndHashes(t *testing.T) { - mockT := new(testing.T) - True(t, JSONEq(mockT, "{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}", - "{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}")) -} - -func TestJSONEq_Array(t *testing.T) { - mockT := new(testing.T) - True(t, JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`)) -} - -func TestJSONEq_HashAndArrayNotEquivalent(t *testing.T) { - mockT := new(testing.T) - False(t, JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`)) -} - -func TestJSONEq_HashesNotEquivalent(t *testing.T) { - mockT := new(testing.T) - False(t, JSONEq(mockT, `{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)) -} - -func TestJSONEq_ActualIsNotJSON(t *testing.T) { - mockT := new(testing.T) - False(t, JSONEq(mockT, `{"foo": "bar"}`, "Not JSON")) -} - -func TestJSONEq_ExpectedIsNotJSON(t *testing.T) { - mockT := new(testing.T) - False(t, JSONEq(mockT, "Not JSON", `{"foo": "bar", "hello": "world"}`)) -} - -func TestJSONEq_ExpectedAndActualNotJSON(t *testing.T) { - mockT := new(testing.T) - False(t, JSONEq(mockT, "Not JSON", "Not JSON")) -} - -func TestJSONEq_ArraysOfDifferentOrder(t *testing.T) { - mockT := new(testing.T) - False(t, JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`)) -} - -func TestDiff(t *testing.T) { - expected := ` - -Diff: ---- Expected -+++ Actual -@@ -1,3 +1,3 @@ - (struct { foo string }) { -- foo: (string) (len=5) "hello" -+ foo: (string) (len=3) "bar" - } -` - actual := diff( - struct{ foo string }{"hello"}, - struct{ foo string }{"bar"}, - ) - Equal(t, expected, actual) - - expected = ` - -Diff: ---- Expected -+++ Actual -@@ -2,5 +2,5 @@ - (int) 1, -- (int) 2, - (int) 3, -- (int) 4 -+ (int) 5, -+ (int) 7 - } -` - actual = diff( - []int{1, 2, 3, 4}, - []int{1, 3, 5, 7}, - ) - Equal(t, expected, actual) - - expected = ` - -Diff: ---- Expected -+++ Actual -@@ -2,4 +2,4 @@ - (int) 1, -- (int) 2, -- (int) 3 -+ (int) 3, -+ (int) 5 - } -` - actual = diff( - []int{1, 2, 3, 4}[0:3], - []int{1, 3, 5, 7}[0:3], - ) - Equal(t, expected, actual) - - expected = ` - -Diff: ---- Expected -+++ Actual -@@ -1,6 +1,6 @@ - (map[string]int) (len=4) { -- (string) (len=4) "four": (int) 4, -+ (string) (len=4) "five": (int) 5, - (string) (len=3) "one": (int) 1, -- (string) (len=5) "three": (int) 3, -- (string) (len=3) "two": (int) 2 -+ (string) (len=5) "seven": (int) 7, -+ (string) (len=5) "three": (int) 3 - } -` - - actual = diff( - map[string]int{"one": 1, "two": 2, "three": 3, "four": 4}, - map[string]int{"one": 1, "three": 3, "five": 5, "seven": 7}, - ) - Equal(t, expected, actual) -} - -func TestDiffEmptyCases(t *testing.T) { - Equal(t, "", diff(nil, nil)) - Equal(t, "", diff(struct{ foo string }{}, nil)) - Equal(t, "", diff(nil, struct{ foo string }{})) - Equal(t, "", diff(1, 2)) - Equal(t, "", diff(1, 2)) - Equal(t, "", diff([]int{1}, []bool{true})) -} - -// Ensure there are no data races -func TestDiffRace(t *testing.T) { - t.Parallel() - - expected := map[string]string{ - "a": "A", - "b": "B", - "c": "C", - } - - actual := map[string]string{ - "d": "D", - "e": "E", - "f": "F", - } - - // run diffs in parallel simulating tests with t.Parallel() - numRoutines := 10 - rChans := make([]chan string, numRoutines) - for idx := range rChans { - rChans[idx] = make(chan string) - go func(ch chan string) { - defer close(ch) - ch <- diff(expected, actual) - }(rChans[idx]) - } - - for _, ch := range rChans { - for msg := range ch { - NotZero(t, msg) // dummy assert - } - } -} - -type mockTestingT struct { -} - -func (m *mockTestingT) Errorf(format string, args ...interface{}) {} - -func TestFailNowWithPlainTestingT(t *testing.T) { - mockT := &mockTestingT{} - - Panics(t, func() { - FailNow(mockT, "failed") - }, "should panic since mockT is missing FailNow()") -} - -type mockFailNowTestingT struct { -} - -func (m *mockFailNowTestingT) Errorf(format string, args ...interface{}) {} - -func (m *mockFailNowTestingT) FailNow() {} - -func TestFailNowWithFullTestingT(t *testing.T) { - mockT := &mockFailNowTestingT{} - - NotPanics(t, func() { - FailNow(mockT, "failed") - }, "should call mockT.FailNow() rather than panicking") -} diff --git a/vendor/github.com/stretchr/testify/assert/doc.go b/vendor/github.com/stretchr/testify/assert/doc.go deleted file mode 100644 index c9dccc4d..00000000 --- a/vendor/github.com/stretchr/testify/assert/doc.go +++ /dev/null @@ -1,45 +0,0 @@ -// Package assert provides a set of comprehensive testing tools for use with the normal Go testing system. -// -// Example Usage -// -// The following is a complete example using assert in a standard test function: -// import ( -// "testing" -// "github.com/stretchr/testify/assert" -// ) -// -// func TestSomething(t *testing.T) { -// -// var a string = "Hello" -// var b string = "Hello" -// -// assert.Equal(t, a, b, "The two words should be the same.") -// -// } -// -// if you assert many times, use the format below: -// -// import ( -// "testing" -// "github.com/stretchr/testify/assert" -// ) -// -// func TestSomething(t *testing.T) { -// assert := assert.New(t) -// -// var a string = "Hello" -// var b string = "Hello" -// -// assert.Equal(a, b, "The two words should be the same.") -// } -// -// Assertions -// -// Assertions allow you to easily write test code, and are global funcs in the `assert` package. -// All assertion functions take, as the first argument, the `*testing.T` object provided by the -// testing framework. This allows the assertion funcs to write the failings and other details to -// the correct place. -// -// Every assertion function also takes an optional string message as the final argument, -// allowing custom error messages to be appended to the message the assertion method outputs. -package assert diff --git a/vendor/github.com/stretchr/testify/assert/errors.go b/vendor/github.com/stretchr/testify/assert/errors.go deleted file mode 100644 index ac9dc9d1..00000000 --- a/vendor/github.com/stretchr/testify/assert/errors.go +++ /dev/null @@ -1,10 +0,0 @@ -package assert - -import ( - "errors" -) - -// AnError is an error instance useful for testing. If the code does not care -// about error specifics, and only needs to return the error for example, this -// error should be used to make the test code more readable. -var AnError = errors.New("assert.AnError general error for testing") diff --git a/vendor/github.com/stretchr/testify/assert/forward_assertions.go b/vendor/github.com/stretchr/testify/assert/forward_assertions.go deleted file mode 100644 index b867e95e..00000000 --- a/vendor/github.com/stretchr/testify/assert/forward_assertions.go +++ /dev/null @@ -1,16 +0,0 @@ -package assert - -// Assertions provides assertion methods around the -// TestingT interface. -type Assertions struct { - t TestingT -} - -// New makes a new Assertions object for the specified TestingT. -func New(t TestingT) *Assertions { - return &Assertions{ - t: t, - } -} - -//go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_forward.go.tmpl diff --git a/vendor/github.com/stretchr/testify/assert/forward_assertions_test.go b/vendor/github.com/stretchr/testify/assert/forward_assertions_test.go deleted file mode 100644 index 22e1df1d..00000000 --- a/vendor/github.com/stretchr/testify/assert/forward_assertions_test.go +++ /dev/null @@ -1,611 +0,0 @@ -package assert - -import ( - "errors" - "regexp" - "testing" - "time" -) - -func TestImplementsWrapper(t *testing.T) { - assert := New(new(testing.T)) - - if !assert.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) { - t.Error("Implements method should return true: AssertionTesterConformingObject implements AssertionTesterInterface") - } - if assert.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) { - t.Error("Implements method should return false: AssertionTesterNonConformingObject does not implements AssertionTesterInterface") - } -} - -func TestIsTypeWrapper(t *testing.T) { - assert := New(new(testing.T)) - - if !assert.IsType(new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) { - t.Error("IsType should return true: AssertionTesterConformingObject is the same type as AssertionTesterConformingObject") - } - if assert.IsType(new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) { - t.Error("IsType should return false: AssertionTesterConformingObject is not the same type as AssertionTesterNonConformingObject") - } - -} - -func TestEqualWrapper(t *testing.T) { - assert := New(new(testing.T)) - - if !assert.Equal("Hello World", "Hello World") { - t.Error("Equal should return true") - } - if !assert.Equal(123, 123) { - t.Error("Equal should return true") - } - if !assert.Equal(123.5, 123.5) { - t.Error("Equal should return true") - } - if !assert.Equal([]byte("Hello World"), []byte("Hello World")) { - t.Error("Equal should return true") - } - if !assert.Equal(nil, nil) { - t.Error("Equal should return true") - } -} - -func TestEqualValuesWrapper(t *testing.T) { - assert := New(new(testing.T)) - - if !assert.EqualValues(uint32(10), int32(10)) { - t.Error("EqualValues should return true") - } -} - -func TestNotNilWrapper(t *testing.T) { - assert := New(new(testing.T)) - - if !assert.NotNil(new(AssertionTesterConformingObject)) { - t.Error("NotNil should return true: object is not nil") - } - if assert.NotNil(nil) { - t.Error("NotNil should return false: object is nil") - } - -} - -func TestNilWrapper(t *testing.T) { - assert := New(new(testing.T)) - - if !assert.Nil(nil) { - t.Error("Nil should return true: object is nil") - } - if assert.Nil(new(AssertionTesterConformingObject)) { - t.Error("Nil should return false: object is not nil") - } - -} - -func TestTrueWrapper(t *testing.T) { - assert := New(new(testing.T)) - - if !assert.True(true) { - t.Error("True should return true") - } - if assert.True(false) { - t.Error("True should return false") - } - -} - -func TestFalseWrapper(t *testing.T) { - assert := New(new(testing.T)) - - if !assert.False(false) { - t.Error("False should return true") - } - if assert.False(true) { - t.Error("False should return false") - } - -} - -func TestExactlyWrapper(t *testing.T) { - assert := New(new(testing.T)) - - a := float32(1) - b := float64(1) - c := float32(1) - d := float32(2) - - if assert.Exactly(a, b) { - t.Error("Exactly should return false") - } - if assert.Exactly(a, d) { - t.Error("Exactly should return false") - } - if !assert.Exactly(a, c) { - t.Error("Exactly should return true") - } - - if assert.Exactly(nil, a) { - t.Error("Exactly should return false") - } - if assert.Exactly(a, nil) { - t.Error("Exactly should return false") - } - -} - -func TestNotEqualWrapper(t *testing.T) { - - assert := New(new(testing.T)) - - if !assert.NotEqual("Hello World", "Hello World!") { - t.Error("NotEqual should return true") - } - if !assert.NotEqual(123, 1234) { - t.Error("NotEqual should return true") - } - if !assert.NotEqual(123.5, 123.55) { - t.Error("NotEqual should return true") - } - if !assert.NotEqual([]byte("Hello World"), []byte("Hello World!")) { - t.Error("NotEqual should return true") - } - if !assert.NotEqual(nil, new(AssertionTesterConformingObject)) { - t.Error("NotEqual should return true") - } -} - -func TestContainsWrapper(t *testing.T) { - - assert := New(new(testing.T)) - list := []string{"Foo", "Bar"} - - if !assert.Contains("Hello World", "Hello") { - t.Error("Contains should return true: \"Hello World\" contains \"Hello\"") - } - if assert.Contains("Hello World", "Salut") { - t.Error("Contains should return false: \"Hello World\" does not contain \"Salut\"") - } - - if !assert.Contains(list, "Foo") { - t.Error("Contains should return true: \"[\"Foo\", \"Bar\"]\" contains \"Foo\"") - } - if assert.Contains(list, "Salut") { - t.Error("Contains should return false: \"[\"Foo\", \"Bar\"]\" does not contain \"Salut\"") - } - -} - -func TestNotContainsWrapper(t *testing.T) { - - assert := New(new(testing.T)) - list := []string{"Foo", "Bar"} - - if !assert.NotContains("Hello World", "Hello!") { - t.Error("NotContains should return true: \"Hello World\" does not contain \"Hello!\"") - } - if assert.NotContains("Hello World", "Hello") { - t.Error("NotContains should return false: \"Hello World\" contains \"Hello\"") - } - - if !assert.NotContains(list, "Foo!") { - t.Error("NotContains should return true: \"[\"Foo\", \"Bar\"]\" does not contain \"Foo!\"") - } - if assert.NotContains(list, "Foo") { - t.Error("NotContains should return false: \"[\"Foo\", \"Bar\"]\" contains \"Foo\"") - } - -} - -func TestConditionWrapper(t *testing.T) { - - assert := New(new(testing.T)) - - if !assert.Condition(func() bool { return true }, "Truth") { - t.Error("Condition should return true") - } - - if assert.Condition(func() bool { return false }, "Lie") { - t.Error("Condition should return false") - } - -} - -func TestDidPanicWrapper(t *testing.T) { - - if funcDidPanic, _ := didPanic(func() { - panic("Panic!") - }); !funcDidPanic { - t.Error("didPanic should return true") - } - - if funcDidPanic, _ := didPanic(func() { - }); funcDidPanic { - t.Error("didPanic should return false") - } - -} - -func TestPanicsWrapper(t *testing.T) { - - assert := New(new(testing.T)) - - if !assert.Panics(func() { - panic("Panic!") - }) { - t.Error("Panics should return true") - } - - if assert.Panics(func() { - }) { - t.Error("Panics should return false") - } - -} - -func TestNotPanicsWrapper(t *testing.T) { - - assert := New(new(testing.T)) - - if !assert.NotPanics(func() { - }) { - t.Error("NotPanics should return true") - } - - if assert.NotPanics(func() { - panic("Panic!") - }) { - t.Error("NotPanics should return false") - } - -} - -func TestNoErrorWrapper(t *testing.T) { - assert := New(t) - mockAssert := New(new(testing.T)) - - // start with a nil error - var err error - - assert.True(mockAssert.NoError(err), "NoError should return True for nil arg") - - // now set an error - err = errors.New("Some error") - - assert.False(mockAssert.NoError(err), "NoError with error should return False") - -} - -func TestErrorWrapper(t *testing.T) { - assert := New(t) - mockAssert := New(new(testing.T)) - - // start with a nil error - var err error - - assert.False(mockAssert.Error(err), "Error should return False for nil arg") - - // now set an error - err = errors.New("Some error") - - assert.True(mockAssert.Error(err), "Error with error should return True") - -} - -func TestEqualErrorWrapper(t *testing.T) { - assert := New(t) - mockAssert := New(new(testing.T)) - - // start with a nil error - var err error - assert.False(mockAssert.EqualError(err, ""), - "EqualError should return false for nil arg") - - // now set an error - err = errors.New("some error") - assert.False(mockAssert.EqualError(err, "Not some error"), - "EqualError should return false for different error string") - assert.True(mockAssert.EqualError(err, "some error"), - "EqualError should return true") -} - -func TestEmptyWrapper(t *testing.T) { - assert := New(t) - mockAssert := New(new(testing.T)) - - assert.True(mockAssert.Empty(""), "Empty string is empty") - assert.True(mockAssert.Empty(nil), "Nil is empty") - assert.True(mockAssert.Empty([]string{}), "Empty string array is empty") - assert.True(mockAssert.Empty(0), "Zero int value is empty") - assert.True(mockAssert.Empty(false), "False value is empty") - - assert.False(mockAssert.Empty("something"), "Non Empty string is not empty") - assert.False(mockAssert.Empty(errors.New("something")), "Non nil object is not empty") - assert.False(mockAssert.Empty([]string{"something"}), "Non empty string array is not empty") - assert.False(mockAssert.Empty(1), "Non-zero int value is not empty") - assert.False(mockAssert.Empty(true), "True value is not empty") - -} - -func TestNotEmptyWrapper(t *testing.T) { - assert := New(t) - mockAssert := New(new(testing.T)) - - assert.False(mockAssert.NotEmpty(""), "Empty string is empty") - assert.False(mockAssert.NotEmpty(nil), "Nil is empty") - assert.False(mockAssert.NotEmpty([]string{}), "Empty string array is empty") - assert.False(mockAssert.NotEmpty(0), "Zero int value is empty") - assert.False(mockAssert.NotEmpty(false), "False value is empty") - - assert.True(mockAssert.NotEmpty("something"), "Non Empty string is not empty") - assert.True(mockAssert.NotEmpty(errors.New("something")), "Non nil object is not empty") - assert.True(mockAssert.NotEmpty([]string{"something"}), "Non empty string array is not empty") - assert.True(mockAssert.NotEmpty(1), "Non-zero int value is not empty") - assert.True(mockAssert.NotEmpty(true), "True value is not empty") - -} - -func TestLenWrapper(t *testing.T) { - assert := New(t) - mockAssert := New(new(testing.T)) - - assert.False(mockAssert.Len(nil, 0), "nil does not have length") - assert.False(mockAssert.Len(0, 0), "int does not have length") - assert.False(mockAssert.Len(true, 0), "true does not have length") - assert.False(mockAssert.Len(false, 0), "false does not have length") - assert.False(mockAssert.Len('A', 0), "Rune does not have length") - assert.False(mockAssert.Len(struct{}{}, 0), "Struct does not have length") - - ch := make(chan int, 5) - ch <- 1 - ch <- 2 - ch <- 3 - - cases := []struct { - v interface{} - l int - }{ - {[]int{1, 2, 3}, 3}, - {[...]int{1, 2, 3}, 3}, - {"ABC", 3}, - {map[int]int{1: 2, 2: 4, 3: 6}, 3}, - {ch, 3}, - - {[]int{}, 0}, - {map[int]int{}, 0}, - {make(chan int), 0}, - - {[]int(nil), 0}, - {map[int]int(nil), 0}, - {(chan int)(nil), 0}, - } - - for _, c := range cases { - assert.True(mockAssert.Len(c.v, c.l), "%#v have %d items", c.v, c.l) - } -} - -func TestWithinDurationWrapper(t *testing.T) { - assert := New(t) - mockAssert := New(new(testing.T)) - a := time.Now() - b := a.Add(10 * time.Second) - - assert.True(mockAssert.WithinDuration(a, b, 10*time.Second), "A 10s difference is within a 10s time difference") - assert.True(mockAssert.WithinDuration(b, a, 10*time.Second), "A 10s difference is within a 10s time difference") - - assert.False(mockAssert.WithinDuration(a, b, 9*time.Second), "A 10s difference is not within a 9s time difference") - assert.False(mockAssert.WithinDuration(b, a, 9*time.Second), "A 10s difference is not within a 9s time difference") - - assert.False(mockAssert.WithinDuration(a, b, -9*time.Second), "A 10s difference is not within a 9s time difference") - assert.False(mockAssert.WithinDuration(b, a, -9*time.Second), "A 10s difference is not within a 9s time difference") - - assert.False(mockAssert.WithinDuration(a, b, -11*time.Second), "A 10s difference is not within a 9s time difference") - assert.False(mockAssert.WithinDuration(b, a, -11*time.Second), "A 10s difference is not within a 9s time difference") -} - -func TestInDeltaWrapper(t *testing.T) { - assert := New(new(testing.T)) - - True(t, assert.InDelta(1.001, 1, 0.01), "|1.001 - 1| <= 0.01") - True(t, assert.InDelta(1, 1.001, 0.01), "|1 - 1.001| <= 0.01") - True(t, assert.InDelta(1, 2, 1), "|1 - 2| <= 1") - False(t, assert.InDelta(1, 2, 0.5), "Expected |1 - 2| <= 0.5 to fail") - False(t, assert.InDelta(2, 1, 0.5), "Expected |2 - 1| <= 0.5 to fail") - False(t, assert.InDelta("", nil, 1), "Expected non numerals to fail") - - cases := []struct { - a, b interface{} - delta float64 - }{ - {uint8(2), uint8(1), 1}, - {uint16(2), uint16(1), 1}, - {uint32(2), uint32(1), 1}, - {uint64(2), uint64(1), 1}, - - {int(2), int(1), 1}, - {int8(2), int8(1), 1}, - {int16(2), int16(1), 1}, - {int32(2), int32(1), 1}, - {int64(2), int64(1), 1}, - - {float32(2), float32(1), 1}, - {float64(2), float64(1), 1}, - } - - for _, tc := range cases { - True(t, assert.InDelta(tc.a, tc.b, tc.delta), "Expected |%V - %V| <= %v", tc.a, tc.b, tc.delta) - } -} - -func TestInEpsilonWrapper(t *testing.T) { - assert := New(new(testing.T)) - - cases := []struct { - a, b interface{} - epsilon float64 - }{ - {uint8(2), uint16(2), .001}, - {2.1, 2.2, 0.1}, - {2.2, 2.1, 0.1}, - {-2.1, -2.2, 0.1}, - {-2.2, -2.1, 0.1}, - {uint64(100), uint8(101), 0.01}, - {0.1, -0.1, 2}, - } - - for _, tc := range cases { - True(t, assert.InEpsilon(tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon)) - } - - cases = []struct { - a, b interface{} - epsilon float64 - }{ - {uint8(2), int16(-2), .001}, - {uint64(100), uint8(102), 0.01}, - {2.1, 2.2, 0.001}, - {2.2, 2.1, 0.001}, - {2.1, -2.2, 1}, - {2.1, "bla-bla", 0}, - {0.1, -0.1, 1.99}, - } - - for _, tc := range cases { - False(t, assert.InEpsilon(tc.a, tc.b, tc.epsilon, "Expected %V and %V to have a relative difference of %v", tc.a, tc.b, tc.epsilon)) - } -} - -func TestRegexpWrapper(t *testing.T) { - - assert := New(new(testing.T)) - - cases := []struct { - rx, str string - }{ - {"^start", "start of the line"}, - {"end$", "in the end"}, - {"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12.34"}, - } - - for _, tc := range cases { - True(t, assert.Regexp(tc.rx, tc.str)) - True(t, assert.Regexp(regexp.MustCompile(tc.rx), tc.str)) - False(t, assert.NotRegexp(tc.rx, tc.str)) - False(t, assert.NotRegexp(regexp.MustCompile(tc.rx), tc.str)) - } - - cases = []struct { - rx, str string - }{ - {"^asdfastart", "Not the start of the line"}, - {"end$", "in the end."}, - {"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12a.34"}, - } - - for _, tc := range cases { - False(t, assert.Regexp(tc.rx, tc.str), "Expected \"%s\" to not match \"%s\"", tc.rx, tc.str) - False(t, assert.Regexp(regexp.MustCompile(tc.rx), tc.str)) - True(t, assert.NotRegexp(tc.rx, tc.str)) - True(t, assert.NotRegexp(regexp.MustCompile(tc.rx), tc.str)) - } -} - -func TestZeroWrapper(t *testing.T) { - assert := New(t) - mockAssert := New(new(testing.T)) - - for _, test := range zeros { - assert.True(mockAssert.Zero(test), "Zero should return true for %v", test) - } - - for _, test := range nonZeros { - assert.False(mockAssert.Zero(test), "Zero should return false for %v", test) - } -} - -func TestNotZeroWrapper(t *testing.T) { - assert := New(t) - mockAssert := New(new(testing.T)) - - for _, test := range zeros { - assert.False(mockAssert.NotZero(test), "Zero should return true for %v", test) - } - - for _, test := range nonZeros { - assert.True(mockAssert.NotZero(test), "Zero should return false for %v", test) - } -} - -func TestJSONEqWrapper_EqualSONString(t *testing.T) { - assert := New(new(testing.T)) - if !assert.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`) { - t.Error("JSONEq should return true") - } - -} - -func TestJSONEqWrapper_EquivalentButNotEqual(t *testing.T) { - assert := New(new(testing.T)) - if !assert.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) { - t.Error("JSONEq should return true") - } - -} - -func TestJSONEqWrapper_HashOfArraysAndHashes(t *testing.T) { - assert := New(new(testing.T)) - if !assert.JSONEq("{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}", - "{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}") { - t.Error("JSONEq should return true") - } -} - -func TestJSONEqWrapper_Array(t *testing.T) { - assert := New(new(testing.T)) - if !assert.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`) { - t.Error("JSONEq should return true") - } - -} - -func TestJSONEqWrapper_HashAndArrayNotEquivalent(t *testing.T) { - assert := New(new(testing.T)) - if assert.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`) { - t.Error("JSONEq should return false") - } -} - -func TestJSONEqWrapper_HashesNotEquivalent(t *testing.T) { - assert := New(new(testing.T)) - if assert.JSONEq(`{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) { - t.Error("JSONEq should return false") - } -} - -func TestJSONEqWrapper_ActualIsNotJSON(t *testing.T) { - assert := New(new(testing.T)) - if assert.JSONEq(`{"foo": "bar"}`, "Not JSON") { - t.Error("JSONEq should return false") - } -} - -func TestJSONEqWrapper_ExpectedIsNotJSON(t *testing.T) { - assert := New(new(testing.T)) - if assert.JSONEq("Not JSON", `{"foo": "bar", "hello": "world"}`) { - t.Error("JSONEq should return false") - } -} - -func TestJSONEqWrapper_ExpectedAndActualNotJSON(t *testing.T) { - assert := New(new(testing.T)) - if assert.JSONEq("Not JSON", "Not JSON") { - t.Error("JSONEq should return false") - } -} - -func TestJSONEqWrapper_ArraysOfDifferentOrder(t *testing.T) { - assert := New(new(testing.T)) - if assert.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`) { - t.Error("JSONEq should return false") - } -} diff --git a/vendor/github.com/stretchr/testify/assert/http_assertions.go b/vendor/github.com/stretchr/testify/assert/http_assertions.go deleted file mode 100644 index fa7ab89b..00000000 --- a/vendor/github.com/stretchr/testify/assert/http_assertions.go +++ /dev/null @@ -1,106 +0,0 @@ -package assert - -import ( - "fmt" - "net/http" - "net/http/httptest" - "net/url" - "strings" -) - -// httpCode is a helper that returns HTTP code of the response. It returns -1 -// if building a new request fails. -func httpCode(handler http.HandlerFunc, method, url string, values url.Values) int { - w := httptest.NewRecorder() - req, err := http.NewRequest(method, url+"?"+values.Encode(), nil) - if err != nil { - return -1 - } - handler(w, req) - return w.Code -} - -// HTTPSuccess asserts that a specified handler returns a success status code. -// -// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) -// -// Returns whether the assertion was successful (true) or not (false). -func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool { - code := httpCode(handler, method, url, values) - if code == -1 { - return false - } - return code >= http.StatusOK && code <= http.StatusPartialContent -} - -// HTTPRedirect asserts that a specified handler returns a redirect status code. -// -// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). -func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool { - code := httpCode(handler, method, url, values) - if code == -1 { - return false - } - return code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect -} - -// HTTPError asserts that a specified handler returns an error status code. -// -// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). -func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool { - code := httpCode(handler, method, url, values) - if code == -1 { - return false - } - return code >= http.StatusBadRequest -} - -// HTTPBody is a helper that returns HTTP body of the response. It returns -// empty string if building a new request fails. -func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string { - w := httptest.NewRecorder() - req, err := http.NewRequest(method, url+"?"+values.Encode(), nil) - if err != nil { - return "" - } - handler(w, req) - return w.Body.String() -} - -// HTTPBodyContains asserts that a specified handler returns a -// body that contains a string. -// -// assert.HTTPBodyContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky") -// -// Returns whether the assertion was successful (true) or not (false). -func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}) bool { - body := HTTPBody(handler, method, url, values) - - contains := strings.Contains(body, fmt.Sprint(str)) - if !contains { - Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)) - } - - return contains -} - -// HTTPBodyNotContains asserts that a specified handler returns a -// body that does not contain a string. -// -// assert.HTTPBodyNotContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky") -// -// Returns whether the assertion was successful (true) or not (false). -func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}) bool { - body := HTTPBody(handler, method, url, values) - - contains := strings.Contains(body, fmt.Sprint(str)) - if contains { - Fail(t, fmt.Sprintf("Expected response body for \"%s\" to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)) - } - - return !contains -} diff --git a/vendor/github.com/stretchr/testify/assert/http_assertions_test.go b/vendor/github.com/stretchr/testify/assert/http_assertions_test.go deleted file mode 100644 index 684c2d5d..00000000 --- a/vendor/github.com/stretchr/testify/assert/http_assertions_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package assert - -import ( - "fmt" - "net/http" - "net/url" - "testing" -) - -func httpOK(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) -} - -func httpRedirect(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusTemporaryRedirect) -} - -func httpError(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusInternalServerError) -} - -func TestHTTPStatuses(t *testing.T) { - assert := New(t) - mockT := new(testing.T) - - assert.Equal(HTTPSuccess(mockT, httpOK, "GET", "/", nil), true) - assert.Equal(HTTPSuccess(mockT, httpRedirect, "GET", "/", nil), false) - assert.Equal(HTTPSuccess(mockT, httpError, "GET", "/", nil), false) - - assert.Equal(HTTPRedirect(mockT, httpOK, "GET", "/", nil), false) - assert.Equal(HTTPRedirect(mockT, httpRedirect, "GET", "/", nil), true) - assert.Equal(HTTPRedirect(mockT, httpError, "GET", "/", nil), false) - - assert.Equal(HTTPError(mockT, httpOK, "GET", "/", nil), false) - assert.Equal(HTTPError(mockT, httpRedirect, "GET", "/", nil), false) - assert.Equal(HTTPError(mockT, httpError, "GET", "/", nil), true) -} - -func TestHTTPStatusesWrapper(t *testing.T) { - assert := New(t) - mockAssert := New(new(testing.T)) - - assert.Equal(mockAssert.HTTPSuccess(httpOK, "GET", "/", nil), true) - assert.Equal(mockAssert.HTTPSuccess(httpRedirect, "GET", "/", nil), false) - assert.Equal(mockAssert.HTTPSuccess(httpError, "GET", "/", nil), false) - - assert.Equal(mockAssert.HTTPRedirect(httpOK, "GET", "/", nil), false) - assert.Equal(mockAssert.HTTPRedirect(httpRedirect, "GET", "/", nil), true) - assert.Equal(mockAssert.HTTPRedirect(httpError, "GET", "/", nil), false) - - assert.Equal(mockAssert.HTTPError(httpOK, "GET", "/", nil), false) - assert.Equal(mockAssert.HTTPError(httpRedirect, "GET", "/", nil), false) - assert.Equal(mockAssert.HTTPError(httpError, "GET", "/", nil), true) -} - -func httpHelloName(w http.ResponseWriter, r *http.Request) { - name := r.FormValue("name") - w.Write([]byte(fmt.Sprintf("Hello, %s!", name))) -} - -func TestHttpBody(t *testing.T) { - assert := New(t) - mockT := new(testing.T) - - assert.True(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!")) - assert.True(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World")) - assert.False(HTTPBodyContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world")) - - assert.False(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!")) - assert.False(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World")) - assert.True(HTTPBodyNotContains(mockT, httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world")) -} - -func TestHttpBodyWrappers(t *testing.T) { - assert := New(t) - mockAssert := New(new(testing.T)) - - assert.True(mockAssert.HTTPBodyContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!")) - assert.True(mockAssert.HTTPBodyContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World")) - assert.False(mockAssert.HTTPBodyContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world")) - - assert.False(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "Hello, World!")) - assert.False(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "World")) - assert.True(mockAssert.HTTPBodyNotContains(httpHelloName, "GET", "/", url.Values{"name": []string{"World"}}, "world")) - -} diff --git a/vendor/github.com/stretchr/testify/doc.go b/vendor/github.com/stretchr/testify/doc.go deleted file mode 100644 index 377d5cc5..00000000 --- a/vendor/github.com/stretchr/testify/doc.go +++ /dev/null @@ -1,22 +0,0 @@ -// Package testify is a set of packages that provide many tools for testifying that your code will behave as you intend. -// -// testify contains the following packages: -// -// The assert package provides a comprehensive set of assertion functions that tie in to the Go testing system. -// -// The http package contains tools to make it easier to test http activity using the Go testing system. -// -// The mock package provides a system by which it is possible to mock your objects and verify calls are happening as expected. -// -// The suite package provides a basic structure for using structs as testing suites, and methods on those structs as tests. It includes setup/teardown functionality in the way of interfaces. -package testify - -// blank imports help docs. -import ( - // assert package - _ "github.com/stretchr/testify/assert" - // http package - _ "github.com/stretchr/testify/http" - // mock package - _ "github.com/stretchr/testify/mock" -) diff --git a/vendor/github.com/stretchr/testify/http/doc.go b/vendor/github.com/stretchr/testify/http/doc.go deleted file mode 100644 index 695167c6..00000000 --- a/vendor/github.com/stretchr/testify/http/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package http DEPRECATED USE net/http/httptest -package http diff --git a/vendor/github.com/stretchr/testify/http/test_response_writer.go b/vendor/github.com/stretchr/testify/http/test_response_writer.go deleted file mode 100644 index 5c3f813f..00000000 --- a/vendor/github.com/stretchr/testify/http/test_response_writer.go +++ /dev/null @@ -1,49 +0,0 @@ -package http - -import ( - "net/http" -) - -// TestResponseWriter DEPRECATED: We recommend you use http://golang.org/pkg/net/http/httptest instead. -type TestResponseWriter struct { - - // StatusCode is the last int written by the call to WriteHeader(int) - StatusCode int - - // Output is a string containing the written bytes using the Write([]byte) func. - Output string - - // header is the internal storage of the http.Header object - header http.Header -} - -// Header DEPRECATED: We recommend you use http://golang.org/pkg/net/http/httptest instead. -func (rw *TestResponseWriter) Header() http.Header { - - if rw.header == nil { - rw.header = make(http.Header) - } - - return rw.header -} - -// Write DEPRECATED: We recommend you use http://golang.org/pkg/net/http/httptest instead. -func (rw *TestResponseWriter) Write(bytes []byte) (int, error) { - - // assume 200 success if no header has been set - if rw.StatusCode == 0 { - rw.WriteHeader(200) - } - - // add these bytes to the output string - rw.Output = rw.Output + string(bytes) - - // return normal values - return 0, nil - -} - -// WriteHeader DEPRECATED: We recommend you use http://golang.org/pkg/net/http/httptest instead. -func (rw *TestResponseWriter) WriteHeader(i int) { - rw.StatusCode = i -} diff --git a/vendor/github.com/stretchr/testify/http/test_round_tripper.go b/vendor/github.com/stretchr/testify/http/test_round_tripper.go deleted file mode 100644 index b1e32f1d..00000000 --- a/vendor/github.com/stretchr/testify/http/test_round_tripper.go +++ /dev/null @@ -1,17 +0,0 @@ -package http - -import ( - "github.com/stretchr/testify/mock" - "net/http" -) - -// TestRoundTripper DEPRECATED USE net/http/httptest -type TestRoundTripper struct { - mock.Mock -} - -// RoundTrip DEPRECATED USE net/http/httptest -func (t *TestRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { - args := t.Called(req) - return args.Get(0).(*http.Response), args.Error(1) -} diff --git a/vendor/github.com/stretchr/testify/mock/doc.go b/vendor/github.com/stretchr/testify/mock/doc.go deleted file mode 100644 index 7324128e..00000000 --- a/vendor/github.com/stretchr/testify/mock/doc.go +++ /dev/null @@ -1,44 +0,0 @@ -// 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 deleted file mode 100644 index 20d7b8b1..00000000 --- a/vendor/github.com/stretchr/testify/mock/mock.go +++ /dev/null @@ -1,763 +0,0 @@ -package mock - -import ( - "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" -) - -func inin() { - spew.Config.SortKeys = true -} - -// 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 - - // 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 - - // 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 - - // 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, methodArguments ...interface{}) *Call { - return &Call{ - Parent: parent, - Method: methodName, - Arguments: methodArguments, - ReturnArguments: make([]interface{}, 0), - 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 { - return c.WaitUntil(time.After(d)) -} - -// 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(Arguments)) *Call { - c.lock() - defer c.unlock() - c.RunFn = fn - 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")) -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 - - // 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 -*/ - -// 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, arguments...) - m.ExpectedCalls = append(m.ExpectedCalls, c) - return c -} - -// /* -// Recording and responding to activity -// */ - -func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) { - m.mutex.Lock() - defer m.mutex.Unlock() - 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{}) (bool, *Call) { - diffCount := 0 - var closestCall *Call - - for _, call := range m.expectedCalls() { - if call.Method == method { - - _, tempDiffCount := call.Arguments.Diff(arguments) - if tempDiffCount < diffCount || diffCount == 0 { - diffCount = tempDiffCount - closestCall = call - } - - } - } - - if closestCall == nil { - return false, nil - } - - return true, closestCall -} - -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 inteface 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] - - found, call := m.findExpectedCall(functionName, 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. - - closestFound, closestCall := m.findClosestCall(functionName, arguments...) - - if closestFound { - panic(fmt.Sprintf("\n\nmock: Unexpected Method Call\n-----------------------------\n\n%s\n\nThe closest call I have is: \n\n%s\n\n%s\n", callString(functionName, arguments, true), callString(functionName, closestCall.Arguments, true), diffArguments(arguments, closestCall.Arguments))) - } else { - panic(fmt.Sprintf("\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", functionName, functionName, callString(functionName, arguments, true), assert.CallerInfo())) - } - } else { - m.mutex.Lock() - switch { - case call.Repeatability == 1: - call.Repeatability = -1 - call.totalCalls++ - - case call.Repeatability > 1: - call.Repeatability-- - call.totalCalls++ - - case call.Repeatability == 0: - call.totalCalls++ - } - m.mutex.Unlock() - } - - // add the call - m.mutex.Lock() - m.Calls = append(m.Calls, *newCall(m, functionName, arguments...)) - m.mutex.Unlock() - - // block if specified - if call.WaitFor != nil { - <-call.WaitFor - } - - if call.RunFn != nil { - call.RunFn(arguments) - } - - return call.ReturnArguments -} - -/* - 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 { - 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) { - 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 { - var somethingMissing bool - var failedExpectations int - - // iterate through each expectation - expectedCalls := m.expectedCalls() - for _, expectedCall := range expectedCalls { - if !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments) && expectedCall.totalCalls == 0 { - somethingMissing = true - failedExpectations++ - t.Logf("\u274C\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String()) - } else { - m.mutex.Lock() - if expectedCall.Repeatability > 0 { - somethingMissing = true - failedExpectations++ - } else { - t.Logf("\u2705\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String()) - } - m.mutex.Unlock() - } - } - - 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 { - 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 !assert.True(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf("The \"%s\" method should have been called with %d argument(s), but was not.", methodName, len(arguments))) { - t.Logf("%v", m.expectedCalls()) - return false - } - 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 !assert.False(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf("The \"%s\" method was called with %d argument(s), but should NOT have been.", methodName, len(arguments))) { - t.Logf("%v", m.expectedCalls()) - return false - } - 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 { - m.mutex.Lock() - defer m.mutex.Unlock() - return append([]*Call{}, m.ExpectedCalls...) -} - -func (m *Mock) calls() []Call { - m.mutex.Lock() - defer m.mutex.Unlock() - 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 string = "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) - - if reflect.TypeOf(argument).AssignableTo(expectType) { - result := f.fn.Call([]reflect.Value{reflect.ValueOf(argument)}) - 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, -// MathedBy() 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) { - - 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{} - - if len(objects) <= i { - actual = "(Missing)" - } else { - actual = objects[i] - } - - if len(args) <= i { - expected = "(Missing)" - } else { - expected = args[i] - } - - if matcher, ok := expected.(argumentMatcher); ok { - if matcher.Matches(actual) { - output = fmt.Sprintf("%s\t%d: \u2705 %s matched by %s\n", output, i, actual, matcher) - } else { - differences++ - output = fmt.Sprintf("%s\t%d: \u2705 %s not matched by %s\n", output, i, actual, 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: \u274C type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actual) - } - - } else { - - // normal checking - - if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) { - // match - output = fmt.Sprintf("%s\t%d: \u2705 %s == %s\n", output, i, actual, expected) - } else { - // not match - differences++ - output = fmt.Sprintf("%s\t%d: \u274C %s != %s\n", output, i, actual, expected) - } - } - - } - - 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 { - - // 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 { - 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 := spew.Sdump(expected) - a := spew.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 -} diff --git a/vendor/github.com/stretchr/testify/mock/mock_test.go b/vendor/github.com/stretchr/testify/mock/mock_test.go deleted file mode 100644 index 8cb4615d..00000000 --- a/vendor/github.com/stretchr/testify/mock/mock_test.go +++ /dev/null @@ -1,1132 +0,0 @@ -package mock - -import ( - "errors" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "testing" - "time" -) - -/* - 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") -} - -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) 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) -} - -type ExampleFuncType func(string) error - -func (i *TestExampleImplementation) TheExampleMethodFuncType(fn ExampleFuncType) error { - args := i.Called(fn) - return args.Error(0) -} - -/* - 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) - - mockedService. - On("TheExampleMethod", 1, 2, 3). - Return(0). - On("TheExampleMethod3", AnythingOfType("*mock.ExampleType")). - Return(nil) - - expectedCalls := []*Call{ - &Call{ - Parent: &mockedService.Mock, - Method: "TheExampleMethod", - Arguments: []interface{}{1, 2, 3}, - ReturnArguments: []interface{}{0}, - }, - &Call{ - Parent: &mockedService.Mock, - Method: "TheExampleMethod3", - Arguments: []interface{}{AnythingOfType("*mock.ExampleType")}, - ReturnArguments: []interface{}{nil}, - }, - } - 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 Test_Mock_On_WithPtrArgMatcher(t *testing.T) { - var mockedService TestExampleImplementation - - mockedService.On("TheExampleMethod3", - MatchedBy(func(a *ExampleType) bool { return a.ran == true }), - ).Return(nil) - - mockedService.On("TheExampleMethod3", - MatchedBy(func(a *ExampleType) bool { return a.ran == false }), - ).Return(errors.New("error")) - - assert.Equal(t, mockedService.TheExampleMethod3(&ExampleType{true}), nil) - assert.EqualError(t, mockedService.TheExampleMethod3(&ExampleType{false}), "error") -} - -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("string") == fixture1 }), - ).Return(errors.New("fixture1")) - - mockedService.On("TheExampleMethodFunc", - MatchedBy(func(a func(string) error) bool { return a("string") == fixture2 }), - ).Return(errors.New("fixture2")) - - assert.EqualError(t, mockedService.TheExampleMethodFunc( - func(string) error { return fixture1 }), "fixture1") - assert.EqualError(t, mockedService.TheExampleMethodFunc( - func(string) error { return fixture2 }), "fixture2") -} - -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_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")) - -} - -/* - 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, `%!s(int=456) != %!s(int=123)`) - assert.Contains(t, diff, `false != %!s(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, `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 - %!s(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, `%!s(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, `%!s(bool=false) not matched by func(int) bool`) - - diff, count = args.Diff([]interface{}{"string", 123, false}) - assert.Contains(t, diff, `%!s(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)) - -} diff --git a/vendor/github.com/stretchr/testify/package_test.go b/vendor/github.com/stretchr/testify/package_test.go deleted file mode 100644 index 7ac5d6d8..00000000 --- a/vendor/github.com/stretchr/testify/package_test.go +++ /dev/null @@ -1,12 +0,0 @@ -package testify - -import ( - "github.com/stretchr/testify/assert" - "testing" -) - -func TestImports(t *testing.T) { - if assert.Equal(t, 1, 1) != true { - t.Error("Something is wrong.") - } -} diff --git a/vendor/github.com/stretchr/testify/require/doc.go b/vendor/github.com/stretchr/testify/require/doc.go deleted file mode 100644 index 169de392..00000000 --- a/vendor/github.com/stretchr/testify/require/doc.go +++ /dev/null @@ -1,28 +0,0 @@ -// Package require implements the same assertions as the `assert` package but -// stops test execution when a test fails. -// -// Example Usage -// -// The following is a complete example using require in a standard test function: -// import ( -// "testing" -// "github.com/stretchr/testify/require" -// ) -// -// func TestSomething(t *testing.T) { -// -// var a string = "Hello" -// var b string = "Hello" -// -// require.Equal(t, a, b, "The two words should be the same.") -// -// } -// -// Assertions -// -// The `require` package have same global functions as in the `assert` package, -// but instead of returning a boolean result they call `t.FailNow()`. -// -// Every assertion function also takes an optional string message as the final argument, -// allowing custom error messages to be appended to the message the assertion method outputs. -package require diff --git a/vendor/github.com/stretchr/testify/require/forward_requirements.go b/vendor/github.com/stretchr/testify/require/forward_requirements.go deleted file mode 100644 index d3c2ab9b..00000000 --- a/vendor/github.com/stretchr/testify/require/forward_requirements.go +++ /dev/null @@ -1,16 +0,0 @@ -package require - -// Assertions provides assertion methods around the -// TestingT interface. -type Assertions struct { - t TestingT -} - -// New makes a new Assertions object for the specified TestingT. -func New(t TestingT) *Assertions { - return &Assertions{ - t: t, - } -} - -//go:generate go run ../_codegen/main.go -output-package=require -template=require_forward.go.tmpl diff --git a/vendor/github.com/stretchr/testify/require/forward_requirements_test.go b/vendor/github.com/stretchr/testify/require/forward_requirements_test.go deleted file mode 100644 index b120ae3b..00000000 --- a/vendor/github.com/stretchr/testify/require/forward_requirements_test.go +++ /dev/null @@ -1,385 +0,0 @@ -package require - -import ( - "errors" - "testing" - "time" -) - -func TestImplementsWrapper(t *testing.T) { - require := New(t) - - require.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestIsTypeWrapper(t *testing.T) { - require := New(t) - require.IsType(new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.IsType(new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestEqualWrapper(t *testing.T) { - require := New(t) - require.Equal(1, 1) - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.Equal(1, 2) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestNotEqualWrapper(t *testing.T) { - require := New(t) - require.NotEqual(1, 2) - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.NotEqual(2, 2) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestExactlyWrapper(t *testing.T) { - require := New(t) - - a := float32(1) - b := float32(1) - c := float64(1) - - require.Exactly(a, b) - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.Exactly(a, c) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestNotNilWrapper(t *testing.T) { - require := New(t) - require.NotNil(t, new(AssertionTesterConformingObject)) - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.NotNil(nil) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestNilWrapper(t *testing.T) { - require := New(t) - require.Nil(nil) - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.Nil(new(AssertionTesterConformingObject)) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestTrueWrapper(t *testing.T) { - require := New(t) - require.True(true) - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.True(false) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestFalseWrapper(t *testing.T) { - require := New(t) - require.False(false) - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.False(true) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestContainsWrapper(t *testing.T) { - require := New(t) - require.Contains("Hello World", "Hello") - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.Contains("Hello World", "Salut") - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestNotContainsWrapper(t *testing.T) { - require := New(t) - require.NotContains("Hello World", "Hello!") - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.NotContains("Hello World", "Hello") - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestPanicsWrapper(t *testing.T) { - require := New(t) - require.Panics(func() { - panic("Panic!") - }) - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.Panics(func() {}) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestNotPanicsWrapper(t *testing.T) { - require := New(t) - require.NotPanics(func() {}) - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.NotPanics(func() { - panic("Panic!") - }) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestNoErrorWrapper(t *testing.T) { - require := New(t) - require.NoError(nil) - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.NoError(errors.New("some error")) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestErrorWrapper(t *testing.T) { - require := New(t) - require.Error(errors.New("some error")) - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.Error(nil) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestEqualErrorWrapper(t *testing.T) { - require := New(t) - require.EqualError(errors.New("some error"), "some error") - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.EqualError(errors.New("some error"), "Not some error") - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestEmptyWrapper(t *testing.T) { - require := New(t) - require.Empty("") - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.Empty("x") - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestNotEmptyWrapper(t *testing.T) { - require := New(t) - require.NotEmpty("x") - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.NotEmpty("") - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestWithinDurationWrapper(t *testing.T) { - require := New(t) - a := time.Now() - b := a.Add(10 * time.Second) - - require.WithinDuration(a, b, 15*time.Second) - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.WithinDuration(a, b, 5*time.Second) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestInDeltaWrapper(t *testing.T) { - require := New(t) - require.InDelta(1.001, 1, 0.01) - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.InDelta(1, 2, 0.5) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestZeroWrapper(t *testing.T) { - require := New(t) - require.Zero(0) - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.Zero(1) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestNotZeroWrapper(t *testing.T) { - require := New(t) - require.NotZero(1) - - mockT := new(MockT) - mockRequire := New(mockT) - mockRequire.NotZero(0) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEqWrapper_EqualSONString(t *testing.T) { - mockT := new(MockT) - mockRequire := New(mockT) - - mockRequire.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`) - if mockT.Failed { - t.Error("Check should pass") - } -} - -func TestJSONEqWrapper_EquivalentButNotEqual(t *testing.T) { - mockT := new(MockT) - mockRequire := New(mockT) - - mockRequire.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) - if mockT.Failed { - t.Error("Check should pass") - } -} - -func TestJSONEqWrapper_HashOfArraysAndHashes(t *testing.T) { - mockT := new(MockT) - mockRequire := New(mockT) - - mockRequire.JSONEq("{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}", - "{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}") - if mockT.Failed { - t.Error("Check should pass") - } -} - -func TestJSONEqWrapper_Array(t *testing.T) { - mockT := new(MockT) - mockRequire := New(mockT) - - mockRequire.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`) - if mockT.Failed { - t.Error("Check should pass") - } -} - -func TestJSONEqWrapper_HashAndArrayNotEquivalent(t *testing.T) { - mockT := new(MockT) - mockRequire := New(mockT) - - mockRequire.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEqWrapper_HashesNotEquivalent(t *testing.T) { - mockT := new(MockT) - mockRequire := New(mockT) - - mockRequire.JSONEq(`{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEqWrapper_ActualIsNotJSON(t *testing.T) { - mockT := new(MockT) - mockRequire := New(mockT) - - mockRequire.JSONEq(`{"foo": "bar"}`, "Not JSON") - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEqWrapper_ExpectedIsNotJSON(t *testing.T) { - mockT := new(MockT) - mockRequire := New(mockT) - - mockRequire.JSONEq("Not JSON", `{"foo": "bar", "hello": "world"}`) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEqWrapper_ExpectedAndActualNotJSON(t *testing.T) { - mockT := new(MockT) - mockRequire := New(mockT) - - mockRequire.JSONEq("Not JSON", "Not JSON") - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEqWrapper_ArraysOfDifferentOrder(t *testing.T) { - mockT := new(MockT) - mockRequire := New(mockT) - - mockRequire.JSONEq(`["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`) - if !mockT.Failed { - t.Error("Check should fail") - } -} diff --git a/vendor/github.com/stretchr/testify/require/require.go b/vendor/github.com/stretchr/testify/require/require.go deleted file mode 100644 index 1bcfcb0d..00000000 --- a/vendor/github.com/stretchr/testify/require/require.go +++ /dev/null @@ -1,464 +0,0 @@ -/* -* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen -* THIS FILE MUST NOT BE EDITED BY HAND -*/ - -package require - -import ( - - assert "github.com/stretchr/testify/assert" - http "net/http" - url "net/url" - time "time" -) - - -// Condition uses a Comparison to assert a complex condition. -func Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interface{}) { - if !assert.Condition(t, comp, msgAndArgs...) { - t.FailNow() - } -} - - -// Contains asserts that the specified string, list(array, slice...) or map contains the -// specified substring or element. -// -// assert.Contains(t, "Hello World", "World", "But 'Hello World' does contain 'World'") -// assert.Contains(t, ["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'") -// assert.Contains(t, {"Hello": "World"}, "Hello", "But {'Hello': 'World'} does contain 'Hello'") -// -// Returns whether the assertion was successful (true) or not (false). -func Contains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) { - if !assert.Contains(t, s, contains, msgAndArgs...) { - t.FailNow() - } -} - - -// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either -// a slice or a channel with len == 0. -// -// assert.Empty(t, obj) -// -// Returns whether the assertion was successful (true) or not (false). -func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) { - if !assert.Empty(t, object, msgAndArgs...) { - t.FailNow() - } -} - - -// Equal asserts that two objects are equal. -// -// assert.Equal(t, 123, 123, "123 and 123 should be equal") -// -// Returns whether the assertion was successful (true) or not (false). -func Equal(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { - if !assert.Equal(t, expected, actual, msgAndArgs...) { - t.FailNow() - } -} - - -// EqualError asserts that a function returned an error (i.e. not `nil`) -// and that it is equal to the provided error. -// -// actualObj, err := SomeFunction() -// if assert.Error(t, err, "An error was expected") { -// assert.Equal(t, err, expectedError) -// } -// -// Returns whether the assertion was successful (true) or not (false). -func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) { - if !assert.EqualError(t, theError, errString, msgAndArgs...) { - t.FailNow() - } -} - - -// EqualValues asserts that two objects are equal or convertable to the same types -// and equal. -// -// assert.EqualValues(t, uint32(123), int32(123), "123 and 123 should be equal") -// -// Returns whether the assertion was successful (true) or not (false). -func EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { - if !assert.EqualValues(t, expected, actual, msgAndArgs...) { - t.FailNow() - } -} - - -// Error asserts that a function returned an error (i.e. not `nil`). -// -// actualObj, err := SomeFunction() -// if assert.Error(t, err, "An error was expected") { -// assert.Equal(t, err, expectedError) -// } -// -// Returns whether the assertion was successful (true) or not (false). -func Error(t TestingT, err error, msgAndArgs ...interface{}) { - if !assert.Error(t, err, msgAndArgs...) { - t.FailNow() - } -} - - -// Exactly asserts that two objects are equal is value and type. -// -// assert.Exactly(t, int32(123), int64(123), "123 and 123 should NOT be equal") -// -// Returns whether the assertion was successful (true) or not (false). -func Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { - if !assert.Exactly(t, expected, actual, msgAndArgs...) { - t.FailNow() - } -} - - -// Fail reports a failure through -func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) { - if !assert.Fail(t, failureMessage, msgAndArgs...) { - t.FailNow() - } -} - - -// FailNow fails test -func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) { - if !assert.FailNow(t, failureMessage, msgAndArgs...) { - t.FailNow() - } -} - - -// False asserts that the specified value is false. -// -// assert.False(t, myBool, "myBool should be false") -// -// Returns whether the assertion was successful (true) or not (false). -func False(t TestingT, value bool, msgAndArgs ...interface{}) { - if !assert.False(t, value, msgAndArgs...) { - t.FailNow() - } -} - - -// HTTPBodyContains asserts that a specified handler returns a -// body that contains a string. -// -// assert.HTTPBodyContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky") -// -// Returns whether the assertion was successful (true) or not (false). -func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) { - if !assert.HTTPBodyContains(t, handler, method, url, values, str) { - t.FailNow() - } -} - - -// HTTPBodyNotContains asserts that a specified handler returns a -// body that does not contain a string. -// -// assert.HTTPBodyNotContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky") -// -// Returns whether the assertion was successful (true) or not (false). -func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) { - if !assert.HTTPBodyNotContains(t, handler, method, url, values, str) { - t.FailNow() - } -} - - -// HTTPError asserts that a specified handler returns an error status code. -// -// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). -func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values) { - if !assert.HTTPError(t, handler, method, url, values) { - t.FailNow() - } -} - - -// HTTPRedirect asserts that a specified handler returns a redirect status code. -// -// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). -func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values) { - if !assert.HTTPRedirect(t, handler, method, url, values) { - t.FailNow() - } -} - - -// HTTPSuccess asserts that a specified handler returns a success status code. -// -// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) -// -// Returns whether the assertion was successful (true) or not (false). -func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values) { - if !assert.HTTPSuccess(t, handler, method, url, values) { - t.FailNow() - } -} - - -// Implements asserts that an object is implemented by the specified interface. -// -// assert.Implements(t, (*MyInterface)(nil), new(MyObject), "MyObject") -func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { - if !assert.Implements(t, interfaceObject, object, msgAndArgs...) { - t.FailNow() - } -} - - -// InDelta asserts that the two numerals are within delta of each other. -// -// assert.InDelta(t, math.Pi, (22 / 7.0), 0.01) -// -// Returns whether the assertion was successful (true) or not (false). -func InDelta(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { - if !assert.InDelta(t, expected, actual, delta, msgAndArgs...) { - t.FailNow() - } -} - - -// InDeltaSlice is the same as InDelta, except it compares two slices. -func InDeltaSlice(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { - if !assert.InDeltaSlice(t, expected, actual, delta, msgAndArgs...) { - t.FailNow() - } -} - - -// InEpsilon asserts that expected and actual have a relative error less than epsilon -// -// Returns whether the assertion was successful (true) or not (false). -func InEpsilon(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { - if !assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) { - t.FailNow() - } -} - - -// InEpsilonSlice is the same as InEpsilon, except it compares two slices. -func InEpsilonSlice(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { - if !assert.InEpsilonSlice(t, expected, actual, delta, msgAndArgs...) { - t.FailNow() - } -} - - -// IsType asserts that the specified objects are of the same type. -func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) { - if !assert.IsType(t, expectedType, object, msgAndArgs...) { - t.FailNow() - } -} - - -// JSONEq asserts that two JSON strings are equivalent. -// -// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) -// -// Returns whether the assertion was successful (true) or not (false). -func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) { - if !assert.JSONEq(t, expected, actual, msgAndArgs...) { - t.FailNow() - } -} - - -// Len asserts that the specified object has specific length. -// Len also fails if the object has a type that len() not accept. -// -// assert.Len(t, mySlice, 3, "The size of slice is not 3") -// -// Returns whether the assertion was successful (true) or not (false). -func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) { - if !assert.Len(t, object, length, msgAndArgs...) { - t.FailNow() - } -} - - -// Nil asserts that the specified object is nil. -// -// assert.Nil(t, err, "err should be nothing") -// -// Returns whether the assertion was successful (true) or not (false). -func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) { - if !assert.Nil(t, object, msgAndArgs...) { - t.FailNow() - } -} - - -// NoError asserts that a function returned no error (i.e. `nil`). -// -// actualObj, err := SomeFunction() -// if assert.NoError(t, err) { -// assert.Equal(t, actualObj, expectedObj) -// } -// -// Returns whether the assertion was successful (true) or not (false). -func NoError(t TestingT, err error, msgAndArgs ...interface{}) { - if !assert.NoError(t, err, msgAndArgs...) { - t.FailNow() - } -} - - -// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the -// specified substring or element. -// -// assert.NotContains(t, "Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'") -// assert.NotContains(t, ["Hello", "World"], "Earth", "But ['Hello', 'World'] does NOT contain 'Earth'") -// assert.NotContains(t, {"Hello": "World"}, "Earth", "But {'Hello': 'World'} does NOT contain 'Earth'") -// -// Returns whether the assertion was successful (true) or not (false). -func NotContains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) { - if !assert.NotContains(t, s, contains, msgAndArgs...) { - t.FailNow() - } -} - - -// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either -// a slice or a channel with len == 0. -// -// if assert.NotEmpty(t, obj) { -// assert.Equal(t, "two", obj[1]) -// } -// -// Returns whether the assertion was successful (true) or not (false). -func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) { - if !assert.NotEmpty(t, object, msgAndArgs...) { - t.FailNow() - } -} - - -// NotEqual asserts that the specified values are NOT equal. -// -// assert.NotEqual(t, obj1, obj2, "two objects shouldn't be equal") -// -// Returns whether the assertion was successful (true) or not (false). -func NotEqual(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { - if !assert.NotEqual(t, expected, actual, msgAndArgs...) { - t.FailNow() - } -} - - -// NotNil asserts that the specified object is not nil. -// -// assert.NotNil(t, err, "err should be something") -// -// Returns whether the assertion was successful (true) or not (false). -func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) { - if !assert.NotNil(t, object, msgAndArgs...) { - t.FailNow() - } -} - - -// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. -// -// assert.NotPanics(t, func(){ -// RemainCalm() -// }, "Calling RemainCalm() should NOT panic") -// -// Returns whether the assertion was successful (true) or not (false). -func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { - if !assert.NotPanics(t, f, msgAndArgs...) { - t.FailNow() - } -} - - -// NotRegexp asserts that a specified regexp does not match a string. -// -// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") -// assert.NotRegexp(t, "^start", "it's not starting") -// -// Returns whether the assertion was successful (true) or not (false). -func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) { - if !assert.NotRegexp(t, rx, str, msgAndArgs...) { - t.FailNow() - } -} - - -// NotZero asserts that i is not the zero value for its type and returns the truth. -func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) { - if !assert.NotZero(t, i, msgAndArgs...) { - t.FailNow() - } -} - - -// Panics asserts that the code inside the specified PanicTestFunc panics. -// -// assert.Panics(t, func(){ -// GoCrazy() -// }, "Calling GoCrazy() should panic") -// -// Returns whether the assertion was successful (true) or not (false). -func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { - if !assert.Panics(t, f, msgAndArgs...) { - t.FailNow() - } -} - - -// Regexp asserts that a specified regexp matches a string. -// -// assert.Regexp(t, regexp.MustCompile("start"), "it's starting") -// assert.Regexp(t, "start...$", "it's not starting") -// -// Returns whether the assertion was successful (true) or not (false). -func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) { - if !assert.Regexp(t, rx, str, msgAndArgs...) { - t.FailNow() - } -} - - -// True asserts that the specified value is true. -// -// assert.True(t, myBool, "myBool should be true") -// -// Returns whether the assertion was successful (true) or not (false). -func True(t TestingT, value bool, msgAndArgs ...interface{}) { - if !assert.True(t, value, msgAndArgs...) { - t.FailNow() - } -} - - -// WithinDuration asserts that the two times are within duration delta of each other. -// -// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s") -// -// Returns whether the assertion was successful (true) or not (false). -func WithinDuration(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) { - if !assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) { - t.FailNow() - } -} - - -// Zero asserts that i is the zero value for its type and returns the truth. -func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) { - if !assert.Zero(t, i, msgAndArgs...) { - t.FailNow() - } -} diff --git a/vendor/github.com/stretchr/testify/require/require.go.tmpl b/vendor/github.com/stretchr/testify/require/require.go.tmpl deleted file mode 100644 index ab1b1e9f..00000000 --- a/vendor/github.com/stretchr/testify/require/require.go.tmpl +++ /dev/null @@ -1,6 +0,0 @@ -{{.Comment}} -func {{.DocInfo.Name}}(t TestingT, {{.Params}}) { - if !assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { - t.FailNow() - } -} diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go b/vendor/github.com/stretchr/testify/require/require_forward.go deleted file mode 100644 index 58324f10..00000000 --- a/vendor/github.com/stretchr/testify/require/require_forward.go +++ /dev/null @@ -1,388 +0,0 @@ -/* -* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen -* THIS FILE MUST NOT BE EDITED BY HAND -*/ - -package require - -import ( - - assert "github.com/stretchr/testify/assert" - http "net/http" - url "net/url" - time "time" -) - - -// Condition uses a Comparison to assert a complex condition. -func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) { - Condition(a.t, comp, msgAndArgs...) -} - - -// Contains asserts that the specified string, list(array, slice...) or map contains the -// specified substring or element. -// -// a.Contains("Hello World", "World", "But 'Hello World' does contain 'World'") -// a.Contains(["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'") -// a.Contains({"Hello": "World"}, "Hello", "But {'Hello': 'World'} does contain 'Hello'") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) { - Contains(a.t, s, contains, msgAndArgs...) -} - - -// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either -// a slice or a channel with len == 0. -// -// a.Empty(obj) -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) { - Empty(a.t, object, msgAndArgs...) -} - - -// Equal asserts that two objects are equal. -// -// a.Equal(123, 123, "123 and 123 should be equal") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { - Equal(a.t, expected, actual, msgAndArgs...) -} - - -// EqualError asserts that a function returned an error (i.e. not `nil`) -// and that it is equal to the provided error. -// -// actualObj, err := SomeFunction() -// if assert.Error(t, err, "An error was expected") { -// assert.Equal(t, err, expectedError) -// } -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) { - EqualError(a.t, theError, errString, msgAndArgs...) -} - - -// EqualValues asserts that two objects are equal or convertable to the same types -// and equal. -// -// a.EqualValues(uint32(123), int32(123), "123 and 123 should be equal") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { - EqualValues(a.t, expected, actual, msgAndArgs...) -} - - -// Error asserts that a function returned an error (i.e. not `nil`). -// -// actualObj, err := SomeFunction() -// if a.Error(err, "An error was expected") { -// assert.Equal(t, err, expectedError) -// } -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) Error(err error, msgAndArgs ...interface{}) { - Error(a.t, err, msgAndArgs...) -} - - -// Exactly asserts that two objects are equal is value and type. -// -// a.Exactly(int32(123), int64(123), "123 and 123 should NOT be equal") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { - Exactly(a.t, expected, actual, msgAndArgs...) -} - - -// Fail reports a failure through -func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) { - Fail(a.t, failureMessage, msgAndArgs...) -} - - -// FailNow fails test -func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) { - FailNow(a.t, failureMessage, msgAndArgs...) -} - - -// False asserts that the specified value is false. -// -// a.False(myBool, "myBool should be false") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) False(value bool, msgAndArgs ...interface{}) { - False(a.t, value, msgAndArgs...) -} - - -// HTTPBodyContains asserts that a specified handler returns a -// body that contains a string. -// -// a.HTTPBodyContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) { - HTTPBodyContains(a.t, handler, method, url, values, str) -} - - -// HTTPBodyNotContains asserts that a specified handler returns a -// body that does not contain a string. -// -// a.HTTPBodyNotContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) { - HTTPBodyNotContains(a.t, handler, method, url, values, str) -} - - -// HTTPError asserts that a specified handler returns an error status code. -// -// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values) { - HTTPError(a.t, handler, method, url, values) -} - - -// HTTPRedirect asserts that a specified handler returns a redirect status code. -// -// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values) { - HTTPRedirect(a.t, handler, method, url, values) -} - - -// HTTPSuccess asserts that a specified handler returns a success status code. -// -// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values) { - HTTPSuccess(a.t, handler, method, url, values) -} - - -// Implements asserts that an object is implemented by the specified interface. -// -// a.Implements((*MyInterface)(nil), new(MyObject), "MyObject") -func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { - Implements(a.t, interfaceObject, object, msgAndArgs...) -} - - -// InDelta asserts that the two numerals are within delta of each other. -// -// a.InDelta(math.Pi, (22 / 7.0), 0.01) -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { - InDelta(a.t, expected, actual, delta, msgAndArgs...) -} - - -// InDeltaSlice is the same as InDelta, except it compares two slices. -func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { - InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...) -} - - -// InEpsilon asserts that expected and actual have a relative error less than epsilon -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { - InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...) -} - - -// InEpsilonSlice is the same as InEpsilon, except it compares two slices. -func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { - InEpsilonSlice(a.t, expected, actual, delta, msgAndArgs...) -} - - -// IsType asserts that the specified objects are of the same type. -func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) { - IsType(a.t, expectedType, object, msgAndArgs...) -} - - -// JSONEq asserts that two JSON strings are equivalent. -// -// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) { - JSONEq(a.t, expected, actual, msgAndArgs...) -} - - -// Len asserts that the specified object has specific length. -// Len also fails if the object has a type that len() not accept. -// -// a.Len(mySlice, 3, "The size of slice is not 3") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) { - Len(a.t, object, length, msgAndArgs...) -} - - -// Nil asserts that the specified object is nil. -// -// a.Nil(err, "err should be nothing") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) { - Nil(a.t, object, msgAndArgs...) -} - - -// NoError asserts that a function returned no error (i.e. `nil`). -// -// actualObj, err := SomeFunction() -// if a.NoError(err) { -// assert.Equal(t, actualObj, expectedObj) -// } -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) { - NoError(a.t, err, msgAndArgs...) -} - - -// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the -// specified substring or element. -// -// a.NotContains("Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'") -// a.NotContains(["Hello", "World"], "Earth", "But ['Hello', 'World'] does NOT contain 'Earth'") -// a.NotContains({"Hello": "World"}, "Earth", "But {'Hello': 'World'} does NOT contain 'Earth'") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) { - NotContains(a.t, s, contains, msgAndArgs...) -} - - -// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either -// a slice or a channel with len == 0. -// -// if a.NotEmpty(obj) { -// assert.Equal(t, "two", obj[1]) -// } -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) { - NotEmpty(a.t, object, msgAndArgs...) -} - - -// NotEqual asserts that the specified values are NOT equal. -// -// a.NotEqual(obj1, obj2, "two objects shouldn't be equal") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { - NotEqual(a.t, expected, actual, msgAndArgs...) -} - - -// NotNil asserts that the specified object is not nil. -// -// a.NotNil(err, "err should be something") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) { - NotNil(a.t, object, msgAndArgs...) -} - - -// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. -// -// a.NotPanics(func(){ -// RemainCalm() -// }, "Calling RemainCalm() should NOT panic") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { - NotPanics(a.t, f, msgAndArgs...) -} - - -// NotRegexp asserts that a specified regexp does not match a string. -// -// a.NotRegexp(regexp.MustCompile("starts"), "it's starting") -// a.NotRegexp("^start", "it's not starting") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) { - NotRegexp(a.t, rx, str, msgAndArgs...) -} - - -// NotZero asserts that i is not the zero value for its type and returns the truth. -func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) { - NotZero(a.t, i, msgAndArgs...) -} - - -// Panics asserts that the code inside the specified PanicTestFunc panics. -// -// a.Panics(func(){ -// GoCrazy() -// }, "Calling GoCrazy() should panic") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { - Panics(a.t, f, msgAndArgs...) -} - - -// Regexp asserts that a specified regexp matches a string. -// -// a.Regexp(regexp.MustCompile("start"), "it's starting") -// a.Regexp("start...$", "it's not starting") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) { - Regexp(a.t, rx, str, msgAndArgs...) -} - - -// True asserts that the specified value is true. -// -// a.True(myBool, "myBool should be true") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) True(value bool, msgAndArgs ...interface{}) { - True(a.t, value, msgAndArgs...) -} - - -// WithinDuration asserts that the two times are within duration delta of each other. -// -// a.WithinDuration(time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s") -// -// Returns whether the assertion was successful (true) or not (false). -func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) { - WithinDuration(a.t, expected, actual, delta, msgAndArgs...) -} - - -// Zero asserts that i is the zero value for its type and returns the truth. -func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) { - Zero(a.t, i, msgAndArgs...) -} diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl b/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl deleted file mode 100644 index b93569e0..00000000 --- a/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl +++ /dev/null @@ -1,4 +0,0 @@ -{{.CommentWithoutT "a"}} -func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) { - {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) -} diff --git a/vendor/github.com/stretchr/testify/require/requirements.go b/vendor/github.com/stretchr/testify/require/requirements.go deleted file mode 100644 index 41147562..00000000 --- a/vendor/github.com/stretchr/testify/require/requirements.go +++ /dev/null @@ -1,9 +0,0 @@ -package require - -// TestingT is an interface wrapper around *testing.T -type TestingT interface { - Errorf(format string, args ...interface{}) - FailNow() -} - -//go:generate go run ../_codegen/main.go -output-package=require -template=require.go.tmpl diff --git a/vendor/github.com/stretchr/testify/require/requirements_test.go b/vendor/github.com/stretchr/testify/require/requirements_test.go deleted file mode 100644 index d2ccc99c..00000000 --- a/vendor/github.com/stretchr/testify/require/requirements_test.go +++ /dev/null @@ -1,369 +0,0 @@ -package require - -import ( - "errors" - "testing" - "time" -) - -// AssertionTesterInterface defines an interface to be used for testing assertion methods -type AssertionTesterInterface interface { - TestMethod() -} - -// AssertionTesterConformingObject is an object that conforms to the AssertionTesterInterface interface -type AssertionTesterConformingObject struct { -} - -func (a *AssertionTesterConformingObject) TestMethod() { -} - -// AssertionTesterNonConformingObject is an object that does not conform to the AssertionTesterInterface interface -type AssertionTesterNonConformingObject struct { -} - -type MockT struct { - Failed bool -} - -func (t *MockT) FailNow() { - t.Failed = true -} - -func (t *MockT) Errorf(format string, args ...interface{}) { - _, _ = format, args -} - -func TestImplements(t *testing.T) { - - Implements(t, (*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject)) - - mockT := new(MockT) - Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject)) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestIsType(t *testing.T) { - - IsType(t, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject)) - - mockT := new(MockT) - IsType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject)) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestEqual(t *testing.T) { - - Equal(t, 1, 1) - - mockT := new(MockT) - Equal(mockT, 1, 2) - if !mockT.Failed { - t.Error("Check should fail") - } - -} - -func TestNotEqual(t *testing.T) { - - NotEqual(t, 1, 2) - mockT := new(MockT) - NotEqual(mockT, 2, 2) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestExactly(t *testing.T) { - - a := float32(1) - b := float32(1) - c := float64(1) - - Exactly(t, a, b) - - mockT := new(MockT) - Exactly(mockT, a, c) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestNotNil(t *testing.T) { - - NotNil(t, new(AssertionTesterConformingObject)) - - mockT := new(MockT) - NotNil(mockT, nil) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestNil(t *testing.T) { - - Nil(t, nil) - - mockT := new(MockT) - Nil(mockT, new(AssertionTesterConformingObject)) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestTrue(t *testing.T) { - - True(t, true) - - mockT := new(MockT) - True(mockT, false) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestFalse(t *testing.T) { - - False(t, false) - - mockT := new(MockT) - False(mockT, true) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestContains(t *testing.T) { - - Contains(t, "Hello World", "Hello") - - mockT := new(MockT) - Contains(mockT, "Hello World", "Salut") - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestNotContains(t *testing.T) { - - NotContains(t, "Hello World", "Hello!") - - mockT := new(MockT) - NotContains(mockT, "Hello World", "Hello") - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestPanics(t *testing.T) { - - Panics(t, func() { - panic("Panic!") - }) - - mockT := new(MockT) - Panics(mockT, func() {}) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestNotPanics(t *testing.T) { - - NotPanics(t, func() {}) - - mockT := new(MockT) - NotPanics(mockT, func() { - panic("Panic!") - }) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestNoError(t *testing.T) { - - NoError(t, nil) - - mockT := new(MockT) - NoError(mockT, errors.New("some error")) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestError(t *testing.T) { - - Error(t, errors.New("some error")) - - mockT := new(MockT) - Error(mockT, nil) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestEqualError(t *testing.T) { - - EqualError(t, errors.New("some error"), "some error") - - mockT := new(MockT) - EqualError(mockT, errors.New("some error"), "Not some error") - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestEmpty(t *testing.T) { - - Empty(t, "") - - mockT := new(MockT) - Empty(mockT, "x") - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestNotEmpty(t *testing.T) { - - NotEmpty(t, "x") - - mockT := new(MockT) - NotEmpty(mockT, "") - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestWithinDuration(t *testing.T) { - - a := time.Now() - b := a.Add(10 * time.Second) - - WithinDuration(t, a, b, 15*time.Second) - - mockT := new(MockT) - WithinDuration(mockT, a, b, 5*time.Second) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestInDelta(t *testing.T) { - - InDelta(t, 1.001, 1, 0.01) - - mockT := new(MockT) - InDelta(mockT, 1, 2, 0.5) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestZero(t *testing.T) { - - Zero(t, "") - - mockT := new(MockT) - Zero(mockT, "x") - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestNotZero(t *testing.T) { - - NotZero(t, "x") - - mockT := new(MockT) - NotZero(mockT, "") - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEq_EqualSONString(t *testing.T) { - mockT := new(MockT) - JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`) - if mockT.Failed { - t.Error("Check should pass") - } -} - -func TestJSONEq_EquivalentButNotEqual(t *testing.T) { - mockT := new(MockT) - JSONEq(mockT, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) - if mockT.Failed { - t.Error("Check should pass") - } -} - -func TestJSONEq_HashOfArraysAndHashes(t *testing.T) { - mockT := new(MockT) - JSONEq(mockT, "{\r\n\t\"numeric\": 1.5,\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]],\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\"\r\n}", - "{\r\n\t\"numeric\": 1.5,\r\n\t\"hash\": {\"nested\": \"hash\", \"nested_slice\": [\"this\", \"is\", \"nested\"]},\r\n\t\"string\": \"foo\",\r\n\t\"array\": [{\"foo\": \"bar\"}, 1, \"string\", [\"nested\", \"array\", 5.5]]\r\n}") - if mockT.Failed { - t.Error("Check should pass") - } -} - -func TestJSONEq_Array(t *testing.T) { - mockT := new(MockT) - JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `["foo", {"nested": "hash", "hello": "world"}]`) - if mockT.Failed { - t.Error("Check should pass") - } -} - -func TestJSONEq_HashAndArrayNotEquivalent(t *testing.T) { - mockT := new(MockT) - JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `{"foo": "bar", {"nested": "hash", "hello": "world"}}`) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEq_HashesNotEquivalent(t *testing.T) { - mockT := new(MockT) - JSONEq(mockT, `{"foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEq_ActualIsNotJSON(t *testing.T) { - mockT := new(MockT) - JSONEq(mockT, `{"foo": "bar"}`, "Not JSON") - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEq_ExpectedIsNotJSON(t *testing.T) { - mockT := new(MockT) - JSONEq(mockT, "Not JSON", `{"foo": "bar", "hello": "world"}`) - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEq_ExpectedAndActualNotJSON(t *testing.T) { - mockT := new(MockT) - JSONEq(mockT, "Not JSON", "Not JSON") - if !mockT.Failed { - t.Error("Check should fail") - } -} - -func TestJSONEq_ArraysOfDifferentOrder(t *testing.T) { - mockT := new(MockT) - JSONEq(mockT, `["foo", {"hello": "world", "nested": "hash"}]`, `[{ "hello": "world", "nested": "hash"}, "foo"]`) - if !mockT.Failed { - t.Error("Check should fail") - } -} diff --git a/vendor/github.com/stretchr/testify/suite/doc.go b/vendor/github.com/stretchr/testify/suite/doc.go deleted file mode 100644 index f91a245d..00000000 --- a/vendor/github.com/stretchr/testify/suite/doc.go +++ /dev/null @@ -1,65 +0,0 @@ -// Package suite contains logic for creating testing suite structs -// and running the methods on those structs as tests. The most useful -// piece of this package is that you can create setup/teardown methods -// on your testing suites, which will run before/after the whole suite -// or individual tests (depending on which interface(s) you -// implement). -// -// A testing suite is usually built by first extending the built-in -// suite functionality from suite.Suite in testify. Alternatively, -// you could reproduce that logic on your own if you wanted (you -// just need to implement the TestingSuite interface from -// suite/interfaces.go). -// -// After that, you can implement any of the interfaces in -// suite/interfaces.go to add setup/teardown functionality to your -// suite, and add any methods that start with "Test" to add tests. -// Methods that do not match any suite interfaces and do not begin -// with "Test" will not be run by testify, and can safely be used as -// helper methods. -// -// Once you've built your testing suite, you need to run the suite -// (using suite.Run from testify) inside any function that matches the -// identity that "go test" is already looking for (i.e. -// func(*testing.T)). -// -// Regular expression to select test suites specified command-line -// argument "-run". Regular expression to select the methods -// of test suites specified command-line argument "-m". -// Suite object has assertion methods. -// -// A crude example: -// // Basic imports -// import ( -// "testing" -// "github.com/stretchr/testify/assert" -// "github.com/stretchr/testify/suite" -// ) -// -// // Define the suite, and absorb the built-in basic suite -// // functionality from testify - including a T() method which -// // returns the current testing context -// type ExampleTestSuite struct { -// suite.Suite -// VariableThatShouldStartAtFive int -// } -// -// // Make sure that VariableThatShouldStartAtFive is set to five -// // before each test -// func (suite *ExampleTestSuite) SetupTest() { -// suite.VariableThatShouldStartAtFive = 5 -// } -// -// // All methods that begin with "Test" are run as tests within a -// // suite. -// func (suite *ExampleTestSuite) TestExample() { -// assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive) -// suite.Equal(5, suite.VariableThatShouldStartAtFive) -// } -// -// // In order for 'go test' to run this suite, we need to create -// // a normal test function and pass our suite to suite.Run -// func TestExampleTestSuite(t *testing.T) { -// suite.Run(t, new(ExampleTestSuite)) -// } -package suite diff --git a/vendor/github.com/stretchr/testify/suite/interfaces.go b/vendor/github.com/stretchr/testify/suite/interfaces.go deleted file mode 100644 index 20969472..00000000 --- a/vendor/github.com/stretchr/testify/suite/interfaces.go +++ /dev/null @@ -1,34 +0,0 @@ -package suite - -import "testing" - -// TestingSuite can store and return the current *testing.T context -// generated by 'go test'. -type TestingSuite interface { - T() *testing.T - SetT(*testing.T) -} - -// SetupAllSuite has a SetupSuite method, which will run before the -// tests in the suite are run. -type SetupAllSuite interface { - SetupSuite() -} - -// SetupTestSuite has a SetupTest method, which will run before each -// test in the suite. -type SetupTestSuite interface { - SetupTest() -} - -// TearDownAllSuite has a TearDownSuite method, which will run after -// all the tests in the suite have been run. -type TearDownAllSuite interface { - TearDownSuite() -} - -// TearDownTestSuite has a TearDownTest method, which will run after -// each test in the suite. -type TearDownTestSuite interface { - TearDownTest() -} diff --git a/vendor/github.com/stretchr/testify/suite/suite.go b/vendor/github.com/stretchr/testify/suite/suite.go deleted file mode 100644 index db741300..00000000 --- a/vendor/github.com/stretchr/testify/suite/suite.go +++ /dev/null @@ -1,115 +0,0 @@ -package suite - -import ( - "flag" - "fmt" - "os" - "reflect" - "regexp" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -var matchMethod = flag.String("testify.m", "", "regular expression to select tests of the testify suite to run") - -// Suite is a basic testing suite with methods for storing and -// retrieving the current *testing.T context. -type Suite struct { - *assert.Assertions - require *require.Assertions - t *testing.T -} - -// T retrieves the current *testing.T context. -func (suite *Suite) T() *testing.T { - return suite.t -} - -// SetT sets the current *testing.T context. -func (suite *Suite) SetT(t *testing.T) { - suite.t = t - suite.Assertions = assert.New(t) - suite.require = require.New(t) -} - -// Require returns a require context for suite. -func (suite *Suite) Require() *require.Assertions { - if suite.require == nil { - suite.require = require.New(suite.T()) - } - return suite.require -} - -// Assert returns an assert context for suite. Normally, you can call -// `suite.NoError(expected, actual)`, but for situations where the embedded -// methods are overridden (for example, you might want to override -// assert.Assertions with require.Assertions), this method is provided so you -// can call `suite.Assert().NoError()`. -func (suite *Suite) Assert() *assert.Assertions { - if suite.Assertions == nil { - suite.Assertions = assert.New(suite.T()) - } - return suite.Assertions -} - -// Run takes a testing suite and runs all of the tests attached -// to it. -func Run(t *testing.T, suite TestingSuite) { - suite.SetT(t) - - if setupAllSuite, ok := suite.(SetupAllSuite); ok { - setupAllSuite.SetupSuite() - } - defer func() { - if tearDownAllSuite, ok := suite.(TearDownAllSuite); ok { - tearDownAllSuite.TearDownSuite() - } - }() - - methodFinder := reflect.TypeOf(suite) - tests := []testing.InternalTest{} - for index := 0; index < methodFinder.NumMethod(); index++ { - method := methodFinder.Method(index) - ok, err := methodFilter(method.Name) - if err != nil { - fmt.Fprintf(os.Stderr, "testify: invalid regexp for -m: %s\n", err) - os.Exit(1) - } - if ok { - test := testing.InternalTest{ - Name: method.Name, - F: func(t *testing.T) { - parentT := suite.T() - suite.SetT(t) - if setupTestSuite, ok := suite.(SetupTestSuite); ok { - setupTestSuite.SetupTest() - } - defer func() { - if tearDownTestSuite, ok := suite.(TearDownTestSuite); ok { - tearDownTestSuite.TearDownTest() - } - suite.SetT(parentT) - }() - method.Func.Call([]reflect.Value{reflect.ValueOf(suite)}) - }, - } - tests = append(tests, test) - } - } - - if !testing.RunTests(func(_, _ string) (bool, error) { return true, nil }, - tests) { - t.Fail() - } -} - -// Filtering method according to set regular expression -// specified command-line argument -m -func methodFilter(name string) (bool, error) { - if ok, _ := regexp.MatchString("^Test", name); !ok { - return false, nil - } - return regexp.MatchString(*matchMethod, name) -} diff --git a/vendor/github.com/stretchr/testify/suite/suite_test.go b/vendor/github.com/stretchr/testify/suite/suite_test.go deleted file mode 100644 index c7c4e88f..00000000 --- a/vendor/github.com/stretchr/testify/suite/suite_test.go +++ /dev/null @@ -1,239 +0,0 @@ -package suite - -import ( - "errors" - "io/ioutil" - "os" - "testing" - - "github.com/stretchr/testify/assert" -) - -// SuiteRequireTwice is intended to test the usage of suite.Require in two -// different tests -type SuiteRequireTwice struct{ Suite } - -// TestSuiteRequireTwice checks for regressions of issue #149 where -// suite.requirements was not initialised in suite.SetT() -// A regression would result on these tests panicking rather than failing. -func TestSuiteRequireTwice(t *testing.T) { - ok := testing.RunTests( - func(_, _ string) (bool, error) { return true, nil }, - []testing.InternalTest{{ - Name: "TestSuiteRequireTwice", - F: func(t *testing.T) { - suite := new(SuiteRequireTwice) - Run(t, suite) - }, - }}, - ) - assert.Equal(t, false, ok) -} - -func (s *SuiteRequireTwice) TestRequireOne() { - r := s.Require() - r.Equal(1, 2) -} - -func (s *SuiteRequireTwice) TestRequireTwo() { - r := s.Require() - r.Equal(1, 2) -} - -// This suite is intended to store values to make sure that only -// testing-suite-related methods are run. It's also a fully -// functional example of a testing suite, using setup/teardown methods -// and a helper method that is ignored by testify. To make this look -// more like a real world example, all tests in the suite perform some -// type of assertion. -type SuiteTester struct { - // Include our basic suite logic. - Suite - - // Keep counts of how many times each method is run. - SetupSuiteRunCount int - TearDownSuiteRunCount int - SetupTestRunCount int - TearDownTestRunCount int - TestOneRunCount int - TestTwoRunCount int - NonTestMethodRunCount int -} - -type SuiteSkipTester struct { - // Include our basic suite logic. - Suite - - // Keep counts of how many times each method is run. - SetupSuiteRunCount int - TearDownSuiteRunCount int -} - -// The SetupSuite method will be run by testify once, at the very -// start of the testing suite, before any tests are run. -func (suite *SuiteTester) SetupSuite() { - suite.SetupSuiteRunCount++ -} - -func (suite *SuiteSkipTester) SetupSuite() { - suite.SetupSuiteRunCount++ - suite.T().Skip() -} - -// The TearDownSuite method will be run by testify once, at the very -// end of the testing suite, after all tests have been run. -func (suite *SuiteTester) TearDownSuite() { - suite.TearDownSuiteRunCount++ -} - -func (suite *SuiteSkipTester) TearDownSuite() { - suite.TearDownSuiteRunCount++ -} - -// The SetupTest method will be run before every test in the suite. -func (suite *SuiteTester) SetupTest() { - suite.SetupTestRunCount++ -} - -// The TearDownTest method will be run after every test in the suite. -func (suite *SuiteTester) TearDownTest() { - suite.TearDownTestRunCount++ -} - -// Every method in a testing suite that begins with "Test" will be run -// as a test. TestOne is an example of a test. For the purposes of -// this example, we've included assertions in the tests, since most -// tests will issue assertions. -func (suite *SuiteTester) TestOne() { - beforeCount := suite.TestOneRunCount - suite.TestOneRunCount++ - assert.Equal(suite.T(), suite.TestOneRunCount, beforeCount+1) - suite.Equal(suite.TestOneRunCount, beforeCount+1) -} - -// TestTwo is another example of a test. -func (suite *SuiteTester) TestTwo() { - beforeCount := suite.TestTwoRunCount - suite.TestTwoRunCount++ - assert.NotEqual(suite.T(), suite.TestTwoRunCount, beforeCount) - suite.NotEqual(suite.TestTwoRunCount, beforeCount) -} - -func (suite *SuiteTester) TestSkip() { - suite.T().Skip() -} - -// NonTestMethod does not begin with "Test", so it will not be run by -// testify as a test in the suite. This is useful for creating helper -// methods for your tests. -func (suite *SuiteTester) NonTestMethod() { - suite.NonTestMethodRunCount++ -} - -// TestRunSuite will be run by the 'go test' command, so within it, we -// can run our suite using the Run(*testing.T, TestingSuite) function. -func TestRunSuite(t *testing.T) { - suiteTester := new(SuiteTester) - Run(t, suiteTester) - - // Normally, the test would end here. The following are simply - // some assertions to ensure that the Run function is working as - // intended - they are not part of the example. - - // The suite was only run once, so the SetupSuite and TearDownSuite - // methods should have each been run only once. - assert.Equal(t, suiteTester.SetupSuiteRunCount, 1) - assert.Equal(t, suiteTester.TearDownSuiteRunCount, 1) - - // There are three test methods (TestOne, TestTwo, and TestSkip), so - // the SetupTest and TearDownTest methods (which should be run once for - // each test) should have been run three times. - assert.Equal(t, suiteTester.SetupTestRunCount, 3) - assert.Equal(t, suiteTester.TearDownTestRunCount, 3) - - // Each test should have been run once. - assert.Equal(t, suiteTester.TestOneRunCount, 1) - assert.Equal(t, suiteTester.TestTwoRunCount, 1) - - // Methods that don't match the test method identifier shouldn't - // have been run at all. - assert.Equal(t, suiteTester.NonTestMethodRunCount, 0) - - suiteSkipTester := new(SuiteSkipTester) - Run(t, suiteSkipTester) - - // The suite was only run once, so the SetupSuite and TearDownSuite - // methods should have each been run only once, even though SetupSuite - // called Skip() - assert.Equal(t, suiteSkipTester.SetupSuiteRunCount, 1) - assert.Equal(t, suiteSkipTester.TearDownSuiteRunCount, 1) - -} - -func TestSuiteGetters(t *testing.T) { - suite := new(SuiteTester) - suite.SetT(t) - assert.NotNil(t, suite.Assert()) - assert.Equal(t, suite.Assertions, suite.Assert()) - assert.NotNil(t, suite.Require()) - assert.Equal(t, suite.require, suite.Require()) -} - -type SuiteLoggingTester struct { - Suite -} - -func (s *SuiteLoggingTester) TestLoggingPass() { - s.T().Log("TESTLOGPASS") -} - -func (s *SuiteLoggingTester) TestLoggingFail() { - s.T().Log("TESTLOGFAIL") - assert.NotNil(s.T(), nil) // expected to fail -} - -type StdoutCapture struct { - oldStdout *os.File - readPipe *os.File -} - -func (sc *StdoutCapture) StartCapture() { - sc.oldStdout = os.Stdout - sc.readPipe, os.Stdout, _ = os.Pipe() -} - -func (sc *StdoutCapture) StopCapture() (string, error) { - if sc.oldStdout == nil || sc.readPipe == nil { - return "", errors.New("StartCapture not called before StopCapture") - } - os.Stdout.Close() - os.Stdout = sc.oldStdout - bytes, err := ioutil.ReadAll(sc.readPipe) - if err != nil { - return "", err - } - return string(bytes), nil -} - -func TestSuiteLogging(t *testing.T) { - testT := testing.T{} - - suiteLoggingTester := new(SuiteLoggingTester) - - capture := StdoutCapture{} - capture.StartCapture() - Run(&testT, suiteLoggingTester) - output, err := capture.StopCapture() - - assert.Nil(t, err, "Got an error trying to capture stdout!") - - // Failed tests' output is always printed - assert.Contains(t, output, "TESTLOGFAIL") - - if testing.Verbose() { - // In verbose mode, output from successful tests is also printed - assert.Contains(t, output, "TESTLOGPASS") - } else { - assert.NotContains(t, output, "TESTLOGPASS") - } -} diff --git a/vendor/github.com/tidwall/boxtree/LICENSE b/vendor/github.com/tidwall/boxtree/LICENSE new file mode 100644 index 00000000..3a6c0261 --- /dev/null +++ b/vendor/github.com/tidwall/boxtree/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018 Josh Baker + +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. \ No newline at end of file diff --git a/vendor/github.com/tidwall/boxtree/README.md b/vendor/github.com/tidwall/boxtree/README.md new file mode 100644 index 00000000..e08328d3 --- /dev/null +++ b/vendor/github.com/tidwall/boxtree/README.md @@ -0,0 +1,94 @@ +# `BoxTree` + +[![GoDoc](https://godoc.org/github.com/tidwall/boxtree?status.svg)](https://godoc.org/github.com/tidwall/boxtree) + +**EXPERIMENTAL** + +This package provides an in-memory R-Tree implementation for Go. It's designed +for [Tile38](https://github.com/tidwall/tile38). + +Cities + +## Features + +- Support for 2 and 3 dimensions +- Optimized for fast box inserts and replacements. + +## Usage + +### Installing + +To start using BoxTree, install Go and run `go get`: + +```sh +$ go get -u github.com/tidwall/boxtree +``` + +### Basic operations + +```go +// create a 2D BoxTree +tr := boxtree.New(2) + +// insert a point +tr.Insert([]float64{-112.0078, 33.4373}, nil, "PHX") + +// insert a box +tr.Insert([]float64{10, 10}, []float64{20, 20}, "rect") + +// search +tr.Search([]float64{-112.1, 33.4}, []float64{-112.0, 33.5}, + func(min, max []float64, value interface{}) bool { + println(value.(string)) // prints "PHX" + }, +) + +// delete +tr.Delete([]float64{-112.0078, 33.4373}, []float64{-112.0078, 33.4373}, "PHX") +``` + +## Algorithms + +This implementation is a variant of the original paper: +[R-TREES. A DYNAMIC INDEX STRUCTURE FOR SPATIAL SEARCHING](http://www-db.deis.unibo.it/courses/SI-LS/papers/Gut84.pdf) + +### Inserting + +Same as the original algorithm. From the root to the leaf, the boxes which will incur the least enlargment are chosen. Ties go to boxes with the smallest area. + +### Deleting + +Same as the original algorithm. A target box is deleted directly. When the number of children in a box falls below it's minumum entries, it is removed from the tree and it's items are re-inserted. + +### Splitting + +This is a custom algorithm. +It attempts to minimize intensive operations such as pre-sorting the children and comparing overlaps & area sizes. +The desire is to do simple single axis distance calculations each child only once, with a target 50/50 chance that the child might be moved in-memory. + +When a box has reached it's max number of entries it's largest axis is calculated and the box is split into two smaller boxes, named `left` and `right`. +Each child boxes is then evaluated to determine which smaller box it should be placed into. +Two values, `min-dist` and `max-dist`, are calcuated for each child. + +- `min-dist` is the distance from the parent's minumum value of it's largest axis to the child's minumum value of the parent largest axis. +- `max-dist` is the distance from the parent's maximum value of it's largest axis to the child's maximum value of the parent largest axis. + +When the `min-dist` is less than `max-dist` then the child is placed into the `left` box. +When the `max-dist` is less than `min-dist` then the child is placed into the `right` box. +When the `min-dist` is equal to `max-dist` then the child is placed into an `equal` bucket until all of the children are evaluated. +Each `equal` box is then one-by-one placed in either `left` or `right`, whichever has less children. + + +## Performance + +In my testing: + +- Insert show similar performance as the quadratic R-tree and ~1.2x - 1.5x faster than R*tree. +- Search and Delete is ~1.5x - 2x faster than quadratic and about the same as R*tree. + +I hope to provide more details in the future. + +## License + +`BoxTree` source code is available under the MIT License. + diff --git a/vendor/github.com/tidwall/boxtree/boxtree.go b/vendor/github.com/tidwall/boxtree/boxtree.go new file mode 100644 index 00000000..d218a048 --- /dev/null +++ b/vendor/github.com/tidwall/boxtree/boxtree.go @@ -0,0 +1,36 @@ +package boxtree + +import ( + "github.com/tidwall/boxtree/d2" + "github.com/tidwall/boxtree/d3" +) + +// BoxTree is an rtree by a different name +type BoxTree interface { + Insert(min, max []float64, value interface{}) + Delete(min, max []float64, value interface{}) + Search(min, max []float64, + iter func(min, max []float64, value interface{}) bool, + ) + TotalOverlapArea() float64 + Traverse(iter func(min, max []float64, height, level int, + value interface{}) int) + Scan(iter func(min, max []float64, value interface{}) bool) + Nearby(min, max []float64, + iter func(min, max []float64, item interface{}) bool, + ) + Bounds() (min, max []float64) + Count() int +} + +// New returns are new BoxTree, only 2 dims are allows +func New(dims int) BoxTree { + switch dims { + default: + panic("invalid dimensions") + case 2: + return new(d2.BoxTree) + case 3: + return new(d3.BoxTree) + } +} diff --git a/vendor/github.com/tidwall/boxtree/boxtree_test.go b/vendor/github.com/tidwall/boxtree/boxtree_test.go new file mode 100644 index 00000000..8eaa42a5 --- /dev/null +++ b/vendor/github.com/tidwall/boxtree/boxtree_test.go @@ -0,0 +1,125 @@ +package boxtree + +import ( + "fmt" + "math/rand" + "os" + "testing" + "time" + + "github.com/tidwall/lotsa" +) + +func TestBoxTree(t *testing.T) { + New(2) + New(3) + defer func() { + s := recover().(string) + if s != "invalid dimensions" { + t.Fatalf("expected '%s', got '%s'", "invalid dimensions", s) + } + }() + New(4) + // there are more test in the d2/d3 directories +} +func TestBenchInsert2D(t *testing.T) { + testBenchInsert(t, 100000, 2) +} + +func TestBenchInsert3D(t *testing.T) { + testBenchInsert(t, 100000, 3) +} + +func testBenchInsert(t *testing.T, N, D int) { + rand.Seed(time.Now().UnixNano()) + points := make([]float64, N*D) + for i := 0; i < N; i++ { + for j := 0; j < D; j++ { + points[i*D+j] = rand.Float64()*100 - 50 + } + } + tr := New(D) + lotsa.Output = os.Stdout + fmt.Printf("Insert(%dD): ", D) + lotsa.Ops(N, 1, func(i, _ int) { + tr.Insert(points[i*D+0:i*D+D], nil, i) + }) + fmt.Printf("Search(%dD): ", D) + var count int + lotsa.Ops(N, 1, func(i, _ int) { + tr.Search(points[i*D+0:i*D+D], points[i*D+0:i*D+D], + func(min, max []float64, value interface{}) bool { + count++ + return true + }, + ) + }) + if count != N { + t.Fatalf("expected %d, got %d", N, count) + } + fmt.Printf("Delete(%dD): ", D) + lotsa.Ops(N, 1, func(i, _ int) { + tr.Delete(points[i*D+0:i*D+D], points[i*D+0:i*D+D], i) + }) + if tr.Count() != 0 { + t.Fatalf("expected %d, got %d", N, tr.Count()) + } +} + +type tItem2 struct { + point [2]float64 +} + +func (item *tItem2) Point() (x, y float64) { + return item.point[0], item.point[1] +} +func (item *tItem2) Rect() (minX, minY, maxX, maxY float64) { + return item.point[0], item.point[1], item.point[0], item.point[1] +} + +/////////////////////////////////////////////// +// Old Tile38 Index < July 27, 2018 +/////////////////////////////////////////////// +// func TestBenchInsert2D_Old(t *testing.T) { +// // import "github.com/tidwall/tile38/pkg/index" +// N := 100000 +// D := 2 +// rand.Seed(time.Now().UnixNano()) +// items := make([]*tItem2, N*D) +// for i := 0; i < N; i++ { +// items[i] = new(tItem2) +// for j := 0; j < D; j++ { +// items[i].point[j] = rand.Float64()*100 - 50 +// } +// } + +// tr := index.New() +// lotsa.Output = os.Stdout +// fmt.Printf("Insert(%dD): ", D) +// lotsa.Ops(N, 1, func(i, _ int) { +// tr.Insert(items[i]) +// }) +// fmt.Printf("Search(%dD): ", D) +// var count int +// lotsa.Ops(N, 1, func(i, _ int) { +// tr.Search( +// items[i].point[0], items[i].point[1], +// items[i].point[0], items[i].point[1], +// func(_ interface{}) bool { +// count++ +// return true +// }, +// ) +// }) +// if count != N { +// t.Fatalf("expected %d, got %d", N, count) +// } +// fmt.Printf("Delete(%dD): ", D) +// lotsa.Ops(N, 1, func(i, _ int) { +// tr.Remove(items[i]) +// }) +// if tr.Count() != 0 { +// t.Fatalf("expected %d, got %d", N, tr.Count()) +// } + +// } diff --git a/vendor/github.com/tidwall/boxtree/d2/boxtree.go b/vendor/github.com/tidwall/boxtree/d2/boxtree.go new file mode 100644 index 00000000..47c63e6a --- /dev/null +++ b/vendor/github.com/tidwall/boxtree/d2/boxtree.go @@ -0,0 +1,707 @@ +package d2 + +const dims = 2 + +const ( + maxEntries = 16 + minEntries = maxEntries * 40 / 100 +) + +type box struct { + data interface{} + min, max [dims]float64 +} + +type node struct { + count int + boxes [maxEntries + 1]box +} + +// BoxTree ... +type BoxTree struct { + height int + root box + count int + reinsert []box +} + +func (r *box) expand(b *box) { + for i := 0; i < dims; i++ { + if b.min[i] < r.min[i] { + r.min[i] = b.min[i] + } + if b.max[i] > r.max[i] { + r.max[i] = b.max[i] + } + } +} + +func (r *box) area() float64 { + area := r.max[0] - r.min[0] + for i := 1; i < dims; i++ { + area *= r.max[i] - r.min[i] + } + return area +} + +func (r *box) overlapArea(b *box) float64 { + area := 1.0 + for i := 0; i < dims; i++ { + var max, min float64 + if r.max[i] < b.max[i] { + max = r.max[i] + } else { + max = b.max[i] + } + if r.min[i] > b.min[i] { + min = r.min[i] + } else { + min = b.min[i] + } + if max > min { + area *= max - min + } else { + return 0 + } + } + return area +} + +func (r *box) enlargedArea(b *box) float64 { + area := 1.0 + for i := 0; i < len(r.min); i++ { + if b.max[i] > r.max[i] { + if b.min[i] < r.min[i] { + area *= b.max[i] - b.min[i] + } else { + area *= b.max[i] - r.min[i] + } + } else { + if b.min[i] < r.min[i] { + area *= r.max[i] - b.min[i] + } else { + area *= r.max[i] - r.min[i] + } + } + } + return area +} + +// Insert inserts an item into the RTree +func (tr *BoxTree) Insert(min, max []float64, value interface{}) { + var item box + fit(min, max, value, &item) + tr.insert(&item) +} + +func (tr *BoxTree) insert(item *box) { + if tr.root.data == nil { + fit(item.min[:], item.max[:], new(node), &tr.root) + } + grown := tr.root.insert(item, tr.height) + if grown { + tr.root.expand(item) + } + if tr.root.data.(*node).count == maxEntries+1 { + newRoot := new(node) + tr.root.splitLargestAxisEdgeSnap(&newRoot.boxes[1]) + newRoot.boxes[0] = tr.root + newRoot.count = 2 + tr.root.data = newRoot + tr.root.recalc() + tr.height++ + } + tr.count++ +} + +func (r *box) chooseLeastEnlargement(b *box) int { + j, jenlargement, jarea := -1, 0.0, 0.0 + n := r.data.(*node) + for i := 0; i < n.count; i++ { + var area float64 + if false { + area = n.boxes[i].area() + } else { + // force inline + area = n.boxes[i].max[0] - n.boxes[i].min[0] + for j := 1; j < dims; j++ { + area *= n.boxes[i].max[j] - n.boxes[i].min[j] + } + } + var enlargement float64 + if false { + enlargement = n.boxes[i].enlargedArea(b) - area + } else { + // force inline + enlargedArea := 1.0 + for j := 0; j < len(n.boxes[i].min); j++ { + if b.max[j] > n.boxes[i].max[j] { + if b.min[j] < n.boxes[i].min[j] { + enlargedArea *= b.max[j] - b.min[j] + } else { + enlargedArea *= b.max[j] - n.boxes[i].min[j] + } + } else { + if b.min[j] < n.boxes[i].min[j] { + enlargedArea *= n.boxes[i].max[j] - b.min[j] + } else { + enlargedArea *= n.boxes[i].max[j] - n.boxes[i].min[j] + } + } + } + enlargement = enlargedArea - area + } + + if j == -1 || enlargement < jenlargement { + j, jenlargement, jarea = i, enlargement, area + } else if enlargement == jenlargement { + if area < jarea { + j, jenlargement, jarea = i, enlargement, area + } + } + } + return j +} + +func (r *box) recalc() { + n := r.data.(*node) + r.min = n.boxes[0].min + r.max = n.boxes[0].max + for i := 1; i < n.count; i++ { + r.expand(&n.boxes[i]) + } +} + +// contains return struct when b is fully contained inside of n +func (r *box) contains(b *box) bool { + for i := 0; i < dims; i++ { + if b.min[i] < r.min[i] || b.max[i] > r.max[i] { + return false + } + } + return true +} + +func (r *box) largestAxis() (axis int, size float64) { + j, jsz := 0, 0.0 + for i := 0; i < dims; i++ { + sz := r.max[i] - r.min[i] + if i == 0 || sz > jsz { + j, jsz = i, sz + } + } + return j, jsz +} + +func (r *box) splitLargestAxisEdgeSnap(right *box) { + axis, _ := r.largestAxis() + left := r + leftNode := left.data.(*node) + rightNode := new(node) + right.data = rightNode + + var equals []box + for i := 0; i < leftNode.count; i++ { + minDist := leftNode.boxes[i].min[axis] - left.min[axis] + maxDist := left.max[axis] - leftNode.boxes[i].max[axis] + if minDist < maxDist { + // stay left + } else { + if minDist > maxDist { + // move to right + rightNode.boxes[rightNode.count] = leftNode.boxes[i] + rightNode.count++ + } else { + // move to equals, at the end of the left array + equals = append(equals, leftNode.boxes[i]) + } + leftNode.boxes[i] = leftNode.boxes[leftNode.count-1] + leftNode.boxes[leftNode.count-1].data = nil + leftNode.count-- + i-- + } + } + for _, b := range equals { + if leftNode.count < rightNode.count { + leftNode.boxes[leftNode.count] = b + leftNode.count++ + } else { + rightNode.boxes[rightNode.count] = b + rightNode.count++ + } + } + left.recalc() + right.recalc() +} + +func (r *box) insert(item *box, height int) (grown bool) { + n := r.data.(*node) + if height == 0 { + n.boxes[n.count] = *item + n.count++ + grown = !r.contains(item) + return grown + } + // choose subtree + index := r.chooseLeastEnlargement(item) + child := &n.boxes[index] + grown = child.insert(item, height-1) + if grown { + child.expand(item) + grown = !r.contains(item) + } + if child.data.(*node).count == maxEntries+1 { + child.splitLargestAxisEdgeSnap(&n.boxes[n.count]) + n.count++ + } + return grown +} + +// fit an external item into a box type +func fit(min, max []float64, value interface{}, target *box) { + if max == nil { + max = min + } + if len(min) != len(max) { + panic("min/max dimension mismatch") + } + if len(min) != dims { + panic("invalid number of dimensions") + } + for i := 0; i < dims; i++ { + target.min[i] = min[i] + target.max[i] = max[i] + } + target.data = value +} + +type overlapsResult int + +const ( + not overlapsResult = iota + intersects + contains +) + +// overlaps detects if r insersects or contains b. +// return not, intersects, contains +func (r *box) overlaps(b *box) overlapsResult { + for i := 0; i < dims; i++ { + if b.min[i] > r.max[i] || b.max[i] < r.min[i] { + return not + } + if r.min[i] > b.min[i] || b.max[i] > r.max[i] { + i++ + for ; i < dims; i++ { + if b.min[i] > r.max[i] || b.max[i] < r.min[i] { + return not + } + } + return intersects + } + } + return contains +} + +// contains return struct when b is fully contained inside of n +func (r *box) intersects(b *box) bool { + for i := 0; i < dims; i++ { + if b.min[i] > r.max[i] || b.max[i] < r.min[i] { + return false + } + } + return true +} + +func (r *box) search( + target *box, height int, + iter func(min, max []float64, value interface{}) bool, +) bool { + n := r.data.(*node) + if height == 0 { + for i := 0; i < n.count; i++ { + if target.intersects(&n.boxes[i]) { + if !iter(n.boxes[i].min[:], n.boxes[i].max[:], + n.boxes[i].data) { + return false + } + } + } + } else { + for i := 0; i < n.count; i++ { + switch target.overlaps(&n.boxes[i]) { + case intersects: + if !n.boxes[i].search(target, height-1, iter) { + return false + } + case contains: + if !n.boxes[i].scan(target, height-1, iter) { + return false + } + } + } + } + return true +} + +func (tr *BoxTree) search( + target *box, + iter func(min, max []float64, value interface{}) bool, +) { + if tr.root.data == nil { + return + } + res := target.overlaps(&tr.root) + if res == intersects { + tr.root.search(target, tr.height, iter) + } else if res == contains { + tr.root.scan(target, tr.height, iter) + } +} + +// Search ... +func (tr *BoxTree) Search(min, max []float64, + iter func(min, max []float64, value interface{}) bool, +) { + var target box + fit(min, max, nil, &target) + tr.search(&target, iter) +} + +const ( + // Continue to first child box and/or next sibling. + Continue = iota + // Ignore child boxes but continue to next sibling. + Ignore + // Stop iterating + Stop +) + +// Traverse iterates through all items and container boxes in tree. +func (tr *BoxTree) Traverse( + iter func(min, max []float64, height, level int, value interface{}) int, +) { + if tr.root.data == nil { + return + } + if iter(tr.root.min[:], tr.root.max[:], tr.height+1, 0, nil) == Continue { + tr.root.traverse(tr.height, 1, iter) + } +} + +func (r *box) traverse( + height, level int, + iter func(min, max []float64, height, level int, value interface{}) int, +) int { + n := r.data.(*node) + if height == 0 { + for i := 0; i < n.count; i++ { + action := iter(n.boxes[i].min[:], n.boxes[i].max[:], height, level, + n.boxes[i].data) + if action == Stop { + return Stop + } + } + } else { + for i := 0; i < n.count; i++ { + switch iter(n.boxes[i].min[:], n.boxes[i].max[:], height, level, + n.boxes[i].data) { + case Ignore: + case Continue: + if n.boxes[i].traverse(height-1, level+1, iter) == Stop { + return Stop + } + case Stop: + return Stop + } + } + } + return Continue +} + +func (r *box) scan( + target *box, height int, + iter func(min, max []float64, value interface{}) bool, +) bool { + n := r.data.(*node) + if height == 0 { + for i := 0; i < n.count; i++ { + if !iter(n.boxes[i].min[:], n.boxes[i].max[:], n.boxes[i].data) { + return false + } + } + } else { + for i := 0; i < n.count; i++ { + if !n.boxes[i].scan(target, height-1, iter) { + return false + } + } + } + return true +} + +// Scan iterates through all items in tree. +func (tr *BoxTree) Scan(iter func(min, max []float64, value interface{}) bool) { + if tr.root.data == nil { + return + } + tr.root.scan(nil, tr.height, iter) +} + +// Delete ... +func (tr *BoxTree) Delete(min, max []float64, value interface{}) { + var item box + fit(min, max, value, &item) + if tr.root.data == nil || !tr.root.contains(&item) { + return + } + var removed, recalced bool + removed, recalced, tr.reinsert = + tr.root.delete(&item, tr.height, tr.reinsert[:0]) + if !removed { + return + } + tr.count -= len(tr.reinsert) + 1 + if tr.count == 0 { + tr.root = box{} + recalced = false + } else { + for tr.height > 0 && tr.root.data.(*node).count == 1 { + tr.root = tr.root.data.(*node).boxes[0] + tr.height-- + tr.root.recalc() + } + } + if recalced { + tr.root.recalc() + } + for i := range tr.reinsert { + tr.insert(&tr.reinsert[i]) + tr.reinsert[i].data = nil + } +} + +func (r *box) delete(item *box, height int, reinsert []box) ( + removed, recalced bool, reinsertOut []box, +) { + n := r.data.(*node) + if height == 0 { + for i := 0; i < n.count; i++ { + if n.boxes[i].data == item.data { + // found the target item to delete + recalced = r.onEdge(&n.boxes[i]) + n.boxes[i] = n.boxes[n.count-1] + n.boxes[n.count-1].data = nil + n.count-- + if recalced { + r.recalc() + } + return true, recalced, reinsert + } + } + } else { + for i := 0; i < n.count; i++ { + if !n.boxes[i].contains(item) { + continue + } + removed, recalced, reinsert = + n.boxes[i].delete(item, height-1, reinsert) + if !removed { + continue + } + if n.boxes[i].data.(*node).count < minEntries { + // underflow + if !recalced { + recalced = r.onEdge(&n.boxes[i]) + } + reinsert = n.boxes[i].flatten(reinsert, height-1) + n.boxes[i] = n.boxes[n.count-1] + n.boxes[n.count-1].data = nil + n.count-- + } + if recalced { + r.recalc() + } + return removed, recalced, reinsert + } + } + return false, false, reinsert +} + +// flatten flattens all leaf boxes into a single list +func (r *box) flatten(all []box, height int) []box { + n := r.data.(*node) + if height == 0 { + all = append(all, n.boxes[:n.count]...) + } else { + for i := 0; i < n.count; i++ { + all = n.boxes[i].flatten(all, height-1) + } + } + return all +} + +// onedge returns true when b is on the edge of r +func (r *box) onEdge(b *box) bool { + for i := 0; i < dims; i++ { + if r.min[i] == b.min[i] || r.max[i] == b.max[i] { + return true + } + } + return false +} + +// Count ... +func (tr *BoxTree) Count() int { + return tr.count +} + +func (r *box) totalOverlapArea(height int) float64 { + var area float64 + n := r.data.(*node) + for i := 0; i < n.count; i++ { + for j := i + 1; j < n.count; j++ { + area += n.boxes[i].overlapArea(&n.boxes[j]) + } + + } + if height > 0 { + for i := 0; i < n.count; i++ { + area += n.boxes[i].totalOverlapArea(height - 1) + } + } + return area +} + +// TotalOverlapArea ... +func (tr *BoxTree) TotalOverlapArea() float64 { + if tr.root.data == nil { + return 0 + } + return tr.root.totalOverlapArea(tr.height) +} + +type qnode struct { + dist float64 + box box +} + +type queue struct { + nodes []qnode + len int + size int +} + +func (q *queue) push(dist float64, box box) { + if q.nodes == nil { + q.nodes = make([]qnode, 2) + } else { + q.nodes = append(q.nodes, qnode{}) + } + i := q.len + 1 + j := i / 2 + for i > 1 && q.nodes[j].dist > dist { + q.nodes[i] = q.nodes[j] + i = j + j = j / 2 + } + q.nodes[i].dist = dist + q.nodes[i].box = box + q.len++ +} + +func (q *queue) peek() qnode { + if q.len == 0 { + return qnode{} + } + return q.nodes[1] +} + +func (q *queue) pop() qnode { + if q.len == 0 { + return qnode{} + } + n := q.nodes[1] + q.nodes[1] = q.nodes[q.len] + q.len-- + var j, k int + i := 1 + for i != q.len+1 { + k = q.len + 1 + j = 2 * i + if j <= q.len && q.nodes[j].dist < q.nodes[k].dist { + k = j + } + if j+1 <= q.len && q.nodes[j+1].dist < q.nodes[k].dist { + k = j + 1 + } + q.nodes[i] = q.nodes[k] + i = k + } + return n +} + +// Nearby returns items nearest to farthest. +// The dist param is the "box distance". +func (tr *BoxTree) Nearby(min, max []float64, + iter func(min, max []float64, item interface{}) bool) { + if tr.root.data == nil { + return + } + var bbox box + fit(min, max, nil, &bbox) + box := tr.root + var q queue + for { + n := box.data.(*node) + for i := 0; i < n.count; i++ { + dist := boxDist(&bbox, &n.boxes[i]) + q.push(dist, n.boxes[i]) + } + for q.len > 0 { + if _, ok := q.peek().box.data.(*node); ok { + break + } + item := q.pop() + if !iter(item.box.min[:], item.box.max[:], item.box.data) { + return + } + } + if q.len == 0 { + break + } else { + box = q.pop().box + } + } + return +} + +func boxDist(a, b *box) float64 { + var dist float64 + for i := 0; i < len(a.min); i++ { + var min, max float64 + if a.min[i] > b.min[i] { + min = a.min[i] + } else { + min = b.min[i] + } + if a.max[i] < b.max[i] { + max = a.max[i] + } else { + max = b.max[i] + } + squared := min - max + if squared > 0 { + dist += squared * squared + } + } + return dist +} + +// Bounds returns the minimum bounding box +func (tr *BoxTree) Bounds() (min, max []float64) { + if tr.root.data == nil { + return + } + return tr.root.min[:], tr.root.max[:] +} diff --git a/vendor/github.com/tidwall/boxtree/d2/boxtree_test.go b/vendor/github.com/tidwall/boxtree/d2/boxtree_test.go new file mode 100644 index 00000000..db9c20a7 --- /dev/null +++ b/vendor/github.com/tidwall/boxtree/d2/boxtree_test.go @@ -0,0 +1,379 @@ +package d2 + +import ( + "fmt" + "math/rand" + "sort" + "strconv" + "strings" + "testing" + "time" +) + +type tBox struct { + min [dims]float64 + max [dims]float64 +} + +var boxes []tBox +var points []tBox + +func init() { + seed := time.Now().UnixNano() + // seed = 1532132365683340889 + println("seed:", seed) + rand.Seed(seed) +} + +func randPoints(N int) []tBox { + boxes := make([]tBox, N) + for i := 0; i < N; i++ { + boxes[i].min[0] = rand.Float64()*360 - 180 + boxes[i].min[1] = rand.Float64()*180 - 90 + for j := 2; j < dims; j++ { + boxes[i].min[j] = rand.Float64() + } + boxes[i].max = boxes[i].min + } + return boxes +} + +func randBoxes(N int) []tBox { + boxes := make([]tBox, N) + for i := 0; i < N; i++ { + boxes[i].min[0] = rand.Float64()*360 - 180 + boxes[i].min[1] = rand.Float64()*180 - 90 + for j := 2; j < dims; j++ { + boxes[i].min[j] = rand.Float64() * 100 + } + boxes[i].max[0] = boxes[i].min[0] + rand.Float64() + boxes[i].max[1] = boxes[i].min[1] + rand.Float64() + for j := 2; j < dims; j++ { + boxes[i].max[j] = boxes[i].min[j] + rand.Float64() + } + if boxes[i].max[0] > 180 || boxes[i].max[1] > 90 { + i-- + } + } + return boxes +} + +func sortBoxes(boxes []tBox) { + sort.Slice(boxes, func(i, j int) bool { + for k := 0; k < len(boxes[i].min); k++ { + if boxes[i].min[k] < boxes[j].min[k] { + return true + } + if boxes[i].min[k] > boxes[j].min[k] { + return false + } + if boxes[i].max[k] < boxes[j].max[k] { + return true + } + if boxes[i].max[k] > boxes[j].max[k] { + return false + } + } + return i < j + }) +} + +func sortBoxesNearby(boxes []tBox, min, max []float64) { + sort.Slice(boxes, func(i, j int) bool { + return testBoxDist(boxes[i].min[:], boxes[i].max[:], min, max) < + testBoxDist(boxes[j].min[:], boxes[j].max[:], min, max) + }) +} + +func testBoxDist(amin, amax, bmin, bmax []float64) float64 { + var dist float64 + for i := 0; i < len(amin); i++ { + var min, max float64 + if amin[i] > bmin[i] { + min = amin[i] + } else { + min = bmin[i] + } + if amax[i] < bmax[i] { + max = amax[i] + } else { + max = bmax[i] + } + squared := min - max + if squared > 0 { + dist += squared * squared + } + } + return dist +} + +func testBoxesVarious(t *testing.T, boxes []tBox, label string) { + N := len(boxes) + + var tr BoxTree + + // N := 10000 + // boxes := randPoints(N) + + ///////////////////////////////////////// + // insert + ///////////////////////////////////////// + for i := 0; i < N; i++ { + tr.Insert(boxes[i].min[:], boxes[i].max[:], boxes[i]) + } + if tr.Count() != N { + t.Fatalf("expected %d, got %d", N, tr.Count()) + } + // area := tr.TotalOverlapArea() + // fmt.Printf("overlap: %.0f, %.1f/item\n", area, area/float64(N)) + + // ioutil.WriteFile(label+".svg", []byte(rtreetools.SVG(&tr)), 0600) + + ///////////////////////////////////////// + // scan all items and count one-by-one + ///////////////////////////////////////// + var count int + tr.Scan(func(min, max []float64, value interface{}) bool { + count++ + return true + }) + if count != N { + t.Fatalf("expected %d, got %d", N, count) + } + + ///////////////////////////////////////// + // check every point for correctness + ///////////////////////////////////////// + var tboxes1 []tBox + tr.Scan(func(min, max []float64, value interface{}) bool { + tboxes1 = append(tboxes1, value.(tBox)) + return true + }) + tboxes2 := make([]tBox, len(boxes)) + copy(tboxes2, boxes) + sortBoxes(tboxes1) + sortBoxes(tboxes2) + for i := 0; i < len(tboxes1); i++ { + if tboxes1[i] != tboxes2[i] { + t.Fatalf("expected '%v', got '%v'", tboxes2[i], tboxes1[i]) + } + } + + ///////////////////////////////////////// + // search for each item one-by-one + ///////////////////////////////////////// + for i := 0; i < N; i++ { + var found bool + tr.Search(boxes[i].min[:], boxes[i].max[:], + func(min, max []float64, value interface{}) bool { + if value == boxes[i] { + found = true + return false + } + return true + }) + if !found { + t.Fatalf("did not find item %d", i) + } + } + + centerMin, centerMax := []float64{-18, -9}, []float64{18, 9} + for j := 2; j < dims; j++ { + centerMin = append(centerMin, -10) + centerMax = append(centerMax, 10) + } + + ///////////////////////////////////////// + // search for 10% of the items + ///////////////////////////////////////// + for i := 0; i < N/5; i++ { + var count int + tr.Search(centerMin, centerMax, + func(min, max []float64, value interface{}) bool { + count++ + return true + }, + ) + } + + ///////////////////////////////////////// + // delete every other item + ///////////////////////////////////////// + for i := 0; i < N/2; i++ { + j := i * 2 + tr.Delete(boxes[j].min[:], boxes[j].max[:], boxes[j]) + } + + ///////////////////////////////////////// + // count all items. should be half of N + ///////////////////////////////////////// + count = 0 + tr.Scan(func(min, max []float64, value interface{}) bool { + count++ + return true + }) + if count != N/2 { + t.Fatalf("expected %d, got %d", N/2, count) + } + + /////////////////////////////////////////////////// + // reinsert every other item, but in random order + /////////////////////////////////////////////////// + var ij []int + for i := 0; i < N/2; i++ { + j := i * 2 + ij = append(ij, j) + } + rand.Shuffle(len(ij), func(i, j int) { + ij[i], ij[j] = ij[j], ij[i] + }) + for i := 0; i < N/2; i++ { + j := ij[i] + tr.Insert(boxes[j].min[:], boxes[j].max[:], boxes[j]) + } + + ////////////////////////////////////////////////////// + // replace each item with an item that is very close + ////////////////////////////////////////////////////// + var nboxes = make([]tBox, N) + for i := 0; i < N; i++ { + for j := 0; j < len(boxes[i].min); j++ { + nboxes[i].min[j] = boxes[i].min[j] + (rand.Float64() - 0.5) + if boxes[i].min == boxes[i].max { + nboxes[i].max[j] = nboxes[i].min[j] + } else { + nboxes[i].max[j] = boxes[i].max[j] + (rand.Float64() - 0.5) + } + } + + } + for i := 0; i < N; i++ { + tr.Insert(nboxes[i].min[:], nboxes[i].max[:], nboxes[i]) + tr.Delete(boxes[i].min[:], boxes[i].max[:], boxes[i]) + } + if tr.Count() != N { + t.Fatalf("expected %d, got %d", N, tr.Count()) + } + // area = tr.TotalOverlapArea() + // fmt.Fprintf(wr, "overlap: %.0f, %.1f/item\n", area, area/float64(N)) + + ///////////////////////////////////////// + // check every point for correctness + ///////////////////////////////////////// + tboxes1 = nil + tr.Scan(func(min, max []float64, value interface{}) bool { + tboxes1 = append(tboxes1, value.(tBox)) + return true + }) + tboxes2 = make([]tBox, len(nboxes)) + copy(tboxes2, nboxes) + sortBoxes(tboxes1) + sortBoxes(tboxes2) + for i := 0; i < len(tboxes1); i++ { + if tboxes1[i] != tboxes2[i] { + t.Fatalf("expected '%v', got '%v'", tboxes2[i], tboxes1[i]) + } + } + + ///////////////////////////////////////// + // search for 10% of the items + ///////////////////////////////////////// + for i := 0; i < N/5; i++ { + var count int + tr.Search(centerMin, centerMax, + func(min, max []float64, value interface{}) bool { + count++ + return true + }, + ) + } + + var boxes3 []tBox + tr.Nearby(centerMin, centerMax, + func(min, max []float64, value interface{}) bool { + boxes3 = append(boxes3, value.(tBox)) + return true + }, + ) + if len(boxes3) != len(nboxes) { + t.Fatalf("expected %d, got %d", len(nboxes), len(boxes3)) + } + if len(boxes3) != tr.Count() { + t.Fatalf("expected %d, got %d", tr.Count(), len(boxes3)) + } + var ldist float64 + for i, box := range boxes3 { + dist := testBoxDist(box.min[:], box.max[:], centerMin, centerMax) + if i > 0 && dist < ldist { + t.Fatalf("out of order") + } + ldist = dist + } +} + +func TestRandomBoxes(t *testing.T) { + testBoxesVarious(t, randBoxes(10000), "boxes") +} + +func TestRandomPoints(t *testing.T) { + testBoxesVarious(t, randPoints(10000), "points") +} + +func (r *box) boxstr() string { + var b []byte + b = append(b, '[', '[') + for i := 0; i < len(r.min); i++ { + if i != 0 { + b = append(b, ' ') + } + b = strconv.AppendFloat(b, r.min[i], 'f', -1, 64) + } + b = append(b, ']', '[') + for i := 0; i < len(r.max); i++ { + if i != 0 { + b = append(b, ' ') + } + b = strconv.AppendFloat(b, r.max[i], 'f', -1, 64) + } + b = append(b, ']', ']') + return string(b) +} + +func (r *box) print(height, indent int) { + fmt.Printf("%s%s", strings.Repeat(" ", indent), r.boxstr()) + if height == 0 { + fmt.Printf("\t'%v'\n", r.data) + } else { + fmt.Printf("\n") + for i := 0; i < r.data.(*node).count; i++ { + r.data.(*node).boxes[i].print(height-1, indent+1) + } + } + +} + +func (tr BoxTree) print() { + if tr.root.data == nil { + println("EMPTY TREE") + return + } + tr.root.print(tr.height+1, 0) +} + +func TestZeroPoints(t *testing.T) { + N := 10000 + var tr BoxTree + pt := make([]float64, dims) + for i := 0; i < N; i++ { + tr.Insert(pt, nil, i) + } +} + +func BenchmarkRandomInsert(b *testing.B) { + var tr BoxTree + boxes := randBoxes(b.N) + b.ResetTimer() + for i := 0; i < b.N; i++ { + tr.Insert(boxes[i].min[:], boxes[i].max[:], i) + } +} diff --git a/vendor/github.com/tidwall/boxtree/d3/boxtree.go b/vendor/github.com/tidwall/boxtree/d3/boxtree.go new file mode 100644 index 00000000..8b0718ed --- /dev/null +++ b/vendor/github.com/tidwall/boxtree/d3/boxtree.go @@ -0,0 +1,707 @@ +package d3 + +const dims = 3 + +const ( + maxEntries = 16 + minEntries = maxEntries * 40 / 100 +) + +type box struct { + data interface{} + min, max [dims]float64 +} + +type node struct { + count int + boxes [maxEntries + 1]box +} + +// BoxTree ... +type BoxTree struct { + height int + root box + count int + reinsert []box +} + +func (r *box) expand(b *box) { + for i := 0; i < dims; i++ { + if b.min[i] < r.min[i] { + r.min[i] = b.min[i] + } + if b.max[i] > r.max[i] { + r.max[i] = b.max[i] + } + } +} + +func (r *box) area() float64 { + area := r.max[0] - r.min[0] + for i := 1; i < dims; i++ { + area *= r.max[i] - r.min[i] + } + return area +} + +func (r *box) overlapArea(b *box) float64 { + area := 1.0 + for i := 0; i < dims; i++ { + var max, min float64 + if r.max[i] < b.max[i] { + max = r.max[i] + } else { + max = b.max[i] + } + if r.min[i] > b.min[i] { + min = r.min[i] + } else { + min = b.min[i] + } + if max > min { + area *= max - min + } else { + return 0 + } + } + return area +} + +func (r *box) enlargedArea(b *box) float64 { + area := 1.0 + for i := 0; i < len(r.min); i++ { + if b.max[i] > r.max[i] { + if b.min[i] < r.min[i] { + area *= b.max[i] - b.min[i] + } else { + area *= b.max[i] - r.min[i] + } + } else { + if b.min[i] < r.min[i] { + area *= r.max[i] - b.min[i] + } else { + area *= r.max[i] - r.min[i] + } + } + } + return area +} + +// Insert inserts an item into the RTree +func (tr *BoxTree) Insert(min, max []float64, value interface{}) { + var item box + fit(min, max, value, &item) + tr.insert(&item) +} + +func (tr *BoxTree) insert(item *box) { + if tr.root.data == nil { + fit(item.min[:], item.max[:], new(node), &tr.root) + } + grown := tr.root.insert(item, tr.height) + if grown { + tr.root.expand(item) + } + if tr.root.data.(*node).count == maxEntries+1 { + newRoot := new(node) + tr.root.splitLargestAxisEdgeSnap(&newRoot.boxes[1]) + newRoot.boxes[0] = tr.root + newRoot.count = 2 + tr.root.data = newRoot + tr.root.recalc() + tr.height++ + } + tr.count++ +} + +func (r *box) chooseLeastEnlargement(b *box) int { + j, jenlargement, jarea := -1, 0.0, 0.0 + n := r.data.(*node) + for i := 0; i < n.count; i++ { + var area float64 + if false { + area = n.boxes[i].area() + } else { + // force inline + area = n.boxes[i].max[0] - n.boxes[i].min[0] + for j := 1; j < dims; j++ { + area *= n.boxes[i].max[j] - n.boxes[i].min[j] + } + } + var enlargement float64 + if false { + enlargement = n.boxes[i].enlargedArea(b) - area + } else { + // force inline + enlargedArea := 1.0 + for j := 0; j < len(n.boxes[i].min); j++ { + if b.max[j] > n.boxes[i].max[j] { + if b.min[j] < n.boxes[i].min[j] { + enlargedArea *= b.max[j] - b.min[j] + } else { + enlargedArea *= b.max[j] - n.boxes[i].min[j] + } + } else { + if b.min[j] < n.boxes[i].min[j] { + enlargedArea *= n.boxes[i].max[j] - b.min[j] + } else { + enlargedArea *= n.boxes[i].max[j] - n.boxes[i].min[j] + } + } + } + enlargement = enlargedArea - area + } + + if j == -1 || enlargement < jenlargement { + j, jenlargement, jarea = i, enlargement, area + } else if enlargement == jenlargement { + if area < jarea { + j, jenlargement, jarea = i, enlargement, area + } + } + } + return j +} + +func (r *box) recalc() { + n := r.data.(*node) + r.min = n.boxes[0].min + r.max = n.boxes[0].max + for i := 1; i < n.count; i++ { + r.expand(&n.boxes[i]) + } +} + +// contains return struct when b is fully contained inside of n +func (r *box) contains(b *box) bool { + for i := 0; i < dims; i++ { + if b.min[i] < r.min[i] || b.max[i] > r.max[i] { + return false + } + } + return true +} + +func (r *box) largestAxis() (axis int, size float64) { + j, jsz := 0, 0.0 + for i := 0; i < dims; i++ { + sz := r.max[i] - r.min[i] + if i == 0 || sz > jsz { + j, jsz = i, sz + } + } + return j, jsz +} + +func (r *box) splitLargestAxisEdgeSnap(right *box) { + axis, _ := r.largestAxis() + left := r + leftNode := left.data.(*node) + rightNode := new(node) + right.data = rightNode + + var equals []box + for i := 0; i < leftNode.count; i++ { + minDist := leftNode.boxes[i].min[axis] - left.min[axis] + maxDist := left.max[axis] - leftNode.boxes[i].max[axis] + if minDist < maxDist { + // stay left + } else { + if minDist > maxDist { + // move to right + rightNode.boxes[rightNode.count] = leftNode.boxes[i] + rightNode.count++ + } else { + // move to equals, at the end of the left array + equals = append(equals, leftNode.boxes[i]) + } + leftNode.boxes[i] = leftNode.boxes[leftNode.count-1] + leftNode.boxes[leftNode.count-1].data = nil + leftNode.count-- + i-- + } + } + for _, b := range equals { + if leftNode.count < rightNode.count { + leftNode.boxes[leftNode.count] = b + leftNode.count++ + } else { + rightNode.boxes[rightNode.count] = b + rightNode.count++ + } + } + left.recalc() + right.recalc() +} + +func (r *box) insert(item *box, height int) (grown bool) { + n := r.data.(*node) + if height == 0 { + n.boxes[n.count] = *item + n.count++ + grown = !r.contains(item) + return grown + } + // choose subtree + index := r.chooseLeastEnlargement(item) + child := &n.boxes[index] + grown = child.insert(item, height-1) + if grown { + child.expand(item) + grown = !r.contains(item) + } + if child.data.(*node).count == maxEntries+1 { + child.splitLargestAxisEdgeSnap(&n.boxes[n.count]) + n.count++ + } + return grown +} + +// fit an external item into a box type +func fit(min, max []float64, value interface{}, target *box) { + if max == nil { + max = min + } + if len(min) != len(max) { + panic("min/max dimension mismatch") + } + if len(min) != dims { + panic("invalid number of dimensions") + } + for i := 0; i < dims; i++ { + target.min[i] = min[i] + target.max[i] = max[i] + } + target.data = value +} + +type overlapsResult int + +const ( + not overlapsResult = iota + intersects + contains +) + +// overlaps detects if r insersects or contains b. +// return not, intersects, contains +func (r *box) overlaps(b *box) overlapsResult { + for i := 0; i < dims; i++ { + if b.min[i] > r.max[i] || b.max[i] < r.min[i] { + return not + } + if r.min[i] > b.min[i] || b.max[i] > r.max[i] { + i++ + for ; i < dims; i++ { + if b.min[i] > r.max[i] || b.max[i] < r.min[i] { + return not + } + } + return intersects + } + } + return contains +} + +// contains return struct when b is fully contained inside of n +func (r *box) intersects(b *box) bool { + for i := 0; i < dims; i++ { + if b.min[i] > r.max[i] || b.max[i] < r.min[i] { + return false + } + } + return true +} + +func (r *box) search( + target *box, height int, + iter func(min, max []float64, value interface{}) bool, +) bool { + n := r.data.(*node) + if height == 0 { + for i := 0; i < n.count; i++ { + if target.intersects(&n.boxes[i]) { + if !iter(n.boxes[i].min[:], n.boxes[i].max[:], + n.boxes[i].data) { + return false + } + } + } + } else { + for i := 0; i < n.count; i++ { + switch target.overlaps(&n.boxes[i]) { + case intersects: + if !n.boxes[i].search(target, height-1, iter) { + return false + } + case contains: + if !n.boxes[i].scan(target, height-1, iter) { + return false + } + } + } + } + return true +} + +func (tr *BoxTree) search( + target *box, + iter func(min, max []float64, value interface{}) bool, +) { + if tr.root.data == nil { + return + } + res := target.overlaps(&tr.root) + if res == intersects { + tr.root.search(target, tr.height, iter) + } else if res == contains { + tr.root.scan(target, tr.height, iter) + } +} + +// Search ... +func (tr *BoxTree) Search(min, max []float64, + iter func(min, max []float64, value interface{}) bool, +) { + var target box + fit(min, max, nil, &target) + tr.search(&target, iter) +} + +const ( + // Continue to first child box and/or next sibling. + Continue = iota + // Ignore child boxes but continue to next sibling. + Ignore + // Stop iterating + Stop +) + +// Traverse iterates through all items and container boxes in tree. +func (tr *BoxTree) Traverse( + iter func(min, max []float64, height, level int, value interface{}) int, +) { + if tr.root.data == nil { + return + } + if iter(tr.root.min[:], tr.root.max[:], tr.height+1, 0, nil) == Continue { + tr.root.traverse(tr.height, 1, iter) + } +} + +func (r *box) traverse( + height, level int, + iter func(min, max []float64, height, level int, value interface{}) int, +) int { + n := r.data.(*node) + if height == 0 { + for i := 0; i < n.count; i++ { + action := iter(n.boxes[i].min[:], n.boxes[i].max[:], height, level, + n.boxes[i].data) + if action == Stop { + return Stop + } + } + } else { + for i := 0; i < n.count; i++ { + switch iter(n.boxes[i].min[:], n.boxes[i].max[:], height, level, + n.boxes[i].data) { + case Ignore: + case Continue: + if n.boxes[i].traverse(height-1, level+1, iter) == Stop { + return Stop + } + case Stop: + return Stop + } + } + } + return Continue +} + +func (r *box) scan( + target *box, height int, + iter func(min, max []float64, value interface{}) bool, +) bool { + n := r.data.(*node) + if height == 0 { + for i := 0; i < n.count; i++ { + if !iter(n.boxes[i].min[:], n.boxes[i].max[:], n.boxes[i].data) { + return false + } + } + } else { + for i := 0; i < n.count; i++ { + if !n.boxes[i].scan(target, height-1, iter) { + return false + } + } + } + return true +} + +// Scan iterates through all items in tree. +func (tr *BoxTree) Scan(iter func(min, max []float64, value interface{}) bool) { + if tr.root.data == nil { + return + } + tr.root.scan(nil, tr.height, iter) +} + +// Delete ... +func (tr *BoxTree) Delete(min, max []float64, value interface{}) { + var item box + fit(min, max, value, &item) + if tr.root.data == nil || !tr.root.contains(&item) { + return + } + var removed, recalced bool + removed, recalced, tr.reinsert = + tr.root.delete(&item, tr.height, tr.reinsert[:0]) + if !removed { + return + } + tr.count -= len(tr.reinsert) + 1 + if tr.count == 0 { + tr.root = box{} + recalced = false + } else { + for tr.height > 0 && tr.root.data.(*node).count == 1 { + tr.root = tr.root.data.(*node).boxes[0] + tr.height-- + tr.root.recalc() + } + } + if recalced { + tr.root.recalc() + } + for i := range tr.reinsert { + tr.insert(&tr.reinsert[i]) + tr.reinsert[i].data = nil + } +} + +func (r *box) delete(item *box, height int, reinsert []box) ( + removed, recalced bool, reinsertOut []box, +) { + n := r.data.(*node) + if height == 0 { + for i := 0; i < n.count; i++ { + if n.boxes[i].data == item.data { + // found the target item to delete + recalced = r.onEdge(&n.boxes[i]) + n.boxes[i] = n.boxes[n.count-1] + n.boxes[n.count-1].data = nil + n.count-- + if recalced { + r.recalc() + } + return true, recalced, reinsert + } + } + } else { + for i := 0; i < n.count; i++ { + if !n.boxes[i].contains(item) { + continue + } + removed, recalced, reinsert = + n.boxes[i].delete(item, height-1, reinsert) + if !removed { + continue + } + if n.boxes[i].data.(*node).count < minEntries { + // underflow + if !recalced { + recalced = r.onEdge(&n.boxes[i]) + } + reinsert = n.boxes[i].flatten(reinsert, height-1) + n.boxes[i] = n.boxes[n.count-1] + n.boxes[n.count-1].data = nil + n.count-- + } + if recalced { + r.recalc() + } + return removed, recalced, reinsert + } + } + return false, false, reinsert +} + +// flatten flattens all leaf boxes into a single list +func (r *box) flatten(all []box, height int) []box { + n := r.data.(*node) + if height == 0 { + all = append(all, n.boxes[:n.count]...) + } else { + for i := 0; i < n.count; i++ { + all = n.boxes[i].flatten(all, height-1) + } + } + return all +} + +// onedge returns true when b is on the edge of r +func (r *box) onEdge(b *box) bool { + for i := 0; i < dims; i++ { + if r.min[i] == b.min[i] || r.max[i] == b.max[i] { + return true + } + } + return false +} + +// Count ... +func (tr *BoxTree) Count() int { + return tr.count +} + +func (r *box) totalOverlapArea(height int) float64 { + var area float64 + n := r.data.(*node) + for i := 0; i < n.count; i++ { + for j := i + 1; j < n.count; j++ { + area += n.boxes[i].overlapArea(&n.boxes[j]) + } + + } + if height > 0 { + for i := 0; i < n.count; i++ { + area += n.boxes[i].totalOverlapArea(height - 1) + } + } + return area +} + +// TotalOverlapArea ... +func (tr *BoxTree) TotalOverlapArea() float64 { + if tr.root.data == nil { + return 0 + } + return tr.root.totalOverlapArea(tr.height) +} + +type qnode struct { + dist float64 + box box +} + +type queue struct { + nodes []qnode + len int + size int +} + +func (q *queue) push(dist float64, box box) { + if q.nodes == nil { + q.nodes = make([]qnode, 2) + } else { + q.nodes = append(q.nodes, qnode{}) + } + i := q.len + 1 + j := i / 2 + for i > 1 && q.nodes[j].dist > dist { + q.nodes[i] = q.nodes[j] + i = j + j = j / 2 + } + q.nodes[i].dist = dist + q.nodes[i].box = box + q.len++ +} + +func (q *queue) peek() qnode { + if q.len == 0 { + return qnode{} + } + return q.nodes[1] +} + +func (q *queue) pop() qnode { + if q.len == 0 { + return qnode{} + } + n := q.nodes[1] + q.nodes[1] = q.nodes[q.len] + q.len-- + var j, k int + i := 1 + for i != q.len+1 { + k = q.len + 1 + j = 2 * i + if j <= q.len && q.nodes[j].dist < q.nodes[k].dist { + k = j + } + if j+1 <= q.len && q.nodes[j+1].dist < q.nodes[k].dist { + k = j + 1 + } + q.nodes[i] = q.nodes[k] + i = k + } + return n +} + +// Nearby returns items nearest to farthest. +// The dist param is the "box distance". +func (tr *BoxTree) Nearby(min, max []float64, + iter func(min, max []float64, item interface{}) bool) { + if tr.root.data == nil { + return + } + var bbox box + fit(min, max, nil, &bbox) + box := tr.root + var q queue + for { + n := box.data.(*node) + for i := 0; i < n.count; i++ { + dist := boxDist(&bbox, &n.boxes[i]) + q.push(dist, n.boxes[i]) + } + for q.len > 0 { + if _, ok := q.peek().box.data.(*node); ok { + break + } + item := q.pop() + if !iter(item.box.min[:], item.box.max[:], item.box.data) { + return + } + } + if q.len == 0 { + break + } else { + box = q.pop().box + } + } + return +} + +func boxDist(a, b *box) float64 { + var dist float64 + for i := 0; i < len(a.min); i++ { + var min, max float64 + if a.min[i] > b.min[i] { + min = a.min[i] + } else { + min = b.min[i] + } + if a.max[i] < b.max[i] { + max = a.max[i] + } else { + max = b.max[i] + } + squared := min - max + if squared > 0 { + dist += squared * squared + } + } + return dist +} + +// Bounds returns the minimum bounding box +func (tr *BoxTree) Bounds() (min, max []float64) { + if tr.root.data == nil { + return + } + return tr.root.min[:], tr.root.max[:] +} diff --git a/vendor/github.com/tidwall/boxtree/d3/boxtree_test.go b/vendor/github.com/tidwall/boxtree/d3/boxtree_test.go new file mode 100644 index 00000000..ddb7bd1e --- /dev/null +++ b/vendor/github.com/tidwall/boxtree/d3/boxtree_test.go @@ -0,0 +1,379 @@ +package d3 + +import ( + "fmt" + "math/rand" + "sort" + "strconv" + "strings" + "testing" + "time" +) + +type tBox struct { + min [dims]float64 + max [dims]float64 +} + +var boxes []tBox +var points []tBox + +func init() { + seed := time.Now().UnixNano() + // seed = 1532132365683340889 + println("seed:", seed) + rand.Seed(seed) +} + +func randPoints(N int) []tBox { + boxes := make([]tBox, N) + for i := 0; i < N; i++ { + boxes[i].min[0] = rand.Float64()*360 - 180 + boxes[i].min[1] = rand.Float64()*180 - 90 + for j := 2; j < dims; j++ { + boxes[i].min[j] = rand.Float64() + } + boxes[i].max = boxes[i].min + } + return boxes +} + +func randBoxes(N int) []tBox { + boxes := make([]tBox, N) + for i := 0; i < N; i++ { + boxes[i].min[0] = rand.Float64()*360 - 180 + boxes[i].min[1] = rand.Float64()*180 - 90 + for j := 2; j < dims; j++ { + boxes[i].min[j] = rand.Float64() * 100 + } + boxes[i].max[0] = boxes[i].min[0] + rand.Float64() + boxes[i].max[1] = boxes[i].min[1] + rand.Float64() + for j := 2; j < dims; j++ { + boxes[i].max[j] = boxes[i].min[j] + rand.Float64() + } + if boxes[i].max[0] > 180 || boxes[i].max[1] > 90 { + i-- + } + } + return boxes +} + +func sortBoxes(boxes []tBox) { + sort.Slice(boxes, func(i, j int) bool { + for k := 0; k < len(boxes[i].min); k++ { + if boxes[i].min[k] < boxes[j].min[k] { + return true + } + if boxes[i].min[k] > boxes[j].min[k] { + return false + } + if boxes[i].max[k] < boxes[j].max[k] { + return true + } + if boxes[i].max[k] > boxes[j].max[k] { + return false + } + } + return i < j + }) +} + +func sortBoxesNearby(boxes []tBox, min, max []float64) { + sort.Slice(boxes, func(i, j int) bool { + return testBoxDist(boxes[i].min[:], boxes[i].max[:], min, max) < + testBoxDist(boxes[j].min[:], boxes[j].max[:], min, max) + }) +} + +func testBoxDist(amin, amax, bmin, bmax []float64) float64 { + var dist float64 + for i := 0; i < len(amin); i++ { + var min, max float64 + if amin[i] > bmin[i] { + min = amin[i] + } else { + min = bmin[i] + } + if amax[i] < bmax[i] { + max = amax[i] + } else { + max = bmax[i] + } + squared := min - max + if squared > 0 { + dist += squared * squared + } + } + return dist +} + +func testBoxesVarious(t *testing.T, boxes []tBox, label string) { + N := len(boxes) + + var tr BoxTree + + // N := 10000 + // boxes := randPoints(N) + + ///////////////////////////////////////// + // insert + ///////////////////////////////////////// + for i := 0; i < N; i++ { + tr.Insert(boxes[i].min[:], boxes[i].max[:], boxes[i]) + } + if tr.Count() != N { + t.Fatalf("expected %d, got %d", N, tr.Count()) + } + // area := tr.TotalOverlapArea() + // fmt.Printf("overlap: %.0f, %.1f/item\n", area, area/float64(N)) + + // ioutil.WriteFile(label+".svg", []byte(rtreetools.SVG(&tr)), 0600) + + ///////////////////////////////////////// + // scan all items and count one-by-one + ///////////////////////////////////////// + var count int + tr.Scan(func(min, max []float64, value interface{}) bool { + count++ + return true + }) + if count != N { + t.Fatalf("expected %d, got %d", N, count) + } + + ///////////////////////////////////////// + // check every point for correctness + ///////////////////////////////////////// + var tboxes1 []tBox + tr.Scan(func(min, max []float64, value interface{}) bool { + tboxes1 = append(tboxes1, value.(tBox)) + return true + }) + tboxes2 := make([]tBox, len(boxes)) + copy(tboxes2, boxes) + sortBoxes(tboxes1) + sortBoxes(tboxes2) + for i := 0; i < len(tboxes1); i++ { + if tboxes1[i] != tboxes2[i] { + t.Fatalf("expected '%v', got '%v'", tboxes2[i], tboxes1[i]) + } + } + + ///////////////////////////////////////// + // search for each item one-by-one + ///////////////////////////////////////// + for i := 0; i < N; i++ { + var found bool + tr.Search(boxes[i].min[:], boxes[i].max[:], + func(min, max []float64, value interface{}) bool { + if value == boxes[i] { + found = true + return false + } + return true + }) + if !found { + t.Fatalf("did not find item %d", i) + } + } + + centerMin, centerMax := []float64{-18, -9}, []float64{18, 9} + for j := 2; j < dims; j++ { + centerMin = append(centerMin, -10) + centerMax = append(centerMax, 10) + } + + ///////////////////////////////////////// + // search for 10% of the items + ///////////////////////////////////////// + for i := 0; i < N/5; i++ { + var count int + tr.Search(centerMin, centerMax, + func(min, max []float64, value interface{}) bool { + count++ + return true + }, + ) + } + + ///////////////////////////////////////// + // delete every other item + ///////////////////////////////////////// + for i := 0; i < N/2; i++ { + j := i * 2 + tr.Delete(boxes[j].min[:], boxes[j].max[:], boxes[j]) + } + + ///////////////////////////////////////// + // count all items. should be half of N + ///////////////////////////////////////// + count = 0 + tr.Scan(func(min, max []float64, value interface{}) bool { + count++ + return true + }) + if count != N/2 { + t.Fatalf("expected %d, got %d", N/2, count) + } + + /////////////////////////////////////////////////// + // reinsert every other item, but in random order + /////////////////////////////////////////////////// + var ij []int + for i := 0; i < N/2; i++ { + j := i * 2 + ij = append(ij, j) + } + rand.Shuffle(len(ij), func(i, j int) { + ij[i], ij[j] = ij[j], ij[i] + }) + for i := 0; i < N/2; i++ { + j := ij[i] + tr.Insert(boxes[j].min[:], boxes[j].max[:], boxes[j]) + } + + ////////////////////////////////////////////////////// + // replace each item with an item that is very close + ////////////////////////////////////////////////////// + var nboxes = make([]tBox, N) + for i := 0; i < N; i++ { + for j := 0; j < len(boxes[i].min); j++ { + nboxes[i].min[j] = boxes[i].min[j] + (rand.Float64() - 0.5) + if boxes[i].min == boxes[i].max { + nboxes[i].max[j] = nboxes[i].min[j] + } else { + nboxes[i].max[j] = boxes[i].max[j] + (rand.Float64() - 0.5) + } + } + + } + for i := 0; i < N; i++ { + tr.Insert(nboxes[i].min[:], nboxes[i].max[:], nboxes[i]) + tr.Delete(boxes[i].min[:], boxes[i].max[:], boxes[i]) + } + if tr.Count() != N { + t.Fatalf("expected %d, got %d", N, tr.Count()) + } + // area = tr.TotalOverlapArea() + // fmt.Fprintf(wr, "overlap: %.0f, %.1f/item\n", area, area/float64(N)) + + ///////////////////////////////////////// + // check every point for correctness + ///////////////////////////////////////// + tboxes1 = nil + tr.Scan(func(min, max []float64, value interface{}) bool { + tboxes1 = append(tboxes1, value.(tBox)) + return true + }) + tboxes2 = make([]tBox, len(nboxes)) + copy(tboxes2, nboxes) + sortBoxes(tboxes1) + sortBoxes(tboxes2) + for i := 0; i < len(tboxes1); i++ { + if tboxes1[i] != tboxes2[i] { + t.Fatalf("expected '%v', got '%v'", tboxes2[i], tboxes1[i]) + } + } + + ///////////////////////////////////////// + // search for 10% of the items + ///////////////////////////////////////// + for i := 0; i < N/5; i++ { + var count int + tr.Search(centerMin, centerMax, + func(min, max []float64, value interface{}) bool { + count++ + return true + }, + ) + } + + var boxes3 []tBox + tr.Nearby(centerMin, centerMax, + func(min, max []float64, value interface{}) bool { + boxes3 = append(boxes3, value.(tBox)) + return true + }, + ) + if len(boxes3) != len(nboxes) { + t.Fatalf("expected %d, got %d", len(nboxes), len(boxes3)) + } + if len(boxes3) != tr.Count() { + t.Fatalf("expected %d, got %d", tr.Count(), len(boxes3)) + } + var ldist float64 + for i, box := range boxes3 { + dist := testBoxDist(box.min[:], box.max[:], centerMin, centerMax) + if i > 0 && dist < ldist { + t.Fatalf("out of order") + } + ldist = dist + } +} + +func TestRandomBoxes(t *testing.T) { + testBoxesVarious(t, randBoxes(10000), "boxes") +} + +func TestRandomPoints(t *testing.T) { + testBoxesVarious(t, randPoints(10000), "points") +} + +func (r *box) boxstr() string { + var b []byte + b = append(b, '[', '[') + for i := 0; i < len(r.min); i++ { + if i != 0 { + b = append(b, ' ') + } + b = strconv.AppendFloat(b, r.min[i], 'f', -1, 64) + } + b = append(b, ']', '[') + for i := 0; i < len(r.max); i++ { + if i != 0 { + b = append(b, ' ') + } + b = strconv.AppendFloat(b, r.max[i], 'f', -1, 64) + } + b = append(b, ']', ']') + return string(b) +} + +func (r *box) print(height, indent int) { + fmt.Printf("%s%s", strings.Repeat(" ", indent), r.boxstr()) + if height == 0 { + fmt.Printf("\t'%v'\n", r.data) + } else { + fmt.Printf("\n") + for i := 0; i < r.data.(*node).count; i++ { + r.data.(*node).boxes[i].print(height-1, indent+1) + } + } + +} + +func (tr BoxTree) print() { + if tr.root.data == nil { + println("EMPTY TREE") + return + } + tr.root.print(tr.height+1, 0) +} + +func TestZeroPoints(t *testing.T) { + N := 10000 + var tr BoxTree + pt := make([]float64, dims) + for i := 0; i < N; i++ { + tr.Insert(pt, nil, i) + } +} + +func BenchmarkRandomInsert(b *testing.B) { + var tr BoxTree + boxes := randBoxes(b.N) + b.ResetTimer() + for i := 0; i < b.N; i++ { + tr.Insert(boxes[i].min[:], boxes[i].max[:], i) + } +} diff --git a/vendor/github.com/tidwall/boxtree/res/cities.png b/vendor/github.com/tidwall/boxtree/res/cities.png new file mode 100644 index 0000000000000000000000000000000000000000..af06bb379834f80a424067f418056ae7d50f3e5a GIT binary patch literal 344308 zcmeGD^;cBw_Xdvps2Cungo1!5-Q6J|Al+SpbaxFfh#~?4(jC$;3?mXlBQYS|&Co*) z-7yTGbzEY>>Q%$#%X*n8jmy7qO4tEx^)X*;q4pETelv* zzIE$P#Dm+we-@B8GQj1Tr>wrGmW#EgkGZ?mEh$SE3#%6jPUbdNnpWnPes0}XVz+Q! zCn>y<()OL%M&9=&K`i__KsNN6`0pitGA$6?l#NKx(^kjkGEIpx;fCP6A$fCGR+gAl z3P+Zob#VJ#eAvxm^CeM^D?%jxx^r1_prNZ3YAIb~%$m9MF;fescWP zx$ge2aqIPo)GfmQYZc2qSp4VzTH_D?5&OSJ4h3!S{r_uezq-5se~n=KPq(Q5ucaPE z^y|+5wMvO^`~F|!HNW)#_p<-@PNN30FKXvHV6TP{&b{$x(f7?t-oLGdSROh3tn5@@ z+IBqQ*Di3&hW98ngj>y^n+RY`w%E>h;$g2f}XfkO=i!996s#Roji^{9YGm9w9< zX&QWQ0dxJF5A@9^U+@SY_~@2k_HktT$uP}zOQ6~Ibam(6cK6tc^jZpzpR6RK_Nj%@ zIxQ}JjRUI7ofmQYpwR1tR4@i>Ixy%JxlYuS;bQN1vp0OhO#nQp_998_Ctc7{Ki0?u zQTwld*#AgsWxodx%#90;I(r(w68G^{h{>F>vo)hQe(&9*53+;-T>&QB8|CApgB
    239hP`y%+DJM5@2-y#l;^b?{llZr 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

    +!@FsgjsE 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 fxZwKz{yHj>EN<6HRGikODWxEv7;g^G2e\n", + (min[0])*svgScale, + (min[1])*svgScale, + (max[0]-min[0]+1/svgScale)*svgScale, + (max[1]-min[1]+1/svgScale)*svgScale, + strokes[height%len(strokes)]) + } else { // is rect + out += fmt.Sprintf( + "\n", + (min[0])*svgScale, + (min[1])*svgScale, + (max[0]-min[0]+1/svgScale)*svgScale, + (max[1]-min[1]+1/svgScale)*svgScale, + strokes[height%len(strokes)]) + } + return out +} + +const ( + // Continue to first child rectangle and/or next sibling. + Continue = iota + // Ignore child rectangles but continue to next sibling. + Ignore + // Stop iterating + Stop +) + +const svgScale = 4.0 + +var strokes = [...]string{"black", "#cccc00", "green", "red", "purple"} + +// SVG prints 2D rtree in wgs84 coordinate space +func SVG(tr RTree) string { + var out string + out += fmt.Sprintf("\n", + -190.0*svgScale, -100.0*svgScale, + 380.0*svgScale, 190.0*svgScale) + + out += fmt.Sprintf("\n") + var outb []byte + tr.Traverse(func(min, max []float64, height, level int, _ interface{}) int { + outb = append(outb, svg(min, max, height)...) + return Continue + }) + out += string(outb) + out += fmt.Sprintf("\n") + out += fmt.Sprintf("\n") + return out +} + +// Cities returns big list of cities base on json from +// https://github.com/lutangar/cities.json +func Cities(bigJSON string) [][2]float64 { + var out [][2]float64 + s := bigJSON + for i := 0; ; i++ { + idx := strings.Index(s, `"lat": "`) + if idx == -1 { + break + } + s = s[idx+8:] + idx = strings.IndexByte(s, '"') + lat, _ := strconv.ParseFloat(s[:idx], 64) + idx = strings.Index(s, `"lng": "`) + s = s[idx+8:] + idx = strings.IndexByte(s, '"') + lng, _ := strconv.ParseFloat(s[:idx], 64) + s = s[idx+1:] + out = append(out, [2]float64{lng, lat}) + } + return out +} diff --git a/vendor/github.com/tidwall/tinyqueue/LICENSE b/vendor/github.com/tidwall/tinyqueue/LICENSE deleted file mode 100644 index 2b7cd9d3..00000000 --- a/vendor/github.com/tidwall/tinyqueue/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -ISC License - -Copyright (c) 2017, Vladimir Agafonkin - -Permission to use, copy, modify, and/or distribute this software for any purpose -with or without fee is hereby granted, provided that the above copyright notice -and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. diff --git a/vendor/github.com/tidwall/tinyqueue/README.md b/vendor/github.com/tidwall/tinyqueue/README.md deleted file mode 100644 index f4edc916..00000000 --- a/vendor/github.com/tidwall/tinyqueue/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# tinyqueue -GoDoc - -tinyqueue is a Go package for binary heap priority queues. -Ported from the [tinyqueue](https://github.com/mourner/tinyqueue) Javascript library. - - diff --git a/vendor/github.com/tidwall/tinyqueue/tinyqueue.go b/vendor/github.com/tidwall/tinyqueue/tinyqueue.go deleted file mode 100644 index 4a06258a..00000000 --- a/vendor/github.com/tidwall/tinyqueue/tinyqueue.go +++ /dev/null @@ -1,86 +0,0 @@ -package tinyqueue - -type Queue struct { - length int - data []Item -} - -type Item interface { - Less(Item) bool -} - -func New(data []Item) *Queue { - q := &Queue{} - q.data = data - q.length = len(data) - if q.length > 0 { - i := q.length >> 1 - for ; i >= 0; i-- { - q.down(i) - } - } - return q -} - -func (q *Queue) Push(item Item) { - q.data = append(q.data, item) - q.length++ - q.up(q.length - 1) -} -func (q *Queue) Pop() Item { - if q.length == 0 { - return nil - } - top := q.data[0] - q.length-- - if q.length > 0 { - q.data[0] = q.data[q.length] - q.down(0) - } - q.data = q.data[:len(q.data)-1] - return top -} -func (q *Queue) Peek() Item { - if q.length == 0 { - return nil - } - return q.data[0] -} -func (q *Queue) Len() int { - return q.length -} -func (q *Queue) down(pos int) { - data := q.data - halfLength := q.length >> 1 - item := data[pos] - for pos < halfLength { - left := (pos << 1) + 1 - right := left + 1 - best := data[left] - if right < q.length && data[right].Less(best) { - left = right - best = data[right] - } - if !best.Less(item) { - break - } - data[pos] = best - pos = left - } - data[pos] = item -} - -func (q *Queue) up(pos int) { - data := q.data - item := data[pos] - for pos > 0 { - parent := (pos - 1) >> 1 - current := data[parent] - if !item.Less(current) { - break - } - data[pos] = current - pos = parent - } - data[pos] = item -} diff --git a/vendor/github.com/tidwall/tinyqueue/tinyqueue_test.go b/vendor/github.com/tidwall/tinyqueue/tinyqueue_test.go deleted file mode 100644 index 9d34df4f..00000000 --- a/vendor/github.com/tidwall/tinyqueue/tinyqueue_test.go +++ /dev/null @@ -1,65 +0,0 @@ -package tinyqueue - -import ( - "math/rand" - "sort" - "testing" - "time" - - "github.com/json-iterator/go/assert" -) - -type floatValue float64 - -func (a floatValue) Less(b Item) bool { - return a < b.(floatValue) -} - -var data, sorted = func() ([]Item, []Item) { - rand.Seed(time.Now().UnixNano()) - var data []Item - for i := 0; i < 100; i++ { - data = append(data, floatValue(rand.Float64()*100)) - } - sorted := make([]Item, len(data)) - copy(sorted, data) - sort.Slice(sorted, func(i, j int) bool { - return sorted[i].Less(sorted[j]) - }) - return data, sorted -}() - -func TestMaintainsPriorityQueue(t *testing.T) { - q := New(nil) - for i := 0; i < len(data); i++ { - q.Push(data[i]) - } - assert.Equal(t, q.Peek(), sorted[0]) - var result []Item - for q.length > 0 { - result = append(result, q.Pop()) - } - assert.Equal(t, result, sorted) -} - -func TestAcceptsDataInConstructor(t *testing.T) { - q := New(data) - var result []Item - for q.length > 0 { - result = append(result, q.Pop()) - } - assert.Equal(t, result, sorted) -} -func TestHandlesEdgeCasesWithFewElements(t *testing.T) { - q := New(nil) - q.Push(floatValue(2)) - q.Push(floatValue(1)) - q.Pop() - q.Pop() - q.Pop() - q.Push(floatValue(2)) - q.Push(floatValue(1)) - assert.Equal(t, float64(q.Pop().(floatValue)), 1.0) - assert.Equal(t, float64(q.Pop().(floatValue)), 2.0) - assert.Equal(t, q.Pop(), nil) -}