package helper import ( "cmp" "fmt" "image/color" "iter" "slices" "testing" ) func cmpRGBA64(a, b color.RGBA64) int { return cmp.Or( cmp.Compare(a.R, b.R), cmp.Compare(a.G, b.G), cmp.Compare(a.B, b.B), cmp.Compare(a.A, b.A), ) } func eqRGBA64(a, b color.RGBA64) bool { return cmpRGBA64(a, b) == 0 } func TestEnum(t *testing.T) { tests := []struct { alpha, slow bool expectedCount int }{ {true, true, 87481}, {false, true, 140608}, {true, false, 649}, {false, false, 216}, } for _, tt := range tests { t.Run(fmt.Sprintf("alpha=%v, slow=%v", tt.alpha, tt.slow), func(t *testing.T) { t.Run("sequence meets expected criteria", func(t *testing.T) { list := slices.Collect(Enum(tt.alpha, tt.slow)) gotCount := len(list) if gotCount != tt.expectedCount { t.Errorf("Enum(%v, %v) returned %d items, wanted %d", tt.alpha, tt.slow, gotCount, tt.expectedCount) } slices.SortFunc(list, cmpRGBA64) list = slices.CompactFunc(list, eqRGBA64) if len(list) != gotCount { t.Errorf("Enum(%v, %v) returned %d duplicate items", tt.alpha, tt.slow, gotCount-len(list)) } listHasAlpha := false for _, c := range list { if c.A != 0xffff { if !tt.alpha { t.Errorf("Enum(%v, %v) returned non-opaque color: %v", tt.alpha, tt.slow, c) } listHasAlpha = true break } } if !listHasAlpha && tt.alpha { t.Errorf("Enum(%v, %v) didn't return non-opaque colors", tt.alpha, tt.slow) } }) t.Run("cancel", func(t *testing.T) { // make sure cancelling the iteration doesn't panic. // But mostly, we want that sweet, sweet test coverage. next, stop := iter.Pull(Enum(tt.alpha, tt.slow)) // need to invoke next to actually have the generated be started. if _, ok := next(); !ok { t.Error("iteration stopped before we could cancel it") } stop() }) }) } } func TestEnumColor(t *testing.T) { tests := []struct { alpha, slow bool }{ {true, true}, {false, true}, {true, false}, {false, false}, } for _, tt := range tests { t.Run(fmt.Sprintf("alpha=%v, slow=%v", tt.alpha, tt.slow), func(t *testing.T) { t.Run("sequence equivalence", func(t *testing.T) { nextRGBA64, stop1 := iter.Pull(Enum(tt.alpha, tt.slow)) defer stop1() nextNRGBA, stop2 := iter.Pull(EnumColor[color.NRGBA](tt.alpha, tt.slow, color.NRGBAModel)) defer stop2() for i := 0; ; i++ { rgba64, gotRgba64 := nextRGBA64() nrgba, gotNrgba := nextNRGBA() if gotRgba64 != gotNrgba { t.Errorf("one sequence terminated at i=%d: gotRgba64=%v, gotNrgba=%v", i, gotRgba64, gotNrgba) return } if !gotRgba64 { break } if wantNrgba := color.NRGBAModel.Convert(rgba64).(color.NRGBA); nrgba != wantNrgba { t.Errorf("i=%d: got %#+v, expected %#+v", i, nrgba, wantNrgba) } } }) t.Run("cancel", func(t *testing.T) { // make sure cancelling the iteration doesn't panic. // But mostly, we want that sweet, sweet test coverage. next, stop := iter.Pull(EnumColor[color.NRGBA](tt.alpha, tt.slow, color.NRGBAModel)) // need to invoke next to actually have the generated be started. if _, ok := next(); !ok { t.Error("iteration stopped before we could cancel it") } stop() }) }) } }