Skip to content

Commit

Permalink
refact
Browse files Browse the repository at this point in the history
  • Loading branch information
adamluzsi committed Jul 2, 2024
1 parent 281b899 commit a1c2c30
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 73 deletions.
12 changes: 6 additions & 6 deletions DSL.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,28 @@ import (
// in order to avoid repetitive test cases in the `Then` I often define a `onSuccess` variable,
// with a function that takes `testcase#variables` as well and test error return value there with `testcase#variables.T()`.
func (spec *Spec) Describe(subjectTopic string, specification sBlock, opts ...SpecOption) {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
opts = append([]SpecOption{Group(subjectTopic)}, opts...)
spec.Context(fmt.Sprintf(`%s %s`, `describe`, subjectTopic), specification, opts...)
}

// When is an alias for testcase#Spec.Context
// When is used usually to represent `if` based decision reasons about your testing subject.
func (spec *Spec) When(desc string, testContextBlock sBlock, opts ...SpecOption) {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
spec.Context(fmt.Sprintf(`%s %s`, `when`, desc), testContextBlock, opts...)
}

// And is an alias for testcase#Spec.Context
// And is used to represent additional requirement for reaching a certain testing runtime contexts.
func (spec *Spec) And(desc string, testContextBlock sBlock, opts ...SpecOption) {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
spec.Context(fmt.Sprintf(`%s %s`, `and`, desc), testContextBlock, opts...)
}

// Then is an alias for Test
func (spec *Spec) Then(desc string, test tBlock, opts ...SpecOption) {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
desc = fmt.Sprintf(`%s %s`, `then`, desc)
spec.Test(desc, test, opts...)
}
Expand All @@ -60,7 +60,7 @@ func (spec *Spec) Then(desc string, test tBlock, opts ...SpecOption) {
// the test specification has side effects that would affect other test specification results,
// and, as such, must be executed sequentially.
func (spec *Spec) NoSideEffect() {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
spec.Parallel()
}

Expand All @@ -73,7 +73,7 @@ func (spec *Spec) NoSideEffect() {
// This allows flexibility for the developers to use side effect free variant for local development that has quick feedback loop,
// and replace them with the production implementation during CI/CD pipeline which less time critical.
func (spec *Spec) HasSideEffect() {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
spec.Sequential()
}

Expand Down
86 changes: 34 additions & 52 deletions Spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
// NewSpec create new Spec struct that is ready for usage.
func NewSpec(tb testing.TB, opts ...SpecOption) *Spec {
h(tb).Helper()
tb, opts = checkSuite(tb, opts)
// tb, opts = checkSuite(tb, opts)
var s *Spec
switch tb := tb.(type) {
case *T:
Expand All @@ -44,7 +44,6 @@ func newSpec(tb testing.TB, opts ...SpecOption) *Spec {
opts: opts,
vars: newVariables(),
immutable: false,
isSuite: tb == nil,
}
s.doc.maker = doc.DocumentFormat{}
for _, to := range opts {
Expand All @@ -54,7 +53,7 @@ func newSpec(tb testing.TB, opts ...SpecOption) *Spec {
}

func (spec *Spec) newSubSpec(desc string, opts ...SpecOption) *Spec {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
spec.immutable = true
sub := newSpec(spec.testingTB, opts...)
sub.parent = spec
Expand Down Expand Up @@ -123,9 +122,6 @@ type Spec struct {
orderer orderer
seed int64
sync bool

isSuite bool
suiteName string
}

type (
Expand All @@ -148,15 +144,14 @@ type (
// To verify easily your state-machine, you can count the `if`s in your implementation,
// and check that each `if` has 2 `When` block to represent the two possible path.
func (spec *Spec) Context(desc string, testContextBlock sBlock, opts ...SpecOption) {
spec.testingTB.Helper()
spec.modify(func(spec *Spec) {
spec.defs = append(spec.defs, func(oth *Spec) {
oth.Context(desc, testContextBlock, opts...)
})
if spec.getIsSuite() {
if spec.isSuite() {
return
}
spec.testingTB.Helper()
h(spec.testingTB).Helper()
sub := spec.newSubSpec(desc, opts...)
if spec.sync {
defer sub.Finish()
Expand Down Expand Up @@ -212,10 +207,10 @@ func (spec *Spec) Test(desc string, test tBlock, opts ...SpecOption) {
spec.defs = append(spec.defs, func(oth *Spec) {
oth.Test(desc, test, opts...)
})
if spec.getIsSuite() {
if spec.isSuite() {
return
}
spec.testingTB.Helper()
h(spec.testingTB).Helper()
s := spec.newSubSpec(desc, opts...)
s.isTest = !s.isBenchmark
s.hasRan = true
Expand Down Expand Up @@ -254,7 +249,7 @@ const warnEventOnImmutableFormat = `you can't use .%s after you already used whe
// It is a shortcut for executing *testing.T#Parallel() for each test
func (spec *Spec) Parallel() {
spec.modify(func(spec *Spec) {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
if spec.immutable {
spec.testingTB.Fatalf(warnEventOnImmutableFormat, `Parallel`)
}
Expand All @@ -266,7 +261,7 @@ func (spec *Spec) Parallel() {
// If you wish to skip only a certain test, not the whole Spec / Context, use the SkipBenchmark SpecOption instead.
func (spec *Spec) SkipBenchmark() {
spec.modify(func(spec *Spec) {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
if spec.immutable {
spec.testingTB.Fatalf(warnEventOnImmutableFormat, `SkipBenchmark`)
}
Expand All @@ -281,7 +276,7 @@ func (spec *Spec) SkipBenchmark() {
// and there you want to manage if you want to use components side effects or not.
func (spec *Spec) Sequential() {
spec.modify(func(spec *Spec) {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
if spec.immutable {
panic(fmt.Sprintf(warnEventOnImmutableFormat, `Sequential`))
}
Expand All @@ -306,13 +301,13 @@ func (spec *Spec) Sequential() {
// TESTCASE_TAG_INCLUDE='E2E' TESTCASE_TAG_EXCLUDE='list,of,excluded,tags' go test ./...
func (spec *Spec) Tag(tags ...string) {
spec.modify(func(spec *Spec) {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
spec.tags = append(spec.tags, tags...)
})
}

func (spec *Spec) isAllowedToRun() bool {
spec.testingTB.Helper()
h(spec.testingTB).Helper()

if spec.isTest && !spec.isTestAllowedToRun() {
return false
Expand Down Expand Up @@ -342,7 +337,7 @@ func (spec *Spec) isAllowedToRun() bool {
}

func (spec *Spec) isTestAllowedToRun() bool {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
for _, context := range spec.specsFromParent() {
if context.skipTest {
return false
Expand All @@ -352,7 +347,7 @@ func (spec *Spec) isTestAllowedToRun() bool {
}

func (spec *Spec) isBenchAllowedToRun() bool {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
for _, context := range spec.specsFromParent() {
if context.skipBenchmark {
return false
Expand All @@ -362,7 +357,7 @@ func (spec *Spec) isBenchAllowedToRun() bool {
}

func (spec *Spec) lookupRetryFlaky() (assert.Retry, bool) {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
for _, context := range spec.specsFromParent() {
if context.flaky != nil {
return *context.flaky, true
Expand All @@ -372,7 +367,7 @@ func (spec *Spec) lookupRetryFlaky() (assert.Retry, bool) {
}

func (spec *Spec) lookupRetryEventually() (assert.Retry, bool) {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
for _, context := range spec.specsFromParent() {
if context.eventually != nil {
return *context.eventually, true
Expand All @@ -382,7 +377,7 @@ func (spec *Spec) lookupRetryEventually() (assert.Retry, bool) {
}

func (spec *Spec) printDescription(tb testing.TB) {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
tb.Helper()
var lines []interface{}

Expand Down Expand Up @@ -421,7 +416,7 @@ func (spec *Spec) name() string {
///////////////////////////////////////////////////////=- run -=////////////////////////////////////////////////////////

func (spec *Spec) run(blk func(*T)) {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
if !spec.isAllowedToRun() {
return
}
Expand Down Expand Up @@ -482,9 +477,10 @@ func (spec *Spec) isTestRunner() bool {
}

func (spec *Spec) modify(blk func(spec *Spec)) {
spec.testingTB.Helper()
spec.mods = append(spec.mods, blk)
blk(spec)
if isValidTestingTB(spec.testingTB) {
blk(spec)
}
}

func (spec *Spec) getTestSeed(tb testing.TB) int64 {
Expand All @@ -495,7 +491,7 @@ func (spec *Spec) getTestSeed(tb testing.TB) int64 {
}

func (spec *Spec) runTB(tb testing.TB, blk func(*T)) {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
tb.Helper()
spec.hasRan = true
if tb, ok := tb.(interface{ Parallel() }); ok && spec.isParallel() {
Expand Down Expand Up @@ -531,7 +527,7 @@ func (spec *Spec) runTB(tb testing.TB, blk func(*T)) {
}

func (spec *Spec) runB(b *testing.B, blk func(*T)) {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
b.Helper()
t := newT(b, spec)
if _, ok := spec.lookupRetryFlaky(); ok {
Expand Down Expand Up @@ -577,7 +573,7 @@ func (spec *Spec) acceptVisitor(v visitor) {
// and resource closed with a deferred function, but the spec is still not ran.
func (spec *Spec) Finish() {
spec.modify(func(spec *Spec) {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
var tests []func()
spec.acceptVisitor(visitorFunc(func(s *Spec) {
if s.finished {
Expand Down Expand Up @@ -605,10 +601,10 @@ func (spec *Spec) documentResults() {
if spec.parent != nil {
return
}
if spec.isSuite || spec.isBenchmark {
if spec.isSuite() || spec.isBenchmark {
return
}
spec.testingTB.Helper()
h(spec.testingTB).Helper()
spec.doc.once.Do(func() {
var collect func(*Spec) []doc.TestingCase
collect = func(spec *Spec) []doc.TestingCase {
Expand All @@ -633,7 +629,7 @@ func (spec *Spec) documentResults() {
}

func (spec *Spec) withFinishUsingTestingTB(tb testing.TB, blk func()) {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
tb.Helper()
ogTB := spec.testingTB
defer func() { spec.testingTB = ogTB }()
Expand All @@ -643,7 +639,7 @@ func (spec *Spec) withFinishUsingTestingTB(tb testing.TB, blk func()) {
}

func (spec *Spec) isParallel() bool {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
var (
isParallel bool
isSequential bool
Expand Down Expand Up @@ -692,7 +688,7 @@ func (spec *Spec) specsFromCurrent() []*Spec {
}

func (spec *Spec) lookupParent() (*Spec, bool) {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
for _, s := range spec.specsFromCurrent() {
if s.hasRan { // skip test
continue
Expand All @@ -706,7 +702,7 @@ func (spec *Spec) lookupParent() (*Spec, bool) {
}

func (spec *Spec) getTagSet() map[string]struct{} {
spec.testingTB.Helper()
h(spec.testingTB).Helper()
tagsSet := make(map[string]struct{})
for _, ctx := range spec.specsFromParent() {
for _, tag := range ctx.tags {
Expand All @@ -719,7 +715,7 @@ func (spec *Spec) getTagSet() map[string]struct{} {
// addTest registers a testing block to be executed as part of the Spec.
// the main purpose is to enable test execution order manipulation throught the TESTCASE_SEED.
func (spec *Spec) addTest(blk func()) {
spec.testingTB.Helper()
h(spec.testingTB).Helper()

if p, ok := spec.lookupParent(); ok && p.sync {
blk()
Expand Down Expand Up @@ -747,30 +743,25 @@ To achieve this, the current "testcase.Spec" needs to be created as a suite by p
Once the "Spec" is converted into a suite, you can use "testcase.Spec#Spec" as the function block for another "testcase.Spec" "#Context" call.`

func (spec *Spec) Spec(oth *Spec) {
if !spec.isSuite {
h(oth.testingTB).Helper()
if !spec.isSuite() {
panic(panicMessageSpecSpec)
}
if oth.isSuite { // if other suite is a spec as well, then it is enough to append the modifications and options only
if oth.isSuite() { // if other suite is a spec as well, then it is enough to append the modifications and options only
oth.opts = append(oth.opts, spec.opts...)
oth.mods = append(oth.mods, spec.mods...)
return
}
oth.testingTB.Helper()
isOthASuite := oth.isSuite
for _, opt := range spec.opts {
opt.setup(oth)
}
oth.isSuite = isOthASuite
for _, mod := range spec.mods {
mod(oth)
}
}

func (spec *Spec) getIsSuite() bool {
func (spec *Spec) isSuite() bool {
for _, s := range spec.specsFromCurrent() {
if s.isSuite {
return true
}
if s.testingTB == nil {
return true
}
Expand All @@ -790,15 +781,6 @@ func (spec *Spec) hasTestRan() bool {
return false
}

func checkSuite(tb testing.TB, opts []SpecOption) (testing.TB, []SpecOption) {
if tb == nil {
return internal.NullTB{}, append(opts, specOptionFunc(func(s *Spec) {
s.isSuite = true
}))
}
return tb, opts
}

func (spec *Spec) AsSuite(name ...string) SpecSuite {
return SpecSuite{N: strings.Join(name, " "), S: spec}
}
Expand Down
19 changes: 18 additions & 1 deletion Spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1692,8 +1692,25 @@ func BenchmarkTestSpec_Benchmark(b *testing.B) {
func TestSpecSuite(t *testing.T) {
var ran int
spec := testcase.NewSpec(nil)

b1 := testcase.Let(spec, func(t *testcase.T) bool {
return t.Random.Bool()
})

b2 := testcase.LetValue(spec, true)

tpl1, tpl2 := testcase.Let2(spec, func(t *testcase.T) (int, string) {
return t.Random.Int(), t.Random.String()
})

spec.Describe("#Foo", func(spec *testcase.Spec) {
spec.Test("x", func(t *testcase.T) { ran++ })
spec.Test("x", func(t *testcase.T) {
ran++
_ = b1.Get(t)
_ = b2.Get(t)
_ = tpl1.Get(t)
_ = tpl2.Get(t)
})
})
suite := spec.AsSuite("the-suite")

Expand Down
2 changes: 1 addition & 1 deletion Suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func getSuiteName(c interface{}) (name string) {
case interface{ Name() string }:
return c.Name()
case *Spec:
return c.suiteName
return c.description
default:
return internal.SymbolicName(c)
}
Expand Down
Loading

0 comments on commit a1c2c30

Please sign in to comment.