| // Copyright 2021 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package main | |
| import ( | |
| "./a" | |
| "context" | |
| "fmt" | |
| "runtime" | |
| "sort" | |
| "sync" | |
| "time" | |
| ) | |
| func TestReadAll() { | |
| c := make(chan int) | |
| go func() { | |
| c <- 4 | |
| c <- 2 | |
| c <- 5 | |
| close(c) | |
| }() | |
| got := a.ReadAll(context.Background(), c) | |
| want := []int{4, 2, 5} | |
| if !a.SliceEqual(got, want) { | |
| panic(fmt.Sprintf("ReadAll returned %v, want %v", got, want)) | |
| } | |
| } | |
| func TestMerge() { | |
| c1 := make(chan int) | |
| c2 := make(chan int) | |
| go func() { | |
| c1 <- 1 | |
| c1 <- 3 | |
| c1 <- 5 | |
| close(c1) | |
| }() | |
| go func() { | |
| c2 <- 2 | |
| c2 <- 4 | |
| c2 <- 6 | |
| close(c2) | |
| }() | |
| ctx := context.Background() | |
| got := a.ReadAll(ctx, a.Merge(ctx, c1, c2)) | |
| sort.Ints(got) | |
| want := []int{1, 2, 3, 4, 5, 6} | |
| if !a.SliceEqual(got, want) { | |
| panic(fmt.Sprintf("Merge returned %v, want %v", got, want)) | |
| } | |
| } | |
| func TestFilter() { | |
| c := make(chan int) | |
| go func() { | |
| c <- 1 | |
| c <- 2 | |
| c <- 3 | |
| close(c) | |
| }() | |
| even := func(i int) bool { return i%2 == 0 } | |
| ctx := context.Background() | |
| got := a.ReadAll(ctx, a.Filter(ctx, c, even)) | |
| want := []int{2} | |
| if !a.SliceEqual(got, want) { | |
| panic(fmt.Sprintf("Filter returned %v, want %v", got, want)) | |
| } | |
| } | |
| func TestSink() { | |
| c := a.Sink[int](context.Background()) | |
| after := time.NewTimer(time.Minute) | |
| defer after.Stop() | |
| send := func(v int) { | |
| select { | |
| case c <- v: | |
| case <-after.C: | |
| panic("timed out sending to Sink") | |
| } | |
| } | |
| send(1) | |
| send(2) | |
| send(3) | |
| close(c) | |
| } | |
| func TestExclusive() { | |
| val := 0 | |
| ex := a.MakeExclusive(&val) | |
| var wg sync.WaitGroup | |
| f := func() { | |
| defer wg.Done() | |
| for i := 0; i < 10; i++ { | |
| p := ex.Acquire() | |
| (*p)++ | |
| ex.Release(p) | |
| } | |
| } | |
| wg.Add(2) | |
| go f() | |
| go f() | |
| wg.Wait() | |
| if val != 20 { | |
| panic(fmt.Sprintf("after Acquire/Release loop got %d, want 20", val)) | |
| } | |
| } | |
| func TestExclusiveTry() { | |
| s := "" | |
| ex := a.MakeExclusive(&s) | |
| p, ok := ex.TryAcquire() | |
| if !ok { | |
| panic("TryAcquire failed") | |
| } | |
| *p = "a" | |
| var wg sync.WaitGroup | |
| wg.Add(1) | |
| go func() { | |
| defer wg.Done() | |
| _, ok := ex.TryAcquire() | |
| if ok { | |
| panic(fmt.Sprintf("TryAcquire succeeded unexpectedly")) | |
| } | |
| }() | |
| wg.Wait() | |
| ex.Release(p) | |
| p, ok = ex.TryAcquire() | |
| if !ok { | |
| panic(fmt.Sprintf("TryAcquire failed")) | |
| } | |
| } | |
| func TestRanger() { | |
| s, r := a.Ranger[int]() | |
| ctx := context.Background() | |
| go func() { | |
| // Receive one value then exit. | |
| v, ok := r.Next(ctx) | |
| if !ok { | |
| panic(fmt.Sprintf("did not receive any values")) | |
| } else if v != 1 { | |
| panic(fmt.Sprintf("received %d, want 1", v)) | |
| } | |
| }() | |
| c1 := make(chan bool) | |
| c2 := make(chan bool) | |
| go func() { | |
| defer close(c2) | |
| if !s.Send(ctx, 1) { | |
| panic(fmt.Sprintf("Send failed unexpectedly")) | |
| } | |
| close(c1) | |
| if s.Send(ctx, 2) { | |
| panic(fmt.Sprintf("Send succeeded unexpectedly")) | |
| } | |
| }() | |
| <-c1 | |
| // Force a garbage collection to try to get the finalizers to run. | |
| runtime.GC() | |
| select { | |
| case <-c2: | |
| case <-time.After(time.Minute): | |
| panic("Ranger Send should have failed, but timed out") | |
| } | |
| } | |
| func main() { | |
| TestReadAll() | |
| TestMerge() | |
| TestFilter() | |
| TestSink() | |
| TestExclusive() | |
| TestExclusiveTry() | |
| TestRanger() | |
| } |