Ver código fonte

vendor: update to fix tests with Go 1.12.x

- github.com/smartystreets/goconvey
- github.com/jtolds/gls
unknwon 5 anos atrás
pai
commit
00a3e368b4

+ 62 - 53
vendor/github.com/jtolds/gls/context.go

@@ -5,12 +5,7 @@ import (
 	"sync"
 )
 
-const (
-	maxCallers = 64
-)
-
 var (
-	stackTagPool   = &idPool{}
 	mgrRegistry    = make(map[*ContextManager]bool)
 	mgrRegistryMtx sync.RWMutex
 )
@@ -25,7 +20,7 @@ type Values map[interface{}]interface{}
 // class of context variables. You should use NewContextManager for
 // construction.
 type ContextManager struct {
-	mtx    sync.RWMutex
+	mtx    sync.Mutex
 	values map[uint]Values
 }
 
@@ -62,63 +57,77 @@ func (m *ContextManager) SetValues(new_values Values, context_call func()) {
 		return
 	}
 
-	tags := readStackTags(1)
+	mutated_keys := make([]interface{}, 0, len(new_values))
+	mutated_vals := make(Values, len(new_values))
 
-	m.mtx.Lock()
-	values := new_values
-	for _, tag := range tags {
-		if existing_values, ok := m.values[tag]; ok {
-			// oh, we found existing values, let's make a copy
-			values = make(Values, len(existing_values)+len(new_values))
-			for key, val := range existing_values {
-				values[key] = val
-			}
-			for key, val := range new_values {
-				values[key] = val
-			}
-			break
-		}
-	}
-	new_tag := stackTagPool.Acquire()
-	m.values[new_tag] = values
-	m.mtx.Unlock()
-	defer func() {
+	EnsureGoroutineId(func(gid uint) {
 		m.mtx.Lock()
-		delete(m.values, new_tag)
+		state, found := m.values[gid]
+		if !found {
+			state = make(Values, len(new_values))
+			m.values[gid] = state
+		}
 		m.mtx.Unlock()
-		stackTagPool.Release(new_tag)
-	}()
 
-	addStackTag(new_tag, context_call)
+		for key, new_val := range new_values {
+			mutated_keys = append(mutated_keys, key)
+			if old_val, ok := state[key]; ok {
+				mutated_vals[key] = old_val
+			}
+			state[key] = new_val
+		}
+
+		defer func() {
+			if !found {
+				m.mtx.Lock()
+				delete(m.values, gid)
+				m.mtx.Unlock()
+				return
+			}
+
+			for _, key := range mutated_keys {
+				if val, ok := mutated_vals[key]; ok {
+					state[key] = val
+				} else {
+					delete(state, key)
+				}
+			}
+		}()
+
+		context_call()
+	})
 }
 
 // GetValue will return a previously set value, provided that the value was set
 // by SetValues somewhere higher up the stack. If the value is not found, ok
 // will be false.
-func (m *ContextManager) GetValue(key interface{}) (value interface{}, ok bool) {
-
-	tags := readStackTags(1)
-	m.mtx.RLock()
-	defer m.mtx.RUnlock()
-	for _, tag := range tags {
-		if values, ok := m.values[tag]; ok {
-			value, ok := values[key]
-			return value, ok
-		}
+func (m *ContextManager) GetValue(key interface{}) (
+	value interface{}, ok bool) {
+	gid, ok := GetGoroutineId()
+	if !ok {
+		return nil, false
 	}
-	return "", false
+
+	m.mtx.Lock()
+	state, found := m.values[gid]
+	m.mtx.Unlock()
+
+	if !found {
+		return nil, false
+	}
+	value, ok = state[key]
+	return value, ok
 }
 
 func (m *ContextManager) getValues() Values {
-	tags := readStackTags(2)
-	m.mtx.RLock()
-	defer m.mtx.RUnlock()
-	for _, tag := range tags {
-		if values, ok := m.values[tag]; ok {
-			return values
-		}
+	gid, ok := GetGoroutineId()
+	if !ok {
+		return nil
 	}
-	return nil
+	m.mtx.Lock()
+	state, _ := m.values[gid]
+	m.mtx.Unlock()
+	return state
 }
 
 // Go preserves ContextManager values and Goroutine-local-storage across new
@@ -131,12 +140,12 @@ func Go(cb func()) {
 	mgrRegistryMtx.RLock()
 	defer mgrRegistryMtx.RUnlock()
 
-	for mgr, _ := range mgrRegistry {
+	for mgr := range mgrRegistry {
 		values := mgr.getValues()
 		if len(values) > 0 {
-			mgr_copy := mgr
-			cb_copy := cb
-			cb = func() { mgr_copy.SetValues(values, cb_copy) }
+			cb = func(mgr *ContextManager, cb func()) func() {
+				return func() { mgr.SetValues(values, cb) }
+			}(mgr, cb)
 		}
 	}
 

+ 11 - 3
vendor/github.com/jtolds/gls/gen_sym.go

@@ -1,13 +1,21 @@
 package gls
 
+import (
+	"sync"
+)
+
 var (
-	symPool = &idPool{}
+	keyMtx     sync.Mutex
+	keyCounter uint64
 )
 
 // ContextKey is a throwaway value you can use as a key to a ContextManager
-type ContextKey struct{ id uint }
+type ContextKey struct{ id uint64 }
 
 // GenSym will return a brand new, never-before-used ContextKey
 func GenSym() ContextKey {
-	return ContextKey{id: symPool.Acquire()}
+	keyMtx.Lock()
+	defer keyMtx.Unlock()
+	keyCounter += 1
+	return ContextKey{id: keyCounter}
 }

+ 25 - 0
vendor/github.com/jtolds/gls/gid.go

@@ -0,0 +1,25 @@
+package gls
+
+var (
+	stackTagPool = &idPool{}
+)
+
+// Will return this goroutine's identifier if set. If you always need a
+// goroutine identifier, you should use EnsureGoroutineId which will make one
+// if there isn't one already.
+func GetGoroutineId() (gid uint, ok bool) {
+	return readStackTag()
+}
+
+// Will call cb with the current goroutine identifier. If one hasn't already
+// been generated, one will be created and set first. The goroutine identifier
+// might be invalid after cb returns.
+func EnsureGoroutineId(cb func(gid uint)) {
+	if gid, ok := readStackTag(); ok {
+		cb(gid)
+		return
+	}
+	gid := stackTagPool.Acquire()
+	defer stackTagPool.Release(gid)
+	addStackTag(gid, func() { cb(gid) })
+}

+ 126 - 22
vendor/github.com/jtolds/gls/stack_tags.go

@@ -3,36 +3,105 @@ package gls
 // so, basically, we're going to encode integer tags in base-16 on the stack
 
 const (
-	bitWidth = 4
+	bitWidth       = 4
+	stackBatchSize = 16
 )
 
+var (
+	pc_lookup   = make(map[uintptr]int8, 17)
+	mark_lookup [16]func(uint, func())
+)
+
+func init() {
+	setEntries := func(f func(uint, func()), v int8) {
+		var ptr uintptr
+		f(0, func() {
+			ptr = findPtr()
+		})
+		pc_lookup[ptr] = v
+		if v >= 0 {
+			mark_lookup[v] = f
+		}
+	}
+	setEntries(github_com_jtolds_gls_markS, -0x1)
+	setEntries(github_com_jtolds_gls_mark0, 0x0)
+	setEntries(github_com_jtolds_gls_mark1, 0x1)
+	setEntries(github_com_jtolds_gls_mark2, 0x2)
+	setEntries(github_com_jtolds_gls_mark3, 0x3)
+	setEntries(github_com_jtolds_gls_mark4, 0x4)
+	setEntries(github_com_jtolds_gls_mark5, 0x5)
+	setEntries(github_com_jtolds_gls_mark6, 0x6)
+	setEntries(github_com_jtolds_gls_mark7, 0x7)
+	setEntries(github_com_jtolds_gls_mark8, 0x8)
+	setEntries(github_com_jtolds_gls_mark9, 0x9)
+	setEntries(github_com_jtolds_gls_markA, 0xa)
+	setEntries(github_com_jtolds_gls_markB, 0xb)
+	setEntries(github_com_jtolds_gls_markC, 0xc)
+	setEntries(github_com_jtolds_gls_markD, 0xd)
+	setEntries(github_com_jtolds_gls_markE, 0xe)
+	setEntries(github_com_jtolds_gls_markF, 0xf)
+}
+
 func addStackTag(tag uint, context_call func()) {
 	if context_call == nil {
 		return
 	}
-	markS(tag, context_call)
+	github_com_jtolds_gls_markS(tag, context_call)
 }
 
-func markS(tag uint, cb func()) { _m(tag, cb) }
-func mark0(tag uint, cb func()) { _m(tag, cb) }
-func mark1(tag uint, cb func()) { _m(tag, cb) }
-func mark2(tag uint, cb func()) { _m(tag, cb) }
-func mark3(tag uint, cb func()) { _m(tag, cb) }
-func mark4(tag uint, cb func()) { _m(tag, cb) }
-func mark5(tag uint, cb func()) { _m(tag, cb) }
-func mark6(tag uint, cb func()) { _m(tag, cb) }
-func mark7(tag uint, cb func()) { _m(tag, cb) }
-func mark8(tag uint, cb func()) { _m(tag, cb) }
-func mark9(tag uint, cb func()) { _m(tag, cb) }
-func markA(tag uint, cb func()) { _m(tag, cb) }
-func markB(tag uint, cb func()) { _m(tag, cb) }
-func markC(tag uint, cb func()) { _m(tag, cb) }
-func markD(tag uint, cb func()) { _m(tag, cb) }
-func markE(tag uint, cb func()) { _m(tag, cb) }
-func markF(tag uint, cb func()) { _m(tag, cb) }
-
-var pc_lookup = make(map[uintptr]int8, 17)
-var mark_lookup [16]func(uint, func())
+// these private methods are named this horrendous name so gopherjs support
+// is easier. it shouldn't add any runtime cost in non-js builds.
+
+//go:noinline
+func github_com_jtolds_gls_markS(tag uint, cb func()) { _m(tag, cb) }
+
+//go:noinline
+func github_com_jtolds_gls_mark0(tag uint, cb func()) { _m(tag, cb) }
+
+//go:noinline
+func github_com_jtolds_gls_mark1(tag uint, cb func()) { _m(tag, cb) }
+
+//go:noinline
+func github_com_jtolds_gls_mark2(tag uint, cb func()) { _m(tag, cb) }
+
+//go:noinline
+func github_com_jtolds_gls_mark3(tag uint, cb func()) { _m(tag, cb) }
+
+//go:noinline
+func github_com_jtolds_gls_mark4(tag uint, cb func()) { _m(tag, cb) }
+
+//go:noinline
+func github_com_jtolds_gls_mark5(tag uint, cb func()) { _m(tag, cb) }
+
+//go:noinline
+func github_com_jtolds_gls_mark6(tag uint, cb func()) { _m(tag, cb) }
+
+//go:noinline
+func github_com_jtolds_gls_mark7(tag uint, cb func()) { _m(tag, cb) }
+
+//go:noinline
+func github_com_jtolds_gls_mark8(tag uint, cb func()) { _m(tag, cb) }
+
+//go:noinline
+func github_com_jtolds_gls_mark9(tag uint, cb func()) { _m(tag, cb) }
+
+//go:noinline
+func github_com_jtolds_gls_markA(tag uint, cb func()) { _m(tag, cb) }
+
+//go:noinline
+func github_com_jtolds_gls_markB(tag uint, cb func()) { _m(tag, cb) }
+
+//go:noinline
+func github_com_jtolds_gls_markC(tag uint, cb func()) { _m(tag, cb) }
+
+//go:noinline
+func github_com_jtolds_gls_markD(tag uint, cb func()) { _m(tag, cb) }
+
+//go:noinline
+func github_com_jtolds_gls_markE(tag uint, cb func()) { _m(tag, cb) }
+
+//go:noinline
+func github_com_jtolds_gls_markF(tag uint, cb func()) { _m(tag, cb) }
 
 func _m(tag_remainder uint, cb func()) {
 	if tag_remainder == 0 {
@@ -41,3 +110,38 @@ func _m(tag_remainder uint, cb func()) {
 		mark_lookup[tag_remainder&0xf](tag_remainder>>bitWidth, cb)
 	}
 }
+
+func readStackTag() (tag uint, ok bool) {
+	var current_tag uint
+	offset := 0
+	for {
+		batch, next_offset := getStack(offset, stackBatchSize)
+		for _, pc := range batch {
+			val, ok := pc_lookup[pc]
+			if !ok {
+				continue
+			}
+			if val < 0 {
+				return current_tag, true
+			}
+			current_tag <<= bitWidth
+			current_tag += uint(val)
+		}
+		if next_offset == 0 {
+			break
+		}
+		offset = next_offset
+	}
+	return 0, false
+}
+
+func (m *ContextManager) preventInlining() {
+	// dunno if findPtr or getStack are likely to get inlined in a future release
+	// of go, but if they are inlined and their callers are inlined, that could
+	// hork some things. let's do our best to explain to the compiler that we
+	// really don't want those two functions inlined by saying they could change
+	// at any time. assumes preventInlining doesn't get compiled out.
+	// this whole thing is probably overkill.
+	findPtr = m.values[0][0].(func() uintptr)
+	getStack = m.values[0][1].(func(int, int) ([]uintptr, int))
+}

+ 51 - 77
vendor/github.com/jtolds/gls/stack_tags_js.go

@@ -2,100 +2,74 @@
 
 package gls
 
-// This file is used for GopherJS builds, which don't have normal runtime support
+// This file is used for GopherJS builds, which don't have normal runtime
+// stack trace support
 
 import (
-	"regexp"
 	"strconv"
 	"strings"
 
 	"github.com/gopherjs/gopherjs/js"
 )
 
-var stackRE = regexp.MustCompile("\\s+at (\\S*) \\([^:]+:(\\d+):(\\d+)")
+const (
+	jsFuncNamePrefix = "github_com_jtolds_gls_mark"
+)
 
-func findPtr() uintptr {
-	jsStack := js.Global.Get("Error").New().Get("stack").Call("split", "\n")
-	for i := 1; i < jsStack.Get("length").Int(); i++ {
-		item := jsStack.Index(i).String()
-		matches := stackRE.FindAllStringSubmatch(item, -1)
-		if matches == nil {
-			return 0
+func jsMarkStack() (f []uintptr) {
+	lines := strings.Split(
+		js.Global.Get("Error").New().Get("stack").String(), "\n")
+	f = make([]uintptr, 0, len(lines))
+	for i, line := range lines {
+		line = strings.TrimSpace(line)
+		if line == "" {
+			continue
 		}
-		pkgPath := matches[0][1]
-		if strings.HasPrefix(pkgPath, "$packages.github.com/jtolds/gls.mark") {
-			line, _ := strconv.Atoi(matches[0][2])
-			char, _ := strconv.Atoi(matches[0][3])
-			x := (uintptr(line) << 16) | uintptr(char)
-			return x
+		if i == 0 {
+			if line != "Error" {
+				panic("didn't understand js stack trace")
+			}
+			continue
+		}
+		fields := strings.Fields(line)
+		if len(fields) < 2 || fields[0] != "at" {
+			panic("didn't understand js stack trace")
 		}
-	}
-
-	return 0
-}
 
-func init() {
-	setEntries := func(f func(uint, func()), v int8) {
-		var ptr uintptr
-		f(0, func() {
-			ptr = findPtr()
-		})
-		pc_lookup[ptr] = v
-		if v >= 0 {
-			mark_lookup[v] = f
+		pos := strings.Index(fields[1], jsFuncNamePrefix)
+		if pos < 0 {
+			continue
+		}
+		pos += len(jsFuncNamePrefix)
+		if pos >= len(fields[1]) {
+			panic("didn't understand js stack trace")
+		}
+		char := string(fields[1][pos])
+		switch char {
+		case "S":
+			f = append(f, uintptr(0))
+		default:
+			val, err := strconv.ParseUint(char, 16, 8)
+			if err != nil {
+				panic("didn't understand js stack trace")
+			}
+			f = append(f, uintptr(val)+1)
 		}
 	}
-	setEntries(markS, -0x1)
-	setEntries(mark0, 0x0)
-	setEntries(mark1, 0x1)
-	setEntries(mark2, 0x2)
-	setEntries(mark3, 0x3)
-	setEntries(mark4, 0x4)
-	setEntries(mark5, 0x5)
-	setEntries(mark6, 0x6)
-	setEntries(mark7, 0x7)
-	setEntries(mark8, 0x8)
-	setEntries(mark9, 0x9)
-	setEntries(markA, 0xa)
-	setEntries(markB, 0xb)
-	setEntries(markC, 0xc)
-	setEntries(markD, 0xd)
-	setEntries(markE, 0xe)
-	setEntries(markF, 0xf)
+	return f
 }
 
-func currentStack(skip int) (stack []uintptr) {
-	jsStack := js.Global.Get("Error").New().Get("stack").Call("split", "\n")
-	for i := skip + 2; i < jsStack.Get("length").Int(); i++ {
-		item := jsStack.Index(i).String()
-		matches := stackRE.FindAllStringSubmatch(item, -1)
-		if matches == nil {
-			return stack
+// variables to prevent inlining
+var (
+	findPtr = func() uintptr {
+		funcs := jsMarkStack()
+		if len(funcs) == 0 {
+			panic("failed to find function pointer")
 		}
-		line, _ := strconv.Atoi(matches[0][2])
-		char, _ := strconv.Atoi(matches[0][3])
-		x := (uintptr(line) << 16) | uintptr(char)&0xffff
-		stack = append(stack, x)
+		return funcs[0]
 	}
 
-	return stack
-}
-
-func readStackTags(skip int) (tags []uint) {
-	stack := currentStack(skip)
-	var current_tag uint
-	for _, pc := range stack {
-		val, ok := pc_lookup[pc]
-		if !ok {
-			continue
-		}
-		if val < 0 {
-			tags = append(tags, current_tag)
-			current_tag = 0
-			continue
-		}
-		current_tag <<= bitWidth
-		current_tag += uint(val)
+	getStack = func(offset, amount int) (stack []uintptr, next_offset int) {
+		return jsMarkStack(), 0
 	}
-	return
-}
+)

+ 16 - 47
vendor/github.com/jtolds/gls/stack_tags_main.go

@@ -2,60 +2,29 @@
 
 package gls
 
-// This file is used for standard Go builds, which have the expected runtime support
+// This file is used for standard Go builds, which have the expected runtime
+// support
 
 import (
-	"reflect"
 	"runtime"
 )
 
-func init() {
-	setEntries := func(f func(uint, func()), v int8) {
-		pc_lookup[reflect.ValueOf(f).Pointer()] = v
-		if v >= 0 {
-			mark_lookup[v] = f
+var (
+	findPtr = func() uintptr {
+		var pc [1]uintptr
+		n := runtime.Callers(4, pc[:])
+		if n != 1 {
+			panic("failed to find function pointer")
 		}
+		return pc[0]
 	}
-	setEntries(markS, -0x1)
-	setEntries(mark0, 0x0)
-	setEntries(mark1, 0x1)
-	setEntries(mark2, 0x2)
-	setEntries(mark3, 0x3)
-	setEntries(mark4, 0x4)
-	setEntries(mark5, 0x5)
-	setEntries(mark6, 0x6)
-	setEntries(mark7, 0x7)
-	setEntries(mark8, 0x8)
-	setEntries(mark9, 0x9)
-	setEntries(markA, 0xa)
-	setEntries(markB, 0xb)
-	setEntries(markC, 0xc)
-	setEntries(markD, 0xd)
-	setEntries(markE, 0xe)
-	setEntries(markF, 0xf)
-}
 
-func currentStack(skip int) []uintptr {
-	stack := make([]uintptr, maxCallers)
-	return stack[:runtime.Callers(3+skip, stack)]
-}
-
-func readStackTags(skip int) (tags []uint) {
-	stack := currentStack(skip)
-	var current_tag uint
-	for _, pc := range stack {
-		pc = runtime.FuncForPC(pc).Entry()
-		val, ok := pc_lookup[pc]
-		if !ok {
-			continue
-		}
-		if val < 0 {
-			tags = append(tags, current_tag)
-			current_tag = 0
-			continue
+	getStack = func(offset, amount int) (stack []uintptr, next_offset int) {
+		stack = make([]uintptr, amount)
+		stack = stack[:runtime.Callers(offset, stack)]
+		if len(stack) < amount {
+			return stack, 0
 		}
-		current_tag <<= bitWidth
-		current_tag += uint(val)
+		return stack, offset + len(stack)
 	}
-	return
-}
+)

+ 35 - 0
vendor/github.com/smartystreets/goconvey/CONTRIBUTING.md

@@ -0,0 +1,35 @@
+# Subject: GoConvey maintainers wanted
+
+We'd like to open the project up to additional maintainers who want to move the project forward in a meaningful way.
+
+We've spent significant time at SmartyStreets building GoConvey and it has perfectly met (and exceeded) all of our initial design specifications. We've used it to great effect. Being so well-matched to our development workflows at SmartyStreets, we haven't had a need to hack on it lately. This had been frustrating to many in the community who have ideas for the project and would like to see new features released (and some old bugs fixed). The release of Go 1.5 and the new vendoring experiment has been a source of confusion and hassle for those who have already upgraded and find that GoConvey needs to be brought up to speed.
+
+GoConvey is a popular 2-pronged, open-source github project (1,600+ stargazers, 100+ forks):
+
+- A package you import in your test code that allows you to write BDD-style tests.
+- An executable that runs a local web server which displays auto-updating test results in a web browser.
+
+----
+
+- http://goconvey.co/
+- https://github.com/smartystreets/goconvey
+- https://github.com/smartystreets/goconvey/wiki
+
+_I should mention that the [assertions package](https://github.com/smartystreets/assertions) imported by the convey package is used by other projects at SmartyStreets and so we will be continuing to maintain that project internally._
+
+We hope to hear from you soon. Thanks!
+
+---
+
+# Contributing
+
+In general, the code posted to the [SmartyStreets github organization](https://github.com/smartystreets) is created to solve specific problems at SmartyStreets that are ancillary to our core products in the address verification industry and may or may not be useful to other organizations or developers. Our reason for posting said code isn't necessarily to solicit feedback or contributions from the community but more as a showcase of some of the approaches to solving problems we have adopted.
+
+Having stated that, we do consider issues raised by other githubbers as well as contributions submitted via pull requests. When submitting such a pull request, please follow these guidelines:
+
+- _Look before you leap:_ If the changes you plan to make are significant, it's in everyone's best interest for you to discuss them with a SmartyStreets team member prior to opening a pull request.
+- _License and ownership:_ If modifying the `LICENSE.md` file, limit your changes to fixing typographical mistakes. Do NOT modify the actual terms in the license or the copyright by **SmartyStreets, LLC**. Code submitted to SmartyStreets projects becomes property of SmartyStreets and must be compatible with the associated license.
+- _Testing:_ If the code you are submitting resides in packages/modules covered by automated tests, be sure to add passing tests that cover your changes and assert expected behavior and state. Submit the additional test cases as part of your change set.
+- _Style:_ Match your approach to **naming** and **formatting** with the surrounding code. Basically, the code you submit shouldn't stand out.
+  - "Naming" refers to such constructs as variables, methods, functions, classes, structs, interfaces, packages, modules, directories, files, etc...
+  - "Formatting" refers to such constructs as whitespace, horizontal line length, vertical function length, vertical file length, indentation, curly braces, etc...

+ 1 - 1
vendor/github.com/smartystreets/goconvey/LICENSE.md

@@ -1,4 +1,4 @@
-Copyright (c) 2014 SmartyStreets, LLC
+Copyright (c) 2016 SmartyStreets, LLC
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal

+ 124 - 0
vendor/github.com/smartystreets/goconvey/README.md

@@ -0,0 +1,124 @@
+GoConvey is awesome Go testing
+==============================
+
+[![Build Status](https://travis-ci.org/smartystreets/goconvey.png)](https://travis-ci.org/smartystreets/goconvey)
+[![GoDoc](https://godoc.org/github.com/smartystreets/goconvey?status.svg)](http://godoc.org/github.com/smartystreets/goconvey)
+
+
+Welcome to GoConvey, a yummy Go testing tool for gophers. Works with `go test`. Use it in the terminal or browser according to your viewing pleasure. **[View full feature tour.](http://goconvey.co)**
+
+**Features:**
+
+- Directly integrates with `go test`
+- Fully-automatic web UI (works with native Go tests, too)
+- Huge suite of regression tests
+- Shows test coverage (Go 1.2+)
+- Readable, colorized console output (understandable by any manager, IT or not)
+- Test code generator
+- Desktop notifications (optional)
+- Immediately open problem lines in [Sublime Text](http://www.sublimetext.com) ([some assembly required](https://github.com/asuth/subl-handler))
+
+
+You can ask questions about how to use GoConvey on [StackOverflow](http://stackoverflow.com/questions/ask?tags=goconvey,go&title=GoConvey%3A%20). Use the tags `go` and `goconvey`.
+
+**Menu:**
+
+- [Installation](#installation)
+- [Quick start](#quick-start)
+- [Documentation](#documentation)
+- [Screenshots](#screenshots)
+- [Contributors](#contributors)
+
+
+
+
+Installation
+------------
+
+	$ go get github.com/smartystreets/goconvey
+
+[Quick start](https://github.com/smartystreets/goconvey/wiki#get-going-in-25-seconds)
+-----------
+
+Make a test, for example:
+
+```go
+package package_name
+
+import (
+    "testing"
+    . "github.com/smartystreets/goconvey/convey"
+)
+
+func TestSpec(t *testing.T) {
+
+	// Only pass t into top-level Convey calls
+	Convey("Given some integer with a starting value", t, func() {
+		x := 1
+
+		Convey("When the integer is incremented", func() {
+			x++
+
+			Convey("The value should be greater by one", func() {
+				So(x, ShouldEqual, 2)
+			})
+		})
+	})
+}
+```
+
+
+#### [In the browser](https://github.com/smartystreets/goconvey/wiki/Web-UI)
+
+Start up the GoConvey web server at your project's path:
+
+	$ $GOPATH/bin/goconvey
+
+Then watch the test results display in your browser at:
+
+	http://localhost:8080
+
+
+If the browser doesn't open automatically, please click [http://localhost:8080](http://localhost:8080) to open manually.
+
+There you have it.
+![](http://d79i1fxsrar4t.cloudfront.net/goconvey.co/gc-1-dark.png)
+As long as GoConvey is running, test results will automatically update in your browser window.
+
+![](http://d79i1fxsrar4t.cloudfront.net/goconvey.co/gc-5-dark.png)
+The design is responsive, so you can squish the browser real tight if you need to put it beside your code.
+
+
+The [web UI](https://github.com/smartystreets/goconvey/wiki/Web-UI) supports traditional Go tests, so use it even if you're not using GoConvey tests.
+
+
+
+#### [In the terminal](https://github.com/smartystreets/goconvey/wiki/Execution)
+
+Just do what you do best:
+
+    $ go test
+
+Or if you want the output to include the story:
+
+    $ go test -v
+
+
+[Documentation](https://github.com/smartystreets/goconvey/wiki)
+-----------
+
+Check out the
+
+- [GoConvey wiki](https://github.com/smartystreets/goconvey/wiki),
+- [![GoDoc](https://godoc.org/github.com/smartystreets/goconvey?status.png)](http://godoc.org/github.com/smartystreets/goconvey)
+- and the *_test.go files scattered throughout this project.
+
+[Screenshots](http://goconvey.co)
+-----------
+
+For web UI and terminal screenshots, check out [the full feature tour](http://goconvey.co).
+
+Contributors
+----------------------
+
+GoConvey is brought to you by [SmartyStreets](https://github.com/smartystreets) and [several contributors](https://github.com/smartystreets/goconvey/graphs/contributors) (Thanks!).

+ 4 - 0
vendor/github.com/smartystreets/goconvey/dependencies.go

@@ -0,0 +1,4 @@
+package main
+
+import _ "github.com/jtolds/gls"
+import _ "github.com/smartystreets/assertions"

+ 8 - 0
vendor/github.com/smartystreets/goconvey/go.mod

@@ -0,0 +1,8 @@
+module github.com/smartystreets/goconvey
+
+require (
+	github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect
+	github.com/jtolds/gls v4.20.0+incompatible
+	github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d
+	golang.org/x/tools v0.0.0-20190328211700-ab21143f2384
+)

+ 12 - 0
vendor/github.com/smartystreets/goconvey/go.sum

@@ -0,0 +1,12 @@
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384 h1:TFlARGu6Czu1z7q93HTxcP1P+/ZFC/IKythI5RzrnRg=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=

+ 293 - 0
vendor/github.com/smartystreets/goconvey/goconvey.go

@@ -0,0 +1,293 @@
+// This executable provides an HTTP server that watches for file system changes
+// to .go files within the working directory (and all nested go packages).
+// Navigating to the configured host and port in a web browser will display the
+// latest results of running `go test` in each go package.
+package main
+
+import (
+	"flag"
+	"fmt"
+	"log"
+	"net"
+	"net/http"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"runtime"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/smartystreets/goconvey/web/server/api"
+	"github.com/smartystreets/goconvey/web/server/contract"
+	"github.com/smartystreets/goconvey/web/server/executor"
+	"github.com/smartystreets/goconvey/web/server/messaging"
+	"github.com/smartystreets/goconvey/web/server/parser"
+	"github.com/smartystreets/goconvey/web/server/system"
+	"github.com/smartystreets/goconvey/web/server/watch"
+)
+
+func init() {
+	flags()
+	folders()
+}
+func flags() {
+	flag.IntVar(&port, "port", 8080, "The port at which to serve http.")
+	flag.StringVar(&host, "host", "127.0.0.1", "The host at which to serve http.")
+	flag.DurationVar(&nap, "poll", quarterSecond, "The interval to wait between polling the file system for changes.")
+	flag.IntVar(&parallelPackages, "packages", 10, "The number of packages to test in parallel. Higher == faster but more costly in terms of computing.")
+	flag.StringVar(&gobin, "gobin", "go", "The path to the 'go' binary (default: search on the PATH).")
+	flag.BoolVar(&cover, "cover", true, "Enable package-level coverage statistics. Requires Go 1.2+ and the go cover tool.")
+	flag.IntVar(&depth, "depth", -1, "The directory scanning depth. If -1, scan infinitely deep directory structures. 0: scan working directory. 1+: Scan into nested directories, limited to value.")
+	flag.StringVar(&timeout, "timeout", "0", "The test execution timeout if none is specified in the *.goconvey file (default is '0', which is the same as not providing this option).")
+	flag.StringVar(&watchedSuffixes, "watchedSuffixes", ".go", "A comma separated list of file suffixes to watch for modifications.")
+	flag.StringVar(&excludedDirs, "excludedDirs", "vendor,node_modules", "A comma separated list of directories that will be excluded from being watched")
+	flag.StringVar(&workDir, "workDir", "", "set goconvey working directory (default current directory)")
+	flag.BoolVar(&autoLaunchBrowser, "launchBrowser", true, "toggle auto launching of browser (default: true)")
+
+	log.SetOutput(os.Stdout)
+	log.SetFlags(log.LstdFlags | log.Lshortfile)
+}
+func folders() {
+	_, file, _, _ := runtime.Caller(0)
+	here := filepath.Dir(file)
+	static = filepath.Join(here, "/web/client")
+	reports = filepath.Join(static, "reports")
+}
+
+func main() {
+	flag.Parse()
+	log.Printf(initialConfiguration, host, port, nap, cover)
+
+	working := getWorkDir()
+	cover = coverageEnabled(cover, reports)
+	shell := system.NewShell(gobin, reports, cover, timeout)
+
+	watcherInput := make(chan messaging.WatcherCommand)
+	watcherOutput := make(chan messaging.Folders)
+	excludedDirItems := strings.Split(excludedDirs, `,`)
+	watcher := watch.NewWatcher(working, depth, nap, watcherInput, watcherOutput, watchedSuffixes, excludedDirItems)
+
+	parser := parser.NewParser(parser.ParsePackageResults)
+	tester := executor.NewConcurrentTester(shell)
+	tester.SetBatchSize(parallelPackages)
+
+	longpollChan := make(chan chan string)
+	executor := executor.NewExecutor(tester, parser, longpollChan)
+	server := api.NewHTTPServer(working, watcherInput, executor, longpollChan)
+	listener := createListener()
+	go runTestOnUpdates(watcherOutput, executor, server)
+	go watcher.Listen()
+	if autoLaunchBrowser {
+		go launchBrowser(listener.Addr().String())
+	}
+	serveHTTP(server, listener)
+}
+
+func browserCmd() (string, bool) {
+	browser := map[string]string{
+		"darwin":  "open",
+		"linux":   "xdg-open",
+		"windows": "start",
+	}
+	cmd, ok := browser[runtime.GOOS]
+	return cmd, ok
+}
+
+func launchBrowser(addr string) {
+	browser, ok := browserCmd()
+	if !ok {
+		log.Printf("Skipped launching browser for this OS: %s", runtime.GOOS)
+		return
+	}
+
+	log.Printf("Launching browser on %s", addr)
+	url := fmt.Sprintf("http://%s", addr)
+	cmd := exec.Command(browser, url)
+
+	output, err := cmd.CombinedOutput()
+	if err != nil {
+		log.Println(err)
+	}
+	log.Println(string(output))
+}
+
+func runTestOnUpdates(queue chan messaging.Folders, executor contract.Executor, server contract.Server) {
+	for update := range queue {
+		log.Println("Received request from watcher to execute tests...")
+		packages := extractPackages(update)
+		output := executor.ExecuteTests(packages)
+		root := extractRoot(update, packages)
+		server.ReceiveUpdate(root, output)
+	}
+}
+
+func extractPackages(folderList messaging.Folders) []*contract.Package {
+	packageList := []*contract.Package{}
+	for _, folder := range folderList {
+		hasImportCycle := testFilesImportTheirOwnPackage(folder.Path)
+		packageName := resolvePackageName(folder.Path)
+		packageList = append(
+			packageList,
+			contract.NewPackage(folder, packageName, hasImportCycle),
+		)
+	}
+	return packageList
+}
+
+func extractRoot(folderList messaging.Folders, packageList []*contract.Package) string {
+	path := packageList[0].Path
+	folder := folderList[path]
+	return folder.Root
+}
+
+func createListener() net.Listener {
+	l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", host, port))
+	if err != nil {
+		log.Println(err)
+	}
+	if l == nil {
+		os.Exit(1)
+	}
+	return l
+}
+
+func serveHTTP(server contract.Server, listener net.Listener) {
+	serveStaticResources()
+	serveAjaxMethods(server)
+	activateServer(listener)
+}
+
+func serveStaticResources() {
+	http.Handle("/", http.FileServer(http.Dir(static)))
+}
+
+func serveAjaxMethods(server contract.Server) {
+	http.HandleFunc("/watch", server.Watch)
+	http.HandleFunc("/ignore", server.Ignore)
+	http.HandleFunc("/reinstate", server.Reinstate)
+	http.HandleFunc("/latest", server.Results)
+	http.HandleFunc("/execute", server.Execute)
+	http.HandleFunc("/status", server.Status)
+	http.HandleFunc("/status/poll", server.LongPollStatus)
+	http.HandleFunc("/pause", server.TogglePause)
+}
+
+func activateServer(listener net.Listener) {
+	log.Printf("Serving HTTP at: http://%s\n", listener.Addr())
+	err := http.Serve(listener, nil)
+	if err != nil {
+		log.Println(err)
+	}
+}
+
+func coverageEnabled(cover bool, reports string) bool {
+	return (cover &&
+		goMinVersion(1, 2) &&
+		coverToolInstalled() &&
+		ensureReportDirectoryExists(reports))
+}
+func goMinVersion(wanted ...int) bool {
+	version := runtime.Version() // 'go1.2....'
+	s := regexp.MustCompile(`go([\d]+)\.([\d]+)\.?([\d]+)?`).FindAllStringSubmatch(version, 1)
+	if len(s) == 0 {
+		log.Printf("Cannot determine if newer than go1.2, disabling coverage.")
+		return false
+	}
+	for idx, str := range s[0][1:] {
+		if len(wanted) == idx {
+			break
+		}
+		if v, _ := strconv.Atoi(str); v < wanted[idx] {
+			log.Printf(pleaseUpgradeGoVersion, version)
+			return false
+		}
+	}
+	return true
+}
+func coverToolInstalled() bool {
+	working := getWorkDir()
+	command := system.NewCommand(working, "go", "tool", "cover").Execute()
+	installed := strings.Contains(command.Output, "Usage of 'go tool cover':")
+	if !installed {
+		log.Print(coverToolMissing)
+		return false
+	}
+	return true
+}
+func ensureReportDirectoryExists(reports string) bool {
+	result, err := exists(reports)
+	if err != nil {
+		log.Fatal(err)
+	}
+	if result {
+		return true
+	}
+
+	if err := os.Mkdir(reports, 0755); err == nil {
+		return true
+	}
+
+	log.Printf(reportDirectoryUnavailable, reports)
+	return false
+}
+func exists(path string) (bool, error) {
+	_, err := os.Stat(path)
+	if err == nil {
+		return true, nil
+	}
+	if os.IsNotExist(err) {
+		return false, nil
+	}
+	return false, err
+}
+func getWorkDir() string {
+	working := ""
+	var err error
+	if workDir != "" {
+		working = workDir
+	} else {
+		working, err = os.Getwd()
+		if err != nil {
+			log.Fatal(err)
+		}
+	}
+	result, err := exists(working)
+	if err != nil {
+		log.Fatal(err)
+	}
+	if !result {
+		log.Fatalf("Path:%s does not exists", working)
+	}
+	return working
+}
+
+var (
+	port              int
+	host              string
+	gobin             string
+	nap               time.Duration
+	parallelPackages  int
+	cover             bool
+	depth             int
+	timeout           string
+	watchedSuffixes   string
+	excludedDirs      string
+	autoLaunchBrowser bool
+
+	static  string
+	reports string
+
+	quarterSecond = time.Millisecond * 250
+	workDir       string
+)
+
+const (
+	initialConfiguration       = "Initial configuration: [host: %s] [port: %d] [poll: %v] [cover: %v]\n"
+	pleaseUpgradeGoVersion     = "Go version is less that 1.2 (%s), please upgrade to the latest stable version to enable coverage reporting.\n"
+	coverToolMissing           = "Go cover tool is not installed or not accessible: for Go < 1.5 run`go get golang.org/x/tools/cmd/cover`\n For >= Go 1.5 run `go install $GOROOT/src/cmd/cover`\n"
+	reportDirectoryUnavailable = "Could not find or create the coverage report directory (at: '%s'). You probably won't see any coverage statistics...\n"
+	separator                  = string(filepath.Separator)
+	endGoPath                  = separator + "src" + separator
+)

+ 42 - 0
vendor/github.com/smartystreets/goconvey/goconvey_1_8.go

@@ -0,0 +1,42 @@
+// +build !go1.9
+
+// To work correctly with out of GOPATH modules, some functions needed to
+// switch from using go/build to golang.org/x/tools/go/packages. But that
+// package depends on changes to go/types that were introduced in Go 1.9. Since
+// modules weren't introduced until Go 1.11, users of Go 1.8 or below can't be
+// using modules, so they can continue to use go/build.
+
+package main
+
+import (
+	"go/build"
+	"strings"
+)
+
+// This method exists because of a bug in the go cover tool that
+// causes an infinite loop when you try to run `go test -cover`
+// on a package that has an import cycle defined in one of it's
+// test files. Yuck.
+func testFilesImportTheirOwnPackage(packagePath string) bool {
+	meta, err := build.ImportDir(packagePath, build.AllowBinary)
+	if err != nil {
+		return false
+	}
+
+	for _, dependency := range meta.TestImports {
+		if dependency == meta.ImportPath {
+			return true
+		}
+	}
+	return false
+}
+
+func resolvePackageName(path string) string {
+	pkg, err := build.ImportDir(path, build.FindOnly)
+	if err == nil {
+		return pkg.ImportPath
+	}
+
+	nameArr := strings.Split(path, endGoPath)
+	return nameArr[len(nameArr)-1]
+}

+ 64 - 0
vendor/github.com/smartystreets/goconvey/goconvey_1_9.go

@@ -0,0 +1,64 @@
+// +build go1.9
+
+// To work correctly with out of GOPATH modules, some functions needed to
+// switch from using go/build to golang.org/x/tools/go/packages. But that
+// package depends on changes to go/types that were introduced in Go 1.9. Since
+// modules weren't introduced until Go 1.11, using
+// golang.org/x/tools/go/packages can safely be restricted to users of Go 1.9
+// or above.
+package main
+
+import (
+	"fmt"
+	"strings"
+
+	"golang.org/x/tools/go/packages"
+)
+
+// This method exists because of a bug in the go cover tool that
+// causes an infinite loop when you try to run `go test -cover`
+// on a package that has an import cycle defined in one of it's
+// test files. Yuck.
+func testFilesImportTheirOwnPackage(packagePath string) bool {
+	meta, err := packages.Load(
+		&packages.Config{
+			Mode:  packages.NeedName | packages.NeedImports,
+			Tests: true,
+		},
+		packagePath,
+	)
+	if err != nil {
+		return false
+	}
+
+	testPackageID := fmt.Sprintf("%s [%s.test]", meta[0], meta[0])
+
+	for _, testPackage := range meta[1:] {
+		if testPackage.ID != testPackageID {
+			continue
+		}
+
+		for dependency := range testPackage.Imports {
+			if dependency == meta[0].PkgPath {
+				return true
+			}
+		}
+		break
+	}
+	return false
+}
+
+func resolvePackageName(path string) string {
+	pkg, err := packages.Load(
+		&packages.Config{
+			Mode: packages.NeedName,
+		},
+		path,
+	)
+	if err == nil {
+		return pkg[0].PkgPath
+	}
+
+	nameArr := strings.Split(path, endGoPath)
+	return nameArr[len(nameArr)-1]
+}

+ 9 - 3
vendor/vendor.json

@@ -261,10 +261,10 @@
 			"revisionTime": "2018-05-26T01:43:29Z"
 		},
 		{
-			"checksumSHA1": "tewA7jXVGCw1zb5mA0BDecWi4iQ=",
+			"checksumSHA1": "cIiyvAduLLFvu+tg1Qr5Jw3jeWo=",
 			"path": "github.com/jtolds/gls",
-			"revision": "8ddce2a84170772b95dd5d576c48d517b22cac63",
-			"revisionTime": "2016-01-05T22:08:40Z"
+			"revision": "b4936e06046bbecbb94cae9c18127ebe510a2cb9",
+			"revisionTime": "2018-11-10T20:28:10Z"
 		},
 		{
 			"checksumSHA1": "vfzz7zTL9TZLpFO7NC1H6/Du3+s=",
@@ -488,6 +488,12 @@
 			"revision": "287b4346dc4e71a038c346375a9d572453bc469b",
 			"revisionTime": "2016-02-05T03:39:31Z"
 		},
+		{
+			"checksumSHA1": "7E7jpXiYAxa4vxc+2ftP4aBrDy8=",
+			"path": "github.com/smartystreets/goconvey",
+			"revision": "9d28bd7c0945047857c9740bd2eb3d62f98d3d35",
+			"revisionTime": "2019-07-10T18:59:42Z"
+		},
 		{
 			"checksumSHA1": "fQeXVv5U9dlo3ufH2vjk1GNf4Lo=",
 			"path": "github.com/smartystreets/goconvey/convey",