diff --git a/DSL.go b/DSL.go index 6974421..e579605 100644 --- a/DSL.go +++ b/DSL.go @@ -42,6 +42,15 @@ func (spec *Spec) Then(desc string, test tBlock, opts ...SpecOption) { spec.Test(desc, test, opts...) } +// TODO allows you to leave notes for a given specification's context, +// which will be visible when the test specification is executed. +func (spec *Spec) TODO(task string) { + helper(spec.testingTB).Helper() + desc := fmt.Sprintf(`TODO: %s`, task) + skip := func(t *T) { t.Skip() } + spec.Test(desc, skip) +} + // NoSideEffect gives a hint to the reader of the current test that during the test execution, // no side effect outside from the test specification scope is expected to be observable. // It is important to note that this flag primary meant to represent the side effect possibility diff --git a/DSL_test.go b/DSL_test.go new file mode 100644 index 0000000..fbeef6a --- /dev/null +++ b/DSL_test.go @@ -0,0 +1,34 @@ +package testcase_test + +import ( + "testing" + + "go.llib.dev/testcase" + "go.llib.dev/testcase/assert" + "go.llib.dev/testcase/internal" + "go.llib.dev/testcase/internal/doubles" +) + +func TestSpec_TODO(t *testing.T) { + dtb := &doubles.TB{} + internal.StubVerbose(t, true) + + todos := []string{"abc", "bcd", "cde"} + s := testcase.NewSpec(dtb) + for _, todo := range todos { + s.TODO(todo) + } + s.Finish() + dtb.Finish() + + assert.False(t, dtb.IsFailed) + assert.False(t, dtb.IsSkipped) + + for _, todo := range todos { + assert.OneOf(t, dtb.Tests, func(t assert.It, got *doubles.TB) { + assert.Contain(t, got.Name(), "TODO: "+todo) + assert.False(t, got.IsFailed) + assert.True(t, got.IsSkipped) + }) + } +} diff --git a/clock/Clock_test.go b/clock/Clock_test.go index 07cc50f..d539155 100644 --- a/clock/Clock_test.go +++ b/clock/Clock_test.go @@ -438,10 +438,15 @@ func TestNewTicker(t *testing.T) { timecop.SetSpeed(t, 1000) // 100x times faster time.Sleep(time.Second/4 + time.Microsecond) runtime.Gosched() + + // TODO: flaky assertion + // + // FLAKY* expectedTickCount += 100 / 4 * 1000 * failureRateMultiplier t.Log("exp:", expectedTickCount, "got:", atomic.LoadInt64(&ticks)) assert.True(t, expectedTickCount <= atomic.LoadInt64(&ticks)) - }) // TODO: FLAKY test + // *FLAKY + }) t.Run("race", func(t *testing.T) { ticker := clock.NewTicker(time.Minute) diff --git a/internal/doubles/TB.go b/internal/doubles/TB.go index 21a80ac..912ecf4 100644 --- a/internal/doubles/TB.go +++ b/internal/doubles/TB.go @@ -35,7 +35,7 @@ type TB struct { td teardown.Teardown mutex sync.Mutex - RunTBs []*TB + Tests []*TB } func (m *TB) Finish() { @@ -143,10 +143,10 @@ func (m *TB) Setenv(key, value string) { func (m *TB) Run(name string, blk func(tb testing.TB)) bool { if name == "" { - name = fmt.Sprintf("%d", time.Now().UnixNano()) + name = fmt.Sprintf("%d", len(m.Tests)) } dtb := &TB{TB: m.TB, StubName: m.Name() + "/" + name} - m.RunTBs = append(m.RunTBs, dtb) + m.Tests = append(m.Tests, dtb) sandbox.Run(func() { blk(dtb) }) if dtb.IsFailed { m.Error(dtb.Logs.String()) @@ -155,10 +155,10 @@ func (m *TB) Run(name string, blk func(tb testing.TB)) bool { } func (m *TB) LastRunTB() (*TB, bool) { - if len(m.RunTBs) == 0 { + if len(m.Tests) == 0 { return nil, false } - return m.RunTBs[len(m.RunTBs)-1], true + return m.Tests[len(m.Tests)-1], true } func (m *TB) LastTB() *TB { diff --git a/internal/doubles/TB_test.go b/internal/doubles/TB_test.go index 5db2949..b6d5436 100644 --- a/internal/doubles/TB_test.go +++ b/internal/doubles/TB_test.go @@ -15,7 +15,7 @@ import ( "go.llib.dev/testcase/internal/doubles" ) -func TestStubTB(t *testing.T) { +func TestTB(t *testing.T) { s := testcase.NewSpec(t) var stub = testcase.Let(s, func(t *testcase.T) *doubles.TB { diff --git a/internal/verbose.go b/internal/verbose.go index 37cfe0e..111cbb1 100644 --- a/internal/verbose.go +++ b/internal/verbose.go @@ -10,7 +10,12 @@ func Verbose() bool { var verbose = testing.Verbose -func StubVerbose(tb testing.TB, fn func() bool) { +func StubVerbose[T bool | func() bool](tb testing.TB, v T) { tb.Cleanup(func() { verbose = testing.Verbose }) - verbose = fn + switch v := any(v).(type) { + case bool: + verbose = func() bool { return v } + case func() bool: + verbose = v + } }