Advertisement
mfgnik

Untitled

Mar 29th, 2020
768
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 1.78 KB | None | 0 0
  1. // +build !solution
  2.  
  3. package tparallel
  4.  
  5. import "sync"
  6.  
  7. type testContext struct {
  8.     mu sync.Mutex
  9.     startParallel chan struct{}
  10.     running int
  11.     numWaiting int
  12.     maxParallel int
  13. }
  14.  
  15. func newTestContext(maxParallel int) *testContext {
  16.     return &testContext{
  17.         startParallel: make(chan struct{}),
  18.         maxParallel:   maxParallel,
  19.         running:       1,
  20.     }
  21. }
  22.  
  23. func (c *testContext) waitParallel() {
  24.     c.mu.Lock()
  25.     if c.running < c.maxParallel {
  26.         c.running++
  27.         c.mu.Unlock()
  28.         return
  29.     }
  30.     c.numWaiting++
  31.     c.mu.Unlock()
  32.     <-c.startParallel
  33. }
  34.  
  35. func (c *testContext) release() {
  36.     c.mu.Lock()
  37.     if c.numWaiting == 0 {
  38.         c.running--
  39.         c.mu.Unlock()
  40.         return
  41.     }
  42.     c.numWaiting--
  43.     c.mu.Unlock()
  44.     c.startParallel <- struct {}{}
  45. }
  46.  
  47. type T struct {
  48.     parallel bool
  49.     signal   chan struct{}
  50.     barrier  chan struct{}
  51.     parent   *T
  52.     sub      []*T
  53.     ctx      *testContext
  54. }
  55.  
  56. func newT(parent *T) *T {
  57.     return &T{signal: make(chan struct{}),
  58.         barrier: make(chan struct{}),
  59.         sub:     make([]*T, 0),
  60.         ctx:     newTestContext(16),
  61.         parent:  parent,
  62.     }
  63. }
  64.  
  65. func (t *T) Parallel() {
  66.     t.parallel = true
  67.     t.parent.sub = append(t.parent.sub, t)
  68.     t.signal <- struct{}{}
  69.     <-t.parent.barrier
  70.     t.ctx.waitParallel()
  71. }
  72.  
  73. func tRunner(t *T, fn func(t *T)) {
  74.     defer func() {
  75.         if len(t.sub) > 0 {
  76.             t.ctx.release()
  77.             close(t.barrier)
  78.             for _, sub := range t.sub {
  79.                 <-sub.signal
  80.             }
  81.             if !t.parallel {
  82.                 t.ctx.waitParallel()
  83.             }
  84.         } else if t.parallel {
  85.             t.ctx.release()
  86.         }
  87.         t.signal <- struct{}{}
  88.     }()
  89.     fn(t)
  90. }
  91.  
  92. func (t *T) Run(subtest func(t *T)) {
  93.     go tRunner(t, subtest)
  94.     <-t.signal
  95. }
  96.  
  97. func Run(topTests []func(t *T)) {
  98.     t := newT(nil)
  99.     tRunner(t, func(t *T) {
  100.         for _, test := range topTests {
  101.             newT(t).Run(test)
  102.         }
  103.         go func() { <-t.signal }()
  104.     })
  105. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement