Skip to content

Commit

Permalink
add fixenv.RunTests
Browse files Browse the repository at this point in the history
  • Loading branch information
rekby committed Nov 26, 2023
1 parent def74bd commit e7bf22c
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 1 deletion.
5 changes: 4 additions & 1 deletion env.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,10 @@ func (e *EnvT) fixtureCallWrapper(key cacheKey, f FixtureCallbackFunc, opt *Fixt
e.m.Unlock()

if si == nil {
e.t.Fatalf("Unexpected scope. Create env for test %q", scopeName)
if opt.Scope == ScopePackage {
e.t.Fatalf("Initialize package scope before use ", scopeName)
}
e.t.Fatalf("Unexpected scope: %q", scopeName)
// not reachable
return nil, nil
}
Expand Down
41 changes: 41 additions & 0 deletions examples/simple_main_test/example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//go:build go1.18
// +build go1.18

package simple_main_test

import (
"github.com/rekby/fixenv"
"math/rand"
"testing"
)

var global int = -1

func FSingleRandom(e fixenv.Env) int {
var f fixenv.GenericFixtureFunction[int] = func() (*fixenv.GenericResult[int], error) {
return fixenv.NewGenericResult(rand.Int()), nil
}
return fixenv.CacheResult(e, f, fixenv.CacheOptions{Scope: fixenv.ScopePackage})
}

func TestFirst(t *testing.T) {
e := fixenv.New(t)
if global == -1 {
global = FSingleRandom(e)
}

if singleRnd := FSingleRandom(e); singleRnd != global {
t.Fatalf("%v != %v", singleRnd, global)
}
}

func TestSecond(t *testing.T) {
e := fixenv.New(t)
if global == -1 {
global = FSingleRandom(e)
}

if singleRnd := FSingleRandom(e); singleRnd != global {
t.Fatalf("%v != %v", singleRnd, global)
}
}
11 changes: 11 additions & 0 deletions examples/simple_main_test/testmain_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package simple_main

import (
"github.com/rekby/fixenv"
"os"
"testing"
)

func TestMain(m *testing.M) {
os.Exit(fixenv.RunTests(m))
}
38 changes: 38 additions & 0 deletions maintest.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package fixenv

import (
"errors"
"fmt"
"log"
"sync"
)

var errPackageEnvInitializedSecondTime = errors.New("package env initialize second time. It must be call not more then once. ")
var errTooManyOptionalArgs = errors.New("allow not more then one optional arg")

// FatalfFunction function signature of Fatalf
type FatalfFunction func(format string, args ...interface{})

Expand Down Expand Up @@ -34,18 +38,52 @@ type CreateMainTestEnvOpts struct {
SkipNow SkipNowFunction
}

// packageLevelVirtualTest now used for tests only
var lastPackageLevelVirtualTest *virtualTest

// CreateMainTestEnv called from TestMain for create global environment.
// It need only for use ScopePackage cache scope.
// If ScopePackage not used - no need to create main env.
func CreateMainTestEnv(opts *CreateMainTestEnvOpts) (env *EnvT, tearDown func()) {
// TODO: handle second time initialize
globalMutex.Lock()
packageLevelVirtualTest := newVirtualTest(opts)
lastPackageLevelVirtualTest = packageLevelVirtualTest
globalMutex.Unlock()

env = New(packageLevelVirtualTest) // register global test for env
return env, packageLevelVirtualTest.cleanup
}

// RunTests runs the tests. It returns an exit code to pass to os.Exit.
//
// Usage:
// declare in _test file TestMain function:
//
// func TestMain(m *testing.M) {
// os.Exit(fixenv.RunTests(m))
// }
func RunTests(m RunTestsI, opts ...CreateMainTestEnvOpts) int {
var options *CreateMainTestEnvOpts
switch len(opts) {
case 0:
// pass
case 1:
options = &opts[0]
default:
panic(errTooManyOptionalArgs)
}

_, cancel := CreateMainTestEnv(options)
defer cancel()
return m.Run()
}

type RunTestsI interface {
// Run runs the tests. It returns an exit code to pass to os.Exit.
Run() (code int)
}

// virtualTest implement T interface for global env scope
type virtualTest struct {
m sync.Mutex
Expand Down
87 changes: 87 additions & 0 deletions maintest_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fixenv

import (
"errors"
"runtime"
"sync"
"testing"
Expand Down Expand Up @@ -76,3 +77,89 @@ func TestCreateMainTestEnv(t *testing.T) {
})
})
}

func TestRunTests(t *testing.T) {
expectedReturnCode := 123

checkInitialized := func(t *testing.T) {
t.Helper()

globalMutex.Lock()
defer globalMutex.Unlock()

if _, ok := globalScopeInfo[packageScopeName]; !ok {
t.Fatal()
}
}
cleanGlobalState := func() {
globalMutex.Lock()
defer globalMutex.Unlock()

delete(globalScopeInfo, packageScopeName)
}

t.Run("without options", func(t *testing.T) {
m := &mTestsMock{
returnCode: expectedReturnCode,
run: func() {
checkInitialized(t)
},
}

if res := RunTests(m); res != expectedReturnCode {
t.Fatalf("%v != %v", res, expectedReturnCode)
}
cleanGlobalState()
})
t.Run("with options", func(t *testing.T) {
m := &mTestsMock{
returnCode: expectedReturnCode,
run: func() {
checkInitialized(t)
lastPackageLevelVirtualTest.SkipNow()
},
}

called := false
RunTests(m, CreateMainTestEnvOpts{SkipNow: func() {
called = true
}})
if !called {
t.Fatal()
}
cleanGlobalState()
})
t.Run("with two options", func(t *testing.T) {
defer func() {
cleanGlobalState()

rec := recover()
if !errors.Is(rec.(error), errTooManyOptionalArgs) {
t.Fatal(rec)
}
}()
m := &mTestsMock{
run: func() {
checkInitialized(t)
},
}
RunTests(m, CreateMainTestEnvOpts{}, CreateMainTestEnvOpts{})
})
}

type mTestsMock struct {
runCalled bool
returnCode int
run func()
}

func (r *mTestsMock) Run() (code int) {
r.runCalled = true
if r.run != nil {
r.run()
}
return r.returnCode
}

// check interface implementation
var _ RunTestsI = &mTestsMock{}

0 comments on commit e7bf22c

Please sign in to comment.