| package combinectx | 
 |  | 
 | import ( | 
 | 	"context" | 
 | 	"errors" | 
 | 	"testing" | 
 | 	"time" | 
 | ) | 
 |  | 
 | func TestCancel(t *testing.T) { | 
 | 	a, aC := context.WithCancel(context.Background()) | 
 | 	b, bC := context.WithCancel(context.Background()) | 
 |  | 
 | 	c := Combine(a, b) | 
 | 	if want, got := error(nil), c.Err(); want != got { | 
 | 		t.Fatalf("Newly combined context should return %v, got %v", want, got) | 
 | 	} | 
 | 	if _, ok := c.Deadline(); ok { | 
 | 		t.Errorf("Newly combined context should have no deadline") | 
 | 	} | 
 |  | 
 | 	// Cancel A. | 
 | 	aC() | 
 | 	// Cancels are not synchronous - wait for it to propagate... | 
 | 	<-c.Done() | 
 | 	// ...then cancel B (no-op). | 
 | 	bC() | 
 |  | 
 | 	if c.Err() == nil { | 
 | 		t.Fatalf("After cancel, ctx.Err() should be non-nil") | 
 | 	} | 
 | 	if !errors.Is(c.Err(), a.Err()) { | 
 | 		t.Errorf("After cancel, ctx.Err() should be a.Err()") | 
 | 	} | 
 | 	if !errors.Is(c.Err(), c.Err()) { | 
 | 		t.Errorf("After cancel, ctx.Err() should be ctx.Err()") | 
 | 	} | 
 | 	if !errors.Is(c.Err(), context.Canceled) { | 
 | 		t.Errorf("After cancel, ctx.Err() should be context.Canceled") | 
 | 	} | 
 | 	if !errors.Is(c.Err(), &Error{}) { | 
 | 		t.Errorf("After cancel, ctx.Err() should be a Error pointer") | 
 | 	} | 
 | 	cerr := &Error{} | 
 | 	if !errors.As(c.Err(), &cerr) { | 
 | 		t.Fatalf("After cancel, ctx.Err() should be usable as *Error") | 
 | 	} | 
 | 	if !cerr.First() { | 
 | 		t.Errorf("ctx.Err().First() should be true") | 
 | 	} | 
 | 	if cerr.Second() { | 
 | 		t.Errorf("ctx.Err().Second() should be false") | 
 | 	} | 
 | 	if want, got := a.Err(), cerr.Unwrap(); want != got { | 
 | 		t.Errorf("ctx.Err().Unwrap() should be %v, got %v", want, got) | 
 | 	} | 
 | } | 
 |  | 
 | func TestDeadline(t *testing.T) { | 
 | 	now := time.Now() | 
 | 	aD := now.Add(100 * time.Millisecond) | 
 | 	bD := now.Add(10 * time.Millisecond) | 
 |  | 
 | 	a, aC := context.WithDeadline(context.Background(), aD) | 
 | 	b, bC := context.WithDeadline(context.Background(), bD) | 
 |  | 
 | 	defer aC() | 
 | 	defer bC() | 
 |  | 
 | 	c := Combine(a, b) | 
 | 	if want, got := error(nil), c.Err(); want != got { | 
 | 		t.Fatalf("Newly combined context should return %v, got %v", want, got) | 
 | 	} | 
 | 	if d, ok := c.Deadline(); !ok || !d.Equal(bD) { | 
 | 		t.Errorf("Newly combined context should have deadline %v, got %v", bD, d) | 
 | 	} | 
 |  | 
 | 	<-c.Done() | 
 |  | 
 | 	if c.Err() == nil { | 
 | 		t.Fatalf("After deadline, ctx.Err() should be non-nil") | 
 | 	} | 
 | 	if !errors.Is(c.Err(), b.Err()) { | 
 | 		t.Errorf("After deadline, ctx.Err() should be b.Err()") | 
 | 	} | 
 | 	if !errors.Is(c.Err(), context.DeadlineExceeded) { | 
 | 		t.Errorf("After cancel, ctx.Err() should be context.DeadlineExceeded") | 
 | 	} | 
 | 	if !errors.Is(c.Err(), &Error{}) { | 
 | 		t.Errorf("After cancel, ctx.Err() should be a Error pointer") | 
 | 	} | 
 | 	cerr := &Error{} | 
 | 	if !errors.As(c.Err(), &cerr) { | 
 | 		t.Fatalf("After cancel, ctx.Err() should be usable as *Error") | 
 | 	} | 
 | 	if cerr.First() { | 
 | 		t.Errorf("ctx.Err().First() should be false") | 
 | 	} | 
 | 	if !cerr.Second() { | 
 | 		t.Errorf("ctx.Err().Second() should be true") | 
 | 	} | 
 | 	if want, got := b.Err(), cerr.Unwrap(); want != got { | 
 | 		t.Errorf("ctx.Err().Unwrap() should be %v, got %v", want, got) | 
 | 	} | 
 | } |