diff options
Diffstat (limited to 'xdelta3/go/src/xdelta/tgroup.go')
-rw-r--r-- | xdelta3/go/src/xdelta/tgroup.go | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/xdelta3/go/src/xdelta/tgroup.go b/xdelta3/go/src/xdelta/tgroup.go new file mode 100644 index 0000000..602b1e1 --- /dev/null +++ b/xdelta3/go/src/xdelta/tgroup.go | |||
@@ -0,0 +1,97 @@ | |||
1 | package xdelta | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "runtime" | ||
6 | "sync" | ||
7 | ) | ||
8 | |||
9 | type TestGroup struct { | ||
10 | *Runner | ||
11 | main *Goroutine | ||
12 | sync.Mutex | ||
13 | sync.WaitGroup | ||
14 | running []*Goroutine | ||
15 | errors []error | ||
16 | nonerrors []error // For tolerated / expected conditions | ||
17 | } | ||
18 | |||
19 | type Goroutine struct { | ||
20 | *TestGroup | ||
21 | name string | ||
22 | done bool | ||
23 | } | ||
24 | |||
25 | func (g *Goroutine) String() string { | ||
26 | return fmt.Sprint("[", g.name, "]") | ||
27 | } | ||
28 | |||
29 | func (g *Goroutine) finish(err error) { | ||
30 | wait := false | ||
31 | tg := g.TestGroup | ||
32 | sbuf := make([]byte, 4096) | ||
33 | sbuf = sbuf[0:runtime.Stack(sbuf, false)] | ||
34 | if err != nil { | ||
35 | err = fmt.Errorf("%v:%v:%v", g.name, err, string(sbuf)) | ||
36 | } | ||
37 | tg.Lock() | ||
38 | if g.done { | ||
39 | if err != nil { | ||
40 | tg.nonerrors = append(tg.nonerrors, err) | ||
41 | } | ||
42 | } else { | ||
43 | wait = true | ||
44 | g.done = true | ||
45 | if err != nil { | ||
46 | tg.errors = append(tg.errors, err) | ||
47 | } | ||
48 | } | ||
49 | tg.Unlock() | ||
50 | if wait { | ||
51 | tg.WaitGroup.Done() | ||
52 | } | ||
53 | } | ||
54 | |||
55 | func (g *Goroutine) OK() { | ||
56 | g.finish(nil) | ||
57 | } | ||
58 | |||
59 | func (g *Goroutine) Panic(err error) { | ||
60 | g.finish(err) | ||
61 | if g != g.TestGroup.main { | ||
62 | runtime.Goexit() | ||
63 | } | ||
64 | } | ||
65 | |||
66 | func (t *TestGroup) Main() *Goroutine { return t.main } | ||
67 | |||
68 | func (t *TestGroup) Panic(err error) { t.Main().Panic(err) } | ||
69 | |||
70 | func (t *TestGroup) Go(name string, f func(*Goroutine)) *Goroutine { | ||
71 | g := &Goroutine{t, name, false} | ||
72 | t.Lock() | ||
73 | t.WaitGroup.Add(1) | ||
74 | t.running = append(t.running, g) | ||
75 | t.Unlock() | ||
76 | go f(g) | ||
77 | return g | ||
78 | } | ||
79 | |||
80 | func (t *TestGroup) Wait(procs... *Run) { | ||
81 | t.Main().OK() | ||
82 | t.WaitGroup.Wait() | ||
83 | for _, p := range procs { | ||
84 | if err := p.Wait(); err != nil { | ||
85 | t.errors = append(t.errors, err) | ||
86 | } | ||
87 | } | ||
88 | for _, err := range t.errors { | ||
89 | fmt.Println(":ERROR:", err) | ||
90 | } | ||
91 | for _, err := range t.nonerrors { | ||
92 | fmt.Println("(ERROR)", err) | ||
93 | } | ||
94 | if len(t.errors) != 0 { | ||
95 | t.Fail("Test failed with", len(t.errors), "errors") | ||
96 | } | ||
97 | } | ||