-
Notifications
You must be signed in to change notification settings - Fork 3
/
given.go
89 lines (78 loc) · 2.83 KB
/
given.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package gogiven
import (
"github.com/corbym/gogiven/base"
"github.com/fatih/camelcase"
"runtime"
"strings"
)
var globalTestContextMap = newSafeMap()
// Given sets up some interesting givens for the test.
// Pass in testing.T here and a function which adds some givens to
// the map.
//
// *Warning:* if you call this method twice in a test, you will start a new test
// which will appear in the test output.
func Given(testing base.TestingT, given ...base.GivenData) *base.Some {
currentFunction, testFileName := testFunctionFileName()
currentTestContext := loadTestContext(testFileName)
someTests := currentTestContext.someTests
keyFor := uniqueKeyFor(someTests, currentFunction.Name())
some := base.NewSome(
testing,
testTitle(testing.Name()),
base.NewTestMetaData(keyFor),
base.ParseGivenWhenThen(currentFunction.Name(), currentTestContext.FileName()),
given...,
)
someTests.Store(keyFor, some)
return some
}
func loadTestContext(testFileName string) (currentTestContext *TestContext) {
if value, ok := globalTestContextMap.Load(testFileName); ok {
currentTestContext = value.(*TestContext)
} else {
currentTestContext = NewTestContext(testFileName)
globalTestContextMap.Store(testFileName, currentTestContext)
}
return
}
// When is a shortcut method when no Given is required.
func When(testing base.TestingT, action ...base.CapturedIOGivenData) *base.Some {
some := Given(testing)
return some.When(action...)
}
func testTitle(functionName string) string {
lastDotInTestName := strings.LastIndex(functionName, ".Test") + (len(".Test") - 1)
return strings.Replace(strings.Join(camelcase.Split(functionName[lastDotInTestName+1:]), " "), "_", " ", -1)
}
func testFunctionFileName() (*runtime.Func, string) {
funcProgramCounters, function := findTestFpcFunction()
testFileName, _ := function.FileLine(funcProgramCounters[0] - 1)
return function, testFileName
}
func findTestFpcFunction() ([]uintptr, *runtime.Func) {
funcProgramCounters := make([]uintptr, 1)
var function *runtime.Func
var cnt = 1
for notFound := true; notFound; notFound = !strings.Contains(function.Name(), ".Test") {
noOfEntries := runtime.Callers(cnt, funcProgramCounters)
if noOfEntries == 0 {
panic("eek, no entries in callers list; cannot set funcProgramCounters")
}
// get the info of the actual function that's in the pointer
function = runtime.FuncForPC(funcProgramCounters[0] - 1)
if function == nil {
panic("arrgh: no function found, or dropped off end of stack!")
}
cnt++
}
return funcProgramCounters, function
}
// uniqueKeyFor generates a unique id for the test loop for this test.
// It deals with table test for loops that do not have t.Run inside... we want different id for each
func uniqueKeyFor(somes *SafeMap, name string) string {
if _, ok := somes.Load(name); !ok {
return name
}
return uniqueKeyFor(somes, name+"_1")
}