Skip to content

Commit 8d47c99

Browse files
authored
Merge pull request #36 add fixenv.RunTests
2 parents def74bd + e85e2be commit 8d47c99

5 files changed

Lines changed: 178 additions & 1 deletion

File tree

env.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,8 @@ func (e *EnvT) fixtureCallWrapper(key cacheKey, f FixtureCallbackFunc, opt *Fixt
299299
e.m.Unlock()
300300

301301
if si == nil {
302-
e.t.Fatalf("Unexpected scope. Create env for test %q", scopeName)
302+
e.t.Fatalf("Unexpected scope: %q. Initialize package scope before use."+
303+
"For scope %s use fixenv.RunTests", scopeName, packageScopeName)
303304
// not reachable
304305
return nil, nil
305306
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//go:build go1.18
2+
// +build go1.18
3+
4+
package simple_main_test
5+
6+
import (
7+
"github.com/rekby/fixenv"
8+
"math/rand"
9+
"testing"
10+
)
11+
12+
var global int = -1
13+
14+
func FSingleRandom(e fixenv.Env) int {
15+
var f fixenv.GenericFixtureFunction[int] = func() (*fixenv.GenericResult[int], error) {
16+
return fixenv.NewGenericResult(rand.Int()), nil
17+
}
18+
return fixenv.CacheResult(e, f, fixenv.CacheOptions{Scope: fixenv.ScopePackage})
19+
}
20+
21+
func TestFirst(t *testing.T) {
22+
e := fixenv.New(t)
23+
if global == -1 {
24+
global = FSingleRandom(e)
25+
}
26+
27+
if singleRnd := FSingleRandom(e); singleRnd != global {
28+
t.Fatalf("%v != %v", singleRnd, global)
29+
}
30+
}
31+
32+
func TestSecond(t *testing.T) {
33+
e := fixenv.New(t)
34+
if global == -1 {
35+
global = FSingleRandom(e)
36+
}
37+
38+
if singleRnd := FSingleRandom(e); singleRnd != global {
39+
t.Fatalf("%v != %v", singleRnd, global)
40+
}
41+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package simple_main
2+
3+
import (
4+
"github.com/rekby/fixenv"
5+
"os"
6+
"testing"
7+
)
8+
9+
func TestMain(m *testing.M) {
10+
os.Exit(fixenv.RunTests(m))
11+
}

maintest.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package fixenv
22

33
import (
4+
"errors"
45
"fmt"
56
"log"
67
"sync"
78
)
89

10+
var errTooManyOptionalArgs = errors.New("allow not more then one optional arg")
11+
912
// FatalfFunction function signature of Fatalf
1013
type FatalfFunction func(format string, args ...interface{})
1114

@@ -34,18 +37,52 @@ type CreateMainTestEnvOpts struct {
3437
SkipNow SkipNowFunction
3538
}
3639

40+
// packageLevelVirtualTest now used for tests only
41+
var lastPackageLevelVirtualTest *virtualTest
42+
3743
// CreateMainTestEnv called from TestMain for create global environment.
3844
// It need only for use ScopePackage cache scope.
3945
// If ScopePackage not used - no need to create main env.
4046
func CreateMainTestEnv(opts *CreateMainTestEnvOpts) (env *EnvT, tearDown func()) {
47+
// TODO: handle second time initialize
4148
globalMutex.Lock()
4249
packageLevelVirtualTest := newVirtualTest(opts)
50+
lastPackageLevelVirtualTest = packageLevelVirtualTest
4351
globalMutex.Unlock()
4452

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

57+
// RunTests runs the tests. It returns an exit code to pass to os.Exit.
58+
//
59+
// Usage:
60+
// declare in _test file TestMain function:
61+
//
62+
// func TestMain(m *testing.M) {
63+
// os.Exit(fixenv.RunTests(m))
64+
// }
65+
func RunTests(m RunTestsI, opts ...CreateMainTestEnvOpts) int {
66+
var options *CreateMainTestEnvOpts
67+
switch len(opts) {
68+
case 0:
69+
// pass
70+
case 1:
71+
options = &opts[0]
72+
default:
73+
panic(errTooManyOptionalArgs)
74+
}
75+
76+
_, cancel := CreateMainTestEnv(options)
77+
defer cancel()
78+
return m.Run()
79+
}
80+
81+
type RunTestsI interface {
82+
// Run runs the tests. It returns an exit code to pass to os.Exit.
83+
Run() (code int)
84+
}
85+
4986
// virtualTest implement T interface for global env scope
5087
type virtualTest struct {
5188
m sync.Mutex

maintest_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package fixenv
22

33
import (
4+
"errors"
45
"runtime"
56
"sync"
67
"testing"
@@ -76,3 +77,89 @@ func TestCreateMainTestEnv(t *testing.T) {
7677
})
7778
})
7879
}
80+
81+
func TestRunTests(t *testing.T) {
82+
expectedReturnCode := 123
83+
84+
checkInitialized := func(t *testing.T) {
85+
t.Helper()
86+
87+
globalMutex.Lock()
88+
defer globalMutex.Unlock()
89+
90+
if _, ok := globalScopeInfo[packageScopeName]; !ok {
91+
t.Fatal()
92+
}
93+
}
94+
cleanGlobalState := func() {
95+
globalMutex.Lock()
96+
defer globalMutex.Unlock()
97+
98+
delete(globalScopeInfo, packageScopeName)
99+
}
100+
101+
t.Run("without options", func(t *testing.T) {
102+
m := &mTestsMock{
103+
returnCode: expectedReturnCode,
104+
run: func() {
105+
checkInitialized(t)
106+
},
107+
}
108+
109+
if res := RunTests(m); res != expectedReturnCode {
110+
t.Fatalf("%v != %v", res, expectedReturnCode)
111+
}
112+
cleanGlobalState()
113+
})
114+
t.Run("with options", func(t *testing.T) {
115+
m := &mTestsMock{
116+
returnCode: expectedReturnCode,
117+
run: func() {
118+
checkInitialized(t)
119+
lastPackageLevelVirtualTest.SkipNow()
120+
},
121+
}
122+
123+
called := false
124+
RunTests(m, CreateMainTestEnvOpts{SkipNow: func() {
125+
called = true
126+
}})
127+
if !called {
128+
t.Fatal()
129+
}
130+
cleanGlobalState()
131+
})
132+
t.Run("with two options", func(t *testing.T) {
133+
defer func() {
134+
cleanGlobalState()
135+
136+
rec := recover()
137+
if !errors.Is(rec.(error), errTooManyOptionalArgs) {
138+
t.Fatal(rec)
139+
}
140+
}()
141+
m := &mTestsMock{
142+
run: func() {
143+
checkInitialized(t)
144+
},
145+
}
146+
RunTests(m, CreateMainTestEnvOpts{}, CreateMainTestEnvOpts{})
147+
})
148+
}
149+
150+
type mTestsMock struct {
151+
runCalled bool
152+
returnCode int
153+
run func()
154+
}
155+
156+
func (r *mTestsMock) Run() (code int) {
157+
r.runCalled = true
158+
if r.run != nil {
159+
r.run()
160+
}
161+
return r.returnCode
162+
}
163+
164+
// check interface implementation
165+
var _ RunTestsI = &mTestsMock{}

0 commit comments

Comments
 (0)