Browse Source

switch logging to lgr

Umputun 5 years ago
parent
commit
b1dc239277
100 changed files with 20047 additions and 531 deletions
  1. 1 0
      .gitignore
  2. 5 5
      Gopkg.lock
  3. 0 31
      Gopkg.toml
  4. 29 17
      app/main.go
  5. 3 3
      app/publisher/publisher.go
  6. 4 3
      app/rss/notify.go
  7. 59 0
      vendor/github.com/ChimeraCoder/anaconda/example_test.go
  8. 39 0
      vendor/github.com/ChimeraCoder/anaconda/oembed_test.go
  9. 437 0
      vendor/github.com/ChimeraCoder/anaconda/twitter_test.go
  10. 77 0
      vendor/github.com/ChimeraCoder/tokenbucket/tokenbucket_test.go
  11. 234 0
      vendor/github.com/PuerkitoBio/goquery/array_test.go
  12. 120 0
      vendor/github.com/PuerkitoBio/goquery/bench_array_test.go
  13. 40 0
      vendor/github.com/PuerkitoBio/goquery/bench_example_test.go
  14. 104 0
      vendor/github.com/PuerkitoBio/goquery/bench_expand_test.go
  15. 236 0
      vendor/github.com/PuerkitoBio/goquery/bench_filter_test.go
  16. 68 0
      vendor/github.com/PuerkitoBio/goquery/bench_iteration_test.go
  17. 51 0
      vendor/github.com/PuerkitoBio/goquery/bench_property_test.go
  18. 111 0
      vendor/github.com/PuerkitoBio/goquery/bench_query_test.go
  19. 802 0
      vendor/github.com/PuerkitoBio/goquery/bench_traversal_test.go
  20. 82 0
      vendor/github.com/PuerkitoBio/goquery/example_test.go
  21. 118 0
      vendor/github.com/PuerkitoBio/goquery/expand_test.go
  22. 206 0
      vendor/github.com/PuerkitoBio/goquery/filter_test.go
  23. 88 0
      vendor/github.com/PuerkitoBio/goquery/iteration_test.go
  24. 513 0
      vendor/github.com/PuerkitoBio/goquery/manipulation_test.go
  25. 252 0
      vendor/github.com/PuerkitoBio/goquery/property_test.go
  26. 103 0
      vendor/github.com/PuerkitoBio/goquery/query_test.go
  27. 793 0
      vendor/github.com/PuerkitoBio/goquery/traversal_test.go
  28. 202 0
      vendor/github.com/PuerkitoBio/goquery/type_test.go
  29. 128 0
      vendor/github.com/PuerkitoBio/goquery/utilities_test.go
  30. 53 0
      vendor/github.com/andybalholm/cascadia/benchmark_test.go
  31. 86 0
      vendor/github.com/andybalholm/cascadia/parser_test.go
  32. 654 0
      vendor/github.com/andybalholm/cascadia/selector_test.go
  33. 18 0
      vendor/github.com/azr/backoff/backoff_test.go
  34. 50 0
      vendor/github.com/azr/backoff/example_test.go
  35. 87 0
      vendor/github.com/azr/backoff/exponential_test.go
  36. 36 0
      vendor/github.com/azr/backoff/linear_test.go
  37. 0 0
      vendor/github.com/davecgh/go-spew/.gitignore
  38. 28 0
      vendor/github.com/davecgh/go-spew/.travis.yml
  39. 201 0
      vendor/github.com/davecgh/go-spew/README.md
  40. 22 0
      vendor/github.com/davecgh/go-spew/cov_report.sh
  41. 298 0
      vendor/github.com/davecgh/go-spew/spew/common_test.go
  42. 1042 0
      vendor/github.com/davecgh/go-spew/spew/dump_test.go
  43. 101 0
      vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go
  44. 26 0
      vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go
  45. 226 0
      vendor/github.com/davecgh/go-spew/spew/example_test.go
  46. 1558 0
      vendor/github.com/davecgh/go-spew/spew/format_test.go
  47. 84 0
      vendor/github.com/davecgh/go-spew/spew/internal_test.go
  48. 101 0
      vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go
  49. 320 0
      vendor/github.com/davecgh/go-spew/spew/spew_test.go
  50. 61 0
      vendor/github.com/davecgh/go-spew/test_coverage.txt
  51. 647 0
      vendor/github.com/dustin/go-jsonpointer/bytes_test.go
  52. 177 0
      vendor/github.com/dustin/go-jsonpointer/map_test.go
  53. 263 0
      vendor/github.com/dustin/go-jsonpointer/reflect_test.go
  54. 189 0
      vendor/github.com/dustin/gojson/bench_test.go
  55. 1391 0
      vendor/github.com/dustin/gojson/decode_test.go
  56. 532 0
      vendor/github.com/dustin/gojson/encode_test.go
  57. 161 0
      vendor/github.com/dustin/gojson/example_test.go
  58. 116 0
      vendor/github.com/dustin/gojson/fold_test.go
  59. 315 0
      vendor/github.com/dustin/gojson/scanner_test.go
  60. 206 0
      vendor/github.com/dustin/gojson/stream_test.go
  61. 115 0
      vendor/github.com/dustin/gojson/tagkey_test.go
  62. 28 0
      vendor/github.com/dustin/gojson/tags_test.go
  63. 5 0
      vendor/github.com/garyburd/go-oauth/.gitignore
  64. 9 0
      vendor/github.com/garyburd/go-oauth/.travis.yml
  65. 34 0
      vendor/github.com/garyburd/go-oauth/README.markdown
  66. 56 0
      vendor/github.com/garyburd/go-oauth/oauth/examples_test.go
  67. 24 0
      vendor/github.com/garyburd/go-oauth/oauth/oauth17_test.go
  68. 484 0
      vendor/github.com/garyburd/go-oauth/oauth/oauth_test.go
  69. 13 0
      vendor/github.com/go-pkgz/lgr/.gitignore
  70. 19 0
      vendor/github.com/go-pkgz/lgr/.travis.yml
  71. 21 0
      vendor/github.com/go-pkgz/lgr/LICENSE
  72. 48 0
      vendor/github.com/go-pkgz/lgr/README.md
  73. 3 0
      vendor/github.com/go-pkgz/lgr/go.mod
  74. 7 0
      vendor/github.com/go-pkgz/lgr/go.sum
  75. 41 0
      vendor/github.com/go-pkgz/lgr/interface.go
  76. 74 0
      vendor/github.com/go-pkgz/lgr/interface_test.go
  77. 173 0
      vendor/github.com/go-pkgz/lgr/logger.go
  78. 174 0
      vendor/github.com/go-pkgz/lgr/logger_test.go
  79. 0 354
      vendor/github.com/hashicorp/logutils/LICENSE
  80. 0 36
      vendor/github.com/hashicorp/logutils/README.md
  81. 0 1
      vendor/github.com/hashicorp/logutils/go.mod
  82. 0 81
      vendor/github.com/hashicorp/logutils/level.go
  83. 163 0
      vendor/github.com/jessevdk/go-flags/arg_test.go
  84. 177 0
      vendor/github.com/jessevdk/go-flags/assert_test.go
  85. 582 0
      vendor/github.com/jessevdk/go-flags/command_test.go
  86. 315 0
      vendor/github.com/jessevdk/go-flags/completion_test.go
  87. 159 0
      vendor/github.com/jessevdk/go-flags/convert_test.go
  88. 110 0
      vendor/github.com/jessevdk/go-flags/example_test.go
  89. 255 0
      vendor/github.com/jessevdk/go-flags/group_test.go
  90. 538 0
      vendor/github.com/jessevdk/go-flags/help_test.go
  91. 1053 0
      vendor/github.com/jessevdk/go-flags/ini_test.go
  92. 85 0
      vendor/github.com/jessevdk/go-flags/long_test.go
  93. 119 0
      vendor/github.com/jessevdk/go-flags/marshal_test.go
  94. 45 0
      vendor/github.com/jessevdk/go-flags/options_test.go
  95. 612 0
      vendor/github.com/jessevdk/go-flags/parser_test.go
  96. 164 0
      vendor/github.com/jessevdk/go-flags/pointer_test.go
  97. 234 0
      vendor/github.com/jessevdk/go-flags/short_test.go
  98. 38 0
      vendor/github.com/jessevdk/go-flags/tag_test.go
  99. 66 0
      vendor/github.com/jessevdk/go-flags/unknown_test.go
  100. 50 0
      vendor/github.com/mmcdole/gofeed/atom/parser_test.go

+ 1 - 0
.gitignore

@@ -10,3 +10,4 @@
 
 # Output of the go coverage tool, specifically when used with LiteIDE
 *.out
+.vscode

+ 5 - 5
Gopkg.lock

@@ -74,12 +74,12 @@
   revision = "bca2e7f09a178fd36b034107a00e2323bca6a82e"
 
 [[projects]]
-  digest = "1:16ae35b3a854c667baaf55ff5d455c486f7c2baf040a2727f2ef0e4b096b2a95"
-  name = "github.com/hashicorp/logutils"
+  digest = "1:a1a91f2decda4ce3dcca272e9f9bdd3eaba137b5d1acf3d6f1d14c2bd03cb290"
+  name = "github.com/go-pkgz/lgr"
   packages = ["."]
   pruneopts = "UT"
-  revision = "a335183dfd075f638afcc820c90591ca3c97eba6"
-  version = "v1.0.0"
+  revision = "e8e3322ba46888900f89c1bbe7c4ae8f5a895aa5"
+  version = "v0.1.4"
 
 [[projects]]
   digest = "1:a2cff208d4759f6ba1b1cd228587b0a1869f95f22542ec9cd17fff64430113c7"
@@ -174,7 +174,7 @@
   analyzer-version = 1
   input-imports = [
     "github.com/ChimeraCoder/anaconda",
-    "github.com/hashicorp/logutils",
+    "github.com/go-pkgz/lgr",
     "github.com/jessevdk/go-flags",
     "github.com/mmcdole/gofeed",
     "github.com/stretchr/testify/assert",

+ 0 - 31
Gopkg.toml

@@ -1,34 +1,3 @@
-# Gopkg.toml example
-#
-# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
-# for detailed Gopkg.toml documentation.
-#
-# required = ["github.com/user/thing/cmd/thing"]
-# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
-#
-# [[constraint]]
-#   name = "github.com/user/project"
-#   version = "1.0.0"
-#
-# [[constraint]]
-#   name = "github.com/user/project2"
-#   branch = "dev"
-#   source = "github.com/myfork/project2"
-#
-# [[override]]
-#   name = "github.com/x/y"
-#   version = "2.4.0"
-#
-# [prune]
-#   non-go = false
-#   go-tests = true
-#   unused-packages = true
-
-
-[[constraint]]
-  name = "github.com/hashicorp/logutils"
-  version = "1.0.0"
-
 [[constraint]]
   name = "github.com/jessevdk/go-flags"
   version = "1.4.0"

+ 29 - 17
app/main.go

@@ -4,13 +4,15 @@ import (
 	"bytes"
 	"context"
 	"fmt"
-	"log"
 	"os"
+	"os/signal"
+	"runtime"
+	"syscall"
 	"text/template"
 	"time"
 
-	"github.com/hashicorp/logutils"
-	"github.com/jessevdk/go-flags"
+	log "github.com/go-pkgz/lgr"
+	flags "github.com/jessevdk/go-flags"
 
 	"github.com/umputun/rss2twitter/app/publisher"
 	"github.com/umputun/rss2twitter/app/rss"
@@ -39,7 +41,9 @@ func main() {
 		os.Exit(1)
 	}
 
-	setupLog(opts.Dbg)
+	if opts.Dbg {
+		log.Setup(log.Debug)
+	}
 
 	notifier := rss.Notify{Feed: opts.Feed, Duration: opts.Refresh, Timeout: opts.TimeOut}
 	var pub publisher.Interface = publisher.Twitter{
@@ -56,10 +60,12 @@ func main() {
 
 	log.Printf("[INFO] message template - %q", opts.Template)
 
-	for event := range notifier.Go(context.Background()) {
+	ch := notifier.Go(context.Background())
+	for event := range ch {
 		err := pub.Publish(event, func(r rss.Event) string {
 			b1 := bytes.Buffer{}
 			if err := template.Must(template.New("twi").Parse(opts.Template)).Execute(&b1, event); err != nil {
+				// template failed to parse record, backup predefined format
 				return fmt.Sprintf("%s - %s", r.Title, r.Link)
 			}
 			return b1.String()
@@ -71,18 +77,24 @@ func main() {
 	log.Print("[INFO] terminated")
 }
 
-func setupLog(dbg bool) {
-	filter := &logutils.LevelFilter{
-		Levels:   []logutils.LogLevel{"DEBUG", "INFO", "WARN", "ERROR"},
-		MinLevel: logutils.LogLevel("INFO"),
-		Writer:   os.Stdout,
+// getDump reads runtime stack and returns as a string
+func getDump() string {
+	maxSize := 5 * 1024 * 1024
+	stacktrace := make([]byte, maxSize)
+	length := runtime.Stack(stacktrace, true)
+	if length > maxSize {
+		length = maxSize
 	}
+	return string(stacktrace[:length])
+}
 
-	log.SetFlags(log.Ldate | log.Ltime)
-
-	if dbg {
-		log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds | log.Lshortfile)
-		filter.MinLevel = logutils.LogLevel("DEBUG")
-	}
-	log.SetOutput(filter)
+func init() {
+	// catch SIGQUIT and print stack traces
+	sigChan := make(chan os.Signal)
+	go func() {
+		for range sigChan {
+			log.Printf("[INFO] SIGQUIT detected, dump:\n%s", getDump())
+		}
+	}()
+	signal.Notify(sigChan, syscall.SIGQUIT)
 }

+ 3 - 3
app/publisher/publisher.go

@@ -1,10 +1,10 @@
 package publisher
 
 import (
-	"log"
 	"net/url"
 
 	"github.com/ChimeraCoder/anaconda"
+	log "github.com/go-pkgz/lgr"
 
 	"github.com/umputun/rss2twitter/app/rss"
 )
@@ -19,7 +19,7 @@ type Stdout struct{}
 
 // Publish to logger
 func (s Stdout) Publish(event rss.Event, formatter func(rss.Event) string) error {
-	log.Printf("[EVENT] %s", formatter(event))
+	log.Printf("[INFO] event - %s", formatter(event))
 	return nil
 }
 
@@ -31,7 +31,7 @@ type Twitter struct {
 
 // Publish to twitter
 func (t Twitter) Publish(event rss.Event, formatter func(rss.Event) string) error {
-	log.Printf("[INFO] publish %+v", event)
+	log.Printf("[INFO] publish to twitter %+v", event)
 	api := anaconda.NewTwitterApiWithCredentials(t.AccessToken, t.AccessSecret, t.ConsumerKey, t.ConsumerSecret)
 	_, err := api.PostTweet(formatter(event), url.Values{})
 	return err

+ 4 - 3
app/rss/notify.go

@@ -2,11 +2,11 @@ package rss
 
 import (
 	"context"
-	"log"
 	"net/http"
 	"sync"
 	"time"
 
+	log "github.com/go-pkgz/lgr"
 	"github.com/mmcdole/gofeed"
 )
 
@@ -59,7 +59,7 @@ func (n *Notify) Go(ctx context.Context) <-chan Event {
 		for {
 			feedData, err := fp.ParseURL(n.Feed)
 			if err != nil {
-				log.Printf("[WARN] failed to fetch from %s, %s", n.Feed, err)
+				log.Printf("[WARN] failed to fetch from %s, %v", n.Feed, err)
 				if !waitOrCancel(n.ctx) {
 					return
 				}
@@ -68,7 +68,7 @@ func (n *Notify) Go(ctx context.Context) <-chan Event {
 			event := n.feedEvent(feedData)
 			if lastGUID != event.guid {
 				if lastGUID != "" { // don't notify on initial change
-					log.Printf("[DEBUG] new event %s", event.guid)
+					log.Printf("[INFO] new event %s - %s", event.guid, event.Title)
 					ch <- event
 				}
 				lastGUID = event.guid
@@ -88,6 +88,7 @@ func (n *Notify) Shutdown() {
 	<-n.ctx.Done()
 }
 
+// feedEvent gets latest item from rss feed
 func (n *Notify) feedEvent(feed *gofeed.Feed) (e Event) {
 	e.ChanTitle = feed.Title
 	if len(feed.Items) > 0 {

+ 59 - 0
vendor/github.com/ChimeraCoder/anaconda/example_test.go

@@ -0,0 +1,59 @@
+package anaconda_test
+
+import (
+	"fmt"
+	"time"
+
+	"github.com/ChimeraCoder/anaconda"
+)
+
+// Initialize an client library for a given user.
+// This only needs to be done *once* per user
+func ExampleTwitterApi_InitializeClient() {
+	api := anaconda.NewTwitterApiWithCredentials(ACCESS_TOKEN, ACCESS_TOKEN_SECRET, "your-consumer-key", "your-consumer-secret")
+	fmt.Println(*api.Credentials)
+}
+
+func ExampleTwitterApi_GetSearch() {
+	anaconda.SetConsumerKey("your-consumer-key")
+	anaconda.SetConsumerSecret("your-consumer-secret")
+	api := anaconda.NewTwitterApi("your-access-token", "your-access-token-secret")
+	search_result, err := api.GetSearch("golang", nil)
+	if err != nil {
+		panic(err)
+	}
+	for _, tweet := range search_result.Statuses {
+		fmt.Print(tweet.Text)
+	}
+}
+
+// Throttling queries can easily be handled in the background, automatically
+func ExampleTwitterApi_Throttling() {
+	api := anaconda.NewTwitterApi("your-access-token", "your-access-token-secret")
+	api.EnableThrottling(10*time.Second, 5)
+
+	// These queries will execute in order
+	// with appropriate delays inserted only if necessary
+	golangTweets, err := api.GetSearch("golang", nil)
+	anacondaTweets, err2 := api.GetSearch("anaconda", nil)
+
+	if err != nil {
+		panic(err)
+	}
+	if err2 != nil {
+		panic(err)
+	}
+
+	fmt.Println(golangTweets)
+	fmt.Println(anacondaTweets)
+}
+
+// Fetch a list of all followers without any need for managing cursors
+// (Each page is automatically fetched when the previous one is read)
+func ExampleTwitterApi_GetFollowersListAll() {
+	pages := api.GetFollowersListAll(nil)
+	for page := range pages {
+		//Print the current page of followers
+		fmt.Println(page.Followers)
+	}
+}

+ 39 - 0
vendor/github.com/ChimeraCoder/anaconda/oembed_test.go

@@ -0,0 +1,39 @@
+package anaconda_test
+
+import (
+	"net/url"
+	"reflect"
+	"testing"
+
+	"github.com/ChimeraCoder/anaconda"
+)
+
+func TestOEmbed(t *testing.T) {
+	// It is the only one that can be tested without auth
+	// However, it is still rate-limited
+	api := anaconda.NewTwitterApi("", "")
+	api.SetBaseUrl(testBase)
+	o, err := api.GetOEmbed(url.Values{"id": []string{"99530515043983360"}})
+	if err != nil {
+		t.Error(err)
+	}
+
+	if !reflect.DeepEqual(o, expectedOEmbed) {
+		t.Errorf("Actual OEmbed differs expected:\n%#v\n Got: \n%#v\n", expectedOEmbed, o)
+	}
+}
+
+var expectedOEmbed anaconda.OEmbed = anaconda.OEmbed{
+	Cache_age:     "3153600000",
+	Url:           "https://twitter.com/twitter/status/99530515043983360",
+	Height:        0,
+	Provider_url:  "https://twitter.com",
+	Provider_name: "Twitter",
+	Author_name:   "Twitter",
+	Version:       "1.0",
+	Author_url:    "https://twitter.com/twitter",
+	Type:          "rich",
+	Html: `<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Cool! “<a href="https://twitter.com/tw1tt3rart">@tw1tt3rart</a>: <a href="https://twitter.com/hashtag/TWITTERART?src=hash">#TWITTERART</a> ╱╱╱╱╱╱╱╱ ╱╱╭━━━━╮╱╱╭━━━━╮ ╱╱┃▇┆┆▇┃╱╭┫ⓦⓔⓔⓚ┃ ╱╱┃▽▽▽▽┃━╯┃♡ⓔⓝⓓ┃ ╱╭┫△△△△┣╮╱╰━━━━╯ ╱┃┃┆┆┆┆┃┃╱╱╱╱╱╱ ╱┗┫┆┏┓┆┣┛╱╱╱╱╱”</p>&mdash; Twitter (@twitter) <a href="https://twitter.com/twitter/status/99530515043983360">August 5, 2011</a></blockquote>
+<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>`,
+	Width: 550,
+}

+ 437 - 0
vendor/github.com/ChimeraCoder/anaconda/twitter_test.go

@@ -0,0 +1,437 @@
+package anaconda_test
+
+import (
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"net/http/httptest"
+	"net/url"
+	"os"
+	"path"
+	"path/filepath"
+	"reflect"
+	"strconv"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/ChimeraCoder/anaconda"
+)
+
+var CONSUMER_KEY = os.Getenv("CONSUMER_KEY")
+var CONSUMER_SECRET = os.Getenv("CONSUMER_SECRET")
+var ACCESS_TOKEN = os.Getenv("ACCESS_TOKEN")
+var ACCESS_TOKEN_SECRET = os.Getenv("ACCESS_TOKEN_SECRET")
+
+var api *anaconda.TwitterApi
+
+var testBase string
+
+func init() {
+	// Initialize api so it can be used even when invidual tests are run in isolation
+	anaconda.SetConsumerKey(CONSUMER_KEY)
+	anaconda.SetConsumerSecret(CONSUMER_SECRET)
+	api = anaconda.NewTwitterApi(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
+
+	if CONSUMER_KEY != "" && CONSUMER_SECRET != "" && ACCESS_TOKEN != "" && ACCESS_TOKEN_SECRET != "" {
+		return
+	}
+
+	mux := http.NewServeMux()
+	server := httptest.NewServer(mux)
+
+	parsed, _ := url.Parse(server.URL)
+	testBase = parsed.String()
+	api.SetBaseUrl(testBase)
+
+	var endpointElems [][]string
+	filepath.Walk("json", func(path string, info os.FileInfo, err error) error {
+		if !info.IsDir() {
+			elems := strings.Split(path, string(os.PathSeparator))[1:]
+			endpointElems = append(endpointElems, elems)
+		}
+
+		return nil
+	})
+
+	for _, elems := range endpointElems {
+		endpoint := strings.Replace("/"+path.Join(elems...), "_id_", "?id=", -1)
+		filename := filepath.Join(append([]string{"json"}, elems...)...)
+
+		mux.HandleFunc(endpoint, func(w http.ResponseWriter, r *http.Request) {
+			// if one filename is the prefix of another, the prefix will always match
+			// check if there is a more specific filename that matches this request
+
+			// create local variable to avoid closing over `filename`
+			sourceFilename := filename
+
+			r.ParseForm()
+			form := strings.Replace(r.Form.Encode(), "=", "_", -1)
+			form = strings.Replace(form, "&", "_", -1)
+			specific := sourceFilename + "_" + form
+			_, err := os.Stat(specific)
+			if err == nil {
+				sourceFilename = specific
+			} else {
+				if err != nil && !os.IsNotExist(err) {
+					fmt.Fprintf(w, "error: %s", err)
+					return
+				}
+			}
+
+			f, err := os.Open(sourceFilename)
+			if err != nil {
+				// either the file does not exist
+				// or something is seriously wrong with the testing environment
+				fmt.Fprintf(w, "error: %s", err)
+			}
+			defer f.Close()
+
+			// TODO not a hack
+			if sourceFilename == filepath.Join("json", "statuses", "show.json_id_404409873170841600_tweet_mode_extended") {
+				bts, err := ioutil.ReadAll(f)
+				if err != nil {
+					http.Error(w, err.Error(), http.StatusInternalServerError)
+
+				}
+				http.Error(w, string(bts), http.StatusNotFound)
+				return
+
+			}
+
+			io.Copy(w, f)
+		})
+	}
+}
+
+// Test_TwitterCredentials tests that non-empty Twitter credentials are set
+// Without this, all following tests will fail
+func Test_TwitterCredentials(t *testing.T) {
+	if CONSUMER_KEY == "" || CONSUMER_SECRET == "" || ACCESS_TOKEN == "" || ACCESS_TOKEN_SECRET == "" {
+		t.Logf("Using HTTP mock responses (API credentials are invalid: at least one is empty)")
+	} else {
+		t.Logf("Tests will query the live Twitter API (API credentials are all non-empty)")
+	}
+}
+
+// Test that creating a TwitterApi client creates a client with non-empty OAuth credentials
+func Test_TwitterApi_NewTwitterApi(t *testing.T) {
+	anaconda.SetConsumerKey(CONSUMER_KEY)
+	anaconda.SetConsumerSecret(CONSUMER_SECRET)
+	apiLocal := anaconda.NewTwitterApi(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
+
+	if apiLocal.Credentials == nil {
+		t.Fatalf("Twitter Api client has empty (nil) credentials")
+	}
+}
+
+// Test that creating a TwitterApi client creates a client with non-empty OAuth credentials
+func Test_TwitterApi_NewTwitterApiWithCredentials(t *testing.T) {
+	apiLocal := anaconda.NewTwitterApiWithCredentials(ACCESS_TOKEN, ACCESS_TOKEN_SECRET, CONSUMER_KEY, CONSUMER_SECRET)
+
+	if apiLocal.Credentials == nil {
+		t.Fatalf("Twitter Api client has empty (nil) credentials")
+	}
+}
+
+// Test that the GetSearch function actually works and returns non-empty results
+func Test_TwitterApi_GetSearch(t *testing.T) {
+	search_result, err := api.GetSearch("golang", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Unless something is seriously wrong, there should be at least two tweets
+	if len(search_result.Statuses) < 2 {
+		t.Fatalf("Expected 2 or more tweets, and found %d", len(search_result.Statuses))
+	}
+
+	// Check that at least one tweet is non-empty
+	for _, tweet := range search_result.Statuses {
+		if tweet.Text != "" {
+			return
+		}
+		fmt.Print(tweet.Text)
+	}
+
+	t.Fatalf("All %d tweets had empty text", len(search_result.Statuses))
+}
+
+// Test that a valid user can be fetched
+// and that unmarshalling works properly
+func Test_GetUser(t *testing.T) {
+	const username = "chimeracoder"
+
+	users, err := api.GetUsersLookup(username, nil)
+	if err != nil {
+		t.Fatalf("GetUsersLookup returned error: %s", err.Error())
+	}
+
+	if len(users) != 1 {
+		t.Fatalf("Expected one user and received %d", len(users))
+	}
+
+	// If all attributes are equal to the zero value for that type,
+	// then the original value was not valid
+	if reflect.DeepEqual(users[0], anaconda.User{}) {
+		t.Fatalf("Received %#v", users[0])
+	}
+}
+
+func Test_GetFavorites(t *testing.T) {
+	v := url.Values{}
+	v.Set("screen_name", "chimeracoder")
+	favorites, err := api.GetFavorites(v)
+	if err != nil {
+		t.Fatalf("GetFavorites returned error: %s", err.Error())
+	}
+
+	if len(favorites) == 0 {
+		t.Fatalf("GetFavorites returned no favorites")
+	}
+
+	if reflect.DeepEqual(favorites[0], anaconda.Tweet{}) {
+		t.Fatalf("GetFavorites returned %d favorites and the first one was empty", len(favorites))
+	}
+}
+
+// Test that a valid tweet can be fetched properly
+// and that unmarshalling of tweet works without error
+func Test_GetTweet(t *testing.T) {
+	const tweetId = 303777106620452864
+	const tweetText = `golang-syd is in session. Dave Symonds is now talking about API design and protobufs. #golang http://t.co/eSq3ROwu`
+
+	tweet, err := api.GetTweet(tweetId, nil)
+	if err != nil {
+		t.Fatalf("GetTweet returned error: %s", err.Error())
+	}
+
+	if tweet.Text != tweetText {
+		t.Fatalf("Tweet %d contained incorrect text. Received: %s", tweetId, tweet.Text)
+	}
+
+	// Check the entities
+	expectedEntities := anaconda.Entities{Hashtags: []struct {
+		Indices []int  `json:"indices"`
+		Text    string `json:"text"`
+	}{struct {
+		Indices []int  `json:"indices"`
+		Text    string `json:"text"`
+	}{Indices: []int{86, 93}, Text: "golang"}}, Urls: []struct {
+		Indices      []int  `json:"indices"`
+		Url          string `json:"url"`
+		Display_url  string `json:"display_url"`
+		Expanded_url string `json:"expanded_url"`
+	}{}, User_mentions: []struct {
+		Name        string `json:"name"`
+		Indices     []int  `json:"indices"`
+		Screen_name string `json:"screen_name"`
+		Id          int64  `json:"id"`
+		Id_str      string `json:"id_str"`
+	}{}, Media: []anaconda.EntityMedia{anaconda.EntityMedia{
+		Id:              303777106628841472,
+		Id_str:          "303777106628841472",
+		Media_url:       "http://pbs.twimg.com/media/BDc7q0OCEAAoe2C.jpg",
+		Media_url_https: "https://pbs.twimg.com/media/BDc7q0OCEAAoe2C.jpg",
+		Url:             "http://t.co/eSq3ROwu",
+		Display_url:     "pic.twitter.com/eSq3ROwu",
+		Expanded_url:    "http://twitter.com/go_nuts/status/303777106620452864/photo/1",
+		Sizes: anaconda.MediaSizes{Medium: anaconda.MediaSize{W: 600,
+			H:      450,
+			Resize: "fit"},
+			Thumb: anaconda.MediaSize{W: 150,
+				H:      150,
+				Resize: "crop"},
+			Small: anaconda.MediaSize{W: 340,
+				H:      255,
+				Resize: "fit"},
+			Large: anaconda.MediaSize{W: 1024,
+				H:      768,
+				Resize: "fit"}},
+		Type: "photo",
+		Indices: []int{94,
+			114}}}}
+	if !reflect.DeepEqual(tweet.Entities, expectedEntities) {
+		t.Fatalf("Tweet entities differ")
+	}
+}
+
+func Test_GetQuotedTweet(t *testing.T) {
+	const tweetId = 738567564641599489
+	const tweetText = `Well, this has certainly come a long way! https://t.co/QomzRzwcti`
+	const quotedID = 284377451625340928
+	const quotedText = `Just created gojson - a simple tool for turning JSON data into Go structs! http://t.co/QM6k9AUV #golang`
+
+	tweet, err := api.GetTweet(tweetId, nil)
+	if err != nil {
+		t.Fatalf("GetTweet returned error: %s", err.Error())
+	}
+
+	if tweet.Text != tweetText {
+		t.Fatalf("Tweet %d contained incorrect text. Received: %s", tweetId, tweet.Text)
+	}
+
+	if tweet.QuotedStatusID != quotedID {
+		t.Fatalf("Expected quoted status %d, received %d", quotedID, tweet.QuotedStatusID)
+	}
+
+	if tweet.QuotedStatusIdStr != strconv.Itoa(quotedID) {
+		t.Fatalf("Expected quoted status %d (as string), received %s", quotedID, tweet.QuotedStatusIdStr)
+	}
+
+	if tweet.QuotedStatus.Text != quotedText {
+		t.Fatalf("Expected quoted status text %#v, received %#v", quotedText, tweet.QuotedStatus.Text)
+	}
+}
+
+// This assumes that the current user has at least two pages' worth of followers
+func Test_GetFollowersListAll(t *testing.T) {
+	result := api.GetFollowersListAll(nil)
+	i := 0
+
+	for page := range result {
+		if i == 2 {
+			return
+		}
+
+		if page.Error != nil {
+			t.Fatalf("Receved error from GetFollowersListAll: %s", page.Error)
+		}
+
+		if page.Followers == nil || len(page.Followers) == 0 {
+			t.Fatalf("Received invalid value for page %d of followers: %v", i, page.Followers)
+		}
+		i++
+	}
+}
+
+// This assumes that the current user has at least two pages' worth of followers
+func Test_GetFollowersIdsAll(t *testing.T) {
+	result := api.GetFollowersIdsAll(nil)
+	i := 0
+
+	for page := range result {
+		if i == 2 {
+			return
+		}
+
+		if page.Error != nil {
+			t.Fatalf("Receved error from GetFollowersIdsAll: %s", page.Error)
+		}
+
+		if page.Ids == nil || len(page.Ids) == 0 {
+			t.Fatalf("Received invalid value for page %d of followers: %v", i, page.Ids)
+		}
+		i++
+	}
+}
+
+// This assumes that the current user has at least two pages' worth of friends
+func Test_GetFriendsIdsAll(t *testing.T) {
+	result := api.GetFriendsIdsAll(nil)
+	i := 0
+
+	for page := range result {
+		if i == 2 {
+			return
+		}
+
+		if page.Error != nil {
+			t.Fatalf("Receved error from GetFriendsIdsAll : %s", page.Error)
+		}
+
+		if page.Ids == nil || len(page.Ids) == 0 {
+			t.Fatalf("Received invalid value for page %d of friends : %v", i, page.Ids)
+		}
+		i++
+	}
+}
+
+// Test that setting the delay actually changes the stored delay value
+func Test_TwitterApi_SetDelay(t *testing.T) {
+	const OLD_DELAY = 1 * time.Second
+	const NEW_DELAY = 20 * time.Second
+	api.EnableThrottling(OLD_DELAY, 4)
+
+	delay := api.GetDelay()
+	if delay != OLD_DELAY {
+		t.Fatalf("Expected initial delay to be the default delay (%s)", anaconda.DEFAULT_DELAY.String())
+	}
+
+	api.SetDelay(NEW_DELAY)
+
+	if newDelay := api.GetDelay(); newDelay != NEW_DELAY {
+		t.Fatalf("Attempted to set delay to %s, but delay is now %s (original delay: %s)", NEW_DELAY, newDelay, delay)
+	}
+}
+
+func Test_TwitterApi_TwitterErrorDoesNotExist(t *testing.T) {
+
+	// Try fetching a tweet that no longer exists (was deleted)
+	const DELETED_TWEET_ID = 404409873170841600
+
+	tweet, err := api.GetTweet(DELETED_TWEET_ID, nil)
+	if err == nil {
+		t.Fatalf("Expected an error when fetching tweet with id %d but got none - tweet object is %+v", DELETED_TWEET_ID, tweet)
+	}
+
+	apiErr, ok := err.(*anaconda.ApiError)
+	if !ok {
+		t.Fatalf("Expected an *anaconda.ApiError, and received error message %s, (%+v)", err.Error(), err)
+	}
+
+	terr, ok := apiErr.Decoded.First().(anaconda.TwitterError)
+
+	if !ok {
+		t.Fatalf("TwitterErrorResponse.First() should return value of type TwitterError, not %s", reflect.TypeOf(apiErr.Decoded.First()))
+	}
+
+	if code := terr.Code; code != anaconda.TwitterErrorDoesNotExist && code != anaconda.TwitterErrorDoesNotExist2 {
+		if code == anaconda.TwitterErrorRateLimitExceeded {
+			t.Fatalf("Rate limit exceeded during testing - received error code %d instead of %d", anaconda.TwitterErrorRateLimitExceeded, anaconda.TwitterErrorDoesNotExist)
+		} else {
+
+			t.Fatalf("Expected Twitter to return error code %d, and instead received error code %d", anaconda.TwitterErrorDoesNotExist, code)
+		}
+	}
+}
+
+func Test_DMScreenName(t *testing.T) {
+	to, err := api.GetSelf(url.Values{})
+	if err != nil {
+		t.Error(err)
+	}
+	_, err = api.PostDMToScreenName("Test the anaconda lib", to.ScreenName)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+}
+
+// Test that the client can be used to throttle to an arbitrary duration
+func Test_TwitterApi_Throttling(t *testing.T) {
+	const MIN_DELAY = 15 * time.Second
+
+	api.EnableThrottling(MIN_DELAY, 5)
+	oldDelay := api.GetDelay()
+	api.SetDelay(MIN_DELAY)
+
+	now := time.Now()
+	_, err := api.GetSearch("golang", nil)
+	if err != nil {
+		t.Fatalf("GetSearch yielded error %s", err.Error())
+	}
+	_, err = api.GetSearch("anaconda", nil)
+	if err != nil {
+		t.Fatalf("GetSearch yielded error %s", err.Error())
+	}
+	after := time.Now()
+
+	if difference := after.Sub(now); difference < MIN_DELAY {
+		t.Fatalf("Expected delay of at least %s. Actual delay: %s", MIN_DELAY.String(), difference.String())
+	}
+
+	// Reset the delay to its previous value
+	api.SetDelay(oldDelay)
+}

+ 77 - 0
vendor/github.com/ChimeraCoder/tokenbucket/tokenbucket_test.go

@@ -0,0 +1,77 @@
+package tokenbucket_test
+
+import (
+	"github.com/ChimeraCoder/tokenbucket"
+	"testing"
+	"time"
+)
+
+func Example_BucketUse() {
+	// Allow a new action every 5 seconds, with a maximum of 3 "in the bank"
+	bucket := tokenbucket.NewBucket(5*time.Second, 3)
+
+	// To perform a regulated action, we must spend a token
+	// RegulatedAction will not be performed until the bucket contains enough tokens
+	<-bucket.SpendToken(1)
+	RegulatedAction()
+}
+
+// RegulatedAction represents some function that is rate-limited, monitored,
+// or otherwise regulated
+func RegulatedAction() {
+	// Some expensive action goes on here
+}
+
+// Test that a bucket that is full does not block execution
+func Test_BucketBuffering(t *testing.T) {
+	// Create a bucket with capacity 3, that adds tokens every 4 seconds
+	const RATE = 4 * time.Second
+	const CAPACITY = 3
+	const ERROR = 500 * time.Millisecond
+	b := tokenbucket.NewBucket(RATE, CAPACITY)
+
+	// Allow the bucket enough time to fill to capacity
+	time.Sleep(CAPACITY * RATE)
+
+	// Check that we can empty the bucket without wasting any time
+	before := time.Now()
+	<-b.SpendToken(1)
+	<-b.SpendToken(1)
+	<-b.SpendToken(1)
+	after := time.Now()
+
+	if diff := after.Sub(before); diff > RATE {
+		t.Errorf("Waited %d seconds, though this should have been nearly instantaneous", diff)
+	}
+}
+
+// Test that a bucket that is empty blocks execution for the correct amount of time
+func Test_BucketCreation(t *testing.T) {
+	// Create a bucket with capacity 3, that adds tokens every 4 seconds
+	const RATE = 4 * time.Second
+	const CAPACITY = 3
+	const ERROR = 500 * time.Millisecond
+	const EXPECTED_DURATION = RATE * CAPACITY
+
+	b := tokenbucket.NewBucket(RATE, CAPACITY)
+
+	// Ensure that the bucket is empty
+	<-b.SpendToken(1)
+	<-b.SpendToken(1)
+	<-b.SpendToken(1)
+	<-b.SpendToken(1)
+
+	// Spending three times on an empty bucket should take 12 seconds
+	// (Take the average across three, due to imprecision/scheduling)
+	before := time.Now()
+	<-b.SpendToken(1)
+	<-b.SpendToken(1)
+	<-b.SpendToken(1)
+	after := time.Now()
+
+	lower := EXPECTED_DURATION - ERROR
+	upper := EXPECTED_DURATION + ERROR
+	if diff := after.Sub(before); diff < lower || diff > upper {
+		t.Errorf("Waited %s seconds, though really should have waited between %s and %s", diff.String(), lower.String(), upper.String())
+	}
+}

+ 234 - 0
vendor/github.com/PuerkitoBio/goquery/array_test.go

@@ -0,0 +1,234 @@
+package goquery
+
+import (
+	"testing"
+)
+
+func TestFirst(t *testing.T) {
+	sel := Doc().Find(".pvk-content").First()
+	assertLength(t, sel.Nodes, 1)
+}
+
+func TestFirstEmpty(t *testing.T) {
+	sel := Doc().Find(".pvk-zzcontentzz").First()
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestFirstInvalid(t *testing.T) {
+	sel := Doc().Find("").First()
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestFirstRollback(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	sel2 := sel.First().End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestLast(t *testing.T) {
+	sel := Doc().Find(".pvk-content").Last()
+	assertLength(t, sel.Nodes, 1)
+
+	// Should contain Footer
+	foot := Doc().Find(".footer")
+	if !sel.Contains(foot.Nodes[0]) {
+		t.Error("Last .pvk-content should contain .footer.")
+	}
+}
+
+func TestLastEmpty(t *testing.T) {
+	sel := Doc().Find(".pvk-zzcontentzz").Last()
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestLastInvalid(t *testing.T) {
+	sel := Doc().Find("").Last()
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestLastRollback(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	sel2 := sel.Last().End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestEq(t *testing.T) {
+	sel := Doc().Find(".pvk-content").Eq(1)
+	assertLength(t, sel.Nodes, 1)
+}
+
+func TestEqNegative(t *testing.T) {
+	sel := Doc().Find(".pvk-content").Eq(-1)
+	assertLength(t, sel.Nodes, 1)
+
+	// Should contain Footer
+	foot := Doc().Find(".footer")
+	if !sel.Contains(foot.Nodes[0]) {
+		t.Error("Index -1 of .pvk-content should contain .footer.")
+	}
+}
+
+func TestEqEmpty(t *testing.T) {
+	sel := Doc().Find("something_random_that_does_not_exists").Eq(0)
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestEqInvalid(t *testing.T) {
+	sel := Doc().Find("").Eq(0)
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestEqInvalidPositive(t *testing.T) {
+	sel := Doc().Find(".pvk-content").Eq(3)
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestEqInvalidNegative(t *testing.T) {
+	sel := Doc().Find(".pvk-content").Eq(-4)
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestEqRollback(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	sel2 := sel.Eq(1).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestSlice(t *testing.T) {
+	sel := Doc().Find(".pvk-content").Slice(0, 2)
+
+	assertLength(t, sel.Nodes, 2)
+	assertSelectionIs(t, sel, "#pc1", "#pc2")
+}
+
+func TestSliceToEnd(t *testing.T) {
+	sel := Doc().Find(".pvk-content").Slice(1, ToEnd)
+
+	assertLength(t, sel.Nodes, 2)
+	assertSelectionIs(t, sel.Eq(0), "#pc2")
+	if _, ok := sel.Eq(1).Attr("id"); ok {
+		t.Error("Want no attribute ID, got one")
+	}
+}
+
+func TestSliceEmpty(t *testing.T) {
+	defer assertPanic(t)
+	Doc().Find("x").Slice(0, 2)
+}
+
+func TestSliceInvalid(t *testing.T) {
+	defer assertPanic(t)
+	Doc().Find("").Slice(0, 2)
+}
+
+func TestSliceInvalidToEnd(t *testing.T) {
+	defer assertPanic(t)
+	Doc().Find("").Slice(2, ToEnd)
+}
+
+func TestSliceOutOfBounds(t *testing.T) {
+	defer assertPanic(t)
+	Doc().Find(".pvk-content").Slice(2, 12)
+}
+
+func TestNegativeSliceStart(t *testing.T) {
+	sel := Doc().Find(".container-fluid").Slice(-2, 3)
+	assertLength(t, sel.Nodes, 1)
+	assertSelectionIs(t, sel.Eq(0), "#cf3")
+}
+
+func TestNegativeSliceEnd(t *testing.T) {
+	sel := Doc().Find(".container-fluid").Slice(1, -1)
+	assertLength(t, sel.Nodes, 2)
+	assertSelectionIs(t, sel.Eq(0), "#cf2")
+	assertSelectionIs(t, sel.Eq(1), "#cf3")
+}
+
+func TestNegativeSliceBoth(t *testing.T) {
+	sel := Doc().Find(".container-fluid").Slice(-3, -1)
+	assertLength(t, sel.Nodes, 2)
+	assertSelectionIs(t, sel.Eq(0), "#cf2")
+	assertSelectionIs(t, sel.Eq(1), "#cf3")
+}
+
+func TestNegativeSliceToEnd(t *testing.T) {
+	sel := Doc().Find(".container-fluid").Slice(-3, ToEnd)
+	assertLength(t, sel.Nodes, 3)
+	assertSelectionIs(t, sel, "#cf2", "#cf3", "#cf4")
+}
+
+func TestNegativeSliceOutOfBounds(t *testing.T) {
+	defer assertPanic(t)
+	Doc().Find(".container-fluid").Slice(-12, -7)
+}
+
+func TestSliceRollback(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	sel2 := sel.Slice(0, 2).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestGet(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	node := sel.Get(1)
+	if sel.Nodes[1] != node {
+		t.Errorf("Expected node %v to be %v.", node, sel.Nodes[1])
+	}
+}
+
+func TestGetNegative(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	node := sel.Get(-3)
+	if sel.Nodes[0] != node {
+		t.Errorf("Expected node %v to be %v.", node, sel.Nodes[0])
+	}
+}
+
+func TestGetInvalid(t *testing.T) {
+	defer assertPanic(t)
+	sel := Doc().Find(".pvk-content")
+	sel.Get(129)
+}
+
+func TestIndex(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	if i := sel.Index(); i != 1 {
+		t.Errorf("Expected index of 1, got %v.", i)
+	}
+}
+
+func TestIndexSelector(t *testing.T) {
+	sel := Doc().Find(".hero-unit")
+	if i := sel.IndexSelector("div"); i != 4 {
+		t.Errorf("Expected index of 4, got %v.", i)
+	}
+}
+
+func TestIndexSelectorInvalid(t *testing.T) {
+	sel := Doc().Find(".hero-unit")
+	if i := sel.IndexSelector(""); i != -1 {
+		t.Errorf("Expected index of -1, got %v.", i)
+	}
+}
+
+func TestIndexOfNode(t *testing.T) {
+	sel := Doc().Find("div.pvk-gutter")
+	if i := sel.IndexOfNode(sel.Nodes[1]); i != 1 {
+		t.Errorf("Expected index of 1, got %v.", i)
+	}
+}
+
+func TestIndexOfNilNode(t *testing.T) {
+	sel := Doc().Find("div.pvk-gutter")
+	if i := sel.IndexOfNode(nil); i != -1 {
+		t.Errorf("Expected index of -1, got %v.", i)
+	}
+}
+
+func TestIndexOfSelection(t *testing.T) {
+	sel := Doc().Find("div")
+	sel2 := Doc().Find(".hero-unit")
+	if i := sel.IndexOfSelection(sel2); i != 4 {
+		t.Errorf("Expected index of 4, got %v.", i)
+	}
+}

+ 120 - 0
vendor/github.com/PuerkitoBio/goquery/bench_array_test.go

@@ -0,0 +1,120 @@
+package goquery
+
+import (
+	"testing"
+)
+
+func BenchmarkFirst(b *testing.B) {
+	b.StopTimer()
+	sel := DocB().Find("dd")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		sel.First()
+	}
+}
+
+func BenchmarkLast(b *testing.B) {
+	b.StopTimer()
+	sel := DocB().Find("dd")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		sel.Last()
+	}
+}
+
+func BenchmarkEq(b *testing.B) {
+	b.StopTimer()
+	sel := DocB().Find("dd")
+	j := 0
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		sel.Eq(j)
+		if j++; j >= sel.Length() {
+			j = 0
+		}
+	}
+}
+
+func BenchmarkSlice(b *testing.B) {
+	b.StopTimer()
+	sel := DocB().Find("dd")
+	j := 0
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		sel.Slice(j, j+4)
+		if j++; j >= (sel.Length() - 4) {
+			j = 0
+		}
+	}
+}
+
+func BenchmarkGet(b *testing.B) {
+	b.StopTimer()
+	sel := DocB().Find("dd")
+	j := 0
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		sel.Get(j)
+		if j++; j >= sel.Length() {
+			j = 0
+		}
+	}
+}
+
+func BenchmarkIndex(b *testing.B) {
+	var j int
+
+	b.StopTimer()
+	sel := DocB().Find("#Main")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		j = sel.Index()
+	}
+	if j != 3 {
+		b.Fatalf("want 3, got %d", j)
+	}
+}
+
+func BenchmarkIndexSelector(b *testing.B) {
+	var j int
+
+	b.StopTimer()
+	sel := DocB().Find("#manual-nav dl dd:nth-child(1)")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		j = sel.IndexSelector("dd")
+	}
+	if j != 4 {
+		b.Fatalf("want 4, got %d", j)
+	}
+}
+
+func BenchmarkIndexOfNode(b *testing.B) {
+	var j int
+
+	b.StopTimer()
+	sel := DocB().Find("span a")
+	sel2 := DocB().Find("span a:nth-child(3)")
+	n := sel2.Get(0)
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		j = sel.IndexOfNode(n)
+	}
+	if j != 2 {
+		b.Fatalf("want 2, got %d", j)
+	}
+}
+
+func BenchmarkIndexOfSelection(b *testing.B) {
+	var j int
+	b.StopTimer()
+	sel := DocB().Find("span a")
+	sel2 := DocB().Find("span a:nth-child(3)")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		j = sel.IndexOfSelection(sel2)
+	}
+	if j != 2 {
+		b.Fatalf("want 2, got %d", j)
+	}
+}

+ 40 - 0
vendor/github.com/PuerkitoBio/goquery/bench_example_test.go

@@ -0,0 +1,40 @@
+package goquery
+
+import (
+	"bytes"
+	"fmt"
+	"strconv"
+	"testing"
+)
+
+func BenchmarkMetalReviewExample(b *testing.B) {
+	var n int
+	var buf bytes.Buffer
+
+	b.StopTimer()
+	doc := loadDoc("metalreview.html")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		doc.Find(".slider-row:nth-child(1) .slider-item").Each(func(i int, s *Selection) {
+			var band, title string
+			var score float64
+			var e error
+
+			n++
+			// For each item found, get the band, title and score, and print it
+			band = s.Find("strong").Text()
+			title = s.Find("em").Text()
+			if score, e = strconv.ParseFloat(s.Find(".score").Text(), 64); e != nil {
+				// Not a valid float, ignore score
+				if n <= 4 {
+					buf.WriteString(fmt.Sprintf("Review %d: %s - %s.\n", i, band, title))
+				}
+			} else {
+				// Print all, including score
+				if n <= 4 {
+					buf.WriteString(fmt.Sprintf("Review %d: %s - %s (%2.1f).\n", i, band, title, score))
+				}
+			}
+		})
+	}
+}

+ 104 - 0
vendor/github.com/PuerkitoBio/goquery/bench_expand_test.go

@@ -0,0 +1,104 @@
+package goquery
+
+import (
+	"testing"
+)
+
+func BenchmarkAdd(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocB().Find("dd")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.Add("h2[title]").Length()
+		} else {
+			sel.Add("h2[title]")
+		}
+	}
+	if n != 43 {
+		b.Fatalf("want 43, got %d", n)
+	}
+}
+
+func BenchmarkAddSelection(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocB().Find("dd")
+	sel2 := DocB().Find("h2[title]")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.AddSelection(sel2).Length()
+		} else {
+			sel.AddSelection(sel2)
+		}
+	}
+	if n != 43 {
+		b.Fatalf("want 43, got %d", n)
+	}
+}
+
+func BenchmarkAddNodes(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocB().Find("dd")
+	sel2 := DocB().Find("h2[title]")
+	nodes := sel2.Nodes
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.AddNodes(nodes...).Length()
+		} else {
+			sel.AddNodes(nodes...)
+		}
+	}
+	if n != 43 {
+		b.Fatalf("want 43, got %d", n)
+	}
+}
+
+func BenchmarkAddNodesBig(b *testing.B) {
+	var n int
+
+	doc := DocW()
+	sel := doc.Find("li")
+	// make nodes > 1000
+	nodes := sel.Nodes
+	nodes = append(nodes, nodes...)
+	nodes = append(nodes, nodes...)
+	sel = doc.Find("xyz")
+	b.ResetTimer()
+
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.AddNodes(nodes...).Length()
+		} else {
+			sel.AddNodes(nodes...)
+		}
+	}
+	if n != 373 {
+		b.Fatalf("want 373, got %d", n)
+	}
+}
+
+func BenchmarkAndSelf(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocB().Find("dd").Parent()
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.AndSelf().Length()
+		} else {
+			sel.AndSelf()
+		}
+	}
+	if n != 44 {
+		b.Fatalf("want 44, got %d", n)
+	}
+}

+ 236 - 0
vendor/github.com/PuerkitoBio/goquery/bench_filter_test.go

@@ -0,0 +1,236 @@
+package goquery
+
+import (
+	"testing"
+)
+
+func BenchmarkFilter(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.Filter(".toclevel-1").Length()
+		} else {
+			sel.Filter(".toclevel-1")
+		}
+	}
+	if n != 13 {
+		b.Fatalf("want 13, got %d", n)
+	}
+}
+
+func BenchmarkNot(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.Not(".toclevel-2").Length()
+		} else {
+			sel.Filter(".toclevel-2")
+		}
+	}
+	if n != 371 {
+		b.Fatalf("want 371, got %d", n)
+	}
+}
+
+func BenchmarkFilterFunction(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li")
+	f := func(i int, s *Selection) bool {
+		return len(s.Get(0).Attr) > 0
+	}
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.FilterFunction(f).Length()
+		} else {
+			sel.FilterFunction(f)
+		}
+	}
+	if n != 112 {
+		b.Fatalf("want 112, got %d", n)
+	}
+}
+
+func BenchmarkNotFunction(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li")
+	f := func(i int, s *Selection) bool {
+		return len(s.Get(0).Attr) > 0
+	}
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.NotFunction(f).Length()
+		} else {
+			sel.NotFunction(f)
+		}
+	}
+	if n != 261 {
+		b.Fatalf("want 261, got %d", n)
+	}
+}
+
+func BenchmarkFilterNodes(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li")
+	sel2 := DocW().Find(".toclevel-2")
+	nodes := sel2.Nodes
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.FilterNodes(nodes...).Length()
+		} else {
+			sel.FilterNodes(nodes...)
+		}
+	}
+	if n != 2 {
+		b.Fatalf("want 2, got %d", n)
+	}
+}
+
+func BenchmarkNotNodes(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li")
+	sel2 := DocW().Find(".toclevel-1")
+	nodes := sel2.Nodes
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.NotNodes(nodes...).Length()
+		} else {
+			sel.NotNodes(nodes...)
+		}
+	}
+	if n != 360 {
+		b.Fatalf("want 360, got %d", n)
+	}
+}
+
+func BenchmarkFilterSelection(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li")
+	sel2 := DocW().Find(".toclevel-2")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.FilterSelection(sel2).Length()
+		} else {
+			sel.FilterSelection(sel2)
+		}
+	}
+	if n != 2 {
+		b.Fatalf("want 2, got %d", n)
+	}
+}
+
+func BenchmarkNotSelection(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li")
+	sel2 := DocW().Find(".toclevel-1")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.NotSelection(sel2).Length()
+		} else {
+			sel.NotSelection(sel2)
+		}
+	}
+	if n != 360 {
+		b.Fatalf("want 360, got %d", n)
+	}
+}
+
+func BenchmarkHas(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("h2")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.Has(".editsection").Length()
+		} else {
+			sel.Has(".editsection")
+		}
+	}
+	if n != 13 {
+		b.Fatalf("want 13, got %d", n)
+	}
+}
+
+func BenchmarkHasNodes(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li")
+	sel2 := DocW().Find(".tocnumber")
+	nodes := sel2.Nodes
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.HasNodes(nodes...).Length()
+		} else {
+			sel.HasNodes(nodes...)
+		}
+	}
+	if n != 15 {
+		b.Fatalf("want 15, got %d", n)
+	}
+}
+
+func BenchmarkHasSelection(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li")
+	sel2 := DocW().Find(".tocnumber")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.HasSelection(sel2).Length()
+		} else {
+			sel.HasSelection(sel2)
+		}
+	}
+	if n != 15 {
+		b.Fatalf("want 15, got %d", n)
+	}
+}
+
+func BenchmarkEnd(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li").Has(".tocnumber")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.End().Length()
+		} else {
+			sel.End()
+		}
+	}
+	if n != 373 {
+		b.Fatalf("want 373, got %d", n)
+	}
+}

+ 68 - 0
vendor/github.com/PuerkitoBio/goquery/bench_iteration_test.go

@@ -0,0 +1,68 @@
+package goquery
+
+import (
+	"testing"
+)
+
+func BenchmarkEach(b *testing.B) {
+	var tmp, n int
+
+	b.StopTimer()
+	sel := DocW().Find("td")
+	f := func(i int, s *Selection) {
+		tmp++
+	}
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		sel.Each(f)
+		if n == 0 {
+			n = tmp
+		}
+	}
+	if n != 59 {
+		b.Fatalf("want 59, got %d", n)
+	}
+}
+
+func BenchmarkMap(b *testing.B) {
+	var tmp, n int
+
+	b.StopTimer()
+	sel := DocW().Find("td")
+	f := func(i int, s *Selection) string {
+		tmp++
+		return string(tmp)
+	}
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		sel.Map(f)
+		if n == 0 {
+			n = tmp
+		}
+	}
+	if n != 59 {
+		b.Fatalf("want 59, got %d", n)
+	}
+}
+
+func BenchmarkEachWithBreak(b *testing.B) {
+	var tmp, n int
+
+	b.StopTimer()
+	sel := DocW().Find("td")
+	f := func(i int, s *Selection) bool {
+		tmp++
+		return tmp < 10
+	}
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		tmp = 0
+		sel.EachWithBreak(f)
+		if n == 0 {
+			n = tmp
+		}
+	}
+	if n != 10 {
+		b.Fatalf("want 10, got %d", n)
+	}
+}

+ 51 - 0
vendor/github.com/PuerkitoBio/goquery/bench_property_test.go

@@ -0,0 +1,51 @@
+package goquery
+
+import (
+	"testing"
+)
+
+func BenchmarkAttr(b *testing.B) {
+	var s string
+
+	b.StopTimer()
+	sel := DocW().Find("h1")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		s, _ = sel.Attr("id")
+	}
+	if s != "firstHeading" {
+		b.Fatalf("want firstHeading, got %q", s)
+	}
+}
+
+func BenchmarkText(b *testing.B) {
+	b.StopTimer()
+	sel := DocW().Find("h2")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		sel.Text()
+	}
+}
+
+func BenchmarkLength(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("h2")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		n = sel.Length()
+	}
+	if n != 14 {
+		b.Fatalf("want 14, got %d", n)
+	}
+}
+
+func BenchmarkHtml(b *testing.B) {
+	b.StopTimer()
+	sel := DocW().Find("h2")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		sel.Html()
+	}
+}

+ 111 - 0
vendor/github.com/PuerkitoBio/goquery/bench_query_test.go

@@ -0,0 +1,111 @@
+package goquery
+
+import (
+	"testing"
+)
+
+func BenchmarkIs(b *testing.B) {
+	var y bool
+
+	b.StopTimer()
+	sel := DocW().Find("li")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		y = sel.Is(".toclevel-2")
+	}
+	if !y {
+		b.Fatal("want true")
+	}
+}
+
+func BenchmarkIsPositional(b *testing.B) {
+	var y bool
+
+	b.StopTimer()
+	sel := DocW().Find("li")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		y = sel.Is("li:nth-child(2)")
+	}
+	if !y {
+		b.Fatal("want true")
+	}
+}
+
+func BenchmarkIsFunction(b *testing.B) {
+	var y bool
+
+	b.StopTimer()
+	sel := DocW().Find(".toclevel-1")
+	f := func(i int, s *Selection) bool {
+		return i == 8
+	}
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		y = sel.IsFunction(f)
+	}
+	if !y {
+		b.Fatal("want true")
+	}
+}
+
+func BenchmarkIsSelection(b *testing.B) {
+	var y bool
+
+	b.StopTimer()
+	sel := DocW().Find("li")
+	sel2 := DocW().Find(".toclevel-2")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		y = sel.IsSelection(sel2)
+	}
+	if !y {
+		b.Fatal("want true")
+	}
+}
+
+func BenchmarkIsNodes(b *testing.B) {
+	var y bool
+
+	b.StopTimer()
+	sel := DocW().Find("li")
+	sel2 := DocW().Find(".toclevel-2")
+	nodes := sel2.Nodes
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		y = sel.IsNodes(nodes...)
+	}
+	if !y {
+		b.Fatal("want true")
+	}
+}
+
+func BenchmarkHasClass(b *testing.B) {
+	var y bool
+
+	b.StopTimer()
+	sel := DocW().Find("span")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		y = sel.HasClass("official")
+	}
+	if !y {
+		b.Fatal("want true")
+	}
+}
+
+func BenchmarkContains(b *testing.B) {
+	var y bool
+
+	b.StopTimer()
+	sel := DocW().Find("span.url")
+	sel2 := DocW().Find("a[rel=\"nofollow\"]")
+	node := sel2.Nodes[0]
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		y = sel.Contains(node)
+	}
+	if !y {
+		b.Fatal("want true")
+	}
+}

+ 802 - 0
vendor/github.com/PuerkitoBio/goquery/bench_traversal_test.go

@@ -0,0 +1,802 @@
+package goquery
+
+import (
+	"testing"
+)
+
+func BenchmarkFind(b *testing.B) {
+	var n int
+
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = DocB().Find("dd").Length()
+
+		} else {
+			DocB().Find("dd")
+		}
+	}
+	if n != 41 {
+		b.Fatalf("want 41, got %d", n)
+	}
+}
+
+func BenchmarkFindWithinSelection(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("ul")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.Find("a[class]").Length()
+		} else {
+			sel.Find("a[class]")
+		}
+	}
+	if n != 39 {
+		b.Fatalf("want 39, got %d", n)
+	}
+}
+
+func BenchmarkFindSelection(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("ul")
+	sel2 := DocW().Find("span")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.FindSelection(sel2).Length()
+		} else {
+			sel.FindSelection(sel2)
+		}
+	}
+	if n != 73 {
+		b.Fatalf("want 73, got %d", n)
+	}
+}
+
+func BenchmarkFindNodes(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("ul")
+	sel2 := DocW().Find("span")
+	nodes := sel2.Nodes
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.FindNodes(nodes...).Length()
+		} else {
+			sel.FindNodes(nodes...)
+		}
+	}
+	if n != 73 {
+		b.Fatalf("want 73, got %d", n)
+	}
+}
+
+func BenchmarkContents(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find(".toclevel-1")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.Contents().Length()
+		} else {
+			sel.Contents()
+		}
+	}
+	if n != 16 {
+		b.Fatalf("want 16, got %d", n)
+	}
+}
+
+func BenchmarkContentsFiltered(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find(".toclevel-1")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.ContentsFiltered("a[href=\"#Examples\"]").Length()
+		} else {
+			sel.ContentsFiltered("a[href=\"#Examples\"]")
+		}
+	}
+	if n != 1 {
+		b.Fatalf("want 1, got %d", n)
+	}
+}
+
+func BenchmarkChildren(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find(".toclevel-2")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.Children().Length()
+		} else {
+			sel.Children()
+		}
+	}
+	if n != 2 {
+		b.Fatalf("want 2, got %d", n)
+	}
+}
+
+func BenchmarkChildrenFiltered(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("h3")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.ChildrenFiltered(".editsection").Length()
+		} else {
+			sel.ChildrenFiltered(".editsection")
+		}
+	}
+	if n != 2 {
+		b.Fatalf("want 2, got %d", n)
+	}
+}
+
+func BenchmarkParent(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.Parent().Length()
+		} else {
+			sel.Parent()
+		}
+	}
+	if n != 55 {
+		b.Fatalf("want 55, got %d", n)
+	}
+}
+
+func BenchmarkParentFiltered(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.ParentFiltered("ul[id]").Length()
+		} else {
+			sel.ParentFiltered("ul[id]")
+		}
+	}
+	if n != 4 {
+		b.Fatalf("want 4, got %d", n)
+	}
+}
+
+func BenchmarkParents(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("th a")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.Parents().Length()
+		} else {
+			sel.Parents()
+		}
+	}
+	if n != 73 {
+		b.Fatalf("want 73, got %d", n)
+	}
+}
+
+func BenchmarkParentsFiltered(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("th a")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.ParentsFiltered("tr").Length()
+		} else {
+			sel.ParentsFiltered("tr")
+		}
+	}
+	if n != 18 {
+		b.Fatalf("want 18, got %d", n)
+	}
+}
+
+func BenchmarkParentsUntil(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("th a")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.ParentsUntil("table").Length()
+		} else {
+			sel.ParentsUntil("table")
+		}
+	}
+	if n != 52 {
+		b.Fatalf("want 52, got %d", n)
+	}
+}
+
+func BenchmarkParentsUntilSelection(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("th a")
+	sel2 := DocW().Find("#content")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.ParentsUntilSelection(sel2).Length()
+		} else {
+			sel.ParentsUntilSelection(sel2)
+		}
+	}
+	if n != 70 {
+		b.Fatalf("want 70, got %d", n)
+	}
+}
+
+func BenchmarkParentsUntilNodes(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("th a")
+	sel2 := DocW().Find("#content")
+	nodes := sel2.Nodes
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.ParentsUntilNodes(nodes...).Length()
+		} else {
+			sel.ParentsUntilNodes(nodes...)
+		}
+	}
+	if n != 70 {
+		b.Fatalf("want 70, got %d", n)
+	}
+}
+
+func BenchmarkParentsFilteredUntil(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find(".toclevel-1 a")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.ParentsFilteredUntil(":nth-child(1)", "ul").Length()
+		} else {
+			sel.ParentsFilteredUntil(":nth-child(1)", "ul")
+		}
+	}
+	if n != 2 {
+		b.Fatalf("want 2, got %d", n)
+	}
+}
+
+func BenchmarkParentsFilteredUntilSelection(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find(".toclevel-1 a")
+	sel2 := DocW().Find("ul")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.ParentsFilteredUntilSelection(":nth-child(1)", sel2).Length()
+		} else {
+			sel.ParentsFilteredUntilSelection(":nth-child(1)", sel2)
+		}
+	}
+	if n != 2 {
+		b.Fatalf("want 2, got %d", n)
+	}
+}
+
+func BenchmarkParentsFilteredUntilNodes(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find(".toclevel-1 a")
+	sel2 := DocW().Find("ul")
+	nodes := sel2.Nodes
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.ParentsFilteredUntilNodes(":nth-child(1)", nodes...).Length()
+		} else {
+			sel.ParentsFilteredUntilNodes(":nth-child(1)", nodes...)
+		}
+	}
+	if n != 2 {
+		b.Fatalf("want 2, got %d", n)
+	}
+}
+
+func BenchmarkSiblings(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("ul li:nth-child(1)")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.Siblings().Length()
+		} else {
+			sel.Siblings()
+		}
+	}
+	if n != 293 {
+		b.Fatalf("want 293, got %d", n)
+	}
+}
+
+func BenchmarkSiblingsFiltered(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("ul li:nth-child(1)")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.SiblingsFiltered("[class]").Length()
+		} else {
+			sel.SiblingsFiltered("[class]")
+		}
+	}
+	if n != 46 {
+		b.Fatalf("want 46, got %d", n)
+	}
+}
+
+func BenchmarkNext(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li:nth-child(1)")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.Next().Length()
+		} else {
+			sel.Next()
+		}
+	}
+	if n != 49 {
+		b.Fatalf("want 49, got %d", n)
+	}
+}
+
+func BenchmarkNextFiltered(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li:nth-child(1)")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.NextFiltered("[class]").Length()
+		} else {
+			sel.NextFiltered("[class]")
+		}
+	}
+	if n != 6 {
+		b.Fatalf("want 6, got %d", n)
+	}
+}
+
+func BenchmarkNextAll(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li:nth-child(3)")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.NextAll().Length()
+		} else {
+			sel.NextAll()
+		}
+	}
+	if n != 234 {
+		b.Fatalf("want 234, got %d", n)
+	}
+}
+
+func BenchmarkNextAllFiltered(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li:nth-child(3)")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.NextAllFiltered("[class]").Length()
+		} else {
+			sel.NextAllFiltered("[class]")
+		}
+	}
+	if n != 33 {
+		b.Fatalf("want 33, got %d", n)
+	}
+}
+
+func BenchmarkPrev(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li:last-child")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.Prev().Length()
+		} else {
+			sel.Prev()
+		}
+	}
+	if n != 49 {
+		b.Fatalf("want 49, got %d", n)
+	}
+}
+
+func BenchmarkPrevFiltered(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li:last-child")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.PrevFiltered("[class]").Length()
+		} else {
+			sel.PrevFiltered("[class]")
+		}
+	}
+	// There is one more Prev li with a class, compared to Next li with a class
+	// (confirmed by looking at the HTML, this is ok)
+	if n != 7 {
+		b.Fatalf("want 7, got %d", n)
+	}
+}
+
+func BenchmarkPrevAll(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li:nth-child(4)")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.PrevAll().Length()
+		} else {
+			sel.PrevAll()
+		}
+	}
+	if n != 78 {
+		b.Fatalf("want 78, got %d", n)
+	}
+}
+
+func BenchmarkPrevAllFiltered(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li:nth-child(4)")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.PrevAllFiltered("[class]").Length()
+		} else {
+			sel.PrevAllFiltered("[class]")
+		}
+	}
+	if n != 6 {
+		b.Fatalf("want 6, got %d", n)
+	}
+}
+
+func BenchmarkNextUntil(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li:first-child")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.NextUntil(":nth-child(4)").Length()
+		} else {
+			sel.NextUntil(":nth-child(4)")
+		}
+	}
+	if n != 84 {
+		b.Fatalf("want 84, got %d", n)
+	}
+}
+
+func BenchmarkNextUntilSelection(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("h2")
+	sel2 := DocW().Find("ul")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.NextUntilSelection(sel2).Length()
+		} else {
+			sel.NextUntilSelection(sel2)
+		}
+	}
+	if n != 42 {
+		b.Fatalf("want 42, got %d", n)
+	}
+}
+
+func BenchmarkNextUntilNodes(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("h2")
+	sel2 := DocW().Find("p")
+	nodes := sel2.Nodes
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.NextUntilNodes(nodes...).Length()
+		} else {
+			sel.NextUntilNodes(nodes...)
+		}
+	}
+	if n != 12 {
+		b.Fatalf("want 12, got %d", n)
+	}
+}
+
+func BenchmarkPrevUntil(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("li:last-child")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.PrevUntil(":nth-child(4)").Length()
+		} else {
+			sel.PrevUntil(":nth-child(4)")
+		}
+	}
+	if n != 238 {
+		b.Fatalf("want 238, got %d", n)
+	}
+}
+
+func BenchmarkPrevUntilSelection(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("h2")
+	sel2 := DocW().Find("ul")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.PrevUntilSelection(sel2).Length()
+		} else {
+			sel.PrevUntilSelection(sel2)
+		}
+	}
+	if n != 49 {
+		b.Fatalf("want 49, got %d", n)
+	}
+}
+
+func BenchmarkPrevUntilNodes(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("h2")
+	sel2 := DocW().Find("p")
+	nodes := sel2.Nodes
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.PrevUntilNodes(nodes...).Length()
+		} else {
+			sel.PrevUntilNodes(nodes...)
+		}
+	}
+	if n != 11 {
+		b.Fatalf("want 11, got %d", n)
+	}
+}
+
+func BenchmarkNextFilteredUntil(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("h2")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.NextFilteredUntil("p", "div").Length()
+		} else {
+			sel.NextFilteredUntil("p", "div")
+		}
+	}
+	if n != 22 {
+		b.Fatalf("want 22, got %d", n)
+	}
+}
+
+func BenchmarkNextFilteredUntilSelection(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("h2")
+	sel2 := DocW().Find("div")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.NextFilteredUntilSelection("p", sel2).Length()
+		} else {
+			sel.NextFilteredUntilSelection("p", sel2)
+		}
+	}
+	if n != 22 {
+		b.Fatalf("want 22, got %d", n)
+	}
+}
+
+func BenchmarkNextFilteredUntilNodes(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("h2")
+	sel2 := DocW().Find("div")
+	nodes := sel2.Nodes
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.NextFilteredUntilNodes("p", nodes...).Length()
+		} else {
+			sel.NextFilteredUntilNodes("p", nodes...)
+		}
+	}
+	if n != 22 {
+		b.Fatalf("want 22, got %d", n)
+	}
+}
+
+func BenchmarkPrevFilteredUntil(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("h2")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.PrevFilteredUntil("p", "div").Length()
+		} else {
+			sel.PrevFilteredUntil("p", "div")
+		}
+	}
+	if n != 20 {
+		b.Fatalf("want 20, got %d", n)
+	}
+}
+
+func BenchmarkPrevFilteredUntilSelection(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("h2")
+	sel2 := DocW().Find("div")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.PrevFilteredUntilSelection("p", sel2).Length()
+		} else {
+			sel.PrevFilteredUntilSelection("p", sel2)
+		}
+	}
+	if n != 20 {
+		b.Fatalf("want 20, got %d", n)
+	}
+}
+
+func BenchmarkPrevFilteredUntilNodes(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := DocW().Find("h2")
+	sel2 := DocW().Find("div")
+	nodes := sel2.Nodes
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.PrevFilteredUntilNodes("p", nodes...).Length()
+		} else {
+			sel.PrevFilteredUntilNodes("p", nodes...)
+		}
+	}
+	if n != 20 {
+		b.Fatalf("want 20, got %d", n)
+	}
+}
+
+func BenchmarkClosest(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := Doc().Find(".container-fluid")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.Closest(".pvk-content").Length()
+		} else {
+			sel.Closest(".pvk-content")
+		}
+	}
+	if n != 2 {
+		b.Fatalf("want 2, got %d", n)
+	}
+}
+
+func BenchmarkClosestSelection(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := Doc().Find(".container-fluid")
+	sel2 := Doc().Find(".pvk-content")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.ClosestSelection(sel2).Length()
+		} else {
+			sel.ClosestSelection(sel2)
+		}
+	}
+	if n != 2 {
+		b.Fatalf("want 2, got %d", n)
+	}
+}
+
+func BenchmarkClosestNodes(b *testing.B) {
+	var n int
+
+	b.StopTimer()
+	sel := Doc().Find(".container-fluid")
+	nodes := Doc().Find(".pvk-content").Nodes
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if n == 0 {
+			n = sel.ClosestNodes(nodes...).Length()
+		} else {
+			sel.ClosestNodes(nodes...)
+		}
+	}
+	if n != 2 {
+		b.Fatalf("want 2, got %d", n)
+	}
+}

+ 82 - 0
vendor/github.com/PuerkitoBio/goquery/example_test.go

@@ -0,0 +1,82 @@
+package goquery_test
+
+import (
+	"fmt"
+	"log"
+	"net/http"
+	"os"
+	"strings"
+
+	"github.com/PuerkitoBio/goquery"
+)
+
+// This example scrapes the reviews shown on the home page of metalsucks.net.
+func Example() {
+	// Request the HTML page.
+	res, err := http.Get("http://metalsucks.net")
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer res.Body.Close()
+	if res.StatusCode != 200 {
+		log.Fatalf("status code error: %d %s", res.StatusCode, res.Status)
+	}
+
+	// Load the HTML document
+	doc, err := goquery.NewDocumentFromReader(res.Body)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// Find the review items
+	doc.Find(".sidebar-reviews article .content-block").Each(func(i int, s *goquery.Selection) {
+		// For each item found, get the band and title
+		band := s.Find("a").Text()
+		title := s.Find("i").Text()
+		fmt.Printf("Review %d: %s - %s\n", i, band, title)
+	})
+	// To see the output of the Example while running the test suite (go test), simply
+	// remove the leading "x" before Output on the next line. This will cause the
+	// example to fail (all the "real" tests should pass).
+
+	// xOutput: voluntarily fail the Example output.
+}
+
+// This example shows how to use NewDocumentFromReader from a file.
+func ExampleNewDocumentFromReader_file() {
+	// create from a file
+	f, err := os.Open("some/file.html")
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer f.Close()
+	doc, err := goquery.NewDocumentFromReader(f)
+	if err != nil {
+		log.Fatal(err)
+	}
+	// use the goquery document...
+	_ = doc.Find("h1")
+}
+
+// This example shows how to use NewDocumentFromReader from a string.
+func ExampleNewDocumentFromReader_string() {
+	// create from a string
+	data := `
+<html>
+	<head>
+		<title>My document</title>
+	</head>
+	<body>
+		<h1>Header</h1>
+	</body>
+</html>`
+
+	doc, err := goquery.NewDocumentFromReader(strings.NewReader(data))
+	if err != nil {
+		log.Fatal(err)
+	}
+	header := doc.Find("h1").Text()
+	fmt.Println(header)
+
+	// Output: Header
+}

+ 118 - 0
vendor/github.com/PuerkitoBio/goquery/expand_test.go

@@ -0,0 +1,118 @@
+package goquery
+
+import (
+	"testing"
+)
+
+func TestAdd(t *testing.T) {
+	sel := Doc().Find("div.row-fluid").Add("a")
+	assertLength(t, sel.Nodes, 19)
+}
+
+func TestAddInvalid(t *testing.T) {
+	sel1 := Doc().Find("div.row-fluid")
+	sel2 := sel1.Add("")
+	assertLength(t, sel1.Nodes, 9)
+	assertLength(t, sel2.Nodes, 9)
+	if sel1 == sel2 {
+		t.Errorf("selections should not be the same")
+	}
+}
+
+func TestAddRollback(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	sel2 := sel.Add("a").End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestAddSelection(t *testing.T) {
+	sel := Doc().Find("div.row-fluid")
+	sel2 := Doc().Find("a")
+	sel = sel.AddSelection(sel2)
+	assertLength(t, sel.Nodes, 19)
+}
+
+func TestAddSelectionNil(t *testing.T) {
+	sel := Doc().Find("div.row-fluid")
+	assertLength(t, sel.Nodes, 9)
+
+	sel = sel.AddSelection(nil)
+	assertLength(t, sel.Nodes, 9)
+}
+
+func TestAddSelectionRollback(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	sel2 := sel.Find("a")
+	sel2 = sel.AddSelection(sel2).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestAddNodes(t *testing.T) {
+	sel := Doc().Find("div.pvk-gutter")
+	sel2 := Doc().Find(".pvk-content")
+	sel = sel.AddNodes(sel2.Nodes...)
+	assertLength(t, sel.Nodes, 9)
+}
+
+func TestAddNodesNone(t *testing.T) {
+	sel := Doc().Find("div.pvk-gutter").AddNodes()
+	assertLength(t, sel.Nodes, 6)
+}
+
+func TestAddNodesRollback(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	sel2 := sel.Find("a")
+	sel2 = sel.AddNodes(sel2.Nodes...).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestAddNodesBig(t *testing.T) {
+	doc := DocW()
+	sel := doc.Find("li")
+	assertLength(t, sel.Nodes, 373)
+	sel2 := doc.Find("xyz")
+	assertLength(t, sel2.Nodes, 0)
+
+	nodes := sel.Nodes
+	sel2 = sel2.AddNodes(nodes...)
+	assertLength(t, sel2.Nodes, 373)
+	nodes2 := append(nodes, nodes...)
+	sel2 = sel2.End().AddNodes(nodes2...)
+	assertLength(t, sel2.Nodes, 373)
+	nodes3 := append(nodes2, nodes...)
+	sel2 = sel2.End().AddNodes(nodes3...)
+	assertLength(t, sel2.Nodes, 373)
+}
+
+func TestAndSelf(t *testing.T) {
+	sel := Doc().Find(".span12").Last().AndSelf()
+	assertLength(t, sel.Nodes, 2)
+}
+
+func TestAndSelfRollback(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	sel2 := sel.Find("a").AndSelf().End().End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestAddBack(t *testing.T) {
+	sel := Doc().Find(".span12").Last().AddBack()
+	assertLength(t, sel.Nodes, 2)
+}
+
+func TestAddBackRollback(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	sel2 := sel.Find("a").AddBack().End().End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestAddBackFiltered(t *testing.T) {
+	sel := Doc().Find(".span12, .footer").Find("h1").AddBackFiltered(".footer")
+	assertLength(t, sel.Nodes, 2)
+}
+
+func TestAddBackFilteredRollback(t *testing.T) {
+	sel := Doc().Find(".span12, .footer")
+	sel2 := sel.Find("h1").AddBackFiltered(".footer").End().End()
+	assertEqual(t, sel, sel2)
+}

+ 206 - 0
vendor/github.com/PuerkitoBio/goquery/filter_test.go

@@ -0,0 +1,206 @@
+package goquery
+
+import (
+	"testing"
+)
+
+func TestFilter(t *testing.T) {
+	sel := Doc().Find(".span12").Filter(".alert")
+	assertLength(t, sel.Nodes, 1)
+}
+
+func TestFilterNone(t *testing.T) {
+	sel := Doc().Find(".span12").Filter(".zzalert")
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestFilterInvalid(t *testing.T) {
+	sel := Doc().Find(".span12").Filter("")
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestFilterRollback(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	sel2 := sel.Filter(".alert").End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestFilterFunction(t *testing.T) {
+	sel := Doc().Find(".pvk-content").FilterFunction(func(i int, s *Selection) bool {
+		return i > 0
+	})
+	assertLength(t, sel.Nodes, 2)
+}
+
+func TestFilterFunctionRollback(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	sel2 := sel.FilterFunction(func(i int, s *Selection) bool {
+		return i > 0
+	}).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestFilterNode(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	sel2 := sel.FilterNodes(sel.Nodes[2])
+	assertLength(t, sel2.Nodes, 1)
+}
+
+func TestFilterNodeRollback(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	sel2 := sel.FilterNodes(sel.Nodes[2]).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestFilterSelection(t *testing.T) {
+	sel := Doc().Find(".link")
+	sel2 := Doc().Find("a[ng-click]")
+	sel3 := sel.FilterSelection(sel2)
+	assertLength(t, sel3.Nodes, 1)
+}
+
+func TestFilterSelectionRollback(t *testing.T) {
+	sel := Doc().Find(".link")
+	sel2 := Doc().Find("a[ng-click]")
+	sel2 = sel.FilterSelection(sel2).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestFilterSelectionNil(t *testing.T) {
+	var sel2 *Selection
+
+	sel := Doc().Find(".link")
+	sel3 := sel.FilterSelection(sel2)
+	assertLength(t, sel3.Nodes, 0)
+}
+
+func TestNot(t *testing.T) {
+	sel := Doc().Find(".span12").Not(".alert")
+	assertLength(t, sel.Nodes, 1)
+}
+
+func TestNotInvalid(t *testing.T) {
+	sel := Doc().Find(".span12").Not("")
+	assertLength(t, sel.Nodes, 2)
+}
+
+func TestNotRollback(t *testing.T) {
+	sel := Doc().Find(".span12")
+	sel2 := sel.Not(".alert").End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestNotNone(t *testing.T) {
+	sel := Doc().Find(".span12").Not(".zzalert")
+	assertLength(t, sel.Nodes, 2)
+}
+
+func TestNotFunction(t *testing.T) {
+	sel := Doc().Find(".pvk-content").NotFunction(func(i int, s *Selection) bool {
+		return i > 0
+	})
+	assertLength(t, sel.Nodes, 1)
+}
+
+func TestNotFunctionRollback(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	sel2 := sel.NotFunction(func(i int, s *Selection) bool {
+		return i > 0
+	}).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestNotNode(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	sel2 := sel.NotNodes(sel.Nodes[2])
+	assertLength(t, sel2.Nodes, 2)
+}
+
+func TestNotNodeRollback(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	sel2 := sel.NotNodes(sel.Nodes[2]).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestNotSelection(t *testing.T) {
+	sel := Doc().Find(".link")
+	sel2 := Doc().Find("a[ng-click]")
+	sel3 := sel.NotSelection(sel2)
+	assertLength(t, sel3.Nodes, 6)
+}
+
+func TestNotSelectionRollback(t *testing.T) {
+	sel := Doc().Find(".link")
+	sel2 := Doc().Find("a[ng-click]")
+	sel2 = sel.NotSelection(sel2).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestIntersection(t *testing.T) {
+	sel := Doc().Find(".pvk-gutter")
+	sel2 := Doc().Find("div").Intersection(sel)
+	assertLength(t, sel2.Nodes, 6)
+}
+
+func TestIntersectionRollback(t *testing.T) {
+	sel := Doc().Find(".pvk-gutter")
+	sel2 := Doc().Find("div")
+	sel2 = sel.Intersection(sel2).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestHas(t *testing.T) {
+	sel := Doc().Find(".container-fluid").Has(".center-content")
+	assertLength(t, sel.Nodes, 2)
+	// Has() returns the high-level .container-fluid div, and the one that is the immediate parent of center-content
+}
+
+func TestHasInvalid(t *testing.T) {
+	sel := Doc().Find(".container-fluid").Has("")
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestHasRollback(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := sel.Has(".center-content").End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestHasNodes(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := Doc().Find(".center-content")
+	sel = sel.HasNodes(sel2.Nodes...)
+	assertLength(t, sel.Nodes, 2)
+	// Has() returns the high-level .container-fluid div, and the one that is the immediate parent of center-content
+}
+
+func TestHasNodesRollback(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := Doc().Find(".center-content")
+	sel2 = sel.HasNodes(sel2.Nodes...).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestHasSelection(t *testing.T) {
+	sel := Doc().Find("p")
+	sel2 := Doc().Find("small")
+	sel = sel.HasSelection(sel2)
+	assertLength(t, sel.Nodes, 1)
+}
+
+func TestHasSelectionRollback(t *testing.T) {
+	sel := Doc().Find("p")
+	sel2 := Doc().Find("small")
+	sel2 = sel.HasSelection(sel2).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestEnd(t *testing.T) {
+	sel := Doc().Find("p").Has("small").End()
+	assertLength(t, sel.Nodes, 4)
+}
+
+func TestEndToTop(t *testing.T) {
+	sel := Doc().Find("p").Has("small").End().End().End()
+	assertLength(t, sel.Nodes, 0)
+}

+ 88 - 0
vendor/github.com/PuerkitoBio/goquery/iteration_test.go

@@ -0,0 +1,88 @@
+package goquery
+
+import (
+	"testing"
+
+	"golang.org/x/net/html"
+)
+
+func TestEach(t *testing.T) {
+	var cnt int
+
+	sel := Doc().Find(".hero-unit .row-fluid").Each(func(i int, n *Selection) {
+		cnt++
+		t.Logf("At index %v, node %v", i, n.Nodes[0].Data)
+	}).Find("a")
+
+	if cnt != 4 {
+		t.Errorf("Expected Each() to call function 4 times, got %v times.", cnt)
+	}
+	assertLength(t, sel.Nodes, 6)
+}
+
+func TestEachWithBreak(t *testing.T) {
+	var cnt int
+
+	sel := Doc().Find(".hero-unit .row-fluid").EachWithBreak(func(i int, n *Selection) bool {
+		cnt++
+		t.Logf("At index %v, node %v", i, n.Nodes[0].Data)
+		return false
+	}).Find("a")
+
+	if cnt != 1 {
+		t.Errorf("Expected Each() to call function 1 time, got %v times.", cnt)
+	}
+	assertLength(t, sel.Nodes, 6)
+}
+
+func TestEachEmptySelection(t *testing.T) {
+	var cnt int
+
+	sel := Doc().Find("zzzz")
+	sel.Each(func(i int, n *Selection) {
+		cnt++
+	})
+	if cnt > 0 {
+		t.Error("Expected Each() to not be called on empty Selection.")
+	}
+	sel2 := sel.Find("div")
+	assertLength(t, sel2.Nodes, 0)
+}
+
+func TestMap(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	vals := sel.Map(func(i int, s *Selection) string {
+		n := s.Get(0)
+		if n.Type == html.ElementNode {
+			return n.Data
+		}
+		return ""
+	})
+	for _, v := range vals {
+		if v != "div" {
+			t.Error("Expected Map array result to be all 'div's.")
+		}
+	}
+	if len(vals) != 3 {
+		t.Errorf("Expected Map array result to have a length of 3, found %v.", len(vals))
+	}
+}
+
+func TestForRange(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	initLen := sel.Length()
+	for i := range sel.Nodes {
+		single := sel.Eq(i)
+		//h, err := single.Html()
+		//if err != nil {
+		//	t.Fatal(err)
+		//}
+		//fmt.Println(i, h)
+		if single.Length() != 1 {
+			t.Errorf("%d: expected length of 1, got %d", i, single.Length())
+		}
+	}
+	if sel.Length() != initLen {
+		t.Errorf("expected initial selection to still have length %d, got %d", initLen, sel.Length())
+	}
+}

+ 513 - 0
vendor/github.com/PuerkitoBio/goquery/manipulation_test.go

@@ -0,0 +1,513 @@
+package goquery
+
+import (
+	"testing"
+)
+
+const (
+	wrapHtml = "<div id=\"ins\">test string<div><p><em><b></b></em></p></div></div>"
+)
+
+func TestAfter(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("#main").After("#nf6")
+
+	assertLength(t, doc.Find("#main #nf6").Nodes, 0)
+	assertLength(t, doc.Find("#foot #nf6").Nodes, 0)
+	assertLength(t, doc.Find("#main + #nf6").Nodes, 1)
+	printSel(t, doc.Selection)
+}
+
+func TestAfterMany(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find(".one").After("#nf6")
+
+	assertLength(t, doc.Find("#foot #nf6").Nodes, 1)
+	assertLength(t, doc.Find("#main #nf6").Nodes, 1)
+	assertLength(t, doc.Find(".one + #nf6").Nodes, 2)
+	printSel(t, doc.Selection)
+}
+
+func TestAfterWithRemoved(t *testing.T) {
+	doc := Doc2Clone()
+	s := doc.Find("#main").Remove()
+	s.After("#nf6")
+
+	assertLength(t, s.Find("#nf6").Nodes, 0)
+	assertLength(t, doc.Find("#nf6").Nodes, 0)
+	printSel(t, doc.Selection)
+}
+
+func TestAfterSelection(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("#main").AfterSelection(doc.Find("#nf1, #nf2"))
+
+	assertLength(t, doc.Find("#main #nf1, #main #nf2").Nodes, 0)
+	assertLength(t, doc.Find("#foot #nf1, #foot #nf2").Nodes, 0)
+	assertLength(t, doc.Find("#main + #nf1, #nf1 + #nf2").Nodes, 2)
+	printSel(t, doc.Selection)
+}
+
+func TestAfterHtml(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("#main").AfterHtml("<strong>new node</strong>")
+
+	assertLength(t, doc.Find("#main + strong").Nodes, 1)
+	printSel(t, doc.Selection)
+}
+
+func TestAppend(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("#main").Append("#nf6")
+
+	assertLength(t, doc.Find("#foot #nf6").Nodes, 0)
+	assertLength(t, doc.Find("#main #nf6").Nodes, 1)
+	printSel(t, doc.Selection)
+}
+
+func TestAppendBody(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("body").Append("#nf6")
+
+	assertLength(t, doc.Find("#foot #nf6").Nodes, 0)
+	assertLength(t, doc.Find("#main #nf6").Nodes, 0)
+	assertLength(t, doc.Find("body > #nf6").Nodes, 1)
+	printSel(t, doc.Selection)
+}
+
+func TestAppendSelection(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("#main").AppendSelection(doc.Find("#nf1, #nf2"))
+
+	assertLength(t, doc.Find("#foot #nf1").Nodes, 0)
+	assertLength(t, doc.Find("#foot #nf2").Nodes, 0)
+	assertLength(t, doc.Find("#main #nf1").Nodes, 1)
+	assertLength(t, doc.Find("#main #nf2").Nodes, 1)
+	printSel(t, doc.Selection)
+}
+
+func TestAppendSelectionExisting(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("#main").AppendSelection(doc.Find("#n1, #n2"))
+
+	assertClass(t, doc.Find("#main :nth-child(1)"), "three")
+	assertClass(t, doc.Find("#main :nth-child(5)"), "one")
+	assertClass(t, doc.Find("#main :nth-child(6)"), "two")
+	printSel(t, doc.Selection)
+}
+
+func TestAppendClone(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("#n1").AppendSelection(doc.Find("#nf1").Clone())
+
+	assertLength(t, doc.Find("#foot #nf1").Nodes, 1)
+	assertLength(t, doc.Find("#main #nf1").Nodes, 1)
+	printSel(t, doc.Selection)
+}
+
+func TestAppendHtml(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("div").AppendHtml("<strong>new node</strong>")
+
+	assertLength(t, doc.Find("strong").Nodes, 14)
+	printSel(t, doc.Selection)
+}
+
+func TestBefore(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("#main").Before("#nf6")
+
+	assertLength(t, doc.Find("#main #nf6").Nodes, 0)
+	assertLength(t, doc.Find("#foot #nf6").Nodes, 0)
+	assertLength(t, doc.Find("body > #nf6:first-child").Nodes, 1)
+	printSel(t, doc.Selection)
+}
+
+func TestBeforeWithRemoved(t *testing.T) {
+	doc := Doc2Clone()
+	s := doc.Find("#main").Remove()
+	s.Before("#nf6")
+
+	assertLength(t, s.Find("#nf6").Nodes, 0)
+	assertLength(t, doc.Find("#nf6").Nodes, 0)
+	printSel(t, doc.Selection)
+}
+
+func TestBeforeSelection(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("#main").BeforeSelection(doc.Find("#nf1, #nf2"))
+
+	assertLength(t, doc.Find("#main #nf1, #main #nf2").Nodes, 0)
+	assertLength(t, doc.Find("#foot #nf1, #foot #nf2").Nodes, 0)
+	assertLength(t, doc.Find("body > #nf1:first-child, #nf1 + #nf2").Nodes, 2)
+	printSel(t, doc.Selection)
+}
+
+func TestBeforeHtml(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("#main").BeforeHtml("<strong>new node</strong>")
+
+	assertLength(t, doc.Find("body > strong:first-child").Nodes, 1)
+	printSel(t, doc.Selection)
+}
+
+func TestEmpty(t *testing.T) {
+	doc := Doc2Clone()
+	s := doc.Find("#main").Empty()
+
+	assertLength(t, doc.Find("#main").Children().Nodes, 0)
+	assertLength(t, s.Filter("div").Nodes, 6)
+	printSel(t, doc.Selection)
+}
+
+func TestPrepend(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("#main").Prepend("#nf6")
+
+	assertLength(t, doc.Find("#foot #nf6").Nodes, 0)
+	assertLength(t, doc.Find("#main #nf6:first-child").Nodes, 1)
+	printSel(t, doc.Selection)
+}
+
+func TestPrependBody(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("body").Prepend("#nf6")
+
+	assertLength(t, doc.Find("#foot #nf6").Nodes, 0)
+	assertLength(t, doc.Find("#main #nf6").Nodes, 0)
+	assertLength(t, doc.Find("body > #nf6:first-child").Nodes, 1)
+	printSel(t, doc.Selection)
+}
+
+func TestPrependSelection(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("#main").PrependSelection(doc.Find("#nf1, #nf2"))
+
+	assertLength(t, doc.Find("#foot #nf1").Nodes, 0)
+	assertLength(t, doc.Find("#foot #nf2").Nodes, 0)
+	assertLength(t, doc.Find("#main #nf1:first-child").Nodes, 1)
+	assertLength(t, doc.Find("#main #nf2:nth-child(2)").Nodes, 1)
+	printSel(t, doc.Selection)
+}
+
+func TestPrependSelectionExisting(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("#main").PrependSelection(doc.Find("#n5, #n6"))
+
+	assertClass(t, doc.Find("#main :nth-child(1)"), "five")
+	assertClass(t, doc.Find("#main :nth-child(2)"), "six")
+	assertClass(t, doc.Find("#main :nth-child(5)"), "three")
+	assertClass(t, doc.Find("#main :nth-child(6)"), "four")
+	printSel(t, doc.Selection)
+}
+
+func TestPrependClone(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("#n1").PrependSelection(doc.Find("#nf1").Clone())
+
+	assertLength(t, doc.Find("#foot #nf1:first-child").Nodes, 1)
+	assertLength(t, doc.Find("#main #nf1:first-child").Nodes, 1)
+	printSel(t, doc.Selection)
+}
+
+func TestPrependHtml(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("div").PrependHtml("<strong>new node</strong>")
+
+	assertLength(t, doc.Find("strong:first-child").Nodes, 14)
+	printSel(t, doc.Selection)
+}
+
+func TestRemove(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("#nf1").Remove()
+
+	assertLength(t, doc.Find("#foot #nf1").Nodes, 0)
+	printSel(t, doc.Selection)
+}
+
+func TestRemoveAll(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("*").Remove()
+
+	assertLength(t, doc.Find("*").Nodes, 0)
+	printSel(t, doc.Selection)
+}
+
+func TestRemoveRoot(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("html").Remove()
+
+	assertLength(t, doc.Find("html").Nodes, 0)
+	printSel(t, doc.Selection)
+}
+
+func TestRemoveFiltered(t *testing.T) {
+	doc := Doc2Clone()
+	nf6 := doc.Find("#nf6")
+	s := doc.Find("div").RemoveFiltered("#nf6")
+
+	assertLength(t, doc.Find("#nf6").Nodes, 0)
+	assertLength(t, s.Nodes, 1)
+	if nf6.Nodes[0] != s.Nodes[0] {
+		t.Error("Removed node does not match original")
+	}
+	printSel(t, doc.Selection)
+}
+
+func TestReplaceWith(t *testing.T) {
+	doc := Doc2Clone()
+
+	doc.Find("#nf6").ReplaceWith("#main")
+	assertLength(t, doc.Find("#foot #main:last-child").Nodes, 1)
+	printSel(t, doc.Selection)
+
+	doc.Find("#foot").ReplaceWith("#main")
+	assertLength(t, doc.Find("#foot").Nodes, 0)
+	assertLength(t, doc.Find("#main").Nodes, 1)
+
+	printSel(t, doc.Selection)
+}
+
+func TestReplaceWithHtml(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("#main, #foot").ReplaceWithHtml("<div id=\"replace\"></div>")
+
+	assertLength(t, doc.Find("#replace").Nodes, 2)
+
+	printSel(t, doc.Selection)
+}
+
+func TestSetHtml(t *testing.T) {
+	doc := Doc2Clone()
+	q := doc.Find("#main, #foot")
+	q.SetHtml(`<div id="replace">test</div>`)
+
+	assertLength(t, doc.Find("#replace").Nodes, 2)
+	assertLength(t, doc.Find("#main, #foot").Nodes, 2)
+
+	if q.Text() != "testtest" {
+		t.Errorf("Expected text to be %v, found %v", "testtest", q.Text())
+	}
+
+	printSel(t, doc.Selection)
+}
+
+func TestSetHtmlNoMatch(t *testing.T) {
+	doc := Doc2Clone()
+	q := doc.Find("#notthere")
+	q.SetHtml(`<div id="replace">test</div>`)
+
+	assertLength(t, doc.Find("#replace").Nodes, 0)
+
+	printSel(t, doc.Selection)
+}
+
+func TestSetHtmlEmpty(t *testing.T) {
+	doc := Doc2Clone()
+	q := doc.Find("#main")
+	q.SetHtml(``)
+
+	assertLength(t, doc.Find("#main").Nodes, 1)
+	assertLength(t, doc.Find("#main").Children().Nodes, 0)
+	printSel(t, doc.Selection)
+}
+
+func TestSetText(t *testing.T) {
+	doc := Doc2Clone()
+	q := doc.Find("#main, #foot")
+	repl := "<div id=\"replace\">test</div>"
+	q.SetText(repl)
+
+	assertLength(t, doc.Find("#replace").Nodes, 0)
+	assertLength(t, doc.Find("#main, #foot").Nodes, 2)
+
+	if q.Text() != (repl + repl) {
+		t.Errorf("Expected text to be %v, found %v", (repl + repl), q.Text())
+	}
+
+	h, err := q.Html()
+	if err != nil {
+		t.Errorf("Error: %v", err)
+	}
+	esc := "&lt;div id=&#34;replace&#34;&gt;test&lt;/div&gt;"
+	if h != esc {
+		t.Errorf("Expected html to be %v, found %v", esc, h)
+	}
+
+	printSel(t, doc.Selection)
+}
+
+func TestReplaceWithSelection(t *testing.T) {
+	doc := Doc2Clone()
+	sel := doc.Find("#nf6").ReplaceWithSelection(doc.Find("#nf5"))
+
+	assertSelectionIs(t, sel, "#nf6")
+	assertLength(t, doc.Find("#nf6").Nodes, 0)
+	assertLength(t, doc.Find("#nf5").Nodes, 1)
+
+	printSel(t, doc.Selection)
+}
+
+func TestUnwrap(t *testing.T) {
+	doc := Doc2Clone()
+
+	doc.Find("#nf5").Unwrap()
+	assertLength(t, doc.Find("#foot").Nodes, 0)
+	assertLength(t, doc.Find("body > #nf1").Nodes, 1)
+	assertLength(t, doc.Find("body > #nf5").Nodes, 1)
+
+	printSel(t, doc.Selection)
+
+	doc = Doc2Clone()
+
+	doc.Find("#nf5, #n1").Unwrap()
+	assertLength(t, doc.Find("#foot").Nodes, 0)
+	assertLength(t, doc.Find("#main").Nodes, 0)
+	assertLength(t, doc.Find("body > #n1").Nodes, 1)
+	assertLength(t, doc.Find("body > #nf5").Nodes, 1)
+
+	printSel(t, doc.Selection)
+}
+
+func TestUnwrapBody(t *testing.T) {
+	doc := Doc2Clone()
+
+	doc.Find("#main").Unwrap()
+	assertLength(t, doc.Find("body").Nodes, 1)
+	assertLength(t, doc.Find("body > #main").Nodes, 1)
+
+	printSel(t, doc.Selection)
+}
+
+func TestUnwrapHead(t *testing.T) {
+	doc := Doc2Clone()
+
+	doc.Find("title").Unwrap()
+	assertLength(t, doc.Find("head").Nodes, 0)
+	assertLength(t, doc.Find("head > title").Nodes, 0)
+	assertLength(t, doc.Find("title").Nodes, 1)
+
+	printSel(t, doc.Selection)
+}
+
+func TestUnwrapHtml(t *testing.T) {
+	doc := Doc2Clone()
+
+	doc.Find("head").Unwrap()
+	assertLength(t, doc.Find("html").Nodes, 0)
+	assertLength(t, doc.Find("html head").Nodes, 0)
+	assertLength(t, doc.Find("head").Nodes, 1)
+
+	printSel(t, doc.Selection)
+}
+
+func TestWrap(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("#nf1").Wrap("#nf2")
+	nf1 := doc.Find("#foot #nf2 #nf1")
+	assertLength(t, nf1.Nodes, 1)
+
+	nf2 := doc.Find("#nf2")
+	assertLength(t, nf2.Nodes, 2)
+
+	printSel(t, doc.Selection)
+}
+
+func TestWrapEmpty(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("#nf1").Wrap("#doesnt-exist")
+
+	origHtml, _ := Doc2().Html()
+	newHtml, _ := doc.Html()
+
+	if origHtml != newHtml {
+		t.Error("Expected the two documents to be identical.")
+	}
+
+	printSel(t, doc.Selection)
+}
+
+func TestWrapHtml(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find(".odd").WrapHtml(wrapHtml)
+	nf2 := doc.Find("#ins #nf2")
+	assertLength(t, nf2.Nodes, 1)
+	printSel(t, doc.Selection)
+}
+
+func TestWrapSelection(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("#nf1").WrapSelection(doc.Find("#nf2"))
+	nf1 := doc.Find("#foot #nf2 #nf1")
+	assertLength(t, nf1.Nodes, 1)
+
+	nf2 := doc.Find("#nf2")
+	assertLength(t, nf2.Nodes, 2)
+
+	printSel(t, doc.Selection)
+}
+
+func TestWrapAll(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find(".odd").WrapAll("#nf1")
+	nf1 := doc.Find("#main #nf1")
+	assertLength(t, nf1.Nodes, 1)
+
+	sel := nf1.Find("#n2 ~ #n4 ~ #n6 ~ #nf2 ~ #nf4 ~ #nf6")
+	assertLength(t, sel.Nodes, 1)
+
+	printSel(t, doc.Selection)
+}
+
+func TestWrapAllHtml(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find(".odd").WrapAllHtml(wrapHtml)
+	nf1 := doc.Find("#main div#ins div p em b #n2 ~ #n4 ~ #n6 ~ #nf2 ~ #nf4 ~ #nf6")
+	assertLength(t, nf1.Nodes, 1)
+	printSel(t, doc.Selection)
+}
+
+func TestWrapInnerNoContent(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find(".one").WrapInner(".two")
+
+	twos := doc.Find(".two")
+	assertLength(t, twos.Nodes, 4)
+	assertLength(t, doc.Find(".one .two").Nodes, 2)
+
+	printSel(t, doc.Selection)
+}
+
+func TestWrapInnerWithContent(t *testing.T) {
+	doc := Doc3Clone()
+	doc.Find(".one").WrapInner(".two")
+
+	twos := doc.Find(".two")
+	assertLength(t, twos.Nodes, 4)
+	assertLength(t, doc.Find(".one .two").Nodes, 2)
+
+	printSel(t, doc.Selection)
+}
+
+func TestWrapInnerNoWrapper(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find(".one").WrapInner(".not-exist")
+
+	twos := doc.Find(".two")
+	assertLength(t, twos.Nodes, 2)
+	assertLength(t, doc.Find(".one").Nodes, 2)
+	assertLength(t, doc.Find(".one .two").Nodes, 0)
+
+	printSel(t, doc.Selection)
+}
+
+func TestWrapInnerHtml(t *testing.T) {
+	doc := Doc2Clone()
+	doc.Find("#foot").WrapInnerHtml(wrapHtml)
+
+	foot := doc.Find("#foot div#ins div p em b #nf1 ~ #nf2 ~ #nf3")
+	assertLength(t, foot.Nodes, 1)
+
+	printSel(t, doc.Selection)
+}

+ 252 - 0
vendor/github.com/PuerkitoBio/goquery/property_test.go

@@ -0,0 +1,252 @@
+package goquery
+
+import (
+	"regexp"
+	"strings"
+	"testing"
+)
+
+func TestAttrExists(t *testing.T) {
+	if val, ok := Doc().Find("a").Attr("href"); !ok {
+		t.Error("Expected a value for the href attribute.")
+	} else {
+		t.Logf("Href of first anchor: %v.", val)
+	}
+}
+
+func TestAttrOr(t *testing.T) {
+	if val := Doc().Find("a").AttrOr("fake-attribute", "alternative"); val != "alternative" {
+		t.Error("Expected an alternative value for 'fake-attribute' attribute.")
+	} else {
+		t.Logf("Value returned for not existing attribute: %v.", val)
+	}
+	if val := Doc().Find("zz").AttrOr("fake-attribute", "alternative"); val != "alternative" {
+		t.Error("Expected an alternative value for 'fake-attribute' on an empty selection.")
+	} else {
+		t.Logf("Value returned for empty selection: %v.", val)
+	}
+}
+
+func TestAttrNotExist(t *testing.T) {
+	if val, ok := Doc().Find("div.row-fluid").Attr("href"); ok {
+		t.Errorf("Expected no value for the href attribute, got %v.", val)
+	}
+}
+
+func TestRemoveAttr(t *testing.T) {
+	sel := Doc2Clone().Find("div")
+
+	sel.RemoveAttr("id")
+
+	_, ok := sel.Attr("id")
+	if ok {
+		t.Error("Expected there to be no id attributes set")
+	}
+}
+
+func TestSetAttr(t *testing.T) {
+	sel := Doc2Clone().Find("#main")
+
+	sel.SetAttr("id", "not-main")
+
+	val, ok := sel.Attr("id")
+	if !ok {
+		t.Error("Expected an id attribute on main")
+	}
+
+	if val != "not-main" {
+		t.Errorf("Expected an attribute id to be not-main, got %s", val)
+	}
+}
+
+func TestSetAttr2(t *testing.T) {
+	sel := Doc2Clone().Find("#main")
+
+	sel.SetAttr("foo", "bar")
+
+	val, ok := sel.Attr("foo")
+	if !ok {
+		t.Error("Expected an 'foo' attribute on main")
+	}
+
+	if val != "bar" {
+		t.Errorf("Expected an attribute 'foo' to be 'bar', got '%s'", val)
+	}
+}
+
+func TestText(t *testing.T) {
+	txt := Doc().Find("h1").Text()
+	if strings.Trim(txt, " \n\r\t") != "Provok.in" {
+		t.Errorf("Expected text to be Provok.in, found %s.", txt)
+	}
+}
+
+func TestText2(t *testing.T) {
+	txt := Doc().Find(".hero-unit .container-fluid .row-fluid:nth-child(1)").Text()
+	if ok, e := regexp.MatchString(`^\s+Provok\.in\s+Prove your point.\s+$`, txt); !ok || e != nil {
+		t.Errorf("Expected text to be Provok.in Prove your point., found %s.", txt)
+		if e != nil {
+			t.Logf("Error: %s.", e.Error())
+		}
+	}
+}
+
+func TestText3(t *testing.T) {
+	txt := Doc().Find(".pvk-gutter").First().Text()
+	// There's an &nbsp; character in there...
+	if ok, e := regexp.MatchString(`^[\s\x{00A0}]+$`, txt); !ok || e != nil {
+		t.Errorf("Expected spaces, found <%v>.", txt)
+		if e != nil {
+			t.Logf("Error: %s.", e.Error())
+		}
+	}
+}
+
+func TestHtml(t *testing.T) {
+	txt, e := Doc().Find("h1").Html()
+	if e != nil {
+		t.Errorf("Error: %s.", e)
+	}
+
+	if ok, e := regexp.MatchString(`^\s*<a href="/">Provok<span class="green">\.</span><span class="red">i</span>n</a>\s*$`, txt); !ok || e != nil {
+		t.Errorf("Unexpected HTML content, found %s.", txt)
+		if e != nil {
+			t.Logf("Error: %s.", e.Error())
+		}
+	}
+}
+
+func TestNbsp(t *testing.T) {
+	src := `<p>Some&nbsp;text</p>`
+	d, err := NewDocumentFromReader(strings.NewReader(src))
+	if err != nil {
+		t.Fatal(err)
+	}
+	txt := d.Find("p").Text()
+	ix := strings.Index(txt, "\u00a0")
+	if ix != 4 {
+		t.Errorf("Text: expected a non-breaking space at index 4, got %d", ix)
+	}
+
+	h, err := d.Find("p").Html()
+	if err != nil {
+		t.Fatal(err)
+	}
+	ix = strings.Index(h, "\u00a0")
+	if ix != 4 {
+		t.Errorf("Html: expected a non-breaking space at index 4, got %d", ix)
+	}
+}
+
+func TestAddClass(t *testing.T) {
+	sel := Doc2Clone().Find("#main")
+	sel.AddClass("main main main")
+
+	// Make sure that class was only added once
+	if a, ok := sel.Attr("class"); !ok || a != "main" {
+		t.Error("Expected #main to have class main")
+	}
+}
+
+func TestAddClassSimilar(t *testing.T) {
+	sel := Doc2Clone().Find("#nf5")
+	sel.AddClass("odd")
+
+	assertClass(t, sel, "odd")
+	assertClass(t, sel, "odder")
+	printSel(t, sel.Parent())
+}
+
+func TestAddEmptyClass(t *testing.T) {
+	sel := Doc2Clone().Find("#main")
+	sel.AddClass("")
+
+	// Make sure that class was only added once
+	if a, ok := sel.Attr("class"); ok {
+		t.Errorf("Expected #main to not to have a class, have: %s", a)
+	}
+}
+
+func TestAddClasses(t *testing.T) {
+	sel := Doc2Clone().Find("#main")
+	sel.AddClass("a b")
+
+	// Make sure that class was only added once
+	if !sel.HasClass("a") || !sel.HasClass("b") {
+		t.Errorf("#main does not have classes")
+	}
+}
+
+func TestHasClass(t *testing.T) {
+	sel := Doc().Find("div")
+	if !sel.HasClass("span12") {
+		t.Error("Expected at least one div to have class span12.")
+	}
+}
+
+func TestHasClassNone(t *testing.T) {
+	sel := Doc().Find("h2")
+	if sel.HasClass("toto") {
+		t.Error("Expected h1 to have no class.")
+	}
+}
+
+func TestHasClassNotFirst(t *testing.T) {
+	sel := Doc().Find(".alert")
+	if !sel.HasClass("alert-error") {
+		t.Error("Expected .alert to also have class .alert-error.")
+	}
+}
+
+func TestRemoveClass(t *testing.T) {
+	sel := Doc2Clone().Find("#nf1")
+	sel.RemoveClass("one row")
+
+	if !sel.HasClass("even") || sel.HasClass("one") || sel.HasClass("row") {
+		classes, _ := sel.Attr("class")
+		t.Error("Expected #nf1 to have class even, has ", classes)
+	}
+}
+
+func TestRemoveClassSimilar(t *testing.T) {
+	sel := Doc2Clone().Find("#nf5, #nf6")
+	assertLength(t, sel.Nodes, 2)
+
+	sel.RemoveClass("odd")
+	assertClass(t, sel.Eq(0), "odder")
+	printSel(t, sel)
+}
+
+func TestRemoveAllClasses(t *testing.T) {
+	sel := Doc2Clone().Find("#nf1")
+	sel.RemoveClass()
+
+	if a, ok := sel.Attr("class"); ok {
+		t.Error("All classes were not removed, has ", a)
+	}
+
+	sel = Doc2Clone().Find("#main")
+	sel.RemoveClass()
+	if a, ok := sel.Attr("class"); ok {
+		t.Error("All classes were not removed, has ", a)
+	}
+}
+
+func TestToggleClass(t *testing.T) {
+	sel := Doc2Clone().Find("#nf1")
+
+	sel.ToggleClass("one")
+	if sel.HasClass("one") {
+		t.Error("Expected #nf1 to not have class one")
+	}
+
+	sel.ToggleClass("one")
+	if !sel.HasClass("one") {
+		t.Error("Expected #nf1 to have class one")
+	}
+
+	sel.ToggleClass("one even row")
+	if a, ok := sel.Attr("class"); ok {
+		t.Errorf("Expected #nf1 to have no classes, have %q", a)
+	}
+}

+ 103 - 0
vendor/github.com/PuerkitoBio/goquery/query_test.go

@@ -0,0 +1,103 @@
+package goquery
+
+import (
+	"testing"
+)
+
+func TestIs(t *testing.T) {
+	sel := Doc().Find(".footer p:nth-child(1)")
+	if !sel.Is("p") {
+		t.Error("Expected .footer p:nth-child(1) to be p.")
+	}
+}
+
+func TestIsInvalid(t *testing.T) {
+	sel := Doc().Find(".footer p:nth-child(1)")
+	if sel.Is("") {
+		t.Error("Is should not succeed with invalid selector string")
+	}
+}
+
+func TestIsPositional(t *testing.T) {
+	sel := Doc().Find(".footer p:nth-child(2)")
+	if !sel.Is("p:nth-child(2)") {
+		t.Error("Expected .footer p:nth-child(2) to be p:nth-child(2).")
+	}
+}
+
+func TestIsPositionalNot(t *testing.T) {
+	sel := Doc().Find(".footer p:nth-child(1)")
+	if sel.Is("p:nth-child(2)") {
+		t.Error("Expected .footer p:nth-child(1) NOT to be p:nth-child(2).")
+	}
+}
+
+func TestIsFunction(t *testing.T) {
+	ok := Doc().Find("div").IsFunction(func(i int, s *Selection) bool {
+		return s.HasClass("container-fluid")
+	})
+
+	if !ok {
+		t.Error("Expected some div to have a container-fluid class.")
+	}
+}
+
+func TestIsFunctionRollback(t *testing.T) {
+	ok := Doc().Find("div").IsFunction(func(i int, s *Selection) bool {
+		return s.HasClass("container-fluid")
+	})
+
+	if !ok {
+		t.Error("Expected some div to have a container-fluid class.")
+	}
+}
+
+func TestIsSelection(t *testing.T) {
+	sel := Doc().Find("div")
+	sel2 := Doc().Find(".pvk-gutter")
+
+	if !sel.IsSelection(sel2) {
+		t.Error("Expected some div to have a pvk-gutter class.")
+	}
+}
+
+func TestIsSelectionNot(t *testing.T) {
+	sel := Doc().Find("div")
+	sel2 := Doc().Find("a")
+
+	if sel.IsSelection(sel2) {
+		t.Error("Expected some div NOT to be an anchor.")
+	}
+}
+
+func TestIsNodes(t *testing.T) {
+	sel := Doc().Find("div")
+	sel2 := Doc().Find(".footer")
+
+	if !sel.IsNodes(sel2.Nodes[0]) {
+		t.Error("Expected some div to have a footer class.")
+	}
+}
+
+func TestDocContains(t *testing.T) {
+	sel := Doc().Find("h1")
+	if !Doc().Contains(sel.Nodes[0]) {
+		t.Error("Expected document to contain H1 tag.")
+	}
+}
+
+func TestSelContains(t *testing.T) {
+	sel := Doc().Find(".row-fluid")
+	sel2 := Doc().Find("a[ng-click]")
+	if !sel.Contains(sel2.Nodes[0]) {
+		t.Error("Expected .row-fluid to contain a[ng-click] tag.")
+	}
+}
+
+func TestSelNotContains(t *testing.T) {
+	sel := Doc().Find("a.link")
+	sel2 := Doc().Find("span")
+	if sel.Contains(sel2.Nodes[0]) {
+		t.Error("Expected a.link to NOT contain span tag.")
+	}
+}

+ 793 - 0
vendor/github.com/PuerkitoBio/goquery/traversal_test.go

@@ -0,0 +1,793 @@
+package goquery
+
+import (
+	"strings"
+	"testing"
+)
+
+func TestFind(t *testing.T) {
+	sel := Doc().Find("div.row-fluid")
+	assertLength(t, sel.Nodes, 9)
+}
+
+func TestFindRollback(t *testing.T) {
+	sel := Doc().Find("div.row-fluid")
+	sel2 := sel.Find("a").End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestFindNotSelf(t *testing.T) {
+	sel := Doc().Find("h1").Find("h1")
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestFindInvalid(t *testing.T) {
+	sel := Doc().Find(":+ ^")
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestFindBig(t *testing.T) {
+	doc := DocW()
+	sel := doc.Find("li")
+	assertLength(t, sel.Nodes, 373)
+	sel2 := doc.Find("span")
+	assertLength(t, sel2.Nodes, 448)
+	sel3 := sel.FindSelection(sel2)
+	assertLength(t, sel3.Nodes, 248)
+}
+
+func TestChainedFind(t *testing.T) {
+	sel := Doc().Find("div.hero-unit").Find(".row-fluid")
+	assertLength(t, sel.Nodes, 4)
+}
+
+func TestChainedFindInvalid(t *testing.T) {
+	sel := Doc().Find("div.hero-unit").Find("")
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestChildren(t *testing.T) {
+	sel := Doc().Find(".pvk-content").Children()
+	assertLength(t, sel.Nodes, 5)
+}
+
+func TestChildrenRollback(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	sel2 := sel.Children().End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestContents(t *testing.T) {
+	sel := Doc().Find(".pvk-content").Contents()
+	assertLength(t, sel.Nodes, 13)
+}
+
+func TestContentsRollback(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	sel2 := sel.Contents().End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestChildrenFiltered(t *testing.T) {
+	sel := Doc().Find(".pvk-content").ChildrenFiltered(".hero-unit")
+	assertLength(t, sel.Nodes, 1)
+}
+
+func TestChildrenFilteredInvalid(t *testing.T) {
+	sel := Doc().Find(".pvk-content").ChildrenFiltered("")
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestChildrenFilteredRollback(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	sel2 := sel.ChildrenFiltered(".hero-unit").End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestContentsFiltered(t *testing.T) {
+	sel := Doc().Find(".pvk-content").ContentsFiltered(".hero-unit")
+	assertLength(t, sel.Nodes, 1)
+}
+
+func TestContentsFilteredInvalid(t *testing.T) {
+	sel := Doc().Find(".pvk-content").ContentsFiltered("~")
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestContentsFilteredRollback(t *testing.T) {
+	sel := Doc().Find(".pvk-content")
+	sel2 := sel.ContentsFiltered(".hero-unit").End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestChildrenFilteredNone(t *testing.T) {
+	sel := Doc().Find(".pvk-content").ChildrenFiltered("a.btn")
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestParent(t *testing.T) {
+	sel := Doc().Find(".container-fluid").Parent()
+	assertLength(t, sel.Nodes, 3)
+}
+
+func TestParentRollback(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := sel.Parent().End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestParentBody(t *testing.T) {
+	sel := Doc().Find("body").Parent()
+	assertLength(t, sel.Nodes, 1)
+}
+
+func TestParentFiltered(t *testing.T) {
+	sel := Doc().Find(".container-fluid").ParentFiltered(".hero-unit")
+	assertLength(t, sel.Nodes, 1)
+	assertClass(t, sel, "hero-unit")
+}
+
+func TestParentFilteredInvalid(t *testing.T) {
+	sel := Doc().Find(".container-fluid").ParentFiltered("")
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestParentFilteredRollback(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := sel.ParentFiltered(".hero-unit").End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestParents(t *testing.T) {
+	sel := Doc().Find(".container-fluid").Parents()
+	assertLength(t, sel.Nodes, 8)
+}
+
+func TestParentsOrder(t *testing.T) {
+	sel := Doc().Find("#cf2").Parents()
+	assertLength(t, sel.Nodes, 6)
+	assertSelectionIs(t, sel, ".hero-unit", ".pvk-content", "div.row-fluid", "#cf1", "body", "html")
+}
+
+func TestParentsRollback(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := sel.Parents().End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestParentsFiltered(t *testing.T) {
+	sel := Doc().Find(".container-fluid").ParentsFiltered("body")
+	assertLength(t, sel.Nodes, 1)
+}
+
+func TestParentsFilteredInvalid(t *testing.T) {
+	sel := Doc().Find(".container-fluid").ParentsFiltered("")
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestParentsFilteredRollback(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := sel.ParentsFiltered("body").End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestParentsUntil(t *testing.T) {
+	sel := Doc().Find(".container-fluid").ParentsUntil("body")
+	assertLength(t, sel.Nodes, 6)
+}
+
+func TestParentsUntilInvalid(t *testing.T) {
+	sel := Doc().Find(".container-fluid").ParentsUntil("")
+	assertLength(t, sel.Nodes, 8)
+}
+
+func TestParentsUntilRollback(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := sel.ParentsUntil("body").End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestParentsUntilSelection(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := Doc().Find(".pvk-content")
+	sel = sel.ParentsUntilSelection(sel2)
+	assertLength(t, sel.Nodes, 3)
+}
+
+func TestParentsUntilSelectionRollback(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := Doc().Find(".pvk-content")
+	sel2 = sel.ParentsUntilSelection(sel2).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestParentsUntilNodes(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := Doc().Find(".pvk-content, .hero-unit")
+	sel = sel.ParentsUntilNodes(sel2.Nodes...)
+	assertLength(t, sel.Nodes, 2)
+}
+
+func TestParentsUntilNodesRollback(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := Doc().Find(".pvk-content, .hero-unit")
+	sel2 = sel.ParentsUntilNodes(sel2.Nodes...).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestParentsFilteredUntil(t *testing.T) {
+	sel := Doc().Find(".container-fluid").ParentsFilteredUntil(".pvk-content", "body")
+	assertLength(t, sel.Nodes, 2)
+}
+
+func TestParentsFilteredUntilInvalid(t *testing.T) {
+	sel := Doc().Find(".container-fluid").ParentsFilteredUntil("", "")
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestParentsFilteredUntilRollback(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := sel.ParentsFilteredUntil(".pvk-content", "body").End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestParentsFilteredUntilSelection(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := Doc().Find(".row-fluid")
+	sel = sel.ParentsFilteredUntilSelection("div", sel2)
+	assertLength(t, sel.Nodes, 3)
+}
+
+func TestParentsFilteredUntilSelectionRollback(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := Doc().Find(".row-fluid")
+	sel2 = sel.ParentsFilteredUntilSelection("div", sel2).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestParentsFilteredUntilNodes(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := Doc().Find(".row-fluid")
+	sel = sel.ParentsFilteredUntilNodes("body", sel2.Nodes...)
+	assertLength(t, sel.Nodes, 1)
+}
+
+func TestParentsFilteredUntilNodesRollback(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := Doc().Find(".row-fluid")
+	sel2 = sel.ParentsFilteredUntilNodes("body", sel2.Nodes...).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestSiblings(t *testing.T) {
+	sel := Doc().Find("h1").Siblings()
+	assertLength(t, sel.Nodes, 1)
+}
+
+func TestSiblingsRollback(t *testing.T) {
+	sel := Doc().Find("h1")
+	sel2 := sel.Siblings().End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestSiblings2(t *testing.T) {
+	sel := Doc().Find(".pvk-gutter").Siblings()
+	assertLength(t, sel.Nodes, 9)
+}
+
+func TestSiblings3(t *testing.T) {
+	sel := Doc().Find("body>.container-fluid").Siblings()
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestSiblingsFiltered(t *testing.T) {
+	sel := Doc().Find(".pvk-gutter").SiblingsFiltered(".pvk-content")
+	assertLength(t, sel.Nodes, 3)
+}
+
+func TestSiblingsFilteredInvalid(t *testing.T) {
+	sel := Doc().Find(".pvk-gutter").SiblingsFiltered("")
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestSiblingsFilteredRollback(t *testing.T) {
+	sel := Doc().Find(".pvk-gutter")
+	sel2 := sel.SiblingsFiltered(".pvk-content").End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestNext(t *testing.T) {
+	sel := Doc().Find("h1").Next()
+	assertLength(t, sel.Nodes, 1)
+}
+
+func TestNextRollback(t *testing.T) {
+	sel := Doc().Find("h1")
+	sel2 := sel.Next().End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestNext2(t *testing.T) {
+	sel := Doc().Find(".close").Next()
+	assertLength(t, sel.Nodes, 1)
+}
+
+func TestNextNone(t *testing.T) {
+	sel := Doc().Find("small").Next()
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestNextFiltered(t *testing.T) {
+	sel := Doc().Find(".container-fluid").NextFiltered("div")
+	assertLength(t, sel.Nodes, 2)
+}
+
+func TestNextFilteredInvalid(t *testing.T) {
+	sel := Doc().Find(".container-fluid").NextFiltered("")
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestNextFilteredRollback(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := sel.NextFiltered("div").End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestNextFiltered2(t *testing.T) {
+	sel := Doc().Find(".container-fluid").NextFiltered("[ng-view]")
+	assertLength(t, sel.Nodes, 1)
+}
+
+func TestPrev(t *testing.T) {
+	sel := Doc().Find(".red").Prev()
+	assertLength(t, sel.Nodes, 1)
+	assertClass(t, sel, "green")
+}
+
+func TestPrevRollback(t *testing.T) {
+	sel := Doc().Find(".red")
+	sel2 := sel.Prev().End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestPrev2(t *testing.T) {
+	sel := Doc().Find(".row-fluid").Prev()
+	assertLength(t, sel.Nodes, 5)
+}
+
+func TestPrevNone(t *testing.T) {
+	sel := Doc().Find("h2").Prev()
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestPrevFiltered(t *testing.T) {
+	sel := Doc().Find(".row-fluid").PrevFiltered(".row-fluid")
+	assertLength(t, sel.Nodes, 5)
+}
+
+func TestPrevFilteredInvalid(t *testing.T) {
+	sel := Doc().Find(".row-fluid").PrevFiltered("")
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestPrevFilteredRollback(t *testing.T) {
+	sel := Doc().Find(".row-fluid")
+	sel2 := sel.PrevFiltered(".row-fluid").End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestNextAll(t *testing.T) {
+	sel := Doc().Find("#cf2 div:nth-child(1)").NextAll()
+	assertLength(t, sel.Nodes, 3)
+}
+
+func TestNextAllRollback(t *testing.T) {
+	sel := Doc().Find("#cf2 div:nth-child(1)")
+	sel2 := sel.NextAll().End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestNextAll2(t *testing.T) {
+	sel := Doc().Find("div[ng-cloak]").NextAll()
+	assertLength(t, sel.Nodes, 1)
+}
+
+func TestNextAllNone(t *testing.T) {
+	sel := Doc().Find(".footer").NextAll()
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestNextAllFiltered(t *testing.T) {
+	sel := Doc().Find("#cf2 .row-fluid").NextAllFiltered("[ng-cloak]")
+	assertLength(t, sel.Nodes, 2)
+}
+
+func TestNextAllFilteredInvalid(t *testing.T) {
+	sel := Doc().Find("#cf2 .row-fluid").NextAllFiltered("")
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestNextAllFilteredRollback(t *testing.T) {
+	sel := Doc().Find("#cf2 .row-fluid")
+	sel2 := sel.NextAllFiltered("[ng-cloak]").End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestNextAllFiltered2(t *testing.T) {
+	sel := Doc().Find(".close").NextAllFiltered("h4")
+	assertLength(t, sel.Nodes, 1)
+}
+
+func TestPrevAll(t *testing.T) {
+	sel := Doc().Find("[ng-view]").PrevAll()
+	assertLength(t, sel.Nodes, 2)
+}
+
+func TestPrevAllOrder(t *testing.T) {
+	sel := Doc().Find("[ng-view]").PrevAll()
+	assertLength(t, sel.Nodes, 2)
+	assertSelectionIs(t, sel, "#cf4", "#cf3")
+}
+
+func TestPrevAllRollback(t *testing.T) {
+	sel := Doc().Find("[ng-view]")
+	sel2 := sel.PrevAll().End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestPrevAll2(t *testing.T) {
+	sel := Doc().Find(".pvk-gutter").PrevAll()
+	assertLength(t, sel.Nodes, 6)
+}
+
+func TestPrevAllFiltered(t *testing.T) {
+	sel := Doc().Find(".pvk-gutter").PrevAllFiltered(".pvk-content")
+	assertLength(t, sel.Nodes, 3)
+}
+
+func TestPrevAllFilteredInvalid(t *testing.T) {
+	sel := Doc().Find(".pvk-gutter").PrevAllFiltered("")
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestPrevAllFilteredRollback(t *testing.T) {
+	sel := Doc().Find(".pvk-gutter")
+	sel2 := sel.PrevAllFiltered(".pvk-content").End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestNextUntil(t *testing.T) {
+	sel := Doc().Find(".alert a").NextUntil("p")
+	assertLength(t, sel.Nodes, 1)
+	assertSelectionIs(t, sel, "h4")
+}
+
+func TestNextUntilInvalid(t *testing.T) {
+	sel := Doc().Find(".alert a").NextUntil("")
+	assertLength(t, sel.Nodes, 2)
+}
+
+func TestNextUntil2(t *testing.T) {
+	sel := Doc().Find("#cf2-1").NextUntil("[ng-cloak]")
+	assertLength(t, sel.Nodes, 1)
+	assertSelectionIs(t, sel, "#cf2-2")
+}
+
+func TestNextUntilOrder(t *testing.T) {
+	sel := Doc().Find("#cf2-1").NextUntil("#cf2-4")
+	assertLength(t, sel.Nodes, 2)
+	assertSelectionIs(t, sel, "#cf2-2", "#cf2-3")
+}
+
+func TestNextUntilRollback(t *testing.T) {
+	sel := Doc().Find("#cf2-1")
+	sel2 := sel.PrevUntil("#cf2-4").End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestNextUntilSelection(t *testing.T) {
+	sel := Doc2().Find("#n2")
+	sel2 := Doc2().Find("#n4")
+	sel2 = sel.NextUntilSelection(sel2)
+	assertLength(t, sel2.Nodes, 1)
+	assertSelectionIs(t, sel2, "#n3")
+}
+
+func TestNextUntilSelectionRollback(t *testing.T) {
+	sel := Doc2().Find("#n2")
+	sel2 := Doc2().Find("#n4")
+	sel2 = sel.NextUntilSelection(sel2).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestNextUntilNodes(t *testing.T) {
+	sel := Doc2().Find("#n2")
+	sel2 := Doc2().Find("#n5")
+	sel2 = sel.NextUntilNodes(sel2.Nodes...)
+	assertLength(t, sel2.Nodes, 2)
+	assertSelectionIs(t, sel2, "#n3", "#n4")
+}
+
+func TestNextUntilNodesRollback(t *testing.T) {
+	sel := Doc2().Find("#n2")
+	sel2 := Doc2().Find("#n5")
+	sel2 = sel.NextUntilNodes(sel2.Nodes...).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestPrevUntil(t *testing.T) {
+	sel := Doc().Find(".alert p").PrevUntil("a")
+	assertLength(t, sel.Nodes, 1)
+	assertSelectionIs(t, sel, "h4")
+}
+
+func TestPrevUntilInvalid(t *testing.T) {
+	sel := Doc().Find(".alert p").PrevUntil("")
+	assertLength(t, sel.Nodes, 2)
+}
+
+func TestPrevUntil2(t *testing.T) {
+	sel := Doc().Find("[ng-cloak]").PrevUntil(":not([ng-cloak])")
+	assertLength(t, sel.Nodes, 1)
+	assertSelectionIs(t, sel, "[ng-cloak]")
+}
+
+func TestPrevUntilOrder(t *testing.T) {
+	sel := Doc().Find("#cf2-4").PrevUntil("#cf2-1")
+	assertLength(t, sel.Nodes, 2)
+	assertSelectionIs(t, sel, "#cf2-3", "#cf2-2")
+}
+
+func TestPrevUntilRollback(t *testing.T) {
+	sel := Doc().Find("#cf2-4")
+	sel2 := sel.PrevUntil("#cf2-1").End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestPrevUntilSelection(t *testing.T) {
+	sel := Doc2().Find("#n4")
+	sel2 := Doc2().Find("#n2")
+	sel2 = sel.PrevUntilSelection(sel2)
+	assertLength(t, sel2.Nodes, 1)
+	assertSelectionIs(t, sel2, "#n3")
+}
+
+func TestPrevUntilSelectionRollback(t *testing.T) {
+	sel := Doc2().Find("#n4")
+	sel2 := Doc2().Find("#n2")
+	sel2 = sel.PrevUntilSelection(sel2).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestPrevUntilNodes(t *testing.T) {
+	sel := Doc2().Find("#n5")
+	sel2 := Doc2().Find("#n2")
+	sel2 = sel.PrevUntilNodes(sel2.Nodes...)
+	assertLength(t, sel2.Nodes, 2)
+	assertSelectionIs(t, sel2, "#n4", "#n3")
+}
+
+func TestPrevUntilNodesRollback(t *testing.T) {
+	sel := Doc2().Find("#n5")
+	sel2 := Doc2().Find("#n2")
+	sel2 = sel.PrevUntilNodes(sel2.Nodes...).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestNextFilteredUntil(t *testing.T) {
+	sel := Doc2().Find(".two").NextFilteredUntil(".even", ".six")
+	assertLength(t, sel.Nodes, 4)
+	assertSelectionIs(t, sel, "#n3", "#n5", "#nf3", "#nf5")
+}
+
+func TestNextFilteredUntilInvalid(t *testing.T) {
+	sel := Doc2().Find(".two").NextFilteredUntil("", "")
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestNextFilteredUntilRollback(t *testing.T) {
+	sel := Doc2().Find(".two")
+	sel2 := sel.NextFilteredUntil(".even", ".six").End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestNextFilteredUntilSelection(t *testing.T) {
+	sel := Doc2().Find(".even")
+	sel2 := Doc2().Find(".five")
+	sel = sel.NextFilteredUntilSelection(".even", sel2)
+	assertLength(t, sel.Nodes, 2)
+	assertSelectionIs(t, sel, "#n3", "#nf3")
+}
+
+func TestNextFilteredUntilSelectionRollback(t *testing.T) {
+	sel := Doc2().Find(".even")
+	sel2 := Doc2().Find(".five")
+	sel3 := sel.NextFilteredUntilSelection(".even", sel2).End()
+	assertEqual(t, sel, sel3)
+}
+
+func TestNextFilteredUntilNodes(t *testing.T) {
+	sel := Doc2().Find(".even")
+	sel2 := Doc2().Find(".four")
+	sel = sel.NextFilteredUntilNodes(".odd", sel2.Nodes...)
+	assertLength(t, sel.Nodes, 4)
+	assertSelectionIs(t, sel, "#n2", "#n6", "#nf2", "#nf6")
+}
+
+func TestNextFilteredUntilNodesRollback(t *testing.T) {
+	sel := Doc2().Find(".even")
+	sel2 := Doc2().Find(".four")
+	sel3 := sel.NextFilteredUntilNodes(".odd", sel2.Nodes...).End()
+	assertEqual(t, sel, sel3)
+}
+
+func TestPrevFilteredUntil(t *testing.T) {
+	sel := Doc2().Find(".five").PrevFilteredUntil(".odd", ".one")
+	assertLength(t, sel.Nodes, 4)
+	assertSelectionIs(t, sel, "#n4", "#n2", "#nf4", "#nf2")
+}
+
+func TestPrevFilteredUntilInvalid(t *testing.T) {
+	sel := Doc2().Find(".five").PrevFilteredUntil("", "")
+	assertLength(t, sel.Nodes, 0)
+}
+
+func TestPrevFilteredUntilRollback(t *testing.T) {
+	sel := Doc2().Find(".four")
+	sel2 := sel.PrevFilteredUntil(".odd", ".one").End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestPrevFilteredUntilSelection(t *testing.T) {
+	sel := Doc2().Find(".odd")
+	sel2 := Doc2().Find(".two")
+	sel = sel.PrevFilteredUntilSelection(".odd", sel2)
+	assertLength(t, sel.Nodes, 2)
+	assertSelectionIs(t, sel, "#n4", "#nf4")
+}
+
+func TestPrevFilteredUntilSelectionRollback(t *testing.T) {
+	sel := Doc2().Find(".even")
+	sel2 := Doc2().Find(".five")
+	sel3 := sel.PrevFilteredUntilSelection(".even", sel2).End()
+	assertEqual(t, sel, sel3)
+}
+
+func TestPrevFilteredUntilNodes(t *testing.T) {
+	sel := Doc2().Find(".even")
+	sel2 := Doc2().Find(".four")
+	sel = sel.PrevFilteredUntilNodes(".odd", sel2.Nodes...)
+	assertLength(t, sel.Nodes, 2)
+	assertSelectionIs(t, sel, "#n2", "#nf2")
+}
+
+func TestPrevFilteredUntilNodesRollback(t *testing.T) {
+	sel := Doc2().Find(".even")
+	sel2 := Doc2().Find(".four")
+	sel3 := sel.PrevFilteredUntilNodes(".odd", sel2.Nodes...).End()
+	assertEqual(t, sel, sel3)
+}
+
+func TestClosestItself(t *testing.T) {
+	sel := Doc2().Find(".three")
+	sel2 := sel.Closest(".row")
+	assertLength(t, sel2.Nodes, sel.Length())
+	assertSelectionIs(t, sel2, "#n3", "#nf3")
+}
+
+func TestClosestNoDupes(t *testing.T) {
+	sel := Doc().Find(".span12")
+	sel2 := sel.Closest(".pvk-content")
+	assertLength(t, sel2.Nodes, 1)
+	assertClass(t, sel2, "pvk-content")
+}
+
+func TestClosestNone(t *testing.T) {
+	sel := Doc().Find("h4")
+	sel2 := sel.Closest("a")
+	assertLength(t, sel2.Nodes, 0)
+}
+
+func TestClosestInvalid(t *testing.T) {
+	sel := Doc().Find("h4")
+	sel2 := sel.Closest("")
+	assertLength(t, sel2.Nodes, 0)
+}
+
+func TestClosestMany(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := sel.Closest(".pvk-content")
+	assertLength(t, sel2.Nodes, 2)
+	assertSelectionIs(t, sel2, "#pc1", "#pc2")
+}
+
+func TestClosestRollback(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := sel.Closest(".pvk-content").End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestClosestSelectionItself(t *testing.T) {
+	sel := Doc2().Find(".three")
+	sel2 := sel.ClosestSelection(Doc2().Find(".row"))
+	assertLength(t, sel2.Nodes, sel.Length())
+}
+
+func TestClosestSelectionNoDupes(t *testing.T) {
+	sel := Doc().Find(".span12")
+	sel2 := sel.ClosestSelection(Doc().Find(".pvk-content"))
+	assertLength(t, sel2.Nodes, 1)
+	assertClass(t, sel2, "pvk-content")
+}
+
+func TestClosestSelectionNone(t *testing.T) {
+	sel := Doc().Find("h4")
+	sel2 := sel.ClosestSelection(Doc().Find("a"))
+	assertLength(t, sel2.Nodes, 0)
+}
+
+func TestClosestSelectionMany(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := sel.ClosestSelection(Doc().Find(".pvk-content"))
+	assertLength(t, sel2.Nodes, 2)
+	assertSelectionIs(t, sel2, "#pc1", "#pc2")
+}
+
+func TestClosestSelectionRollback(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := sel.ClosestSelection(Doc().Find(".pvk-content")).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestClosestNodesItself(t *testing.T) {
+	sel := Doc2().Find(".three")
+	sel2 := sel.ClosestNodes(Doc2().Find(".row").Nodes...)
+	assertLength(t, sel2.Nodes, sel.Length())
+}
+
+func TestClosestNodesNoDupes(t *testing.T) {
+	sel := Doc().Find(".span12")
+	sel2 := sel.ClosestNodes(Doc().Find(".pvk-content").Nodes...)
+	assertLength(t, sel2.Nodes, 1)
+	assertClass(t, sel2, "pvk-content")
+}
+
+func TestClosestNodesNone(t *testing.T) {
+	sel := Doc().Find("h4")
+	sel2 := sel.ClosestNodes(Doc().Find("a").Nodes...)
+	assertLength(t, sel2.Nodes, 0)
+}
+
+func TestClosestNodesMany(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := sel.ClosestNodes(Doc().Find(".pvk-content").Nodes...)
+	assertLength(t, sel2.Nodes, 2)
+	assertSelectionIs(t, sel2, "#pc1", "#pc2")
+}
+
+func TestClosestNodesRollback(t *testing.T) {
+	sel := Doc().Find(".container-fluid")
+	sel2 := sel.ClosestNodes(Doc().Find(".pvk-content").Nodes...).End()
+	assertEqual(t, sel, sel2)
+}
+
+func TestIssue26(t *testing.T) {
+	img1 := `<img src="assets/images/gallery/thumb-1.jpg" alt="150x150" />`
+	img2 := `<img alt="150x150" src="assets/images/gallery/thumb-1.jpg" />`
+	cases := []struct {
+		s string
+		l int
+	}{
+		{s: img1 + img2, l: 2},
+		{s: img1, l: 1},
+		{s: img2, l: 1},
+	}
+	for _, c := range cases {
+		doc, err := NewDocumentFromReader(strings.NewReader(c.s))
+		if err != nil {
+			t.Fatal(err)
+		}
+		sel := doc.Find("img[src]")
+		assertLength(t, sel.Nodes, c.l)
+	}
+}

+ 202 - 0
vendor/github.com/PuerkitoBio/goquery/type_test.go

@@ -0,0 +1,202 @@
+package goquery
+
+import (
+	"bytes"
+	"fmt"
+	"os"
+	"strings"
+	"testing"
+
+	"golang.org/x/net/html"
+)
+
+// Test helper functions and members
+var doc *Document
+var doc2 *Document
+var doc3 *Document
+var docB *Document
+var docW *Document
+
+func Doc() *Document {
+	if doc == nil {
+		doc = loadDoc("page.html")
+	}
+	return doc
+}
+
+func Doc2() *Document {
+	if doc2 == nil {
+		doc2 = loadDoc("page2.html")
+	}
+	return doc2
+}
+
+func Doc2Clone() *Document {
+	return CloneDocument(Doc2())
+}
+
+func Doc3() *Document {
+	if doc3 == nil {
+		doc3 = loadDoc("page3.html")
+	}
+	return doc3
+}
+
+func Doc3Clone() *Document {
+	return CloneDocument(Doc3())
+}
+
+func DocB() *Document {
+	if docB == nil {
+		docB = loadDoc("gotesting.html")
+	}
+	return docB
+}
+
+func DocW() *Document {
+	if docW == nil {
+		docW = loadDoc("gowiki.html")
+	}
+	return docW
+}
+
+func assertLength(t *testing.T, nodes []*html.Node, length int) {
+	if len(nodes) != length {
+		t.Errorf("Expected %d nodes, found %d.", length, len(nodes))
+		for i, n := range nodes {
+			t.Logf("Node %d: %+v.", i, n)
+		}
+	}
+}
+
+func assertClass(t *testing.T, sel *Selection, class string) {
+	if !sel.HasClass(class) {
+		t.Errorf("Expected node to have class %s, found %+v.", class, sel.Get(0))
+	}
+}
+
+func assertPanic(t *testing.T) {
+	if e := recover(); e == nil {
+		t.Error("Expected a panic.")
+	}
+}
+
+func assertEqual(t *testing.T, s1 *Selection, s2 *Selection) {
+	if s1 != s2 {
+		t.Error("Expected selection objects to be the same.")
+	}
+}
+
+func assertSelectionIs(t *testing.T, sel *Selection, is ...string) {
+	for i := 0; i < sel.Length(); i++ {
+		if !sel.Eq(i).Is(is[i]) {
+			t.Errorf("Expected node %d to be %s, found %+v", i, is[i], sel.Get(i))
+		}
+	}
+}
+
+func printSel(t *testing.T, sel *Selection) {
+	if testing.Verbose() {
+		h, err := sel.Html()
+		if err != nil {
+			t.Fatal(err)
+		}
+		t.Log(h)
+	}
+}
+
+func loadDoc(page string) *Document {
+	var f *os.File
+	var e error
+
+	if f, e = os.Open(fmt.Sprintf("./testdata/%s", page)); e != nil {
+		panic(e.Error())
+	}
+	defer f.Close()
+
+	var node *html.Node
+	if node, e = html.Parse(f); e != nil {
+		panic(e.Error())
+	}
+	return NewDocumentFromNode(node)
+}
+
+func TestNewDocument(t *testing.T) {
+	if f, e := os.Open("./testdata/page.html"); e != nil {
+		t.Error(e.Error())
+	} else {
+		defer f.Close()
+		if node, e := html.Parse(f); e != nil {
+			t.Error(e.Error())
+		} else {
+			doc = NewDocumentFromNode(node)
+		}
+	}
+}
+
+func TestNewDocumentFromReader(t *testing.T) {
+	cases := []struct {
+		src string
+		err bool
+		sel string
+		cnt int
+	}{
+		0: {
+			src: `
+<html>
+<head>
+<title>Test</title>
+<body>
+<h1>Hi</h1>
+</body>
+</html>`,
+			sel: "h1",
+			cnt: 1,
+		},
+		1: {
+			// Actually pretty hard to make html.Parse return an error
+			// based on content...
+			src: `<html><body><aef<eqf>>>qq></body></ht>`,
+		},
+	}
+	buf := bytes.NewBuffer(nil)
+
+	for i, c := range cases {
+		buf.Reset()
+		buf.WriteString(c.src)
+
+		d, e := NewDocumentFromReader(buf)
+		if (e != nil) != c.err {
+			if c.err {
+				t.Errorf("[%d] - expected error, got none", i)
+			} else {
+				t.Errorf("[%d] - expected no error, got %s", i, e)
+			}
+		}
+		if c.sel != "" {
+			s := d.Find(c.sel)
+			if s.Length() != c.cnt {
+				t.Errorf("[%d] - expected %d nodes, found %d", i, c.cnt, s.Length())
+			}
+		}
+	}
+}
+
+func TestNewDocumentFromResponseNil(t *testing.T) {
+	_, e := NewDocumentFromResponse(nil)
+	if e == nil {
+		t.Error("Expected error, got none")
+	}
+}
+
+func TestIssue103(t *testing.T) {
+	d, err := NewDocumentFromReader(strings.NewReader("<html><title>Scientists Stored These Images in DNA—Then Flawlessly Retrieved Them</title></html>"))
+	if err != nil {
+		t.Error(err)
+	}
+	text := d.Find("title").Text()
+	for i, r := range text {
+		t.Logf("%d: %d - %q\n", i, r, string(r))
+	}
+	t.Log(text)
+}

+ 128 - 0
vendor/github.com/PuerkitoBio/goquery/utilities_test.go

@@ -0,0 +1,128 @@
+package goquery
+
+import (
+	"reflect"
+	"sort"
+	"strings"
+	"testing"
+
+	"golang.org/x/net/html"
+)
+
+var allNodes = `<!doctype html>
+<html>
+	<head>
+		<meta a="b">
+	</head>
+	<body>
+		<p><!-- this is a comment -->
+		This is some text.
+		</p>
+		<div></div>
+		<h1 class="header"></h1>
+		<h2 class="header"></h2>
+	</body>
+</html>`
+
+func TestNodeName(t *testing.T) {
+	doc, err := NewDocumentFromReader(strings.NewReader(allNodes))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	n0 := doc.Nodes[0]
+	nDT := n0.FirstChild
+	sMeta := doc.Find("meta")
+	nMeta := sMeta.Get(0)
+	sP := doc.Find("p")
+	nP := sP.Get(0)
+	nComment := nP.FirstChild
+	nText := nComment.NextSibling
+
+	cases := []struct {
+		node *html.Node
+		typ  html.NodeType
+		want string
+	}{
+		{n0, html.DocumentNode, nodeNames[html.DocumentNode]},
+		{nDT, html.DoctypeNode, "html"},
+		{nMeta, html.ElementNode, "meta"},
+		{nP, html.ElementNode, "p"},
+		{nComment, html.CommentNode, nodeNames[html.CommentNode]},
+		{nText, html.TextNode, nodeNames[html.TextNode]},
+	}
+	for i, c := range cases {
+		got := NodeName(newSingleSelection(c.node, doc))
+		if c.node.Type != c.typ {
+			t.Errorf("%d: want type %v, got %v", i, c.typ, c.node.Type)
+		}
+		if got != c.want {
+			t.Errorf("%d: want %q, got %q", i, c.want, got)
+		}
+	}
+}
+
+func TestNodeNameMultiSel(t *testing.T) {
+	doc, err := NewDocumentFromReader(strings.NewReader(allNodes))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	in := []string{"p", "h1", "div"}
+	var out []string
+	doc.Find(strings.Join(in, ", ")).Each(func(i int, s *Selection) {
+		got := NodeName(s)
+		out = append(out, got)
+	})
+	sort.Strings(in)
+	sort.Strings(out)
+	if !reflect.DeepEqual(in, out) {
+		t.Errorf("want %v, got %v", in, out)
+	}
+}
+
+func TestOuterHtml(t *testing.T) {
+	doc, err := NewDocumentFromReader(strings.NewReader(allNodes))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	n0 := doc.Nodes[0]
+	nDT := n0.FirstChild
+	sMeta := doc.Find("meta")
+	sP := doc.Find("p")
+	nP := sP.Get(0)
+	nComment := nP.FirstChild
+	nText := nComment.NextSibling
+	sHeaders := doc.Find(".header")
+
+	cases := []struct {
+		node *html.Node
+		sel  *Selection
+		want string
+	}{
+		{nDT, nil, "<!DOCTYPE html>"}, // render makes DOCTYPE all caps
+		{nil, sMeta, `<meta a="b"/>`}, // and auto-closes the meta
+		{nil, sP, `<p><!-- this is a comment -->
+		This is some text.
+		</p>`},
+		{nComment, nil, "<!-- this is a comment -->"},
+		{nText, nil, `
+		This is some text.
+		`},
+		{nil, sHeaders, `<h1 class="header"></h1>`},
+	}
+	for i, c := range cases {
+		if c.sel == nil {
+			c.sel = newSingleSelection(c.node, doc)
+		}
+		got, err := OuterHtml(c.sel)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		if got != c.want {
+			t.Errorf("%d: want %q, got %q", i, c.want, got)
+		}
+	}
+}

+ 53 - 0
vendor/github.com/andybalholm/cascadia/benchmark_test.go

@@ -0,0 +1,53 @@
+package cascadia
+
+import (
+	"strings"
+	"testing"
+
+	"golang.org/x/net/html"
+)
+
+func MustParseHTML(doc string) *html.Node {
+	dom, err := html.Parse(strings.NewReader(doc))
+	if err != nil {
+		panic(err)
+	}
+	return dom
+}
+
+var selector = MustCompile(`div.matched`)
+var doc = `<!DOCTYPE html>
+<html>
+<body>
+<div class="matched">
+  <div>
+    <div class="matched"></div>
+    <div class="matched"></div>
+    <div class="matched"></div>
+    <div class="matched"></div>
+    <div class="matched"></div>
+    <div class="matched"></div>
+    <div class="matched"></div>
+    <div class="matched"></div>
+    <div class="matched"></div>
+    <div class="matched"></div>
+    <div class="matched"></div>
+    <div class="matched"></div>
+    <div class="matched"></div>
+    <div class="matched"></div>
+    <div class="matched"></div>
+    <div class="matched"></div>
+  </div>
+</div>
+</body>
+</html>
+`
+var dom = MustParseHTML(doc)
+
+func BenchmarkMatchAll(b *testing.B) {
+	var matches []*html.Node
+	for i := 0; i < b.N; i++ {
+		matches = selector.MatchAll(dom)
+	}
+	_ = matches
+}

+ 86 - 0
vendor/github.com/andybalholm/cascadia/parser_test.go

@@ -0,0 +1,86 @@
+package cascadia
+
+import (
+	"testing"
+)
+
+var identifierTests = map[string]string{
+	"x":         "x",
+	"96":        "",
+	"-x":        "-x",
+	`r\e9 sumé`: "résumé",
+	`a\"b`:      `a"b`,
+}
+
+func TestParseIdentifier(t *testing.T) {
+	for source, want := range identifierTests {
+		p := &parser{s: source}
+		got, err := p.parseIdentifier()
+
+		if err != nil {
+			if want == "" {
+				// It was supposed to be an error.
+				continue
+			}
+			t.Errorf("parsing %q: got error (%s), want %q", source, err, want)
+			continue
+		}
+
+		if want == "" {
+			if err == nil {
+				t.Errorf("parsing %q: got %q, want error", source, got)
+			}
+			continue
+		}
+
+		if p.i < len(source) {
+			t.Errorf("parsing %q: %d bytes left over", source, len(source)-p.i)
+			continue
+		}
+
+		if got != want {
+			t.Errorf("parsing %q: got %q, want %q", source, got, want)
+		}
+	}
+}
+
+var stringTests = map[string]string{
+	`"x"`:         "x",
+	`'x'`:         "x",
+	`'x`:          "",
+	"'x\\\r\nx'":  "xx",
+	`"r\e9 sumé"`: "résumé",
+	`"a\"b"`:      `a"b`,
+}
+
+func TestParseString(t *testing.T) {
+	for source, want := range stringTests {
+		p := &parser{s: source}
+		got, err := p.parseString()
+
+		if err != nil {
+			if want == "" {
+				// It was supposed to be an error.
+				continue
+			}
+			t.Errorf("parsing %q: got error (%s), want %q", source, err, want)
+			continue
+		}
+
+		if want == "" {
+			if err == nil {
+				t.Errorf("parsing %q: got %q, want error", source, got)
+			}
+			continue
+		}
+
+		if p.i < len(source) {
+			t.Errorf("parsing %q: %d bytes left over", source, len(source)-p.i)
+			continue
+		}
+
+		if got != want {
+			t.Errorf("parsing %q: got %q, want %q", source, got, want)
+		}
+	}
+}

+ 654 - 0
vendor/github.com/andybalholm/cascadia/selector_test.go

@@ -0,0 +1,654 @@
+package cascadia
+
+import (
+	"bytes"
+	"strings"
+	"testing"
+
+	"golang.org/x/net/html"
+)
+
+type selectorTest struct {
+	HTML, selector string
+	results        []string
+}
+
+func nodeString(n *html.Node) string {
+	buf := bytes.NewBufferString("")
+	html.Render(buf, n)
+	return buf.String()
+}
+
+var selectorTests = []selectorTest{
+	{
+		`<body><address>This address...</address></body>`,
+		"address",
+		[]string{
+			"<address>This address...</address>",
+		},
+	},
+	{
+		`<!-- comment --><html><head></head><body>text</body></html>`,
+		"*",
+		[]string{
+			"<html><head></head><body>text</body></html>",
+			"<head></head>",
+			"<body>text</body>",
+		},
+	},
+	{
+		`<html><head></head><body></body></html>`,
+		"*",
+		[]string{
+			"<html><head></head><body></body></html>",
+			"<head></head>",
+			"<body></body>",
+		},
+	},
+	{
+		`<p id="foo"><p id="bar">`,
+		"#foo",
+		[]string{
+			`<p id="foo"></p>`,
+		},
+	},
+	{
+		`<ul><li id="t1"><p id="t1">`,
+		"li#t1",
+		[]string{
+			`<li id="t1"><p id="t1"></p></li>`,
+		},
+	},
+	{
+		`<ol><li id="t4"><li id="t44">`,
+		"*#t4",
+		[]string{
+			`<li id="t4"></li>`,
+		},
+	},
+	{
+		`<ul><li class="t1"><li class="t2">`,
+		".t1",
+		[]string{
+			`<li class="t1"></li>`,
+		},
+	},
+	{
+		`<p class="t1 t2">`,
+		"p.t1",
+		[]string{
+			`<p class="t1 t2"></p>`,
+		},
+	},
+	{
+		`<div class="test">`,
+		"div.teST",
+		[]string{},
+	},
+	{
+		`<p class="t1 t2">`,
+		".t1.fail",
+		[]string{},
+	},
+	{
+		`<p class="t1 t2">`,
+		"p.t1.t2",
+		[]string{
+			`<p class="t1 t2"></p>`,
+		},
+	},
+	{
+		`<p><p title="title">`,
+		"p[title]",
+		[]string{
+			`<p title="title"></p>`,
+		},
+	},
+	{
+		`<address><address title="foo"><address title="bar">`,
+		`address[title="foo"]`,
+		[]string{
+			`<address title="foo"><address title="bar"></address></address>`,
+		},
+	},
+	{
+		`<address><address title="foo"><address title="bar">`,
+		`address[title!="foo"]`,
+		[]string{
+			`<address><address title="foo"><address title="bar"></address></address></address>`,
+			`<address title="bar"></address>`,
+		},
+	},
+	{
+		`<p title="tot foo bar">`,
+		`[    	title        ~=       foo    ]`,
+		[]string{
+			`<p title="tot foo bar"></p>`,
+		},
+	},
+	{
+		`<p title="hello world">`,
+		`[title~="hello world"]`,
+		[]string{},
+	},
+	{
+		`<p lang="en"><p lang="en-gb"><p lang="enough"><p lang="fr-en">`,
+		`[lang|="en"]`,
+		[]string{
+			`<p lang="en"></p>`,
+			`<p lang="en-gb"></p>`,
+		},
+	},
+	{
+		`<p title="foobar"><p title="barfoo">`,
+		`[title^="foo"]`,
+		[]string{
+			`<p title="foobar"></p>`,
+		},
+	},
+	{
+		`<p title="foobar"><p title="barfoo">`,
+		`[title$="bar"]`,
+		[]string{
+			`<p title="foobar"></p>`,
+		},
+	},
+	{
+		`<p title="foobarufoo">`,
+		`[title*="bar"]`,
+		[]string{
+			`<p title="foobarufoo"></p>`,
+		},
+	},
+	{
+		`<p class=" ">This text should be green.</p><p>This text should be green.</p>`,
+		`p[class$=" "]`,
+		[]string{},
+	},
+	{
+		`<p class="">This text should be green.</p><p>This text should be green.</p>`,
+		`p[class$=""]`,
+		[]string{},
+	},
+	{
+		`<p class=" ">This text should be green.</p><p>This text should be green.</p>`,
+		`p[class^=" "]`,
+		[]string{},
+	},
+	{
+		`<p class="">This text should be green.</p><p>This text should be green.</p>`,
+		`p[class^=""]`,
+		[]string{},
+	},
+	{
+		`<p class=" ">This text should be green.</p><p>This text should be green.</p>`,
+		`p[class*=" "]`,
+		[]string{},
+	},
+	{
+		`<p class="">This text should be green.</p><p>This text should be green.</p>`,
+		`p[class*=""]`,
+		[]string{},
+	},
+	{
+		`<input type="radio" name="Sex" value="F"/>`,
+		`input[name=Sex][value=F]`,
+		[]string{
+			`<input type="radio" name="Sex" value="F"/>`,
+		},
+	},
+	{
+		`<table border="0" cellpadding="0" cellspacing="0" style="table-layout: fixed; width: 100%; border: 0 dashed; border-color: #FFFFFF"><tr style="height:64px">aaa</tr></table>`,
+		`table[border="0"][cellpadding="0"][cellspacing="0"]`,
+		[]string{
+			`<table border="0" cellpadding="0" cellspacing="0" style="table-layout: fixed; width: 100%; border: 0 dashed; border-color: #FFFFFF"><tbody><tr style="height:64px"></tr></tbody></table>`,
+		},
+	},
+	{
+		`<p class="t1 t2">`,
+		".t1:not(.t2)",
+		[]string{},
+	},
+	{
+		`<div class="t3">`,
+		`div:not(.t1)`,
+		[]string{
+			`<div class="t3"></div>`,
+		},
+	},
+	{
+		`<div><div class="t2"><div class="t3">`,
+		`div:not([class="t2"])`,
+		[]string{
+			`<div><div class="t2"><div class="t3"></div></div></div>`,
+			`<div class="t3"></div>`,
+		},
+	},
+	{
+		`<ol><li id=1><li id=2><li id=3></ol>`,
+		`li:nth-child(odd)`,
+		[]string{
+			`<li id="1"></li>`,
+			`<li id="3"></li>`,
+		},
+	},
+	{
+		`<ol><li id=1><li id=2><li id=3></ol>`,
+		`li:nth-child(even)`,
+		[]string{
+			`<li id="2"></li>`,
+		},
+	},
+	{
+		`<ol><li id=1><li id=2><li id=3></ol>`,
+		`li:nth-child(-n+2)`,
+		[]string{
+			`<li id="1"></li>`,
+			`<li id="2"></li>`,
+		},
+	},
+	{
+		`<ol><li id=1><li id=2><li id=3></ol>`,
+		`li:nth-child(3n+1)`,
+		[]string{
+			`<li id="1"></li>`,
+		},
+	},
+	{
+		`<ol><li id=1><li id=2><li id=3><li id=4></ol>`,
+		`li:nth-last-child(odd)`,
+		[]string{
+			`<li id="2"></li>`,
+			`<li id="4"></li>`,
+		},
+	},
+	{
+		`<ol><li id=1><li id=2><li id=3><li id=4></ol>`,
+		`li:nth-last-child(even)`,
+		[]string{
+			`<li id="1"></li>`,
+			`<li id="3"></li>`,
+		},
+	},
+	{
+		`<ol><li id=1><li id=2><li id=3><li id=4></ol>`,
+		`li:nth-last-child(-n+2)`,
+		[]string{
+			`<li id="3"></li>`,
+			`<li id="4"></li>`,
+		},
+	},
+	{
+		`<ol><li id=1><li id=2><li id=3><li id=4></ol>`,
+		`li:nth-last-child(3n+1)`,
+		[]string{
+			`<li id="1"></li>`,
+			`<li id="4"></li>`,
+		},
+	},
+	{
+		`<p>some text <span id="1">and a span</span><span id="2"> and another</span></p>`,
+		`span:first-child`,
+		[]string{
+			`<span id="1">and a span</span>`,
+		},
+	},
+	{
+		`<span>a span</span> and some text`,
+		`span:last-child`,
+		[]string{
+			`<span>a span</span>`,
+		},
+	},
+	{
+		`<address></address><p id=1><p id=2>`,
+		`p:nth-of-type(2)`,
+		[]string{
+			`<p id="2"></p>`,
+		},
+	},
+	{
+		`<address></address><p id=1><p id=2></p><a>`,
+		`p:nth-last-of-type(2)`,
+		[]string{
+			`<p id="1"></p>`,
+		},
+	},
+	{
+		`<address></address><p id=1><p id=2></p><a>`,
+		`p:last-of-type`,
+		[]string{
+			`<p id="2"></p>`,
+		},
+	},
+	{
+		`<address></address><p id=1><p id=2></p><a>`,
+		`p:first-of-type`,
+		[]string{
+			`<p id="1"></p>`,
+		},
+	},
+	{
+		`<div><p id="1"></p><a></a></div><div><p id="2"></p></div>`,
+		`p:only-child`,
+		[]string{
+			`<p id="2"></p>`,
+		},
+	},
+	{
+		`<div><p id="1"></p><a></a></div><div><p id="2"></p><p id="3"></p></div>`,
+		`p:only-of-type`,
+		[]string{
+			`<p id="1"></p>`,
+		},
+	},
+	{
+		`<p id="1"><!-- --><p id="2">Hello<p id="3"><span>`,
+		`:empty`,
+		[]string{
+			`<head></head>`,
+			`<p id="1"><!-- --></p>`,
+			`<span></span>`,
+		},
+	},
+	{
+		`<div><p id="1"><table><tr><td><p id="2"></table></div><p id="3">`,
+		`div p`,
+		[]string{
+			`<p id="1"><table><tbody><tr><td><p id="2"></p></td></tr></tbody></table></p>`,
+			`<p id="2"></p>`,
+		},
+	},
+	{
+		`<div><p id="1"><table><tr><td><p id="2"></table></div><p id="3">`,
+		`div table p`,
+		[]string{
+			`<p id="2"></p>`,
+		},
+	},
+	{
+		`<div><p id="1"><div><p id="2"></div><table><tr><td><p id="3"></table></div>`,
+		`div > p`,
+		[]string{
+			`<p id="1"></p>`,
+			`<p id="2"></p>`,
+		},
+	},
+	{
+		`<p id="1"><p id="2"></p><address></address><p id="3">`,
+		`p ~ p`,
+		[]string{
+			`<p id="2"></p>`,
+			`<p id="3"></p>`,
+		},
+	},
+	{
+		`<p id="1"></p>
+		 <!--comment-->
+		 <p id="2"></p><address></address><p id="3">`,
+		`p + p`,
+		[]string{
+			`<p id="2"></p>`,
+		},
+	},
+	{
+		`<ul><li></li><li></li></ul><p>`,
+		`li, p`,
+		[]string{
+			"<li></li>",
+			"<li></li>",
+			"<p></p>",
+		},
+	},
+	{
+		`<p id="1"><p id="2"></p><address></address><p id="3">`,
+		`p +/*This is a comment*/ p`,
+		[]string{
+			`<p id="2"></p>`,
+		},
+	},
+	{
+		`<p>Text block that <span>wraps inner text</span> and continues</p>`,
+		`p:contains("that wraps")`,
+		[]string{
+			`<p>Text block that <span>wraps inner text</span> and continues</p>`,
+		},
+	},
+	{
+		`<p>Text block that <span>wraps inner text</span> and continues</p>`,
+		`p:containsOwn("that wraps")`,
+		[]string{},
+	},
+	{
+		`<p>Text block that <span>wraps inner text</span> and continues</p>`,
+		`:containsOwn("inner")`,
+		[]string{
+			`<span>wraps inner text</span>`,
+		},
+	},
+	{
+		`<p>Text block that <span>wraps inner text</span> and continues</p>`,
+		`p:containsOwn("block")`,
+		[]string{
+			`<p>Text block that <span>wraps inner text</span> and continues</p>`,
+		},
+	},
+	{
+		`<div id="d1"><p id="p1"><span>text content</span></p></div><div id="d2"/>`,
+		`div:has(#p1)`,
+		[]string{
+			`<div id="d1"><p id="p1"><span>text content</span></p></div>`,
+		},
+	},
+	{
+		`<div id="d1"><p id="p1"><span>contents 1</span></p></div>
+		<div id="d2"><p>contents <em>2</em></p></div>`,
+		`div:has(:containsOwn("2"))`,
+		[]string{
+			`<div id="d2"><p>contents <em>2</em></p></div>`,
+		},
+	},
+	{
+		`<body><div id="d1"><p id="p1"><span>contents 1</span></p></div>
+		<div id="d2"><p id="p2">contents <em>2</em></p></div></body>`,
+		`body :has(:containsOwn("2"))`,
+		[]string{
+			`<div id="d2"><p id="p2">contents <em>2</em></p></div>`,
+			`<p id="p2">contents <em>2</em></p>`,
+		},
+	},
+	{
+		`<body><div id="d1"><p id="p1"><span>contents 1</span></p></div>
+		<div id="d2"><p id="p2">contents <em>2</em></p></div></body>`,
+		`body :haschild(:containsOwn("2"))`,
+		[]string{
+			`<p id="p2">contents <em>2</em></p>`,
+		},
+	},
+	{
+		`<p id="p1">0123456789</p><p id="p2">abcdef</p><p id="p3">0123ABCD</p>`,
+		`p:matches([\d])`,
+		[]string{
+			`<p id="p1">0123456789</p>`,
+			`<p id="p3">0123ABCD</p>`,
+		},
+	},
+	{
+		`<p id="p1">0123456789</p><p id="p2">abcdef</p><p id="p3">0123ABCD</p>`,
+		`p:matches([a-z])`,
+		[]string{
+			`<p id="p2">abcdef</p>`,
+		},
+	},
+	{
+		`<p id="p1">0123456789</p><p id="p2">abcdef</p><p id="p3">0123ABCD</p>`,
+		`p:matches([a-zA-Z])`,
+		[]string{
+			`<p id="p2">abcdef</p>`,
+			`<p id="p3">0123ABCD</p>`,
+		},
+	},
+	{
+		`<p id="p1">0123456789</p><p id="p2">abcdef</p><p id="p3">0123ABCD</p>`,
+		`p:matches([^\d])`,
+		[]string{
+			`<p id="p2">abcdef</p>`,
+			`<p id="p3">0123ABCD</p>`,
+		},
+	},
+	{
+		`<p id="p1">0123456789</p><p id="p2">abcdef</p><p id="p3">0123ABCD</p>`,
+		`p:matches(^(0|a))`,
+		[]string{
+			`<p id="p1">0123456789</p>`,
+			`<p id="p2">abcdef</p>`,
+			`<p id="p3">0123ABCD</p>`,
+		},
+	},
+	{
+		`<p id="p1">0123456789</p><p id="p2">abcdef</p><p id="p3">0123ABCD</p>`,
+		`p:matches(^\d+$)`,
+		[]string{
+			`<p id="p1">0123456789</p>`,
+		},
+	},
+	{
+		`<p id="p1">0123456789</p><p id="p2">abcdef</p><p id="p3">0123ABCD</p>`,
+		`p:not(:matches(^\d+$))`,
+		[]string{
+			`<p id="p2">abcdef</p>`,
+			`<p id="p3">0123ABCD</p>`,
+		},
+	},
+	{
+		`<div><p id="p1">01234<em>567</em>89</p><div>`,
+		`div :matchesOwn(^\d+$)`,
+		[]string{
+			`<p id="p1">01234<em>567</em>89</p>`,
+			`<em>567</em>`,
+		},
+	},
+	{
+		`<ul>
+			<li><a id="a1" href="http://www.google.com/finance"></a>
+			<li><a id="a2" href="http://finance.yahoo.com/"></a>
+			<li><a id="a2" href="http://finance.untrusted.com/"/>
+			<li><a id="a3" href="https://www.google.com/news"/>
+			<li><a id="a4" href="http://news.yahoo.com"/>
+		</ul>`,
+		`[href#=(fina)]:not([href#=(\/\/[^\/]+untrusted)])`,
+		[]string{
+			`<a id="a1" href="http://www.google.com/finance"></a>`,
+			`<a id="a2" href="http://finance.yahoo.com/"></a>`,
+		},
+	},
+	{
+		`<ul>
+			<li><a id="a1" href="http://www.google.com/finance"/>
+			<li><a id="a2" href="http://finance.yahoo.com/"/>
+			<li><a id="a3" href="https://www.google.com/news"></a>
+			<li><a id="a4" href="http://news.yahoo.com"/>
+		</ul>`,
+		`[href#=(^https:\/\/[^\/]*\/?news)]`,
+		[]string{
+			`<a id="a3" href="https://www.google.com/news"></a>`,
+		},
+	},
+	{
+		`<form>
+			<label>Username <input type="text" name="username" /></label>
+			<label>Password <input type="password" name="password" /></label>
+			<label>Country
+				<select name="country">
+					<option value="ca">Canada</option>
+					<option value="us">United States</option>
+				</select>
+			</label>
+			<label>Bio <textarea name="bio"></textarea></label>
+			<button>Sign up</button>
+		</form>`,
+		`:input`,
+		[]string{
+			`<input type="text" name="username"/>`,
+			`<input type="password" name="password"/>`,
+			`<select name="country">
+					<option value="ca">Canada</option>
+					<option value="us">United States</option>
+				</select>`,
+			`<textarea name="bio"></textarea>`,
+			`<button>Sign up</button>`,
+		},
+	},
+	{
+		`<html><head></head><body></body></html>`,
+		":root",
+		[]string{
+			"<html><head></head><body></body></html>",
+		},
+	},
+	{
+		`<html><head></head><body></body></html>`,
+		"*:root",
+		[]string{
+			"<html><head></head><body></body></html>",
+		},
+	},
+	{
+		`<html><head></head><body></body></html>`,
+		"*:root:first-child",
+		[]string{},
+	},
+	{
+		`<html><head></head><body></body></html>`,
+		"*:root:nth-child(1)",
+		[]string{},
+	},
+	{
+		`<html><head></head><body><a href="http://www.foo.com"></a></body></html>`,
+		"a:not(:root)",
+		[]string{
+			`<a href="http://www.foo.com"></a>`,
+		},
+	},
+}
+
+func TestSelectors(t *testing.T) {
+	for _, test := range selectorTests {
+		s, err := Compile(test.selector)
+		if err != nil {
+			t.Errorf("error compiling %q: %s", test.selector, err)
+			continue
+		}
+
+		doc, err := html.Parse(strings.NewReader(test.HTML))
+		if err != nil {
+			t.Errorf("error parsing %q: %s", test.HTML, err)
+			continue
+		}
+
+		matches := s.MatchAll(doc)
+		if len(matches) != len(test.results) {
+			t.Errorf("selector %s wanted %d elements, got %d instead", test.selector, len(test.results), len(matches))
+			continue
+		}
+
+		for i, m := range matches {
+			got := nodeString(m)
+			if got != test.results[i] {
+				t.Errorf("selector %s wanted %s, got %s instead", test.selector, test.results[i], got)
+			}
+		}
+
+		firstMatch := s.MatchFirst(doc)
+		if len(test.results) == 0 {
+			if firstMatch != nil {
+				t.Errorf("MatchFirst: selector %s want nil, got %s", test.selector, nodeString(firstMatch))
+			}
+		} else {
+			got := nodeString(firstMatch)
+			if got != test.results[0] {
+				t.Errorf("MatchFirst: selector %s want %s, got %s", test.selector, test.results[0], got)
+			}
+		}
+	}
+}

+ 18 - 0
vendor/github.com/azr/backoff/backoff_test.go

@@ -0,0 +1,18 @@
+package backoff
+
+import (
+	"time"
+
+	"testing"
+)
+
+func TestNextBackOffMillis(t *testing.T) {
+	new(ZeroBackOff).BackOff()
+}
+
+func TestConstantBackOff(t *testing.T) {
+	backoff := NewConstant(time.Second)
+	if backoff.Interval != time.Second {
+		t.Error("invalid interval")
+	}
+}

+ 50 - 0
vendor/github.com/azr/backoff/example_test.go

@@ -0,0 +1,50 @@
+package backoff_test
+
+import (
+	"fmt"
+	"time"
+
+	"github.com/azr/backoff"
+)
+
+func ExampleNewExponential_defaultWaitingIntervals() {
+	exp := backoff.NewExponential()
+
+	for i := 0; i < 25; i++ {
+		d := exp.GetSleepTime()
+		fmt.Printf("Random duration was %2.2fs, interval: %2.2fs in [ %2.2fs , %2.2fs ]\n",
+			d.Seconds(),
+			exp.Inverval().Seconds(),
+			(exp.Inverval() - time.Duration(exp.RandomizationFactor*float64(exp.Inverval()))).Seconds(),
+			(exp.Inverval() + time.Duration(exp.RandomizationFactor*float64(exp.Inverval()))).Seconds(),
+		)
+		exp.IncrementCurrentInterval()
+		// exp.BackOff() would have executed time.Sleep(exp.GetSleepTime()) and exp.IncrementCurrentInterval()
+	}
+	// Output:
+	// Random duration was 0.51s, interval: 0.50s in [ 0.25s , 0.75s ]
+	// Random duration was 0.99s, interval: 0.75s in [ 0.38s , 1.12s ]
+	// Random duration was 0.80s, interval: 1.12s in [ 0.56s , 1.69s ]
+	// Random duration was 1.49s, interval: 1.69s in [ 0.84s , 2.53s ]
+	// Random duration was 2.07s, interval: 2.53s in [ 1.27s , 3.80s ]
+	// Random duration was 3.68s, interval: 3.80s in [ 1.90s , 5.70s ]
+	// Random duration was 4.46s, interval: 5.70s in [ 2.85s , 8.54s ]
+	// Random duration was 6.78s, interval: 8.54s in [ 4.27s , 12.81s ]
+	// Random duration was 15.11s, interval: 12.81s in [ 6.41s , 19.22s ]
+	// Random duration was 13.81s, interval: 19.22s in [ 9.61s , 28.83s ]
+	// Random duration was 20.27s, interval: 28.83s in [ 14.42s , 43.25s ]
+	// Random duration was 37.23s, interval: 43.25s in [ 21.62s , 64.87s ]
+	// Random duration was 64.24s, interval: 60.00s in [ 30.00s , 90.00s ]
+	// Random duration was 81.75s, interval: 60.00s in [ 30.00s , 90.00s ]
+	// Random duration was 47.59s, interval: 60.00s in [ 30.00s , 90.00s ]
+	// Random duration was 47.82s, interval: 60.00s in [ 30.00s , 90.00s ]
+	// Random duration was 75.15s, interval: 60.00s in [ 30.00s , 90.00s ]
+	// Random duration was 42.39s, interval: 60.00s in [ 30.00s , 90.00s ]
+	// Random duration was 81.92s, interval: 60.00s in [ 30.00s , 90.00s ]
+	// Random duration was 71.80s, interval: 60.00s in [ 30.00s , 90.00s ]
+	// Random duration was 61.43s, interval: 60.00s in [ 30.00s , 90.00s ]
+	// Random duration was 31.70s, interval: 60.00s in [ 30.00s , 90.00s ]
+	// Random duration was 39.50s, interval: 60.00s in [ 30.00s , 90.00s ]
+	// Random duration was 66.44s, interval: 60.00s in [ 30.00s , 90.00s ]
+	// Random duration was 88.51s, interval: 60.00s in [ 30.00s , 90.00s ]
+}

+ 87 - 0
vendor/github.com/azr/backoff/exponential_test.go

@@ -0,0 +1,87 @@
+package backoff
+
+import (
+	"math"
+	"testing"
+	"time"
+)
+
+func TestBackOff(t *testing.T) {
+	var (
+		testInitialInterval     = 500 * time.Millisecond
+		testRandomizationFactor = 0.1
+		testMultiplier          = 2.0
+		testMaxInterval         = 5 * time.Second
+	)
+
+	exp := NewExponential()
+	exp.InitialInterval = testInitialInterval
+	exp.RandomizationFactor = testRandomizationFactor
+	exp.Multiplier = testMultiplier
+	exp.MaxInterval = testMaxInterval
+	exp.Reset()
+
+	var expectedResults = []time.Duration{500, 1000, 2000, 4000, 5000, 5000, 5000, 5000, 5000, 5000}
+	for i, d := range expectedResults {
+		expectedResults[i] = d * time.Millisecond
+	}
+
+	for _, expected := range expectedResults {
+		assertEquals(t, expected, exp.currentInterval)
+		// Assert that the next back off falls in the expected range.
+		var minInterval = expected - time.Duration(testRandomizationFactor*float64(expected))
+		var maxInterval = expected + time.Duration(testRandomizationFactor*float64(expected))
+		var actualInterval = exp.GetSleepTime()
+		if !(minInterval <= actualInterval && actualInterval <= maxInterval) {
+			t.Error("error")
+		}
+		exp.IncrementCurrentInterval()
+	}
+}
+
+func TestGetRandomizedInterval(t *testing.T) {
+	// 33% chance of being 1.
+	assertEquals(t, 1, getRandomValueFromInterval(0.5, 0, 2))
+	assertEquals(t, 1, getRandomValueFromInterval(0.5, 0.33, 2))
+	// 33% chance of being 2.
+	assertEquals(t, 2, getRandomValueFromInterval(0.5, 0.34, 2))
+	assertEquals(t, 2, getRandomValueFromInterval(0.5, 0.66, 2))
+	// 33% chance of being 3.
+	assertEquals(t, 3, getRandomValueFromInterval(0.5, 0.67, 2))
+	assertEquals(t, 3, getRandomValueFromInterval(0.5, 0.99, 2))
+}
+
+type TestClock struct {
+	i     time.Duration
+	start time.Time
+}
+
+func (c *TestClock) Now() time.Time {
+	t := c.start.Add(c.i)
+	c.i += time.Second
+	return t
+}
+
+func TestBackOffOverflow(t *testing.T) {
+	var (
+		testInitialInterval time.Duration = math.MaxInt64 / 2
+		testMaxInterval     time.Duration = math.MaxInt64
+		testMultiplier      float64       = 2.1
+	)
+
+	exp := NewExponential()
+	exp.InitialInterval = testInitialInterval
+	exp.Multiplier = testMultiplier
+	exp.MaxInterval = testMaxInterval
+	exp.Reset()
+
+	exp.IncrementCurrentInterval()
+	// Assert that when an overflow is possible the current varerval   time.Duration    is set to the max varerval   time.Duration   .
+	assertEquals(t, testMaxInterval, exp.currentInterval)
+}
+
+func assertEquals(t *testing.T, expected, value time.Duration) {
+	if expected != value {
+		t.Errorf("got: %d, expected: %d", value, expected)
+	}
+}

+ 36 - 0
vendor/github.com/azr/backoff/linear_test.go

@@ -0,0 +1,36 @@
+package backoff
+
+import (
+	"testing"
+	"time"
+)
+
+func TestLinear(t *testing.T) {
+	bmult := NewLinear(time.Minute, 10*time.Minute, 0, 4)
+
+	bmult.increment()
+
+	if bmult.currentInterval != time.Minute*4 {
+		t.Errorf("increment did not work got %s expected %s.", bmult.currentInterval, time.Minute*2)
+	}
+
+	bincr := NewLinear(time.Minute, 10*time.Minute, time.Minute, 1)
+
+	bincr.increment()
+
+	if bincr.currentInterval != time.Minute*2 {
+		t.Errorf("increment did not work got %s expected %s.", bincr.currentInterval, time.Minute*2)
+	}
+
+	bmultincr := NewLinear(time.Minute, 10*time.Minute, time.Minute, 2)
+	bmultincr.increment()
+	if bmultincr.currentInterval != time.Minute*3 {
+		t.Errorf("increment did not work got %s expected %s.", bmultincr.currentInterval, time.Minute*3)
+	}
+
+	bmultincr.Reset()
+
+	if bmultincr.currentInterval != time.Minute {
+		t.Errorf("reset did not work got %s expected %s.", bmultincr.currentInterval, time.Minute)
+	}
+}

+ 0 - 0
vendor/github.com/hashicorp/logutils/.gitignore → vendor/github.com/davecgh/go-spew/.gitignore


+ 28 - 0
vendor/github.com/davecgh/go-spew/.travis.yml

@@ -0,0 +1,28 @@
+language: go
+go_import_path: github.com/davecgh/go-spew
+go:
+    - 1.6.x
+    - 1.7.x
+    - 1.8.x
+    - 1.9.x
+    - 1.10.x
+    - tip
+sudo: false
+install:
+    - go get -v github.com/alecthomas/gometalinter
+    - gometalinter --install
+script:
+    - export PATH=$PATH:$HOME/gopath/bin
+    - export GORACE="halt_on_error=1"
+    - test -z "$(gometalinter --disable-all
+      --enable=gofmt
+      --enable=golint
+      --enable=vet
+      --enable=gosimple
+      --enable=unconvert
+      --deadline=4m ./spew | tee /dev/stderr)"
+    - go test -v -race -tags safe ./spew
+    - go test -v -race -tags testcgo ./spew -covermode=atomic -coverprofile=profile.cov
+after_success:
+    - go get -v github.com/mattn/goveralls
+    - goveralls -coverprofile=profile.cov -service=travis-ci

+ 201 - 0
vendor/github.com/davecgh/go-spew/README.md

@@ -0,0 +1,201 @@
+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, "<!--\n" + html.EscapeString(spew.Sdump(w)) + "\n-->")
+}
+
+func main() {
+    http.HandleFunc("/", handler)
+    http.ListenAndServe(":8080", nil)
+}
+```
+
+## Sample Dump Output
+
+```
+(main.Foo) {
+ unexportedField: (*main.Bar)(0xf84002e210)({
+  flag: (main.Flag) flagTwo,
+  data: (uintptr) <nil>
+ }),
+ 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 <*><shown>}
+	 %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)<shown>}
+	 %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)<shown>}
+	%#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)<shown>}
+```
+
+## 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.

+ 22 - 0
vendor/github.com/davecgh/go-spew/cov_report.sh

@@ -0,0 +1,22 @@
+#!/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

+ 298 - 0
vendor/github.com/davecgh/go-spew/spew/common_test.go

@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+ *
+ * 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)
+}

+ 1042 - 0
vendor/github.com/davecgh/go-spew/spew/dump_test.go

@@ -0,0 +1,1042 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+ *
+ * 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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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 + ") <nil>\n}"
+	addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+	addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
+	addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
+	addDumpTest(nv3, "(*"+v3t+")(<nil>)\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+")(<nil>)\n")
+
+	// Nil slice.
+	v5 := []int(nil)
+	nv5 := (*[]int)(nil)
+	pv5 := &v5
+	v5Addr := fmt.Sprintf("%p", pv5)
+	pv5Addr := fmt.Sprintf("%p", &pv5)
+	v5t := "[]int"
+	v5s := "<nil>"
+	addDumpTest(v5, "("+v5t+") "+v5s+"\n")
+	addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n")
+	addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n")
+	addDumpTest(nv5, "(*"+v5t+")(<nil>)\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+")(<nil>)\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 := "<nil>"
+	addDumpTest(v, "("+vt+") "+vs+"\n")
+	addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+	addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+	addDumpTest(nv, "(*"+vt+")(<nil>)\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+")(<nil>)\n")
+	addDumpTest(nilMap, "("+mt+") <nil>\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+")(<nil>)\n")
+	addDumpTest(nilMap2, "("+m2t+") <nil>\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+")(<nil>)\n")
+	addDumpTest(nilMap3, "("+m3t+") <nil>\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 + ") <nil>\n}"
+	addDumpTest(m4, "("+m4t+") "+m4s+"\n")
+	addDumpTest(pm4, "(*"+m4t+")("+m4Addr+")("+m4s+")\n")
+	addDumpTest(&pm4, "(**"+m4t+")("+pm4Addr+"->"+m4Addr+")("+m4s+")\n")
+	addDumpTest(nm4, "(*"+m4t+")(<nil>)\n")
+	addDumpTest(nilMap4, "("+m4t+") <nil>\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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\n")
+}
+
+func addUintptrDumpTests() {
+	// Null pointer.
+	v := uintptr(0)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "uintptr"
+	vs := "<nil>"
+	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+")(<nil>)\n")
+}
+
+func addUnsafePointerDumpTests() {
+	// Null pointer.
+	v := unsafe.Pointer(nil)
+	nv := (*unsafe.Pointer)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "unsafe.Pointer"
+	vs := "<nil>"
+	addDumpTest(v, "("+vt+") "+vs+"\n")
+	addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+	addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+	addDumpTest(nv, "(*"+vt+")(<nil>)\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+")(<nil>)\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 := "<nil>"
+	addDumpTest(v, "("+vt+") "+vs+"\n")
+	addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+	addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+	addDumpTest(nv, "(*"+vt+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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+")(<nil>)\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 + ")(<already shown>)\n })\n}"
+	vs2 := "{\n c: (*" + vt + ")(" + vAddr + ")(<already shown>)\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 +
+		")(<already shown>)\n  })\n })\n}"
+	v2s2 := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n  ps1: (*" + v2t +
+		")(" + v2Addr + ")(<already shown>)\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 +
+		")(<already shown>)\n   })\n  })\n })\n}"
+	v3s2 := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n  ps3: (*" + v3t3 +
+		")(" + tic3Addr + ")({\n   ps1: (*" + v3t + ")(" + v3Addr +
+		")(<already shown>)\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+")(<nil>)\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+")(<nil>)\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)
+	}
+
+}

+ 101 - 0
vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go

@@ -0,0 +1,101 @@
+// Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+//
+// 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+")(<nil>)\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"
+	v5t2 := "[6]testdata._Ctype_uchar"
+	v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " +
+		"{\n 00000000  74 65 73 74 35 00                               " +
+		"  |test5.|\n}"
+	addDumpTest(v5, "("+v5t+") "+v5s+"\n", "("+v5t2+") "+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"
+	v6t2 := "[6]testdata._Ctype_uchar"
+	v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " +
+		"{\n 00000000  74 65 73 74 36 00                               " +
+		"  |test6.|\n}"
+	addDumpTest(v6, "("+v6t+") "+v6s+"\n", "("+v6t2+") "+v6s+"\n")
+}

+ 26 - 0
vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go

@@ -0,0 +1,26 @@
+// Copyright (c) 2013 Dave Collins <dave@davec.name>
+//
+// 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.
+}

+ 226 - 0
vendor/github.com/davecgh/go-spew/spew/example_test.go

@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+ *
+ * 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) <nil>
+	//  },
+	//  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 <*><shown>}}
+}
+
+// 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) <nil>
+	// 	},
+	// 	ExportedField: (map[interface {}]interface {}) (len=1) {
+	//		(string) (len=3) "one": (bool) true
+	// 	}
+	// }
+	// (spew_test.Foo) {
+	//  unexportedField: (spew_test.Bar) {
+	//   data: (uintptr) <nil>
+	//  },
+	//  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
+}

+ 1558 - 0
vendor/github.com/davecgh/go-spew/spew/format_test.go

@@ -0,0 +1,1558 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+ *
+ * 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, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+	addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v3, v3s)
+	addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+	addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%#v", v3, "("+v3t+")"+v3s)
+	addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s)
+	addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s)
+	addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+	addFormatterTest("%#+v", v3, "("+v3t+")"+v3s)
+	addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s)
+	addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v4, v4s)
+	addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
+	addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
+	addFormatterTest("%+v", nv4, "<nil>")
+	addFormatterTest("%#v", v4, "("+v4t+")"+v4s)
+	addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s)
+	addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s)
+	addFormatterTest("%#v", nv4, "(*"+v4t+")"+"<nil>")
+	addFormatterTest("%#+v", v4, "("+v4t+")"+v4s)
+	addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s)
+	addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s)
+	addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v5, v5s)
+	addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s)
+	addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s)
+	addFormatterTest("%+v", nv5, "<nil>")
+	addFormatterTest("%#v", v5, "("+v5t+")"+v5s)
+	addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s)
+	addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s)
+	addFormatterTest("%#v", nv5, "(*"+v5t+")"+"<nil>")
+	addFormatterTest("%#+v", v5, "("+v5t+")"+v5s)
+	addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s)
+	addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s)
+	addFormatterTest("%#+v", nv5, "(*"+v5t+")"+"<nil>")
+}
+
+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, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+	addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v3, v3s)
+	addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+	addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%#v", v3, "("+v3t+")"+v3s)
+	addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s)
+	addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s)
+	addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+	addFormatterTest("%#+v", v3, "("+v3t+")"+v3s)
+	addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s)
+	addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v4, v4s)
+	addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
+	addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
+	addFormatterTest("%+v", nv4, "<nil>")
+	addFormatterTest("%#v", v4, "("+v4t+")"+v4s)
+	addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s)
+	addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s)
+	addFormatterTest("%#v", nv4, "(*"+v4t+")"+"<nil>")
+	addFormatterTest("%#+v", v4, "("+v4t+")"+v4s)
+	addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s)
+	addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s)
+	addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v5, v5s)
+	addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s)
+	addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s)
+	addFormatterTest("%+v", nv5, "<nil>")
+	addFormatterTest("%#v", v5, "("+v5t+")"+v5s)
+	addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s)
+	addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s)
+	addFormatterTest("%#v", nv5, "(*"+v5t+")"+"<nil>")
+	addFormatterTest("%#+v", v5, "("+v5t+")"+v5s)
+	addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s)
+	addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s)
+	addFormatterTest("%#v", nv5, "(*"+v5t+")"+"<nil>")
+}
+
+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, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+	addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+}
+
+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, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+	addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+}
+
+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, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2sp)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2sp)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2sp)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2sp)
+	addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2sp)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2sp)
+	addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v3, v3s)
+	addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+	addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%#v", v3, "("+v3t+")"+v3s2)
+	addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2)
+	addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2)
+	addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+	addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2)
+	addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2)
+	addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2)
+	addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"<nil>")
+}
+
+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, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+	addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+
+	// 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 <nil>]"
+	v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3 (" + v3t5 +
+		")<nil>]"
+	addFormatterTest("%v", v3, v3s)
+	addFormatterTest("%v", pv3, "<*>"+v3s)
+	addFormatterTest("%v", &pv3, "<**>"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%+v", v3, v3s)
+	addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+	addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%#v", v3, "("+v3t+")"+v3s2)
+	addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2)
+	addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2)
+	addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+	addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2)
+	addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2)
+	addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2)
+	addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"<nil>")
+
+	// Nil slice.
+	var v4 []int
+	nv4 := (*[]int)(nil)
+	pv4 := &v4
+	v4Addr := fmt.Sprintf("%p", pv4)
+	pv4Addr := fmt.Sprintf("%p", &pv4)
+	v4t := "[]int"
+	v4s := "<nil>"
+	addFormatterTest("%v", v4, v4s)
+	addFormatterTest("%v", pv4, "<*>"+v4s)
+	addFormatterTest("%v", &pv4, "<**>"+v4s)
+	addFormatterTest("%+v", nv4, "<nil>")
+	addFormatterTest("%+v", v4, v4s)
+	addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
+	addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
+	addFormatterTest("%+v", nv4, "<nil>")
+	addFormatterTest("%#v", v4, "("+v4t+")"+v4s)
+	addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s)
+	addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s)
+	addFormatterTest("%#v", nv4, "(*"+v4t+")"+"<nil>")
+	addFormatterTest("%#+v", v4, "("+v4t+")"+v4s)
+	addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s)
+	addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s)
+	addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"<nil>")
+}
+
+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, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+}
+
+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 := "<nil>"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs, vs2)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs, "<*>("+vAddr+")"+vs2)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs,
+		"<**>("+pvAddr+"->"+vAddr+")"+vs2)
+	addFormatterTest("%+v", nilMap, "<nil>")
+	addFormatterTest("%+v", nv, "<nil>")
+	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+")"+"<nil>")
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	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+")"+"<nil>")
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+	addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v3, v3s)
+	addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+	addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%#v", v3, "("+v3t+")"+v3s2)
+	addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2)
+	addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2)
+	addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+	addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2)
+	addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2)
+	addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2)
+	addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"<nil>")
+
+	// 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:<nil>]"
+	v4s2 := "map[nil:(" + v4t1 + ")<nil>]"
+	addFormatterTest("%v", v4, v4s)
+	addFormatterTest("%v", pv4, "<*>"+v4s)
+	addFormatterTest("%v", &pv4, "<**>"+v4s)
+	addFormatterTest("%+v", nv4, "<nil>")
+	addFormatterTest("%+v", v4, v4s)
+	addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
+	addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
+	addFormatterTest("%+v", nv4, "<nil>")
+	addFormatterTest("%#v", v4, "("+v4t+")"+v4s2)
+	addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s2)
+	addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s2)
+	addFormatterTest("%#v", nv4, "(*"+v4t+")"+"<nil>")
+	addFormatterTest("%#+v", v4, "("+v4t+")"+v4s2)
+	addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s2)
+	addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s2)
+	addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"<nil>")
+}
+
+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, "<nil>")
+	addFormatterTest("%+v", v, vs2)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs2)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs2)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs3)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs3)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs3)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs3)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs3)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs3)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v2, v2s2)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s2)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s2)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s3)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s3)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s3)
+	addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s3)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s3)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s3)
+	addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v3, v3s2)
+	addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s2p)
+	addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s2p)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%#v", v3, "("+v3t+")"+v3s3)
+	addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s3p)
+	addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s3p)
+	addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+	addFormatterTest("%#+v", v3, "("+v3t+")"+v3s3)
+	addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s3p)
+	addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s3p)
+	addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v4, v4s2)
+	addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s2)
+	addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s2)
+	addFormatterTest("%+v", nv4, "<nil>")
+	addFormatterTest("%#v", v4, "("+v4t+")"+v4s3)
+	addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s3)
+	addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s3)
+	addFormatterTest("%#v", nv4, "(*"+v4t+")"+"<nil>")
+	addFormatterTest("%#+v", v4, "("+v4t+")"+v4s4)
+	addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s4)
+	addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s4)
+	addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"<nil>")
+}
+
+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 := "<nil>"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// 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(nil)
+	nv := (*unsafe.Pointer)(nil)
+	pv := &v
+	vAddr := fmt.Sprintf("%p", pv)
+	pvAddr := fmt.Sprintf("%p", &pv)
+	vt := "unsafe.Pointer"
+	vs := "<nil>"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// 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 := "<nil>"
+	addFormatterTest("%v", v, vs)
+	addFormatterTest("%v", pv, "<*>"+vs)
+	addFormatterTest("%v", &pv, "<**>"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v2, v2s)
+	addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+	addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%+v", nv2, "<nil>")
+	addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+	addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+	addFormatterTest("%#v", nv2, "(*"+v2t+")"+"<nil>")
+	addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+	addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+	addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"<nil>")
+
+	// 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, "<nil>")
+	addFormatterTest("%+v", v3, v3s)
+	addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+	addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%+v", nv3, "<nil>")
+	addFormatterTest("%#v", v3, "("+v3t+")"+v3s)
+	addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s)
+	addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s)
+	addFormatterTest("%#v", nv3, "(*"+v3t+")"+"<nil>")
+	addFormatterTest("%#+v", v3, "("+v3t+")"+v3s)
+	addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s)
+	addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s)
+	addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"<nil>")
+}
+
+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 := "{<*>{<*><shown>}}"
+	vs2 := "{<*><shown>}"
+	vs3 := "{c:<*>(" + vAddr + "){c:<*>(" + vAddr + ")<shown>}}"
+	vs4 := "{c:<*>(" + vAddr + ")<shown>}"
+	vs5 := "{c:(*" + vt + "){c:(*" + vt + ")<shown>}}"
+	vs6 := "{c:(*" + vt + ")<shown>}"
+	vs7 := "{c:(*" + vt + ")(" + vAddr + "){c:(*" + vt + ")(" + vAddr +
+		")<shown>}}"
+	vs8 := "{c:(*" + vt + ")(" + vAddr + ")<shown>}"
+	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 := "{<*>{<*>{<*><shown>}}}"
+	v2s2 := "{<*>{<*><shown>}}"
+	v2s3 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + "){ps2:<*>(" +
+		ts2Addr + ")<shown>}}}"
+	v2s4 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + ")<shown>}}"
+	v2s5 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + "){ps2:(*" + v2t2 +
+		")<shown>}}}"
+	v2s6 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + ")<shown>}}"
+	v2s7 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t +
+		")(" + v2Addr + "){ps2:(*" + v2t2 + ")(" + ts2Addr +
+		")<shown>}}}"
+	v2s8 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t +
+		")(" + v2Addr + ")<shown>}}"
+	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 := "{<*>{<*>{<*>{<*><shown>}}}}"
+	v3s2 := "{<*>{<*>{<*><shown>}}}"
+	v3s3 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" +
+		v3Addr + "){ps2:<*>(" + tic2Addr + ")<shown>}}}}"
+	v3s4 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" +
+		v3Addr + ")<shown>}}}"
+	v3s5 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t +
+		"){ps2:(*" + v3t2 + ")<shown>}}}}"
+	v3s6 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t +
+		")<shown>}}}"
+	v3s7 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" +
+		tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + "){ps2:(*" + v3t2 +
+		")(" + tic2Addr + ")<shown>}}}}"
+	v3s8 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" +
+		tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + ")<shown>}}}"
+	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, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+}
+
+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, "<nil>")
+	addFormatterTest("%+v", v, vs)
+	addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+	addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%+v", nv, "<nil>")
+	addFormatterTest("%#v", v, "("+vt+")"+vs)
+	addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+	addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+	addFormatterTest("%#v", nv, "(*"+vt+")"+"<nil>")
+	addFormatterTest("%#+v", v, "("+vt+")"+vs)
+	addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+	addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+	addFormatterTest("%#+v", nv, "(*"+vt+")"+"<nil>")
+}
+
+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{{1}: 1, {3}: 3, {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{{1}: 1, {3}: 3, {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)
+	}
+}

+ 84 - 0
vendor/github.com/davecgh/go-spew/spew/internal_test.go

@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+ *
+ * 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 {
+	return f == int('+')
+}
+
+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 := "<invalid>"
+	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 = "<invalid>"
+	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)
+}

+ 101 - 0
vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go

@@ -0,0 +1,101 @@
+// Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+
+// 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,go1.4
+
+/*
+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"
+)
+
+// 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) {
+	flags := flagField(v)
+	if readOnly {
+		*flags |= flagRO
+	} else {
+		*flags &^= flagRO
+	}
+	*flags |= flagKindMask
+}
+
+// TestAddedReflectValue tests functionaly of the dump and formatter code which
+// falls back to the standard fmt library for new types that might get added to
+// the language.
+func TestAddedReflectValue(t *testing.T) {
+	i := 1
+
+	// Dump using a reflect.Value that is exported.
+	v := reflect.ValueOf(int8(5))
+	changeKind(&v, false)
+	buf := new(bytes.Buffer)
+	d := dumpState{w: buf, cs: &Config}
+	d.dump(v)
+	s := buf.String()
+	want := "(int8) 5"
+	if s != want {
+		t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
+	}
+	i++
+
+	// Dump using a reflect.Value that is not exported.
+	changeKind(&v, true)
+	buf.Reset()
+	d.dump(v)
+	s = buf.String()
+	want = "(int8) <int8 Value>"
+	if s != want {
+		t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
+	}
+	i++
+
+	// Formatter using a reflect.Value that is exported.
+	changeKind(&v, false)
+	buf2 := new(dummyFmtState)
+	f := formatState{value: v, cs: &Config, fs: buf2}
+	f.format(v)
+	s = buf2.String()
+	want = "5"
+	if s != want {
+		t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
+	}
+	i++
+
+	// Formatter using a reflect.Value that is not exported.
+	changeKind(&v, true)
+	buf2.Reset()
+	f = formatState{value: v, cs: &Config, fs: buf2}
+	f.format(v)
+	s = buf2.String()
+	want = "<int8 Value>"
+	if s != want {
+		t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
+	}
+}

+ 320 - 0
vendor/github.com/davecgh/go-spew/spew/spew_test.go

@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
+ *
+ * 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, "{{<max>} [<max>] [<max>] map[<max>]}"},
+		{scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" +
+			" ic: (spew_test.indirCir1) {\n  <max depth reached>\n },\n" +
+			" arr: ([1]string) (len=1 cap=1) {\n  <max depth reached>\n },\n" +
+			" slice: ([]string) (len=1 cap=1) {\n  <max depth reached>\n },\n" +
+			" m: (map[string]int) (len=1) {\n  <max depth reached>\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
+		}
+	}
+}

+ 61 - 0
vendor/github.com/davecgh/go-spew/test_coverage.txt

@@ -0,0 +1,61 @@
+
+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)
+

+ 647 - 0
vendor/github.com/dustin/go-jsonpointer/bytes_test.go

@@ -0,0 +1,647 @@
+package jsonpointer
+
+import (
+	"compress/gzip"
+	"io/ioutil"
+	"math/rand"
+	"os"
+	"reflect"
+	"strings"
+	"testing"
+	"testing/quick"
+
+	"github.com/dustin/gojson"
+)
+
+var ptests = []struct {
+	path string
+	exp  interface{}
+}{
+	{"/foo", []interface{}{"bar", "baz"}},
+	{"/foo/0", "bar"},
+	{"/", 0.0},
+	{"/a~1b", 1.0},
+	{"/c%d", 2.0},
+	{"/e^f", 3.0},
+	{"/g|h", 4.0},
+	{"/i\\j", 5.0},
+	{"/k\"l", 6.0},
+	{"/ ", 7.0},
+	{"/m~0n", 8.0},
+	{"/g~1n~1r", "has slash, will travel"},
+	{"/g/n/r", "where's tito?"},
+}
+
+func TestFindDecode(t *testing.T) {
+	in := []byte(objSrc)
+
+	var fl float64
+	if err := FindDecode(in, "/g|h", &fl); err != nil {
+		t.Errorf("Failed to decode /g|h: %v", err)
+	}
+	if fl != 4.0 {
+		t.Errorf("Expected 4.0 at /g|h, got %v", fl)
+	}
+
+	fl = 0
+	if err := FindDecode(in, "/z", &fl); err == nil {
+		t.Errorf("Expected failure to decode /z: got %v", fl)
+	}
+
+	if err := FindDecode([]byte(`{"a": 1.x35}`), "/a", &fl); err == nil {
+		t.Errorf("Expected failure, got %v", fl)
+	}
+}
+
+func TestListPointers(t *testing.T) {
+	got, err := ListPointers(nil)
+	if err == nil {
+		t.Errorf("Expected error on nil input, got %v", got)
+	}
+	got, err = ListPointers([]byte(`{"x": {"y"}}`))
+	if err == nil {
+		t.Errorf("Expected error on broken input, got %v", got)
+	}
+	got, err = ListPointers([]byte(objSrc))
+	if err != nil {
+		t.Fatalf("Error getting list of pointers: %v", err)
+	}
+
+	exp := []string{"", "/foo", "/foo/0", "/foo/1", "/", "/a~1b",
+		"/c%d", "/e^f", "/g|h", "/i\\j", "/k\"l", "/ ", "/m~0n",
+		"/g~1n~1r", "/g", "/g/n", "/g/n/r",
+	}
+
+	if !reflect.DeepEqual(exp, got) {
+		t.Fatalf("Expected\n%#v\ngot\n%#v", exp, got)
+	}
+}
+
+func TestPointerRoot(t *testing.T) {
+	got, err := Find([]byte(objSrc), "")
+	if err != nil {
+		t.Fatalf("Error finding root: %v", err)
+	}
+	if !reflect.DeepEqual([]byte(objSrc), got) {
+		t.Fatalf("Error finding root, found\n%s\n, wanted\n%s",
+			got, objSrc)
+	}
+}
+
+func TestPointerManyRoot(t *testing.T) {
+	got, err := FindMany([]byte(objSrc), []string{""})
+	if err != nil {
+		t.Fatalf("Error finding root: %v", err)
+	}
+	if !reflect.DeepEqual([]byte(objSrc), got[""]) {
+		t.Fatalf("Error finding root, found\n%s\n, wanted\n%s",
+			got, objSrc)
+	}
+}
+
+func TestPointerManyBroken(t *testing.T) {
+	got, err := FindMany([]byte(`{"a": {"b": "something}}`), []string{"/a/b"})
+	if err == nil {
+		t.Errorf("Expected error parsing broken JSON, got %v", got)
+	}
+}
+
+func TestPointerMissing(t *testing.T) {
+	got, err := Find([]byte(objSrc), "/missing")
+	if err != nil {
+		t.Fatalf("Error finding missing item: %v", err)
+	}
+	if got != nil {
+		t.Fatalf("Expected nil looking for /missing, got %v",
+			got)
+	}
+}
+
+func TestManyPointers(t *testing.T) {
+	pointers := []string{}
+	exp := map[string]interface{}{}
+	for _, test := range ptests {
+		pointers = append(pointers, test.path)
+		exp[test.path] = test.exp
+	}
+
+	rv, err := FindMany([]byte(objSrc), pointers)
+	if err != nil {
+		t.Fatalf("Error finding many: %v", err)
+	}
+
+	got := map[string]interface{}{}
+	for k, v := range rv {
+		var val interface{}
+		err = json.Unmarshal(v, &val)
+		if err != nil {
+			t.Fatalf("Error unmarshaling %s: %v", v, err)
+		}
+		got[k] = val
+	}
+
+	if !reflect.DeepEqual(got, exp) {
+		for k, v := range exp {
+			if !reflect.DeepEqual(got[k], v) {
+				t.Errorf("At %v, expected %#v, got %#v", k, v, got[k])
+			}
+		}
+		t.Fail()
+	}
+}
+
+func TestManyPointersMissing(t *testing.T) {
+	got, err := FindMany([]byte(objSrc), []string{"/missing"})
+	if err != nil {
+		t.Fatalf("Error finding missing item: %v", err)
+	}
+	if len(got) != 0 {
+		t.Fatalf("Expected empty looking for many /missing, got %v",
+			got)
+	}
+}
+
+var badDocs = [][]byte{
+	[]byte{}, []byte(" "), nil,
+	[]byte{'{'}, []byte{'['},
+	[]byte{'}'}, []byte{']'},
+}
+
+func TestManyPointersBadDoc(t *testing.T) {
+	for _, b := range badDocs {
+		got, _ := FindMany(b, []string{"/broken"})
+		if len(got) > 0 {
+			t.Errorf("Expected failure on %v, got %v", b, got)
+		}
+	}
+}
+
+func TestPointersBadDoc(t *testing.T) {
+	for _, b := range badDocs {
+		got, _ := Find(b, "/broken")
+		if len(got) > 0 {
+			t.Errorf("Expected failure on %s, got %v", b, got)
+		}
+	}
+}
+
+func TestPointer(t *testing.T) {
+
+	for _, test := range ptests {
+		got, err := Find([]byte(objSrc), test.path)
+		var val interface{}
+		if err == nil {
+			err = json.Unmarshal([]byte(got), &val)
+		}
+		if err != nil {
+			t.Errorf("Got an error on key %v: %v", test.path, err)
+		} else if !reflect.DeepEqual(val, test.exp) {
+			t.Errorf("On %#v, expected %+v (%T), got %+v (%T)",
+				test.path, test.exp, test.exp, val, val)
+		} else {
+			t.Logf("Success - got %s for %#v", got, test.path)
+		}
+	}
+}
+
+func TestPointerCoder(t *testing.T) {
+	tests := map[string][]string{
+		"/":        []string{""},
+		"/a":       []string{"a"},
+		"/a~1b":    []string{"a/b"},
+		"/m~0n":    []string{"m~n"},
+		"/ ":       []string{" "},
+		"/g~1n~1r": []string{"g/n/r"},
+		"/g/n/r":   []string{"g", "n", "r"},
+	}
+
+	for k, v := range tests {
+		parsed := parsePointer(k)
+		encoded := encodePointer(v)
+
+		if k != encoded {
+			t.Errorf("Expected to encode %#v as %#v, got %#v",
+				v, k, encoded)
+		}
+		if !arreq(v, parsed) {
+			t.Errorf("Expected to decode %#v as %#v, got %#v",
+				k, v, parsed)
+		}
+	}
+}
+
+func TestCBugg406(t *testing.T) {
+	data, err := ioutil.ReadFile("testdata/pools.json")
+	if err != nil {
+		t.Fatalf("Error reading pools data: %v", err)
+	}
+
+	found, err := Find(data, "/implementationVersion")
+	if err != nil {
+		t.Fatalf("Failed to find thing: %v", err)
+	}
+	exp := ` "2.0.0-1976-rel-enterprise"`
+	if string(found) != exp {
+		t.Fatalf("Expected %q, got %q", exp, found)
+	}
+}
+
+func BenchmarkEncodePointer(b *testing.B) {
+	aPath := []string{"a", "ab", "a~0b", "a~1b", "a~0~1~0~1b"}
+	for i := 0; i < b.N; i++ {
+		encodePointer(aPath)
+	}
+}
+
+func BenchmarkAll(b *testing.B) {
+	obj := []byte(objSrc)
+	for i := 0; i < b.N; i++ {
+		for _, test := range tests {
+			Find(obj, test.path)
+		}
+	}
+}
+
+func BenchmarkManyPointer(b *testing.B) {
+	pointers := []string{}
+	for _, test := range ptests {
+		pointers = append(pointers, test.path)
+	}
+	obj := []byte(objSrc)
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		FindMany(obj, pointers)
+	}
+}
+
+func TestMustParseInt(t *testing.T) {
+	tests := map[string]bool{
+		"":   true,
+		"0":  false,
+		"13": false,
+	}
+
+	for in, out := range tests {
+		var panicked bool
+		func() {
+			defer func() {
+				panicked = recover() != nil
+			}()
+			mustParseInt(in)
+			if panicked != out {
+				t.Logf("Expected panicked=%v", panicked)
+			}
+		}()
+	}
+}
+
+func TestFindBrokenJSON(t *testing.T) {
+	x, err := Find([]byte(`{]`), "/foo/x")
+	if err == nil {
+		t.Errorf("Expected error, got %q", x)
+	}
+}
+
+func TestGrokLiteral(t *testing.T) {
+	brokenStr := "---broken---"
+	tests := []struct {
+		in  []byte
+		exp string
+	}{
+		{[]byte(`"simple"`), "simple"},
+		{[]byte(`"has\nnewline"`), "has\nnewline"},
+		{[]byte(`"broken`), brokenStr},
+	}
+
+	for _, test := range tests {
+		var got string
+		func() {
+			defer func() {
+				if e := recover(); e != nil {
+					got = brokenStr
+				}
+			}()
+			got = grokLiteral(test.in)
+		}()
+		if test.exp != got {
+			t.Errorf("Expected %q for %s, got %q",
+				test.exp, test.in, got)
+		}
+	}
+}
+
+func TestSerieslySample(t *testing.T) {
+	data, err := ioutil.ReadFile("testdata/serieslysample.json")
+	if err != nil {
+		t.Fatalf("Error opening sample file: %v", err)
+	}
+
+	tests := []struct {
+		pointer string
+		exp     string
+	}{
+		{"/kind", "Listing"},
+		{"/data/children/0/data/id", "w568e"},
+		{"/data/children/0/data/name", "t3_w568e"},
+	}
+
+	for _, test := range tests {
+		var found string
+		err := FindDecode(data, test.pointer, &found)
+		if err != nil {
+			t.Errorf("Error on %v: %v", test.pointer, err)
+		}
+		if found != test.exp {
+			t.Errorf("Expected %q, got %q", test.exp, found)
+		}
+	}
+}
+
+func TestSerieslySampleMany(t *testing.T) {
+	data, err := ioutil.ReadFile("testdata/serieslysample.json")
+	if err != nil {
+		t.Fatalf("Error opening sample file: %v", err)
+	}
+
+	keys := []string{"/kind", "/data/children/0/data/id", "/data/children/0/data/name"}
+	exp := []string{` "Listing"`, ` "w568e"`, ` "t3_w568e"`}
+
+	found, err := FindMany(data, keys)
+	if err != nil {
+		t.Fatalf("Error in FindMany: %v", err)
+	}
+
+	for i, k := range keys {
+		if string(found[k]) != exp[i] {
+			t.Errorf("Expected %q on %q, got %q", exp[i], k, found[k])
+		}
+	}
+}
+
+func TestSerieslySampleList(t *testing.T) {
+	data, err := ioutil.ReadFile("testdata/serieslysample.json")
+	if err != nil {
+		t.Fatalf("Error opening sample file: %v", err)
+	}
+
+	pointers, err := ListPointers(data)
+	if err != nil {
+		t.Fatalf("Error listing pointers: %v", err)
+	}
+	exp := 932
+	if len(pointers) != exp {
+		t.Fatalf("Expected %v pointers, got %v", exp, len(pointers))
+	}
+}
+
+func Test357ListPointers(t *testing.T) {
+	data, err := ioutil.ReadFile("testdata/357.json")
+	if err != nil {
+		t.Fatalf("Error beer-sample brewery 357 data: %v", err)
+	}
+
+	exp := []string{"", "/name", "/city", "/state", "/code",
+		"/country", "/phone", "/website", "/type", "/updated",
+		"/description",
+		"/address", "/address/0", "/address2",
+		"/address2/0", "/address3", "/address3/0"}
+
+	got, err := ListPointers(data)
+	if err != nil {
+		t.Fatalf("error listing pointers: %v", err)
+	}
+	if !reflect.DeepEqual(exp, got) {
+		t.Fatalf("Expected\n%#v\ngot\n%#v", exp, got)
+	}
+}
+
+func TestEscape(t *testing.T) {
+	tests := []string{
+		"/", "~1", "~0", "/~1", "/~1/",
+	}
+
+	for _, test := range tests {
+		esc := string(escape(test, nil))
+		got := unescape(esc)
+		if got != test {
+			t.Errorf("unescape(escape(%q) [%q]) = %q", test, esc, got)
+		}
+	}
+
+	tf := func(s chars) bool {
+		uns := unescape(string(s))
+		got := string(escape(uns, nil))
+		return got == string(s)
+	}
+	quick.Check(tf, nil)
+}
+
+func TestUnescape(t *testing.T) {
+	tests := []struct {
+		in, exp string
+	}{
+		{"", ""},
+		{"/", "/"},
+		{"/thing", "/thing"},
+		{"~0", "~"},
+		{"~1", "/"},
+		{"~2", "~2"},
+		{"~", "~"},
+		{"thing~", "thing~"},
+	}
+	for _, test := range tests {
+		got := string(unescape(test.in))
+		if got != test.exp {
+			t.Errorf("on %q, got %q, wanted %q", test.in, got, test.exp)
+		}
+	}
+}
+
+var codeJSON []byte
+
+func init() {
+	f, err := os.Open("testdata/code.json.gz")
+	if err != nil {
+		panic(err)
+	}
+	defer f.Close()
+	gz, err := gzip.NewReader(f)
+	if err != nil {
+		panic(err)
+	}
+	data, err := ioutil.ReadAll(gz)
+	if err != nil {
+		panic(err)
+	}
+
+	codeJSON = data
+}
+
+func BenchmarkLarge3Key(b *testing.B) {
+	keys := []string{
+		"/tree/kids/0/kids/0/name",
+		"/tree/kids/0/name",
+		"/tree/kids/0/kids/0/kids/0/kids/0/kids/0/name",
+	}
+	b.SetBytes(int64(len(codeJSON)))
+
+	for i := 0; i < b.N; i++ {
+		found, err := FindMany(codeJSON, keys)
+		if err != nil || len(found) != 3 {
+			b.Fatalf("Didn't find all the things from %v/%v",
+				found, err)
+		}
+	}
+}
+
+func BenchmarkLargeShallow(b *testing.B) {
+	keys := []string{
+		"/tree/kids/0/kids/0/kids/1/kids/1/kids/3/name",
+	}
+	b.SetBytes(int64(len(codeJSON)))
+
+	for i := 0; i < b.N; i++ {
+		found, err := FindMany(codeJSON, keys)
+		if err != nil || len(found) != 1 {
+			b.Fatalf("Didn't find all the things: %v/%v",
+				found, err)
+		}
+	}
+}
+
+func BenchmarkLargeMissing(b *testing.B) {
+	keys := []string{
+		"/this/does/not/exist",
+	}
+	b.SetBytes(int64(len(codeJSON)))
+
+	for i := 0; i < b.N; i++ {
+		found, err := FindMany(codeJSON, keys)
+		if err != nil || len(found) != 0 {
+			b.Fatalf("Didn't find all the things: %v/%v",
+				found, err)
+		}
+	}
+}
+
+func BenchmarkLargeIdentity(b *testing.B) {
+	keys := []string{
+		"",
+	}
+	b.SetBytes(int64(len(codeJSON)))
+
+	for i := 0; i < b.N; i++ {
+		found, err := FindMany(codeJSON, keys)
+		if err != nil || len(found) != 1 {
+			b.Fatalf("Didn't find all the things: %v/%v",
+				found, err)
+		}
+	}
+}
+
+func BenchmarkLargeBest(b *testing.B) {
+	keys := []string{
+		"/tree/name",
+	}
+	b.SetBytes(int64(len(codeJSON)))
+
+	for i := 0; i < b.N; i++ {
+		found, err := FindMany(codeJSON, keys)
+		if err != nil || len(found) != 1 {
+			b.Fatalf("Didn't find all the things: %v/%v",
+				found, err)
+		}
+	}
+}
+
+const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01233456789/~."
+
+type chars string
+
+func (c chars) Generate(rand *rand.Rand, _ int) reflect.Value {
+	size := rand.Intn(128)
+	var o []byte
+	for i := 0; i < size; i++ {
+		o = append(o, alphabet[rand.Intn(len(alphabet))])
+	}
+	s := chars(escape(string(o), nil))
+	return reflect.ValueOf(s)
+}
+
+// unescape unescapes a tilde escaped string.
+//
+// It's dumb looking, but it benches faster than strings.NewReplacer
+func oldunescape(s string) string {
+	return strings.Replace(strings.Replace(s, "~1", "/", -1), "~0", "~", -1)
+}
+
+func TestNewEscaper(t *testing.T) {
+	of := func(in chars) string {
+		return oldunescape(string(in))
+	}
+	nf := func(in chars) string {
+		return unescape(string(in))
+	}
+	if err := quick.CheckEqual(of, nf, nil); err != nil {
+		t.Errorf("quickcheck failure: %v", err)
+	}
+}
+
+func BenchmarkLargeMap(b *testing.B) {
+	keys := []string{
+		"/tree/kids/0/kids/0/kids/0/kids/0/kids/0/name",
+	}
+	b.SetBytes(int64(len(codeJSON)))
+
+	for i := 0; i < b.N; i++ {
+		m := map[string]interface{}{}
+		err := json.Unmarshal(codeJSON, &m)
+		if err != nil {
+			b.Fatalf("Error parsing JSON: %v", err)
+		}
+		Get(m, keys[0])
+	}
+}
+
+const (
+	tildeTestKey = "/name~0contained"
+	slashTestKey = "/name~1contained"
+	twoTestKey   = "/name~1cont~0ned"
+)
+
+func testDoubleReplacer(s string) string {
+	return unescape(s)
+}
+
+func BenchmarkReplacerSlash(b *testing.B) {
+	r := strings.NewReplacer("~1", "/", "~0", "~")
+	for i := 0; i < b.N; i++ {
+		r.Replace(slashTestKey)
+	}
+}
+
+func BenchmarkReplacerTilde(b *testing.B) {
+	r := strings.NewReplacer("~1", "/", "~0", "~")
+	for i := 0; i < b.N; i++ {
+		r.Replace(tildeTestKey)
+	}
+}
+
+func BenchmarkDblReplacerSlash(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		testDoubleReplacer(slashTestKey)
+	}
+}
+
+func BenchmarkDblReplacerTilde(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		testDoubleReplacer(tildeTestKey)
+	}
+}
+
+func BenchmarkDblReplacerTwo(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		testDoubleReplacer(twoTestKey)
+	}
+}

+ 177 - 0
vendor/github.com/dustin/go-jsonpointer/map_test.go

@@ -0,0 +1,177 @@
+package jsonpointer
+
+import (
+	"io/ioutil"
+	"reflect"
+	"testing"
+
+	"github.com/dustin/gojson"
+)
+
+const objSrc = `{
+      "foo": ["bar", "baz"],
+      "": 0,
+      "a/b": 1,
+      "c%d": 2,
+      "e^f": 3,
+      "g|h": 4,
+      "i\\j": 5,
+      "k\"l": 6,
+      " ": 7,
+      "m~n": 8,
+      "g/n/r": "has slash, will travel",
+      "g": { "n": {"r": "where's tito?"}}
+}`
+
+var obj = map[string]interface{}{}
+
+var tests = []struct {
+	path string
+	exp  interface{}
+}{
+	{"", obj},
+	{"/foo", []interface{}{"bar", "baz"}},
+	{"/foo/0", "bar"},
+	{"/foo/99", nil},
+	{"/foo/0/3", nil},
+	{"/", 0.0},
+	{"/a~1b", 1.0},
+	{"/c%d", 2.0},
+	{"/e^f", 3.0},
+	{"/g|h", 4.0},
+	{"/i\\j", 5.0},
+	{"/k\"l", 6.0},
+	{"/ ", 7.0},
+	{"/m~0n", 8.0},
+	{"/g~1n~1r", "has slash, will travel"},
+	{"/g/n/r", "where's tito?"},
+}
+
+func init() {
+	err := json.Unmarshal([]byte(objSrc), &obj)
+	if err != nil {
+		panic(err)
+	}
+}
+
+func TestPaths(t *testing.T) {
+	for _, test := range tests {
+		got := Get(obj, test.path)
+		if !reflect.DeepEqual(got, test.exp) {
+			t.Errorf("On %v, expected %+v (%T), got %+v (%T)",
+				test.path, test.exp, test.exp, got, got)
+		} else {
+			t.Logf("Success - got %v for %v", got, test.path)
+		}
+	}
+}
+
+func BenchmarkPaths(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		for _, test := range tests {
+			Get(obj, test.path)
+		}
+	}
+}
+
+func BenchmarkParseAndPath(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		for _, test := range tests {
+			o := map[string]interface{}{}
+			err := json.Unmarshal([]byte(objSrc), &o)
+			if err != nil {
+				b.Fatalf("Error parsing: %v", err)
+			}
+			Get(o, test.path)
+		}
+	}
+}
+
+var bug3Data = []byte(`{"foo" : "bar"}`)
+
+func TestFindSpaceBeforeColon(t *testing.T) {
+	val, err := Find(bug3Data, "/foo")
+	if err != nil {
+		t.Fatalf("Failed to find /foo: %v", err)
+	}
+	x, ok := json.UnquoteBytes(val)
+	if !ok {
+		t.Fatalf("Failed to unquote json bytes from %q", val)
+	}
+	if string(x) != "bar" {
+		t.Fatalf("Expected %q, got %q", "bar", val)
+	}
+}
+
+func TestListSpaceBeforeColon(t *testing.T) {
+	ptrs, err := ListPointers(bug3Data)
+	if err != nil {
+		t.Fatalf("Error listing pointers: %v", err)
+	}
+	if len(ptrs) != 2 || ptrs[0] != "" || ptrs[1] != "/foo" {
+		t.Fatalf(`Expected ["", "/foo"], got %#v`, ptrs)
+	}
+}
+
+func TestIndexNotFoundSameAsPropertyNotFound(t *testing.T) {
+	data, err := ioutil.ReadFile("testdata/357.json")
+	if err != nil {
+		t.Fatalf("Error beer-sample brewery 357 data: %v", err)
+	}
+
+	expectedResult, expectedError := Find(data, "/doesNotExist")
+
+	missingVals := []string{
+		"/address/0",
+		"/address/1",
+		"/address2/1",
+		"/address2/2",
+		"/address3/0",
+		"/address3/1",
+	}
+
+	for _, a := range missingVals {
+		found, err := Find(data, a)
+
+		if !reflect.DeepEqual(err, expectedError) {
+			t.Errorf("Expected %v at %v, got %v", expectedError, a, err)
+		}
+		if !reflect.DeepEqual(expectedResult, found) {
+			t.Errorf("Expected %v at %v, got %v", expectedResult, a, found)
+		}
+	}
+}
+
+const bug822src = `{
+      "foo": ["bar", "baz"],
+      "": 0,
+      "a/b": 1,
+      "c%d": 2,
+      "e^f": 3,
+      "g|h": 4,
+      "i\\j": 5,
+      "k\"l": 6,
+      "k2": {},
+      " ": 7,
+      "m~n": 8,
+      "g/n/r": "has slash, will travel",
+      "g": { "n": {"r": "where's tito?"}},
+      "h": {}
+}`
+
+func TestListEmptyObjectPanic822(t *testing.T) {
+	ptrs, err := ListPointers([]byte(bug822src))
+	if err != nil {
+		t.Fatalf("Error parsing: %v", err)
+	}
+	t.Logf("Got pointers: %v", ptrs)
+}
+
+func TestFindEmptyObjectPanic823(t *testing.T) {
+	for _, test := range tests {
+		_, err := Find([]byte(bug822src), test.path)
+		if err != nil {
+			t.Errorf("Error looking for %v: %v", test.path, err)
+		}
+	}
+}

+ 263 - 0
vendor/github.com/dustin/go-jsonpointer/reflect_test.go

@@ -0,0 +1,263 @@
+package jsonpointer
+
+import (
+	"reflect"
+	"testing"
+)
+
+type address struct {
+	Street string `json:"street"`
+	Zip    string
+}
+
+type person struct {
+	Name               string `json:"name,omitempty"`
+	Twitter            string
+	Aliases            []string   `json:"aliases"`
+	Addresses          []*address `json:"addresses"`
+	NameTildeContained string     `json:"name~contained"`
+	NameSlashContained string     `json:"name/contained"`
+	AnActualArray      [4]int
+	NestedMap          map[string]float64 `json:"nestedmap"`
+	MapIntKey          map[int]string
+	MapUintKey         map[uint]string
+	MapFloatKey        map[float64]string
+}
+
+var input = &person{
+	Name:    "marty",
+	Twitter: "mschoch",
+	Aliases: []string{
+		"jabroni",
+		"beer",
+	},
+	Addresses: []*address{
+		&address{
+			Street: "123 Sesame St.",
+			Zip:    "99099",
+		},
+	},
+	NameTildeContained: "yessir",
+	NameSlashContained: "nosir",
+	AnActualArray:      [4]int{0, 1, 2, 3},
+	NestedMap: map[string]float64{
+		"pi":          3.14,
+		"back/saidhe": 2.71,
+		"till~duh":    1.41,
+	},
+	MapIntKey: map[int]string{
+		1: "one",
+		2: "two",
+	},
+	MapUintKey: map[uint]string{
+		3: "three",
+		4: "four",
+	},
+	MapFloatKey: map[float64]string{
+		3.14: "pi",
+		4.15: "notpi",
+	},
+}
+
+func benchReflect(b *testing.B, path string) {
+	for i := 0; i < b.N; i++ {
+		if Reflect(input, path) == nil {
+			b.FailNow()
+		}
+	}
+}
+
+func BenchmarkReflectRoot(b *testing.B) {
+	benchReflect(b, "")
+}
+
+func BenchmarkReflectToplevelExact(b *testing.B) {
+	benchReflect(b, "/Twitter")
+}
+
+func BenchmarkReflectToplevelTagged(b *testing.B) {
+	benchReflect(b, "/Name")
+}
+
+func BenchmarkReflectToplevelTaggedLower(b *testing.B) {
+	benchReflect(b, "/name")
+}
+
+func BenchmarkReflectDeep(b *testing.B) {
+	benchReflect(b, "/addresses/0/Zip")
+}
+
+func BenchmarkReflectSlash(b *testing.B) {
+	benchReflect(b, "/name~1contained")
+}
+
+func BenchmarkReflectTilde(b *testing.B) {
+	benchReflect(b, "/name~0contained")
+}
+
+func compareStringArrayIgnoringOrder(a, b []string) bool {
+	if len(a) != len(b) {
+		return false
+	}
+	tmp := make(map[string]bool, len(a))
+	for _, av := range a {
+		tmp[av] = true
+	}
+	for _, bv := range b {
+		if tmp[bv] != true {
+			return false
+		}
+	}
+	return true
+}
+
+func TestReflectListPointers(t *testing.T) {
+	pointers, err := ReflectListPointers(input)
+	if err != nil {
+		t.Fatal(err)
+	}
+	expect := []string{"", "/name", "/Twitter", "/aliases",
+		"/aliases/0", "/aliases/1", "/addresses", "/addresses/0",
+		"/addresses/0/street", "/addresses/0/Zip",
+		"/name~0contained", "/name~1contained", "/AnActualArray",
+		"/AnActualArray/0", "/AnActualArray/1", "/AnActualArray/2",
+		"/AnActualArray/3", "/nestedmap", "/nestedmap/pi",
+		"/nestedmap/back~1saidhe", "/nestedmap/till~0duh",
+		"/MapIntKey", "/MapIntKey/1", "/MapIntKey/2", "/MapUintKey",
+		"/MapUintKey/3", "/MapUintKey/4", "/MapFloatKey",
+		"/MapFloatKey/3.14", "/MapFloatKey/4.15"}
+	if !compareStringArrayIgnoringOrder(expect, pointers) {
+		t.Fatalf("expected %#v, got %#v", expect, pointers)
+	}
+}
+
+func TestReflectNonObjectOrSlice(t *testing.T) {
+	got := Reflect(36, "/test")
+	if got != nil {
+		t.Errorf("expected nil, got %#v", got)
+	}
+}
+
+type structThatCanBeUsedAsKey struct {
+	name   string
+	domain string
+}
+
+func TestReflectMapThatWontWork(t *testing.T) {
+
+	amapthatwontwork := map[structThatCanBeUsedAsKey]string{}
+	akey := structThatCanBeUsedAsKey{name: "marty", domain: "couchbase"}
+	amapthatwontwork[akey] = "verycontrived"
+
+	got := Reflect(amapthatwontwork, "/anykey")
+	if got != nil {
+		t.Errorf("expected nil, got %#v", got)
+	}
+}
+
+func TestReflect(t *testing.T) {
+
+	tests := []struct {
+		path string
+		exp  interface{}
+	}{
+		{
+			path: "",
+			exp:  input,
+		},
+		{
+			path: "/", exp: nil,
+		},
+		{
+			path: "/name",
+			exp:  "marty",
+		},
+		{
+			path: "/Name",
+			exp:  "marty",
+		},
+		{
+			path: "/Twitter",
+			exp:  "mschoch",
+		},
+		{
+			path: "/aliases/0",
+			exp:  "jabroni",
+		},
+		{
+			path: "/Aliases/0",
+			exp:  "jabroni",
+		},
+		{
+			path: "/addresses/0/street",
+			exp:  "123 Sesame St.",
+		},
+		{
+			path: "/addresses/4/street",
+			exp:  nil,
+		},
+		{
+			path: "/doesntexist",
+			exp:  nil,
+		},
+		{
+			path: "/does/not/exit",
+			exp:  nil,
+		},
+		{
+			path: "/doesntexist/7",
+			exp:  nil,
+		},
+		{
+			path: "/name~0contained",
+			exp:  "yessir",
+		},
+		{
+			path: "/name~1contained",
+			exp:  "nosir",
+		},
+		{
+			path: "/AnActualArray/2",
+			exp:  2,
+		},
+		{
+			path: "/AnActualArray/5",
+			exp:  nil,
+		},
+		{
+			path: "/nestedmap/pi",
+			exp:  3.14,
+		},
+		{
+			path: "/nestedmap/back~1saidhe",
+			exp:  2.71,
+		},
+		{
+			path: "/nestedmap/till~0duh",
+			exp:  1.41,
+		},
+		{
+			path: "/MapIntKey/1",
+			exp:  "one",
+		},
+		{
+			path: "/MapUintKey/3",
+			exp:  "three",
+		},
+		{
+			path: "/MapFloatKey/3.14",
+			exp:  "pi",
+		},
+		{
+			path: "/MapFloatKey/4.0",
+			exp:  nil,
+		},
+	}
+
+	for _, test := range tests {
+		output := Reflect(input, test.path)
+		if !reflect.DeepEqual(output, test.exp) {
+			t.Errorf("Expected %#v for %q, got %#v", test.exp, test.path, output)
+		}
+	}
+}

+ 189 - 0
vendor/github.com/dustin/gojson/bench_test.go

@@ -0,0 +1,189 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Large data benchmark.
+// The JSON data is a summary of agl's changes in the
+// go, webkit, and chromium open source projects.
+// We benchmark converting between the JSON form
+// and in-memory data structures.
+
+package json
+
+import (
+	"bytes"
+	"compress/gzip"
+	"io/ioutil"
+	"os"
+	"testing"
+)
+
+type codeResponse struct {
+	Tree     *codeNode `json:"tree"`
+	Username string    `json:"username"`
+}
+
+type codeNode struct {
+	Name     string      `json:"name"`
+	Kids     []*codeNode `json:"kids"`
+	CLWeight float64     `json:"cl_weight"`
+	Touches  int         `json:"touches"`
+	MinT     int64       `json:"min_t"`
+	MaxT     int64       `json:"max_t"`
+	MeanT    int64       `json:"mean_t"`
+}
+
+var codeJSON []byte
+var codeStruct codeResponse
+
+func codeInit() {
+	f, err := os.Open("testdata/code.json.gz")
+	if err != nil {
+		panic(err)
+	}
+	defer f.Close()
+	gz, err := gzip.NewReader(f)
+	if err != nil {
+		panic(err)
+	}
+	data, err := ioutil.ReadAll(gz)
+	if err != nil {
+		panic(err)
+	}
+
+	codeJSON = data
+
+	if err := Unmarshal(codeJSON, &codeStruct); err != nil {
+		panic("unmarshal code.json: " + err.Error())
+	}
+
+	if data, err = Marshal(&codeStruct); err != nil {
+		panic("marshal code.json: " + err.Error())
+	}
+
+	if !bytes.Equal(data, codeJSON) {
+		println("different lengths", len(data), len(codeJSON))
+		for i := 0; i < len(data) && i < len(codeJSON); i++ {
+			if data[i] != codeJSON[i] {
+				println("re-marshal: changed at byte", i)
+				println("orig: ", string(codeJSON[i-10:i+10]))
+				println("new: ", string(data[i-10:i+10]))
+				break
+			}
+		}
+		panic("re-marshal code.json: different result")
+	}
+}
+
+func BenchmarkCodeEncoder(b *testing.B) {
+	if codeJSON == nil {
+		b.StopTimer()
+		codeInit()
+		b.StartTimer()
+	}
+	enc := NewEncoder(ioutil.Discard)
+	for i := 0; i < b.N; i++ {
+		if err := enc.Encode(&codeStruct); err != nil {
+			b.Fatal("Encode:", err)
+		}
+	}
+	b.SetBytes(int64(len(codeJSON)))
+}
+
+func BenchmarkCodeMarshal(b *testing.B) {
+	if codeJSON == nil {
+		b.StopTimer()
+		codeInit()
+		b.StartTimer()
+	}
+	for i := 0; i < b.N; i++ {
+		if _, err := Marshal(&codeStruct); err != nil {
+			b.Fatal("Marshal:", err)
+		}
+	}
+	b.SetBytes(int64(len(codeJSON)))
+}
+
+func BenchmarkCodeDecoder(b *testing.B) {
+	if codeJSON == nil {
+		b.StopTimer()
+		codeInit()
+		b.StartTimer()
+	}
+	var buf bytes.Buffer
+	dec := NewDecoder(&buf)
+	var r codeResponse
+	for i := 0; i < b.N; i++ {
+		buf.Write(codeJSON)
+		// hide EOF
+		buf.WriteByte('\n')
+		buf.WriteByte('\n')
+		buf.WriteByte('\n')
+		if err := dec.Decode(&r); err != nil {
+			b.Fatal("Decode:", err)
+		}
+	}
+	b.SetBytes(int64(len(codeJSON)))
+}
+
+func BenchmarkCodeUnmarshal(b *testing.B) {
+	if codeJSON == nil {
+		b.StopTimer()
+		codeInit()
+		b.StartTimer()
+	}
+	for i := 0; i < b.N; i++ {
+		var r codeResponse
+		if err := Unmarshal(codeJSON, &r); err != nil {
+			b.Fatal("Unmmarshal:", err)
+		}
+	}
+	b.SetBytes(int64(len(codeJSON)))
+}
+
+func BenchmarkCodeUnmarshalReuse(b *testing.B) {
+	if codeJSON == nil {
+		b.StopTimer()
+		codeInit()
+		b.StartTimer()
+	}
+	var r codeResponse
+	for i := 0; i < b.N; i++ {
+		if err := Unmarshal(codeJSON, &r); err != nil {
+			b.Fatal("Unmmarshal:", err)
+		}
+	}
+}
+
+func BenchmarkUnmarshalString(b *testing.B) {
+	data := []byte(`"hello, world"`)
+	var s string
+
+	for i := 0; i < b.N; i++ {
+		if err := Unmarshal(data, &s); err != nil {
+			b.Fatal("Unmarshal:", err)
+		}
+	}
+}
+
+func BenchmarkUnmarshalFloat64(b *testing.B) {
+	var f float64
+	data := []byte(`3.14`)
+
+	for i := 0; i < b.N; i++ {
+		if err := Unmarshal(data, &f); err != nil {
+			b.Fatal("Unmarshal:", err)
+		}
+	}
+}
+
+func BenchmarkUnmarshalInt64(b *testing.B) {
+	var x int64
+	data := []byte(`3`)
+
+	for i := 0; i < b.N; i++ {
+		if err := Unmarshal(data, &x); err != nil {
+			b.Fatal("Unmarshal:", err)
+		}
+	}
+}

+ 1391 - 0
vendor/github.com/dustin/gojson/decode_test.go

@@ -0,0 +1,1391 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+	"bytes"
+	"encoding"
+	"fmt"
+	"image"
+	"reflect"
+	"strings"
+	"testing"
+	"time"
+)
+
+type T struct {
+	X string
+	Y int
+	Z int `json:"-"`
+}
+
+type U struct {
+	Alphabet string `json:"alpha"`
+}
+
+type V struct {
+	F1 interface{}
+	F2 int32
+	F3 Number
+}
+
+// ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshaling with and
+// without UseNumber
+var ifaceNumAsFloat64 = map[string]interface{}{
+	"k1": float64(1),
+	"k2": "s",
+	"k3": []interface{}{float64(1), float64(2.0), float64(3e-3)},
+	"k4": map[string]interface{}{"kk1": "s", "kk2": float64(2)},
+}
+
+var ifaceNumAsNumber = map[string]interface{}{
+	"k1": Number("1"),
+	"k2": "s",
+	"k3": []interface{}{Number("1"), Number("2.0"), Number("3e-3")},
+	"k4": map[string]interface{}{"kk1": "s", "kk2": Number("2")},
+}
+
+type tx struct {
+	x int
+}
+
+// A type that can unmarshal itself.
+
+type unmarshaler struct {
+	T bool
+}
+
+func (u *unmarshaler) UnmarshalJSON(b []byte) error {
+	*u = unmarshaler{true} // All we need to see that UnmarshalJSON is called.
+	return nil
+}
+
+type ustruct struct {
+	M unmarshaler
+}
+
+type unmarshalerText struct {
+	T bool
+}
+
+// needed for re-marshaling tests
+func (u *unmarshalerText) MarshalText() ([]byte, error) {
+	return []byte(""), nil
+}
+
+func (u *unmarshalerText) UnmarshalText(b []byte) error {
+	*u = unmarshalerText{true} // All we need to see that UnmarshalText is called.
+	return nil
+}
+
+var _ encoding.TextUnmarshaler = (*unmarshalerText)(nil)
+
+type ustructText struct {
+	M unmarshalerText
+}
+
+var (
+	um0, um1 unmarshaler // target2 of unmarshaling
+	ump      = &um1
+	umtrue   = unmarshaler{true}
+	umslice  = []unmarshaler{{true}}
+	umslicep = new([]unmarshaler)
+	umstruct = ustruct{unmarshaler{true}}
+
+	um0T, um1T unmarshalerText // target2 of unmarshaling
+	umpT       = &um1T
+	umtrueT    = unmarshalerText{true}
+	umsliceT   = []unmarshalerText{{true}}
+	umslicepT  = new([]unmarshalerText)
+	umstructT  = ustructText{unmarshalerText{true}}
+)
+
+// Test data structures for anonymous fields.
+
+type Point struct {
+	Z int
+}
+
+type Top struct {
+	Level0 int
+	Embed0
+	*Embed0a
+	*Embed0b `json:"e,omitempty"` // treated as named
+	Embed0c  `json:"-"`           // ignored
+	Loop
+	Embed0p // has Point with X, Y, used
+	Embed0q // has Point with Z, used
+}
+
+type Embed0 struct {
+	Level1a int // overridden by Embed0a's Level1a with json tag
+	Level1b int // used because Embed0a's Level1b is renamed
+	Level1c int // used because Embed0a's Level1c is ignored
+	Level1d int // annihilated by Embed0a's Level1d
+	Level1e int `json:"x"` // annihilated by Embed0a.Level1e
+}
+
+type Embed0a struct {
+	Level1a int `json:"Level1a,omitempty"`
+	Level1b int `json:"LEVEL1B,omitempty"`
+	Level1c int `json:"-"`
+	Level1d int // annihilated by Embed0's Level1d
+	Level1f int `json:"x"` // annihilated by Embed0's Level1e
+}
+
+type Embed0b Embed0
+
+type Embed0c Embed0
+
+type Embed0p struct {
+	image.Point
+}
+
+type Embed0q struct {
+	Point
+}
+
+type Loop struct {
+	Loop1 int `json:",omitempty"`
+	Loop2 int `json:",omitempty"`
+	*Loop
+}
+
+// From reflect test:
+// The X in S6 and S7 annihilate, but they also block the X in S8.S9.
+type S5 struct {
+	S6
+	S7
+	S8
+}
+
+type S6 struct {
+	X int
+}
+
+type S7 S6
+
+type S8 struct {
+	S9
+}
+
+type S9 struct {
+	X int
+	Y int
+}
+
+// From reflect test:
+// The X in S11.S6 and S12.S6 annihilate, but they also block the X in S13.S8.S9.
+type S10 struct {
+	S11
+	S12
+	S13
+}
+
+type S11 struct {
+	S6
+}
+
+type S12 struct {
+	S6
+}
+
+type S13 struct {
+	S8
+}
+
+type unmarshalTest struct {
+	in        string
+	ptr       interface{}
+	out       interface{}
+	err       error
+	useNumber bool
+}
+
+type Ambig struct {
+	// Given "hello", the first match should win.
+	First  int `json:"HELLO"`
+	Second int `json:"Hello"`
+}
+
+type XYZ struct {
+	X interface{}
+	Y interface{}
+	Z interface{}
+}
+
+var unmarshalTests = []unmarshalTest{
+	// basic types
+	{in: `true`, ptr: new(bool), out: true},
+	{in: `1`, ptr: new(int), out: 1},
+	{in: `1.2`, ptr: new(float64), out: 1.2},
+	{in: `-5`, ptr: new(int16), out: int16(-5)},
+	{in: `2`, ptr: new(Number), out: Number("2"), useNumber: true},
+	{in: `2`, ptr: new(Number), out: Number("2")},
+	{in: `2`, ptr: new(interface{}), out: float64(2.0)},
+	{in: `2`, ptr: new(interface{}), out: Number("2"), useNumber: true},
+	{in: `"a\u1234"`, ptr: new(string), out: "a\u1234"},
+	{in: `"http:\/\/"`, ptr: new(string), out: "http://"},
+	{in: `"g-clef: \uD834\uDD1E"`, ptr: new(string), out: "g-clef: \U0001D11E"},
+	{in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"},
+	{in: "null", ptr: new(interface{}), out: nil},
+	{in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf("")}},
+	{in: `{"x": 1}`, ptr: new(tx), out: tx{}},
+	{in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}},
+	{in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true},
+	{in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsFloat64},
+	{in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsNumber, useNumber: true},
+
+	// raw values with whitespace
+	{in: "\n true ", ptr: new(bool), out: true},
+	{in: "\t 1 ", ptr: new(int), out: 1},
+	{in: "\r 1.2 ", ptr: new(float64), out: 1.2},
+	{in: "\t -5 \n", ptr: new(int16), out: int16(-5)},
+	{in: "\t \"a\\u1234\" \n", ptr: new(string), out: "a\u1234"},
+
+	// Z has a "-" tag.
+	{in: `{"Y": 1, "Z": 2}`, ptr: new(T), out: T{Y: 1}},
+
+	{in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), out: U{Alphabet: "abc"}},
+	{in: `{"alpha": "abc"}`, ptr: new(U), out: U{Alphabet: "abc"}},
+	{in: `{"alphabet": "xyz"}`, ptr: new(U), out: U{}},
+
+	// syntax errors
+	{in: `{"X": "foo", "Y"}`, err: &SyntaxError{"invalid character '}' after object key", 17}},
+	{in: `[1, 2, 3+]`, err: &SyntaxError{"invalid character '+' after array element", 9}},
+	{in: `{"X":12x}`, err: &SyntaxError{"invalid character 'x' after object key:value pair", 8}, useNumber: true},
+
+	// raw value errors
+	{in: "\x01 42", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
+	{in: " 42 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 5}},
+	{in: "\x01 true", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
+	{in: " false \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 8}},
+	{in: "\x01 1.2", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
+	{in: " 3.4 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 6}},
+	{in: "\x01 \"string\"", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
+	{in: " \"string\" \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 11}},
+
+	// array tests
+	{in: `[1, 2, 3]`, ptr: new([3]int), out: [3]int{1, 2, 3}},
+	{in: `[1, 2, 3]`, ptr: new([1]int), out: [1]int{1}},
+	{in: `[1, 2, 3]`, ptr: new([5]int), out: [5]int{1, 2, 3, 0, 0}},
+
+	// empty array to interface test
+	{in: `[]`, ptr: new([]interface{}), out: []interface{}{}},
+	{in: `null`, ptr: new([]interface{}), out: []interface{}(nil)},
+	{in: `{"T":[]}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": []interface{}{}}},
+	{in: `{"T":null}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": interface{}(nil)}},
+
+	// composite tests
+	{in: allValueIndent, ptr: new(All), out: allValue},
+	{in: allValueCompact, ptr: new(All), out: allValue},
+	{in: allValueIndent, ptr: new(*All), out: &allValue},
+	{in: allValueCompact, ptr: new(*All), out: &allValue},
+	{in: pallValueIndent, ptr: new(All), out: pallValue},
+	{in: pallValueCompact, ptr: new(All), out: pallValue},
+	{in: pallValueIndent, ptr: new(*All), out: &pallValue},
+	{in: pallValueCompact, ptr: new(*All), out: &pallValue},
+
+	// unmarshal interface test
+	{in: `{"T":false}`, ptr: &um0, out: umtrue}, // use "false" so test will fail if custom unmarshaler is not called
+	{in: `{"T":false}`, ptr: &ump, out: &umtrue},
+	{in: `[{"T":false}]`, ptr: &umslice, out: umslice},
+	{in: `[{"T":false}]`, ptr: &umslicep, out: &umslice},
+	{in: `{"M":{"T":false}}`, ptr: &umstruct, out: umstruct},
+
+	// UnmarshalText interface test
+	{in: `"X"`, ptr: &um0T, out: umtrueT}, // use "false" so test will fail if custom unmarshaler is not called
+	{in: `"X"`, ptr: &umpT, out: &umtrueT},
+	{in: `["X"]`, ptr: &umsliceT, out: umsliceT},
+	{in: `["X"]`, ptr: &umslicepT, out: &umsliceT},
+	{in: `{"M":"X"}`, ptr: &umstructT, out: umstructT},
+
+	{
+		in: `{
+			"Level0": 1,
+			"Level1b": 2,
+			"Level1c": 3,
+			"x": 4,
+			"Level1a": 5,
+			"LEVEL1B": 6,
+			"e": {
+				"Level1a": 8,
+				"Level1b": 9,
+				"Level1c": 10,
+				"Level1d": 11,
+				"x": 12
+			},
+			"Loop1": 13,
+			"Loop2": 14,
+			"X": 15,
+			"Y": 16,
+			"Z": 17
+		}`,
+		ptr: new(Top),
+		out: Top{
+			Level0: 1,
+			Embed0: Embed0{
+				Level1b: 2,
+				Level1c: 3,
+			},
+			Embed0a: &Embed0a{
+				Level1a: 5,
+				Level1b: 6,
+			},
+			Embed0b: &Embed0b{
+				Level1a: 8,
+				Level1b: 9,
+				Level1c: 10,
+				Level1d: 11,
+				Level1e: 12,
+			},
+			Loop: Loop{
+				Loop1: 13,
+				Loop2: 14,
+			},
+			Embed0p: Embed0p{
+				Point: image.Point{X: 15, Y: 16},
+			},
+			Embed0q: Embed0q{
+				Point: Point{Z: 17},
+			},
+		},
+	},
+	{
+		in:  `{"hello": 1}`,
+		ptr: new(Ambig),
+		out: Ambig{First: 1},
+	},
+
+	{
+		in:  `{"X": 1,"Y":2}`,
+		ptr: new(S5),
+		out: S5{S8: S8{S9: S9{Y: 2}}},
+	},
+	{
+		in:  `{"X": 1,"Y":2}`,
+		ptr: new(S10),
+		out: S10{S13: S13{S8: S8{S9: S9{Y: 2}}}},
+	},
+
+	// invalid UTF-8 is coerced to valid UTF-8.
+	{
+		in:  "\"hello\xffworld\"",
+		ptr: new(string),
+		out: "hello\ufffdworld",
+	},
+	{
+		in:  "\"hello\xc2\xc2world\"",
+		ptr: new(string),
+		out: "hello\ufffd\ufffdworld",
+	},
+	{
+		in:  "\"hello\xc2\xffworld\"",
+		ptr: new(string),
+		out: "hello\ufffd\ufffdworld",
+	},
+	{
+		in:  "\"hello\\ud800world\"",
+		ptr: new(string),
+		out: "hello\ufffdworld",
+	},
+	{
+		in:  "\"hello\\ud800\\ud800world\"",
+		ptr: new(string),
+		out: "hello\ufffd\ufffdworld",
+	},
+	{
+		in:  "\"hello\\ud800\\ud800world\"",
+		ptr: new(string),
+		out: "hello\ufffd\ufffdworld",
+	},
+	{
+		in:  "\"hello\xed\xa0\x80\xed\xb0\x80world\"",
+		ptr: new(string),
+		out: "hello\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdworld",
+	},
+
+	// issue 8305
+	{
+		in:  `{"2009-11-10T23:00:00Z": "hello world"}`,
+		ptr: &map[time.Time]string{},
+		err: &UnmarshalTypeError{"object", reflect.TypeOf(map[time.Time]string{})},
+	},
+}
+
+func TestMarshal(t *testing.T) {
+	b, err := Marshal(allValue)
+	if err != nil {
+		t.Fatalf("Marshal allValue: %v", err)
+	}
+	if string(b) != allValueCompact {
+		t.Errorf("Marshal allValueCompact")
+		diff(t, b, []byte(allValueCompact))
+		return
+	}
+
+	b, err = Marshal(pallValue)
+	if err != nil {
+		t.Fatalf("Marshal pallValue: %v", err)
+	}
+	if string(b) != pallValueCompact {
+		t.Errorf("Marshal pallValueCompact")
+		diff(t, b, []byte(pallValueCompact))
+		return
+	}
+}
+
+var badUTF8 = []struct {
+	in, out string
+}{
+	{"hello\xffworld", `"hello\ufffdworld"`},
+	{"", `""`},
+	{"\xff", `"\ufffd"`},
+	{"\xff\xff", `"\ufffd\ufffd"`},
+	{"a\xffb", `"a\ufffdb"`},
+	{"\xe6\x97\xa5\xe6\x9c\xac\xff\xaa\x9e", `"日本\ufffd\ufffd\ufffd"`},
+}
+
+func TestMarshalBadUTF8(t *testing.T) {
+	for _, tt := range badUTF8 {
+		b, err := Marshal(tt.in)
+		if string(b) != tt.out || err != nil {
+			t.Errorf("Marshal(%q) = %#q, %v, want %#q, nil", tt.in, b, err, tt.out)
+		}
+	}
+}
+
+func TestMarshalNumberZeroVal(t *testing.T) {
+	var n Number
+	out, err := Marshal(n)
+	if err != nil {
+		t.Fatal(err)
+	}
+	outStr := string(out)
+	if outStr != "0" {
+		t.Fatalf("Invalid zero val for Number: %q", outStr)
+	}
+}
+
+func TestMarshalEmbeds(t *testing.T) {
+	top := &Top{
+		Level0: 1,
+		Embed0: Embed0{
+			Level1b: 2,
+			Level1c: 3,
+		},
+		Embed0a: &Embed0a{
+			Level1a: 5,
+			Level1b: 6,
+		},
+		Embed0b: &Embed0b{
+			Level1a: 8,
+			Level1b: 9,
+			Level1c: 10,
+			Level1d: 11,
+			Level1e: 12,
+		},
+		Loop: Loop{
+			Loop1: 13,
+			Loop2: 14,
+		},
+		Embed0p: Embed0p{
+			Point: image.Point{X: 15, Y: 16},
+		},
+		Embed0q: Embed0q{
+			Point: Point{Z: 17},
+		},
+	}
+	b, err := Marshal(top)
+	if err != nil {
+		t.Fatal(err)
+	}
+	want := "{\"Level0\":1,\"Level1b\":2,\"Level1c\":3,\"Level1a\":5,\"LEVEL1B\":6,\"e\":{\"Level1a\":8,\"Level1b\":9,\"Level1c\":10,\"Level1d\":11,\"x\":12},\"Loop1\":13,\"Loop2\":14,\"X\":15,\"Y\":16,\"Z\":17}"
+	if string(b) != want {
+		t.Errorf("Wrong marshal result.\n got: %q\nwant: %q", b, want)
+	}
+}
+
+func TestUnmarshal(t *testing.T) {
+	for i, tt := range unmarshalTests {
+		var scan Scanner
+		in := []byte(tt.in)
+		if err := checkValid(in, &scan); err != nil {
+			if !reflect.DeepEqual(err, tt.err) {
+				t.Errorf("#%d: checkValid: %#v", i, err)
+				continue
+			}
+		}
+		if tt.ptr == nil {
+			continue
+		}
+
+		// v = new(right-type)
+		v := reflect.New(reflect.TypeOf(tt.ptr).Elem())
+		dec := NewDecoder(bytes.NewReader(in))
+		if tt.useNumber {
+			dec.UseNumber()
+		}
+		if err := dec.Decode(v.Interface()); !reflect.DeepEqual(err, tt.err) {
+			t.Errorf("#%d: %v, want %v", i, err, tt.err)
+			continue
+		} else if err != nil {
+			continue
+		}
+		if !reflect.DeepEqual(v.Elem().Interface(), tt.out) {
+			t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), tt.out)
+			data, _ := Marshal(v.Elem().Interface())
+			println(string(data))
+			data, _ = Marshal(tt.out)
+			println(string(data))
+			continue
+		}
+
+		// Check round trip.
+		if tt.err == nil {
+			enc, err := Marshal(v.Interface())
+			if err != nil {
+				t.Errorf("#%d: error re-marshaling: %v", i, err)
+				continue
+			}
+			vv := reflect.New(reflect.TypeOf(tt.ptr).Elem())
+			dec = NewDecoder(bytes.NewReader(enc))
+			if tt.useNumber {
+				dec.UseNumber()
+			}
+			if err := dec.Decode(vv.Interface()); err != nil {
+				t.Errorf("#%d: error re-unmarshaling %#q: %v", i, enc, err)
+				continue
+			}
+			if !reflect.DeepEqual(v.Elem().Interface(), vv.Elem().Interface()) {
+				t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), vv.Elem().Interface())
+				t.Errorf("     In: %q", strings.Map(noSpace, string(in)))
+				t.Errorf("Marshal: %q", strings.Map(noSpace, string(enc)))
+				continue
+			}
+		}
+	}
+}
+
+func TestUnmarshalMarshal(t *testing.T) {
+	initBig()
+	var v interface{}
+	if err := Unmarshal(jsonBig, &v); err != nil {
+		t.Fatalf("Unmarshal: %v", err)
+	}
+	b, err := Marshal(v)
+	if err != nil {
+		t.Fatalf("Marshal: %v", err)
+	}
+	if !bytes.Equal(jsonBig, b) {
+		t.Errorf("Marshal jsonBig")
+		diff(t, b, jsonBig)
+		return
+	}
+}
+
+var numberTests = []struct {
+	in       string
+	i        int64
+	intErr   string
+	f        float64
+	floatErr string
+}{
+	{in: "-1.23e1", intErr: "strconv.ParseInt: parsing \"-1.23e1\": invalid syntax", f: -1.23e1},
+	{in: "-12", i: -12, f: -12.0},
+	{in: "1e1000", intErr: "strconv.ParseInt: parsing \"1e1000\": invalid syntax", floatErr: "strconv.ParseFloat: parsing \"1e1000\": value out of range"},
+}
+
+// Independent of Decode, basic coverage of the accessors in Number
+func TestNumberAccessors(t *testing.T) {
+	for _, tt := range numberTests {
+		n := Number(tt.in)
+		if s := n.String(); s != tt.in {
+			t.Errorf("Number(%q).String() is %q", tt.in, s)
+		}
+		if i, err := n.Int64(); err == nil && tt.intErr == "" && i != tt.i {
+			t.Errorf("Number(%q).Int64() is %d", tt.in, i)
+		} else if (err == nil && tt.intErr != "") || (err != nil && err.Error() != tt.intErr) {
+			t.Errorf("Number(%q).Int64() wanted error %q but got: %v", tt.in, tt.intErr, err)
+		}
+		if f, err := n.Float64(); err == nil && tt.floatErr == "" && f != tt.f {
+			t.Errorf("Number(%q).Float64() is %g", tt.in, f)
+		} else if (err == nil && tt.floatErr != "") || (err != nil && err.Error() != tt.floatErr) {
+			t.Errorf("Number(%q).Float64() wanted error %q but got: %v", tt.in, tt.floatErr, err)
+		}
+	}
+}
+
+func TestLargeByteSlice(t *testing.T) {
+	s0 := make([]byte, 2000)
+	for i := range s0 {
+		s0[i] = byte(i)
+	}
+	b, err := Marshal(s0)
+	if err != nil {
+		t.Fatalf("Marshal: %v", err)
+	}
+	var s1 []byte
+	if err := Unmarshal(b, &s1); err != nil {
+		t.Fatalf("Unmarshal: %v", err)
+	}
+	if !bytes.Equal(s0, s1) {
+		t.Errorf("Marshal large byte slice")
+		diff(t, s0, s1)
+	}
+}
+
+type Xint struct {
+	X int
+}
+
+func TestUnmarshalInterface(t *testing.T) {
+	var xint Xint
+	var i interface{} = &xint
+	if err := Unmarshal([]byte(`{"X":1}`), &i); err != nil {
+		t.Fatalf("Unmarshal: %v", err)
+	}
+	if xint.X != 1 {
+		t.Fatalf("Did not write to xint")
+	}
+}
+
+func TestUnmarshalPtrPtr(t *testing.T) {
+	var xint Xint
+	pxint := &xint
+	if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil {
+		t.Fatalf("Unmarshal: %v", err)
+	}
+	if xint.X != 1 {
+		t.Fatalf("Did not write to xint")
+	}
+}
+
+func TestEscape(t *testing.T) {
+	const input = `"foobar"<html>` + " [\u2028 \u2029]"
+	const expected = `"\"foobar\"\u003chtml\u003e [\u2028 \u2029]"`
+	b, err := Marshal(input)
+	if err != nil {
+		t.Fatalf("Marshal error: %v", err)
+	}
+	if s := string(b); s != expected {
+		t.Errorf("Encoding of [%s]:\n got [%s]\nwant [%s]", input, s, expected)
+	}
+}
+
+// WrongString is a struct that's misusing the ,string modifier.
+type WrongString struct {
+	Message string `json:"result,string"`
+}
+
+type wrongStringTest struct {
+	in, err string
+}
+
+var wrongStringTests = []wrongStringTest{
+	{`{"result":"x"}`, `json: invalid use of ,string struct tag, trying to unmarshal "x" into string`},
+	{`{"result":"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "foo" into string`},
+	{`{"result":"123"}`, `json: invalid use of ,string struct tag, trying to unmarshal "123" into string`},
+}
+
+// If people misuse the ,string modifier, the error message should be
+// helpful, telling the user that they're doing it wrong.
+func TestErrorMessageFromMisusedString(t *testing.T) {
+	for n, tt := range wrongStringTests {
+		r := strings.NewReader(tt.in)
+		var s WrongString
+		err := NewDecoder(r).Decode(&s)
+		got := fmt.Sprintf("%v", err)
+		if got != tt.err {
+			t.Errorf("%d. got err = %q, want %q", n, got, tt.err)
+		}
+	}
+}
+
+func noSpace(c rune) rune {
+	if isSpace(c) {
+		return -1
+	}
+	return c
+}
+
+type All struct {
+	Bool    bool
+	Int     int
+	Int8    int8
+	Int16   int16
+	Int32   int32
+	Int64   int64
+	Uint    uint
+	Uint8   uint8
+	Uint16  uint16
+	Uint32  uint32
+	Uint64  uint64
+	Uintptr uintptr
+	Float32 float32
+	Float64 float64
+
+	Foo  string `json:"bar"`
+	Foo2 string `json:"bar2,dummyopt"`
+
+	IntStr int64 `json:",string"`
+
+	PBool    *bool
+	PInt     *int
+	PInt8    *int8
+	PInt16   *int16
+	PInt32   *int32
+	PInt64   *int64
+	PUint    *uint
+	PUint8   *uint8
+	PUint16  *uint16
+	PUint32  *uint32
+	PUint64  *uint64
+	PUintptr *uintptr
+	PFloat32 *float32
+	PFloat64 *float64
+
+	String  string
+	PString *string
+
+	Map   map[string]Small
+	MapP  map[string]*Small
+	PMap  *map[string]Small
+	PMapP *map[string]*Small
+
+	EmptyMap map[string]Small
+	NilMap   map[string]Small
+
+	Slice   []Small
+	SliceP  []*Small
+	PSlice  *[]Small
+	PSliceP *[]*Small
+
+	EmptySlice []Small
+	NilSlice   []Small
+
+	StringSlice []string
+	ByteSlice   []byte
+
+	Small   Small
+	PSmall  *Small
+	PPSmall **Small
+
+	Interface  interface{}
+	PInterface *interface{}
+
+	unexported int
+}
+
+type Small struct {
+	Tag string
+}
+
+var allValue = All{
+	Bool:    true,
+	Int:     2,
+	Int8:    3,
+	Int16:   4,
+	Int32:   5,
+	Int64:   6,
+	Uint:    7,
+	Uint8:   8,
+	Uint16:  9,
+	Uint32:  10,
+	Uint64:  11,
+	Uintptr: 12,
+	Float32: 14.1,
+	Float64: 15.1,
+	Foo:     "foo",
+	Foo2:    "foo2",
+	IntStr:  42,
+	String:  "16",
+	Map: map[string]Small{
+		"17": {Tag: "tag17"},
+		"18": {Tag: "tag18"},
+	},
+	MapP: map[string]*Small{
+		"19": {Tag: "tag19"},
+		"20": nil,
+	},
+	EmptyMap:    map[string]Small{},
+	Slice:       []Small{{Tag: "tag20"}, {Tag: "tag21"}},
+	SliceP:      []*Small{{Tag: "tag22"}, nil, {Tag: "tag23"}},
+	EmptySlice:  []Small{},
+	StringSlice: []string{"str24", "str25", "str26"},
+	ByteSlice:   []byte{27, 28, 29},
+	Small:       Small{Tag: "tag30"},
+	PSmall:      &Small{Tag: "tag31"},
+	Interface:   5.2,
+}
+
+var pallValue = All{
+	PBool:      &allValue.Bool,
+	PInt:       &allValue.Int,
+	PInt8:      &allValue.Int8,
+	PInt16:     &allValue.Int16,
+	PInt32:     &allValue.Int32,
+	PInt64:     &allValue.Int64,
+	PUint:      &allValue.Uint,
+	PUint8:     &allValue.Uint8,
+	PUint16:    &allValue.Uint16,
+	PUint32:    &allValue.Uint32,
+	PUint64:    &allValue.Uint64,
+	PUintptr:   &allValue.Uintptr,
+	PFloat32:   &allValue.Float32,
+	PFloat64:   &allValue.Float64,
+	PString:    &allValue.String,
+	PMap:       &allValue.Map,
+	PMapP:      &allValue.MapP,
+	PSlice:     &allValue.Slice,
+	PSliceP:    &allValue.SliceP,
+	PPSmall:    &allValue.PSmall,
+	PInterface: &allValue.Interface,
+}
+
+var allValueIndent = `{
+	"Bool": true,
+	"Int": 2,
+	"Int8": 3,
+	"Int16": 4,
+	"Int32": 5,
+	"Int64": 6,
+	"Uint": 7,
+	"Uint8": 8,
+	"Uint16": 9,
+	"Uint32": 10,
+	"Uint64": 11,
+	"Uintptr": 12,
+	"Float32": 14.1,
+	"Float64": 15.1,
+	"bar": "foo",
+	"bar2": "foo2",
+	"IntStr": "42",
+	"PBool": null,
+	"PInt": null,
+	"PInt8": null,
+	"PInt16": null,
+	"PInt32": null,
+	"PInt64": null,
+	"PUint": null,
+	"PUint8": null,
+	"PUint16": null,
+	"PUint32": null,
+	"PUint64": null,
+	"PUintptr": null,
+	"PFloat32": null,
+	"PFloat64": null,
+	"String": "16",
+	"PString": null,
+	"Map": {
+		"17": {
+			"Tag": "tag17"
+		},
+		"18": {
+			"Tag": "tag18"
+		}
+	},
+	"MapP": {
+		"19": {
+			"Tag": "tag19"
+		},
+		"20": null
+	},
+	"PMap": null,
+	"PMapP": null,
+	"EmptyMap": {},
+	"NilMap": null,
+	"Slice": [
+		{
+			"Tag": "tag20"
+		},
+		{
+			"Tag": "tag21"
+		}
+	],
+	"SliceP": [
+		{
+			"Tag": "tag22"
+		},
+		null,
+		{
+			"Tag": "tag23"
+		}
+	],
+	"PSlice": null,
+	"PSliceP": null,
+	"EmptySlice": [],
+	"NilSlice": null,
+	"StringSlice": [
+		"str24",
+		"str25",
+		"str26"
+	],
+	"ByteSlice": "Gxwd",
+	"Small": {
+		"Tag": "tag30"
+	},
+	"PSmall": {
+		"Tag": "tag31"
+	},
+	"PPSmall": null,
+	"Interface": 5.2,
+	"PInterface": null
+}`
+
+var allValueCompact = strings.Map(noSpace, allValueIndent)
+
+var pallValueIndent = `{
+	"Bool": false,
+	"Int": 0,
+	"Int8": 0,
+	"Int16": 0,
+	"Int32": 0,
+	"Int64": 0,
+	"Uint": 0,
+	"Uint8": 0,
+	"Uint16": 0,
+	"Uint32": 0,
+	"Uint64": 0,
+	"Uintptr": 0,
+	"Float32": 0,
+	"Float64": 0,
+	"bar": "",
+	"bar2": "",
+        "IntStr": "0",
+	"PBool": true,
+	"PInt": 2,
+	"PInt8": 3,
+	"PInt16": 4,
+	"PInt32": 5,
+	"PInt64": 6,
+	"PUint": 7,
+	"PUint8": 8,
+	"PUint16": 9,
+	"PUint32": 10,
+	"PUint64": 11,
+	"PUintptr": 12,
+	"PFloat32": 14.1,
+	"PFloat64": 15.1,
+	"String": "",
+	"PString": "16",
+	"Map": null,
+	"MapP": null,
+	"PMap": {
+		"17": {
+			"Tag": "tag17"
+		},
+		"18": {
+			"Tag": "tag18"
+		}
+	},
+	"PMapP": {
+		"19": {
+			"Tag": "tag19"
+		},
+		"20": null
+	},
+	"EmptyMap": null,
+	"NilMap": null,
+	"Slice": null,
+	"SliceP": null,
+	"PSlice": [
+		{
+			"Tag": "tag20"
+		},
+		{
+			"Tag": "tag21"
+		}
+	],
+	"PSliceP": [
+		{
+			"Tag": "tag22"
+		},
+		null,
+		{
+			"Tag": "tag23"
+		}
+	],
+	"EmptySlice": null,
+	"NilSlice": null,
+	"StringSlice": null,
+	"ByteSlice": null,
+	"Small": {
+		"Tag": ""
+	},
+	"PSmall": null,
+	"PPSmall": {
+		"Tag": "tag31"
+	},
+	"Interface": null,
+	"PInterface": 5.2
+}`
+
+var pallValueCompact = strings.Map(noSpace, pallValueIndent)
+
+func TestRefUnmarshal(t *testing.T) {
+	type S struct {
+		// Ref is defined in encode_test.go.
+		R0 Ref
+		R1 *Ref
+		R2 RefText
+		R3 *RefText
+	}
+	want := S{
+		R0: 12,
+		R1: new(Ref),
+		R2: 13,
+		R3: new(RefText),
+	}
+	*want.R1 = 12
+	*want.R3 = 13
+
+	var got S
+	if err := Unmarshal([]byte(`{"R0":"ref","R1":"ref","R2":"ref","R3":"ref"}`), &got); err != nil {
+		t.Fatalf("Unmarshal: %v", err)
+	}
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("got %+v, want %+v", got, want)
+	}
+}
+
+// Test that the empty string doesn't panic decoding when ,string is specified
+// Issue 3450
+func TestEmptyString(t *testing.T) {
+	type T2 struct {
+		Number1 int `json:",string"`
+		Number2 int `json:",string"`
+	}
+	data := `{"Number1":"1", "Number2":""}`
+	dec := NewDecoder(strings.NewReader(data))
+	var t2 T2
+	err := dec.Decode(&t2)
+	if err == nil {
+		t.Fatal("Decode: did not return error")
+	}
+	if t2.Number1 != 1 {
+		t.Fatal("Decode: did not set Number1")
+	}
+}
+
+// Test that a null for ,string is not replaced with the previous quoted string (issue 7046).
+// It should also not be an error (issue 2540, issue 8587).
+func TestNullString(t *testing.T) {
+	type T struct {
+		A int  `json:",string"`
+		B int  `json:",string"`
+		C *int `json:",string"`
+	}
+	data := []byte(`{"A": "1", "B": null, "C": null}`)
+	var s T
+	s.B = 1
+	s.C = new(int)
+	*s.C = 2
+	err := Unmarshal(data, &s)
+	if err != nil {
+		t.Fatalf("Unmarshal: %v")
+	}
+	if s.B != 1 || s.C != nil {
+		t.Fatalf("after Unmarshal, s.B=%d, s.C=%p, want 1, nil", s.B, s.C)
+	}
+}
+
+func intp(x int) *int {
+	p := new(int)
+	*p = x
+	return p
+}
+
+func intpp(x *int) **int {
+	pp := new(*int)
+	*pp = x
+	return pp
+}
+
+var interfaceSetTests = []struct {
+	pre  interface{}
+	json string
+	post interface{}
+}{
+	{"foo", `"bar"`, "bar"},
+	{"foo", `2`, 2.0},
+	{"foo", `true`, true},
+	{"foo", `null`, nil},
+
+	{nil, `null`, nil},
+	{new(int), `null`, nil},
+	{(*int)(nil), `null`, nil},
+	{new(*int), `null`, new(*int)},
+	{(**int)(nil), `null`, nil},
+	{intp(1), `null`, nil},
+	{intpp(nil), `null`, intpp(nil)},
+	{intpp(intp(1)), `null`, intpp(nil)},
+}
+
+func TestInterfaceSet(t *testing.T) {
+	for _, tt := range interfaceSetTests {
+		b := struct{ X interface{} }{tt.pre}
+		blob := `{"X":` + tt.json + `}`
+		if err := Unmarshal([]byte(blob), &b); err != nil {
+			t.Errorf("Unmarshal %#q: %v", blob, err)
+			continue
+		}
+		if !reflect.DeepEqual(b.X, tt.post) {
+			t.Errorf("Unmarshal %#q into %#v: X=%#v, want %#v", blob, tt.pre, b.X, tt.post)
+		}
+	}
+}
+
+// JSON null values should be ignored for primitives and string values instead of resulting in an error.
+// Issue 2540
+func TestUnmarshalNulls(t *testing.T) {
+	jsonData := []byte(`{
+		"Bool"    : null,
+		"Int"     : null,
+		"Int8"    : null,
+		"Int16"   : null,
+		"Int32"   : null,
+		"Int64"   : null,
+		"Uint"    : null,
+		"Uint8"   : null,
+		"Uint16"  : null,
+		"Uint32"  : null,
+		"Uint64"  : null,
+		"Float32" : null,
+		"Float64" : null,
+		"String"  : null}`)
+
+	nulls := All{
+		Bool:    true,
+		Int:     2,
+		Int8:    3,
+		Int16:   4,
+		Int32:   5,
+		Int64:   6,
+		Uint:    7,
+		Uint8:   8,
+		Uint16:  9,
+		Uint32:  10,
+		Uint64:  11,
+		Float32: 12.1,
+		Float64: 13.1,
+		String:  "14"}
+
+	err := Unmarshal(jsonData, &nulls)
+	if err != nil {
+		t.Errorf("Unmarshal of null values failed: %v", err)
+	}
+	if !nulls.Bool || nulls.Int != 2 || nulls.Int8 != 3 || nulls.Int16 != 4 || nulls.Int32 != 5 || nulls.Int64 != 6 ||
+		nulls.Uint != 7 || nulls.Uint8 != 8 || nulls.Uint16 != 9 || nulls.Uint32 != 10 || nulls.Uint64 != 11 ||
+		nulls.Float32 != 12.1 || nulls.Float64 != 13.1 || nulls.String != "14" {
+
+		t.Errorf("Unmarshal of null values affected primitives")
+	}
+}
+
+func TestStringKind(t *testing.T) {
+	type stringKind string
+
+	var m1, m2 map[stringKind]int
+	m1 = map[stringKind]int{
+		"foo": 42,
+	}
+
+	data, err := Marshal(m1)
+	if err != nil {
+		t.Errorf("Unexpected error marshalling: %v", err)
+	}
+
+	err = Unmarshal(data, &m2)
+	if err != nil {
+		t.Errorf("Unexpected error unmarshalling: %v", err)
+	}
+
+	if !reflect.DeepEqual(m1, m2) {
+		t.Error("Items should be equal after encoding and then decoding")
+	}
+
+}
+
+var decodeTypeErrorTests = []struct {
+	dest interface{}
+	src  string
+}{
+	{new(string), `{"user": "name"}`}, // issue 4628.
+	{new(error), `{}`},                // issue 4222
+	{new(error), `[]`},
+	{new(error), `""`},
+	{new(error), `123`},
+	{new(error), `true`},
+}
+
+func TestUnmarshalTypeError(t *testing.T) {
+	for _, item := range decodeTypeErrorTests {
+		err := Unmarshal([]byte(item.src), item.dest)
+		if _, ok := err.(*UnmarshalTypeError); !ok {
+			t.Errorf("expected type error for Unmarshal(%q, type %T): got %T",
+				item.src, item.dest, err)
+		}
+	}
+}
+
+var unmarshalSyntaxTests = []string{
+	"tru",
+	"fals",
+	"nul",
+	"123e",
+	`"hello`,
+	`[1,2,3`,
+	`{"key":1`,
+	`{"key":1,`,
+}
+
+func TestUnmarshalSyntax(t *testing.T) {
+	var x interface{}
+	for _, src := range unmarshalSyntaxTests {
+		err := Unmarshal([]byte(src), &x)
+		if _, ok := err.(*SyntaxError); !ok {
+			t.Errorf("expected syntax error for Unmarshal(%q): got %T", src, err)
+		}
+	}
+}
+
+// Test handling of unexported fields that should be ignored.
+// Issue 4660
+type unexportedFields struct {
+	Name string
+	m    map[string]interface{} `json:"-"`
+	m2   map[string]interface{} `json:"abcd"`
+}
+
+func TestUnmarshalUnexported(t *testing.T) {
+	input := `{"Name": "Bob", "m": {"x": 123}, "m2": {"y": 456}, "abcd": {"z": 789}}`
+	want := &unexportedFields{Name: "Bob"}
+
+	out := &unexportedFields{}
+	err := Unmarshal([]byte(input), out)
+	if err != nil {
+		t.Errorf("got error %v, expected nil", err)
+	}
+	if !reflect.DeepEqual(out, want) {
+		t.Errorf("got %q, want %q", out, want)
+	}
+}
+
+// Time3339 is a time.Time which encodes to and from JSON
+// as an RFC 3339 time in UTC.
+type Time3339 time.Time
+
+func (t *Time3339) UnmarshalJSON(b []byte) error {
+	if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' {
+		return fmt.Errorf("types: failed to unmarshal non-string value %q as an RFC 3339 time", b)
+	}
+	tm, err := time.Parse(time.RFC3339, string(b[1:len(b)-1]))
+	if err != nil {
+		return err
+	}
+	*t = Time3339(tm)
+	return nil
+}
+
+func TestUnmarshalJSONLiteralError(t *testing.T) {
+	var t3 Time3339
+	err := Unmarshal([]byte(`"0000-00-00T00:00:00Z"`), &t3)
+	if err == nil {
+		t.Fatalf("expected error; got time %v", time.Time(t3))
+	}
+	if !strings.Contains(err.Error(), "range") {
+		t.Errorf("got err = %v; want out of range error", err)
+	}
+}
+
+// Test that extra object elements in an array do not result in a
+// "data changing underfoot" error.
+// Issue 3717
+func TestSkipArrayObjects(t *testing.T) {
+	json := `[{}]`
+	var dest [0]interface{}
+
+	err := Unmarshal([]byte(json), &dest)
+	if err != nil {
+		t.Errorf("got error %q, want nil", err)
+	}
+}
+
+// Test semantics of pre-filled struct fields and pre-filled map fields.
+// Issue 4900.
+func TestPrefilled(t *testing.T) {
+	ptrToMap := func(m map[string]interface{}) *map[string]interface{} { return &m }
+
+	// Values here change, cannot reuse table across runs.
+	var prefillTests = []struct {
+		in  string
+		ptr interface{}
+		out interface{}
+	}{
+		{
+			in:  `{"X": 1, "Y": 2}`,
+			ptr: &XYZ{X: float32(3), Y: int16(4), Z: 1.5},
+			out: &XYZ{X: float64(1), Y: float64(2), Z: 1.5},
+		},
+		{
+			in:  `{"X": 1, "Y": 2}`,
+			ptr: ptrToMap(map[string]interface{}{"X": float32(3), "Y": int16(4), "Z": 1.5}),
+			out: ptrToMap(map[string]interface{}{"X": float64(1), "Y": float64(2), "Z": 1.5}),
+		},
+	}
+
+	for _, tt := range prefillTests {
+		ptrstr := fmt.Sprintf("%v", tt.ptr)
+		err := Unmarshal([]byte(tt.in), tt.ptr) // tt.ptr edited here
+		if err != nil {
+			t.Errorf("Unmarshal: %v", err)
+		}
+		if !reflect.DeepEqual(tt.ptr, tt.out) {
+			t.Errorf("Unmarshal(%#q, %s): have %v, want %v", tt.in, ptrstr, tt.ptr, tt.out)
+		}
+	}
+}
+
+var invalidUnmarshalTests = []struct {
+	v    interface{}
+	want string
+}{
+	{nil, "json: Unmarshal(nil)"},
+	{struct{}{}, "json: Unmarshal(non-pointer struct {})"},
+	{(*int)(nil), "json: Unmarshal(nil *int)"},
+}
+
+func TestInvalidUnmarshal(t *testing.T) {
+	buf := []byte(`{"a":"1"}`)
+	for _, tt := range invalidUnmarshalTests {
+		err := Unmarshal(buf, tt.v)
+		if err == nil {
+			t.Errorf("Unmarshal expecting error, got nil")
+			continue
+		}
+		if got := err.Error(); got != tt.want {
+			t.Errorf("Unmarshal = %q; want %q", got, tt.want)
+		}
+	}
+}
+
+func TestValidator(t *testing.T) {
+	for _, tt := range unmarshalTests {
+		// Don't care about the valid json with type errors
+		expectederr := tt.err
+		if _, ok := expectederr.(*UnmarshalTypeError); ok {
+			expectederr = nil
+		}
+		if _, ok := expectederr.(*UnmarshalFieldError); ok {
+			expectederr = nil
+		}
+		err := Validate([]byte(tt.in))
+		if (expectederr == nil) != (err == nil) {
+			t.Errorf("Incorrectly validated %v - %v/%v",
+			tt.in, expectederr, err)
+		}
+	}
+}

+ 532 - 0
vendor/github.com/dustin/gojson/encode_test.go

@@ -0,0 +1,532 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+	"bytes"
+	"math"
+	"reflect"
+	"testing"
+	"unicode"
+)
+
+type Optionals struct {
+	Sr string `json:"sr"`
+	So string `json:"so,omitempty"`
+	Sw string `json:"-"`
+
+	Ir int `json:"omitempty"` // actually named omitempty, not an option
+	Io int `json:"io,omitempty"`
+
+	Slr []string `json:"slr,random"`
+	Slo []string `json:"slo,omitempty"`
+
+	Mr map[string]interface{} `json:"mr"`
+	Mo map[string]interface{} `json:",omitempty"`
+
+	Fr float64 `json:"fr"`
+	Fo float64 `json:"fo,omitempty"`
+
+	Br bool `json:"br"`
+	Bo bool `json:"bo,omitempty"`
+
+	Ur uint `json:"ur"`
+	Uo uint `json:"uo,omitempty"`
+
+	Str struct{} `json:"str"`
+	Sto struct{} `json:"sto,omitempty"`
+}
+
+var optionalsExpected = `{
+ "sr": "",
+ "omitempty": 0,
+ "slr": null,
+ "mr": {},
+ "fr": 0,
+ "br": false,
+ "ur": 0,
+ "str": {},
+ "sto": {}
+}`
+
+func TestOmitEmpty(t *testing.T) {
+	var o Optionals
+	o.Sw = "something"
+	o.Mr = map[string]interface{}{}
+	o.Mo = map[string]interface{}{}
+
+	got, err := MarshalIndent(&o, "", " ")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if got := string(got); got != optionalsExpected {
+		t.Errorf(" got: %s\nwant: %s\n", got, optionalsExpected)
+	}
+}
+
+type StringTag struct {
+	BoolStr bool   `json:",string"`
+	IntStr  int64  `json:",string"`
+	StrStr  string `json:",string"`
+}
+
+var stringTagExpected = `{
+ "BoolStr": "true",
+ "IntStr": "42",
+ "StrStr": "\"xzbit\""
+}`
+
+func TestStringTag(t *testing.T) {
+	var s StringTag
+	s.BoolStr = true
+	s.IntStr = 42
+	s.StrStr = "xzbit"
+	got, err := MarshalIndent(&s, "", " ")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if got := string(got); got != stringTagExpected {
+		t.Fatalf(" got: %s\nwant: %s\n", got, stringTagExpected)
+	}
+
+	// Verify that it round-trips.
+	var s2 StringTag
+	err = NewDecoder(bytes.NewReader(got)).Decode(&s2)
+	if err != nil {
+		t.Fatalf("Decode: %v", err)
+	}
+	if !reflect.DeepEqual(s, s2) {
+		t.Fatalf("decode didn't match.\nsource: %#v\nEncoded as:\n%s\ndecode: %#v", s, string(got), s2)
+	}
+}
+
+// byte slices are special even if they're renamed types.
+type renamedByte byte
+type renamedByteSlice []byte
+type renamedRenamedByteSlice []renamedByte
+
+func TestEncodeRenamedByteSlice(t *testing.T) {
+	s := renamedByteSlice("abc")
+	result, err := Marshal(s)
+	if err != nil {
+		t.Fatal(err)
+	}
+	expect := `"YWJj"`
+	if string(result) != expect {
+		t.Errorf(" got %s want %s", result, expect)
+	}
+	r := renamedRenamedByteSlice("abc")
+	result, err = Marshal(r)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if string(result) != expect {
+		t.Errorf(" got %s want %s", result, expect)
+	}
+}
+
+var unsupportedValues = []interface{}{
+	math.NaN(),
+	math.Inf(-1),
+	math.Inf(1),
+}
+
+func TestUnsupportedValues(t *testing.T) {
+	for _, v := range unsupportedValues {
+		if _, err := Marshal(v); err != nil {
+			if _, ok := err.(*UnsupportedValueError); !ok {
+				t.Errorf("for %v, got %T want UnsupportedValueError", v, err)
+			}
+		} else {
+			t.Errorf("for %v, expected error", v)
+		}
+	}
+}
+
+// Ref has Marshaler and Unmarshaler methods with pointer receiver.
+type Ref int
+
+func (*Ref) MarshalJSON() ([]byte, error) {
+	return []byte(`"ref"`), nil
+}
+
+func (r *Ref) UnmarshalJSON([]byte) error {
+	*r = 12
+	return nil
+}
+
+// Val has Marshaler methods with value receiver.
+type Val int
+
+func (Val) MarshalJSON() ([]byte, error) {
+	return []byte(`"val"`), nil
+}
+
+// RefText has Marshaler and Unmarshaler methods with pointer receiver.
+type RefText int
+
+func (*RefText) MarshalText() ([]byte, error) {
+	return []byte(`"ref"`), nil
+}
+
+func (r *RefText) UnmarshalText([]byte) error {
+	*r = 13
+	return nil
+}
+
+// ValText has Marshaler methods with value receiver.
+type ValText int
+
+func (ValText) MarshalText() ([]byte, error) {
+	return []byte(`"val"`), nil
+}
+
+func TestRefValMarshal(t *testing.T) {
+	var s = struct {
+		R0 Ref
+		R1 *Ref
+		R2 RefText
+		R3 *RefText
+		V0 Val
+		V1 *Val
+		V2 ValText
+		V3 *ValText
+	}{
+		R0: 12,
+		R1: new(Ref),
+		R2: 14,
+		R3: new(RefText),
+		V0: 13,
+		V1: new(Val),
+		V2: 15,
+		V3: new(ValText),
+	}
+	const want = `{"R0":"ref","R1":"ref","R2":"\"ref\"","R3":"\"ref\"","V0":"val","V1":"val","V2":"\"val\"","V3":"\"val\""}`
+	b, err := Marshal(&s)
+	if err != nil {
+		t.Fatalf("Marshal: %v", err)
+	}
+	if got := string(b); got != want {
+		t.Errorf("got %q, want %q", got, want)
+	}
+}
+
+// C implements Marshaler and returns unescaped JSON.
+type C int
+
+func (C) MarshalJSON() ([]byte, error) {
+	return []byte(`"<&>"`), nil
+}
+
+// CText implements Marshaler and returns unescaped text.
+type CText int
+
+func (CText) MarshalText() ([]byte, error) {
+	return []byte(`"<&>"`), nil
+}
+
+func TestMarshalerEscaping(t *testing.T) {
+	var c C
+	want := `"\u003c\u0026\u003e"`
+	b, err := Marshal(c)
+	if err != nil {
+		t.Fatalf("Marshal(c): %v", err)
+	}
+	if got := string(b); got != want {
+		t.Errorf("Marshal(c) = %#q, want %#q", got, want)
+	}
+
+	var ct CText
+	want = `"\"\u003c\u0026\u003e\""`
+	b, err = Marshal(ct)
+	if err != nil {
+		t.Fatalf("Marshal(ct): %v", err)
+	}
+	if got := string(b); got != want {
+		t.Errorf("Marshal(ct) = %#q, want %#q", got, want)
+	}
+}
+
+type IntType int
+
+type MyStruct struct {
+	IntType
+}
+
+func TestAnonymousNonstruct(t *testing.T) {
+	var i IntType = 11
+	a := MyStruct{i}
+	const want = `{"IntType":11}`
+
+	b, err := Marshal(a)
+	if err != nil {
+		t.Fatalf("Marshal: %v", err)
+	}
+	if got := string(b); got != want {
+		t.Errorf("got %q, want %q", got, want)
+	}
+}
+
+type BugA struct {
+	S string
+}
+
+type BugB struct {
+	BugA
+	S string
+}
+
+type BugC struct {
+	S string
+}
+
+// Legal Go: We never use the repeated embedded field (S).
+type BugX struct {
+	A int
+	BugA
+	BugB
+}
+
+// Issue 5245.
+func TestEmbeddedBug(t *testing.T) {
+	v := BugB{
+		BugA{"A"},
+		"B",
+	}
+	b, err := Marshal(v)
+	if err != nil {
+		t.Fatal("Marshal:", err)
+	}
+	want := `{"S":"B"}`
+	got := string(b)
+	if got != want {
+		t.Fatalf("Marshal: got %s want %s", got, want)
+	}
+	// Now check that the duplicate field, S, does not appear.
+	x := BugX{
+		A: 23,
+	}
+	b, err = Marshal(x)
+	if err != nil {
+		t.Fatal("Marshal:", err)
+	}
+	want = `{"A":23}`
+	got = string(b)
+	if got != want {
+		t.Fatalf("Marshal: got %s want %s", got, want)
+	}
+}
+
+type BugD struct { // Same as BugA after tagging.
+	XXX string `json:"S"`
+}
+
+// BugD's tagged S field should dominate BugA's.
+type BugY struct {
+	BugA
+	BugD
+}
+
+// Test that a field with a tag dominates untagged fields.
+func TestTaggedFieldDominates(t *testing.T) {
+	v := BugY{
+		BugA{"BugA"},
+		BugD{"BugD"},
+	}
+	b, err := Marshal(v)
+	if err != nil {
+		t.Fatal("Marshal:", err)
+	}
+	want := `{"S":"BugD"}`
+	got := string(b)
+	if got != want {
+		t.Fatalf("Marshal: got %s want %s", got, want)
+	}
+}
+
+// There are no tags here, so S should not appear.
+type BugZ struct {
+	BugA
+	BugC
+	BugY // Contains a tagged S field through BugD; should not dominate.
+}
+
+func TestDuplicatedFieldDisappears(t *testing.T) {
+	v := BugZ{
+		BugA{"BugA"},
+		BugC{"BugC"},
+		BugY{
+			BugA{"nested BugA"},
+			BugD{"nested BugD"},
+		},
+	}
+	b, err := Marshal(v)
+	if err != nil {
+		t.Fatal("Marshal:", err)
+	}
+	want := `{}`
+	got := string(b)
+	if got != want {
+		t.Fatalf("Marshal: got %s want %s", got, want)
+	}
+}
+
+func TestStringBytes(t *testing.T) {
+	// Test that encodeState.stringBytes and encodeState.string use the same encoding.
+	es := &encodeState{}
+	var r []rune
+	for i := '\u0000'; i <= unicode.MaxRune; i++ {
+		r = append(r, i)
+	}
+	s := string(r) + "\xff\xff\xffhello" // some invalid UTF-8 too
+	_, err := es.string(s)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	esBytes := &encodeState{}
+	_, err = esBytes.stringBytes([]byte(s))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	enc := es.Buffer.String()
+	encBytes := esBytes.Buffer.String()
+	if enc != encBytes {
+		i := 0
+		for i < len(enc) && i < len(encBytes) && enc[i] == encBytes[i] {
+			i++
+		}
+		enc = enc[i:]
+		encBytes = encBytes[i:]
+		i = 0
+		for i < len(enc) && i < len(encBytes) && enc[len(enc)-i-1] == encBytes[len(encBytes)-i-1] {
+			i++
+		}
+		enc = enc[:len(enc)-i]
+		encBytes = encBytes[:len(encBytes)-i]
+
+		if len(enc) > 20 {
+			enc = enc[:20] + "..."
+		}
+		if len(encBytes) > 20 {
+			encBytes = encBytes[:20] + "..."
+		}
+
+		t.Errorf("encodings differ at %#q vs %#q", enc, encBytes)
+	}
+}
+
+func TestIssue6458(t *testing.T) {
+	type Foo struct {
+		M RawMessage
+	}
+	x := Foo{RawMessage(`"foo"`)}
+
+	b, err := Marshal(&x)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if want := `{"M":"foo"}`; string(b) != want {
+		t.Errorf("Marshal(&x) = %#q; want %#q", b, want)
+	}
+
+	b, err = Marshal(x)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if want := `{"M":"ImZvbyI="}`; string(b) != want {
+		t.Errorf("Marshal(x) = %#q; want %#q", b, want)
+	}
+}
+
+func TestHTMLEscape(t *testing.T) {
+	var b, want bytes.Buffer
+	m := `{"M":"<html>foo &` + "\xe2\x80\xa8 \xe2\x80\xa9" + `</html>"}`
+	want.Write([]byte(`{"M":"\u003chtml\u003efoo \u0026\u2028 \u2029\u003c/html\u003e"}`))
+	HTMLEscape(&b, []byte(m))
+	if !bytes.Equal(b.Bytes(), want.Bytes()) {
+		t.Errorf("HTMLEscape(&b, []byte(m)) = %s; want %s", b.Bytes(), want.Bytes())
+	}
+}
+
+// golang.org/issue/8582
+func TestEncodePointerString(t *testing.T) {
+	type stringPointer struct {
+		N *int64 `json:"n,string"`
+	}
+	var n int64 = 42
+	b, err := Marshal(stringPointer{N: &n})
+	if err != nil {
+		t.Fatalf("Marshal: %v", err)
+	}
+	if got, want := string(b), `{"n":"42"}`; got != want {
+		t.Errorf("Marshal = %s, want %s", got, want)
+	}
+	var back stringPointer
+	err = Unmarshal(b, &back)
+	if err != nil {
+		t.Fatalf("Unmarshal: %v", err)
+	}
+	if back.N == nil {
+		t.Fatalf("Unmarshalled nil N field")
+	}
+	if *back.N != 42 {
+		t.Fatalf("*N = %d; want 42", *back.N)
+	}
+}
+
+var encodeStringTests = []struct {
+	in  string
+	out string
+}{
+	{"\x00", `"\u0000"`},
+	{"\x01", `"\u0001"`},
+	{"\x02", `"\u0002"`},
+	{"\x03", `"\u0003"`},
+	{"\x04", `"\u0004"`},
+	{"\x05", `"\u0005"`},
+	{"\x06", `"\u0006"`},
+	{"\x07", `"\u0007"`},
+	{"\x08", `"\u0008"`},
+	{"\x09", `"\t"`},
+	{"\x0a", `"\n"`},
+	{"\x0b", `"\u000b"`},
+	{"\x0c", `"\u000c"`},
+	{"\x0d", `"\r"`},
+	{"\x0e", `"\u000e"`},
+	{"\x0f", `"\u000f"`},
+	{"\x10", `"\u0010"`},
+	{"\x11", `"\u0011"`},
+	{"\x12", `"\u0012"`},
+	{"\x13", `"\u0013"`},
+	{"\x14", `"\u0014"`},
+	{"\x15", `"\u0015"`},
+	{"\x16", `"\u0016"`},
+	{"\x17", `"\u0017"`},
+	{"\x18", `"\u0018"`},
+	{"\x19", `"\u0019"`},
+	{"\x1a", `"\u001a"`},
+	{"\x1b", `"\u001b"`},
+	{"\x1c", `"\u001c"`},
+	{"\x1d", `"\u001d"`},
+	{"\x1e", `"\u001e"`},
+	{"\x1f", `"\u001f"`},
+}
+
+func TestEncodeString(t *testing.T) {
+	for _, tt := range encodeStringTests {
+		b, err := Marshal(tt.in)
+		if err != nil {
+			t.Errorf("Marshal(%q): %v", tt.in, err)
+			continue
+		}
+		out := string(b)
+		if out != tt.out {
+			t.Errorf("Marshal(%q) = %#q, want %#q", tt.in, out, tt.out)
+		}
+	}
+}

+ 161 - 0
vendor/github.com/dustin/gojson/example_test.go

@@ -0,0 +1,161 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json_test
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"log"
+	"os"
+	"strings"
+)
+
+func ExampleMarshal() {
+	type ColorGroup struct {
+		ID     int
+		Name   string
+		Colors []string
+	}
+	group := ColorGroup{
+		ID:     1,
+		Name:   "Reds",
+		Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
+	}
+	b, err := json.Marshal(group)
+	if err != nil {
+		fmt.Println("error:", err)
+	}
+	os.Stdout.Write(b)
+	// Output:
+	// {"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}
+}
+
+func ExampleUnmarshal() {
+	var jsonBlob = []byte(`[
+		{"Name": "Platypus", "Order": "Monotremata"},
+		{"Name": "Quoll",    "Order": "Dasyuromorphia"}
+	]`)
+	type Animal struct {
+		Name  string
+		Order string
+	}
+	var animals []Animal
+	err := json.Unmarshal(jsonBlob, &animals)
+	if err != nil {
+		fmt.Println("error:", err)
+	}
+	fmt.Printf("%+v", animals)
+	// Output:
+	// [{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]
+}
+
+// This example uses a Decoder to decode a stream of distinct JSON values.
+func ExampleDecoder() {
+	const jsonStream = `
+		{"Name": "Ed", "Text": "Knock knock."}
+		{"Name": "Sam", "Text": "Who's there?"}
+		{"Name": "Ed", "Text": "Go fmt."}
+		{"Name": "Sam", "Text": "Go fmt who?"}
+		{"Name": "Ed", "Text": "Go fmt yourself!"}
+	`
+	type Message struct {
+		Name, Text string
+	}
+	dec := json.NewDecoder(strings.NewReader(jsonStream))
+	for {
+		var m Message
+		if err := dec.Decode(&m); err == io.EOF {
+			break
+		} else if err != nil {
+			log.Fatal(err)
+		}
+		fmt.Printf("%s: %s\n", m.Name, m.Text)
+	}
+	// Output:
+	// Ed: Knock knock.
+	// Sam: Who's there?
+	// Ed: Go fmt.
+	// Sam: Go fmt who?
+	// Ed: Go fmt yourself!
+}
+
+// This example uses RawMessage to delay parsing part of a JSON message.
+func ExampleRawMessage() {
+	type Color struct {
+		Space string
+		Point json.RawMessage // delay parsing until we know the color space
+	}
+	type RGB struct {
+		R uint8
+		G uint8
+		B uint8
+	}
+	type YCbCr struct {
+		Y  uint8
+		Cb int8
+		Cr int8
+	}
+
+	var j = []byte(`[
+		{"Space": "YCbCr", "Point": {"Y": 255, "Cb": 0, "Cr": -10}},
+		{"Space": "RGB",   "Point": {"R": 98, "G": 218, "B": 255}}
+	]`)
+	var colors []Color
+	err := json.Unmarshal(j, &colors)
+	if err != nil {
+		log.Fatalln("error:", err)
+	}
+
+	for _, c := range colors {
+		var dst interface{}
+		switch c.Space {
+		case "RGB":
+			dst = new(RGB)
+		case "YCbCr":
+			dst = new(YCbCr)
+		}
+		err := json.Unmarshal(c.Point, dst)
+		if err != nil {
+			log.Fatalln("error:", err)
+		}
+		fmt.Println(c.Space, dst)
+	}
+	// Output:
+	// YCbCr &{255 0 -10}
+	// RGB &{98 218 255}
+}
+
+func ExampleIndent() {
+	type Road struct {
+		Name   string
+		Number int
+	}
+	roads := []Road{
+		{"Diamond Fork", 29},
+		{"Sheep Creek", 51},
+	}
+
+	b, err := json.Marshal(roads)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	var out bytes.Buffer
+	json.Indent(&out, b, "=", "\t")
+	out.WriteTo(os.Stdout)
+	// Output:
+	// [
+	// =	{
+	// =		"Name": "Diamond Fork",
+	// =		"Number": 29
+	// =	},
+	// =	{
+	// =		"Name": "Sheep Creek",
+	// =		"Number": 51
+	// =	}
+	// =]
+}

+ 116 - 0
vendor/github.com/dustin/gojson/fold_test.go

@@ -0,0 +1,116 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+	"bytes"
+	"strings"
+	"testing"
+	"unicode/utf8"
+)
+
+var foldTests = []struct {
+	fn   func(s, t []byte) bool
+	s, t string
+	want bool
+}{
+	{equalFoldRight, "", "", true},
+	{equalFoldRight, "a", "a", true},
+	{equalFoldRight, "", "a", false},
+	{equalFoldRight, "a", "", false},
+	{equalFoldRight, "a", "A", true},
+	{equalFoldRight, "AB", "ab", true},
+	{equalFoldRight, "AB", "ac", false},
+	{equalFoldRight, "sbkKc", "ſbKKc", true},
+	{equalFoldRight, "SbKkc", "ſbKKc", true},
+	{equalFoldRight, "SbKkc", "ſbKK", false},
+	{equalFoldRight, "e", "é", false},
+	{equalFoldRight, "s", "S", true},
+
+	{simpleLetterEqualFold, "", "", true},
+	{simpleLetterEqualFold, "abc", "abc", true},
+	{simpleLetterEqualFold, "abc", "ABC", true},
+	{simpleLetterEqualFold, "abc", "ABCD", false},
+	{simpleLetterEqualFold, "abc", "xxx", false},
+
+	{asciiEqualFold, "a_B", "A_b", true},
+	{asciiEqualFold, "aa@", "aa`", false}, // verify 0x40 and 0x60 aren't case-equivalent
+}
+
+func TestFold(t *testing.T) {
+	for i, tt := range foldTests {
+		if got := tt.fn([]byte(tt.s), []byte(tt.t)); got != tt.want {
+			t.Errorf("%d. %q, %q = %v; want %v", i, tt.s, tt.t, got, tt.want)
+		}
+		truth := strings.EqualFold(tt.s, tt.t)
+		if truth != tt.want {
+			t.Errorf("strings.EqualFold doesn't agree with case %d", i)
+		}
+	}
+}
+
+func TestFoldAgainstUnicode(t *testing.T) {
+	const bufSize = 5
+	buf1 := make([]byte, 0, bufSize)
+	buf2 := make([]byte, 0, bufSize)
+	var runes []rune
+	for i := 0x20; i <= 0x7f; i++ {
+		runes = append(runes, rune(i))
+	}
+	runes = append(runes, kelvin, smallLongEss)
+
+	funcs := []struct {
+		name   string
+		fold   func(s, t []byte) bool
+		letter bool // must be ASCII letter
+		simple bool // must be simple ASCII letter (not 'S' or 'K')
+	}{
+		{
+			name: "equalFoldRight",
+			fold: equalFoldRight,
+		},
+		{
+			name:   "asciiEqualFold",
+			fold:   asciiEqualFold,
+			simple: true,
+		},
+		{
+			name:   "simpleLetterEqualFold",
+			fold:   simpleLetterEqualFold,
+			simple: true,
+			letter: true,
+		},
+	}
+
+	for _, ff := range funcs {
+		for _, r := range runes {
+			if r >= utf8.RuneSelf {
+				continue
+			}
+			if ff.letter && !isASCIILetter(byte(r)) {
+				continue
+			}
+			if ff.simple && (r == 's' || r == 'S' || r == 'k' || r == 'K') {
+				continue
+			}
+			for _, r2 := range runes {
+				buf1 := append(buf1[:0], 'x')
+				buf2 := append(buf2[:0], 'x')
+				buf1 = buf1[:1+utf8.EncodeRune(buf1[1:bufSize], r)]
+				buf2 = buf2[:1+utf8.EncodeRune(buf2[1:bufSize], r2)]
+				buf1 = append(buf1, 'x')
+				buf2 = append(buf2, 'x')
+				want := bytes.EqualFold(buf1, buf2)
+				if got := ff.fold(buf1, buf2); got != want {
+					t.Errorf("%s(%q, %q) = %v; want %v", ff.name, buf1, buf2, got, want)
+				}
+			}
+		}
+	}
+}
+
+func isASCIILetter(b byte) bool {
+	return ('A' <= b && b <= 'Z') || ('a' <= b && b <= 'z')
+}

+ 315 - 0
vendor/github.com/dustin/gojson/scanner_test.go

@@ -0,0 +1,315 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+	"bytes"
+	"math"
+	"math/rand"
+	"reflect"
+	"testing"
+)
+
+// Tests of simple examples.
+
+type example struct {
+	compact string
+	indent  string
+}
+
+var examples = []example{
+	{`1`, `1`},
+	{`{}`, `{}`},
+	{`[]`, `[]`},
+	{`{"":2}`, "{\n\t\"\": 2\n}"},
+	{`[3]`, "[\n\t3\n]"},
+	{`[1,2,3]`, "[\n\t1,\n\t2,\n\t3\n]"},
+	{`{"x":1}`, "{\n\t\"x\": 1\n}"},
+	{ex1, ex1i},
+}
+
+var ex1 = `[true,false,null,"x",1,1.5,0,-5e+2]`
+
+var ex1i = `[
+	true,
+	false,
+	null,
+	"x",
+	1,
+	1.5,
+	0,
+	-5e+2
+]`
+
+func TestCompact(t *testing.T) {
+	var buf bytes.Buffer
+	for _, tt := range examples {
+		buf.Reset()
+		if err := Compact(&buf, []byte(tt.compact)); err != nil {
+			t.Errorf("Compact(%#q): %v", tt.compact, err)
+		} else if s := buf.String(); s != tt.compact {
+			t.Errorf("Compact(%#q) = %#q, want original", tt.compact, s)
+		}
+
+		buf.Reset()
+		if err := Compact(&buf, []byte(tt.indent)); err != nil {
+			t.Errorf("Compact(%#q): %v", tt.indent, err)
+			continue
+		} else if s := buf.String(); s != tt.compact {
+			t.Errorf("Compact(%#q) = %#q, want %#q", tt.indent, s, tt.compact)
+		}
+	}
+}
+
+func TestCompactSeparators(t *testing.T) {
+	// U+2028 and U+2029 should be escaped inside strings.
+	// They should not appear outside strings.
+	tests := []struct {
+		in, compact string
+	}{
+		{"{\"\u2028\": 1}", `{"\u2028":1}`},
+		{"{\"\u2029\" :2}", `{"\u2029":2}`},
+	}
+	for _, tt := range tests {
+		var buf bytes.Buffer
+		if err := Compact(&buf, []byte(tt.in)); err != nil {
+			t.Errorf("Compact(%q): %v", tt.in, err)
+		} else if s := buf.String(); s != tt.compact {
+			t.Errorf("Compact(%q) = %q, want %q", tt.in, s, tt.compact)
+		}
+	}
+}
+
+func TestIndent(t *testing.T) {
+	var buf bytes.Buffer
+	for _, tt := range examples {
+		buf.Reset()
+		if err := Indent(&buf, []byte(tt.indent), "", "\t"); err != nil {
+			t.Errorf("Indent(%#q): %v", tt.indent, err)
+		} else if s := buf.String(); s != tt.indent {
+			t.Errorf("Indent(%#q) = %#q, want original", tt.indent, s)
+		}
+
+		buf.Reset()
+		if err := Indent(&buf, []byte(tt.compact), "", "\t"); err != nil {
+			t.Errorf("Indent(%#q): %v", tt.compact, err)
+			continue
+		} else if s := buf.String(); s != tt.indent {
+			t.Errorf("Indent(%#q) = %#q, want %#q", tt.compact, s, tt.indent)
+		}
+	}
+}
+
+// Tests of a large random structure.
+
+func TestCompactBig(t *testing.T) {
+	initBig()
+	var buf bytes.Buffer
+	if err := Compact(&buf, jsonBig); err != nil {
+		t.Fatalf("Compact: %v", err)
+	}
+	b := buf.Bytes()
+	if !bytes.Equal(b, jsonBig) {
+		t.Error("Compact(jsonBig) != jsonBig")
+		diff(t, b, jsonBig)
+		return
+	}
+}
+
+func TestIndentBig(t *testing.T) {
+	initBig()
+	var buf bytes.Buffer
+	if err := Indent(&buf, jsonBig, "", "\t"); err != nil {
+		t.Fatalf("Indent1: %v", err)
+	}
+	b := buf.Bytes()
+	if len(b) == len(jsonBig) {
+		// jsonBig is compact (no unnecessary spaces);
+		// indenting should make it bigger
+		t.Fatalf("Indent(jsonBig) did not get bigger")
+	}
+
+	// should be idempotent
+	var buf1 bytes.Buffer
+	if err := Indent(&buf1, b, "", "\t"); err != nil {
+		t.Fatalf("Indent2: %v", err)
+	}
+	b1 := buf1.Bytes()
+	if !bytes.Equal(b1, b) {
+		t.Error("Indent(Indent(jsonBig)) != Indent(jsonBig)")
+		diff(t, b1, b)
+		return
+	}
+
+	// should get back to original
+	buf1.Reset()
+	if err := Compact(&buf1, b); err != nil {
+		t.Fatalf("Compact: %v", err)
+	}
+	b1 = buf1.Bytes()
+	if !bytes.Equal(b1, jsonBig) {
+		t.Error("Compact(Indent(jsonBig)) != jsonBig")
+		diff(t, b1, jsonBig)
+		return
+	}
+}
+
+type indentErrorTest struct {
+	in  string
+	err error
+}
+
+var indentErrorTests = []indentErrorTest{
+	{`{"X": "foo", "Y"}`, &SyntaxError{"invalid character '}' after object key", 17}},
+	{`{"X": "foo" "Y": "bar"}`, &SyntaxError{"invalid character '\"' after object key:value pair", 13}},
+}
+
+func TestIndentErrors(t *testing.T) {
+	for i, tt := range indentErrorTests {
+		slice := make([]uint8, 0)
+		buf := bytes.NewBuffer(slice)
+		if err := Indent(buf, []uint8(tt.in), "", ""); err != nil {
+			if !reflect.DeepEqual(err, tt.err) {
+				t.Errorf("#%d: Indent: %#v", i, err)
+				continue
+			}
+		}
+	}
+}
+
+func TestNextValueBig(t *testing.T) {
+	initBig()
+	var scan Scanner
+	item, rest, err := NextValue(jsonBig, &scan)
+	if err != nil {
+		t.Fatalf("NextValue: %s", err)
+	}
+	if len(item) != len(jsonBig) || &item[0] != &jsonBig[0] {
+		t.Errorf("invalid item: %d %d", len(item), len(jsonBig))
+	}
+	if len(rest) != 0 {
+		t.Errorf("invalid rest: %d", len(rest))
+	}
+
+	item, rest, err = NextValue(append(jsonBig, "HELLO WORLD"...), &scan)
+	if err != nil {
+		t.Fatalf("NextValue extra: %s", err)
+	}
+	if len(item) != len(jsonBig) {
+		t.Errorf("invalid item: %d %d", len(item), len(jsonBig))
+	}
+	if string(rest) != "HELLO WORLD" {
+		t.Errorf("invalid rest: %d", len(rest))
+	}
+}
+
+var benchScan Scanner
+
+func BenchmarkSkipValue(b *testing.B) {
+	initBig()
+	for i := 0; i < b.N; i++ {
+		NextValue(jsonBig, &benchScan)
+	}
+	b.SetBytes(int64(len(jsonBig)))
+}
+
+func diff(t *testing.T, a, b []byte) {
+	for i := 0; ; i++ {
+		if i >= len(a) || i >= len(b) || a[i] != b[i] {
+			j := i - 10
+			if j < 0 {
+				j = 0
+			}
+			t.Errorf("diverge at %d: «%s» vs «%s»", i, trim(a[j:]), trim(b[j:]))
+			return
+		}
+	}
+}
+
+func trim(b []byte) []byte {
+	if len(b) > 20 {
+		return b[0:20]
+	}
+	return b
+}
+
+// Generate a random JSON object.
+
+var jsonBig []byte
+
+func initBig() {
+	n := 10000
+	if testing.Short() {
+		n = 100
+	}
+	b, err := Marshal(genValue(n))
+	if err != nil {
+		panic(err)
+	}
+	jsonBig = b
+}
+
+func genValue(n int) interface{} {
+	if n > 1 {
+		switch rand.Intn(2) {
+		case 0:
+			return genArray(n)
+		case 1:
+			return genMap(n)
+		}
+	}
+	switch rand.Intn(3) {
+	case 0:
+		return rand.Intn(2) == 0
+	case 1:
+		return rand.NormFloat64()
+	case 2:
+		return genString(30)
+	}
+	panic("unreachable")
+}
+
+func genString(stddev float64) string {
+	n := int(math.Abs(rand.NormFloat64()*stddev + stddev/2))
+	c := make([]rune, n)
+	for i := range c {
+		f := math.Abs(rand.NormFloat64()*64 + 32)
+		if f > 0x10ffff {
+			f = 0x10ffff
+		}
+		c[i] = rune(f)
+	}
+	return string(c)
+}
+
+func genArray(n int) []interface{} {
+	f := int(math.Abs(rand.NormFloat64()) * math.Min(10, float64(n/2)))
+	if f > n {
+		f = n
+	}
+	if f < 1 {
+		f = 1
+	}
+	x := make([]interface{}, f)
+	for i := range x {
+		x[i] = genValue(((i+1)*n)/f - (i*n)/f)
+	}
+	return x
+}
+
+func genMap(n int) map[string]interface{} {
+	f := int(math.Abs(rand.NormFloat64()) * math.Min(10, float64(n/2)))
+	if f > n {
+		f = n
+	}
+	if n > 0 && f == 0 {
+		f = 1
+	}
+	x := make(map[string]interface{})
+	for i := 0; i < f; i++ {
+		x[genString(10)] = genValue(((i+1)*n)/f - (i*n)/f)
+	}
+	return x
+}

+ 206 - 0
vendor/github.com/dustin/gojson/stream_test.go

@@ -0,0 +1,206 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+	"bytes"
+	"io/ioutil"
+	"net"
+	"reflect"
+	"strings"
+	"testing"
+)
+
+// Test values for the stream test.
+// One of each JSON kind.
+var streamTest = []interface{}{
+	0.1,
+	"hello",
+	nil,
+	true,
+	false,
+	[]interface{}{"a", "b", "c"},
+	map[string]interface{}{"K": "Kelvin", "ß": "long s"},
+	3.14, // another value to make sure something can follow map
+}
+
+var streamEncoded = `0.1
+"hello"
+null
+true
+false
+["a","b","c"]
+{"ß":"long s","K":"Kelvin"}
+3.14
+`
+
+func TestEncoder(t *testing.T) {
+	for i := 0; i <= len(streamTest); i++ {
+		var buf bytes.Buffer
+		enc := NewEncoder(&buf)
+		for j, v := range streamTest[0:i] {
+			if err := enc.Encode(v); err != nil {
+				t.Fatalf("encode #%d: %v", j, err)
+			}
+		}
+		if have, want := buf.String(), nlines(streamEncoded, i); have != want {
+			t.Errorf("encoding %d items: mismatch", i)
+			diff(t, []byte(have), []byte(want))
+			break
+		}
+	}
+}
+
+func TestDecoder(t *testing.T) {
+	for i := 0; i <= len(streamTest); i++ {
+		// Use stream without newlines as input,
+		// just to stress the decoder even more.
+		// Our test input does not include back-to-back numbers.
+		// Otherwise stripping the newlines would
+		// merge two adjacent JSON values.
+		var buf bytes.Buffer
+		for _, c := range nlines(streamEncoded, i) {
+			if c != '\n' {
+				buf.WriteRune(c)
+			}
+		}
+		out := make([]interface{}, i)
+		dec := NewDecoder(&buf)
+		for j := range out {
+			if err := dec.Decode(&out[j]); err != nil {
+				t.Fatalf("decode #%d/%d: %v", j, i, err)
+			}
+		}
+		if !reflect.DeepEqual(out, streamTest[0:i]) {
+			t.Errorf("decoding %d items: mismatch", i)
+			for j := range out {
+				if !reflect.DeepEqual(out[j], streamTest[j]) {
+					t.Errorf("#%d: have %v want %v", j, out[j], streamTest[j])
+				}
+			}
+			break
+		}
+	}
+}
+
+func TestDecoderBuffered(t *testing.T) {
+	r := strings.NewReader(`{"Name": "Gopher"} extra `)
+	var m struct {
+		Name string
+	}
+	d := NewDecoder(r)
+	err := d.Decode(&m)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if m.Name != "Gopher" {
+		t.Errorf("Name = %q; want Gopher", m.Name)
+	}
+	rest, err := ioutil.ReadAll(d.Buffered())
+	if err != nil {
+		t.Fatal(err)
+	}
+	if g, w := string(rest), " extra "; g != w {
+		t.Errorf("Remaining = %q; want %q", g, w)
+	}
+}
+
+func nlines(s string, n int) string {
+	if n <= 0 {
+		return ""
+	}
+	for i, c := range s {
+		if c == '\n' {
+			if n--; n == 0 {
+				return s[0 : i+1]
+			}
+		}
+	}
+	return s
+}
+
+func TestRawMessage(t *testing.T) {
+	// TODO(rsc): Should not need the * in *RawMessage
+	var data struct {
+		X  float64
+		Id *RawMessage
+		Y  float32
+	}
+	const raw = `["\u0056",null]`
+	const msg = `{"X":0.1,"Id":["\u0056",null],"Y":0.2}`
+	err := Unmarshal([]byte(msg), &data)
+	if err != nil {
+		t.Fatalf("Unmarshal: %v", err)
+	}
+	if string([]byte(*data.Id)) != raw {
+		t.Fatalf("Raw mismatch: have %#q want %#q", []byte(*data.Id), raw)
+	}
+	b, err := Marshal(&data)
+	if err != nil {
+		t.Fatalf("Marshal: %v", err)
+	}
+	if string(b) != msg {
+		t.Fatalf("Marshal: have %#q want %#q", b, msg)
+	}
+}
+
+func TestNullRawMessage(t *testing.T) {
+	// TODO(rsc): Should not need the * in *RawMessage
+	var data struct {
+		X  float64
+		Id *RawMessage
+		Y  float32
+	}
+	data.Id = new(RawMessage)
+	const msg = `{"X":0.1,"Id":null,"Y":0.2}`
+	err := Unmarshal([]byte(msg), &data)
+	if err != nil {
+		t.Fatalf("Unmarshal: %v", err)
+	}
+	if data.Id != nil {
+		t.Fatalf("Raw mismatch: have non-nil, want nil")
+	}
+	b, err := Marshal(&data)
+	if err != nil {
+		t.Fatalf("Marshal: %v", err)
+	}
+	if string(b) != msg {
+		t.Fatalf("Marshal: have %#q want %#q", b, msg)
+	}
+}
+
+var blockingTests = []string{
+	`{"x": 1}`,
+	`[1, 2, 3]`,
+}
+
+func TestBlocking(t *testing.T) {
+	for _, enc := range blockingTests {
+		r, w := net.Pipe()
+		go w.Write([]byte(enc))
+		var val interface{}
+
+		// If Decode reads beyond what w.Write writes above,
+		// it will block, and the test will deadlock.
+		if err := NewDecoder(r).Decode(&val); err != nil {
+			t.Errorf("decoding %s: %v", enc, err)
+		}
+		r.Close()
+		w.Close()
+	}
+}
+
+func BenchmarkEncoderEncode(b *testing.B) {
+	b.ReportAllocs()
+	type T struct {
+		X, Y string
+	}
+	v := &T{"foo", "bar"}
+	for i := 0; i < b.N; i++ {
+		if err := NewEncoder(ioutil.Discard).Encode(v); err != nil {
+			b.Fatal(err)
+		}
+	}
+}

+ 115 - 0
vendor/github.com/dustin/gojson/tagkey_test.go

@@ -0,0 +1,115 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+	"testing"
+)
+
+type basicLatin2xTag struct {
+	V string `json:"$%-/"`
+}
+
+type basicLatin3xTag struct {
+	V string `json:"0123456789"`
+}
+
+type basicLatin4xTag struct {
+	V string `json:"ABCDEFGHIJKLMO"`
+}
+
+type basicLatin5xTag struct {
+	V string `json:"PQRSTUVWXYZ_"`
+}
+
+type basicLatin6xTag struct {
+	V string `json:"abcdefghijklmno"`
+}
+
+type basicLatin7xTag struct {
+	V string `json:"pqrstuvwxyz"`
+}
+
+type miscPlaneTag struct {
+	V string `json:"色は匂へど"`
+}
+
+type percentSlashTag struct {
+	V string `json:"text/html%"` // http://golang.org/issue/2718
+}
+
+type punctuationTag struct {
+	V string `json:"!#$%&()*+-./:<=>?@[]^_{|}~"` // http://golang.org/issue/3546
+}
+
+type emptyTag struct {
+	W string
+}
+
+type misnamedTag struct {
+	X string `jsom:"Misnamed"`
+}
+
+type badFormatTag struct {
+	Y string `:"BadFormat"`
+}
+
+type badCodeTag struct {
+	Z string `json:" !\"#&'()*+,."`
+}
+
+type spaceTag struct {
+	Q string `json:"With space"`
+}
+
+type unicodeTag struct {
+	W string `json:"Ελλάδα"`
+}
+
+var structTagObjectKeyTests = []struct {
+	raw   interface{}
+	value string
+	key   string
+}{
+	{basicLatin2xTag{"2x"}, "2x", "$%-/"},
+	{basicLatin3xTag{"3x"}, "3x", "0123456789"},
+	{basicLatin4xTag{"4x"}, "4x", "ABCDEFGHIJKLMO"},
+	{basicLatin5xTag{"5x"}, "5x", "PQRSTUVWXYZ_"},
+	{basicLatin6xTag{"6x"}, "6x", "abcdefghijklmno"},
+	{basicLatin7xTag{"7x"}, "7x", "pqrstuvwxyz"},
+	{miscPlaneTag{"いろはにほへと"}, "いろはにほへと", "色は匂へど"},
+	{emptyTag{"Pour Moi"}, "Pour Moi", "W"},
+	{misnamedTag{"Animal Kingdom"}, "Animal Kingdom", "X"},
+	{badFormatTag{"Orfevre"}, "Orfevre", "Y"},
+	{badCodeTag{"Reliable Man"}, "Reliable Man", "Z"},
+	{percentSlashTag{"brut"}, "brut", "text/html%"},
+	{punctuationTag{"Union Rags"}, "Union Rags", "!#$%&()*+-./:<=>?@[]^_{|}~"},
+	{spaceTag{"Perreddu"}, "Perreddu", "With space"},
+	{unicodeTag{"Loukanikos"}, "Loukanikos", "Ελλάδα"},
+}
+
+func TestStructTagObjectKey(t *testing.T) {
+	for _, tt := range structTagObjectKeyTests {
+		b, err := Marshal(tt.raw)
+		if err != nil {
+			t.Fatalf("Marshal(%#q) failed: %v", tt.raw, err)
+		}
+		var f interface{}
+		err = Unmarshal(b, &f)
+		if err != nil {
+			t.Fatalf("Unmarshal(%#q) failed: %v", b, err)
+		}
+		for i, v := range f.(map[string]interface{}) {
+			switch i {
+			case tt.key:
+				if s, ok := v.(string); !ok || s != tt.value {
+					t.Fatalf("Unexpected value: %#q, want %v", s, tt.value)
+				}
+			default:
+				t.Fatalf("Unexpected key: %#q, from %#q", i, b)
+			}
+		}
+	}
+}

+ 28 - 0
vendor/github.com/dustin/gojson/tags_test.go

@@ -0,0 +1,28 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+	"testing"
+)
+
+func TestTagParsing(t *testing.T) {
+	name, opts := parseTag("field,foobar,foo")
+	if name != "field" {
+		t.Fatalf("name = %q, want field", name)
+	}
+	for _, tt := range []struct {
+		opt  string
+		want bool
+	}{
+		{"foobar", true},
+		{"foo", true},
+		{"bar", false},
+	} {
+		if opts.Contains(tt.opt) != tt.want {
+			t.Errorf("Contains(%q) = %v", tt.opt, !tt.want)
+		}
+	}
+}

+ 5 - 0
vendor/github.com/garyburd/go-oauth/.gitignore

@@ -0,0 +1,5 @@
+_testmain.go
+*.6
+*.a
+6.out
+example

+ 9 - 0
vendor/github.com/garyburd/go-oauth/.travis.yml

@@ -0,0 +1,9 @@
+language: go
+
+sudo: false
+
+go:
+  - 1.6
+  - 1.7
+  - 1.8
+  - tip

+ 34 - 0
vendor/github.com/garyburd/go-oauth/README.markdown

@@ -0,0 +1,34 @@
+# Go-OAuth
+
+[![GoDoc](https://godoc.org/github.com/garyburd/go-oauth/oauth?status.svg)](https://godoc.org/github.com/garyburd/go-oauth/oauth)
+[![Build Status](https://travis-ci.org/garyburd/go-oauth.svg?branch=master)](https://travis-ci.org/garyburd/go-oauth)
+
+Go-OAuth is a [Go](http://golang.org/) client for the OAuth 1.0, OAuth 1.0a and
+[RFC 5849](https://tools.ietf.org/html/rfc5849) Protocols. The package supports
+HMAC-SHA1, RSA-SHA1 and PLAINTEXT signatures.
+
+Future development of Go-OAuth is at
+[github.com/gomodule/oauth1](https://github.com/gomodule/oauth1). Please submit
+issues at gomodule/oauth1.
+
+
+## Installation
+
+    go get github.com/garyburd/go-oauth/oauth
+
+## License
+
+Go-OAuth is available under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html).
+
+## Documentation
+    
+- [Reference](http://godoc.org/github.com/garyburd/go-oauth/oauth)
+- Examples
+    - [Discogs](http://github.com/garyburd/go-oauth/tree/master/examples/discogs)
+    - [Dropbox](http://github.com/garyburd/go-oauth/tree/master/examples/dropbox)
+    - [Quickbooks](http://github.com/garyburd/go-oauth/tree/master/examples/quickbooks)
+    - [SmugMug](https://github.com/garyburd/go-oauth/tree/master/examples/smugmug)
+    - [Twitter on App Engine](http://github.com/garyburd/go-oauth/tree/master/examples/appengine) 
+    - [Twitter](http://github.com/garyburd/go-oauth/tree/master/examples/twitter) 
+    - [Twitter OOB](http://github.com/garyburd/go-oauth/tree/master/examples/twitteroob) (a command line application using OOB authorization)
+    - [Yelp](https://github.com/garyburd/go-oauth/tree/master/examples/yelp)

+ 56 - 0
vendor/github.com/garyburd/go-oauth/oauth/examples_test.go

@@ -0,0 +1,56 @@
+// Copyright 2013 Gary Burd
+//
+// 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 oauth_test
+
+import (
+	"github.com/garyburd/go-oauth/oauth"
+	"net/http"
+	"net/url"
+	"strings"
+)
+
+// This example shows how to sign a request when the URL Opaque field is used.
+// See the note at http://golang.org/pkg/net/url/#URL for information on the
+// use of the URL Opaque field.
+func ExampleClient_SetAuthorizationHeader(client *oauth.Client, credentials *oauth.Credentials) error {
+	form := url.Values{"maxResults": {"100"}}
+
+	// The last element of path contains a "/".
+	path := "/document/encoding%2gizp"
+
+	// Create the request with the temporary path "/".
+	req, err := http.NewRequest("GET", "http://api.example.com/", strings.NewReader(form.Encode()))
+	if err != nil {
+		return err
+	}
+
+	// Overwrite the temporary path with the actual request path.
+	req.URL.Opaque = path
+
+	// Sign the request.
+	if err := client.SetAuthorizationHeader(req.Header, credentials, "GET", req.URL, form); err != nil {
+		return err
+	}
+
+	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+
+	resp, err := http.DefaultClient.Do(req)
+	if err != nil {
+		return err
+	}
+	defer resp.Body.Close()
+	// process the response
+	return nil
+}

+ 24 - 0
vendor/github.com/garyburd/go-oauth/oauth/oauth17_test.go

@@ -0,0 +1,24 @@
+// +build go1.7
+
+package oauth
+
+import (
+	"context"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+)
+
+func TestGetContext_Cancel(t *testing.T) {
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+	}))
+	defer ts.Close()
+
+	ctx, cancel := context.WithCancel(context.Background())
+	cancel()
+	c := Client{}
+	_, err := c.GetContext(ctx, &Credentials{}, ts.URL, nil)
+	if err == nil {
+		t.Error("error should not be nil")
+	}
+}

+ 484 - 0
vendor/github.com/garyburd/go-oauth/oauth/oauth_test.go

@@ -0,0 +1,484 @@
+// Copyright 2010 Gary Burd
+//
+// 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 oauth
+
+import (
+	"bytes"
+	"crypto/x509"
+	"encoding/pem"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"net/http/cookiejar"
+	"net/http/httptest"
+	"net/url"
+	"strings"
+	"testing"
+
+	"golang.org/x/net/context"
+)
+
+func parseURL(urlStr string) *url.URL {
+	u, err := url.Parse(urlStr)
+	if err != nil {
+		panic(err)
+	}
+	return u
+}
+
+var oauthTests = []struct {
+	method    string
+	url       *url.URL
+	form      url.Values
+	nonce     string
+	timestamp string
+
+	clientCredentials Credentials
+	credentials       Credentials
+
+	signatureMethod SignatureMethod
+
+	base   string
+	header string
+}{
+	{
+		// Simple example from Twitter OAuth tool
+		method:            "GET",
+		url:               parseURL("https://api.twitter.com/1/"),
+		form:              url.Values{"page": {"10"}},
+		nonce:             "8067e8abc6bdca2006818132445c8f4c",
+		timestamp:         "1355795903",
+		clientCredentials: Credentials{"kMViZR2MHk2mM7hUNVw9A", "56Fgl58yOfqXOhHXX0ybvOmSnPQFvR2miYmm30A"},
+		credentials:       Credentials{"10212-JJ3Zc1A49qSMgdcAO2GMOpW9l7A348ESmhjmOBOU", "yF75mvq4LZMHj9O0DXwoC3ZxUnN1ptvieThYuOAYM"},
+		base:              `GET&https%3A%2F%2Fapi.twitter.com%2F1%2F&oauth_consumer_key%3DkMViZR2MHk2mM7hUNVw9A%26oauth_nonce%3D8067e8abc6bdca2006818132445c8f4c%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1355795903%26oauth_token%3D10212-JJ3Zc1A49qSMgdcAO2GMOpW9l7A348ESmhjmOBOU%26oauth_version%3D1.0%26page%3D10`,
+		header:            `OAuth oauth_consumer_key="kMViZR2MHk2mM7hUNVw9A", oauth_nonce="8067e8abc6bdca2006818132445c8f4c", oauth_signature="o5cx1ggJrY9ognZuVVeUwglKV8U%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1355795903", oauth_token="10212-JJ3Zc1A49qSMgdcAO2GMOpW9l7A348ESmhjmOBOU", oauth_version="1.0"`,
+	},
+	{
+		// Test case and port insensitivity.
+		method:            "GeT",
+		url:               parseURL("https://apI.twItter.com:443/1/"),
+		form:              url.Values{"page": {"10"}},
+		nonce:             "8067e8abc6bdca2006818132445c8f4c",
+		timestamp:         "1355795903",
+		clientCredentials: Credentials{"kMViZR2MHk2mM7hUNVw9A", "56Fgl58yOfqXOhHXX0ybvOmSnPQFvR2miYmm30A"},
+		credentials:       Credentials{"10212-JJ3Zc1A49qSMgdcAO2GMOpW9l7A348ESmhjmOBOU", "yF75mvq4LZMHj9O0DXwoC3ZxUnN1ptvieThYuOAYM"},
+		base:              `GET&https%3A%2F%2Fapi.twitter.com%2F1%2F&oauth_consumer_key%3DkMViZR2MHk2mM7hUNVw9A%26oauth_nonce%3D8067e8abc6bdca2006818132445c8f4c%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1355795903%26oauth_token%3D10212-JJ3Zc1A49qSMgdcAO2GMOpW9l7A348ESmhjmOBOU%26oauth_version%3D1.0%26page%3D10`,
+		header:            `OAuth oauth_consumer_key="kMViZR2MHk2mM7hUNVw9A", oauth_nonce="8067e8abc6bdca2006818132445c8f4c", oauth_signature="o5cx1ggJrY9ognZuVVeUwglKV8U%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1355795903", oauth_token="10212-JJ3Zc1A49qSMgdcAO2GMOpW9l7A348ESmhjmOBOU", oauth_version="1.0"`,
+	},
+	{
+		// Example generated using the Netflix OAuth tool.
+		method:            "GET",
+		url:               parseURL("http://api-public.netflix.com/catalog/titles"),
+		form:              url.Values{"term": {"Dark Knight"}, "count": {"2"}},
+		nonce:             "1234",
+		timestamp:         "1355850443",
+		clientCredentials: Credentials{"apiKey001", "sharedSecret002"},
+		credentials:       Credentials{"accessToken003", "accessSecret004"},
+		base:              `GET&http%3A%2F%2Fapi-public.netflix.com%2Fcatalog%2Ftitles&count%3D2%26oauth_consumer_key%3DapiKey001%26oauth_nonce%3D1234%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1355850443%26oauth_token%3DaccessToken003%26oauth_version%3D1.0%26term%3DDark%2520Knight`,
+		header:            `OAuth oauth_consumer_key="apiKey001", oauth_nonce="1234", oauth_signature="0JAoaqt6oz6TJx8N%2B06XmhPjcOs%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1355850443", oauth_token="accessToken003", oauth_version="1.0"`,
+	},
+	{
+		// Special characters in form values.
+		method:            "GET",
+		url:               parseURL("http://PHOTOS.example.net:8001/Photos"),
+		form:              url.Values{"photo size": {"300%"}, "title": {"Back of $100 Dollars Bill"}},
+		nonce:             "kllo~9940~pd9333jh",
+		timestamp:         "1191242096",
+		clientCredentials: Credentials{"dpf43f3++p+#2l4k3l03", "secret01"},
+		credentials:       Credentials{"nnch734d(0)0sl2jdk", "secret02"},
+		base:              "GET&http%3A%2F%2Fphotos.example.net%3A8001%2FPhotos&oauth_consumer_key%3Ddpf43f3%252B%252Bp%252B%25232l4k3l03%26oauth_nonce%3Dkllo~9940~pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d%25280%25290sl2jdk%26oauth_version%3D1.0%26photo%2520size%3D300%2525%26title%3DBack%2520of%2520%2524100%2520Dollars%2520Bill",
+		header:            `OAuth oauth_consumer_key="dpf43f3%2B%2Bp%2B%232l4k3l03", oauth_nonce="kllo~9940~pd9333jh", oauth_signature="n1UAoQy2PoIYizZUiWvkdCxM3P0%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1191242096", oauth_token="nnch734d%280%290sl2jdk", oauth_version="1.0"`,
+	},
+	{
+		// Special characters in path, multiple values for same key in form.
+		method:            "GET",
+		url:               parseURL("http://EXAMPLE.COM:80/Space%20Craft"),
+		form:              url.Values{"name": {"value", "value"}},
+		nonce:             "Ix4U1Ei3RFL",
+		timestamp:         "1327384901",
+		clientCredentials: Credentials{"abcd", "efgh"},
+		credentials:       Credentials{"ijkl", "mnop"},
+		base:              "GET&http%3A%2F%2Fexample.com%2FSpace%2520Craft&name%3Dvalue%26name%3Dvalue%26oauth_consumer_key%3Dabcd%26oauth_nonce%3DIx4U1Ei3RFL%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1327384901%26oauth_token%3Dijkl%26oauth_version%3D1.0",
+		header:            `OAuth oauth_consumer_key="abcd", oauth_nonce="Ix4U1Ei3RFL", oauth_signature="TZZ5u7qQorLnmKs%2Biqunb8gqkh4%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1327384901", oauth_token="ijkl", oauth_version="1.0"`,
+	},
+	{
+		// Query string in URL.
+		method:            "GET",
+		url:               parseURL("http://EXAMPLE.COM:80/Space%20Craft?name=value"),
+		form:              url.Values{"name": {"value"}},
+		nonce:             "Ix4U1Ei3RFL",
+		timestamp:         "1327384901",
+		clientCredentials: Credentials{"abcd", "efgh"},
+		credentials:       Credentials{"ijkl", "mnop"},
+		base:              "GET&http%3A%2F%2Fexample.com%2FSpace%2520Craft&name%3Dvalue%26name%3Dvalue%26oauth_consumer_key%3Dabcd%26oauth_nonce%3DIx4U1Ei3RFL%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1327384901%26oauth_token%3Dijkl%26oauth_version%3D1.0",
+		header:            `OAuth oauth_consumer_key="abcd", oauth_nonce="Ix4U1Ei3RFL", oauth_signature="TZZ5u7qQorLnmKs%2Biqunb8gqkh4%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1327384901", oauth_token="ijkl", oauth_version="1.0"`,
+	},
+	{
+		// "/" in form value.
+		method:            "POST",
+		url:               parseURL("https://stream.twitter.com/1.1/statuses/filter.json"),
+		form:              url.Values{"track": {"example.com/abcd"}},
+		nonce:             "bf2cb6d611e59f99103238fc9a3bb8d8",
+		timestamp:         "1362434376",
+		clientCredentials: Credentials{"consumer_key", "consumer_secret"},
+		credentials:       Credentials{"token", "secret"},
+		base:              "POST&https%3A%2F%2Fstream.twitter.com%2F1.1%2Fstatuses%2Ffilter.json&oauth_consumer_key%3Dconsumer_key%26oauth_nonce%3Dbf2cb6d611e59f99103238fc9a3bb8d8%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1362434376%26oauth_token%3Dtoken%26oauth_version%3D1.0%26track%3Dexample.com%252Fabcd",
+		header:            `OAuth oauth_consumer_key="consumer_key", oauth_nonce="bf2cb6d611e59f99103238fc9a3bb8d8", oauth_signature="LcxylEOnNdgoKSJi7jX07mxcvfM%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1362434376", oauth_token="token", oauth_version="1.0"`,
+	},
+	{
+		// "/" in query string
+		method:            "POST",
+		url:               parseURL("https://stream.twitter.com/1.1/statuses/filter.json?track=example.com/query"),
+		form:              url.Values{},
+		nonce:             "884275759fbab914654b50ae643c563a",
+		timestamp:         "1362435218",
+		clientCredentials: Credentials{"consumer_key", "consumer_secret"},
+		credentials:       Credentials{"token", "secret"},
+		base:              "POST&https%3A%2F%2Fstream.twitter.com%2F1.1%2Fstatuses%2Ffilter.json&oauth_consumer_key%3Dconsumer_key%26oauth_nonce%3D884275759fbab914654b50ae643c563a%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1362435218%26oauth_token%3Dtoken%26oauth_version%3D1.0%26track%3Dexample.com%252Fquery",
+		header:            `OAuth oauth_consumer_key="consumer_key", oauth_nonce="884275759fbab914654b50ae643c563a", oauth_signature="OAldqvRrKDXRGZ9BqSi2CqeVH0g%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1362435218", oauth_token="token", oauth_version="1.0"`,
+	},
+	{
+		// QuickBooks query string
+		method:            "GET",
+		url:               parseURL("https://qb.sbfinance.intuit.com/v3/company/1273852765/query"),
+		form:              url.Values{"query": {"select * from account"}},
+		nonce:             "12345678",
+		timestamp:         "1409876517",
+		clientCredentials: Credentials{"consumer_key", "consumer_secret"},
+		credentials:       Credentials{"token", "secret"},
+		base:              "GET&https%3A%2F%2Fqb.sbfinance.intuit.com%2Fv3%2Fcompany%2F1273852765%2Fquery&oauth_consumer_key%3Dconsumer_key%26oauth_nonce%3D12345678%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1409876517%26oauth_token%3Dtoken%26oauth_version%3D1.0%26query%3Dselect%2520%252A%2520from%2520account",
+		header:            `OAuth oauth_consumer_key="consumer_key", oauth_nonce="12345678", oauth_signature="7crYee%2BJLvg7dksQiHbarUHN3rY%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1409876517", oauth_token="token", oauth_version="1.0"`,
+	},
+	{
+		// Plain text signature method
+		signatureMethod:   PLAINTEXT,
+		method:            "GET",
+		url:               parseURL("http://example.com/"),
+		clientCredentials: Credentials{"key", "secret"},
+		credentials:       Credentials{"accesskey", "accesssecret"},
+		header:            `OAuth oauth_consumer_key="key", oauth_signature="secret%26accesssecret", oauth_signature_method="PLAINTEXT", oauth_token="accesskey", oauth_version="1.0"`,
+	},
+	{
+		// RSA-SHA1 signature method
+		signatureMethod:   RSASHA1,
+		method:            "GET",
+		url:               parseURL("http://term.ie/oauth/example/echo_api.php"),
+		form:              url.Values{"method": {"foo%20bar"}, "bar": {"baz"}},
+		nonce:             "a7da4d14579d61886be9d596d1a6a720",
+		timestamp:         "1420240290",
+		clientCredentials: Credentials{Token: "key"},
+		credentials:       Credentials{Token: "accesskey"},
+		base:              `GET&http%3A%2F%2Fterm.ie%2Foauth%2Fexample%2Fecho_api.php&bar%3Dbaz%26method%3Dfoo%252520bar%26oauth_consumer_key%3Dkey%26oauth_nonce%3Da7da4d14579d61886be9d596d1a6a720%26oauth_signature_method%3DRSA-SHA1%26oauth_timestamp%3D1420240290%26oauth_token%3Daccesskey%26oauth_version%3D1.0`,
+		header:            `OAuth oauth_consumer_key="key", oauth_nonce="a7da4d14579d61886be9d596d1a6a720", oauth_signature="jPun728OkfFo7BjZiaQ5UBVChwk6tf0uKNFDmNKVb%2Bd6aWYEzsDVkqqjcgTrCRNabK8ubAnhyprafk0mk3zEJe%2BxGb9GKauqwUJ6ZZoGJNYYZg3BZUQvdxSKFs1M4MUMv3fxntmD%2BoyE8jPbrVM2zD1G1AAPm79sX%2B8XE25tBE8%3D", oauth_signature_method="RSA-SHA1", oauth_timestamp="1420240290", oauth_token="accesskey", oauth_version="1.0"`,
+	},
+}
+
+func TestBaseString(t *testing.T) {
+	for _, ot := range oauthTests {
+		if ot.signatureMethod == PLAINTEXT {
+			// PLAINTEXT signature does not use the base string.
+			continue
+		}
+		oauthParams := map[string]string{
+			"oauth_consumer_key":     ot.clientCredentials.Token,
+			"oauth_nonce":            ot.nonce,
+			"oauth_signature_method": ot.signatureMethod.String(),
+			"oauth_timestamp":        ot.timestamp,
+			"oauth_token":            ot.credentials.Token,
+			"oauth_version":          "1.0",
+		}
+		var buf bytes.Buffer
+		writeBaseString(&buf, ot.method, ot.url, ot.form, oauthParams)
+		base := buf.String()
+		if base != ot.base {
+			t.Errorf("base string for %s %s\n    = %q,\n want %q", ot.method, ot.url, base, ot.base)
+		}
+	}
+}
+
+var pemPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQC0YjCwIfYoprq/FQO6lb3asXrxLlJFuCvtinTF5p0GxvQGu5O3
+gYytUvtC2JlYzypSRjVxwxrsuRcP3e641SdASwfrmzyvIgP08N4S0IFzEURkV1wp
+/IpH7kH41EtbmUmrXSwfNZsnQRE5SYSOhh+LcK2wyQkdgcMv11l4KoBkcwIDAQAB
+AoGAWFlbZXlM2r5G6z48tE+RTKLvB1/btgAtq8vLw/5e3KnnbcDD6fZO07m4DRaP
+jRryrJdsp8qazmUdcY0O1oK4FQfpprknDjP+R1XHhbhkQ4WEwjmxPstZMUZaDWF5
+8d3otc23mCzwh3YcUWFu09KnMpzZsK59OfyjtkS44EDWpbECQQDXgN0ODboKsuEA
+VAhAtPUqspU9ivRa6yLai9kCnPb9GcztrsJZQm4NHcKVbmD2F2L4pDRx4Pmglhfl
+V7G/a6T7AkEA1kfU0+DkXc6I/jXHJ6pDLA5s7dBHzWgDsBzplSdkVQbKT3MbeYje
+ByOxzXhulOWLBQW/vxmW4HwU95KTRlj06QJASPoBYY3yb0cN/J94P/lHgJMDCNky
+UEuJ/PoYndLrrN/8zow8kh91xwlJ6HJ9cTiQMmTgwaOOxPuu0eI1df4M2wJBAJJS
+WrKUT1z/O+zbLDOZwGTFNPzvzRgmft4z4A1J6OlmyZ+XKpvDKloVtcRpCJoEZPn5
+AwaroquID4k/PfI7rIECQHeWa6+kPADv9IrK/92mujujS0MSEiynDw5NjTnHAH0v
+8TrXzs+LCWDN/gbOCKPfnWRkgwgOeC8NN3h0zUIIUtA=
+-----END RSA PRIVATE KEY-----
+`
+
+func TestAuthorizationHeader(t *testing.T) {
+	originalTestHook := testHook
+	defer func() {
+		testHook = originalTestHook
+	}()
+
+	block, _ := pem.Decode([]byte(pemPrivateKey))
+	privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, ot := range oauthTests {
+		testHook = func(p map[string]string) {
+			if _, ok := p["oauth_nonce"]; ok {
+				p["oauth_nonce"] = ot.nonce
+			}
+			if _, ok := p["oauth_timestamp"]; ok {
+				p["oauth_timestamp"] = ot.timestamp
+			}
+		}
+		c := Client{Credentials: ot.clientCredentials, SignatureMethod: ot.signatureMethod, PrivateKey: privateKey}
+		header, err := c.authorizationHeader(&request{credentials: &ot.credentials, method: ot.method, u: ot.url, form: ot.form})
+		if err != nil {
+			t.Errorf("authorizationHeader(&cred, %q, %q, %v) returned error %v", ot.method, ot.url.String(), ot.form, err)
+			continue
+		}
+		if header != ot.header {
+			t.Errorf("authorizationHeader(&cred, %q, %q, %v) =\n      %s\nwant: %s", ot.method, ot.url.String(), ot.form, header, ot.header)
+		}
+	}
+}
+
+func TestNonce(t *testing.T) {
+	// This test is flaky, but failures should be very rare.
+	n := nonce()
+	if len(n) < 8 {
+		t.Fatalf("nonce is %s, exected something longer", n)
+	}
+}
+
+func TestRequestToken(t *testing.T) {
+	var method string
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		expectedMethod := method
+		if method == "" {
+			expectedMethod = http.MethodPost
+		}
+		if r.Method != expectedMethod {
+			t.Errorf("got method %s, want %s", r.Method, expectedMethod)
+		}
+		expectedContenType := ""
+		if r.Method != http.MethodGet {
+			expectedContenType = "application/x-www-form-urlencoded"
+		}
+		if contentType := r.Header.Get("Content-Type"); contentType != expectedContenType {
+			t.Errorf("got content type %q, want %q", contentType, expectedContenType)
+		}
+		if auth := r.Header.Get("Authorization"); !strings.Contains(auth, `oauth_verifier="verifier"`) {
+			t.Errorf("verifier missing from auth header %q", auth)
+		}
+		v := url.Values{}
+		v.Set("oauth_token", "token")
+		v.Set("oauth_token_secret", "secret")
+		io.WriteString(w, v.Encode())
+	}))
+	defer ts.Close()
+
+	for _, method = range []string{"", "GET", "POST"} {
+		c := Client{TokenRequestURI: ts.URL, TokenCredentailsMethod: method}
+		cred, _, err := c.RequestToken(http.DefaultClient, &Credentials{}, "verifier")
+		if err != nil {
+			t.Errorf("returned error %v", err)
+		}
+		if cred.Token != "token" {
+			t.Errorf("token for %s want %s", cred.Token, "token")
+		}
+		if cred.Secret != "secret" {
+			t.Errorf("secret for %s want %s", cred.Secret, "secret")
+		}
+	}
+}
+
+func TestRenewRequestCredentials(t *testing.T) {
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		a := r.Header.Get("Authorization")
+		if !strings.Contains(a, `oauth_token="token"`) {
+			t.Errorf("Authorization header %q should contains %q", a, `oauth_token="token"`)
+		}
+		if !strings.Contains(a, `oauth_session_handle="session-handle"`) {
+			t.Errorf("Authorization header %q should contains %q", a, `oauth_session_handle="session-handle"`)
+		}
+		v := url.Values{}
+		v.Set("oauth_token", "response-token")
+		v.Set("oauth_token_secret", "response-token-secret")
+		v.Set("oauth_session_handle", "response-session-handle")
+		io.WriteString(w, v.Encode())
+	}))
+	defer ts.Close()
+
+	c := Client{RenewCredentialRequestURI: ts.URL}
+	cred, rv, err := c.RenewRequestCredentials(http.DefaultClient, &Credentials{Token: "token"}, "session-handle")
+	if err != nil {
+		t.Errorf("returned error %v", err)
+	}
+	if cred.Token != "response-token" {
+		t.Errorf("token for %s want %s", cred.Token, "response-token")
+	}
+	if cred.Secret != "response-token-secret" {
+		t.Errorf("secret for %s want %s", cred.Secret, "response-token-secret")
+	}
+	if rv.Get("oauth_session_handle") != "response-session-handle" {
+		t.Errorf("session handle for %s want %s", rv.Get("oauth_session_handle"), "response-session-handle")
+	}
+}
+
+func TestGet(t *testing.T) {
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.Method != http.MethodGet {
+			t.Errorf("got method %s, want %s", r.Method, http.MethodGet)
+		}
+		if err := r.ParseForm(); err != nil {
+			t.Errorf("returned error %v", err)
+		}
+		if form := r.Form.Get("form"); form != "foo" {
+			t.Errorf("form %s, want %s", form, "foo")
+		}
+		cookie, err := r.Cookie("client-cookie")
+		if err != nil {
+			t.Errorf("returned error %v", err)
+		}
+		if cookie.Value != "foobar" {
+			t.Errorf("client-cookie %s, want %s", cookie.Value, "foobar")
+		}
+		io.WriteString(w, "bar")
+	}))
+	defer ts.Close()
+
+	u, err := url.Parse(ts.URL)
+	if err != nil {
+		t.Errorf("returned error %v", err)
+	}
+	jar, err := cookiejar.New(nil)
+	if err != nil {
+		t.Errorf("returned error %v", err)
+	}
+	jar.SetCookies(u, []*http.Cookie{&http.Cookie{Name: "client-cookie", Value: "foobar"}})
+	v := url.Values{}
+	v.Set("form", "foo")
+	c := Client{}
+	resp, err := c.Get(&http.Client{Jar: jar}, &Credentials{}, u.String(), v)
+	if err != nil {
+		t.Errorf("returned error %v", err)
+	}
+	defer resp.Body.Close()
+	b, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		t.Errorf("returned error %v", err)
+	}
+	if string(b) != "bar" {
+		t.Errorf("body %s, want %s", string(b), "bar")
+	}
+}
+
+func TestGet_ClientNil(t *testing.T) {
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.Method != http.MethodGet {
+			t.Errorf("got method %s, want %s", r.Method, http.MethodGet)
+		}
+		io.WriteString(w, "bar")
+	}))
+	defer ts.Close()
+
+	c := Client{}
+	resp, err := c.Get(nil, &Credentials{}, ts.URL, nil)
+	if err != nil {
+		t.Errorf("returned error %v", err)
+	}
+	defer resp.Body.Close()
+	b, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		t.Errorf("returned error %v", err)
+	}
+	if string(b) != "bar" {
+		t.Errorf("body %s, want %s", string(b), "bar")
+	}
+}
+
+func TestGetContext(t *testing.T) {
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.Method != http.MethodGet {
+			t.Errorf("got method %s, want %s", r.Method, http.MethodGet)
+		}
+		cookie, err := r.Cookie("client-cookie")
+		if err != nil {
+			t.Errorf("returned error %v", err)
+		}
+		if cookie.Value != "foobar" {
+			t.Errorf("client-cookie %s, want %s", cookie.Value, "foobar")
+		}
+		io.WriteString(w, "bar")
+	}))
+	defer ts.Close()
+
+	u, err := url.Parse(ts.URL)
+	if err != nil {
+		t.Errorf("returned error %v", err)
+	}
+	jar, err := cookiejar.New(nil)
+	if err != nil {
+		t.Errorf("returned error %v", err)
+	}
+	jar.SetCookies(u, []*http.Cookie{&http.Cookie{Name: "client-cookie", Value: "foobar"}})
+	ctx := context.WithValue(context.Background(), HTTPClient, &http.Client{Jar: jar})
+	c := Client{}
+	resp, err := c.GetContext(ctx, &Credentials{}, u.String(), nil)
+	if err != nil {
+		t.Errorf("returned error %v", err)
+	}
+	defer resp.Body.Close()
+	b, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		t.Errorf("returned error %v", err)
+	}
+	if string(b) != "bar" {
+		t.Errorf("body %s, want %s", string(b), "bar")
+	}
+}
+
+func TestRequestCredentialsError(t *testing.T) {
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("WWW-Authenticate", "oauth_problem=token_rejected")
+		w.WriteHeader(http.StatusUnauthorized)
+		io.WriteString(w, "oauth_problem=token_rejected")
+	}))
+	defer ts.Close()
+
+	c := Client{TokenRequestURI: ts.URL}
+	_, _, err := c.RequestToken(http.DefaultClient, &Credentials{}, "verifier")
+	if err == nil {
+		t.Error("error should not be nil")
+	}
+	if rce, ok := err.(RequestCredentialsError); ok {
+		if rce.StatusCode != http.StatusUnauthorized {
+			t.Errorf("status code %d, want %d", rce.StatusCode, http.StatusUnauthorized)
+		}
+		wa := rce.Header.Get("WWW-Authenticate")
+		if wa != "oauth_problem=token_rejected" {
+			t.Errorf("WWW-Authenticate header %s, want %s", wa, "oauth_problem=token_rejected")
+		}
+		if string(rce.Body) != "oauth_problem=token_rejected" {
+			t.Errorf("body %s,want %s", rce.Body, "oauth_problem=token_rejected")
+		}
+	} else {
+		t.Error("error should be assertable RequestCredentialsError")
+	}
+}

+ 13 - 0
vendor/github.com/go-pkgz/lgr/.gitignore

@@ -0,0 +1,13 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, build with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+vendor

+ 19 - 0
vendor/github.com/go-pkgz/lgr/.travis.yml

@@ -0,0 +1,19 @@
+language: go
+
+go:
+  - "1.11.x"
+
+install: true
+
+before_install:
+  - export TZ=America/Chicago
+  - curl -L https://git.io/vp6lP | sh 
+  - go get github.com/mattn/goveralls
+  - export PATH=$(pwd)/bin:$PATH
+
+script:
+  - GO111MODULE=on go get ./...
+  - GO111MODULE=on go mod vendor
+  - GO111MODULE=on go test  -v -mod=vendor -covermode=count -coverprofile=profile.cov ./... || travis_terminate 1;
+  - ./bin/gometalinter --deadline=120s --exclude=test --exclude=mock --exclude=vendor --exclude=_example --disable-all --enable=errcheck --enable=vet --enable=vetshadow --enable=megacheck --enable=ineffassign --enable=varcheck --enable=unconvert --enable=deadcode --enable=interfacer --enable=gotype ./... || travis_terminate 1;
+  - $GOPATH/bin/goveralls -coverprofile=profile.cov -service=travis-ci

+ 21 - 0
vendor/github.com/go-pkgz/lgr/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Umputun
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 48 - 0
vendor/github.com/go-pkgz/lgr/README.md

@@ -0,0 +1,48 @@
+# lgr - simple logger with some extras [![Build Status](https://travis-ci.org/go-pkgz/lgr.svg?branch=master)](https://travis-ci.org/go-pkgz/lgr) [![Coverage Status](https://coveralls.io/repos/github/go-pkgz/lgr/badge.svg?branch=master)](https://coveralls.io/github/go-pkgz/lgr?branch=master) [![godoc](https://godoc.org/github.com/go-pkgz/lgr?status.svg)](https://godoc.org/github.com/go-pkgz/lgr)
+
+## install
+
+`go get github/go-pkgz/lgr`
+
+## usage
+
+```go
+    l := lgr.New(lgr.Debug, lgr.Caller) // allow debug and caller info
+    l.Logf("INFO some important err message, %v", err)
+    l.Logf("DEBUG some less important err message, %v", err)
+```
+
+output looks like this:
+```
+2018/01/07 13:02:34.000 INFO  {svc/handler.go:101 h.MyFunc1} some important err message, can't open file`
+2018/01/07 13:02:34.015 DEBUG {svc/handler.go:155 h.MyFunc2} some less important err message, file is too small`
+```
+
+_Without `lgr.Caller` it will drop `{caller}` part_
+
+## details
+
+### interfaces and default loggers
+
+- `lgr` package provides a single interface `lgr.L` with a single method `Logf(format string, args ...interface{})`. Function wrapper `lgr.Func` allows to make `lgr.L` from a function directly.
+- Default logger functionality can be used without `lgr.New`, but just `lgr.Printf`
+- Two predefined loggers available: `lgr.NoOp` (do-nothing logger) and `lgr.Std` (passing directly to stdlib log)
+
+### options
+
+`lgr.New` call accepts functional options:
+
+- `lgr.Debug` - turn debug mode on. This allows messages with "DEBUG" level (filtered overwise)
+- `lgr.Caller` - adds the caller info each message
+- `lgr.Out(io.Writer)` - sets the output writer, default `os.Stdout`
+- `lgr.Err(io.Writer)` - sets the error writer, default `os.Stderr`
+
+### levels
+
+`lgr.Logf` recognizes prefixes like "INFO" or "[INFO]" as levels. The full list of supported levels - "DEBUG", "INFO", "WARN", "ERROR", "PANIC" and "FATAL"
+
+- `DEBUG` will be filtered unless `lgr.Debug` option defined
+- `INFO` and `WARN` don't have any special behavior attached
+- `ERROR` sends messages to both out and err writers
+- "PANIC" and "FATAL" send messages to both out and err writers. In addition sends dump of callers and runtime info to err only, and call `os.Exit(1)`.
+  

+ 3 - 0
vendor/github.com/go-pkgz/lgr/go.mod

@@ -0,0 +1,3 @@
+module github.com/go-pkgz/lgr
+
+require github.com/stretchr/testify v1.3.0

+ 7 - 0
vendor/github.com/go-pkgz/lgr/go.sum

@@ -0,0 +1,7 @@
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=

+ 41 - 0
vendor/github.com/go-pkgz/lgr/interface.go

@@ -0,0 +1,41 @@
+package lgr
+
+import stdlog "log"
+
+var def = New() // default logger doesn't allow DEBUG and doesn't add caller info
+
+// L defines minimal interface used to log things
+type L interface {
+	Logf(format string, args ...interface{})
+}
+
+// Func type is an adapter to allow the use of ordinary functions as Logger.
+type Func func(format string, args ...interface{})
+
+// Logf calls f(id)
+func (f Func) Logf(format string, args ...interface{}) { f(format, args...) }
+
+// NoOp logger
+var NoOp = Func(func(format string, args ...interface{}) {})
+
+// Std logger sends to std default logger directly
+var Std = Func(func(format string, args ...interface{}) { stdlog.Printf(format, args...) })
+
+// Printf simplifies replacement of std logger
+func Printf(format string, args ...interface{}) {
+	def.Logf(format, args...)
+}
+
+// Print simplifies replacement of std logger
+func Print(line string) {
+	def.Logf(line)
+}
+
+// Setup default logger with options
+func Setup(opts ...Option) {
+	def = New(opts...)
+	def.skipCallers = 2
+}
+
+// Default returns pre-constructed def logger (debug on, callers disabled)
+func Default() L { return def }

+ 74 - 0
vendor/github.com/go-pkgz/lgr/interface_test.go

@@ -0,0 +1,74 @@
+package lgr
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"log"
+	"os"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestLogger(t *testing.T) {
+	buff := bytes.NewBufferString("")
+	lg := Func(func(format string, args ...interface{}) {
+		fmt.Fprintf(buff, format, args...)
+	})
+
+	lg.Logf("blah %s %d something", "str", 123)
+	assert.Equal(t, "blah str 123 something", buff.String())
+
+	Std.Logf("blah %s %d something", "str", 123)
+	Std.Logf("[DEBUG] auth failed, %s", errors.New("blah blah"))
+}
+
+func TestStd(t *testing.T) {
+	buff := bytes.NewBufferString("")
+	log.SetOutput(buff)
+	defer log.SetOutput(os.Stdout)
+
+	Std.Logf("blah %s %d something", "str", 123)
+	assert.True(t, strings.HasSuffix(buff.String(), "blah str 123 something\n"), buff.String())
+}
+
+func TestNoOp(t *testing.T) {
+	buff := bytes.NewBufferString("")
+	log.SetOutput(buff)
+	defer log.SetOutput(os.Stdout)
+
+	NoOp.Logf("blah %s %d something", "str", 123)
+	assert.Equal(t, "", buff.String())
+}
+
+func TestDefault(t *testing.T) {
+	buff := bytes.NewBuffer([]byte{})
+	def.stdout = buff
+	def.now = func() time.Time { return time.Date(2018, 1, 7, 13, 2, 34, 0, time.Local) }
+	defer func() {
+		def.stdout = os.Stdout
+		def.now = time.Now
+	}()
+
+	Printf("[INFO] something 123 %s", "xyz")
+	assert.Equal(t, "2018/01/07 13:02:34.000 INFO  something 123 xyz\n", buff.String())
+
+	buff.Reset()
+	Printf("[DEBUG] something 123 %s", "xyz")
+	assert.Equal(t, "", buff.String())
+
+	buff.Reset()
+	Print("[WARN] something 123")
+	assert.Equal(t, "2018/01/07 13:02:34.000 WARN  something 123\n", buff.String())
+}
+
+func TestDefaultWithSetup(t *testing.T) {
+	buff := bytes.NewBuffer([]byte{})
+	Setup(Out(buff), Debug, CallerFile, CallerFunc)
+	def.now = func() time.Time { return time.Date(2018, 1, 7, 13, 2, 34, 0, time.Local) }
+	Printf("[INFO] something 123 %s", "xyz")
+	assert.Equal(t, "2018/01/07 13:02:34.000 INFO  {lgr/interface_test.go:72 lgr.TestDefaultWithSetup} something 123 xyz\n", buff.String())
+}

+ 173 - 0
vendor/github.com/go-pkgz/lgr/logger.go

@@ -0,0 +1,173 @@
+package lgr
+
+import (
+	"fmt"
+	"io"
+	"os"
+	"runtime"
+	"strings"
+	"sync"
+	"time"
+)
+
+var levels = []string{"DEBUG", "INFO", "WARN", "ERROR", "PANIC", "FATAL"}
+
+// Logger provided simple logger with basic support of levels. Thread safe
+type Logger struct {
+	stdout, stderr         io.Writer
+	dbg                    bool
+	lock                   sync.Mutex
+	callerFile, callerFunc bool
+	now                    nowFn
+	fatal                  panicFn
+	skipCallers            int
+	levelBraces            bool
+}
+
+type nowFn func() time.Time
+type panicFn func()
+
+// New makes new leveled logger. Accepts dbg flag turing on info about the caller and allowing DEBUG messages/
+// Two writers can be passed optionally - first for out and second for err
+func New(options ...Option) *Logger {
+	res := Logger{
+		now:         time.Now,
+		fatal:       func() { os.Exit(1) },
+		stdout:      os.Stdout,
+		stderr:      os.Stderr,
+		skipCallers: 1,
+	}
+	for _, opt := range options {
+		opt(&res)
+	}
+	return &res
+}
+
+// Logf implements L interface to output with printf style.
+// Each line prefixed with ts, level and optionally (dbg mode only) by caller info.
+// ERROR and FATAL also send the same line to err writer.
+// FATAL adds runtime stack and os.exit(1), like panic.
+func (l *Logger) Logf(format string, args ...interface{}) {
+
+	lv, msg := l.extractLevel(fmt.Sprintf(format, args...))
+	var bld strings.Builder
+	bld.WriteString(l.now().Format("2006/01/02 15:04:05.000 "))
+	bld.WriteString(lv)
+
+	if l.dbg && (l.callerFile || l.callerFunc) {
+		if pc, file, line, ok := runtime.Caller(l.skipCallers); ok {
+
+			funcName := ""
+			if l.callerFunc {
+				funcNameElems := strings.Split(runtime.FuncForPC(pc).Name(), "/")
+				funcName = funcNameElems[len(funcNameElems)-1]
+			}
+			fileInfo := ""
+			if l.callerFile {
+				fnameElems := strings.Split(file, "/")
+				fileInfo = fmt.Sprintf("%s:%d", strings.Join(fnameElems[len(fnameElems)-2:], "/"), line)
+				if l.callerFunc {
+					fileInfo += " "
+				}
+			}
+			srcFileInfo := fmt.Sprintf("{%s%s} ", fileInfo, funcName)
+			bld.WriteString(srcFileInfo)
+		}
+	}
+
+	if lv == "DEBUG " && !l.dbg {
+		return
+	}
+	bld.WriteString(msg)  //nolint
+	bld.WriteString("\n") //nolint
+
+	l.lock.Lock()
+	msgb := []byte(bld.String())
+	l.stdout.Write(msgb) //nolint
+
+	switch lv {
+	case "PANIC ", "FATAL ":
+		l.stderr.Write(msgb)      //nolint
+		l.stderr.Write(getDump()) //nolint
+		l.fatal()
+	case "ERROR ":
+		l.stderr.Write(msgb) //nolint
+	}
+
+	l.lock.Unlock()
+}
+
+func (l *Logger) extractLevel(line string) (level, msg string) {
+
+	brace := func(b string) string {
+		if l.levelBraces {
+			return b
+		}
+		return ""
+	}
+
+	spaces := " "
+	for _, lv := range levels {
+		if strings.HasPrefix(line, lv) {
+			if len(lv) == 4 {
+				spaces = "  "
+			}
+			return brace("[") + lv + brace("]") + spaces, line[len(lv)+1:]
+		}
+		if strings.HasPrefix(line, "["+lv+"]") {
+			if len(lv) == 4 {
+				spaces = "  "
+			}
+			return brace("[") + lv + brace("]") + spaces, line[len(lv)+3:]
+		}
+	}
+	return "", line
+}
+
+// getDump reads runtime stack and returns as a string
+func getDump() []byte {
+	maxSize := 5 * 1024 * 1024
+	stacktrace := make([]byte, maxSize)
+	length := runtime.Stack(stacktrace, true)
+	if length > maxSize {
+		length = maxSize
+	}
+	return stacktrace[:length]
+}
+
+// Option func type
+type Option func(l *Logger)
+
+// Out sets out writer
+func Out(w io.Writer) Option {
+	return func(l *Logger) {
+		l.stdout = w
+	}
+}
+
+// Err sets error writer
+func Err(w io.Writer) Option {
+	return func(l *Logger) {
+		l.stderr = w
+	}
+}
+
+// Debug turn on dbg mode
+func Debug(l *Logger) {
+	l.dbg = true
+}
+
+// CallerFile adds caller info with file, and line number
+func CallerFile(l *Logger) {
+	l.callerFile = true
+}
+
+// CallerFunc adds caller info with function name
+func CallerFunc(l *Logger) {
+	l.callerFunc = true
+}
+
+// LevelBraces adds [] to level
+func LevelBraces(l *Logger) {
+	l.levelBraces = true
+}

+ 174 - 0
vendor/github.com/go-pkgz/lgr/logger_test.go

@@ -0,0 +1,174 @@
+package lgr
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"strings"
+	"sync"
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestLoggerNoDbg(t *testing.T) {
+	tbl := []struct {
+		format     string
+		args       []interface{}
+		rout, rerr string
+	}{
+		{"", []interface{}{}, "2018/01/07 13:02:34.000 \n", ""},
+		{"DEBUG something 123 %s", []interface{}{"aaa"}, "", ""},
+		{"[DEBUG] something 123 %s", []interface{}{"aaa"}, "", ""},
+		{"INFO something 123 %s", []interface{}{"aaa"}, "2018/01/07 13:02:34.000 INFO  something 123 aaa\n", ""},
+		{"[INFO] something 123 %s", []interface{}{"aaa"}, "2018/01/07 13:02:34.000 INFO  something 123 aaa\n", ""},
+		{"blah something 123 %s", []interface{}{"aaa"}, "2018/01/07 13:02:34.000 blah something 123 aaa\n", ""},
+		{"WARN something 123 %s", []interface{}{"aaa"}, "2018/01/07 13:02:34.000 WARN  something 123 aaa\n", ""},
+		{"ERROR something 123 %s", []interface{}{"aaa"}, "2018/01/07 13:02:34.000 ERROR something 123 aaa\n",
+			"2018/01/07 13:02:34.000 ERROR something 123 aaa\n"},
+	}
+	rout, rerr := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
+	l := New(Out(rout), Err(rerr))
+	l.now = func() time.Time { return time.Date(2018, 1, 7, 13, 2, 34, 0, time.Local) }
+
+	for i, tt := range tbl {
+		rout.Reset()
+		rerr.Reset()
+		t.Run(fmt.Sprintf("check-%d", i), func(t *testing.T) {
+			l.Logf(tt.format, tt.args...)
+			assert.Equal(t, tt.rout, rout.String())
+			assert.Equal(t, tt.rerr, rerr.String())
+		})
+	}
+}
+
+func TestLoggerWithDbg(t *testing.T) {
+	tbl := []struct {
+		format     string
+		args       []interface{}
+		rout, rerr string
+	}{
+		{"", []interface{}{},
+			"2018/01/07 13:02:34.000 {lgr/logger_test.go:79 lgr.TestLoggerWithDbg.func2} \n", ""},
+		{"DEBUG something 123 %s", []interface{}{"aaa"},
+			"2018/01/07 13:02:34.000 DEBUG {lgr/logger_test.go:79 lgr.TestLoggerWithDbg.func2} something 123 aaa\n", ""},
+		{"[DEBUG] something 123 %s", []interface{}{"aaa"},
+			"2018/01/07 13:02:34.000 DEBUG {lgr/logger_test.go:79 lgr.TestLoggerWithDbg.func2} something 123 aaa\n", ""},
+		{"INFO something 123 %s", []interface{}{"aaa"},
+			"2018/01/07 13:02:34.000 INFO  {lgr/logger_test.go:79 lgr.TestLoggerWithDbg.func2} something 123 aaa\n", ""},
+		{"[INFO] something 123 %s", []interface{}{"aaa"},
+			"2018/01/07 13:02:34.000 INFO  {lgr/logger_test.go:79 lgr.TestLoggerWithDbg.func2} something 123 aaa\n", ""},
+		{"blah something 123 %s", []interface{}{"aaa"},
+			"2018/01/07 13:02:34.000 {lgr/logger_test.go:79 lgr.TestLoggerWithDbg.func2} blah something 123 aaa\n", ""},
+		{"WARN something 123 %s", []interface{}{"aaa"},
+			"2018/01/07 13:02:34.000 WARN  {lgr/logger_test.go:79 lgr.TestLoggerWithDbg.func2} something 123 aaa\n", ""},
+		{"ERROR something 123 %s", []interface{}{"aaa"},
+			"2018/01/07 13:02:34.000 ERROR {lgr/logger_test.go:79 lgr.TestLoggerWithDbg.func2} something 123 aaa\n",
+			"2018/01/07 13:02:34.000 ERROR {lgr/logger_test.go:79 lgr.TestLoggerWithDbg.func2} something 123 aaa\n"},
+	}
+
+	rout, rerr := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
+	l := New(Debug, CallerFile, CallerFunc, Out(rout), Err(rerr))
+	l.now = func() time.Time { return time.Date(2018, 1, 7, 13, 2, 34, 0, time.Local) }
+
+	for i, tt := range tbl {
+		rout.Reset()
+		rerr.Reset()
+		t.Run(fmt.Sprintf("check-%d", i), func(t *testing.T) {
+			l.Logf(tt.format, tt.args...)
+			assert.Equal(t, tt.rout, rout.String())
+			assert.Equal(t, tt.rerr, rerr.String())
+		})
+	}
+
+	l = New(Debug, Out(rout), Err(rerr)) // no caller
+	l.now = func() time.Time { return time.Date(2018, 1, 7, 13, 2, 34, 0, time.Local) }
+	rout.Reset()
+	rerr.Reset()
+	l.Logf("[DEBUG] something 123 %s", "err")
+	assert.Equal(t, "2018/01/07 13:02:34.000 DEBUG something 123 err\n", rout.String())
+	assert.Equal(t, "", rerr.String())
+
+	l = New(Debug, Out(rout), Err(rerr), CallerFile) // caller file only
+	l.now = func() time.Time { return time.Date(2018, 1, 7, 13, 2, 34, 0, time.Local) }
+	rout.Reset()
+	rerr.Reset()
+	l.Logf("[DEBUG] something 123 %s", "err")
+	assert.Equal(t, "2018/01/07 13:02:34.000 DEBUG {lgr/logger_test.go:97} something 123 err\n", rout.String())
+
+	l = New(Debug, Out(rout), Err(rerr), CallerFunc) // caller func only
+	l.now = func() time.Time { return time.Date(2018, 1, 7, 13, 2, 34, 0, time.Local) }
+	rout.Reset()
+	rerr.Reset()
+	l.Logf("[DEBUG] something 123 %s", "err")
+	assert.Equal(t, "2018/01/07 13:02:34.000 DEBUG {lgr.TestLoggerWithDbg} something 123 err\n", rout.String())
+}
+
+func TestLoggerWithLevelBraces(t *testing.T) {
+	rout, rerr := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
+	l := New(Debug, Out(rout), Err(rerr), LevelBraces)
+	l.now = func() time.Time { return time.Date(2018, 1, 7, 13, 2, 34, 0, time.Local) }
+	l.Logf("[DEBUG] something 123 %s", "err")
+	assert.Equal(t, "2018/01/07 13:02:34.000 [DEBUG] something 123 err\n", rout.String())
+}
+
+func TestLoggerWithPanic(t *testing.T) {
+	fatalCalls := 0
+	rout, rerr := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
+	l := New(Debug, CallerFunc, Out(rout), Err(rerr))
+	l.now = func() time.Time { return time.Date(2018, 1, 7, 13, 2, 34, 0, time.Local) }
+	l.fatal = func() { fatalCalls++ }
+
+	l.Logf("[PANIC] oh my, panic now! %v", errors.New("bad thing happened"))
+	assert.Equal(t, 1, fatalCalls)
+	assert.Equal(t, "2018/01/07 13:02:34.000 PANIC {lgr.TestLoggerWithPanic} oh my, panic now! bad thing happened\n", rout.String())
+
+	t.Logf(rerr.String())
+	assert.True(t, strings.HasPrefix(rerr.String(), "2018/01/07 13:02:34.000 PANIC"))
+	assert.True(t, strings.Contains(rerr.String(), "github.com/go-pkgz/lgr.getDump"))
+	assert.True(t, strings.Contains(rerr.String(), "go-pkgz/lgr/logger.go:"))
+}
+
+func TestLoggerConcurrent(t *testing.T) {
+	rout, rerr := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
+	l := New(Debug, Out(rout), Err(rerr))
+	l.now = func() time.Time { return time.Date(2018, 1, 7, 13, 2, 34, 0, time.Local) }
+
+	var wg sync.WaitGroup
+	wg.Add(1000)
+	for i := 0; i < 1000; i++ {
+		go func(i int) {
+			l.Logf("[DEBUG] test test 123 debug message #%d, %v", i, errors.New("some error"))
+			wg.Done()
+		}(i)
+	}
+	wg.Wait()
+
+	assert.Equal(t, 1001, len(strings.Split(rout.String(), "\n")))
+	assert.Equal(t, "", rerr.String())
+}
+
+func BenchmarkNoDbg(b *testing.B) {
+
+	rout, rerr := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
+	l := New(Out(rout), Err(rerr))
+	l.now = func() time.Time { return time.Date(2018, 1, 7, 13, 2, 34, 0, time.Local) }
+
+	e := errors.New("some error")
+	for n := 0; n < b.N; n++ {
+		l.Logf("[INFO] test test 123 debug message #%d, %v", n, e)
+	}
+}
+
+func BenchmarkWithDbg(b *testing.B) {
+
+	rout, rerr := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
+	l := New(Debug, CallerFile, CallerFunc, Out(rout), Err(rerr))
+	l.now = func() time.Time { return time.Date(2018, 1, 7, 13, 2, 34, 0, time.Local) }
+
+	e := errors.New("some error")
+	for n := 0; n < b.N; n++ {
+		l.Logf("[INFO] test test 123 debug message #%d, %v", n, e)
+	}
+}

+ 0 - 354
vendor/github.com/hashicorp/logutils/LICENSE

@@ -1,354 +0,0 @@
-Mozilla Public License, version 2.0
-
-1. Definitions
-
-1.1. “Contributor”
-
-     means each individual or legal entity that creates, contributes to the
-     creation of, or owns Covered Software.
-
-1.2. “Contributor Version”
-
-     means the combination of the Contributions of others (if any) used by a
-     Contributor and that particular Contributor’s Contribution.
-
-1.3. “Contribution”
-
-     means Covered Software of a particular Contributor.
-
-1.4. “Covered Software”
-
-     means Source Code Form to which the initial Contributor has attached the
-     notice in Exhibit A, the Executable Form of such Source Code Form, and
-     Modifications of such Source Code Form, in each case including portions
-     thereof.
-
-1.5. “Incompatible With Secondary Licenses”
-     means
-
-     a. that the initial Contributor has attached the notice described in
-        Exhibit B to the Covered Software; or
-
-     b. that the Covered Software was made available under the terms of version
-        1.1 or earlier of the License, but not also under the terms of a
-        Secondary License.
-
-1.6. “Executable Form”
-
-     means any form of the work other than Source Code Form.
-
-1.7. “Larger Work”
-
-     means a work that combines Covered Software with other material, in a separate
-     file or files, that is not Covered Software.
-
-1.8. “License”
-
-     means this document.
-
-1.9. “Licensable”
-
-     means having the right to grant, to the maximum extent possible, whether at the
-     time of the initial grant or subsequently, any and all of the rights conveyed by
-     this License.
-
-1.10. “Modifications”
-
-     means any of the following:
-
-     a. any file in Source Code Form that results from an addition to, deletion
-        from, or modification of the contents of Covered Software; or
-
-     b. any new file in Source Code Form that contains any Covered Software.
-
-1.11. “Patent Claims” of a Contributor
-
-      means any patent claim(s), including without limitation, method, process,
-      and apparatus claims, in any patent Licensable by such Contributor that
-      would be infringed, but for the grant of the License, by the making,
-      using, selling, offering for sale, having made, import, or transfer of
-      either its Contributions or its Contributor Version.
-
-1.12. “Secondary License”
-
-      means either the GNU General Public License, Version 2.0, the GNU Lesser
-      General Public License, Version 2.1, the GNU Affero General Public
-      License, Version 3.0, or any later versions of those licenses.
-
-1.13. “Source Code Form”
-
-      means the form of the work preferred for making modifications.
-
-1.14. “You” (or “Your”)
-
-      means an individual or a legal entity exercising rights under this
-      License. For legal entities, “You” includes any entity that controls, is
-      controlled by, or is under common control with You. For purposes of this
-      definition, “control” means (a) the power, direct or indirect, to cause
-      the direction or management of such entity, whether by contract or
-      otherwise, or (b) ownership of more than fifty percent (50%) of the
-      outstanding shares or beneficial ownership of such entity.
-
-
-2. License Grants and Conditions
-
-2.1. Grants
-
-     Each Contributor hereby grants You a world-wide, royalty-free,
-     non-exclusive license:
-
-     a. under intellectual property rights (other than patent or trademark)
-        Licensable by such Contributor to use, reproduce, make available,
-        modify, display, perform, distribute, and otherwise exploit its
-        Contributions, either on an unmodified basis, with Modifications, or as
-        part of a Larger Work; and
-
-     b. under Patent Claims of such Contributor to make, use, sell, offer for
-        sale, have made, import, and otherwise transfer either its Contributions
-        or its Contributor Version.
-
-2.2. Effective Date
-
-     The licenses granted in Section 2.1 with respect to any Contribution become
-     effective for each Contribution on the date the Contributor first distributes
-     such Contribution.
-
-2.3. Limitations on Grant Scope
-
-     The licenses granted in this Section 2 are the only rights granted under this
-     License. No additional rights or licenses will be implied from the distribution
-     or licensing of Covered Software under this License. Notwithstanding Section
-     2.1(b) above, no patent license is granted by a Contributor:
-
-     a. for any code that a Contributor has removed from Covered Software; or
-
-     b. for infringements caused by: (i) Your and any other third party’s
-        modifications of Covered Software, or (ii) the combination of its
-        Contributions with other software (except as part of its Contributor
-        Version); or
-
-     c. under Patent Claims infringed by Covered Software in the absence of its
-        Contributions.
-
-     This License does not grant any rights in the trademarks, service marks, or
-     logos of any Contributor (except as may be necessary to comply with the
-     notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
-     No Contributor makes additional grants as a result of Your choice to
-     distribute the Covered Software under a subsequent version of this License
-     (see Section 10.2) or under the terms of a Secondary License (if permitted
-     under the terms of Section 3.3).
-
-2.5. Representation
-
-     Each Contributor represents that the Contributor believes its Contributions
-     are its original creation(s) or it has sufficient rights to grant the
-     rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
-     This License is not intended to limit any rights You have under applicable
-     copyright doctrines of fair use, fair dealing, or other equivalents.
-
-2.7. Conditions
-
-     Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
-     Section 2.1.
-
-
-3. Responsibilities
-
-3.1. Distribution of Source Form
-
-     All distribution of Covered Software in Source Code Form, including any
-     Modifications that You create or to which You contribute, must be under the
-     terms of this License. You must inform recipients that the Source Code Form
-     of the Covered Software is governed by the terms of this License, and how
-     they can obtain a copy of this License. You may not attempt to alter or
-     restrict the recipients’ rights in the Source Code Form.
-
-3.2. Distribution of Executable Form
-
-     If You distribute Covered Software in Executable Form then:
-
-     a. such Covered Software must also be made available in Source Code Form,
-        as described in Section 3.1, and You must inform recipients of the
-        Executable Form how they can obtain a copy of such Source Code Form by
-        reasonable means in a timely manner, at a charge no more than the cost
-        of distribution to the recipient; and
-
-     b. You may distribute such Executable Form under the terms of this License,
-        or sublicense it under different terms, provided that the license for
-        the Executable Form does not attempt to limit or alter the recipients’
-        rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
-     You may create and distribute a Larger Work under terms of Your choice,
-     provided that You also comply with the requirements of this License for the
-     Covered Software. If the Larger Work is a combination of Covered Software
-     with a work governed by one or more Secondary Licenses, and the Covered
-     Software is not Incompatible With Secondary Licenses, this License permits
-     You to additionally distribute such Covered Software under the terms of
-     such Secondary License(s), so that the recipient of the Larger Work may, at
-     their option, further distribute the Covered Software under the terms of
-     either this License or such Secondary License(s).
-
-3.4. Notices
-
-     You may not remove or alter the substance of any license notices (including
-     copyright notices, patent notices, disclaimers of warranty, or limitations
-     of liability) contained within the Source Code Form of the Covered
-     Software, except that You may alter any license notices to the extent
-     required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
-     You may choose to offer, and to charge a fee for, warranty, support,
-     indemnity or liability obligations to one or more recipients of Covered
-     Software. However, You may do so only on Your own behalf, and not on behalf
-     of any Contributor. You must make it absolutely clear that any such
-     warranty, support, indemnity, or liability obligation is offered by You
-     alone, and You hereby agree to indemnify every Contributor for any
-     liability incurred by such Contributor as a result of warranty, support,
-     indemnity or liability terms You offer. You may include additional
-     disclaimers of warranty and limitations of liability specific to any
-     jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
-
-   If it is impossible for You to comply with any of the terms of this License
-   with respect to some or all of the Covered Software due to statute, judicial
-   order, or regulation then You must: (a) comply with the terms of this License
-   to the maximum extent possible; and (b) describe the limitations and the code
-   they affect. Such description must be placed in a text file included with all
-   distributions of the Covered Software under this License. Except to the
-   extent prohibited by statute or regulation, such description must be
-   sufficiently detailed for a recipient of ordinary skill to be able to
-   understand it.
-
-5. Termination
-
-5.1. The rights granted under this License will terminate automatically if You
-     fail to comply with any of its terms. However, if You become compliant,
-     then the rights granted under this License from a particular Contributor
-     are reinstated (a) provisionally, unless and until such Contributor
-     explicitly and finally terminates Your grants, and (b) on an ongoing basis,
-     if such Contributor fails to notify You of the non-compliance by some
-     reasonable means prior to 60 days after You have come back into compliance.
-     Moreover, Your grants from a particular Contributor are reinstated on an
-     ongoing basis if such Contributor notifies You of the non-compliance by
-     some reasonable means, this is the first time You have received notice of
-     non-compliance with this License from such Contributor, and You become
-     compliant prior to 30 days after Your receipt of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
-     infringement claim (excluding declaratory judgment actions, counter-claims,
-     and cross-claims) alleging that a Contributor Version directly or
-     indirectly infringes any patent, then the rights granted to You by any and
-     all Contributors for the Covered Software under Section 2.1 of this License
-     shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
-     license agreements (excluding distributors and resellers) which have been
-     validly granted by You or Your distributors under this License prior to
-     termination shall survive termination.
-
-6. Disclaimer of Warranty
-
-   Covered Software is provided under this License on an “as is” basis, without
-   warranty of any kind, either expressed, implied, or statutory, including,
-   without limitation, warranties that the Covered Software is free of defects,
-   merchantable, fit for a particular purpose or non-infringing. The entire
-   risk as to the quality and performance of the Covered Software is with You.
-   Should any Covered Software prove defective in any respect, You (not any
-   Contributor) assume the cost of any necessary servicing, repair, or
-   correction. This disclaimer of warranty constitutes an essential part of this
-   License. No use of  any Covered Software is authorized under this License
-   except under this disclaimer.
-
-7. Limitation of Liability
-
-   Under no circumstances and under no legal theory, whether tort (including
-   negligence), contract, or otherwise, shall any Contributor, or anyone who
-   distributes Covered Software as permitted above, be liable to You for any
-   direct, indirect, special, incidental, or consequential damages of any
-   character including, without limitation, damages for lost profits, loss of
-   goodwill, work stoppage, computer failure or malfunction, or any and all
-   other commercial damages or losses, even if such party shall have been
-   informed of the possibility of such damages. This limitation of liability
-   shall not apply to liability for death or personal injury resulting from such
-   party’s negligence to the extent applicable law prohibits such limitation.
-   Some jurisdictions do not allow the exclusion or limitation of incidental or
-   consequential damages, so this exclusion and limitation may not apply to You.
-
-8. Litigation
-
-   Any litigation relating to this License may be brought only in the courts of
-   a jurisdiction where the defendant maintains its principal place of business
-   and such litigation shall be governed by laws of that jurisdiction, without
-   reference to its conflict-of-law provisions. Nothing in this Section shall
-   prevent a party’s ability to bring cross-claims or counter-claims.
-
-9. Miscellaneous
-
-   This License represents the complete agreement concerning the subject matter
-   hereof. If any provision of this License is held to be unenforceable, such
-   provision shall be reformed only to the extent necessary to make it
-   enforceable. Any law or regulation which provides that the language of a
-   contract shall be construed against the drafter shall not be used to construe
-   this License against a Contributor.
-
-
-10. Versions of the License
-
-10.1. New Versions
-
-      Mozilla Foundation is the license steward. Except as provided in Section
-      10.3, no one other than the license steward has the right to modify or
-      publish new versions of this License. Each version will be given a
-      distinguishing version number.
-
-10.2. Effect of New Versions
-
-      You may distribute the Covered Software under the terms of the version of
-      the License under which You originally received the Covered Software, or
-      under the terms of any subsequent version published by the license
-      steward.
-
-10.3. Modified Versions
-
-      If you create software not governed by this License, and you want to
-      create a new license for such software, you may create and use a modified
-      version of this License if you rename the license and remove any
-      references to the name of the license steward (except to note that such
-      modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
-      If You choose to distribute Source Code Form that is Incompatible With
-      Secondary Licenses under the terms of this version of the License, the
-      notice described in Exhibit B of this License must be attached.
-
-Exhibit A - Source Code Form License Notice
-
-      This Source Code Form is subject to the
-      terms of the Mozilla Public License, v.
-      2.0. If a copy of the MPL was not
-      distributed with this file, You can
-      obtain one at
-      http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular file, then
-You may include the notice in a location (such as a LICENSE file in a relevant
-directory) where a recipient would be likely to look for such a notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - “Incompatible With Secondary Licenses” Notice
-
-      This Source Code Form is “Incompatible
-      With Secondary Licenses”, as defined by
-      the Mozilla Public License, v. 2.0.
-

+ 0 - 36
vendor/github.com/hashicorp/logutils/README.md

@@ -1,36 +0,0 @@
-# logutils
-
-logutils is a Go package that augments the standard library "log" package
-to make logging a bit more modern, without fragmenting the Go ecosystem
-with new logging packages.
-
-## The simplest thing that could possibly work
-
-Presumably your application already uses the default `log` package. To switch, you'll want your code to look like the following:
-
-```go
-package main
-
-import (
-	"log"
-	"os"
-
-	"github.com/hashicorp/logutils"
-)
-
-func main() {
-	filter := &logutils.LevelFilter{
-		Levels: []logutils.LogLevel{"DEBUG", "WARN", "ERROR"},
-		MinLevel: logutils.LogLevel("WARN"),
-		Writer: os.Stderr,
-	}
-	log.SetOutput(filter)
-
-	log.Print("[DEBUG] Debugging") // this will not print
-	log.Print("[WARN] Warning") // this will
-	log.Print("[ERROR] Erring") // and so will this
-	log.Print("Message I haven't updated") // and so will this
-}
-```
-
-This logs to standard error exactly like go's standard logger. Any log messages you haven't converted to have a level will continue to print as before.

+ 0 - 1
vendor/github.com/hashicorp/logutils/go.mod

@@ -1 +0,0 @@
-module github.com/hashicorp/logutils

+ 0 - 81
vendor/github.com/hashicorp/logutils/level.go

@@ -1,81 +0,0 @@
-// Package logutils augments the standard log package with levels.
-package logutils
-
-import (
-	"bytes"
-	"io"
-	"sync"
-)
-
-type LogLevel string
-
-// LevelFilter is an io.Writer that can be used with a logger that
-// will filter out log messages that aren't at least a certain level.
-//
-// Once the filter is in use somewhere, it is not safe to modify
-// the structure.
-type LevelFilter struct {
-	// Levels is the list of log levels, in increasing order of
-	// severity. Example might be: {"DEBUG", "WARN", "ERROR"}.
-	Levels []LogLevel
-
-	// MinLevel is the minimum level allowed through
-	MinLevel LogLevel
-
-	// The underlying io.Writer where log messages that pass the filter
-	// will be set.
-	Writer io.Writer
-
-	badLevels map[LogLevel]struct{}
-	once      sync.Once
-}
-
-// Check will check a given line if it would be included in the level
-// filter.
-func (f *LevelFilter) Check(line []byte) bool {
-	f.once.Do(f.init)
-
-	// Check for a log level
-	var level LogLevel
-	x := bytes.IndexByte(line, '[')
-	if x >= 0 {
-		y := bytes.IndexByte(line[x:], ']')
-		if y >= 0 {
-			level = LogLevel(line[x+1 : x+y])
-		}
-	}
-
-	_, ok := f.badLevels[level]
-	return !ok
-}
-
-func (f *LevelFilter) Write(p []byte) (n int, err error) {
-	// Note in general that io.Writer can receive any byte sequence
-	// to write, but the "log" package always guarantees that we only
-	// get a single line. We use that as a slight optimization within
-	// this method, assuming we're dealing with a single, complete line
-	// of log data.
-
-	if !f.Check(p) {
-		return len(p), nil
-	}
-
-	return f.Writer.Write(p)
-}
-
-// SetMinLevel is used to update the minimum log level
-func (f *LevelFilter) SetMinLevel(min LogLevel) {
-	f.MinLevel = min
-	f.init()
-}
-
-func (f *LevelFilter) init() {
-	badLevels := make(map[LogLevel]struct{})
-	for _, level := range f.Levels {
-		if level == f.MinLevel {
-			break
-		}
-		badLevels[level] = struct{}{}
-	}
-	f.badLevels = badLevels
-}

+ 163 - 0
vendor/github.com/jessevdk/go-flags/arg_test.go

@@ -0,0 +1,163 @@
+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")
+}
+
+func TestPositionalRequiredRestRangeFail(t *testing.T) {
+	var opts = struct {
+		Value bool `short:"v"`
+
+		Positional struct {
+			Rest []string `required:"1-2"`
+		} `positional-args:"yes"`
+	}{}
+
+	p := NewParser(&opts, None)
+	_, err := p.ParseArgs([]string{"rest1", "rest2", "rest3"})
+
+	assertError(t, err, ErrRequired, "the required argument `Rest (at most 2 arguments, but got 3)` was not provided")
+}
+
+func TestPositionalRequiredRestRangeEmptyFail(t *testing.T) {
+	var opts = struct {
+		Value bool `short:"v"`
+
+		Positional struct {
+			Rest []string `required:"0-0"`
+		} `positional-args:"yes"`
+	}{}
+
+	p := NewParser(&opts, None)
+	_, err := p.ParseArgs([]string{"some", "thing"})
+
+	assertError(t, err, ErrRequired, "the required argument `Rest (zero arguments)` was not provided")
+}

+ 177 - 0
vendor/github.com/jessevdk/go-flags/assert_test.go

@@ -0,0 +1,177 @@
+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)
+	}
+}

+ 582 - 0
vendor/github.com/jessevdk/go-flags/command_test.go

@@ -0,0 +1,582 @@
+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)
+	}
+}

+ 315 - 0
vendor/github.com/jessevdk/go-flags/completion_test.go

@@ -0,0 +1,315 @@
+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"`
+	Info     bool `short:"i" description:"Display info"`
+	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"`
+		Extra []Filename `short:"f"`
+	} `command:"add-multi" description:"add multiple items"`
+
+	AddMultiCommandFlag struct {
+		Files []Filename `short:"f"`
+	} `command:"add-multi-flag" description:"add multiple items via flags"`
+
+	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{"--debug", "--required", "--verbose", "--version", "-i"},
+			false,
+		},
+
+		{
+			// Short names full
+			[]string{"-i"},
+			[]string{"-i"},
+			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", "add-multi-flag", "rename", "rm"},
+			false,
+		},
+
+		{
+			// Commands with descriptions
+			[]string{""},
+			[]string{
+				"add             # add an item",
+				"add-multi       # add multiple items",
+				"add-multi-flag  # add multiple items via flags",
+				"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,
+		},
+		{
+			// Multiple flag filename
+			[]string{"add-multi-flag", "-f", filepath.Join(completionTestSourcedir, "completion")},
+			completionTestFilename,
+			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", "")
+}

+ 159 - 0
vendor/github.com/jessevdk/go-flags/convert_test.go

@@ -0,0 +1,159 @@
+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")
+}

+ 110 - 0
vendor/github.com/jessevdk/go-flags/example_test.go

@@ -0,0 +1,110 @@
+// 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:<argument> 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]
+}

+ 255 - 0
vendor/github.com/jessevdk/go-flags/group_test.go

@@ -0,0 +1,255 @@
+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)
+	}
+}

+ 538 - 0
vendor/github.com/jessevdk/go-flags/help_test.go

@@ -0,0 +1,538 @@
+package flags
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"os"
+	"runtime"
+	"strings"
+	"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"`
+		NotHiddenInsideGroup string `long:"not-hidden-inside-group" description:"Not hidden inside group" hidden:"false"`
+
+		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] <command>
+
+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
+      /sip.not-hidden-inside-group:         Not hidden inside group
+
+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 with a long description
+                                            to trigger line wrapping
+  num:                                      A number
+
+Available commands:
+  command  A command (aliases: cm, cmd)
+`
+		} else {
+			expected = `Usage:
+  TestHelp [OPTIONS] [filename] [num] [hidden-in-help] <command>
+
+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
+      --sip.not-hidden-inside-group=        Not hidden inside group
+
+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 <default: \fI"Some\\nvalue"\fR>\fP
+Test default value
+.TP
+\fB\fB\-\-default-array\fR <default: \fI"Some value", "Other\\tvalue"\fR>\fP
+Test default array value
+.TP
+\fB\fB\-\-default-map\fR <default: \fI"some:value", "another:value"\fR>\fP
+Testdefault map value
+.TP
+\fB\fB\-\-env-default1\fR <default: \fI"Some value"\fR>\fP
+Test env-default1 value
+.TP
+\fB\fB\-\-env-default2\fR <default: \fI%s\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 <default: \fI"some", "value"\fR>\fP
+A slice of strings
+.TP
+\fB\fB\-\-intmap\fR <default: \fI"a:1"\fR>\fP
+A map from string to int
+.SS Subgroup
+.TP
+\fB\fB\-\-sip.opt\fR\fP
+This is a subgroup option
+.TP
+\fB\fB\-\-sip.not-hidden-inside-group\fR\fP
+Not hidden inside group
+.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")
+}
+
+func TestHelpDefaultMask(t *testing.T) {
+	var tests = []struct {
+		opts    interface{}
+		present string
+	}{
+		{
+			opts: &struct {
+				Value string `short:"v" default:"123" description:"V"`
+			}{},
+			present: "V (default: 123)\n",
+		},
+		{
+			opts: &struct {
+				Value string `short:"v" default:"123" default-mask:"abc" description:"V"`
+			}{},
+			present: "V (default: abc)\n",
+		},
+		{
+			opts: &struct {
+				Value string `short:"v" default:"123" default-mask:"-" description:"V"`
+			}{},
+			present: "V\n",
+		},
+		{
+			opts: &struct {
+				Value string `short:"v" description:"V"`
+			}{Value: "123"},
+			present: "V (default: 123)\n",
+		},
+		{
+			opts: &struct {
+				Value string `short:"v" default-mask:"abc" description:"V"`
+			}{Value: "123"},
+			present: "V (default: abc)\n",
+		},
+		{
+			opts: &struct {
+				Value string `short:"v" default-mask:"-" description:"V"`
+			}{Value: "123"},
+			present: "V\n",
+		},
+	}
+
+	for _, test := range tests {
+		p := NewParser(test.opts, HelpFlag)
+		_, err := p.ParseArgs([]string{"-h"})
+		if flagsErr, ok := err.(*Error); ok && flagsErr.Type == ErrHelp {
+			err = nil
+		}
+		if err != nil {
+			t.Fatalf("Unexpected error: %v", err)
+		}
+		h := &bytes.Buffer{}
+		w := bufio.NewWriter(h)
+		p.writeHelpOption(w, p.FindOptionByShortName('v'), p.getAlignmentInfo())
+		w.Flush()
+		if strings.Index(h.String(), test.present) < 0 {
+			t.Errorf("Not present %q\n%s", test.present, h.String())
+		}
+	}
+}

+ 1053 - 0
vendor/github.com/jessevdk/go-flags/ini_test.go

@@ -0,0 +1,1053 @@
+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 =
+
+; Not hidden inside group
+NotHiddenInsideGroup =
+
+[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 =
+
+; Not hidden inside group
+; NotHiddenInsideGroup =
+
+[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 =
+
+; Not hidden inside group
+; NotHiddenInsideGroup =
+
+[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[1] 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 TestIniRequired(t *testing.T) {
+	var opts struct {
+		Required string               `short:"r" required:"yes" description:"required"`
+		Config   func(s string) error `long:"config" default:"no-ini-file" no-ini:"true"`
+	}
+
+	p := NewParser(&opts, Default)
+
+	opts.Config = func(s string) error {
+		inip := NewIniParser(p)
+		inip.ParseAsDefaults = true
+		return inip.Parse(strings.NewReader("Required = ini-value\n"))
+	}
+
+	_, err := p.ParseArgs([]string{"-r", "cli-value"})
+
+	if err != nil {
+		t.Fatalf("Failed to parse arguments: %s", err)
+	}
+
+	assertString(t, opts.Required, "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)
+		}
+	}
+}
+
+func TestIniOverwriteOptions(t *testing.T) {
+	var tests = []struct {
+		args     []string
+		expected string
+		toggled  bool
+	}{
+		{
+			args:     []string{},
+			expected: "from default",
+		},
+		{
+			args:     []string{"--value", "from CLI"},
+			expected: "from CLI",
+		},
+		{
+			args:     []string{"--config", "no file name"},
+			expected: "from INI",
+			toggled:  true,
+		},
+		{
+			args:     []string{"--value", "from CLI before", "--config", "no file name"},
+			expected: "from CLI before",
+			toggled:  true,
+		},
+		{
+			args:     []string{"--config", "no file name", "--value", "from CLI after"},
+			expected: "from CLI after",
+			toggled:  true,
+		},
+		{
+			args:     []string{"--toggle"},
+			toggled:  true,
+			expected: "from default",
+		},
+	}
+
+	for _, test := range tests {
+		var opts struct {
+			Config string `long:"config" no-ini:"true"`
+			Value  string `long:"value" default:"from default"`
+			Toggle bool   `long:"toggle"`
+		}
+
+		p := NewParser(&opts, Default)
+
+		_, err := p.ParseArgs(test.args)
+		if err != nil {
+			t.Fatalf("Unexpected error %s with args %+v", err, test.args)
+		}
+
+		if opts.Config != "" {
+			inip := NewIniParser(p)
+			inip.ParseAsDefaults = true
+
+			err = inip.Parse(bytes.NewBufferString("value = from INI\ntoggle = true"))
+			if err != nil {
+				t.Fatalf("Unexpected error %s with args %+v", err, test.args)
+			}
+		}
+
+		if opts.Value != test.expected {
+			t.Fatalf("Expected Value to be \"%s\" but was \"%s\" with args %+v", test.expected, opts.Value, test.args)
+		}
+
+		if opts.Toggle != test.toggled {
+			t.Fatalf("Expected Toggle to be \"%v\" but was \"%v\" with args %+v", test.toggled, opts.Toggle, test.args)
+		}
+
+	}
+}

+ 85 - 0
vendor/github.com/jessevdk/go-flags/long_test.go

@@ -0,0 +1,85 @@
+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")
+}

+ 119 - 0
vendor/github.com/jessevdk/go-flags/marshal_test.go

@@ -0,0 +1,119 @@
+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 TestUnmarshalPositionalError(t *testing.T) {
+	var opts = struct {
+		Args struct {
+			Value marshalled
+		} `positional-args:"yes"`
+	}{}
+
+	parser := NewParser(&opts, Default&^PrintErrors)
+	_, err := parser.ParseArgs([]string{"invalid"})
+
+	msg := "`invalid' is not a valid value, please specify `yes' or `no'"
+
+	if err == nil {
+		assertFatalf(t, "Expected error: %s", msg)
+		return
+	}
+
+	if err.Error() != msg {
+		assertErrorf(t, "Expected error message %#v, but got %#v", msg, err.Error())
+	}
+}
+
+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")
+}

+ 45 - 0
vendor/github.com/jessevdk/go-flags/options_test.go

@@ -0,0 +1,45 @@
+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"})
+}

+ 612 - 0
vendor/github.com/jessevdk/go-flags/parser_test.go

@@ -0,0 +1,612 @@
+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{"-", "-"},
+		},
+		{
+			// Accept arguments which start with '-' if the next character is a digit, for number options only
+			args: []string{"--int-slice", "-3"},
+		},
+		{
+			// Accept arguments which start with '-' if the next character is a digit, for number options only
+			args: []string{"--int16", "-3"},
+		},
+		{
+			// Accept arguments which start with '-' if the next character is a digit, for number options only
+			args: []string{"--float32", "-3.2"},
+		},
+		{
+			// Accept arguments which start with '-' if the next character is a digit, for number options only
+			args: []string{"--float32ptr", "-3.2"},
+		},
+	}
+
+	var opts struct {
+		StringSlice []string `long:"string-slice"`
+		IntSlice    []int    `long:"int-slice"`
+		Int16       int16    `long:"int16"`
+		Float32     float32  `long:"float32"`
+		Float32Ptr  *float32 `long:"float32ptr"`
+		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"})
+}

+ 164 - 0
vendor/github.com/jessevdk/go-flags/pointer_test.go

@@ -0,0 +1,164 @@
+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 marshalledString string
+
+func (m *marshalledString) UnmarshalFlag(value string) error {
+	*m = marshalledString(value)
+	return nil
+}
+
+func (m marshalledString) MarshalFlag() (string, error) {
+	return string(m), nil
+}
+
+func TestPointerStringMarshalled(t *testing.T) {
+	var opts = struct {
+		Value *marshalledString `short:"v"`
+	}{}
+
+	ret := assertParseSuccess(t, &opts, "-v", "value")
+
+	assertStringArray(t, ret, []string{})
+
+	if opts.Value == nil {
+		t.Error("Expected value not to be nil")
+		return
+	}
+
+	assertString(t, string(*opts.Value), "value")
+}
+
+type marshalledStruct struct {
+	Value string
+}
+
+func (m *marshalledStruct) UnmarshalFlag(value string) error {
+	m.Value = value
+	return nil
+}
+
+func (m marshalledStruct) MarshalFlag() (string, error) {
+	return m.Value, nil
+}
+
+func TestPointerStructMarshalled(t *testing.T) {
+	var opts = struct {
+		Value *marshalledStruct `short:"v"`
+	}{}
+
+	ret := assertParseSuccess(t, &opts, "-v", "value")
+
+	assertStringArray(t, ret, []string{})
+
+	if opts.Value == nil {
+		t.Error("Expected value not to be nil")
+		return
+	}
+
+	assertString(t, opts.Value.Value, "value")
+}
+
+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")
+	}
+}
+
+func TestDoNotChangeNonTaggedFields(t *testing.T) {
+	var opts struct {
+		A struct {
+			Pointer *int
+		}
+		B *struct {
+			Pointer *int
+		}
+	}
+
+	ret := assertParseSuccess(t, &opts)
+
+	assertStringArray(t, ret, []string{})
+
+	if opts.A.Pointer != nil {
+		t.Error("Expected A.Pointer to be nil")
+	}
+	if opts.B != nil {
+		t.Error("Expected B to be nil")
+	}
+	if opts.B != nil && opts.B.Pointer != nil {
+		t.Error("Expected B.Pointer to be nil")
+	}
+}

+ 234 - 0
vendor/github.com/jessevdk/go-flags/short_test.go

@@ -0,0 +1,234 @@
+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 TestShortRequiredFalsy1(t *testing.T) {
+	var opts = struct {
+		Value bool `short:"v" required:"false"`
+	}{}
+
+	assertParseSuccess(t, &opts)
+}
+
+func TestShortRequiredFalsy2(t *testing.T) {
+	var opts = struct {
+		Value bool `short:"v" required:"no"`
+	}{}
+
+	assertParseSuccess(t, &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")
+}
+
+func TestShortOptionalFalsy1(t *testing.T) {
+	var opts = struct {
+		F     []bool `short:"f"`
+		Value string `short:"v" optional:"false" optional-value:"value"`
+	}{}
+
+	ret := assertParseSuccess(t, &opts, "-fv", "f")
+
+	assertStringArray(t, ret, []string{})
+	assertString(t, opts.Value, "f")
+}
+
+func TestShortOptionalFalsy2(t *testing.T) {
+	var opts = struct {
+		F     []bool `short:"f"`
+		Value string `short:"v" optional:"no" optional-value:"value"`
+	}{}
+
+	ret := assertParseSuccess(t, &opts, "-fv", "f")
+
+	assertStringArray(t, ret, []string{})
+	assertString(t, opts.Value, "f")
+}

+ 38 - 0
vendor/github.com/jessevdk/go-flags/tag_test.go

@@ -0,0 +1,38 @@
+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, "")
+}

+ 66 - 0
vendor/github.com/jessevdk/go-flags/unknown_test.go

@@ -0,0 +1,66 @@
+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)
+	}
+}

+ 50 - 0
vendor/github.com/mmcdole/gofeed/atom/parser_test.go

@@ -0,0 +1,50 @@
+package atom_test
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/mmcdole/gofeed/atom"
+	"github.com/stretchr/testify/assert"
+)
+
+// Tests
+
+func TestParser_Parse(t *testing.T) {
+	files, _ := filepath.Glob("../testdata/parser/atom/*.xml")
+	for _, f := range files {
+		base := filepath.Base(f)
+		name := strings.TrimSuffix(base, filepath.Ext(base))
+
+		fmt.Printf("Testing %s... ", name)
+
+		// Get actual source feed
+		ff := fmt.Sprintf("../testdata/parser/atom/%s.xml", name)
+		f, _ := ioutil.ReadFile(ff)
+
+		// Parse actual feed
+		fp := &atom.Parser{}
+		actual, _ := fp.Parse(bytes.NewReader(f))
+
+		// Get json encoded expected feed result
+		ef := fmt.Sprintf("../testdata/parser/atom/%s.json", name)
+		e, _ := ioutil.ReadFile(ef)
+
+		// Unmarshal expected feed
+		expected := &atom.Feed{}
+		json.Unmarshal(e, &expected)
+
+		if assert.Equal(t, actual, expected, "Feed file %s.xml did not match expected output %s.json", name, name) {
+			fmt.Printf("OK\n")
+		} else {
+			fmt.Printf("Failed\n")
+		}
+	}
+}
+
+// TODO: Examples

Some files were not shown because too many files changed in this diff