diff --git a/Gopkg.lock b/Gopkg.lock index a7096cd0..fb7dfe2f 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -4,12 +4,14 @@ [[projects]] name = "cloud.google.com/go" packages = ["compute/metadata"] - revision = "0677a068e184b780ac5966664e075b9486d19a93" + revision = "767c40d6a2e058483c25fa193e963a22da17236d" + version = "v0.18.0" [[projects]] name = "github.com/boltdb/bolt" packages = ["."] - revision = "e9cf4fae01b5a8ff89d0ec6b32f0d9c9f79aefdd" + revision = "2f1ce7a837dcb8da3ec595b1dac9d0632f0f99e8" + version = "v1.3.1" [[projects]] name = "github.com/davecgh/go-spew" @@ -21,11 +23,18 @@ name = "github.com/didip/tollbooth" packages = [ ".", - "config", "errors", - "libstring" + "libstring", + "limiter" ] - revision = "9adc32f5171e833befc340a64b63602529fc0373" + revision = "c95eaa3ddc98f635a91e218b48727fb2e06613ea" + version = "v4.0.0" + +[[projects]] + branch = "master" + name = "github.com/didip/tollbooth_chi" + packages = ["."] + revision = "6ab5f3083f3d925e1944d58cdaebf43bbbff9238" [[projects]] branch = "master" @@ -61,15 +70,16 @@ revision = "08b5f424b9271eedf6f9f0ce86cb9396ed337a42" [[projects]] - branch = "master" name = "github.com/gorilla/securecookie" packages = ["."] - revision = "e59506cc896acb7f7bf732d4fdf5e25f7ccd8983" + revision = "667fe4e3466a040b780561fe9b51a83a3753eefc" + version = "v1.1" [[projects]] name = "github.com/gorilla/sessions" packages = ["."] - revision = "a3acf13e802c358d65f249324d14ed24aac11370" + revision = "ca9ada44574153444b00d3fd9c8559e4cc95f896" + version = "v1.1" [[projects]] branch = "master" @@ -80,12 +90,8 @@ [[projects]] name = "github.com/jessevdk/go-flags" packages = ["."] - revision = "f2785f5820ec967043de79c8be97edfc464ca745" - -[[projects]] - name = "github.com/juju/ratelimit" - packages = ["."] - revision = "77ed1c8a01217656d2080ad51981f6e99adaa177" + revision = "96dc06278ce32a0e9d957d590bb987c81ee66407" + version = "v1.3.0" [[projects]] branch = "master" @@ -102,7 +108,8 @@ [[projects]] name = "github.com/pkg/errors" packages = ["."] - revision = "c605e284fe17294bda444b34710735b29d1a9d90" + revision = "645ef00459ed84a119197bfb8d8205042c6df63d" + version = "v0.8.0" [[projects]] name = "github.com/pmezard/go-difflib" @@ -122,9 +129,11 @@ "assert", "require" ] - revision = "05e8a0eda380579888eb53c394909df027f06991" + revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71" + version = "v1.2.1" [[projects]] + branch = "master" name = "golang.org/x/net" packages = [ "context", @@ -132,9 +141,10 @@ "html", "html/atom" ] - revision = "d1e1b351919c6738fdeb9893d5c998b161464f0c" + revision = "f5dfe339be1d06f81b22525fe34671ee7d2c8904" [[projects]] + branch = "master" name = "golang.org/x/oauth2" packages = [ ".", @@ -145,12 +155,19 @@ "jws", "jwt" ] - revision = "0448841f0cbe9d174c6c1cedd177f583337b8e2c" + revision = "543e37812f10c46c622c9575afd7ad22f22a12ba" [[projects]] + branch = "master" name = "golang.org/x/sys" packages = ["unix"] - revision = "478fcf54317e52ab69f40bb4c7a1520288d7f7ea" + revision = "37707fdb30a5b38865cfb95e5aab41707daec7fd" + +[[projects]] + branch = "master" + name = "golang.org/x/time" + packages = ["rate"] + revision = "6dc17368e09b0e8634d71cac8168d853e869a0c7" [[projects]] name = "google.golang.org/appengine" @@ -178,6 +195,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "9e3265f58be3aeaa6ad630d749378d16bf18748f41ad9934d45c01fb2b4112c1" + inputs-digest = "a236f3e2f3ef27b096361283719cdc2d9b712b4923a754f661d6057cef545d69" solver-name = "gps-cdcl" solver-version = 1 diff --git a/app/rest/middleware.go b/app/rest/middleware.go index 80fa804c..43ad166d 100644 --- a/app/rest/middleware.go +++ b/app/rest/middleware.go @@ -13,9 +13,7 @@ import ( "strings" "time" - "github.com/didip/tollbooth" "github.com/go-chi/chi/middleware" - "github.com/go-chi/render" "github.com/umputun/remark/app/rest/common" ) @@ -23,41 +21,6 @@ import ( // JSON is a map alias, just for convenience type JSON map[string]interface{} -// Limiter middleware defines max recs/sec for given client. Client detected as a combination -// of source IP, auth key and user agent. Requests rejected with 429 status code. -func Limiter(recSec int, excludeIps ...string) func(http.Handler) http.Handler { - - return func(h http.Handler) http.Handler { - l := tollbooth.NewLimiter(int64(recSec), time.Second) - - fn := func(w http.ResponseWriter, r *http.Request) { - - for _, exclIP := range excludeIps { - if strings.HasPrefix(r.RemoteAddr, exclIP) { - h.ServeHTTP(w, r) - return - } - } - - keys := []string{ - r.Header.Get("RemoteAddr"), - r.Header.Get("X-Forwarded-For"), - r.Header.Get("X-Real-IP"), - r.Header.Get("User-Agent"), - r.Header.Get("Authorization"), - } - - if httpError := tollbooth.LimitByKeys(l, keys); httpError != nil { - render.Status(r, httpError.StatusCode) - render.JSON(w, r, JSON{"error": httpError.Message}) - return - } - h.ServeHTTP(w, r) - } - return http.HandlerFunc(fn) - } -} - // AppInfo adds custom app-info to the response header func AppInfo(app string, version string) func(http.Handler) http.Handler { f := func(h http.Handler) http.Handler { diff --git a/app/rest/server.go b/app/rest/server.go index c31ae355..4736cf75 100644 --- a/app/rest/server.go +++ b/app/rest/server.go @@ -11,6 +11,8 @@ import ( "strings" "time" + "github.com/didip/tollbooth" + "github.com/didip/tollbooth_chi" "github.com/go-chi/chi" "github.com/go-chi/chi/middleware" "github.com/go-chi/render" @@ -61,7 +63,8 @@ func (s *Server) Run(port int) { router := chi.NewRouter() router.Use(middleware.RealIP, Recoverer) router.Use(middleware.Throttle(1000), middleware.Timeout(60*time.Second)) - router.Use(Limiter(10), AppInfo("remark42", s.Version), Ping, Logger(LogAll)) + router.Use(tollbooth_chi.LimitHandler(tollbooth.NewLimiter(10, nil))) + router.Use(AppInfo("remark42", s.Version), Ping, Logger(LogAll)) // all request by default allow anonymous access router.Use(auth.Auth(s.SessionStore, s.Admins, maybeWithDevMode(auth.Anonymous))) router.Use(context.ClearHandler) // if you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler diff --git a/vendor/cloud.google.com/go/.travis.yml b/vendor/cloud.google.com/go/.travis.yml deleted file mode 100644 index 59594d41..00000000 --- a/vendor/cloud.google.com/go/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -sudo: false -language: go -go: -- 1.6.x -- 1.7.x -- 1.8.x -- 1.9.x -install: -- go get -v cloud.google.com/go/... -script: -- openssl aes-256-cbc -K $encrypted_a8b3f4fc85f4_key -iv $encrypted_a8b3f4fc85f4_iv -in keys.tar.enc -out keys.tar -d -- tar xvf keys.tar -- GCLOUD_TESTS_GOLANG_PROJECT_ID="dulcet-port-762" - GCLOUD_TESTS_GOLANG_KEY="$(pwd)/dulcet-port-762-key.json" - GCLOUD_TESTS_GOLANG_FIRESTORE_PROJECT_ID="gcloud-golang-firestore-tests" - GCLOUD_TESTS_GOLANG_FIRESTORE_KEY="$(pwd)/gcloud-golang-firestore-tests-key.json" - ./run-tests.sh $TRAVIS_COMMIT -env: - matrix: - # The GCLOUD_TESTS_API_KEY environment variable. - secure: VdldogUOoubQ60LhuHJ+g/aJoBiujkSkWEWl79Zb8cvQorcQbxISS+JsOOp4QkUOU4WwaHAm8/3pIH1QMWOR6O78DaLmDKi5Q4RpkVdCpUXy+OAfQaZIcBsispMrjxLXnqFjo9ELnrArfjoeCTzaX0QTCfwQwVmigC8rR30JBKI= diff --git a/vendor/cloud.google.com/go/CONTRIBUTING.md b/vendor/cloud.google.com/go/CONTRIBUTING.md deleted file mode 100644 index 95c94a48..00000000 --- a/vendor/cloud.google.com/go/CONTRIBUTING.md +++ /dev/null @@ -1,152 +0,0 @@ -# Contributing - -1. Sign one of the contributor license agreements below. -1. `go get golang.org/x/review/git-codereview` to install the code reviewing tool. - 1. You will need to ensure that your `GOBIN` directory (by default - `$GOPATH/bin`) is in your `PATH` so that git can find the command. - 1. If you would like, you may want to set up aliases for git-codereview, - such that `git codereview change` becomes `git change`. See the - [godoc](https://godoc.org/golang.org/x/review/git-codereview) for details. - 1. Should you run into issues with the git-codereview tool, please note - that all error messages will assume that you have set up these - aliases. -1. Get the cloud package by running `go get -d cloud.google.com/go`. - 1. If you have already checked out the source, make sure that the remote git - origin is https://code.googlesource.com/gocloud: - - git remote set-url origin https://code.googlesource.com/gocloud -1. Make sure your auth is configured correctly by visiting - https://code.googlesource.com, clicking "Generate Password", and following - the directions. -1. Make changes and create a change by running `git codereview change `, -provide a commit message, and use `git codereview mail` to create a Gerrit CL. -1. Keep amending to the change with `git codereview change` and mail as your receive -feedback. Each new mailed amendment will create a new patch set for your change in Gerrit. - -## Integration Tests - -In addition to the unit tests, you may run the integration test suite. - -To run the integrations tests, creating and configuration of a project in the -Google Developers Console is required. - -After creating a project, you must [create a service account](https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatinganaccount). -Ensure the project-level **Owner** -[IAM role](console.cloud.google.com/iam-admin/iam/project) role is added to the -service account. Alternatively, the account can be granted all of the following roles: -- **Editor** -- **Logs Configuration Writer** -- **PubSub Admin** - -Once you create a project, set the following environment variables to be able to -run the against the actual APIs. - -- **GCLOUD_TESTS_GOLANG_PROJECT_ID**: Developers Console project's ID (e.g. bamboo-shift-455) -- **GCLOUD_TESTS_GOLANG_KEY**: The path to the JSON key file. -- **GCLOUD_TESTS_API_KEY**: Your API key. - -Firestore requires a different project and key: - -- **GCLOUD_TESTS_GOLANG_FIRESTORE_PROJECT_ID**: Developers Console project's ID - supporting Firestore -- **GCLOUD_TESTS_GOLANG_FIRESTORE_KEY**: The path to the JSON key file. - -Install the [gcloud command-line tool][gcloudcli] to your machine and use it -to create some resources used in integration tests. - -From the project's root directory: - -``` sh -# Set the default project in your env. -$ gcloud config set project $GCLOUD_TESTS_GOLANG_PROJECT_ID - -# Authenticate the gcloud tool with your account. -$ gcloud auth login - -# Create the indexes used in the datastore integration tests. -$ gcloud preview datastore create-indexes datastore/testdata/index.yaml - -# Create a Google Cloud storage bucket with the same name as your test project, -# and with the Stackdriver Logging service account as owner, for the sink -# integration tests in logging. -$ gsutil mb gs://$GCLOUD_TESTS_GOLANG_PROJECT_ID -$ gsutil acl ch -g cloud-logs@google.com:O gs://$GCLOUD_TESTS_GOLANG_PROJECT_ID - -# Create a PubSub topic for integration tests of storage notifications. -$ gcloud beta pubsub topics create go-storage-notification-test - -# Create a Spanner instance for the spanner integration tests. -$ gcloud beta spanner instances create go-integration-test --config regional-us-central1 --nodes 1 --description 'Instance for go client test' -# NOTE: Spanner instances are priced by the node-hour, so you may want to delete -# the instance after testing with 'gcloud beta spanner instances delete'. - - -``` - -Once you've set the environment variables, you can run the integration tests by -running: - -``` sh -$ go test -v cloud.google.com/go/... -``` - -## Contributor License Agreements - -Before we can accept your pull requests you'll need to sign a Contributor -License Agreement (CLA): - -- **If you are an individual writing original source code** and **you own the -intellectual property**, then you'll need to sign an [individual CLA][indvcla]. -- **If you work for a company that wants to allow you to contribute your -work**, then you'll need to sign a [corporate CLA][corpcla]. - -You can sign these electronically (just scroll to the bottom). After that, -we'll be able to accept your pull requests. - -## Contributor Code of Conduct - -As contributors and maintainers of this project, -and in the interest of fostering an open and welcoming community, -we pledge to respect all people who contribute through reporting issues, -posting feature requests, updating documentation, -submitting pull requests or patches, and other activities. - -We are committed to making participation in this project -a harassment-free experience for everyone, -regardless of level of experience, gender, gender identity and expression, -sexual orientation, disability, personal appearance, -body size, race, ethnicity, age, religion, or nationality. - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery -* Personal attacks -* Trolling or insulting/derogatory comments -* Public or private harassment -* Publishing other's private information, -such as physical or electronic -addresses, without explicit permission -* Other unethical or unprofessional conduct. - -Project maintainers have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct. -By adopting this Code of Conduct, -project maintainers commit themselves to fairly and consistently -applying these principles to every aspect of managing this project. -Project maintainers who do not follow or enforce the Code of Conduct -may be permanently removed from the project team. - -This code of conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. - -Instances of abusive, harassing, or otherwise unacceptable behavior -may be reported by opening an issue -or contacting one or more of the project maintainers. - -This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, -available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) - -[gcloudcli]: https://developers.google.com/cloud/sdk/gcloud/ -[indvcla]: https://developers.google.com/open-source/cla/individual -[corpcla]: https://developers.google.com/open-source/cla/corporate diff --git a/vendor/cloud.google.com/go/LICENSE b/vendor/cloud.google.com/go/LICENSE index a4c5efd8..d6456956 100644 --- a/vendor/cloud.google.com/go/LICENSE +++ b/vendor/cloud.google.com/go/LICENSE @@ -187,7 +187,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2014 Google Inc. + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/vendor/cloud.google.com/go/MIGRATION.md b/vendor/cloud.google.com/go/MIGRATION.md deleted file mode 100644 index 791210de..00000000 --- a/vendor/cloud.google.com/go/MIGRATION.md +++ /dev/null @@ -1,54 +0,0 @@ -# Code Changes - -## v0.10.0 - -- pubsub: Replace - - ``` - sub.ModifyPushConfig(ctx, pubsub.PushConfig{Endpoint: "https://example.com/push"}) - ``` - - with - - ``` - sub.Update(ctx, pubsub.SubscriptionConfigToUpdate{ - PushConfig: &pubsub.PushConfig{Endpoint: "https://example.com/push"}, - }) - ``` - -- trace: traceGRPCServerInterceptor will be provided from *trace.Client. -Given an initialized `*trace.Client` named `tc`, instead of - - ``` - s := grpc.NewServer(grpc.UnaryInterceptor(trace.GRPCServerInterceptor(tc))) - ``` - - write - - ``` - s := grpc.NewServer(grpc.UnaryInterceptor(tc.GRPCServerInterceptor())) - ``` - -- trace trace.GRPCClientInterceptor will also provided from *trace.Client. -Instead of - - ``` - conn, err := grpc.Dial(srv.Addr, grpc.WithUnaryInterceptor(trace.GRPCClientInterceptor())) - ``` - - write - - ``` - conn, err := grpc.Dial(srv.Addr, grpc.WithUnaryInterceptor(tc.GRPCClientInterceptor())) - ``` - -- trace: We removed the deprecated `trace.EnableGRPCTracing`. Use the gRPC -interceptor as a dial option as shown below when initializing Cloud package -clients: - - ``` - c, err := pubsub.NewClient(ctx, "project-id", option.WithGRPCDialOption(grpc.WithUnaryInterceptor(tc.GRPCClientInterceptor()))) - if err != nil { - ... - } - ``` diff --git a/vendor/cloud.google.com/go/README.md b/vendor/cloud.google.com/go/README.md deleted file mode 100644 index 04f492f4..00000000 --- a/vendor/cloud.google.com/go/README.md +++ /dev/null @@ -1,510 +0,0 @@ -# Google Cloud Client Libraries for Go - -[![GoDoc](https://godoc.org/cloud.google.com/go?status.svg)](https://godoc.org/cloud.google.com/go) - -Go packages for [Google Cloud Platform](https://cloud.google.com) services. - -``` go -import "cloud.google.com/go" -``` - -To install the packages on your system, - -``` -$ go get -u cloud.google.com/go/... -``` - -**NOTE:** Some of these packages are under development, and may occasionally -make backwards-incompatible changes. - -**NOTE:** Github repo is a mirror of [https://code.googlesource.com/gocloud](https://code.googlesource.com/gocloud). - - * [News](#news) - * [Supported APIs](#supported-apis) - * [Go Versions Supported](#go-versions-supported) - * [Authorization](#authorization) - * [Cloud Datastore](#cloud-datastore-) - * [Cloud Storage](#cloud-storage-) - * [Cloud Pub/Sub](#cloud-pub-sub-) - * [Cloud BigQuery](#cloud-bigquery-) - * [Stackdriver Logging](#stackdriver-logging-) - * [Cloud Spanner](#cloud-spanner-) - - -## News - -_December 11, 2017_ - -*v0.17.0* - -- firestore BREAKING CHANGES: - - Remove UpdateMap and UpdateStruct; rename UpdatePaths to Update. - Change - `docref.UpdateMap(ctx, map[string]interface{}{"a.b", 1})` - to - `docref.Update(ctx, []firestore.Update{{Path: "a.b", Value: 1}})` - - Change - `docref.UpdateStruct(ctx, []string{"Field"}, aStruct)` - to - `docref.Update(ctx, []firestore.Update{{Path: "Field", Value: aStruct.Field}})` - - Rename MergePaths to Merge; require args to be FieldPaths - - A value stored as an integer can be read into a floating-point field, and vice versa. -- bigtable/cmd/cbt: - - Support deleting a column. - - Add regex option for row read. -- spanner: Mark stable. -- storage: - - Add Reader.ContentEncoding method. - - Fix handling of SignedURL headers. -- bigquery: - - If Uploader.Put is called with no rows, it returns nil without making a - call. - - Schema inference supports the "nullable" option in struct tags for - non-required fields. - - TimePartitioning supports "Field". - - -_October 30, 2017_ - -*v0.16.0* - -- Other bigquery changes: - - `JobIterator.Next` returns `*Job`; removed `JobInfo` (BREAKING CHANGE). - - UseStandardSQL is deprecated; set UseLegacySQL to true if you need - Legacy SQL. - - Uploader.Put will generate a random insert ID if you do not provide one. - - Support time partitioning for load jobs. - - Support dry-run queries. - - A `Job` remembers its last retrieved status. - - Support retrieving job configuration. - - Support labels for jobs and tables. - - Support dataset access lists. - - Improve support for external data sources, including data from Bigtable and - Google Sheets, and tables with external data. - - Support updating a table's view configuration. - - Fix uploading civil times with nanoseconds. - -- storage: - - Support PubSub notifications. - - Support Requester Pays buckets. - -- profiler: Support goroutine and mutex profile types. - - -_October 3, 2017_ - -*v0.15.0* - -- firestore: beta release. See the - [announcement](https://firebase.googleblog.com/2017/10/introducing-cloud-firestore.html). - -- errorreporting: The existing package has been redesigned. - -- errors: This package has been removed. Use errorreporting. - - -[Older news](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/old-news.md) - -## Supported APIs - -Google API | Status | Package ----------------------------------|--------------|----------------------------------------------------------- -[BigQuery][cloud-bigquery] | beta | [`cloud.google.com/go/bigquery`][cloud-bigquery-ref] -[Bigtable][cloud-bigtable] | beta | [`cloud.google.com/go/bigtable`][cloud-bigtable-ref] -[Container][cloud-container] | alpha | [`cloud.google.com/go/container/apiv1`][cloud-container-ref] -[Data Loss Prevention][cloud-dlp]| alpha | [`cloud.google.com/go/dlp/apiv2beta1`][cloud-dlp-ref] -[Datastore][cloud-datastore] | stable | [`cloud.google.com/go/datastore`][cloud-datastore-ref] -[Debugger][cloud-debugger] | alpha | [`cloud.google.com/go/debugger/apiv2`][cloud-debugger-ref] -[ErrorReporting][cloud-errors] | alpha | [`cloud.google.com/go/errorreporting`][cloud-errors-ref] -[Firestore][cloud-firestore] | beta | [`cloud.google.com/go/firestore`][cloud-firestore-ref] -[Language][cloud-language] | stable | [`cloud.google.com/go/language/apiv1`][cloud-language-ref] -[Logging][cloud-logging] | stable | [`cloud.google.com/go/logging`][cloud-logging-ref] -[Monitoring][cloud-monitoring] | beta | [`cloud.google.com/go/monitoring/apiv3`][cloud-monitoring-ref] -[Pub/Sub][cloud-pubsub] | beta | [`cloud.google.com/go/pubsub`][cloud-pubsub-ref] -[Spanner][cloud-spanner] | stable | [`cloud.google.com/go/spanner`][cloud-spanner-ref] -[Speech][cloud-speech] | stable | [`cloud.google.com/go/speech/apiv1`][cloud-speech-ref] -[Storage][cloud-storage] | stable | [`cloud.google.com/go/storage`][cloud-storage-ref] -[Translation][cloud-translation] | stable | [`cloud.google.com/go/translate`][cloud-translation-ref] -[Video Intelligence][cloud-video]| beta | [`cloud.google.com/go/videointelligence/apiv1beta1`][cloud-video-ref] -[Vision][cloud-vision] | stable | [`cloud.google.com/go/vision/apiv1`][cloud-vision-ref] - - -> **Alpha status**: the API is still being actively developed. As a -> result, it might change in backward-incompatible ways and is not recommended -> for production use. -> -> **Beta status**: the API is largely complete, but still has outstanding -> features and bugs to be addressed. There may be minor backwards-incompatible -> changes where necessary. -> -> **Stable status**: the API is mature and ready for production use. We will -> continue addressing bugs and feature requests. - -Documentation and examples are available at -https://godoc.org/cloud.google.com/go - -Visit or join the -[google-api-go-announce group](https://groups.google.com/forum/#!forum/google-api-go-announce) -for updates on these packages. - -## Go Versions Supported - -We support the two most recent major versions of Go. If Google App Engine uses -an older version, we support that as well. You can see which versions are -currently supported by looking at the lines following `go:` in -[`.travis.yml`](.travis.yml). - -## Authorization - -By default, each API will use [Google Application Default Credentials][default-creds] -for authorization credentials used in calling the API endpoints. This will allow your -application to run in many environments without requiring explicit configuration. - -[snip]:# (auth) -```go -client, err := storage.NewClient(ctx) -``` - -To authorize using a -[JSON key file](https://cloud.google.com/iam/docs/managing-service-account-keys), -pass -[`option.WithServiceAccountFile`](https://godoc.org/google.golang.org/api/option#WithServiceAccountFile) -to the `NewClient` function of the desired package. For example: - -[snip]:# (auth-JSON) -```go -client, err := storage.NewClient(ctx, option.WithServiceAccountFile("path/to/keyfile.json")) -``` - -You can exert more control over authorization by using the -[`golang.org/x/oauth2`](https://godoc.org/golang.org/x/oauth2) package to -create an `oauth2.TokenSource`. Then pass -[`option.WithTokenSource`](https://godoc.org/google.golang.org/api/option#WithTokenSource) -to the `NewClient` function: -[snip]:# (auth-ts) -```go -tokenSource := ... -client, err := storage.NewClient(ctx, option.WithTokenSource(tokenSource)) -``` - -## Cloud Datastore [![GoDoc](https://godoc.org/cloud.google.com/go/datastore?status.svg)](https://godoc.org/cloud.google.com/go/datastore) - -- [About Cloud Datastore][cloud-datastore] -- [Activating the API for your project][cloud-datastore-activation] -- [API documentation][cloud-datastore-docs] -- [Go client documentation](https://godoc.org/cloud.google.com/go/datastore) -- [Complete sample program](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/datastore/tasks) - -### Example Usage - -First create a `datastore.Client` to use throughout your application: - -[snip]:# (datastore-1) -```go -client, err := datastore.NewClient(ctx, "my-project-id") -if err != nil { - log.Fatal(err) -} -``` - -Then use that client to interact with the API: - -[snip]:# (datastore-2) -```go -type Post struct { - Title string - Body string `datastore:",noindex"` - PublishedAt time.Time -} -keys := []*datastore.Key{ - datastore.NameKey("Post", "post1", nil), - datastore.NameKey("Post", "post2", nil), -} -posts := []*Post{ - {Title: "Post 1", Body: "...", PublishedAt: time.Now()}, - {Title: "Post 2", Body: "...", PublishedAt: time.Now()}, -} -if _, err := client.PutMulti(ctx, keys, posts); err != nil { - log.Fatal(err) -} -``` - -## Cloud Storage [![GoDoc](https://godoc.org/cloud.google.com/go/storage?status.svg)](https://godoc.org/cloud.google.com/go/storage) - -- [About Cloud Storage][cloud-storage] -- [API documentation][cloud-storage-docs] -- [Go client documentation](https://godoc.org/cloud.google.com/go/storage) -- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/storage) - -### Example Usage - -First create a `storage.Client` to use throughout your application: - -[snip]:# (storage-1) -```go -client, err := storage.NewClient(ctx) -if err != nil { - log.Fatal(err) -} -``` - -[snip]:# (storage-2) -```go -// Read the object1 from bucket. -rc, err := client.Bucket("bucket").Object("object1").NewReader(ctx) -if err != nil { - log.Fatal(err) -} -defer rc.Close() -body, err := ioutil.ReadAll(rc) -if err != nil { - log.Fatal(err) -} -``` - -## Cloud Pub/Sub [![GoDoc](https://godoc.org/cloud.google.com/go/pubsub?status.svg)](https://godoc.org/cloud.google.com/go/pubsub) - -- [About Cloud Pubsub][cloud-pubsub] -- [API documentation][cloud-pubsub-docs] -- [Go client documentation](https://godoc.org/cloud.google.com/go/pubsub) -- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/pubsub) - -### Example Usage - -First create a `pubsub.Client` to use throughout your application: - -[snip]:# (pubsub-1) -```go -client, err := pubsub.NewClient(ctx, "project-id") -if err != nil { - log.Fatal(err) -} -``` - -Then use the client to publish and subscribe: - -[snip]:# (pubsub-2) -```go -// Publish "hello world" on topic1. -topic := client.Topic("topic1") -res := topic.Publish(ctx, &pubsub.Message{ - Data: []byte("hello world"), -}) -// The publish happens asynchronously. -// Later, you can get the result from res: -... -msgID, err := res.Get(ctx) -if err != nil { - log.Fatal(err) -} - -// Use a callback to receive messages via subscription1. -sub := client.Subscription("subscription1") -err = sub.Receive(ctx, func(ctx context.Context, m *pubsub.Message) { - fmt.Println(m.Data) - m.Ack() // Acknowledge that we've consumed the message. -}) -if err != nil { - log.Println(err) -} -``` - -## Cloud BigQuery [![GoDoc](https://godoc.org/cloud.google.com/go/bigquery?status.svg)](https://godoc.org/cloud.google.com/go/bigquery) - -- [About Cloud BigQuery][cloud-bigquery] -- [API documentation][cloud-bigquery-docs] -- [Go client documentation][cloud-bigquery-ref] -- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/bigquery) - -### Example Usage - -First create a `bigquery.Client` to use throughout your application: -[snip]:# (bq-1) -```go -c, err := bigquery.NewClient(ctx, "my-project-ID") -if err != nil { - // TODO: Handle error. -} -``` - -Then use that client to interact with the API: -[snip]:# (bq-2) -```go -// Construct a query. -q := c.Query(` - SELECT year, SUM(number) - FROM [bigquery-public-data:usa_names.usa_1910_2013] - WHERE name = "William" - GROUP BY year - ORDER BY year -`) -// Execute the query. -it, err := q.Read(ctx) -if err != nil { - // TODO: Handle error. -} -// Iterate through the results. -for { - var values []bigquery.Value - err := it.Next(&values) - if err == iterator.Done { - break - } - if err != nil { - // TODO: Handle error. - } - fmt.Println(values) -} -``` - - -## Stackdriver Logging [![GoDoc](https://godoc.org/cloud.google.com/go/logging?status.svg)](https://godoc.org/cloud.google.com/go/logging) - -- [About Stackdriver Logging][cloud-logging] -- [API documentation][cloud-logging-docs] -- [Go client documentation][cloud-logging-ref] -- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/logging) - -### Example Usage - -First create a `logging.Client` to use throughout your application: -[snip]:# (logging-1) -```go -ctx := context.Background() -client, err := logging.NewClient(ctx, "my-project") -if err != nil { - // TODO: Handle error. -} -``` - -Usually, you'll want to add log entries to a buffer to be periodically flushed -(automatically and asynchronously) to the Stackdriver Logging service. -[snip]:# (logging-2) -```go -logger := client.Logger("my-log") -logger.Log(logging.Entry{Payload: "something happened!"}) -``` - -Close your client before your program exits, to flush any buffered log entries. -[snip]:# (logging-3) -```go -err = client.Close() -if err != nil { - // TODO: Handle error. -} -``` - -## Cloud Spanner [![GoDoc](https://godoc.org/cloud.google.com/go/spanner?status.svg)](https://godoc.org/cloud.google.com/go/spanner) - -- [About Cloud Spanner][cloud-spanner] -- [API documentation][cloud-spanner-docs] -- [Go client documentation](https://godoc.org/cloud.google.com/go/spanner) - -### Example Usage - -First create a `spanner.Client` to use throughout your application: - -[snip]:# (spanner-1) -```go -client, err := spanner.NewClient(ctx, "projects/P/instances/I/databases/D") -if err != nil { - log.Fatal(err) -} -``` - -[snip]:# (spanner-2) -```go -// Simple Reads And Writes -_, err = client.Apply(ctx, []*spanner.Mutation{ - spanner.Insert("Users", - []string{"name", "email"}, - []interface{}{"alice", "a@example.com"})}) -if err != nil { - log.Fatal(err) -} -row, err := client.Single().ReadRow(ctx, "Users", - spanner.Key{"alice"}, []string{"email"}) -if err != nil { - log.Fatal(err) -} -``` - - -## Contributing - -Contributions are welcome. Please, see the -[CONTRIBUTING](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/CONTRIBUTING.md) -document for details. We're using Gerrit for our code reviews. Please don't open pull -requests against this repo, new pull requests will be automatically closed. - -Please note that this project is released with a Contributor Code of Conduct. -By participating in this project you agree to abide by its terms. -See [Contributor Code of Conduct](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/CONTRIBUTING.md#contributor-code-of-conduct) -for more information. - -[cloud-datastore]: https://cloud.google.com/datastore/ -[cloud-datastore-ref]: https://godoc.org/cloud.google.com/go/datastore -[cloud-datastore-docs]: https://cloud.google.com/datastore/docs -[cloud-datastore-activation]: https://cloud.google.com/datastore/docs/activate - -[cloud-firestore]: https://cloud.google.com/firestore/ -[cloud-firestore-ref]: https://godoc.org/cloud.google.com/go/firestore -[cloud-firestore-docs]: https://cloud.google.com/firestore/docs -[cloud-firestore-activation]: https://cloud.google.com/firestore/docs/activate - -[cloud-pubsub]: https://cloud.google.com/pubsub/ -[cloud-pubsub-ref]: https://godoc.org/cloud.google.com/go/pubsub -[cloud-pubsub-docs]: https://cloud.google.com/pubsub/docs - -[cloud-storage]: https://cloud.google.com/storage/ -[cloud-storage-ref]: https://godoc.org/cloud.google.com/go/storage -[cloud-storage-docs]: https://cloud.google.com/storage/docs -[cloud-storage-create-bucket]: https://cloud.google.com/storage/docs/cloud-console#_creatingbuckets - -[cloud-bigtable]: https://cloud.google.com/bigtable/ -[cloud-bigtable-ref]: https://godoc.org/cloud.google.com/go/bigtable - -[cloud-bigquery]: https://cloud.google.com/bigquery/ -[cloud-bigquery-docs]: https://cloud.google.com/bigquery/docs -[cloud-bigquery-ref]: https://godoc.org/cloud.google.com/go/bigquery - -[cloud-logging]: https://cloud.google.com/logging/ -[cloud-logging-docs]: https://cloud.google.com/logging/docs -[cloud-logging-ref]: https://godoc.org/cloud.google.com/go/logging - -[cloud-monitoring]: https://cloud.google.com/monitoring/ -[cloud-monitoring-ref]: https://godoc.org/cloud.google.com/go/monitoring/apiv3 - -[cloud-vision]: https://cloud.google.com/vision -[cloud-vision-ref]: https://godoc.org/cloud.google.com/go/vision/apiv1 - -[cloud-language]: https://cloud.google.com/natural-language -[cloud-language-ref]: https://godoc.org/cloud.google.com/go/language/apiv1 - -[cloud-speech]: https://cloud.google.com/speech -[cloud-speech-ref]: https://godoc.org/cloud.google.com/go/speech/apiv1 - -[cloud-spanner]: https://cloud.google.com/spanner/ -[cloud-spanner-ref]: https://godoc.org/cloud.google.com/go/spanner -[cloud-spanner-docs]: https://cloud.google.com/spanner/docs - -[cloud-translation]: https://cloud.google.com/translation -[cloud-translation-ref]: https://godoc.org/cloud.google.com/go/translation - -[cloud-video]: https://cloud.google.com/video-intelligence/ -[cloud-video-ref]: https://godoc.org/cloud.google.com/go/videointelligence/apiv1beta1 - -[cloud-errors]: https://cloud.google.com/error-reporting/ -[cloud-errors-ref]: https://godoc.org/cloud.google.com/go/errorreporting - -[cloud-container]: https://cloud.google.com/containers/ -[cloud-container-ref]: https://godoc.org/cloud.google.com/go/container/apiv1 - -[cloud-debugger]: https://cloud.google.com/debugger/ -[cloud-debugger-ref]: https://godoc.org/cloud.google.com/go/debugger/apiv2 - -[cloud-dlp]: https://cloud.google.com/dlp/ -[cloud-dlp-ref]: https://godoc.org/cloud.google.com/go/dlp/apiv2beta1 - -[default-creds]: https://developers.google.com/identity/protocols/application-default-credentials diff --git a/vendor/cloud.google.com/go/appveyor.yml b/vendor/cloud.google.com/go/appveyor.yml deleted file mode 100644 index e66cd00a..00000000 --- a/vendor/cloud.google.com/go/appveyor.yml +++ /dev/null @@ -1,32 +0,0 @@ -# This file configures AppVeyor (http://www.appveyor.com), -# a Windows-based CI service similar to Travis. - -# Identifier for this run -version: "{build}" - -# Clone the repo into this path, which conforms to the standard -# Go workspace structure. -clone_folder: c:\gopath\src\cloud.google.com\go - -environment: - GOPATH: c:\gopath - GCLOUD_TESTS_GOLANG_PROJECT_ID: dulcet-port-762 - GCLOUD_TESTS_GOLANG_KEY: c:\gopath\src\cloud.google.com\go\key.json - KEYFILE_CONTENTS: - secure: IvRbDAhM2PIQqzVkjzJ4FjizUvoQ+c3vG/qhJQG+HlZ/L5KEkqLu+x6WjLrExrNMyGku4znB2jmbTrUW3Ob4sGG+R5vvqeQ3YMHCVIkw5CxY+/bUDkW5RZWsVbuCnNa/vKsWmCP+/sZW6ICe29yKJ2ZOb6QaauI4s9R6j+cqBbU9pumMGYFRb0Rw3uUU7DKmVFCy+NjTENZIlDP9rmjANgAzigowJJEb2Tg9sLlQKmQeKiBSRN8lKc5Nq60a+fIzHGKvql4eIitDDDpOpyHv15/Xr1BzFw2yDoiR4X1lng0u7q0X9RgX4VIYa6gT16NXBEmQgbuX8gh7SfPMp9RhiZD9sVUaV+yogEabYpyPnmUURo0hXwkctKaBkQlEmKvjHwF5dvbg8+yqGhwtjAgFNimXG3INrwQsfQsZskkQWanutbJf9xy50GyWWFZZdi0uT4oXP/b5P7aklPXKXsvrJKBh7RjEaqBrhi86IJwOjBspvoR4l2WmcQyxb2xzQS1pjbBJFQfYJJ8+JgsstTL8PBO9d4ybJC0li1Om1qnWxkaewvPxxuoHJ9LpRKof19yRYWBmhTXb2tTASKG/zslvl4fgG4DmQBS93WC7dsiGOhAraGw2eCTgd0lYZOhk1FjWl9TS80aktXxzH/7nTvem5ohm+eDl6O0wnTL4KXjQVNSQ1PyLn4lGRJ5MNGzBTRFWIr2API2rca4Fysyfh/UdmazPGlNbY9JPGqb9+F04QzLfqm+Zz/cHy59E7lOSMBlUI4KD6d6ZNNKNRH+/g9i+fSiyiXKugTfda8KBnWGyPwprxuWGYaiQUGUYOwJY5R6x5c4mjImAB310V+Wo33UbWFJiwxEDsiCNqW1meVkBzt2er26vh4qbgCUIQ3iM3gFPfHgy+QxkmIhic7Q1HYacQElt8AAP41M7cCKWCuZidegP37MBB//mjjiNt047ZSQEvB4tqsX/OvfbByVef+cbtVw9T0yjHvmCdPW1XrhyrCCgclu6oYYdbmc5D7BBDRbjjMWGv6YvceAbfGf6ukdB5PuV+TGEN/FoQ1QTRA6Aqf+3fLMg4mS4oyTfw5xyYNbv3qoyLPrp+BnxI53WB9p0hfMg4n9FD6NntBxjDq+Q3Lk/bjC/Y4MaRWdzbMzF9a0lgGfcw9DURlK5p7uGJC9vg34feNoQprxVEZRQ01cHLeob6eGkYm4HxSRx8JY39Mh+9wzJo+k/aIvFleNC3e35NOrkXr6wb5e42n2DwBdPqdNolTLtLFRglAL1LTpp27UjvjieWJAKfoDTR5CKl01sZqt0wPdLLcvsMj6CiPFmccUIOYeZMe86kLBD61Qa5F1EwkgO3Om2qSjW96FzL4skRc+BmU5RrHlAFSldR1wpUgtkUMv9vH5Cy+UJdcvpZ8KbmhZ2PsjF7ddJ1ve9RAw3cP325AyIMwZ77Ef1mgTM0NJze6eSW1qKlEsgt1FADPyeUu1NQTA2H2dueMPGlArWTSUgyWR9AdfpqouT7eg0JWI5w+yUZZC+/rPglYbt84oLmYpwuli0z8FyEQRPIc3EtkfWIv/yYgDr2TZ0N2KvGfpi/MAUWgxI1gleC2uKgEOEtuJthd3XZjF2NoE7IBqjQOINybcJOjyeB5vRLDY1FLuxYzdg1y1etkV4XQig/vje - -install: - # Info for debugging. - - echo %PATH% - - go version - - go env - - go get -v -d -t ./... - - -# Provide a build script, or AppVeyor will call msbuild. -build_script: - - go install -v ./... - - echo %KEYFILE_CONTENTS% > %GCLOUD_TESTS_GOLANG_KEY% - -test_script: - - go test -v ./... diff --git a/vendor/cloud.google.com/go/authexample_test.go b/vendor/cloud.google.com/go/authexample_test.go deleted file mode 100644 index fe75467f..00000000 --- a/vendor/cloud.google.com/go/authexample_test.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cloud_test - -import ( - "cloud.google.com/go/datastore" - "golang.org/x/net/context" - "google.golang.org/api/option" -) - -func Example_applicationDefaultCredentials() { - // Google Application Default Credentials is the recommended way to authorize - // and authenticate clients. - // - // See the following link on how to create and obtain Application Default Credentials: - // https://developers.google.com/identity/protocols/application-default-credentials. - client, err := datastore.NewClient(context.Background(), "project-id") - if err != nil { - // TODO: handle error. - } - _ = client // Use the client. -} - -func Example_serviceAccountFile() { - // Use a JSON key file associated with a Google service account to - // authenticate and authorize. Service Account keys can be created and - // downloaded from https://console.developers.google.com/permissions/serviceaccounts. - // - // Note: This example uses the datastore client, but the same steps apply to - // the other client libraries underneath this package. - client, err := datastore.NewClient(context.Background(), - "project-id", option.WithServiceAccountFile("/path/to/service-account-key.json")) - if err != nil { - // TODO: handle error. - } - _ = client // Use the client. -} diff --git a/vendor/cloud.google.com/go/cloud.go b/vendor/cloud.google.com/go/cloud.go deleted file mode 100644 index 6ba428dc..00000000 --- a/vendor/cloud.google.com/go/cloud.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package cloud is the root of the packages used to access Google Cloud -// Services. See https://godoc.org/cloud.google.com/go for a full list -// of sub-packages. -// -// This package documents how to authorize and authenticate the sub packages. -package cloud // import "cloud.google.com/go" diff --git a/vendor/cloud.google.com/go/compute/metadata/metadata_test.go b/vendor/cloud.google.com/go/compute/metadata/metadata_test.go deleted file mode 100644 index 9ac59269..00000000 --- a/vendor/cloud.google.com/go/compute/metadata/metadata_test.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metadata - -import ( - "os" - "sync" - "testing" -) - -func TestOnGCE_Stress(t *testing.T) { - if testing.Short() { - t.Skip("skipping in -short mode") - } - var last bool - for i := 0; i < 100; i++ { - onGCEOnce = sync.Once{} - - now := OnGCE() - if i > 0 && now != last { - t.Errorf("%d. changed from %v to %v", i, last, now) - } - last = now - } - t.Logf("OnGCE() = %v", last) -} - -func TestOnGCE_Force(t *testing.T) { - onGCEOnce = sync.Once{} - old := os.Getenv(metadataHostEnv) - defer os.Setenv(metadataHostEnv, old) - os.Setenv(metadataHostEnv, "127.0.0.1") - if !OnGCE() { - t.Error("OnGCE() = false; want true") - } -} diff --git a/vendor/cloud.google.com/go/import_test.go b/vendor/cloud.google.com/go/import_test.go deleted file mode 100644 index 839fae45..00000000 --- a/vendor/cloud.google.com/go/import_test.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cloud - -import ( - "go/parser" - "go/token" - "os" - "path/filepath" - "strconv" - "testing" -) - -func TestContextImport(t *testing.T) { - t.Parallel() - - whiteList := map[string]bool{ - "storage/go17.go": true, - } - - err := filepath.Walk(".", func(path string, fi os.FileInfo, err error) error { - if err != nil { - return err - } - if filepath.Ext(path) != ".go" || whiteList[path] { - return nil - } - - fset := token.NewFileSet() - file, err := parser.ParseFile(fset, path, nil, parser.ImportsOnly) - if err != nil { - return err - } - - for _, imp := range file.Imports { - impPath, err := strconv.Unquote(imp.Path.Value) - if err != nil { - return err - } - if impPath == "context" { - t.Errorf(`file %q import "context", want "golang.org/x/net/context"`, path) - } - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} diff --git a/vendor/cloud.google.com/go/keys.tar.enc b/vendor/cloud.google.com/go/keys.tar.enc deleted file mode 100644 index c54408c9..00000000 Binary files a/vendor/cloud.google.com/go/keys.tar.enc and /dev/null differ diff --git a/vendor/cloud.google.com/go/license_test.go b/vendor/cloud.google.com/go/license_test.go deleted file mode 100644 index f93e9e00..00000000 --- a/vendor/cloud.google.com/go/license_test.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cloud - -import ( - "bytes" - "io/ioutil" - "os" - "path/filepath" - "strings" - "testing" -) - -var sentinels = []string{ - "Copyright", - "Google", - `Licensed under the Apache License, Version 2.0 (the "License");`, -} - -func TestLicense(t *testing.T) { - t.Parallel() - err := filepath.Walk(".", func(path string, fi os.FileInfo, err error) error { - if err != nil { - return err - } - - if ext := filepath.Ext(path); ext != ".go" && ext != ".proto" { - return nil - } - if strings.HasSuffix(path, ".pb.go") { - // .pb.go files are generated from the proto files. - // .proto files must have license headers. - return nil - } - if path == "bigtable/cmd/cbt/cbtdoc.go" { - // Automatically generated. - return nil - } - - src, err := ioutil.ReadFile(path) - if err != nil { - return nil - } - src = src[:140] // Ensure all of the sentinel values are at the top of the file. - - // Find license - for _, sentinel := range sentinels { - if !bytes.Contains(src, []byte(sentinel)) { - t.Errorf("%v: license header not present. want %q", path, sentinel) - return nil - } - } - - return nil - }) - if err != nil { - t.Fatal(err) - } -} diff --git a/vendor/cloud.google.com/go/old-news.md b/vendor/cloud.google.com/go/old-news.md deleted file mode 100644 index 0c8a224d..00000000 --- a/vendor/cloud.google.com/go/old-news.md +++ /dev/null @@ -1,557 +0,0 @@ -_September 28, 2017_ - -*v0.14.0* - -- bigquery BREAKING CHANGES: - - Standard SQL is the default for queries and views. - - `Table.Create` takes `TableMetadata` as a second argument, instead of - options. - - `Dataset.Create` takes `DatasetMetadata` as a second argument. - - `DatasetMetadata` field `ID` renamed to `FullID` - - `TableMetadata` field `ID` renamed to `FullID` - -- Other bigquery changes: - - The client will append a random suffix to a provided job ID if you set - `AddJobIDSuffix` to true in a job config. - - Listing jobs is supported. - - Better retry logic. - -- vision, language, speech: clients are now stable - -- monitoring: client is now beta - -- profiler: - - Rename InstanceName to Instance, ZoneName to Zone - - Auto-detect service name and version on AppEngine. - -_September 8, 2017_ - -*v0.13.0* - -- bigquery: UseLegacySQL options for CreateTable and QueryConfig. Use these - options to continue using Legacy SQL after the client switches its default - to Standard SQL. - -- bigquery: Support for updating dataset labels. - -- bigquery: Set DatasetIterator.ProjectID to list datasets in a project other - than the client's. DatasetsInProject is no longer needed and is deprecated. - -- bigtable: Fail ListInstances when any zones fail. - -- spanner: support decoding of slices of basic types (e.g. []string, []int64, - etc.) - -- logging/logadmin: UpdateSink no longer creates a sink if it is missing - (actually a change to the underlying service, not the client) - -- profiler: Service and ServiceVersion replace Target in Config. - -_August 22, 2017_ - -*v0.12.0* - -- pubsub: Subscription.Receive now uses streaming pull. - -- pubsub: add Client.TopicInProject to access topics in a different project - than the client. - -- errors: renamed errorreporting. The errors package will be removed shortly. - -- datastore: improved retry behavior. - -- bigquery: support updates to dataset metadata, with etags. - -- bigquery: add etag support to Table.Update (BREAKING: etag argument added). - -- bigquery: generate all job IDs on the client. - -- storage: support bucket lifecycle configurations. - - -_July 31, 2017_ - -*v0.11.0* - -- Clients for spanner, pubsub and video are now in beta. - -- New client for DLP. - -- spanner: performance and testing improvements. - -- storage: requester-pays buckets are supported. - -- storage, profiler, bigtable, bigquery: bug fixes and other minor improvements. - -- pubsub: bug fixes and other minor improvements - -_June 17, 2017_ - - -*v0.10.0* - -- pubsub: Subscription.ModifyPushConfig replaced with Subscription.Update. - -- pubsub: Subscription.Receive now runs concurrently for higher throughput. - -- vision: cloud.google.com/go/vision is deprecated. Use -cloud.google.com/go/vision/apiv1 instead. - -- translation: now stable. - -- trace: several changes to the surface. See the link below. - -[Code changes required from v0.9.0.](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/MIGRATION.md) - - -_March 17, 2017_ - -Breaking Pubsub changes. -* Publish is now asynchronous -([announcement](https://groups.google.com/d/topic/google-api-go-announce/aaqRDIQ3rvU/discussion)). -* Subscription.Pull replaced by Subscription.Receive, which takes a callback ([announcement](https://groups.google.com/d/topic/google-api-go-announce/8pt6oetAdKc/discussion)). -* Message.Done replaced with Message.Ack and Message.Nack. - -_February 14, 2017_ - -Release of a client library for Spanner. See -the -[blog post](https://cloudplatform.googleblog.com/2017/02/introducing-Cloud-Spanner-a-global-database-service-for-mission-critical-applications.html). - -Note that although the Spanner service is beta, the Go client library is alpha. - -_December 12, 2016_ - -Beta release of BigQuery, DataStore, Logging and Storage. See the -[blog post](https://cloudplatform.googleblog.com/2016/12/announcing-new-google-cloud-client.html). - -Also, BigQuery now supports structs. Read a row directly into a struct with -`RowIterator.Next`, and upload a row directly from a struct with `Uploader.Put`. -You can also use field tags. See the [package documentation][cloud-bigquery-ref] -for details. - -_December 5, 2016_ - -More changes to BigQuery: - -* The `ValueList` type was removed. It is no longer necessary. Instead of - ```go - var v ValueList - ... it.Next(&v) .. - ``` - use - - ```go - var v []Value - ... it.Next(&v) ... - ``` - -* Previously, repeatedly calling `RowIterator.Next` on the same `[]Value` or - `ValueList` would append to the slice. Now each call resets the size to zero first. - -* Schema inference will infer the SQL type BYTES for a struct field of - type []byte. Previously it inferred STRING. - -* The types `uint`, `uint64` and `uintptr` are no longer supported in schema - inference. BigQuery's integer type is INT64, and those types may hold values - that are not correctly represented in a 64-bit signed integer. - -* The SQL types DATE, TIME and DATETIME are now supported. They correspond to - the `Date`, `Time` and `DateTime` types in the new `cloud.google.com/go/civil` - package. - -_November 17, 2016_ - -Change to BigQuery: values from INTEGER columns will now be returned as int64, -not int. This will avoid errors arising from large values on 32-bit systems. - -_November 8, 2016_ - -New datastore feature: datastore now encodes your nested Go structs as Entity values, -instead of a flattened list of the embedded struct's fields. -This means that you may now have twice-nested slices, eg. -```go -type State struct { - Cities []struct{ - Populations []int - } -} -``` - -See [the announcement](https://groups.google.com/forum/#!topic/google-api-go-announce/79jtrdeuJAg) for -more details. - -_November 8, 2016_ - -Breaking changes to datastore: contexts no longer hold namespaces; instead you -must set a key's namespace explicitly. Also, key functions have been changed -and renamed. - -* The WithNamespace function has been removed. To specify a namespace in a Query, use the Query.Namespace method: - ```go - q := datastore.NewQuery("Kind").Namespace("ns") - ``` - -* All the fields of Key are exported. That means you can construct any Key with a struct literal: - ```go - k := &Key{Kind: "Kind", ID: 37, Namespace: "ns"} - ``` - -* As a result of the above, the Key methods Kind, ID, d.Name, Parent, SetParent and Namespace have been removed. - -* `NewIncompleteKey` has been removed, replaced by `IncompleteKey`. Replace - ```go - NewIncompleteKey(ctx, kind, parent) - ``` - with - ```go - IncompleteKey(kind, parent) - ``` - and if you do use namespaces, make sure you set the namespace on the returned key. - -* `NewKey` has been removed, replaced by `NameKey` and `IDKey`. Replace - ```go - NewKey(ctx, kind, name, 0, parent) - NewKey(ctx, kind, "", id, parent) - ``` - with - ```go - NameKey(kind, name, parent) - IDKey(kind, id, parent) - ``` - and if you do use namespaces, make sure you set the namespace on the returned key. - -* The `Done` variable has been removed. Replace `datastore.Done` with `iterator.Done`, from the package `google.golang.org/api/iterator`. - -* The `Client.Close` method will have a return type of error. It will return the result of closing the underlying gRPC connection. - -See [the announcement](https://groups.google.com/forum/#!topic/google-api-go-announce/hqXtM_4Ix-0) for -more details. - -_October 27, 2016_ - -Breaking change to bigquery: `NewGCSReference` is now a function, -not a method on `Client`. - -New bigquery feature: `Table.LoaderFrom` now accepts a `ReaderSource`, enabling -loading data into a table from a file or any `io.Reader`. - -_October 21, 2016_ - -Breaking change to pubsub: removed `pubsub.Done`. - -Use `iterator.Done` instead, where `iterator` is the package -`google.golang.org/api/iterator`. - -_October 19, 2016_ - -Breaking changes to cloud.google.com/go/bigquery: - -* Client.Table and Client.OpenTable have been removed. - Replace - ```go - client.OpenTable("project", "dataset", "table") - ``` - with - ```go - client.DatasetInProject("project", "dataset").Table("table") - ``` - -* Client.CreateTable has been removed. - Replace - ```go - client.CreateTable(ctx, "project", "dataset", "table") - ``` - with - ```go - client.DatasetInProject("project", "dataset").Table("table").Create(ctx) - ``` - -* Dataset.ListTables have been replaced with Dataset.Tables. - Replace - ```go - tables, err := ds.ListTables(ctx) - ``` - with - ```go - it := ds.Tables(ctx) - for { - table, err := it.Next() - if err == iterator.Done { - break - } - if err != nil { - // TODO: Handle error. - } - // TODO: use table. - } - ``` - -* Client.Read has been replaced with Job.Read, Table.Read and Query.Read. - Replace - ```go - it, err := client.Read(ctx, job) - ``` - with - ```go - it, err := job.Read(ctx) - ``` - and similarly for reading from tables or queries. - -* The iterator returned from the Read methods is now named RowIterator. Its - behavior is closer to the other iterators in these libraries. It no longer - supports the Schema method; see the next item. - Replace - ```go - for it.Next(ctx) { - var vals ValueList - if err := it.Get(&vals); err != nil { - // TODO: Handle error. - } - // TODO: use vals. - } - if err := it.Err(); err != nil { - // TODO: Handle error. - } - ``` - with - ``` - for { - var vals ValueList - err := it.Next(&vals) - if err == iterator.Done { - break - } - if err != nil { - // TODO: Handle error. - } - // TODO: use vals. - } - ``` - Instead of the `RecordsPerRequest(n)` option, write - ```go - it.PageInfo().MaxSize = n - ``` - Instead of the `StartIndex(i)` option, write - ```go - it.StartIndex = i - ``` - -* ValueLoader.Load now takes a Schema in addition to a slice of Values. - Replace - ```go - func (vl *myValueLoader) Load(v []bigquery.Value) - ``` - with - ```go - func (vl *myValueLoader) Load(v []bigquery.Value, s bigquery.Schema) - ``` - - -* Table.Patch is replace by Table.Update. - Replace - ```go - p := table.Patch() - p.Description("new description") - metadata, err := p.Apply(ctx) - ``` - with - ```go - metadata, err := table.Update(ctx, bigquery.TableMetadataToUpdate{ - Description: "new description", - }) - ``` - -* Client.Copy is replaced by separate methods for each of its four functions. - All options have been replaced by struct fields. - - * To load data from Google Cloud Storage into a table, use Table.LoaderFrom. - - Replace - ```go - client.Copy(ctx, table, gcsRef) - ``` - with - ```go - table.LoaderFrom(gcsRef).Run(ctx) - ``` - Instead of passing options to Copy, set fields on the Loader: - ```go - loader := table.LoaderFrom(gcsRef) - loader.WriteDisposition = bigquery.WriteTruncate - ``` - - * To extract data from a table into Google Cloud Storage, use - Table.ExtractorTo. Set fields on the returned Extractor instead of - passing options. - - Replace - ```go - client.Copy(ctx, gcsRef, table) - ``` - with - ```go - table.ExtractorTo(gcsRef).Run(ctx) - ``` - - * To copy data into a table from one or more other tables, use - Table.CopierFrom. Set fields on the returned Copier instead of passing options. - - Replace - ```go - client.Copy(ctx, dstTable, srcTable) - ``` - with - ```go - dst.Table.CopierFrom(srcTable).Run(ctx) - ``` - - * To start a query job, create a Query and call its Run method. Set fields - on the query instead of passing options. - - Replace - ```go - client.Copy(ctx, table, query) - ``` - with - ```go - query.Run(ctx) - ``` - -* Table.NewUploader has been renamed to Table.Uploader. Instead of options, - configure an Uploader by setting its fields. - Replace - ```go - u := table.NewUploader(bigquery.UploadIgnoreUnknownValues()) - ``` - with - ```go - u := table.NewUploader(bigquery.UploadIgnoreUnknownValues()) - u.IgnoreUnknownValues = true - ``` - -_October 10, 2016_ - -Breaking changes to cloud.google.com/go/storage: - -* AdminClient replaced by methods on Client. - Replace - ```go - adminClient.CreateBucket(ctx, bucketName, attrs) - ``` - with - ```go - client.Bucket(bucketName).Create(ctx, projectID, attrs) - ``` - -* BucketHandle.List replaced by BucketHandle.Objects. - Replace - ```go - for query != nil { - objs, err := bucket.List(d.ctx, query) - if err != nil { ... } - query = objs.Next - for _, obj := range objs.Results { - fmt.Println(obj) - } - } - ``` - with - ```go - iter := bucket.Objects(d.ctx, query) - for { - obj, err := iter.Next() - if err == iterator.Done { - break - } - if err != nil { ... } - fmt.Println(obj) - } - ``` - (The `iterator` package is at `google.golang.org/api/iterator`.) - - Replace `Query.Cursor` with `ObjectIterator.PageInfo().Token`. - - Replace `Query.MaxResults` with `ObjectIterator.PageInfo().MaxSize`. - - -* ObjectHandle.CopyTo replaced by ObjectHandle.CopierFrom. - Replace - ```go - attrs, err := src.CopyTo(ctx, dst, nil) - ``` - with - ```go - attrs, err := dst.CopierFrom(src).Run(ctx) - ``` - - Replace - ```go - attrs, err := src.CopyTo(ctx, dst, &storage.ObjectAttrs{ContextType: "text/html"}) - ``` - with - ```go - c := dst.CopierFrom(src) - c.ContextType = "text/html" - attrs, err := c.Run(ctx) - ``` - -* ObjectHandle.ComposeFrom replaced by ObjectHandle.ComposerFrom. - Replace - ```go - attrs, err := dst.ComposeFrom(ctx, []*storage.ObjectHandle{src1, src2}, nil) - ``` - with - ```go - attrs, err := dst.ComposerFrom(src1, src2).Run(ctx) - ``` - -* ObjectHandle.Update's ObjectAttrs argument replaced by ObjectAttrsToUpdate. - Replace - ```go - attrs, err := obj.Update(ctx, &storage.ObjectAttrs{ContextType: "text/html"}) - ``` - with - ```go - attrs, err := obj.Update(ctx, storage.ObjectAttrsToUpdate{ContextType: "text/html"}) - ``` - -* ObjectHandle.WithConditions replaced by ObjectHandle.If. - Replace - ```go - obj.WithConditions(storage.Generation(gen), storage.IfMetaGenerationMatch(mgen)) - ``` - with - ```go - obj.Generation(gen).If(storage.Conditions{MetagenerationMatch: mgen}) - ``` - - Replace - ```go - obj.WithConditions(storage.IfGenerationMatch(0)) - ``` - with - ```go - obj.If(storage.Conditions{DoesNotExist: true}) - ``` - -* `storage.Done` replaced by `iterator.Done` (from package `google.golang.org/api/iterator`). - -_October 6, 2016_ - -Package preview/logging deleted. Use logging instead. - -_September 27, 2016_ - -Logging client replaced with preview version (see below). - -_September 8, 2016_ - -* New clients for some of Google's Machine Learning APIs: Vision, Speech, and -Natural Language. - -* Preview version of a new [Stackdriver Logging][cloud-logging] client in -[`cloud.google.com/go/preview/logging`](https://godoc.org/cloud.google.com/go/preview/logging). -This client uses gRPC as its transport layer, and supports log reading, sinks -and metrics. It will replace the current client at `cloud.google.com/go/logging` shortly. - diff --git a/vendor/cloud.google.com/go/regen-gapic.sh b/vendor/cloud.google.com/go/regen-gapic.sh deleted file mode 100755 index f6e64c51..00000000 --- a/vendor/cloud.google.com/go/regen-gapic.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -# This script generates all GAPIC clients in this repo. -# One-time setup: -# cd path/to/googleapis # https://github.com/googleapis/googleapis -# virtualenv env -# . env/bin/activate -# pip install googleapis-artman -# deactivate -# -# Regenerate: -# cd path/to/googleapis -# . env/bin/activate -# $GOPATH/src/cloud.google.com/go/regen-gapic.sh -# deactivate -# -# Being in googleapis directory is important; -# that's where we find YAML files and where artman puts the "artman-genfiles" directory. -# -# NOTE: This script does not generate the "raw" gRPC client found in google.golang.org/genproto. -# To do that, use the regen.sh script in the genproto repo instead. - -set -ex - -APIS=( -google/cloud/bigquery/datatransfer/artman_bigquerydatatransfer.yaml -google/cloud/dataproc/artman_dataproc_v1.yaml -google/cloud/language/artman_language_v1.yaml -google/cloud/language/artman_language_v1beta2.yaml -google/cloud/speech/artman_speech_v1.yaml -google/cloud/speech/artman_speech_v1beta1.yaml -google/cloud/videointelligence/artman_videointelligence_v1beta1.yaml -google/cloud/videointelligence/artman_videointelligence_v1beta2.yaml -google/cloud/vision/artman_vision_v1.yaml -google/cloud/vision/artman_vision_v1p1beta1.yaml -google/container/artman_container.yaml -google/devtools/artman_clouddebugger.yaml -google/devtools/clouderrorreporting/artman_errorreporting.yaml -google/devtools/cloudtrace/artman_cloudtrace_v1.yaml -google/devtools/cloudtrace/artman_cloudtrace_v2.yaml -google/firestore/artman_firestore.yaml -google/logging/artman_logging.yaml -google/longrunning/artman_longrunning.yaml -google/monitoring/artman_monitoring.yaml -google/privacy/dlp/artman_dlp.yaml -google/pubsub/artman_pubsub.yaml -google/spanner/admin/database/artman_spanner_admin_database.yaml -google/spanner/admin/instance/artman_spanner_admin_instance.yaml -google/spanner/artman_spanner.yaml -) - -for api in "${APIS[@]}"; do - rm -rf artman-genfiles/* - artman2 --config "$api" generate go_gapic - cp -r artman-genfiles/gapi-*/cloud.google.com/go/* $GOPATH/src/cloud.google.com/go/ -done - -go list cloud.google.com/go/... | grep apiv | xargs go test - -go test -short cloud.google.com/go/... - -echo "googleapis version: $(git rev-parse HEAD)" diff --git a/vendor/cloud.google.com/go/run-tests.sh b/vendor/cloud.google.com/go/run-tests.sh deleted file mode 100755 index f47ff50a..00000000 --- a/vendor/cloud.google.com/go/run-tests.sh +++ /dev/null @@ -1,88 +0,0 @@ -#!/bin/bash - -# Selectively run tests for this repo, based on what has changed -# in a commit. Runs short tests for the whole repo, and full tests -# for changed directories. - -set -e - -prefix=cloud.google.com/go - -dryrun=false -if [[ $1 == "-n" ]]; then - dryrun=true - shift -fi - -if [[ $1 == "" ]]; then - echo >&2 "usage: $0 [-n] COMMIT" - exit 1 -fi - -# Files or directories that cause all tests to run if modified. -declare -A run_all -run_all=([.travis.yml]=1 [run-tests.sh]=1) - -function run { - if $dryrun; then - echo $* - else - (set -x; $*) - fi -} - - -# Find all the packages that have changed in this commit. -declare -A changed_packages - -for f in $(git diff-tree --no-commit-id --name-only -r $1); do - if [[ ${run_all[$f]} == 1 ]]; then - # This change requires a full test. Do it and exit. - run go test -race -v $prefix/... - exit - fi - # Map, e.g., "spanner/client.go" to "$prefix/spanner". - d=$(dirname $f) - if [[ $d == "." ]]; then - pkg=$prefix - else - pkg=$prefix/$d - fi - changed_packages[$pkg]=1 -done - -echo "changed packages: ${!changed_packages[*]}" - - -# Reports whether its argument, a package name, depends (recursively) -# on a changed package. -function depends_on_changed_package { - # According to go list, a package does not depend on itself, so - # we test that separately. - if [[ ${changed_packages[$1]} == 1 ]]; then - return 0 - fi - for dep in $(go list -f '{{range .Deps}}{{.}} {{end}}' $1); do - if [[ ${changed_packages[$dep]} == 1 ]]; then - return 0 - fi - done - return 1 -} - -# Collect the packages into two separate lists. (It is faster go test a list of -# packages than to individually go test each one.) - -shorts= -fulls= -for pkg in $(go list $prefix/...); do # for each package in the repo - if depends_on_changed_package $pkg; then # if it depends on a changed package - fulls="$fulls $pkg" # run the full test - else # otherwise - shorts="$shorts $pkg" # run the short test - fi -done -run go test -race -v -short $shorts -if [[ $fulls != "" ]]; then - run go test -race -v $fulls -fi diff --git a/vendor/github.com/boltdb/bolt/README.md b/vendor/github.com/boltdb/bolt/README.md index d7f80e97..7d43a15b 100644 --- a/vendor/github.com/boltdb/bolt/README.md +++ b/vendor/github.com/boltdb/bolt/README.md @@ -911,5 +911,6 @@ Below is a list of public, open source projects that use Bolt: * [dcrwallet](https://github.com/decred/dcrwallet) - A wallet for the Decred cryptocurrency. * [Ironsmith](https://github.com/timshannon/ironsmith) - A simple, script-driven continuous integration (build - > test -> release) tool, with no external dependencies * [BoltHold](https://github.com/timshannon/bolthold) - An embeddable NoSQL store for Go types built on BoltDB +* [Ponzu CMS](https://ponzu-cms.org) - Headless CMS + automatic JSON API with auto-HTTPS, HTTP/2 Server Push, and flexible server framework. If you are using Bolt in a project please send a pull request to add it to the list. diff --git a/vendor/github.com/boltdb/bolt/bucket_test.go b/vendor/github.com/boltdb/bolt/bucket_test.go deleted file mode 100644 index cddbe271..00000000 --- a/vendor/github.com/boltdb/bolt/bucket_test.go +++ /dev/null @@ -1,1909 +0,0 @@ -package bolt_test - -import ( - "bytes" - "encoding/binary" - "errors" - "fmt" - "log" - "math/rand" - "os" - "strconv" - "strings" - "testing" - "testing/quick" - - "github.com/boltdb/bolt" -) - -// Ensure that a bucket that gets a non-existent key returns nil. -func TestBucket_Get_NonExistent(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if v := b.Get([]byte("foo")); v != nil { - t.Fatal("expected nil value") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket can read a value that is not flushed yet. -func TestBucket_Get_FromNode(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if v := b.Get([]byte("foo")); !bytes.Equal(v, []byte("bar")) { - t.Fatalf("unexpected value: %v", v) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket retrieved via Get() returns a nil. -func TestBucket_Get_IncompatibleValue(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - if _, err := tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo")); err != nil { - t.Fatal(err) - } - - if tx.Bucket([]byte("widgets")).Get([]byte("foo")) != nil { - t.Fatal("expected nil value") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a slice returned from a bucket has a capacity equal to its length. -// This also allows slices to be appended to since it will require a realloc by Go. -// -// https://github.com/boltdb/bolt/issues/544 -func TestBucket_Get_Capacity(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - // Write key to a bucket. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("bucket")) - if err != nil { - return err - } - return b.Put([]byte("key"), []byte("val")) - }); err != nil { - t.Fatal(err) - } - - // Retrieve value and attempt to append to it. - if err := db.Update(func(tx *bolt.Tx) error { - k, v := tx.Bucket([]byte("bucket")).Cursor().First() - - // Verify capacity. - if len(k) != cap(k) { - t.Fatalf("unexpected key slice capacity: %d", cap(k)) - } else if len(v) != cap(v) { - t.Fatalf("unexpected value slice capacity: %d", cap(v)) - } - - // Ensure slice can be appended to without a segfault. - k = append(k, []byte("123")...) - v = append(v, []byte("123")...) - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket can write a key/value. -func TestBucket_Put(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - - v := tx.Bucket([]byte("widgets")).Get([]byte("foo")) - if !bytes.Equal([]byte("bar"), v) { - t.Fatalf("unexpected value: %v", v) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket can rewrite a key in the same transaction. -func TestBucket_Put_Repeat(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("baz")); err != nil { - t.Fatal(err) - } - - value := tx.Bucket([]byte("widgets")).Get([]byte("foo")) - if !bytes.Equal([]byte("baz"), value) { - t.Fatalf("unexpected value: %v", value) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket can write a bunch of large values. -func TestBucket_Put_Large(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - count, factor := 100, 200 - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - for i := 1; i < count; i++ { - if err := b.Put([]byte(strings.Repeat("0", i*factor)), []byte(strings.Repeat("X", (count-i)*factor))); err != nil { - t.Fatal(err) - } - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - for i := 1; i < count; i++ { - value := b.Get([]byte(strings.Repeat("0", i*factor))) - if !bytes.Equal(value, []byte(strings.Repeat("X", (count-i)*factor))) { - t.Fatalf("unexpected value: %v", value) - } - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a database can perform multiple large appends safely. -func TestDB_Put_VeryLarge(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - - n, batchN := 400000, 200000 - ksize, vsize := 8, 500 - - db := MustOpenDB() - defer db.MustClose() - - for i := 0; i < n; i += batchN { - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucketIfNotExists([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - for j := 0; j < batchN; j++ { - k, v := make([]byte, ksize), make([]byte, vsize) - binary.BigEndian.PutUint32(k, uint32(i+j)) - if err := b.Put(k, v); err != nil { - t.Fatal(err) - } - } - return nil - }); err != nil { - t.Fatal(err) - } - } -} - -// Ensure that a setting a value on a key with a bucket value returns an error. -func TestBucket_Put_IncompatibleValue(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b0, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - if _, err := tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo")); err != nil { - t.Fatal(err) - } - if err := b0.Put([]byte("foo"), []byte("bar")); err != bolt.ErrIncompatibleValue { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a setting a value while the transaction is closed returns an error. -func TestBucket_Put_Closed(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } - - if err := b.Put([]byte("foo"), []byte("bar")); err != bolt.ErrTxClosed { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that setting a value on a read-only bucket returns an error. -func TestBucket_Put_ReadOnly(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - if err := b.Put([]byte("foo"), []byte("bar")); err != bolt.ErrTxNotWritable { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket can delete an existing key. -func TestBucket_Delete(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if err := b.Delete([]byte("foo")); err != nil { - t.Fatal(err) - } - if v := b.Get([]byte("foo")); v != nil { - t.Fatalf("unexpected value: %v", v) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that deleting a large set of keys will work correctly. -func TestBucket_Delete_Large(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - for i := 0; i < 100; i++ { - if err := b.Put([]byte(strconv.Itoa(i)), []byte(strings.Repeat("*", 1024))); err != nil { - t.Fatal(err) - } - } - - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - for i := 0; i < 100; i++ { - if err := b.Delete([]byte(strconv.Itoa(i))); err != nil { - t.Fatal(err) - } - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - for i := 0; i < 100; i++ { - if v := b.Get([]byte(strconv.Itoa(i))); v != nil { - t.Fatalf("unexpected value: %v, i=%d", v, i) - } - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Deleting a very large list of keys will cause the freelist to use overflow. -func TestBucket_Delete_FreelistOverflow(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - - db := MustOpenDB() - defer db.MustClose() - - k := make([]byte, 16) - for i := uint64(0); i < 10000; i++ { - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucketIfNotExists([]byte("0")) - if err != nil { - t.Fatalf("bucket error: %s", err) - } - - for j := uint64(0); j < 1000; j++ { - binary.BigEndian.PutUint64(k[:8], i) - binary.BigEndian.PutUint64(k[8:], j) - if err := b.Put(k, nil); err != nil { - t.Fatalf("put error: %s", err) - } - } - - return nil - }); err != nil { - t.Fatal(err) - } - } - - // Delete all of them in one large transaction - if err := db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("0")) - c := b.Cursor() - for k, _ := c.First(); k != nil; k, _ = c.Next() { - if err := c.Delete(); err != nil { - t.Fatal(err) - } - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that accessing and updating nested buckets is ok across transactions. -func TestBucket_Nested(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - // Create a widgets bucket. - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - // Create a widgets/foo bucket. - _, err = b.CreateBucket([]byte("foo")) - if err != nil { - t.Fatal(err) - } - - // Create a widgets/bar key. - if err := b.Put([]byte("bar"), []byte("0000")); err != nil { - t.Fatal(err) - } - - return nil - }); err != nil { - t.Fatal(err) - } - db.MustCheck() - - // Update widgets/bar. - if err := db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - if err := b.Put([]byte("bar"), []byte("xxxx")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - db.MustCheck() - - // Cause a split. - if err := db.Update(func(tx *bolt.Tx) error { - var b = tx.Bucket([]byte("widgets")) - for i := 0; i < 10000; i++ { - if err := b.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil { - t.Fatal(err) - } - } - return nil - }); err != nil { - t.Fatal(err) - } - db.MustCheck() - - // Insert into widgets/foo/baz. - if err := db.Update(func(tx *bolt.Tx) error { - var b = tx.Bucket([]byte("widgets")) - if err := b.Bucket([]byte("foo")).Put([]byte("baz"), []byte("yyyy")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - db.MustCheck() - - // Verify. - if err := db.View(func(tx *bolt.Tx) error { - var b = tx.Bucket([]byte("widgets")) - if v := b.Bucket([]byte("foo")).Get([]byte("baz")); !bytes.Equal(v, []byte("yyyy")) { - t.Fatalf("unexpected value: %v", v) - } - if v := b.Get([]byte("bar")); !bytes.Equal(v, []byte("xxxx")) { - t.Fatalf("unexpected value: %v", v) - } - for i := 0; i < 10000; i++ { - if v := b.Get([]byte(strconv.Itoa(i))); !bytes.Equal(v, []byte(strconv.Itoa(i))) { - t.Fatalf("unexpected value: %v", v) - } - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that deleting a bucket using Delete() returns an error. -func TestBucket_Delete_Bucket(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if _, err := b.CreateBucket([]byte("foo")); err != nil { - t.Fatal(err) - } - if err := b.Delete([]byte("foo")); err != bolt.ErrIncompatibleValue { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that deleting a key on a read-only bucket returns an error. -func TestBucket_Delete_ReadOnly(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - if err := tx.Bucket([]byte("widgets")).Delete([]byte("foo")); err != bolt.ErrTxNotWritable { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a deleting value while the transaction is closed returns an error. -func TestBucket_Delete_Closed(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } - if err := b.Delete([]byte("foo")); err != bolt.ErrTxClosed { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that deleting a bucket causes nested buckets to be deleted. -func TestBucket_DeleteBucket_Nested(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - widgets, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - foo, err := widgets.CreateBucket([]byte("foo")) - if err != nil { - t.Fatal(err) - } - - bar, err := foo.CreateBucket([]byte("bar")) - if err != nil { - t.Fatal(err) - } - if err := bar.Put([]byte("baz"), []byte("bat")); err != nil { - t.Fatal(err) - } - if err := tx.Bucket([]byte("widgets")).DeleteBucket([]byte("foo")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that deleting a bucket causes nested buckets to be deleted after they have been committed. -func TestBucket_DeleteBucket_Nested2(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - widgets, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - foo, err := widgets.CreateBucket([]byte("foo")) - if err != nil { - t.Fatal(err) - } - - bar, err := foo.CreateBucket([]byte("bar")) - if err != nil { - t.Fatal(err) - } - - if err := bar.Put([]byte("baz"), []byte("bat")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.Update(func(tx *bolt.Tx) error { - widgets := tx.Bucket([]byte("widgets")) - if widgets == nil { - t.Fatal("expected widgets bucket") - } - - foo := widgets.Bucket([]byte("foo")) - if foo == nil { - t.Fatal("expected foo bucket") - } - - bar := foo.Bucket([]byte("bar")) - if bar == nil { - t.Fatal("expected bar bucket") - } - - if v := bar.Get([]byte("baz")); !bytes.Equal(v, []byte("bat")) { - t.Fatalf("unexpected value: %v", v) - } - if err := tx.DeleteBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - if tx.Bucket([]byte("widgets")) != nil { - t.Fatal("expected bucket to be deleted") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that deleting a child bucket with multiple pages causes all pages to get collected. -// NOTE: Consistency check in bolt_test.DB.Close() will panic if pages not freed properly. -func TestBucket_DeleteBucket_Large(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - widgets, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - foo, err := widgets.CreateBucket([]byte("foo")) - if err != nil { - t.Fatal(err) - } - - for i := 0; i < 1000; i++ { - if err := foo.Put([]byte(fmt.Sprintf("%d", i)), []byte(fmt.Sprintf("%0100d", i))); err != nil { - t.Fatal(err) - } - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.Update(func(tx *bolt.Tx) error { - if err := tx.DeleteBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a simple value retrieved via Bucket() returns a nil. -func TestBucket_Bucket_IncompatibleValue(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - widgets, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - if err := widgets.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if b := tx.Bucket([]byte("widgets")).Bucket([]byte("foo")); b != nil { - t.Fatal("expected nil bucket") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that creating a bucket on an existing non-bucket key returns an error. -func TestBucket_CreateBucket_IncompatibleValue(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - widgets, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - if err := widgets.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if _, err := widgets.CreateBucket([]byte("foo")); err != bolt.ErrIncompatibleValue { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that deleting a bucket on an existing non-bucket key returns an error. -func TestBucket_DeleteBucket_IncompatibleValue(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - widgets, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := widgets.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if err := tx.Bucket([]byte("widgets")).DeleteBucket([]byte("foo")); err != bolt.ErrIncompatibleValue { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure bucket can set and update its sequence number. -func TestBucket_Sequence(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - bkt, err := tx.CreateBucket([]byte("0")) - if err != nil { - t.Fatal(err) - } - - // Retrieve sequence. - if v := bkt.Sequence(); v != 0 { - t.Fatalf("unexpected sequence: %d", v) - } - - // Update sequence. - if err := bkt.SetSequence(1000); err != nil { - t.Fatal(err) - } - - // Read sequence again. - if v := bkt.Sequence(); v != 1000 { - t.Fatalf("unexpected sequence: %d", v) - } - - return nil - }); err != nil { - t.Fatal(err) - } - - // Verify sequence in separate transaction. - if err := db.View(func(tx *bolt.Tx) error { - if v := tx.Bucket([]byte("0")).Sequence(); v != 1000 { - t.Fatalf("unexpected sequence: %d", v) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket can return an autoincrementing sequence. -func TestBucket_NextSequence(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - widgets, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - woojits, err := tx.CreateBucket([]byte("woojits")) - if err != nil { - t.Fatal(err) - } - - // Make sure sequence increments. - if seq, err := widgets.NextSequence(); err != nil { - t.Fatal(err) - } else if seq != 1 { - t.Fatalf("unexpecte sequence: %d", seq) - } - - if seq, err := widgets.NextSequence(); err != nil { - t.Fatal(err) - } else if seq != 2 { - t.Fatalf("unexpected sequence: %d", seq) - } - - // Buckets should be separate. - if seq, err := woojits.NextSequence(); err != nil { - t.Fatal(err) - } else if seq != 1 { - t.Fatalf("unexpected sequence: %d", 1) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket will persist an autoincrementing sequence even if its -// the only thing updated on the bucket. -// https://github.com/boltdb/bolt/issues/296 -func TestBucket_NextSequence_Persist(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.Bucket([]byte("widgets")).NextSequence(); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.Update(func(tx *bolt.Tx) error { - seq, err := tx.Bucket([]byte("widgets")).NextSequence() - if err != nil { - t.Fatalf("unexpected error: %s", err) - } else if seq != 2 { - t.Fatalf("unexpected sequence: %d", seq) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that retrieving the next sequence on a read-only bucket returns an error. -func TestBucket_NextSequence_ReadOnly(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - _, err := tx.Bucket([]byte("widgets")).NextSequence() - if err != bolt.ErrTxNotWritable { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that retrieving the next sequence for a bucket on a closed database return an error. -func TestBucket_NextSequence_Closed(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } - if _, err := b.NextSequence(); err != bolt.ErrTxClosed { - t.Fatal(err) - } -} - -// Ensure a user can loop over all key/value pairs in a bucket. -func TestBucket_ForEach(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("0000")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("baz"), []byte("0001")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("bar"), []byte("0002")); err != nil { - t.Fatal(err) - } - - var index int - if err := b.ForEach(func(k, v []byte) error { - switch index { - case 0: - if !bytes.Equal(k, []byte("bar")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte("0002")) { - t.Fatalf("unexpected value: %v", v) - } - case 1: - if !bytes.Equal(k, []byte("baz")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte("0001")) { - t.Fatalf("unexpected value: %v", v) - } - case 2: - if !bytes.Equal(k, []byte("foo")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte("0000")) { - t.Fatalf("unexpected value: %v", v) - } - } - index++ - return nil - }); err != nil { - t.Fatal(err) - } - - if index != 3 { - t.Fatalf("unexpected index: %d", index) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure a database can stop iteration early. -func TestBucket_ForEach_ShortCircuit(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("bar"), []byte("0000")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("baz"), []byte("0000")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("0000")); err != nil { - t.Fatal(err) - } - - var index int - if err := tx.Bucket([]byte("widgets")).ForEach(func(k, v []byte) error { - index++ - if bytes.Equal(k, []byte("baz")) { - return errors.New("marker") - } - return nil - }); err == nil || err.Error() != "marker" { - t.Fatalf("unexpected error: %s", err) - } - if index != 2 { - t.Fatalf("unexpected index: %d", index) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that looping over a bucket on a closed database returns an error. -func TestBucket_ForEach_Closed(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } - - if err := b.ForEach(func(k, v []byte) error { return nil }); err != bolt.ErrTxClosed { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that an error is returned when inserting with an empty key. -func TestBucket_Put_EmptyKey(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte(""), []byte("bar")); err != bolt.ErrKeyRequired { - t.Fatalf("unexpected error: %s", err) - } - if err := b.Put(nil, []byte("bar")); err != bolt.ErrKeyRequired { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that an error is returned when inserting with a key that's too large. -func TestBucket_Put_KeyTooLarge(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put(make([]byte, 32769), []byte("bar")); err != bolt.ErrKeyTooLarge { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that an error is returned when inserting a value that's too large. -func TestBucket_Put_ValueTooLarge(t *testing.T) { - // Skip this test on DroneCI because the machine is resource constrained. - if os.Getenv("DRONE") == "true" { - t.Skip("not enough RAM for test") - } - - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), make([]byte, bolt.MaxValueSize+1)); err != bolt.ErrValueTooLarge { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure a bucket can calculate stats. -func TestBucket_Stats(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - // Add bucket with fewer keys but one big value. - bigKey := []byte("really-big-value") - for i := 0; i < 500; i++ { - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucketIfNotExists([]byte("woojits")) - if err != nil { - t.Fatal(err) - } - - if err := b.Put([]byte(fmt.Sprintf("%03d", i)), []byte(strconv.Itoa(i))); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - } - if err := db.Update(func(tx *bolt.Tx) error { - if err := tx.Bucket([]byte("woojits")).Put(bigKey, []byte(strings.Repeat("*", 10000))); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - db.MustCheck() - - if err := db.View(func(tx *bolt.Tx) error { - stats := tx.Bucket([]byte("woojits")).Stats() - if stats.BranchPageN != 1 { - t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN) - } else if stats.BranchOverflowN != 0 { - t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN) - } else if stats.LeafPageN != 7 { - t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN) - } else if stats.LeafOverflowN != 2 { - t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN) - } else if stats.KeyN != 501 { - t.Fatalf("unexpected KeyN: %d", stats.KeyN) - } else if stats.Depth != 2 { - t.Fatalf("unexpected Depth: %d", stats.Depth) - } - - branchInuse := 16 // branch page header - branchInuse += 7 * 16 // branch elements - branchInuse += 7 * 3 // branch keys (6 3-byte keys) - if stats.BranchInuse != branchInuse { - t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse) - } - - leafInuse := 7 * 16 // leaf page header - leafInuse += 501 * 16 // leaf elements - leafInuse += 500*3 + len(bigKey) // leaf keys - leafInuse += 1*10 + 2*90 + 3*400 + 10000 // leaf values - if stats.LeafInuse != leafInuse { - t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse) - } - - // Only check allocations for 4KB pages. - if os.Getpagesize() == 4096 { - if stats.BranchAlloc != 4096 { - t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc) - } else if stats.LeafAlloc != 36864 { - t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc) - } - } - - if stats.BucketN != 1 { - t.Fatalf("unexpected BucketN: %d", stats.BucketN) - } else if stats.InlineBucketN != 0 { - t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN) - } else if stats.InlineBucketInuse != 0 { - t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure a bucket with random insertion utilizes fill percentage correctly. -func TestBucket_Stats_RandomFill(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } else if os.Getpagesize() != 4096 { - t.Skip("invalid page size for test") - } - - db := MustOpenDB() - defer db.MustClose() - - // Add a set of values in random order. It will be the same random - // order so we can maintain consistency between test runs. - var count int - rand := rand.New(rand.NewSource(42)) - for _, i := range rand.Perm(1000) { - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucketIfNotExists([]byte("woojits")) - if err != nil { - t.Fatal(err) - } - b.FillPercent = 0.9 - for _, j := range rand.Perm(100) { - index := (j * 10000) + i - if err := b.Put([]byte(fmt.Sprintf("%d000000000000000", index)), []byte("0000000000")); err != nil { - t.Fatal(err) - } - count++ - } - return nil - }); err != nil { - t.Fatal(err) - } - } - - db.MustCheck() - - if err := db.View(func(tx *bolt.Tx) error { - stats := tx.Bucket([]byte("woojits")).Stats() - if stats.KeyN != 100000 { - t.Fatalf("unexpected KeyN: %d", stats.KeyN) - } - - if stats.BranchPageN != 98 { - t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN) - } else if stats.BranchOverflowN != 0 { - t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN) - } else if stats.BranchInuse != 130984 { - t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse) - } else if stats.BranchAlloc != 401408 { - t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc) - } - - if stats.LeafPageN != 3412 { - t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN) - } else if stats.LeafOverflowN != 0 { - t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN) - } else if stats.LeafInuse != 4742482 { - t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse) - } else if stats.LeafAlloc != 13975552 { - t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure a bucket can calculate stats. -func TestBucket_Stats_Small(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - // Add a bucket that fits on a single root leaf. - b, err := tx.CreateBucket([]byte("whozawhats")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - - return nil - }); err != nil { - t.Fatal(err) - } - - db.MustCheck() - - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("whozawhats")) - stats := b.Stats() - if stats.BranchPageN != 0 { - t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN) - } else if stats.BranchOverflowN != 0 { - t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN) - } else if stats.LeafPageN != 0 { - t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN) - } else if stats.LeafOverflowN != 0 { - t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN) - } else if stats.KeyN != 1 { - t.Fatalf("unexpected KeyN: %d", stats.KeyN) - } else if stats.Depth != 1 { - t.Fatalf("unexpected Depth: %d", stats.Depth) - } else if stats.BranchInuse != 0 { - t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse) - } else if stats.LeafInuse != 0 { - t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse) - } - - if os.Getpagesize() == 4096 { - if stats.BranchAlloc != 0 { - t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc) - } else if stats.LeafAlloc != 0 { - t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc) - } - } - - if stats.BucketN != 1 { - t.Fatalf("unexpected BucketN: %d", stats.BucketN) - } else if stats.InlineBucketN != 1 { - t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN) - } else if stats.InlineBucketInuse != 16+16+6 { - t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -func TestBucket_Stats_EmptyBucket(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - // Add a bucket that fits on a single root leaf. - if _, err := tx.CreateBucket([]byte("whozawhats")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - db.MustCheck() - - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("whozawhats")) - stats := b.Stats() - if stats.BranchPageN != 0 { - t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN) - } else if stats.BranchOverflowN != 0 { - t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN) - } else if stats.LeafPageN != 0 { - t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN) - } else if stats.LeafOverflowN != 0 { - t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN) - } else if stats.KeyN != 0 { - t.Fatalf("unexpected KeyN: %d", stats.KeyN) - } else if stats.Depth != 1 { - t.Fatalf("unexpected Depth: %d", stats.Depth) - } else if stats.BranchInuse != 0 { - t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse) - } else if stats.LeafInuse != 0 { - t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse) - } - - if os.Getpagesize() == 4096 { - if stats.BranchAlloc != 0 { - t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc) - } else if stats.LeafAlloc != 0 { - t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc) - } - } - - if stats.BucketN != 1 { - t.Fatalf("unexpected BucketN: %d", stats.BucketN) - } else if stats.InlineBucketN != 1 { - t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN) - } else if stats.InlineBucketInuse != 16 { - t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure a bucket can calculate stats. -func TestBucket_Stats_Nested(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("foo")) - if err != nil { - t.Fatal(err) - } - for i := 0; i < 100; i++ { - if err := b.Put([]byte(fmt.Sprintf("%02d", i)), []byte(fmt.Sprintf("%02d", i))); err != nil { - t.Fatal(err) - } - } - - bar, err := b.CreateBucket([]byte("bar")) - if err != nil { - t.Fatal(err) - } - for i := 0; i < 10; i++ { - if err := bar.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil { - t.Fatal(err) - } - } - - baz, err := bar.CreateBucket([]byte("baz")) - if err != nil { - t.Fatal(err) - } - for i := 0; i < 10; i++ { - if err := baz.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil { - t.Fatal(err) - } - } - - return nil - }); err != nil { - t.Fatal(err) - } - - db.MustCheck() - - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("foo")) - stats := b.Stats() - if stats.BranchPageN != 0 { - t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN) - } else if stats.BranchOverflowN != 0 { - t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN) - } else if stats.LeafPageN != 2 { - t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN) - } else if stats.LeafOverflowN != 0 { - t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN) - } else if stats.KeyN != 122 { - t.Fatalf("unexpected KeyN: %d", stats.KeyN) - } else if stats.Depth != 3 { - t.Fatalf("unexpected Depth: %d", stats.Depth) - } else if stats.BranchInuse != 0 { - t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse) - } - - foo := 16 // foo (pghdr) - foo += 101 * 16 // foo leaf elements - foo += 100*2 + 100*2 // foo leaf key/values - foo += 3 + 16 // foo -> bar key/value - - bar := 16 // bar (pghdr) - bar += 11 * 16 // bar leaf elements - bar += 10 + 10 // bar leaf key/values - bar += 3 + 16 // bar -> baz key/value - - baz := 16 // baz (inline) (pghdr) - baz += 10 * 16 // baz leaf elements - baz += 10 + 10 // baz leaf key/values - - if stats.LeafInuse != foo+bar+baz { - t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse) - } - - if os.Getpagesize() == 4096 { - if stats.BranchAlloc != 0 { - t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc) - } else if stats.LeafAlloc != 8192 { - t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc) - } - } - - if stats.BucketN != 3 { - t.Fatalf("unexpected BucketN: %d", stats.BucketN) - } else if stats.InlineBucketN != 1 { - t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN) - } else if stats.InlineBucketInuse != baz { - t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure a large bucket can calculate stats. -func TestBucket_Stats_Large(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - - db := MustOpenDB() - defer db.MustClose() - - var index int - for i := 0; i < 100; i++ { - // Add bucket with lots of keys. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucketIfNotExists([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - for i := 0; i < 1000; i++ { - if err := b.Put([]byte(strconv.Itoa(index)), []byte(strconv.Itoa(index))); err != nil { - t.Fatal(err) - } - index++ - } - return nil - }); err != nil { - t.Fatal(err) - } - } - - db.MustCheck() - - if err := db.View(func(tx *bolt.Tx) error { - stats := tx.Bucket([]byte("widgets")).Stats() - if stats.BranchPageN != 13 { - t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN) - } else if stats.BranchOverflowN != 0 { - t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN) - } else if stats.LeafPageN != 1196 { - t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN) - } else if stats.LeafOverflowN != 0 { - t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN) - } else if stats.KeyN != 100000 { - t.Fatalf("unexpected KeyN: %d", stats.KeyN) - } else if stats.Depth != 3 { - t.Fatalf("unexpected Depth: %d", stats.Depth) - } else if stats.BranchInuse != 25257 { - t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse) - } else if stats.LeafInuse != 2596916 { - t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse) - } - - if os.Getpagesize() == 4096 { - if stats.BranchAlloc != 53248 { - t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc) - } else if stats.LeafAlloc != 4898816 { - t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc) - } - } - - if stats.BucketN != 1 { - t.Fatalf("unexpected BucketN: %d", stats.BucketN) - } else if stats.InlineBucketN != 0 { - t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN) - } else if stats.InlineBucketInuse != 0 { - t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket can write random keys and values across multiple transactions. -func TestBucket_Put_Single(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - - index := 0 - if err := quick.Check(func(items testdata) bool { - db := MustOpenDB() - defer db.MustClose() - - m := make(map[string][]byte) - - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - for _, item := range items { - if err := db.Update(func(tx *bolt.Tx) error { - if err := tx.Bucket([]byte("widgets")).Put(item.Key, item.Value); err != nil { - panic("put error: " + err.Error()) - } - m[string(item.Key)] = item.Value - return nil - }); err != nil { - t.Fatal(err) - } - - // Verify all key/values so far. - if err := db.View(func(tx *bolt.Tx) error { - i := 0 - for k, v := range m { - value := tx.Bucket([]byte("widgets")).Get([]byte(k)) - if !bytes.Equal(value, v) { - t.Logf("value mismatch [run %d] (%d of %d):\nkey: %x\ngot: %x\nexp: %x", index, i, len(m), []byte(k), value, v) - db.CopyTempFile() - t.FailNow() - } - i++ - } - return nil - }); err != nil { - t.Fatal(err) - } - } - - index++ - return true - }, nil); err != nil { - t.Error(err) - } -} - -// Ensure that a transaction can insert multiple key/value pairs at once. -func TestBucket_Put_Multiple(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - - if err := quick.Check(func(items testdata) bool { - db := MustOpenDB() - defer db.MustClose() - - // Bulk insert all values. - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - for _, item := range items { - if err := b.Put(item.Key, item.Value); err != nil { - t.Fatal(err) - } - } - return nil - }); err != nil { - t.Fatal(err) - } - - // Verify all items exist. - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - for _, item := range items { - value := b.Get(item.Key) - if !bytes.Equal(item.Value, value) { - db.CopyTempFile() - t.Fatalf("exp=%x; got=%x", item.Value, value) - } - } - return nil - }); err != nil { - t.Fatal(err) - } - - return true - }, qconfig()); err != nil { - t.Error(err) - } -} - -// Ensure that a transaction can delete all key/value pairs and return to a single leaf page. -func TestBucket_Delete_Quick(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - - if err := quick.Check(func(items testdata) bool { - db := MustOpenDB() - defer db.MustClose() - - // Bulk insert all values. - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - for _, item := range items { - if err := b.Put(item.Key, item.Value); err != nil { - t.Fatal(err) - } - } - return nil - }); err != nil { - t.Fatal(err) - } - - // Remove items one at a time and check consistency. - for _, item := range items { - if err := db.Update(func(tx *bolt.Tx) error { - return tx.Bucket([]byte("widgets")).Delete(item.Key) - }); err != nil { - t.Fatal(err) - } - } - - // Anything before our deletion index should be nil. - if err := db.View(func(tx *bolt.Tx) error { - if err := tx.Bucket([]byte("widgets")).ForEach(func(k, v []byte) error { - t.Fatalf("bucket should be empty; found: %06x", trunc(k, 3)) - return nil - }); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - return true - }, qconfig()); err != nil { - t.Error(err) - } -} - -func ExampleBucket_Put() { - // Open the database. - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - log.Fatal(err) - } - defer os.Remove(db.Path()) - - // Start a write transaction. - if err := db.Update(func(tx *bolt.Tx) error { - // Create a bucket. - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - return err - } - - // Set the value "bar" for the key "foo". - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - return err - } - return nil - }); err != nil { - log.Fatal(err) - } - - // Read value back in a different read-only transaction. - if err := db.View(func(tx *bolt.Tx) error { - value := tx.Bucket([]byte("widgets")).Get([]byte("foo")) - fmt.Printf("The value of 'foo' is: %s\n", value) - return nil - }); err != nil { - log.Fatal(err) - } - - // Close database to release file lock. - if err := db.Close(); err != nil { - log.Fatal(err) - } - - // Output: - // The value of 'foo' is: bar -} - -func ExampleBucket_Delete() { - // Open the database. - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - log.Fatal(err) - } - defer os.Remove(db.Path()) - - // Start a write transaction. - if err := db.Update(func(tx *bolt.Tx) error { - // Create a bucket. - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - return err - } - - // Set the value "bar" for the key "foo". - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - return err - } - - // Retrieve the key back from the database and verify it. - value := b.Get([]byte("foo")) - fmt.Printf("The value of 'foo' was: %s\n", value) - - return nil - }); err != nil { - log.Fatal(err) - } - - // Delete the key in a different write transaction. - if err := db.Update(func(tx *bolt.Tx) error { - return tx.Bucket([]byte("widgets")).Delete([]byte("foo")) - }); err != nil { - log.Fatal(err) - } - - // Retrieve the key again. - if err := db.View(func(tx *bolt.Tx) error { - value := tx.Bucket([]byte("widgets")).Get([]byte("foo")) - if value == nil { - fmt.Printf("The value of 'foo' is now: nil\n") - } - return nil - }); err != nil { - log.Fatal(err) - } - - // Close database to release file lock. - if err := db.Close(); err != nil { - log.Fatal(err) - } - - // Output: - // The value of 'foo' was: bar - // The value of 'foo' is now: nil -} - -func ExampleBucket_ForEach() { - // Open the database. - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - log.Fatal(err) - } - defer os.Remove(db.Path()) - - // Insert data into a bucket. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("animals")) - if err != nil { - return err - } - - if err := b.Put([]byte("dog"), []byte("fun")); err != nil { - return err - } - if err := b.Put([]byte("cat"), []byte("lame")); err != nil { - return err - } - if err := b.Put([]byte("liger"), []byte("awesome")); err != nil { - return err - } - - // Iterate over items in sorted key order. - if err := b.ForEach(func(k, v []byte) error { - fmt.Printf("A %s is %s.\n", k, v) - return nil - }); err != nil { - return err - } - - return nil - }); err != nil { - log.Fatal(err) - } - - // Close database to release file lock. - if err := db.Close(); err != nil { - log.Fatal(err) - } - - // Output: - // A cat is lame. - // A dog is fun. - // A liger is awesome. -} diff --git a/vendor/github.com/boltdb/bolt/cursor_test.go b/vendor/github.com/boltdb/bolt/cursor_test.go deleted file mode 100644 index 562d60f9..00000000 --- a/vendor/github.com/boltdb/bolt/cursor_test.go +++ /dev/null @@ -1,817 +0,0 @@ -package bolt_test - -import ( - "bytes" - "encoding/binary" - "fmt" - "log" - "os" - "reflect" - "sort" - "testing" - "testing/quick" - - "github.com/boltdb/bolt" -) - -// Ensure that a cursor can return a reference to the bucket that created it. -func TestCursor_Bucket(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if cb := b.Cursor().Bucket(); !reflect.DeepEqual(cb, b) { - t.Fatal("cursor bucket mismatch") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a Tx cursor can seek to the appropriate keys. -func TestCursor_Seek(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("0001")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("bar"), []byte("0002")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("baz"), []byte("0003")); err != nil { - t.Fatal(err) - } - - if _, err := b.CreateBucket([]byte("bkt")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - c := tx.Bucket([]byte("widgets")).Cursor() - - // Exact match should go to the key. - if k, v := c.Seek([]byte("bar")); !bytes.Equal(k, []byte("bar")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte("0002")) { - t.Fatalf("unexpected value: %v", v) - } - - // Inexact match should go to the next key. - if k, v := c.Seek([]byte("bas")); !bytes.Equal(k, []byte("baz")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte("0003")) { - t.Fatalf("unexpected value: %v", v) - } - - // Low key should go to the first key. - if k, v := c.Seek([]byte("")); !bytes.Equal(k, []byte("bar")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte("0002")) { - t.Fatalf("unexpected value: %v", v) - } - - // High key should return no key. - if k, v := c.Seek([]byte("zzz")); k != nil { - t.Fatalf("expected nil key: %v", k) - } else if v != nil { - t.Fatalf("expected nil value: %v", v) - } - - // Buckets should return their key but no value. - if k, v := c.Seek([]byte("bkt")); !bytes.Equal(k, []byte("bkt")) { - t.Fatalf("unexpected key: %v", k) - } else if v != nil { - t.Fatalf("expected nil value: %v", v) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -func TestCursor_Delete(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - const count = 1000 - - // Insert every other key between 0 and $count. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - for i := 0; i < count; i += 1 { - k := make([]byte, 8) - binary.BigEndian.PutUint64(k, uint64(i)) - if err := b.Put(k, make([]byte, 100)); err != nil { - t.Fatal(err) - } - } - if _, err := b.CreateBucket([]byte("sub")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.Update(func(tx *bolt.Tx) error { - c := tx.Bucket([]byte("widgets")).Cursor() - bound := make([]byte, 8) - binary.BigEndian.PutUint64(bound, uint64(count/2)) - for key, _ := c.First(); bytes.Compare(key, bound) < 0; key, _ = c.Next() { - if err := c.Delete(); err != nil { - t.Fatal(err) - } - } - - c.Seek([]byte("sub")) - if err := c.Delete(); err != bolt.ErrIncompatibleValue { - t.Fatalf("unexpected error: %s", err) - } - - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - stats := tx.Bucket([]byte("widgets")).Stats() - if stats.KeyN != count/2+1 { - t.Fatalf("unexpected KeyN: %d", stats.KeyN) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a Tx cursor can seek to the appropriate keys when there are a -// large number of keys. This test also checks that seek will always move -// forward to the next key. -// -// Related: https://github.com/boltdb/bolt/pull/187 -func TestCursor_Seek_Large(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - var count = 10000 - - // Insert every other key between 0 and $count. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - for i := 0; i < count; i += 100 { - for j := i; j < i+100; j += 2 { - k := make([]byte, 8) - binary.BigEndian.PutUint64(k, uint64(j)) - if err := b.Put(k, make([]byte, 100)); err != nil { - t.Fatal(err) - } - } - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - c := tx.Bucket([]byte("widgets")).Cursor() - for i := 0; i < count; i++ { - seek := make([]byte, 8) - binary.BigEndian.PutUint64(seek, uint64(i)) - - k, _ := c.Seek(seek) - - // The last seek is beyond the end of the the range so - // it should return nil. - if i == count-1 { - if k != nil { - t.Fatal("expected nil key") - } - continue - } - - // Otherwise we should seek to the exact key or the next key. - num := binary.BigEndian.Uint64(k) - if i%2 == 0 { - if num != uint64(i) { - t.Fatalf("unexpected num: %d", num) - } - } else { - if num != uint64(i+1) { - t.Fatalf("unexpected num: %d", num) - } - } - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a cursor can iterate over an empty bucket without error. -func TestCursor_EmptyBucket(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("widgets")) - return err - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - c := tx.Bucket([]byte("widgets")).Cursor() - k, v := c.First() - if k != nil { - t.Fatalf("unexpected key: %v", k) - } else if v != nil { - t.Fatalf("unexpected value: %v", v) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a Tx cursor can reverse iterate over an empty bucket without error. -func TestCursor_EmptyBucketReverse(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("widgets")) - return err - }); err != nil { - t.Fatal(err) - } - if err := db.View(func(tx *bolt.Tx) error { - c := tx.Bucket([]byte("widgets")).Cursor() - k, v := c.Last() - if k != nil { - t.Fatalf("unexpected key: %v", k) - } else if v != nil { - t.Fatalf("unexpected value: %v", v) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a Tx cursor can iterate over a single root with a couple elements. -func TestCursor_Iterate_Leaf(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("baz"), []byte{}); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte{0}); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("bar"), []byte{1}); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - tx, err := db.Begin(false) - if err != nil { - t.Fatal(err) - } - defer func() { _ = tx.Rollback() }() - - c := tx.Bucket([]byte("widgets")).Cursor() - - k, v := c.First() - if !bytes.Equal(k, []byte("bar")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte{1}) { - t.Fatalf("unexpected value: %v", v) - } - - k, v = c.Next() - if !bytes.Equal(k, []byte("baz")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte{}) { - t.Fatalf("unexpected value: %v", v) - } - - k, v = c.Next() - if !bytes.Equal(k, []byte("foo")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte{0}) { - t.Fatalf("unexpected value: %v", v) - } - - k, v = c.Next() - if k != nil { - t.Fatalf("expected nil key: %v", k) - } else if v != nil { - t.Fatalf("expected nil value: %v", v) - } - - k, v = c.Next() - if k != nil { - t.Fatalf("expected nil key: %v", k) - } else if v != nil { - t.Fatalf("expected nil value: %v", v) - } - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } -} - -// Ensure that a Tx cursor can iterate in reverse over a single root with a couple elements. -func TestCursor_LeafRootReverse(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("baz"), []byte{}); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte{0}); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("bar"), []byte{1}); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - tx, err := db.Begin(false) - if err != nil { - t.Fatal(err) - } - c := tx.Bucket([]byte("widgets")).Cursor() - - if k, v := c.Last(); !bytes.Equal(k, []byte("foo")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte{0}) { - t.Fatalf("unexpected value: %v", v) - } - - if k, v := c.Prev(); !bytes.Equal(k, []byte("baz")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte{}) { - t.Fatalf("unexpected value: %v", v) - } - - if k, v := c.Prev(); !bytes.Equal(k, []byte("bar")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte{1}) { - t.Fatalf("unexpected value: %v", v) - } - - if k, v := c.Prev(); k != nil { - t.Fatalf("expected nil key: %v", k) - } else if v != nil { - t.Fatalf("expected nil value: %v", v) - } - - if k, v := c.Prev(); k != nil { - t.Fatalf("expected nil key: %v", k) - } else if v != nil { - t.Fatalf("expected nil value: %v", v) - } - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } -} - -// Ensure that a Tx cursor can restart from the beginning. -func TestCursor_Restart(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("bar"), []byte{}); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte{}); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - tx, err := db.Begin(false) - if err != nil { - t.Fatal(err) - } - c := tx.Bucket([]byte("widgets")).Cursor() - - if k, _ := c.First(); !bytes.Equal(k, []byte("bar")) { - t.Fatalf("unexpected key: %v", k) - } - if k, _ := c.Next(); !bytes.Equal(k, []byte("foo")) { - t.Fatalf("unexpected key: %v", k) - } - - if k, _ := c.First(); !bytes.Equal(k, []byte("bar")) { - t.Fatalf("unexpected key: %v", k) - } - if k, _ := c.Next(); !bytes.Equal(k, []byte("foo")) { - t.Fatalf("unexpected key: %v", k) - } - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } -} - -// Ensure that a cursor can skip over empty pages that have been deleted. -func TestCursor_First_EmptyPages(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - // Create 1000 keys in the "widgets" bucket. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - for i := 0; i < 1000; i++ { - if err := b.Put(u64tob(uint64(i)), []byte{}); err != nil { - t.Fatal(err) - } - } - - return nil - }); err != nil { - t.Fatal(err) - } - - // Delete half the keys and then try to iterate. - if err := db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - for i := 0; i < 600; i++ { - if err := b.Delete(u64tob(uint64(i))); err != nil { - t.Fatal(err) - } - } - - c := b.Cursor() - var n int - for k, _ := c.First(); k != nil; k, _ = c.Next() { - n++ - } - if n != 400 { - t.Fatalf("unexpected key count: %d", n) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a Tx can iterate over all elements in a bucket. -func TestCursor_QuickCheck(t *testing.T) { - f := func(items testdata) bool { - db := MustOpenDB() - defer db.MustClose() - - // Bulk insert all values. - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - for _, item := range items { - if err := b.Put(item.Key, item.Value); err != nil { - t.Fatal(err) - } - } - if err := tx.Commit(); err != nil { - t.Fatal(err) - } - - // Sort test data. - sort.Sort(items) - - // Iterate over all items and check consistency. - var index = 0 - tx, err = db.Begin(false) - if err != nil { - t.Fatal(err) - } - - c := tx.Bucket([]byte("widgets")).Cursor() - for k, v := c.First(); k != nil && index < len(items); k, v = c.Next() { - if !bytes.Equal(k, items[index].Key) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, items[index].Value) { - t.Fatalf("unexpected value: %v", v) - } - index++ - } - if len(items) != index { - t.Fatalf("unexpected item count: %v, expected %v", len(items), index) - } - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } - - return true - } - if err := quick.Check(f, qconfig()); err != nil { - t.Error(err) - } -} - -// Ensure that a transaction can iterate over all elements in a bucket in reverse. -func TestCursor_QuickCheck_Reverse(t *testing.T) { - f := func(items testdata) bool { - db := MustOpenDB() - defer db.MustClose() - - // Bulk insert all values. - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - for _, item := range items { - if err := b.Put(item.Key, item.Value); err != nil { - t.Fatal(err) - } - } - if err := tx.Commit(); err != nil { - t.Fatal(err) - } - - // Sort test data. - sort.Sort(revtestdata(items)) - - // Iterate over all items and check consistency. - var index = 0 - tx, err = db.Begin(false) - if err != nil { - t.Fatal(err) - } - c := tx.Bucket([]byte("widgets")).Cursor() - for k, v := c.Last(); k != nil && index < len(items); k, v = c.Prev() { - if !bytes.Equal(k, items[index].Key) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, items[index].Value) { - t.Fatalf("unexpected value: %v", v) - } - index++ - } - if len(items) != index { - t.Fatalf("unexpected item count: %v, expected %v", len(items), index) - } - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } - - return true - } - if err := quick.Check(f, qconfig()); err != nil { - t.Error(err) - } -} - -// Ensure that a Tx cursor can iterate over subbuckets. -func TestCursor_QuickCheck_BucketsOnly(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if _, err := b.CreateBucket([]byte("foo")); err != nil { - t.Fatal(err) - } - if _, err := b.CreateBucket([]byte("bar")); err != nil { - t.Fatal(err) - } - if _, err := b.CreateBucket([]byte("baz")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - var names []string - c := tx.Bucket([]byte("widgets")).Cursor() - for k, v := c.First(); k != nil; k, v = c.Next() { - names = append(names, string(k)) - if v != nil { - t.Fatalf("unexpected value: %v", v) - } - } - if !reflect.DeepEqual(names, []string{"bar", "baz", "foo"}) { - t.Fatalf("unexpected names: %+v", names) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a Tx cursor can reverse iterate over subbuckets. -func TestCursor_QuickCheck_BucketsOnly_Reverse(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if _, err := b.CreateBucket([]byte("foo")); err != nil { - t.Fatal(err) - } - if _, err := b.CreateBucket([]byte("bar")); err != nil { - t.Fatal(err) - } - if _, err := b.CreateBucket([]byte("baz")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - var names []string - c := tx.Bucket([]byte("widgets")).Cursor() - for k, v := c.Last(); k != nil; k, v = c.Prev() { - names = append(names, string(k)) - if v != nil { - t.Fatalf("unexpected value: %v", v) - } - } - if !reflect.DeepEqual(names, []string{"foo", "baz", "bar"}) { - t.Fatalf("unexpected names: %+v", names) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -func ExampleCursor() { - // Open the database. - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - log.Fatal(err) - } - defer os.Remove(db.Path()) - - // Start a read-write transaction. - if err := db.Update(func(tx *bolt.Tx) error { - // Create a new bucket. - b, err := tx.CreateBucket([]byte("animals")) - if err != nil { - return err - } - - // Insert data into a bucket. - if err := b.Put([]byte("dog"), []byte("fun")); err != nil { - log.Fatal(err) - } - if err := b.Put([]byte("cat"), []byte("lame")); err != nil { - log.Fatal(err) - } - if err := b.Put([]byte("liger"), []byte("awesome")); err != nil { - log.Fatal(err) - } - - // Create a cursor for iteration. - c := b.Cursor() - - // Iterate over items in sorted key order. This starts from the - // first key/value pair and updates the k/v variables to the - // next key/value on each iteration. - // - // The loop finishes at the end of the cursor when a nil key is returned. - for k, v := c.First(); k != nil; k, v = c.Next() { - fmt.Printf("A %s is %s.\n", k, v) - } - - return nil - }); err != nil { - log.Fatal(err) - } - - if err := db.Close(); err != nil { - log.Fatal(err) - } - - // Output: - // A cat is lame. - // A dog is fun. - // A liger is awesome. -} - -func ExampleCursor_reverse() { - // Open the database. - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - log.Fatal(err) - } - defer os.Remove(db.Path()) - - // Start a read-write transaction. - if err := db.Update(func(tx *bolt.Tx) error { - // Create a new bucket. - b, err := tx.CreateBucket([]byte("animals")) - if err != nil { - return err - } - - // Insert data into a bucket. - if err := b.Put([]byte("dog"), []byte("fun")); err != nil { - log.Fatal(err) - } - if err := b.Put([]byte("cat"), []byte("lame")); err != nil { - log.Fatal(err) - } - if err := b.Put([]byte("liger"), []byte("awesome")); err != nil { - log.Fatal(err) - } - - // Create a cursor for iteration. - c := b.Cursor() - - // Iterate over items in reverse sorted key order. This starts - // from the last key/value pair and updates the k/v variables to - // the previous key/value on each iteration. - // - // The loop finishes at the beginning of the cursor when a nil key - // is returned. - for k, v := c.Last(); k != nil; k, v = c.Prev() { - fmt.Printf("A %s is %s.\n", k, v) - } - - return nil - }); err != nil { - log.Fatal(err) - } - - // Close the database to release the file lock. - if err := db.Close(); err != nil { - log.Fatal(err) - } - - // Output: - // A liger is awesome. - // A dog is fun. - // A cat is lame. -} diff --git a/vendor/github.com/boltdb/bolt/db_test.go b/vendor/github.com/boltdb/bolt/db_test.go deleted file mode 100644 index 3034d4f4..00000000 --- a/vendor/github.com/boltdb/bolt/db_test.go +++ /dev/null @@ -1,1545 +0,0 @@ -package bolt_test - -import ( - "bytes" - "encoding/binary" - "errors" - "flag" - "fmt" - "hash/fnv" - "io/ioutil" - "log" - "os" - "path/filepath" - "regexp" - "sort" - "strings" - "sync" - "testing" - "time" - "unsafe" - - "github.com/boltdb/bolt" -) - -var statsFlag = flag.Bool("stats", false, "show performance stats") - -// version is the data file format version. -const version = 2 - -// magic is the marker value to indicate that a file is a Bolt DB. -const magic uint32 = 0xED0CDAED - -// pageSize is the size of one page in the data file. -const pageSize = 4096 - -// pageHeaderSize is the size of a page header. -const pageHeaderSize = 16 - -// meta represents a simplified version of a database meta page for testing. -type meta struct { - magic uint32 - version uint32 - _ uint32 - _ uint32 - _ [16]byte - _ uint64 - pgid uint64 - _ uint64 - checksum uint64 -} - -// Ensure that a database can be opened without error. -func TestOpen(t *testing.T) { - path := tempfile() - db, err := bolt.Open(path, 0666, nil) - if err != nil { - t.Fatal(err) - } else if db == nil { - t.Fatal("expected db") - } - - if s := db.Path(); s != path { - t.Fatalf("unexpected path: %s", s) - } - - if err := db.Close(); err != nil { - t.Fatal(err) - } -} - -// Ensure that opening a database with a blank path returns an error. -func TestOpen_ErrPathRequired(t *testing.T) { - _, err := bolt.Open("", 0666, nil) - if err == nil { - t.Fatalf("expected error") - } -} - -// Ensure that opening a database with a bad path returns an error. -func TestOpen_ErrNotExists(t *testing.T) { - _, err := bolt.Open(filepath.Join(tempfile(), "bad-path"), 0666, nil) - if err == nil { - t.Fatal("expected error") - } -} - -// Ensure that opening a file that is not a Bolt database returns ErrInvalid. -func TestOpen_ErrInvalid(t *testing.T) { - path := tempfile() - - f, err := os.Create(path) - if err != nil { - t.Fatal(err) - } - if _, err := fmt.Fprintln(f, "this is not a bolt database"); err != nil { - t.Fatal(err) - } - if err := f.Close(); err != nil { - t.Fatal(err) - } - defer os.Remove(path) - - if _, err := bolt.Open(path, 0666, nil); err != bolt.ErrInvalid { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that opening a file with two invalid versions returns ErrVersionMismatch. -func TestOpen_ErrVersionMismatch(t *testing.T) { - if pageSize != os.Getpagesize() { - t.Skip("page size mismatch") - } - - // Create empty database. - db := MustOpenDB() - path := db.Path() - defer db.MustClose() - - // Close database. - if err := db.DB.Close(); err != nil { - t.Fatal(err) - } - - // Read data file. - buf, err := ioutil.ReadFile(path) - if err != nil { - t.Fatal(err) - } - - // Rewrite meta pages. - meta0 := (*meta)(unsafe.Pointer(&buf[pageHeaderSize])) - meta0.version++ - meta1 := (*meta)(unsafe.Pointer(&buf[pageSize+pageHeaderSize])) - meta1.version++ - if err := ioutil.WriteFile(path, buf, 0666); err != nil { - t.Fatal(err) - } - - // Reopen data file. - if _, err := bolt.Open(path, 0666, nil); err != bolt.ErrVersionMismatch { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that opening a file with two invalid checksums returns ErrChecksum. -func TestOpen_ErrChecksum(t *testing.T) { - if pageSize != os.Getpagesize() { - t.Skip("page size mismatch") - } - - // Create empty database. - db := MustOpenDB() - path := db.Path() - defer db.MustClose() - - // Close database. - if err := db.DB.Close(); err != nil { - t.Fatal(err) - } - - // Read data file. - buf, err := ioutil.ReadFile(path) - if err != nil { - t.Fatal(err) - } - - // Rewrite meta pages. - meta0 := (*meta)(unsafe.Pointer(&buf[pageHeaderSize])) - meta0.pgid++ - meta1 := (*meta)(unsafe.Pointer(&buf[pageSize+pageHeaderSize])) - meta1.pgid++ - if err := ioutil.WriteFile(path, buf, 0666); err != nil { - t.Fatal(err) - } - - // Reopen data file. - if _, err := bolt.Open(path, 0666, nil); err != bolt.ErrChecksum { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that opening a database does not increase its size. -// https://github.com/boltdb/bolt/issues/291 -func TestOpen_Size(t *testing.T) { - // Open a data file. - db := MustOpenDB() - path := db.Path() - defer db.MustClose() - - pagesize := db.Info().PageSize - - // Insert until we get above the minimum 4MB size. - if err := db.Update(func(tx *bolt.Tx) error { - b, _ := tx.CreateBucketIfNotExists([]byte("data")) - for i := 0; i < 10000; i++ { - if err := b.Put([]byte(fmt.Sprintf("%04d", i)), make([]byte, 1000)); err != nil { - t.Fatal(err) - } - } - return nil - }); err != nil { - t.Fatal(err) - } - - // Close database and grab the size. - if err := db.DB.Close(); err != nil { - t.Fatal(err) - } - sz := fileSize(path) - if sz == 0 { - t.Fatalf("unexpected new file size: %d", sz) - } - - // Reopen database, update, and check size again. - db0, err := bolt.Open(path, 0666, nil) - if err != nil { - t.Fatal(err) - } - if err := db0.Update(func(tx *bolt.Tx) error { - if err := tx.Bucket([]byte("data")).Put([]byte{0}, []byte{0}); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - if err := db0.Close(); err != nil { - t.Fatal(err) - } - newSz := fileSize(path) - if newSz == 0 { - t.Fatalf("unexpected new file size: %d", newSz) - } - - // Compare the original size with the new size. - // db size might increase by a few page sizes due to the new small update. - if sz < newSz-5*int64(pagesize) { - t.Fatalf("unexpected file growth: %d => %d", sz, newSz) - } -} - -// Ensure that opening a database beyond the max step size does not increase its size. -// https://github.com/boltdb/bolt/issues/303 -func TestOpen_Size_Large(t *testing.T) { - if testing.Short() { - t.Skip("short mode") - } - - // Open a data file. - db := MustOpenDB() - path := db.Path() - defer db.MustClose() - - pagesize := db.Info().PageSize - - // Insert until we get above the minimum 4MB size. - var index uint64 - for i := 0; i < 10000; i++ { - if err := db.Update(func(tx *bolt.Tx) error { - b, _ := tx.CreateBucketIfNotExists([]byte("data")) - for j := 0; j < 1000; j++ { - if err := b.Put(u64tob(index), make([]byte, 50)); err != nil { - t.Fatal(err) - } - index++ - } - return nil - }); err != nil { - t.Fatal(err) - } - } - - // Close database and grab the size. - if err := db.DB.Close(); err != nil { - t.Fatal(err) - } - sz := fileSize(path) - if sz == 0 { - t.Fatalf("unexpected new file size: %d", sz) - } else if sz < (1 << 30) { - t.Fatalf("expected larger initial size: %d", sz) - } - - // Reopen database, update, and check size again. - db0, err := bolt.Open(path, 0666, nil) - if err != nil { - t.Fatal(err) - } - if err := db0.Update(func(tx *bolt.Tx) error { - return tx.Bucket([]byte("data")).Put([]byte{0}, []byte{0}) - }); err != nil { - t.Fatal(err) - } - if err := db0.Close(); err != nil { - t.Fatal(err) - } - - newSz := fileSize(path) - if newSz == 0 { - t.Fatalf("unexpected new file size: %d", newSz) - } - - // Compare the original size with the new size. - // db size might increase by a few page sizes due to the new small update. - if sz < newSz-5*int64(pagesize) { - t.Fatalf("unexpected file growth: %d => %d", sz, newSz) - } -} - -// Ensure that a re-opened database is consistent. -func TestOpen_Check(t *testing.T) { - path := tempfile() - - db, err := bolt.Open(path, 0666, nil) - if err != nil { - t.Fatal(err) - } - if err := db.View(func(tx *bolt.Tx) error { return <-tx.Check() }); err != nil { - t.Fatal(err) - } - if err := db.Close(); err != nil { - t.Fatal(err) - } - - db, err = bolt.Open(path, 0666, nil) - if err != nil { - t.Fatal(err) - } - if err := db.View(func(tx *bolt.Tx) error { return <-tx.Check() }); err != nil { - t.Fatal(err) - } - if err := db.Close(); err != nil { - t.Fatal(err) - } -} - -// Ensure that write errors to the meta file handler during initialization are returned. -func TestOpen_MetaInitWriteError(t *testing.T) { - t.Skip("pending") -} - -// Ensure that a database that is too small returns an error. -func TestOpen_FileTooSmall(t *testing.T) { - path := tempfile() - - db, err := bolt.Open(path, 0666, nil) - if err != nil { - t.Fatal(err) - } - if err := db.Close(); err != nil { - t.Fatal(err) - } - - // corrupt the database - if err := os.Truncate(path, int64(os.Getpagesize())); err != nil { - t.Fatal(err) - } - - db, err = bolt.Open(path, 0666, nil) - if err == nil || err.Error() != "file size too small" { - t.Fatalf("unexpected error: %s", err) - } -} - -// TestDB_Open_InitialMmapSize tests if having InitialMmapSize large enough -// to hold data from concurrent write transaction resolves the issue that -// read transaction blocks the write transaction and causes deadlock. -// This is a very hacky test since the mmap size is not exposed. -func TestDB_Open_InitialMmapSize(t *testing.T) { - path := tempfile() - defer os.Remove(path) - - initMmapSize := 1 << 31 // 2GB - testWriteSize := 1 << 27 // 134MB - - db, err := bolt.Open(path, 0666, &bolt.Options{InitialMmapSize: initMmapSize}) - if err != nil { - t.Fatal(err) - } - - // create a long-running read transaction - // that never gets closed while writing - rtx, err := db.Begin(false) - if err != nil { - t.Fatal(err) - } - - // create a write transaction - wtx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - - b, err := wtx.CreateBucket([]byte("test")) - if err != nil { - t.Fatal(err) - } - - // and commit a large write - err = b.Put([]byte("foo"), make([]byte, testWriteSize)) - if err != nil { - t.Fatal(err) - } - - done := make(chan struct{}) - - go func() { - if err := wtx.Commit(); err != nil { - t.Fatal(err) - } - done <- struct{}{} - }() - - select { - case <-time.After(5 * time.Second): - t.Errorf("unexpected that the reader blocks writer") - case <-done: - } - - if err := rtx.Rollback(); err != nil { - t.Fatal(err) - } -} - -// Ensure that a database cannot open a transaction when it's not open. -func TestDB_Begin_ErrDatabaseNotOpen(t *testing.T) { - var db bolt.DB - if _, err := db.Begin(false); err != bolt.ErrDatabaseNotOpen { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that a read-write transaction can be retrieved. -func TestDB_BeginRW(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } else if tx == nil { - t.Fatal("expected tx") - } - - if tx.DB() != db.DB { - t.Fatal("unexpected tx database") - } else if !tx.Writable() { - t.Fatal("expected writable tx") - } - - if err := tx.Commit(); err != nil { - t.Fatal(err) - } -} - -// Ensure that opening a transaction while the DB is closed returns an error. -func TestDB_BeginRW_Closed(t *testing.T) { - var db bolt.DB - if _, err := db.Begin(true); err != bolt.ErrDatabaseNotOpen { - t.Fatalf("unexpected error: %s", err) - } -} - -func TestDB_Close_PendingTx_RW(t *testing.T) { testDB_Close_PendingTx(t, true) } -func TestDB_Close_PendingTx_RO(t *testing.T) { testDB_Close_PendingTx(t, false) } - -// Ensure that a database cannot close while transactions are open. -func testDB_Close_PendingTx(t *testing.T, writable bool) { - db := MustOpenDB() - defer db.MustClose() - - // Start transaction. - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - - // Open update in separate goroutine. - done := make(chan struct{}) - go func() { - if err := db.Close(); err != nil { - t.Fatal(err) - } - close(done) - }() - - // Ensure database hasn't closed. - time.Sleep(100 * time.Millisecond) - select { - case <-done: - t.Fatal("database closed too early") - default: - } - - // Commit transaction. - if err := tx.Commit(); err != nil { - t.Fatal(err) - } - - // Ensure database closed now. - time.Sleep(100 * time.Millisecond) - select { - case <-done: - default: - t.Fatal("database did not close") - } -} - -// Ensure a database can provide a transactional block. -func TestDB_Update(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("baz"), []byte("bat")); err != nil { - t.Fatal(err) - } - if err := b.Delete([]byte("foo")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - if v := b.Get([]byte("foo")); v != nil { - t.Fatalf("expected nil value, got: %v", v) - } - if v := b.Get([]byte("baz")); !bytes.Equal(v, []byte("bat")) { - t.Fatalf("unexpected value: %v", v) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure a closed database returns an error while running a transaction block -func TestDB_Update_Closed(t *testing.T) { - var db bolt.DB - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != bolt.ErrDatabaseNotOpen { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure a panic occurs while trying to commit a managed transaction. -func TestDB_Update_ManualCommit(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - var panicked bool - if err := db.Update(func(tx *bolt.Tx) error { - func() { - defer func() { - if r := recover(); r != nil { - panicked = true - } - }() - - if err := tx.Commit(); err != nil { - t.Fatal(err) - } - }() - return nil - }); err != nil { - t.Fatal(err) - } else if !panicked { - t.Fatal("expected panic") - } -} - -// Ensure a panic occurs while trying to rollback a managed transaction. -func TestDB_Update_ManualRollback(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - var panicked bool - if err := db.Update(func(tx *bolt.Tx) error { - func() { - defer func() { - if r := recover(); r != nil { - panicked = true - } - }() - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } - }() - return nil - }); err != nil { - t.Fatal(err) - } else if !panicked { - t.Fatal("expected panic") - } -} - -// Ensure a panic occurs while trying to commit a managed transaction. -func TestDB_View_ManualCommit(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - var panicked bool - if err := db.View(func(tx *bolt.Tx) error { - func() { - defer func() { - if r := recover(); r != nil { - panicked = true - } - }() - - if err := tx.Commit(); err != nil { - t.Fatal(err) - } - }() - return nil - }); err != nil { - t.Fatal(err) - } else if !panicked { - t.Fatal("expected panic") - } -} - -// Ensure a panic occurs while trying to rollback a managed transaction. -func TestDB_View_ManualRollback(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - var panicked bool - if err := db.View(func(tx *bolt.Tx) error { - func() { - defer func() { - if r := recover(); r != nil { - panicked = true - } - }() - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } - }() - return nil - }); err != nil { - t.Fatal(err) - } else if !panicked { - t.Fatal("expected panic") - } -} - -// Ensure a write transaction that panics does not hold open locks. -func TestDB_Update_Panic(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - // Panic during update but recover. - func() { - defer func() { - if r := recover(); r != nil { - t.Log("recover: update", r) - } - }() - - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - panic("omg") - }); err != nil { - t.Fatal(err) - } - }() - - // Verify we can update again. - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - // Verify that our change persisted. - if err := db.Update(func(tx *bolt.Tx) error { - if tx.Bucket([]byte("widgets")) == nil { - t.Fatal("expected bucket") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure a database can return an error through a read-only transactional block. -func TestDB_View_Error(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.View(func(tx *bolt.Tx) error { - return errors.New("xxx") - }); err == nil || err.Error() != "xxx" { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure a read transaction that panics does not hold open locks. -func TestDB_View_Panic(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - // Panic during view transaction but recover. - func() { - defer func() { - if r := recover(); r != nil { - t.Log("recover: view", r) - } - }() - - if err := db.View(func(tx *bolt.Tx) error { - if tx.Bucket([]byte("widgets")) == nil { - t.Fatal("expected bucket") - } - panic("omg") - }); err != nil { - t.Fatal(err) - } - }() - - // Verify that we can still use read transactions. - if err := db.View(func(tx *bolt.Tx) error { - if tx.Bucket([]byte("widgets")) == nil { - t.Fatal("expected bucket") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that DB stats can be returned. -func TestDB_Stats(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("widgets")) - return err - }); err != nil { - t.Fatal(err) - } - - stats := db.Stats() - if stats.TxStats.PageCount != 2 { - t.Fatalf("unexpected TxStats.PageCount: %d", stats.TxStats.PageCount) - } else if stats.FreePageN != 0 { - t.Fatalf("unexpected FreePageN != 0: %d", stats.FreePageN) - } else if stats.PendingPageN != 2 { - t.Fatalf("unexpected PendingPageN != 2: %d", stats.PendingPageN) - } -} - -// Ensure that database pages are in expected order and type. -func TestDB_Consistency(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("widgets")) - return err - }); err != nil { - t.Fatal(err) - } - - for i := 0; i < 10; i++ { - if err := db.Update(func(tx *bolt.Tx) error { - if err := tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - } - - if err := db.Update(func(tx *bolt.Tx) error { - if p, _ := tx.Page(0); p == nil { - t.Fatal("expected page") - } else if p.Type != "meta" { - t.Fatalf("unexpected page type: %s", p.Type) - } - - if p, _ := tx.Page(1); p == nil { - t.Fatal("expected page") - } else if p.Type != "meta" { - t.Fatalf("unexpected page type: %s", p.Type) - } - - if p, _ := tx.Page(2); p == nil { - t.Fatal("expected page") - } else if p.Type != "free" { - t.Fatalf("unexpected page type: %s", p.Type) - } - - if p, _ := tx.Page(3); p == nil { - t.Fatal("expected page") - } else if p.Type != "free" { - t.Fatalf("unexpected page type: %s", p.Type) - } - - if p, _ := tx.Page(4); p == nil { - t.Fatal("expected page") - } else if p.Type != "leaf" { - t.Fatalf("unexpected page type: %s", p.Type) - } - - if p, _ := tx.Page(5); p == nil { - t.Fatal("expected page") - } else if p.Type != "freelist" { - t.Fatalf("unexpected page type: %s", p.Type) - } - - if p, _ := tx.Page(6); p != nil { - t.Fatal("unexpected page") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that DB stats can be subtracted from one another. -func TestDBStats_Sub(t *testing.T) { - var a, b bolt.Stats - a.TxStats.PageCount = 3 - a.FreePageN = 4 - b.TxStats.PageCount = 10 - b.FreePageN = 14 - diff := b.Sub(&a) - if diff.TxStats.PageCount != 7 { - t.Fatalf("unexpected TxStats.PageCount: %d", diff.TxStats.PageCount) - } - - // free page stats are copied from the receiver and not subtracted - if diff.FreePageN != 14 { - t.Fatalf("unexpected FreePageN: %d", diff.FreePageN) - } -} - -// Ensure two functions can perform updates in a single batch. -func TestDB_Batch(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - // Iterate over multiple updates in separate goroutines. - n := 2 - ch := make(chan error) - for i := 0; i < n; i++ { - go func(i int) { - ch <- db.Batch(func(tx *bolt.Tx) error { - return tx.Bucket([]byte("widgets")).Put(u64tob(uint64(i)), []byte{}) - }) - }(i) - } - - // Check all responses to make sure there's no error. - for i := 0; i < n; i++ { - if err := <-ch; err != nil { - t.Fatal(err) - } - } - - // Ensure data is correct. - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - for i := 0; i < n; i++ { - if v := b.Get(u64tob(uint64(i))); v == nil { - t.Errorf("key not found: %d", i) - } - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -func TestDB_Batch_Panic(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - var sentinel int - var bork = &sentinel - var problem interface{} - var err error - - // Execute a function inside a batch that panics. - func() { - defer func() { - if p := recover(); p != nil { - problem = p - } - }() - err = db.Batch(func(tx *bolt.Tx) error { - panic(bork) - }) - }() - - // Verify there is no error. - if g, e := err, error(nil); g != e { - t.Fatalf("wrong error: %v != %v", g, e) - } - // Verify the panic was captured. - if g, e := problem, bork; g != e { - t.Fatalf("wrong error: %v != %v", g, e) - } -} - -func TestDB_BatchFull(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("widgets")) - return err - }); err != nil { - t.Fatal(err) - } - - const size = 3 - // buffered so we never leak goroutines - ch := make(chan error, size) - put := func(i int) { - ch <- db.Batch(func(tx *bolt.Tx) error { - return tx.Bucket([]byte("widgets")).Put(u64tob(uint64(i)), []byte{}) - }) - } - - db.MaxBatchSize = size - // high enough to never trigger here - db.MaxBatchDelay = 1 * time.Hour - - go put(1) - go put(2) - - // Give the batch a chance to exhibit bugs. - time.Sleep(10 * time.Millisecond) - - // not triggered yet - select { - case <-ch: - t.Fatalf("batch triggered too early") - default: - } - - go put(3) - - // Check all responses to make sure there's no error. - for i := 0; i < size; i++ { - if err := <-ch; err != nil { - t.Fatal(err) - } - } - - // Ensure data is correct. - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - for i := 1; i <= size; i++ { - if v := b.Get(u64tob(uint64(i))); v == nil { - t.Errorf("key not found: %d", i) - } - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -func TestDB_BatchTime(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("widgets")) - return err - }); err != nil { - t.Fatal(err) - } - - const size = 1 - // buffered so we never leak goroutines - ch := make(chan error, size) - put := func(i int) { - ch <- db.Batch(func(tx *bolt.Tx) error { - return tx.Bucket([]byte("widgets")).Put(u64tob(uint64(i)), []byte{}) - }) - } - - db.MaxBatchSize = 1000 - db.MaxBatchDelay = 0 - - go put(1) - - // Batch must trigger by time alone. - - // Check all responses to make sure there's no error. - for i := 0; i < size; i++ { - if err := <-ch; err != nil { - t.Fatal(err) - } - } - - // Ensure data is correct. - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - for i := 1; i <= size; i++ { - if v := b.Get(u64tob(uint64(i))); v == nil { - t.Errorf("key not found: %d", i) - } - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -func ExampleDB_Update() { - // Open the database. - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - log.Fatal(err) - } - defer os.Remove(db.Path()) - - // Execute several commands within a read-write transaction. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - return err - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - return err - } - return nil - }); err != nil { - log.Fatal(err) - } - - // Read the value back from a separate read-only transaction. - if err := db.View(func(tx *bolt.Tx) error { - value := tx.Bucket([]byte("widgets")).Get([]byte("foo")) - fmt.Printf("The value of 'foo' is: %s\n", value) - return nil - }); err != nil { - log.Fatal(err) - } - - // Close database to release the file lock. - if err := db.Close(); err != nil { - log.Fatal(err) - } - - // Output: - // The value of 'foo' is: bar -} - -func ExampleDB_View() { - // Open the database. - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - log.Fatal(err) - } - defer os.Remove(db.Path()) - - // Insert data into a bucket. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("people")) - if err != nil { - return err - } - if err := b.Put([]byte("john"), []byte("doe")); err != nil { - return err - } - if err := b.Put([]byte("susy"), []byte("que")); err != nil { - return err - } - return nil - }); err != nil { - log.Fatal(err) - } - - // Access data from within a read-only transactional block. - if err := db.View(func(tx *bolt.Tx) error { - v := tx.Bucket([]byte("people")).Get([]byte("john")) - fmt.Printf("John's last name is %s.\n", v) - return nil - }); err != nil { - log.Fatal(err) - } - - // Close database to release the file lock. - if err := db.Close(); err != nil { - log.Fatal(err) - } - - // Output: - // John's last name is doe. -} - -func ExampleDB_Begin_ReadOnly() { - // Open the database. - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - log.Fatal(err) - } - defer os.Remove(db.Path()) - - // Create a bucket using a read-write transaction. - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("widgets")) - return err - }); err != nil { - log.Fatal(err) - } - - // Create several keys in a transaction. - tx, err := db.Begin(true) - if err != nil { - log.Fatal(err) - } - b := tx.Bucket([]byte("widgets")) - if err := b.Put([]byte("john"), []byte("blue")); err != nil { - log.Fatal(err) - } - if err := b.Put([]byte("abby"), []byte("red")); err != nil { - log.Fatal(err) - } - if err := b.Put([]byte("zephyr"), []byte("purple")); err != nil { - log.Fatal(err) - } - if err := tx.Commit(); err != nil { - log.Fatal(err) - } - - // Iterate over the values in sorted key order. - tx, err = db.Begin(false) - if err != nil { - log.Fatal(err) - } - c := tx.Bucket([]byte("widgets")).Cursor() - for k, v := c.First(); k != nil; k, v = c.Next() { - fmt.Printf("%s likes %s\n", k, v) - } - - if err := tx.Rollback(); err != nil { - log.Fatal(err) - } - - if err := db.Close(); err != nil { - log.Fatal(err) - } - - // Output: - // abby likes red - // john likes blue - // zephyr likes purple -} - -func BenchmarkDBBatchAutomatic(b *testing.B) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("bench")) - return err - }); err != nil { - b.Fatal(err) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - start := make(chan struct{}) - var wg sync.WaitGroup - - for round := 0; round < 1000; round++ { - wg.Add(1) - - go func(id uint32) { - defer wg.Done() - <-start - - h := fnv.New32a() - buf := make([]byte, 4) - binary.LittleEndian.PutUint32(buf, id) - _, _ = h.Write(buf[:]) - k := h.Sum(nil) - insert := func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("bench")) - return b.Put(k, []byte("filler")) - } - if err := db.Batch(insert); err != nil { - b.Error(err) - return - } - }(uint32(round)) - } - close(start) - wg.Wait() - } - - b.StopTimer() - validateBatchBench(b, db) -} - -func BenchmarkDBBatchSingle(b *testing.B) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("bench")) - return err - }); err != nil { - b.Fatal(err) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - start := make(chan struct{}) - var wg sync.WaitGroup - - for round := 0; round < 1000; round++ { - wg.Add(1) - go func(id uint32) { - defer wg.Done() - <-start - - h := fnv.New32a() - buf := make([]byte, 4) - binary.LittleEndian.PutUint32(buf, id) - _, _ = h.Write(buf[:]) - k := h.Sum(nil) - insert := func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("bench")) - return b.Put(k, []byte("filler")) - } - if err := db.Update(insert); err != nil { - b.Error(err) - return - } - }(uint32(round)) - } - close(start) - wg.Wait() - } - - b.StopTimer() - validateBatchBench(b, db) -} - -func BenchmarkDBBatchManual10x100(b *testing.B) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("bench")) - return err - }); err != nil { - b.Fatal(err) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - start := make(chan struct{}) - var wg sync.WaitGroup - - for major := 0; major < 10; major++ { - wg.Add(1) - go func(id uint32) { - defer wg.Done() - <-start - - insert100 := func(tx *bolt.Tx) error { - h := fnv.New32a() - buf := make([]byte, 4) - for minor := uint32(0); minor < 100; minor++ { - binary.LittleEndian.PutUint32(buf, uint32(id*100+minor)) - h.Reset() - _, _ = h.Write(buf[:]) - k := h.Sum(nil) - b := tx.Bucket([]byte("bench")) - if err := b.Put(k, []byte("filler")); err != nil { - return err - } - } - return nil - } - if err := db.Update(insert100); err != nil { - b.Fatal(err) - } - }(uint32(major)) - } - close(start) - wg.Wait() - } - - b.StopTimer() - validateBatchBench(b, db) -} - -func validateBatchBench(b *testing.B, db *DB) { - var rollback = errors.New("sentinel error to cause rollback") - validate := func(tx *bolt.Tx) error { - bucket := tx.Bucket([]byte("bench")) - h := fnv.New32a() - buf := make([]byte, 4) - for id := uint32(0); id < 1000; id++ { - binary.LittleEndian.PutUint32(buf, id) - h.Reset() - _, _ = h.Write(buf[:]) - k := h.Sum(nil) - v := bucket.Get(k) - if v == nil { - b.Errorf("not found id=%d key=%x", id, k) - continue - } - if g, e := v, []byte("filler"); !bytes.Equal(g, e) { - b.Errorf("bad value for id=%d key=%x: %s != %q", id, k, g, e) - } - if err := bucket.Delete(k); err != nil { - return err - } - } - // should be empty now - c := bucket.Cursor() - for k, v := c.First(); k != nil; k, v = c.Next() { - b.Errorf("unexpected key: %x = %q", k, v) - } - return rollback - } - if err := db.Update(validate); err != nil && err != rollback { - b.Error(err) - } -} - -// DB is a test wrapper for bolt.DB. -type DB struct { - *bolt.DB -} - -// MustOpenDB returns a new, open DB at a temporary location. -func MustOpenDB() *DB { - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - panic(err) - } - return &DB{db} -} - -// Close closes the database and deletes the underlying file. -func (db *DB) Close() error { - // Log statistics. - if *statsFlag { - db.PrintStats() - } - - // Check database consistency after every test. - db.MustCheck() - - // Close database and remove file. - defer os.Remove(db.Path()) - return db.DB.Close() -} - -// MustClose closes the database and deletes the underlying file. Panic on error. -func (db *DB) MustClose() { - if err := db.Close(); err != nil { - panic(err) - } -} - -// PrintStats prints the database stats -func (db *DB) PrintStats() { - var stats = db.Stats() - fmt.Printf("[db] %-20s %-20s %-20s\n", - fmt.Sprintf("pg(%d/%d)", stats.TxStats.PageCount, stats.TxStats.PageAlloc), - fmt.Sprintf("cur(%d)", stats.TxStats.CursorCount), - fmt.Sprintf("node(%d/%d)", stats.TxStats.NodeCount, stats.TxStats.NodeDeref), - ) - fmt.Printf(" %-20s %-20s %-20s\n", - fmt.Sprintf("rebal(%d/%v)", stats.TxStats.Rebalance, truncDuration(stats.TxStats.RebalanceTime)), - fmt.Sprintf("spill(%d/%v)", stats.TxStats.Spill, truncDuration(stats.TxStats.SpillTime)), - fmt.Sprintf("w(%d/%v)", stats.TxStats.Write, truncDuration(stats.TxStats.WriteTime)), - ) -} - -// MustCheck runs a consistency check on the database and panics if any errors are found. -func (db *DB) MustCheck() { - if err := db.Update(func(tx *bolt.Tx) error { - // Collect all the errors. - var errors []error - for err := range tx.Check() { - errors = append(errors, err) - if len(errors) > 10 { - break - } - } - - // If errors occurred, copy the DB and print the errors. - if len(errors) > 0 { - var path = tempfile() - if err := tx.CopyFile(path, 0600); err != nil { - panic(err) - } - - // Print errors. - fmt.Print("\n\n") - fmt.Printf("consistency check failed (%d errors)\n", len(errors)) - for _, err := range errors { - fmt.Println(err) - } - fmt.Println("") - fmt.Println("db saved to:") - fmt.Println(path) - fmt.Print("\n\n") - os.Exit(-1) - } - - return nil - }); err != nil && err != bolt.ErrDatabaseNotOpen { - panic(err) - } -} - -// CopyTempFile copies a database to a temporary file. -func (db *DB) CopyTempFile() { - path := tempfile() - if err := db.View(func(tx *bolt.Tx) error { - return tx.CopyFile(path, 0600) - }); err != nil { - panic(err) - } - fmt.Println("db copied to: ", path) -} - -// tempfile returns a temporary file path. -func tempfile() string { - f, err := ioutil.TempFile("", "bolt-") - if err != nil { - panic(err) - } - if err := f.Close(); err != nil { - panic(err) - } - if err := os.Remove(f.Name()); err != nil { - panic(err) - } - return f.Name() -} - -// mustContainKeys checks that a bucket contains a given set of keys. -func mustContainKeys(b *bolt.Bucket, m map[string]string) { - found := make(map[string]string) - if err := b.ForEach(func(k, _ []byte) error { - found[string(k)] = "" - return nil - }); err != nil { - panic(err) - } - - // Check for keys found in bucket that shouldn't be there. - var keys []string - for k, _ := range found { - if _, ok := m[string(k)]; !ok { - keys = append(keys, k) - } - } - if len(keys) > 0 { - sort.Strings(keys) - panic(fmt.Sprintf("keys found(%d): %s", len(keys), strings.Join(keys, ","))) - } - - // Check for keys not found in bucket that should be there. - for k, _ := range m { - if _, ok := found[string(k)]; !ok { - keys = append(keys, k) - } - } - if len(keys) > 0 { - sort.Strings(keys) - panic(fmt.Sprintf("keys not found(%d): %s", len(keys), strings.Join(keys, ","))) - } -} - -func trunc(b []byte, length int) []byte { - if length < len(b) { - return b[:length] - } - return b -} - -func truncDuration(d time.Duration) string { - return regexp.MustCompile(`^(\d+)(\.\d+)`).ReplaceAllString(d.String(), "$1") -} - -func fileSize(path string) int64 { - fi, err := os.Stat(path) - if err != nil { - return 0 - } - return fi.Size() -} - -func warn(v ...interface{}) { fmt.Fprintln(os.Stderr, v...) } -func warnf(msg string, v ...interface{}) { fmt.Fprintf(os.Stderr, msg+"\n", v...) } - -// u64tob converts a uint64 into an 8-byte slice. -func u64tob(v uint64) []byte { - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, v) - return b -} - -// btou64 converts an 8-byte slice into an uint64. -func btou64(b []byte) uint64 { return binary.BigEndian.Uint64(b) } diff --git a/vendor/github.com/boltdb/bolt/freelist_test.go b/vendor/github.com/boltdb/bolt/freelist_test.go deleted file mode 100644 index 4e9b3a8d..00000000 --- a/vendor/github.com/boltdb/bolt/freelist_test.go +++ /dev/null @@ -1,158 +0,0 @@ -package bolt - -import ( - "math/rand" - "reflect" - "sort" - "testing" - "unsafe" -) - -// Ensure that a page is added to a transaction's freelist. -func TestFreelist_free(t *testing.T) { - f := newFreelist() - f.free(100, &page{id: 12}) - if !reflect.DeepEqual([]pgid{12}, f.pending[100]) { - t.Fatalf("exp=%v; got=%v", []pgid{12}, f.pending[100]) - } -} - -// Ensure that a page and its overflow is added to a transaction's freelist. -func TestFreelist_free_overflow(t *testing.T) { - f := newFreelist() - f.free(100, &page{id: 12, overflow: 3}) - if exp := []pgid{12, 13, 14, 15}; !reflect.DeepEqual(exp, f.pending[100]) { - t.Fatalf("exp=%v; got=%v", exp, f.pending[100]) - } -} - -// Ensure that a transaction's free pages can be released. -func TestFreelist_release(t *testing.T) { - f := newFreelist() - f.free(100, &page{id: 12, overflow: 1}) - f.free(100, &page{id: 9}) - f.free(102, &page{id: 39}) - f.release(100) - f.release(101) - if exp := []pgid{9, 12, 13}; !reflect.DeepEqual(exp, f.ids) { - t.Fatalf("exp=%v; got=%v", exp, f.ids) - } - - f.release(102) - if exp := []pgid{9, 12, 13, 39}; !reflect.DeepEqual(exp, f.ids) { - t.Fatalf("exp=%v; got=%v", exp, f.ids) - } -} - -// Ensure that a freelist can find contiguous blocks of pages. -func TestFreelist_allocate(t *testing.T) { - f := &freelist{ids: []pgid{3, 4, 5, 6, 7, 9, 12, 13, 18}} - if id := int(f.allocate(3)); id != 3 { - t.Fatalf("exp=3; got=%v", id) - } - if id := int(f.allocate(1)); id != 6 { - t.Fatalf("exp=6; got=%v", id) - } - if id := int(f.allocate(3)); id != 0 { - t.Fatalf("exp=0; got=%v", id) - } - if id := int(f.allocate(2)); id != 12 { - t.Fatalf("exp=12; got=%v", id) - } - if id := int(f.allocate(1)); id != 7 { - t.Fatalf("exp=7; got=%v", id) - } - if id := int(f.allocate(0)); id != 0 { - t.Fatalf("exp=0; got=%v", id) - } - if id := int(f.allocate(0)); id != 0 { - t.Fatalf("exp=0; got=%v", id) - } - if exp := []pgid{9, 18}; !reflect.DeepEqual(exp, f.ids) { - t.Fatalf("exp=%v; got=%v", exp, f.ids) - } - - if id := int(f.allocate(1)); id != 9 { - t.Fatalf("exp=9; got=%v", id) - } - if id := int(f.allocate(1)); id != 18 { - t.Fatalf("exp=18; got=%v", id) - } - if id := int(f.allocate(1)); id != 0 { - t.Fatalf("exp=0; got=%v", id) - } - if exp := []pgid{}; !reflect.DeepEqual(exp, f.ids) { - t.Fatalf("exp=%v; got=%v", exp, f.ids) - } -} - -// Ensure that a freelist can deserialize from a freelist page. -func TestFreelist_read(t *testing.T) { - // Create a page. - var buf [4096]byte - page := (*page)(unsafe.Pointer(&buf[0])) - page.flags = freelistPageFlag - page.count = 2 - - // Insert 2 page ids. - ids := (*[3]pgid)(unsafe.Pointer(&page.ptr)) - ids[0] = 23 - ids[1] = 50 - - // Deserialize page into a freelist. - f := newFreelist() - f.read(page) - - // Ensure that there are two page ids in the freelist. - if exp := []pgid{23, 50}; !reflect.DeepEqual(exp, f.ids) { - t.Fatalf("exp=%v; got=%v", exp, f.ids) - } -} - -// Ensure that a freelist can serialize into a freelist page. -func TestFreelist_write(t *testing.T) { - // Create a freelist and write it to a page. - var buf [4096]byte - f := &freelist{ids: []pgid{12, 39}, pending: make(map[txid][]pgid)} - f.pending[100] = []pgid{28, 11} - f.pending[101] = []pgid{3} - p := (*page)(unsafe.Pointer(&buf[0])) - if err := f.write(p); err != nil { - t.Fatal(err) - } - - // Read the page back out. - f2 := newFreelist() - f2.read(p) - - // Ensure that the freelist is correct. - // All pages should be present and in reverse order. - if exp := []pgid{3, 11, 12, 28, 39}; !reflect.DeepEqual(exp, f2.ids) { - t.Fatalf("exp=%v; got=%v", exp, f2.ids) - } -} - -func Benchmark_FreelistRelease10K(b *testing.B) { benchmark_FreelistRelease(b, 10000) } -func Benchmark_FreelistRelease100K(b *testing.B) { benchmark_FreelistRelease(b, 100000) } -func Benchmark_FreelistRelease1000K(b *testing.B) { benchmark_FreelistRelease(b, 1000000) } -func Benchmark_FreelistRelease10000K(b *testing.B) { benchmark_FreelistRelease(b, 10000000) } - -func benchmark_FreelistRelease(b *testing.B, size int) { - ids := randomPgids(size) - pending := randomPgids(len(ids) / 400) - b.ResetTimer() - for i := 0; i < b.N; i++ { - f := &freelist{ids: ids, pending: map[txid][]pgid{1: pending}} - f.release(1) - } -} - -func randomPgids(n int) []pgid { - rand.Seed(42) - pgids := make(pgids, n) - for i := range pgids { - pgids[i] = pgid(rand.Int63()) - } - sort.Sort(pgids) - return pgids -} diff --git a/vendor/github.com/boltdb/bolt/node_test.go b/vendor/github.com/boltdb/bolt/node_test.go deleted file mode 100644 index fa5d10f9..00000000 --- a/vendor/github.com/boltdb/bolt/node_test.go +++ /dev/null @@ -1,156 +0,0 @@ -package bolt - -import ( - "testing" - "unsafe" -) - -// Ensure that a node can insert a key/value. -func TestNode_put(t *testing.T) { - n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{meta: &meta{pgid: 1}}}} - n.put([]byte("baz"), []byte("baz"), []byte("2"), 0, 0) - n.put([]byte("foo"), []byte("foo"), []byte("0"), 0, 0) - n.put([]byte("bar"), []byte("bar"), []byte("1"), 0, 0) - n.put([]byte("foo"), []byte("foo"), []byte("3"), 0, leafPageFlag) - - if len(n.inodes) != 3 { - t.Fatalf("exp=3; got=%d", len(n.inodes)) - } - if k, v := n.inodes[0].key, n.inodes[0].value; string(k) != "bar" || string(v) != "1" { - t.Fatalf("exp=; got=<%s,%s>", k, v) - } - if k, v := n.inodes[1].key, n.inodes[1].value; string(k) != "baz" || string(v) != "2" { - t.Fatalf("exp=; got=<%s,%s>", k, v) - } - if k, v := n.inodes[2].key, n.inodes[2].value; string(k) != "foo" || string(v) != "3" { - t.Fatalf("exp=; got=<%s,%s>", k, v) - } - if n.inodes[2].flags != uint32(leafPageFlag) { - t.Fatalf("not a leaf: %d", n.inodes[2].flags) - } -} - -// Ensure that a node can deserialize from a leaf page. -func TestNode_read_LeafPage(t *testing.T) { - // Create a page. - var buf [4096]byte - page := (*page)(unsafe.Pointer(&buf[0])) - page.flags = leafPageFlag - page.count = 2 - - // Insert 2 elements at the beginning. sizeof(leafPageElement) == 16 - nodes := (*[3]leafPageElement)(unsafe.Pointer(&page.ptr)) - nodes[0] = leafPageElement{flags: 0, pos: 32, ksize: 3, vsize: 4} // pos = sizeof(leafPageElement) * 2 - nodes[1] = leafPageElement{flags: 0, pos: 23, ksize: 10, vsize: 3} // pos = sizeof(leafPageElement) + 3 + 4 - - // Write data for the nodes at the end. - data := (*[4096]byte)(unsafe.Pointer(&nodes[2])) - copy(data[:], []byte("barfooz")) - copy(data[7:], []byte("helloworldbye")) - - // Deserialize page into a leaf. - n := &node{} - n.read(page) - - // Check that there are two inodes with correct data. - if !n.isLeaf { - t.Fatal("expected leaf") - } - if len(n.inodes) != 2 { - t.Fatalf("exp=2; got=%d", len(n.inodes)) - } - if k, v := n.inodes[0].key, n.inodes[0].value; string(k) != "bar" || string(v) != "fooz" { - t.Fatalf("exp=; got=<%s,%s>", k, v) - } - if k, v := n.inodes[1].key, n.inodes[1].value; string(k) != "helloworld" || string(v) != "bye" { - t.Fatalf("exp=; got=<%s,%s>", k, v) - } -} - -// Ensure that a node can serialize into a leaf page. -func TestNode_write_LeafPage(t *testing.T) { - // Create a node. - n := &node{isLeaf: true, inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, meta: &meta{pgid: 1}}}} - n.put([]byte("susy"), []byte("susy"), []byte("que"), 0, 0) - n.put([]byte("ricki"), []byte("ricki"), []byte("lake"), 0, 0) - n.put([]byte("john"), []byte("john"), []byte("johnson"), 0, 0) - - // Write it to a page. - var buf [4096]byte - p := (*page)(unsafe.Pointer(&buf[0])) - n.write(p) - - // Read the page back in. - n2 := &node{} - n2.read(p) - - // Check that the two pages are the same. - if len(n2.inodes) != 3 { - t.Fatalf("exp=3; got=%d", len(n2.inodes)) - } - if k, v := n2.inodes[0].key, n2.inodes[0].value; string(k) != "john" || string(v) != "johnson" { - t.Fatalf("exp=; got=<%s,%s>", k, v) - } - if k, v := n2.inodes[1].key, n2.inodes[1].value; string(k) != "ricki" || string(v) != "lake" { - t.Fatalf("exp=; got=<%s,%s>", k, v) - } - if k, v := n2.inodes[2].key, n2.inodes[2].value; string(k) != "susy" || string(v) != "que" { - t.Fatalf("exp=; got=<%s,%s>", k, v) - } -} - -// Ensure that a node can split into appropriate subgroups. -func TestNode_split(t *testing.T) { - // Create a node. - n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, meta: &meta{pgid: 1}}}} - n.put([]byte("00000001"), []byte("00000001"), []byte("0123456701234567"), 0, 0) - n.put([]byte("00000002"), []byte("00000002"), []byte("0123456701234567"), 0, 0) - n.put([]byte("00000003"), []byte("00000003"), []byte("0123456701234567"), 0, 0) - n.put([]byte("00000004"), []byte("00000004"), []byte("0123456701234567"), 0, 0) - n.put([]byte("00000005"), []byte("00000005"), []byte("0123456701234567"), 0, 0) - - // Split between 2 & 3. - n.split(100) - - var parent = n.parent - if len(parent.children) != 2 { - t.Fatalf("exp=2; got=%d", len(parent.children)) - } - if len(parent.children[0].inodes) != 2 { - t.Fatalf("exp=2; got=%d", len(parent.children[0].inodes)) - } - if len(parent.children[1].inodes) != 3 { - t.Fatalf("exp=3; got=%d", len(parent.children[1].inodes)) - } -} - -// Ensure that a page with the minimum number of inodes just returns a single node. -func TestNode_split_MinKeys(t *testing.T) { - // Create a node. - n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, meta: &meta{pgid: 1}}}} - n.put([]byte("00000001"), []byte("00000001"), []byte("0123456701234567"), 0, 0) - n.put([]byte("00000002"), []byte("00000002"), []byte("0123456701234567"), 0, 0) - - // Split. - n.split(20) - if n.parent != nil { - t.Fatalf("expected nil parent") - } -} - -// Ensure that a node that has keys that all fit on a page just returns one leaf. -func TestNode_split_SinglePage(t *testing.T) { - // Create a node. - n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, meta: &meta{pgid: 1}}}} - n.put([]byte("00000001"), []byte("00000001"), []byte("0123456701234567"), 0, 0) - n.put([]byte("00000002"), []byte("00000002"), []byte("0123456701234567"), 0, 0) - n.put([]byte("00000003"), []byte("00000003"), []byte("0123456701234567"), 0, 0) - n.put([]byte("00000004"), []byte("00000004"), []byte("0123456701234567"), 0, 0) - n.put([]byte("00000005"), []byte("00000005"), []byte("0123456701234567"), 0, 0) - - // Split. - n.split(4096) - if n.parent != nil { - t.Fatalf("expected nil parent") - } -} diff --git a/vendor/github.com/boltdb/bolt/page_test.go b/vendor/github.com/boltdb/bolt/page_test.go deleted file mode 100644 index 59f4a30e..00000000 --- a/vendor/github.com/boltdb/bolt/page_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package bolt - -import ( - "reflect" - "sort" - "testing" - "testing/quick" -) - -// Ensure that the page type can be returned in human readable format. -func TestPage_typ(t *testing.T) { - if typ := (&page{flags: branchPageFlag}).typ(); typ != "branch" { - t.Fatalf("exp=branch; got=%v", typ) - } - if typ := (&page{flags: leafPageFlag}).typ(); typ != "leaf" { - t.Fatalf("exp=leaf; got=%v", typ) - } - if typ := (&page{flags: metaPageFlag}).typ(); typ != "meta" { - t.Fatalf("exp=meta; got=%v", typ) - } - if typ := (&page{flags: freelistPageFlag}).typ(); typ != "freelist" { - t.Fatalf("exp=freelist; got=%v", typ) - } - if typ := (&page{flags: 20000}).typ(); typ != "unknown<4e20>" { - t.Fatalf("exp=unknown<4e20>; got=%v", typ) - } -} - -// Ensure that the hexdump debugging function doesn't blow up. -func TestPage_dump(t *testing.T) { - (&page{id: 256}).hexdump(16) -} - -func TestPgids_merge(t *testing.T) { - a := pgids{4, 5, 6, 10, 11, 12, 13, 27} - b := pgids{1, 3, 8, 9, 25, 30} - c := a.merge(b) - if !reflect.DeepEqual(c, pgids{1, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 25, 27, 30}) { - t.Errorf("mismatch: %v", c) - } - - a = pgids{4, 5, 6, 10, 11, 12, 13, 27, 35, 36} - b = pgids{8, 9, 25, 30} - c = a.merge(b) - if !reflect.DeepEqual(c, pgids{4, 5, 6, 8, 9, 10, 11, 12, 13, 25, 27, 30, 35, 36}) { - t.Errorf("mismatch: %v", c) - } -} - -func TestPgids_merge_quick(t *testing.T) { - if err := quick.Check(func(a, b pgids) bool { - // Sort incoming lists. - sort.Sort(a) - sort.Sort(b) - - // Merge the two lists together. - got := a.merge(b) - - // The expected value should be the two lists combined and sorted. - exp := append(a, b...) - sort.Sort(exp) - - if !reflect.DeepEqual(exp, got) { - t.Errorf("\nexp=%+v\ngot=%+v\n", exp, got) - return false - } - - return true - }, nil); err != nil { - t.Fatal(err) - } -} diff --git a/vendor/github.com/boltdb/bolt/quick_test.go b/vendor/github.com/boltdb/bolt/quick_test.go deleted file mode 100644 index 9e27792e..00000000 --- a/vendor/github.com/boltdb/bolt/quick_test.go +++ /dev/null @@ -1,87 +0,0 @@ -package bolt_test - -import ( - "bytes" - "flag" - "fmt" - "math/rand" - "os" - "reflect" - "testing/quick" - "time" -) - -// testing/quick defaults to 5 iterations and a random seed. -// You can override these settings from the command line: -// -// -quick.count The number of iterations to perform. -// -quick.seed The seed to use for randomizing. -// -quick.maxitems The maximum number of items to insert into a DB. -// -quick.maxksize The maximum size of a key. -// -quick.maxvsize The maximum size of a value. -// - -var qcount, qseed, qmaxitems, qmaxksize, qmaxvsize int - -func init() { - flag.IntVar(&qcount, "quick.count", 5, "") - flag.IntVar(&qseed, "quick.seed", int(time.Now().UnixNano())%100000, "") - flag.IntVar(&qmaxitems, "quick.maxitems", 1000, "") - flag.IntVar(&qmaxksize, "quick.maxksize", 1024, "") - flag.IntVar(&qmaxvsize, "quick.maxvsize", 1024, "") - flag.Parse() - fmt.Fprintln(os.Stderr, "seed:", qseed) - fmt.Fprintf(os.Stderr, "quick settings: count=%v, items=%v, ksize=%v, vsize=%v\n", qcount, qmaxitems, qmaxksize, qmaxvsize) -} - -func qconfig() *quick.Config { - return &quick.Config{ - MaxCount: qcount, - Rand: rand.New(rand.NewSource(int64(qseed))), - } -} - -type testdata []testdataitem - -func (t testdata) Len() int { return len(t) } -func (t testdata) Swap(i, j int) { t[i], t[j] = t[j], t[i] } -func (t testdata) Less(i, j int) bool { return bytes.Compare(t[i].Key, t[j].Key) == -1 } - -func (t testdata) Generate(rand *rand.Rand, size int) reflect.Value { - n := rand.Intn(qmaxitems-1) + 1 - items := make(testdata, n) - used := make(map[string]bool) - for i := 0; i < n; i++ { - item := &items[i] - // Ensure that keys are unique by looping until we find one that we have not already used. - for { - item.Key = randByteSlice(rand, 1, qmaxksize) - if !used[string(item.Key)] { - used[string(item.Key)] = true - break - } - } - item.Value = randByteSlice(rand, 0, qmaxvsize) - } - return reflect.ValueOf(items) -} - -type revtestdata []testdataitem - -func (t revtestdata) Len() int { return len(t) } -func (t revtestdata) Swap(i, j int) { t[i], t[j] = t[j], t[i] } -func (t revtestdata) Less(i, j int) bool { return bytes.Compare(t[i].Key, t[j].Key) == 1 } - -type testdataitem struct { - Key []byte - Value []byte -} - -func randByteSlice(rand *rand.Rand, minSize, maxSize int) []byte { - n := rand.Intn(maxSize-minSize) + minSize - b := make([]byte, n) - for i := 0; i < n; i++ { - b[i] = byte(rand.Intn(255)) - } - return b -} diff --git a/vendor/github.com/boltdb/bolt/simulation_test.go b/vendor/github.com/boltdb/bolt/simulation_test.go deleted file mode 100644 index 38310165..00000000 --- a/vendor/github.com/boltdb/bolt/simulation_test.go +++ /dev/null @@ -1,329 +0,0 @@ -package bolt_test - -import ( - "bytes" - "fmt" - "math/rand" - "sync" - "testing" - - "github.com/boltdb/bolt" -) - -func TestSimulate_1op_1p(t *testing.T) { testSimulate(t, 1, 1) } -func TestSimulate_10op_1p(t *testing.T) { testSimulate(t, 10, 1) } -func TestSimulate_100op_1p(t *testing.T) { testSimulate(t, 100, 1) } -func TestSimulate_1000op_1p(t *testing.T) { testSimulate(t, 1000, 1) } -func TestSimulate_10000op_1p(t *testing.T) { testSimulate(t, 10000, 1) } - -func TestSimulate_10op_10p(t *testing.T) { testSimulate(t, 10, 10) } -func TestSimulate_100op_10p(t *testing.T) { testSimulate(t, 100, 10) } -func TestSimulate_1000op_10p(t *testing.T) { testSimulate(t, 1000, 10) } -func TestSimulate_10000op_10p(t *testing.T) { testSimulate(t, 10000, 10) } - -func TestSimulate_100op_100p(t *testing.T) { testSimulate(t, 100, 100) } -func TestSimulate_1000op_100p(t *testing.T) { testSimulate(t, 1000, 100) } -func TestSimulate_10000op_100p(t *testing.T) { testSimulate(t, 10000, 100) } - -func TestSimulate_10000op_1000p(t *testing.T) { testSimulate(t, 10000, 1000) } - -// Randomly generate operations on a given database with multiple clients to ensure consistency and thread safety. -func testSimulate(t *testing.T, threadCount, parallelism int) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - - rand.Seed(int64(qseed)) - - // A list of operations that readers and writers can perform. - var readerHandlers = []simulateHandler{simulateGetHandler} - var writerHandlers = []simulateHandler{simulateGetHandler, simulatePutHandler} - - var versions = make(map[int]*QuickDB) - versions[1] = NewQuickDB() - - db := MustOpenDB() - defer db.MustClose() - - var mutex sync.Mutex - - // Run n threads in parallel, each with their own operation. - var wg sync.WaitGroup - var threads = make(chan bool, parallelism) - var i int - for { - threads <- true - wg.Add(1) - writable := ((rand.Int() % 100) < 20) // 20% writers - - // Choose an operation to execute. - var handler simulateHandler - if writable { - handler = writerHandlers[rand.Intn(len(writerHandlers))] - } else { - handler = readerHandlers[rand.Intn(len(readerHandlers))] - } - - // Execute a thread for the given operation. - go func(writable bool, handler simulateHandler) { - defer wg.Done() - - // Start transaction. - tx, err := db.Begin(writable) - if err != nil { - t.Fatal("tx begin: ", err) - } - - // Obtain current state of the dataset. - mutex.Lock() - var qdb = versions[tx.ID()] - if writable { - qdb = versions[tx.ID()-1].Copy() - } - mutex.Unlock() - - // Make sure we commit/rollback the tx at the end and update the state. - if writable { - defer func() { - mutex.Lock() - versions[tx.ID()] = qdb - mutex.Unlock() - - if err := tx.Commit(); err != nil { - t.Fatal(err) - } - }() - } else { - defer func() { _ = tx.Rollback() }() - } - - // Ignore operation if we don't have data yet. - if qdb == nil { - return - } - - // Execute handler. - handler(tx, qdb) - - // Release a thread back to the scheduling loop. - <-threads - }(writable, handler) - - i++ - if i > threadCount { - break - } - } - - // Wait until all threads are done. - wg.Wait() -} - -type simulateHandler func(tx *bolt.Tx, qdb *QuickDB) - -// Retrieves a key from the database and verifies that it is what is expected. -func simulateGetHandler(tx *bolt.Tx, qdb *QuickDB) { - // Randomly retrieve an existing exist. - keys := qdb.Rand() - if len(keys) == 0 { - return - } - - // Retrieve root bucket. - b := tx.Bucket(keys[0]) - if b == nil { - panic(fmt.Sprintf("bucket[0] expected: %08x\n", trunc(keys[0], 4))) - } - - // Drill into nested buckets. - for _, key := range keys[1 : len(keys)-1] { - b = b.Bucket(key) - if b == nil { - panic(fmt.Sprintf("bucket[n] expected: %v -> %v\n", keys, key)) - } - } - - // Verify key/value on the final bucket. - expected := qdb.Get(keys) - actual := b.Get(keys[len(keys)-1]) - if !bytes.Equal(actual, expected) { - fmt.Println("=== EXPECTED ===") - fmt.Println(expected) - fmt.Println("=== ACTUAL ===") - fmt.Println(actual) - fmt.Println("=== END ===") - panic("value mismatch") - } -} - -// Inserts a key into the database. -func simulatePutHandler(tx *bolt.Tx, qdb *QuickDB) { - var err error - keys, value := randKeys(), randValue() - - // Retrieve root bucket. - b := tx.Bucket(keys[0]) - if b == nil { - b, err = tx.CreateBucket(keys[0]) - if err != nil { - panic("create bucket: " + err.Error()) - } - } - - // Create nested buckets, if necessary. - for _, key := range keys[1 : len(keys)-1] { - child := b.Bucket(key) - if child != nil { - b = child - } else { - b, err = b.CreateBucket(key) - if err != nil { - panic("create bucket: " + err.Error()) - } - } - } - - // Insert into database. - if err := b.Put(keys[len(keys)-1], value); err != nil { - panic("put: " + err.Error()) - } - - // Insert into in-memory database. - qdb.Put(keys, value) -} - -// QuickDB is an in-memory database that replicates the functionality of the -// Bolt DB type except that it is entirely in-memory. It is meant for testing -// that the Bolt database is consistent. -type QuickDB struct { - sync.RWMutex - m map[string]interface{} -} - -// NewQuickDB returns an instance of QuickDB. -func NewQuickDB() *QuickDB { - return &QuickDB{m: make(map[string]interface{})} -} - -// Get retrieves the value at a key path. -func (db *QuickDB) Get(keys [][]byte) []byte { - db.RLock() - defer db.RUnlock() - - m := db.m - for _, key := range keys[:len(keys)-1] { - value := m[string(key)] - if value == nil { - return nil - } - switch value := value.(type) { - case map[string]interface{}: - m = value - case []byte: - return nil - } - } - - // Only return if it's a simple value. - if value, ok := m[string(keys[len(keys)-1])].([]byte); ok { - return value - } - return nil -} - -// Put inserts a value into a key path. -func (db *QuickDB) Put(keys [][]byte, value []byte) { - db.Lock() - defer db.Unlock() - - // Build buckets all the way down the key path. - m := db.m - for _, key := range keys[:len(keys)-1] { - if _, ok := m[string(key)].([]byte); ok { - return // Keypath intersects with a simple value. Do nothing. - } - - if m[string(key)] == nil { - m[string(key)] = make(map[string]interface{}) - } - m = m[string(key)].(map[string]interface{}) - } - - // Insert value into the last key. - m[string(keys[len(keys)-1])] = value -} - -// Rand returns a random key path that points to a simple value. -func (db *QuickDB) Rand() [][]byte { - db.RLock() - defer db.RUnlock() - if len(db.m) == 0 { - return nil - } - var keys [][]byte - db.rand(db.m, &keys) - return keys -} - -func (db *QuickDB) rand(m map[string]interface{}, keys *[][]byte) { - i, index := 0, rand.Intn(len(m)) - for k, v := range m { - if i == index { - *keys = append(*keys, []byte(k)) - if v, ok := v.(map[string]interface{}); ok { - db.rand(v, keys) - } - return - } - i++ - } - panic("quickdb rand: out-of-range") -} - -// Copy copies the entire database. -func (db *QuickDB) Copy() *QuickDB { - db.RLock() - defer db.RUnlock() - return &QuickDB{m: db.copy(db.m)} -} - -func (db *QuickDB) copy(m map[string]interface{}) map[string]interface{} { - clone := make(map[string]interface{}, len(m)) - for k, v := range m { - switch v := v.(type) { - case map[string]interface{}: - clone[k] = db.copy(v) - default: - clone[k] = v - } - } - return clone -} - -func randKey() []byte { - var min, max = 1, 1024 - n := rand.Intn(max-min) + min - b := make([]byte, n) - for i := 0; i < n; i++ { - b[i] = byte(rand.Intn(255)) - } - return b -} - -func randKeys() [][]byte { - var keys [][]byte - var count = rand.Intn(2) + 2 - for i := 0; i < count; i++ { - keys = append(keys, randKey()) - } - return keys -} - -func randValue() []byte { - n := rand.Intn(8192) - b := make([]byte, n) - for i := 0; i < n; i++ { - b[i] = byte(rand.Intn(255)) - } - return b -} diff --git a/vendor/github.com/boltdb/bolt/tx_test.go b/vendor/github.com/boltdb/bolt/tx_test.go deleted file mode 100644 index 2201e792..00000000 --- a/vendor/github.com/boltdb/bolt/tx_test.go +++ /dev/null @@ -1,716 +0,0 @@ -package bolt_test - -import ( - "bytes" - "errors" - "fmt" - "log" - "os" - "testing" - - "github.com/boltdb/bolt" -) - -// Ensure that committing a closed transaction returns an error. -func TestTx_Commit_ErrTxClosed(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - - if _, err := tx.CreateBucket([]byte("foo")); err != nil { - t.Fatal(err) - } - - if err := tx.Commit(); err != nil { - t.Fatal(err) - } - - if err := tx.Commit(); err != bolt.ErrTxClosed { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that rolling back a closed transaction returns an error. -func TestTx_Rollback_ErrTxClosed(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } - if err := tx.Rollback(); err != bolt.ErrTxClosed { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that committing a read-only transaction returns an error. -func TestTx_Commit_ErrTxNotWritable(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - tx, err := db.Begin(false) - if err != nil { - t.Fatal(err) - } - if err := tx.Commit(); err != bolt.ErrTxNotWritable { - t.Fatal(err) - } -} - -// Ensure that a transaction can retrieve a cursor on the root bucket. -func TestTx_Cursor(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - - if _, err := tx.CreateBucket([]byte("woojits")); err != nil { - t.Fatal(err) - } - - c := tx.Cursor() - if k, v := c.First(); !bytes.Equal(k, []byte("widgets")) { - t.Fatalf("unexpected key: %v", k) - } else if v != nil { - t.Fatalf("unexpected value: %v", v) - } - - if k, v := c.Next(); !bytes.Equal(k, []byte("woojits")) { - t.Fatalf("unexpected key: %v", k) - } else if v != nil { - t.Fatalf("unexpected value: %v", v) - } - - if k, v := c.Next(); k != nil { - t.Fatalf("unexpected key: %v", k) - } else if v != nil { - t.Fatalf("unexpected value: %v", k) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that creating a bucket with a read-only transaction returns an error. -func TestTx_CreateBucket_ErrTxNotWritable(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.View(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("foo")) - if err != bolt.ErrTxNotWritable { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that creating a bucket on a closed transaction returns an error. -func TestTx_CreateBucket_ErrTxClosed(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - if err := tx.Commit(); err != nil { - t.Fatal(err) - } - - if _, err := tx.CreateBucket([]byte("foo")); err != bolt.ErrTxClosed { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that a Tx can retrieve a bucket. -func TestTx_Bucket(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - if tx.Bucket([]byte("widgets")) == nil { - t.Fatal("expected bucket") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a Tx retrieving a non-existent key returns nil. -func TestTx_Get_NotFound(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if b.Get([]byte("no_such_key")) != nil { - t.Fatal("expected nil value") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket can be created and retrieved. -func TestTx_CreateBucket(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - // Create a bucket. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } else if b == nil { - t.Fatal("expected bucket") - } - return nil - }); err != nil { - t.Fatal(err) - } - - // Read the bucket through a separate transaction. - if err := db.View(func(tx *bolt.Tx) error { - if tx.Bucket([]byte("widgets")) == nil { - t.Fatal("expected bucket") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket can be created if it doesn't already exist. -func TestTx_CreateBucketIfNotExists(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - // Create bucket. - if b, err := tx.CreateBucketIfNotExists([]byte("widgets")); err != nil { - t.Fatal(err) - } else if b == nil { - t.Fatal("expected bucket") - } - - // Create bucket again. - if b, err := tx.CreateBucketIfNotExists([]byte("widgets")); err != nil { - t.Fatal(err) - } else if b == nil { - t.Fatal("expected bucket") - } - - return nil - }); err != nil { - t.Fatal(err) - } - - // Read the bucket through a separate transaction. - if err := db.View(func(tx *bolt.Tx) error { - if tx.Bucket([]byte("widgets")) == nil { - t.Fatal("expected bucket") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure transaction returns an error if creating an unnamed bucket. -func TestTx_CreateBucketIfNotExists_ErrBucketNameRequired(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucketIfNotExists([]byte{}); err != bolt.ErrBucketNameRequired { - t.Fatalf("unexpected error: %s", err) - } - - if _, err := tx.CreateBucketIfNotExists(nil); err != bolt.ErrBucketNameRequired { - t.Fatalf("unexpected error: %s", err) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket cannot be created twice. -func TestTx_CreateBucket_ErrBucketExists(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - // Create a bucket. - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - // Create the same bucket again. - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != bolt.ErrBucketExists { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket is created with a non-blank name. -func TestTx_CreateBucket_ErrBucketNameRequired(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket(nil); err != bolt.ErrBucketNameRequired { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket can be deleted. -func TestTx_DeleteBucket(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - // Create a bucket and add a value. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - // Delete the bucket and make sure we can't get the value. - if err := db.Update(func(tx *bolt.Tx) error { - if err := tx.DeleteBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - if tx.Bucket([]byte("widgets")) != nil { - t.Fatal("unexpected bucket") - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.Update(func(tx *bolt.Tx) error { - // Create the bucket again and make sure there's not a phantom value. - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if v := b.Get([]byte("foo")); v != nil { - t.Fatalf("unexpected phantom value: %v", v) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that deleting a bucket on a closed transaction returns an error. -func TestTx_DeleteBucket_ErrTxClosed(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - if err := tx.Commit(); err != nil { - t.Fatal(err) - } - if err := tx.DeleteBucket([]byte("foo")); err != bolt.ErrTxClosed { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that deleting a bucket with a read-only transaction returns an error. -func TestTx_DeleteBucket_ReadOnly(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.View(func(tx *bolt.Tx) error { - if err := tx.DeleteBucket([]byte("foo")); err != bolt.ErrTxNotWritable { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that nothing happens when deleting a bucket that doesn't exist. -func TestTx_DeleteBucket_NotFound(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - if err := tx.DeleteBucket([]byte("widgets")); err != bolt.ErrBucketNotFound { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that no error is returned when a tx.ForEach function does not return -// an error. -func TestTx_ForEach_NoError(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - - if err := tx.ForEach(func(name []byte, b *bolt.Bucket) error { - return nil - }); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that an error is returned when a tx.ForEach function returns an error. -func TestTx_ForEach_WithError(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - - marker := errors.New("marker") - if err := tx.ForEach(func(name []byte, b *bolt.Bucket) error { - return marker - }); err != marker { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that Tx commit handlers are called after a transaction successfully commits. -func TestTx_OnCommit(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - var x int - if err := db.Update(func(tx *bolt.Tx) error { - tx.OnCommit(func() { x += 1 }) - tx.OnCommit(func() { x += 2 }) - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } else if x != 3 { - t.Fatalf("unexpected x: %d", x) - } -} - -// Ensure that Tx commit handlers are NOT called after a transaction rolls back. -func TestTx_OnCommit_Rollback(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - var x int - if err := db.Update(func(tx *bolt.Tx) error { - tx.OnCommit(func() { x += 1 }) - tx.OnCommit(func() { x += 2 }) - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return errors.New("rollback this commit") - }); err == nil || err.Error() != "rollback this commit" { - t.Fatalf("unexpected error: %s", err) - } else if x != 0 { - t.Fatalf("unexpected x: %d", x) - } -} - -// Ensure that the database can be copied to a file path. -func TestTx_CopyFile(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - path := tempfile() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("baz"), []byte("bat")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - return tx.CopyFile(path, 0600) - }); err != nil { - t.Fatal(err) - } - - db2, err := bolt.Open(path, 0600, nil) - if err != nil { - t.Fatal(err) - } - - if err := db2.View(func(tx *bolt.Tx) error { - if v := tx.Bucket([]byte("widgets")).Get([]byte("foo")); !bytes.Equal(v, []byte("bar")) { - t.Fatalf("unexpected value: %v", v) - } - if v := tx.Bucket([]byte("widgets")).Get([]byte("baz")); !bytes.Equal(v, []byte("bat")) { - t.Fatalf("unexpected value: %v", v) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db2.Close(); err != nil { - t.Fatal(err) - } -} - -type failWriterError struct{} - -func (failWriterError) Error() string { - return "error injected for tests" -} - -type failWriter struct { - // fail after this many bytes - After int -} - -func (f *failWriter) Write(p []byte) (n int, err error) { - n = len(p) - if n > f.After { - n = f.After - err = failWriterError{} - } - f.After -= n - return n, err -} - -// Ensure that Copy handles write errors right. -func TestTx_CopyFile_Error_Meta(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("baz"), []byte("bat")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - return tx.Copy(&failWriter{}) - }); err == nil || err.Error() != "meta 0 copy: error injected for tests" { - t.Fatalf("unexpected error: %v", err) - } -} - -// Ensure that Copy handles write errors right. -func TestTx_CopyFile_Error_Normal(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("baz"), []byte("bat")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - return tx.Copy(&failWriter{3 * db.Info().PageSize}) - }); err == nil || err.Error() != "error injected for tests" { - t.Fatalf("unexpected error: %v", err) - } -} - -func ExampleTx_Rollback() { - // Open the database. - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - log.Fatal(err) - } - defer os.Remove(db.Path()) - - // Create a bucket. - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("widgets")) - return err - }); err != nil { - log.Fatal(err) - } - - // Set a value for a key. - if err := db.Update(func(tx *bolt.Tx) error { - return tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar")) - }); err != nil { - log.Fatal(err) - } - - // Update the key but rollback the transaction so it never saves. - tx, err := db.Begin(true) - if err != nil { - log.Fatal(err) - } - b := tx.Bucket([]byte("widgets")) - if err := b.Put([]byte("foo"), []byte("baz")); err != nil { - log.Fatal(err) - } - if err := tx.Rollback(); err != nil { - log.Fatal(err) - } - - // Ensure that our original value is still set. - if err := db.View(func(tx *bolt.Tx) error { - value := tx.Bucket([]byte("widgets")).Get([]byte("foo")) - fmt.Printf("The value for 'foo' is still: %s\n", value) - return nil - }); err != nil { - log.Fatal(err) - } - - // Close database to release file lock. - if err := db.Close(); err != nil { - log.Fatal(err) - } - - // Output: - // The value for 'foo' is still: bar -} - -func ExampleTx_CopyFile() { - // Open the database. - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - log.Fatal(err) - } - defer os.Remove(db.Path()) - - // Create a bucket and a key. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - return err - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - return err - } - return nil - }); err != nil { - log.Fatal(err) - } - - // Copy the database to another file. - toFile := tempfile() - if err := db.View(func(tx *bolt.Tx) error { - return tx.CopyFile(toFile, 0666) - }); err != nil { - log.Fatal(err) - } - defer os.Remove(toFile) - - // Open the cloned database. - db2, err := bolt.Open(toFile, 0666, nil) - if err != nil { - log.Fatal(err) - } - - // Ensure that the key exists in the copy. - if err := db2.View(func(tx *bolt.Tx) error { - value := tx.Bucket([]byte("widgets")).Get([]byte("foo")) - fmt.Printf("The value for 'foo' in the clone is: %s\n", value) - return nil - }); err != nil { - log.Fatal(err) - } - - // Close database to release file lock. - if err := db.Close(); err != nil { - log.Fatal(err) - } - - if err := db2.Close(); err != nil { - log.Fatal(err) - } - - // Output: - // The value for 'foo' in the clone is: bar -} diff --git a/vendor/github.com/davecgh/go-spew/.gitignore b/vendor/github.com/davecgh/go-spew/.gitignore deleted file mode 100644 index 00268614..00000000 --- a/vendor/github.com/davecgh/go-spew/.gitignore +++ /dev/null @@ -1,22 +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 diff --git a/vendor/github.com/davecgh/go-spew/.travis.yml b/vendor/github.com/davecgh/go-spew/.travis.yml deleted file mode 100644 index 984e0736..00000000 --- a/vendor/github.com/davecgh/go-spew/.travis.yml +++ /dev/null @@ -1,14 +0,0 @@ -language: go -go: - - 1.5.4 - - 1.6.3 - - 1.7 -install: - - go get -v golang.org/x/tools/cmd/cover -script: - - go test -v -tags=safe ./spew - - go test -v -tags=testcgo ./spew -covermode=count -coverprofile=profile.cov -after_success: - - go get -v github.com/mattn/goveralls - - export PATH=$PATH:$HOME/gopath/bin - - goveralls -coverprofile=profile.cov -service=travis-ci diff --git a/vendor/github.com/davecgh/go-spew/README.md b/vendor/github.com/davecgh/go-spew/README.md deleted file mode 100644 index 26243044..00000000 --- a/vendor/github.com/davecgh/go-spew/README.md +++ /dev/null @@ -1,205 +0,0 @@ -go-spew -======= - -[![Build Status](https://img.shields.io/travis/davecgh/go-spew.svg)] -(https://travis-ci.org/davecgh/go-spew) [![ISC License] -(http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![Coverage Status] -(https://img.shields.io/coveralls/davecgh/go-spew.svg)] -(https://coveralls.io/r/davecgh/go-spew?branch=master) - - -Go-spew implements a deep pretty printer for Go data structures to aid in -debugging. A comprehensive suite of tests with 100% test coverage is provided -to ensure proper functionality. See `test_coverage.txt` for the gocov coverage -report. Go-spew is licensed under the liberal ISC license, so it may be used in -open source or commercial projects. - -If you're interested in reading about how this package came to life and some -of the challenges involved in providing a deep pretty printer, there is a blog -post about it -[here](https://web.archive.org/web/20160304013555/https://blog.cyphertite.com/go-spew-a-journey-into-dumping-go-data-structures/). - -## Documentation - -[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)] -(http://godoc.org/github.com/davecgh/go-spew/spew) - -Full `go doc` style documentation for the project can be viewed online without -installing this package by using the excellent GoDoc site here: -http://godoc.org/github.com/davecgh/go-spew/spew - -You can also view the documentation locally once the package is installed with -the `godoc` tool by running `godoc -http=":6060"` and pointing your browser to -http://localhost:6060/pkg/github.com/davecgh/go-spew/spew - -## Installation - -```bash -$ go get -u github.com/davecgh/go-spew/spew -``` - -## Quick Start - -Add this import line to the file you're working in: - -```Go -import "github.com/davecgh/go-spew/spew" -``` - -To dump a variable with full newlines, indentation, type, and pointer -information use Dump, Fdump, or Sdump: - -```Go -spew.Dump(myVar1, myVar2, ...) -spew.Fdump(someWriter, myVar1, myVar2, ...) -str := spew.Sdump(myVar1, myVar2, ...) -``` - -Alternatively, if you would prefer to use format strings with a compacted inline -printing style, use the convenience wrappers Printf, Fprintf, etc with %v (most -compact), %+v (adds pointer addresses), %#v (adds types), or %#+v (adds types -and pointer addresses): - -```Go -spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) -spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) -spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) -spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) -``` - -## Debugging a Web Application Example - -Here is an example of how you can use `spew.Sdump()` to help debug a web application. Please be sure to wrap your output using the `html.EscapeString()` function for safety reasons. You should also only use this debugging technique in a development environment, never in production. - -```Go -package main - -import ( - "fmt" - "html" - "net/http" - - "github.com/davecgh/go-spew/spew" -) - -func handler(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "text/html") - fmt.Fprintf(w, "Hi there, %s!", r.URL.Path[1:]) - fmt.Fprintf(w, "") -} - -func main() { - http.HandleFunc("/", handler) - http.ListenAndServe(":8080", nil) -} -``` - -## Sample Dump Output - -``` -(main.Foo) { - unexportedField: (*main.Bar)(0xf84002e210)({ - flag: (main.Flag) flagTwo, - data: (uintptr) - }), - ExportedField: (map[interface {}]interface {}) { - (string) "one": (bool) true - } -} -([]uint8) { - 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | - 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| - 00000020 31 32 |12| -} -``` - -## Sample Formatter Output - -Double pointer to a uint8: -``` - %v: <**>5 - %+v: <**>(0xf8400420d0->0xf8400420c8)5 - %#v: (**uint8)5 - %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5 -``` - -Pointer to circular struct with a uint8 field and a pointer to itself: -``` - %v: <*>{1 <*>} - %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)} - %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)} - %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)} -``` - -## Configuration Options - -Configuration of spew is handled by fields in the ConfigState type. For -convenience, all of the top-level functions use a global state available via the -spew.Config global. - -It is also possible to create a ConfigState instance that provides methods -equivalent to the top-level functions. This allows concurrent configuration -options. See the ConfigState documentation for more details. - -``` -* Indent - String to use for each indentation level for Dump functions. - It is a single space by default. A popular alternative is "\t". - -* MaxDepth - Maximum number of levels to descend into nested data structures. - There is no limit by default. - -* DisableMethods - Disables invocation of error and Stringer interface methods. - Method invocation is enabled by default. - -* DisablePointerMethods - Disables invocation of error and Stringer interface methods on types - which only accept pointer receivers from non-pointer variables. This option - relies on access to the unsafe package, so it will not have any effect when - running in environments without access to the unsafe package such as Google - App Engine or with the "safe" build tag specified. - Pointer method invocation is enabled by default. - -* DisablePointerAddresses - DisablePointerAddresses specifies whether to disable the printing of - pointer addresses. This is useful when diffing data structures in tests. - -* DisableCapacities - DisableCapacities specifies whether to disable the printing of capacities - for arrays, slices, maps and channels. This is useful when diffing data - structures in tests. - -* ContinueOnMethod - Enables recursion into types after invoking error and Stringer interface - methods. Recursion after method invocation is disabled by default. - -* SortKeys - Specifies map keys should be sorted before being printed. Use - this to have a more deterministic, diffable output. Note that - only native types (bool, int, uint, floats, uintptr and string) - and types which implement error or Stringer interfaces are supported, - with other types sorted according to the reflect.Value.String() output - which guarantees display stability. Natural map order is used by - default. - -* SpewKeys - SpewKeys specifies that, as a last resort attempt, map keys should be - spewed to strings and sorted by those strings. This is only considered - if SortKeys is true. - -``` - -## Unsafe Package Dependency - -This package relies on the unsafe package to perform some of the more advanced -features, however it also supports a "limited" mode which allows it to work in -environments where the unsafe package is not available. By default, it will -operate in this mode on Google App Engine and when compiled with GopherJS. The -"safe" build tag may also be specified to force the package to build without -using the unsafe package. - -## License - -Go-spew is licensed under the [copyfree](http://copyfree.org) ISC License. diff --git a/vendor/github.com/davecgh/go-spew/cov_report.sh b/vendor/github.com/davecgh/go-spew/cov_report.sh deleted file mode 100644 index 9579497e..00000000 --- a/vendor/github.com/davecgh/go-spew/cov_report.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh - -# This script uses gocov to generate a test coverage report. -# The gocov tool my be obtained with the following command: -# go get github.com/axw/gocov/gocov -# -# It will be installed to $GOPATH/bin, so ensure that location is in your $PATH. - -# Check for gocov. -if ! type gocov >/dev/null 2>&1; then - echo >&2 "This script requires the gocov tool." - echo >&2 "You may obtain it with the following command:" - echo >&2 "go get github.com/axw/gocov/gocov" - exit 1 -fi - -# Only run the cgo tests if gcc is installed. -if type gcc >/dev/null 2>&1; then - (cd spew && gocov test -tags testcgo | gocov report) -else - (cd spew && gocov test | gocov report) -fi diff --git a/vendor/github.com/davecgh/go-spew/spew/common_test.go b/vendor/github.com/davecgh/go-spew/spew/common_test.go deleted file mode 100644 index 0f5ce47d..00000000 --- a/vendor/github.com/davecgh/go-spew/spew/common_test.go +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (c) 2013-2016 Dave Collins - * - * Permission to use, copy, modify, and 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. - */ - -package spew_test - -import ( - "fmt" - "reflect" - "testing" - - "github.com/davecgh/go-spew/spew" -) - -// custom type to test Stinger interface on non-pointer receiver. -type stringer string - -// String implements the Stringer interface for testing invocation of custom -// stringers on types with non-pointer receivers. -func (s stringer) String() string { - return "stringer " + string(s) -} - -// custom type to test Stinger interface on pointer receiver. -type pstringer string - -// String implements the Stringer interface for testing invocation of custom -// stringers on types with only pointer receivers. -func (s *pstringer) String() string { - return "stringer " + string(*s) -} - -// xref1 and xref2 are cross referencing structs for testing circular reference -// detection. -type xref1 struct { - ps2 *xref2 -} -type xref2 struct { - ps1 *xref1 -} - -// indirCir1, indirCir2, and indirCir3 are used to generate an indirect circular -// reference for testing detection. -type indirCir1 struct { - ps2 *indirCir2 -} -type indirCir2 struct { - ps3 *indirCir3 -} -type indirCir3 struct { - ps1 *indirCir1 -} - -// embed is used to test embedded structures. -type embed struct { - a string -} - -// embedwrap is used to test embedded structures. -type embedwrap struct { - *embed - e *embed -} - -// panicer is used to intentionally cause a panic for testing spew properly -// handles them -type panicer int - -func (p panicer) String() string { - panic("test panic") -} - -// customError is used to test custom error interface invocation. -type customError int - -func (e customError) Error() string { - return fmt.Sprintf("error: %d", int(e)) -} - -// stringizeWants converts a slice of wanted test output into a format suitable -// for a test error message. -func stringizeWants(wants []string) string { - s := "" - for i, want := range wants { - if i > 0 { - s += fmt.Sprintf("want%d: %s", i+1, want) - } else { - s += "want: " + want - } - } - return s -} - -// testFailed returns whether or not a test failed by checking if the result -// of the test is in the slice of wanted strings. -func testFailed(result string, wants []string) bool { - for _, want := range wants { - if result == want { - return false - } - } - return true -} - -type sortableStruct struct { - x int -} - -func (ss sortableStruct) String() string { - return fmt.Sprintf("ss.%d", ss.x) -} - -type unsortableStruct struct { - x int -} - -type sortTestCase struct { - input []reflect.Value - expected []reflect.Value -} - -func helpTestSortValues(tests []sortTestCase, cs *spew.ConfigState, t *testing.T) { - getInterfaces := func(values []reflect.Value) []interface{} { - interfaces := []interface{}{} - for _, v := range values { - interfaces = append(interfaces, v.Interface()) - } - return interfaces - } - - for _, test := range tests { - spew.SortValues(test.input, cs) - // reflect.DeepEqual cannot really make sense of reflect.Value, - // probably because of all the pointer tricks. For instance, - // v(2.0) != v(2.0) on a 32-bits system. Turn them into interface{} - // instead. - input := getInterfaces(test.input) - expected := getInterfaces(test.expected) - if !reflect.DeepEqual(input, expected) { - t.Errorf("Sort mismatch:\n %v != %v", input, expected) - } - } -} - -// TestSortValues ensures the sort functionality for relect.Value based sorting -// works as intended. -func TestSortValues(t *testing.T) { - v := reflect.ValueOf - - a := v("a") - b := v("b") - c := v("c") - embedA := v(embed{"a"}) - embedB := v(embed{"b"}) - embedC := v(embed{"c"}) - tests := []sortTestCase{ - // No values. - { - []reflect.Value{}, - []reflect.Value{}, - }, - // Bools. - { - []reflect.Value{v(false), v(true), v(false)}, - []reflect.Value{v(false), v(false), v(true)}, - }, - // Ints. - { - []reflect.Value{v(2), v(1), v(3)}, - []reflect.Value{v(1), v(2), v(3)}, - }, - // Uints. - { - []reflect.Value{v(uint8(2)), v(uint8(1)), v(uint8(3))}, - []reflect.Value{v(uint8(1)), v(uint8(2)), v(uint8(3))}, - }, - // Floats. - { - []reflect.Value{v(2.0), v(1.0), v(3.0)}, - []reflect.Value{v(1.0), v(2.0), v(3.0)}, - }, - // Strings. - { - []reflect.Value{b, a, c}, - []reflect.Value{a, b, c}, - }, - // Array - { - []reflect.Value{v([3]int{3, 2, 1}), v([3]int{1, 3, 2}), v([3]int{1, 2, 3})}, - []reflect.Value{v([3]int{1, 2, 3}), v([3]int{1, 3, 2}), v([3]int{3, 2, 1})}, - }, - // Uintptrs. - { - []reflect.Value{v(uintptr(2)), v(uintptr(1)), v(uintptr(3))}, - []reflect.Value{v(uintptr(1)), v(uintptr(2)), v(uintptr(3))}, - }, - // SortableStructs. - { - // Note: not sorted - DisableMethods is set. - []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, - []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, - }, - // UnsortableStructs. - { - // Note: not sorted - SpewKeys is false. - []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, - []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, - }, - // Invalid. - { - []reflect.Value{embedB, embedA, embedC}, - []reflect.Value{embedB, embedA, embedC}, - }, - } - cs := spew.ConfigState{DisableMethods: true, SpewKeys: false} - helpTestSortValues(tests, &cs, t) -} - -// TestSortValuesWithMethods ensures the sort functionality for relect.Value -// based sorting works as intended when using string methods. -func TestSortValuesWithMethods(t *testing.T) { - v := reflect.ValueOf - - a := v("a") - b := v("b") - c := v("c") - tests := []sortTestCase{ - // Ints. - { - []reflect.Value{v(2), v(1), v(3)}, - []reflect.Value{v(1), v(2), v(3)}, - }, - // Strings. - { - []reflect.Value{b, a, c}, - []reflect.Value{a, b, c}, - }, - // SortableStructs. - { - []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, - []reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})}, - }, - // UnsortableStructs. - { - // Note: not sorted - SpewKeys is false. - []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, - []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, - }, - } - cs := spew.ConfigState{DisableMethods: false, SpewKeys: false} - helpTestSortValues(tests, &cs, t) -} - -// TestSortValuesWithSpew ensures the sort functionality for relect.Value -// based sorting works as intended when using spew to stringify keys. -func TestSortValuesWithSpew(t *testing.T) { - v := reflect.ValueOf - - a := v("a") - b := v("b") - c := v("c") - tests := []sortTestCase{ - // Ints. - { - []reflect.Value{v(2), v(1), v(3)}, - []reflect.Value{v(1), v(2), v(3)}, - }, - // Strings. - { - []reflect.Value{b, a, c}, - []reflect.Value{a, b, c}, - }, - // SortableStructs. - { - []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, - []reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})}, - }, - // UnsortableStructs. - { - []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, - []reflect.Value{v(unsortableStruct{1}), v(unsortableStruct{2}), v(unsortableStruct{3})}, - }, - } - cs := spew.ConfigState{DisableMethods: true, SpewKeys: true} - helpTestSortValues(tests, &cs, t) -} diff --git a/vendor/github.com/davecgh/go-spew/spew/dump_test.go b/vendor/github.com/davecgh/go-spew/spew/dump_test.go deleted file mode 100644 index 5aad9c7a..00000000 --- a/vendor/github.com/davecgh/go-spew/spew/dump_test.go +++ /dev/null @@ -1,1042 +0,0 @@ -/* - * Copyright (c) 2013-2016 Dave Collins - * - * Permission to use, copy, modify, and 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. - */ - -/* -Test Summary: -NOTE: For each test, a nil pointer, a single pointer and double pointer to the -base test element are also tested to ensure proper indirection across all types. - -- Max int8, int16, int32, int64, int -- Max uint8, uint16, uint32, uint64, uint -- Boolean true and false -- Standard complex64 and complex128 -- Array containing standard ints -- Array containing type with custom formatter on pointer receiver only -- Array containing interfaces -- Array containing bytes -- Slice containing standard float32 values -- Slice containing type with custom formatter on pointer receiver only -- Slice containing interfaces -- Slice containing bytes -- Nil slice -- Standard string -- Nil interface -- Sub-interface -- Map with string keys and int vals -- Map with custom formatter type on pointer receiver only keys and vals -- Map with interface keys and values -- Map with nil interface value -- Struct with primitives -- Struct that contains another struct -- Struct that contains custom type with Stringer pointer interface via both - exported and unexported fields -- Struct that contains embedded struct and field to same struct -- Uintptr to 0 (null pointer) -- Uintptr address of real variable -- Unsafe.Pointer to 0 (null pointer) -- Unsafe.Pointer to address of real variable -- Nil channel -- Standard int channel -- Function with no params and no returns -- Function with param and no returns -- Function with multiple params and multiple returns -- Struct that is circular through self referencing -- Structs that are circular through cross referencing -- Structs that are indirectly circular -- Type that panics in its Stringer interface -*/ - -package spew_test - -import ( - "bytes" - "fmt" - "testing" - "unsafe" - - "github.com/davecgh/go-spew/spew" -) - -// dumpTest is used to describe a test to be performed against the Dump method. -type dumpTest struct { - in interface{} - wants []string -} - -// dumpTests houses all of the tests to be performed against the Dump method. -var dumpTests = make([]dumpTest, 0) - -// addDumpTest is a helper method to append the passed input and desired result -// to dumpTests -func addDumpTest(in interface{}, wants ...string) { - test := dumpTest{in, wants} - dumpTests = append(dumpTests, test) -} - -func addIntDumpTests() { - // Max int8. - v := int8(127) - nv := (*int8)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "int8" - vs := "127" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") - - // Max int16. - v2 := int16(32767) - nv2 := (*int16)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "int16" - v2s := "32767" - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") - addDumpTest(nv2, "(*"+v2t+")()\n") - - // Max int32. - v3 := int32(2147483647) - nv3 := (*int32)(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "int32" - v3s := "2147483647" - addDumpTest(v3, "("+v3t+") "+v3s+"\n") - addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") - addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") - addDumpTest(nv3, "(*"+v3t+")()\n") - - // Max int64. - v4 := int64(9223372036854775807) - nv4 := (*int64)(nil) - pv4 := &v4 - v4Addr := fmt.Sprintf("%p", pv4) - pv4Addr := fmt.Sprintf("%p", &pv4) - v4t := "int64" - v4s := "9223372036854775807" - addDumpTest(v4, "("+v4t+") "+v4s+"\n") - addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") - addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") - addDumpTest(nv4, "(*"+v4t+")()\n") - - // Max int. - v5 := int(2147483647) - nv5 := (*int)(nil) - pv5 := &v5 - v5Addr := fmt.Sprintf("%p", pv5) - pv5Addr := fmt.Sprintf("%p", &pv5) - v5t := "int" - v5s := "2147483647" - addDumpTest(v5, "("+v5t+") "+v5s+"\n") - addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n") - addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n") - addDumpTest(nv5, "(*"+v5t+")()\n") -} - -func addUintDumpTests() { - // Max uint8. - v := uint8(255) - nv := (*uint8)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "uint8" - vs := "255" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") - - // Max uint16. - v2 := uint16(65535) - nv2 := (*uint16)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "uint16" - v2s := "65535" - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") - addDumpTest(nv2, "(*"+v2t+")()\n") - - // Max uint32. - v3 := uint32(4294967295) - nv3 := (*uint32)(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "uint32" - v3s := "4294967295" - addDumpTest(v3, "("+v3t+") "+v3s+"\n") - addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") - addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") - addDumpTest(nv3, "(*"+v3t+")()\n") - - // Max uint64. - v4 := uint64(18446744073709551615) - nv4 := (*uint64)(nil) - pv4 := &v4 - v4Addr := fmt.Sprintf("%p", pv4) - pv4Addr := fmt.Sprintf("%p", &pv4) - v4t := "uint64" - v4s := "18446744073709551615" - addDumpTest(v4, "("+v4t+") "+v4s+"\n") - addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") - addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") - addDumpTest(nv4, "(*"+v4t+")()\n") - - // Max uint. - v5 := uint(4294967295) - nv5 := (*uint)(nil) - pv5 := &v5 - v5Addr := fmt.Sprintf("%p", pv5) - pv5Addr := fmt.Sprintf("%p", &pv5) - v5t := "uint" - v5s := "4294967295" - addDumpTest(v5, "("+v5t+") "+v5s+"\n") - addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n") - addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n") - addDumpTest(nv5, "(*"+v5t+")()\n") -} - -func addBoolDumpTests() { - // Boolean true. - v := bool(true) - nv := (*bool)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "bool" - vs := "true" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") - - // Boolean false. - v2 := bool(false) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "bool" - v2s := "false" - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") -} - -func addFloatDumpTests() { - // Standard float32. - v := float32(3.1415) - nv := (*float32)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "float32" - vs := "3.1415" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") - - // Standard float64. - v2 := float64(3.1415926) - nv2 := (*float64)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "float64" - v2s := "3.1415926" - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") - addDumpTest(nv2, "(*"+v2t+")()\n") -} - -func addComplexDumpTests() { - // Standard complex64. - v := complex(float32(6), -2) - nv := (*complex64)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "complex64" - vs := "(6-2i)" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") - - // Standard complex128. - v2 := complex(float64(-6), 2) - nv2 := (*complex128)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "complex128" - v2s := "(-6+2i)" - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") - addDumpTest(nv2, "(*"+v2t+")()\n") -} - -func addArrayDumpTests() { - // Array containing standard ints. - v := [3]int{1, 2, 3} - vLen := fmt.Sprintf("%d", len(v)) - vCap := fmt.Sprintf("%d", cap(v)) - nv := (*[3]int)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "int" - vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 1,\n (" + - vt + ") 2,\n (" + vt + ") 3\n}" - addDumpTest(v, "([3]"+vt+") "+vs+"\n") - addDumpTest(pv, "(*[3]"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**[3]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*[3]"+vt+")()\n") - - // Array containing type with custom formatter on pointer receiver only. - v2i0 := pstringer("1") - v2i1 := pstringer("2") - v2i2 := pstringer("3") - v2 := [3]pstringer{v2i0, v2i1, v2i2} - v2i0Len := fmt.Sprintf("%d", len(v2i0)) - v2i1Len := fmt.Sprintf("%d", len(v2i1)) - v2i2Len := fmt.Sprintf("%d", len(v2i2)) - v2Len := fmt.Sprintf("%d", len(v2)) - v2Cap := fmt.Sprintf("%d", cap(v2)) - nv2 := (*[3]pstringer)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "spew_test.pstringer" - v2sp := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + - ") (len=" + v2i0Len + ") stringer 1,\n (" + v2t + - ") (len=" + v2i1Len + ") stringer 2,\n (" + v2t + - ") (len=" + v2i2Len + ") " + "stringer 3\n}" - v2s := v2sp - if spew.UnsafeDisabled { - v2s = "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + - ") (len=" + v2i0Len + ") \"1\",\n (" + v2t + ") (len=" + - v2i1Len + ") \"2\",\n (" + v2t + ") (len=" + v2i2Len + - ") " + "\"3\"\n}" - } - addDumpTest(v2, "([3]"+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*[3]"+v2t+")("+v2Addr+")("+v2sp+")\n") - addDumpTest(&pv2, "(**[3]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2sp+")\n") - addDumpTest(nv2, "(*[3]"+v2t+")()\n") - - // Array containing interfaces. - v3i0 := "one" - v3 := [3]interface{}{v3i0, int(2), uint(3)} - v3i0Len := fmt.Sprintf("%d", len(v3i0)) - v3Len := fmt.Sprintf("%d", len(v3)) - v3Cap := fmt.Sprintf("%d", cap(v3)) - nv3 := (*[3]interface{})(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "[3]interface {}" - v3t2 := "string" - v3t3 := "int" - v3t4 := "uint" - v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " + - "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" + - v3t4 + ") 3\n}" - addDumpTest(v3, "("+v3t+") "+v3s+"\n") - addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") - addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") - addDumpTest(nv3, "(*"+v3t+")()\n") - - // Array containing bytes. - v4 := [34]byte{ - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, - 0x31, 0x32, - } - v4Len := fmt.Sprintf("%d", len(v4)) - v4Cap := fmt.Sprintf("%d", cap(v4)) - nv4 := (*[34]byte)(nil) - pv4 := &v4 - v4Addr := fmt.Sprintf("%p", pv4) - pv4Addr := fmt.Sprintf("%p", &pv4) - v4t := "[34]uint8" - v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " + - "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" + - " |............... |\n" + - " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" + - " |!\"#$%&'()*+,-./0|\n" + - " 00000020 31 32 " + - " |12|\n}" - addDumpTest(v4, "("+v4t+") "+v4s+"\n") - addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") - addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") - addDumpTest(nv4, "(*"+v4t+")()\n") -} - -func addSliceDumpTests() { - // Slice containing standard float32 values. - v := []float32{3.14, 6.28, 12.56} - vLen := fmt.Sprintf("%d", len(v)) - vCap := fmt.Sprintf("%d", cap(v)) - nv := (*[]float32)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "float32" - vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 3.14,\n (" + - vt + ") 6.28,\n (" + vt + ") 12.56\n}" - addDumpTest(v, "([]"+vt+") "+vs+"\n") - addDumpTest(pv, "(*[]"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**[]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*[]"+vt+")()\n") - - // Slice containing type with custom formatter on pointer receiver only. - v2i0 := pstringer("1") - v2i1 := pstringer("2") - v2i2 := pstringer("3") - v2 := []pstringer{v2i0, v2i1, v2i2} - v2i0Len := fmt.Sprintf("%d", len(v2i0)) - v2i1Len := fmt.Sprintf("%d", len(v2i1)) - v2i2Len := fmt.Sprintf("%d", len(v2i2)) - v2Len := fmt.Sprintf("%d", len(v2)) - v2Cap := fmt.Sprintf("%d", cap(v2)) - nv2 := (*[]pstringer)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "spew_test.pstringer" - v2s := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" + - v2i0Len + ") stringer 1,\n (" + v2t + ") (len=" + v2i1Len + - ") stringer 2,\n (" + v2t + ") (len=" + v2i2Len + ") " + - "stringer 3\n}" - addDumpTest(v2, "([]"+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*[]"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**[]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") - addDumpTest(nv2, "(*[]"+v2t+")()\n") - - // Slice containing interfaces. - v3i0 := "one" - v3 := []interface{}{v3i0, int(2), uint(3), nil} - v3i0Len := fmt.Sprintf("%d", len(v3i0)) - v3Len := fmt.Sprintf("%d", len(v3)) - v3Cap := fmt.Sprintf("%d", cap(v3)) - nv3 := (*[]interface{})(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "[]interface {}" - v3t2 := "string" - v3t3 := "int" - v3t4 := "uint" - v3t5 := "interface {}" - v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " + - "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" + - v3t4 + ") 3,\n (" + v3t5 + ") \n}" - addDumpTest(v3, "("+v3t+") "+v3s+"\n") - addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") - addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") - addDumpTest(nv3, "(*"+v3t+")()\n") - - // Slice containing bytes. - v4 := []byte{ - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, - 0x31, 0x32, - } - v4Len := fmt.Sprintf("%d", len(v4)) - v4Cap := fmt.Sprintf("%d", cap(v4)) - nv4 := (*[]byte)(nil) - pv4 := &v4 - v4Addr := fmt.Sprintf("%p", pv4) - pv4Addr := fmt.Sprintf("%p", &pv4) - v4t := "[]uint8" - v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " + - "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" + - " |............... |\n" + - " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" + - " |!\"#$%&'()*+,-./0|\n" + - " 00000020 31 32 " + - " |12|\n}" - addDumpTest(v4, "("+v4t+") "+v4s+"\n") - addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") - addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") - addDumpTest(nv4, "(*"+v4t+")()\n") - - // Nil slice. - v5 := []int(nil) - nv5 := (*[]int)(nil) - pv5 := &v5 - v5Addr := fmt.Sprintf("%p", pv5) - pv5Addr := fmt.Sprintf("%p", &pv5) - v5t := "[]int" - v5s := "" - addDumpTest(v5, "("+v5t+") "+v5s+"\n") - addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n") - addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n") - addDumpTest(nv5, "(*"+v5t+")()\n") -} - -func addStringDumpTests() { - // Standard string. - v := "test" - vLen := fmt.Sprintf("%d", len(v)) - nv := (*string)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "string" - vs := "(len=" + vLen + ") \"test\"" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") -} - -func addInterfaceDumpTests() { - // Nil interface. - var v interface{} - nv := (*interface{})(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "interface {}" - vs := "" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") - - // Sub-interface. - v2 := interface{}(uint16(65535)) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "uint16" - v2s := "65535" - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") -} - -func addMapDumpTests() { - // Map with string keys and int vals. - k := "one" - kk := "two" - m := map[string]int{k: 1, kk: 2} - klen := fmt.Sprintf("%d", len(k)) // not kLen to shut golint up - kkLen := fmt.Sprintf("%d", len(kk)) - mLen := fmt.Sprintf("%d", len(m)) - nilMap := map[string]int(nil) - nm := (*map[string]int)(nil) - pm := &m - mAddr := fmt.Sprintf("%p", pm) - pmAddr := fmt.Sprintf("%p", &pm) - mt := "map[string]int" - mt1 := "string" - mt2 := "int" - ms := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + klen + ") " + - "\"one\": (" + mt2 + ") 1,\n (" + mt1 + ") (len=" + kkLen + - ") \"two\": (" + mt2 + ") 2\n}" - ms2 := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + kkLen + ") " + - "\"two\": (" + mt2 + ") 2,\n (" + mt1 + ") (len=" + klen + - ") \"one\": (" + mt2 + ") 1\n}" - addDumpTest(m, "("+mt+") "+ms+"\n", "("+mt+") "+ms2+"\n") - addDumpTest(pm, "(*"+mt+")("+mAddr+")("+ms+")\n", - "(*"+mt+")("+mAddr+")("+ms2+")\n") - addDumpTest(&pm, "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms+")\n", - "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms2+")\n") - addDumpTest(nm, "(*"+mt+")()\n") - addDumpTest(nilMap, "("+mt+") \n") - - // Map with custom formatter type on pointer receiver only keys and vals. - k2 := pstringer("one") - v2 := pstringer("1") - m2 := map[pstringer]pstringer{k2: v2} - k2Len := fmt.Sprintf("%d", len(k2)) - v2Len := fmt.Sprintf("%d", len(v2)) - m2Len := fmt.Sprintf("%d", len(m2)) - nilMap2 := map[pstringer]pstringer(nil) - nm2 := (*map[pstringer]pstringer)(nil) - pm2 := &m2 - m2Addr := fmt.Sprintf("%p", pm2) - pm2Addr := fmt.Sprintf("%p", &pm2) - m2t := "map[spew_test.pstringer]spew_test.pstringer" - m2t1 := "spew_test.pstringer" - m2t2 := "spew_test.pstringer" - m2s := "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len + ") " + - "stringer one: (" + m2t2 + ") (len=" + v2Len + ") stringer 1\n}" - if spew.UnsafeDisabled { - m2s = "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len + - ") " + "\"one\": (" + m2t2 + ") (len=" + v2Len + - ") \"1\"\n}" - } - addDumpTest(m2, "("+m2t+") "+m2s+"\n") - addDumpTest(pm2, "(*"+m2t+")("+m2Addr+")("+m2s+")\n") - addDumpTest(&pm2, "(**"+m2t+")("+pm2Addr+"->"+m2Addr+")("+m2s+")\n") - addDumpTest(nm2, "(*"+m2t+")()\n") - addDumpTest(nilMap2, "("+m2t+") \n") - - // Map with interface keys and values. - k3 := "one" - k3Len := fmt.Sprintf("%d", len(k3)) - m3 := map[interface{}]interface{}{k3: 1} - m3Len := fmt.Sprintf("%d", len(m3)) - nilMap3 := map[interface{}]interface{}(nil) - nm3 := (*map[interface{}]interface{})(nil) - pm3 := &m3 - m3Addr := fmt.Sprintf("%p", pm3) - pm3Addr := fmt.Sprintf("%p", &pm3) - m3t := "map[interface {}]interface {}" - m3t1 := "string" - m3t2 := "int" - m3s := "(len=" + m3Len + ") {\n (" + m3t1 + ") (len=" + k3Len + ") " + - "\"one\": (" + m3t2 + ") 1\n}" - addDumpTest(m3, "("+m3t+") "+m3s+"\n") - addDumpTest(pm3, "(*"+m3t+")("+m3Addr+")("+m3s+")\n") - addDumpTest(&pm3, "(**"+m3t+")("+pm3Addr+"->"+m3Addr+")("+m3s+")\n") - addDumpTest(nm3, "(*"+m3t+")()\n") - addDumpTest(nilMap3, "("+m3t+") \n") - - // Map with nil interface value. - k4 := "nil" - k4Len := fmt.Sprintf("%d", len(k4)) - m4 := map[string]interface{}{k4: nil} - m4Len := fmt.Sprintf("%d", len(m4)) - nilMap4 := map[string]interface{}(nil) - nm4 := (*map[string]interface{})(nil) - pm4 := &m4 - m4Addr := fmt.Sprintf("%p", pm4) - pm4Addr := fmt.Sprintf("%p", &pm4) - m4t := "map[string]interface {}" - m4t1 := "string" - m4t2 := "interface {}" - m4s := "(len=" + m4Len + ") {\n (" + m4t1 + ") (len=" + k4Len + ")" + - " \"nil\": (" + m4t2 + ") \n}" - addDumpTest(m4, "("+m4t+") "+m4s+"\n") - addDumpTest(pm4, "(*"+m4t+")("+m4Addr+")("+m4s+")\n") - addDumpTest(&pm4, "(**"+m4t+")("+pm4Addr+"->"+m4Addr+")("+m4s+")\n") - addDumpTest(nm4, "(*"+m4t+")()\n") - addDumpTest(nilMap4, "("+m4t+") \n") -} - -func addStructDumpTests() { - // Struct with primitives. - type s1 struct { - a int8 - b uint8 - } - v := s1{127, 255} - nv := (*s1)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "spew_test.s1" - vt2 := "int8" - vt3 := "uint8" - vs := "{\n a: (" + vt2 + ") 127,\n b: (" + vt3 + ") 255\n}" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") - - // Struct that contains another struct. - type s2 struct { - s1 s1 - b bool - } - v2 := s2{s1{127, 255}, true} - nv2 := (*s2)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "spew_test.s2" - v2t2 := "spew_test.s1" - v2t3 := "int8" - v2t4 := "uint8" - v2t5 := "bool" - v2s := "{\n s1: (" + v2t2 + ") {\n a: (" + v2t3 + ") 127,\n b: (" + - v2t4 + ") 255\n },\n b: (" + v2t5 + ") true\n}" - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") - addDumpTest(nv2, "(*"+v2t+")()\n") - - // Struct that contains custom type with Stringer pointer interface via both - // exported and unexported fields. - type s3 struct { - s pstringer - S pstringer - } - v3 := s3{"test", "test2"} - nv3 := (*s3)(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "spew_test.s3" - v3t2 := "spew_test.pstringer" - v3s := "{\n s: (" + v3t2 + ") (len=4) stringer test,\n S: (" + v3t2 + - ") (len=5) stringer test2\n}" - v3sp := v3s - if spew.UnsafeDisabled { - v3s = "{\n s: (" + v3t2 + ") (len=4) \"test\",\n S: (" + - v3t2 + ") (len=5) \"test2\"\n}" - v3sp = "{\n s: (" + v3t2 + ") (len=4) \"test\",\n S: (" + - v3t2 + ") (len=5) stringer test2\n}" - } - addDumpTest(v3, "("+v3t+") "+v3s+"\n") - addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3sp+")\n") - addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3sp+")\n") - addDumpTest(nv3, "(*"+v3t+")()\n") - - // Struct that contains embedded struct and field to same struct. - e := embed{"embedstr"} - eLen := fmt.Sprintf("%d", len("embedstr")) - v4 := embedwrap{embed: &e, e: &e} - nv4 := (*embedwrap)(nil) - pv4 := &v4 - eAddr := fmt.Sprintf("%p", &e) - v4Addr := fmt.Sprintf("%p", pv4) - pv4Addr := fmt.Sprintf("%p", &pv4) - v4t := "spew_test.embedwrap" - v4t2 := "spew_test.embed" - v4t3 := "string" - v4s := "{\n embed: (*" + v4t2 + ")(" + eAddr + ")({\n a: (" + v4t3 + - ") (len=" + eLen + ") \"embedstr\"\n }),\n e: (*" + v4t2 + - ")(" + eAddr + ")({\n a: (" + v4t3 + ") (len=" + eLen + ")" + - " \"embedstr\"\n })\n}" - addDumpTest(v4, "("+v4t+") "+v4s+"\n") - addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") - addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") - addDumpTest(nv4, "(*"+v4t+")()\n") -} - -func addUintptrDumpTests() { - // Null pointer. - v := uintptr(0) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "uintptr" - vs := "" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - - // Address of real variable. - i := 1 - v2 := uintptr(unsafe.Pointer(&i)) - nv2 := (*uintptr)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "uintptr" - v2s := fmt.Sprintf("%p", &i) - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") - addDumpTest(nv2, "(*"+v2t+")()\n") -} - -func addUnsafePointerDumpTests() { - // Null pointer. - v := unsafe.Pointer(uintptr(0)) - nv := (*unsafe.Pointer)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "unsafe.Pointer" - vs := "" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") - - // Address of real variable. - i := 1 - v2 := unsafe.Pointer(&i) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "unsafe.Pointer" - v2s := fmt.Sprintf("%p", &i) - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") - addDumpTest(nv, "(*"+vt+")()\n") -} - -func addChanDumpTests() { - // Nil channel. - var v chan int - pv := &v - nv := (*chan int)(nil) - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "chan int" - vs := "" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") - - // Real channel. - v2 := make(chan int) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "chan int" - v2s := fmt.Sprintf("%p", v2) - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") -} - -func addFuncDumpTests() { - // Function with no params and no returns. - v := addIntDumpTests - nv := (*func())(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "func()" - vs := fmt.Sprintf("%p", v) - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") - - // Function with param and no returns. - v2 := TestDump - nv2 := (*func(*testing.T))(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "func(*testing.T)" - v2s := fmt.Sprintf("%p", v2) - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") - addDumpTest(nv2, "(*"+v2t+")()\n") - - // Function with multiple params and multiple returns. - var v3 = func(i int, s string) (b bool, err error) { - return true, nil - } - nv3 := (*func(int, string) (bool, error))(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "func(int, string) (bool, error)" - v3s := fmt.Sprintf("%p", v3) - addDumpTest(v3, "("+v3t+") "+v3s+"\n") - addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") - addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") - addDumpTest(nv3, "(*"+v3t+")()\n") -} - -func addCircularDumpTests() { - // Struct that is circular through self referencing. - type circular struct { - c *circular - } - v := circular{nil} - v.c = &v - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "spew_test.circular" - vs := "{\n c: (*" + vt + ")(" + vAddr + ")({\n c: (*" + vt + ")(" + - vAddr + ")()\n })\n}" - vs2 := "{\n c: (*" + vt + ")(" + vAddr + ")()\n}" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs2+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs2+")\n") - - // Structs that are circular through cross referencing. - v2 := xref1{nil} - ts2 := xref2{&v2} - v2.ps2 = &ts2 - pv2 := &v2 - ts2Addr := fmt.Sprintf("%p", &ts2) - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "spew_test.xref1" - v2t2 := "spew_test.xref2" - v2s := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t + - ")(" + v2Addr + ")({\n ps2: (*" + v2t2 + ")(" + ts2Addr + - ")()\n })\n })\n}" - v2s2 := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t + - ")(" + v2Addr + ")()\n })\n}" - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s2+")\n") - addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s2+")\n") - - // Structs that are indirectly circular. - v3 := indirCir1{nil} - tic2 := indirCir2{nil} - tic3 := indirCir3{&v3} - tic2.ps3 = &tic3 - v3.ps2 = &tic2 - pv3 := &v3 - tic2Addr := fmt.Sprintf("%p", &tic2) - tic3Addr := fmt.Sprintf("%p", &tic3) - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "spew_test.indirCir1" - v3t2 := "spew_test.indirCir2" - v3t3 := "spew_test.indirCir3" - v3s := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 + - ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr + - ")({\n ps2: (*" + v3t2 + ")(" + tic2Addr + - ")()\n })\n })\n })\n}" - v3s2 := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 + - ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr + - ")()\n })\n })\n}" - addDumpTest(v3, "("+v3t+") "+v3s+"\n") - addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s2+")\n") - addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s2+")\n") -} - -func addPanicDumpTests() { - // Type that panics in its Stringer interface. - v := panicer(127) - nv := (*panicer)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "spew_test.panicer" - vs := "(PANIC=test panic)127" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") -} - -func addErrorDumpTests() { - // Type that has a custom Error interface. - v := customError(127) - nv := (*customError)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "spew_test.customError" - vs := "error: 127" - addDumpTest(v, "("+vt+") "+vs+"\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") - addDumpTest(nv, "(*"+vt+")()\n") -} - -// TestDump executes all of the tests described by dumpTests. -func TestDump(t *testing.T) { - // Setup tests. - addIntDumpTests() - addUintDumpTests() - addBoolDumpTests() - addFloatDumpTests() - addComplexDumpTests() - addArrayDumpTests() - addSliceDumpTests() - addStringDumpTests() - addInterfaceDumpTests() - addMapDumpTests() - addStructDumpTests() - addUintptrDumpTests() - addUnsafePointerDumpTests() - addChanDumpTests() - addFuncDumpTests() - addCircularDumpTests() - addPanicDumpTests() - addErrorDumpTests() - addCgoDumpTests() - - t.Logf("Running %d tests", len(dumpTests)) - for i, test := range dumpTests { - buf := new(bytes.Buffer) - spew.Fdump(buf, test.in) - s := buf.String() - if testFailed(s, test.wants) { - t.Errorf("Dump #%d\n got: %s %s", i, s, stringizeWants(test.wants)) - continue - } - } -} - -func TestDumpSortedKeys(t *testing.T) { - cfg := spew.ConfigState{SortKeys: true} - s := cfg.Sdump(map[int]string{1: "1", 3: "3", 2: "2"}) - expected := "(map[int]string) (len=3) {\n(int) 1: (string) (len=1) " + - "\"1\",\n(int) 2: (string) (len=1) \"2\",\n(int) 3: (string) " + - "(len=1) \"3\"\n" + - "}\n" - if s != expected { - t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) - } - - s = cfg.Sdump(map[stringer]int{"1": 1, "3": 3, "2": 2}) - expected = "(map[spew_test.stringer]int) (len=3) {\n" + - "(spew_test.stringer) (len=1) stringer 1: (int) 1,\n" + - "(spew_test.stringer) (len=1) stringer 2: (int) 2,\n" + - "(spew_test.stringer) (len=1) stringer 3: (int) 3\n" + - "}\n" - if s != expected { - t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) - } - - s = cfg.Sdump(map[pstringer]int{pstringer("1"): 1, pstringer("3"): 3, pstringer("2"): 2}) - expected = "(map[spew_test.pstringer]int) (len=3) {\n" + - "(spew_test.pstringer) (len=1) stringer 1: (int) 1,\n" + - "(spew_test.pstringer) (len=1) stringer 2: (int) 2,\n" + - "(spew_test.pstringer) (len=1) stringer 3: (int) 3\n" + - "}\n" - if spew.UnsafeDisabled { - expected = "(map[spew_test.pstringer]int) (len=3) {\n" + - "(spew_test.pstringer) (len=1) \"1\": (int) 1,\n" + - "(spew_test.pstringer) (len=1) \"2\": (int) 2,\n" + - "(spew_test.pstringer) (len=1) \"3\": (int) 3\n" + - "}\n" - } - if s != expected { - t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) - } - - s = cfg.Sdump(map[customError]int{customError(1): 1, customError(3): 3, customError(2): 2}) - expected = "(map[spew_test.customError]int) (len=3) {\n" + - "(spew_test.customError) error: 1: (int) 1,\n" + - "(spew_test.customError) error: 2: (int) 2,\n" + - "(spew_test.customError) error: 3: (int) 3\n" + - "}\n" - if s != expected { - t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) - } - -} diff --git a/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go b/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go deleted file mode 100644 index 6ab18080..00000000 --- a/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) 2013-2016 Dave Collins -// -// Permission to use, copy, modify, and 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. - -// NOTE: Due to the following build constraints, this file will only be compiled -// when both cgo is supported and "-tags testcgo" is added to the go test -// command line. This means the cgo tests are only added (and hence run) when -// specifially requested. This configuration is used because spew itself -// does not require cgo to run even though it does handle certain cgo types -// specially. Rather than forcing all clients to require cgo and an external -// C compiler just to run the tests, this scheme makes them optional. -// +build cgo,testcgo - -package spew_test - -import ( - "fmt" - - "github.com/davecgh/go-spew/spew/testdata" -) - -func addCgoDumpTests() { - // C char pointer. - v := testdata.GetCgoCharPointer() - nv := testdata.GetCgoNullCharPointer() - pv := &v - vcAddr := fmt.Sprintf("%p", v) - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "*testdata._Ctype_char" - vs := "116" - addDumpTest(v, "("+vt+")("+vcAddr+")("+vs+")\n") - addDumpTest(pv, "(*"+vt+")("+vAddr+"->"+vcAddr+")("+vs+")\n") - addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+"->"+vcAddr+")("+vs+")\n") - addDumpTest(nv, "("+vt+")()\n") - - // C char array. - v2, v2l, v2c := testdata.GetCgoCharArray() - v2Len := fmt.Sprintf("%d", v2l) - v2Cap := fmt.Sprintf("%d", v2c) - v2t := "[6]testdata._Ctype_char" - v2s := "(len=" + v2Len + " cap=" + v2Cap + ") " + - "{\n 00000000 74 65 73 74 32 00 " + - " |test2.|\n}" - addDumpTest(v2, "("+v2t+") "+v2s+"\n") - - // C unsigned char array. - v3, v3l, v3c := testdata.GetCgoUnsignedCharArray() - v3Len := fmt.Sprintf("%d", v3l) - v3Cap := fmt.Sprintf("%d", v3c) - v3t := "[6]testdata._Ctype_unsignedchar" - v3t2 := "[6]testdata._Ctype_uchar" - v3s := "(len=" + v3Len + " cap=" + v3Cap + ") " + - "{\n 00000000 74 65 73 74 33 00 " + - " |test3.|\n}" - addDumpTest(v3, "("+v3t+") "+v3s+"\n", "("+v3t2+") "+v3s+"\n") - - // C signed char array. - v4, v4l, v4c := testdata.GetCgoSignedCharArray() - v4Len := fmt.Sprintf("%d", v4l) - v4Cap := fmt.Sprintf("%d", v4c) - v4t := "[6]testdata._Ctype_schar" - v4t2 := "testdata._Ctype_schar" - v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " + - "{\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 101,\n (" + v4t2 + - ") 115,\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 52,\n (" + v4t2 + - ") 0\n}" - addDumpTest(v4, "("+v4t+") "+v4s+"\n") - - // C uint8_t array. - v5, v5l, v5c := testdata.GetCgoUint8tArray() - v5Len := fmt.Sprintf("%d", v5l) - v5Cap := fmt.Sprintf("%d", v5c) - v5t := "[6]testdata._Ctype_uint8_t" - v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " + - "{\n 00000000 74 65 73 74 35 00 " + - " |test5.|\n}" - addDumpTest(v5, "("+v5t+") "+v5s+"\n") - - // C typedefed unsigned char array. - v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray() - v6Len := fmt.Sprintf("%d", v6l) - v6Cap := fmt.Sprintf("%d", v6c) - v6t := "[6]testdata._Ctype_custom_uchar_t" - v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " + - "{\n 00000000 74 65 73 74 36 00 " + - " |test6.|\n}" - addDumpTest(v6, "("+v6t+") "+v6s+"\n") -} diff --git a/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go b/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go deleted file mode 100644 index 52a0971f..00000000 --- a/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2013 Dave Collins -// -// Permission to use, copy, modify, and 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. - -// NOTE: Due to the following build constraints, this file will only be compiled -// when either cgo is not supported or "-tags testcgo" is not added to the go -// test command line. This file intentionally does not setup any cgo tests in -// this scenario. -// +build !cgo !testcgo - -package spew_test - -func addCgoDumpTests() { - // Don't add any tests for cgo since this file is only compiled when - // there should not be any cgo tests. -} diff --git a/vendor/github.com/davecgh/go-spew/spew/example_test.go b/vendor/github.com/davecgh/go-spew/spew/example_test.go deleted file mode 100644 index c6ec8c6d..00000000 --- a/vendor/github.com/davecgh/go-spew/spew/example_test.go +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (c) 2013-2016 Dave Collins - * - * Permission to use, copy, modify, and 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. - */ - -package spew_test - -import ( - "fmt" - - "github.com/davecgh/go-spew/spew" -) - -type Flag int - -const ( - flagOne Flag = iota - flagTwo -) - -var flagStrings = map[Flag]string{ - flagOne: "flagOne", - flagTwo: "flagTwo", -} - -func (f Flag) String() string { - if s, ok := flagStrings[f]; ok { - return s - } - return fmt.Sprintf("Unknown flag (%d)", int(f)) -} - -type Bar struct { - data uintptr -} - -type Foo struct { - unexportedField Bar - ExportedField map[interface{}]interface{} -} - -// This example demonstrates how to use Dump to dump variables to stdout. -func ExampleDump() { - // The following package level declarations are assumed for this example: - /* - type Flag int - - const ( - flagOne Flag = iota - flagTwo - ) - - var flagStrings = map[Flag]string{ - flagOne: "flagOne", - flagTwo: "flagTwo", - } - - func (f Flag) String() string { - if s, ok := flagStrings[f]; ok { - return s - } - return fmt.Sprintf("Unknown flag (%d)", int(f)) - } - - type Bar struct { - data uintptr - } - - type Foo struct { - unexportedField Bar - ExportedField map[interface{}]interface{} - } - */ - - // Setup some sample data structures for the example. - bar := Bar{uintptr(0)} - s1 := Foo{bar, map[interface{}]interface{}{"one": true}} - f := Flag(5) - b := []byte{ - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, - 0x31, 0x32, - } - - // Dump! - spew.Dump(s1, f, b) - - // Output: - // (spew_test.Foo) { - // unexportedField: (spew_test.Bar) { - // data: (uintptr) - // }, - // ExportedField: (map[interface {}]interface {}) (len=1) { - // (string) (len=3) "one": (bool) true - // } - // } - // (spew_test.Flag) Unknown flag (5) - // ([]uint8) (len=34 cap=34) { - // 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | - // 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| - // 00000020 31 32 |12| - // } - // -} - -// This example demonstrates how to use Printf to display a variable with a -// format string and inline formatting. -func ExamplePrintf() { - // Create a double pointer to a uint 8. - ui8 := uint8(5) - pui8 := &ui8 - ppui8 := &pui8 - - // Create a circular data type. - type circular struct { - ui8 uint8 - c *circular - } - c := circular{ui8: 1} - c.c = &c - - // Print! - spew.Printf("ppui8: %v\n", ppui8) - spew.Printf("circular: %v\n", c) - - // Output: - // ppui8: <**>5 - // circular: {1 <*>{1 <*>}} -} - -// This example demonstrates how to use a ConfigState. -func ExampleConfigState() { - // Modify the indent level of the ConfigState only. The global - // configuration is not modified. - scs := spew.ConfigState{Indent: "\t"} - - // Output using the ConfigState instance. - v := map[string]int{"one": 1} - scs.Printf("v: %v\n", v) - scs.Dump(v) - - // Output: - // v: map[one:1] - // (map[string]int) (len=1) { - // (string) (len=3) "one": (int) 1 - // } -} - -// This example demonstrates how to use ConfigState.Dump to dump variables to -// stdout -func ExampleConfigState_Dump() { - // See the top-level Dump example for details on the types used in this - // example. - - // Create two ConfigState instances with different indentation. - scs := spew.ConfigState{Indent: "\t"} - scs2 := spew.ConfigState{Indent: " "} - - // Setup some sample data structures for the example. - bar := Bar{uintptr(0)} - s1 := Foo{bar, map[interface{}]interface{}{"one": true}} - - // Dump using the ConfigState instances. - scs.Dump(s1) - scs2.Dump(s1) - - // Output: - // (spew_test.Foo) { - // unexportedField: (spew_test.Bar) { - // data: (uintptr) - // }, - // ExportedField: (map[interface {}]interface {}) (len=1) { - // (string) (len=3) "one": (bool) true - // } - // } - // (spew_test.Foo) { - // unexportedField: (spew_test.Bar) { - // data: (uintptr) - // }, - // ExportedField: (map[interface {}]interface {}) (len=1) { - // (string) (len=3) "one": (bool) true - // } - // } - // -} - -// This example demonstrates how to use ConfigState.Printf to display a variable -// with a format string and inline formatting. -func ExampleConfigState_Printf() { - // See the top-level Dump example for details on the types used in this - // example. - - // Create two ConfigState instances and modify the method handling of the - // first ConfigState only. - scs := spew.NewDefaultConfig() - scs2 := spew.NewDefaultConfig() - scs.DisableMethods = true - - // Alternatively - // scs := spew.ConfigState{Indent: " ", DisableMethods: true} - // scs2 := spew.ConfigState{Indent: " "} - - // This is of type Flag which implements a Stringer and has raw value 1. - f := flagTwo - - // Dump using the ConfigState instances. - scs.Printf("f: %v\n", f) - scs2.Printf("f: %v\n", f) - - // Output: - // f: 1 - // f: flagTwo -} diff --git a/vendor/github.com/davecgh/go-spew/spew/format_test.go b/vendor/github.com/davecgh/go-spew/spew/format_test.go deleted file mode 100644 index f9b93abe..00000000 --- a/vendor/github.com/davecgh/go-spew/spew/format_test.go +++ /dev/null @@ -1,1558 +0,0 @@ -/* - * Copyright (c) 2013-2016 Dave Collins - * - * Permission to use, copy, modify, and 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. - */ - -/* -Test Summary: -NOTE: For each test, a nil pointer, a single pointer and double pointer to the -base test element are also tested to ensure proper indirection across all types. - -- Max int8, int16, int32, int64, int -- Max uint8, uint16, uint32, uint64, uint -- Boolean true and false -- Standard complex64 and complex128 -- Array containing standard ints -- Array containing type with custom formatter on pointer receiver only -- Array containing interfaces -- Slice containing standard float32 values -- Slice containing type with custom formatter on pointer receiver only -- Slice containing interfaces -- Nil slice -- Standard string -- Nil interface -- Sub-interface -- Map with string keys and int vals -- Map with custom formatter type on pointer receiver only keys and vals -- Map with interface keys and values -- Map with nil interface value -- Struct with primitives -- Struct that contains another struct -- Struct that contains custom type with Stringer pointer interface via both - exported and unexported fields -- Struct that contains embedded struct and field to same struct -- Uintptr to 0 (null pointer) -- Uintptr address of real variable -- Unsafe.Pointer to 0 (null pointer) -- Unsafe.Pointer to address of real variable -- Nil channel -- Standard int channel -- Function with no params and no returns -- Function with param and no returns -- Function with multiple params and multiple returns -- Struct that is circular through self referencing -- Structs that are circular through cross referencing -- Structs that are indirectly circular -- Type that panics in its Stringer interface -- Type that has a custom Error interface -- %x passthrough with uint -- %#x passthrough with uint -- %f passthrough with precision -- %f passthrough with width and precision -- %d passthrough with width -- %q passthrough with string -*/ - -package spew_test - -import ( - "bytes" - "fmt" - "testing" - "unsafe" - - "github.com/davecgh/go-spew/spew" -) - -// formatterTest is used to describe a test to be performed against NewFormatter. -type formatterTest struct { - format string - in interface{} - wants []string -} - -// formatterTests houses all of the tests to be performed against NewFormatter. -var formatterTests = make([]formatterTest, 0) - -// addFormatterTest is a helper method to append the passed input and desired -// result to formatterTests. -func addFormatterTest(format string, in interface{}, wants ...string) { - test := formatterTest{format, in, wants} - formatterTests = append(formatterTests, test) -} - -func addIntFormatterTests() { - // Max int8. - v := int8(127) - nv := (*int8)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "int8" - vs := "127" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Max int16. - v2 := int16(32767) - nv2 := (*int16)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "int16" - v2s := "32767" - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%v", nv2, "") - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") - - // Max int32. - v3 := int32(2147483647) - nv3 := (*int32)(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "int32" - v3s := "2147483647" - addFormatterTest("%v", v3, v3s) - addFormatterTest("%v", pv3, "<*>"+v3s) - addFormatterTest("%v", &pv3, "<**>"+v3s) - addFormatterTest("%v", nv3, "") - addFormatterTest("%+v", v3, v3s) - addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) - addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%#v", v3, "("+v3t+")"+v3s) - addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s) - addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s) - addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") - addFormatterTest("%#+v", v3, "("+v3t+")"+v3s) - addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s) - addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s) - addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") - - // Max int64. - v4 := int64(9223372036854775807) - nv4 := (*int64)(nil) - pv4 := &v4 - v4Addr := fmt.Sprintf("%p", pv4) - pv4Addr := fmt.Sprintf("%p", &pv4) - v4t := "int64" - v4s := "9223372036854775807" - addFormatterTest("%v", v4, v4s) - addFormatterTest("%v", pv4, "<*>"+v4s) - addFormatterTest("%v", &pv4, "<**>"+v4s) - addFormatterTest("%v", nv4, "") - addFormatterTest("%+v", v4, v4s) - addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) - addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) - addFormatterTest("%+v", nv4, "") - addFormatterTest("%#v", v4, "("+v4t+")"+v4s) - addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s) - addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s) - addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") - addFormatterTest("%#+v", v4, "("+v4t+")"+v4s) - addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s) - addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s) - addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") - - // Max int. - v5 := int(2147483647) - nv5 := (*int)(nil) - pv5 := &v5 - v5Addr := fmt.Sprintf("%p", pv5) - pv5Addr := fmt.Sprintf("%p", &pv5) - v5t := "int" - v5s := "2147483647" - addFormatterTest("%v", v5, v5s) - addFormatterTest("%v", pv5, "<*>"+v5s) - addFormatterTest("%v", &pv5, "<**>"+v5s) - addFormatterTest("%v", nv5, "") - addFormatterTest("%+v", v5, v5s) - addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s) - addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s) - addFormatterTest("%+v", nv5, "") - addFormatterTest("%#v", v5, "("+v5t+")"+v5s) - addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s) - addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s) - addFormatterTest("%#v", nv5, "(*"+v5t+")"+"") - addFormatterTest("%#+v", v5, "("+v5t+")"+v5s) - addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s) - addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s) - addFormatterTest("%#+v", nv5, "(*"+v5t+")"+"") -} - -func addUintFormatterTests() { - // Max uint8. - v := uint8(255) - nv := (*uint8)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "uint8" - vs := "255" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Max uint16. - v2 := uint16(65535) - nv2 := (*uint16)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "uint16" - v2s := "65535" - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%v", nv2, "") - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") - - // Max uint32. - v3 := uint32(4294967295) - nv3 := (*uint32)(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "uint32" - v3s := "4294967295" - addFormatterTest("%v", v3, v3s) - addFormatterTest("%v", pv3, "<*>"+v3s) - addFormatterTest("%v", &pv3, "<**>"+v3s) - addFormatterTest("%v", nv3, "") - addFormatterTest("%+v", v3, v3s) - addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) - addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%#v", v3, "("+v3t+")"+v3s) - addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s) - addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s) - addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") - addFormatterTest("%#+v", v3, "("+v3t+")"+v3s) - addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s) - addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s) - addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") - - // Max uint64. - v4 := uint64(18446744073709551615) - nv4 := (*uint64)(nil) - pv4 := &v4 - v4Addr := fmt.Sprintf("%p", pv4) - pv4Addr := fmt.Sprintf("%p", &pv4) - v4t := "uint64" - v4s := "18446744073709551615" - addFormatterTest("%v", v4, v4s) - addFormatterTest("%v", pv4, "<*>"+v4s) - addFormatterTest("%v", &pv4, "<**>"+v4s) - addFormatterTest("%v", nv4, "") - addFormatterTest("%+v", v4, v4s) - addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) - addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) - addFormatterTest("%+v", nv4, "") - addFormatterTest("%#v", v4, "("+v4t+")"+v4s) - addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s) - addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s) - addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") - addFormatterTest("%#+v", v4, "("+v4t+")"+v4s) - addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s) - addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s) - addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") - - // Max uint. - v5 := uint(4294967295) - nv5 := (*uint)(nil) - pv5 := &v5 - v5Addr := fmt.Sprintf("%p", pv5) - pv5Addr := fmt.Sprintf("%p", &pv5) - v5t := "uint" - v5s := "4294967295" - addFormatterTest("%v", v5, v5s) - addFormatterTest("%v", pv5, "<*>"+v5s) - addFormatterTest("%v", &pv5, "<**>"+v5s) - addFormatterTest("%v", nv5, "") - addFormatterTest("%+v", v5, v5s) - addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s) - addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s) - addFormatterTest("%+v", nv5, "") - addFormatterTest("%#v", v5, "("+v5t+")"+v5s) - addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s) - addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s) - addFormatterTest("%#v", nv5, "(*"+v5t+")"+"") - addFormatterTest("%#+v", v5, "("+v5t+")"+v5s) - addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s) - addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s) - addFormatterTest("%#v", nv5, "(*"+v5t+")"+"") -} - -func addBoolFormatterTests() { - // Boolean true. - v := bool(true) - nv := (*bool)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "bool" - vs := "true" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Boolean false. - v2 := bool(false) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "bool" - v2s := "false" - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) -} - -func addFloatFormatterTests() { - // Standard float32. - v := float32(3.1415) - nv := (*float32)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "float32" - vs := "3.1415" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Standard float64. - v2 := float64(3.1415926) - nv2 := (*float64)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "float64" - v2s := "3.1415926" - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") -} - -func addComplexFormatterTests() { - // Standard complex64. - v := complex(float32(6), -2) - nv := (*complex64)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "complex64" - vs := "(6-2i)" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Standard complex128. - v2 := complex(float64(-6), 2) - nv2 := (*complex128)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "complex128" - v2s := "(-6+2i)" - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") -} - -func addArrayFormatterTests() { - // Array containing standard ints. - v := [3]int{1, 2, 3} - nv := (*[3]int)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "[3]int" - vs := "[1 2 3]" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Array containing type with custom formatter on pointer receiver only. - v2 := [3]pstringer{"1", "2", "3"} - nv2 := (*[3]pstringer)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "[3]spew_test.pstringer" - v2sp := "[stringer 1 stringer 2 stringer 3]" - v2s := v2sp - if spew.UnsafeDisabled { - v2s = "[1 2 3]" - } - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2sp) - addFormatterTest("%v", &pv2, "<**>"+v2sp) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2sp) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2sp) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2sp) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2sp) - addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2sp) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2sp) - addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") - - // Array containing interfaces. - v3 := [3]interface{}{"one", int(2), uint(3)} - nv3 := (*[3]interface{})(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "[3]interface {}" - v3t2 := "string" - v3t3 := "int" - v3t4 := "uint" - v3s := "[one 2 3]" - v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3]" - addFormatterTest("%v", v3, v3s) - addFormatterTest("%v", pv3, "<*>"+v3s) - addFormatterTest("%v", &pv3, "<**>"+v3s) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%+v", v3, v3s) - addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) - addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%#v", v3, "("+v3t+")"+v3s2) - addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2) - addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2) - addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") - addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2) - addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2) - addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2) - addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") -} - -func addSliceFormatterTests() { - // Slice containing standard float32 values. - v := []float32{3.14, 6.28, 12.56} - nv := (*[]float32)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "[]float32" - vs := "[3.14 6.28 12.56]" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Slice containing type with custom formatter on pointer receiver only. - v2 := []pstringer{"1", "2", "3"} - nv2 := (*[]pstringer)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "[]spew_test.pstringer" - v2s := "[stringer 1 stringer 2 stringer 3]" - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") - - // Slice containing interfaces. - v3 := []interface{}{"one", int(2), uint(3), nil} - nv3 := (*[]interface{})(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "[]interface {}" - v3t2 := "string" - v3t3 := "int" - v3t4 := "uint" - v3t5 := "interface {}" - v3s := "[one 2 3 ]" - v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3 (" + v3t5 + - ")]" - addFormatterTest("%v", v3, v3s) - addFormatterTest("%v", pv3, "<*>"+v3s) - addFormatterTest("%v", &pv3, "<**>"+v3s) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%+v", v3, v3s) - addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) - addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%#v", v3, "("+v3t+")"+v3s2) - addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2) - addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2) - addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") - addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2) - addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2) - addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2) - addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") - - // Nil slice. - var v4 []int - nv4 := (*[]int)(nil) - pv4 := &v4 - v4Addr := fmt.Sprintf("%p", pv4) - pv4Addr := fmt.Sprintf("%p", &pv4) - v4t := "[]int" - v4s := "" - addFormatterTest("%v", v4, v4s) - addFormatterTest("%v", pv4, "<*>"+v4s) - addFormatterTest("%v", &pv4, "<**>"+v4s) - addFormatterTest("%+v", nv4, "") - addFormatterTest("%+v", v4, v4s) - addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) - addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) - addFormatterTest("%+v", nv4, "") - addFormatterTest("%#v", v4, "("+v4t+")"+v4s) - addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s) - addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s) - addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") - addFormatterTest("%#+v", v4, "("+v4t+")"+v4s) - addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s) - addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s) - addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") -} - -func addStringFormatterTests() { - // Standard string. - v := "test" - nv := (*string)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "string" - vs := "test" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") -} - -func addInterfaceFormatterTests() { - // Nil interface. - var v interface{} - nv := (*interface{})(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "interface {}" - vs := "" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Sub-interface. - v2 := interface{}(uint16(65535)) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "uint16" - v2s := "65535" - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) -} - -func addMapFormatterTests() { - // Map with string keys and int vals. - v := map[string]int{"one": 1, "two": 2} - nilMap := map[string]int(nil) - nv := (*map[string]int)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "map[string]int" - vs := "map[one:1 two:2]" - vs2 := "map[two:2 one:1]" - addFormatterTest("%v", v, vs, vs2) - addFormatterTest("%v", pv, "<*>"+vs, "<*>"+vs2) - addFormatterTest("%v", &pv, "<**>"+vs, "<**>"+vs2) - addFormatterTest("%+v", nilMap, "") - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs, vs2) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs, "<*>("+vAddr+")"+vs2) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs, - "<**>("+pvAddr+"->"+vAddr+")"+vs2) - addFormatterTest("%+v", nilMap, "") - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs, "("+vt+")"+vs2) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs, "(*"+vt+")"+vs2) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs, "(**"+vt+")"+vs2) - addFormatterTest("%#v", nilMap, "("+vt+")"+"") - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs, "("+vt+")"+vs2) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs, - "(*"+vt+")("+vAddr+")"+vs2) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs, - "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs2) - addFormatterTest("%#+v", nilMap, "("+vt+")"+"") - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Map with custom formatter type on pointer receiver only keys and vals. - v2 := map[pstringer]pstringer{"one": "1"} - nv2 := (*map[pstringer]pstringer)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "map[spew_test.pstringer]spew_test.pstringer" - v2s := "map[stringer one:stringer 1]" - if spew.UnsafeDisabled { - v2s = "map[one:1]" - } - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") - - // Map with interface keys and values. - v3 := map[interface{}]interface{}{"one": 1} - nv3 := (*map[interface{}]interface{})(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "map[interface {}]interface {}" - v3t1 := "string" - v3t2 := "int" - v3s := "map[one:1]" - v3s2 := "map[(" + v3t1 + ")one:(" + v3t2 + ")1]" - addFormatterTest("%v", v3, v3s) - addFormatterTest("%v", pv3, "<*>"+v3s) - addFormatterTest("%v", &pv3, "<**>"+v3s) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%+v", v3, v3s) - addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) - addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%#v", v3, "("+v3t+")"+v3s2) - addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2) - addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2) - addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") - addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2) - addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2) - addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2) - addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") - - // Map with nil interface value - v4 := map[string]interface{}{"nil": nil} - nv4 := (*map[string]interface{})(nil) - pv4 := &v4 - v4Addr := fmt.Sprintf("%p", pv4) - pv4Addr := fmt.Sprintf("%p", &pv4) - v4t := "map[string]interface {}" - v4t1 := "interface {}" - v4s := "map[nil:]" - v4s2 := "map[nil:(" + v4t1 + ")]" - addFormatterTest("%v", v4, v4s) - addFormatterTest("%v", pv4, "<*>"+v4s) - addFormatterTest("%v", &pv4, "<**>"+v4s) - addFormatterTest("%+v", nv4, "") - addFormatterTest("%+v", v4, v4s) - addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) - addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) - addFormatterTest("%+v", nv4, "") - addFormatterTest("%#v", v4, "("+v4t+")"+v4s2) - addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s2) - addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s2) - addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") - addFormatterTest("%#+v", v4, "("+v4t+")"+v4s2) - addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s2) - addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s2) - addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") -} - -func addStructFormatterTests() { - // Struct with primitives. - type s1 struct { - a int8 - b uint8 - } - v := s1{127, 255} - nv := (*s1)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "spew_test.s1" - vt2 := "int8" - vt3 := "uint8" - vs := "{127 255}" - vs2 := "{a:127 b:255}" - vs3 := "{a:(" + vt2 + ")127 b:(" + vt3 + ")255}" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs2) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs2) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs2) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs3) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs3) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs3) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs3) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs3) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs3) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Struct that contains another struct. - type s2 struct { - s1 s1 - b bool - } - v2 := s2{s1{127, 255}, true} - nv2 := (*s2)(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "spew_test.s2" - v2t2 := "spew_test.s1" - v2t3 := "int8" - v2t4 := "uint8" - v2t5 := "bool" - v2s := "{{127 255} true}" - v2s2 := "{s1:{a:127 b:255} b:true}" - v2s3 := "{s1:(" + v2t2 + "){a:(" + v2t3 + ")127 b:(" + v2t4 + ")255} b:(" + - v2t5 + ")true}" - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%+v", v2, v2s2) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s2) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s2) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%#v", v2, "("+v2t+")"+v2s3) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s3) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s3) - addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s3) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s3) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s3) - addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") - - // Struct that contains custom type with Stringer pointer interface via both - // exported and unexported fields. - type s3 struct { - s pstringer - S pstringer - } - v3 := s3{"test", "test2"} - nv3 := (*s3)(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "spew_test.s3" - v3t2 := "spew_test.pstringer" - v3s := "{stringer test stringer test2}" - v3sp := v3s - v3s2 := "{s:stringer test S:stringer test2}" - v3s2p := v3s2 - v3s3 := "{s:(" + v3t2 + ")stringer test S:(" + v3t2 + ")stringer test2}" - v3s3p := v3s3 - if spew.UnsafeDisabled { - v3s = "{test test2}" - v3sp = "{test stringer test2}" - v3s2 = "{s:test S:test2}" - v3s2p = "{s:test S:stringer test2}" - v3s3 = "{s:(" + v3t2 + ")test S:(" + v3t2 + ")test2}" - v3s3p = "{s:(" + v3t2 + ")test S:(" + v3t2 + ")stringer test2}" - } - addFormatterTest("%v", v3, v3s) - addFormatterTest("%v", pv3, "<*>"+v3sp) - addFormatterTest("%v", &pv3, "<**>"+v3sp) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%+v", v3, v3s2) - addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s2p) - addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s2p) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%#v", v3, "("+v3t+")"+v3s3) - addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s3p) - addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s3p) - addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") - addFormatterTest("%#+v", v3, "("+v3t+")"+v3s3) - addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s3p) - addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s3p) - addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") - - // Struct that contains embedded struct and field to same struct. - e := embed{"embedstr"} - v4 := embedwrap{embed: &e, e: &e} - nv4 := (*embedwrap)(nil) - pv4 := &v4 - eAddr := fmt.Sprintf("%p", &e) - v4Addr := fmt.Sprintf("%p", pv4) - pv4Addr := fmt.Sprintf("%p", &pv4) - v4t := "spew_test.embedwrap" - v4t2 := "spew_test.embed" - v4t3 := "string" - v4s := "{<*>{embedstr} <*>{embedstr}}" - v4s2 := "{embed:<*>(" + eAddr + "){a:embedstr} e:<*>(" + eAddr + - "){a:embedstr}}" - v4s3 := "{embed:(*" + v4t2 + "){a:(" + v4t3 + ")embedstr} e:(*" + v4t2 + - "){a:(" + v4t3 + ")embedstr}}" - v4s4 := "{embed:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 + - ")embedstr} e:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 + ")embedstr}}" - addFormatterTest("%v", v4, v4s) - addFormatterTest("%v", pv4, "<*>"+v4s) - addFormatterTest("%v", &pv4, "<**>"+v4s) - addFormatterTest("%+v", nv4, "") - addFormatterTest("%+v", v4, v4s2) - addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s2) - addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s2) - addFormatterTest("%+v", nv4, "") - addFormatterTest("%#v", v4, "("+v4t+")"+v4s3) - addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s3) - addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s3) - addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") - addFormatterTest("%#+v", v4, "("+v4t+")"+v4s4) - addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s4) - addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s4) - addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") -} - -func addUintptrFormatterTests() { - // Null pointer. - v := uintptr(0) - nv := (*uintptr)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "uintptr" - vs := "" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Address of real variable. - i := 1 - v2 := uintptr(unsafe.Pointer(&i)) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "uintptr" - v2s := fmt.Sprintf("%p", &i) - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) -} - -func addUnsafePointerFormatterTests() { - // Null pointer. - v := unsafe.Pointer(uintptr(0)) - nv := (*unsafe.Pointer)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "unsafe.Pointer" - vs := "" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Address of real variable. - i := 1 - v2 := unsafe.Pointer(&i) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "unsafe.Pointer" - v2s := fmt.Sprintf("%p", &i) - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) -} - -func addChanFormatterTests() { - // Nil channel. - var v chan int - pv := &v - nv := (*chan int)(nil) - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "chan int" - vs := "" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Real channel. - v2 := make(chan int) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "chan int" - v2s := fmt.Sprintf("%p", v2) - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) -} - -func addFuncFormatterTests() { - // Function with no params and no returns. - v := addIntFormatterTests - nv := (*func())(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "func()" - vs := fmt.Sprintf("%p", v) - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") - - // Function with param and no returns. - v2 := TestFormatter - nv2 := (*func(*testing.T))(nil) - pv2 := &v2 - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "func(*testing.T)" - v2s := fmt.Sprintf("%p", v2) - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s) - addFormatterTest("%v", &pv2, "<**>"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%+v", v2, v2s) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%+v", nv2, "") - addFormatterTest("%#v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) - addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) - addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") - - // Function with multiple params and multiple returns. - var v3 = func(i int, s string) (b bool, err error) { - return true, nil - } - nv3 := (*func(int, string) (bool, error))(nil) - pv3 := &v3 - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "func(int, string) (bool, error)" - v3s := fmt.Sprintf("%p", v3) - addFormatterTest("%v", v3, v3s) - addFormatterTest("%v", pv3, "<*>"+v3s) - addFormatterTest("%v", &pv3, "<**>"+v3s) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%+v", v3, v3s) - addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) - addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) - addFormatterTest("%+v", nv3, "") - addFormatterTest("%#v", v3, "("+v3t+")"+v3s) - addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s) - addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s) - addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") - addFormatterTest("%#+v", v3, "("+v3t+")"+v3s) - addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s) - addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s) - addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") -} - -func addCircularFormatterTests() { - // Struct that is circular through self referencing. - type circular struct { - c *circular - } - v := circular{nil} - v.c = &v - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "spew_test.circular" - vs := "{<*>{<*>}}" - vs2 := "{<*>}" - vs3 := "{c:<*>(" + vAddr + "){c:<*>(" + vAddr + ")}}" - vs4 := "{c:<*>(" + vAddr + ")}" - vs5 := "{c:(*" + vt + "){c:(*" + vt + ")}}" - vs6 := "{c:(*" + vt + ")}" - vs7 := "{c:(*" + vt + ")(" + vAddr + "){c:(*" + vt + ")(" + vAddr + - ")}}" - vs8 := "{c:(*" + vt + ")(" + vAddr + ")}" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs2) - addFormatterTest("%v", &pv, "<**>"+vs2) - addFormatterTest("%+v", v, vs3) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs4) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs4) - addFormatterTest("%#v", v, "("+vt+")"+vs5) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs6) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs6) - addFormatterTest("%#+v", v, "("+vt+")"+vs7) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs8) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs8) - - // Structs that are circular through cross referencing. - v2 := xref1{nil} - ts2 := xref2{&v2} - v2.ps2 = &ts2 - pv2 := &v2 - ts2Addr := fmt.Sprintf("%p", &ts2) - v2Addr := fmt.Sprintf("%p", pv2) - pv2Addr := fmt.Sprintf("%p", &pv2) - v2t := "spew_test.xref1" - v2t2 := "spew_test.xref2" - v2s := "{<*>{<*>{<*>}}}" - v2s2 := "{<*>{<*>}}" - v2s3 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + "){ps2:<*>(" + - ts2Addr + ")}}}" - v2s4 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + ")}}" - v2s5 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + "){ps2:(*" + v2t2 + - ")}}}" - v2s6 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + ")}}" - v2s7 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t + - ")(" + v2Addr + "){ps2:(*" + v2t2 + ")(" + ts2Addr + - ")}}}" - v2s8 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t + - ")(" + v2Addr + ")}}" - addFormatterTest("%v", v2, v2s) - addFormatterTest("%v", pv2, "<*>"+v2s2) - addFormatterTest("%v", &pv2, "<**>"+v2s2) - addFormatterTest("%+v", v2, v2s3) - addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s4) - addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s4) - addFormatterTest("%#v", v2, "("+v2t+")"+v2s5) - addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s6) - addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s6) - addFormatterTest("%#+v", v2, "("+v2t+")"+v2s7) - addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s8) - addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s8) - - // Structs that are indirectly circular. - v3 := indirCir1{nil} - tic2 := indirCir2{nil} - tic3 := indirCir3{&v3} - tic2.ps3 = &tic3 - v3.ps2 = &tic2 - pv3 := &v3 - tic2Addr := fmt.Sprintf("%p", &tic2) - tic3Addr := fmt.Sprintf("%p", &tic3) - v3Addr := fmt.Sprintf("%p", pv3) - pv3Addr := fmt.Sprintf("%p", &pv3) - v3t := "spew_test.indirCir1" - v3t2 := "spew_test.indirCir2" - v3t3 := "spew_test.indirCir3" - v3s := "{<*>{<*>{<*>{<*>}}}}" - v3s2 := "{<*>{<*>{<*>}}}" - v3s3 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" + - v3Addr + "){ps2:<*>(" + tic2Addr + ")}}}}" - v3s4 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" + - v3Addr + ")}}}" - v3s5 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t + - "){ps2:(*" + v3t2 + ")}}}}" - v3s6 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t + - ")}}}" - v3s7 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" + - tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + "){ps2:(*" + v3t2 + - ")(" + tic2Addr + ")}}}}" - v3s8 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" + - tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + ")}}}" - addFormatterTest("%v", v3, v3s) - addFormatterTest("%v", pv3, "<*>"+v3s2) - addFormatterTest("%v", &pv3, "<**>"+v3s2) - addFormatterTest("%+v", v3, v3s3) - addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s4) - addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s4) - addFormatterTest("%#v", v3, "("+v3t+")"+v3s5) - addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s6) - addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s6) - addFormatterTest("%#+v", v3, "("+v3t+")"+v3s7) - addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s8) - addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s8) -} - -func addPanicFormatterTests() { - // Type that panics in its Stringer interface. - v := panicer(127) - nv := (*panicer)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "spew_test.panicer" - vs := "(PANIC=test panic)127" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") -} - -func addErrorFormatterTests() { - // Type that has a custom Error interface. - v := customError(127) - nv := (*customError)(nil) - pv := &v - vAddr := fmt.Sprintf("%p", pv) - pvAddr := fmt.Sprintf("%p", &pv) - vt := "spew_test.customError" - vs := "error: 127" - addFormatterTest("%v", v, vs) - addFormatterTest("%v", pv, "<*>"+vs) - addFormatterTest("%v", &pv, "<**>"+vs) - addFormatterTest("%v", nv, "") - addFormatterTest("%+v", v, vs) - addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) - addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%+v", nv, "") - addFormatterTest("%#v", v, "("+vt+")"+vs) - addFormatterTest("%#v", pv, "(*"+vt+")"+vs) - addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) - addFormatterTest("%#v", nv, "(*"+vt+")"+"") - addFormatterTest("%#+v", v, "("+vt+")"+vs) - addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) - addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) - addFormatterTest("%#+v", nv, "(*"+vt+")"+"") -} - -func addPassthroughFormatterTests() { - // %x passthrough with uint. - v := uint(4294967295) - pv := &v - vAddr := fmt.Sprintf("%x", pv) - pvAddr := fmt.Sprintf("%x", &pv) - vs := "ffffffff" - addFormatterTest("%x", v, vs) - addFormatterTest("%x", pv, vAddr) - addFormatterTest("%x", &pv, pvAddr) - - // %#x passthrough with uint. - v2 := int(2147483647) - pv2 := &v2 - v2Addr := fmt.Sprintf("%#x", pv2) - pv2Addr := fmt.Sprintf("%#x", &pv2) - v2s := "0x7fffffff" - addFormatterTest("%#x", v2, v2s) - addFormatterTest("%#x", pv2, v2Addr) - addFormatterTest("%#x", &pv2, pv2Addr) - - // %f passthrough with precision. - addFormatterTest("%.2f", 3.1415, "3.14") - addFormatterTest("%.3f", 3.1415, "3.142") - addFormatterTest("%.4f", 3.1415, "3.1415") - - // %f passthrough with width and precision. - addFormatterTest("%5.2f", 3.1415, " 3.14") - addFormatterTest("%6.3f", 3.1415, " 3.142") - addFormatterTest("%7.4f", 3.1415, " 3.1415") - - // %d passthrough with width. - addFormatterTest("%3d", 127, "127") - addFormatterTest("%4d", 127, " 127") - addFormatterTest("%5d", 127, " 127") - - // %q passthrough with string. - addFormatterTest("%q", "test", "\"test\"") -} - -// TestFormatter executes all of the tests described by formatterTests. -func TestFormatter(t *testing.T) { - // Setup tests. - addIntFormatterTests() - addUintFormatterTests() - addBoolFormatterTests() - addFloatFormatterTests() - addComplexFormatterTests() - addArrayFormatterTests() - addSliceFormatterTests() - addStringFormatterTests() - addInterfaceFormatterTests() - addMapFormatterTests() - addStructFormatterTests() - addUintptrFormatterTests() - addUnsafePointerFormatterTests() - addChanFormatterTests() - addFuncFormatterTests() - addCircularFormatterTests() - addPanicFormatterTests() - addErrorFormatterTests() - addPassthroughFormatterTests() - - t.Logf("Running %d tests", len(formatterTests)) - for i, test := range formatterTests { - buf := new(bytes.Buffer) - spew.Fprintf(buf, test.format, test.in) - s := buf.String() - if testFailed(s, test.wants) { - t.Errorf("Formatter #%d format: %s got: %s %s", i, test.format, s, - stringizeWants(test.wants)) - continue - } - } -} - -type testStruct struct { - x int -} - -func (ts testStruct) String() string { - return fmt.Sprintf("ts.%d", ts.x) -} - -type testStructP struct { - x int -} - -func (ts *testStructP) String() string { - return fmt.Sprintf("ts.%d", ts.x) -} - -func TestPrintSortedKeys(t *testing.T) { - cfg := spew.ConfigState{SortKeys: true} - s := cfg.Sprint(map[int]string{1: "1", 3: "3", 2: "2"}) - expected := "map[1:1 2:2 3:3]" - if s != expected { - t.Errorf("Sorted keys mismatch 1:\n %v %v", s, expected) - } - - s = cfg.Sprint(map[stringer]int{"1": 1, "3": 3, "2": 2}) - expected = "map[stringer 1:1 stringer 2:2 stringer 3:3]" - if s != expected { - t.Errorf("Sorted keys mismatch 2:\n %v %v", s, expected) - } - - s = cfg.Sprint(map[pstringer]int{pstringer("1"): 1, pstringer("3"): 3, pstringer("2"): 2}) - expected = "map[stringer 1:1 stringer 2:2 stringer 3:3]" - if spew.UnsafeDisabled { - expected = "map[1:1 2:2 3:3]" - } - if s != expected { - t.Errorf("Sorted keys mismatch 3:\n %v %v", s, expected) - } - - s = cfg.Sprint(map[testStruct]int{testStruct{1}: 1, testStruct{3}: 3, testStruct{2}: 2}) - expected = "map[ts.1:1 ts.2:2 ts.3:3]" - if s != expected { - t.Errorf("Sorted keys mismatch 4:\n %v %v", s, expected) - } - - if !spew.UnsafeDisabled { - s = cfg.Sprint(map[testStructP]int{testStructP{1}: 1, testStructP{3}: 3, testStructP{2}: 2}) - expected = "map[ts.1:1 ts.2:2 ts.3:3]" - if s != expected { - t.Errorf("Sorted keys mismatch 5:\n %v %v", s, expected) - } - } - - s = cfg.Sprint(map[customError]int{customError(1): 1, customError(3): 3, customError(2): 2}) - expected = "map[error: 1:1 error: 2:2 error: 3:3]" - if s != expected { - t.Errorf("Sorted keys mismatch 6:\n %v %v", s, expected) - } -} diff --git a/vendor/github.com/davecgh/go-spew/spew/internal_test.go b/vendor/github.com/davecgh/go-spew/spew/internal_test.go deleted file mode 100644 index 20a9cfef..00000000 --- a/vendor/github.com/davecgh/go-spew/spew/internal_test.go +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2013-2016 Dave Collins - * - * Permission to use, copy, modify, and 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. - */ - -/* -This test file is part of the spew package rather than than the spew_test -package because it needs access to internals to properly test certain cases -which are not possible via the public interface since they should never happen. -*/ - -package spew - -import ( - "bytes" - "reflect" - "testing" -) - -// dummyFmtState implements a fake fmt.State to use for testing invalid -// reflect.Value handling. This is necessary because the fmt package catches -// invalid values before invoking the formatter on them. -type dummyFmtState struct { - bytes.Buffer -} - -func (dfs *dummyFmtState) Flag(f int) bool { - if f == int('+') { - return true - } - return false -} - -func (dfs *dummyFmtState) Precision() (int, bool) { - return 0, false -} - -func (dfs *dummyFmtState) Width() (int, bool) { - return 0, false -} - -// TestInvalidReflectValue ensures the dump and formatter code handles an -// invalid reflect value properly. This needs access to internal state since it -// should never happen in real code and therefore can't be tested via the public -// API. -func TestInvalidReflectValue(t *testing.T) { - i := 1 - - // Dump invalid reflect value. - v := new(reflect.Value) - buf := new(bytes.Buffer) - d := dumpState{w: buf, cs: &Config} - d.dump(*v) - s := buf.String() - want := "" - if s != want { - t.Errorf("InvalidReflectValue #%d\n got: %s want: %s", i, s, want) - } - i++ - - // Formatter invalid reflect value. - buf2 := new(dummyFmtState) - f := formatState{value: *v, cs: &Config, fs: buf2} - f.format(*v) - s = buf2.String() - want = "" - if s != want { - t.Errorf("InvalidReflectValue #%d got: %s want: %s", i, s, want) - } -} - -// SortValues makes the internal sortValues function available to the test -// package. -func SortValues(values []reflect.Value, cs *ConfigState) { - sortValues(values, cs) -} diff --git a/vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go b/vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go deleted file mode 100644 index a0c612ec..00000000 --- a/vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) 2013-2016 Dave Collins - -// Permission to use, copy, modify, and 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. - -// NOTE: Due to the following build constraints, this file will only be compiled -// when the code is not running on Google App Engine, compiled by GopherJS, and -// "-tags safe" is not added to the go build command line. The "disableunsafe" -// tag is deprecated and thus should not be used. -// +build !js,!appengine,!safe,!disableunsafe - -/* -This test file is part of the spew package rather than than the spew_test -package because it needs access to internals to properly test certain cases -which are not possible via the public interface since they should never happen. -*/ - -package spew - -import ( - "bytes" - "reflect" - "testing" - "unsafe" -) - -// changeKind uses unsafe to intentionally change the kind of a reflect.Value to -// the maximum kind value which does not exist. This is needed to test the -// fallback code which punts to the standard fmt library for new types that -// might get added to the language. -func changeKind(v *reflect.Value, readOnly bool) { - rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + offsetFlag)) - *rvf = *rvf | ((1< - * - * Permission to use, copy, modify, and 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. - */ - -package spew_test - -import ( - "bytes" - "fmt" - "io/ioutil" - "os" - "testing" - - "github.com/davecgh/go-spew/spew" -) - -// spewFunc is used to identify which public function of the spew package or -// ConfigState a test applies to. -type spewFunc int - -const ( - fCSFdump spewFunc = iota - fCSFprint - fCSFprintf - fCSFprintln - fCSPrint - fCSPrintln - fCSSdump - fCSSprint - fCSSprintf - fCSSprintln - fCSErrorf - fCSNewFormatter - fErrorf - fFprint - fFprintln - fPrint - fPrintln - fSdump - fSprint - fSprintf - fSprintln -) - -// Map of spewFunc values to names for pretty printing. -var spewFuncStrings = map[spewFunc]string{ - fCSFdump: "ConfigState.Fdump", - fCSFprint: "ConfigState.Fprint", - fCSFprintf: "ConfigState.Fprintf", - fCSFprintln: "ConfigState.Fprintln", - fCSSdump: "ConfigState.Sdump", - fCSPrint: "ConfigState.Print", - fCSPrintln: "ConfigState.Println", - fCSSprint: "ConfigState.Sprint", - fCSSprintf: "ConfigState.Sprintf", - fCSSprintln: "ConfigState.Sprintln", - fCSErrorf: "ConfigState.Errorf", - fCSNewFormatter: "ConfigState.NewFormatter", - fErrorf: "spew.Errorf", - fFprint: "spew.Fprint", - fFprintln: "spew.Fprintln", - fPrint: "spew.Print", - fPrintln: "spew.Println", - fSdump: "spew.Sdump", - fSprint: "spew.Sprint", - fSprintf: "spew.Sprintf", - fSprintln: "spew.Sprintln", -} - -func (f spewFunc) String() string { - if s, ok := spewFuncStrings[f]; ok { - return s - } - return fmt.Sprintf("Unknown spewFunc (%d)", int(f)) -} - -// spewTest is used to describe a test to be performed against the public -// functions of the spew package or ConfigState. -type spewTest struct { - cs *spew.ConfigState - f spewFunc - format string - in interface{} - want string -} - -// spewTests houses the tests to be performed against the public functions of -// the spew package and ConfigState. -// -// These tests are only intended to ensure the public functions are exercised -// and are intentionally not exhaustive of types. The exhaustive type -// tests are handled in the dump and format tests. -var spewTests []spewTest - -// redirStdout is a helper function to return the standard output from f as a -// byte slice. -func redirStdout(f func()) ([]byte, error) { - tempFile, err := ioutil.TempFile("", "ss-test") - if err != nil { - return nil, err - } - fileName := tempFile.Name() - defer os.Remove(fileName) // Ignore error - - origStdout := os.Stdout - os.Stdout = tempFile - f() - os.Stdout = origStdout - tempFile.Close() - - return ioutil.ReadFile(fileName) -} - -func initSpewTests() { - // Config states with various settings. - scsDefault := spew.NewDefaultConfig() - scsNoMethods := &spew.ConfigState{Indent: " ", DisableMethods: true} - scsNoPmethods := &spew.ConfigState{Indent: " ", DisablePointerMethods: true} - scsMaxDepth := &spew.ConfigState{Indent: " ", MaxDepth: 1} - scsContinue := &spew.ConfigState{Indent: " ", ContinueOnMethod: true} - scsNoPtrAddr := &spew.ConfigState{DisablePointerAddresses: true} - scsNoCap := &spew.ConfigState{DisableCapacities: true} - - // Variables for tests on types which implement Stringer interface with and - // without a pointer receiver. - ts := stringer("test") - tps := pstringer("test") - - type ptrTester struct { - s *struct{} - } - tptr := &ptrTester{s: &struct{}{}} - - // depthTester is used to test max depth handling for structs, array, slices - // and maps. - type depthTester struct { - ic indirCir1 - arr [1]string - slice []string - m map[string]int - } - dt := depthTester{indirCir1{nil}, [1]string{"arr"}, []string{"slice"}, - map[string]int{"one": 1}} - - // Variable for tests on types which implement error interface. - te := customError(10) - - spewTests = []spewTest{ - {scsDefault, fCSFdump, "", int8(127), "(int8) 127\n"}, - {scsDefault, fCSFprint, "", int16(32767), "32767"}, - {scsDefault, fCSFprintf, "%v", int32(2147483647), "2147483647"}, - {scsDefault, fCSFprintln, "", int(2147483647), "2147483647\n"}, - {scsDefault, fCSPrint, "", int64(9223372036854775807), "9223372036854775807"}, - {scsDefault, fCSPrintln, "", uint8(255), "255\n"}, - {scsDefault, fCSSdump, "", uint8(64), "(uint8) 64\n"}, - {scsDefault, fCSSprint, "", complex(1, 2), "(1+2i)"}, - {scsDefault, fCSSprintf, "%v", complex(float32(3), 4), "(3+4i)"}, - {scsDefault, fCSSprintln, "", complex(float64(5), 6), "(5+6i)\n"}, - {scsDefault, fCSErrorf, "%#v", uint16(65535), "(uint16)65535"}, - {scsDefault, fCSNewFormatter, "%v", uint32(4294967295), "4294967295"}, - {scsDefault, fErrorf, "%v", uint64(18446744073709551615), "18446744073709551615"}, - {scsDefault, fFprint, "", float32(3.14), "3.14"}, - {scsDefault, fFprintln, "", float64(6.28), "6.28\n"}, - {scsDefault, fPrint, "", true, "true"}, - {scsDefault, fPrintln, "", false, "false\n"}, - {scsDefault, fSdump, "", complex(-10, -20), "(complex128) (-10-20i)\n"}, - {scsDefault, fSprint, "", complex(-1, -2), "(-1-2i)"}, - {scsDefault, fSprintf, "%v", complex(float32(-3), -4), "(-3-4i)"}, - {scsDefault, fSprintln, "", complex(float64(-5), -6), "(-5-6i)\n"}, - {scsNoMethods, fCSFprint, "", ts, "test"}, - {scsNoMethods, fCSFprint, "", &ts, "<*>test"}, - {scsNoMethods, fCSFprint, "", tps, "test"}, - {scsNoMethods, fCSFprint, "", &tps, "<*>test"}, - {scsNoPmethods, fCSFprint, "", ts, "stringer test"}, - {scsNoPmethods, fCSFprint, "", &ts, "<*>stringer test"}, - {scsNoPmethods, fCSFprint, "", tps, "test"}, - {scsNoPmethods, fCSFprint, "", &tps, "<*>stringer test"}, - {scsMaxDepth, fCSFprint, "", dt, "{{} [] [] map[]}"}, - {scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" + - " ic: (spew_test.indirCir1) {\n \n },\n" + - " arr: ([1]string) (len=1 cap=1) {\n \n },\n" + - " slice: ([]string) (len=1 cap=1) {\n \n },\n" + - " m: (map[string]int) (len=1) {\n \n }\n}\n"}, - {scsContinue, fCSFprint, "", ts, "(stringer test) test"}, - {scsContinue, fCSFdump, "", ts, "(spew_test.stringer) " + - "(len=4) (stringer test) \"test\"\n"}, - {scsContinue, fCSFprint, "", te, "(error: 10) 10"}, - {scsContinue, fCSFdump, "", te, "(spew_test.customError) " + - "(error: 10) 10\n"}, - {scsNoPtrAddr, fCSFprint, "", tptr, "<*>{<*>{}}"}, - {scsNoPtrAddr, fCSSdump, "", tptr, "(*spew_test.ptrTester)({\ns: (*struct {})({\n})\n})\n"}, - {scsNoCap, fCSSdump, "", make([]string, 0, 10), "([]string) {\n}\n"}, - {scsNoCap, fCSSdump, "", make([]string, 1, 10), "([]string) (len=1) {\n(string) \"\"\n}\n"}, - } -} - -// TestSpew executes all of the tests described by spewTests. -func TestSpew(t *testing.T) { - initSpewTests() - - t.Logf("Running %d tests", len(spewTests)) - for i, test := range spewTests { - buf := new(bytes.Buffer) - switch test.f { - case fCSFdump: - test.cs.Fdump(buf, test.in) - - case fCSFprint: - test.cs.Fprint(buf, test.in) - - case fCSFprintf: - test.cs.Fprintf(buf, test.format, test.in) - - case fCSFprintln: - test.cs.Fprintln(buf, test.in) - - case fCSPrint: - b, err := redirStdout(func() { test.cs.Print(test.in) }) - if err != nil { - t.Errorf("%v #%d %v", test.f, i, err) - continue - } - buf.Write(b) - - case fCSPrintln: - b, err := redirStdout(func() { test.cs.Println(test.in) }) - if err != nil { - t.Errorf("%v #%d %v", test.f, i, err) - continue - } - buf.Write(b) - - case fCSSdump: - str := test.cs.Sdump(test.in) - buf.WriteString(str) - - case fCSSprint: - str := test.cs.Sprint(test.in) - buf.WriteString(str) - - case fCSSprintf: - str := test.cs.Sprintf(test.format, test.in) - buf.WriteString(str) - - case fCSSprintln: - str := test.cs.Sprintln(test.in) - buf.WriteString(str) - - case fCSErrorf: - err := test.cs.Errorf(test.format, test.in) - buf.WriteString(err.Error()) - - case fCSNewFormatter: - fmt.Fprintf(buf, test.format, test.cs.NewFormatter(test.in)) - - case fErrorf: - err := spew.Errorf(test.format, test.in) - buf.WriteString(err.Error()) - - case fFprint: - spew.Fprint(buf, test.in) - - case fFprintln: - spew.Fprintln(buf, test.in) - - case fPrint: - b, err := redirStdout(func() { spew.Print(test.in) }) - if err != nil { - t.Errorf("%v #%d %v", test.f, i, err) - continue - } - buf.Write(b) - - case fPrintln: - b, err := redirStdout(func() { spew.Println(test.in) }) - if err != nil { - t.Errorf("%v #%d %v", test.f, i, err) - continue - } - buf.Write(b) - - case fSdump: - str := spew.Sdump(test.in) - buf.WriteString(str) - - case fSprint: - str := spew.Sprint(test.in) - buf.WriteString(str) - - case fSprintf: - str := spew.Sprintf(test.format, test.in) - buf.WriteString(str) - - case fSprintln: - str := spew.Sprintln(test.in) - buf.WriteString(str) - - default: - t.Errorf("%v #%d unrecognized function", test.f, i) - continue - } - s := buf.String() - if test.want != s { - t.Errorf("ConfigState #%d\n got: %s want: %s", i, s, test.want) - continue - } - } -} diff --git a/vendor/github.com/davecgh/go-spew/test_coverage.txt b/vendor/github.com/davecgh/go-spew/test_coverage.txt deleted file mode 100644 index 2cd087a2..00000000 --- a/vendor/github.com/davecgh/go-spew/test_coverage.txt +++ /dev/null @@ -1,61 +0,0 @@ - -github.com/davecgh/go-spew/spew/dump.go dumpState.dump 100.00% (88/88) -github.com/davecgh/go-spew/spew/format.go formatState.format 100.00% (82/82) -github.com/davecgh/go-spew/spew/format.go formatState.formatPtr 100.00% (52/52) -github.com/davecgh/go-spew/spew/dump.go dumpState.dumpPtr 100.00% (44/44) -github.com/davecgh/go-spew/spew/dump.go dumpState.dumpSlice 100.00% (39/39) -github.com/davecgh/go-spew/spew/common.go handleMethods 100.00% (30/30) -github.com/davecgh/go-spew/spew/common.go printHexPtr 100.00% (18/18) -github.com/davecgh/go-spew/spew/common.go unsafeReflectValue 100.00% (13/13) -github.com/davecgh/go-spew/spew/format.go formatState.constructOrigFormat 100.00% (12/12) -github.com/davecgh/go-spew/spew/dump.go fdump 100.00% (11/11) -github.com/davecgh/go-spew/spew/format.go formatState.Format 100.00% (11/11) -github.com/davecgh/go-spew/spew/common.go init 100.00% (10/10) -github.com/davecgh/go-spew/spew/common.go printComplex 100.00% (9/9) -github.com/davecgh/go-spew/spew/common.go valuesSorter.Less 100.00% (8/8) -github.com/davecgh/go-spew/spew/format.go formatState.buildDefaultFormat 100.00% (7/7) -github.com/davecgh/go-spew/spew/format.go formatState.unpackValue 100.00% (5/5) -github.com/davecgh/go-spew/spew/dump.go dumpState.indent 100.00% (4/4) -github.com/davecgh/go-spew/spew/common.go catchPanic 100.00% (4/4) -github.com/davecgh/go-spew/spew/config.go ConfigState.convertArgs 100.00% (4/4) -github.com/davecgh/go-spew/spew/spew.go convertArgs 100.00% (4/4) -github.com/davecgh/go-spew/spew/format.go newFormatter 100.00% (3/3) -github.com/davecgh/go-spew/spew/dump.go Sdump 100.00% (3/3) -github.com/davecgh/go-spew/spew/common.go printBool 100.00% (3/3) -github.com/davecgh/go-spew/spew/common.go sortValues 100.00% (3/3) -github.com/davecgh/go-spew/spew/config.go ConfigState.Sdump 100.00% (3/3) -github.com/davecgh/go-spew/spew/dump.go dumpState.unpackValue 100.00% (3/3) -github.com/davecgh/go-spew/spew/spew.go Printf 100.00% (1/1) -github.com/davecgh/go-spew/spew/spew.go Println 100.00% (1/1) -github.com/davecgh/go-spew/spew/spew.go Sprint 100.00% (1/1) -github.com/davecgh/go-spew/spew/spew.go Sprintf 100.00% (1/1) -github.com/davecgh/go-spew/spew/spew.go Sprintln 100.00% (1/1) -github.com/davecgh/go-spew/spew/common.go printFloat 100.00% (1/1) -github.com/davecgh/go-spew/spew/config.go NewDefaultConfig 100.00% (1/1) -github.com/davecgh/go-spew/spew/common.go printInt 100.00% (1/1) -github.com/davecgh/go-spew/spew/common.go printUint 100.00% (1/1) -github.com/davecgh/go-spew/spew/common.go valuesSorter.Len 100.00% (1/1) -github.com/davecgh/go-spew/spew/common.go valuesSorter.Swap 100.00% (1/1) -github.com/davecgh/go-spew/spew/config.go ConfigState.Errorf 100.00% (1/1) -github.com/davecgh/go-spew/spew/config.go ConfigState.Fprint 100.00% (1/1) -github.com/davecgh/go-spew/spew/config.go ConfigState.Fprintf 100.00% (1/1) -github.com/davecgh/go-spew/spew/config.go ConfigState.Fprintln 100.00% (1/1) -github.com/davecgh/go-spew/spew/config.go ConfigState.Print 100.00% (1/1) -github.com/davecgh/go-spew/spew/config.go ConfigState.Printf 100.00% (1/1) -github.com/davecgh/go-spew/spew/config.go ConfigState.Println 100.00% (1/1) -github.com/davecgh/go-spew/spew/config.go ConfigState.Sprint 100.00% (1/1) -github.com/davecgh/go-spew/spew/config.go ConfigState.Sprintf 100.00% (1/1) -github.com/davecgh/go-spew/spew/config.go ConfigState.Sprintln 100.00% (1/1) -github.com/davecgh/go-spew/spew/config.go ConfigState.NewFormatter 100.00% (1/1) -github.com/davecgh/go-spew/spew/config.go ConfigState.Fdump 100.00% (1/1) -github.com/davecgh/go-spew/spew/config.go ConfigState.Dump 100.00% (1/1) -github.com/davecgh/go-spew/spew/dump.go Fdump 100.00% (1/1) -github.com/davecgh/go-spew/spew/dump.go Dump 100.00% (1/1) -github.com/davecgh/go-spew/spew/spew.go Fprintln 100.00% (1/1) -github.com/davecgh/go-spew/spew/format.go NewFormatter 100.00% (1/1) -github.com/davecgh/go-spew/spew/spew.go Errorf 100.00% (1/1) -github.com/davecgh/go-spew/spew/spew.go Fprint 100.00% (1/1) -github.com/davecgh/go-spew/spew/spew.go Fprintf 100.00% (1/1) -github.com/davecgh/go-spew/spew/spew.go Print 100.00% (1/1) -github.com/davecgh/go-spew/spew ------------------------------- 100.00% (505/505) - diff --git a/vendor/github.com/didip/tollbooth/.gitignore b/vendor/github.com/didip/tollbooth/.gitignore new file mode 100644 index 00000000..1043f539 --- /dev/null +++ b/vendor/github.com/didip/tollbooth/.gitignore @@ -0,0 +1,2 @@ +/debug +/.vscode diff --git a/vendor/github.com/didip/tollbooth/README.md b/vendor/github.com/didip/tollbooth/README.md index 08dd9a22..d1971b84 100644 --- a/vendor/github.com/didip/tollbooth/README.md +++ b/vendor/github.com/didip/tollbooth/README.md @@ -5,11 +5,24 @@ This is a generic middleware to rate-limit HTTP requests. -**NOTE:** This library is considered finished, any new activities are probably centered around `thirdparty` modules. +**NOTE 1:** This library is considered finished. + +**NOTE 2:** In the coming weeks, I will be removing thirdparty modules and moving them to their own dedicated repos. + +**NOTE 3:** Major version changes are backward-incompatible. `v2.0.0` streamlines the ugliness of the old API. + + +## Versions + +**v1.0.0:** This version maintains the old API but all of the thirdparty modules are moved to their own repo. + +**v2.x.x:** Brand new API for the sake of code cleanup, thread safety, & auto-expiring data structures. + +**v3.x.x:** Apparently we have been using golang.org/x/time/rate incorrectly. See issue #48. It always limit X number per 1 second. The time duration is not changeable, so it does not make sense to pass TTL to tollbooth. ## Five Minutes Tutorial -``` +```go package main import ( @@ -24,7 +37,7 @@ func HelloHandler(w http.ResponseWriter, req *http.Request) { func main() { // Create a request limiter per handler. - http.Handle("/", tollbooth.LimitFuncHandler(tollbooth.NewLimiter(1, time.Second), HelloHandler)) + http.Handle("/", tollbooth.LimitFuncHandler(tollbooth.NewLimiter(1, nil), HelloHandler)) http.ListenAndServe(":12345", nil) } ``` @@ -32,34 +45,120 @@ func main() { ## Features 1. Rate-limit by request's remote IP, path, methods, custom headers, & basic auth usernames. - ``` - limiter := tollbooth.NewLimiter(1, time.Second) + ```go + import ( + "time" + "github.com/didip/tollbooth/limiter" + ) + + lmt := tollbooth.NewLimiter(1, nil) + + // or create a limiter with expirable token buckets + // This setting means: + // create a 1 request/second limiter and + // every token bucket in it will expire 1 hour after it was initially set. + lmt = tollbooth.NewLimiter(1, &limiter.ExpirableOptions{DefaultExpirationTTL: time.Hour}) // Configure list of places to look for IP address. // By default it's: "RemoteAddr", "X-Forwarded-For", "X-Real-IP" // If your application is behind a proxy, set "X-Forwarded-For" first. - limiter.IPLookups = []string{"RemoteAddr", "X-Forwarded-For", "X-Real-IP"} + lmt.SetIPLookups([]string{"RemoteAddr", "X-Forwarded-For", "X-Real-IP"}) // Limit only GET and POST requests. - limiter.Methods = []string{"GET", "POST"} - - // Limit request headers containing certain values. - // Typically, you prefetched these values from the database. - limiter.Headers = make(map[string][]string) - limiter.Headers["X-Access-Token"] = []string{"abc123", "xyz098"} + lmt.SetMethods([]string{"GET", "POST"}) // Limit based on basic auth usernames. - // Typically, you prefetched these values from the database. - limiter.BasicAuthUsers = []string{"bob", "joe", "didip"} + // You add them on-load, or later as you handle requests. + lmt.SetBasicAuthUsers([]string{"bob", "jane", "didip", "vip"}) + // You can remove them later as well. + lmt.RemoveBasicAuthUsers([]string{"vip"}) + + // Limit request headers containing certain values. + // You add them on-load, or later as you handle requests. + lmt.SetHeader("X-Access-Token", []string{"abc123", "xyz098"}) + // You can remove all entries at once. + lmt.RemoveHeader("X-Access-Token") + // Or remove specific ones. + lmt.RemoveHeaderEntries("X-Access-Token", []string{"limitless-token"}) + + // By the way, the setters are chainable. Example: + lmt.SetIPLookups([]string{"RemoteAddr", "X-Forwarded-For", "X-Real-IP"}). + SetMethods([]string{"GET", "POST"}). + SetBasicAuthUsers([]string{"sansa"}). + SetBasicAuthUsers([]string{"tyrion"}) ``` -2. Each request handler can be rate-limited individually. +2. Compose your own middleware by using `LimitByKeys()`. -3. Compose your own middleware by using `LimitByKeys()`. +3. Header entries and basic auth users can expire over time (to conserve memory). -4. Tollbooth does not require external storage since it uses an algorithm called [Token Bucket](http://en.wikipedia.org/wiki/Token_bucket) [(Go library: ratelimit)](https://github.com/juju/ratelimit). + ```go + import "time" + + lmt := tollbooth.NewLimiter(1, nil) + + // Set a custom expiration TTL for token bucket. + lmt.SetTokenBucketExpirationTTL(time.Hour) + + // Set a custom expiration TTL for basic auth users. + lmt.SetBasicAuthExpirationTTL(time.Hour) + + // Set a custom expiration TTL for header entries. + lmt.SetHeaderEntryExpirationTTL(time.Hour) + ``` + +4. Upon rejection, the following HTTP response headers are available to users: + + * `X-Rate-Limit-Limit` The maximum request limit. + + * `X-Rate-Limit-Duration` The rate-limiter duration. + + * `X-Rate-Limit-Request-Forwarded-For` The rejected request `X-Forwarded-For`. + + * `X-Rate-Limit-Request-Remote-Addr` The rejected request `RemoteAddr`. -# Other Web Frameworks +5. Customize your own message or function when limit is reached. -Support for other web frameworks are defined under `/thirdparty` directory. + ```go + lmt := tollbooth.NewLimiter(1, nil) + + // Set a custom message. + lmt.SetMessage("You have reached maximum request limit.") + + // Set a custom content-type. + lmt.SetMessageContentType("text/plain; charset=utf-8") + + // Set a custom function for rejection. + lmt.SetOnLimitReached(func(w http.ResponseWriter, r *http.Request) { fmt.Println("A request was rejected") }) + ``` + +6. Tollbooth does not require external storage since it uses an algorithm called [Token Bucket](http://en.wikipedia.org/wiki/Token_bucket) [(Go library: golang.org/x/time/rate)](//godoc.org/golang.org/x/time/rate). + + +## Other Web Frameworks + +Sometimes, other frameworks require a little bit of shim to use Tollbooth. These shims below are contributed by the community, so I make no promises on how well they work. The one I am familiar with are: Chi, Gin, and Negroni. + +* [Chi](https://github.com/didip/tollbooth_chi) + +* [Echo](https://github.com/didip/tollbooth_echo) + +* [FastHTTP](https://github.com/didip/tollbooth_fasthttp) + +* [Gin](https://github.com/didip/tollbooth_gin) + +* [GoRestful](https://github.com/didip/tollbooth_gorestful) + +* [HTTPRouter](https://github.com/didip/tollbooth_httprouter) + +* [Iris](https://github.com/didip/tollbooth_iris) + +* [Negroni](https://github.com/didip/tollbooth_negroni) + + +## My other Go libraries + +* [Stopwatch](https://github.com/didip/stopwatch): A small library to measure latency of things. Useful if you want to report latency data to Graphite. + +* [Gomet](https://github.com/didip/gomet): Simple HTTP client & server long poll library for Go. Useful for receiving live updates without needing Websocket. diff --git a/vendor/github.com/didip/tollbooth/config/config.go b/vendor/github.com/didip/tollbooth/config/config.go deleted file mode 100644 index a95257a4..00000000 --- a/vendor/github.com/didip/tollbooth/config/config.go +++ /dev/null @@ -1,76 +0,0 @@ -// Package config provides data structure to configure rate-limiter. -package config - -import ( - "github.com/juju/ratelimit" - "sync" - "time" -) - -// NewLimiter is a constructor for Limiter. -func NewLimiter(max int64, ttl time.Duration) *Limiter { - limiter := &Limiter{Max: max, TTL: ttl} - limiter.MessageContentType = "text/plain; charset=utf-8" - limiter.Message = "You have reached maximum request limit." - limiter.StatusCode = 429 - limiter.tokenBuckets = make(map[string]*ratelimit.Bucket) - limiter.IPLookups = []string{"RemoteAddr", "X-Forwarded-For", "X-Real-IP"} - - return limiter -} - -// Limiter is a config struct to limit a particular request handler. -type Limiter struct { - // HTTP message when limit is reached. - Message string - - // Content-Type for Message - MessageContentType string - - // HTTP status code when limit is reached. - StatusCode int - - // Maximum number of requests to limit per duration. - Max int64 - - // Duration of rate-limiter. - TTL time.Duration - - // List of places to look up IP address. - // Default is "RemoteAddr", "X-Forwarded-For", "X-Real-IP". - // You can rearrange the order as you like. - IPLookups []string - - // List of HTTP Methods to limit (GET, POST, PUT, etc.). - // Empty means limit all methods. - Methods []string - - // List of HTTP headers to limit. - // Empty means skip headers checking. - Headers map[string][]string - - // List of basic auth usernames to limit. - BasicAuthUsers []string - - // Throttler struct - tokenBuckets map[string]*ratelimit.Bucket - - sync.RWMutex -} - -// LimitReached returns a bool indicating if the Bucket identified by key ran out of tokens. -func (l *Limiter) LimitReached(key string) bool { - l.Lock() - if _, found := l.tokenBuckets[key]; !found { - l.tokenBuckets[key] = ratelimit.NewBucket(l.TTL, l.Max) - } - - _, isSoonerThanMaxWait := l.tokenBuckets[key].TakeMaxDuration(1, 0) - l.Unlock() - - if isSoonerThanMaxWait { - return false - } - - return true -} diff --git a/vendor/github.com/didip/tollbooth/config/config_benchmark_test.go b/vendor/github.com/didip/tollbooth/config/config_benchmark_test.go deleted file mode 100644 index 77ae5672..00000000 --- a/vendor/github.com/didip/tollbooth/config/config_benchmark_test.go +++ /dev/null @@ -1,15 +0,0 @@ -package config - -import ( - "testing" - "time" -) - -func BenchmarkLimitReached(b *testing.B) { - limiter := NewLimiter(1, time.Second) - key := "127.0.0.1|/" - - for i := 0; i < b.N; i++ { - limiter.LimitReached(key) - } -} diff --git a/vendor/github.com/didip/tollbooth/config/config_test.go b/vendor/github.com/didip/tollbooth/config/config_test.go deleted file mode 100644 index 7b3b3ab8..00000000 --- a/vendor/github.com/didip/tollbooth/config/config_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package config - -import ( - "testing" - "time" -) - -func TestConstructor(t *testing.T) { - limiter := NewLimiter(1, time.Second) - if limiter.Max != 1 { - t.Errorf("Max field is incorrect. Value: %v", limiter.Max) - } - if limiter.TTL != time.Second { - t.Errorf("TTL field is incorrect. Value: %v", limiter.TTL) - } - if limiter.Message != "You have reached maximum request limit." { - t.Errorf("Message field is incorrect. Value: %v", limiter.Message) - } - if limiter.StatusCode != 429 { - t.Errorf("StatusCode field is incorrect. Value: %v", limiter.StatusCode) - } -} - -func TestLimitReached(t *testing.T) { - limiter := NewLimiter(1, time.Second) - key := "127.0.0.1|/" - - if limiter.LimitReached(key) == true { - t.Error("First time count should not reached the limit.") - } - - if limiter.LimitReached(key) == false { - t.Error("Second time count should return true because it exceeds 1 request per second.") - } - - <-time.After(1 * time.Second) - if limiter.LimitReached(key) == true { - t.Error("Third time count should not reached the limit because the 1 second window has passed.") - } -} - -func TestMuchHigherMaxRequests(t *testing.T) { - numRequests := 1000 - limiter := NewLimiter(int64(numRequests), time.Second) - key := "127.0.0.1|/" - - for i := 0; i < numRequests; i++ { - if limiter.LimitReached(key) == true { - t.Errorf("N(%v) limit should not be reached.", i) - } - } - - if limiter.LimitReached(key) == false { - t.Errorf("N(%v) limit should be reached because it exceeds %v request per second.", numRequests+2, numRequests) - } - -} diff --git a/vendor/github.com/didip/tollbooth/errors/errors_test.go b/vendor/github.com/didip/tollbooth/errors/errors_test.go deleted file mode 100644 index a5d04aec..00000000 --- a/vendor/github.com/didip/tollbooth/errors/errors_test.go +++ /dev/null @@ -1,10 +0,0 @@ -package errors - -import "testing" - -func TestError(t *testing.T) { - errs := HTTPError{"blah", 429} - if errs.Error() == "" { - t.Errorf("Unable to print Error(). Value: %v", errs.Error()) - } -} diff --git a/vendor/github.com/didip/tollbooth/libstring/libstring.go b/vendor/github.com/didip/tollbooth/libstring/libstring.go index 8e6a356b..fef29afe 100644 --- a/vendor/github.com/didip/tollbooth/libstring/libstring.go +++ b/vendor/github.com/didip/tollbooth/libstring/libstring.go @@ -2,6 +2,7 @@ package libstring import ( + "net" "net/http" "strings" ) @@ -16,22 +17,20 @@ func StringInSlice(sliceString []string, needle string) bool { return false } -func ipAddrFromRemoteAddr(s string) string { - idx := strings.LastIndex(s, ":") - if idx == -1 { - return s - } - return s[:idx] -} - // RemoteIP finds IP Address given http.Request struct. -func RemoteIP(ipLookups []string, r *http.Request) string { +func RemoteIP(ipLookups []string, forwardedForIndexFromBehind int, r *http.Request) string { realIP := r.Header.Get("X-Real-IP") forwardedFor := r.Header.Get("X-Forwarded-For") for _, lookup := range ipLookups { if lookup == "RemoteAddr" { - return ipAddrFromRemoteAddr(r.RemoteAddr) + // 1. Cover the basic use cases for both ipv4 and ipv6 + ip, _, err := net.SplitHostPort(r.RemoteAddr) + if err != nil { + // 2. Upon error, just return the remote addr. + return r.RemoteAddr + } + return ip } if lookup == "X-Forwarded-For" && forwardedFor != "" { // X-Forwarded-For is potentially a list of addresses separated with "," @@ -39,7 +38,13 @@ func RemoteIP(ipLookups []string, r *http.Request) string { for i, p := range parts { parts[i] = strings.TrimSpace(p) } - return parts[0] + + partIndex := len(parts) - 1 - forwardedForIndexFromBehind + if partIndex < 0 { + partIndex = 0 + } + + return parts[partIndex] } if lookup == "X-Real-IP" && realIP != "" { return realIP diff --git a/vendor/github.com/didip/tollbooth/libstring/libstring_test.go b/vendor/github.com/didip/tollbooth/libstring/libstring_test.go deleted file mode 100644 index f11245af..00000000 --- a/vendor/github.com/didip/tollbooth/libstring/libstring_test.go +++ /dev/null @@ -1,81 +0,0 @@ -package libstring - -import ( - "net/http" - "strings" - "testing" -) - -func TestStringInSlice(t *testing.T) { - if StringInSlice([]string{"alice", "dan", "didip", "jason", "karl"}, "brotato") { - t.Error("brotato should not be in slice.") - } -} - -func TestIPAddrFromRemoteAddr(t *testing.T) { - if ipAddrFromRemoteAddr("127.0.0.1:8989") != "127.0.0.1" { - t.Errorf("ipAddrFromRemoteAddr did not chop the port number correctly.") - } -} - -func TestRemoteIPDefault(t *testing.T) { - ipLookups := []string{"RemoteAddr", "X-Real-IP"} - ipv6 := "2601:7:1c82:4097:59a0:a80b:2841:b8c8" - - request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!")) - if err != nil { - t.Errorf("Unable to create new HTTP request. Error: %v", err) - } - - request.Header.Set("X-Real-IP", ipv6) - - ip := RemoteIP(ipLookups, request) - if ip != request.RemoteAddr { - t.Errorf("Did not get the right IP. IP: %v", ip) - } - if ip == ipv6 { - t.Errorf("X-Real-IP should have been skipped. IP: %v", ip) - } -} - -func TestRemoteIPForwardedFor(t *testing.T) { - ipLookups := []string{"X-Forwarded-For", "X-Real-IP", "RemoteAddr"} - ipv6 := "2601:7:1c82:4097:59a0:a80b:2841:b8c8" - - request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!")) - if err != nil { - t.Errorf("Unable to create new HTTP request. Error: %v", err) - } - - request.Header.Set("X-Forwarded-For", "54.223.11.104") - request.Header.Set("X-Real-IP", ipv6) - - ip := RemoteIP(ipLookups, request) - if ip != "54.223.11.104" { - t.Errorf("Did not get the right IP. IP: %v", ip) - } - if ip == ipv6 { - t.Errorf("X-Real-IP should have been skipped. IP: %v", ip) - } -} - -func TestRemoteIPRealIP(t *testing.T) { - ipLookups := []string{"X-Real-IP", "X-Forwarded-For", "RemoteAddr"} - ipv6 := "2601:7:1c82:4097:59a0:a80b:2841:b8c8" - - request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!")) - if err != nil { - t.Errorf("Unable to create new HTTP request. Error: %v", err) - } - - request.Header.Set("X-Forwarded-For", "54.223.11.104") - request.Header.Set("X-Real-IP", ipv6) - - ip := RemoteIP(ipLookups, request) - if ip != ipv6 { - t.Errorf("Did not get the right IP. IP: %v", ip) - } - if ip == "54.223.11.104" { - t.Errorf("X-Forwarded-For should have been skipped. IP: %v", ip) - } -} diff --git a/vendor/github.com/didip/tollbooth/limiter/limiter.go b/vendor/github.com/didip/tollbooth/limiter/limiter.go new file mode 100644 index 00000000..1d6cfdd5 --- /dev/null +++ b/vendor/github.com/didip/tollbooth/limiter/limiter.go @@ -0,0 +1,474 @@ +// Package limiter provides data structure to configure rate-limiter. +package limiter + +import ( + "net/http" + "sync" + "time" + + gocache "github.com/patrickmn/go-cache" + "golang.org/x/time/rate" +) + +// New is a constructor for Limiter. +func New(generalExpirableOptions *ExpirableOptions) *Limiter { + lmt := &Limiter{} + + lmt.SetMessageContentType("text/plain; charset=utf-8"). + SetMessage("You have reached maximum request limit."). + SetStatusCode(429). + SetOnLimitReached(nil). + SetIPLookups([]string{"RemoteAddr", "X-Forwarded-For", "X-Real-IP"}). + SetForwardedForIndexFromBehind(0). + SetHeaders(make(map[string][]string)) + + if generalExpirableOptions != nil { + lmt.generalExpirableOptions = generalExpirableOptions + } else { + lmt.generalExpirableOptions = &ExpirableOptions{} + } + + // Default for ExpireJobInterval is every minute. + if lmt.generalExpirableOptions.ExpireJobInterval <= 0 { + lmt.generalExpirableOptions.ExpireJobInterval = time.Minute + } + + // Default for DefaultExpirationTTL is 10 years. + if lmt.generalExpirableOptions.DefaultExpirationTTL <= 0 { + lmt.generalExpirableOptions.DefaultExpirationTTL = 87600 * time.Hour + } + + lmt.tokenBuckets = gocache.New( + lmt.generalExpirableOptions.DefaultExpirationTTL, + lmt.generalExpirableOptions.ExpireJobInterval, + ) + + lmt.basicAuthUsers = gocache.New( + lmt.generalExpirableOptions.DefaultExpirationTTL, + lmt.generalExpirableOptions.ExpireJobInterval, + ) + + return lmt +} + +// Limiter is a config struct to limit a particular request handler. +type Limiter struct { + // Maximum number of requests to limit per second. + max float64 + + // Limiter burst size + burst int + + // HTTP message when limit is reached. + message string + + // Content-Type for Message + messageContentType string + + // HTTP status code when limit is reached. + statusCode int + + // A function to call when a request is rejected. + onLimitReached func(w http.ResponseWriter, r *http.Request) + + // List of places to look up IP address. + // Default is "RemoteAddr", "X-Forwarded-For", "X-Real-IP". + // You can rearrange the order as you like. + ipLookups []string + + forwardedForIndex int + + // List of HTTP Methods to limit (GET, POST, PUT, etc.). + // Empty means limit all methods. + methods []string + + // Able to configure token bucket expirations. + generalExpirableOptions *ExpirableOptions + + // List of basic auth usernames to limit. + basicAuthUsers *gocache.Cache + + // Map of HTTP headers to limit. + // Empty means skip headers checking. + headers map[string]*gocache.Cache + + // Map of limiters with TTL + tokenBuckets *gocache.Cache + + tokenBucketExpirationTTL time.Duration + basicAuthExpirationTTL time.Duration + headerEntryExpirationTTL time.Duration + + sync.RWMutex +} + +// SetTokenBucketExpirationTTL is thread-safe way of setting custom token bucket expiration TTL. +func (l *Limiter) SetTokenBucketExpirationTTL(ttl time.Duration) *Limiter { + l.Lock() + l.tokenBucketExpirationTTL = ttl + l.Unlock() + + return l +} + +// GettokenBucketExpirationTTL is thread-safe way of getting custom token bucket expiration TTL. +func (l *Limiter) GetTokenBucketExpirationTTL() time.Duration { + l.RLock() + defer l.RUnlock() + return l.tokenBucketExpirationTTL +} + +// SetBasicAuthExpirationTTL is thread-safe way of setting custom basic auth expiration TTL. +func (l *Limiter) SetBasicAuthExpirationTTL(ttl time.Duration) *Limiter { + l.Lock() + l.basicAuthExpirationTTL = ttl + l.Unlock() + + return l +} + +// GetBasicAuthExpirationTTL is thread-safe way of getting custom basic auth expiration TTL. +func (l *Limiter) GetBasicAuthExpirationTTL() time.Duration { + l.RLock() + defer l.RUnlock() + return l.basicAuthExpirationTTL +} + +// SetHeaderEntryExpirationTTL is thread-safe way of setting custom basic auth expiration TTL. +func (l *Limiter) SetHeaderEntryExpirationTTL(ttl time.Duration) *Limiter { + l.Lock() + l.headerEntryExpirationTTL = ttl + l.Unlock() + + return l +} + +// GetHeaderEntryExpirationTTL is thread-safe way of getting custom basic auth expiration TTL. +func (l *Limiter) GetHeaderEntryExpirationTTL() time.Duration { + l.RLock() + defer l.RUnlock() + return l.headerEntryExpirationTTL +} + +// SetMax is thread-safe way of setting maximum number of requests to limit per duration. +func (l *Limiter) SetMax(max float64) *Limiter { + l.Lock() + l.max = max + l.Unlock() + + return l +} + +// GetMax is thread-safe way of getting maximum number of requests to limit per duration. +func (l *Limiter) GetMax() float64 { + l.RLock() + defer l.RUnlock() + return l.max +} + +// SetBurst is thread-safe way of setting maximum burst size. +func (l *Limiter) SetBurst(burst int) *Limiter { + l.Lock() + l.burst = burst + l.Unlock() + + return l +} + +// GetBurst is thread-safe way of setting maximum burst size. +func (l *Limiter) GetBurst() int { + l.RLock() + defer l.RUnlock() + + return l.burst +} + +// SetMessage is thread-safe way of setting HTTP message when limit is reached. +func (l *Limiter) SetMessage(msg string) *Limiter { + l.Lock() + l.message = msg + l.Unlock() + + return l +} + +// GetMessage is thread-safe way of getting HTTP message when limit is reached. +func (l *Limiter) GetMessage() string { + l.RLock() + defer l.RUnlock() + return l.message +} + +// SetMessageContentType is thread-safe way of setting HTTP message Content-Type when limit is reached. +func (l *Limiter) SetMessageContentType(contentType string) *Limiter { + l.Lock() + l.messageContentType = contentType + l.Unlock() + + return l +} + +// GetMessageContentType is thread-safe way of getting HTTP message Content-Type when limit is reached. +func (l *Limiter) GetMessageContentType() string { + l.RLock() + defer l.RUnlock() + return l.messageContentType +} + +// SetStatusCode is thread-safe way of setting HTTP status code when limit is reached. +func (l *Limiter) SetStatusCode(statusCode int) *Limiter { + l.Lock() + l.statusCode = statusCode + l.Unlock() + + return l +} + +// GetStatusCode is thread-safe way of getting HTTP status code when limit is reached. +func (l *Limiter) GetStatusCode() int { + l.RLock() + defer l.RUnlock() + return l.statusCode +} + +// SetOnLimitReached is thread-safe way of setting after-rejection function when limit is reached. +func (l *Limiter) SetOnLimitReached(fn func(w http.ResponseWriter, r *http.Request)) *Limiter { + l.Lock() + l.onLimitReached = fn + l.Unlock() + + return l +} + +// ExecOnLimitReached is thread-safe way of executing after-rejection function when limit is reached. +func (l *Limiter) ExecOnLimitReached(w http.ResponseWriter, r *http.Request) { + l.RLock() + defer l.RUnlock() + + fn := l.onLimitReached + if fn != nil { + fn(w, r) + } +} + +// SetIPLookups is thread-safe way of setting list of places to look up IP address. +func (l *Limiter) SetIPLookups(ipLookups []string) *Limiter { + l.Lock() + l.ipLookups = ipLookups + l.Unlock() + + return l +} + +// GetIPLookups is thread-safe way of getting list of places to look up IP address. +func (l *Limiter) GetIPLookups() []string { + l.RLock() + defer l.RUnlock() + return l.ipLookups +} + +// SetForwardedForIndexFromBehind is thread-safe way of setting which X-Forwarded-For index to choose. +func (l *Limiter) SetForwardedForIndexFromBehind(forwardedForIndex int) *Limiter { + l.Lock() + l.forwardedForIndex = forwardedForIndex + l.Unlock() + + return l +} + +// GetForwardedForIndexFromBehind is thread-safe way of getting which X-Forwarded-For index to choose. +func (l *Limiter) GetForwardedForIndexFromBehind() int { + l.RLock() + defer l.RUnlock() + return l.forwardedForIndex +} + +// SetMethods is thread-safe way of setting list of HTTP Methods to limit (GET, POST, PUT, etc.). +func (l *Limiter) SetMethods(methods []string) *Limiter { + l.Lock() + l.methods = methods + l.Unlock() + + return l +} + +// GetMethods is thread-safe way of getting list of HTTP Methods to limit (GET, POST, PUT, etc.). +func (l *Limiter) GetMethods() []string { + l.RLock() + defer l.RUnlock() + return l.methods +} + +// SetBasicAuthUsers is thread-safe way of setting list of basic auth usernames to limit. +func (l *Limiter) SetBasicAuthUsers(basicAuthUsers []string) *Limiter { + ttl := l.GetBasicAuthExpirationTTL() + if ttl <= 0 { + ttl = l.generalExpirableOptions.DefaultExpirationTTL + } + + for _, basicAuthUser := range basicAuthUsers { + l.basicAuthUsers.Set(basicAuthUser, true, ttl) + } + + return l +} + +// GetBasicAuthUsers is thread-safe way of getting list of basic auth usernames to limit. +func (l *Limiter) GetBasicAuthUsers() []string { + asMap := l.basicAuthUsers.Items() + + var basicAuthUsers []string + for basicAuthUser, _ := range asMap { + basicAuthUsers = append(basicAuthUsers, basicAuthUser) + } + + return basicAuthUsers +} + +// RemoveBasicAuthUsers is thread-safe way of removing basic auth usernames from existing list. +func (l *Limiter) RemoveBasicAuthUsers(basicAuthUsers []string) *Limiter { + for _, toBeRemoved := range basicAuthUsers { + l.basicAuthUsers.Delete(toBeRemoved) + } + + return l +} + +// SetHeaders is thread-safe way of setting map of HTTP headers to limit. +func (l *Limiter) SetHeaders(headers map[string][]string) *Limiter { + if l.headers == nil { + l.headers = make(map[string]*gocache.Cache) + } + + for header, entries := range headers { + l.SetHeader(header, entries) + } + + return l +} + +// GetHeaders is thread-safe way of getting map of HTTP headers to limit. +func (l *Limiter) GetHeaders() map[string][]string { + results := make(map[string][]string) + + l.RLock() + defer l.RUnlock() + + for header, entriesAsGoCache := range l.headers { + entries := make([]string, 0) + + for entry, _ := range entriesAsGoCache.Items() { + entries = append(entries, entry) + } + + results[header] = entries + } + + return results +} + +// SetHeader is thread-safe way of setting entries of 1 HTTP header. +func (l *Limiter) SetHeader(header string, entries []string) *Limiter { + l.RLock() + existing, found := l.headers[header] + l.RUnlock() + + ttl := l.GetHeaderEntryExpirationTTL() + if ttl <= 0 { + ttl = l.generalExpirableOptions.DefaultExpirationTTL + } + + if !found { + existing = gocache.New(ttl, l.generalExpirableOptions.ExpireJobInterval) + } + + for _, entry := range entries { + existing.Set(entry, true, ttl) + } + + l.Lock() + l.headers[header] = existing + l.Unlock() + + return l +} + +// GetHeader is thread-safe way of getting entries of 1 HTTP header. +func (l *Limiter) GetHeader(header string) []string { + l.RLock() + entriesAsGoCache := l.headers[header] + l.RUnlock() + + entriesAsMap := entriesAsGoCache.Items() + entries := make([]string, 0) + + for entry, _ := range entriesAsMap { + entries = append(entries, entry) + } + + return entries +} + +// RemoveHeader is thread-safe way of removing entries of 1 HTTP header. +func (l *Limiter) RemoveHeader(header string) *Limiter { + ttl := l.GetHeaderEntryExpirationTTL() + if ttl <= 0 { + ttl = l.generalExpirableOptions.DefaultExpirationTTL + } + + l.Lock() + l.headers[header] = gocache.New(ttl, l.generalExpirableOptions.ExpireJobInterval) + l.Unlock() + + return l +} + +// RemoveHeaderEntries is thread-safe way of adding new entries to 1 HTTP header rule. +func (l *Limiter) RemoveHeaderEntries(header string, entriesForRemoval []string) *Limiter { + l.RLock() + entries, found := l.headers[header] + l.RUnlock() + + if !found { + return l + } + + for _, toBeRemoved := range entriesForRemoval { + entries.Delete(toBeRemoved) + } + + return l +} + +func (l *Limiter) limitReachedWithTokenBucketTTL(key string, tokenBucketTTL time.Duration) bool { + lmtMax := l.GetMax() + lmtBurst := l.GetBurst() + l.Lock() + defer l.Unlock() + + if _, found := l.tokenBuckets.Get(key); !found { + l.tokenBuckets.Set( + key, + rate.NewLimiter(rate.Limit(lmtMax), lmtBurst), + tokenBucketTTL, + ) + } + + expiringMap, found := l.tokenBuckets.Get(key) + if !found { + return false + } + + return !expiringMap.(*rate.Limiter).Allow() +} + +// LimitReached returns a bool indicating if the Bucket identified by key ran out of tokens. +func (l *Limiter) LimitReached(key string) bool { + ttl := l.GetTokenBucketExpirationTTL() + + if ttl <= 0 { + ttl = l.generalExpirableOptions.DefaultExpirationTTL + } + + return l.limitReachedWithTokenBucketTTL(key, ttl) +} diff --git a/vendor/github.com/didip/tollbooth/limiter/limiter_options.go b/vendor/github.com/didip/tollbooth/limiter/limiter_options.go new file mode 100644 index 00000000..9836c502 --- /dev/null +++ b/vendor/github.com/didip/tollbooth/limiter/limiter_options.go @@ -0,0 +1,12 @@ +package limiter + +import ( + "time" +) + +type ExpirableOptions struct { + DefaultExpirationTTL time.Duration + + // How frequently expire job triggers + ExpireJobInterval time.Duration +} diff --git a/vendor/github.com/didip/tollbooth/tollbooth.go b/vendor/github.com/didip/tollbooth/tollbooth.go index 1477db86..c023db26 100644 --- a/vendor/github.com/didip/tollbooth/tollbooth.go +++ b/vendor/github.com/didip/tollbooth/tollbooth.go @@ -2,48 +2,42 @@ package tollbooth import ( - "github.com/didip/tollbooth/config" - "github.com/didip/tollbooth/errors" - "github.com/didip/tollbooth/libstring" "net/http" "strings" - "time" + + "fmt" + "github.com/didip/tollbooth/errors" + "github.com/didip/tollbooth/libstring" + "github.com/didip/tollbooth/limiter" + "math" ) -// NewLimiter is a convenience function to config.NewLimiter. -func NewLimiter(max int64, ttl time.Duration) *config.Limiter { - return config.NewLimiter(max, ttl) +// setResponseHeaders configures X-Rate-Limit-Limit and X-Rate-Limit-Duration +func setResponseHeaders(lmt *limiter.Limiter, w http.ResponseWriter, r *http.Request) { + w.Header().Add("X-Rate-Limit-Limit", fmt.Sprintf("%.2f", lmt.GetMax())) + w.Header().Add("X-Rate-Limit-Duration", "1") + w.Header().Add("X-Rate-Limit-Request-Forwarded-For", r.Header.Get("X-Forwarded-For")) + w.Header().Add("X-Rate-Limit-Request-Remote-Addr", r.RemoteAddr) +} + +// NewLimiter is a convenience function to limiter.New. +func NewLimiter(max float64, tbOptions *limiter.ExpirableOptions) *limiter.Limiter { + return limiter.New(tbOptions).SetMax(max).SetBurst(int(math.Max(1, max))) } // LimitByKeys keeps track number of request made by keys separated by pipe. // It returns HTTPError when limit is exceeded. -func LimitByKeys(limiter *config.Limiter, keys []string) *errors.HTTPError { - if limiter.LimitReached(strings.Join(keys, "|")) { - return &errors.HTTPError{Message: limiter.Message, StatusCode: limiter.StatusCode} +func LimitByKeys(lmt *limiter.Limiter, keys []string) *errors.HTTPError { + if lmt.LimitReached(strings.Join(keys, "|")) { + return &errors.HTTPError{Message: lmt.GetMessage(), StatusCode: lmt.GetStatusCode()} } return nil } -// LimitByRequest builds keys based on http.Request struct, -// loops through all the keys, and check if any one of them returns HTTPError. -func LimitByRequest(limiter *config.Limiter, r *http.Request) *errors.HTTPError { - sliceKeys := BuildKeys(limiter, r) - - // Loop sliceKeys and check if one of them has error. - for _, keys := range sliceKeys { - httpError := LimitByKeys(limiter, keys) - if httpError != nil { - return httpError - } - } - - return nil -} - -// BuildKeys generates a slice of keys to rate-limit by given config and request structs. -func BuildKeys(limiter *config.Limiter, r *http.Request) [][]string { - remoteIP := libstring.RemoteIP(limiter.IPLookups, r) +// BuildKeys generates a slice of keys to rate-limit by given limiter and request structs. +func BuildKeys(lmt *limiter.Limiter, r *http.Request) [][]string { + remoteIP := libstring.RemoteIP(lmt.GetIPLookups(), lmt.GetForwardedForIndexFromBehind(), r) path := r.URL.Path sliceKeys := make([][]string, 0) @@ -52,14 +46,21 @@ func BuildKeys(limiter *config.Limiter, r *http.Request) [][]string { return sliceKeys } - if limiter.Methods != nil && limiter.Headers != nil && limiter.BasicAuthUsers != nil { + lmtMethods := lmt.GetMethods() + lmtHeaders := lmt.GetHeaders() + lmtBasicAuthUsers := lmt.GetBasicAuthUsers() + + lmtHeadersIsSet := len(lmtHeaders) > 0 + lmtBasicAuthUsersIsSet := len(lmtBasicAuthUsers) > 0 + + if lmtMethods != nil && lmtHeadersIsSet && lmtBasicAuthUsersIsSet { // Limit by HTTP methods and HTTP headers+values and Basic Auth credentials. - if libstring.StringInSlice(limiter.Methods, r.Method) { - for headerKey, headerValues := range limiter.Headers { + if libstring.StringInSlice(lmtMethods, r.Method) { + for headerKey, headerValues := range lmtHeaders { if (headerValues == nil || len(headerValues) <= 0) && r.Header.Get(headerKey) != "" { // If header values are empty, rate-limit all request with headerKey. username, _, ok := r.BasicAuth() - if ok && libstring.StringInSlice(limiter.BasicAuthUsers, username) { + if ok && libstring.StringInSlice(lmtBasicAuthUsers, username) { sliceKeys = append(sliceKeys, []string{remoteIP, path, r.Method, headerKey, username}) } @@ -67,7 +68,7 @@ func BuildKeys(limiter *config.Limiter, r *http.Request) [][]string { // If header values are not empty, rate-limit all request with headerKey and headerValues. for _, headerValue := range headerValues { username, _, ok := r.BasicAuth() - if ok && libstring.StringInSlice(limiter.BasicAuthUsers, username) { + if ok && libstring.StringInSlice(lmtBasicAuthUsers, username) { sliceKeys = append(sliceKeys, []string{remoteIP, path, r.Method, headerKey, headerValue, username}) } } @@ -75,10 +76,10 @@ func BuildKeys(limiter *config.Limiter, r *http.Request) [][]string { } } - } else if limiter.Methods != nil && limiter.Headers != nil { + } else if lmtMethods != nil && lmtHeadersIsSet { // Limit by HTTP methods and HTTP headers+values. - if libstring.StringInSlice(limiter.Methods, r.Method) { - for headerKey, headerValues := range limiter.Headers { + if libstring.StringInSlice(lmtMethods, r.Method) { + for headerKey, headerValues := range lmtHeaders { if (headerValues == nil || len(headerValues) <= 0) && r.Header.Get(headerKey) != "" { // If header values are empty, rate-limit all request with headerKey. sliceKeys = append(sliceKeys, []string{remoteIP, path, r.Method, headerKey}) @@ -92,24 +93,24 @@ func BuildKeys(limiter *config.Limiter, r *http.Request) [][]string { } } - } else if limiter.Methods != nil && limiter.BasicAuthUsers != nil { + } else if lmtMethods != nil && lmtBasicAuthUsersIsSet { // Limit by HTTP methods and Basic Auth credentials. - if libstring.StringInSlice(limiter.Methods, r.Method) { + if libstring.StringInSlice(lmtMethods, r.Method) { username, _, ok := r.BasicAuth() - if ok && libstring.StringInSlice(limiter.BasicAuthUsers, username) { + if ok && libstring.StringInSlice(lmtBasicAuthUsers, username) { sliceKeys = append(sliceKeys, []string{remoteIP, path, r.Method, username}) } } - } else if limiter.Methods != nil { + } else if lmtMethods != nil { // Limit by HTTP methods. - if libstring.StringInSlice(limiter.Methods, r.Method) { + if libstring.StringInSlice(lmtMethods, r.Method) { sliceKeys = append(sliceKeys, []string{remoteIP, path, r.Method}) } - } else if limiter.Headers != nil { + } else if lmtHeadersIsSet { // Limit by HTTP headers+values. - for headerKey, headerValues := range limiter.Headers { + for headerKey, headerValues := range lmtHeaders { if (headerValues == nil || len(headerValues) <= 0) && r.Header.Get(headerKey) != "" { // If header values are empty, rate-limit all request with headerKey. sliceKeys = append(sliceKeys, []string{remoteIP, path, headerKey}) @@ -122,10 +123,10 @@ func BuildKeys(limiter *config.Limiter, r *http.Request) [][]string { } } - } else if limiter.BasicAuthUsers != nil { + } else if lmtBasicAuthUsersIsSet { // Limit by Basic Auth credentials. username, _, ok := r.BasicAuth() - if ok && libstring.StringInSlice(limiter.BasicAuthUsers, username) { + if ok && libstring.StringInSlice(lmtBasicAuthUsers, username) { sliceKeys = append(sliceKeys, []string{remoteIP, path, username}) } } else { @@ -136,12 +137,31 @@ func BuildKeys(limiter *config.Limiter, r *http.Request) [][]string { return sliceKeys } -// LimitHandler is a middleware that performs rate-limiting given http.Handler struct. -func LimitHandler(limiter *config.Limiter, next http.Handler) http.Handler { - middle := func(w http.ResponseWriter, r *http.Request) { - httpError := LimitByRequest(limiter, r) +// LimitByRequest builds keys based on http.Request struct, +// loops through all the keys, and check if any one of them returns HTTPError. +func LimitByRequest(lmt *limiter.Limiter, w http.ResponseWriter, r *http.Request) *errors.HTTPError { + setResponseHeaders(lmt, w, r) + + sliceKeys := BuildKeys(lmt, r) + + // Loop sliceKeys and check if one of them has error. + for _, keys := range sliceKeys { + httpError := LimitByKeys(lmt, keys) if httpError != nil { - w.Header().Add("Content-Type", limiter.MessageContentType) + return httpError + } + } + + return nil +} + +// LimitHandler is a middleware that performs rate-limiting given http.Handler struct. +func LimitHandler(lmt *limiter.Limiter, next http.Handler) http.Handler { + middle := func(w http.ResponseWriter, r *http.Request) { + httpError := LimitByRequest(lmt, w, r) + if httpError != nil { + lmt.ExecOnLimitReached(w, r) + w.Header().Add("Content-Type", lmt.GetMessageContentType()) w.WriteHeader(httpError.StatusCode) w.Write([]byte(httpError.Message)) return @@ -155,6 +175,6 @@ func LimitHandler(limiter *config.Limiter, next http.Handler) http.Handler { } // LimitFuncHandler is a middleware that performs rate-limiting given request handler function. -func LimitFuncHandler(limiter *config.Limiter, nextFunc func(http.ResponseWriter, *http.Request)) http.Handler { - return LimitHandler(limiter, http.HandlerFunc(nextFunc)) +func LimitFuncHandler(lmt *limiter.Limiter, nextFunc func(http.ResponseWriter, *http.Request)) http.Handler { + return LimitHandler(lmt, http.HandlerFunc(nextFunc)) } diff --git a/vendor/github.com/didip/tollbooth/tollbooth_benchmark_test.go b/vendor/github.com/didip/tollbooth/tollbooth_benchmark_test.go deleted file mode 100644 index 9136ec36..00000000 --- a/vendor/github.com/didip/tollbooth/tollbooth_benchmark_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package tollbooth - -import ( - "fmt" - "net/http" - "strings" - "testing" - "time" -) - -func BenchmarkLimitByKeys(b *testing.B) { - limiter := NewLimiter(1, time.Second) // Only 1 request per second is allowed. - - for i := 0; i < b.N; i++ { - LimitByKeys(limiter, []string{"127.0.0.1", "/"}) - } -} - -func BenchmarkBuildKeys(b *testing.B) { - limiter := NewLimiter(1, time.Second) - - request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!")) - if err != nil { - fmt.Printf("Unable to create new HTTP request. Error: %v", err) - } - - request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8") - for i := 0; i < b.N; i++ { - sliceKeys := BuildKeys(limiter, request) - if len(sliceKeys) == 0 { - fmt.Print("Length of sliceKeys should never be empty.") - } - } -} diff --git a/vendor/github.com/didip/tollbooth/tollbooth_test.go b/vendor/github.com/didip/tollbooth/tollbooth_test.go deleted file mode 100644 index c7792d1b..00000000 --- a/vendor/github.com/didip/tollbooth/tollbooth_test.go +++ /dev/null @@ -1,266 +0,0 @@ -package tollbooth - -import ( - "net/http" - "strings" - "testing" - "time" -) - -func TestLimitByKeys(t *testing.T) { - limiter := NewLimiter(1, time.Second) // Only 1 request per second is allowed. - - httperror := LimitByKeys(limiter, []string{"127.0.0.1", "/"}) - if httperror != nil { - t.Errorf("First time count should not return error. Error: %v", httperror.Error()) - } - - httperror = LimitByKeys(limiter, []string{"127.0.0.1", "/"}) - if httperror == nil { - t.Errorf("Second time count should return error because it exceeds 1 request per second.") - } - - <-time.After(1 * time.Second) - httperror = LimitByKeys(limiter, []string{"127.0.0.1", "/"}) - if httperror != nil { - t.Errorf("Third time count should not return error because the 1 second window has passed.") - } -} - -func TestDefaultBuildKeys(t *testing.T) { - limiter := NewLimiter(1, time.Second) - limiter.IPLookups = []string{"X-Forwarded-For", "X-Real-IP", "RemoteAddr"} - - request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!")) - if err != nil { - t.Errorf("Unable to create new HTTP request. Error: %v", err) - } - - request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8") - - sliceKeys := BuildKeys(limiter, request) - if len(sliceKeys) == 0 { - t.Error("Length of sliceKeys should never be empty.") - } - - for _, keys := range sliceKeys { - for i, keyChunk := range keys { - if i == 0 && keyChunk != request.Header.Get("X-Real-IP") { - t.Errorf("The first chunk should be remote IP. KeyChunk: %v", keyChunk) - } - if i == 1 && keyChunk != request.URL.Path { - t.Errorf("The second chunk should be request path. KeyChunk: %v", keyChunk) - } - } - } -} - -func TestBasicAuthBuildKeys(t *testing.T) { - limiter := NewLimiter(1, time.Second) - limiter.BasicAuthUsers = []string{"bro"} - - request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!")) - if err != nil { - t.Errorf("Unable to create new HTTP request. Error: %v", err) - } - - request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8") - - request.SetBasicAuth("bro", "tato") - - for _, keys := range BuildKeys(limiter, request) { - if len(keys) != 3 { - t.Error("Keys should be made of 3 parts.") - } - for i, keyChunk := range keys { - if i == 0 && keyChunk != request.Header.Get("X-Real-IP") { - t.Errorf("The (%v) chunk should be remote IP. KeyChunk: %v", i+1, keyChunk) - } - if i == 1 && keyChunk != request.URL.Path { - t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk) - } - if i == 2 && keyChunk != "bro" { - t.Errorf("The (%v) chunk should be request username. KeyChunk: %v", i+1, keyChunk) - } - } - } -} - -func TestCustomHeadersBuildKeys(t *testing.T) { - limiter := NewLimiter(1, time.Second) - limiter.Headers = make(map[string][]string) - limiter.Headers["X-Auth-Token"] = []string{"totally-top-secret", "another-secret"} - - request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!")) - if err != nil { - t.Errorf("Unable to create new HTTP request. Error: %v", err) - } - - request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8") - request.Header.Set("X-Auth-Token", "totally-top-secret") - - for _, keys := range BuildKeys(limiter, request) { - if len(keys) != 4 { - t.Errorf("Keys should be made of 4 parts. Keys: %v", keys) - } - for i, keyChunk := range keys { - if i == 0 && keyChunk != request.Header.Get("X-Real-IP") { - t.Errorf("The (%v) chunk should be remote IP. KeyChunk: %v", i+1, keyChunk) - } - if i == 1 && keyChunk != request.URL.Path { - t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk) - } - if i == 2 && keyChunk != "X-Auth-Token" { - t.Errorf("The (%v) chunk should be request header. KeyChunk: %v", i+1, keyChunk) - } - if i == 3 && (keyChunk != "totally-top-secret" && keyChunk != "another-secret") { - t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk) - } - } - } -} - -func TestRequestMethodBuildKeys(t *testing.T) { - limiter := NewLimiter(1, time.Second) - limiter.Methods = []string{"GET"} - - request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!")) - if err != nil { - t.Errorf("Unable to create new HTTP request. Error: %v", err) - } - - request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8") - - for _, keys := range BuildKeys(limiter, request) { - if len(keys) != 3 { - t.Errorf("Keys should be made of 3 parts. Keys: %v", keys) - } - for i, keyChunk := range keys { - if i == 0 && keyChunk != request.Header.Get("X-Real-IP") { - t.Errorf("The (%v) chunk should be remote IP. KeyChunk: %v", i+1, keyChunk) - } - if i == 1 && keyChunk != request.URL.Path { - t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk) - } - if i == 2 && keyChunk != "GET" { - t.Errorf("The (%v) chunk should be request method. KeyChunk: %v", i+1, keyChunk) - } - } - } -} - -func TestRequestMethodAndCustomHeadersBuildKeys(t *testing.T) { - limiter := NewLimiter(1, time.Second) - limiter.Methods = []string{"GET"} - limiter.Headers = make(map[string][]string) - limiter.Headers["X-Auth-Token"] = []string{"totally-top-secret", "another-secret"} - - request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!")) - if err != nil { - t.Errorf("Unable to create new HTTP request. Error: %v", err) - } - - request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8") - request.Header.Set("X-Auth-Token", "totally-top-secret") - - for _, keys := range BuildKeys(limiter, request) { - if len(keys) != 5 { - t.Errorf("Keys should be made of 4 parts. Keys: %v", keys) - } - for i, keyChunk := range keys { - if i == 0 && keyChunk != request.Header.Get("X-Real-IP") { - t.Errorf("The (%v) chunk should be remote IP. KeyChunk: %v", i+1, keyChunk) - } - if i == 1 && keyChunk != request.URL.Path { - t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk) - } - if i == 2 && keyChunk != "GET" { - t.Errorf("The (%v) chunk should be request method. KeyChunk: %v", i+1, keyChunk) - } - if i == 3 && keyChunk != "X-Auth-Token" { - t.Errorf("The (%v) chunk should be request header. KeyChunk: %v", i+1, keyChunk) - } - if i == 4 && (keyChunk != "totally-top-secret" && keyChunk != "another-secret") { - t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk) - } - } - } -} - -func TestRequestMethodAndBasicAuthUsersBuildKeys(t *testing.T) { - limiter := NewLimiter(1, time.Second) - limiter.Methods = []string{"GET"} - limiter.BasicAuthUsers = []string{"bro"} - - request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!")) - if err != nil { - t.Errorf("Unable to create new HTTP request. Error: %v", err) - } - - request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8") - request.SetBasicAuth("bro", "tato") - - for _, keys := range BuildKeys(limiter, request) { - if len(keys) != 4 { - t.Errorf("Keys should be made of 4 parts. Keys: %v", keys) - } - for i, keyChunk := range keys { - if i == 0 && keyChunk != request.Header.Get("X-Real-IP") { - t.Errorf("The (%v) chunk should be remote IP. KeyChunk: %v", i+1, keyChunk) - } - if i == 1 && keyChunk != request.URL.Path { - t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk) - } - if i == 2 && keyChunk != "GET" { - t.Errorf("The (%v) chunk should be request method. KeyChunk: %v", i+1, keyChunk) - } - if i == 3 && keyChunk != "bro" { - t.Errorf("The (%v) chunk should be basic auth user. KeyChunk: %v", i+1, keyChunk) - } - } - } -} - -func TestRequestMethodCustomHeadersAndBasicAuthUsersBuildKeys(t *testing.T) { - limiter := NewLimiter(1, time.Second) - limiter.Methods = []string{"GET"} - limiter.Headers = make(map[string][]string) - limiter.Headers["X-Auth-Token"] = []string{"totally-top-secret", "another-secret"} - limiter.BasicAuthUsers = []string{"bro"} - - request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!")) - if err != nil { - t.Errorf("Unable to create new HTTP request. Error: %v", err) - } - - request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8") - request.Header.Set("X-Auth-Token", "totally-top-secret") - request.SetBasicAuth("bro", "tato") - - for _, keys := range BuildKeys(limiter, request) { - if len(keys) != 6 { - t.Errorf("Keys should be made of 4 parts. Keys: %v", keys) - } - for i, keyChunk := range keys { - if i == 0 && keyChunk != request.Header.Get("X-Real-IP") { - t.Errorf("The (%v) chunk should be remote IP. KeyChunk: %v", i+1, keyChunk) - } - if i == 1 && keyChunk != request.URL.Path { - t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk) - } - if i == 2 && keyChunk != "GET" { - t.Errorf("The (%v) chunk should be request method. KeyChunk: %v", i+1, keyChunk) - } - if i == 3 && keyChunk != "X-Auth-Token" { - t.Errorf("The (%v) chunk should be request header. KeyChunk: %v", i+1, keyChunk) - } - if i == 4 && (keyChunk != "totally-top-secret" && keyChunk != "another-secret") { - t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk) - } - if i == 5 && keyChunk != "bro" { - t.Errorf("The (%v) chunk should be basic auth user. KeyChunk: %v", i+1, keyChunk) - } - } - } - -} diff --git a/vendor/github.com/didip/tollbooth_chi/README.md b/vendor/github.com/didip/tollbooth_chi/README.md new file mode 100644 index 00000000..fa1b97f6 --- /dev/null +++ b/vendor/github.com/didip/tollbooth_chi/README.md @@ -0,0 +1,33 @@ +## tollbooth_chi + +[Chi](https://github.com/pressly/chi) middleware for rate limiting HTTP requests. + + +## Five Minutes Tutorial + +``` +package main + +import ( + "github.com/didip/tollbooth" + "github.com/didip/tollbooth_chi" + "github.com/pressly/chi" + "net/http" + "time" +) + +func main() { + // Create a limiter struct. + limiter := tollbooth.NewLimiter(1, time.Second, nil) + + r := chi.NewRouter() + + r.Use(tollbooth_chi.LimitHandler(limiter)) + + r.Get("/", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("Hello, world!")) + }) + + http.ListenAndServe(":12345", r) +} +``` diff --git a/vendor/github.com/didip/tollbooth_chi/tollbooth_chi.go b/vendor/github.com/didip/tollbooth_chi/tollbooth_chi.go new file mode 100644 index 00000000..7f093d2a --- /dev/null +++ b/vendor/github.com/didip/tollbooth_chi/tollbooth_chi.go @@ -0,0 +1,43 @@ +package tollbooth_chi + +import ( + "github.com/didip/tollbooth" + "github.com/didip/tollbooth/limiter" + "net/http" +) + +func LimitHandler(lmt *limiter.Limiter) func(http.Handler) http.Handler { + return func(handler http.Handler) http.Handler { + wrapper := &limiterWrapper{ + lmt: lmt, + } + + wrapper.handler = handler + return wrapper + } +} + +type limiterWrapper struct { + lmt *limiter.Limiter + handler http.Handler +} + +func (l *limiterWrapper) ServeHTTP(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + select { + case <-ctx.Done(): + http.Error(w, "Context was canceled", http.StatusServiceUnavailable) + return + + default: + httpError := tollbooth.LimitByRequest(l.lmt, w, r) + if httpError != nil { + w.Header().Add("Content-Type", l.lmt.GetMessageContentType()) + w.WriteHeader(httpError.StatusCode) + w.Write([]byte(httpError.Message)) + return + } + + l.handler.ServeHTTP(w, r) + } +} diff --git a/vendor/github.com/go-chi/chi/middleware/content_charset_test.go b/vendor/github.com/go-chi/chi/middleware/content_charset_test.go deleted file mode 100644 index 6095cb00..00000000 --- a/vendor/github.com/go-chi/chi/middleware/content_charset_test.go +++ /dev/null @@ -1,124 +0,0 @@ -package middleware - -import ( - "net/http" - "net/http/httptest" - "testing" - - "github.com/go-chi/chi" -) - -func TestContentCharset(t *testing.T) { - t.Parallel() - - var tests = []struct { - name string - inputValue string - inputContentCharset []string - want int - }{ - { - "should accept requests with a matching charset", - "application/json; charset=UTF-8", - []string{"UTF-8"}, - http.StatusOK, - }, - { - "should be case-insensitive", - "application/json; charset=utf-8", - []string{"UTF-8"}, - http.StatusOK, - }, - { - "should accept requests with a matching charset with extra values", - "application/json; foo=bar; charset=UTF-8; spam=eggs", - []string{"UTF-8"}, - http.StatusOK, - }, - { - "should accept requests with a matching charset when multiple charsets are supported", - "text/xml; charset=UTF-8", - []string{"UTF-8", "Latin-1"}, - http.StatusOK, - }, - { - "should accept requests with no charset if empty charset headers are allowed", - "text/xml", - []string{"UTF-8", ""}, - http.StatusOK, - }, - { - "should not accept requests with no charset if empty charset headers are not allowed", - "text/xml", - []string{"UTF-8"}, - http.StatusUnsupportedMediaType, - }, - { - "should not accept requests with a mismatching charset", - "text/plain; charset=Latin-1", - []string{"UTF-8"}, - http.StatusUnsupportedMediaType, - }, - { - "should not accept requests with a mismatching charset even if empty charsets are allowed", - "text/plain; charset=Latin-1", - []string{"UTF-8", ""}, - http.StatusUnsupportedMediaType, - }, - } - - for _, tt := range tests { - var tt = tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - - var recorder = httptest.NewRecorder() - - var r = chi.NewRouter() - r.Use(ContentCharset(tt.inputContentCharset...)) - r.Get("/", func(w http.ResponseWriter, r *http.Request) {}) - - var req, _ = http.NewRequest("GET", "/", nil) - req.Header.Set("Content-Type", tt.inputValue) - - r.ServeHTTP(recorder, req) - var res = recorder.Result() - - if res.StatusCode != tt.want { - t.Errorf("response is incorrect, got %d, want %d", recorder.Code, tt.want) - } - }) - } -} - -func TestSplit(t *testing.T) { - t.Parallel() - - var s1, s2 = split(" type1;type2 ", ";") - - if s1 != "type1" || s2 != "type2" { - t.Errorf("Want type1, type2 got %s, %s", s1, s2) - } - - s1, s2 = split("type1 ", ";") - - if s1 != "type1" { - t.Errorf("Want \"type1\" got \"%s\"", s1) - } -} - -func TestContentEncoding(t *testing.T) { - t.Parallel() - - if !contentEncoding("application/json; foo=bar; charset=utf-8; spam=eggs", []string{"utf-8"}...) { - t.Error("Want true, got false") - } - - if contentEncoding("text/plain; charset=latin-1", []string{"utf-8"}...) { - t.Error("Want false, got true") - } - - if !contentEncoding("text/xml; charset=UTF-8", []string{"latin-1", "utf-8"}...) { - t.Error("Want true, got false") - } -} diff --git a/vendor/github.com/go-chi/chi/middleware/get_head_test.go b/vendor/github.com/go-chi/chi/middleware/get_head_test.go deleted file mode 100644 index edfeb5b7..00000000 --- a/vendor/github.com/go-chi/chi/middleware/get_head_test.go +++ /dev/null @@ -1,66 +0,0 @@ -package middleware - -import ( - "net/http" - "net/http/httptest" - "testing" - - "github.com/go-chi/chi" -) - -func TestGetHead(t *testing.T) { - r := chi.NewRouter() - r.Use(GetHead) - r.Get("/hi", func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("X-Test", "yes") - w.Write([]byte("bye")) - }) - r.Route("/articles", func(r chi.Router) { - r.Get("/{id}", func(w http.ResponseWriter, r *http.Request) { - id := chi.URLParam(r, "id") - w.Header().Set("X-Article", id) - w.Write([]byte("article:" + id)) - }) - }) - r.Route("/users", func(r chi.Router) { - r.Head("/{id}", func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("X-User", "-") - w.Write([]byte("user")) - }) - r.Get("/{id}", func(w http.ResponseWriter, r *http.Request) { - id := chi.URLParam(r, "id") - w.Header().Set("X-User", id) - w.Write([]byte("user:" + id)) - }) - }) - - ts := httptest.NewServer(r) - defer ts.Close() - - if _, body := testRequest(t, ts, "GET", "/hi", nil); body != "bye" { - t.Fatalf(body) - } - if req, body := testRequest(t, ts, "HEAD", "/hi", nil); body != "" || req.Header.Get("X-Test") != "yes" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "GET", "/", nil); body != "404 page not found\n" { - t.Fatalf(body) - } - if req, body := testRequest(t, ts, "HEAD", "/", nil); body != "" || req.StatusCode != 404 { - t.Fatalf(body) - } - - if _, body := testRequest(t, ts, "GET", "/articles/5", nil); body != "article:5" { - t.Fatalf(body) - } - if req, body := testRequest(t, ts, "HEAD", "/articles/5", nil); body != "" || req.Header.Get("X-Article") != "5" { - t.Fatalf("expecting X-Article header '5' but got '%s'", req.Header.Get("X-Article")) - } - - if _, body := testRequest(t, ts, "GET", "/users/1", nil); body != "user:1" { - t.Fatalf(body) - } - if req, body := testRequest(t, ts, "HEAD", "/users/1", nil); body != "" || req.Header.Get("X-User") != "-" { - t.Fatalf("expecting X-User header '-' but got '%s'", req.Header.Get("X-User")) - } -} diff --git a/vendor/github.com/go-chi/chi/middleware/middleware18_test.go b/vendor/github.com/go-chi/chi/middleware/middleware18_test.go deleted file mode 100644 index 0a697ad5..00000000 --- a/vendor/github.com/go-chi/chi/middleware/middleware18_test.go +++ /dev/null @@ -1,77 +0,0 @@ -// +build go1.8 - -package middleware - -import ( - "crypto/tls" - "io" - "net/http" - "testing" - "time" - - "golang.org/x/net/http2" -) - -// NOTE: we must import `golang.org/x/net/http2` in order to explicitly enable -// http2 transports for certain tests. The runtime pkg does not have this dependency -// though as the transport configuration happens under the hood on go 1.7+. - -func TestWrapWriterHTTP2(t *testing.T) { - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - _, cn := w.(http.CloseNotifier) - if !cn { - t.Fatal("request should have been a http.CloseNotifier") - } - _, fl := w.(http.Flusher) - if !fl { - t.Fatal("request should have been a http.Flusher") - } - _, hj := w.(http.Hijacker) - if hj { - t.Fatal("request should not have been a http.Hijacker") - } - _, rf := w.(io.ReaderFrom) - if rf { - t.Fatal("request should not have been a io.ReaderFrom") - } - _, ps := w.(http.Pusher) - if !ps { - t.Fatal("request should have been a http.Pusher") - } - - w.Write([]byte("OK")) - }) - - wmw := func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - next.ServeHTTP(NewWrapResponseWriter(w, r.ProtoMajor), r) - }) - } - - server := http.Server{ - Addr: ":7072", - Handler: wmw(handler), - } - // By serving over TLS, we get HTTP2 requests - go server.ListenAndServeTLS(testdataDir+"/cert.pem", testdataDir+"/key.pem") - defer server.Close() - // We need the server to start before making the request - time.Sleep(100 * time.Millisecond) - - client := &http.Client{ - Transport: &http2.Transport{ - TLSClientConfig: &tls.Config{ - // The certificates we are using are self signed - InsecureSkipVerify: true, - }, - }, - } - - resp, err := client.Get("https://localhost:7072") - if err != nil { - t.Fatalf("could not get server: %v", err) - } - if resp.StatusCode != 200 { - t.Fatalf("non 200 response: %v", resp.StatusCode) - } -} diff --git a/vendor/github.com/go-chi/chi/middleware/middleware_test.go b/vendor/github.com/go-chi/chi/middleware/middleware_test.go deleted file mode 100644 index e004b296..00000000 --- a/vendor/github.com/go-chi/chi/middleware/middleware_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package middleware - -import ( - "io" - "io/ioutil" - "net/http" - "net/http/httptest" - "path" - "reflect" - "runtime" - "testing" -) - -// NOTE: we must import `golang.org/x/net/http2` in order to explicitly enable -// http2 transports for certain tests. The runtime pkg does not have this dependency -// though as the transport configuration happens under the hood on go 1.7+. - -var testdataDir string - -func init() { - _, filename, _, _ := runtime.Caller(0) - testdataDir = path.Join(path.Dir(filename), "/../testdata") -} - -func testRequest(t *testing.T, ts *httptest.Server, method, path string, body io.Reader) (*http.Response, string) { - req, err := http.NewRequest(method, ts.URL+path, body) - if err != nil { - t.Fatal(err) - return nil, "" - } - - resp, err := http.DefaultClient.Do(req) - if err != nil { - t.Fatal(err) - return nil, "" - } - - respBody, err := ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatal(err) - return nil, "" - } - defer resp.Body.Close() - - return resp, string(respBody) -} - -func assertNoError(t *testing.T, err error) { - if err != nil { - t.Fatalf("expecting no error") - } -} - -func assertError(t *testing.T, err error) { - if err == nil { - t.Fatalf("expecting error") - } -} - -func assertEqual(t *testing.T, a, b interface{}) { - if !reflect.DeepEqual(a, b) { - t.Fatalf("expecting values to be equal but got: '%v' and '%v'", a, b) - } -} diff --git a/vendor/github.com/go-chi/chi/middleware/realip_test.go b/vendor/github.com/go-chi/chi/middleware/realip_test.go deleted file mode 100644 index 84700735..00000000 --- a/vendor/github.com/go-chi/chi/middleware/realip_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package middleware - -import ( - "net/http" - "net/http/httptest" - "testing" - - "github.com/go-chi/chi" -) - -func TestXRealIP(t *testing.T) { - req, _ := http.NewRequest("GET", "/", nil) - req.Header.Add("X-Real-IP", "100.100.100.100") - w := httptest.NewRecorder() - - r := chi.NewRouter() - r.Use(RealIP) - - realIP := "" - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - realIP = r.RemoteAddr - w.Write([]byte("Hello World")) - }) - r.ServeHTTP(w, req) - - if w.Code != 200 { - t.Fatal("Response Code should be 200") - } - - if realIP != "100.100.100.100" { - t.Fatal("Test get real IP error.") - } -} - -func TestXForwardForIP(t *testing.T) { - req, _ := http.NewRequest("GET", "/", nil) - req.Header.Add("X-Forwarded-For", "100.100.100.100") - w := httptest.NewRecorder() - - r := chi.NewRouter() - r.Use(RealIP) - - realIP := "" - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - realIP = r.RemoteAddr - w.Write([]byte("Hello World")) - }) - r.ServeHTTP(w, req) - - if w.Code != 200 { - t.Fatal("Response Code should be 200") - } - - if realIP != "100.100.100.100" { - t.Fatal("Test get real IP error.") - } -} diff --git a/vendor/github.com/go-chi/chi/middleware/strip_test.go b/vendor/github.com/go-chi/chi/middleware/strip_test.go deleted file mode 100644 index 5cbb8923..00000000 --- a/vendor/github.com/go-chi/chi/middleware/strip_test.go +++ /dev/null @@ -1,147 +0,0 @@ -package middleware - -import ( - "net/http" - "net/http/httptest" - "testing" - - "github.com/go-chi/chi" -) - -func TestStripSlashes(t *testing.T) { - r := chi.NewRouter() - - // This middleware must be mounted at the top level of the router, not at the end-handler - // because then it'll be too late and will end up in a 404 - r.Use(StripSlashes) - - r.NotFound(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(404) - w.Write([]byte("nothing here")) - }) - - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("root")) - }) - - r.Route("/accounts/{accountID}", func(r chi.Router) { - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - accountID := chi.URLParam(r, "accountID") - w.Write([]byte(accountID)) - }) - }) - - ts := httptest.NewServer(r) - defer ts.Close() - - if _, resp := testRequest(t, ts, "GET", "/", nil); resp != "root" { - t.Fatalf(resp) - } - if _, resp := testRequest(t, ts, "GET", "//", nil); resp != "root" { - t.Fatalf(resp) - } - if _, resp := testRequest(t, ts, "GET", "/accounts/admin", nil); resp != "admin" { - t.Fatalf(resp) - } - if _, resp := testRequest(t, ts, "GET", "/accounts/admin/", nil); resp != "admin" { - t.Fatalf(resp) - } - if _, resp := testRequest(t, ts, "GET", "/nothing-here", nil); resp != "nothing here" { - t.Fatalf(resp) - } -} - -func TestStripSlashesInRoute(t *testing.T) { - r := chi.NewRouter() - - r.NotFound(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(404) - w.Write([]byte("nothing here")) - }) - - r.Get("/hi", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("hi")) - }) - - r.Route("/accounts/{accountID}", func(r chi.Router) { - r.Use(StripSlashes) - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("accounts index")) - }) - r.Get("/query", func(w http.ResponseWriter, r *http.Request) { - accountID := chi.URLParam(r, "accountID") - w.Write([]byte(accountID)) - }) - }) - - ts := httptest.NewServer(r) - defer ts.Close() - - if _, resp := testRequest(t, ts, "GET", "/hi", nil); resp != "hi" { - t.Fatalf(resp) - } - if _, resp := testRequest(t, ts, "GET", "/hi/", nil); resp != "nothing here" { - t.Fatalf(resp) - } - if _, resp := testRequest(t, ts, "GET", "/accounts/admin", nil); resp != "accounts index" { - t.Fatalf(resp) - } - if _, resp := testRequest(t, ts, "GET", "/accounts/admin/", nil); resp != "accounts index" { - t.Fatalf(resp) - } - if _, resp := testRequest(t, ts, "GET", "/accounts/admin/query", nil); resp != "admin" { - t.Fatalf(resp) - } - if _, resp := testRequest(t, ts, "GET", "/accounts/admin/query/", nil); resp != "admin" { - t.Fatalf(resp) - } -} - -func TestRedirectSlashes(t *testing.T) { - r := chi.NewRouter() - - // This middleware must be mounted at the top level of the router, not at the end-handler - // because then it'll be too late and will end up in a 404 - r.Use(RedirectSlashes) - - r.NotFound(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(404) - w.Write([]byte("nothing here")) - }) - - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("root")) - }) - - r.Route("/accounts/{accountID}", func(r chi.Router) { - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - accountID := chi.URLParam(r, "accountID") - w.Write([]byte(accountID)) - }) - }) - - ts := httptest.NewServer(r) - defer ts.Close() - - if req, resp := testRequest(t, ts, "GET", "/", nil); resp != "root" && req.StatusCode != 200 { - t.Fatalf(resp) - } - - // NOTE: the testRequest client will follow the redirection.. - if req, resp := testRequest(t, ts, "GET", "//", nil); resp != "root" && req.StatusCode != 200 { - t.Fatalf(resp) - } - - if req, resp := testRequest(t, ts, "GET", "/accounts/admin", nil); resp != "admin" && req.StatusCode != 200 { - t.Fatalf(resp) - } - - // NOTE: the testRequest client will follow the redirection.. - if req, resp := testRequest(t, ts, "GET", "/accounts/admin/", nil); resp != "admin" && req.StatusCode != 200 { - t.Fatalf(resp) - } - - if req, resp := testRequest(t, ts, "GET", "/nothing-here", nil); resp != "nothing here" && req.StatusCode != 200 { - t.Fatalf(resp) - } -} diff --git a/vendor/github.com/go-chi/chi/middleware/throttle_test.go b/vendor/github.com/go-chi/chi/middleware/throttle_test.go deleted file mode 100644 index 626397ee..00000000 --- a/vendor/github.com/go-chi/chi/middleware/throttle_test.go +++ /dev/null @@ -1,204 +0,0 @@ -package middleware - -import ( - "io/ioutil" - "net/http" - "net/http/httptest" - "strings" - "sync" - "testing" - "time" - - "github.com/go-chi/chi" -) - -var testContent = []byte("Hello world!") - -func TestThrottleBacklog(t *testing.T) { - r := chi.NewRouter() - - r.Use(ThrottleBacklog(10, 50, time.Second*10)) - - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - time.Sleep(time.Second * 1) // Expensive operation. - w.Write(testContent) - }) - - server := httptest.NewServer(r) - defer server.Close() - - client := http.Client{ - Timeout: time.Second * 5, // Maximum waiting time. - } - - var wg sync.WaitGroup - - // The throttler proccesses 10 consecutive requests, each one of those - // requests lasts 1s. The maximum number of requests this can possible serve - // before the clients time out (5s) is 40. - for i := 0; i < 40; i++ { - wg.Add(1) - go func(i int) { - defer wg.Done() - - res, err := client.Get(server.URL) - assertNoError(t, err) - - assertEqual(t, http.StatusOK, res.StatusCode) - buf, err := ioutil.ReadAll(res.Body) - assertNoError(t, err) - assertEqual(t, testContent, buf) - }(i) - } - - wg.Wait() -} - -func TestThrottleClientTimeout(t *testing.T) { - r := chi.NewRouter() - - r.Use(ThrottleBacklog(10, 50, time.Second*10)) - - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - time.Sleep(time.Second * 5) // Expensive operation. - w.Write(testContent) - }) - - server := httptest.NewServer(r) - defer server.Close() - - client := http.Client{ - Timeout: time.Second * 3, // Maximum waiting time. - } - - var wg sync.WaitGroup - - for i := 0; i < 10; i++ { - wg.Add(1) - go func(i int) { - defer wg.Done() - _, err := client.Get(server.URL) - assertError(t, err) - }(i) - } - - wg.Wait() -} - -func TestThrottleTriggerGatewayTimeout(t *testing.T) { - r := chi.NewRouter() - - r.Use(ThrottleBacklog(50, 100, time.Second*5)) - - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - time.Sleep(time.Second * 10) // Expensive operation. - w.Write(testContent) - }) - - server := httptest.NewServer(r) - defer server.Close() - - client := http.Client{ - Timeout: time.Second * 60, // Maximum waiting time. - } - - var wg sync.WaitGroup - - // These requests will be processed normally until they finish. - for i := 0; i < 50; i++ { - wg.Add(1) - go func(i int) { - defer wg.Done() - - res, err := client.Get(server.URL) - assertNoError(t, err) - assertEqual(t, http.StatusOK, res.StatusCode) - - }(i) - } - - time.Sleep(time.Second * 1) - - // These requests will wait for the first batch to complete but it will take - // too much time, so they will eventually receive a timeout error. - for i := 0; i < 50; i++ { - wg.Add(1) - go func(i int) { - defer wg.Done() - - res, err := client.Get(server.URL) - assertNoError(t, err) - - buf, err := ioutil.ReadAll(res.Body) - assertNoError(t, err) - assertEqual(t, http.StatusServiceUnavailable, res.StatusCode) - assertEqual(t, errTimedOut, strings.TrimSpace(string(buf))) - - }(i) - } - - wg.Wait() -} - -func TestThrottleMaximum(t *testing.T) { - r := chi.NewRouter() - - r.Use(ThrottleBacklog(50, 50, time.Second*5)) - - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - time.Sleep(time.Second * 2) // Expensive operation. - w.Write(testContent) - }) - - server := httptest.NewServer(r) - defer server.Close() - - client := http.Client{ - Timeout: time.Second * 60, // Maximum waiting time. - } - - var wg sync.WaitGroup - - for i := 0; i < 100; i++ { - wg.Add(1) - go func(i int) { - defer wg.Done() - - res, err := client.Get(server.URL) - assertNoError(t, err) - assertEqual(t, http.StatusOK, res.StatusCode) - - buf, err := ioutil.ReadAll(res.Body) - assertNoError(t, err) - assertEqual(t, testContent, buf) - - }(i) - } - - // Wait less time than what the server takes to reply. - time.Sleep(time.Second * 1) - - // At this point the server is still processing, all the following request - // will be beyond the server capacity. - for i := 0; i < 100; i++ { - wg.Add(1) - go func(i int) { - defer wg.Done() - - res, err := client.Get(server.URL) - assertNoError(t, err) - - buf, err := ioutil.ReadAll(res.Body) - assertNoError(t, err) - assertEqual(t, http.StatusServiceUnavailable, res.StatusCode) - assertEqual(t, errCapacityExceeded, strings.TrimSpace(string(buf))) - - }(i) - } - - wg.Wait() -} diff --git a/vendor/github.com/go-chi/chi/middleware/wrap_writer_test.go b/vendor/github.com/go-chi/chi/middleware/wrap_writer_test.go deleted file mode 100644 index 705908d9..00000000 --- a/vendor/github.com/go-chi/chi/middleware/wrap_writer_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package middleware - -import ( - "net/http/httptest" - "testing" -) - -func TestFlushWriterRemembersWroteHeaderWhenFlushed(t *testing.T) { - f := &flushWriter{basicWriter{ResponseWriter: httptest.NewRecorder()}} - f.Flush() - - if !f.wroteHeader { - t.Fatal("want Flush to have set wroteHeader=true") - } -} - -func TestHttpFancyWriterRemembersWroteHeaderWhenFlushed(t *testing.T) { - f := &httpFancyWriter{basicWriter{ResponseWriter: httptest.NewRecorder()}} - f.Flush() - - if !f.wroteHeader { - t.Fatal("want Flush to have set wroteHeader=true") - } -} - -func TestHttp2FancyWriterRemembersWroteHeaderWhenFlushed(t *testing.T) { - f := &http2FancyWriter{basicWriter{ResponseWriter: httptest.NewRecorder()}} - f.Flush() - - if !f.wroteHeader { - t.Fatal("want Flush to have set wroteHeader=true") - } -} diff --git a/vendor/github.com/go-chi/chi/mux_test.go b/vendor/github.com/go-chi/chi/mux_test.go deleted file mode 100644 index 55a9bf32..00000000 --- a/vendor/github.com/go-chi/chi/mux_test.go +++ /dev/null @@ -1,1662 +0,0 @@ -package chi - -import ( - "bytes" - "context" - "fmt" - "io" - "io/ioutil" - "net" - "net/http" - "net/http/httptest" - "os" - "sync" - "testing" - "time" -) - -func TestMuxBasic(t *testing.T) { - var count uint64 - countermw := func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - count++ - next.ServeHTTP(w, r) - }) - } - - usermw := func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - ctx = context.WithValue(ctx, ctxKey{"user"}, "peter") - r = r.WithContext(ctx) - next.ServeHTTP(w, r) - }) - } - - exmw := func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := context.WithValue(r.Context(), ctxKey{"ex"}, "a") - r = r.WithContext(ctx) - next.ServeHTTP(w, r) - }) - } - - logbuf := bytes.NewBufferString("") - logmsg := "logmw test" - logmw := func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - logbuf.WriteString(logmsg) - next.ServeHTTP(w, r) - }) - } - - cxindex := func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - user := ctx.Value(ctxKey{"user"}).(string) - w.WriteHeader(200) - w.Write([]byte(fmt.Sprintf("hi %s", user))) - } - - ping := func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(200) - w.Write([]byte(".")) - } - - headPing := func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("X-Ping", "1") - w.WriteHeader(200) - } - - createPing := func(w http.ResponseWriter, r *http.Request) { - // create .... - w.WriteHeader(201) - } - - pingAll := func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(200) - w.Write([]byte("ping all")) - } - - pingAll2 := func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(200) - w.Write([]byte("ping all2")) - } - - pingOne := func(w http.ResponseWriter, r *http.Request) { - idParam := URLParam(r, "id") - w.WriteHeader(200) - w.Write([]byte(fmt.Sprintf("ping one id: %s", idParam))) - } - - pingWoop := func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(200) - w.Write([]byte("woop." + URLParam(r, "iidd"))) - } - - catchAll := func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(200) - w.Write([]byte("catchall")) - } - - m := NewRouter() - m.Use(countermw) - m.Use(usermw) - m.Use(exmw) - m.Use(logmw) - m.Get("/", cxindex) - m.Method("GET", "/ping", http.HandlerFunc(ping)) - m.MethodFunc("GET", "/pingall", pingAll) - m.MethodFunc("get", "/ping/all", pingAll) - m.Get("/ping/all2", pingAll2) - - m.Head("/ping", headPing) - m.Post("/ping", createPing) - m.Get("/ping/{id}", pingWoop) - m.Get("/ping/{id}", pingOne) // expected to overwrite to pingOne handler - m.Get("/ping/{iidd}/woop", pingWoop) - m.HandleFunc("/admin/*", catchAll) - // m.Post("/admin/*", catchAll) - - ts := httptest.NewServer(m) - defer ts.Close() - - // GET / - if _, body := testRequest(t, ts, "GET", "/", nil); body != "hi peter" { - t.Fatalf(body) - } - tlogmsg, _ := logbuf.ReadString(0) - if tlogmsg != logmsg { - t.Error("expecting log message from middleware:", logmsg) - } - - // GET /ping - if _, body := testRequest(t, ts, "GET", "/ping", nil); body != "." { - t.Fatalf(body) - } - - // GET /pingall - if _, body := testRequest(t, ts, "GET", "/pingall", nil); body != "ping all" { - t.Fatalf(body) - } - - // GET /ping/all - if _, body := testRequest(t, ts, "GET", "/ping/all", nil); body != "ping all" { - t.Fatalf(body) - } - - // GET /ping/all2 - if _, body := testRequest(t, ts, "GET", "/ping/all2", nil); body != "ping all2" { - t.Fatalf(body) - } - - // GET /ping/123 - if _, body := testRequest(t, ts, "GET", "/ping/123", nil); body != "ping one id: 123" { - t.Fatalf(body) - } - - // GET /ping/allan - if _, body := testRequest(t, ts, "GET", "/ping/allan", nil); body != "ping one id: allan" { - t.Fatalf(body) - } - - // GET /ping/1/woop - if _, body := testRequest(t, ts, "GET", "/ping/1/woop", nil); body != "woop.1" { - t.Fatalf(body) - } - - // HEAD /ping - resp, err := http.Head(ts.URL + "/ping") - if err != nil { - t.Fatal(err) - } - if resp.StatusCode != 200 { - t.Error("head failed, should be 200") - } - if resp.Header.Get("X-Ping") == "" { - t.Error("expecting X-Ping header") - } - - // GET /admin/catch-this - if _, body := testRequest(t, ts, "GET", "/admin/catch-thazzzzz", nil); body != "catchall" { - t.Fatalf(body) - } - - // POST /admin/catch-this - resp, err = http.Post(ts.URL+"/admin/casdfsadfs", "text/plain", bytes.NewReader([]byte{})) - if err != nil { - t.Fatal(err) - } - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - - if resp.StatusCode != 200 { - t.Error("POST failed, should be 200") - } - - if string(body) != "catchall" { - t.Error("expecting response body: 'catchall'") - } - - // Custom http method DIE /ping/1/woop - if resp, body := testRequest(t, ts, "DIE", "/ping/1/woop", nil); body != "" || resp.StatusCode != 405 { - t.Fatalf(fmt.Sprintf("expecting 405 status and empty body, got %d '%s'", resp.StatusCode, body)) - } -} - -func TestMuxMounts(t *testing.T) { - r := NewRouter() - - r.Get("/{hash}", func(w http.ResponseWriter, r *http.Request) { - v := URLParam(r, "hash") - w.Write([]byte(fmt.Sprintf("/%s", v))) - }) - - r.Route("/{hash}/share", func(r Router) { - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - v := URLParam(r, "hash") - w.Write([]byte(fmt.Sprintf("/%s/share", v))) - }) - r.Get("/{network}", func(w http.ResponseWriter, r *http.Request) { - v := URLParam(r, "hash") - n := URLParam(r, "network") - w.Write([]byte(fmt.Sprintf("/%s/share/%s", v, n))) - }) - }) - - m := NewRouter() - m.Mount("/sharing", r) - - ts := httptest.NewServer(m) - defer ts.Close() - - if _, body := testRequest(t, ts, "GET", "/sharing/aBc", nil); body != "/aBc" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "GET", "/sharing/aBc/share", nil); body != "/aBc/share" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "GET", "/sharing/aBc/share/twitter", nil); body != "/aBc/share/twitter" { - t.Fatalf(body) - } -} - -func TestMuxPlain(t *testing.T) { - r := NewRouter() - r.Get("/hi", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("bye")) - }) - r.NotFound(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(404) - w.Write([]byte("nothing here")) - }) - - ts := httptest.NewServer(r) - defer ts.Close() - - if _, body := testRequest(t, ts, "GET", "/hi", nil); body != "bye" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "GET", "/nothing-here", nil); body != "nothing here" { - t.Fatalf(body) - } -} - -func TestMuxEmptyRoutes(t *testing.T) { - mux := NewRouter() - - apiRouter := NewRouter() - // oops, we forgot to declare any route handlers - - mux.Handle("/api*", apiRouter) - - if _, body := testHandler(t, mux, "GET", "/", nil); body != "404 page not found\n" { - t.Fatalf(body) - } - - func() { - defer func() { - if r := recover(); r != nil { - if r != `chi: attempting to route to a mux with no handlers.` { - t.Fatalf("expecting empty route panic") - } - } - }() - - _, body := testHandler(t, mux, "GET", "/api", nil) - t.Fatalf("oops, we are expecting a panic instead of getting resp: %s", body) - }() - - func() { - defer func() { - if r := recover(); r != nil { - if r != `chi: attempting to route to a mux with no handlers.` { - t.Fatalf("expecting empty route panic") - } - } - }() - - _, body := testHandler(t, mux, "GET", "/api/abc", nil) - t.Fatalf("oops, we are expecting a panic instead of getting resp: %s", body) - }() -} - -// Test a mux that routes a trailing slash, see also middleware/strip_test.go -// for an example of using a middleware to handle trailing slashes. -func TestMuxTrailingSlash(t *testing.T) { - r := NewRouter() - r.NotFound(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(404) - w.Write([]byte("nothing here")) - }) - - subRoutes := NewRouter() - indexHandler := func(w http.ResponseWriter, r *http.Request) { - accountID := URLParam(r, "accountID") - w.Write([]byte(accountID)) - } - subRoutes.Get("/", indexHandler) - - r.Mount("/accounts/{accountID}", subRoutes) - r.Get("/accounts/{accountID}/", indexHandler) - - ts := httptest.NewServer(r) - defer ts.Close() - - if _, body := testRequest(t, ts, "GET", "/accounts/admin", nil); body != "admin" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "GET", "/accounts/admin/", nil); body != "admin" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "GET", "/nothing-here", nil); body != "nothing here" { - t.Fatalf(body) - } -} - -func TestMuxNestedNotFound(t *testing.T) { - r := NewRouter() - - r.Use(func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - r = r.WithContext(context.WithValue(r.Context(), ctxKey{"mw"}, "mw")) - next.ServeHTTP(w, r) - }) - }) - - r.Get("/hi", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("bye")) - }) - - r.With(func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - r = r.WithContext(context.WithValue(r.Context(), ctxKey{"with"}, "with")) - next.ServeHTTP(w, r) - }) - }).NotFound(func(w http.ResponseWriter, r *http.Request) { - chkMw := r.Context().Value(ctxKey{"mw"}).(string) - chkWith := r.Context().Value(ctxKey{"with"}).(string) - w.WriteHeader(404) - w.Write([]byte(fmt.Sprintf("root 404 %s %s", chkMw, chkWith))) - }) - - sr1 := NewRouter() - - sr1.Get("/sub", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("sub")) - }) - sr1.Group(func(sr1 Router) { - sr1.Use(func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - r = r.WithContext(context.WithValue(r.Context(), ctxKey{"mw2"}, "mw2")) - next.ServeHTTP(w, r) - }) - }) - sr1.NotFound(func(w http.ResponseWriter, r *http.Request) { - chkMw2 := r.Context().Value(ctxKey{"mw2"}).(string) - w.WriteHeader(404) - w.Write([]byte(fmt.Sprintf("sub 404 %s", chkMw2))) - }) - }) - - sr2 := NewRouter() - sr2.Get("/sub", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("sub2")) - }) - - r.Mount("/admin1", sr1) - r.Mount("/admin2", sr2) - - ts := httptest.NewServer(r) - defer ts.Close() - - if _, body := testRequest(t, ts, "GET", "/hi", nil); body != "bye" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "GET", "/nothing-here", nil); body != "root 404 mw with" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "GET", "/admin1/sub", nil); body != "sub" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "GET", "/admin1/nope", nil); body != "sub 404 mw2" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "GET", "/admin2/sub", nil); body != "sub2" { - t.Fatalf(body) - } - - // Not found pages should bubble up to the root. - if _, body := testRequest(t, ts, "GET", "/admin2/nope", nil); body != "root 404 mw with" { - t.Fatalf(body) - } -} - -func TestMuxNestedMethodNotAllowed(t *testing.T) { - r := NewRouter() - r.Get("/root", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("root")) - }) - r.MethodNotAllowed(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(405) - w.Write([]byte("root 405")) - }) - - sr1 := NewRouter() - sr1.Get("/sub1", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("sub1")) - }) - sr1.MethodNotAllowed(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(405) - w.Write([]byte("sub1 405")) - }) - - sr2 := NewRouter() - sr2.Get("/sub2", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("sub2")) - }) - - r.Mount("/prefix1", sr1) - r.Mount("/prefix2", sr2) - - ts := httptest.NewServer(r) - defer ts.Close() - - if _, body := testRequest(t, ts, "GET", "/root", nil); body != "root" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "PUT", "/root", nil); body != "root 405" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "GET", "/prefix1/sub1", nil); body != "sub1" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "PUT", "/prefix1/sub1", nil); body != "sub1 405" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "GET", "/prefix2/sub2", nil); body != "sub2" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "PUT", "/prefix2/sub2", nil); body != "root 405" { - t.Fatalf(body) - } -} - -func TestMuxComplicatedNotFound(t *testing.T) { - // sub router with groups - sub := NewRouter() - sub.Route("/resource", func(r Router) { - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("private get")) - }) - }) - - // Root router with groups - r := NewRouter() - r.Get("/auth", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("auth get")) - }) - r.Route("/public", func(r Router) { - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("public get")) - }) - }) - r.Mount("/private", sub) - r.NotFound(func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("custom not-found")) - }) - - ts := httptest.NewServer(r) - defer ts.Close() - - // check that we didn't break correct routes - if _, body := testRequest(t, ts, "GET", "/auth", nil); body != "auth get" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "GET", "/public", nil); body != "public get" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "GET", "/public/", nil); body != "public get" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "GET", "/private/resource", nil); body != "private get" { - t.Fatalf(body) - } - // check custom not-found on all levels - if _, body := testRequest(t, ts, "GET", "/nope", nil); body != "custom not-found" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "GET", "/public/nope", nil); body != "custom not-found" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "GET", "/private/nope", nil); body != "custom not-found" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "GET", "/private/resource/nope", nil); body != "custom not-found" { - t.Fatalf(body) - } - // check custom not-found on trailing slash routes - if _, body := testRequest(t, ts, "GET", "/auth/", nil); body != "custom not-found" { - t.Fatalf(body) - } -} - -func TestMuxWith(t *testing.T) { - var cmwInit1, cmwHandler1 uint64 - var cmwInit2, cmwHandler2 uint64 - mw1 := func(next http.Handler) http.Handler { - cmwInit1++ - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - cmwHandler1++ - r = r.WithContext(context.WithValue(r.Context(), ctxKey{"inline1"}, "yes")) - next.ServeHTTP(w, r) - }) - } - mw2 := func(next http.Handler) http.Handler { - cmwInit2++ - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - cmwHandler2++ - r = r.WithContext(context.WithValue(r.Context(), ctxKey{"inline2"}, "yes")) - next.ServeHTTP(w, r) - }) - } - - r := NewRouter() - r.Get("/hi", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("bye")) - }) - r.With(mw1).With(mw2).Get("/inline", func(w http.ResponseWriter, r *http.Request) { - v1 := r.Context().Value(ctxKey{"inline1"}).(string) - v2 := r.Context().Value(ctxKey{"inline2"}).(string) - w.Write([]byte(fmt.Sprintf("inline %s %s", v1, v2))) - }) - - ts := httptest.NewServer(r) - defer ts.Close() - - if _, body := testRequest(t, ts, "GET", "/hi", nil); body != "bye" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "GET", "/inline", nil); body != "inline yes yes" { - t.Fatalf(body) - } - if cmwInit1 != 1 { - t.Fatalf("expecting cmwInit1 to be 1, got %d", cmwInit1) - } - if cmwHandler1 != 1 { - t.Fatalf("expecting cmwHandler1 to be 1, got %d", cmwHandler1) - } - if cmwInit2 != 1 { - t.Fatalf("expecting cmwInit2 to be 1, got %d", cmwInit2) - } - if cmwHandler2 != 1 { - t.Fatalf("expecting cmwHandler2 to be 1, got %d", cmwHandler2) - } -} - -func TestRouterFromMuxWith(t *testing.T) { - t.Parallel() - - r := NewRouter() - - with := r.With(func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - next.ServeHTTP(w, r) - }) - }) - - with.Get("/with_middleware", func(w http.ResponseWriter, r *http.Request) {}) - - ts := httptest.NewServer(with) - defer ts.Close() - - // Without the fix this test was committed with, this causes a panic. - testRequest(t, ts, http.MethodGet, "/with_middleware", nil) -} - -func TestMuxMiddlewareStack(t *testing.T) { - var stdmwInit, stdmwHandler uint64 - stdmw := func(next http.Handler) http.Handler { - stdmwInit++ - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - stdmwHandler++ - next.ServeHTTP(w, r) - }) - } - _ = stdmw - - var ctxmwInit, ctxmwHandler uint64 - ctxmw := func(next http.Handler) http.Handler { - ctxmwInit++ - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctxmwHandler++ - ctx := r.Context() - ctx = context.WithValue(ctx, ctxKey{"count.ctxmwHandler"}, ctxmwHandler) - r = r.WithContext(ctx) - next.ServeHTTP(w, r) - }) - } - - var inCtxmwInit, inCtxmwHandler uint64 - inCtxmw := func(next http.Handler) http.Handler { - inCtxmwInit++ - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - inCtxmwHandler++ - next.ServeHTTP(w, r) - }) - } - - r := NewRouter() - r.Use(stdmw) - r.Use(ctxmw) - r.Use(func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.URL.Path == "/ping" { - w.Write([]byte("pong")) - return - } - next.ServeHTTP(w, r) - }) - }) - - var handlerCount uint64 - - r.With(inCtxmw).Get("/", func(w http.ResponseWriter, r *http.Request) { - handlerCount++ - ctx := r.Context() - ctxmwHandlerCount := ctx.Value(ctxKey{"count.ctxmwHandler"}).(uint64) - w.Write([]byte(fmt.Sprintf("inits:%d reqs:%d ctxValue:%d", ctxmwInit, handlerCount, ctxmwHandlerCount))) - }) - - r.Get("/hi", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("wooot")) - }) - - ts := httptest.NewServer(r) - defer ts.Close() - - testRequest(t, ts, "GET", "/", nil) - testRequest(t, ts, "GET", "/", nil) - var body string - _, body = testRequest(t, ts, "GET", "/", nil) - if body != "inits:1 reqs:3 ctxValue:3" { - t.Fatalf("got: '%s'", body) - } - - _, body = testRequest(t, ts, "GET", "/ping", nil) - if body != "pong" { - t.Fatalf("got: '%s'", body) - } -} - -func TestMuxRouteGroups(t *testing.T) { - var stdmwInit, stdmwHandler uint64 - - stdmw := func(next http.Handler) http.Handler { - stdmwInit++ - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - stdmwHandler++ - next.ServeHTTP(w, r) - }) - } - - var stdmwInit2, stdmwHandler2 uint64 - stdmw2 := func(next http.Handler) http.Handler { - stdmwInit2++ - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - stdmwHandler2++ - next.ServeHTTP(w, r) - }) - } - - r := NewRouter() - r.Group(func(r Router) { - r.Use(stdmw) - r.Get("/group", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("root group")) - }) - }) - r.Group(func(r Router) { - r.Use(stdmw2) - r.Get("/group2", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("root group2")) - }) - }) - - ts := httptest.NewServer(r) - defer ts.Close() - - // GET /group - _, body := testRequest(t, ts, "GET", "/group", nil) - if body != "root group" { - t.Fatalf("got: '%s'", body) - } - if stdmwInit != 1 || stdmwHandler != 1 { - t.Logf("stdmw counters failed, should be 1:1, got %d:%d", stdmwInit, stdmwHandler) - } - - // GET /group2 - _, body = testRequest(t, ts, "GET", "/group2", nil) - if body != "root group2" { - t.Fatalf("got: '%s'", body) - } - if stdmwInit2 != 1 || stdmwHandler2 != 1 { - t.Fatalf("stdmw2 counters failed, should be 1:1, got %d:%d", stdmwInit2, stdmwHandler2) - } -} - -func TestMuxBig(t *testing.T) { - r := bigMux() - - ts := httptest.NewServer(r) - defer ts.Close() - - var body, expected string - - _, body = testRequest(t, ts, "GET", "/favicon.ico", nil) - if body != "fav" { - t.Fatalf("got '%s'", body) - } - _, body = testRequest(t, ts, "GET", "/hubs/4/view", nil) - if body != "/hubs/4/view reqid:1 session:anonymous" { - t.Fatalf("got '%v'", body) - } - _, body = testRequest(t, ts, "GET", "/hubs/4/view/index.html", nil) - if body != "/hubs/4/view/index.html reqid:1 session:anonymous" { - t.Fatalf("got '%s'", body) - } - _, body = testRequest(t, ts, "POST", "/hubs/ethereumhub/view/index.html", nil) - if body != "/hubs/ethereumhub/view/index.html reqid:1 session:anonymous" { - t.Fatalf("got '%s'", body) - } - _, body = testRequest(t, ts, "GET", "/", nil) - if body != "/ reqid:1 session:elvis" { - t.Fatalf("got '%s'", body) - } - _, body = testRequest(t, ts, "GET", "/suggestions", nil) - if body != "/suggestions reqid:1 session:elvis" { - t.Fatalf("got '%s'", body) - } - _, body = testRequest(t, ts, "GET", "/woot/444/hiiii", nil) - if body != "/woot/444/hiiii" { - t.Fatalf("got '%s'", body) - } - _, body = testRequest(t, ts, "GET", "/hubs/123", nil) - expected = "/hubs/123 reqid:1 session:elvis" - if body != expected { - t.Fatalf("expected:%s got:%s", expected, body) - } - _, body = testRequest(t, ts, "GET", "/hubs/123/touch", nil) - if body != "/hubs/123/touch reqid:1 session:elvis" { - t.Fatalf("got '%s'", body) - } - _, body = testRequest(t, ts, "GET", "/hubs/123/webhooks", nil) - if body != "/hubs/123/webhooks reqid:1 session:elvis" { - t.Fatalf("got '%s'", body) - } - _, body = testRequest(t, ts, "GET", "/hubs/123/posts", nil) - if body != "/hubs/123/posts reqid:1 session:elvis" { - t.Fatalf("got '%s'", body) - } - _, body = testRequest(t, ts, "GET", "/folders", nil) - if body != "404 page not found\n" { - t.Fatalf("got '%s'", body) - } - _, body = testRequest(t, ts, "GET", "/folders/", nil) - if body != "/folders/ reqid:1 session:elvis" { - t.Fatalf("got '%s'", body) - } - _, body = testRequest(t, ts, "GET", "/folders/public", nil) - if body != "/folders/public reqid:1 session:elvis" { - t.Fatalf("got '%s'", body) - } - _, body = testRequest(t, ts, "GET", "/folders/nothing", nil) - if body != "404 page not found\n" { - t.Fatalf("got '%s'", body) - } -} - -func bigMux() Router { - var r, sr1, sr2, sr3, sr4, sr5, sr6 *Mux - r = NewRouter() - r.Use(func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := context.WithValue(r.Context(), ctxKey{"requestID"}, "1") - next.ServeHTTP(w, r.WithContext(ctx)) - }) - }) - r.Use(func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - next.ServeHTTP(w, r) - }) - }) - r.Group(func(r Router) { - r.Use(func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := context.WithValue(r.Context(), ctxKey{"session.user"}, "anonymous") - next.ServeHTTP(w, r.WithContext(ctx)) - }) - }) - r.Get("/favicon.ico", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("fav")) - }) - r.Get("/hubs/{hubID}/view", func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - s := fmt.Sprintf("/hubs/%s/view reqid:%s session:%s", URLParam(r, "hubID"), - ctx.Value(ctxKey{"requestID"}), ctx.Value(ctxKey{"session.user"})) - w.Write([]byte(s)) - }) - r.Get("/hubs/{hubID}/view/*", func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - s := fmt.Sprintf("/hubs/%s/view/%s reqid:%s session:%s", URLParamFromCtx(ctx, "hubID"), - URLParam(r, "*"), ctx.Value(ctxKey{"requestID"}), ctx.Value(ctxKey{"session.user"})) - w.Write([]byte(s)) - }) - r.Post("/hubs/{hubSlug}/view/*", func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - s := fmt.Sprintf("/hubs/%s/view/%s reqid:%s session:%s", URLParamFromCtx(ctx, "hubSlug"), - URLParam(r, "*"), ctx.Value(ctxKey{"requestID"}), ctx.Value(ctxKey{"session.user"})) - w.Write([]byte(s)) - }) - }) - r.Group(func(r Router) { - r.Use(func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := context.WithValue(r.Context(), ctxKey{"session.user"}, "elvis") - next.ServeHTTP(w, r.WithContext(ctx)) - }) - }) - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - s := fmt.Sprintf("/ reqid:%s session:%s", ctx.Value(ctxKey{"requestID"}), ctx.Value(ctxKey{"session.user"})) - w.Write([]byte(s)) - }) - r.Get("/suggestions", func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - s := fmt.Sprintf("/suggestions reqid:%s session:%s", ctx.Value(ctxKey{"requestID"}), ctx.Value(ctxKey{"session.user"})) - w.Write([]byte(s)) - }) - - r.Get("/woot/{wootID}/*", func(w http.ResponseWriter, r *http.Request) { - s := fmt.Sprintf("/woot/%s/%s", URLParam(r, "wootID"), URLParam(r, "*")) - w.Write([]byte(s)) - }) - - r.Route("/hubs", func(r Router) { - sr1 = r.(*Mux) - r.Route("/{hubID}", func(r Router) { - sr2 = r.(*Mux) - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - s := fmt.Sprintf("/hubs/%s reqid:%s session:%s", - URLParam(r, "hubID"), ctx.Value(ctxKey{"requestID"}), ctx.Value(ctxKey{"session.user"})) - w.Write([]byte(s)) - }) - r.Get("/touch", func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - s := fmt.Sprintf("/hubs/%s/touch reqid:%s session:%s", URLParam(r, "hubID"), - ctx.Value(ctxKey{"requestID"}), ctx.Value(ctxKey{"session.user"})) - w.Write([]byte(s)) - }) - - sr3 = NewRouter() - sr3.Get("/", func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - s := fmt.Sprintf("/hubs/%s/webhooks reqid:%s session:%s", URLParam(r, "hubID"), - ctx.Value(ctxKey{"requestID"}), ctx.Value(ctxKey{"session.user"})) - w.Write([]byte(s)) - }) - sr3.Route("/{webhookID}", func(r Router) { - sr4 = r.(*Mux) - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - s := fmt.Sprintf("/hubs/%s/webhooks/%s reqid:%s session:%s", URLParam(r, "hubID"), - URLParam(r, "webhookID"), ctx.Value(ctxKey{"requestID"}), ctx.Value(ctxKey{"session.user"})) - w.Write([]byte(s)) - }) - }) - - r.Mount("/webhooks", Chain(func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - next.ServeHTTP(w, r.WithContext(context.WithValue(r.Context(), ctxKey{"hook"}, true))) - }) - }).Handler(sr3)) - - r.Route("/posts", func(r Router) { - sr5 = r.(*Mux) - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - s := fmt.Sprintf("/hubs/%s/posts reqid:%s session:%s", URLParam(r, "hubID"), - ctx.Value(ctxKey{"requestID"}), ctx.Value(ctxKey{"session.user"})) - w.Write([]byte(s)) - }) - }) - }) - }) - - r.Route("/folders/", func(r Router) { - sr6 = r.(*Mux) - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - s := fmt.Sprintf("/folders/ reqid:%s session:%s", - ctx.Value(ctxKey{"requestID"}), ctx.Value(ctxKey{"session.user"})) - w.Write([]byte(s)) - }) - r.Get("/public", func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - s := fmt.Sprintf("/folders/public reqid:%s session:%s", - ctx.Value(ctxKey{"requestID"}), ctx.Value(ctxKey{"session.user"})) - w.Write([]byte(s)) - }) - }) - }) - - return r -} - -func TestMuxSubroutesBasic(t *testing.T) { - hIndex := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("index")) - }) - hArticlesList := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("articles-list")) - }) - hSearchArticles := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("search-articles")) - }) - hGetArticle := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(fmt.Sprintf("get-article:%s", URLParam(r, "id")))) - }) - hSyncArticle := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(fmt.Sprintf("sync-article:%s", URLParam(r, "id")))) - }) - - r := NewRouter() - var rr1, rr2 *Mux - r.Get("/", hIndex) - r.Route("/articles", func(r Router) { - rr1 = r.(*Mux) - r.Get("/", hArticlesList) - r.Get("/search", hSearchArticles) - r.Route("/{id}", func(r Router) { - rr2 = r.(*Mux) - r.Get("/", hGetArticle) - r.Get("/sync", hSyncArticle) - }) - }) - - // log.Println("~~~~~~~~~") - // log.Println("~~~~~~~~~") - // debugPrintTree(0, 0, r.tree, 0) - // log.Println("~~~~~~~~~") - // log.Println("~~~~~~~~~") - - // log.Println("~~~~~~~~~") - // log.Println("~~~~~~~~~") - // debugPrintTree(0, 0, rr1.tree, 0) - // log.Println("~~~~~~~~~") - // log.Println("~~~~~~~~~") - - // log.Println("~~~~~~~~~") - // log.Println("~~~~~~~~~") - // debugPrintTree(0, 0, rr2.tree, 0) - // log.Println("~~~~~~~~~") - // log.Println("~~~~~~~~~") - - ts := httptest.NewServer(r) - defer ts.Close() - - var body, expected string - - _, body = testRequest(t, ts, "GET", "/", nil) - expected = "index" - if body != expected { - t.Fatalf("expected:%s got:%s", expected, body) - } - _, body = testRequest(t, ts, "GET", "/articles", nil) - expected = "articles-list" - if body != expected { - t.Fatalf("expected:%s got:%s", expected, body) - } - _, body = testRequest(t, ts, "GET", "/articles/search", nil) - expected = "search-articles" - if body != expected { - t.Fatalf("expected:%s got:%s", expected, body) - } - _, body = testRequest(t, ts, "GET", "/articles/123", nil) - expected = "get-article:123" - if body != expected { - t.Fatalf("expected:%s got:%s", expected, body) - } - _, body = testRequest(t, ts, "GET", "/articles/123/sync", nil) - expected = "sync-article:123" - if body != expected { - t.Fatalf("expected:%s got:%s", expected, body) - } -} - -func TestMuxSubroutes(t *testing.T) { - hHubView1 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("hub1")) - }) - hHubView2 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("hub2")) - }) - hHubView3 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("hub3")) - }) - hAccountView1 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("account1")) - }) - hAccountView2 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("account2")) - }) - - r := NewRouter() - r.Get("/hubs/{hubID}/view", hHubView1) - r.Get("/hubs/{hubID}/view/*", hHubView2) - - sr := NewRouter() - sr.Get("/", hHubView3) - r.Mount("/hubs/{hubID}/users", sr) - r.Get("/hubs/{hubID}/users/", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("hub3 override")) - }) - - sr3 := NewRouter() - sr3.Get("/", hAccountView1) - sr3.Get("/hi", hAccountView2) - - var sr2 *Mux - r.Route("/accounts/{accountID}", func(r Router) { - sr2 = r.(*Mux) - // r.Get("/", hAccountView1) - r.Mount("/", sr3) - }) - - // This is the same as the r.Route() call mounted on sr2 - // sr2 := NewRouter() - // sr2.Mount("/", sr3) - // r.Mount("/accounts/{accountID}", sr2) - - ts := httptest.NewServer(r) - defer ts.Close() - - var body, expected string - - _, body = testRequest(t, ts, "GET", "/hubs/123/view", nil) - expected = "hub1" - if body != expected { - t.Fatalf("expected:%s got:%s", expected, body) - } - _, body = testRequest(t, ts, "GET", "/hubs/123/view/index.html", nil) - expected = "hub2" - if body != expected { - t.Fatalf("expected:%s got:%s", expected, body) - } - _, body = testRequest(t, ts, "GET", "/hubs/123/users", nil) - expected = "hub3" - if body != expected { - t.Fatalf("expected:%s got:%s", expected, body) - } - _, body = testRequest(t, ts, "GET", "/hubs/123/users/", nil) - expected = "hub3 override" - if body != expected { - t.Fatalf("expected:%s got:%s", expected, body) - } - _, body = testRequest(t, ts, "GET", "/accounts/44", nil) - expected = "account1" - if body != expected { - t.Fatalf("request:%s expected:%s got:%s", "GET /accounts/44", expected, body) - } - _, body = testRequest(t, ts, "GET", "/accounts/44/hi", nil) - expected = "account2" - if body != expected { - t.Fatalf("expected:%s got:%s", expected, body) - } - - // Test that we're building the routingPatterns properly - router := r - req, _ := http.NewRequest("GET", "/accounts/44/hi", nil) - - rctx := NewRouteContext() - req = req.WithContext(context.WithValue(req.Context(), RouteCtxKey, rctx)) - - w := httptest.NewRecorder() - router.ServeHTTP(w, req) - - body = string(w.Body.Bytes()) - expected = "account2" - if body != expected { - t.Fatalf("expected:%s got:%s", expected, body) - } - - routePatterns := rctx.RoutePatterns - if len(rctx.RoutePatterns) != 3 { - t.Fatalf("expected 3 routing patterns, got:%d", len(rctx.RoutePatterns)) - } - expected = "/accounts/{accountID}/*" - if routePatterns[0] != expected { - t.Fatalf("routePattern, expected:%s got:%s", expected, routePatterns[0]) - } - expected = "/*" - if routePatterns[1] != expected { - t.Fatalf("routePattern, expected:%s got:%s", expected, routePatterns[1]) - } - expected = "/hi" - if routePatterns[2] != expected { - t.Fatalf("routePattern, expected:%s got:%s", expected, routePatterns[2]) - } - -} - -func TestSingleHandler(t *testing.T) { - h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - name := URLParam(r, "name") - w.Write([]byte("hi " + name)) - }) - - r, _ := http.NewRequest("GET", "/", nil) - rctx := NewRouteContext() - r = r.WithContext(context.WithValue(r.Context(), RouteCtxKey, rctx)) - rctx.URLParams.Add("name", "joe") - - w := httptest.NewRecorder() - h.ServeHTTP(w, r) - - body := string(w.Body.Bytes()) - expected := "hi joe" - if body != expected { - t.Fatalf("expected:%s got:%s", expected, body) - } -} - -// TODO: a Router wrapper test.. -// -// type ACLMux struct { -// *Mux -// XX string -// } -// -// func NewACLMux() *ACLMux { -// return &ACLMux{Mux: NewRouter(), XX: "hihi"} -// } -// -// // TODO: this should be supported... -// func TestWoot(t *testing.T) { -// var r Router = NewRouter() -// -// var r2 Router = NewACLMux() //NewRouter() -// r2.Get("/hi", func(w http.ResponseWriter, r *http.Request) { -// w.Write([]byte("hi")) -// }) -// -// r.Mount("/", r2) -// } - -func TestServeHTTPExistingContext(t *testing.T) { - r := NewRouter() - r.Get("/hi", func(w http.ResponseWriter, r *http.Request) { - s, _ := r.Context().Value(ctxKey{"testCtx"}).(string) - w.Write([]byte(s)) - }) - r.NotFound(func(w http.ResponseWriter, r *http.Request) { - s, _ := r.Context().Value(ctxKey{"testCtx"}).(string) - w.WriteHeader(404) - w.Write([]byte(s)) - }) - - testcases := []struct { - Method string - Path string - Ctx context.Context - ExpectedStatus int - ExpectedBody string - }{ - { - Method: "GET", - Path: "/hi", - Ctx: context.WithValue(context.Background(), ctxKey{"testCtx"}, "hi ctx"), - ExpectedStatus: 200, - ExpectedBody: "hi ctx", - }, - { - Method: "GET", - Path: "/hello", - Ctx: context.WithValue(context.Background(), ctxKey{"testCtx"}, "nothing here ctx"), - ExpectedStatus: 404, - ExpectedBody: "nothing here ctx", - }, - } - - for _, tc := range testcases { - resp := httptest.NewRecorder() - req, err := http.NewRequest(tc.Method, tc.Path, nil) - if err != nil { - t.Fatalf("%v", err) - } - req = req.WithContext(tc.Ctx) - r.ServeHTTP(resp, req) - b, err := ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatalf("%v", err) - } - if resp.Code != tc.ExpectedStatus { - t.Fatalf("%v != %v", tc.ExpectedStatus, resp.Code) - } - if string(b) != tc.ExpectedBody { - t.Fatalf("%s != %s", tc.ExpectedBody, b) - } - } -} - -func TestNestedGroups(t *testing.T) { - handlerPrintCounter := func(w http.ResponseWriter, r *http.Request) { - counter, _ := r.Context().Value(ctxKey{"counter"}).(int) - w.Write([]byte(fmt.Sprintf("%v", counter))) - } - - mwIncreaseCounter := func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - counter, _ := ctx.Value(ctxKey{"counter"}).(int) - counter++ - ctx = context.WithValue(ctx, ctxKey{"counter"}, counter) - next.ServeHTTP(w, r.WithContext(ctx)) - }) - } - - // Each route represents value of its counter (number of applied middlewares). - r := NewRouter() // counter == 0 - r.Get("/0", handlerPrintCounter) - r.Group(func(r Router) { - r.Use(mwIncreaseCounter) // counter == 1 - r.Get("/1", handlerPrintCounter) - - // r.Handle(GET, "/2", Chain(mwIncreaseCounter).HandlerFunc(handlerPrintCounter)) - r.With(mwIncreaseCounter).Get("/2", handlerPrintCounter) - - r.Group(func(r Router) { - r.Use(mwIncreaseCounter, mwIncreaseCounter) // counter == 3 - r.Get("/3", handlerPrintCounter) - }) - r.Route("/", func(r Router) { - r.Use(mwIncreaseCounter, mwIncreaseCounter) // counter == 3 - - // r.Handle(GET, "/4", Chain(mwIncreaseCounter).HandlerFunc(handlerPrintCounter)) - r.With(mwIncreaseCounter).Get("/4", handlerPrintCounter) - - r.Group(func(r Router) { - r.Use(mwIncreaseCounter, mwIncreaseCounter) // counter == 5 - r.Get("/5", handlerPrintCounter) - // r.Handle(GET, "/6", Chain(mwIncreaseCounter).HandlerFunc(handlerPrintCounter)) - r.With(mwIncreaseCounter).Get("/6", handlerPrintCounter) - - }) - }) - }) - - ts := httptest.NewServer(r) - defer ts.Close() - - for _, route := range []string{"0", "1", "2", "3", "4", "5", "6"} { - if _, body := testRequest(t, ts, "GET", "/"+route, nil); body != route { - t.Errorf("expected %v, got %v", route, body) - } - } -} - -func TestMiddlewarePanicOnLateUse(t *testing.T) { - handler := func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("hello\n")) - } - - mw := func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - next.ServeHTTP(w, r) - }) - } - - defer func() { - if recover() == nil { - t.Error("expected panic()") - } - }() - - r := NewRouter() - r.Get("/", handler) - r.Use(mw) // Too late to apply middleware, we're expecting panic(). -} - -func TestMountingExistingPath(t *testing.T) { - handler := func(w http.ResponseWriter, r *http.Request) {} - - defer func() { - if recover() == nil { - t.Error("expected panic()") - } - }() - - r := NewRouter() - r.Get("/", handler) - r.Mount("/hi", http.HandlerFunc(handler)) - r.Mount("/hi", http.HandlerFunc(handler)) -} - -func TestMountingSimilarPattern(t *testing.T) { - r := NewRouter() - r.Get("/hi", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("bye")) - }) - - r2 := NewRouter() - r2.Get("/", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("foobar")) - }) - - r3 := NewRouter() - r3.Get("/", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("foo")) - }) - - r.Mount("/foobar", r2) - r.Mount("/foo", r3) - - ts := httptest.NewServer(r) - defer ts.Close() - - if _, body := testRequest(t, ts, "GET", "/hi", nil); body != "bye" { - t.Fatalf(body) - } -} - -func TestMuxEmptyParams(t *testing.T) { - r := NewRouter() - r.Get(`/users/{x}/{y}/{z}`, func(w http.ResponseWriter, r *http.Request) { - x := URLParam(r, "x") - y := URLParam(r, "y") - z := URLParam(r, "z") - w.Write([]byte(fmt.Sprintf("%s-%s-%s", x, y, z))) - }) - - ts := httptest.NewServer(r) - defer ts.Close() - - if _, body := testRequest(t, ts, "GET", "/users/a/b/c", nil); body != "a-b-c" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "GET", "/users///c", nil); body != "--c" { - t.Fatalf(body) - } -} - -func TestMuxMissingParams(t *testing.T) { - r := NewRouter() - r.Get(`/user/{userId:\d+}`, func(w http.ResponseWriter, r *http.Request) { - userID := URLParam(r, "userId") - w.Write([]byte(fmt.Sprintf("userId = '%s'", userID))) - }) - r.NotFound(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(404) - w.Write([]byte("nothing here")) - }) - - ts := httptest.NewServer(r) - defer ts.Close() - - if _, body := testRequest(t, ts, "GET", "/user/123", nil); body != "userId = '123'" { - t.Fatalf(body) - } - if _, body := testRequest(t, ts, "GET", "/user/", nil); body != "nothing here" { - t.Fatalf(body) - } -} - -func TestMuxContextIsThreadSafe(t *testing.T) { - router := NewRouter() - router.Get("/{id}", func(w http.ResponseWriter, r *http.Request) { - ctx, cancel := context.WithTimeout(r.Context(), 1*time.Millisecond) - defer cancel() - - <-ctx.Done() - }) - - wg := sync.WaitGroup{} - - for i := 0; i < 100; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for j := 0; j < 10000; j++ { - w := httptest.NewRecorder() - r, err := http.NewRequest("GET", "/ok", nil) - if err != nil { - t.Fatal(err) - } - - ctx, cancel := context.WithCancel(r.Context()) - r = r.WithContext(ctx) - - go func() { - cancel() - }() - router.ServeHTTP(w, r) - } - }() - } - wg.Wait() -} - -func TestEscapedURLParams(t *testing.T) { - m := NewRouter() - m.Get("/api/{identifier}/{region}/{size}/{rotation}/*", func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(200) - rctx := RouteContext(r.Context()) - if rctx == nil { - t.Error("no context") - return - } - identifier := URLParam(r, "identifier") - if identifier != "http:%2f%2fexample.com%2fimage.png" { - t.Errorf("identifier path parameter incorrect %s", identifier) - return - } - region := URLParam(r, "region") - if region != "full" { - t.Errorf("region path parameter incorrect %s", region) - return - } - size := URLParam(r, "size") - if size != "max" { - t.Errorf("size path parameter incorrect %s", size) - return - } - rotation := URLParam(r, "rotation") - if rotation != "0" { - t.Errorf("rotation path parameter incorrect %s", rotation) - return - } - w.Write([]byte("success")) - }) - - ts := httptest.NewServer(m) - defer ts.Close() - - if _, body := testRequest(t, ts, "GET", "/api/http:%2f%2fexample.com%2fimage.png/full/max/0/color.png", nil); body != "success" { - t.Fatalf(body) - } -} - -func TestMuxMatch(t *testing.T) { - r := NewRouter() - r.Get("/hi", func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("X-Test", "yes") - w.Write([]byte("bye")) - }) - r.Route("/articles", func(r Router) { - r.Get("/{id}", func(w http.ResponseWriter, r *http.Request) { - id := URLParam(r, "id") - w.Header().Set("X-Article", id) - w.Write([]byte("article:" + id)) - }) - }) - r.Route("/users", func(r Router) { - r.Head("/{id}", func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("X-User", "-") - w.Write([]byte("user")) - }) - r.Get("/{id}", func(w http.ResponseWriter, r *http.Request) { - id := URLParam(r, "id") - w.Header().Set("X-User", id) - w.Write([]byte("user:" + id)) - }) - }) - - tctx := NewRouteContext() - - tctx.Reset() - if r.Match(tctx, "GET", "/users/1") == false { - t.Fatal("expecting to find match for route:", "GET", "/users/1") - } - - tctx.Reset() - if r.Match(tctx, "HEAD", "/articles/10") == true { - t.Fatal("not expecting to find match for route:", "HEAD", "/articles/10") - } -} - -func TestServerBaseContext(t *testing.T) { - r := NewRouter() - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - baseYes := r.Context().Value(ctxKey{"base"}).(string) - if _, ok := r.Context().Value(http.ServerContextKey).(*http.Server); !ok { - panic("missing server context") - } - if _, ok := r.Context().Value(http.LocalAddrContextKey).(net.Addr); !ok { - panic("missing local addr context") - } - w.Write([]byte(baseYes)) - }) - - // Setup http Server with a base context - ctx := context.WithValue(context.Background(), ctxKey{"base"}, "yes") - ts := httptest.NewServer(ServerBaseContext(ctx, r)) - defer ts.Close() - - if _, body := testRequest(t, ts, "GET", "/", nil); body != "yes" { - t.Fatalf(body) - } -} - -func testRequest(t *testing.T, ts *httptest.Server, method, path string, body io.Reader) (*http.Response, string) { - req, err := http.NewRequest(method, ts.URL+path, body) - if err != nil { - t.Fatal(err) - return nil, "" - } - - resp, err := http.DefaultClient.Do(req) - if err != nil { - t.Fatal(err) - return nil, "" - } - - respBody, err := ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatal(err) - return nil, "" - } - defer resp.Body.Close() - - return resp, string(respBody) -} - -func testHandler(t *testing.T, h http.Handler, method, path string, body io.Reader) (*http.Response, string) { - r, _ := http.NewRequest(method, path, body) - w := httptest.NewRecorder() - h.ServeHTTP(w, r) - return w.Result(), string(w.Body.Bytes()) -} - -type testFileSystem struct { - open func(name string) (http.File, error) -} - -func (fs *testFileSystem) Open(name string) (http.File, error) { - return fs.open(name) -} - -type testFile struct { - name string - contents []byte -} - -func (tf *testFile) Close() error { - return nil -} - -func (tf *testFile) Read(p []byte) (n int, err error) { - copy(p, tf.contents) - return len(p), nil -} - -func (tf *testFile) Seek(offset int64, whence int) (int64, error) { - return 0, nil -} - -func (tf *testFile) Readdir(count int) ([]os.FileInfo, error) { - stat, _ := tf.Stat() - return []os.FileInfo{stat}, nil -} - -func (tf *testFile) Stat() (os.FileInfo, error) { - return &testFileInfo{tf.name, int64(len(tf.contents))}, nil -} - -type testFileInfo struct { - name string - size int64 -} - -func (tfi *testFileInfo) Name() string { return tfi.name } -func (tfi *testFileInfo) Size() int64 { return tfi.size } -func (tfi *testFileInfo) Mode() os.FileMode { return 0755 } -func (tfi *testFileInfo) ModTime() time.Time { return time.Now() } -func (tfi *testFileInfo) IsDir() bool { return false } -func (tfi *testFileInfo) Sys() interface{} { return nil } - -type ctxKey struct { - name string -} - -func (k ctxKey) String() string { - return "context value " + k.name -} - -func BenchmarkMux(b *testing.B) { - h1 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - h2 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - h3 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - h4 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - h5 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - h6 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - - mx := NewRouter() - mx.Get("/", h1) - mx.Get("/hi", h2) - mx.Get("/sup/{id}/and/{this}", h3) - - mx.Route("/sharing/{hash}", func(mx Router) { - mx.Get("/", h4) // subrouter-1 - mx.Get("/{network}", h5) // subrouter-1 - mx.Get("/twitter", h5) - mx.Route("/direct", func(mx Router) { - mx.Get("/", h6) // subrouter-2 - }) - }) - - routes := []string{ - "/", - "/sup/123/and/this", - "/sharing/aBc", // subrouter-1 - "/sharing/aBc/twitter", // subrouter-1 - "/sharing/aBc/direct", // subrouter-2 - } - - for _, path := range routes { - b.Run("route:"+path, func(b *testing.B) { - w := httptest.NewRecorder() - r, _ := http.NewRequest("GET", path, nil) - - b.ReportAllocs() - b.ResetTimer() - - for i := 0; i < b.N; i++ { - mx.ServeHTTP(w, r) - } - }) - } -} diff --git a/vendor/github.com/go-chi/chi/tree_test.go b/vendor/github.com/go-chi/chi/tree_test.go deleted file mode 100644 index 89a835ca..00000000 --- a/vendor/github.com/go-chi/chi/tree_test.go +++ /dev/null @@ -1,467 +0,0 @@ -package chi - -import ( - "fmt" - "log" - "net/http" - "testing" -) - -func TestTree(t *testing.T) { - hStub := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hIndex := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hFavicon := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hArticleList := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hArticleNear := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hArticleShow := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hArticleShowRelated := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hArticleShowOpts := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hArticleSlug := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hArticleByUser := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hUserList := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hUserShow := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hAdminCatchall := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hAdminAppShow := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hAdminAppShowCatchall := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hUserProfile := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hUserSuper := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hUserAll := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hHubView1 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hHubView2 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hHubView3 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - - tr := &node{} - - tr.InsertRoute(mGET, "/", hIndex) - tr.InsertRoute(mGET, "/favicon.ico", hFavicon) - - tr.InsertRoute(mGET, "/pages/*", hStub) - - tr.InsertRoute(mGET, "/article", hArticleList) - tr.InsertRoute(mGET, "/article/", hArticleList) - - tr.InsertRoute(mGET, "/article/near", hArticleNear) - tr.InsertRoute(mGET, "/article/{id}", hStub) - tr.InsertRoute(mGET, "/article/{id}", hArticleShow) - tr.InsertRoute(mGET, "/article/{id}", hArticleShow) // duplicate will have no effect - tr.InsertRoute(mGET, "/article/@{user}", hArticleByUser) - - tr.InsertRoute(mGET, "/article/{sup}/{opts}", hArticleShowOpts) - tr.InsertRoute(mGET, "/article/{id}/{opts}", hArticleShowOpts) // overwrite above route, latest wins - - tr.InsertRoute(mGET, "/article/{iffd}/edit", hStub) - tr.InsertRoute(mGET, "/article/{id}//related", hArticleShowRelated) - tr.InsertRoute(mGET, "/article/slug/{month}/-/{day}/{year}", hArticleSlug) - - tr.InsertRoute(mGET, "/admin/user", hUserList) - tr.InsertRoute(mGET, "/admin/user/", hStub) // will get replaced by next route - tr.InsertRoute(mGET, "/admin/user/", hUserList) - - tr.InsertRoute(mGET, "/admin/user//{id}", hUserShow) - tr.InsertRoute(mGET, "/admin/user/{id}", hUserShow) - - tr.InsertRoute(mGET, "/admin/apps/{id}", hAdminAppShow) - tr.InsertRoute(mGET, "/admin/apps/{id}/*ff", hAdminAppShowCatchall) // TODO: ALLOWED...? prob not.. panic..? - - tr.InsertRoute(mGET, "/admin/*ff", hStub) // catchall segment will get replaced by next route - tr.InsertRoute(mGET, "/admin/*", hAdminCatchall) - - tr.InsertRoute(mGET, "/users/{userID}/profile", hUserProfile) - tr.InsertRoute(mGET, "/users/super/*", hUserSuper) - tr.InsertRoute(mGET, "/users/*", hUserAll) - - tr.InsertRoute(mGET, "/hubs/{hubID}/view", hHubView1) - tr.InsertRoute(mGET, "/hubs/{hubID}/view/*", hHubView2) - sr := NewRouter() - sr.Get("/users", hHubView3) - tr.InsertRoute(mGET, "/hubs/{hubID}/*", sr) - tr.InsertRoute(mGET, "/hubs/{hubID}/users", hHubView3) - - tests := []struct { - r string // input request path - h http.Handler // output matched handler - k []string // output param keys - v []string // output param values - }{ - {r: "/", h: hIndex, k: []string{}, v: []string{}}, - {r: "/favicon.ico", h: hFavicon, k: []string{}, v: []string{}}, - - {r: "/pages", h: nil, k: []string{}, v: []string{}}, - {r: "/pages/", h: hStub, k: []string{"*"}, v: []string{""}}, - {r: "/pages/yes", h: hStub, k: []string{"*"}, v: []string{"yes"}}, - - {r: "/article", h: hArticleList, k: []string{}, v: []string{}}, - {r: "/article/", h: hArticleList, k: []string{}, v: []string{}}, - {r: "/article/near", h: hArticleNear, k: []string{}, v: []string{}}, - {r: "/article/neard", h: hArticleShow, k: []string{"id"}, v: []string{"neard"}}, - {r: "/article/123", h: hArticleShow, k: []string{"id"}, v: []string{"123"}}, - {r: "/article/123/456", h: hArticleShowOpts, k: []string{"id", "opts"}, v: []string{"123", "456"}}, - {r: "/article/@peter", h: hArticleByUser, k: []string{"user"}, v: []string{"peter"}}, - {r: "/article/22//related", h: hArticleShowRelated, k: []string{"id"}, v: []string{"22"}}, - {r: "/article/111/edit", h: hStub, k: []string{"iffd"}, v: []string{"111"}}, - {r: "/article/slug/sept/-/4/2015", h: hArticleSlug, k: []string{"month", "day", "year"}, v: []string{"sept", "4", "2015"}}, - {r: "/article/:id", h: hArticleShow, k: []string{"id"}, v: []string{":id"}}, - - {r: "/admin/user", h: hUserList, k: []string{}, v: []string{}}, - {r: "/admin/user/", h: hUserList, k: []string{}, v: []string{}}, - {r: "/admin/user/1", h: hUserShow, k: []string{"id"}, v: []string{"1"}}, - {r: "/admin/user//1", h: hUserShow, k: []string{"id"}, v: []string{"1"}}, - {r: "/admin/hi", h: hAdminCatchall, k: []string{"*"}, v: []string{"hi"}}, - {r: "/admin/lots/of/:fun", h: hAdminCatchall, k: []string{"*"}, v: []string{"lots/of/:fun"}}, - {r: "/admin/apps/333", h: hAdminAppShow, k: []string{"id"}, v: []string{"333"}}, - {r: "/admin/apps/333/woot", h: hAdminAppShowCatchall, k: []string{"id", "*"}, v: []string{"333", "woot"}}, - - {r: "/hubs/123/view", h: hHubView1, k: []string{"hubID"}, v: []string{"123"}}, - {r: "/hubs/123/view/index.html", h: hHubView2, k: []string{"hubID", "*"}, v: []string{"123", "index.html"}}, - {r: "/hubs/123/users", h: hHubView3, k: []string{"hubID"}, v: []string{"123"}}, - - {r: "/users/123/profile", h: hUserProfile, k: []string{"userID"}, v: []string{"123"}}, - {r: "/users/super/123/okay/yes", h: hUserSuper, k: []string{"*"}, v: []string{"123/okay/yes"}}, - {r: "/users/123/okay/yes", h: hUserAll, k: []string{"*"}, v: []string{"123/okay/yes"}}, - } - - // log.Println("~~~~~~~~~") - // log.Println("~~~~~~~~~") - // debugPrintTree(0, 0, tr, 0) - // log.Println("~~~~~~~~~") - // log.Println("~~~~~~~~~") - - for i, tt := range tests { - rctx := NewRouteContext() - - _, handlers, _ := tr.FindRoute(rctx, mGET, tt.r) - - var handler http.Handler - if methodHandler, ok := handlers[mGET]; ok { - handler = methodHandler.handler - } - - paramKeys := rctx.routeParams.Keys - paramValues := rctx.routeParams.Values - - if fmt.Sprintf("%v", tt.h) != fmt.Sprintf("%v", handler) { - t.Errorf("input [%d]: find '%s' expecting handler:%v , got:%v", i, tt.r, tt.h, handler) - } - if !stringSliceEqual(tt.k, paramKeys) { - t.Errorf("input [%d]: find '%s' expecting paramKeys:(%d)%v , got:(%d)%v", i, tt.r, len(tt.k), tt.k, len(paramKeys), paramKeys) - } - if !stringSliceEqual(tt.v, paramValues) { - t.Errorf("input [%d]: find '%s' expecting paramValues:(%d)%v , got:(%d)%v", i, tt.r, len(tt.v), tt.v, len(paramValues), paramValues) - } - } -} - -func TestTreeMoar(t *testing.T) { - hStub := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub1 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub2 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub3 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub4 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub5 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub6 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub7 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub8 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub9 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub10 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub11 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub12 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub13 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub14 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub15 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub16 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - - // TODO: panic if we see {id}{x} because we're missing a delimiter, its not possible. - // also {:id}* is not possible. - - tr := &node{} - - tr.InsertRoute(mGET, "/articlefun", hStub5) - tr.InsertRoute(mGET, "/articles/{id}", hStub) - tr.InsertRoute(mDELETE, "/articles/{slug}", hStub8) - tr.InsertRoute(mGET, "/articles/search", hStub1) - tr.InsertRoute(mGET, "/articles/{id}:delete", hStub8) - tr.InsertRoute(mGET, "/articles/{iidd}!sup", hStub4) - tr.InsertRoute(mGET, "/articles/{id}:{op}", hStub3) - tr.InsertRoute(mGET, "/articles/{id}:{op}", hStub2) // this route sets a new handler for the above route - tr.InsertRoute(mGET, "/articles/{slug:^[a-z]+}/posts", hStub) // up to tail '/' will only match if contents match the rex - tr.InsertRoute(mGET, "/articles/{id}/posts/{pid}", hStub6) // /articles/123/posts/1 - tr.InsertRoute(mGET, "/articles/{id}/posts/{month}/{day}/{year}/{slug}", hStub7) // /articles/123/posts/09/04/1984/juice - tr.InsertRoute(mGET, "/articles/{id}.json", hStub10) - tr.InsertRoute(mGET, "/articles/{id}/data.json", hStub11) - tr.InsertRoute(mGET, "/articles/files/{file}.{ext}", hStub12) - tr.InsertRoute(mPUT, "/articles/me", hStub13) - - // TODO: make a separate test case for this one.. - // tr.InsertRoute(mGET, "/articles/{id}/{id}", hStub1) // panic expected, we're duplicating param keys - - tr.InsertRoute(mGET, "/pages/*ff", hStub) // TODO: panic, allow it..? - tr.InsertRoute(mGET, "/pages/*", hStub9) - - tr.InsertRoute(mGET, "/users/{id}", hStub14) - tr.InsertRoute(mGET, "/users/{id}/settings/{key}", hStub15) - tr.InsertRoute(mGET, "/users/{id}/settings/*", hStub16) - - tests := []struct { - m methodTyp // input request http method - r string // input request path - h http.Handler // output matched handler - k []string // output param keys - v []string // output param values - }{ - {m: mGET, r: "/articles/search", h: hStub1, k: []string{}, v: []string{}}, - {m: mGET, r: "/articlefun", h: hStub5, k: []string{}, v: []string{}}, - {m: mGET, r: "/articles/123", h: hStub, k: []string{"id"}, v: []string{"123"}}, - {m: mDELETE, r: "/articles/123mm", h: hStub8, k: []string{"slug"}, v: []string{"123mm"}}, - {m: mGET, r: "/articles/789:delete", h: hStub8, k: []string{"id"}, v: []string{"789"}}, - {m: mGET, r: "/articles/789!sup", h: hStub4, k: []string{"iidd"}, v: []string{"789"}}, - {m: mGET, r: "/articles/123:sync", h: hStub2, k: []string{"id", "op"}, v: []string{"123", "sync"}}, - {m: mGET, r: "/articles/456/posts/1", h: hStub6, k: []string{"id", "pid"}, v: []string{"456", "1"}}, - {m: mGET, r: "/articles/456/posts/09/04/1984/juice", h: hStub7, k: []string{"id", "month", "day", "year", "slug"}, v: []string{"456", "09", "04", "1984", "juice"}}, - {m: mGET, r: "/articles/456.json", h: hStub10, k: []string{"id"}, v: []string{"456"}}, - {m: mGET, r: "/articles/456/data.json", h: hStub11, k: []string{"id"}, v: []string{"456"}}, - - {m: mGET, r: "/articles/files/file.zip", h: hStub12, k: []string{"file", "ext"}, v: []string{"file", "zip"}}, - {m: mGET, r: "/articles/files/photos.tar.gz", h: hStub12, k: []string{"file", "ext"}, v: []string{"photos", "tar.gz"}}, - {m: mGET, r: "/articles/files/photos.tar.gz", h: hStub12, k: []string{"file", "ext"}, v: []string{"photos", "tar.gz"}}, - - {m: mPUT, r: "/articles/me", h: hStub13, k: []string{}, v: []string{}}, - {m: mGET, r: "/articles/me", h: hStub, k: []string{"id"}, v: []string{"me"}}, - {m: mGET, r: "/pages", h: nil, k: []string{}, v: []string{}}, - {m: mGET, r: "/pages/", h: hStub9, k: []string{"*"}, v: []string{""}}, - {m: mGET, r: "/pages/yes", h: hStub9, k: []string{"*"}, v: []string{"yes"}}, - - {m: mGET, r: "/users/1", h: hStub14, k: []string{"id"}, v: []string{"1"}}, - {m: mGET, r: "/users/", h: nil, k: []string{}, v: []string{}}, - {m: mGET, r: "/users/2/settings/password", h: hStub15, k: []string{"id", "key"}, v: []string{"2", "password"}}, - {m: mGET, r: "/users/2/settings/", h: hStub16, k: []string{"id", "*"}, v: []string{"2", ""}}, - } - - // log.Println("~~~~~~~~~") - // log.Println("~~~~~~~~~") - // debugPrintTree(0, 0, tr, 0) - // log.Println("~~~~~~~~~") - // log.Println("~~~~~~~~~") - - for i, tt := range tests { - rctx := NewRouteContext() - - _, handlers, _ := tr.FindRoute(rctx, tt.m, tt.r) - - var handler http.Handler - if methodHandler, ok := handlers[tt.m]; ok { - handler = methodHandler.handler - } - - paramKeys := rctx.routeParams.Keys - paramValues := rctx.routeParams.Values - - if fmt.Sprintf("%v", tt.h) != fmt.Sprintf("%v", handler) { - t.Errorf("input [%d]: find '%s' expecting handler:%v , got:%v", i, tt.r, tt.h, handler) - } - if !stringSliceEqual(tt.k, paramKeys) { - t.Errorf("input [%d]: find '%s' expecting paramKeys:(%d)%v , got:(%d)%v", i, tt.r, len(tt.k), tt.k, len(paramKeys), paramKeys) - } - if !stringSliceEqual(tt.v, paramValues) { - t.Errorf("input [%d]: find '%s' expecting paramValues:(%d)%v , got:(%d)%v", i, tt.r, len(tt.v), tt.v, len(paramValues), paramValues) - } - } -} - -func TestTreeRegexp(t *testing.T) { - hStub1 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub2 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub3 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub4 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub5 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub6 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub7 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - - tr := &node{} - tr.InsertRoute(mGET, "/articles/{rid:^[0-9]{5,6}}", hStub7) - tr.InsertRoute(mGET, "/articles/{zid:^0[0-9]+}", hStub3) - tr.InsertRoute(mGET, "/articles/{name:^@[a-z]+}/posts", hStub4) - tr.InsertRoute(mGET, "/articles/{op:^[0-9]+}/run", hStub5) - tr.InsertRoute(mGET, "/articles/{id:^[0-9]+}", hStub1) - tr.InsertRoute(mGET, "/articles/{id:^[1-9]+}-{aux}", hStub6) - tr.InsertRoute(mGET, "/articles/{slug}", hStub2) - - // log.Println("~~~~~~~~~") - // log.Println("~~~~~~~~~") - // debugPrintTree(0, 0, tr, 0) - // log.Println("~~~~~~~~~") - // log.Println("~~~~~~~~~") - - tests := []struct { - r string // input request path - h http.Handler // output matched handler - k []string // output param keys - v []string // output param values - }{ - {r: "/articles", h: nil, k: []string{}, v: []string{}}, - {r: "/articles/12345", h: hStub7, k: []string{"rid"}, v: []string{"12345"}}, - {r: "/articles/123", h: hStub1, k: []string{"id"}, v: []string{"123"}}, - {r: "/articles/how-to-build-a-router", h: hStub2, k: []string{"slug"}, v: []string{"how-to-build-a-router"}}, - {r: "/articles/0456", h: hStub3, k: []string{"zid"}, v: []string{"0456"}}, - {r: "/articles/@pk/posts", h: hStub4, k: []string{"name"}, v: []string{"@pk"}}, - {r: "/articles/1/run", h: hStub5, k: []string{"op"}, v: []string{"1"}}, - {r: "/articles/1122", h: hStub1, k: []string{"id"}, v: []string{"1122"}}, - {r: "/articles/1122-yes", h: hStub6, k: []string{"id", "aux"}, v: []string{"1122", "yes"}}, - } - - for i, tt := range tests { - rctx := NewRouteContext() - - _, handlers, _ := tr.FindRoute(rctx, mGET, tt.r) - - var handler http.Handler - if methodHandler, ok := handlers[mGET]; ok { - handler = methodHandler.handler - } - - paramKeys := rctx.routeParams.Keys - paramValues := rctx.routeParams.Values - - if fmt.Sprintf("%v", tt.h) != fmt.Sprintf("%v", handler) { - t.Errorf("input [%d]: find '%s' expecting handler:%v , got:%v", i, tt.r, tt.h, handler) - } - if !stringSliceEqual(tt.k, paramKeys) { - t.Errorf("input [%d]: find '%s' expecting paramKeys:(%d)%v , got:(%d)%v", i, tt.r, len(tt.k), tt.k, len(paramKeys), paramKeys) - } - if !stringSliceEqual(tt.v, paramValues) { - t.Errorf("input [%d]: find '%s' expecting paramValues:(%d)%v , got:(%d)%v", i, tt.r, len(tt.v), tt.v, len(paramValues), paramValues) - } - } -} - -func TestTreeRegexMatchWholeParam(t *testing.T) { - hStub1 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - - rctx := NewRouteContext() - tr := &node{} - tr.InsertRoute(mGET, "/{id:[0-9]+}", hStub1) - - tests := []struct { - url string - expectedHandler http.Handler - }{ - {url: "/13", expectedHandler: hStub1}, - {url: "/a13", expectedHandler: nil}, - {url: "/13.jpg", expectedHandler: nil}, - {url: "/a13.jpg", expectedHandler: nil}, - } - - for _, tc := range tests { - _, _, handler := tr.FindRoute(rctx, mGET, tc.url) - if fmt.Sprintf("%v", tc.expectedHandler) != fmt.Sprintf("%v", handler) { - t.Errorf("expecting handler:%v , got:%v", tc.expectedHandler, handler) - } - } -} - -func TestTreeFindPattern(t *testing.T) { - hStub1 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub2 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - hStub3 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - - tr := &node{} - tr.InsertRoute(mGET, "/pages/*", hStub1) - tr.InsertRoute(mGET, "/articles/{id}/*", hStub2) - tr.InsertRoute(mGET, "/articles/{slug}/{uid}/*", hStub3) - - if tr.findPattern("/pages") != false { - t.Errorf("find /pages failed") - } - if tr.findPattern("/pages*") != false { - t.Errorf("find /pages* failed - should be nil") - } - if tr.findPattern("/pages/*") == false { - t.Errorf("find /pages/* failed") - } - if tr.findPattern("/articles/{id}/*") == false { - t.Errorf("find /articles/{id}/* failed") - } - if tr.findPattern("/articles/{something}/*") == false { - t.Errorf("find /articles/{something}/* failed") - } - if tr.findPattern("/articles/{slug}/{uid}/*") == false { - t.Errorf("find /articles/{slug}/{uid}/* failed") - } -} - -func debugPrintTree(parent int, i int, n *node, label byte) bool { - numEdges := 0 - for _, nds := range n.children { - numEdges += len(nds) - } - - // if n.handlers != nil { - // log.Printf("[node %d parent:%d] typ:%d prefix:%s label:%s tail:%s numEdges:%d isLeaf:%v handler:%v pat:%s keys:%v\n", i, parent, n.typ, n.prefix, string(label), string(n.tail), numEdges, n.isLeaf(), n.handlers, n.pattern, n.paramKeys) - // } else { - // log.Printf("[node %d parent:%d] typ:%d prefix:%s label:%s tail:%s numEdges:%d isLeaf:%v pat:%s keys:%v\n", i, parent, n.typ, n.prefix, string(label), string(n.tail), numEdges, n.isLeaf(), n.pattern, n.paramKeys) - // } - if n.endpoints != nil { - log.Printf("[node %d parent:%d] typ:%d prefix:%s label:%s tail:%s numEdges:%d isLeaf:%v handler:%v\n", i, parent, n.typ, n.prefix, string(label), string(n.tail), numEdges, n.isLeaf(), n.endpoints) - } else { - log.Printf("[node %d parent:%d] typ:%d prefix:%s label:%s tail:%s numEdges:%d isLeaf:%v\n", i, parent, n.typ, n.prefix, string(label), string(n.tail), numEdges, n.isLeaf()) - } - parent = i - for _, nds := range n.children { - for _, e := range nds { - i++ - if debugPrintTree(parent, i, e, e.label) { - return true - } - } - } - return false -} - -func stringSliceEqual(a, b []string) bool { - if len(a) != len(b) { - return false - } - for i := range a { - if b[i] != a[i] { - return false - } - } - return true -} - -func BenchmarkTreeGet(b *testing.B) { - h1 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - h2 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - - tr := &node{} - tr.InsertRoute(mGET, "/", h1) - tr.InsertRoute(mGET, "/ping", h2) - tr.InsertRoute(mGET, "/pingall", h2) - tr.InsertRoute(mGET, "/ping/{id}", h2) - tr.InsertRoute(mGET, "/ping/{id}/woop", h2) - tr.InsertRoute(mGET, "/ping/{id}/{opt}", h2) - tr.InsertRoute(mGET, "/pinggggg", h2) - tr.InsertRoute(mGET, "/hello", h1) - - mctx := NewRouteContext() - - b.ReportAllocs() - b.ResetTimer() - - for i := 0; i < b.N; i++ { - mctx.Reset() - tr.FindRoute(mctx, mGET, "/ping/123/456") - } -} - -func TestWalker(t *testing.T) { - r := bigMux() - - // Walk the muxBig router tree. - if err := Walk(r, func(method string, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error { - t.Logf("%v %v", method, route) - - return nil - }); err != nil { - t.Error(err) - } -} diff --git a/vendor/github.com/golang/protobuf/.gitignore b/vendor/github.com/golang/protobuf/.gitignore deleted file mode 100644 index 8f5b596b..00000000 --- a/vendor/github.com/golang/protobuf/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -.DS_Store -*.[568ao] -*.ao -*.so -*.pyc -._* -.nfs.* -[568a].out -*~ -*.orig -core -_obj -_test -_testmain.go -protoc-gen-go/testdata/multi/*.pb.go -_conformance/_conformance diff --git a/vendor/github.com/golang/protobuf/.travis.yml b/vendor/github.com/golang/protobuf/.travis.yml deleted file mode 100644 index 93c67805..00000000 --- a/vendor/github.com/golang/protobuf/.travis.yml +++ /dev/null @@ -1,18 +0,0 @@ -sudo: false -language: go -go: -- 1.6.x -- 1.7.x -- 1.8.x -- 1.9.x - -install: - - go get -v -d -t github.com/golang/protobuf/... - - curl -L https://github.com/google/protobuf/releases/download/v3.3.0/protoc-3.3.0-linux-x86_64.zip -o /tmp/protoc.zip - - unzip /tmp/protoc.zip -d $HOME/protoc - -env: - - PATH=$HOME/protoc/bin:$PATH - -script: - - make all test diff --git a/vendor/github.com/golang/protobuf/Make.protobuf b/vendor/github.com/golang/protobuf/Make.protobuf deleted file mode 100644 index 15071de1..00000000 --- a/vendor/github.com/golang/protobuf/Make.protobuf +++ /dev/null @@ -1,40 +0,0 @@ -# Go support for Protocol Buffers - Google's data interchange format -# -# Copyright 2010 The Go Authors. All rights reserved. -# https://github.com/golang/protobuf -# -# 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. -# * Neither the name of Google Inc. nor the names of its -# contributors may 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 -# OWNER 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. - -# Includable Makefile to add a rule for generating .pb.go files from .proto files -# (Google protocol buffer descriptions). -# Typical use if myproto.proto is a file in package mypackage in this directory: -# -# include $(GOROOT)/src/pkg/github.com/golang/protobuf/Make.protobuf - -%.pb.go: %.proto - protoc --go_out=. $< - diff --git a/vendor/github.com/golang/protobuf/Makefile b/vendor/github.com/golang/protobuf/Makefile deleted file mode 100644 index a1421d8b..00000000 --- a/vendor/github.com/golang/protobuf/Makefile +++ /dev/null @@ -1,55 +0,0 @@ -# Go support for Protocol Buffers - Google's data interchange format -# -# Copyright 2010 The Go Authors. All rights reserved. -# https://github.com/golang/protobuf -# -# 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. -# * Neither the name of Google Inc. nor the names of its -# contributors may 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 -# OWNER 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. - - -all: install - -install: - go install ./proto ./jsonpb ./ptypes - go install ./protoc-gen-go - -test: - go test ./proto ./jsonpb ./ptypes - make -C protoc-gen-go/testdata test - -clean: - go clean ./... - -nuke: - go clean -i ./... - -regenerate: - make -C protoc-gen-go/descriptor regenerate - make -C protoc-gen-go/plugin regenerate - make -C protoc-gen-go/testdata regenerate - make -C proto/testdata regenerate - make -C jsonpb/jsonpb_test_proto regenerate - make -C _conformance regenerate diff --git a/vendor/github.com/golang/protobuf/README.md b/vendor/github.com/golang/protobuf/README.md deleted file mode 100644 index 9c4c815c..00000000 --- a/vendor/github.com/golang/protobuf/README.md +++ /dev/null @@ -1,244 +0,0 @@ -# Go support for Protocol Buffers - -[![Build Status](https://travis-ci.org/golang/protobuf.svg?branch=master)](https://travis-ci.org/golang/protobuf) -[![GoDoc](https://godoc.org/github.com/golang/protobuf?status.svg)](https://godoc.org/github.com/golang/protobuf) - -Google's data interchange format. -Copyright 2010 The Go Authors. -https://github.com/golang/protobuf - -This package and the code it generates requires at least Go 1.4. - -This software implements Go bindings for protocol buffers. For -information about protocol buffers themselves, see - https://developers.google.com/protocol-buffers/ - -## Installation ## - -To use this software, you must: -- Install the standard C++ implementation of protocol buffers from - https://developers.google.com/protocol-buffers/ -- Of course, install the Go compiler and tools from - https://golang.org/ - See - https://golang.org/doc/install - for details or, if you are using gccgo, follow the instructions at - https://golang.org/doc/install/gccgo -- Grab the code from the repository and install the proto package. - The simplest way is to run `go get -u github.com/golang/protobuf/protoc-gen-go`. - The compiler plugin, protoc-gen-go, will be installed in $GOBIN, - defaulting to $GOPATH/bin. It must be in your $PATH for the protocol - compiler, protoc, to find it. - -This software has two parts: a 'protocol compiler plugin' that -generates Go source files that, once compiled, can access and manage -protocol buffers; and a library that implements run-time support for -encoding (marshaling), decoding (unmarshaling), and accessing protocol -buffers. - -There is support for gRPC in Go using protocol buffers. -See the note at the bottom of this file for details. - -There are no insertion points in the plugin. - - -## Using protocol buffers with Go ## - -Once the software is installed, there are two steps to using it. -First you must compile the protocol buffer definitions and then import -them, with the support library, into your program. - -To compile the protocol buffer definition, run protoc with the --go_out -parameter set to the directory you want to output the Go code to. - - protoc --go_out=. *.proto - -The generated files will be suffixed .pb.go. See the Test code below -for an example using such a file. - - -The package comment for the proto library contains text describing -the interface provided in Go for protocol buffers. Here is an edited -version. - -========== - -The proto package converts data structures to and from the -wire format of protocol buffers. It works in concert with the -Go source code generated for .proto files by the protocol compiler. - -A summary of the properties of the protocol buffer interface -for a protocol buffer variable v: - - - Names are turned from camel_case to CamelCase for export. - - There are no methods on v to set fields; just treat - them as structure fields. - - There are getters that return a field's value if set, - and return the field's default value if unset. - The getters work even if the receiver is a nil message. - - The zero value for a struct is its correct initialization state. - All desired fields must be set before marshaling. - - A Reset() method will restore a protobuf struct to its zero state. - - Non-repeated fields are pointers to the values; nil means unset. - That is, optional or required field int32 f becomes F *int32. - - Repeated fields are slices. - - Helper functions are available to aid the setting of fields. - Helpers for getting values are superseded by the - GetFoo methods and their use is deprecated. - msg.Foo = proto.String("hello") // set field - - Constants are defined to hold the default values of all fields that - have them. They have the form Default_StructName_FieldName. - Because the getter methods handle defaulted values, - direct use of these constants should be rare. - - Enums are given type names and maps from names to values. - Enum values are prefixed with the enum's type name. Enum types have - a String method, and a Enum method to assist in message construction. - - Nested groups and enums have type names prefixed with the name of - the surrounding message type. - - Extensions are given descriptor names that start with E_, - followed by an underscore-delimited list of the nested messages - that contain it (if any) followed by the CamelCased name of the - extension field itself. HasExtension, ClearExtension, GetExtension - and SetExtension are functions for manipulating extensions. - - Oneof field sets are given a single field in their message, - with distinguished wrapper types for each possible field value. - - Marshal and Unmarshal are functions to encode and decode the wire format. - -When the .proto file specifies `syntax="proto3"`, there are some differences: - - - Non-repeated fields of non-message type are values instead of pointers. - - Enum types do not get an Enum method. - -Consider file test.proto, containing - -```proto - syntax = "proto2"; - package example; - - enum FOO { X = 17; }; - - message Test { - required string label = 1; - optional int32 type = 2 [default=77]; - repeated int64 reps = 3; - optional group OptionalGroup = 4 { - required string RequiredField = 5; - } - } -``` - -To create and play with a Test object from the example package, - -```go - package main - - import ( - "log" - - "github.com/golang/protobuf/proto" - "path/to/example" - ) - - func main() { - test := &example.Test { - Label: proto.String("hello"), - Type: proto.Int32(17), - Reps: []int64{1, 2, 3}, - Optionalgroup: &example.Test_OptionalGroup { - RequiredField: proto.String("good bye"), - }, - } - data, err := proto.Marshal(test) - if err != nil { - log.Fatal("marshaling error: ", err) - } - newTest := &example.Test{} - err = proto.Unmarshal(data, newTest) - if err != nil { - log.Fatal("unmarshaling error: ", err) - } - // Now test and newTest contain the same data. - if test.GetLabel() != newTest.GetLabel() { - log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) - } - // etc. - } -``` - -## Parameters ## - -To pass extra parameters to the plugin, use a comma-separated -parameter list separated from the output directory by a colon: - - - protoc --go_out=plugins=grpc,import_path=mypackage:. *.proto - - -- `import_prefix=xxx` - a prefix that is added onto the beginning of - all imports. Useful for things like generating protos in a - subdirectory, or regenerating vendored protobufs in-place. -- `import_path=foo/bar` - used as the package if no input files - declare `go_package`. If it contains slashes, everything up to the - rightmost slash is ignored. -- `plugins=plugin1+plugin2` - specifies the list of sub-plugins to - load. The only plugin in this repo is `grpc`. -- `Mfoo/bar.proto=quux/shme` - declares that foo/bar.proto is - associated with Go package quux/shme. This is subject to the - import_prefix parameter. - -## gRPC Support ## - -If a proto file specifies RPC services, protoc-gen-go can be instructed to -generate code compatible with gRPC (http://www.grpc.io/). To do this, pass -the `plugins` parameter to protoc-gen-go; the usual way is to insert it into -the --go_out argument to protoc: - - protoc --go_out=plugins=grpc:. *.proto - -## Compatibility ## - -The library and the generated code are expected to be stable over time. -However, we reserve the right to make breaking changes without notice for the -following reasons: - -- Security. A security issue in the specification or implementation may come to - light whose resolution requires breaking compatibility. We reserve the right - to address such security issues. -- Unspecified behavior. There are some aspects of the Protocol Buffers - specification that are undefined. Programs that depend on such unspecified - behavior may break in future releases. -- Specification errors or changes. If it becomes necessary to address an - inconsistency, incompleteness, or change in the Protocol Buffers - specification, resolving the issue could affect the meaning or legality of - existing programs. We reserve the right to address such issues, including - updating the implementations. -- Bugs. If the library has a bug that violates the specification, a program - that depends on the buggy behavior may break if the bug is fixed. We reserve - the right to fix such bugs. -- Adding methods or fields to generated structs. These may conflict with field - names that already exist in a schema, causing applications to break. When the - code generator encounters a field in the schema that would collide with a - generated field or method name, the code generator will append an underscore - to the generated field or method name. -- Adding, removing, or changing methods or fields in generated structs that - start with `XXX`. These parts of the generated code are exported out of - necessity, but should not be considered part of the public API. -- Adding, removing, or changing unexported symbols in generated code. - -Any breaking changes outside of these will be announced 6 months in advance to -protobuf@googlegroups.com. - -You should, whenever possible, use generated code created by the `protoc-gen-go` -tool built at the same commit as the `proto` package. The `proto` package -declares package-level constants in the form `ProtoPackageIsVersionX`. -Application code and generated code may depend on one of these constants to -ensure that compilation will fail if the available version of the proto library -is too old. Whenever we make a change to the generated code that requires newer -library support, in the same commit we will increment the version number of the -generated code and declare a new package-level constant whose name incorporates -the latest version number. Removing a compatibility constant is considered a -breaking change and would be subject to the announcement policy stated above. - -The `protoc-gen-go/generator` package exposes a plugin interface, -which is used by the gRPC code generation. This interface is not -supported and is subject to incompatible changes without notice. diff --git a/vendor/github.com/golang/protobuf/proto/all_test.go b/vendor/github.com/golang/protobuf/proto/all_test.go deleted file mode 100644 index 41451a40..00000000 --- a/vendor/github.com/golang/protobuf/proto/all_test.go +++ /dev/null @@ -1,2278 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may 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 -// OWNER 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. - -package proto_test - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "math" - "math/rand" - "reflect" - "runtime/debug" - "strings" - "testing" - "time" - - . "github.com/golang/protobuf/proto" - . "github.com/golang/protobuf/proto/testdata" -) - -var globalO *Buffer - -func old() *Buffer { - if globalO == nil { - globalO = NewBuffer(nil) - } - globalO.Reset() - return globalO -} - -func equalbytes(b1, b2 []byte, t *testing.T) { - if len(b1) != len(b2) { - t.Errorf("wrong lengths: 2*%d != %d", len(b1), len(b2)) - return - } - for i := 0; i < len(b1); i++ { - if b1[i] != b2[i] { - t.Errorf("bad byte[%d]:%x %x: %s %s", i, b1[i], b2[i], b1, b2) - } - } -} - -func initGoTestField() *GoTestField { - f := new(GoTestField) - f.Label = String("label") - f.Type = String("type") - return f -} - -// These are all structurally equivalent but the tag numbers differ. -// (It's remarkable that required, optional, and repeated all have -// 8 letters.) -func initGoTest_RequiredGroup() *GoTest_RequiredGroup { - return &GoTest_RequiredGroup{ - RequiredField: String("required"), - } -} - -func initGoTest_OptionalGroup() *GoTest_OptionalGroup { - return &GoTest_OptionalGroup{ - RequiredField: String("optional"), - } -} - -func initGoTest_RepeatedGroup() *GoTest_RepeatedGroup { - return &GoTest_RepeatedGroup{ - RequiredField: String("repeated"), - } -} - -func initGoTest(setdefaults bool) *GoTest { - pb := new(GoTest) - if setdefaults { - pb.F_BoolDefaulted = Bool(Default_GoTest_F_BoolDefaulted) - pb.F_Int32Defaulted = Int32(Default_GoTest_F_Int32Defaulted) - pb.F_Int64Defaulted = Int64(Default_GoTest_F_Int64Defaulted) - pb.F_Fixed32Defaulted = Uint32(Default_GoTest_F_Fixed32Defaulted) - pb.F_Fixed64Defaulted = Uint64(Default_GoTest_F_Fixed64Defaulted) - pb.F_Uint32Defaulted = Uint32(Default_GoTest_F_Uint32Defaulted) - pb.F_Uint64Defaulted = Uint64(Default_GoTest_F_Uint64Defaulted) - pb.F_FloatDefaulted = Float32(Default_GoTest_F_FloatDefaulted) - pb.F_DoubleDefaulted = Float64(Default_GoTest_F_DoubleDefaulted) - pb.F_StringDefaulted = String(Default_GoTest_F_StringDefaulted) - pb.F_BytesDefaulted = Default_GoTest_F_BytesDefaulted - pb.F_Sint32Defaulted = Int32(Default_GoTest_F_Sint32Defaulted) - pb.F_Sint64Defaulted = Int64(Default_GoTest_F_Sint64Defaulted) - } - - pb.Kind = GoTest_TIME.Enum() - pb.RequiredField = initGoTestField() - pb.F_BoolRequired = Bool(true) - pb.F_Int32Required = Int32(3) - pb.F_Int64Required = Int64(6) - pb.F_Fixed32Required = Uint32(32) - pb.F_Fixed64Required = Uint64(64) - pb.F_Uint32Required = Uint32(3232) - pb.F_Uint64Required = Uint64(6464) - pb.F_FloatRequired = Float32(3232) - pb.F_DoubleRequired = Float64(6464) - pb.F_StringRequired = String("string") - pb.F_BytesRequired = []byte("bytes") - pb.F_Sint32Required = Int32(-32) - pb.F_Sint64Required = Int64(-64) - pb.Requiredgroup = initGoTest_RequiredGroup() - - return pb -} - -func fail(msg string, b *bytes.Buffer, s string, t *testing.T) { - data := b.Bytes() - ld := len(data) - ls := len(s) / 2 - - fmt.Printf("fail %s ld=%d ls=%d\n", msg, ld, ls) - - // find the interesting spot - n - n := ls - if ld < ls { - n = ld - } - j := 0 - for i := 0; i < n; i++ { - bs := hex(s[j])*16 + hex(s[j+1]) - j += 2 - if data[i] == bs { - continue - } - n = i - break - } - l := n - 10 - if l < 0 { - l = 0 - } - h := n + 10 - - // find the interesting spot - n - fmt.Printf("is[%d]:", l) - for i := l; i < h; i++ { - if i >= ld { - fmt.Printf(" --") - continue - } - fmt.Printf(" %.2x", data[i]) - } - fmt.Printf("\n") - - fmt.Printf("sb[%d]:", l) - for i := l; i < h; i++ { - if i >= ls { - fmt.Printf(" --") - continue - } - bs := hex(s[j])*16 + hex(s[j+1]) - j += 2 - fmt.Printf(" %.2x", bs) - } - fmt.Printf("\n") - - t.Fail() - - // t.Errorf("%s: \ngood: %s\nbad: %x", msg, s, b.Bytes()) - // Print the output in a partially-decoded format; can - // be helpful when updating the test. It produces the output - // that is pasted, with minor edits, into the argument to verify(). - // data := b.Bytes() - // nesting := 0 - // for b.Len() > 0 { - // start := len(data) - b.Len() - // var u uint64 - // u, err := DecodeVarint(b) - // if err != nil { - // fmt.Printf("decode error on varint:", err) - // return - // } - // wire := u & 0x7 - // tag := u >> 3 - // switch wire { - // case WireVarint: - // v, err := DecodeVarint(b) - // if err != nil { - // fmt.Printf("decode error on varint:", err) - // return - // } - // fmt.Printf("\t\t\"%x\" // field %d, encoding %d, value %d\n", - // data[start:len(data)-b.Len()], tag, wire, v) - // case WireFixed32: - // v, err := DecodeFixed32(b) - // if err != nil { - // fmt.Printf("decode error on fixed32:", err) - // return - // } - // fmt.Printf("\t\t\"%x\" // field %d, encoding %d, value %d\n", - // data[start:len(data)-b.Len()], tag, wire, v) - // case WireFixed64: - // v, err := DecodeFixed64(b) - // if err != nil { - // fmt.Printf("decode error on fixed64:", err) - // return - // } - // fmt.Printf("\t\t\"%x\" // field %d, encoding %d, value %d\n", - // data[start:len(data)-b.Len()], tag, wire, v) - // case WireBytes: - // nb, err := DecodeVarint(b) - // if err != nil { - // fmt.Printf("decode error on bytes:", err) - // return - // } - // after_tag := len(data) - b.Len() - // str := make([]byte, nb) - // _, err = b.Read(str) - // if err != nil { - // fmt.Printf("decode error on bytes:", err) - // return - // } - // fmt.Printf("\t\t\"%x\" \"%x\" // field %d, encoding %d (FIELD)\n", - // data[start:after_tag], str, tag, wire) - // case WireStartGroup: - // nesting++ - // fmt.Printf("\t\t\"%x\"\t\t// start group field %d level %d\n", - // data[start:len(data)-b.Len()], tag, nesting) - // case WireEndGroup: - // fmt.Printf("\t\t\"%x\"\t\t// end group field %d level %d\n", - // data[start:len(data)-b.Len()], tag, nesting) - // nesting-- - // default: - // fmt.Printf("unrecognized wire type %d\n", wire) - // return - // } - // } -} - -func hex(c uint8) uint8 { - if '0' <= c && c <= '9' { - return c - '0' - } - if 'a' <= c && c <= 'f' { - return 10 + c - 'a' - } - if 'A' <= c && c <= 'F' { - return 10 + c - 'A' - } - return 0 -} - -func equal(b []byte, s string, t *testing.T) bool { - if 2*len(b) != len(s) { - // fail(fmt.Sprintf("wrong lengths: 2*%d != %d", len(b), len(s)), b, s, t) - fmt.Printf("wrong lengths: 2*%d != %d\n", len(b), len(s)) - return false - } - for i, j := 0, 0; i < len(b); i, j = i+1, j+2 { - x := hex(s[j])*16 + hex(s[j+1]) - if b[i] != x { - // fail(fmt.Sprintf("bad byte[%d]:%x %x", i, b[i], x), b, s, t) - fmt.Printf("bad byte[%d]:%x %x", i, b[i], x) - return false - } - } - return true -} - -func overify(t *testing.T, pb *GoTest, expected string) { - o := old() - err := o.Marshal(pb) - if err != nil { - fmt.Printf("overify marshal-1 err = %v", err) - o.DebugPrint("", o.Bytes()) - t.Fatalf("expected = %s", expected) - } - if !equal(o.Bytes(), expected, t) { - o.DebugPrint("overify neq 1", o.Bytes()) - t.Fatalf("expected = %s", expected) - } - - // Now test Unmarshal by recreating the original buffer. - pbd := new(GoTest) - err = o.Unmarshal(pbd) - if err != nil { - t.Fatalf("overify unmarshal err = %v", err) - o.DebugPrint("", o.Bytes()) - t.Fatalf("string = %s", expected) - } - o.Reset() - err = o.Marshal(pbd) - if err != nil { - t.Errorf("overify marshal-2 err = %v", err) - o.DebugPrint("", o.Bytes()) - t.Fatalf("string = %s", expected) - } - if !equal(o.Bytes(), expected, t) { - o.DebugPrint("overify neq 2", o.Bytes()) - t.Fatalf("string = %s", expected) - } -} - -// Simple tests for numeric encode/decode primitives (varint, etc.) -func TestNumericPrimitives(t *testing.T) { - for i := uint64(0); i < 1e6; i += 111 { - o := old() - if o.EncodeVarint(i) != nil { - t.Error("EncodeVarint") - break - } - x, e := o.DecodeVarint() - if e != nil { - t.Fatal("DecodeVarint") - } - if x != i { - t.Fatal("varint decode fail:", i, x) - } - - o = old() - if o.EncodeFixed32(i) != nil { - t.Fatal("encFixed32") - } - x, e = o.DecodeFixed32() - if e != nil { - t.Fatal("decFixed32") - } - if x != i { - t.Fatal("fixed32 decode fail:", i, x) - } - - o = old() - if o.EncodeFixed64(i*1234567) != nil { - t.Error("encFixed64") - break - } - x, e = o.DecodeFixed64() - if e != nil { - t.Error("decFixed64") - break - } - if x != i*1234567 { - t.Error("fixed64 decode fail:", i*1234567, x) - break - } - - o = old() - i32 := int32(i - 12345) - if o.EncodeZigzag32(uint64(i32)) != nil { - t.Fatal("EncodeZigzag32") - } - x, e = o.DecodeZigzag32() - if e != nil { - t.Fatal("DecodeZigzag32") - } - if x != uint64(uint32(i32)) { - t.Fatal("zigzag32 decode fail:", i32, x) - } - - o = old() - i64 := int64(i - 12345) - if o.EncodeZigzag64(uint64(i64)) != nil { - t.Fatal("EncodeZigzag64") - } - x, e = o.DecodeZigzag64() - if e != nil { - t.Fatal("DecodeZigzag64") - } - if x != uint64(i64) { - t.Fatal("zigzag64 decode fail:", i64, x) - } - } -} - -// fakeMarshaler is a simple struct implementing Marshaler and Message interfaces. -type fakeMarshaler struct { - b []byte - err error -} - -func (f *fakeMarshaler) Marshal() ([]byte, error) { return f.b, f.err } -func (f *fakeMarshaler) String() string { return fmt.Sprintf("Bytes: %v Error: %v", f.b, f.err) } -func (f *fakeMarshaler) ProtoMessage() {} -func (f *fakeMarshaler) Reset() {} - -type msgWithFakeMarshaler struct { - M *fakeMarshaler `protobuf:"bytes,1,opt,name=fake"` -} - -func (m *msgWithFakeMarshaler) String() string { return CompactTextString(m) } -func (m *msgWithFakeMarshaler) ProtoMessage() {} -func (m *msgWithFakeMarshaler) Reset() {} - -// Simple tests for proto messages that implement the Marshaler interface. -func TestMarshalerEncoding(t *testing.T) { - tests := []struct { - name string - m Message - want []byte - errType reflect.Type - }{ - { - name: "Marshaler that fails", - m: &fakeMarshaler{ - err: errors.New("some marshal err"), - b: []byte{5, 6, 7}, - }, - // Since the Marshal method returned bytes, they should be written to the - // buffer. (For efficiency, we assume that Marshal implementations are - // always correct w.r.t. RequiredNotSetError and output.) - want: []byte{5, 6, 7}, - errType: reflect.TypeOf(errors.New("some marshal err")), - }, - { - name: "Marshaler that fails with RequiredNotSetError", - m: &msgWithFakeMarshaler{ - M: &fakeMarshaler{ - err: &RequiredNotSetError{}, - b: []byte{5, 6, 7}, - }, - }, - // Since there's an error that can be continued after, - // the buffer should be written. - want: []byte{ - 10, 3, // for &msgWithFakeMarshaler - 5, 6, 7, // for &fakeMarshaler - }, - errType: reflect.TypeOf(&RequiredNotSetError{}), - }, - { - name: "Marshaler that succeeds", - m: &fakeMarshaler{ - b: []byte{0, 1, 2, 3, 4, 127, 255}, - }, - want: []byte{0, 1, 2, 3, 4, 127, 255}, - }, - } - for _, test := range tests { - b := NewBuffer(nil) - err := b.Marshal(test.m) - if reflect.TypeOf(err) != test.errType { - t.Errorf("%s: got err %T(%v) wanted %T", test.name, err, err, test.errType) - } - if !reflect.DeepEqual(test.want, b.Bytes()) { - t.Errorf("%s: got bytes %v wanted %v", test.name, b.Bytes(), test.want) - } - if size := Size(test.m); size != len(b.Bytes()) { - t.Errorf("%s: Size(_) = %v, but marshaled to %v bytes", test.name, size, len(b.Bytes())) - } - - m, mErr := Marshal(test.m) - if !bytes.Equal(b.Bytes(), m) { - t.Errorf("%s: Marshal returned %v, but (*Buffer).Marshal wrote %v", test.name, m, b.Bytes()) - } - if !reflect.DeepEqual(err, mErr) { - t.Errorf("%s: Marshal err = %q, but (*Buffer).Marshal returned %q", - test.name, fmt.Sprint(mErr), fmt.Sprint(err)) - } - } -} - -// Simple tests for bytes -func TestBytesPrimitives(t *testing.T) { - o := old() - bytes := []byte{'n', 'o', 'w', ' ', 'i', 's', ' ', 't', 'h', 'e', ' ', 't', 'i', 'm', 'e'} - if o.EncodeRawBytes(bytes) != nil { - t.Error("EncodeRawBytes") - } - decb, e := o.DecodeRawBytes(false) - if e != nil { - t.Error("DecodeRawBytes") - } - equalbytes(bytes, decb, t) -} - -// Simple tests for strings -func TestStringPrimitives(t *testing.T) { - o := old() - s := "now is the time" - if o.EncodeStringBytes(s) != nil { - t.Error("enc_string") - } - decs, e := o.DecodeStringBytes() - if e != nil { - t.Error("dec_string") - } - if s != decs { - t.Error("string encode/decode fail:", s, decs) - } -} - -// Do we catch the "required bit not set" case? -func TestRequiredBit(t *testing.T) { - o := old() - pb := new(GoTest) - err := o.Marshal(pb) - if err == nil { - t.Error("did not catch missing required fields") - } else if strings.Index(err.Error(), "Kind") < 0 { - t.Error("wrong error type:", err) - } -} - -// Check that all fields are nil. -// Clearly silly, and a residue from a more interesting test with an earlier, -// different initialization property, but it once caught a compiler bug so -// it lives. -func checkInitialized(pb *GoTest, t *testing.T) { - if pb.F_BoolDefaulted != nil { - t.Error("New or Reset did not set boolean:", *pb.F_BoolDefaulted) - } - if pb.F_Int32Defaulted != nil { - t.Error("New or Reset did not set int32:", *pb.F_Int32Defaulted) - } - if pb.F_Int64Defaulted != nil { - t.Error("New or Reset did not set int64:", *pb.F_Int64Defaulted) - } - if pb.F_Fixed32Defaulted != nil { - t.Error("New or Reset did not set fixed32:", *pb.F_Fixed32Defaulted) - } - if pb.F_Fixed64Defaulted != nil { - t.Error("New or Reset did not set fixed64:", *pb.F_Fixed64Defaulted) - } - if pb.F_Uint32Defaulted != nil { - t.Error("New or Reset did not set uint32:", *pb.F_Uint32Defaulted) - } - if pb.F_Uint64Defaulted != nil { - t.Error("New or Reset did not set uint64:", *pb.F_Uint64Defaulted) - } - if pb.F_FloatDefaulted != nil { - t.Error("New or Reset did not set float:", *pb.F_FloatDefaulted) - } - if pb.F_DoubleDefaulted != nil { - t.Error("New or Reset did not set double:", *pb.F_DoubleDefaulted) - } - if pb.F_StringDefaulted != nil { - t.Error("New or Reset did not set string:", *pb.F_StringDefaulted) - } - if pb.F_BytesDefaulted != nil { - t.Error("New or Reset did not set bytes:", string(pb.F_BytesDefaulted)) - } - if pb.F_Sint32Defaulted != nil { - t.Error("New or Reset did not set int32:", *pb.F_Sint32Defaulted) - } - if pb.F_Sint64Defaulted != nil { - t.Error("New or Reset did not set int64:", *pb.F_Sint64Defaulted) - } -} - -// Does Reset() reset? -func TestReset(t *testing.T) { - pb := initGoTest(true) - // muck with some values - pb.F_BoolDefaulted = Bool(false) - pb.F_Int32Defaulted = Int32(237) - pb.F_Int64Defaulted = Int64(12346) - pb.F_Fixed32Defaulted = Uint32(32000) - pb.F_Fixed64Defaulted = Uint64(666) - pb.F_Uint32Defaulted = Uint32(323232) - pb.F_Uint64Defaulted = nil - pb.F_FloatDefaulted = nil - pb.F_DoubleDefaulted = Float64(0) - pb.F_StringDefaulted = String("gotcha") - pb.F_BytesDefaulted = []byte("asdfasdf") - pb.F_Sint32Defaulted = Int32(123) - pb.F_Sint64Defaulted = Int64(789) - pb.Reset() - checkInitialized(pb, t) -} - -// All required fields set, no defaults provided. -func TestEncodeDecode1(t *testing.T) { - pb := initGoTest(false) - overify(t, pb, - "0807"+ // field 1, encoding 0, value 7 - "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) - "5001"+ // field 10, encoding 0, value 1 - "5803"+ // field 11, encoding 0, value 3 - "6006"+ // field 12, encoding 0, value 6 - "6d20000000"+ // field 13, encoding 5, value 0x20 - "714000000000000000"+ // field 14, encoding 1, value 0x40 - "78a019"+ // field 15, encoding 0, value 0xca0 = 3232 - "8001c032"+ // field 16, encoding 0, value 0x1940 = 6464 - "8d0100004a45"+ // field 17, encoding 5, value 3232.0 - "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 - "9a0106"+"737472696e67"+ // field 19, encoding 2, string "string" - "b304"+ // field 70, encoding 3, start group - "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" - "b404"+ // field 70, encoding 4, end group - "aa0605"+"6279746573"+ // field 101, encoding 2, string "bytes" - "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 - "b8067f") // field 103, encoding 0, 0x7f zigzag64 -} - -// All required fields set, defaults provided. -func TestEncodeDecode2(t *testing.T) { - pb := initGoTest(true) - overify(t, pb, - "0807"+ // field 1, encoding 0, value 7 - "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) - "5001"+ // field 10, encoding 0, value 1 - "5803"+ // field 11, encoding 0, value 3 - "6006"+ // field 12, encoding 0, value 6 - "6d20000000"+ // field 13, encoding 5, value 32 - "714000000000000000"+ // field 14, encoding 1, value 64 - "78a019"+ // field 15, encoding 0, value 3232 - "8001c032"+ // field 16, encoding 0, value 6464 - "8d0100004a45"+ // field 17, encoding 5, value 3232.0 - "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 - "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" - "c00201"+ // field 40, encoding 0, value 1 - "c80220"+ // field 41, encoding 0, value 32 - "d00240"+ // field 42, encoding 0, value 64 - "dd0240010000"+ // field 43, encoding 5, value 320 - "e1028002000000000000"+ // field 44, encoding 1, value 640 - "e8028019"+ // field 45, encoding 0, value 3200 - "f0028032"+ // field 46, encoding 0, value 6400 - "fd02e0659948"+ // field 47, encoding 5, value 314159.0 - "81030000000050971041"+ // field 48, encoding 1, value 271828.0 - "8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n" - "b304"+ // start group field 70 level 1 - "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" - "b404"+ // end group field 70 level 1 - "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" - "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 - "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 - "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" - "90193f"+ // field 402, encoding 0, value 63 - "98197f") // field 403, encoding 0, value 127 - -} - -// All default fields set to their default value by hand -func TestEncodeDecode3(t *testing.T) { - pb := initGoTest(false) - pb.F_BoolDefaulted = Bool(true) - pb.F_Int32Defaulted = Int32(32) - pb.F_Int64Defaulted = Int64(64) - pb.F_Fixed32Defaulted = Uint32(320) - pb.F_Fixed64Defaulted = Uint64(640) - pb.F_Uint32Defaulted = Uint32(3200) - pb.F_Uint64Defaulted = Uint64(6400) - pb.F_FloatDefaulted = Float32(314159) - pb.F_DoubleDefaulted = Float64(271828) - pb.F_StringDefaulted = String("hello, \"world!\"\n") - pb.F_BytesDefaulted = []byte("Bignose") - pb.F_Sint32Defaulted = Int32(-32) - pb.F_Sint64Defaulted = Int64(-64) - - overify(t, pb, - "0807"+ // field 1, encoding 0, value 7 - "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) - "5001"+ // field 10, encoding 0, value 1 - "5803"+ // field 11, encoding 0, value 3 - "6006"+ // field 12, encoding 0, value 6 - "6d20000000"+ // field 13, encoding 5, value 32 - "714000000000000000"+ // field 14, encoding 1, value 64 - "78a019"+ // field 15, encoding 0, value 3232 - "8001c032"+ // field 16, encoding 0, value 6464 - "8d0100004a45"+ // field 17, encoding 5, value 3232.0 - "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 - "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" - "c00201"+ // field 40, encoding 0, value 1 - "c80220"+ // field 41, encoding 0, value 32 - "d00240"+ // field 42, encoding 0, value 64 - "dd0240010000"+ // field 43, encoding 5, value 320 - "e1028002000000000000"+ // field 44, encoding 1, value 640 - "e8028019"+ // field 45, encoding 0, value 3200 - "f0028032"+ // field 46, encoding 0, value 6400 - "fd02e0659948"+ // field 47, encoding 5, value 314159.0 - "81030000000050971041"+ // field 48, encoding 1, value 271828.0 - "8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n" - "b304"+ // start group field 70 level 1 - "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" - "b404"+ // end group field 70 level 1 - "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" - "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 - "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 - "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" - "90193f"+ // field 402, encoding 0, value 63 - "98197f") // field 403, encoding 0, value 127 - -} - -// All required fields set, defaults provided, all non-defaulted optional fields have values. -func TestEncodeDecode4(t *testing.T) { - pb := initGoTest(true) - pb.Table = String("hello") - pb.Param = Int32(7) - pb.OptionalField = initGoTestField() - pb.F_BoolOptional = Bool(true) - pb.F_Int32Optional = Int32(32) - pb.F_Int64Optional = Int64(64) - pb.F_Fixed32Optional = Uint32(3232) - pb.F_Fixed64Optional = Uint64(6464) - pb.F_Uint32Optional = Uint32(323232) - pb.F_Uint64Optional = Uint64(646464) - pb.F_FloatOptional = Float32(32.) - pb.F_DoubleOptional = Float64(64.) - pb.F_StringOptional = String("hello") - pb.F_BytesOptional = []byte("Bignose") - pb.F_Sint32Optional = Int32(-32) - pb.F_Sint64Optional = Int64(-64) - pb.Optionalgroup = initGoTest_OptionalGroup() - - overify(t, pb, - "0807"+ // field 1, encoding 0, value 7 - "1205"+"68656c6c6f"+ // field 2, encoding 2, string "hello" - "1807"+ // field 3, encoding 0, value 7 - "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) - "320d"+"0a056c6162656c120474797065"+ // field 6, encoding 2 (GoTestField) - "5001"+ // field 10, encoding 0, value 1 - "5803"+ // field 11, encoding 0, value 3 - "6006"+ // field 12, encoding 0, value 6 - "6d20000000"+ // field 13, encoding 5, value 32 - "714000000000000000"+ // field 14, encoding 1, value 64 - "78a019"+ // field 15, encoding 0, value 3232 - "8001c032"+ // field 16, encoding 0, value 6464 - "8d0100004a45"+ // field 17, encoding 5, value 3232.0 - "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 - "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" - "f00101"+ // field 30, encoding 0, value 1 - "f80120"+ // field 31, encoding 0, value 32 - "800240"+ // field 32, encoding 0, value 64 - "8d02a00c0000"+ // field 33, encoding 5, value 3232 - "91024019000000000000"+ // field 34, encoding 1, value 6464 - "9802a0dd13"+ // field 35, encoding 0, value 323232 - "a002c0ba27"+ // field 36, encoding 0, value 646464 - "ad0200000042"+ // field 37, encoding 5, value 32.0 - "b1020000000000005040"+ // field 38, encoding 1, value 64.0 - "ba0205"+"68656c6c6f"+ // field 39, encoding 2, string "hello" - "c00201"+ // field 40, encoding 0, value 1 - "c80220"+ // field 41, encoding 0, value 32 - "d00240"+ // field 42, encoding 0, value 64 - "dd0240010000"+ // field 43, encoding 5, value 320 - "e1028002000000000000"+ // field 44, encoding 1, value 640 - "e8028019"+ // field 45, encoding 0, value 3200 - "f0028032"+ // field 46, encoding 0, value 6400 - "fd02e0659948"+ // field 47, encoding 5, value 314159.0 - "81030000000050971041"+ // field 48, encoding 1, value 271828.0 - "8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n" - "b304"+ // start group field 70 level 1 - "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" - "b404"+ // end group field 70 level 1 - "d305"+ // start group field 90 level 1 - "da0508"+"6f7074696f6e616c"+ // field 91, encoding 2, string "optional" - "d405"+ // end group field 90 level 1 - "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" - "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 - "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 - "ea1207"+"4269676e6f7365"+ // field 301, encoding 2, string "Bignose" - "f0123f"+ // field 302, encoding 0, value 63 - "f8127f"+ // field 303, encoding 0, value 127 - "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" - "90193f"+ // field 402, encoding 0, value 63 - "98197f") // field 403, encoding 0, value 127 - -} - -// All required fields set, defaults provided, all repeated fields given two values. -func TestEncodeDecode5(t *testing.T) { - pb := initGoTest(true) - pb.RepeatedField = []*GoTestField{initGoTestField(), initGoTestField()} - pb.F_BoolRepeated = []bool{false, true} - pb.F_Int32Repeated = []int32{32, 33} - pb.F_Int64Repeated = []int64{64, 65} - pb.F_Fixed32Repeated = []uint32{3232, 3333} - pb.F_Fixed64Repeated = []uint64{6464, 6565} - pb.F_Uint32Repeated = []uint32{323232, 333333} - pb.F_Uint64Repeated = []uint64{646464, 656565} - pb.F_FloatRepeated = []float32{32., 33.} - pb.F_DoubleRepeated = []float64{64., 65.} - pb.F_StringRepeated = []string{"hello", "sailor"} - pb.F_BytesRepeated = [][]byte{[]byte("big"), []byte("nose")} - pb.F_Sint32Repeated = []int32{32, -32} - pb.F_Sint64Repeated = []int64{64, -64} - pb.Repeatedgroup = []*GoTest_RepeatedGroup{initGoTest_RepeatedGroup(), initGoTest_RepeatedGroup()} - - overify(t, pb, - "0807"+ // field 1, encoding 0, value 7 - "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) - "2a0d"+"0a056c6162656c120474797065"+ // field 5, encoding 2 (GoTestField) - "2a0d"+"0a056c6162656c120474797065"+ // field 5, encoding 2 (GoTestField) - "5001"+ // field 10, encoding 0, value 1 - "5803"+ // field 11, encoding 0, value 3 - "6006"+ // field 12, encoding 0, value 6 - "6d20000000"+ // field 13, encoding 5, value 32 - "714000000000000000"+ // field 14, encoding 1, value 64 - "78a019"+ // field 15, encoding 0, value 3232 - "8001c032"+ // field 16, encoding 0, value 6464 - "8d0100004a45"+ // field 17, encoding 5, value 3232.0 - "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 - "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" - "a00100"+ // field 20, encoding 0, value 0 - "a00101"+ // field 20, encoding 0, value 1 - "a80120"+ // field 21, encoding 0, value 32 - "a80121"+ // field 21, encoding 0, value 33 - "b00140"+ // field 22, encoding 0, value 64 - "b00141"+ // field 22, encoding 0, value 65 - "bd01a00c0000"+ // field 23, encoding 5, value 3232 - "bd01050d0000"+ // field 23, encoding 5, value 3333 - "c1014019000000000000"+ // field 24, encoding 1, value 6464 - "c101a519000000000000"+ // field 24, encoding 1, value 6565 - "c801a0dd13"+ // field 25, encoding 0, value 323232 - "c80195ac14"+ // field 25, encoding 0, value 333333 - "d001c0ba27"+ // field 26, encoding 0, value 646464 - "d001b58928"+ // field 26, encoding 0, value 656565 - "dd0100000042"+ // field 27, encoding 5, value 32.0 - "dd0100000442"+ // field 27, encoding 5, value 33.0 - "e1010000000000005040"+ // field 28, encoding 1, value 64.0 - "e1010000000000405040"+ // field 28, encoding 1, value 65.0 - "ea0105"+"68656c6c6f"+ // field 29, encoding 2, string "hello" - "ea0106"+"7361696c6f72"+ // field 29, encoding 2, string "sailor" - "c00201"+ // field 40, encoding 0, value 1 - "c80220"+ // field 41, encoding 0, value 32 - "d00240"+ // field 42, encoding 0, value 64 - "dd0240010000"+ // field 43, encoding 5, value 320 - "e1028002000000000000"+ // field 44, encoding 1, value 640 - "e8028019"+ // field 45, encoding 0, value 3200 - "f0028032"+ // field 46, encoding 0, value 6400 - "fd02e0659948"+ // field 47, encoding 5, value 314159.0 - "81030000000050971041"+ // field 48, encoding 1, value 271828.0 - "8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n" - "b304"+ // start group field 70 level 1 - "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" - "b404"+ // end group field 70 level 1 - "8305"+ // start group field 80 level 1 - "8a0508"+"7265706561746564"+ // field 81, encoding 2, string "repeated" - "8405"+ // end group field 80 level 1 - "8305"+ // start group field 80 level 1 - "8a0508"+"7265706561746564"+ // field 81, encoding 2, string "repeated" - "8405"+ // end group field 80 level 1 - "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" - "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 - "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 - "ca0c03"+"626967"+ // field 201, encoding 2, string "big" - "ca0c04"+"6e6f7365"+ // field 201, encoding 2, string "nose" - "d00c40"+ // field 202, encoding 0, value 32 - "d00c3f"+ // field 202, encoding 0, value -32 - "d80c8001"+ // field 203, encoding 0, value 64 - "d80c7f"+ // field 203, encoding 0, value -64 - "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" - "90193f"+ // field 402, encoding 0, value 63 - "98197f") // field 403, encoding 0, value 127 - -} - -// All required fields set, all packed repeated fields given two values. -func TestEncodeDecode6(t *testing.T) { - pb := initGoTest(false) - pb.F_BoolRepeatedPacked = []bool{false, true} - pb.F_Int32RepeatedPacked = []int32{32, 33} - pb.F_Int64RepeatedPacked = []int64{64, 65} - pb.F_Fixed32RepeatedPacked = []uint32{3232, 3333} - pb.F_Fixed64RepeatedPacked = []uint64{6464, 6565} - pb.F_Uint32RepeatedPacked = []uint32{323232, 333333} - pb.F_Uint64RepeatedPacked = []uint64{646464, 656565} - pb.F_FloatRepeatedPacked = []float32{32., 33.} - pb.F_DoubleRepeatedPacked = []float64{64., 65.} - pb.F_Sint32RepeatedPacked = []int32{32, -32} - pb.F_Sint64RepeatedPacked = []int64{64, -64} - - overify(t, pb, - "0807"+ // field 1, encoding 0, value 7 - "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) - "5001"+ // field 10, encoding 0, value 1 - "5803"+ // field 11, encoding 0, value 3 - "6006"+ // field 12, encoding 0, value 6 - "6d20000000"+ // field 13, encoding 5, value 32 - "714000000000000000"+ // field 14, encoding 1, value 64 - "78a019"+ // field 15, encoding 0, value 3232 - "8001c032"+ // field 16, encoding 0, value 6464 - "8d0100004a45"+ // field 17, encoding 5, value 3232.0 - "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 - "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" - "9203020001"+ // field 50, encoding 2, 2 bytes, value 0, value 1 - "9a03022021"+ // field 51, encoding 2, 2 bytes, value 32, value 33 - "a203024041"+ // field 52, encoding 2, 2 bytes, value 64, value 65 - "aa0308"+ // field 53, encoding 2, 8 bytes - "a00c0000050d0000"+ // value 3232, value 3333 - "b20310"+ // field 54, encoding 2, 16 bytes - "4019000000000000a519000000000000"+ // value 6464, value 6565 - "ba0306"+ // field 55, encoding 2, 6 bytes - "a0dd1395ac14"+ // value 323232, value 333333 - "c20306"+ // field 56, encoding 2, 6 bytes - "c0ba27b58928"+ // value 646464, value 656565 - "ca0308"+ // field 57, encoding 2, 8 bytes - "0000004200000442"+ // value 32.0, value 33.0 - "d20310"+ // field 58, encoding 2, 16 bytes - "00000000000050400000000000405040"+ // value 64.0, value 65.0 - "b304"+ // start group field 70 level 1 - "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" - "b404"+ // end group field 70 level 1 - "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" - "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 - "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 - "b21f02"+ // field 502, encoding 2, 2 bytes - "403f"+ // value 32, value -32 - "ba1f03"+ // field 503, encoding 2, 3 bytes - "80017f") // value 64, value -64 -} - -// Test that we can encode empty bytes fields. -func TestEncodeDecodeBytes1(t *testing.T) { - pb := initGoTest(false) - - // Create our bytes - pb.F_BytesRequired = []byte{} - pb.F_BytesRepeated = [][]byte{{}} - pb.F_BytesOptional = []byte{} - - d, err := Marshal(pb) - if err != nil { - t.Error(err) - } - - pbd := new(GoTest) - if err := Unmarshal(d, pbd); err != nil { - t.Error(err) - } - - if pbd.F_BytesRequired == nil || len(pbd.F_BytesRequired) != 0 { - t.Error("required empty bytes field is incorrect") - } - if pbd.F_BytesRepeated == nil || len(pbd.F_BytesRepeated) == 1 && pbd.F_BytesRepeated[0] == nil { - t.Error("repeated empty bytes field is incorrect") - } - if pbd.F_BytesOptional == nil || len(pbd.F_BytesOptional) != 0 { - t.Error("optional empty bytes field is incorrect") - } -} - -// Test that we encode nil-valued fields of a repeated bytes field correctly. -// Since entries in a repeated field cannot be nil, nil must mean empty value. -func TestEncodeDecodeBytes2(t *testing.T) { - pb := initGoTest(false) - - // Create our bytes - pb.F_BytesRepeated = [][]byte{nil} - - d, err := Marshal(pb) - if err != nil { - t.Error(err) - } - - pbd := new(GoTest) - if err := Unmarshal(d, pbd); err != nil { - t.Error(err) - } - - if len(pbd.F_BytesRepeated) != 1 || pbd.F_BytesRepeated[0] == nil { - t.Error("Unexpected value for repeated bytes field") - } -} - -// All required fields set, defaults provided, all repeated fields given two values. -func TestSkippingUnrecognizedFields(t *testing.T) { - o := old() - pb := initGoTestField() - - // Marshal it normally. - o.Marshal(pb) - - // Now new a GoSkipTest record. - skip := &GoSkipTest{ - SkipInt32: Int32(32), - SkipFixed32: Uint32(3232), - SkipFixed64: Uint64(6464), - SkipString: String("skipper"), - Skipgroup: &GoSkipTest_SkipGroup{ - GroupInt32: Int32(75), - GroupString: String("wxyz"), - }, - } - - // Marshal it into same buffer. - o.Marshal(skip) - - pbd := new(GoTestField) - o.Unmarshal(pbd) - - // The __unrecognized field should be a marshaling of GoSkipTest - skipd := new(GoSkipTest) - - o.SetBuf(pbd.XXX_unrecognized) - o.Unmarshal(skipd) - - if *skipd.SkipInt32 != *skip.SkipInt32 { - t.Error("skip int32", skipd.SkipInt32) - } - if *skipd.SkipFixed32 != *skip.SkipFixed32 { - t.Error("skip fixed32", skipd.SkipFixed32) - } - if *skipd.SkipFixed64 != *skip.SkipFixed64 { - t.Error("skip fixed64", skipd.SkipFixed64) - } - if *skipd.SkipString != *skip.SkipString { - t.Error("skip string", *skipd.SkipString) - } - if *skipd.Skipgroup.GroupInt32 != *skip.Skipgroup.GroupInt32 { - t.Error("skip group int32", skipd.Skipgroup.GroupInt32) - } - if *skipd.Skipgroup.GroupString != *skip.Skipgroup.GroupString { - t.Error("skip group string", *skipd.Skipgroup.GroupString) - } -} - -// Check that unrecognized fields of a submessage are preserved. -func TestSubmessageUnrecognizedFields(t *testing.T) { - nm := &NewMessage{ - Nested: &NewMessage_Nested{ - Name: String("Nigel"), - FoodGroup: String("carbs"), - }, - } - b, err := Marshal(nm) - if err != nil { - t.Fatalf("Marshal of NewMessage: %v", err) - } - - // Unmarshal into an OldMessage. - om := new(OldMessage) - if err := Unmarshal(b, om); err != nil { - t.Fatalf("Unmarshal to OldMessage: %v", err) - } - exp := &OldMessage{ - Nested: &OldMessage_Nested{ - Name: String("Nigel"), - // normal protocol buffer users should not do this - XXX_unrecognized: []byte("\x12\x05carbs"), - }, - } - if !Equal(om, exp) { - t.Errorf("om = %v, want %v", om, exp) - } - - // Clone the OldMessage. - om = Clone(om).(*OldMessage) - if !Equal(om, exp) { - t.Errorf("Clone(om) = %v, want %v", om, exp) - } - - // Marshal the OldMessage, then unmarshal it into an empty NewMessage. - if b, err = Marshal(om); err != nil { - t.Fatalf("Marshal of OldMessage: %v", err) - } - t.Logf("Marshal(%v) -> %q", om, b) - nm2 := new(NewMessage) - if err := Unmarshal(b, nm2); err != nil { - t.Fatalf("Unmarshal to NewMessage: %v", err) - } - if !Equal(nm, nm2) { - t.Errorf("NewMessage round-trip: %v => %v", nm, nm2) - } -} - -// Check that an int32 field can be upgraded to an int64 field. -func TestNegativeInt32(t *testing.T) { - om := &OldMessage{ - Num: Int32(-1), - } - b, err := Marshal(om) - if err != nil { - t.Fatalf("Marshal of OldMessage: %v", err) - } - - // Check the size. It should be 11 bytes; - // 1 for the field/wire type, and 10 for the negative number. - if len(b) != 11 { - t.Errorf("%v marshaled as %q, wanted 11 bytes", om, b) - } - - // Unmarshal into a NewMessage. - nm := new(NewMessage) - if err := Unmarshal(b, nm); err != nil { - t.Fatalf("Unmarshal to NewMessage: %v", err) - } - want := &NewMessage{ - Num: Int64(-1), - } - if !Equal(nm, want) { - t.Errorf("nm = %v, want %v", nm, want) - } -} - -// Check that we can grow an array (repeated field) to have many elements. -// This test doesn't depend only on our encoding; for variety, it makes sure -// we create, encode, and decode the correct contents explicitly. It's therefore -// a bit messier. -// This test also uses (and hence tests) the Marshal/Unmarshal functions -// instead of the methods. -func TestBigRepeated(t *testing.T) { - pb := initGoTest(true) - - // Create the arrays - const N = 50 // Internally the library starts much smaller. - pb.Repeatedgroup = make([]*GoTest_RepeatedGroup, N) - pb.F_Sint64Repeated = make([]int64, N) - pb.F_Sint32Repeated = make([]int32, N) - pb.F_BytesRepeated = make([][]byte, N) - pb.F_StringRepeated = make([]string, N) - pb.F_DoubleRepeated = make([]float64, N) - pb.F_FloatRepeated = make([]float32, N) - pb.F_Uint64Repeated = make([]uint64, N) - pb.F_Uint32Repeated = make([]uint32, N) - pb.F_Fixed64Repeated = make([]uint64, N) - pb.F_Fixed32Repeated = make([]uint32, N) - pb.F_Int64Repeated = make([]int64, N) - pb.F_Int32Repeated = make([]int32, N) - pb.F_BoolRepeated = make([]bool, N) - pb.RepeatedField = make([]*GoTestField, N) - - // Fill in the arrays with checkable values. - igtf := initGoTestField() - igtrg := initGoTest_RepeatedGroup() - for i := 0; i < N; i++ { - pb.Repeatedgroup[i] = igtrg - pb.F_Sint64Repeated[i] = int64(i) - pb.F_Sint32Repeated[i] = int32(i) - s := fmt.Sprint(i) - pb.F_BytesRepeated[i] = []byte(s) - pb.F_StringRepeated[i] = s - pb.F_DoubleRepeated[i] = float64(i) - pb.F_FloatRepeated[i] = float32(i) - pb.F_Uint64Repeated[i] = uint64(i) - pb.F_Uint32Repeated[i] = uint32(i) - pb.F_Fixed64Repeated[i] = uint64(i) - pb.F_Fixed32Repeated[i] = uint32(i) - pb.F_Int64Repeated[i] = int64(i) - pb.F_Int32Repeated[i] = int32(i) - pb.F_BoolRepeated[i] = i%2 == 0 - pb.RepeatedField[i] = igtf - } - - // Marshal. - buf, _ := Marshal(pb) - - // Now test Unmarshal by recreating the original buffer. - pbd := new(GoTest) - Unmarshal(buf, pbd) - - // Check the checkable values - for i := uint64(0); i < N; i++ { - if pbd.Repeatedgroup[i] == nil { // TODO: more checking? - t.Error("pbd.Repeatedgroup bad") - } - var x uint64 - x = uint64(pbd.F_Sint64Repeated[i]) - if x != i { - t.Error("pbd.F_Sint64Repeated bad", x, i) - } - x = uint64(pbd.F_Sint32Repeated[i]) - if x != i { - t.Error("pbd.F_Sint32Repeated bad", x, i) - } - s := fmt.Sprint(i) - equalbytes(pbd.F_BytesRepeated[i], []byte(s), t) - if pbd.F_StringRepeated[i] != s { - t.Error("pbd.F_Sint32Repeated bad", pbd.F_StringRepeated[i], i) - } - x = uint64(pbd.F_DoubleRepeated[i]) - if x != i { - t.Error("pbd.F_DoubleRepeated bad", x, i) - } - x = uint64(pbd.F_FloatRepeated[i]) - if x != i { - t.Error("pbd.F_FloatRepeated bad", x, i) - } - x = pbd.F_Uint64Repeated[i] - if x != i { - t.Error("pbd.F_Uint64Repeated bad", x, i) - } - x = uint64(pbd.F_Uint32Repeated[i]) - if x != i { - t.Error("pbd.F_Uint32Repeated bad", x, i) - } - x = pbd.F_Fixed64Repeated[i] - if x != i { - t.Error("pbd.F_Fixed64Repeated bad", x, i) - } - x = uint64(pbd.F_Fixed32Repeated[i]) - if x != i { - t.Error("pbd.F_Fixed32Repeated bad", x, i) - } - x = uint64(pbd.F_Int64Repeated[i]) - if x != i { - t.Error("pbd.F_Int64Repeated bad", x, i) - } - x = uint64(pbd.F_Int32Repeated[i]) - if x != i { - t.Error("pbd.F_Int32Repeated bad", x, i) - } - if pbd.F_BoolRepeated[i] != (i%2 == 0) { - t.Error("pbd.F_BoolRepeated bad", x, i) - } - if pbd.RepeatedField[i] == nil { // TODO: more checking? - t.Error("pbd.RepeatedField bad") - } - } -} - -// Verify we give a useful message when decoding to the wrong structure type. -func TestTypeMismatch(t *testing.T) { - pb1 := initGoTest(true) - - // Marshal - o := old() - o.Marshal(pb1) - - // Now Unmarshal it to the wrong type. - pb2 := initGoTestField() - err := o.Unmarshal(pb2) - if err == nil { - t.Error("expected error, got no error") - } else if !strings.Contains(err.Error(), "bad wiretype") { - t.Error("expected bad wiretype error, got", err) - } -} - -func encodeDecode(t *testing.T, in, out Message, msg string) { - buf, err := Marshal(in) - if err != nil { - t.Fatalf("failed marshaling %v: %v", msg, err) - } - if err := Unmarshal(buf, out); err != nil { - t.Fatalf("failed unmarshaling %v: %v", msg, err) - } -} - -func TestPackedNonPackedDecoderSwitching(t *testing.T) { - np, p := new(NonPackedTest), new(PackedTest) - - // non-packed -> packed - np.A = []int32{0, 1, 1, 2, 3, 5} - encodeDecode(t, np, p, "non-packed -> packed") - if !reflect.DeepEqual(np.A, p.B) { - t.Errorf("failed non-packed -> packed; np.A=%+v, p.B=%+v", np.A, p.B) - } - - // packed -> non-packed - np.Reset() - p.B = []int32{3, 1, 4, 1, 5, 9} - encodeDecode(t, p, np, "packed -> non-packed") - if !reflect.DeepEqual(p.B, np.A) { - t.Errorf("failed packed -> non-packed; p.B=%+v, np.A=%+v", p.B, np.A) - } -} - -func TestProto1RepeatedGroup(t *testing.T) { - pb := &MessageList{ - Message: []*MessageList_Message{ - { - Name: String("blah"), - Count: Int32(7), - }, - // NOTE: pb.Message[1] is a nil - nil, - }, - } - - o := old() - err := o.Marshal(pb) - if err == nil || !strings.Contains(err.Error(), "repeated field Message has nil") { - t.Fatalf("unexpected or no error when marshaling: %v", err) - } -} - -// Test that enums work. Checks for a bug introduced by making enums -// named types instead of int32: newInt32FromUint64 would crash with -// a type mismatch in reflect.PointTo. -func TestEnum(t *testing.T) { - pb := new(GoEnum) - pb.Foo = FOO_FOO1.Enum() - o := old() - if err := o.Marshal(pb); err != nil { - t.Fatal("error encoding enum:", err) - } - pb1 := new(GoEnum) - if err := o.Unmarshal(pb1); err != nil { - t.Fatal("error decoding enum:", err) - } - if *pb1.Foo != FOO_FOO1 { - t.Error("expected 7 but got ", *pb1.Foo) - } -} - -// Enum types have String methods. Check that enum fields can be printed. -// We don't care what the value actually is, just as long as it doesn't crash. -func TestPrintingNilEnumFields(t *testing.T) { - pb := new(GoEnum) - _ = fmt.Sprintf("%+v", pb) -} - -// Verify that absent required fields cause Marshal/Unmarshal to return errors. -func TestRequiredFieldEnforcement(t *testing.T) { - pb := new(GoTestField) - _, err := Marshal(pb) - if err == nil { - t.Error("marshal: expected error, got nil") - } else if _, ok := err.(*RequiredNotSetError); !ok || !strings.Contains(err.Error(), "Label") { - t.Errorf("marshal: bad error type: %v", err) - } - - // A slightly sneaky, yet valid, proto. It encodes the same required field twice, - // so simply counting the required fields is insufficient. - // field 1, encoding 2, value "hi" - buf := []byte("\x0A\x02hi\x0A\x02hi") - err = Unmarshal(buf, pb) - if err == nil { - t.Error("unmarshal: expected error, got nil") - } else if _, ok := err.(*RequiredNotSetError); !ok || !strings.Contains(err.Error(), "{Unknown}") { - t.Errorf("unmarshal: bad error type: %v", err) - } -} - -// Verify that absent required fields in groups cause Marshal/Unmarshal to return errors. -func TestRequiredFieldEnforcementGroups(t *testing.T) { - pb := &GoTestRequiredGroupField{Group: &GoTestRequiredGroupField_Group{}} - if _, err := Marshal(pb); err == nil { - t.Error("marshal: expected error, got nil") - } else if _, ok := err.(*RequiredNotSetError); !ok || !strings.Contains(err.Error(), "Group.Field") { - t.Errorf("marshal: bad error type: %v", err) - } - - buf := []byte{11, 12} - if err := Unmarshal(buf, pb); err == nil { - t.Error("unmarshal: expected error, got nil") - } else if _, ok := err.(*RequiredNotSetError); !ok || !strings.Contains(err.Error(), "Group.{Unknown}") { - t.Errorf("unmarshal: bad error type: %v", err) - } -} - -func TestTypedNilMarshal(t *testing.T) { - // A typed nil should return ErrNil and not crash. - { - var m *GoEnum - if _, err := Marshal(m); err != ErrNil { - t.Errorf("Marshal(%#v): got %v, want ErrNil", m, err) - } - } - - { - m := &Communique{Union: &Communique_Msg{nil}} - if _, err := Marshal(m); err == nil || err == ErrNil { - t.Errorf("Marshal(%#v): got %v, want errOneofHasNil", m, err) - } - } -} - -// A type that implements the Marshaler interface, but is not nillable. -type nonNillableInt uint64 - -func (nni nonNillableInt) Marshal() ([]byte, error) { - return EncodeVarint(uint64(nni)), nil -} - -type NNIMessage struct { - nni nonNillableInt -} - -func (*NNIMessage) Reset() {} -func (*NNIMessage) String() string { return "" } -func (*NNIMessage) ProtoMessage() {} - -// A type that implements the Marshaler interface and is nillable. -type nillableMessage struct { - x uint64 -} - -func (nm *nillableMessage) Marshal() ([]byte, error) { - return EncodeVarint(nm.x), nil -} - -type NMMessage struct { - nm *nillableMessage -} - -func (*NMMessage) Reset() {} -func (*NMMessage) String() string { return "" } -func (*NMMessage) ProtoMessage() {} - -// Verify a type that uses the Marshaler interface, but has a nil pointer. -func TestNilMarshaler(t *testing.T) { - // Try a struct with a Marshaler field that is nil. - // It should be directly marshable. - nmm := new(NMMessage) - if _, err := Marshal(nmm); err != nil { - t.Error("unexpected error marshaling nmm: ", err) - } - - // Try a struct with a Marshaler field that is not nillable. - nnim := new(NNIMessage) - nnim.nni = 7 - var _ Marshaler = nnim.nni // verify it is truly a Marshaler - if _, err := Marshal(nnim); err != nil { - t.Error("unexpected error marshaling nnim: ", err) - } -} - -func TestAllSetDefaults(t *testing.T) { - // Exercise SetDefaults with all scalar field types. - m := &Defaults{ - // NaN != NaN, so override that here. - F_Nan: Float32(1.7), - } - expected := &Defaults{ - F_Bool: Bool(true), - F_Int32: Int32(32), - F_Int64: Int64(64), - F_Fixed32: Uint32(320), - F_Fixed64: Uint64(640), - F_Uint32: Uint32(3200), - F_Uint64: Uint64(6400), - F_Float: Float32(314159), - F_Double: Float64(271828), - F_String: String(`hello, "world!"` + "\n"), - F_Bytes: []byte("Bignose"), - F_Sint32: Int32(-32), - F_Sint64: Int64(-64), - F_Enum: Defaults_GREEN.Enum(), - F_Pinf: Float32(float32(math.Inf(1))), - F_Ninf: Float32(float32(math.Inf(-1))), - F_Nan: Float32(1.7), - StrZero: String(""), - } - SetDefaults(m) - if !Equal(m, expected) { - t.Errorf("SetDefaults failed\n got %v\nwant %v", m, expected) - } -} - -func TestSetDefaultsWithSetField(t *testing.T) { - // Check that a set value is not overridden. - m := &Defaults{ - F_Int32: Int32(12), - } - SetDefaults(m) - if v := m.GetF_Int32(); v != 12 { - t.Errorf("m.FInt32 = %v, want 12", v) - } -} - -func TestSetDefaultsWithSubMessage(t *testing.T) { - m := &OtherMessage{ - Key: Int64(123), - Inner: &InnerMessage{ - Host: String("gopher"), - }, - } - expected := &OtherMessage{ - Key: Int64(123), - Inner: &InnerMessage{ - Host: String("gopher"), - Port: Int32(4000), - }, - } - SetDefaults(m) - if !Equal(m, expected) { - t.Errorf("\n got %v\nwant %v", m, expected) - } -} - -func TestSetDefaultsWithRepeatedSubMessage(t *testing.T) { - m := &MyMessage{ - RepInner: []*InnerMessage{{}}, - } - expected := &MyMessage{ - RepInner: []*InnerMessage{{ - Port: Int32(4000), - }}, - } - SetDefaults(m) - if !Equal(m, expected) { - t.Errorf("\n got %v\nwant %v", m, expected) - } -} - -func TestSetDefaultWithRepeatedNonMessage(t *testing.T) { - m := &MyMessage{ - Pet: []string{"turtle", "wombat"}, - } - expected := Clone(m) - SetDefaults(m) - if !Equal(m, expected) { - t.Errorf("\n got %v\nwant %v", m, expected) - } -} - -func TestMaximumTagNumber(t *testing.T) { - m := &MaxTag{ - LastField: String("natural goat essence"), - } - buf, err := Marshal(m) - if err != nil { - t.Fatalf("proto.Marshal failed: %v", err) - } - m2 := new(MaxTag) - if err := Unmarshal(buf, m2); err != nil { - t.Fatalf("proto.Unmarshal failed: %v", err) - } - if got, want := m2.GetLastField(), *m.LastField; got != want { - t.Errorf("got %q, want %q", got, want) - } -} - -func TestJSON(t *testing.T) { - m := &MyMessage{ - Count: Int32(4), - Pet: []string{"bunny", "kitty"}, - Inner: &InnerMessage{ - Host: String("cauchy"), - }, - Bikeshed: MyMessage_GREEN.Enum(), - } - const expected = `{"count":4,"pet":["bunny","kitty"],"inner":{"host":"cauchy"},"bikeshed":1}` - - b, err := json.Marshal(m) - if err != nil { - t.Fatalf("json.Marshal failed: %v", err) - } - s := string(b) - if s != expected { - t.Errorf("got %s\nwant %s", s, expected) - } - - received := new(MyMessage) - if err := json.Unmarshal(b, received); err != nil { - t.Fatalf("json.Unmarshal failed: %v", err) - } - if !Equal(received, m) { - t.Fatalf("got %s, want %s", received, m) - } - - // Test unmarshalling of JSON with symbolic enum name. - const old = `{"count":4,"pet":["bunny","kitty"],"inner":{"host":"cauchy"},"bikeshed":"GREEN"}` - received.Reset() - if err := json.Unmarshal([]byte(old), received); err != nil { - t.Fatalf("json.Unmarshal failed: %v", err) - } - if !Equal(received, m) { - t.Fatalf("got %s, want %s", received, m) - } -} - -func TestBadWireType(t *testing.T) { - b := []byte{7<<3 | 6} // field 7, wire type 6 - pb := new(OtherMessage) - if err := Unmarshal(b, pb); err == nil { - t.Errorf("Unmarshal did not fail") - } else if !strings.Contains(err.Error(), "unknown wire type") { - t.Errorf("wrong error: %v", err) - } -} - -func TestBytesWithInvalidLength(t *testing.T) { - // If a byte sequence has an invalid (negative) length, Unmarshal should not panic. - b := []byte{2<<3 | WireBytes, 0xff, 0xff, 0xff, 0xff, 0xff, 0} - Unmarshal(b, new(MyMessage)) -} - -func TestLengthOverflow(t *testing.T) { - // Overflowing a length should not panic. - b := []byte{2<<3 | WireBytes, 1, 1, 3<<3 | WireBytes, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x01} - Unmarshal(b, new(MyMessage)) -} - -func TestVarintOverflow(t *testing.T) { - // Overflowing a 64-bit length should not be allowed. - b := []byte{1<<3 | WireVarint, 0x01, 3<<3 | WireBytes, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01} - if err := Unmarshal(b, new(MyMessage)); err == nil { - t.Fatalf("Overflowed uint64 length without error") - } -} - -func TestUnmarshalFuzz(t *testing.T) { - const N = 1000 - seed := time.Now().UnixNano() - t.Logf("RNG seed is %d", seed) - rng := rand.New(rand.NewSource(seed)) - buf := make([]byte, 20) - for i := 0; i < N; i++ { - for j := range buf { - buf[j] = byte(rng.Intn(256)) - } - fuzzUnmarshal(t, buf) - } -} - -func TestMergeMessages(t *testing.T) { - pb := &MessageList{Message: []*MessageList_Message{{Name: String("x"), Count: Int32(1)}}} - data, err := Marshal(pb) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - - pb1 := new(MessageList) - if err := Unmarshal(data, pb1); err != nil { - t.Fatalf("first Unmarshal: %v", err) - } - if err := Unmarshal(data, pb1); err != nil { - t.Fatalf("second Unmarshal: %v", err) - } - if len(pb1.Message) != 1 { - t.Errorf("two Unmarshals produced %d Messages, want 1", len(pb1.Message)) - } - - pb2 := new(MessageList) - if err := UnmarshalMerge(data, pb2); err != nil { - t.Fatalf("first UnmarshalMerge: %v", err) - } - if err := UnmarshalMerge(data, pb2); err != nil { - t.Fatalf("second UnmarshalMerge: %v", err) - } - if len(pb2.Message) != 2 { - t.Errorf("two UnmarshalMerges produced %d Messages, want 2", len(pb2.Message)) - } -} - -func TestExtensionMarshalOrder(t *testing.T) { - m := &MyMessage{Count: Int(123)} - if err := SetExtension(m, E_Ext_More, &Ext{Data: String("alpha")}); err != nil { - t.Fatalf("SetExtension: %v", err) - } - if err := SetExtension(m, E_Ext_Text, String("aleph")); err != nil { - t.Fatalf("SetExtension: %v", err) - } - if err := SetExtension(m, E_Ext_Number, Int32(1)); err != nil { - t.Fatalf("SetExtension: %v", err) - } - - // Serialize m several times, and check we get the same bytes each time. - var orig []byte - for i := 0; i < 100; i++ { - b, err := Marshal(m) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - if i == 0 { - orig = b - continue - } - if !bytes.Equal(b, orig) { - t.Errorf("Bytes differ on attempt #%d", i) - } - } -} - -// Many extensions, because small maps might not iterate differently on each iteration. -var exts = []*ExtensionDesc{ - E_X201, - E_X202, - E_X203, - E_X204, - E_X205, - E_X206, - E_X207, - E_X208, - E_X209, - E_X210, - E_X211, - E_X212, - E_X213, - E_X214, - E_X215, - E_X216, - E_X217, - E_X218, - E_X219, - E_X220, - E_X221, - E_X222, - E_X223, - E_X224, - E_X225, - E_X226, - E_X227, - E_X228, - E_X229, - E_X230, - E_X231, - E_X232, - E_X233, - E_X234, - E_X235, - E_X236, - E_X237, - E_X238, - E_X239, - E_X240, - E_X241, - E_X242, - E_X243, - E_X244, - E_X245, - E_X246, - E_X247, - E_X248, - E_X249, - E_X250, -} - -func TestMessageSetMarshalOrder(t *testing.T) { - m := &MyMessageSet{} - for _, x := range exts { - if err := SetExtension(m, x, &Empty{}); err != nil { - t.Fatalf("SetExtension: %v", err) - } - } - - buf, err := Marshal(m) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - - // Serialize m several times, and check we get the same bytes each time. - for i := 0; i < 10; i++ { - b1, err := Marshal(m) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - if !bytes.Equal(b1, buf) { - t.Errorf("Bytes differ on re-Marshal #%d", i) - } - - m2 := &MyMessageSet{} - if err := Unmarshal(buf, m2); err != nil { - t.Errorf("Unmarshal: %v", err) - } - b2, err := Marshal(m2) - if err != nil { - t.Errorf("re-Marshal: %v", err) - } - if !bytes.Equal(b2, buf) { - t.Errorf("Bytes differ on round-trip #%d", i) - } - } -} - -func TestUnmarshalMergesMessages(t *testing.T) { - // If a nested message occurs twice in the input, - // the fields should be merged when decoding. - a := &OtherMessage{ - Key: Int64(123), - Inner: &InnerMessage{ - Host: String("polhode"), - Port: Int32(1234), - }, - } - aData, err := Marshal(a) - if err != nil { - t.Fatalf("Marshal(a): %v", err) - } - b := &OtherMessage{ - Weight: Float32(1.2), - Inner: &InnerMessage{ - Host: String("herpolhode"), - Connected: Bool(true), - }, - } - bData, err := Marshal(b) - if err != nil { - t.Fatalf("Marshal(b): %v", err) - } - want := &OtherMessage{ - Key: Int64(123), - Weight: Float32(1.2), - Inner: &InnerMessage{ - Host: String("herpolhode"), - Port: Int32(1234), - Connected: Bool(true), - }, - } - got := new(OtherMessage) - if err := Unmarshal(append(aData, bData...), got); err != nil { - t.Fatalf("Unmarshal: %v", err) - } - if !Equal(got, want) { - t.Errorf("\n got %v\nwant %v", got, want) - } -} - -func TestEncodingSizes(t *testing.T) { - tests := []struct { - m Message - n int - }{ - {&Defaults{F_Int32: Int32(math.MaxInt32)}, 6}, - {&Defaults{F_Int32: Int32(math.MinInt32)}, 11}, - {&Defaults{F_Uint32: Uint32(uint32(math.MaxInt32) + 1)}, 6}, - {&Defaults{F_Uint32: Uint32(math.MaxUint32)}, 6}, - } - for _, test := range tests { - b, err := Marshal(test.m) - if err != nil { - t.Errorf("Marshal(%v): %v", test.m, err) - continue - } - if len(b) != test.n { - t.Errorf("Marshal(%v) yielded %d bytes, want %d bytes", test.m, len(b), test.n) - } - } -} - -func TestRequiredNotSetError(t *testing.T) { - pb := initGoTest(false) - pb.RequiredField.Label = nil - pb.F_Int32Required = nil - pb.F_Int64Required = nil - - expected := "0807" + // field 1, encoding 0, value 7 - "2206" + "120474797065" + // field 4, encoding 2 (GoTestField) - "5001" + // field 10, encoding 0, value 1 - "6d20000000" + // field 13, encoding 5, value 0x20 - "714000000000000000" + // field 14, encoding 1, value 0x40 - "78a019" + // field 15, encoding 0, value 0xca0 = 3232 - "8001c032" + // field 16, encoding 0, value 0x1940 = 6464 - "8d0100004a45" + // field 17, encoding 5, value 3232.0 - "9101000000000040b940" + // field 18, encoding 1, value 6464.0 - "9a0106" + "737472696e67" + // field 19, encoding 2, string "string" - "b304" + // field 70, encoding 3, start group - "ba0408" + "7265717569726564" + // field 71, encoding 2, string "required" - "b404" + // field 70, encoding 4, end group - "aa0605" + "6279746573" + // field 101, encoding 2, string "bytes" - "b0063f" + // field 102, encoding 0, 0x3f zigzag32 - "b8067f" // field 103, encoding 0, 0x7f zigzag64 - - o := old() - bytes, err := Marshal(pb) - if _, ok := err.(*RequiredNotSetError); !ok { - fmt.Printf("marshal-1 err = %v, want *RequiredNotSetError", err) - o.DebugPrint("", bytes) - t.Fatalf("expected = %s", expected) - } - if strings.Index(err.Error(), "RequiredField.Label") < 0 { - t.Errorf("marshal-1 wrong err msg: %v", err) - } - if !equal(bytes, expected, t) { - o.DebugPrint("neq 1", bytes) - t.Fatalf("expected = %s", expected) - } - - // Now test Unmarshal by recreating the original buffer. - pbd := new(GoTest) - err = Unmarshal(bytes, pbd) - if _, ok := err.(*RequiredNotSetError); !ok { - t.Fatalf("unmarshal err = %v, want *RequiredNotSetError", err) - o.DebugPrint("", bytes) - t.Fatalf("string = %s", expected) - } - if strings.Index(err.Error(), "RequiredField.{Unknown}") < 0 { - t.Errorf("unmarshal wrong err msg: %v", err) - } - bytes, err = Marshal(pbd) - if _, ok := err.(*RequiredNotSetError); !ok { - t.Errorf("marshal-2 err = %v, want *RequiredNotSetError", err) - o.DebugPrint("", bytes) - t.Fatalf("string = %s", expected) - } - if strings.Index(err.Error(), "RequiredField.Label") < 0 { - t.Errorf("marshal-2 wrong err msg: %v", err) - } - if !equal(bytes, expected, t) { - o.DebugPrint("neq 2", bytes) - t.Fatalf("string = %s", expected) - } -} - -func fuzzUnmarshal(t *testing.T, data []byte) { - defer func() { - if e := recover(); e != nil { - t.Errorf("These bytes caused a panic: %+v", data) - t.Logf("Stack:\n%s", debug.Stack()) - t.FailNow() - } - }() - - pb := new(MyMessage) - Unmarshal(data, pb) -} - -func TestMapFieldMarshal(t *testing.T) { - m := &MessageWithMap{ - NameMapping: map[int32]string{ - 1: "Rob", - 4: "Ian", - 8: "Dave", - }, - } - b, err := Marshal(m) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - - // b should be the concatenation of these three byte sequences in some order. - parts := []string{ - "\n\a\b\x01\x12\x03Rob", - "\n\a\b\x04\x12\x03Ian", - "\n\b\b\x08\x12\x04Dave", - } - ok := false - for i := range parts { - for j := range parts { - if j == i { - continue - } - for k := range parts { - if k == i || k == j { - continue - } - try := parts[i] + parts[j] + parts[k] - if bytes.Equal(b, []byte(try)) { - ok = true - break - } - } - } - } - if !ok { - t.Fatalf("Incorrect Marshal output.\n got %q\nwant %q (or a permutation of that)", b, parts[0]+parts[1]+parts[2]) - } - t.Logf("FYI b: %q", b) - - (new(Buffer)).DebugPrint("Dump of b", b) -} - -func TestMapFieldRoundTrips(t *testing.T) { - m := &MessageWithMap{ - NameMapping: map[int32]string{ - 1: "Rob", - 4: "Ian", - 8: "Dave", - }, - MsgMapping: map[int64]*FloatingPoint{ - 0x7001: &FloatingPoint{F: Float64(2.0)}, - }, - ByteMapping: map[bool][]byte{ - false: []byte("that's not right!"), - true: []byte("aye, 'tis true!"), - }, - } - b, err := Marshal(m) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - t.Logf("FYI b: %q", b) - m2 := new(MessageWithMap) - if err := Unmarshal(b, m2); err != nil { - t.Fatalf("Unmarshal: %v", err) - } - for _, pair := range [][2]interface{}{ - {m.NameMapping, m2.NameMapping}, - {m.MsgMapping, m2.MsgMapping}, - {m.ByteMapping, m2.ByteMapping}, - } { - if !reflect.DeepEqual(pair[0], pair[1]) { - t.Errorf("Map did not survive a round trip.\ninitial: %v\n final: %v", pair[0], pair[1]) - } - } -} - -func TestMapFieldWithNil(t *testing.T) { - m1 := &MessageWithMap{ - MsgMapping: map[int64]*FloatingPoint{ - 1: nil, - }, - } - b, err := Marshal(m1) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - m2 := new(MessageWithMap) - if err := Unmarshal(b, m2); err != nil { - t.Fatalf("Unmarshal: %v, got these bytes: %v", err, b) - } - if v, ok := m2.MsgMapping[1]; !ok { - t.Error("msg_mapping[1] not present") - } else if v != nil { - t.Errorf("msg_mapping[1] not nil: %v", v) - } -} - -func TestMapFieldWithNilBytes(t *testing.T) { - m1 := &MessageWithMap{ - ByteMapping: map[bool][]byte{ - false: []byte{}, - true: nil, - }, - } - n := Size(m1) - b, err := Marshal(m1) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - if n != len(b) { - t.Errorf("Size(m1) = %d; want len(Marshal(m1)) = %d", n, len(b)) - } - m2 := new(MessageWithMap) - if err := Unmarshal(b, m2); err != nil { - t.Fatalf("Unmarshal: %v, got these bytes: %v", err, b) - } - if v, ok := m2.ByteMapping[false]; !ok { - t.Error("byte_mapping[false] not present") - } else if len(v) != 0 { - t.Errorf("byte_mapping[false] not empty: %#v", v) - } - if v, ok := m2.ByteMapping[true]; !ok { - t.Error("byte_mapping[true] not present") - } else if len(v) != 0 { - t.Errorf("byte_mapping[true] not empty: %#v", v) - } -} - -func TestDecodeMapFieldMissingKey(t *testing.T) { - b := []byte{ - 0x0A, 0x03, // message, tag 1 (name_mapping), of length 3 bytes - // no key - 0x12, 0x01, 0x6D, // string value of length 1 byte, value "m" - } - got := &MessageWithMap{} - err := Unmarshal(b, got) - if err != nil { - t.Fatalf("failed to marshal map with missing key: %v", err) - } - want := &MessageWithMap{NameMapping: map[int32]string{0: "m"}} - if !Equal(got, want) { - t.Errorf("Unmarshaled map with no key was not as expected. got: %v, want %v", got, want) - } -} - -func TestDecodeMapFieldMissingValue(t *testing.T) { - b := []byte{ - 0x0A, 0x02, // message, tag 1 (name_mapping), of length 2 bytes - 0x08, 0x01, // varint key, value 1 - // no value - } - got := &MessageWithMap{} - err := Unmarshal(b, got) - if err != nil { - t.Fatalf("failed to marshal map with missing value: %v", err) - } - want := &MessageWithMap{NameMapping: map[int32]string{1: ""}} - if !Equal(got, want) { - t.Errorf("Unmarshaled map with no value was not as expected. got: %v, want %v", got, want) - } -} - -func TestOneof(t *testing.T) { - m := &Communique{} - b, err := Marshal(m) - if err != nil { - t.Fatalf("Marshal of empty message with oneof: %v", err) - } - if len(b) != 0 { - t.Errorf("Marshal of empty message yielded too many bytes: %v", b) - } - - m = &Communique{ - Union: &Communique_Name{"Barry"}, - } - - // Round-trip. - b, err = Marshal(m) - if err != nil { - t.Fatalf("Marshal of message with oneof: %v", err) - } - if len(b) != 7 { // name tag/wire (1) + name len (1) + name (5) - t.Errorf("Incorrect marshal of message with oneof: %v", b) - } - m.Reset() - if err := Unmarshal(b, m); err != nil { - t.Fatalf("Unmarshal of message with oneof: %v", err) - } - if x, ok := m.Union.(*Communique_Name); !ok || x.Name != "Barry" { - t.Errorf("After round trip, Union = %+v", m.Union) - } - if name := m.GetName(); name != "Barry" { - t.Errorf("After round trip, GetName = %q, want %q", name, "Barry") - } - - // Let's try with a message in the oneof. - m.Union = &Communique_Msg{&Strings{StringField: String("deep deep string")}} - b, err = Marshal(m) - if err != nil { - t.Fatalf("Marshal of message with oneof set to message: %v", err) - } - if len(b) != 20 { // msg tag/wire (1) + msg len (1) + msg (1 + 1 + 16) - t.Errorf("Incorrect marshal of message with oneof set to message: %v", b) - } - m.Reset() - if err := Unmarshal(b, m); err != nil { - t.Fatalf("Unmarshal of message with oneof set to message: %v", err) - } - ss, ok := m.Union.(*Communique_Msg) - if !ok || ss.Msg.GetStringField() != "deep deep string" { - t.Errorf("After round trip with oneof set to message, Union = %+v", m.Union) - } -} - -func TestInefficientPackedBool(t *testing.T) { - // https://github.com/golang/protobuf/issues/76 - inp := []byte{ - 0x12, 0x02, // 0x12 = 2<<3|2; 2 bytes - // Usually a bool should take a single byte, - // but it is permitted to be any varint. - 0xb9, 0x30, - } - if err := Unmarshal(inp, new(MoreRepeated)); err != nil { - t.Error(err) - } -} - -// Benchmarks - -func testMsg() *GoTest { - pb := initGoTest(true) - const N = 1000 // Internally the library starts much smaller. - pb.F_Int32Repeated = make([]int32, N) - pb.F_DoubleRepeated = make([]float64, N) - for i := 0; i < N; i++ { - pb.F_Int32Repeated[i] = int32(i) - pb.F_DoubleRepeated[i] = float64(i) - } - return pb -} - -func bytesMsg() *GoTest { - pb := initGoTest(true) - buf := make([]byte, 4000) - for i := range buf { - buf[i] = byte(i) - } - pb.F_BytesDefaulted = buf - return pb -} - -func benchmarkMarshal(b *testing.B, pb Message, marshal func(Message) ([]byte, error)) { - d, _ := marshal(pb) - b.SetBytes(int64(len(d))) - b.ResetTimer() - for i := 0; i < b.N; i++ { - marshal(pb) - } -} - -func benchmarkBufferMarshal(b *testing.B, pb Message) { - p := NewBuffer(nil) - benchmarkMarshal(b, pb, func(pb0 Message) ([]byte, error) { - p.Reset() - err := p.Marshal(pb0) - return p.Bytes(), err - }) -} - -func benchmarkSize(b *testing.B, pb Message) { - benchmarkMarshal(b, pb, func(pb0 Message) ([]byte, error) { - Size(pb) - return nil, nil - }) -} - -func newOf(pb Message) Message { - in := reflect.ValueOf(pb) - if in.IsNil() { - return pb - } - return reflect.New(in.Type().Elem()).Interface().(Message) -} - -func benchmarkUnmarshal(b *testing.B, pb Message, unmarshal func([]byte, Message) error) { - d, _ := Marshal(pb) - b.SetBytes(int64(len(d))) - pbd := newOf(pb) - - b.ResetTimer() - for i := 0; i < b.N; i++ { - unmarshal(d, pbd) - } -} - -func benchmarkBufferUnmarshal(b *testing.B, pb Message) { - p := NewBuffer(nil) - benchmarkUnmarshal(b, pb, func(d []byte, pb0 Message) error { - p.SetBuf(d) - return p.Unmarshal(pb0) - }) -} - -// Benchmark{Marshal,BufferMarshal,Size,Unmarshal,BufferUnmarshal}{,Bytes} - -func BenchmarkMarshal(b *testing.B) { - benchmarkMarshal(b, testMsg(), Marshal) -} - -func BenchmarkBufferMarshal(b *testing.B) { - benchmarkBufferMarshal(b, testMsg()) -} - -func BenchmarkSize(b *testing.B) { - benchmarkSize(b, testMsg()) -} - -func BenchmarkUnmarshal(b *testing.B) { - benchmarkUnmarshal(b, testMsg(), Unmarshal) -} - -func BenchmarkBufferUnmarshal(b *testing.B) { - benchmarkBufferUnmarshal(b, testMsg()) -} - -func BenchmarkMarshalBytes(b *testing.B) { - benchmarkMarshal(b, bytesMsg(), Marshal) -} - -func BenchmarkBufferMarshalBytes(b *testing.B) { - benchmarkBufferMarshal(b, bytesMsg()) -} - -func BenchmarkSizeBytes(b *testing.B) { - benchmarkSize(b, bytesMsg()) -} - -func BenchmarkUnmarshalBytes(b *testing.B) { - benchmarkUnmarshal(b, bytesMsg(), Unmarshal) -} - -func BenchmarkBufferUnmarshalBytes(b *testing.B) { - benchmarkBufferUnmarshal(b, bytesMsg()) -} - -func BenchmarkUnmarshalUnrecognizedFields(b *testing.B) { - b.StopTimer() - pb := initGoTestField() - skip := &GoSkipTest{ - SkipInt32: Int32(32), - SkipFixed32: Uint32(3232), - SkipFixed64: Uint64(6464), - SkipString: String("skipper"), - Skipgroup: &GoSkipTest_SkipGroup{ - GroupInt32: Int32(75), - GroupString: String("wxyz"), - }, - } - - pbd := new(GoTestField) - p := NewBuffer(nil) - p.Marshal(pb) - p.Marshal(skip) - p2 := NewBuffer(nil) - - b.StartTimer() - for i := 0; i < b.N; i++ { - p2.SetBuf(p.Bytes()) - p2.Unmarshal(pbd) - } -} diff --git a/vendor/github.com/golang/protobuf/proto/any_test.go b/vendor/github.com/golang/protobuf/proto/any_test.go deleted file mode 100644 index 1a3c22ed..00000000 --- a/vendor/github.com/golang/protobuf/proto/any_test.go +++ /dev/null @@ -1,300 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2016 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may 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 -// OWNER 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. - -package proto_test - -import ( - "strings" - "testing" - - "github.com/golang/protobuf/proto" - - pb "github.com/golang/protobuf/proto/proto3_proto" - testpb "github.com/golang/protobuf/proto/testdata" - anypb "github.com/golang/protobuf/ptypes/any" -) - -var ( - expandedMarshaler = proto.TextMarshaler{ExpandAny: true} - expandedCompactMarshaler = proto.TextMarshaler{Compact: true, ExpandAny: true} -) - -// anyEqual reports whether two messages which may be google.protobuf.Any or may -// contain google.protobuf.Any fields are equal. We can't use proto.Equal for -// comparison, because semantically equivalent messages may be marshaled to -// binary in different tag order. Instead, trust that TextMarshaler with -// ExpandAny option works and compare the text marshaling results. -func anyEqual(got, want proto.Message) bool { - // if messages are proto.Equal, no need to marshal. - if proto.Equal(got, want) { - return true - } - g := expandedMarshaler.Text(got) - w := expandedMarshaler.Text(want) - return g == w -} - -type golden struct { - m proto.Message - t, c string -} - -var goldenMessages = makeGolden() - -func makeGolden() []golden { - nested := &pb.Nested{Bunny: "Monty"} - nb, err := proto.Marshal(nested) - if err != nil { - panic(err) - } - m1 := &pb.Message{ - Name: "David", - ResultCount: 47, - Anything: &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(nested), Value: nb}, - } - m2 := &pb.Message{ - Name: "David", - ResultCount: 47, - Anything: &anypb.Any{TypeUrl: "http://[::1]/type.googleapis.com/" + proto.MessageName(nested), Value: nb}, - } - m3 := &pb.Message{ - Name: "David", - ResultCount: 47, - Anything: &anypb.Any{TypeUrl: `type.googleapis.com/"/` + proto.MessageName(nested), Value: nb}, - } - m4 := &pb.Message{ - Name: "David", - ResultCount: 47, - Anything: &anypb.Any{TypeUrl: "type.googleapis.com/a/path/" + proto.MessageName(nested), Value: nb}, - } - m5 := &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(nested), Value: nb} - - any1 := &testpb.MyMessage{Count: proto.Int32(47), Name: proto.String("David")} - proto.SetExtension(any1, testpb.E_Ext_More, &testpb.Ext{Data: proto.String("foo")}) - proto.SetExtension(any1, testpb.E_Ext_Text, proto.String("bar")) - any1b, err := proto.Marshal(any1) - if err != nil { - panic(err) - } - any2 := &testpb.MyMessage{Count: proto.Int32(42), Bikeshed: testpb.MyMessage_GREEN.Enum(), RepBytes: [][]byte{[]byte("roboto")}} - proto.SetExtension(any2, testpb.E_Ext_More, &testpb.Ext{Data: proto.String("baz")}) - any2b, err := proto.Marshal(any2) - if err != nil { - panic(err) - } - m6 := &pb.Message{ - Name: "David", - ResultCount: 47, - Anything: &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(any1), Value: any1b}, - ManyThings: []*anypb.Any{ - &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(any2), Value: any2b}, - &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(any1), Value: any1b}, - }, - } - - const ( - m1Golden = ` -name: "David" -result_count: 47 -anything: < - [type.googleapis.com/proto3_proto.Nested]: < - bunny: "Monty" - > -> -` - m2Golden = ` -name: "David" -result_count: 47 -anything: < - ["http://[::1]/type.googleapis.com/proto3_proto.Nested"]: < - bunny: "Monty" - > -> -` - m3Golden = ` -name: "David" -result_count: 47 -anything: < - ["type.googleapis.com/\"/proto3_proto.Nested"]: < - bunny: "Monty" - > -> -` - m4Golden = ` -name: "David" -result_count: 47 -anything: < - [type.googleapis.com/a/path/proto3_proto.Nested]: < - bunny: "Monty" - > -> -` - m5Golden = ` -[type.googleapis.com/proto3_proto.Nested]: < - bunny: "Monty" -> -` - m6Golden = ` -name: "David" -result_count: 47 -anything: < - [type.googleapis.com/testdata.MyMessage]: < - count: 47 - name: "David" - [testdata.Ext.more]: < - data: "foo" - > - [testdata.Ext.text]: "bar" - > -> -many_things: < - [type.googleapis.com/testdata.MyMessage]: < - count: 42 - bikeshed: GREEN - rep_bytes: "roboto" - [testdata.Ext.more]: < - data: "baz" - > - > -> -many_things: < - [type.googleapis.com/testdata.MyMessage]: < - count: 47 - name: "David" - [testdata.Ext.more]: < - data: "foo" - > - [testdata.Ext.text]: "bar" - > -> -` - ) - return []golden{ - {m1, strings.TrimSpace(m1Golden) + "\n", strings.TrimSpace(compact(m1Golden)) + " "}, - {m2, strings.TrimSpace(m2Golden) + "\n", strings.TrimSpace(compact(m2Golden)) + " "}, - {m3, strings.TrimSpace(m3Golden) + "\n", strings.TrimSpace(compact(m3Golden)) + " "}, - {m4, strings.TrimSpace(m4Golden) + "\n", strings.TrimSpace(compact(m4Golden)) + " "}, - {m5, strings.TrimSpace(m5Golden) + "\n", strings.TrimSpace(compact(m5Golden)) + " "}, - {m6, strings.TrimSpace(m6Golden) + "\n", strings.TrimSpace(compact(m6Golden)) + " "}, - } -} - -func TestMarshalGolden(t *testing.T) { - for _, tt := range goldenMessages { - if got, want := expandedMarshaler.Text(tt.m), tt.t; got != want { - t.Errorf("message %v: got:\n%s\nwant:\n%s", tt.m, got, want) - } - if got, want := expandedCompactMarshaler.Text(tt.m), tt.c; got != want { - t.Errorf("message %v: got:\n`%s`\nwant:\n`%s`", tt.m, got, want) - } - } -} - -func TestUnmarshalGolden(t *testing.T) { - for _, tt := range goldenMessages { - want := tt.m - got := proto.Clone(tt.m) - got.Reset() - if err := proto.UnmarshalText(tt.t, got); err != nil { - t.Errorf("failed to unmarshal\n%s\nerror: %v", tt.t, err) - } - if !anyEqual(got, want) { - t.Errorf("message:\n%s\ngot:\n%s\nwant:\n%s", tt.t, got, want) - } - got.Reset() - if err := proto.UnmarshalText(tt.c, got); err != nil { - t.Errorf("failed to unmarshal\n%s\nerror: %v", tt.c, err) - } - if !anyEqual(got, want) { - t.Errorf("message:\n%s\ngot:\n%s\nwant:\n%s", tt.c, got, want) - } - } -} - -func TestMarshalUnknownAny(t *testing.T) { - m := &pb.Message{ - Anything: &anypb.Any{ - TypeUrl: "foo", - Value: []byte("bar"), - }, - } - want := `anything: < - type_url: "foo" - value: "bar" -> -` - got := expandedMarshaler.Text(m) - if got != want { - t.Errorf("got\n`%s`\nwant\n`%s`", got, want) - } -} - -func TestAmbiguousAny(t *testing.T) { - pb := &anypb.Any{} - err := proto.UnmarshalText(` - type_url: "ttt/proto3_proto.Nested" - value: "\n\x05Monty" - `, pb) - t.Logf("result: %v (error: %v)", expandedMarshaler.Text(pb), err) - if err != nil { - t.Errorf("failed to parse ambiguous Any message: %v", err) - } -} - -func TestUnmarshalOverwriteAny(t *testing.T) { - pb := &anypb.Any{} - err := proto.UnmarshalText(` - [type.googleapis.com/a/path/proto3_proto.Nested]: < - bunny: "Monty" - > - [type.googleapis.com/a/path/proto3_proto.Nested]: < - bunny: "Rabbit of Caerbannog" - > - `, pb) - want := `line 7: Any message unpacked multiple times, or "type_url" already set` - if err.Error() != want { - t.Errorf("incorrect error.\nHave: %v\nWant: %v", err.Error(), want) - } -} - -func TestUnmarshalAnyMixAndMatch(t *testing.T) { - pb := &anypb.Any{} - err := proto.UnmarshalText(` - value: "\n\x05Monty" - [type.googleapis.com/a/path/proto3_proto.Nested]: < - bunny: "Rabbit of Caerbannog" - > - `, pb) - want := `line 5: Any message unpacked multiple times, or "value" already set` - if err.Error() != want { - t.Errorf("incorrect error.\nHave: %v\nWant: %v", err.Error(), want) - } -} diff --git a/vendor/github.com/golang/protobuf/proto/clone_test.go b/vendor/github.com/golang/protobuf/proto/clone_test.go deleted file mode 100644 index f607ff49..00000000 --- a/vendor/github.com/golang/protobuf/proto/clone_test.go +++ /dev/null @@ -1,300 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2011 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may 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 -// OWNER 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. - -package proto_test - -import ( - "testing" - - "github.com/golang/protobuf/proto" - - proto3pb "github.com/golang/protobuf/proto/proto3_proto" - pb "github.com/golang/protobuf/proto/testdata" -) - -var cloneTestMessage = &pb.MyMessage{ - Count: proto.Int32(42), - Name: proto.String("Dave"), - Pet: []string{"bunny", "kitty", "horsey"}, - Inner: &pb.InnerMessage{ - Host: proto.String("niles"), - Port: proto.Int32(9099), - Connected: proto.Bool(true), - }, - Others: []*pb.OtherMessage{ - { - Value: []byte("some bytes"), - }, - }, - Somegroup: &pb.MyMessage_SomeGroup{ - GroupField: proto.Int32(6), - }, - RepBytes: [][]byte{[]byte("sham"), []byte("wow")}, -} - -func init() { - ext := &pb.Ext{ - Data: proto.String("extension"), - } - if err := proto.SetExtension(cloneTestMessage, pb.E_Ext_More, ext); err != nil { - panic("SetExtension: " + err.Error()) - } -} - -func TestClone(t *testing.T) { - m := proto.Clone(cloneTestMessage).(*pb.MyMessage) - if !proto.Equal(m, cloneTestMessage) { - t.Errorf("Clone(%v) = %v", cloneTestMessage, m) - } - - // Verify it was a deep copy. - *m.Inner.Port++ - if proto.Equal(m, cloneTestMessage) { - t.Error("Mutating clone changed the original") - } - // Byte fields and repeated fields should be copied. - if &m.Pet[0] == &cloneTestMessage.Pet[0] { - t.Error("Pet: repeated field not copied") - } - if &m.Others[0] == &cloneTestMessage.Others[0] { - t.Error("Others: repeated field not copied") - } - if &m.Others[0].Value[0] == &cloneTestMessage.Others[0].Value[0] { - t.Error("Others[0].Value: bytes field not copied") - } - if &m.RepBytes[0] == &cloneTestMessage.RepBytes[0] { - t.Error("RepBytes: repeated field not copied") - } - if &m.RepBytes[0][0] == &cloneTestMessage.RepBytes[0][0] { - t.Error("RepBytes[0]: bytes field not copied") - } -} - -func TestCloneNil(t *testing.T) { - var m *pb.MyMessage - if c := proto.Clone(m); !proto.Equal(m, c) { - t.Errorf("Clone(%v) = %v", m, c) - } -} - -var mergeTests = []struct { - src, dst, want proto.Message -}{ - { - src: &pb.MyMessage{ - Count: proto.Int32(42), - }, - dst: &pb.MyMessage{ - Name: proto.String("Dave"), - }, - want: &pb.MyMessage{ - Count: proto.Int32(42), - Name: proto.String("Dave"), - }, - }, - { - src: &pb.MyMessage{ - Inner: &pb.InnerMessage{ - Host: proto.String("hey"), - Connected: proto.Bool(true), - }, - Pet: []string{"horsey"}, - Others: []*pb.OtherMessage{ - { - Value: []byte("some bytes"), - }, - }, - }, - dst: &pb.MyMessage{ - Inner: &pb.InnerMessage{ - Host: proto.String("niles"), - Port: proto.Int32(9099), - }, - Pet: []string{"bunny", "kitty"}, - Others: []*pb.OtherMessage{ - { - Key: proto.Int64(31415926535), - }, - { - // Explicitly test a src=nil field - Inner: nil, - }, - }, - }, - want: &pb.MyMessage{ - Inner: &pb.InnerMessage{ - Host: proto.String("hey"), - Connected: proto.Bool(true), - Port: proto.Int32(9099), - }, - Pet: []string{"bunny", "kitty", "horsey"}, - Others: []*pb.OtherMessage{ - { - Key: proto.Int64(31415926535), - }, - {}, - { - Value: []byte("some bytes"), - }, - }, - }, - }, - { - src: &pb.MyMessage{ - RepBytes: [][]byte{[]byte("wow")}, - }, - dst: &pb.MyMessage{ - Somegroup: &pb.MyMessage_SomeGroup{ - GroupField: proto.Int32(6), - }, - RepBytes: [][]byte{[]byte("sham")}, - }, - want: &pb.MyMessage{ - Somegroup: &pb.MyMessage_SomeGroup{ - GroupField: proto.Int32(6), - }, - RepBytes: [][]byte{[]byte("sham"), []byte("wow")}, - }, - }, - // Check that a scalar bytes field replaces rather than appends. - { - src: &pb.OtherMessage{Value: []byte("foo")}, - dst: &pb.OtherMessage{Value: []byte("bar")}, - want: &pb.OtherMessage{Value: []byte("foo")}, - }, - { - src: &pb.MessageWithMap{ - NameMapping: map[int32]string{6: "Nigel"}, - MsgMapping: map[int64]*pb.FloatingPoint{ - 0x4001: &pb.FloatingPoint{F: proto.Float64(2.0)}, - 0x4002: &pb.FloatingPoint{ - F: proto.Float64(2.0), - }, - }, - ByteMapping: map[bool][]byte{true: []byte("wowsa")}, - }, - dst: &pb.MessageWithMap{ - NameMapping: map[int32]string{ - 6: "Bruce", // should be overwritten - 7: "Andrew", - }, - MsgMapping: map[int64]*pb.FloatingPoint{ - 0x4002: &pb.FloatingPoint{ - F: proto.Float64(3.0), - Exact: proto.Bool(true), - }, // the entire message should be overwritten - }, - }, - want: &pb.MessageWithMap{ - NameMapping: map[int32]string{ - 6: "Nigel", - 7: "Andrew", - }, - MsgMapping: map[int64]*pb.FloatingPoint{ - 0x4001: &pb.FloatingPoint{F: proto.Float64(2.0)}, - 0x4002: &pb.FloatingPoint{ - F: proto.Float64(2.0), - }, - }, - ByteMapping: map[bool][]byte{true: []byte("wowsa")}, - }, - }, - // proto3 shouldn't merge zero values, - // in the same way that proto2 shouldn't merge nils. - { - src: &proto3pb.Message{ - Name: "Aaron", - Data: []byte(""), // zero value, but not nil - }, - dst: &proto3pb.Message{ - HeightInCm: 176, - Data: []byte("texas!"), - }, - want: &proto3pb.Message{ - Name: "Aaron", - HeightInCm: 176, - Data: []byte("texas!"), - }, - }, - // Oneof fields should merge by assignment. - { - src: &pb.Communique{ - Union: &pb.Communique_Number{41}, - }, - dst: &pb.Communique{ - Union: &pb.Communique_Name{"Bobby Tables"}, - }, - want: &pb.Communique{ - Union: &pb.Communique_Number{41}, - }, - }, - // Oneof nil is the same as not set. - { - src: &pb.Communique{}, - dst: &pb.Communique{ - Union: &pb.Communique_Name{"Bobby Tables"}, - }, - want: &pb.Communique{ - Union: &pb.Communique_Name{"Bobby Tables"}, - }, - }, - { - src: &proto3pb.Message{ - Terrain: map[string]*proto3pb.Nested{ - "kay_a": &proto3pb.Nested{Cute: true}, // replace - "kay_b": &proto3pb.Nested{Bunny: "rabbit"}, // insert - }, - }, - dst: &proto3pb.Message{ - Terrain: map[string]*proto3pb.Nested{ - "kay_a": &proto3pb.Nested{Bunny: "lost"}, // replaced - "kay_c": &proto3pb.Nested{Bunny: "bunny"}, // keep - }, - }, - want: &proto3pb.Message{ - Terrain: map[string]*proto3pb.Nested{ - "kay_a": &proto3pb.Nested{Cute: true}, - "kay_b": &proto3pb.Nested{Bunny: "rabbit"}, - "kay_c": &proto3pb.Nested{Bunny: "bunny"}, - }, - }, - }, -} - -func TestMerge(t *testing.T) { - for _, m := range mergeTests { - got := proto.Clone(m.dst) - proto.Merge(got, m.src) - if !proto.Equal(got, m.want) { - t.Errorf("Merge(%v, %v)\n got %v\nwant %v\n", m.dst, m.src, got, m.want) - } - } -} diff --git a/vendor/github.com/golang/protobuf/proto/decode_test.go b/vendor/github.com/golang/protobuf/proto/decode_test.go deleted file mode 100644 index 2c4c31d1..00000000 --- a/vendor/github.com/golang/protobuf/proto/decode_test.go +++ /dev/null @@ -1,258 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may 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 -// OWNER 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. - -// +build go1.7 - -package proto_test - -import ( - "fmt" - "testing" - - "github.com/golang/protobuf/proto" - tpb "github.com/golang/protobuf/proto/proto3_proto" -) - -var ( - bytesBlackhole []byte - msgBlackhole = new(tpb.Message) -) - -// BenchmarkVarint32ArraySmall shows the performance on an array of small int32 fields (1 and -// 2 bytes long). -func BenchmarkVarint32ArraySmall(b *testing.B) { - for i := uint(1); i <= 10; i++ { - dist := genInt32Dist([7]int{0, 3, 1}, 1<unmarshal. -} - -func TestMarshalUnmarshalRepeatedExtension(t *testing.T) { - // Add a repeated extension to the result. - tests := []struct { - name string - ext []*pb.ComplexExtension - }{ - { - "two fields", - []*pb.ComplexExtension{ - {First: proto.Int32(7)}, - {Second: proto.Int32(11)}, - }, - }, - { - "repeated field", - []*pb.ComplexExtension{ - {Third: []int32{1000}}, - {Third: []int32{2000}}, - }, - }, - { - "two fields and repeated field", - []*pb.ComplexExtension{ - {Third: []int32{1000}}, - {First: proto.Int32(9)}, - {Second: proto.Int32(21)}, - {Third: []int32{2000}}, - }, - }, - } - for _, test := range tests { - // Marshal message with a repeated extension. - msg1 := new(pb.OtherMessage) - err := proto.SetExtension(msg1, pb.E_RComplex, test.ext) - if err != nil { - t.Fatalf("[%s] Error setting extension: %v", test.name, err) - } - b, err := proto.Marshal(msg1) - if err != nil { - t.Fatalf("[%s] Error marshaling message: %v", test.name, err) - } - - // Unmarshal and read the merged proto. - msg2 := new(pb.OtherMessage) - err = proto.Unmarshal(b, msg2) - if err != nil { - t.Fatalf("[%s] Error unmarshaling message: %v", test.name, err) - } - e, err := proto.GetExtension(msg2, pb.E_RComplex) - if err != nil { - t.Fatalf("[%s] Error getting extension: %v", test.name, err) - } - ext := e.([]*pb.ComplexExtension) - if ext == nil { - t.Fatalf("[%s] Invalid extension", test.name) - } - if !reflect.DeepEqual(ext, test.ext) { - t.Errorf("[%s] Wrong value for ComplexExtension: got: %v want: %v\n", test.name, ext, test.ext) - } - } -} - -func TestUnmarshalRepeatingNonRepeatedExtension(t *testing.T) { - // We may see multiple instances of the same extension in the wire - // format. For example, the proto compiler may encode custom options in - // this way. Here, we verify that we merge the extensions together. - tests := []struct { - name string - ext []*pb.ComplexExtension - }{ - { - "two fields", - []*pb.ComplexExtension{ - {First: proto.Int32(7)}, - {Second: proto.Int32(11)}, - }, - }, - { - "repeated field", - []*pb.ComplexExtension{ - {Third: []int32{1000}}, - {Third: []int32{2000}}, - }, - }, - { - "two fields and repeated field", - []*pb.ComplexExtension{ - {Third: []int32{1000}}, - {First: proto.Int32(9)}, - {Second: proto.Int32(21)}, - {Third: []int32{2000}}, - }, - }, - } - for _, test := range tests { - var buf bytes.Buffer - var want pb.ComplexExtension - - // Generate a serialized representation of a repeated extension - // by catenating bytes together. - for i, e := range test.ext { - // Merge to create the wanted proto. - proto.Merge(&want, e) - - // serialize the message - msg := new(pb.OtherMessage) - err := proto.SetExtension(msg, pb.E_Complex, e) - if err != nil { - t.Fatalf("[%s] Error setting extension %d: %v", test.name, i, err) - } - b, err := proto.Marshal(msg) - if err != nil { - t.Fatalf("[%s] Error marshaling message %d: %v", test.name, i, err) - } - buf.Write(b) - } - - // Unmarshal and read the merged proto. - msg2 := new(pb.OtherMessage) - err := proto.Unmarshal(buf.Bytes(), msg2) - if err != nil { - t.Fatalf("[%s] Error unmarshaling message: %v", test.name, err) - } - e, err := proto.GetExtension(msg2, pb.E_Complex) - if err != nil { - t.Fatalf("[%s] Error getting extension: %v", test.name, err) - } - ext := e.(*pb.ComplexExtension) - if ext == nil { - t.Fatalf("[%s] Invalid extension", test.name) - } - if !reflect.DeepEqual(*ext, want) { - t.Errorf("[%s] Wrong value for ComplexExtension: got: %s want: %s\n", test.name, ext, want) - } - } -} - -func TestClearAllExtensions(t *testing.T) { - // unregistered extension - desc := &proto.ExtensionDesc{ - ExtendedType: (*pb.MyMessage)(nil), - ExtensionType: (*bool)(nil), - Field: 101010100, - Name: "emptyextension", - Tag: "varint,0,opt", - } - m := &pb.MyMessage{} - if proto.HasExtension(m, desc) { - t.Errorf("proto.HasExtension(%s): got true, want false", proto.MarshalTextString(m)) - } - if err := proto.SetExtension(m, desc, proto.Bool(true)); err != nil { - t.Errorf("proto.SetExtension(m, desc, true): got error %q, want nil", err) - } - if !proto.HasExtension(m, desc) { - t.Errorf("proto.HasExtension(%s): got false, want true", proto.MarshalTextString(m)) - } - proto.ClearAllExtensions(m) - if proto.HasExtension(m, desc) { - t.Errorf("proto.HasExtension(%s): got true, want false", proto.MarshalTextString(m)) - } -} - -func TestMarshalRace(t *testing.T) { - // unregistered extension - desc := &proto.ExtensionDesc{ - ExtendedType: (*pb.MyMessage)(nil), - ExtensionType: (*bool)(nil), - Field: 101010100, - Name: "emptyextension", - Tag: "varint,0,opt", - } - - m := &pb.MyMessage{Count: proto.Int32(4)} - if err := proto.SetExtension(m, desc, proto.Bool(true)); err != nil { - t.Errorf("proto.SetExtension(m, desc, true): got error %q, want nil", err) - } - - var g errgroup.Group - for n := 3; n > 0; n-- { - g.Go(func() error { - _, err := proto.Marshal(m) - return err - }) - } - if err := g.Wait(); err != nil { - t.Fatal(err) - } -} diff --git a/vendor/github.com/golang/protobuf/proto/map_test.go b/vendor/github.com/golang/protobuf/proto/map_test.go deleted file mode 100644 index 313e8792..00000000 --- a/vendor/github.com/golang/protobuf/proto/map_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package proto_test - -import ( - "fmt" - "testing" - - "github.com/golang/protobuf/proto" - ppb "github.com/golang/protobuf/proto/proto3_proto" -) - -func marshalled() []byte { - m := &ppb.IntMaps{} - for i := 0; i < 1000; i++ { - m.Maps = append(m.Maps, &ppb.IntMap{ - Rtt: map[int32]int32{1: 2}, - }) - } - b, err := proto.Marshal(m) - if err != nil { - panic(fmt.Sprintf("Can't marshal %+v: %v", m, err)) - } - return b -} - -func BenchmarkConcurrentMapUnmarshal(b *testing.B) { - in := marshalled() - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - var out ppb.IntMaps - if err := proto.Unmarshal(in, &out); err != nil { - b.Errorf("Can't unmarshal ppb.IntMaps: %v", err) - } - } - }) -} - -func BenchmarkSequentialMapUnmarshal(b *testing.B) { - in := marshalled() - b.ResetTimer() - for i := 0; i < b.N; i++ { - var out ppb.IntMaps - if err := proto.Unmarshal(in, &out); err != nil { - b.Errorf("Can't unmarshal ppb.IntMaps: %v", err) - } - } -} diff --git a/vendor/github.com/golang/protobuf/proto/message_set_test.go b/vendor/github.com/golang/protobuf/proto/message_set_test.go deleted file mode 100644 index 353a3ea7..00000000 --- a/vendor/github.com/golang/protobuf/proto/message_set_test.go +++ /dev/null @@ -1,66 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2014 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may 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 -// OWNER 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. - -package proto - -import ( - "bytes" - "testing" -) - -func TestUnmarshalMessageSetWithDuplicate(t *testing.T) { - // Check that a repeated message set entry will be concatenated. - in := &messageSet{ - Item: []*_MessageSet_Item{ - {TypeId: Int32(12345), Message: []byte("hoo")}, - {TypeId: Int32(12345), Message: []byte("hah")}, - }, - } - b, err := Marshal(in) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - t.Logf("Marshaled bytes: %q", b) - - var extensions XXX_InternalExtensions - if err := UnmarshalMessageSet(b, &extensions); err != nil { - t.Fatalf("UnmarshalMessageSet: %v", err) - } - ext, ok := extensions.p.extensionMap[12345] - if !ok { - t.Fatalf("Didn't retrieve extension 12345; map is %v", extensions.p.extensionMap) - } - // Skip wire type/field number and length varints. - got := skipVarint(skipVarint(ext.enc)) - if want := []byte("hoohah"); !bytes.Equal(got, want) { - t.Errorf("Combined extension is %q, want %q", got, want) - } -} diff --git a/vendor/github.com/golang/protobuf/proto/proto3_test.go b/vendor/github.com/golang/protobuf/proto/proto3_test.go deleted file mode 100644 index 735837f2..00000000 --- a/vendor/github.com/golang/protobuf/proto/proto3_test.go +++ /dev/null @@ -1,135 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2014 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may 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 -// OWNER 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. - -package proto_test - -import ( - "testing" - - "github.com/golang/protobuf/proto" - pb "github.com/golang/protobuf/proto/proto3_proto" - tpb "github.com/golang/protobuf/proto/testdata" -) - -func TestProto3ZeroValues(t *testing.T) { - tests := []struct { - desc string - m proto.Message - }{ - {"zero message", &pb.Message{}}, - {"empty bytes field", &pb.Message{Data: []byte{}}}, - } - for _, test := range tests { - b, err := proto.Marshal(test.m) - if err != nil { - t.Errorf("%s: proto.Marshal: %v", test.desc, err) - continue - } - if len(b) > 0 { - t.Errorf("%s: Encoding is non-empty: %q", test.desc, b) - } - } -} - -func TestRoundTripProto3(t *testing.T) { - m := &pb.Message{ - Name: "David", // (2 | 1<<3): 0x0a 0x05 "David" - Hilarity: pb.Message_PUNS, // (0 | 2<<3): 0x10 0x01 - HeightInCm: 178, // (0 | 3<<3): 0x18 0xb2 0x01 - Data: []byte("roboto"), // (2 | 4<<3): 0x20 0x06 "roboto" - ResultCount: 47, // (0 | 7<<3): 0x38 0x2f - TrueScotsman: true, // (0 | 8<<3): 0x40 0x01 - Score: 8.1, // (5 | 9<<3): 0x4d <8.1> - - Key: []uint64{1, 0xdeadbeef}, - Nested: &pb.Nested{ - Bunny: "Monty", - }, - } - t.Logf(" m: %v", m) - - b, err := proto.Marshal(m) - if err != nil { - t.Fatalf("proto.Marshal: %v", err) - } - t.Logf(" b: %q", b) - - m2 := new(pb.Message) - if err := proto.Unmarshal(b, m2); err != nil { - t.Fatalf("proto.Unmarshal: %v", err) - } - t.Logf("m2: %v", m2) - - if !proto.Equal(m, m2) { - t.Errorf("proto.Equal returned false:\n m: %v\nm2: %v", m, m2) - } -} - -func TestGettersForBasicTypesExist(t *testing.T) { - var m pb.Message - if got := m.GetNested().GetBunny(); got != "" { - t.Errorf("m.GetNested().GetBunny() = %q, want empty string", got) - } - if got := m.GetNested().GetCute(); got { - t.Errorf("m.GetNested().GetCute() = %t, want false", got) - } -} - -func TestProto3SetDefaults(t *testing.T) { - in := &pb.Message{ - Terrain: map[string]*pb.Nested{ - "meadow": new(pb.Nested), - }, - Proto2Field: new(tpb.SubDefaults), - Proto2Value: map[string]*tpb.SubDefaults{ - "badlands": new(tpb.SubDefaults), - }, - } - - got := proto.Clone(in).(*pb.Message) - proto.SetDefaults(got) - - // There are no defaults in proto3. Everything should be the zero value, but - // we need to remember to set defaults for nested proto2 messages. - want := &pb.Message{ - Terrain: map[string]*pb.Nested{ - "meadow": new(pb.Nested), - }, - Proto2Field: &tpb.SubDefaults{N: proto.Int64(7)}, - Proto2Value: map[string]*tpb.SubDefaults{ - "badlands": &tpb.SubDefaults{N: proto.Int64(7)}, - }, - } - - if !proto.Equal(got, want) { - t.Errorf("with in = %v\nproto.SetDefaults(in) =>\ngot %v\nwant %v", in, got, want) - } -} diff --git a/vendor/github.com/golang/protobuf/proto/size2_test.go b/vendor/github.com/golang/protobuf/proto/size2_test.go deleted file mode 100644 index a2729c39..00000000 --- a/vendor/github.com/golang/protobuf/proto/size2_test.go +++ /dev/null @@ -1,63 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2012 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may 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 -// OWNER 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. - -package proto - -import ( - "testing" -) - -// This is a separate file and package from size_test.go because that one uses -// generated messages and thus may not be in package proto without having a circular -// dependency, whereas this file tests unexported details of size.go. - -func TestVarintSize(t *testing.T) { - // Check the edge cases carefully. - testCases := []struct { - n uint64 - size int - }{ - {0, 1}, - {1, 1}, - {127, 1}, - {128, 2}, - {16383, 2}, - {16384, 3}, - {1<<63 - 1, 9}, - {1 << 63, 10}, - } - for _, tc := range testCases { - size := sizeVarint(tc.n) - if size != tc.size { - t.Errorf("sizeVarint(%d) = %d, want %d", tc.n, size, tc.size) - } - } -} diff --git a/vendor/github.com/golang/protobuf/proto/size_test.go b/vendor/github.com/golang/protobuf/proto/size_test.go deleted file mode 100644 index af1034dc..00000000 --- a/vendor/github.com/golang/protobuf/proto/size_test.go +++ /dev/null @@ -1,164 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2012 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may 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 -// OWNER 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. - -package proto_test - -import ( - "log" - "strings" - "testing" - - . "github.com/golang/protobuf/proto" - proto3pb "github.com/golang/protobuf/proto/proto3_proto" - pb "github.com/golang/protobuf/proto/testdata" -) - -var messageWithExtension1 = &pb.MyMessage{Count: Int32(7)} - -// messageWithExtension2 is in equal_test.go. -var messageWithExtension3 = &pb.MyMessage{Count: Int32(8)} - -func init() { - if err := SetExtension(messageWithExtension1, pb.E_Ext_More, &pb.Ext{Data: String("Abbott")}); err != nil { - log.Panicf("SetExtension: %v", err) - } - if err := SetExtension(messageWithExtension3, pb.E_Ext_More, &pb.Ext{Data: String("Costello")}); err != nil { - log.Panicf("SetExtension: %v", err) - } - - // Force messageWithExtension3 to have the extension encoded. - Marshal(messageWithExtension3) - -} - -var SizeTests = []struct { - desc string - pb Message -}{ - {"empty", &pb.OtherMessage{}}, - // Basic types. - {"bool", &pb.Defaults{F_Bool: Bool(true)}}, - {"int32", &pb.Defaults{F_Int32: Int32(12)}}, - {"negative int32", &pb.Defaults{F_Int32: Int32(-1)}}, - {"small int64", &pb.Defaults{F_Int64: Int64(1)}}, - {"big int64", &pb.Defaults{F_Int64: Int64(1 << 20)}}, - {"negative int64", &pb.Defaults{F_Int64: Int64(-1)}}, - {"fixed32", &pb.Defaults{F_Fixed32: Uint32(71)}}, - {"fixed64", &pb.Defaults{F_Fixed64: Uint64(72)}}, - {"uint32", &pb.Defaults{F_Uint32: Uint32(123)}}, - {"uint64", &pb.Defaults{F_Uint64: Uint64(124)}}, - {"float", &pb.Defaults{F_Float: Float32(12.6)}}, - {"double", &pb.Defaults{F_Double: Float64(13.9)}}, - {"string", &pb.Defaults{F_String: String("niles")}}, - {"bytes", &pb.Defaults{F_Bytes: []byte("wowsa")}}, - {"bytes, empty", &pb.Defaults{F_Bytes: []byte{}}}, - {"sint32", &pb.Defaults{F_Sint32: Int32(65)}}, - {"sint64", &pb.Defaults{F_Sint64: Int64(67)}}, - {"enum", &pb.Defaults{F_Enum: pb.Defaults_BLUE.Enum()}}, - // Repeated. - {"empty repeated bool", &pb.MoreRepeated{Bools: []bool{}}}, - {"repeated bool", &pb.MoreRepeated{Bools: []bool{false, true, true, false}}}, - {"packed repeated bool", &pb.MoreRepeated{BoolsPacked: []bool{false, true, true, false, true, true, true}}}, - {"repeated int32", &pb.MoreRepeated{Ints: []int32{1, 12203, 1729, -1}}}, - {"repeated int32 packed", &pb.MoreRepeated{IntsPacked: []int32{1, 12203, 1729}}}, - {"repeated int64 packed", &pb.MoreRepeated{Int64SPacked: []int64{ - // Need enough large numbers to verify that the header is counting the number of bytes - // for the field, not the number of elements. - 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, - 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, - }}}, - {"repeated string", &pb.MoreRepeated{Strings: []string{"r", "ken", "gri"}}}, - {"repeated fixed", &pb.MoreRepeated{Fixeds: []uint32{1, 2, 3, 4}}}, - // Nested. - {"nested", &pb.OldMessage{Nested: &pb.OldMessage_Nested{Name: String("whatever")}}}, - {"group", &pb.GroupOld{G: &pb.GroupOld_G{X: Int32(12345)}}}, - // Other things. - {"unrecognized", &pb.MoreRepeated{XXX_unrecognized: []byte{13<<3 | 0, 4}}}, - {"extension (unencoded)", messageWithExtension1}, - {"extension (encoded)", messageWithExtension3}, - // proto3 message - {"proto3 empty", &proto3pb.Message{}}, - {"proto3 bool", &proto3pb.Message{TrueScotsman: true}}, - {"proto3 int64", &proto3pb.Message{ResultCount: 1}}, - {"proto3 uint32", &proto3pb.Message{HeightInCm: 123}}, - {"proto3 float", &proto3pb.Message{Score: 12.6}}, - {"proto3 string", &proto3pb.Message{Name: "Snezana"}}, - {"proto3 bytes", &proto3pb.Message{Data: []byte("wowsa")}}, - {"proto3 bytes, empty", &proto3pb.Message{Data: []byte{}}}, - {"proto3 enum", &proto3pb.Message{Hilarity: proto3pb.Message_PUNS}}, - {"proto3 map field with empty bytes", &proto3pb.MessageWithMap{ByteMapping: map[bool][]byte{false: []byte{}}}}, - - {"map field", &pb.MessageWithMap{NameMapping: map[int32]string{1: "Rob", 7: "Andrew"}}}, - {"map field with message", &pb.MessageWithMap{MsgMapping: map[int64]*pb.FloatingPoint{0x7001: &pb.FloatingPoint{F: Float64(2.0)}}}}, - {"map field with bytes", &pb.MessageWithMap{ByteMapping: map[bool][]byte{true: []byte("this time for sure")}}}, - {"map field with empty bytes", &pb.MessageWithMap{ByteMapping: map[bool][]byte{true: []byte{}}}}, - - {"map field with big entry", &pb.MessageWithMap{NameMapping: map[int32]string{8: strings.Repeat("x", 125)}}}, - {"map field with big key and val", &pb.MessageWithMap{StrToStr: map[string]string{strings.Repeat("x", 70): strings.Repeat("y", 70)}}}, - {"map field with big numeric key", &pb.MessageWithMap{NameMapping: map[int32]string{0xf00d: "om nom nom"}}}, - - {"oneof not set", &pb.Oneof{}}, - {"oneof bool", &pb.Oneof{Union: &pb.Oneof_F_Bool{true}}}, - {"oneof zero int32", &pb.Oneof{Union: &pb.Oneof_F_Int32{0}}}, - {"oneof big int32", &pb.Oneof{Union: &pb.Oneof_F_Int32{1 << 20}}}, - {"oneof int64", &pb.Oneof{Union: &pb.Oneof_F_Int64{42}}}, - {"oneof fixed32", &pb.Oneof{Union: &pb.Oneof_F_Fixed32{43}}}, - {"oneof fixed64", &pb.Oneof{Union: &pb.Oneof_F_Fixed64{44}}}, - {"oneof uint32", &pb.Oneof{Union: &pb.Oneof_F_Uint32{45}}}, - {"oneof uint64", &pb.Oneof{Union: &pb.Oneof_F_Uint64{46}}}, - {"oneof float", &pb.Oneof{Union: &pb.Oneof_F_Float{47.1}}}, - {"oneof double", &pb.Oneof{Union: &pb.Oneof_F_Double{48.9}}}, - {"oneof string", &pb.Oneof{Union: &pb.Oneof_F_String{"Rhythmic Fman"}}}, - {"oneof bytes", &pb.Oneof{Union: &pb.Oneof_F_Bytes{[]byte("let go")}}}, - {"oneof sint32", &pb.Oneof{Union: &pb.Oneof_F_Sint32{50}}}, - {"oneof sint64", &pb.Oneof{Union: &pb.Oneof_F_Sint64{51}}}, - {"oneof enum", &pb.Oneof{Union: &pb.Oneof_F_Enum{pb.MyMessage_BLUE}}}, - {"message for oneof", &pb.GoTestField{Label: String("k"), Type: String("v")}}, - {"oneof message", &pb.Oneof{Union: &pb.Oneof_F_Message{&pb.GoTestField{Label: String("k"), Type: String("v")}}}}, - {"oneof group", &pb.Oneof{Union: &pb.Oneof_FGroup{&pb.Oneof_F_Group{X: Int32(52)}}}}, - {"oneof largest tag", &pb.Oneof{Union: &pb.Oneof_F_Largest_Tag{1}}}, - {"multiple oneofs", &pb.Oneof{Union: &pb.Oneof_F_Int32{1}, Tormato: &pb.Oneof_Value{2}}}, -} - -func TestSize(t *testing.T) { - for _, tc := range SizeTests { - size := Size(tc.pb) - b, err := Marshal(tc.pb) - if err != nil { - t.Errorf("%v: Marshal failed: %v", tc.desc, err) - continue - } - if size != len(b) { - t.Errorf("%v: Size(%v) = %d, want %d", tc.desc, tc.pb, size, len(b)) - t.Logf("%v: bytes: %#v", tc.desc, b) - } - } -} diff --git a/vendor/github.com/golang/protobuf/proto/text_parser_test.go b/vendor/github.com/golang/protobuf/proto/text_parser_test.go deleted file mode 100644 index 8f7cb4d2..00000000 --- a/vendor/github.com/golang/protobuf/proto/text_parser_test.go +++ /dev/null @@ -1,673 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may 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 -// OWNER 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. - -package proto_test - -import ( - "math" - "reflect" - "testing" - - . "github.com/golang/protobuf/proto" - proto3pb "github.com/golang/protobuf/proto/proto3_proto" - . "github.com/golang/protobuf/proto/testdata" -) - -type UnmarshalTextTest struct { - in string - err string // if "", no error expected - out *MyMessage -} - -func buildExtStructTest(text string) UnmarshalTextTest { - msg := &MyMessage{ - Count: Int32(42), - } - SetExtension(msg, E_Ext_More, &Ext{ - Data: String("Hello, world!"), - }) - return UnmarshalTextTest{in: text, out: msg} -} - -func buildExtDataTest(text string) UnmarshalTextTest { - msg := &MyMessage{ - Count: Int32(42), - } - SetExtension(msg, E_Ext_Text, String("Hello, world!")) - SetExtension(msg, E_Ext_Number, Int32(1729)) - return UnmarshalTextTest{in: text, out: msg} -} - -func buildExtRepStringTest(text string) UnmarshalTextTest { - msg := &MyMessage{ - Count: Int32(42), - } - if err := SetExtension(msg, E_Greeting, []string{"bula", "hola"}); err != nil { - panic(err) - } - return UnmarshalTextTest{in: text, out: msg} -} - -var unMarshalTextTests = []UnmarshalTextTest{ - // Basic - { - in: " count:42\n name:\"Dave\" ", - out: &MyMessage{ - Count: Int32(42), - Name: String("Dave"), - }, - }, - - // Empty quoted string - { - in: `count:42 name:""`, - out: &MyMessage{ - Count: Int32(42), - Name: String(""), - }, - }, - - // Quoted string concatenation with double quotes - { - in: `count:42 name: "My name is "` + "\n" + `"elsewhere"`, - out: &MyMessage{ - Count: Int32(42), - Name: String("My name is elsewhere"), - }, - }, - - // Quoted string concatenation with single quotes - { - in: "count:42 name: 'My name is '\n'elsewhere'", - out: &MyMessage{ - Count: Int32(42), - Name: String("My name is elsewhere"), - }, - }, - - // Quoted string concatenations with mixed quotes - { - in: "count:42 name: 'My name is '\n\"elsewhere\"", - out: &MyMessage{ - Count: Int32(42), - Name: String("My name is elsewhere"), - }, - }, - { - in: "count:42 name: \"My name is \"\n'elsewhere'", - out: &MyMessage{ - Count: Int32(42), - Name: String("My name is elsewhere"), - }, - }, - - // Quoted string with escaped apostrophe - { - in: `count:42 name: "HOLIDAY - New Year\'s Day"`, - out: &MyMessage{ - Count: Int32(42), - Name: String("HOLIDAY - New Year's Day"), - }, - }, - - // Quoted string with single quote - { - in: `count:42 name: 'Roger "The Ramster" Ramjet'`, - out: &MyMessage{ - Count: Int32(42), - Name: String(`Roger "The Ramster" Ramjet`), - }, - }, - - // Quoted string with all the accepted special characters from the C++ test - { - in: `count:42 name: ` + "\"\\\"A string with \\' characters \\n and \\r newlines and \\t tabs and \\001 slashes \\\\ and multiple spaces\"", - out: &MyMessage{ - Count: Int32(42), - Name: String("\"A string with ' characters \n and \r newlines and \t tabs and \001 slashes \\ and multiple spaces"), - }, - }, - - // Quoted string with quoted backslash - { - in: `count:42 name: "\\'xyz"`, - out: &MyMessage{ - Count: Int32(42), - Name: String(`\'xyz`), - }, - }, - - // Quoted string with UTF-8 bytes. - { - in: "count:42 name: '\303\277\302\201\xAB'", - out: &MyMessage{ - Count: Int32(42), - Name: String("\303\277\302\201\xAB"), - }, - }, - - // Bad quoted string - { - in: `inner: < host: "\0" >` + "\n", - err: `line 1.15: invalid quoted string "\0": \0 requires 2 following digits`, - }, - - // Number too large for int64 - { - in: "count: 1 others { key: 123456789012345678901 }", - err: "line 1.23: invalid int64: 123456789012345678901", - }, - - // Number too large for int32 - { - in: "count: 1234567890123", - err: "line 1.7: invalid int32: 1234567890123", - }, - - // Number in hexadecimal - { - in: "count: 0x2beef", - out: &MyMessage{ - Count: Int32(0x2beef), - }, - }, - - // Number in octal - { - in: "count: 024601", - out: &MyMessage{ - Count: Int32(024601), - }, - }, - - // Floating point number with "f" suffix - { - in: "count: 4 others:< weight: 17.0f >", - out: &MyMessage{ - Count: Int32(4), - Others: []*OtherMessage{ - { - Weight: Float32(17), - }, - }, - }, - }, - - // Floating point positive infinity - { - in: "count: 4 bigfloat: inf", - out: &MyMessage{ - Count: Int32(4), - Bigfloat: Float64(math.Inf(1)), - }, - }, - - // Floating point negative infinity - { - in: "count: 4 bigfloat: -inf", - out: &MyMessage{ - Count: Int32(4), - Bigfloat: Float64(math.Inf(-1)), - }, - }, - - // Number too large for float32 - { - in: "others:< weight: 12345678901234567890123456789012345678901234567890 >", - err: "line 1.17: invalid float32: 12345678901234567890123456789012345678901234567890", - }, - - // Number posing as a quoted string - { - in: `inner: < host: 12 >` + "\n", - err: `line 1.15: invalid string: 12`, - }, - - // Quoted string posing as int32 - { - in: `count: "12"`, - err: `line 1.7: invalid int32: "12"`, - }, - - // Quoted string posing a float32 - { - in: `others:< weight: "17.4" >`, - err: `line 1.17: invalid float32: "17.4"`, - }, - - // Enum - { - in: `count:42 bikeshed: BLUE`, - out: &MyMessage{ - Count: Int32(42), - Bikeshed: MyMessage_BLUE.Enum(), - }, - }, - - // Repeated field - { - in: `count:42 pet: "horsey" pet:"bunny"`, - out: &MyMessage{ - Count: Int32(42), - Pet: []string{"horsey", "bunny"}, - }, - }, - - // Repeated field with list notation - { - in: `count:42 pet: ["horsey", "bunny"]`, - out: &MyMessage{ - Count: Int32(42), - Pet: []string{"horsey", "bunny"}, - }, - }, - - // Repeated message with/without colon and <>/{} - { - in: `count:42 others:{} others{} others:<> others:{}`, - out: &MyMessage{ - Count: Int32(42), - Others: []*OtherMessage{ - {}, - {}, - {}, - {}, - }, - }, - }, - - // Missing colon for inner message - { - in: `count:42 inner < host: "cauchy.syd" >`, - out: &MyMessage{ - Count: Int32(42), - Inner: &InnerMessage{ - Host: String("cauchy.syd"), - }, - }, - }, - - // Missing colon for string field - { - in: `name "Dave"`, - err: `line 1.5: expected ':', found "\"Dave\""`, - }, - - // Missing colon for int32 field - { - in: `count 42`, - err: `line 1.6: expected ':', found "42"`, - }, - - // Missing required field - { - in: `name: "Pawel"`, - err: `proto: required field "testdata.MyMessage.count" not set`, - out: &MyMessage{ - Name: String("Pawel"), - }, - }, - - // Missing required field in a required submessage - { - in: `count: 42 we_must_go_deeper < leo_finally_won_an_oscar <> >`, - err: `proto: required field "testdata.InnerMessage.host" not set`, - out: &MyMessage{ - Count: Int32(42), - WeMustGoDeeper: &RequiredInnerMessage{LeoFinallyWonAnOscar: &InnerMessage{}}, - }, - }, - - // Repeated non-repeated field - { - in: `name: "Rob" name: "Russ"`, - err: `line 1.12: non-repeated field "name" was repeated`, - }, - - // Group - { - in: `count: 17 SomeGroup { group_field: 12 }`, - out: &MyMessage{ - Count: Int32(17), - Somegroup: &MyMessage_SomeGroup{ - GroupField: Int32(12), - }, - }, - }, - - // Semicolon between fields - { - in: `count:3;name:"Calvin"`, - out: &MyMessage{ - Count: Int32(3), - Name: String("Calvin"), - }, - }, - // Comma between fields - { - in: `count:4,name:"Ezekiel"`, - out: &MyMessage{ - Count: Int32(4), - Name: String("Ezekiel"), - }, - }, - - // Boolean false - { - in: `count:42 inner { host: "example.com" connected: false }`, - out: &MyMessage{ - Count: Int32(42), - Inner: &InnerMessage{ - Host: String("example.com"), - Connected: Bool(false), - }, - }, - }, - // Boolean true - { - in: `count:42 inner { host: "example.com" connected: true }`, - out: &MyMessage{ - Count: Int32(42), - Inner: &InnerMessage{ - Host: String("example.com"), - Connected: Bool(true), - }, - }, - }, - // Boolean 0 - { - in: `count:42 inner { host: "example.com" connected: 0 }`, - out: &MyMessage{ - Count: Int32(42), - Inner: &InnerMessage{ - Host: String("example.com"), - Connected: Bool(false), - }, - }, - }, - // Boolean 1 - { - in: `count:42 inner { host: "example.com" connected: 1 }`, - out: &MyMessage{ - Count: Int32(42), - Inner: &InnerMessage{ - Host: String("example.com"), - Connected: Bool(true), - }, - }, - }, - // Boolean f - { - in: `count:42 inner { host: "example.com" connected: f }`, - out: &MyMessage{ - Count: Int32(42), - Inner: &InnerMessage{ - Host: String("example.com"), - Connected: Bool(false), - }, - }, - }, - // Boolean t - { - in: `count:42 inner { host: "example.com" connected: t }`, - out: &MyMessage{ - Count: Int32(42), - Inner: &InnerMessage{ - Host: String("example.com"), - Connected: Bool(true), - }, - }, - }, - // Boolean False - { - in: `count:42 inner { host: "example.com" connected: False }`, - out: &MyMessage{ - Count: Int32(42), - Inner: &InnerMessage{ - Host: String("example.com"), - Connected: Bool(false), - }, - }, - }, - // Boolean True - { - in: `count:42 inner { host: "example.com" connected: True }`, - out: &MyMessage{ - Count: Int32(42), - Inner: &InnerMessage{ - Host: String("example.com"), - Connected: Bool(true), - }, - }, - }, - - // Extension - buildExtStructTest(`count: 42 [testdata.Ext.more]:`), - buildExtStructTest(`count: 42 [testdata.Ext.more] {data:"Hello, world!"}`), - buildExtDataTest(`count: 42 [testdata.Ext.text]:"Hello, world!" [testdata.Ext.number]:1729`), - buildExtRepStringTest(`count: 42 [testdata.greeting]:"bula" [testdata.greeting]:"hola"`), - - // Big all-in-one - { - in: "count:42 # Meaning\n" + - `name:"Dave" ` + - `quote:"\"I didn't want to go.\"" ` + - `pet:"bunny" ` + - `pet:"kitty" ` + - `pet:"horsey" ` + - `inner:<` + - ` host:"footrest.syd" ` + - ` port:7001 ` + - ` connected:true ` + - `> ` + - `others:<` + - ` key:3735928559 ` + - ` value:"\x01A\a\f" ` + - `> ` + - `others:<` + - " weight:58.9 # Atomic weight of Co\n" + - ` inner:<` + - ` host:"lesha.mtv" ` + - ` port:8002 ` + - ` >` + - `>`, - out: &MyMessage{ - Count: Int32(42), - Name: String("Dave"), - Quote: String(`"I didn't want to go."`), - Pet: []string{"bunny", "kitty", "horsey"}, - Inner: &InnerMessage{ - Host: String("footrest.syd"), - Port: Int32(7001), - Connected: Bool(true), - }, - Others: []*OtherMessage{ - { - Key: Int64(3735928559), - Value: []byte{0x1, 'A', '\a', '\f'}, - }, - { - Weight: Float32(58.9), - Inner: &InnerMessage{ - Host: String("lesha.mtv"), - Port: Int32(8002), - }, - }, - }, - }, - }, -} - -func TestUnmarshalText(t *testing.T) { - for i, test := range unMarshalTextTests { - pb := new(MyMessage) - err := UnmarshalText(test.in, pb) - if test.err == "" { - // We don't expect failure. - if err != nil { - t.Errorf("Test %d: Unexpected error: %v", i, err) - } else if !reflect.DeepEqual(pb, test.out) { - t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v", - i, pb, test.out) - } - } else { - // We do expect failure. - if err == nil { - t.Errorf("Test %d: Didn't get expected error: %v", i, test.err) - } else if err.Error() != test.err { - t.Errorf("Test %d: Incorrect error.\nHave: %v\nWant: %v", - i, err.Error(), test.err) - } else if _, ok := err.(*RequiredNotSetError); ok && test.out != nil && !reflect.DeepEqual(pb, test.out) { - t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v", - i, pb, test.out) - } - } - } -} - -func TestUnmarshalTextCustomMessage(t *testing.T) { - msg := &textMessage{} - if err := UnmarshalText("custom", msg); err != nil { - t.Errorf("Unexpected error from custom unmarshal: %v", err) - } - if UnmarshalText("not custom", msg) == nil { - t.Errorf("Didn't get expected error from custom unmarshal") - } -} - -// Regression test; this caused a panic. -func TestRepeatedEnum(t *testing.T) { - pb := new(RepeatedEnum) - if err := UnmarshalText("color: RED", pb); err != nil { - t.Fatal(err) - } - exp := &RepeatedEnum{ - Color: []RepeatedEnum_Color{RepeatedEnum_RED}, - } - if !Equal(pb, exp) { - t.Errorf("Incorrect populated \nHave: %v\nWant: %v", pb, exp) - } -} - -func TestProto3TextParsing(t *testing.T) { - m := new(proto3pb.Message) - const in = `name: "Wallace" true_scotsman: true` - want := &proto3pb.Message{ - Name: "Wallace", - TrueScotsman: true, - } - if err := UnmarshalText(in, m); err != nil { - t.Fatal(err) - } - if !Equal(m, want) { - t.Errorf("\n got %v\nwant %v", m, want) - } -} - -func TestMapParsing(t *testing.T) { - m := new(MessageWithMap) - const in = `name_mapping: name_mapping:` + - `msg_mapping:,>` + // separating commas are okay - `msg_mapping>` + // no colon after "value" - `msg_mapping:>` + // omitted key - `msg_mapping:` + // omitted value - `byte_mapping:` + - `byte_mapping:<>` // omitted key and value - want := &MessageWithMap{ - NameMapping: map[int32]string{ - 1: "Beatles", - 1234: "Feist", - }, - MsgMapping: map[int64]*FloatingPoint{ - -4: {F: Float64(2.0)}, - -2: {F: Float64(4.0)}, - 0: {F: Float64(5.0)}, - 1: nil, - }, - ByteMapping: map[bool][]byte{ - false: nil, - true: []byte("so be it"), - }, - } - if err := UnmarshalText(in, m); err != nil { - t.Fatal(err) - } - if !Equal(m, want) { - t.Errorf("\n got %v\nwant %v", m, want) - } -} - -func TestOneofParsing(t *testing.T) { - const in = `name:"Shrek"` - m := new(Communique) - want := &Communique{Union: &Communique_Name{"Shrek"}} - if err := UnmarshalText(in, m); err != nil { - t.Fatal(err) - } - if !Equal(m, want) { - t.Errorf("\n got %v\nwant %v", m, want) - } - - const inOverwrite = `name:"Shrek" number:42` - m = new(Communique) - testErr := "line 1.13: field 'number' would overwrite already parsed oneof 'Union'" - if err := UnmarshalText(inOverwrite, m); err == nil { - t.Errorf("TestOneofParsing: Didn't get expected error: %v", testErr) - } else if err.Error() != testErr { - t.Errorf("TestOneofParsing: Incorrect error.\nHave: %v\nWant: %v", - err.Error(), testErr) - } - -} - -var benchInput string - -func init() { - benchInput = "count: 4\n" - for i := 0; i < 1000; i++ { - benchInput += "pet: \"fido\"\n" - } - - // Check it is valid input. - pb := new(MyMessage) - err := UnmarshalText(benchInput, pb) - if err != nil { - panic("Bad benchmark input: " + err.Error()) - } -} - -func BenchmarkUnmarshalText(b *testing.B) { - pb := new(MyMessage) - for i := 0; i < b.N; i++ { - UnmarshalText(benchInput, pb) - } - b.SetBytes(int64(len(benchInput))) -} diff --git a/vendor/github.com/golang/protobuf/proto/text_test.go b/vendor/github.com/golang/protobuf/proto/text_test.go deleted file mode 100644 index 3eabacac..00000000 --- a/vendor/github.com/golang/protobuf/proto/text_test.go +++ /dev/null @@ -1,474 +0,0 @@ -// Go support for Protocol Buffers - Google's data interchange format -// -// Copyright 2010 The Go Authors. All rights reserved. -// https://github.com/golang/protobuf -// -// 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may 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 -// OWNER 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. - -package proto_test - -import ( - "bytes" - "errors" - "io/ioutil" - "math" - "strings" - "testing" - - "github.com/golang/protobuf/proto" - - proto3pb "github.com/golang/protobuf/proto/proto3_proto" - pb "github.com/golang/protobuf/proto/testdata" -) - -// textMessage implements the methods that allow it to marshal and unmarshal -// itself as text. -type textMessage struct { -} - -func (*textMessage) MarshalText() ([]byte, error) { - return []byte("custom"), nil -} - -func (*textMessage) UnmarshalText(bytes []byte) error { - if string(bytes) != "custom" { - return errors.New("expected 'custom'") - } - return nil -} - -func (*textMessage) Reset() {} -func (*textMessage) String() string { return "" } -func (*textMessage) ProtoMessage() {} - -func newTestMessage() *pb.MyMessage { - msg := &pb.MyMessage{ - Count: proto.Int32(42), - Name: proto.String("Dave"), - Quote: proto.String(`"I didn't want to go."`), - Pet: []string{"bunny", "kitty", "horsey"}, - Inner: &pb.InnerMessage{ - Host: proto.String("footrest.syd"), - Port: proto.Int32(7001), - Connected: proto.Bool(true), - }, - Others: []*pb.OtherMessage{ - { - Key: proto.Int64(0xdeadbeef), - Value: []byte{1, 65, 7, 12}, - }, - { - Weight: proto.Float32(6.022), - Inner: &pb.InnerMessage{ - Host: proto.String("lesha.mtv"), - Port: proto.Int32(8002), - }, - }, - }, - Bikeshed: pb.MyMessage_BLUE.Enum(), - Somegroup: &pb.MyMessage_SomeGroup{ - GroupField: proto.Int32(8), - }, - // One normally wouldn't do this. - // This is an undeclared tag 13, as a varint (wire type 0) with value 4. - XXX_unrecognized: []byte{13<<3 | 0, 4}, - } - ext := &pb.Ext{ - Data: proto.String("Big gobs for big rats"), - } - if err := proto.SetExtension(msg, pb.E_Ext_More, ext); err != nil { - panic(err) - } - greetings := []string{"adg", "easy", "cow"} - if err := proto.SetExtension(msg, pb.E_Greeting, greetings); err != nil { - panic(err) - } - - // Add an unknown extension. We marshal a pb.Ext, and fake the ID. - b, err := proto.Marshal(&pb.Ext{Data: proto.String("3G skiing")}) - if err != nil { - panic(err) - } - b = append(proto.EncodeVarint(201<<3|proto.WireBytes), b...) - proto.SetRawExtension(msg, 201, b) - - // Extensions can be plain fields, too, so let's test that. - b = append(proto.EncodeVarint(202<<3|proto.WireVarint), 19) - proto.SetRawExtension(msg, 202, b) - - return msg -} - -const text = `count: 42 -name: "Dave" -quote: "\"I didn't want to go.\"" -pet: "bunny" -pet: "kitty" -pet: "horsey" -inner: < - host: "footrest.syd" - port: 7001 - connected: true -> -others: < - key: 3735928559 - value: "\001A\007\014" -> -others: < - weight: 6.022 - inner: < - host: "lesha.mtv" - port: 8002 - > -> -bikeshed: BLUE -SomeGroup { - group_field: 8 -} -/* 2 unknown bytes */ -13: 4 -[testdata.Ext.more]: < - data: "Big gobs for big rats" -> -[testdata.greeting]: "adg" -[testdata.greeting]: "easy" -[testdata.greeting]: "cow" -/* 13 unknown bytes */ -201: "\t3G skiing" -/* 3 unknown bytes */ -202: 19 -` - -func TestMarshalText(t *testing.T) { - buf := new(bytes.Buffer) - if err := proto.MarshalText(buf, newTestMessage()); err != nil { - t.Fatalf("proto.MarshalText: %v", err) - } - s := buf.String() - if s != text { - t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", s, text) - } -} - -func TestMarshalTextCustomMessage(t *testing.T) { - buf := new(bytes.Buffer) - if err := proto.MarshalText(buf, &textMessage{}); err != nil { - t.Fatalf("proto.MarshalText: %v", err) - } - s := buf.String() - if s != "custom" { - t.Errorf("Got %q, expected %q", s, "custom") - } -} -func TestMarshalTextNil(t *testing.T) { - want := "" - tests := []proto.Message{nil, (*pb.MyMessage)(nil)} - for i, test := range tests { - buf := new(bytes.Buffer) - if err := proto.MarshalText(buf, test); err != nil { - t.Fatal(err) - } - if got := buf.String(); got != want { - t.Errorf("%d: got %q want %q", i, got, want) - } - } -} - -func TestMarshalTextUnknownEnum(t *testing.T) { - // The Color enum only specifies values 0-2. - m := &pb.MyMessage{Bikeshed: pb.MyMessage_Color(3).Enum()} - got := m.String() - const want = `bikeshed:3 ` - if got != want { - t.Errorf("\n got %q\nwant %q", got, want) - } -} - -func TestTextOneof(t *testing.T) { - tests := []struct { - m proto.Message - want string - }{ - // zero message - {&pb.Communique{}, ``}, - // scalar field - {&pb.Communique{Union: &pb.Communique_Number{4}}, `number:4`}, - // message field - {&pb.Communique{Union: &pb.Communique_Msg{ - &pb.Strings{StringField: proto.String("why hello!")}, - }}, `msg:`}, - // bad oneof (should not panic) - {&pb.Communique{Union: &pb.Communique_Msg{nil}}, `msg:/* nil */`}, - } - for _, test := range tests { - got := strings.TrimSpace(test.m.String()) - if got != test.want { - t.Errorf("\n got %s\nwant %s", got, test.want) - } - } -} - -func BenchmarkMarshalTextBuffered(b *testing.B) { - buf := new(bytes.Buffer) - m := newTestMessage() - for i := 0; i < b.N; i++ { - buf.Reset() - proto.MarshalText(buf, m) - } -} - -func BenchmarkMarshalTextUnbuffered(b *testing.B) { - w := ioutil.Discard - m := newTestMessage() - for i := 0; i < b.N; i++ { - proto.MarshalText(w, m) - } -} - -func compact(src string) string { - // s/[ \n]+/ /g; s/ $//; - dst := make([]byte, len(src)) - space, comment := false, false - j := 0 - for i := 0; i < len(src); i++ { - if strings.HasPrefix(src[i:], "/*") { - comment = true - i++ - continue - } - if comment && strings.HasPrefix(src[i:], "*/") { - comment = false - i++ - continue - } - if comment { - continue - } - c := src[i] - if c == ' ' || c == '\n' { - space = true - continue - } - if j > 0 && (dst[j-1] == ':' || dst[j-1] == '<' || dst[j-1] == '{') { - space = false - } - if c == '{' { - space = false - } - if space { - dst[j] = ' ' - j++ - space = false - } - dst[j] = c - j++ - } - if space { - dst[j] = ' ' - j++ - } - return string(dst[0:j]) -} - -var compactText = compact(text) - -func TestCompactText(t *testing.T) { - s := proto.CompactTextString(newTestMessage()) - if s != compactText { - t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v\n===\n", s, compactText) - } -} - -func TestStringEscaping(t *testing.T) { - testCases := []struct { - in *pb.Strings - out string - }{ - { - // Test data from C++ test (TextFormatTest.StringEscape). - // Single divergence: we don't escape apostrophes. - &pb.Strings{StringField: proto.String("\"A string with ' characters \n and \r newlines and \t tabs and \001 slashes \\ and multiple spaces")}, - "string_field: \"\\\"A string with ' characters \\n and \\r newlines and \\t tabs and \\001 slashes \\\\ and multiple spaces\"\n", - }, - { - // Test data from the same C++ test. - &pb.Strings{StringField: proto.String("\350\260\267\346\255\214")}, - "string_field: \"\\350\\260\\267\\346\\255\\214\"\n", - }, - { - // Some UTF-8. - &pb.Strings{StringField: proto.String("\x00\x01\xff\x81")}, - `string_field: "\000\001\377\201"` + "\n", - }, - } - - for i, tc := range testCases { - var buf bytes.Buffer - if err := proto.MarshalText(&buf, tc.in); err != nil { - t.Errorf("proto.MarsalText: %v", err) - continue - } - s := buf.String() - if s != tc.out { - t.Errorf("#%d: Got:\n%s\nExpected:\n%s\n", i, s, tc.out) - continue - } - - // Check round-trip. - pb := new(pb.Strings) - if err := proto.UnmarshalText(s, pb); err != nil { - t.Errorf("#%d: UnmarshalText: %v", i, err) - continue - } - if !proto.Equal(pb, tc.in) { - t.Errorf("#%d: Round-trip failed:\nstart: %v\n end: %v", i, tc.in, pb) - } - } -} - -// A limitedWriter accepts some output before it fails. -// This is a proxy for something like a nearly-full or imminently-failing disk, -// or a network connection that is about to die. -type limitedWriter struct { - b bytes.Buffer - limit int -} - -var outOfSpace = errors.New("proto: insufficient space") - -func (w *limitedWriter) Write(p []byte) (n int, err error) { - var avail = w.limit - w.b.Len() - if avail <= 0 { - return 0, outOfSpace - } - if len(p) <= avail { - return w.b.Write(p) - } - n, _ = w.b.Write(p[:avail]) - return n, outOfSpace -} - -func TestMarshalTextFailing(t *testing.T) { - // Try lots of different sizes to exercise more error code-paths. - for lim := 0; lim < len(text); lim++ { - buf := new(limitedWriter) - buf.limit = lim - err := proto.MarshalText(buf, newTestMessage()) - // We expect a certain error, but also some partial results in the buffer. - if err != outOfSpace { - t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", err, outOfSpace) - } - s := buf.b.String() - x := text[:buf.limit] - if s != x { - t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", s, x) - } - } -} - -func TestFloats(t *testing.T) { - tests := []struct { - f float64 - want string - }{ - {0, "0"}, - {4.7, "4.7"}, - {math.Inf(1), "inf"}, - {math.Inf(-1), "-inf"}, - {math.NaN(), "nan"}, - } - for _, test := range tests { - msg := &pb.FloatingPoint{F: &test.f} - got := strings.TrimSpace(msg.String()) - want := `f:` + test.want - if got != want { - t.Errorf("f=%f: got %q, want %q", test.f, got, want) - } - } -} - -func TestRepeatedNilText(t *testing.T) { - m := &pb.MessageList{ - Message: []*pb.MessageList_Message{ - nil, - &pb.MessageList_Message{ - Name: proto.String("Horse"), - }, - nil, - }, - } - want := `Message -Message { - name: "Horse" -} -Message -` - if s := proto.MarshalTextString(m); s != want { - t.Errorf(" got: %s\nwant: %s", s, want) - } -} - -func TestProto3Text(t *testing.T) { - tests := []struct { - m proto.Message - want string - }{ - // zero message - {&proto3pb.Message{}, ``}, - // zero message except for an empty byte slice - {&proto3pb.Message{Data: []byte{}}, ``}, - // trivial case - {&proto3pb.Message{Name: "Rob", HeightInCm: 175}, `name:"Rob" height_in_cm:175`}, - // empty map - {&pb.MessageWithMap{}, ``}, - // non-empty map; map format is the same as a repeated struct, - // and they are sorted by key (numerically for numeric keys). - { - &pb.MessageWithMap{NameMapping: map[int32]string{ - -1: "Negatory", - 7: "Lucky", - 1234: "Feist", - 6345789: "Otis", - }}, - `name_mapping: ` + - `name_mapping: ` + - `name_mapping: ` + - `name_mapping:`, - }, - // map with nil value; not well-defined, but we shouldn't crash - { - &pb.MessageWithMap{MsgMapping: map[int64]*pb.FloatingPoint{7: nil}}, - `msg_mapping:`, - }, - } - for _, test := range tests { - got := strings.TrimSpace(test.m.String()) - if got != test.want { - t.Errorf("\n got %s\nwant %s", got, test.want) - } - } -} diff --git a/vendor/github.com/google/uuid/json_test.go b/vendor/github.com/google/uuid/json_test.go deleted file mode 100644 index 245f91ed..00000000 --- a/vendor/github.com/google/uuid/json_test.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "encoding/json" - "reflect" - "testing" -) - -var testUUID = Must(Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")) - -func TestJSON(t *testing.T) { - type S struct { - ID1 UUID - ID2 UUID - } - s1 := S{ID1: testUUID} - data, err := json.Marshal(&s1) - if err != nil { - t.Fatal(err) - } - var s2 S - if err := json.Unmarshal(data, &s2); err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(&s1, &s2) { - t.Errorf("got %#v, want %#v", s2, s1) - } -} - -func BenchmarkUUID_MarshalJSON(b *testing.B) { - x := &struct { - UUID UUID `json:"uuid"` - }{} - var err error - x.UUID, err = Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479") - if err != nil { - b.Fatal(err) - } - for i := 0; i < b.N; i++ { - js, err := json.Marshal(x) - if err != nil { - b.Fatalf("marshal json: %#v (%v)", js, err) - } - } -} - -func BenchmarkUUID_UnmarshalJSON(b *testing.B) { - js := []byte(`{"uuid":"f47ac10b-58cc-0372-8567-0e02b2c3d479"}`) - var x *struct { - UUID UUID `json:"uuid"` - } - for i := 0; i < b.N; i++ { - err := json.Unmarshal(js, &x) - if err != nil { - b.Fatalf("marshal json: %#v (%v)", js, err) - } - } -} diff --git a/vendor/github.com/google/uuid/seq_test.go b/vendor/github.com/google/uuid/seq_test.go deleted file mode 100644 index 853a4aa3..00000000 --- a/vendor/github.com/google/uuid/seq_test.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "flag" - "runtime" - "testing" - "time" -) - -// This test is only run when --regressions is passed on the go test line. -var regressions = flag.Bool("regressions", false, "run uuid regression tests") - -// TestClockSeqRace tests for a particular race condition of returning two -// identical Version1 UUIDs. The duration of 1 minute was chosen as the race -// condition, before being fixed, nearly always occured in under 30 seconds. -func TestClockSeqRace(t *testing.T) { - if !*regressions { - t.Skip("skipping regression tests") - } - duration := time.Minute - - done := make(chan struct{}) - defer close(done) - - ch := make(chan UUID, 10000) - ncpu := runtime.NumCPU() - switch ncpu { - case 0, 1: - // We can't run the test effectively. - t.Skip("skipping race test, only one CPU detected") - return - default: - runtime.GOMAXPROCS(ncpu) - } - for i := 0; i < ncpu; i++ { - go func() { - for { - select { - case <-done: - return - case ch <- Must(NewUUID()): - } - } - }() - } - - uuids := make(map[string]bool) - cnt := 0 - start := time.Now() - for u := range ch { - s := u.String() - if uuids[s] { - t.Errorf("duplicate uuid after %d in %v: %s", cnt, time.Since(start), s) - return - } - uuids[s] = true - if time.Since(start) > duration { - return - } - cnt++ - } -} diff --git a/vendor/github.com/google/uuid/sql_test.go b/vendor/github.com/google/uuid/sql_test.go deleted file mode 100644 index c1931960..00000000 --- a/vendor/github.com/google/uuid/sql_test.go +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "strings" - "testing" -) - -func TestScan(t *testing.T) { - var stringTest string = "f47ac10b-58cc-0372-8567-0e02b2c3d479" - var badTypeTest int = 6 - var invalidTest string = "f47ac10b-58cc-0372-8567-0e02b2c3d4" - - byteTest := make([]byte, 16) - byteTestUUID := Must(Parse(stringTest)) - copy(byteTest, byteTestUUID[:]) - - // sunny day tests - - var uuid UUID - err := (&uuid).Scan(stringTest) - if err != nil { - t.Fatal(err) - } - - err = (&uuid).Scan([]byte(stringTest)) - if err != nil { - t.Fatal(err) - } - - err = (&uuid).Scan(byteTest) - if err != nil { - t.Fatal(err) - } - - // bad type tests - - err = (&uuid).Scan(badTypeTest) - if err == nil { - t.Error("int correctly parsed and shouldn't have") - } - if !strings.Contains(err.Error(), "unable to scan type") { - t.Error("attempting to parse an int returned an incorrect error message") - } - - // invalid/incomplete uuids - - err = (&uuid).Scan(invalidTest) - if err == nil { - t.Error("invalid uuid was parsed without error") - } - if !strings.Contains(err.Error(), "invalid UUID") { - t.Error("attempting to parse an invalid UUID returned an incorrect error message") - } - - err = (&uuid).Scan(byteTest[:len(byteTest)-2]) - if err == nil { - t.Error("invalid byte uuid was parsed without error") - } - if !strings.Contains(err.Error(), "invalid UUID") { - t.Error("attempting to parse an invalid byte UUID returned an incorrect error message") - } - - // empty tests - - uuid = UUID{} - var emptySlice []byte - err = (&uuid).Scan(emptySlice) - if err != nil { - t.Fatal(err) - } - - for _, v := range uuid { - if v != 0 { - t.Error("UUID was not nil after scanning empty byte slice") - } - } - - uuid = UUID{} - var emptyString string - err = (&uuid).Scan(emptyString) - if err != nil { - t.Fatal(err) - } - for _, v := range uuid { - if v != 0 { - t.Error("UUID was not nil after scanning empty byte slice") - } - } -} - -func TestValue(t *testing.T) { - stringTest := "f47ac10b-58cc-0372-8567-0e02b2c3d479" - uuid := Must(Parse(stringTest)) - val, _ := uuid.Value() - if val != stringTest { - t.Error("Value() did not return expected string") - } -} diff --git a/vendor/github.com/google/uuid/uuid_test.go b/vendor/github.com/google/uuid/uuid_test.go deleted file mode 100644 index 70986ff3..00000000 --- a/vendor/github.com/google/uuid/uuid_test.go +++ /dev/null @@ -1,526 +0,0 @@ -// Copyright 2016 Google Inc. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package uuid - -import ( - "bytes" - "fmt" - "os" - "strings" - "testing" - "time" - "unsafe" -) - -type test struct { - in string - version Version - variant Variant - isuuid bool -} - -var tests = []test{ - {"f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, RFC4122, true}, - {"f47ac10b-58cc-1372-8567-0e02b2c3d479", 1, RFC4122, true}, - {"f47ac10b-58cc-2372-8567-0e02b2c3d479", 2, RFC4122, true}, - {"f47ac10b-58cc-3372-8567-0e02b2c3d479", 3, RFC4122, true}, - {"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true}, - {"f47ac10b-58cc-5372-8567-0e02b2c3d479", 5, RFC4122, true}, - {"f47ac10b-58cc-6372-8567-0e02b2c3d479", 6, RFC4122, true}, - {"f47ac10b-58cc-7372-8567-0e02b2c3d479", 7, RFC4122, true}, - {"f47ac10b-58cc-8372-8567-0e02b2c3d479", 8, RFC4122, true}, - {"f47ac10b-58cc-9372-8567-0e02b2c3d479", 9, RFC4122, true}, - {"f47ac10b-58cc-a372-8567-0e02b2c3d479", 10, RFC4122, true}, - {"f47ac10b-58cc-b372-8567-0e02b2c3d479", 11, RFC4122, true}, - {"f47ac10b-58cc-c372-8567-0e02b2c3d479", 12, RFC4122, true}, - {"f47ac10b-58cc-d372-8567-0e02b2c3d479", 13, RFC4122, true}, - {"f47ac10b-58cc-e372-8567-0e02b2c3d479", 14, RFC4122, true}, - {"f47ac10b-58cc-f372-8567-0e02b2c3d479", 15, RFC4122, true}, - - {"urn:uuid:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, - {"URN:UUID:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, - {"f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, - {"f47ac10b-58cc-4372-1567-0e02b2c3d479", 4, Reserved, true}, - {"f47ac10b-58cc-4372-2567-0e02b2c3d479", 4, Reserved, true}, - {"f47ac10b-58cc-4372-3567-0e02b2c3d479", 4, Reserved, true}, - {"f47ac10b-58cc-4372-4567-0e02b2c3d479", 4, Reserved, true}, - {"f47ac10b-58cc-4372-5567-0e02b2c3d479", 4, Reserved, true}, - {"f47ac10b-58cc-4372-6567-0e02b2c3d479", 4, Reserved, true}, - {"f47ac10b-58cc-4372-7567-0e02b2c3d479", 4, Reserved, true}, - {"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true}, - {"f47ac10b-58cc-4372-9567-0e02b2c3d479", 4, RFC4122, true}, - {"f47ac10b-58cc-4372-a567-0e02b2c3d479", 4, RFC4122, true}, - {"f47ac10b-58cc-4372-b567-0e02b2c3d479", 4, RFC4122, true}, - {"f47ac10b-58cc-4372-c567-0e02b2c3d479", 4, Microsoft, true}, - {"f47ac10b-58cc-4372-d567-0e02b2c3d479", 4, Microsoft, true}, - {"f47ac10b-58cc-4372-e567-0e02b2c3d479", 4, Future, true}, - {"f47ac10b-58cc-4372-f567-0e02b2c3d479", 4, Future, true}, - - {"f47ac10b158cc-5372-a567-0e02b2c3d479", 0, Invalid, false}, - {"f47ac10b-58cc25372-a567-0e02b2c3d479", 0, Invalid, false}, - {"f47ac10b-58cc-53723a567-0e02b2c3d479", 0, Invalid, false}, - {"f47ac10b-58cc-5372-a56740e02b2c3d479", 0, Invalid, false}, - {"f47ac10b-58cc-5372-a567-0e02-2c3d479", 0, Invalid, false}, - {"g47ac10b-58cc-4372-a567-0e02b2c3d479", 0, Invalid, false}, -} - -var constants = []struct { - c interface{} - name string -}{ - {Person, "Person"}, - {Group, "Group"}, - {Org, "Org"}, - {Invalid, "Invalid"}, - {RFC4122, "RFC4122"}, - {Reserved, "Reserved"}, - {Microsoft, "Microsoft"}, - {Future, "Future"}, - {Domain(17), "Domain17"}, - {Variant(42), "BadVariant42"}, -} - -func testTest(t *testing.T, in string, tt test) { - uuid, err := Parse(in) - if ok := (err == nil); ok != tt.isuuid { - t.Errorf("Parse(%s) got %v expected %v\b", in, ok, tt.isuuid) - } - if err != nil { - return - } - - if v := uuid.Variant(); v != tt.variant { - t.Errorf("Variant(%s) got %d expected %d\b", in, v, tt.variant) - } - if v := uuid.Version(); v != tt.version { - t.Errorf("Version(%s) got %d expected %d\b", in, v, tt.version) - } -} - -func testBytes(t *testing.T, in []byte, tt test) { - uuid, err := ParseBytes(in) - if ok := (err == nil); ok != tt.isuuid { - t.Errorf("ParseBytes(%s) got %v expected %v\b", in, ok, tt.isuuid) - } - if err != nil { - return - } - suuid, _ := Parse(string(in)) - if uuid != suuid { - t.Errorf("ParseBytes(%s) got %v expected %v\b", in, uuid, suuid) - } -} - -func TestUUID(t *testing.T) { - for _, tt := range tests { - testTest(t, tt.in, tt) - testTest(t, strings.ToUpper(tt.in), tt) - testBytes(t, []byte(tt.in), tt) - } -} - -func TestConstants(t *testing.T) { - for x, tt := range constants { - v, ok := tt.c.(fmt.Stringer) - if !ok { - t.Errorf("%x: %v: not a stringer", x, v) - } else if s := v.String(); s != tt.name { - v, _ := tt.c.(int) - t.Errorf("%x: Constant %T:%d gives %q, expected %q", x, tt.c, v, s, tt.name) - } - } -} - -func TestRandomUUID(t *testing.T) { - m := make(map[string]bool) - for x := 1; x < 32; x++ { - uuid := New() - s := uuid.String() - if m[s] { - t.Errorf("NewRandom returned duplicated UUID %s", s) - } - m[s] = true - if v := uuid.Version(); v != 4 { - t.Errorf("Random UUID of version %s", v) - } - if uuid.Variant() != RFC4122 { - t.Errorf("Random UUID is variant %d", uuid.Variant()) - } - } -} - -func TestNew(t *testing.T) { - m := make(map[UUID]bool) - for x := 1; x < 32; x++ { - s := New() - if m[s] { - t.Errorf("New returned duplicated UUID %s", s) - } - m[s] = true - uuid, err := Parse(s.String()) - if err != nil { - t.Errorf("New.String() returned %q which does not decode", s) - continue - } - if v := uuid.Version(); v != 4 { - t.Errorf("Random UUID of version %s", v) - } - if uuid.Variant() != RFC4122 { - t.Errorf("Random UUID is variant %d", uuid.Variant()) - } - } -} - -func TestClockSeq(t *testing.T) { - // Fake time.Now for this test to return a monotonically advancing time; restore it at end. - defer func(orig func() time.Time) { timeNow = orig }(timeNow) - monTime := time.Now() - timeNow = func() time.Time { - monTime = monTime.Add(1 * time.Second) - return monTime - } - - SetClockSequence(-1) - uuid1, err := NewUUID() - if err != nil { - t.Fatalf("could not create UUID: %v", err) - } - uuid2, err := NewUUID() - if err != nil { - t.Fatalf("could not create UUID: %v", err) - } - - if s1, s2 := uuid1.ClockSequence(), uuid2.ClockSequence(); s1 != s2 { - t.Errorf("clock sequence %d != %d", s1, s2) - } - - SetClockSequence(-1) - uuid2, err = NewUUID() - if err != nil { - t.Fatalf("could not create UUID: %v", err) - } - - // Just on the very off chance we generated the same sequence - // two times we try again. - if uuid1.ClockSequence() == uuid2.ClockSequence() { - SetClockSequence(-1) - uuid2, err = NewUUID() - if err != nil { - t.Fatalf("could not create UUID: %v", err) - } - } - if s1, s2 := uuid1.ClockSequence(), uuid2.ClockSequence(); s1 == s2 { - t.Errorf("Duplicate clock sequence %d", s1) - } - - SetClockSequence(0x1234) - uuid1, err = NewUUID() - if err != nil { - t.Fatalf("could not create UUID: %v", err) - } - if seq := uuid1.ClockSequence(); seq != 0x1234 { - t.Errorf("%s: expected seq 0x1234 got 0x%04x", uuid1, seq) - } -} - -func TestCoding(t *testing.T) { - text := "7d444840-9dc0-11d1-b245-5ffdce74fad2" - urn := "urn:uuid:7d444840-9dc0-11d1-b245-5ffdce74fad2" - data := UUID{ - 0x7d, 0x44, 0x48, 0x40, - 0x9d, 0xc0, - 0x11, 0xd1, - 0xb2, 0x45, - 0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2, - } - if v := data.String(); v != text { - t.Errorf("%x: encoded to %s, expected %s", data, v, text) - } - if v := data.URN(); v != urn { - t.Errorf("%x: urn is %s, expected %s", data, v, urn) - } - - uuid, err := Parse(text) - if err != nil { - t.Errorf("Parse returned unexpected error %v", err) - } - if data != data { - t.Errorf("%s: decoded to %s, expected %s", text, uuid, data) - } -} - -func TestVersion1(t *testing.T) { - uuid1, err := NewUUID() - if err != nil { - t.Fatalf("could not create UUID: %v", err) - } - uuid2, err := NewUUID() - if err != nil { - t.Fatalf("could not create UUID: %v", err) - } - - if uuid1 == uuid2 { - t.Errorf("%s:duplicate uuid", uuid1) - } - if v := uuid1.Version(); v != 1 { - t.Errorf("%s: version %s expected 1", uuid1, v) - } - if v := uuid2.Version(); v != 1 { - t.Errorf("%s: version %s expected 1", uuid2, v) - } - n1 := uuid1.NodeID() - n2 := uuid2.NodeID() - if !bytes.Equal(n1, n2) { - t.Errorf("Different nodes %x != %x", n1, n2) - } - t1 := uuid1.Time() - t2 := uuid2.Time() - q1 := uuid1.ClockSequence() - q2 := uuid2.ClockSequence() - - switch { - case t1 == t2 && q1 == q2: - t.Error("time stopped") - case t1 > t2 && q1 == q2: - t.Error("time reversed") - case t1 < t2 && q1 != q2: - t.Error("clock sequence chaned unexpectedly") - } -} - -func TestNode(t *testing.T) { - // This test is mostly to make sure we don't leave nodeMu locked. - ifname = "" - if ni := NodeInterface(); ni != "" { - t.Errorf("NodeInterface got %q, want %q", ni, "") - } - if SetNodeInterface("xyzzy") { - t.Error("SetNodeInterface succeeded on a bad interface name") - } - if !SetNodeInterface("") { - t.Error("SetNodeInterface failed") - } - if ni := NodeInterface(); ni == "" { - t.Error("NodeInterface returned an empty string") - } - - ni := NodeID() - if len(ni) != 6 { - t.Errorf("ni got %d bytes, want 6", len(ni)) - } - hasData := false - for _, b := range ni { - if b != 0 { - hasData = true - } - } - if !hasData { - t.Error("nodeid is all zeros") - } - - id := []byte{1, 2, 3, 4, 5, 6, 7, 8} - SetNodeID(id) - ni = NodeID() - if !bytes.Equal(ni, id[:6]) { - t.Errorf("got nodeid %v, want %v", ni, id[:6]) - } - - if ni := NodeInterface(); ni != "user" { - t.Errorf("got inteface %q, want %q", ni, "user") - } -} - -func TestNodeAndTime(t *testing.T) { - // Time is February 5, 1998 12:30:23.136364800 AM GMT - - uuid, err := Parse("7d444840-9dc0-11d1-b245-5ffdce74fad2") - if err != nil { - t.Fatalf("Parser returned unexpected error %v", err) - } - node := []byte{0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2} - - ts := uuid.Time() - c := time.Unix(ts.UnixTime()) - want := time.Date(1998, 2, 5, 0, 30, 23, 136364800, time.UTC) - if !c.Equal(want) { - t.Errorf("Got time %v, want %v", c, want) - } - if !bytes.Equal(node, uuid.NodeID()) { - t.Errorf("Expected node %v got %v", node, uuid.NodeID()) - } -} - -func TestMD5(t *testing.T) { - uuid := NewMD5(NameSpaceDNS, []byte("python.org")).String() - want := "6fa459ea-ee8a-3ca4-894e-db77e160355e" - if uuid != want { - t.Errorf("MD5: got %q expected %q", uuid, want) - } -} - -func TestSHA1(t *testing.T) { - uuid := NewSHA1(NameSpaceDNS, []byte("python.org")).String() - want := "886313e1-3b8a-5372-9b90-0c9aee199e5d" - if uuid != want { - t.Errorf("SHA1: got %q expected %q", uuid, want) - } -} - -func TestNodeID(t *testing.T) { - nid := []byte{1, 2, 3, 4, 5, 6} - SetNodeInterface("") - s := NodeInterface() - if s == "" || s == "user" { - t.Errorf("NodeInterface %q after SetInteface", s) - } - node1 := NodeID() - if node1 == nil { - t.Error("NodeID nil after SetNodeInterface", s) - } - SetNodeID(nid) - s = NodeInterface() - if s != "user" { - t.Errorf("Expected NodeInterface %q got %q", "user", s) - } - node2 := NodeID() - if node2 == nil { - t.Error("NodeID nil after SetNodeID", s) - } - if bytes.Equal(node1, node2) { - t.Error("NodeID not changed after SetNodeID", s) - } else if !bytes.Equal(nid, node2) { - t.Errorf("NodeID is %x, expected %x", node2, nid) - } -} - -func testDCE(t *testing.T, name string, uuid UUID, err error, domain Domain, id uint32) { - if err != nil { - t.Errorf("%s failed: %v", name, err) - return - } - if v := uuid.Version(); v != 2 { - t.Errorf("%s: %s: expected version 2, got %s", name, uuid, v) - return - } - if v := uuid.Domain(); v != domain { - t.Errorf("%s: %s: expected domain %d, got %d", name, uuid, domain, v) - } - if v := uuid.ID(); v != id { - t.Errorf("%s: %s: expected id %d, got %d", name, uuid, id, v) - } -} - -func TestDCE(t *testing.T) { - uuid, err := NewDCESecurity(42, 12345678) - testDCE(t, "NewDCESecurity", uuid, err, 42, 12345678) - uuid, err = NewDCEPerson() - testDCE(t, "NewDCEPerson", uuid, err, Person, uint32(os.Getuid())) - uuid, err = NewDCEGroup() - testDCE(t, "NewDCEGroup", uuid, err, Group, uint32(os.Getgid())) -} - -type badRand struct{} - -func (r badRand) Read(buf []byte) (int, error) { - for i, _ := range buf { - buf[i] = byte(i) - } - return len(buf), nil -} - -func TestBadRand(t *testing.T) { - SetRand(badRand{}) - uuid1 := New() - uuid2 := New() - if uuid1 != uuid2 { - t.Errorf("execpted duplicates, got %q and %q", uuid1, uuid2) - } - SetRand(nil) - uuid1 = New() - uuid2 = New() - if uuid1 == uuid2 { - t.Errorf("unexecpted duplicates, got %q", uuid1) - } -} - -var asString = "f47ac10b-58cc-0372-8567-0e02b2c3d479" -var asBytes = []byte(asString) - -func BenchmarkParse(b *testing.B) { - for i := 0; i < b.N; i++ { - _, err := Parse(asString) - if err != nil { - b.Fatal(err) - } - } -} - -func BenchmarkParseBytes(b *testing.B) { - for i := 0; i < b.N; i++ { - _, err := ParseBytes(asBytes) - if err != nil { - b.Fatal(err) - } - } -} - -// parseBytesUnsafe is to benchmark using unsafe. -func parseBytesUnsafe(b []byte) (UUID, error) { - return Parse(*(*string)(unsafe.Pointer(&b))) -} - - -func BenchmarkParseBytesUnsafe(b *testing.B) { - for i := 0; i < b.N; i++ { - _, err := parseBytesUnsafe(asBytes) - if err != nil { - b.Fatal(err) - } - } -} - -// parseBytesCopy is to benchmark not using unsafe. -func parseBytesCopy(b []byte) (UUID, error) { - return Parse(string(b)) -} - -func BenchmarkParseBytesCopy(b *testing.B) { - for i := 0; i < b.N; i++ { - _, err := parseBytesCopy(asBytes) - if err != nil { - b.Fatal(err) - } - } -} - -func BenchmarkNew(b *testing.B) { - for i := 0; i < b.N; i++ { - New() - } -} - -func BenchmarkUUID_String(b *testing.B) { - uuid, err := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479") - if err != nil { - b.Fatal(err) - } - for i := 0; i < b.N; i++ { - if uuid.String() == "" { - b.Fatal("invalid uuid") - } - } -} - -func BenchmarkUUID_URN(b *testing.B) { - uuid, err := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479") - if err != nil { - b.Fatal(err) - } - for i := 0; i < b.N; i++ { - if uuid.URN() == "" { - b.Fatal("invalid uuid") - } - } -} diff --git a/vendor/github.com/gorilla/context/context_test.go b/vendor/github.com/gorilla/context/context_test.go deleted file mode 100644 index d70e91a2..00000000 --- a/vendor/github.com/gorilla/context/context_test.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2012 The Gorilla Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package context - -import ( - "net/http" - "testing" -) - -type keyType int - -const ( - key1 keyType = iota - key2 -) - -func TestContext(t *testing.T) { - assertEqual := func(val interface{}, exp interface{}) { - if val != exp { - t.Errorf("Expected %v, got %v.", exp, val) - } - } - - r, _ := http.NewRequest("GET", "http://localhost:8080/", nil) - emptyR, _ := http.NewRequest("GET", "http://localhost:8080/", nil) - - // Get() - assertEqual(Get(r, key1), nil) - - // Set() - Set(r, key1, "1") - assertEqual(Get(r, key1), "1") - assertEqual(len(data[r]), 1) - - Set(r, key2, "2") - assertEqual(Get(r, key2), "2") - assertEqual(len(data[r]), 2) - - //GetOk - value, ok := GetOk(r, key1) - assertEqual(value, "1") - assertEqual(ok, true) - - value, ok = GetOk(r, "not exists") - assertEqual(value, nil) - assertEqual(ok, false) - - Set(r, "nil value", nil) - value, ok = GetOk(r, "nil value") - assertEqual(value, nil) - assertEqual(ok, true) - - // GetAll() - values := GetAll(r) - assertEqual(len(values), 3) - - // GetAll() for empty request - values = GetAll(emptyR) - if values != nil { - t.Error("GetAll didn't return nil value for invalid request") - } - - // GetAllOk() - values, ok = GetAllOk(r) - assertEqual(len(values), 3) - assertEqual(ok, true) - - // GetAllOk() for empty request - values, ok = GetAllOk(emptyR) - assertEqual(len(values), 0) - assertEqual(ok, false) - - // Delete() - Delete(r, key1) - assertEqual(Get(r, key1), nil) - assertEqual(len(data[r]), 2) - - Delete(r, key2) - assertEqual(Get(r, key2), nil) - assertEqual(len(data[r]), 1) - - // Clear() - Clear(r) - assertEqual(len(data), 0) -} - -func parallelReader(r *http.Request, key string, iterations int, wait, done chan struct{}) { - <-wait - for i := 0; i < iterations; i++ { - Get(r, key) - } - done <- struct{}{} - -} - -func parallelWriter(r *http.Request, key, value string, iterations int, wait, done chan struct{}) { - <-wait - for i := 0; i < iterations; i++ { - Set(r, key, value) - } - done <- struct{}{} - -} - -func benchmarkMutex(b *testing.B, numReaders, numWriters, iterations int) { - - b.StopTimer() - r, _ := http.NewRequest("GET", "http://localhost:8080/", nil) - done := make(chan struct{}) - b.StartTimer() - - for i := 0; i < b.N; i++ { - wait := make(chan struct{}) - - for i := 0; i < numReaders; i++ { - go parallelReader(r, "test", iterations, wait, done) - } - - for i := 0; i < numWriters; i++ { - go parallelWriter(r, "test", "123", iterations, wait, done) - } - - close(wait) - - for i := 0; i < numReaders+numWriters; i++ { - <-done - } - - } - -} - -func BenchmarkMutexSameReadWrite1(b *testing.B) { - benchmarkMutex(b, 1, 1, 32) -} -func BenchmarkMutexSameReadWrite2(b *testing.B) { - benchmarkMutex(b, 2, 2, 32) -} -func BenchmarkMutexSameReadWrite4(b *testing.B) { - benchmarkMutex(b, 4, 4, 32) -} -func BenchmarkMutex1(b *testing.B) { - benchmarkMutex(b, 2, 8, 32) -} -func BenchmarkMutex2(b *testing.B) { - benchmarkMutex(b, 16, 4, 64) -} -func BenchmarkMutex3(b *testing.B) { - benchmarkMutex(b, 1, 2, 128) -} -func BenchmarkMutex4(b *testing.B) { - benchmarkMutex(b, 128, 32, 256) -} -func BenchmarkMutex5(b *testing.B) { - benchmarkMutex(b, 1024, 2048, 64) -} -func BenchmarkMutex6(b *testing.B) { - benchmarkMutex(b, 2048, 1024, 512) -} diff --git a/vendor/github.com/gorilla/securecookie/.travis.yml b/vendor/github.com/gorilla/securecookie/.travis.yml index 6f440f1e..24882fc7 100644 --- a/vendor/github.com/gorilla/securecookie/.travis.yml +++ b/vendor/github.com/gorilla/securecookie/.travis.yml @@ -7,7 +7,6 @@ matrix: - go: 1.4 - go: 1.5 - go: 1.6 - - go: 1.7 - go: tip allow_failures: - go: tip diff --git a/vendor/github.com/gorilla/securecookie/README.md b/vendor/github.com/gorilla/securecookie/README.md index aa7bd1a5..5ed299e5 100644 --- a/vendor/github.com/gorilla/securecookie/README.md +++ b/vendor/github.com/gorilla/securecookie/README.md @@ -1,8 +1,6 @@ securecookie ============ [![GoDoc](https://godoc.org/github.com/gorilla/securecookie?status.svg)](https://godoc.org/github.com/gorilla/securecookie) [![Build Status](https://travis-ci.org/gorilla/securecookie.png?branch=master)](https://travis-ci.org/gorilla/securecookie) -[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/securecookie/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/securecookie?badge) - securecookie encodes and decodes authenticated and optionally encrypted cookie values. @@ -47,8 +45,6 @@ func SetCookieHandler(w http.ResponseWriter, r *http.Request) { Name: "cookie-name", Value: encoded, Path: "/", - Secure: true, - HttpOnly: true, } http.SetCookie(w, cookie) } diff --git a/vendor/github.com/gorilla/securecookie/securecookie.go b/vendor/github.com/gorilla/securecookie/securecookie.go index cd4e0976..83dd606a 100644 --- a/vendor/github.com/gorilla/securecookie/securecookie.go +++ b/vendor/github.com/gorilla/securecookie/securecookie.go @@ -102,7 +102,6 @@ var ( errTimestampExpired = cookieError{typ: decodeError, msg: "expired timestamp"} errDecryptionFailed = cookieError{typ: decodeError, msg: "the value could not be decrypted"} errValueNotByte = cookieError{typ: decodeError, msg: "value not a []byte."} - errValueNotBytePtr = cookieError{typ: decodeError, msg: "value not a pointer to []byte."} // ErrMacInvalid indicates that cookie decoding failed because the HMAC // could not be extracted and verified. Direct use of this error @@ -475,11 +474,12 @@ func (e NopEncoder) Serialize(src interface{}) ([]byte, error) { // Deserialize passes a []byte through as-is. func (e NopEncoder) Deserialize(src []byte, dst interface{}) error { - if dat, ok := dst.(*[]byte); ok { - *dat = src + if _, ok := dst.([]byte); ok { + dst = src return nil } - return errValueNotBytePtr + + return errValueNotByte } // Encoding ------------------------------------------------------------------- diff --git a/vendor/github.com/gorilla/securecookie/securecookie_test.go b/vendor/github.com/gorilla/securecookie/securecookie_test.go deleted file mode 100644 index 2b0f8a1e..00000000 --- a/vendor/github.com/gorilla/securecookie/securecookie_test.go +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright 2012 The Gorilla Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package securecookie - -import ( - "crypto/aes" - "crypto/hmac" - "crypto/sha256" - "encoding/base64" - "fmt" - "reflect" - "strings" - "testing" -) - -// Asserts that cookieError and MultiError are Error implementations. -var _ Error = cookieError{} -var _ Error = MultiError{} - -var testCookies = []interface{}{ - map[string]string{"foo": "bar"}, - map[string]string{"baz": "ding"}, -} - -var testStrings = []string{"foo", "bar", "baz"} - -func TestSecureCookie(t *testing.T) { - // TODO test too old / too new timestamps - s1 := New([]byte("12345"), []byte("1234567890123456")) - s2 := New([]byte("54321"), []byte("6543210987654321")) - value := map[string]interface{}{ - "foo": "bar", - "baz": 128, - } - - for i := 0; i < 50; i++ { - // Running this multiple times to check if any special character - // breaks encoding/decoding. - encoded, err1 := s1.Encode("sid", value) - if err1 != nil { - t.Error(err1) - continue - } - dst := make(map[string]interface{}) - err2 := s1.Decode("sid", encoded, &dst) - if err2 != nil { - t.Fatalf("%v: %v", err2, encoded) - } - if !reflect.DeepEqual(dst, value) { - t.Fatalf("Expected %v, got %v.", value, dst) - } - dst2 := make(map[string]interface{}) - err3 := s2.Decode("sid", encoded, &dst2) - if err3 == nil { - t.Fatalf("Expected failure decoding.") - } - err4, ok := err3.(Error) - if !ok { - t.Fatalf("Expected error to implement Error, got: %#v", err3) - } - if !err4.IsDecode() { - t.Fatalf("Expected DecodeError, got: %#v", err4) - } - - // Test other error type flags. - if err4.IsUsage() { - t.Fatalf("Expected IsUsage() == false, got: %#v", err4) - } - if err4.IsInternal() { - t.Fatalf("Expected IsInternal() == false, got: %#v", err4) - } - } -} - -func TestSecureCookieNilKey(t *testing.T) { - s1 := New(nil, nil) - value := map[string]interface{}{ - "foo": "bar", - "baz": 128, - } - _, err := s1.Encode("sid", value) - if err != errHashKeyNotSet { - t.Fatal("Wrong error returned:", err) - } -} - -func TestDecodeInvalid(t *testing.T) { - // List of invalid cookies, which must not be accepted, base64-decoded - // (they will be encoded before passing to Decode). - invalidCookies := []string{ - "", - " ", - "\n", - "||", - "|||", - "cookie", - } - s := New([]byte("12345"), nil) - var dst string - for i, v := range invalidCookies { - for _, enc := range []*base64.Encoding{ - base64.StdEncoding, - base64.URLEncoding, - } { - err := s.Decode("name", enc.EncodeToString([]byte(v)), &dst) - if err == nil { - t.Fatalf("%d: expected failure decoding", i) - } - err2, ok := err.(Error) - if !ok || !err2.IsDecode() { - t.Fatalf("%d: Expected IsDecode(), got: %#v", i, err) - } - } - } -} - -func TestAuthentication(t *testing.T) { - hash := hmac.New(sha256.New, []byte("secret-key")) - for _, value := range testStrings { - hash.Reset() - signed := createMac(hash, []byte(value)) - hash.Reset() - err := verifyMac(hash, []byte(value), signed) - if err != nil { - t.Error(err) - } - } -} - -func TestEncryption(t *testing.T) { - block, err := aes.NewCipher([]byte("1234567890123456")) - if err != nil { - t.Fatalf("Block could not be created") - } - var encrypted, decrypted []byte - for _, value := range testStrings { - if encrypted, err = encrypt(block, []byte(value)); err != nil { - t.Error(err) - } else { - if decrypted, err = decrypt(block, encrypted); err != nil { - t.Error(err) - } - if string(decrypted) != value { - t.Errorf("Expected %v, got %v.", value, string(decrypted)) - } - } - } -} - -func TestGobSerialization(t *testing.T) { - var ( - sz GobEncoder - serialized []byte - deserialized map[string]string - err error - ) - for _, value := range testCookies { - if serialized, err = sz.Serialize(value); err != nil { - t.Error(err) - } else { - deserialized = make(map[string]string) - if err = sz.Deserialize(serialized, &deserialized); err != nil { - t.Error(err) - } - if fmt.Sprintf("%v", deserialized) != fmt.Sprintf("%v", value) { - t.Errorf("Expected %v, got %v.", value, deserialized) - } - } - } -} - -func TestJSONSerialization(t *testing.T) { - var ( - sz JSONEncoder - serialized []byte - deserialized map[string]string - err error - ) - for _, value := range testCookies { - if serialized, err = sz.Serialize(value); err != nil { - t.Error(err) - } else { - deserialized = make(map[string]string) - if err = sz.Deserialize(serialized, &deserialized); err != nil { - t.Error(err) - } - if fmt.Sprintf("%v", deserialized) != fmt.Sprintf("%v", value) { - t.Errorf("Expected %v, got %v.", value, deserialized) - } - } - } -} - -func TestNopSerialization(t *testing.T) { - cookieData := "fooobar123" - sz := NopEncoder{} - - if _, err := sz.Serialize(cookieData); err != errValueNotByte { - t.Fatal("Expected error passing string") - } - dat, err := sz.Serialize([]byte(cookieData)) - if err != nil { - t.Fatal(err) - } - if (string(dat)) != cookieData { - t.Fatal("Expected serialized data to be same as source") - } - - var dst []byte - if err = sz.Deserialize(dat, dst); err != errValueNotBytePtr { - t.Fatal("Expect error unless you pass a *[]byte") - } - if err = sz.Deserialize(dat, &dst); err != nil { - t.Fatal(err) - } - if (string(dst)) != cookieData { - t.Fatal("Expected deserialized data to be same as source") - } -} - -func TestEncoding(t *testing.T) { - for _, value := range testStrings { - encoded := encode([]byte(value)) - decoded, err := decode(encoded) - if err != nil { - t.Error(err) - } else if string(decoded) != value { - t.Errorf("Expected %v, got %s.", value, string(decoded)) - } - } -} - -func TestMultiError(t *testing.T) { - s1, s2 := New(nil, nil), New(nil, nil) - _, err := EncodeMulti("sid", "value", s1, s2) - if len(err.(MultiError)) != 2 { - t.Errorf("Expected 2 errors, got %s.", err) - } else { - if strings.Index(err.Error(), "hash key is not set") == -1 { - t.Errorf("Expected missing hash key error, got %s.", err.Error()) - } - ourErr, ok := err.(Error) - if !ok || !ourErr.IsUsage() { - t.Fatalf("Expected error to be a usage error; got %#v", err) - } - if ourErr.IsDecode() { - t.Errorf("Expected error NOT to be a decode error; got %#v", ourErr) - } - if ourErr.IsInternal() { - t.Errorf("Expected error NOT to be an internal error; got %#v", ourErr) - } - } -} - -func TestMultiNoCodecs(t *testing.T) { - _, err := EncodeMulti("foo", "bar") - if err != errNoCodecs { - t.Errorf("EncodeMulti: bad value for error, got: %v", err) - } - - var dst []byte - err = DecodeMulti("foo", "bar", &dst) - if err != errNoCodecs { - t.Errorf("DecodeMulti: bad value for error, got: %v", err) - } -} - -func TestMissingKey(t *testing.T) { - s1 := New(nil, nil) - - var dst []byte - err := s1.Decode("sid", "value", &dst) - if err != errHashKeyNotSet { - t.Fatalf("Expected %#v, got %#v", errHashKeyNotSet, err) - } - if err2, ok := err.(Error); !ok || !err2.IsUsage() { - t.Errorf("Expected missing hash key to be IsUsage(); was %#v", err) - } -} - -// ---------------------------------------------------------------------------- - -type FooBar struct { - Foo int - Bar string -} - -func TestCustomType(t *testing.T) { - s1 := New([]byte("12345"), []byte("1234567890123456")) - // Type is not registered in gob. (!!!) - src := &FooBar{42, "bar"} - encoded, _ := s1.Encode("sid", src) - - dst := &FooBar{} - _ = s1.Decode("sid", encoded, dst) - if dst.Foo != 42 || dst.Bar != "bar" { - t.Fatalf("Expected %#v, got %#v", src, dst) - } -} diff --git a/vendor/github.com/gorilla/sessions/README.md b/vendor/github.com/gorilla/sessions/README.md index 10eb7f04..65e5e1b3 100644 --- a/vendor/github.com/gorilla/sessions/README.md +++ b/vendor/github.com/gorilla/sessions/README.md @@ -1,8 +1,6 @@ sessions ======== [![GoDoc](https://godoc.org/github.com/gorilla/sessions?status.svg)](https://godoc.org/github.com/gorilla/sessions) [![Build Status](https://travis-ci.org/gorilla/sessions.png?branch=master)](https://travis-ci.org/gorilla/sessions) -[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/sessions/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/sessions?badge) - gorilla/sessions provides cookie and filesystem sessions and infrastructure for custom session backends. @@ -44,22 +42,16 @@ Let's start with an example that shows the sessions API in a nutshell: First we initialize a session store calling `NewCookieStore()` and passing a secret key used to authenticate the session. Inside the handler, we call -`store.Get()` to retrieve an existing session or create a new one. Then we set -some session values in session.Values, which is a `map[interface{}]interface{}`. +`store.Get()` to retrieve an existing session or a new one. Then we set some +session values in session.Values, which is a `map[interface{}]interface{}`. And finally we call `session.Save()` to save the session in the response. Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with [`context.ClearHandler`](http://www.gorillatoolkit.org/pkg/context#ClearHandler) -or else you will leak memory! An easy way to do this is to wrap the top-level +as or else you will leak memory! An easy way to do this is to wrap the top-level mux when calling http.ListenAndServe: -```go - http.ListenAndServe(":8080", context.ClearHandler(http.DefaultServeMux)) -``` - -The ClearHandler function is provided by the gorilla/context package. - More examples are available [on the Gorilla website](http://www.gorillatoolkit.org/pkg/sessions). @@ -71,19 +63,16 @@ Other implementations of the `sessions.Store` interface: * [github.com/yosssi/boltstore](https://github.com/yosssi/boltstore) - Bolt * [github.com/srinathgs/couchbasestore](https://github.com/srinathgs/couchbasestore) - Couchbase * [github.com/denizeren/dynamostore](https://github.com/denizeren/dynamostore) - Dynamodb on AWS -* [github.com/savaki/dynastore](https://github.com/savaki/dynastore) - DynamoDB on AWS (Official AWS library) * [github.com/bradleypeabody/gorilla-sessions-memcache](https://github.com/bradleypeabody/gorilla-sessions-memcache) - Memcache * [github.com/dsoprea/go-appengine-sessioncascade](https://github.com/dsoprea/go-appengine-sessioncascade) - Memcache/Datastore/Context in AppEngine * [github.com/kidstuff/mongostore](https://github.com/kidstuff/mongostore) - MongoDB * [github.com/srinathgs/mysqlstore](https://github.com/srinathgs/mysqlstore) - MySQL -* [github.com/EnumApps/clustersqlstore](https://github.com/EnumApps/clustersqlstore) - MySQL Cluster * [github.com/antonlindstrom/pgstore](https://github.com/antonlindstrom/pgstore) - PostgreSQL * [github.com/boj/redistore](https://github.com/boj/redistore) - Redis * [github.com/boj/rethinkstore](https://github.com/boj/rethinkstore) - RethinkDB * [github.com/boj/riakstore](https://github.com/boj/riakstore) - Riak * [github.com/michaeljs1990/sqlitestore](https://github.com/michaeljs1990/sqlitestore) - SQLite * [github.com/wader/gormstore](https://github.com/wader/gormstore) - GORM (MySQL, PostgreSQL, SQLite) -* [github.com/gernest/qlstore](https://github.com/gernest/qlstore) - ql ## License diff --git a/vendor/github.com/gorilla/sessions/doc.go b/vendor/github.com/gorilla/sessions/doc.go index 591d9326..668e05e4 100644 --- a/vendor/github.com/gorilla/sessions/doc.go +++ b/vendor/github.com/gorilla/sessions/doc.go @@ -29,7 +29,8 @@ Let's start with an example that shows the sessions API in a nutshell: var store = sessions.NewCookieStore([]byte("something-very-secret")) func MyHandler(w http.ResponseWriter, r *http.Request) { - // Get a session. Get() always returns a session, even if empty. + // Get a session. We're ignoring the error resulted from decoding an + // existing session: Get() always returns a session, even if empty. session, err := store.Get(r, "session-name") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) diff --git a/vendor/github.com/gorilla/sessions/sessions_test.go b/vendor/github.com/gorilla/sessions/sessions_test.go deleted file mode 100644 index c166b05b..00000000 --- a/vendor/github.com/gorilla/sessions/sessions_test.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2012 The Gorilla Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sessions - -import ( - "bytes" - "encoding/gob" - "net/http" - "net/http/httptest" - "testing" -) - -// NewRecorder returns an initialized ResponseRecorder. -func NewRecorder() *httptest.ResponseRecorder { - return &httptest.ResponseRecorder{ - HeaderMap: make(http.Header), - Body: new(bytes.Buffer), - } -} - -// DefaultRemoteAddr is the default remote address to return in RemoteAddr if -// an explicit DefaultRemoteAddr isn't set on ResponseRecorder. -const DefaultRemoteAddr = "1.2.3.4" - -// ---------------------------------------------------------------------------- - -type FlashMessage struct { - Type int - Message string -} - -func TestFlashes(t *testing.T) { - var req *http.Request - var rsp *httptest.ResponseRecorder - var hdr http.Header - var err error - var ok bool - var cookies []string - var session *Session - var flashes []interface{} - - store := NewCookieStore([]byte("secret-key")) - - // Round 1 ---------------------------------------------------------------- - - req, _ = http.NewRequest("GET", "http://localhost:8080/", nil) - rsp = NewRecorder() - // Get a session. - if session, err = store.Get(req, "session-key"); err != nil { - t.Fatalf("Error getting session: %v", err) - } - // Get a flash. - flashes = session.Flashes() - if len(flashes) != 0 { - t.Errorf("Expected empty flashes; Got %v", flashes) - } - // Add some flashes. - session.AddFlash("foo") - session.AddFlash("bar") - // Custom key. - session.AddFlash("baz", "custom_key") - // Save. - if err = Save(req, rsp); err != nil { - t.Fatalf("Error saving session: %v", err) - } - hdr = rsp.Header() - cookies, ok = hdr["Set-Cookie"] - if !ok || len(cookies) != 1 { - t.Fatal("No cookies. Header:", hdr) - } - - if _, err = store.Get(req, "session:key"); err.Error() != "sessions: invalid character in cookie name: session:key" { - t.Fatalf("Expected error due to invalid cookie name") - } - - // Round 2 ---------------------------------------------------------------- - - req, _ = http.NewRequest("GET", "http://localhost:8080/", nil) - req.Header.Add("Cookie", cookies[0]) - rsp = NewRecorder() - // Get a session. - if session, err = store.Get(req, "session-key"); err != nil { - t.Fatalf("Error getting session: %v", err) - } - // Check all saved values. - flashes = session.Flashes() - if len(flashes) != 2 { - t.Fatalf("Expected flashes; Got %v", flashes) - } - if flashes[0] != "foo" || flashes[1] != "bar" { - t.Errorf("Expected foo,bar; Got %v", flashes) - } - flashes = session.Flashes() - if len(flashes) != 0 { - t.Errorf("Expected dumped flashes; Got %v", flashes) - } - // Custom key. - flashes = session.Flashes("custom_key") - if len(flashes) != 1 { - t.Errorf("Expected flashes; Got %v", flashes) - } else if flashes[0] != "baz" { - t.Errorf("Expected baz; Got %v", flashes) - } - flashes = session.Flashes("custom_key") - if len(flashes) != 0 { - t.Errorf("Expected dumped flashes; Got %v", flashes) - } - - // Round 3 ---------------------------------------------------------------- - // Custom type - - req, _ = http.NewRequest("GET", "http://localhost:8080/", nil) - rsp = NewRecorder() - // Get a session. - if session, err = store.Get(req, "session-key"); err != nil { - t.Fatalf("Error getting session: %v", err) - } - // Get a flash. - flashes = session.Flashes() - if len(flashes) != 0 { - t.Errorf("Expected empty flashes; Got %v", flashes) - } - // Add some flashes. - session.AddFlash(&FlashMessage{42, "foo"}) - // Save. - if err = Save(req, rsp); err != nil { - t.Fatalf("Error saving session: %v", err) - } - hdr = rsp.Header() - cookies, ok = hdr["Set-Cookie"] - if !ok || len(cookies) != 1 { - t.Fatal("No cookies. Header:", hdr) - } - - // Round 4 ---------------------------------------------------------------- - // Custom type - - req, _ = http.NewRequest("GET", "http://localhost:8080/", nil) - req.Header.Add("Cookie", cookies[0]) - rsp = NewRecorder() - // Get a session. - if session, err = store.Get(req, "session-key"); err != nil { - t.Fatalf("Error getting session: %v", err) - } - // Check all saved values. - flashes = session.Flashes() - if len(flashes) != 1 { - t.Fatalf("Expected flashes; Got %v", flashes) - } - custom := flashes[0].(FlashMessage) - if custom.Type != 42 || custom.Message != "foo" { - t.Errorf("Expected %#v, got %#v", FlashMessage{42, "foo"}, custom) - } -} - -func init() { - gob.Register(FlashMessage{}) -} diff --git a/vendor/github.com/gorilla/sessions/store_test.go b/vendor/github.com/gorilla/sessions/store_test.go deleted file mode 100644 index 3561e5d1..00000000 --- a/vendor/github.com/gorilla/sessions/store_test.go +++ /dev/null @@ -1,129 +0,0 @@ -package sessions - -import ( - "encoding/base64" - "net/http" - "net/http/httptest" - "testing" -) - -// Test for GH-8 for CookieStore -func TestGH8CookieStore(t *testing.T) { - originalPath := "/" - store := NewCookieStore() - store.Options.Path = originalPath - req, err := http.NewRequest("GET", "http://www.example.com", nil) - if err != nil { - t.Fatal("failed to create request", err) - } - - session, err := store.New(req, "hello") - if err != nil { - t.Fatal("failed to create session", err) - } - - store.Options.Path = "/foo" - if session.Options.Path != originalPath { - t.Fatalf("bad session path: got %q, want %q", session.Options.Path, originalPath) - } -} - -// Test for GH-8 for FilesystemStore -func TestGH8FilesystemStore(t *testing.T) { - originalPath := "/" - store := NewFilesystemStore("") - store.Options.Path = originalPath - req, err := http.NewRequest("GET", "http://www.example.com", nil) - if err != nil { - t.Fatal("failed to create request", err) - } - - session, err := store.New(req, "hello") - if err != nil { - t.Fatal("failed to create session", err) - } - - store.Options.Path = "/foo" - if session.Options.Path != originalPath { - t.Fatalf("bad session path: got %q, want %q", session.Options.Path, originalPath) - } -} - -// Test for GH-2. -func TestGH2MaxLength(t *testing.T) { - store := NewFilesystemStore("", []byte("some key")) - req, err := http.NewRequest("GET", "http://www.example.com", nil) - if err != nil { - t.Fatal("failed to create request", err) - } - w := httptest.NewRecorder() - - session, err := store.New(req, "my session") - if err != nil { - t.Fatal("failed to create session", err) - } - - session.Values["big"] = make([]byte, base64.StdEncoding.DecodedLen(4096*2)) - err = session.Save(req, w) - if err == nil { - t.Fatal("expected an error, got nil") - } - - store.MaxLength(4096 * 3) // A bit more than the value size to account for encoding overhead. - err = session.Save(req, w) - if err != nil { - t.Fatal("failed to Save:", err) - } -} - -// Test delete filesystem store with max-age: -1 -func TestGH8FilesystemStoreDelete(t *testing.T) { - store := NewFilesystemStore("", []byte("some key")) - req, err := http.NewRequest("GET", "http://www.example.com", nil) - if err != nil { - t.Fatal("failed to create request", err) - } - w := httptest.NewRecorder() - - session, err := store.New(req, "hello") - if err != nil { - t.Fatal("failed to create session", err) - } - - err = session.Save(req, w) - if err != nil { - t.Fatal("failed to save session", err) - } - - session.Options.MaxAge = -1 - err = session.Save(req, w) - if err != nil { - t.Fatal("failed to delete session", err) - } -} - -// Test delete filesystem store with max-age: 0 -func TestGH8FilesystemStoreDelete2(t *testing.T) { - store := NewFilesystemStore("", []byte("some key")) - req, err := http.NewRequest("GET", "http://www.example.com", nil) - if err != nil { - t.Fatal("failed to create request", err) - } - w := httptest.NewRecorder() - - session, err := store.New(req, "hello") - if err != nil { - t.Fatal("failed to create session", err) - } - - err = session.Save(req, w) - if err != nil { - t.Fatal("failed to save session", err) - } - - session.Options.MaxAge = 0 - err = session.Save(req, w) - if err != nil { - t.Fatal("failed to delete session", err) - } -} diff --git a/vendor/github.com/hashicorp/logutils/level_benchmark_test.go b/vendor/github.com/hashicorp/logutils/level_benchmark_test.go deleted file mode 100644 index 3c2caf70..00000000 --- a/vendor/github.com/hashicorp/logutils/level_benchmark_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package logutils - -import ( - "io/ioutil" - "testing" -) - -var messages [][]byte - -func init() { - messages = [][]byte{ - []byte("[TRACE] foo"), - []byte("[DEBUG] foo"), - []byte("[INFO] foo"), - []byte("[WARN] foo"), - []byte("[ERROR] foo"), - } -} - -func BenchmarkDiscard(b *testing.B) { - for i := 0; i < b.N; i++ { - ioutil.Discard.Write(messages[i%len(messages)]) - } -} - -func BenchmarkLevelFilter(b *testing.B) { - filter := &LevelFilter{ - Levels: []LogLevel{"TRACE", "DEBUG", "INFO", "WARN", "ERROR"}, - MinLevel: "WARN", - Writer: ioutil.Discard, - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - filter.Write(messages[i%len(messages)]) - } -} diff --git a/vendor/github.com/hashicorp/logutils/level_test.go b/vendor/github.com/hashicorp/logutils/level_test.go deleted file mode 100644 index f6b6ac3c..00000000 --- a/vendor/github.com/hashicorp/logutils/level_test.go +++ /dev/null @@ -1,94 +0,0 @@ -package logutils - -import ( - "bytes" - "io" - "log" - "testing" -) - -func TestLevelFilter_impl(t *testing.T) { - var _ io.Writer = new(LevelFilter) -} - -func TestLevelFilter(t *testing.T) { - buf := new(bytes.Buffer) - filter := &LevelFilter{ - Levels: []LogLevel{"DEBUG", "WARN", "ERROR"}, - MinLevel: "WARN", - Writer: buf, - } - - logger := log.New(filter, "", 0) - logger.Print("[WARN] foo") - logger.Println("[ERROR] bar") - logger.Println("[DEBUG] baz") - logger.Println("[WARN] buzz") - - result := buf.String() - expected := "[WARN] foo\n[ERROR] bar\n[WARN] buzz\n" - if result != expected { - t.Fatalf("bad: %#v", result) - } -} - -func TestLevelFilterCheck(t *testing.T) { - filter := &LevelFilter{ - Levels: []LogLevel{"DEBUG", "WARN", "ERROR"}, - MinLevel: "WARN", - Writer: nil, - } - - testCases := []struct { - line string - check bool - }{ - {"[WARN] foo\n", true}, - {"[ERROR] bar\n", true}, - {"[DEBUG] baz\n", false}, - {"[WARN] buzz\n", true}, - } - - for _, testCase := range testCases { - result := filter.Check([]byte(testCase.line)) - if result != testCase.check { - t.Errorf("Fail: %s", testCase.line) - } - } -} - -func TestLevelFilter_SetMinLevel(t *testing.T) { - filter := &LevelFilter{ - Levels: []LogLevel{"DEBUG", "WARN", "ERROR"}, - MinLevel: "ERROR", - Writer: nil, - } - - testCases := []struct { - line string - checkBefore bool - checkAfter bool - }{ - {"[WARN] foo\n", false, true}, - {"[ERROR] bar\n", true, true}, - {"[DEBUG] baz\n", false, false}, - {"[WARN] buzz\n", false, true}, - } - - for _, testCase := range testCases { - result := filter.Check([]byte(testCase.line)) - if result != testCase.checkBefore { - t.Errorf("Fail: %s", testCase.line) - } - } - - // Update the minimum level to WARN - filter.SetMinLevel("WARN") - - for _, testCase := range testCases { - result := filter.Check([]byte(testCase.line)) - if result != testCase.checkAfter { - t.Errorf("Fail: %s", testCase.line) - } - } -} diff --git a/vendor/github.com/jessevdk/go-flags/.travis.yml b/vendor/github.com/jessevdk/go-flags/.travis.yml index c47256eb..e7c4be05 100644 --- a/vendor/github.com/jessevdk/go-flags/.travis.yml +++ b/vendor/github.com/jessevdk/go-flags/.travis.yml @@ -1,7 +1,8 @@ language: go go: - - 1.6 + - 1.6.x + - 1.7.x install: # go-flags diff --git a/vendor/github.com/jessevdk/go-flags/arg.go b/vendor/github.com/jessevdk/go-flags/arg.go index d1606440..8ec62048 100644 --- a/vendor/github.com/jessevdk/go-flags/arg.go +++ b/vendor/github.com/jessevdk/go-flags/arg.go @@ -12,9 +12,12 @@ type Arg struct { // A description of the positional argument (used in the help) Description string - // Whether a positional argument is required + // The minimal number of required positional arguments Required int + // The maximum number of required positional arguments + RequiredMaximum int + value reflect.Value tag multiTag } diff --git a/vendor/github.com/jessevdk/go-flags/arg_test.go b/vendor/github.com/jessevdk/go-flags/arg_test.go deleted file mode 100644 index 117e90ec..00000000 --- a/vendor/github.com/jessevdk/go-flags/arg_test.go +++ /dev/null @@ -1,133 +0,0 @@ -package flags - -import ( - "testing" -) - -func TestPositional(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Positional struct { - Command int - Filename string - Rest []string - } `positional-args:"yes" required:"yes"` - }{} - - p := NewParser(&opts, Default) - ret, err := p.ParseArgs([]string{"10", "arg_test.go", "a", "b"}) - - if err != nil { - t.Fatalf("Unexpected error: %v", err) - return - } - - if opts.Positional.Command != 10 { - t.Fatalf("Expected opts.Positional.Command to be 10, but got %v", opts.Positional.Command) - } - - if opts.Positional.Filename != "arg_test.go" { - t.Fatalf("Expected opts.Positional.Filename to be \"arg_test.go\", but got %v", opts.Positional.Filename) - } - - assertStringArray(t, opts.Positional.Rest, []string{"a", "b"}) - assertStringArray(t, ret, []string{}) -} - -func TestPositionalRequired(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Positional struct { - Command int - Filename string - Rest []string - } `positional-args:"yes" required:"yes"` - }{} - - p := NewParser(&opts, None) - _, err := p.ParseArgs([]string{"10"}) - - assertError(t, err, ErrRequired, "the required argument `Filename` was not provided") -} - -func TestPositionalRequiredRest1Fail(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Positional struct { - Rest []string `required:"yes"` - } `positional-args:"yes"` - }{} - - p := NewParser(&opts, None) - _, err := p.ParseArgs([]string{}) - - assertError(t, err, ErrRequired, "the required argument `Rest (at least 1 argument)` was not provided") -} - -func TestPositionalRequiredRest1Pass(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Positional struct { - Rest []string `required:"yes"` - } `positional-args:"yes"` - }{} - - p := NewParser(&opts, None) - _, err := p.ParseArgs([]string{"rest1"}) - - if err != nil { - t.Fatalf("Unexpected error: %v", err) - return - } - - if len(opts.Positional.Rest) != 1 { - t.Fatalf("Expected 1 positional rest argument") - } - - assertString(t, opts.Positional.Rest[0], "rest1") -} - -func TestPositionalRequiredRest2Fail(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Positional struct { - Rest []string `required:"2"` - } `positional-args:"yes"` - }{} - - p := NewParser(&opts, None) - _, err := p.ParseArgs([]string{"rest1"}) - - assertError(t, err, ErrRequired, "the required argument `Rest (at least 2 arguments, but got only 1)` was not provided") -} - -func TestPositionalRequiredRest2Pass(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Positional struct { - Rest []string `required:"2"` - } `positional-args:"yes"` - }{} - - p := NewParser(&opts, None) - _, err := p.ParseArgs([]string{"rest1", "rest2", "rest3"}) - - if err != nil { - t.Fatalf("Unexpected error: %v", err) - return - } - - if len(opts.Positional.Rest) != 3 { - t.Fatalf("Expected 3 positional rest argument") - } - - assertString(t, opts.Positional.Rest[0], "rest1") - assertString(t, opts.Positional.Rest[1], "rest2") - assertString(t, opts.Positional.Rest[2], "rest3") -} diff --git a/vendor/github.com/jessevdk/go-flags/assert_test.go b/vendor/github.com/jessevdk/go-flags/assert_test.go deleted file mode 100644 index 8e06636b..00000000 --- a/vendor/github.com/jessevdk/go-flags/assert_test.go +++ /dev/null @@ -1,177 +0,0 @@ -package flags - -import ( - "fmt" - "io" - "io/ioutil" - "os" - "os/exec" - "path" - "runtime" - "testing" -) - -func assertCallerInfo() (string, int) { - ptr := make([]uintptr, 15) - n := runtime.Callers(1, ptr) - - if n == 0 { - return "", 0 - } - - mef := runtime.FuncForPC(ptr[0]) - mefile, meline := mef.FileLine(ptr[0]) - - for i := 2; i < n; i++ { - f := runtime.FuncForPC(ptr[i]) - file, line := f.FileLine(ptr[i]) - - if file != mefile { - return file, line - } - } - - return mefile, meline -} - -func assertErrorf(t *testing.T, format string, args ...interface{}) { - msg := fmt.Sprintf(format, args...) - - file, line := assertCallerInfo() - - t.Errorf("%s:%d: %s", path.Base(file), line, msg) -} - -func assertFatalf(t *testing.T, format string, args ...interface{}) { - msg := fmt.Sprintf(format, args...) - - file, line := assertCallerInfo() - - t.Fatalf("%s:%d: %s", path.Base(file), line, msg) -} - -func assertString(t *testing.T, a string, b string) { - if a != b { - assertErrorf(t, "Expected %#v, but got %#v", b, a) - } -} - -func assertStringArray(t *testing.T, a []string, b []string) { - if len(a) != len(b) { - assertErrorf(t, "Expected %#v, but got %#v", b, a) - return - } - - for i, v := range a { - if b[i] != v { - assertErrorf(t, "Expected %#v, but got %#v", b, a) - return - } - } -} - -func assertBoolArray(t *testing.T, a []bool, b []bool) { - if len(a) != len(b) { - assertErrorf(t, "Expected %#v, but got %#v", b, a) - return - } - - for i, v := range a { - if b[i] != v { - assertErrorf(t, "Expected %#v, but got %#v", b, a) - return - } - } -} - -func assertParserSuccess(t *testing.T, data interface{}, args ...string) (*Parser, []string) { - parser := NewParser(data, Default&^PrintErrors) - ret, err := parser.ParseArgs(args) - - if err != nil { - t.Fatalf("Unexpected parse error: %s", err) - return nil, nil - } - - return parser, ret -} - -func assertParseSuccess(t *testing.T, data interface{}, args ...string) []string { - _, ret := assertParserSuccess(t, data, args...) - return ret -} - -func assertError(t *testing.T, err error, typ ErrorType, msg string) { - if err == nil { - assertFatalf(t, "Expected error: %s", msg) - return - } - - if e, ok := err.(*Error); !ok { - assertFatalf(t, "Expected Error type, but got %#v", err) - } else { - if e.Type != typ { - assertErrorf(t, "Expected error type {%s}, but got {%s}", typ, e.Type) - } - - if e.Message != msg { - assertErrorf(t, "Expected error message %#v, but got %#v", msg, e.Message) - } - } -} - -func assertParseFail(t *testing.T, typ ErrorType, msg string, data interface{}, args ...string) []string { - parser := NewParser(data, Default&^PrintErrors) - ret, err := parser.ParseArgs(args) - - assertError(t, err, typ, msg) - return ret -} - -func diff(a, b string) (string, error) { - atmp, err := ioutil.TempFile("", "help-diff") - - if err != nil { - return "", err - } - - btmp, err := ioutil.TempFile("", "help-diff") - - if err != nil { - return "", err - } - - if _, err := io.WriteString(atmp, a); err != nil { - return "", err - } - - if _, err := io.WriteString(btmp, b); err != nil { - return "", err - } - - ret, err := exec.Command("diff", "-u", "-d", "--label", "got", atmp.Name(), "--label", "expected", btmp.Name()).Output() - - os.Remove(atmp.Name()) - os.Remove(btmp.Name()) - - if err.Error() == "exit status 1" { - return string(ret), nil - } - - return string(ret), err -} - -func assertDiff(t *testing.T, actual, expected, msg string) { - if actual == expected { - return - } - - ret, err := diff(actual, expected) - - if err != nil { - assertErrorf(t, "Unexpected diff error: %s", err) - assertErrorf(t, "Unexpected %s, expected:\n\n%s\n\nbut got\n\n%s", msg, expected, actual) - } else { - assertErrorf(t, "Unexpected %s:\n\n%s", msg, ret) - } -} diff --git a/vendor/github.com/jessevdk/go-flags/command.go b/vendor/github.com/jessevdk/go-flags/command.go index aab34e6e..26628436 100644 --- a/vendor/github.com/jessevdk/go-flags/command.go +++ b/vendor/github.com/jessevdk/go-flags/command.go @@ -181,22 +181,36 @@ func (c *Command) scanSubcommandHandler(parentg *Group) scanHandler { name = field.Name } - var required int + required := -1 + requiredMaximum := -1 sreq := m.Get("required") if sreq != "" { required = 1 - if preq, err := strconv.ParseInt(sreq, 10, 32); err == nil { - required = int(preq) + rng := strings.SplitN(sreq, "-", 2) + + if len(rng) > 1 { + if preq, err := strconv.ParseInt(rng[0], 10, 32); err == nil { + required = int(preq) + } + + if preq, err := strconv.ParseInt(rng[1], 10, 32); err == nil { + requiredMaximum = int(preq) + } + } else { + if preq, err := strconv.ParseInt(sreq, 10, 32); err == nil { + required = int(preq) + } } } arg := &Arg{ - Name: name, - Description: m.Get("description"), - Required: required, + Name: name, + Description: m.Get("description"), + Required: required, + RequiredMaximum: requiredMaximum, value: realval.Field(i), tag: m, diff --git a/vendor/github.com/jessevdk/go-flags/command_test.go b/vendor/github.com/jessevdk/go-flags/command_test.go deleted file mode 100644 index dc04b66c..00000000 --- a/vendor/github.com/jessevdk/go-flags/command_test.go +++ /dev/null @@ -1,582 +0,0 @@ -package flags - -import ( - "fmt" - "testing" -) - -func TestCommandInline(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Command struct { - G bool `short:"g"` - } `command:"cmd"` - }{} - - p, ret := assertParserSuccess(t, &opts, "-v", "cmd", "-g") - - assertStringArray(t, ret, []string{}) - - if p.Active == nil { - t.Errorf("Expected active command") - } - - if !opts.Value { - t.Errorf("Expected Value to be true") - } - - if !opts.Command.G { - t.Errorf("Expected Command.G to be true") - } - - if p.Command.Find("cmd") != p.Active { - t.Errorf("Expected to find command `cmd' to be active") - } -} - -func TestCommandInlineMulti(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - C1 struct { - } `command:"c1"` - - C2 struct { - G bool `short:"g"` - } `command:"c2"` - }{} - - p, ret := assertParserSuccess(t, &opts, "-v", "c2", "-g") - - assertStringArray(t, ret, []string{}) - - if p.Active == nil { - t.Errorf("Expected active command") - } - - if !opts.Value { - t.Errorf("Expected Value to be true") - } - - if !opts.C2.G { - t.Errorf("Expected C2.G to be true") - } - - if p.Command.Find("c1") == nil { - t.Errorf("Expected to find command `c1'") - } - - if c2 := p.Command.Find("c2"); c2 == nil { - t.Errorf("Expected to find command `c2'") - } else if c2 != p.Active { - t.Errorf("Expected to find command `c2' to be active") - } -} - -func TestCommandFlagOrder1(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Command struct { - G bool `short:"g"` - } `command:"cmd"` - }{} - - assertParseFail(t, ErrUnknownFlag, "unknown flag `g'", &opts, "-v", "-g", "cmd") -} - -func TestCommandFlagOrder2(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Command struct { - G bool `short:"g"` - } `command:"cmd"` - }{} - - assertParseSuccess(t, &opts, "cmd", "-v", "-g") - - if !opts.Value { - t.Errorf("Expected Value to be true") - } - - if !opts.Command.G { - t.Errorf("Expected Command.G to be true") - } -} - -func TestCommandFlagOrderSub(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Command struct { - G bool `short:"g"` - - SubCommand struct { - B bool `short:"b"` - } `command:"sub"` - } `command:"cmd"` - }{} - - assertParseSuccess(t, &opts, "cmd", "sub", "-v", "-g", "-b") - - if !opts.Value { - t.Errorf("Expected Value to be true") - } - - if !opts.Command.G { - t.Errorf("Expected Command.G to be true") - } - - if !opts.Command.SubCommand.B { - t.Errorf("Expected Command.SubCommand.B to be true") - } -} - -func TestCommandFlagOverride1(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Command struct { - Value bool `short:"v"` - } `command:"cmd"` - }{} - - assertParseSuccess(t, &opts, "-v", "cmd") - - if !opts.Value { - t.Errorf("Expected Value to be true") - } - - if opts.Command.Value { - t.Errorf("Expected Command.Value to be false") - } -} - -func TestCommandFlagOverride2(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Command struct { - Value bool `short:"v"` - } `command:"cmd"` - }{} - - assertParseSuccess(t, &opts, "cmd", "-v") - - if opts.Value { - t.Errorf("Expected Value to be false") - } - - if !opts.Command.Value { - t.Errorf("Expected Command.Value to be true") - } -} - -func TestCommandFlagOverrideSub(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Command struct { - Value bool `short:"v"` - - SubCommand struct { - Value bool `short:"v"` - } `command:"sub"` - } `command:"cmd"` - }{} - - assertParseSuccess(t, &opts, "cmd", "sub", "-v") - - if opts.Value { - t.Errorf("Expected Value to be false") - } - - if opts.Command.Value { - t.Errorf("Expected Command.Value to be false") - } - - if !opts.Command.SubCommand.Value { - t.Errorf("Expected Command.Value to be true") - } -} - -func TestCommandFlagOverrideSub2(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Command struct { - Value bool `short:"v"` - - SubCommand struct { - G bool `short:"g"` - } `command:"sub"` - } `command:"cmd"` - }{} - - assertParseSuccess(t, &opts, "cmd", "sub", "-v") - - if opts.Value { - t.Errorf("Expected Value to be false") - } - - if !opts.Command.Value { - t.Errorf("Expected Command.Value to be true") - } -} - -func TestCommandEstimate(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Cmd1 struct { - } `command:"remove"` - - Cmd2 struct { - } `command:"add"` - }{} - - p := NewParser(&opts, None) - _, err := p.ParseArgs([]string{}) - - assertError(t, err, ErrCommandRequired, "Please specify one command of: add or remove") -} - -func TestCommandEstimate2(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Cmd1 struct { - } `command:"remove"` - - Cmd2 struct { - } `command:"add"` - }{} - - p := NewParser(&opts, None) - _, err := p.ParseArgs([]string{"rmive"}) - - assertError(t, err, ErrUnknownCommand, "Unknown command `rmive', did you mean `remove'?") -} - -type testCommand struct { - G bool `short:"g"` - Executed bool - EArgs []string -} - -func (c *testCommand) Execute(args []string) error { - c.Executed = true - c.EArgs = args - - return nil -} - -func TestCommandExecute(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Command testCommand `command:"cmd"` - }{} - - assertParseSuccess(t, &opts, "-v", "cmd", "-g", "a", "b") - - if !opts.Value { - t.Errorf("Expected Value to be true") - } - - if !opts.Command.Executed { - t.Errorf("Did not execute command") - } - - if !opts.Command.G { - t.Errorf("Expected Command.C to be true") - } - - assertStringArray(t, opts.Command.EArgs, []string{"a", "b"}) -} - -func TestCommandClosest(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Cmd1 struct { - } `command:"remove"` - - Cmd2 struct { - } `command:"add"` - }{} - - args := assertParseFail(t, ErrUnknownCommand, "Unknown command `addd', did you mean `add'?", &opts, "-v", "addd") - - assertStringArray(t, args, []string{"addd"}) -} - -func TestCommandAdd(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - }{} - - var cmd = struct { - G bool `short:"g"` - }{} - - p := NewParser(&opts, Default) - c, err := p.AddCommand("cmd", "", "", &cmd) - - if err != nil { - t.Fatalf("Unexpected error: %v", err) - return - } - - ret, err := p.ParseArgs([]string{"-v", "cmd", "-g", "rest"}) - - if err != nil { - t.Fatalf("Unexpected error: %v", err) - return - } - - assertStringArray(t, ret, []string{"rest"}) - - if !opts.Value { - t.Errorf("Expected Value to be true") - } - - if !cmd.G { - t.Errorf("Expected Command.G to be true") - } - - if p.Command.Find("cmd") != c { - t.Errorf("Expected to find command `cmd'") - } - - if p.Commands()[0] != c { - t.Errorf("Expected command %#v, but got %#v", c, p.Commands()[0]) - } - - if c.Options()[0].ShortName != 'g' { - t.Errorf("Expected short name `g' but got %v", c.Options()[0].ShortName) - } -} - -func TestCommandNestedInline(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Command struct { - G bool `short:"g"` - - Nested struct { - N string `long:"n"` - } `command:"nested"` - } `command:"cmd"` - }{} - - p, ret := assertParserSuccess(t, &opts, "-v", "cmd", "-g", "nested", "--n", "n", "rest") - - assertStringArray(t, ret, []string{"rest"}) - - if !opts.Value { - t.Errorf("Expected Value to be true") - } - - if !opts.Command.G { - t.Errorf("Expected Command.G to be true") - } - - assertString(t, opts.Command.Nested.N, "n") - - if c := p.Command.Find("cmd"); c == nil { - t.Errorf("Expected to find command `cmd'") - } else { - if c != p.Active { - t.Errorf("Expected `cmd' to be the active parser command") - } - - if nested := c.Find("nested"); nested == nil { - t.Errorf("Expected to find command `nested'") - } else if nested != c.Active { - t.Errorf("Expected to find command `nested' to be the active `cmd' command") - } - } -} - -func TestRequiredOnCommand(t *testing.T) { - var opts = struct { - Value bool `short:"v" required:"true"` - - Command struct { - G bool `short:"g"` - } `command:"cmd"` - }{} - - assertParseFail(t, ErrRequired, fmt.Sprintf("the required flag `%cv' was not specified", defaultShortOptDelimiter), &opts, "cmd") -} - -func TestRequiredAllOnCommand(t *testing.T) { - var opts = struct { - Value bool `short:"v" required:"true"` - Missing bool `long:"missing" required:"true"` - - Command struct { - G bool `short:"g"` - } `command:"cmd"` - }{} - - assertParseFail(t, ErrRequired, fmt.Sprintf("the required flags `%smissing' and `%cv' were not specified", defaultLongOptDelimiter, defaultShortOptDelimiter), &opts, "cmd") -} - -func TestDefaultOnCommand(t *testing.T) { - var opts = struct { - Command struct { - G string `short:"g" default:"value"` - } `command:"cmd"` - }{} - - assertParseSuccess(t, &opts, "cmd") - - if opts.Command.G != "value" { - t.Errorf("Expected G to be \"value\"") - } -} - -func TestAfterNonCommand(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Cmd1 struct { - } `command:"remove"` - - Cmd2 struct { - } `command:"add"` - }{} - - assertParseFail(t, ErrUnknownCommand, "Unknown command `nocmd'. Please specify one command of: add or remove", &opts, "nocmd", "remove") -} - -func TestSubcommandsOptional(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Cmd1 struct { - } `command:"remove"` - - Cmd2 struct { - } `command:"add"` - }{} - - p := NewParser(&opts, None) - p.SubcommandsOptional = true - - _, err := p.ParseArgs([]string{"-v"}) - - if err != nil { - t.Fatalf("Unexpected error: %v", err) - return - } - - if !opts.Value { - t.Errorf("Expected Value to be true") - } -} - -func TestSubcommandsOptionalAfterNonCommand(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Cmd1 struct { - } `command:"remove"` - - Cmd2 struct { - } `command:"add"` - }{} - - p := NewParser(&opts, None) - p.SubcommandsOptional = true - - retargs, err := p.ParseArgs([]string{"nocmd", "remove"}) - - if err != nil { - t.Fatalf("Unexpected error: %v", err) - return - } - - assertStringArray(t, retargs, []string{"nocmd", "remove"}) -} - -func TestCommandAlias(t *testing.T) { - var opts = struct { - Command struct { - G string `short:"g" default:"value"` - } `command:"cmd" alias:"cm"` - }{} - - assertParseSuccess(t, &opts, "cm") - - if opts.Command.G != "value" { - t.Errorf("Expected G to be \"value\"") - } -} - -func TestSubCommandFindOptionByLongFlag(t *testing.T) { - var opts struct { - Testing bool `long:"testing" description:"Testing"` - } - - var cmd struct { - Other bool `long:"other" description:"Other"` - } - - p := NewParser(&opts, Default) - c, _ := p.AddCommand("command", "Short", "Long", &cmd) - - opt := c.FindOptionByLongName("other") - - if opt == nil { - t.Errorf("Expected option, but found none") - } - - assertString(t, opt.LongName, "other") - - opt = c.FindOptionByLongName("testing") - - if opt == nil { - t.Errorf("Expected option, but found none") - } - - assertString(t, opt.LongName, "testing") -} - -func TestSubCommandFindOptionByShortFlag(t *testing.T) { - var opts struct { - Testing bool `short:"t" description:"Testing"` - } - - var cmd struct { - Other bool `short:"o" description:"Other"` - } - - p := NewParser(&opts, Default) - c, _ := p.AddCommand("command", "Short", "Long", &cmd) - - opt := c.FindOptionByShortName('o') - - if opt == nil { - t.Errorf("Expected option, but found none") - } - - if opt.ShortName != 'o' { - t.Errorf("Expected 'o', but got %v", opt.ShortName) - } - - opt = c.FindOptionByShortName('t') - - if opt == nil { - t.Errorf("Expected option, but found none") - } - - if opt.ShortName != 't' { - t.Errorf("Expected 'o', but got %v", opt.ShortName) - } -} diff --git a/vendor/github.com/jessevdk/go-flags/completion.go b/vendor/github.com/jessevdk/go-flags/completion.go index 708fa9e9..7a7a08b9 100644 --- a/vendor/github.com/jessevdk/go-flags/completion.go +++ b/vendor/github.com/jessevdk/go-flags/completion.go @@ -73,27 +73,8 @@ func (c *completion) skipPositional(s *parseState, n int) { } } -func (c *completion) completeOptionNames(names map[string]*Option, prefix string, match string) []Completion { - n := make([]Completion, 0, len(names)) - - for k, opt := range names { - if strings.HasPrefix(k, match) && !opt.Hidden { - n = append(n, Completion{ - Item: prefix + k, - Description: opt.Description, - }) - } - } - - return n -} - -func (c *completion) completeLongNames(s *parseState, prefix string, match string) []Completion { - return c.completeOptionNames(s.lookup.longNames, prefix, match) -} - -func (c *completion) completeShortNames(s *parseState, prefix string, match string) []Completion { - if len(match) != 0 { +func (c *completion) completeOptionNames(s *parseState, prefix string, match string, short bool) []Completion { + if short && len(match) != 0 { return []Completion{ Completion{ Item: prefix + match, @@ -101,7 +82,42 @@ func (c *completion) completeShortNames(s *parseState, prefix string, match stri } } - return c.completeOptionNames(s.lookup.shortNames, prefix, match) + var results []Completion + repeats := map[string]bool{} + + for name, opt := range s.lookup.longNames { + if strings.HasPrefix(name, match) && !opt.Hidden { + results = append(results, Completion{ + Item: defaultLongOptDelimiter + name, + Description: opt.Description, + }) + + if short { + repeats[string(opt.ShortName)] = true + } + } + } + + if short { + for name, opt := range s.lookup.shortNames { + if _, exist := repeats[name]; !exist && strings.HasPrefix(name, match) && !opt.Hidden { + results = append(results, Completion{ + Item: string(defaultShortOptDelimiter) + name, + Description: opt.Description, + }) + } + } + } + + return results +} + +func (c *completion) completeNamesForLongPrefix(s *parseState, prefix string, match string) []Completion { + return c.completeOptionNames(s, prefix, match, false) +} + +func (c *completion) completeNamesForShortPrefix(s *parseState, prefix string, match string) []Completion { + return c.completeOptionNames(s, prefix, match, true) } func (c *completion) completeCommands(s *parseState, match string) []Completion { @@ -120,6 +136,9 @@ func (c *completion) completeCommands(s *parseState, match string) []Completion } func (c *completion) completeValue(value reflect.Value, prefix string, match string) []Completion { + if value.Kind() == reflect.Slice { + value = reflect.New(value.Type().Elem()) + } i := value.Interface() var ret []Completion @@ -139,16 +158,6 @@ func (c *completion) completeValue(value reflect.Value, prefix string, match str return ret } -func (c *completion) completeArg(arg *Arg, prefix string, match string) []Completion { - if arg.isRemaining() { - // For remaining positional args (that are parsed into a slice), complete - // based on the element type. - return c.completeValue(reflect.New(arg.value.Type().Elem()), prefix, match) - } - - return c.completeValue(arg.value, prefix, match) -} - func (c *completion) complete(args []string) []Completion { if len(args) == 0 { args = []string{""} @@ -244,7 +253,7 @@ func (c *completion) complete(args []string) []Completion { if opt := s.lookup.shortNames[sname]; opt != nil && opt.canArgument() { ret = c.completeValue(opt.value, prefix+sname, optname[n:]) } else { - ret = c.completeShortNames(s, prefix, optname) + ret = c.completeNamesForShortPrefix(s, prefix, optname) } } else if argument != nil { if islong { @@ -257,13 +266,13 @@ func (c *completion) complete(args []string) []Completion { ret = c.completeValue(opt.value, prefix+optname+split, *argument) } } else if islong { - ret = c.completeLongNames(s, prefix, optname) + ret = c.completeNamesForLongPrefix(s, prefix, optname) } else { - ret = c.completeShortNames(s, prefix, optname) + ret = c.completeNamesForShortPrefix(s, prefix, optname) } } else if len(s.positional) > 0 { // Complete for positional argument - ret = c.completeArg(s.positional[0], "", lastarg) + ret = c.completeValue(s.positional[0].value, "", lastarg) } else if len(s.command.commands) > 0 { // Complete for command ret = c.completeCommands(s, lastarg) diff --git a/vendor/github.com/jessevdk/go-flags/completion_test.go b/vendor/github.com/jessevdk/go-flags/completion_test.go deleted file mode 100644 index 72ee1580..00000000 --- a/vendor/github.com/jessevdk/go-flags/completion_test.go +++ /dev/null @@ -1,295 +0,0 @@ -package flags - -import ( - "bytes" - "io" - "os" - "path" - "path/filepath" - "reflect" - "runtime" - "strings" - "testing" -) - -type TestComplete struct { -} - -func (t *TestComplete) Complete(match string) []Completion { - options := []string{ - "hello world", - "hello universe", - "hello multiverse", - } - - ret := make([]Completion, 0, len(options)) - - for _, o := range options { - if strings.HasPrefix(o, match) { - ret = append(ret, Completion{ - Item: o, - }) - } - } - - return ret -} - -var completionTestOptions struct { - Verbose bool `short:"v" long:"verbose" description:"Verbose messages"` - Debug bool `short:"d" long:"debug" description:"Enable debug"` - Version bool `long:"version" description:"Show version"` - Required bool `long:"required" required:"true" description:"This is required"` - Hidden bool `long:"hidden" hidden:"true" description:"This is hidden"` - - AddCommand struct { - Positional struct { - Filename Filename - } `positional-args:"yes"` - } `command:"add" description:"add an item"` - - AddMultiCommand struct { - Positional struct { - Filename []Filename - } `positional-args:"yes"` - } `command:"add-multi" description:"add multiple items"` - - RemoveCommand struct { - Other bool `short:"o"` - File Filename `short:"f" long:"filename"` - } `command:"rm" description:"remove an item"` - - RenameCommand struct { - Completed TestComplete `short:"c" long:"completed"` - } `command:"rename" description:"rename an item"` -} - -type completionTest struct { - Args []string - Completed []string - ShowDescriptions bool -} - -var completionTests []completionTest - -func init() { - _, sourcefile, _, _ := runtime.Caller(0) - completionTestSourcedir := filepath.Join(filepath.SplitList(path.Dir(sourcefile))...) - - completionTestFilename := []string{filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion_test.go")} - - completionTests = []completionTest{ - { - // Short names - []string{"-"}, - []string{"-d", "-v"}, - false, - }, - - { - // Short names concatenated - []string{"-dv"}, - []string{"-dv"}, - false, - }, - - { - // Long names - []string{"--"}, - []string{"--debug", "--required", "--verbose", "--version"}, - false, - }, - - { - // Long names with descriptions - []string{"--"}, - []string{ - "--debug # Enable debug", - "--required # This is required", - "--verbose # Verbose messages", - "--version # Show version", - }, - true, - }, - - { - // Long names partial - []string{"--ver"}, - []string{"--verbose", "--version"}, - false, - }, - - { - // Commands - []string{""}, - []string{"add", "add-multi", "rename", "rm"}, - false, - }, - - { - // Commands with descriptions - []string{""}, - []string{ - "add # add an item", - "add-multi # add multiple items", - "rename # rename an item", - "rm # remove an item", - }, - true, - }, - - { - // Commands partial - []string{"r"}, - []string{"rename", "rm"}, - false, - }, - - { - // Positional filename - []string{"add", filepath.Join(completionTestSourcedir, "completion")}, - completionTestFilename, - false, - }, - - { - // Multiple positional filename (1 arg) - []string{"add-multi", filepath.Join(completionTestSourcedir, "completion")}, - completionTestFilename, - false, - }, - { - // Multiple positional filename (2 args) - []string{"add-multi", filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion")}, - completionTestFilename, - false, - }, - { - // Multiple positional filename (3 args) - []string{"add-multi", filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion")}, - completionTestFilename, - false, - }, - - { - // Flag filename - []string{"rm", "-f", path.Join(completionTestSourcedir, "completion")}, - completionTestFilename, - false, - }, - - { - // Flag short concat last filename - []string{"rm", "-of", path.Join(completionTestSourcedir, "completion")}, - completionTestFilename, - false, - }, - - { - // Flag concat filename - []string{"rm", "-f" + path.Join(completionTestSourcedir, "completion")}, - []string{"-f" + completionTestFilename[0], "-f" + completionTestFilename[1]}, - false, - }, - - { - // Flag equal concat filename - []string{"rm", "-f=" + path.Join(completionTestSourcedir, "completion")}, - []string{"-f=" + completionTestFilename[0], "-f=" + completionTestFilename[1]}, - false, - }, - - { - // Flag concat long filename - []string{"rm", "--filename=" + path.Join(completionTestSourcedir, "completion")}, - []string{"--filename=" + completionTestFilename[0], "--filename=" + completionTestFilename[1]}, - false, - }, - - { - // Flag long filename - []string{"rm", "--filename", path.Join(completionTestSourcedir, "completion")}, - completionTestFilename, - false, - }, - - { - // Custom completed - []string{"rename", "-c", "hello un"}, - []string{"hello universe"}, - false, - }, - } -} - -func TestCompletion(t *testing.T) { - p := NewParser(&completionTestOptions, Default) - c := &completion{parser: p} - - for _, test := range completionTests { - if test.ShowDescriptions { - continue - } - - ret := c.complete(test.Args) - items := make([]string, len(ret)) - - for i, v := range ret { - items[i] = v.Item - } - - if !reflect.DeepEqual(items, test.Completed) { - t.Errorf("Args: %#v, %#v\n Expected: %#v\n Got: %#v", test.Args, test.ShowDescriptions, test.Completed, items) - } - } -} - -func TestParserCompletion(t *testing.T) { - for _, test := range completionTests { - if test.ShowDescriptions { - os.Setenv("GO_FLAGS_COMPLETION", "verbose") - } else { - os.Setenv("GO_FLAGS_COMPLETION", "1") - } - - tmp := os.Stdout - - r, w, _ := os.Pipe() - os.Stdout = w - - out := make(chan string) - - go func() { - var buf bytes.Buffer - - io.Copy(&buf, r) - - out <- buf.String() - }() - - p := NewParser(&completionTestOptions, None) - - p.CompletionHandler = func(items []Completion) { - comp := &completion{parser: p} - comp.print(items, test.ShowDescriptions) - } - - _, err := p.ParseArgs(test.Args) - - w.Close() - - os.Stdout = tmp - - if err != nil { - t.Fatalf("Unexpected error: %s", err) - } - - got := strings.Split(strings.Trim(<-out, "\n"), "\n") - - if !reflect.DeepEqual(got, test.Completed) { - t.Errorf("Expected: %#v\nGot: %#v", test.Completed, got) - } - } - - os.Setenv("GO_FLAGS_COMPLETION", "") -} diff --git a/vendor/github.com/jessevdk/go-flags/convert.go b/vendor/github.com/jessevdk/go-flags/convert.go index 938c3ac1..984aac89 100644 --- a/vendor/github.com/jessevdk/go-flags/convert.go +++ b/vendor/github.com/jessevdk/go-flags/convert.go @@ -154,6 +154,13 @@ func convertToString(val reflect.Value, options multiTag) (string, error) { func convertUnmarshal(val string, retval reflect.Value) (bool, error) { if retval.Type().NumMethod() > 0 && retval.CanInterface() { if unmarshaler, ok := retval.Interface().(Unmarshaler); ok { + if retval.IsNil() { + retval.Set(reflect.New(retval.Type().Elem())) + + // Re-assign from the new value + unmarshaler = retval.Interface().(Unmarshaler) + } + return true, unmarshaler.UnmarshalFlag(val) } } diff --git a/vendor/github.com/jessevdk/go-flags/convert_test.go b/vendor/github.com/jessevdk/go-flags/convert_test.go deleted file mode 100644 index ef131dc8..00000000 --- a/vendor/github.com/jessevdk/go-flags/convert_test.go +++ /dev/null @@ -1,159 +0,0 @@ -package flags - -import ( - "testing" - "time" -) - -func expectConvert(t *testing.T, o *Option, expected string) { - s, err := convertToString(o.value, o.tag) - - if err != nil { - t.Errorf("Unexpected error: %v", err) - return - } - - assertString(t, s, expected) -} - -func TestConvertToString(t *testing.T) { - d, _ := time.ParseDuration("1h2m4s") - - var opts = struct { - String string `long:"string"` - - Int int `long:"int"` - Int8 int8 `long:"int8"` - Int16 int16 `long:"int16"` - Int32 int32 `long:"int32"` - Int64 int64 `long:"int64"` - - Uint uint `long:"uint"` - Uint8 uint8 `long:"uint8"` - Uint16 uint16 `long:"uint16"` - Uint32 uint32 `long:"uint32"` - Uint64 uint64 `long:"uint64"` - - Float32 float32 `long:"float32"` - Float64 float64 `long:"float64"` - - Duration time.Duration `long:"duration"` - - Bool bool `long:"bool"` - - IntSlice []int `long:"int-slice"` - IntFloatMap map[int]float64 `long:"int-float-map"` - - PtrBool *bool `long:"ptr-bool"` - Interface interface{} `long:"interface"` - - Int32Base int32 `long:"int32-base" base:"16"` - Uint32Base uint32 `long:"uint32-base" base:"16"` - }{ - "string", - - -2, - -1, - 0, - 1, - 2, - - 1, - 2, - 3, - 4, - 5, - - 1.2, - -3.4, - - d, - true, - - []int{-3, 4, -2}, - map[int]float64{-2: 4.5}, - - new(bool), - float32(5.2), - - -5823, - 4232, - } - - p := NewNamedParser("test", Default) - grp, _ := p.AddGroup("test group", "", &opts) - - expects := []string{ - "string", - "-2", - "-1", - "0", - "1", - "2", - - "1", - "2", - "3", - "4", - "5", - - "1.2", - "-3.4", - - "1h2m4s", - "true", - - "[-3, 4, -2]", - "{-2:4.5}", - - "false", - "5.2", - - "-16bf", - "1088", - } - - for i, v := range grp.Options() { - expectConvert(t, v, expects[i]) - } -} - -func TestConvertToStringInvalidIntBase(t *testing.T) { - var opts = struct { - Int int `long:"int" base:"no"` - }{ - 2, - } - - p := NewNamedParser("test", Default) - grp, _ := p.AddGroup("test group", "", &opts) - o := grp.Options()[0] - - _, err := convertToString(o.value, o.tag) - - if err != nil { - err = newErrorf(ErrMarshal, "%v", err) - } - - assertError(t, err, ErrMarshal, "strconv.ParseInt: parsing \"no\": invalid syntax") -} - -func TestConvertToStringInvalidUintBase(t *testing.T) { - var opts = struct { - Uint uint `long:"uint" base:"no"` - }{ - 2, - } - - p := NewNamedParser("test", Default) - grp, _ := p.AddGroup("test group", "", &opts) - o := grp.Options()[0] - - _, err := convertToString(o.value, o.tag) - - if err != nil { - err = newErrorf(ErrMarshal, "%v", err) - } - - assertError(t, err, ErrMarshal, "strconv.ParseInt: parsing \"no\": invalid syntax") -} diff --git a/vendor/github.com/jessevdk/go-flags/example_test.go b/vendor/github.com/jessevdk/go-flags/example_test.go deleted file mode 100644 index 4321ed8e..00000000 --- a/vendor/github.com/jessevdk/go-flags/example_test.go +++ /dev/null @@ -1,110 +0,0 @@ -// Example of use of the flags package. -package flags - -import ( - "fmt" - "os/exec" -) - -func Example() { - var opts struct { - // Slice of bool will append 'true' each time the option - // is encountered (can be set multiple times, like -vvv) - Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"` - - // Example of automatic marshalling to desired type (uint) - Offset uint `long:"offset" description:"Offset"` - - // Example of a callback, called each time the option is found. - Call func(string) `short:"c" description:"Call phone number"` - - // Example of a required flag - Name string `short:"n" long:"name" description:"A name" required:"true"` - - // Example of a value name - File string `short:"f" long:"file" description:"A file" value-name:"FILE"` - - // Example of a pointer - Ptr *int `short:"p" description:"A pointer to an integer"` - - // Example of a slice of strings - StringSlice []string `short:"s" description:"A slice of strings"` - - // Example of a slice of pointers - PtrSlice []*string `long:"ptrslice" description:"A slice of pointers to string"` - - // Example of a map - IntMap map[string]int `long:"intmap" description:"A map from string to int"` - - // Example of a filename (useful for completion) - Filename Filename `long:"filename" description:"A filename"` - - // Example of positional arguments - Args struct { - ID string - Num int - Rest []string - } `positional-args:"yes" required:"yes"` - } - - // Callback which will invoke callto: to call a number. - // Note that this works just on OS X (and probably only with - // Skype) but it shows the idea. - opts.Call = func(num string) { - cmd := exec.Command("open", "callto:"+num) - cmd.Start() - cmd.Process.Release() - } - - // Make some fake arguments to parse. - args := []string{ - "-vv", - "--offset=5", - "-n", "Me", - "-p", "3", - "-s", "hello", - "-s", "world", - "--ptrslice", "hello", - "--ptrslice", "world", - "--intmap", "a:1", - "--intmap", "b:5", - "--filename", "hello.go", - "id", - "10", - "remaining1", - "remaining2", - } - - // Parse flags from `args'. Note that here we use flags.ParseArgs for - // the sake of making a working example. Normally, you would simply use - // flags.Parse(&opts) which uses os.Args - _, err := ParseArgs(&opts, args) - - if err != nil { - panic(err) - } - - fmt.Printf("Verbosity: %v\n", opts.Verbose) - fmt.Printf("Offset: %d\n", opts.Offset) - fmt.Printf("Name: %s\n", opts.Name) - fmt.Printf("Ptr: %d\n", *opts.Ptr) - fmt.Printf("StringSlice: %v\n", opts.StringSlice) - fmt.Printf("PtrSlice: [%v %v]\n", *opts.PtrSlice[0], *opts.PtrSlice[1]) - fmt.Printf("IntMap: [a:%v b:%v]\n", opts.IntMap["a"], opts.IntMap["b"]) - fmt.Printf("Filename: %v\n", opts.Filename) - fmt.Printf("Args.ID: %s\n", opts.Args.ID) - fmt.Printf("Args.Num: %d\n", opts.Args.Num) - fmt.Printf("Args.Rest: %v\n", opts.Args.Rest) - - // Output: Verbosity: [true true] - // Offset: 5 - // Name: Me - // Ptr: 3 - // StringSlice: [hello world] - // PtrSlice: [hello world] - // IntMap: [a:1 b:5] - // Filename: hello.go - // Args.ID: id - // Args.Num: 10 - // Args.Rest: [remaining1 remaining2] -} diff --git a/vendor/github.com/jessevdk/go-flags/flags.go b/vendor/github.com/jessevdk/go-flags/flags.go index 757d42a5..889762d1 100644 --- a/vendor/github.com/jessevdk/go-flags/flags.go +++ b/vendor/github.com/jessevdk/go-flags/flags.go @@ -35,6 +35,8 @@ Additional features specific to Windows: Options with long names (/verbose) Windows-style options with arguments use a colon as the delimiter Modify generated help message with Windows-style / options + Windows style options can be disabled at build time using the "forceposix" + build tag Basic usage @@ -76,15 +78,15 @@ The following is a list of tags for struct fields supported by go-flags: short: the short name of the option (single character) long: the long name of the option - required: whether an option is required to appear on the command + required: if non empty, makes the option required to appear on the command line. If a required option is not present, the parser will return ErrRequired (optional) description: the description of the option (optional) long-description: the long description of the option. Currently only displayed in generated man pages (optional) - no-flag: if non-empty this field is ignored as an option (optional) + no-flag: if non-empty, this field is ignored as an option (optional) - optional: whether an argument of the option is optional. When an + optional: if non-empty, makes the argument of the option optional. When an argument is optional it can only be specified using --option=argument (optional) optional-value: the value of an optional option when the option occurs @@ -107,8 +109,8 @@ The following is a list of tags for struct fields supported by go-flags: value-name: the name of the argument value (to be shown in the help) (optional) choice: limits the values for an option to a set of values. - This tag can be specified mltiple times (optional) - hidden: the option is not visible in the help or man page. + This tag can be specified multiple times (optional) + hidden: if non-empty, the option is not visible in the help or man page. base: a base (radix) used to convert strings to integer values, the default base is 10 (i.e. decimal) (optional) diff --git a/vendor/github.com/jessevdk/go-flags/group.go b/vendor/github.com/jessevdk/go-flags/group.go index b1ef6ed6..6133a718 100644 --- a/vendor/github.com/jessevdk/go-flags/group.go +++ b/vendor/github.com/jessevdk/go-flags/group.go @@ -174,6 +174,10 @@ func (g *Group) eachGroup(f func(*Group)) { } } +func isStringFalsy(s string) bool { + return s == "" || s == "false" || s == "no" || s == "0" +} + func (g *Group) scanStruct(realval reflect.Value, sfield *reflect.StructField, handler scanHandler) error { stype := realval.Type() @@ -213,13 +217,19 @@ func (g *Group) scanStruct(realval reflect.Value, sfield *reflect.StructField, h return err } } else if kind == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct { + flagCountBefore := len(g.options) + len(g.groups) + if fld.IsNil() { - fld.Set(reflect.New(fld.Type().Elem())) + fld = reflect.New(fld.Type().Elem()) } if err := g.scanStruct(reflect.Indirect(fld), &field, handler); err != nil { return err } + + if len(g.options)+len(g.groups) != flagCountBefore { + realval.Field(i).Set(fld) + } } longname := mtag.Get("long") @@ -249,10 +259,10 @@ func (g *Group) scanStruct(realval reflect.Value, sfield *reflect.StructField, h valueName := mtag.Get("value-name") defaultMask := mtag.Get("default-mask") - optional := (mtag.Get("optional") != "") - required := (mtag.Get("required") != "") + optional := !isStringFalsy(mtag.Get("optional")) + required := !isStringFalsy(mtag.Get("required")) choices := mtag.GetMany("choice") - hidden := (mtag.Get("hidden") != "") + hidden := !isStringFalsy(mtag.Get("hidden")) option := &Option{ Description: description, diff --git a/vendor/github.com/jessevdk/go-flags/group_test.go b/vendor/github.com/jessevdk/go-flags/group_test.go deleted file mode 100644 index 18cd6c17..00000000 --- a/vendor/github.com/jessevdk/go-flags/group_test.go +++ /dev/null @@ -1,255 +0,0 @@ -package flags - -import ( - "testing" -) - -func TestGroupInline(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Group struct { - G bool `short:"g"` - } `group:"Grouped Options"` - }{} - - p, ret := assertParserSuccess(t, &opts, "-v", "-g") - - assertStringArray(t, ret, []string{}) - - if !opts.Value { - t.Errorf("Expected Value to be true") - } - - if !opts.Group.G { - t.Errorf("Expected Group.G to be true") - } - - if p.Command.Group.Find("Grouped Options") == nil { - t.Errorf("Expected to find group `Grouped Options'") - } -} - -func TestGroupAdd(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - }{} - - var grp = struct { - G bool `short:"g"` - }{} - - p := NewParser(&opts, Default) - g, err := p.AddGroup("Grouped Options", "", &grp) - - if err != nil { - t.Fatalf("Unexpected error: %v", err) - return - } - - ret, err := p.ParseArgs([]string{"-v", "-g", "rest"}) - - if err != nil { - t.Fatalf("Unexpected error: %v", err) - return - } - - assertStringArray(t, ret, []string{"rest"}) - - if !opts.Value { - t.Errorf("Expected Value to be true") - } - - if !grp.G { - t.Errorf("Expected Group.G to be true") - } - - if p.Command.Group.Find("Grouped Options") != g { - t.Errorf("Expected to find group `Grouped Options'") - } - - if p.Groups()[1] != g { - t.Errorf("Expected group %#v, but got %#v", g, p.Groups()[0]) - } - - if g.Options()[0].ShortName != 'g' { - t.Errorf("Expected short name `g' but got %v", g.Options()[0].ShortName) - } -} - -func TestGroupNestedInline(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Group struct { - G bool `short:"g"` - - Nested struct { - N string `long:"n"` - } `group:"Nested Options"` - } `group:"Grouped Options"` - }{} - - p, ret := assertParserSuccess(t, &opts, "-v", "-g", "--n", "n", "rest") - - assertStringArray(t, ret, []string{"rest"}) - - if !opts.Value { - t.Errorf("Expected Value to be true") - } - - if !opts.Group.G { - t.Errorf("Expected Group.G to be true") - } - - assertString(t, opts.Group.Nested.N, "n") - - if p.Command.Group.Find("Grouped Options") == nil { - t.Errorf("Expected to find group `Grouped Options'") - } - - if p.Command.Group.Find("Nested Options") == nil { - t.Errorf("Expected to find group `Nested Options'") - } -} - -func TestGroupNestedInlineNamespace(t *testing.T) { - var opts = struct { - Opt string `long:"opt"` - - Group struct { - Opt string `long:"opt"` - Group struct { - Opt string `long:"opt"` - } `group:"Subsubgroup" namespace:"sap"` - } `group:"Subgroup" namespace:"sip"` - }{} - - p, ret := assertParserSuccess(t, &opts, "--opt", "a", "--sip.opt", "b", "--sip.sap.opt", "c", "rest") - - assertStringArray(t, ret, []string{"rest"}) - - assertString(t, opts.Opt, "a") - assertString(t, opts.Group.Opt, "b") - assertString(t, opts.Group.Group.Opt, "c") - - for _, name := range []string{"Subgroup", "Subsubgroup"} { - if p.Command.Group.Find(name) == nil { - t.Errorf("Expected to find group '%s'", name) - } - } -} - -func TestDuplicateShortFlags(t *testing.T) { - var opts struct { - Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"` - Variables []string `short:"v" long:"variable" description:"Set a variable value."` - } - - args := []string{ - "--verbose", - "-v", "123", - "-v", "456", - } - - _, err := ParseArgs(&opts, args) - - if err == nil { - t.Errorf("Expected an error with type ErrDuplicatedFlag") - } else { - err2 := err.(*Error) - if err2.Type != ErrDuplicatedFlag { - t.Errorf("Expected an error with type ErrDuplicatedFlag") - } - } -} - -func TestDuplicateLongFlags(t *testing.T) { - var opts struct { - Test1 []bool `short:"a" long:"testing" description:"Test 1"` - Test2 []string `short:"b" long:"testing" description:"Test 2."` - } - - args := []string{ - "--testing", - } - - _, err := ParseArgs(&opts, args) - - if err == nil { - t.Errorf("Expected an error with type ErrDuplicatedFlag") - } else { - err2 := err.(*Error) - if err2.Type != ErrDuplicatedFlag { - t.Errorf("Expected an error with type ErrDuplicatedFlag") - } - } -} - -func TestFindOptionByLongFlag(t *testing.T) { - var opts struct { - Testing bool `long:"testing" description:"Testing"` - } - - p := NewParser(&opts, Default) - opt := p.FindOptionByLongName("testing") - - if opt == nil { - t.Errorf("Expected option, but found none") - } - - assertString(t, opt.LongName, "testing") -} - -func TestFindOptionByShortFlag(t *testing.T) { - var opts struct { - Testing bool `short:"t" description:"Testing"` - } - - p := NewParser(&opts, Default) - opt := p.FindOptionByShortName('t') - - if opt == nil { - t.Errorf("Expected option, but found none") - } - - if opt.ShortName != 't' { - t.Errorf("Expected 't', but got %v", opt.ShortName) - } -} - -func TestFindOptionByLongFlagInSubGroup(t *testing.T) { - var opts struct { - Group struct { - Testing bool `long:"testing" description:"Testing"` - } `group:"sub-group"` - } - - p := NewParser(&opts, Default) - opt := p.FindOptionByLongName("testing") - - if opt == nil { - t.Errorf("Expected option, but found none") - } - - assertString(t, opt.LongName, "testing") -} - -func TestFindOptionByShortFlagInSubGroup(t *testing.T) { - var opts struct { - Group struct { - Testing bool `short:"t" description:"Testing"` - } `group:"sub-group"` - } - - p := NewParser(&opts, Default) - opt := p.FindOptionByShortName('t') - - if opt == nil { - t.Errorf("Expected option, but found none") - } - - if opt.ShortName != 't' { - t.Errorf("Expected 't', but got %v", opt.ShortName) - } -} diff --git a/vendor/github.com/jessevdk/go-flags/help.go b/vendor/github.com/jessevdk/go-flags/help.go index 1b0c2c60..d3803050 100644 --- a/vendor/github.com/jessevdk/go-flags/help.go +++ b/vendor/github.com/jessevdk/go-flags/help.go @@ -107,6 +107,10 @@ func (p *Parser) getAlignmentInfo() alignmentInfo { func wrapText(s string, l int, prefix string) string { var ret string + if l < 10 { + l = 10 + } + // Basic text wrapping of s at spaces to fit in l lines := strings.Split(s, "\n") @@ -212,8 +216,10 @@ func (p *Parser) writeHelpOption(writer *bufio.Writer, option *Option, info alig var def string - if len(option.DefaultMask) != 0 && option.DefaultMask != "-" { - def = option.DefaultMask + if len(option.DefaultMask) != 0 { + if option.DefaultMask != "-" { + def = option.DefaultMask + } } else { def = option.defaultLiteral } diff --git a/vendor/github.com/jessevdk/go-flags/help_test.go b/vendor/github.com/jessevdk/go-flags/help_test.go deleted file mode 100644 index 1248ebe2..00000000 --- a/vendor/github.com/jessevdk/go-flags/help_test.go +++ /dev/null @@ -1,468 +0,0 @@ -package flags - -import ( - "bytes" - "fmt" - "os" - "runtime" - "testing" - "time" -) - -type helpOptions struct { - Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information" ini-name:"verbose"` - Call func(string) `short:"c" description:"Call phone number" ini-name:"call"` - PtrSlice []*string `long:"ptrslice" description:"A slice of pointers to string"` - EmptyDescription bool `long:"empty-description"` - - Default string `long:"default" default:"Some\nvalue" description:"Test default value"` - DefaultArray []string `long:"default-array" default:"Some value" default:"Other\tvalue" description:"Test default array value"` - DefaultMap map[string]string `long:"default-map" default:"some:value" default:"another:value" description:"Testdefault map value"` - EnvDefault1 string `long:"env-default1" default:"Some value" env:"ENV_DEFAULT" description:"Test env-default1 value"` - EnvDefault2 string `long:"env-default2" env:"ENV_DEFAULT" description:"Test env-default2 value"` - OptionWithArgName string `long:"opt-with-arg-name" value-name:"something" description:"Option with named argument"` - OptionWithChoices string `long:"opt-with-choices" value-name:"choice" choice:"dog" choice:"cat" description:"Option with choices"` - Hidden string `long:"hidden" description:"Hidden option" hidden:"yes"` - - OnlyIni string `ini-name:"only-ini" description:"Option only available in ini"` - - Other struct { - StringSlice []string `short:"s" default:"some" default:"value" description:"A slice of strings"` - IntMap map[string]int `long:"intmap" default:"a:1" description:"A map from string to int" ini-name:"int-map"` - } `group:"Other Options"` - - HiddenGroup struct { - InsideHiddenGroup string `long:"inside-hidden-group" description:"Inside hidden group"` - } `group:"Hidden group" hidden:"yes"` - - Group struct { - Opt string `long:"opt" description:"This is a subgroup option"` - HiddenInsideGroup string `long:"hidden-inside-group" description:"Hidden inside group" hidden:"yes"` - - Group struct { - Opt string `long:"opt" description:"This is a subsubgroup option"` - } `group:"Subsubgroup" namespace:"sap"` - } `group:"Subgroup" namespace:"sip"` - - Command struct { - ExtraVerbose []bool `long:"extra-verbose" description:"Use for extra verbosity"` - } `command:"command" alias:"cm" alias:"cmd" description:"A command"` - - HiddenCommand struct { - ExtraVerbose []bool `long:"extra-verbose" description:"Use for extra verbosity"` - } `command:"hidden-command" description:"A hidden command" hidden:"yes"` - - Args struct { - Filename string `positional-arg-name:"filename" description:"A filename with a long description to trigger line wrapping"` - Number int `positional-arg-name:"num" description:"A number"` - HiddenInHelp float32 `positional-arg-name:"hidden-in-help" required:"yes"` - } `positional-args:"yes"` -} - -func TestHelp(t *testing.T) { - oldEnv := EnvSnapshot() - defer oldEnv.Restore() - os.Setenv("ENV_DEFAULT", "env-def") - - var opts helpOptions - p := NewNamedParser("TestHelp", HelpFlag) - p.AddGroup("Application Options", "The application options", &opts) - - _, err := p.ParseArgs([]string{"--help"}) - - if err == nil { - t.Fatalf("Expected help error") - } - - if e, ok := err.(*Error); !ok { - t.Fatalf("Expected flags.Error, but got %T", err) - } else { - if e.Type != ErrHelp { - t.Errorf("Expected flags.ErrHelp type, but got %s", e.Type) - } - - var expected string - - if runtime.GOOS == "windows" { - expected = `Usage: - TestHelp [OPTIONS] [filename] [num] [hidden-in-help] - - -Application Options: - /v, /verbose Show verbose debug information - /c: Call phone number - /ptrslice: A slice of pointers to string - /empty-description - /default: Test default value (default: - "Some\nvalue") - /default-array: Test default array value (default: - Some value, "Other\tvalue") - /default-map: Testdefault map value (default: - some:value, another:value) - /env-default1: Test env-default1 value (default: - Some value) [%ENV_DEFAULT%] - /env-default2: Test env-default2 value - [%ENV_DEFAULT%] - /opt-with-arg-name:something Option with named argument - /opt-with-choices:choice[dog|cat] Option with choices - -Other Options: - /s: A slice of strings (default: some, - value) - /intmap: A map from string to int (default: - a:1) - -Subgroup: - /sip.opt: This is a subgroup option - -Subsubgroup: - /sip.sap.opt: This is a subsubgroup option - -Help Options: - /? Show this help message - /h, /help Show this help message - -Arguments: - filename: A filename - num: A number - -Available commands: - command A command (aliases: cm, cmd) -` - } else { - expected = `Usage: - TestHelp [OPTIONS] [filename] [num] [hidden-in-help] - -Application Options: - -v, --verbose Show verbose debug information - -c= Call phone number - --ptrslice= A slice of pointers to string - --empty-description - --default= Test default value (default: - "Some\nvalue") - --default-array= Test default array value (default: - Some value, "Other\tvalue") - --default-map= Testdefault map value (default: - some:value, another:value) - --env-default1= Test env-default1 value (default: - Some value) [$ENV_DEFAULT] - --env-default2= Test env-default2 value - [$ENV_DEFAULT] - --opt-with-arg-name=something Option with named argument - --opt-with-choices=choice[dog|cat] Option with choices - -Other Options: - -s= A slice of strings (default: some, - value) - --intmap= A map from string to int (default: - a:1) - -Subgroup: - --sip.opt= This is a subgroup option - -Subsubgroup: - --sip.sap.opt= This is a subsubgroup option - -Help Options: - -h, --help Show this help message - -Arguments: - filename: A filename with a long description - to trigger line wrapping - num: A number - -Available commands: - command A command (aliases: cm, cmd) -` - } - - assertDiff(t, e.Message, expected, "help message") - } -} - -func TestMan(t *testing.T) { - oldEnv := EnvSnapshot() - defer oldEnv.Restore() - os.Setenv("ENV_DEFAULT", "env-def") - - var opts helpOptions - p := NewNamedParser("TestMan", HelpFlag) - p.ShortDescription = "Test manpage generation" - p.LongDescription = "This is a somewhat `longer' description of what this does" - p.AddGroup("Application Options", "The application options", &opts) - - p.Commands()[0].LongDescription = "Longer `command' description" - - var buf bytes.Buffer - p.WriteManPage(&buf) - - got := buf.String() - - tt := time.Now() - - var envDefaultName string - - if runtime.GOOS == "windows" { - envDefaultName = "%ENV_DEFAULT%" - } else { - envDefaultName = "$ENV_DEFAULT" - } - - expected := fmt.Sprintf(`.TH TestMan 1 "%s" -.SH NAME -TestMan \- Test manpage generation -.SH SYNOPSIS -\fBTestMan\fP [OPTIONS] -.SH DESCRIPTION -This is a somewhat \fBlonger\fP description of what this does -.SH OPTIONS -.SS Application Options -The application options -.TP -\fB\fB\-v\fR, \fB\-\-verbose\fR\fP -Show verbose debug information -.TP -\fB\fB\-c\fR\fP -Call phone number -.TP -\fB\fB\-\-ptrslice\fR\fP -A slice of pointers to string -.TP -\fB\fB\-\-empty-description\fR\fP -.TP -\fB\fB\-\-default\fR \fP -Test default value -.TP -\fB\fB\-\-default-array\fR \fP -Test default array value -.TP -\fB\fB\-\-default-map\fR \fP -Testdefault map value -.TP -\fB\fB\-\-env-default1\fR \fP -Test env-default1 value -.TP -\fB\fB\-\-env-default2\fR \fP -Test env-default2 value -.TP -\fB\fB\-\-opt-with-arg-name\fR \fIsomething\fR\fP -Option with named argument -.TP -\fB\fB\-\-opt-with-choices\fR \fIchoice\fR\fP -Option with choices -.SS Other Options -.TP -\fB\fB\-s\fR \fP -A slice of strings -.TP -\fB\fB\-\-intmap\fR \fP -A map from string to int -.SS Subgroup -.TP -\fB\fB\-\-sip.opt\fR\fP -This is a subgroup option -.SS Subsubgroup -.TP -\fB\fB\-\-sip.sap.opt\fR\fP -This is a subsubgroup option -.SH COMMANDS -.SS command -A command - -Longer \fBcommand\fP description - -\fBUsage\fP: TestMan [OPTIONS] command [command-OPTIONS] -.TP - -\fBAliases\fP: cm, cmd - -.TP -\fB\fB\-\-extra-verbose\fR\fP -Use for extra verbosity -`, tt.Format("2 January 2006"), envDefaultName) - - assertDiff(t, got, expected, "man page") -} - -type helpCommandNoOptions struct { - Command struct { - } `command:"command" description:"A command"` -} - -func TestHelpCommand(t *testing.T) { - oldEnv := EnvSnapshot() - defer oldEnv.Restore() - os.Setenv("ENV_DEFAULT", "env-def") - - var opts helpCommandNoOptions - p := NewNamedParser("TestHelpCommand", HelpFlag) - p.AddGroup("Application Options", "The application options", &opts) - - _, err := p.ParseArgs([]string{"command", "--help"}) - - if err == nil { - t.Fatalf("Expected help error") - } - - if e, ok := err.(*Error); !ok { - t.Fatalf("Expected flags.Error, but got %T", err) - } else { - if e.Type != ErrHelp { - t.Errorf("Expected flags.ErrHelp type, but got %s", e.Type) - } - - var expected string - - if runtime.GOOS == "windows" { - expected = `Usage: - TestHelpCommand [OPTIONS] command - -Help Options: - /? Show this help message - /h, /help Show this help message -` - } else { - expected = `Usage: - TestHelpCommand [OPTIONS] command - -Help Options: - -h, --help Show this help message -` - } - - assertDiff(t, e.Message, expected, "help message") - } -} - -func TestHelpDefaults(t *testing.T) { - var expected string - - if runtime.GOOS == "windows" { - expected = `Usage: - TestHelpDefaults [OPTIONS] - -Application Options: - /with-default: With default (default: default-value) - /without-default: Without default - /with-programmatic-default: With programmatic default (default: - default-value) - -Help Options: - /? Show this help message - /h, /help Show this help message -` - } else { - expected = `Usage: - TestHelpDefaults [OPTIONS] - -Application Options: - --with-default= With default (default: default-value) - --without-default= Without default - --with-programmatic-default= With programmatic default (default: - default-value) - -Help Options: - -h, --help Show this help message -` - } - - tests := []struct { - Args []string - Output string - }{ - { - Args: []string{"-h"}, - Output: expected, - }, - { - Args: []string{"--with-default", "other-value", "--with-programmatic-default", "other-value", "-h"}, - Output: expected, - }, - } - - for _, test := range tests { - var opts struct { - WithDefault string `long:"with-default" default:"default-value" description:"With default"` - WithoutDefault string `long:"without-default" description:"Without default"` - WithProgrammaticDefault string `long:"with-programmatic-default" description:"With programmatic default"` - } - - opts.WithProgrammaticDefault = "default-value" - - p := NewNamedParser("TestHelpDefaults", HelpFlag) - p.AddGroup("Application Options", "The application options", &opts) - - _, err := p.ParseArgs(test.Args) - - if err == nil { - t.Fatalf("Expected help error") - } - - if e, ok := err.(*Error); !ok { - t.Fatalf("Expected flags.Error, but got %T", err) - } else { - if e.Type != ErrHelp { - t.Errorf("Expected flags.ErrHelp type, but got %s", e.Type) - } - - assertDiff(t, e.Message, test.Output, "help message") - } - } -} - -func TestHelpRestArgs(t *testing.T) { - opts := struct { - Verbose bool `short:"v"` - }{} - - p := NewNamedParser("TestHelpDefaults", HelpFlag) - p.AddGroup("Application Options", "The application options", &opts) - - retargs, err := p.ParseArgs([]string{"-h", "-v", "rest"}) - - if err == nil { - t.Fatalf("Expected help error") - } - - assertStringArray(t, retargs, []string{"-v", "rest"}) -} - -func TestWrapText(t *testing.T) { - s := "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." - - got := wrapText(s, 60, " ") - expected := `Lorem ipsum dolor sit amet, consectetur adipisicing elit, - sed do eiusmod tempor incididunt ut labore et dolore magna - aliqua. Ut enim ad minim veniam, quis nostrud exercitation - ullamco laboris nisi ut aliquip ex ea commodo consequat. - Duis aute irure dolor in reprehenderit in voluptate velit - esse cillum dolore eu fugiat nulla pariatur. Excepteur sint - occaecat cupidatat non proident, sunt in culpa qui officia - deserunt mollit anim id est laborum.` - - assertDiff(t, got, expected, "wrapped text") -} - -func TestWrapParagraph(t *testing.T) { - s := "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n\n" - s += "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n\n" - s += "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\n\n" - s += "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n" - - got := wrapText(s, 60, " ") - expected := `Lorem ipsum dolor sit amet, consectetur adipisicing elit, - sed do eiusmod tempor incididunt ut labore et dolore magna - aliqua. - - Ut enim ad minim veniam, quis nostrud exercitation ullamco - laboris nisi ut aliquip ex ea commodo consequat. - - Duis aute irure dolor in reprehenderit in voluptate velit - esse cillum dolore eu fugiat nulla pariatur. - - Excepteur sint occaecat cupidatat non proident, sunt in - culpa qui officia deserunt mollit anim id est laborum. -` - - assertDiff(t, got, expected, "wrapped paragraph") -} diff --git a/vendor/github.com/jessevdk/go-flags/ini.go b/vendor/github.com/jessevdk/go-flags/ini.go index cfdf57cc..e714d3d3 100644 --- a/vendor/github.com/jessevdk/go-flags/ini.go +++ b/vendor/github.com/jessevdk/go-flags/ini.go @@ -11,7 +11,7 @@ import ( "strings" ) -// IniError contains location information on where an error occured. +// IniError contains location information on where an error occurred. type IniError struct { // The error message. Message string @@ -58,6 +58,8 @@ const ( // IniParser is a utility to read and write flags options from and to ini // formatted strings. type IniParser struct { + ParseAsDefaults bool // override default flags + parser *Parser } @@ -96,8 +98,6 @@ func IniParse(filename string, data interface{}) error { // information on the ini file format. The returned errors can be of the type // flags.Error or flags.IniError. func (i *IniParser) ParseFile(filename string) error { - i.parser.clearIsSet() - ini, err := readIniFromFile(filename) if err != nil { @@ -132,8 +132,6 @@ func (i *IniParser) ParseFile(filename string) error { // // The returned errors can be of the type flags.Error or flags.IniError. func (i *IniParser) Parse(reader io.Reader) error { - i.parser.clearIsSet() - ini, err := readIni(reader, "") if err != nil { @@ -143,7 +141,7 @@ func (i *IniParser) Parse(reader io.Reader) error { return i.parse(ini) } -// WriteFile writes the flags as ini format into a file. See WriteIni +// WriteFile writes the flags as ini format into a file. See Write // for more information. The returned error occurs when the specified file // could not be opened for writing. func (i *IniParser) WriteFile(filename string, options IniOptions) error { @@ -539,6 +537,12 @@ func (i *IniParser) parse(ini *ini) error { continue } + // ini value is ignored if override is set and + // value was previously set from non default + if i.ParseAsDefaults && !opt.isSetDefault { + continue + } + pval := &inival.Value if !opt.canArgument() && len(inival.Value) == 0 { diff --git a/vendor/github.com/jessevdk/go-flags/ini_test.go b/vendor/github.com/jessevdk/go-flags/ini_test.go deleted file mode 100644 index dfe49ce7..00000000 --- a/vendor/github.com/jessevdk/go-flags/ini_test.go +++ /dev/null @@ -1,950 +0,0 @@ -package flags - -import ( - "bytes" - "fmt" - "io/ioutil" - "os" - "reflect" - "strings" - "testing" -) - -func TestWriteIni(t *testing.T) { - oldEnv := EnvSnapshot() - defer oldEnv.Restore() - os.Setenv("ENV_DEFAULT", "env-def") - - var tests = []struct { - args []string - options IniOptions - expected string - }{ - { - []string{"-vv", "--intmap=a:2", "--intmap", "b:3", "filename", "0", "3.14", "command"}, - IniDefault, - `[Application Options] -; Show verbose debug information -verbose = true -verbose = true - -; Test env-default1 value -EnvDefault1 = env-def - -; Test env-default2 value -EnvDefault2 = env-def - -[Other Options] -; A map from string to int -int-map = a:2 -int-map = b:3 - -`, - }, - { - []string{"-vv", "--intmap=a:2", "--intmap", "b:3", "filename", "0", "3.14", "command"}, - IniDefault | IniIncludeDefaults, - `[Application Options] -; Show verbose debug information -verbose = true -verbose = true - -; A slice of pointers to string -; PtrSlice = - -EmptyDescription = false - -; Test default value -Default = "Some\nvalue" - -; Test default array value -DefaultArray = Some value -DefaultArray = "Other\tvalue" - -; Testdefault map value -DefaultMap = another:value -DefaultMap = some:value - -; Test env-default1 value -EnvDefault1 = env-def - -; Test env-default2 value -EnvDefault2 = env-def - -; Option with named argument -OptionWithArgName = - -; Option with choices -OptionWithChoices = - -; Option only available in ini -only-ini = - -[Other Options] -; A slice of strings -StringSlice = some -StringSlice = value - -; A map from string to int -int-map = a:2 -int-map = b:3 - -[Subgroup] -; This is a subgroup option -Opt = - -[Subsubgroup] -; This is a subsubgroup option -Opt = - -[command] -; Use for extra verbosity -; ExtraVerbose = - -`, - }, - { - []string{"filename", "0", "3.14", "command"}, - IniDefault | IniIncludeDefaults | IniCommentDefaults, - `[Application Options] -; Show verbose debug information -; verbose = - -; A slice of pointers to string -; PtrSlice = - -; EmptyDescription = false - -; Test default value -; Default = "Some\nvalue" - -; Test default array value -; DefaultArray = Some value -; DefaultArray = "Other\tvalue" - -; Testdefault map value -; DefaultMap = another:value -; DefaultMap = some:value - -; Test env-default1 value -EnvDefault1 = env-def - -; Test env-default2 value -EnvDefault2 = env-def - -; Option with named argument -; OptionWithArgName = - -; Option with choices -; OptionWithChoices = - -; Option only available in ini -; only-ini = - -[Other Options] -; A slice of strings -; StringSlice = some -; StringSlice = value - -; A map from string to int -; int-map = a:1 - -[Subgroup] -; This is a subgroup option -; Opt = - -[Subsubgroup] -; This is a subsubgroup option -; Opt = - -[command] -; Use for extra verbosity -; ExtraVerbose = - -`, - }, - { - []string{"--default=New value", "--default-array=New value", "--default-map=new:value", "filename", "0", "3.14", "command"}, - IniDefault | IniIncludeDefaults | IniCommentDefaults, - `[Application Options] -; Show verbose debug information -; verbose = - -; A slice of pointers to string -; PtrSlice = - -; EmptyDescription = false - -; Test default value -Default = New value - -; Test default array value -DefaultArray = New value - -; Testdefault map value -DefaultMap = new:value - -; Test env-default1 value -EnvDefault1 = env-def - -; Test env-default2 value -EnvDefault2 = env-def - -; Option with named argument -; OptionWithArgName = - -; Option with choices -; OptionWithChoices = - -; Option only available in ini -; only-ini = - -[Other Options] -; A slice of strings -; StringSlice = some -; StringSlice = value - -; A map from string to int -; int-map = a:1 - -[Subgroup] -; This is a subgroup option -; Opt = - -[Subsubgroup] -; This is a subsubgroup option -; Opt = - -[command] -; Use for extra verbosity -; ExtraVerbose = - -`, - }, - } - - for _, test := range tests { - var opts helpOptions - - p := NewNamedParser("TestIni", Default) - p.AddGroup("Application Options", "The application options", &opts) - - _, err := p.ParseArgs(test.args) - - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - - inip := NewIniParser(p) - - var b bytes.Buffer - inip.Write(&b, test.options) - - got := b.String() - expected := test.expected - - msg := fmt.Sprintf("with arguments %+v and ini options %b", test.args, test.options) - assertDiff(t, got, expected, msg) - } -} - -func TestReadIni_flagEquivalent(t *testing.T) { - type options struct { - Opt1 bool `long:"opt1"` - - Group1 struct { - Opt2 bool `long:"opt2"` - } `group:"group1"` - - Group2 struct { - Opt3 bool `long:"opt3"` - } `group:"group2" namespace:"ns1"` - - Cmd1 struct { - Opt4 bool `long:"opt4"` - Opt5 bool `long:"foo.opt5"` - - Group1 struct { - Opt6 bool `long:"opt6"` - Opt7 bool `long:"foo.opt7"` - } `group:"group1"` - - Group2 struct { - Opt8 bool `long:"opt8"` - } `group:"group2" namespace:"ns1"` - } `command:"cmd1"` - } - - a := ` -opt1=true - -[group1] -opt2=true - -[group2] -ns1.opt3=true - -[cmd1] -opt4=true -foo.opt5=true - -[cmd1.group1] -opt6=true -foo.opt7=true - -[cmd1.group2] -ns1.opt8=true -` - b := ` -opt1=true -opt2=true -ns1.opt3=true - -[cmd1] -opt4=true -foo.opt5=true -opt6=true -foo.opt7=true -ns1.opt8=true -` - - parse := func(readIni string) (opts options, writeIni string) { - p := NewNamedParser("TestIni", Default) - p.AddGroup("Application Options", "The application options", &opts) - - inip := NewIniParser(p) - err := inip.Parse(strings.NewReader(readIni)) - - if err != nil { - t.Fatalf("Unexpected error: %s\n\nFile:\n%s", err, readIni) - } - - var b bytes.Buffer - inip.Write(&b, Default) - - return opts, b.String() - } - - aOpt, aIni := parse(a) - bOpt, bIni := parse(b) - - assertDiff(t, aIni, bIni, "") - if !reflect.DeepEqual(aOpt, bOpt) { - t.Errorf("not equal") - } -} - -func TestReadIni(t *testing.T) { - var opts helpOptions - - p := NewNamedParser("TestIni", Default) - p.AddGroup("Application Options", "The application options", &opts) - - inip := NewIniParser(p) - - inic := ` -; Show verbose debug information -verbose = true -verbose = true - -DefaultMap = another:"value\n1" -DefaultMap = some:value 2 - -[Application Options] -; A slice of pointers to string -; PtrSlice = - -; Test default value -Default = "New\nvalue" - -; Test env-default1 value -EnvDefault1 = New value - -[Other Options] -# A slice of strings -StringSlice = "some\nvalue" -StringSlice = another value - -; A map from string to int -int-map = a:2 -int-map = b:3 - -` - - b := strings.NewReader(inic) - err := inip.Parse(b) - - if err != nil { - t.Fatalf("Unexpected error: %s", err) - } - - assertBoolArray(t, opts.Verbose, []bool{true, true}) - - if v := map[string]string{"another": "value\n1", "some": "value 2"}; !reflect.DeepEqual(opts.DefaultMap, v) { - t.Fatalf("Expected %#v for DefaultMap but got %#v", v, opts.DefaultMap) - } - - assertString(t, opts.Default, "New\nvalue") - - assertString(t, opts.EnvDefault1, "New value") - - assertStringArray(t, opts.Other.StringSlice, []string{"some\nvalue", "another value"}) - - if v, ok := opts.Other.IntMap["a"]; !ok { - t.Errorf("Expected \"a\" in Other.IntMap") - } else if v != 2 { - t.Errorf("Expected Other.IntMap[\"a\"] = 2, but got %v", v) - } - - if v, ok := opts.Other.IntMap["b"]; !ok { - t.Errorf("Expected \"b\" in Other.IntMap") - } else if v != 3 { - t.Errorf("Expected Other.IntMap[\"b\"] = 3, but got %v", v) - } -} - -func TestReadAndWriteIni(t *testing.T) { - var tests = []struct { - options IniOptions - read string - write string - }{ - { - IniIncludeComments, - `[Application Options] -; Show verbose debug information -verbose = true -verbose = true - -; Test default value -Default = "quote me" - -; Test default array value -DefaultArray = 1 -DefaultArray = "2" -DefaultArray = 3 - -; Testdefault map value -; DefaultMap = - -; Test env-default1 value -EnvDefault1 = env-def - -; Test env-default2 value -EnvDefault2 = env-def - -[Other Options] -; A slice of strings -; StringSlice = - -; A map from string to int -int-map = a:2 -int-map = b:"3" - -`, - `[Application Options] -; Show verbose debug information -verbose = true -verbose = true - -; Test default value -Default = "quote me" - -; Test default array value -DefaultArray = 1 -DefaultArray = 2 -DefaultArray = 3 - -; Testdefault map value -; DefaultMap = - -; Test env-default1 value -EnvDefault1 = env-def - -; Test env-default2 value -EnvDefault2 = env-def - -[Other Options] -; A slice of strings -; StringSlice = - -; A map from string to int -int-map = a:2 -int-map = b:3 - -`, - }, - { - IniIncludeComments, - `[Application Options] -; Show verbose debug information -verbose = true -verbose = true - -; Test default value -Default = "quote me" - -; Test default array value -DefaultArray = "1" -DefaultArray = "2" -DefaultArray = "3" - -; Testdefault map value -; DefaultMap = - -; Test env-default1 value -EnvDefault1 = env-def - -; Test env-default2 value -EnvDefault2 = env-def - -[Other Options] -; A slice of strings -; StringSlice = - -; A map from string to int -int-map = a:"2" -int-map = b:"3" - -`, - `[Application Options] -; Show verbose debug information -verbose = true -verbose = true - -; Test default value -Default = "quote me" - -; Test default array value -DefaultArray = "1" -DefaultArray = "2" -DefaultArray = "3" - -; Testdefault map value -; DefaultMap = - -; Test env-default1 value -EnvDefault1 = env-def - -; Test env-default2 value -EnvDefault2 = env-def - -[Other Options] -; A slice of strings -; StringSlice = - -; A map from string to int -int-map = a:"2" -int-map = b:"3" - -`, - }, - } - - for _, test := range tests { - var opts helpOptions - - p := NewNamedParser("TestIni", Default) - p.AddGroup("Application Options", "The application options", &opts) - - inip := NewIniParser(p) - - read := strings.NewReader(test.read) - err := inip.Parse(read) - if err != nil { - t.Fatalf("Unexpected error: %s", err) - } - - var write bytes.Buffer - inip.Write(&write, test.options) - - got := write.String() - - msg := fmt.Sprintf("with ini options %b", test.options) - assertDiff(t, got, test.write, msg) - } -} - -func TestReadIniWrongQuoting(t *testing.T) { - var tests = []struct { - iniFile string - lineNumber uint - }{ - { - iniFile: `Default = "New\nvalue`, - lineNumber: 1, - }, - { - iniFile: `StringSlice = "New\nvalue`, - lineNumber: 1, - }, - { - iniFile: `StringSlice = "New\nvalue" - StringSlice = "Second\nvalue`, - lineNumber: 2, - }, - { - iniFile: `DefaultMap = some:"value`, - lineNumber: 1, - }, - { - iniFile: `DefaultMap = some:value - DefaultMap = another:"value`, - lineNumber: 2, - }, - } - - for _, test := range tests { - var opts helpOptions - - p := NewNamedParser("TestIni", Default) - p.AddGroup("Application Options", "The application options", &opts) - - inip := NewIniParser(p) - - inic := test.iniFile - - b := strings.NewReader(inic) - err := inip.Parse(b) - - if err == nil { - t.Fatalf("Expect error") - } - - iniError := err.(*IniError) - - if iniError.LineNumber != test.lineNumber { - t.Fatalf("Expect error on line %d", test.lineNumber) - } - } -} - -func TestIniCommands(t *testing.T) { - var opts struct { - Value string `short:"v" long:"value"` - - Add struct { - Name int `short:"n" long:"name" ini-name:"AliasName"` - - Other struct { - O string `short:"o" long:"other"` - } `group:"Other Options"` - } `command:"add"` - } - - p := NewNamedParser("TestIni", Default) - p.AddGroup("Application Options", "The application options", &opts) - - inip := NewIniParser(p) - - inic := `[Application Options] -value = some value - -[add] -AliasName = 5 - -[add.Other Options] -other = subgroup - -` - - b := strings.NewReader(inic) - err := inip.Parse(b) - - if err != nil { - t.Fatalf("Unexpected error: %s", err) - } - - assertString(t, opts.Value, "some value") - - if opts.Add.Name != 5 { - t.Errorf("Expected opts.Add.Name to be 5, but got %v", opts.Add.Name) - } - - assertString(t, opts.Add.Other.O, "subgroup") - - // Test writing it back - buf := &bytes.Buffer{} - - inip.Write(buf, IniDefault) - - assertDiff(t, buf.String(), inic, "ini contents") -} - -func TestIniNoIni(t *testing.T) { - var opts struct { - NoValue string `short:"n" long:"novalue" no-ini:"yes"` - Value string `short:"v" long:"value"` - } - - p := NewNamedParser("TestIni", Default) - p.AddGroup("Application Options", "The application options", &opts) - - inip := NewIniParser(p) - - // read INI - inic := `[Application Options] -novalue = some value -value = some other value -` - - b := strings.NewReader(inic) - err := inip.Parse(b) - - if err == nil { - t.Fatalf("Expected error") - } - - iniError := err.(*IniError) - - if v := uint(2); iniError.LineNumber != v { - t.Errorf("Expected opts.Add.Name to be %d, but got %d", v, iniError.LineNumber) - } - - if v := "unknown option: novalue"; iniError.Message != v { - t.Errorf("Expected opts.Add.Name to be %s, but got %s", v, iniError.Message) - } - - // write INI - opts.NoValue = "some value" - opts.Value = "some other value" - - file, err := ioutil.TempFile("", "") - if err != nil { - t.Fatalf("Cannot create temporary file: %s", err) - } - defer os.Remove(file.Name()) - - err = inip.WriteFile(file.Name(), IniIncludeDefaults) - if err != nil { - t.Fatalf("Could not write ini file: %s", err) - } - - found, err := ioutil.ReadFile(file.Name()) - if err != nil { - t.Fatalf("Could not read written ini file: %s", err) - } - - expected := "[Application Options]\nValue = some other value\n\n" - - assertDiff(t, string(found), expected, "ini content") -} - -func TestIniParse(t *testing.T) { - file, err := ioutil.TempFile("", "") - if err != nil { - t.Fatalf("Cannot create temporary file: %s", err) - } - defer os.Remove(file.Name()) - - _, err = file.WriteString("value = 123") - if err != nil { - t.Fatalf("Cannot write to temporary file: %s", err) - } - - file.Close() - - var opts struct { - Value int `long:"value"` - } - - err = IniParse(file.Name(), &opts) - if err != nil { - t.Fatalf("Could not parse ini: %s", err) - } - - if opts.Value != 123 { - t.Fatalf("Expected Value to be \"123\" but was \"%d\"", opts.Value) - } -} - -func TestIniCliOverrides(t *testing.T) { - file, err := ioutil.TempFile("", "") - - if err != nil { - t.Fatalf("Cannot create temporary file: %s", err) - } - - defer os.Remove(file.Name()) - - _, err = file.WriteString("values = 123\n") - _, err = file.WriteString("values = 456\n") - - if err != nil { - t.Fatalf("Cannot write to temporary file: %s", err) - } - - file.Close() - - var opts struct { - Values []int `long:"values"` - } - - p := NewParser(&opts, Default) - err = NewIniParser(p).ParseFile(file.Name()) - - if err != nil { - t.Fatalf("Could not parse ini: %s", err) - } - - _, err = p.ParseArgs([]string{"--values", "111", "--values", "222"}) - - if err != nil { - t.Fatalf("Failed to parse arguments: %s", err) - } - - if len(opts.Values) != 2 { - t.Fatalf("Expected Values to contain two elements, but got %d", len(opts.Values)) - } - - if opts.Values[0] != 111 { - t.Fatalf("Expected Values[0] to be 111, but got '%d'", opts.Values[0]) - } - - if opts.Values[1] != 222 { - t.Fatalf("Expected Values[0] to be 222, but got '%d'", opts.Values[1]) - } -} - -func TestIniOverrides(t *testing.T) { - file, err := ioutil.TempFile("", "") - - if err != nil { - t.Fatalf("Cannot create temporary file: %s", err) - } - - defer os.Remove(file.Name()) - - _, err = file.WriteString("value-with-default = \"ini-value\"\n") - _, err = file.WriteString("value-with-default-override-cli = \"ini-value\"\n") - - if err != nil { - t.Fatalf("Cannot write to temporary file: %s", err) - } - - file.Close() - - var opts struct { - ValueWithDefault string `long:"value-with-default" default:"value"` - ValueWithDefaultOverrideCli string `long:"value-with-default-override-cli" default:"value"` - } - - p := NewParser(&opts, Default) - err = NewIniParser(p).ParseFile(file.Name()) - - if err != nil { - t.Fatalf("Could not parse ini: %s", err) - } - - _, err = p.ParseArgs([]string{"--value-with-default-override-cli", "cli-value"}) - - if err != nil { - t.Fatalf("Failed to parse arguments: %s", err) - } - - assertString(t, opts.ValueWithDefault, "ini-value") - assertString(t, opts.ValueWithDefaultOverrideCli, "cli-value") -} - -func TestWriteFile(t *testing.T) { - file, err := ioutil.TempFile("", "") - if err != nil { - t.Fatalf("Cannot create temporary file: %s", err) - } - defer os.Remove(file.Name()) - - var opts struct { - Value int `long:"value"` - } - - opts.Value = 123 - - p := NewParser(&opts, Default) - ini := NewIniParser(p) - - err = ini.WriteFile(file.Name(), IniIncludeDefaults) - if err != nil { - t.Fatalf("Could not write ini file: %s", err) - } - - found, err := ioutil.ReadFile(file.Name()) - if err != nil { - t.Fatalf("Could not read written ini file: %s", err) - } - - expected := "[Application Options]\nValue = 123\n\n" - - assertDiff(t, string(found), expected, "ini content") -} - -func TestOverwriteRequiredOptions(t *testing.T) { - var tests = []struct { - args []string - expected []string - }{ - { - args: []string{"--value", "from CLI"}, - expected: []string{ - "from CLI", - "from default", - }, - }, - { - args: []string{"--value", "from CLI", "--default", "from CLI"}, - expected: []string{ - "from CLI", - "from CLI", - }, - }, - { - args: []string{"--config", "no file name"}, - expected: []string{ - "from INI", - "from INI", - }, - }, - { - args: []string{"--value", "from CLI before", "--default", "from CLI before", "--config", "no file name"}, - expected: []string{ - "from INI", - "from INI", - }, - }, - { - args: []string{"--value", "from CLI before", "--default", "from CLI before", "--config", "no file name", "--value", "from CLI after", "--default", "from CLI after"}, - expected: []string{ - "from CLI after", - "from CLI after", - }, - }, - } - - for _, test := range tests { - var opts struct { - Config func(s string) error `long:"config" no-ini:"true"` - Value string `long:"value" required:"true"` - Default string `long:"default" required:"true" default:"from default"` - } - - p := NewParser(&opts, Default) - - opts.Config = func(s string) error { - ini := NewIniParser(p) - - return ini.Parse(bytes.NewBufferString("value = from INI\ndefault = from INI")) - } - - _, err := p.ParseArgs(test.args) - if err != nil { - t.Fatalf("Unexpected error %s with args %+v", err, test.args) - } - - if opts.Value != test.expected[0] { - t.Fatalf("Expected Value to be \"%s\" but was \"%s\" with args %+v", test.expected[0], opts.Value, test.args) - } - - if opts.Default != test.expected[1] { - t.Fatalf("Expected Default to be \"%s\" but was \"%s\" with args %+v", test.expected[1], opts.Default, test.args) - } - } -} diff --git a/vendor/github.com/jessevdk/go-flags/long_test.go b/vendor/github.com/jessevdk/go-flags/long_test.go deleted file mode 100644 index 02fc8c70..00000000 --- a/vendor/github.com/jessevdk/go-flags/long_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package flags - -import ( - "testing" -) - -func TestLong(t *testing.T) { - var opts = struct { - Value bool `long:"value"` - }{} - - ret := assertParseSuccess(t, &opts, "--value") - - assertStringArray(t, ret, []string{}) - - if !opts.Value { - t.Errorf("Expected Value to be true") - } -} - -func TestLongArg(t *testing.T) { - var opts = struct { - Value string `long:"value"` - }{} - - ret := assertParseSuccess(t, &opts, "--value", "value") - - assertStringArray(t, ret, []string{}) - assertString(t, opts.Value, "value") -} - -func TestLongArgEqual(t *testing.T) { - var opts = struct { - Value string `long:"value"` - }{} - - ret := assertParseSuccess(t, &opts, "--value=value") - - assertStringArray(t, ret, []string{}) - assertString(t, opts.Value, "value") -} - -func TestLongDefault(t *testing.T) { - var opts = struct { - Value string `long:"value" default:"value"` - }{} - - ret := assertParseSuccess(t, &opts) - - assertStringArray(t, ret, []string{}) - assertString(t, opts.Value, "value") -} - -func TestLongOptional(t *testing.T) { - var opts = struct { - Value string `long:"value" optional:"yes" optional-value:"value"` - }{} - - ret := assertParseSuccess(t, &opts, "--value") - - assertStringArray(t, ret, []string{}) - assertString(t, opts.Value, "value") -} - -func TestLongOptionalArg(t *testing.T) { - var opts = struct { - Value string `long:"value" optional:"yes" optional-value:"value"` - }{} - - ret := assertParseSuccess(t, &opts, "--value", "no") - - assertStringArray(t, ret, []string{"no"}) - assertString(t, opts.Value, "value") -} - -func TestLongOptionalArgEqual(t *testing.T) { - var opts = struct { - Value string `long:"value" optional:"yes" optional-value:"value"` - }{} - - ret := assertParseSuccess(t, &opts, "--value=value", "no") - - assertStringArray(t, ret, []string{"no"}) - assertString(t, opts.Value, "value") -} diff --git a/vendor/github.com/jessevdk/go-flags/marshal_test.go b/vendor/github.com/jessevdk/go-flags/marshal_test.go deleted file mode 100644 index 095e9e44..00000000 --- a/vendor/github.com/jessevdk/go-flags/marshal_test.go +++ /dev/null @@ -1,97 +0,0 @@ -package flags - -import ( - "fmt" - "testing" -) - -type marshalled string - -func (m *marshalled) UnmarshalFlag(value string) error { - if value == "yes" { - *m = "true" - } else if value == "no" { - *m = "false" - } else { - return fmt.Errorf("`%s' is not a valid value, please specify `yes' or `no'", value) - } - - return nil -} - -func (m marshalled) MarshalFlag() (string, error) { - if m == "true" { - return "yes", nil - } - - return "no", nil -} - -type marshalledError bool - -func (m marshalledError) MarshalFlag() (string, error) { - return "", newErrorf(ErrMarshal, "Failed to marshal") -} - -func TestUnmarshal(t *testing.T) { - var opts = struct { - Value marshalled `short:"v"` - }{} - - ret := assertParseSuccess(t, &opts, "-v=yes") - - assertStringArray(t, ret, []string{}) - - if opts.Value != "true" { - t.Errorf("Expected Value to be \"true\"") - } -} - -func TestUnmarshalDefault(t *testing.T) { - var opts = struct { - Value marshalled `short:"v" default:"yes"` - }{} - - ret := assertParseSuccess(t, &opts) - - assertStringArray(t, ret, []string{}) - - if opts.Value != "true" { - t.Errorf("Expected Value to be \"true\"") - } -} - -func TestUnmarshalOptional(t *testing.T) { - var opts = struct { - Value marshalled `short:"v" optional:"yes" optional-value:"yes"` - }{} - - ret := assertParseSuccess(t, &opts, "-v") - - assertStringArray(t, ret, []string{}) - - if opts.Value != "true" { - t.Errorf("Expected Value to be \"true\"") - } -} - -func TestUnmarshalError(t *testing.T) { - var opts = struct { - Value marshalled `short:"v"` - }{} - - assertParseFail(t, ErrMarshal, fmt.Sprintf("invalid argument for flag `%cv' (expected flags.marshalled): `invalid' is not a valid value, please specify `yes' or `no'", defaultShortOptDelimiter), &opts, "-vinvalid") -} - -func TestMarshalError(t *testing.T) { - var opts = struct { - Value marshalledError `short:"v"` - }{} - - p := NewParser(&opts, Default) - o := p.Command.Groups()[0].Options()[0] - - _, err := convertToString(o.value, o.tag) - - assertError(t, err, ErrMarshal, "Failed to marshal") -} diff --git a/vendor/github.com/jessevdk/go-flags/option.go b/vendor/github.com/jessevdk/go-flags/option.go index b2a69c70..ea09fb4a 100644 --- a/vendor/github.com/jessevdk/go-flags/option.go +++ b/vendor/github.com/jessevdk/go-flags/option.go @@ -82,6 +82,7 @@ type Option struct { tag multiTag isSet bool + isSetDefault bool preventDefault bool defaultLiteral string @@ -168,11 +169,21 @@ func (option *Option) Value() interface{} { return option.value.Interface() } +// Field returns the reflect struct field of the option. +func (option *Option) Field() reflect.StructField { + return option.field +} + // IsSet returns true if option has been set func (option *Option) IsSet() bool { return option.isSet } +// IsSetDefault returns true if option has been set via the default option tag +func (option *Option) IsSetDefault() bool { + return option.isSetDefault +} + // Set the value of an option to the specified value. An error will be returned // if the specified value could not be converted to the corresponding option // value type. @@ -262,11 +273,14 @@ func (option *Option) clearDefault() { } } + option.isSetDefault = true + if len(usedDefault) > 0 { option.empty() for _, d := range usedDefault { option.set(&d) + option.isSetDefault = true } } else { tp := option.value.Type() @@ -332,14 +346,27 @@ func (option *Option) isBool() bool { for { switch tp.Kind() { + case reflect.Slice, reflect.Ptr: + tp = tp.Elem() case reflect.Bool: return true - case reflect.Slice: - return (tp.Elem().Kind() == reflect.Bool) case reflect.Func: return tp.NumIn() == 0 - case reflect.Ptr: + default: + return false + } + } +} + +func (option *Option) isSignedNumber() bool { + tp := option.value.Type() + + for { + switch tp.Kind() { + case reflect.Slice, reflect.Ptr: tp = tp.Elem() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float32, reflect.Float64: + return true default: return false } diff --git a/vendor/github.com/jessevdk/go-flags/options_test.go b/vendor/github.com/jessevdk/go-flags/options_test.go deleted file mode 100644 index b0fe9f45..00000000 --- a/vendor/github.com/jessevdk/go-flags/options_test.go +++ /dev/null @@ -1,45 +0,0 @@ -package flags - -import ( - "testing" -) - -func TestPassDoubleDash(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - }{} - - p := NewParser(&opts, PassDoubleDash) - ret, err := p.ParseArgs([]string{"-v", "--", "-v", "-g"}) - - if err != nil { - t.Fatalf("Unexpected error: %v", err) - return - } - - if !opts.Value { - t.Errorf("Expected Value to be true") - } - - assertStringArray(t, ret, []string{"-v", "-g"}) -} - -func TestPassAfterNonOption(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - }{} - - p := NewParser(&opts, PassAfterNonOption) - ret, err := p.ParseArgs([]string{"-v", "arg", "-v", "-g"}) - - if err != nil { - t.Fatalf("Unexpected error: %v", err) - return - } - - if !opts.Value { - t.Errorf("Expected Value to be true") - } - - assertStringArray(t, ret, []string{"arg", "-v", "-g"}) -} diff --git a/vendor/github.com/jessevdk/go-flags/optstyle_other.go b/vendor/github.com/jessevdk/go-flags/optstyle_other.go index 29ca4b60..56dfdae1 100644 --- a/vendor/github.com/jessevdk/go-flags/optstyle_other.go +++ b/vendor/github.com/jessevdk/go-flags/optstyle_other.go @@ -1,4 +1,4 @@ -// +build !windows +// +build !windows forceposix package flags diff --git a/vendor/github.com/jessevdk/go-flags/optstyle_windows.go b/vendor/github.com/jessevdk/go-flags/optstyle_windows.go index a51de9cb..f3f28aee 100644 --- a/vendor/github.com/jessevdk/go-flags/optstyle_windows.go +++ b/vendor/github.com/jessevdk/go-flags/optstyle_windows.go @@ -1,3 +1,5 @@ +// +build !forceposix + package flags import ( diff --git a/vendor/github.com/jessevdk/go-flags/parser.go b/vendor/github.com/jessevdk/go-flags/parser.go index a52647cb..0a7922a0 100644 --- a/vendor/github.com/jessevdk/go-flags/parser.go +++ b/vendor/github.com/jessevdk/go-flags/parser.go @@ -87,7 +87,7 @@ const ( // -h and --help options. When either -h or --help is specified on the // command line, the parser will return the special error of type // ErrHelp. When PrintErrors is also specified, then the help message - // will also be automatically printed to os.Stderr. + // will also be automatically printed to os.Stdout. HelpFlag = 1 << iota // PassDoubleDash passes all arguments after a double dash, --, as @@ -100,7 +100,8 @@ const ( IgnoreUnknown // PrintErrors prints any errors which occurred during parsing to - // os.Stderr. + // os.Stderr. In the special case of ErrHelp, the message will be printed + // to os.Stdout. PrintErrors // PassAfterNonOption passes all arguments after the first non option @@ -203,6 +204,7 @@ func (p *Parser) ParseArgs(args []string) ([]string, error) { p.eachOption(func(c *Command, g *Group, option *Option) { option.isSet = false + option.isSetDefault = false option.updateDefaultLiteral() }) @@ -377,7 +379,7 @@ func (p *parseState) checkRequired(parser *Parser) error { var reqnames []string for _, arg := range p.positional { - argRequired := (!arg.isRemaining() && p.command.ArgsRequired) || arg.Required != 0 + argRequired := (!arg.isRemaining() && p.command.ArgsRequired) || arg.Required != -1 || arg.RequiredMaximum != -1 if !argRequired { continue @@ -394,6 +396,20 @@ func (p *parseState) checkRequired(parser *Parser) error { } reqnames = append(reqnames, "`"+arg.Name+" (at least "+fmt.Sprintf("%d", arg.Required)+" "+arguments+")`") + } else if arg.RequiredMaximum != -1 && arg.value.Len() > arg.RequiredMaximum { + if arg.RequiredMaximum == 0 { + reqnames = append(reqnames, "`"+arg.Name+" (zero arguments)`") + } else { + var arguments string + + if arg.RequiredMaximum > 1 { + arguments = "arguments, but got " + fmt.Sprintf("%d", arg.value.Len()) + } else { + arguments = "argument" + } + + reqnames = append(reqnames, "`"+arg.Name+" (at most "+fmt.Sprintf("%d", arg.RequiredMaximum)+" "+arguments+")`") + } } } else { reqnames = append(reqnames, "`"+arg.Name+"`") @@ -463,7 +479,7 @@ func (p *parseState) estimateCommand() error { msg = fmt.Sprintf("%s. You should use the %s command", msg, cmdnames[0]) - } else { + } else if len(cmdnames) > 1 { msg = fmt.Sprintf("%s. Please specify one command of: %s or %s", msg, strings.Join(cmdnames[:len(cmdnames)-1], ", "), @@ -474,7 +490,7 @@ func (p *parseState) estimateCommand() error { if len(cmdnames) == 1 { msg = fmt.Sprintf("Please specify the %s command", cmdnames[0]) - } else { + } else if len(cmdnames) > 1 { msg = fmt.Sprintf("Please specify one command of: %s or %s", strings.Join(cmdnames[:len(cmdnames)-1], ", "), cmdnames[len(cmdnames)-1]) @@ -499,7 +515,7 @@ func (p *Parser) parseOption(s *parseState, name string, option *Option, canarg } else { arg = s.pop() - if argumentIsOption(arg) { + if argumentIsOption(arg) && !(option.isSignedNumber() && len(arg) > 1 && arg[0] == '-' && arg[1] >= '0' && arg[1] <= '9') { return newErrorf(ErrExpectedArgument, "expected argument for flag `%s', but got option `%s'", option, arg) } else if p.Options&PassDoubleDash != 0 && arg == "--" { return newErrorf(ErrExpectedArgument, "expected argument for flag `%s', but got double dash `--'", option) @@ -601,6 +617,7 @@ func (p *parseState) addArgs(args ...string) error { arg := p.positional[0] if err := convert(args[0], arg.value, arg.tag); err != nil { + p.err = err return err } @@ -660,7 +677,13 @@ func (p *Parser) showBuiltinHelp() error { func (p *Parser) printError(err error) error { if err != nil && (p.Options&PrintErrors) != None { - fmt.Fprintln(os.Stderr, err) + flagsErr, ok := err.(*Error) + + if ok && flagsErr.Type == ErrHelp { + fmt.Fprintln(os.Stdout, err) + } else { + fmt.Fprintln(os.Stderr, err) + } } return err diff --git a/vendor/github.com/jessevdk/go-flags/parser_test.go b/vendor/github.com/jessevdk/go-flags/parser_test.go deleted file mode 100644 index 9f527b76..00000000 --- a/vendor/github.com/jessevdk/go-flags/parser_test.go +++ /dev/null @@ -1,591 +0,0 @@ -package flags - -import ( - "fmt" - "os" - "reflect" - "runtime" - "strconv" - "strings" - "testing" - "time" -) - -type defaultOptions struct { - Int int `long:"i"` - IntDefault int `long:"id" default:"1"` - - Float64 float64 `long:"f"` - Float64Default float64 `long:"fd" default:"-3.14"` - - NumericFlag bool `short:"3"` - - String string `long:"str"` - StringDefault string `long:"strd" default:"abc"` - StringNotUnquoted string `long:"strnot" unquote:"false"` - - Time time.Duration `long:"t"` - TimeDefault time.Duration `long:"td" default:"1m"` - - Map map[string]int `long:"m"` - MapDefault map[string]int `long:"md" default:"a:1"` - - Slice []int `long:"s"` - SliceDefault []int `long:"sd" default:"1" default:"2"` -} - -func TestDefaults(t *testing.T) { - var tests = []struct { - msg string - args []string - expected defaultOptions - }{ - { - msg: "no arguments, expecting default values", - args: []string{}, - expected: defaultOptions{ - Int: 0, - IntDefault: 1, - - Float64: 0.0, - Float64Default: -3.14, - - NumericFlag: false, - - String: "", - StringDefault: "abc", - - Time: 0, - TimeDefault: time.Minute, - - Map: map[string]int{}, - MapDefault: map[string]int{"a": 1}, - - Slice: []int{}, - SliceDefault: []int{1, 2}, - }, - }, - { - msg: "non-zero value arguments, expecting overwritten arguments", - args: []string{"--i=3", "--id=3", "--f=-2.71", "--fd=2.71", "-3", "--str=def", "--strd=def", "--t=3ms", "--td=3ms", "--m=c:3", "--md=c:3", "--s=3", "--sd=3"}, - expected: defaultOptions{ - Int: 3, - IntDefault: 3, - - Float64: -2.71, - Float64Default: 2.71, - - NumericFlag: true, - - String: "def", - StringDefault: "def", - - Time: 3 * time.Millisecond, - TimeDefault: 3 * time.Millisecond, - - Map: map[string]int{"c": 3}, - MapDefault: map[string]int{"c": 3}, - - Slice: []int{3}, - SliceDefault: []int{3}, - }, - }, - { - msg: "zero value arguments, expecting overwritten arguments", - args: []string{"--i=0", "--id=0", "--f=0", "--fd=0", "--str", "", "--strd=\"\"", "--t=0ms", "--td=0s", "--m=:0", "--md=:0", "--s=0", "--sd=0"}, - expected: defaultOptions{ - Int: 0, - IntDefault: 0, - - Float64: 0, - Float64Default: 0, - - String: "", - StringDefault: "", - - Time: 0, - TimeDefault: 0, - - Map: map[string]int{"": 0}, - MapDefault: map[string]int{"": 0}, - - Slice: []int{0}, - SliceDefault: []int{0}, - }, - }, - } - - for _, test := range tests { - var opts defaultOptions - - _, err := ParseArgs(&opts, test.args) - if err != nil { - t.Fatalf("%s:\nUnexpected error: %v", test.msg, err) - } - - if opts.Slice == nil { - opts.Slice = []int{} - } - - if !reflect.DeepEqual(opts, test.expected) { - t.Errorf("%s:\nUnexpected options with arguments %+v\nexpected\n%+v\nbut got\n%+v\n", test.msg, test.args, test.expected, opts) - } - } -} - -func TestNoDefaultsForBools(t *testing.T) { - var opts struct { - DefaultBool bool `short:"d" default:"true"` - } - - if runtime.GOOS == "windows" { - assertParseFail(t, ErrInvalidTag, "boolean flag `/d' may not have default values, they always default to `false' and can only be turned on", &opts) - } else { - assertParseFail(t, ErrInvalidTag, "boolean flag `-d' may not have default values, they always default to `false' and can only be turned on", &opts) - } -} - -func TestUnquoting(t *testing.T) { - var tests = []struct { - arg string - err error - value string - }{ - { - arg: "\"abc", - err: strconv.ErrSyntax, - value: "", - }, - { - arg: "\"\"abc\"", - err: strconv.ErrSyntax, - value: "", - }, - { - arg: "\"abc\"", - err: nil, - value: "abc", - }, - { - arg: "\"\\\"abc\\\"\"", - err: nil, - value: "\"abc\"", - }, - { - arg: "\"\\\"abc\"", - err: nil, - value: "\"abc", - }, - } - - for _, test := range tests { - var opts defaultOptions - - for _, delimiter := range []bool{false, true} { - p := NewParser(&opts, None) - - var err error - if delimiter { - _, err = p.ParseArgs([]string{"--str=" + test.arg, "--strnot=" + test.arg}) - } else { - _, err = p.ParseArgs([]string{"--str", test.arg, "--strnot", test.arg}) - } - - if test.err == nil { - if err != nil { - t.Fatalf("Expected no error but got: %v", err) - } - - if test.value != opts.String { - t.Fatalf("Expected String to be %q but got %q", test.value, opts.String) - } - if q := strconv.Quote(test.value); q != opts.StringNotUnquoted { - t.Fatalf("Expected StringDefault to be %q but got %q", q, opts.StringNotUnquoted) - } - } else { - if err == nil { - t.Fatalf("Expected error") - } else if e, ok := err.(*Error); ok { - if strings.HasPrefix(e.Message, test.err.Error()) { - t.Fatalf("Expected error message to end with %q but got %v", test.err.Error(), e.Message) - } - } - } - } - } -} - -// EnvRestorer keeps a copy of a set of env variables and can restore the env from them -type EnvRestorer struct { - env map[string]string -} - -func (r *EnvRestorer) Restore() { - os.Clearenv() - - for k, v := range r.env { - os.Setenv(k, v) - } -} - -// EnvSnapshot returns a snapshot of the currently set env variables -func EnvSnapshot() *EnvRestorer { - r := EnvRestorer{make(map[string]string)} - - for _, kv := range os.Environ() { - parts := strings.SplitN(kv, "=", 2) - - if len(parts) != 2 { - panic("got a weird env variable: " + kv) - } - - r.env[parts[0]] = parts[1] - } - - return &r -} - -type envDefaultOptions struct { - Int int `long:"i" default:"1" env:"TEST_I"` - Time time.Duration `long:"t" default:"1m" env:"TEST_T"` - Map map[string]int `long:"m" default:"a:1" env:"TEST_M" env-delim:";"` - Slice []int `long:"s" default:"1" default:"2" env:"TEST_S" env-delim:","` -} - -func TestEnvDefaults(t *testing.T) { - var tests = []struct { - msg string - args []string - expected envDefaultOptions - env map[string]string - }{ - { - msg: "no arguments, no env, expecting default values", - args: []string{}, - expected: envDefaultOptions{ - Int: 1, - Time: time.Minute, - Map: map[string]int{"a": 1}, - Slice: []int{1, 2}, - }, - }, - { - msg: "no arguments, env defaults, expecting env default values", - args: []string{}, - expected: envDefaultOptions{ - Int: 2, - Time: 2 * time.Minute, - Map: map[string]int{"a": 2, "b": 3}, - Slice: []int{4, 5, 6}, - }, - env: map[string]string{ - "TEST_I": "2", - "TEST_T": "2m", - "TEST_M": "a:2;b:3", - "TEST_S": "4,5,6", - }, - }, - { - msg: "non-zero value arguments, expecting overwritten arguments", - args: []string{"--i=3", "--t=3ms", "--m=c:3", "--s=3"}, - expected: envDefaultOptions{ - Int: 3, - Time: 3 * time.Millisecond, - Map: map[string]int{"c": 3}, - Slice: []int{3}, - }, - env: map[string]string{ - "TEST_I": "2", - "TEST_T": "2m", - "TEST_M": "a:2;b:3", - "TEST_S": "4,5,6", - }, - }, - { - msg: "zero value arguments, expecting overwritten arguments", - args: []string{"--i=0", "--t=0ms", "--m=:0", "--s=0"}, - expected: envDefaultOptions{ - Int: 0, - Time: 0, - Map: map[string]int{"": 0}, - Slice: []int{0}, - }, - env: map[string]string{ - "TEST_I": "2", - "TEST_T": "2m", - "TEST_M": "a:2;b:3", - "TEST_S": "4,5,6", - }, - }, - } - - oldEnv := EnvSnapshot() - defer oldEnv.Restore() - - for _, test := range tests { - var opts envDefaultOptions - oldEnv.Restore() - for envKey, envValue := range test.env { - os.Setenv(envKey, envValue) - } - _, err := ParseArgs(&opts, test.args) - if err != nil { - t.Fatalf("%s:\nUnexpected error: %v", test.msg, err) - } - - if opts.Slice == nil { - opts.Slice = []int{} - } - - if !reflect.DeepEqual(opts, test.expected) { - t.Errorf("%s:\nUnexpected options with arguments %+v\nexpected\n%+v\nbut got\n%+v\n", test.msg, test.args, test.expected, opts) - } - } -} - -func TestOptionAsArgument(t *testing.T) { - var tests = []struct { - args []string - expectError bool - errType ErrorType - errMsg string - rest []string - }{ - { - // short option must not be accepted as argument - args: []string{"--string-slice", "foobar", "--string-slice", "-o"}, - expectError: true, - errType: ErrExpectedArgument, - errMsg: "expected argument for flag `" + defaultLongOptDelimiter + "string-slice', but got option `-o'", - }, - { - // long option must not be accepted as argument - args: []string{"--string-slice", "foobar", "--string-slice", "--other-option"}, - expectError: true, - errType: ErrExpectedArgument, - errMsg: "expected argument for flag `" + defaultLongOptDelimiter + "string-slice', but got option `--other-option'", - }, - { - // long option must not be accepted as argument - args: []string{"--string-slice", "--"}, - expectError: true, - errType: ErrExpectedArgument, - errMsg: "expected argument for flag `" + defaultLongOptDelimiter + "string-slice', but got double dash `--'", - }, - { - // quoted and appended option should be accepted as argument (even if it looks like an option) - args: []string{"--string-slice", "foobar", "--string-slice=\"--other-option\""}, - }, - { - // Accept any single character arguments including '-' - args: []string{"--string-slice", "-"}, - }, - { - // Do not accept arguments which start with '-' even if the next character is a digit - args: []string{"--string-slice", "-3.14"}, - expectError: true, - errType: ErrExpectedArgument, - errMsg: "expected argument for flag `" + defaultLongOptDelimiter + "string-slice', but got option `-3.14'", - }, - { - // Do not accept arguments which start with '-' if the next character is not a digit - args: []string{"--string-slice", "-character"}, - expectError: true, - errType: ErrExpectedArgument, - errMsg: "expected argument for flag `" + defaultLongOptDelimiter + "string-slice', but got option `-character'", - }, - { - args: []string{"-o", "-", "-"}, - rest: []string{"-", "-"}, - }, - } - var opts struct { - StringSlice []string `long:"string-slice"` - OtherOption bool `long:"other-option" short:"o"` - } - - for _, test := range tests { - if test.expectError { - assertParseFail(t, test.errType, test.errMsg, &opts, test.args...) - } else { - args := assertParseSuccess(t, &opts, test.args...) - - assertStringArray(t, args, test.rest) - } - } -} - -func TestUnknownFlagHandler(t *testing.T) { - - var opts struct { - Flag1 string `long:"flag1"` - Flag2 string `long:"flag2"` - } - - p := NewParser(&opts, None) - - var unknownFlag1 string - var unknownFlag2 bool - var unknownFlag3 string - - // Set up a callback to intercept unknown options during parsing - p.UnknownOptionHandler = func(option string, arg SplitArgument, args []string) ([]string, error) { - if option == "unknownFlag1" { - if argValue, ok := arg.Value(); ok { - unknownFlag1 = argValue - return args, nil - } - // consume a value from remaining args list - unknownFlag1 = args[0] - return args[1:], nil - } else if option == "unknownFlag2" { - // treat this one as a bool switch, don't consume any args - unknownFlag2 = true - return args, nil - } else if option == "unknownFlag3" { - if argValue, ok := arg.Value(); ok { - unknownFlag3 = argValue - return args, nil - } - // consume a value from remaining args list - unknownFlag3 = args[0] - return args[1:], nil - } - - return args, fmt.Errorf("Unknown flag: %v", option) - } - - // Parse args containing some unknown flags, verify that - // our callback can handle all of them - _, err := p.ParseArgs([]string{"--flag1=stuff", "--unknownFlag1", "blah", "--unknownFlag2", "--unknownFlag3=baz", "--flag2=foo"}) - - if err != nil { - assertErrorf(t, "Parser returned unexpected error %v", err) - } - - assertString(t, opts.Flag1, "stuff") - assertString(t, opts.Flag2, "foo") - assertString(t, unknownFlag1, "blah") - assertString(t, unknownFlag3, "baz") - - if !unknownFlag2 { - assertErrorf(t, "Flag should have been set by unknown handler, but had value: %v", unknownFlag2) - } - - // Parse args with unknown flags that callback doesn't handle, verify it returns error - _, err = p.ParseArgs([]string{"--flag1=stuff", "--unknownFlagX", "blah", "--flag2=foo"}) - - if err == nil { - assertErrorf(t, "Parser should have returned error, but returned nil") - } -} - -func TestChoices(t *testing.T) { - var opts struct { - Choice string `long:"choose" choice:"v1" choice:"v2"` - } - - assertParseFail(t, ErrInvalidChoice, "Invalid value `invalid' for option `"+defaultLongOptDelimiter+"choose'. Allowed values are: v1 or v2", &opts, "--choose", "invalid") - assertParseSuccess(t, &opts, "--choose", "v2") - assertString(t, opts.Choice, "v2") -} - -func TestEmbedded(t *testing.T) { - type embedded struct { - V bool `short:"v"` - } - var opts struct { - embedded - } - - assertParseSuccess(t, &opts, "-v") - - if !opts.V { - t.Errorf("Expected V to be true") - } -} - -type command struct { -} - -func (c *command) Execute(args []string) error { - return nil -} - -func TestCommandHandlerNoCommand(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - }{} - - parser := NewParser(&opts, Default&^PrintErrors) - - var executedCommand Commander - var executedArgs []string - - executed := false - - parser.CommandHandler = func(command Commander, args []string) error { - executed = true - - executedCommand = command - executedArgs = args - - return nil - } - - _, err := parser.ParseArgs([]string{"arg1", "arg2"}) - - if err != nil { - t.Fatalf("Unexpected parse error: %s", err) - } - - if !executed { - t.Errorf("Expected command handler to be executed") - } - - if executedCommand != nil { - t.Errorf("Did not exect an executed command") - } - - assertStringArray(t, executedArgs, []string{"arg1", "arg2"}) -} - -func TestCommandHandler(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - - Command command `command:"cmd"` - }{} - - parser := NewParser(&opts, Default&^PrintErrors) - - var executedCommand Commander - var executedArgs []string - - executed := false - - parser.CommandHandler = func(command Commander, args []string) error { - executed = true - - executedCommand = command - executedArgs = args - - return nil - } - - _, err := parser.ParseArgs([]string{"cmd", "arg1", "arg2"}) - - if err != nil { - t.Fatalf("Unexpected parse error: %s", err) - } - - if !executed { - t.Errorf("Expected command handler to be executed") - } - - if executedCommand == nil { - t.Errorf("Expected command handler to be executed") - } - - assertStringArray(t, executedArgs, []string{"arg1", "arg2"}) -} diff --git a/vendor/github.com/jessevdk/go-flags/pointer_test.go b/vendor/github.com/jessevdk/go-flags/pointer_test.go deleted file mode 100644 index e17445f6..00000000 --- a/vendor/github.com/jessevdk/go-flags/pointer_test.go +++ /dev/null @@ -1,81 +0,0 @@ -package flags - -import ( - "testing" -) - -func TestPointerBool(t *testing.T) { - var opts = struct { - Value *bool `short:"v"` - }{} - - ret := assertParseSuccess(t, &opts, "-v") - - assertStringArray(t, ret, []string{}) - - if !*opts.Value { - t.Errorf("Expected Value to be true") - } -} - -func TestPointerString(t *testing.T) { - var opts = struct { - Value *string `short:"v"` - }{} - - ret := assertParseSuccess(t, &opts, "-v", "value") - - assertStringArray(t, ret, []string{}) - assertString(t, *opts.Value, "value") -} - -func TestPointerSlice(t *testing.T) { - var opts = struct { - Value *[]string `short:"v"` - }{} - - ret := assertParseSuccess(t, &opts, "-v", "value1", "-v", "value2") - - assertStringArray(t, ret, []string{}) - assertStringArray(t, *opts.Value, []string{"value1", "value2"}) -} - -func TestPointerMap(t *testing.T) { - var opts = struct { - Value *map[string]int `short:"v"` - }{} - - ret := assertParseSuccess(t, &opts, "-v", "k1:2", "-v", "k2:-5") - - assertStringArray(t, ret, []string{}) - - if v, ok := (*opts.Value)["k1"]; !ok { - t.Errorf("Expected key \"k1\" to exist") - } else if v != 2 { - t.Errorf("Expected \"k1\" to be 2, but got %#v", v) - } - - if v, ok := (*opts.Value)["k2"]; !ok { - t.Errorf("Expected key \"k2\" to exist") - } else if v != -5 { - t.Errorf("Expected \"k2\" to be -5, but got %#v", v) - } -} - -type PointerGroup struct { - Value bool `short:"v"` -} - -func TestPointerGroup(t *testing.T) { - var opts = struct { - Group *PointerGroup `group:"Group Options"` - }{} - - ret := assertParseSuccess(t, &opts, "-v") - - assertStringArray(t, ret, []string{}) - - if !opts.Group.Value { - t.Errorf("Expected Group.Value to be true") - } -} diff --git a/vendor/github.com/jessevdk/go-flags/short_test.go b/vendor/github.com/jessevdk/go-flags/short_test.go deleted file mode 100644 index 95712c16..00000000 --- a/vendor/github.com/jessevdk/go-flags/short_test.go +++ /dev/null @@ -1,194 +0,0 @@ -package flags - -import ( - "fmt" - "testing" -) - -func TestShort(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - }{} - - ret := assertParseSuccess(t, &opts, "-v") - - assertStringArray(t, ret, []string{}) - - if !opts.Value { - t.Errorf("Expected Value to be true") - } -} - -func TestShortTooLong(t *testing.T) { - var opts = struct { - Value bool `short:"vv"` - }{} - - assertParseFail(t, ErrShortNameTooLong, "short names can only be 1 character long, not `vv'", &opts) -} - -func TestShortRequired(t *testing.T) { - var opts = struct { - Value bool `short:"v" required:"true"` - }{} - - assertParseFail(t, ErrRequired, fmt.Sprintf("the required flag `%cv' was not specified", defaultShortOptDelimiter), &opts) -} - -func TestShortMultiConcat(t *testing.T) { - var opts = struct { - V bool `short:"v"` - O bool `short:"o"` - F bool `short:"f"` - }{} - - ret := assertParseSuccess(t, &opts, "-vo", "-f") - - assertStringArray(t, ret, []string{}) - - if !opts.V { - t.Errorf("Expected V to be true") - } - - if !opts.O { - t.Errorf("Expected O to be true") - } - - if !opts.F { - t.Errorf("Expected F to be true") - } -} - -func TestShortMultiRequiredConcat(t *testing.T) { - var opts = struct { - V bool `short:"v" required:"true"` - O bool `short:"o" required:"true"` - F bool `short:"f" required:"true"` - }{} - - ret := assertParseSuccess(t, &opts, "-vo", "-f") - - assertStringArray(t, ret, []string{}) - - if !opts.V { - t.Errorf("Expected V to be true") - } - - if !opts.O { - t.Errorf("Expected O to be true") - } - - if !opts.F { - t.Errorf("Expected F to be true") - } -} - -func TestShortMultiSlice(t *testing.T) { - var opts = struct { - Values []bool `short:"v"` - }{} - - ret := assertParseSuccess(t, &opts, "-v", "-v") - - assertStringArray(t, ret, []string{}) - assertBoolArray(t, opts.Values, []bool{true, true}) -} - -func TestShortMultiSliceConcat(t *testing.T) { - var opts = struct { - Values []bool `short:"v"` - }{} - - ret := assertParseSuccess(t, &opts, "-vvv") - - assertStringArray(t, ret, []string{}) - assertBoolArray(t, opts.Values, []bool{true, true, true}) -} - -func TestShortWithEqualArg(t *testing.T) { - var opts = struct { - Value string `short:"v"` - }{} - - ret := assertParseSuccess(t, &opts, "-v=value") - - assertStringArray(t, ret, []string{}) - assertString(t, opts.Value, "value") -} - -func TestShortWithArg(t *testing.T) { - var opts = struct { - Value string `short:"v"` - }{} - - ret := assertParseSuccess(t, &opts, "-vvalue") - - assertStringArray(t, ret, []string{}) - assertString(t, opts.Value, "value") -} - -func TestShortArg(t *testing.T) { - var opts = struct { - Value string `short:"v"` - }{} - - ret := assertParseSuccess(t, &opts, "-v", "value") - - assertStringArray(t, ret, []string{}) - assertString(t, opts.Value, "value") -} - -func TestShortMultiWithEqualArg(t *testing.T) { - var opts = struct { - F []bool `short:"f"` - Value string `short:"v"` - }{} - - assertParseFail(t, ErrExpectedArgument, fmt.Sprintf("expected argument for flag `%cv'", defaultShortOptDelimiter), &opts, "-ffv=value") -} - -func TestShortMultiArg(t *testing.T) { - var opts = struct { - F []bool `short:"f"` - Value string `short:"v"` - }{} - - ret := assertParseSuccess(t, &opts, "-ffv", "value") - - assertStringArray(t, ret, []string{}) - assertBoolArray(t, opts.F, []bool{true, true}) - assertString(t, opts.Value, "value") -} - -func TestShortMultiArgConcatFail(t *testing.T) { - var opts = struct { - F []bool `short:"f"` - Value string `short:"v"` - }{} - - assertParseFail(t, ErrExpectedArgument, fmt.Sprintf("expected argument for flag `%cv'", defaultShortOptDelimiter), &opts, "-ffvvalue") -} - -func TestShortMultiArgConcat(t *testing.T) { - var opts = struct { - F []bool `short:"f"` - Value string `short:"v"` - }{} - - ret := assertParseSuccess(t, &opts, "-vff") - - assertStringArray(t, ret, []string{}) - assertString(t, opts.Value, "ff") -} - -func TestShortOptional(t *testing.T) { - var opts = struct { - F []bool `short:"f"` - Value string `short:"v" optional:"yes" optional-value:"value"` - }{} - - ret := assertParseSuccess(t, &opts, "-fv", "f") - - assertStringArray(t, ret, []string{"f"}) - assertString(t, opts.Value, "value") -} diff --git a/vendor/github.com/jessevdk/go-flags/tag_test.go b/vendor/github.com/jessevdk/go-flags/tag_test.go deleted file mode 100644 index 9daa7401..00000000 --- a/vendor/github.com/jessevdk/go-flags/tag_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package flags - -import ( - "testing" -) - -func TestTagMissingColon(t *testing.T) { - var opts = struct { - Value bool `short` - }{} - - assertParseFail(t, ErrTag, "expected `:' after key name, but got end of tag (in `short`)", &opts, "") -} - -func TestTagMissingValue(t *testing.T) { - var opts = struct { - Value bool `short:` - }{} - - assertParseFail(t, ErrTag, "expected `\"' to start tag value at end of tag (in `short:`)", &opts, "") -} - -func TestTagMissingQuote(t *testing.T) { - var opts = struct { - Value bool `short:"v` - }{} - - assertParseFail(t, ErrTag, "expected end of tag value `\"' at end of tag (in `short:\"v`)", &opts, "") -} - -func TestTagNewline(t *testing.T) { - var opts = struct { - Value bool `long:"verbose" description:"verbose -something"` - }{} - - assertParseFail(t, ErrTag, "unexpected newline in tag value `description' (in `long:\"verbose\" description:\"verbose\nsomething\"`)", &opts, "") -} diff --git a/vendor/github.com/jessevdk/go-flags/unknown_test.go b/vendor/github.com/jessevdk/go-flags/unknown_test.go deleted file mode 100644 index 858be458..00000000 --- a/vendor/github.com/jessevdk/go-flags/unknown_test.go +++ /dev/null @@ -1,66 +0,0 @@ -package flags - -import ( - "testing" -) - -func TestUnknownFlags(t *testing.T) { - var opts = struct { - Verbose []bool `short:"v" long:"verbose" description:"Verbose output"` - }{} - - args := []string{ - "-f", - } - - p := NewParser(&opts, 0) - args, err := p.ParseArgs(args) - - if err == nil { - t.Fatal("Expected error for unknown argument") - } -} - -func TestIgnoreUnknownFlags(t *testing.T) { - var opts = struct { - Verbose []bool `short:"v" long:"verbose" description:"Verbose output"` - }{} - - args := []string{ - "hello", - "world", - "-v", - "--foo=bar", - "--verbose", - "-f", - } - - p := NewParser(&opts, IgnoreUnknown) - args, err := p.ParseArgs(args) - - if err != nil { - t.Fatal(err) - } - - exargs := []string{ - "hello", - "world", - "--foo=bar", - "-f", - } - - issame := (len(args) == len(exargs)) - - if issame { - for i := 0; i < len(args); i++ { - if args[i] != exargs[i] { - issame = false - break - } - } - } - - if !issame { - t.Fatalf("Expected %v but got %v", exargs, args) - } -} diff --git a/vendor/github.com/juju/ratelimit/LICENSE b/vendor/github.com/juju/ratelimit/LICENSE deleted file mode 100644 index ade9307b..00000000 --- a/vendor/github.com/juju/ratelimit/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ -All files in this repository are licensed as follows. If you contribute -to this repository, it is assumed that you license your contribution -under the same license unless you state otherwise. - -All files Copyright (C) 2015 Canonical Ltd. unless otherwise specified in the file. - -This software is licensed under the LGPLv3, included below. - -As a special exception to the GNU Lesser General Public License version 3 -("LGPL3"), the copyright holders of this Library give you permission to -convey to a third party a Combined Work that links statically or dynamically -to this Library without providing any Minimal Corresponding Source or -Minimal Application Code as set out in 4d or providing the installation -information set out in section 4e, provided that you comply with the other -provisions of LGPL3 and provided that you meet, for the Application the -terms and conditions of the license(s) which apply to the Application. - -Except as stated in this special exception, the provisions of LGPL3 will -continue to comply in full to this Library. If you modify this Library, you -may apply this exception to your version of this Library, but you are not -obliged to do so. If you do not wish to do so, delete this exception -statement from your version. This exception does not (and cannot) modify any -license terms which apply to the Application, with which you must still -comply. - - - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/vendor/github.com/juju/ratelimit/README.md b/vendor/github.com/juju/ratelimit/README.md deleted file mode 100644 index a0fdfe2b..00000000 --- a/vendor/github.com/juju/ratelimit/README.md +++ /dev/null @@ -1,117 +0,0 @@ -# ratelimit --- - import "github.com/juju/ratelimit" - -The ratelimit package provides an efficient token bucket implementation. See -http://en.wikipedia.org/wiki/Token_bucket. - -## Usage - -#### func Reader - -```go -func Reader(r io.Reader, bucket *Bucket) io.Reader -``` -Reader returns a reader that is rate limited by the given token bucket. Each -token in the bucket represents one byte. - -#### func Writer - -```go -func Writer(w io.Writer, bucket *Bucket) io.Writer -``` -Writer returns a writer that is rate limited by the given token bucket. Each -token in the bucket represents one byte. - -#### type Bucket - -```go -type Bucket struct { -} -``` - -Bucket represents a token bucket that fills at a predetermined rate. Methods on -Bucket may be called concurrently. - -#### func NewBucket - -```go -func NewBucket(fillInterval time.Duration, capacity int64) *Bucket -``` -NewBucket returns a new token bucket that fills at the rate of one token every -fillInterval, up to the given maximum capacity. Both arguments must be positive. -The bucket is initially full. - -#### func NewBucketWithQuantum - -```go -func NewBucketWithQuantum(fillInterval time.Duration, capacity, quantum int64) *Bucket -``` -NewBucketWithQuantum is similar to NewBucket, but allows the specification of -the quantum size - quantum tokens are added every fillInterval. - -#### func NewBucketWithRate - -```go -func NewBucketWithRate(rate float64, capacity int64) *Bucket -``` -NewBucketWithRate returns a token bucket that fills the bucket at the rate of -rate tokens per second up to the given maximum capacity. Because of limited -clock resolution, at high rates, the actual rate may be up to 1% different from -the specified rate. - -#### func (*Bucket) Rate - -```go -func (tb *Bucket) Rate() float64 -``` -Rate returns the fill rate of the bucket, in tokens per second. - -#### func (*Bucket) Take - -```go -func (tb *Bucket) Take(count int64) time.Duration -``` -Take takes count tokens from the bucket without blocking. It returns the time -that the caller should wait until the tokens are actually available. - -Note that if the request is irrevocable - there is no way to return tokens to -the bucket once this method commits us to taking them. - -#### func (*Bucket) TakeAvailable - -```go -func (tb *Bucket) TakeAvailable(count int64) int64 -``` -TakeAvailable takes up to count immediately available tokens from the bucket. It -returns the number of tokens removed, or zero if there are no available tokens. -It does not block. - -#### func (*Bucket) TakeMaxDuration - -```go -func (tb *Bucket) TakeMaxDuration(count int64, maxWait time.Duration) (time.Duration, bool) -``` -TakeMaxDuration is like Take, except that it will only take tokens from the -bucket if the wait time for the tokens is no greater than maxWait. - -If it would take longer than maxWait for the tokens to become available, it does -nothing and reports false, otherwise it returns the time that the caller should -wait until the tokens are actually available, and reports true. - -#### func (*Bucket) Wait - -```go -func (tb *Bucket) Wait(count int64) -``` -Wait takes count tokens from the bucket, waiting until they are available. - -#### func (*Bucket) WaitMaxDuration - -```go -func (tb *Bucket) WaitMaxDuration(count int64, maxWait time.Duration) bool -``` -WaitMaxDuration is like Wait except that it will only take tokens from the -bucket if it needs to wait for no greater than maxWait. It reports whether any -tokens have been removed from the bucket If no tokens have been removed, it -returns immediately. diff --git a/vendor/github.com/juju/ratelimit/ratelimit.go b/vendor/github.com/juju/ratelimit/ratelimit.go deleted file mode 100644 index 3ef32fbc..00000000 --- a/vendor/github.com/juju/ratelimit/ratelimit.go +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright 2014 Canonical Ltd. -// Licensed under the LGPLv3 with static-linking exception. -// See LICENCE file for details. - -// The ratelimit package provides an efficient token bucket implementation -// that can be used to limit the rate of arbitrary things. -// See http://en.wikipedia.org/wiki/Token_bucket. -package ratelimit - -import ( - "math" - "strconv" - "sync" - "time" -) - -// Bucket represents a token bucket that fills at a predetermined rate. -// Methods on Bucket may be called concurrently. -type Bucket struct { - startTime time.Time - capacity int64 - quantum int64 - fillInterval time.Duration - - // The mutex guards the fields following it. - mu sync.Mutex - - // avail holds the number of available tokens - // in the bucket, as of availTick ticks from startTime. - // It will be negative when there are consumers - // waiting for tokens. - avail int64 - availTick int64 -} - -// NewBucket returns a new token bucket that fills at the -// rate of one token every fillInterval, up to the given -// maximum capacity. Both arguments must be -// positive. The bucket is initially full. -func NewBucket(fillInterval time.Duration, capacity int64) *Bucket { - return NewBucketWithQuantum(fillInterval, capacity, 1) -} - -// rateMargin specifes the allowed variance of actual -// rate from specified rate. 1% seems reasonable. -const rateMargin = 0.01 - -// NewBucketWithRate returns a token bucket that fills the bucket -// at the rate of rate tokens per second up to the given -// maximum capacity. Because of limited clock resolution, -// at high rates, the actual rate may be up to 1% different from the -// specified rate. -func NewBucketWithRate(rate float64, capacity int64) *Bucket { - for quantum := int64(1); quantum < 1<<50; quantum = nextQuantum(quantum) { - fillInterval := time.Duration(1e9 * float64(quantum) / rate) - if fillInterval <= 0 { - continue - } - tb := NewBucketWithQuantum(fillInterval, capacity, quantum) - if diff := math.Abs(tb.Rate() - rate); diff/rate <= rateMargin { - return tb - } - } - panic("cannot find suitable quantum for " + strconv.FormatFloat(rate, 'g', -1, 64)) -} - -// nextQuantum returns the next quantum to try after q. -// We grow the quantum exponentially, but slowly, so we -// get a good fit in the lower numbers. -func nextQuantum(q int64) int64 { - q1 := q * 11 / 10 - if q1 == q { - q1++ - } - return q1 -} - -// NewBucketWithQuantum is similar to NewBucket, but allows -// the specification of the quantum size - quantum tokens -// are added every fillInterval. -func NewBucketWithQuantum(fillInterval time.Duration, capacity, quantum int64) *Bucket { - if fillInterval <= 0 { - panic("token bucket fill interval is not > 0") - } - if capacity <= 0 { - panic("token bucket capacity is not > 0") - } - if quantum <= 0 { - panic("token bucket quantum is not > 0") - } - return &Bucket{ - startTime: time.Now(), - capacity: capacity, - quantum: quantum, - avail: capacity, - fillInterval: fillInterval, - } -} - -// Wait takes count tokens from the bucket, waiting until they are -// available. -func (tb *Bucket) Wait(count int64) { - if d := tb.Take(count); d > 0 { - time.Sleep(d) - } -} - -// WaitMaxDuration is like Wait except that it will -// only take tokens from the bucket if it needs to wait -// for no greater than maxWait. It reports whether -// any tokens have been removed from the bucket -// If no tokens have been removed, it returns immediately. -func (tb *Bucket) WaitMaxDuration(count int64, maxWait time.Duration) bool { - d, ok := tb.TakeMaxDuration(count, maxWait) - if d > 0 { - time.Sleep(d) - } - return ok -} - -const infinityDuration time.Duration = 0x7fffffffffffffff - -// Take takes count tokens from the bucket without blocking. It returns -// the time that the caller should wait until the tokens are actually -// available. -// -// Note that if the request is irrevocable - there is no way to return -// tokens to the bucket once this method commits us to taking them. -func (tb *Bucket) Take(count int64) time.Duration { - d, _ := tb.take(time.Now(), count, infinityDuration) - return d -} - -// TakeMaxDuration is like Take, except that -// it will only take tokens from the bucket if the wait -// time for the tokens is no greater than maxWait. -// -// If it would take longer than maxWait for the tokens -// to become available, it does nothing and reports false, -// otherwise it returns the time that the caller should -// wait until the tokens are actually available, and reports -// true. -func (tb *Bucket) TakeMaxDuration(count int64, maxWait time.Duration) (time.Duration, bool) { - return tb.take(time.Now(), count, maxWait) -} - -// TakeAvailable takes up to count immediately available tokens from the -// bucket. It returns the number of tokens removed, or zero if there are -// no available tokens. It does not block. -func (tb *Bucket) TakeAvailable(count int64) int64 { - return tb.takeAvailable(time.Now(), count) -} - -// takeAvailable is the internal version of TakeAvailable - it takes the -// current time as an argument to enable easy testing. -func (tb *Bucket) takeAvailable(now time.Time, count int64) int64 { - if count <= 0 { - return 0 - } - tb.mu.Lock() - defer tb.mu.Unlock() - - tb.adjust(now) - if tb.avail <= 0 { - return 0 - } - if count > tb.avail { - count = tb.avail - } - tb.avail -= count - return count -} - -// Available returns the number of available tokens. It will be negative -// when there are consumers waiting for tokens. Note that if this -// returns greater than zero, it does not guarantee that calls that take -// tokens from the buffer will succeed, as the number of available -// tokens could have changed in the meantime. This method is intended -// primarily for metrics reporting and debugging. -func (tb *Bucket) Available() int64 { - return tb.available(time.Now()) -} - -// available is the internal version of available - it takes the current time as -// an argument to enable easy testing. -func (tb *Bucket) available(now time.Time) int64 { - tb.mu.Lock() - defer tb.mu.Unlock() - tb.adjust(now) - return tb.avail -} - -// Capacity returns the capacity that the bucket was created with. -func (tb *Bucket) Capacity() int64 { - return tb.capacity -} - -// Rate returns the fill rate of the bucket, in tokens per second. -func (tb *Bucket) Rate() float64 { - return 1e9 * float64(tb.quantum) / float64(tb.fillInterval) -} - -// take is the internal version of Take - it takes the current time as -// an argument to enable easy testing. -func (tb *Bucket) take(now time.Time, count int64, maxWait time.Duration) (time.Duration, bool) { - if count <= 0 { - return 0, true - } - tb.mu.Lock() - defer tb.mu.Unlock() - - currentTick := tb.adjust(now) - avail := tb.avail - count - if avail >= 0 { - tb.avail = avail - return 0, true - } - // Round up the missing tokens to the nearest multiple - // of quantum - the tokens won't be available until - // that tick. - endTick := currentTick + (-avail+tb.quantum-1)/tb.quantum - endTime := tb.startTime.Add(time.Duration(endTick) * tb.fillInterval) - waitTime := endTime.Sub(now) - if waitTime > maxWait { - return 0, false - } - tb.avail = avail - return waitTime, true -} - -// adjust adjusts the current bucket capacity based on the current time. -// It returns the current tick. -func (tb *Bucket) adjust(now time.Time) (currentTick int64) { - currentTick = int64(now.Sub(tb.startTime) / tb.fillInterval) - - if tb.avail >= tb.capacity { - return - } - tb.avail += (currentTick - tb.availTick) * tb.quantum - if tb.avail > tb.capacity { - tb.avail = tb.capacity - } - tb.availTick = currentTick - return -} diff --git a/vendor/github.com/juju/ratelimit/ratelimit_test.go b/vendor/github.com/juju/ratelimit/ratelimit_test.go deleted file mode 100644 index 62d88ded..00000000 --- a/vendor/github.com/juju/ratelimit/ratelimit_test.go +++ /dev/null @@ -1,389 +0,0 @@ -// Copyright 2014 Canonical Ltd. -// Licensed under the LGPLv3 with static-linking exception. -// See LICENCE file for details. - -package ratelimit - -import ( - "math" - "testing" - "time" - - gc "gopkg.in/check.v1" -) - -func TestPackage(t *testing.T) { - gc.TestingT(t) -} - -type rateLimitSuite struct{} - -var _ = gc.Suite(rateLimitSuite{}) - -type takeReq struct { - time time.Duration - count int64 - expectWait time.Duration -} - -var takeTests = []struct { - about string - fillInterval time.Duration - capacity int64 - reqs []takeReq -}{{ - about: "serial requests", - fillInterval: 250 * time.Millisecond, - capacity: 10, - reqs: []takeReq{{ - time: 0, - count: 0, - expectWait: 0, - }, { - time: 0, - count: 10, - expectWait: 0, - }, { - time: 0, - count: 1, - expectWait: 250 * time.Millisecond, - }, { - time: 250 * time.Millisecond, - count: 1, - expectWait: 250 * time.Millisecond, - }}, -}, { - about: "concurrent requests", - fillInterval: 250 * time.Millisecond, - capacity: 10, - reqs: []takeReq{{ - time: 0, - count: 10, - expectWait: 0, - }, { - time: 0, - count: 2, - expectWait: 500 * time.Millisecond, - }, { - time: 0, - count: 2, - expectWait: 1000 * time.Millisecond, - }, { - time: 0, - count: 1, - expectWait: 1250 * time.Millisecond, - }}, -}, { - about: "more than capacity", - fillInterval: 1 * time.Millisecond, - capacity: 10, - reqs: []takeReq{{ - time: 0, - count: 10, - expectWait: 0, - }, { - time: 20 * time.Millisecond, - count: 15, - expectWait: 5 * time.Millisecond, - }}, -}, { - about: "sub-quantum time", - fillInterval: 10 * time.Millisecond, - capacity: 10, - reqs: []takeReq{{ - time: 0, - count: 10, - expectWait: 0, - }, { - time: 7 * time.Millisecond, - count: 1, - expectWait: 3 * time.Millisecond, - }, { - time: 8 * time.Millisecond, - count: 1, - expectWait: 12 * time.Millisecond, - }}, -}, { - about: "within capacity", - fillInterval: 10 * time.Millisecond, - capacity: 5, - reqs: []takeReq{{ - time: 0, - count: 5, - expectWait: 0, - }, { - time: 60 * time.Millisecond, - count: 5, - expectWait: 0, - }, { - time: 60 * time.Millisecond, - count: 1, - expectWait: 10 * time.Millisecond, - }, { - time: 80 * time.Millisecond, - count: 2, - expectWait: 10 * time.Millisecond, - }}, -}} - -var availTests = []struct { - about string - capacity int64 - fillInterval time.Duration - take int64 - sleep time.Duration - - expectCountAfterTake int64 - expectCountAfterSleep int64 -}{{ - about: "should fill tokens after interval", - capacity: 5, - fillInterval: time.Second, - take: 5, - sleep: time.Second, - expectCountAfterTake: 0, - expectCountAfterSleep: 1, -}, { - about: "should fill tokens plus existing count", - capacity: 2, - fillInterval: time.Second, - take: 1, - sleep: time.Second, - expectCountAfterTake: 1, - expectCountAfterSleep: 2, -}, { - about: "shouldn't fill before interval", - capacity: 2, - fillInterval: 2 * time.Second, - take: 1, - sleep: time.Second, - expectCountAfterTake: 1, - expectCountAfterSleep: 1, -}, { - about: "should fill only once after 1*interval before 2*interval", - capacity: 2, - fillInterval: 2 * time.Second, - take: 1, - sleep: 3 * time.Second, - expectCountAfterTake: 1, - expectCountAfterSleep: 2, -}} - -func (rateLimitSuite) TestTake(c *gc.C) { - for i, test := range takeTests { - tb := NewBucket(test.fillInterval, test.capacity) - for j, req := range test.reqs { - d, ok := tb.take(tb.startTime.Add(req.time), req.count, infinityDuration) - c.Assert(ok, gc.Equals, true) - if d != req.expectWait { - c.Fatalf("test %d.%d, %s, got %v want %v", i, j, test.about, d, req.expectWait) - } - } - } -} - -func (rateLimitSuite) TestTakeMaxDuration(c *gc.C) { - for i, test := range takeTests { - tb := NewBucket(test.fillInterval, test.capacity) - for j, req := range test.reqs { - if req.expectWait > 0 { - d, ok := tb.take(tb.startTime.Add(req.time), req.count, req.expectWait-1) - c.Assert(ok, gc.Equals, false) - c.Assert(d, gc.Equals, time.Duration(0)) - } - d, ok := tb.take(tb.startTime.Add(req.time), req.count, req.expectWait) - c.Assert(ok, gc.Equals, true) - if d != req.expectWait { - c.Fatalf("test %d.%d, %s, got %v want %v", i, j, test.about, d, req.expectWait) - } - } - } -} - -type takeAvailableReq struct { - time time.Duration - count int64 - expect int64 -} - -var takeAvailableTests = []struct { - about string - fillInterval time.Duration - capacity int64 - reqs []takeAvailableReq -}{{ - about: "serial requests", - fillInterval: 250 * time.Millisecond, - capacity: 10, - reqs: []takeAvailableReq{{ - time: 0, - count: 0, - expect: 0, - }, { - time: 0, - count: 10, - expect: 10, - }, { - time: 0, - count: 1, - expect: 0, - }, { - time: 250 * time.Millisecond, - count: 1, - expect: 1, - }}, -}, { - about: "concurrent requests", - fillInterval: 250 * time.Millisecond, - capacity: 10, - reqs: []takeAvailableReq{{ - time: 0, - count: 5, - expect: 5, - }, { - time: 0, - count: 2, - expect: 2, - }, { - time: 0, - count: 5, - expect: 3, - }, { - time: 0, - count: 1, - expect: 0, - }}, -}, { - about: "more than capacity", - fillInterval: 1 * time.Millisecond, - capacity: 10, - reqs: []takeAvailableReq{{ - time: 0, - count: 10, - expect: 10, - }, { - time: 20 * time.Millisecond, - count: 15, - expect: 10, - }}, -}, { - about: "within capacity", - fillInterval: 10 * time.Millisecond, - capacity: 5, - reqs: []takeAvailableReq{{ - time: 0, - count: 5, - expect: 5, - }, { - time: 60 * time.Millisecond, - count: 5, - expect: 5, - }, { - time: 70 * time.Millisecond, - count: 1, - expect: 1, - }}, -}} - -func (rateLimitSuite) TestTakeAvailable(c *gc.C) { - for i, test := range takeAvailableTests { - tb := NewBucket(test.fillInterval, test.capacity) - for j, req := range test.reqs { - d := tb.takeAvailable(tb.startTime.Add(req.time), req.count) - if d != req.expect { - c.Fatalf("test %d.%d, %s, got %v want %v", i, j, test.about, d, req.expect) - } - } - } -} - -func (rateLimitSuite) TestPanics(c *gc.C) { - c.Assert(func() { NewBucket(0, 1) }, gc.PanicMatches, "token bucket fill interval is not > 0") - c.Assert(func() { NewBucket(-2, 1) }, gc.PanicMatches, "token bucket fill interval is not > 0") - c.Assert(func() { NewBucket(1, 0) }, gc.PanicMatches, "token bucket capacity is not > 0") - c.Assert(func() { NewBucket(1, -2) }, gc.PanicMatches, "token bucket capacity is not > 0") -} - -func isCloseTo(x, y, tolerance float64) bool { - return math.Abs(x-y)/y < tolerance -} - -func (rateLimitSuite) TestRate(c *gc.C) { - tb := NewBucket(1, 1) - if !isCloseTo(tb.Rate(), 1e9, 0.00001) { - c.Fatalf("got %v want 1e9", tb.Rate()) - } - tb = NewBucket(2*time.Second, 1) - if !isCloseTo(tb.Rate(), 0.5, 0.00001) { - c.Fatalf("got %v want 0.5", tb.Rate()) - } - tb = NewBucketWithQuantum(100*time.Millisecond, 1, 5) - if !isCloseTo(tb.Rate(), 50, 0.00001) { - c.Fatalf("got %v want 50", tb.Rate()) - } -} - -func checkRate(c *gc.C, rate float64) { - tb := NewBucketWithRate(rate, 1<<62) - if !isCloseTo(tb.Rate(), rate, rateMargin) { - c.Fatalf("got %g want %v", tb.Rate(), rate) - } - d, ok := tb.take(tb.startTime, 1<<62, infinityDuration) - c.Assert(ok, gc.Equals, true) - c.Assert(d, gc.Equals, time.Duration(0)) - - // Check that the actual rate is as expected by - // asking for a not-quite multiple of the bucket's - // quantum and checking that the wait time - // correct. - d, ok = tb.take(tb.startTime, tb.quantum*2-tb.quantum/2, infinityDuration) - c.Assert(ok, gc.Equals, true) - expectTime := 1e9 * float64(tb.quantum) * 2 / rate - if !isCloseTo(float64(d), expectTime, rateMargin) { - c.Fatalf("rate %g: got %g want %v", rate, float64(d), expectTime) - } -} - -func (rateLimitSuite) TestNewWithRate(c *gc.C) { - for rate := float64(1); rate < 1e6; rate += 7 { - checkRate(c, rate) - } - for _, rate := range []float64{ - 1024 * 1024 * 1024, - 1e-5, - 0.9e-5, - 0.5, - 0.9, - 0.9e8, - 3e12, - 4e18, - } { - checkRate(c, rate) - checkRate(c, rate/3) - checkRate(c, rate*1.3) - } -} - -func TestAvailable(t *testing.T) { - for i, tt := range availTests { - tb := NewBucket(tt.fillInterval, tt.capacity) - if c := tb.takeAvailable(tb.startTime, tt.take); c != tt.take { - t.Fatalf("#%d: %s, take = %d, want = %d", i, tt.about, c, tt.take) - } - if c := tb.available(tb.startTime); c != tt.expectCountAfterTake { - t.Fatalf("#%d: %s, after take, available = %d, want = %d", i, tt.about, c, tt.expectCountAfterTake) - } - if c := tb.available(tb.startTime.Add(tt.sleep)); c != tt.expectCountAfterSleep { - t.Fatalf("#%d: %s, after some time it should fill in new tokens, available = %d, want = %d", - i, tt.about, c, tt.expectCountAfterSleep) - } - } - -} - -func BenchmarkWait(b *testing.B) { - tb := NewBucket(1, 16*1024) - for i := b.N - 1; i >= 0; i-- { - tb.Wait(1) - } -} diff --git a/vendor/github.com/juju/ratelimit/reader.go b/vendor/github.com/juju/ratelimit/reader.go deleted file mode 100644 index 6403bf78..00000000 --- a/vendor/github.com/juju/ratelimit/reader.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2014 Canonical Ltd. -// Licensed under the LGPLv3 with static-linking exception. -// See LICENCE file for details. - -package ratelimit - -import "io" - -type reader struct { - r io.Reader - bucket *Bucket -} - -// Reader returns a reader that is rate limited by -// the given token bucket. Each token in the bucket -// represents one byte. -func Reader(r io.Reader, bucket *Bucket) io.Reader { - return &reader{ - r: r, - bucket: bucket, - } -} - -func (r *reader) Read(buf []byte) (int, error) { - n, err := r.r.Read(buf) - if n <= 0 { - return n, err - } - r.bucket.Wait(int64(n)) - return n, err -} - -type writer struct { - w io.Writer - bucket *Bucket -} - -// Writer returns a reader that is rate limited by -// the given token bucket. Each token in the bucket -// represents one byte. -func Writer(w io.Writer, bucket *Bucket) io.Writer { - return &writer{ - w: w, - bucket: bucket, - } -} - -func (w *writer) Write(buf []byte) (int, error) { - w.bucket.Wait(int64(len(buf))) - return w.w.Write(buf) -} diff --git a/vendor/github.com/microcosm-cc/bluemonday/example_test.go b/vendor/github.com/microcosm-cc/bluemonday/example_test.go deleted file mode 100644 index e85f5dda..00000000 --- a/vendor/github.com/microcosm-cc/bluemonday/example_test.go +++ /dev/null @@ -1,240 +0,0 @@ -// Copyright (c) 2014, David Kitchen -// -// 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. -// -// * Neither the name of the organisation (Microcosm) nor the names of its -// contributors may 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. - -package bluemonday_test - -import ( - "fmt" - "regexp" - "strings" - - "github.com/microcosm-cc/bluemonday" -) - -func Example() { - // Create a new policy - p := bluemonday.NewPolicy() - - // Add elements to a policy without attributes - p.AllowElements("b", "strong") - - // Add elements as a virtue of adding an attribute - p.AllowAttrs("nowrap").OnElements("td", "th") - - // Attributes can either be added to all elements - p.AllowAttrs("dir").Globally() - - //Or attributes can be added to specific elements - p.AllowAttrs("value").OnElements("li") - - // It is ALWAYS recommended that an attribute be made to match a pattern - // XSS in HTML attributes is a very easy attack vector - - // \p{L} matches unicode letters, \p{N} matches unicode numbers - p.AllowAttrs("title").Matching(regexp.MustCompile(`[\p{L}\p{N}\s\-_',:\[\]!\./\\\(\)&]*`)).Globally() - - // You can stop at any time and call .Sanitize() - - // Assumes that string htmlIn was passed in from a HTTP POST and contains - // untrusted user generated content - htmlIn := `untrusted user generated content ` - fmt.Println(p.Sanitize(htmlIn)) - - // And you can take any existing policy and extend it - p = bluemonday.UGCPolicy() - p.AllowElements("fieldset", "select", "option") - - // Links are complex beasts and one of the biggest attack vectors for - // malicious content so we have included features specifically to help here. - - // This is not recommended: - p = bluemonday.NewPolicy() - p.AllowAttrs("href").Matching(regexp.MustCompile(`(?i)mailto|https?`)).OnElements("a") - - // The regexp is insufficient in this case to have prevented a malformed - // value doing something unexpected. - - // This will ensure that URLs are not considered invalid by Go's net/url - // package. - p.RequireParseableURLs(true) - - // If you have enabled parseable URLs then the following option will allow - // relative URLs. By default this is disabled and will prevent all local and - // schema relative URLs (i.e. `href="//www.google.com"` is schema relative). - p.AllowRelativeURLs(true) - - // If you have enabled parseable URLs then you can whitelist the schemas - // that are permitted. Bear in mind that allowing relative URLs in the above - // option allows for blank schemas. - p.AllowURLSchemes("mailto", "http", "https") - - // Regardless of whether you have enabled parseable URLs, you can force all - // URLs to have a rel="nofollow" attribute. This will be added if it does - // not exist. - - // This applies to "a" "area" "link" elements that have a "href" attribute - p.RequireNoFollowOnLinks(true) - - // We provide a convenience function that applies all of the above, but you - // will still need to whitelist the linkable elements: - p = bluemonday.NewPolicy() - p.AllowStandardURLs() - p.AllowAttrs("cite").OnElements("blockquote") - p.AllowAttrs("href").OnElements("a", "area") - p.AllowAttrs("src").OnElements("img") - - // Policy Building Helpers - - // If you've got this far and you're bored already, we also bundle some - // other convenience functions - p = bluemonday.NewPolicy() - p.AllowStandardAttributes() - p.AllowImages() - p.AllowLists() - p.AllowTables() -} - -func ExampleNewPolicy() { - // NewPolicy is a blank policy and we need to explicitly whitelist anything - // that we wish to allow through - p := bluemonday.NewPolicy() - - // We ensure any URLs are parseable and have rel="nofollow" where applicable - p.AllowStandardURLs() - - // AllowStandardURLs already ensures that the href will be valid, and so we - // can skip the .Matching() - p.AllowAttrs("href").OnElements("a") - - // We allow paragraphs too - p.AllowElements("p") - - html := p.Sanitize( - `

Google

`, - ) - - fmt.Println(html) - - // Output: - //

Google

-} - -func ExampleStrictPolicy() { - // StrictPolicy is equivalent to NewPolicy and as nothing else is declared - // we are stripping all elements (and their attributes) - p := bluemonday.StrictPolicy() - - html := p.Sanitize( - `Goodbye Cruel World`, - ) - - fmt.Println(html) - - // Output: - //Goodbye Cruel World -} - -func ExampleUGCPolicy() { - // UGCPolicy is a convenience policy for user generated content. - p := bluemonday.UGCPolicy() - - html := p.Sanitize( - `Google`, - ) - - fmt.Println(html) - - // Output: - //Google -} - -func ExamplePolicy_AllowAttrs() { - p := bluemonday.NewPolicy() - - // Allow the 'title' attribute on every HTML element that has been - // whitelisted - p.AllowAttrs("title").Matching(bluemonday.Paragraph).Globally() - - // Allow the 'abbr' attribute on only the 'td' and 'th' elements. - p.AllowAttrs("abbr").Matching(bluemonday.Paragraph).OnElements("td", "th") - - // Allow the 'colspan' and 'rowspan' attributes, matching a positive integer - // pattern, on only the 'td' and 'th' elements. - p.AllowAttrs("colspan", "rowspan").Matching( - bluemonday.Integer, - ).OnElements("td", "th") -} - -func ExamplePolicy_AllowElements() { - p := bluemonday.NewPolicy() - - // Allow styling elements without attributes - p.AllowElements("br", "div", "hr", "p", "span") -} - -func ExamplePolicy_Sanitize() { - // UGCPolicy is a convenience policy for user generated content. - p := bluemonday.UGCPolicy() - - // string in, string out - html := p.Sanitize(`Google`) - - fmt.Println(html) - - // Output: - //Google -} - -func ExamplePolicy_SanitizeBytes() { - // UGCPolicy is a convenience policy for user generated content. - p := bluemonday.UGCPolicy() - - // []byte in, []byte out - b := []byte(`Google`) - b = p.SanitizeBytes(b) - - fmt.Println(string(b)) - - // Output: - //Google -} - -func ExamplePolicy_SanitizeReader() { - // UGCPolicy is a convenience policy for user generated content. - p := bluemonday.UGCPolicy() - - // io.Reader in, bytes.Buffer out - r := strings.NewReader(`Google`) - buf := p.SanitizeReader(r) - - fmt.Println(buf.String()) - - // Output: - //Google -} diff --git a/vendor/github.com/microcosm-cc/bluemonday/helpers_test.go b/vendor/github.com/microcosm-cc/bluemonday/helpers_test.go deleted file mode 100644 index 6964e16c..00000000 --- a/vendor/github.com/microcosm-cc/bluemonday/helpers_test.go +++ /dev/null @@ -1,377 +0,0 @@ -// Copyright (c) 2014, David Kitchen -// -// 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. -// -// * Neither the name of the organisation (Microcosm) nor the names of its -// contributors may 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. - -package bluemonday - -import ( - "sync" - "testing" -) - -func TestRegexpVars(t *testing.T) { - // CellAlign - if !CellAlign.MatchString("CENTER") { - t.Error("CellAlign did not match: CENTER") - } - if !CellAlign.MatchString("justIFY") { - t.Error("CellAlign did not match: justIFY") - } - if !CellAlign.MatchString("left") { - t.Error("CellAlign did not match: left") - } - if !CellAlign.MatchString("right") { - t.Error("CellAlign did not match: right") - } - if !CellAlign.MatchString("char") { - t.Error("CellAlign did not match: char") - } - if CellAlign.MatchString("char char") { - t.Error("CellAlign matched: char char") - } - - // CellVerticalAlign - if !CellVerticalAlign.MatchString("BASELINE") { - t.Error("CellVerticalAlign did not match: BASELINE") - } - if !CellVerticalAlign.MatchString("boTtOM") { - t.Error("CellVerticalAlign did not match: boTtOM") - } - if !CellVerticalAlign.MatchString("middle") { - t.Error("CellVerticalAlign did not match: middle") - } - if !CellVerticalAlign.MatchString("top") { - t.Error("CellVerticalAlign did not match: top") - } - if CellVerticalAlign.MatchString("top top") { - t.Error("CellVerticalAlign matched: top top") - } - - // Direction - if !Direction.MatchString("RTL") { - t.Error("Direction did not match: RTL") - } - if !Direction.MatchString("ltr") { - t.Error("Direction did not match: ltr") - } - if Direction.MatchString("") { - t.Error("Direction matched: ") - } - if Direction.MatchString("rtltr") { - t.Error("Direction matched: rtltr") - } - if Direction.MatchString("rtl rtl") { - t.Error("Direction matched: rtl rtl") - } - - // ImageAlign - if !ImageAlign.MatchString("LEFT") { - t.Error("CellAlign did not match: LEFT") - } - if !ImageAlign.MatchString("right") { - t.Error("CellAlign did not match: right") - } - if !ImageAlign.MatchString("tOP") { - t.Error("CellAlign did not match: tOP") - } - if !ImageAlign.MatchString("texttop") { - t.Error("CellAlign did not match: texttop") - } - if !ImageAlign.MatchString("middle") { - t.Error("CellAlign did not match: middle") - } - if !ImageAlign.MatchString("absmiddle") { - t.Error("CellAlign did not match: absmiddle") - } - if !ImageAlign.MatchString("baseline") { - t.Error("CellAlign did not match: baseline") - } - if !ImageAlign.MatchString("bottom") { - t.Error("CellAlign did not match: bottom") - } - if !ImageAlign.MatchString("absbottom") { - t.Error("CellAlign did not match: absbottom") - } - if ImageAlign.MatchString("left right") { - t.Error("CellAlign matched: left right") - } - if ImageAlign.MatchString("left left") { - t.Error("CellAlign matched: left left") - } - if ImageAlign.MatchString("char") { - t.Error("CellAlign matched: char") - } - if ImageAlign.MatchString("char") { - t.Error("CellAlign matched: char") - } - - // Integer - if !Integer.MatchString("123") { - t.Error("Integer did not match: 123") - } - if !Integer.MatchString("0") { - t.Error("Integer did not match: 0") - } - if Integer.MatchString("-1") { - t.Error("Integer matched: -1") - } - if Integer.MatchString("1abc") { - t.Error("Integer matched: 1abc") - } - - // ISO8601 - if !ISO8601.MatchString("2014") { - t.Error("ISO8601 did not match: 2014") - } - if !ISO8601.MatchString("2014-02") { - t.Error("ISO8601 did not match: 2014-02") - } - if !ISO8601.MatchString("2014-02-28") { - t.Error("ISO8601 did not match: 2014-02-28") - } - if !ISO8601.MatchString("2014-02-28T23:59") { - t.Error("ISO8601 did not match: 2014-02-28T23:59") - } - if !ISO8601.MatchString("2014-02-28T23:59-05:00") { - t.Error("ISO8601 did not match: 2014-02-28T23:59-05:00") - } - if !ISO8601.MatchString("2014-02-28T23:59-05:00") { - t.Error("ISO8601 did not match: 2014-02-28T23:59+01:00") - } - if !ISO8601.MatchString("2014-02-28T23:59:59") { - t.Error("ISO8601 did not match: 2014-02-28T23:59:59") - } - if !ISO8601.MatchString("2014-02-28T23:59:59-05:00") { - t.Error("ISO8601 did not match: 2014-02-28T23:59:59-05:00") - } - if !ISO8601.MatchString("2014-02-28T23:59:59-05:00") { - t.Error("ISO8601 did not match: 2014-02-28T23:59:59+01:00") - } - if ISO8601.MatchString("201-") { - t.Error("ISO8601 matched: 201-") - } - if ISO8601.MatchString("2014-0") { - t.Error("ISO8601 matched: 2014-0") - } - if ISO8601.MatchString("2014-02-28-") { - t.Error("ISO8601 matched: 2014-02-28-") - } - if ISO8601.MatchString("20-02-28T23:59-05:00") { - t.Error("ISO8601 matched: 20-02-28T23:59+01:00") - } - if ISO8601.MatchString(" 2014-02-28T23:59:59") { - t.Error("ISO8601 matched: 2014-02-28T23:59:59") - } - - // ListType - if !ListType.MatchString("CIRCLE") { - t.Error("ListType did not match: CIRCLE") - } - if !ListType.MatchString("disc") { - t.Error("ListType did not match: disc") - } - if !ListType.MatchString("square") { - t.Error("ListType did not match: square") - } - if !ListType.MatchString("a") { - t.Error("ListType did not match: a") - } - if !ListType.MatchString("A") { - t.Error("ListType did not match: A") - } - if !ListType.MatchString("i") { - t.Error("ListType did not match: i") - } - if !ListType.MatchString("I") { - t.Error("ListType did not match: I") - } - if !ListType.MatchString("1") { - t.Error("ListType did not match: 1") - } - if ListType.MatchString("circle circle") { - t.Error("ListType matched: circle circle") - } - if ListType.MatchString("aa") { - t.Error("ListType matched: aa") - } - - // SpaceSeparatedTokens - if !SpaceSeparatedTokens.MatchString("nofollow") { - t.Error("SpaceSeparatedTokens did not match: nofollow") - } - if !SpaceSeparatedTokens.MatchString("nofollow person") { - t.Error("SpaceSeparatedTokens did not match: nofollow person") - } - if !SpaceSeparatedTokens.MatchString("header") { - t.Error("SpaceSeparatedTokens did not match: header") - } - if !SpaceSeparatedTokens.MatchString("bläh") { - t.Error("SpaceSeparatedTokens did not match: bläh") - } - if !SpaceSeparatedTokens.MatchString("blah bläh") { - t.Error("SpaceSeparatedTokens did not match: blah bläh") - } - if SpaceSeparatedTokens.MatchString("bläh blah ☃") { - t.Error("SpaceSeparatedTokens matched: bläh blah ☃") - } - if SpaceSeparatedTokens.MatchString("header javascript:alert(1)") { - t.Error("SpaceSeparatedTokens matched: header javascript:alert(1)") - } - if SpaceSeparatedTokens.MatchString("header >") { - t.Error("SpaceSeparatedTokens matched: header >") - } - - // Number - if !Number.MatchString("0") { - t.Error("Number did not match: 0") - } - if !Number.MatchString("1") { - t.Error("Number did not match: 1") - } - if !Number.MatchString("+1") { - t.Error("Number did not match: +1") - } - if !Number.MatchString("-1") { - t.Error("Number did not match: -1") - } - if !Number.MatchString("1.1") { - t.Error("Number did not match: 1.1") - } - if !Number.MatchString("1.2e3") { - t.Error("Number did not match: 1.2e3") - } - if !Number.MatchString("7E-10") { - t.Error("Number did not match: 7E-10") - } - if Number.MatchString("e7.13") { - t.Error("Number matched: e7.13") - } - if Number.MatchString(`7E`) { - t.Error(`Number matched: 7E`) - } - - // NumberOrPercent - if !NumberOrPercent.MatchString("0") { - t.Error("NumberOrPercent did not match: 0") - } - if !NumberOrPercent.MatchString("1") { - t.Error("NumberOrPercent did not match: 1") - } - if !NumberOrPercent.MatchString(`1%`) { - t.Error(`NumberOrPercent did not match: 1(percent)`) - } - if NumberOrPercent.MatchString("-1") { - t.Error("NumberOrPercent matched: -1") - } - if NumberOrPercent.MatchString("1.1") { - t.Error("NumberOrPercent matched: 1.1") - } - if NumberOrPercent.MatchString("1.2e3") { - t.Error("NumberOrPercent matched: 1.2e3") - } - if NumberOrPercent.MatchString("7E-10") { - t.Error("NumberOrPercent matched: 7E-10") - } - if NumberOrPercent.MatchString("e7.13") { - t.Error("NumberOrPercent matched: e7.13") - } - if NumberOrPercent.MatchString(`7E`) { - t.Error(`NumberOrPercent matched: 7E`) - } - - // Paragraph - if !Paragraph.MatchString("hello world") { - t.Error("Paragraph did not match: hello world") - } - if !Paragraph.MatchString("blah bläh blah") { - t.Error("Paragraph did not match: blah bläh blah") - } - if Paragraph.MatchString("bläh blah ☃") { - t.Error("Paragraph matched: bläh blah ☃") - } - if Paragraph.MatchString("javascript:alert(1)") { - t.Error("Paragraph matched: javascript:alert(1)") - } -} - -func TestAllowDataURIImages(t *testing.T) { - - p := NewPolicy() - p.AllowDataURIImages() - p.AllowImages() - - tests := []test{ - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - } - - wg := sync.WaitGroup{} - wg.Add(len(tests)) - for ii, tt := range tests { - go func(ii int, tt test) { - out := p.Sanitize(tt.in) - if out != tt.expected { - t.Errorf( - "test %d failed;\ninput : %s\noutput : %s\nexpected: %s", - ii, - tt.in, - out, - tt.expected, - ) - } - wg.Done() - }(ii, tt) - } - wg.Wait() -} diff --git a/vendor/github.com/microcosm-cc/bluemonday/policies_test.go b/vendor/github.com/microcosm-cc/bluemonday/policies_test.go deleted file mode 100644 index 2e89c8cb..00000000 --- a/vendor/github.com/microcosm-cc/bluemonday/policies_test.go +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright (c) 2014, David Kitchen -// -// 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. -// -// * Neither the name of the organisation (Microcosm) nor the names of its -// contributors may 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. - -package bluemonday - -import "testing" - -func TestStrictPolicy(t *testing.T) { - - p := StrictPolicy() - - tests := []test{ - { - in: "Hello, World!", - expected: "Hello, World!", - }, - { - in: "
Hello, World!", - expected: "Hello, World!", - }, - { // Real world example from a message board - in: `email me - addy in profile`, - expected: `email me - addy in profile`, - }, - {}, - } - - for ii, test := range tests { - out := p.Sanitize(test.in) - if out != test.expected { - t.Errorf( - "test %d failed;\ninput : %s\noutput : %s\nexpected: %s", - ii, - test.in, - out, - test.expected, - ) - } - } -} - -func TestUGCPolicy(t *testing.T) { - - tests := []test{ - // Simple formatting - {in: "Hello, World!", expected: "Hello, World!"}, - {in: "Hello, World!", expected: "Hello, World!"}, - // Blocks and formatting - { - in: "

Hello, World!

", - expected: "

Hello, World!

", - }, - { - in: "

Hello, World!

", - expected: "

Hello, World!

", - }, - // Inline tags featuring globals - { - in: `Hello, World!`, - expected: `Hello, World!`, - }, - { - in: `Hello, World!`, - expected: `Hello, World!`, - }, - // Images - { - in: `foo`, - expected: `foo`, - }, - { - in: ``, - expected: ``, - }, - { - in: `y`, - expected: `y`, - }, - { - in: `y`, - expected: `y`, - }, - // Anchors - { - in: `Link text`, - expected: `Link text`, - }, - { - in: `Link text`, - expected: `Link text`, - }, - { - in: `Link text`, - expected: `Link text`, - }, - { - in: `Link text`, - expected: `Link text`, - }, - { - in: `Link text`, - expected: `Link text`, - }, - { - in: `Link text`, - expected: `Link text`, - }, - { - in: `Link text`, - expected: `Link text`, - }, - { - in: `Header text`, - expected: `Header text`, - }, - // Image map and links - { - in: `123`, - expected: `123`, - }, - // Tables - { - in: `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `
Column OneColumn Two
` + - `Size 2` + - `Size 7
`, - expected: "" + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `` + - `
Column OneColumn Two
Size 2Size 7
`, - }, - // Ordering - { - in: `xssgoogle`, - expected: `xssgoogle`, - }, - // OWASP 25 June 2014 09:15 Strange behaviour - { - in: "Hallo\r\n\nEnde\n\r", - expected: "
Hallo\n\nEnde\n\n", - }, - } - - p := UGCPolicy() - - for ii, test := range tests { - out := p.Sanitize(test.in) - if out != test.expected { - t.Errorf( - "test %d failed;\ninput : %s\noutput : %s\nexpected: %s", - ii, - test.in, - out, - test.expected, - ) - } - } -} diff --git a/vendor/github.com/microcosm-cc/bluemonday/policy_test.go b/vendor/github.com/microcosm-cc/bluemonday/policy_test.go deleted file mode 100644 index ee9e2be6..00000000 --- a/vendor/github.com/microcosm-cc/bluemonday/policy_test.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2014, David Kitchen -// -// 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. -// -// * Neither the name of the organisation (Microcosm) nor the names of its -// contributors may 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. - -package bluemonday - -import "testing" - -func TestAllowElementsContent(t *testing.T) { - policy := NewPolicy().AllowElementsContent("iframe", "script") - - tests := []test{ - { - in: "", - expected: "this is fallback content", - }, - { - in: "", - expected: "var a = 10; alert(a);", - }, - } - - for ii, test := range tests { - out := policy.Sanitize(test.in) - if out != test.expected { - t.Errorf( - "test %d failed;\ninput : %s\noutput : %s\nexpected: %s", - ii, - test.in, - out, - test.expected, - ) - } - } -} diff --git a/vendor/github.com/microcosm-cc/bluemonday/sanitize_go1.8_test.go b/vendor/github.com/microcosm-cc/bluemonday/sanitize_go1.8_test.go deleted file mode 100644 index a6d00a94..00000000 --- a/vendor/github.com/microcosm-cc/bluemonday/sanitize_go1.8_test.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2014, David Kitchen -// -// 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. -// -// * Neither the name of the organisation (Microcosm) nor the names of its -// contributors may 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. - -// +build go1.8 - -package bluemonday - -import ( - "sync" - "testing" -) - -func TestXSSGo18(t *testing.T) { - - p := UGCPolicy() - - tests := []test{ - { - in: ``, - expected: ``, - }, - { - in: "", - expected: ``, - }, - } - - // These tests are run concurrently to enable the race detector to pick up - // potential issues - wg := sync.WaitGroup{} - wg.Add(len(tests)) - for ii, tt := range tests { - go func(ii int, tt test) { - out := p.Sanitize(tt.in) - if out != tt.expected { - t.Errorf( - "test %d failed;\ninput : %s\noutput : %s\nexpected: %s", - ii, - tt.in, - out, - tt.expected, - ) - } - wg.Done() - }(ii, tt) - } - wg.Wait() -} diff --git a/vendor/github.com/microcosm-cc/bluemonday/sanitize_ltgo1.8_test.go b/vendor/github.com/microcosm-cc/bluemonday/sanitize_ltgo1.8_test.go deleted file mode 100644 index a2000ce4..00000000 --- a/vendor/github.com/microcosm-cc/bluemonday/sanitize_ltgo1.8_test.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2014, David Kitchen -// -// 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. -// -// * Neither the name of the organisation (Microcosm) nor the names of its -// contributors may 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. - -// +build go1.1,!go1.8 - -package bluemonday - -import ( - "sync" - "testing" -) - -func TestXSSLTGo18(t *testing.T) { - - p := UGCPolicy() - - tests := []test{ - { - in: ``, - expected: ``, - }, - { - in: "", - expected: ``, - }, - } - - // These tests are run concurrently to enable the race detector to pick up - // potential issues - wg := sync.WaitGroup{} - wg.Add(len(tests)) - for ii, tt := range tests { - go func(ii int, tt test) { - out := p.Sanitize(tt.in) - if out != tt.expected { - t.Errorf( - "test %d failed;\ninput : %s\noutput : %s\nexpected: %s", - ii, - tt.in, - out, - tt.expected, - ) - } - wg.Done() - }(ii, tt) - } - wg.Wait() -} diff --git a/vendor/github.com/microcosm-cc/bluemonday/sanitize_test.go b/vendor/github.com/microcosm-cc/bluemonday/sanitize_test.go deleted file mode 100644 index f7c8a760..00000000 --- a/vendor/github.com/microcosm-cc/bluemonday/sanitize_test.go +++ /dev/null @@ -1,1686 +0,0 @@ -// Copyright (c) 2014, David Kitchen -// -// 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. -// -// * Neither the name of the organisation (Microcosm) nor the names of its -// contributors may 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. - -package bluemonday - -import ( - "encoding/base64" - "net/url" - "regexp" - "strings" - "sync" - "testing" -) - -// test is a simple input vs output struct used to construct a slice of many -// tests to run within a single test method. -type test struct { - in string - expected string -} - -func TestEmpty(t *testing.T) { - p := StrictPolicy() - - if "" != p.Sanitize(``) { - t.Error("Empty string is not empty") - } -} - -func TestSignatureBehaviour(t *testing.T) { - // https://github.com/microcosm-cc/bluemonday/issues/8 - p := UGCPolicy() - - input := "Hi.\n" - - if output := p.Sanitize(input); output != input { - t.Errorf(`Sanitize() input = %s, output = %s`, input, output) - } - - if output := string(p.SanitizeBytes([]byte(input))); output != input { - t.Errorf(`SanitizeBytes() input = %s, output = %s`, input, output) - } - - if output := p.SanitizeReader( - strings.NewReader(input), - ).String(); output != input { - - t.Errorf(`SanitizeReader() input = %s, output = %s`, input, output) - } - - input = "\t\n \n\t" - - if output := p.Sanitize(input); output != input { - t.Errorf(`Sanitize() input = %s, output = %s`, input, output) - } - - if output := string(p.SanitizeBytes([]byte(input))); output != input { - t.Errorf(`SanitizeBytes() input = %s, output = %s`, input, output) - } - - if output := p.SanitizeReader( - strings.NewReader(input), - ).String(); output != input { - - t.Errorf(`SanitizeReader() input = %s, output = %s`, input, output) - } -} - -func TestLinks(t *testing.T) { - - tests := []test{ - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: `Red dot`, - expected: `Red dot`, - }, - { - in: ``, - expected: ``, - }, - } - - p := UGCPolicy() - p.RequireParseableURLs(true) - - // These tests are run concurrently to enable the race detector to pick up - // potential issues - wg := sync.WaitGroup{} - wg.Add(len(tests)) - for ii, tt := range tests { - go func(ii int, tt test) { - out := p.Sanitize(tt.in) - if out != tt.expected { - t.Errorf( - "test %d failed;\ninput : %s\noutput : %s\nexpected: %s", - ii, - tt.in, - out, - tt.expected, - ) - } - wg.Done() - }(ii, tt) - } - wg.Wait() -} - -func TestLinkTargets(t *testing.T) { - - tests := []test{ - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: `Red dot`, - expected: `Red dot`, - }, - { - in: ``, - expected: ``, - }, - } - - p := UGCPolicy() - p.RequireParseableURLs(true) - p.RequireNoFollowOnLinks(false) - p.RequireNoFollowOnFullyQualifiedLinks(true) - p.AddTargetBlankToFullyQualifiedLinks(true) - - // These tests are run concurrently to enable the race detector to pick up - // potential issues - wg := sync.WaitGroup{} - wg.Add(len(tests)) - for ii, tt := range tests { - go func(ii int, tt test) { - out := p.Sanitize(tt.in) - if out != tt.expected { - t.Errorf( - "test %d failed;\ninput : %s\noutput : %s\nexpected: %s", - ii, - tt.in, - out, - tt.expected, - ) - } - wg.Done() - }(ii, tt) - } - wg.Wait() -} - -func TestStyling(t *testing.T) { - - tests := []test{ - { - in: `Hello World`, - expected: `Hello World`, - }, - { - in: `Hello World`, - expected: `Hello World`, - }, - } - - p := UGCPolicy() - p.AllowStyling() - - // These tests are run concurrently to enable the race detector to pick up - // potential issues - wg := sync.WaitGroup{} - wg.Add(len(tests)) - for ii, tt := range tests { - go func(ii int, tt test) { - out := p.Sanitize(tt.in) - if out != tt.expected { - t.Errorf( - "test %d failed;\ninput : %s\noutput : %s\nexpected: %s", - ii, - tt.in, - out, - tt.expected, - ) - } - wg.Done() - }(ii, tt) - } - wg.Wait() -} - -func TestEmptyAttributes(t *testing.T) { - - p := UGCPolicy() - // Do not do this, especially without a Matching() clause, this is a test - p.AllowAttrs("disabled").OnElements("textarea") - - tests := []test{ - // Empty elements - { - in: `` + - `
Styled by span
`, - expected: `` + - `
Styled by span
`, - }, - { - in: `foo
bar`, - expected: `foo
bar`, - }, - { - in: `foo
bar`, - expected: `foo
bar`, - }, - { - in: `foo
bar`, - expected: `foo
bar`, - }, - { - in: `foo
bar`, - expected: `foo
bar`, - }, - } - - for ii, test := range tests { - out := p.Sanitize(test.in) - if out != test.expected { - t.Errorf( - "test %d failed;\ninput : %s\noutput : %s\nexpected: %s", - ii, - test.in, - out, - test.expected, - ) - } - } -} - -func TestDataUri(t *testing.T) { - - p := UGCPolicy() - p.AllowURLSchemeWithCustomPolicy( - "data", - func(url *url.URL) (allowUrl bool) { - // Allows PNG images only - const prefix = "image/png;base64," - if !strings.HasPrefix(url.Opaque, prefix) { - return false - } - if _, err := base64.StdEncoding.DecodeString(url.Opaque[len(prefix):]); err != nil { - return false - } - if url.RawQuery != "" || url.Fragment != "" { - return false - } - return true - }, - ) - - tests := []test{ - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - } - - for ii, test := range tests { - out := p.Sanitize(test.in) - if out != test.expected { - t.Errorf( - "test %d failed;\ninput : %s\noutput : %s\nexpected: %s", - ii, - test.in, - out, - test.expected, - ) - } - } -} - -func TestAntiSamy(t *testing.T) { - - standardUrls := regexp.MustCompile(`(?i)^https?|mailto`) - - p := NewPolicy() - - p.AllowElements( - "a", "b", "br", "div", "font", "i", "img", "input", "li", "ol", "p", - "span", "td", "ul", - ) - p.AllowAttrs("checked", "type").OnElements("input") - p.AllowAttrs("color").OnElements("font") - p.AllowAttrs("href").Matching(standardUrls).OnElements("a") - p.AllowAttrs("src").Matching(standardUrls).OnElements("img") - p.AllowAttrs("class", "id", "title").Globally() - p.AllowAttrs("char").Matching( - regexp.MustCompile(`p{L}`), // Single character or HTML entity only - ).OnElements("td") - - tests := []test{ - // Base64 strings - // - // first string is - //
click here - { - in: `PGEgLSBocmVmPSJodHRwOi8vd3d3Lm93YXNwLm9yZyI+Y2xpY2sgaGVyZTwvYT4=`, - expected: `PGEgLSBocmVmPSJodHRwOi8vd3d3Lm93YXNwLm9yZyI+Y2xpY2sgaGVyZTwvYT4=`, - }, - // the rest are randomly generated 300 byte sequences which generate - // parser errors, turned into Strings - { - in: `uz0sEy5aDiok6oufQRaYPyYOxbtlACRnfrOnUVIbOstiaoB95iw+dJYuO5sI9nudhRtSYLANlcdgO0pRb+65qKDwZ5o6GJRMWv4YajZk+7Q3W/GN295XmyWUpxuyPGVi7d5fhmtYaYNW6vxyKK1Wjn9IEhIrfvNNjtEF90vlERnz3wde4WMaKMeciqgDXuZHEApYmUcu6Wbx4Q6WcNDqohAN/qCli74tvC+Umy0ZsQGU7E+BvJJ1tLfMcSzYiz7Q15ByZOYrA2aa0wDu0no3gSatjGt6aB4h30D9xUP31LuPGZ2GdWwMfZbFcfRgDSh42JPwa1bODmt5cw0Y8ACeyrIbfk9IkX1bPpYfIgtO7TwuXjBbhh2EEixOZ2YkcsvmcOSVTvraChbxv6kP`, - expected: `uz0sEy5aDiok6oufQRaYPyYOxbtlACRnfrOnUVIbOstiaoB95iw+dJYuO5sI9nudhRtSYLANlcdgO0pRb+65qKDwZ5o6GJRMWv4YajZk+7Q3W/GN295XmyWUpxuyPGVi7d5fhmtYaYNW6vxyKK1Wjn9IEhIrfvNNjtEF90vlERnz3wde4WMaKMeciqgDXuZHEApYmUcu6Wbx4Q6WcNDqohAN/qCli74tvC+Umy0ZsQGU7E+BvJJ1tLfMcSzYiz7Q15ByZOYrA2aa0wDu0no3gSatjGt6aB4h30D9xUP31LuPGZ2GdWwMfZbFcfRgDSh42JPwa1bODmt5cw0Y8ACeyrIbfk9IkX1bPpYfIgtO7TwuXjBbhh2EEixOZ2YkcsvmcOSVTvraChbxv6kP`, - }, - { - in: `PIWjMV4y+MpuNLtcY3vBRG4ZcNaCkB9wXJr3pghmFA6rVXAik+d5lei48TtnHvfvb5rQZVceWKv9cR/9IIsLokMyN0omkd8j3TV0DOh3JyBjPHFCu1Gp4Weo96h5C6RBoB0xsE4QdS2Y1sq/yiha9IebyHThAfnGU8AMC4AvZ7DDBccD2leZy2Q617ekz5grvxEG6tEcZ3fCbJn4leQVVo9MNoerim8KFHGloT+LxdgQR6YN5y1ii3bVGreM51S4TeANujdqJXp8B7B1Gk3PKCRS2T1SNFZedut45y+/w7wp5AUQCBUpIPUj6RLp+y3byWhcbZbJ70KOzTSZuYYIKLLo8047Fej43bIaghJm0F9yIKk3C5gtBcw8T5pciJoVXrTdBAK/8fMVo29P`, - expected: `PIWjMV4y+MpuNLtcY3vBRG4ZcNaCkB9wXJr3pghmFA6rVXAik+d5lei48TtnHvfvb5rQZVceWKv9cR/9IIsLokMyN0omkd8j3TV0DOh3JyBjPHFCu1Gp4Weo96h5C6RBoB0xsE4QdS2Y1sq/yiha9IebyHThAfnGU8AMC4AvZ7DDBccD2leZy2Q617ekz5grvxEG6tEcZ3fCbJn4leQVVo9MNoerim8KFHGloT+LxdgQR6YN5y1ii3bVGreM51S4TeANujdqJXp8B7B1Gk3PKCRS2T1SNFZedut45y+/w7wp5AUQCBUpIPUj6RLp+y3byWhcbZbJ70KOzTSZuYYIKLLo8047Fej43bIaghJm0F9yIKk3C5gtBcw8T5pciJoVXrTdBAK/8fMVo29P`, - }, - { - in: `uCk7HocubT6KzJw2eXpSUItZFGkr7U+D89mJw70rxdqXP2JaG04SNjx3dd84G4bz+UVPPhPO2gBAx2vHI0xhgJG9T4vffAYh2D1kenmr+8gIHt6WDNeD+HwJeAbJYhfVFMJsTuIGlYIw8+I+TARK0vqjACyRwMDAndhXnDrk4E5U3hyjqS14XX0kIDZYM6FGFPXe/s+ba2886Q8o1a7WosgqqAmt4u6R3IHOvVf5/PIeZrBJKrVptxjdjelP8Xwjq2ujWNtR3/HM1kjRlJi4xedvMRe4Rlxek0NDLC9hNd18RYi0EjzQ0bGSDDl0813yv6s6tcT6xHMzKvDcUcFRkX6BbxmoIcMsVeHM/ur6yRv834o/TT5IdiM9/wpkuICFOWIfM+Y8OWhiU6BK`, - expected: `uCk7HocubT6KzJw2eXpSUItZFGkr7U+D89mJw70rxdqXP2JaG04SNjx3dd84G4bz+UVPPhPO2gBAx2vHI0xhgJG9T4vffAYh2D1kenmr+8gIHt6WDNeD+HwJeAbJYhfVFMJsTuIGlYIw8+I+TARK0vqjACyRwMDAndhXnDrk4E5U3hyjqS14XX0kIDZYM6FGFPXe/s+ba2886Q8o1a7WosgqqAmt4u6R3IHOvVf5/PIeZrBJKrVptxjdjelP8Xwjq2ujWNtR3/HM1kjRlJi4xedvMRe4Rlxek0NDLC9hNd18RYi0EjzQ0bGSDDl0813yv6s6tcT6xHMzKvDcUcFRkX6BbxmoIcMsVeHM/ur6yRv834o/TT5IdiM9/wpkuICFOWIfM+Y8OWhiU6BK`, - }, - { - in: `Bb6Cqy6stJ0YhtPirRAQ8OXrPFKAeYHeuZXuC1qdHJRlweEzl4F2z/ZFG7hzr5NLZtzrRG3wm5TXl6Aua5G6v0WKcjJiS2V43WB8uY1BFK1d2y68c1gTRSF0u+VTThGjz+q/R6zE8HG8uchO+KPw64RehXDbPQ4uadiL+UwfZ4BzY1OHhvM5+2lVlibG+awtH6qzzx6zOWemTih932Lt9mMnm3FzEw7uGzPEYZ3aBV5xnbQ2a2N4UXIdm7RtIUiYFzHcLe5PZM/utJF8NdHKy0SPaKYkdXHli7g3tarzAabLZqLT4k7oemKYCn/eKRreZjqTB2E8Kc9Swf3jHDkmSvzOYE8wi1vQ3X7JtPcQ2O4muvpSa70NIE+XK1CgnnsL79Qzci1/1xgkBlNq`, - expected: `Bb6Cqy6stJ0YhtPirRAQ8OXrPFKAeYHeuZXuC1qdHJRlweEzl4F2z/ZFG7hzr5NLZtzrRG3wm5TXl6Aua5G6v0WKcjJiS2V43WB8uY1BFK1d2y68c1gTRSF0u+VTThGjz+q/R6zE8HG8uchO+KPw64RehXDbPQ4uadiL+UwfZ4BzY1OHhvM5+2lVlibG+awtH6qzzx6zOWemTih932Lt9mMnm3FzEw7uGzPEYZ3aBV5xnbQ2a2N4UXIdm7RtIUiYFzHcLe5PZM/utJF8NdHKy0SPaKYkdXHli7g3tarzAabLZqLT4k7oemKYCn/eKRreZjqTB2E8Kc9Swf3jHDkmSvzOYE8wi1vQ3X7JtPcQ2O4muvpSa70NIE+XK1CgnnsL79Qzci1/1xgkBlNq`, - }, - { - in: `FZNVr4nOICD1cNfAvQwZvZWi+P4I2Gubzrt+wK+7gLEY144BosgKeK7snwlA/vJjPAnkFW72APTBjY6kk4EOyoUef0MxRnZEU11vby5Ru19eixZBFB/SVXDJleLK0z3zXXE8U5Zl5RzLActHakG8Psvdt8TDscQc4MPZ1K7mXDhi7FQdpjRTwVxFyCFoybQ9WNJNGPsAkkm84NtFb4KjGpwVC70oq87tM2gYCrNgMhBfdBl0bnQHoNBCp76RKdpq1UAY01t1ipfgt7BoaAr0eTw1S32DezjfkAz04WyPTzkdBKd3b44rX9dXEbm6szAz0SjgztRPDJKSMELjq16W2Ua8d1AHq2Dz8JlsvGzi2jICUjpFsIfRmQ/STSvOT8VsaCFhwL1zDLbn5jCr`, - expected: `FZNVr4nOICD1cNfAvQwZvZWi+P4I2Gubzrt+wK+7gLEY144BosgKeK7snwlA/vJjPAnkFW72APTBjY6kk4EOyoUef0MxRnZEU11vby5Ru19eixZBFB/SVXDJleLK0z3zXXE8U5Zl5RzLActHakG8Psvdt8TDscQc4MPZ1K7mXDhi7FQdpjRTwVxFyCFoybQ9WNJNGPsAkkm84NtFb4KjGpwVC70oq87tM2gYCrNgMhBfdBl0bnQHoNBCp76RKdpq1UAY01t1ipfgt7BoaAr0eTw1S32DezjfkAz04WyPTzkdBKd3b44rX9dXEbm6szAz0SjgztRPDJKSMELjq16W2Ua8d1AHq2Dz8JlsvGzi2jICUjpFsIfRmQ/STSvOT8VsaCFhwL1zDLbn5jCr`, - }, - { - in: `RuiRkvYjH2FcCjNzFPT2PJWh7Q6vUbfMadMIEnw49GvzTmhk4OUFyjY13GL52JVyqdyFrnpgEOtXiTu88Cm+TiBI7JRh0jRs3VJRP3N+5GpyjKX7cJA46w8PrH3ovJo3PES7o8CSYKRa3eUs7BnFt7kUCvMqBBqIhTIKlnQd2JkMNnhhCcYdPygLx7E1Vg+H3KybcETsYWBeUVrhRl/RAyYJkn6LddjPuWkDdgIcnKhNvpQu4MMqF3YbzHgyTh7bdWjy1liZle7xR/uRbOrRIRKTxkUinQGEWyW3bbXOvPO71E7xyKywBanwg2FtvzOoRFRVF7V9mLzPSqdvbM7VMQoLFob2UgeNLbVHkWeQtEqQWIV5RMu3+knhoqGYxP/3Srszp0ELRQy/xyyD`, - expected: `RuiRkvYjH2FcCjNzFPT2PJWh7Q6vUbfMadMIEnw49GvzTmhk4OUFyjY13GL52JVyqdyFrnpgEOtXiTu88Cm+TiBI7JRh0jRs3VJRP3N+5GpyjKX7cJA46w8PrH3ovJo3PES7o8CSYKRa3eUs7BnFt7kUCvMqBBqIhTIKlnQd2JkMNnhhCcYdPygLx7E1Vg+H3KybcETsYWBeUVrhRl/RAyYJkn6LddjPuWkDdgIcnKhNvpQu4MMqF3YbzHgyTh7bdWjy1liZle7xR/uRbOrRIRKTxkUinQGEWyW3bbXOvPO71E7xyKywBanwg2FtvzOoRFRVF7V9mLzPSqdvbM7VMQoLFob2UgeNLbVHkWeQtEqQWIV5RMu3+knhoqGYxP/3Srszp0ELRQy/xyyD`, - }, - { - in: `mqBEVbNnL929CUA3sjkOmPB5dL0/a0spq8LgbIsJa22SfP580XduzUIKnCtdeC9TjPB/GEPp/LvEUFaLTUgPDQQGu3H5UCZyjVTAMHl45me/0qISEf903zFFqW5Lk3TS6iPrithqMMvhdK29Eg5OhhcoHS+ALpn0EjzUe86NywuFNb6ID4o8aF/ztZlKJegnpDAm3JuhCBauJ+0gcOB8GNdWd5a06qkokmwk1tgwWat7cQGFIH1NOvBwRMKhD51MJ7V28806a3zkOVwwhOiyyTXR+EcDA/aq5acX0yailLWB82g/2GR/DiaqNtusV+gpcMTNYemEv3c/xLkClJc29DSfTsJGKsmIDMqeBMM7RRBNinNAriY9iNX1UuHZLr/tUrRNrfuNT5CvvK1K`, - expected: `mqBEVbNnL929CUA3sjkOmPB5dL0/a0spq8LgbIsJa22SfP580XduzUIKnCtdeC9TjPB/GEPp/LvEUFaLTUgPDQQGu3H5UCZyjVTAMHl45me/0qISEf903zFFqW5Lk3TS6iPrithqMMvhdK29Eg5OhhcoHS+ALpn0EjzUe86NywuFNb6ID4o8aF/ztZlKJegnpDAm3JuhCBauJ+0gcOB8GNdWd5a06qkokmwk1tgwWat7cQGFIH1NOvBwRMKhD51MJ7V28806a3zkOVwwhOiyyTXR+EcDA/aq5acX0yailLWB82g/2GR/DiaqNtusV+gpcMTNYemEv3c/xLkClJc29DSfTsJGKsmIDMqeBMM7RRBNinNAriY9iNX1UuHZLr/tUrRNrfuNT5CvvK1K`, - }, - { - in: `IMcfbWZ/iCa/LDcvMlk6LEJ0gDe4ohy2Vi0pVBd9aqR5PnRj8zGit8G2rLuNUkDmQ95bMURasmaPw2Xjf6SQjRk8coIHDLtbg/YNQVMabE8pKd6EaFdsGWJkcFoonxhPR29aH0xvjC4Mp3cJX3mjqyVsOp9xdk6d0Y2hzV3W/oPCq0DV03pm7P3+jH2OzoVVIDYgG1FD12S03otJrCXuzDmE2LOQ0xwgBQ9sREBLXwQzUKfXH8ogZzjdR19pX9qe0rRKMNz8k5lqcF9R2z+XIS1QAfeV9xopXA0CeyrhtoOkXV2i8kBxyodDp7tIeOvbEfvaqZGJgaJyV8UMTDi7zjwNeVdyKa8USH7zrXSoCl+Ud5eflI9vxKS+u9Bt1ufBHJtULOCHGA2vimkU`, - expected: `IMcfbWZ/iCa/LDcvMlk6LEJ0gDe4ohy2Vi0pVBd9aqR5PnRj8zGit8G2rLuNUkDmQ95bMURasmaPw2Xjf6SQjRk8coIHDLtbg/YNQVMabE8pKd6EaFdsGWJkcFoonxhPR29aH0xvjC4Mp3cJX3mjqyVsOp9xdk6d0Y2hzV3W/oPCq0DV03pm7P3+jH2OzoVVIDYgG1FD12S03otJrCXuzDmE2LOQ0xwgBQ9sREBLXwQzUKfXH8ogZzjdR19pX9qe0rRKMNz8k5lqcF9R2z+XIS1QAfeV9xopXA0CeyrhtoOkXV2i8kBxyodDp7tIeOvbEfvaqZGJgaJyV8UMTDi7zjwNeVdyKa8USH7zrXSoCl+Ud5eflI9vxKS+u9Bt1ufBHJtULOCHGA2vimkU`, - }, - { - in: `AqC2sr44HVueGzgW13zHvJkqOEBWA8XA66ZEb3EoL1ehypSnJ07cFoWZlO8kf3k57L1fuHFWJ6quEdLXQaT9SJKHlUaYQvanvjbBlqWwaH3hODNsBGoK0DatpoQ+FxcSkdVE/ki3rbEUuJiZzU0BnDxH+Q6FiNsBaJuwau29w24MlD28ELJsjCcUVwtTQkaNtUxIlFKHLj0++T+IVrQH8KZlmVLvDefJ6llWbrFNVuh674HfKr/GEUatG6KI4gWNtGKKRYh76mMl5xH5qDfBZqxyRaKylJaDIYbx5xP5I4DDm4gOnxH+h/Pu6dq6FJ/U3eDio/KQ9xwFqTuyjH0BIRBsvWWgbTNURVBheq+am92YBhkj1QmdKTxQ9fQM55O8DpyWzRhky0NevM9j`, - expected: `AqC2sr44HVueGzgW13zHvJkqOEBWA8XA66ZEb3EoL1ehypSnJ07cFoWZlO8kf3k57L1fuHFWJ6quEdLXQaT9SJKHlUaYQvanvjbBlqWwaH3hODNsBGoK0DatpoQ+FxcSkdVE/ki3rbEUuJiZzU0BnDxH+Q6FiNsBaJuwau29w24MlD28ELJsjCcUVwtTQkaNtUxIlFKHLj0++T+IVrQH8KZlmVLvDefJ6llWbrFNVuh674HfKr/GEUatG6KI4gWNtGKKRYh76mMl5xH5qDfBZqxyRaKylJaDIYbx5xP5I4DDm4gOnxH+h/Pu6dq6FJ/U3eDio/KQ9xwFqTuyjH0BIRBsvWWgbTNURVBheq+am92YBhkj1QmdKTxQ9fQM55O8DpyWzRhky0NevM9j`, - }, - { - in: `qkFfS3WfLyj3QTQT9i/s57uOPQCTN1jrab8bwxaxyeYUlz2tEtYyKGGUufua8WzdBT2VvWTvH0JkK0LfUJ+vChvcnMFna+tEaCKCFMIOWMLYVZSJDcYMIqaIr8d0Bi2bpbVf5z4WNma0pbCKaXpkYgeg1Sb8HpKG0p0fAez7Q/QRASlvyM5vuIOH8/CM4fF5Ga6aWkTRG0lfxiyeZ2vi3q7uNmsZF490J79r/6tnPPXIIC4XGnijwho5NmhZG0XcQeyW5KnT7VmGACFdTHOb9oS5WxZZU29/oZ5Y23rBBoSDX/xZ1LNFiZk6Xfl4ih207jzogv+3nOro93JHQydNeKEwxOtbKqEe7WWJLDw/EzVdJTODrhBYKbjUce10XsavuiTvv+H1Qh4lo2Vx`, - expected: `qkFfS3WfLyj3QTQT9i/s57uOPQCTN1jrab8bwxaxyeYUlz2tEtYyKGGUufua8WzdBT2VvWTvH0JkK0LfUJ+vChvcnMFna+tEaCKCFMIOWMLYVZSJDcYMIqaIr8d0Bi2bpbVf5z4WNma0pbCKaXpkYgeg1Sb8HpKG0p0fAez7Q/QRASlvyM5vuIOH8/CM4fF5Ga6aWkTRG0lfxiyeZ2vi3q7uNmsZF490J79r/6tnPPXIIC4XGnijwho5NmhZG0XcQeyW5KnT7VmGACFdTHOb9oS5WxZZU29/oZ5Y23rBBoSDX/xZ1LNFiZk6Xfl4ih207jzogv+3nOro93JHQydNeKEwxOtbKqEe7WWJLDw/EzVdJTODrhBYKbjUce10XsavuiTvv+H1Qh4lo2Vx`, - }, - { - in: `O900/Gn82AjyLYqiWZ4ILXBBv/ZaXpTpQL0p9nv7gwF2MWsS2OWEImcVDa+1ElrjUumG6CVEv/rvax53krqJJDg+4Z/XcHxv58w6hNrXiWqFNjxlu5RZHvj1oQQXnS2n8qw8e/c+8ea2TiDIVr4OmgZz1G9uSPBeOZJvySqdgNPMpgfjZwkL2ez9/x31sLuQxi/FW3DFXU6kGSUjaq8g/iGXlaaAcQ0t9Gy+y005Z9wpr2JWWzishL+1JZp9D4SY/r3NHDphN4MNdLHMNBRPSIgfsaSqfLraIt+zWIycsd+nksVxtPv9wcyXy51E1qlHr6Uygz2VZYD9q9zyxEX4wRP2VEewHYUomL9d1F6gGG5fN3z82bQ4hI9uDirWhneWazUOQBRud5otPOm9`, - expected: `O900/Gn82AjyLYqiWZ4ILXBBv/ZaXpTpQL0p9nv7gwF2MWsS2OWEImcVDa+1ElrjUumG6CVEv/rvax53krqJJDg+4Z/XcHxv58w6hNrXiWqFNjxlu5RZHvj1oQQXnS2n8qw8e/c+8ea2TiDIVr4OmgZz1G9uSPBeOZJvySqdgNPMpgfjZwkL2ez9/x31sLuQxi/FW3DFXU6kGSUjaq8g/iGXlaaAcQ0t9Gy+y005Z9wpr2JWWzishL+1JZp9D4SY/r3NHDphN4MNdLHMNBRPSIgfsaSqfLraIt+zWIycsd+nksVxtPv9wcyXy51E1qlHr6Uygz2VZYD9q9zyxEX4wRP2VEewHYUomL9d1F6gGG5fN3z82bQ4hI9uDirWhneWazUOQBRud5otPOm9`, - }, - { - in: `C3c+d5Q9lyTafPLdelG1TKaLFinw1TOjyI6KkrQyHKkttfnO58WFvScl1TiRcB/iHxKahskoE2+VRLUIhctuDU4sUvQh/g9Arw0LAA4QTxuLFt01XYdigurz4FT15ox2oDGGGrRb3VGjDTXK1OWVJoLMW95EVqyMc9F+Fdej85LHE+8WesIfacjUQtTG1tzYVQTfubZq0+qxXws8QrxMLFtVE38tbeXo+Ok1/U5TUa6FjWflEfvKY3XVcl8RKkXua7fVz/Blj8Gh+dWe2cOxa0lpM75ZHyz9adQrB2Pb4571E4u2xI5un0R0MFJZBQuPDc1G5rPhyk+Hb4LRG3dS0m8IASQUOskv93z978L1+Abu9CLP6d6s5p+BzWxhMUqwQXC/CCpTywrkJ0RG`, - expected: `C3c+d5Q9lyTafPLdelG1TKaLFinw1TOjyI6KkrQyHKkttfnO58WFvScl1TiRcB/iHxKahskoE2+VRLUIhctuDU4sUvQh/g9Arw0LAA4QTxuLFt01XYdigurz4FT15ox2oDGGGrRb3VGjDTXK1OWVJoLMW95EVqyMc9F+Fdej85LHE+8WesIfacjUQtTG1tzYVQTfubZq0+qxXws8QrxMLFtVE38tbeXo+Ok1/U5TUa6FjWflEfvKY3XVcl8RKkXua7fVz/Blj8Gh+dWe2cOxa0lpM75ZHyz9adQrB2Pb4571E4u2xI5un0R0MFJZBQuPDc1G5rPhyk+Hb4LRG3dS0m8IASQUOskv93z978L1+Abu9CLP6d6s5p+BzWxhMUqwQXC/CCpTywrkJ0RG`, - }, - // Basic XSS - { - in: `test`, - expected: `test`, - }, - { - in: `<<<><`, - expected: ``, - }, - { - in: "", - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: `
`, - expected: ``, - }, - { - in: `
`, - expected: ``, - }, - { - in: `
`, - expected: `
`, - }, - { - in: `
`, - expected: `
`, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: "", - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: `PT SRC="http://ha.ckers.org/xss.js">`, - expected: `PT SRC="http://ha.ckers.org/xss.js">`, - }, - { - in: `PT SRC="http://ha.ckers.org/xss.js">`, - expected: `PT SRC="http://ha.ckers.org/xss.js">`, - }, - { - in: ``, - expected: ``, - }, - { - in: "", - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ` +ADw-SCRIPT+AD4-alert('XSS')`, - expected: ` +ADw-SCRIPT+AD4-alert('XSS')`, - }, - { - in: ``, - expected: ``, - }, - { - in: `alert("XSS")'); ?>`, - expected: `alert("XSS")'); ?>`, - }, - { - in: ``, - expected: ``, - }, - { - in: ` - - -"> -`, - expected: "\n\n\n">\n", - }, - { - in: ` -`, - expected: ` -`, - }, - { - in: ` -`, - expected: ` -`, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: `
`, - expected: `
`, - }, - { - in: `
`, - expected: `
`, - }, - { - in: `
`, - expected: `
`, - }, - { - in: `
`, - expected: `
`, - }, - { - in: `
`, - expected: `
`, - }, - { - in: ``, - expected: `
`, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: `
`, - expected: `
`, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: `
  • XSS
    `, - expected: `
    • XSS
      `, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: ``, - expected: ``, - }, - { - in: `\";alert('XSS');//`, - expected: `\";alert('XSS');//`, - }, - { - in: `