118 lines
3.1 KiB
Go
118 lines
3.1 KiB
Go
package pixel_test
|
|
|
|
import (
|
|
"math"
|
|
"slices"
|
|
"testing"
|
|
|
|
"github.com/egoist/mygo/ui"
|
|
|
|
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/pixel"
|
|
)
|
|
|
|
func luminance(c ui.Color) float64 {
|
|
lin := func(v uint8) float64 {
|
|
s := float64(v) / 255
|
|
if s <= 0.04045 {
|
|
return s / 12.92
|
|
}
|
|
return math.Pow((s+0.055)/1.055, 2.4)
|
|
}
|
|
return 0.2126*lin(c.R) + 0.7152*lin(c.G) + 0.0722*lin(c.B)
|
|
}
|
|
|
|
func contrast(a, b ui.Color) float64 {
|
|
la, lb := luminance(a), luminance(b)
|
|
return (max(la, lb) + 0.05) / (min(la, lb) + 0.05)
|
|
}
|
|
|
|
func TestPaletteContrast(t *testing.T) {
|
|
rules := []struct {
|
|
fg, bg pixel.Slot
|
|
min float64
|
|
}{
|
|
{pixel.Ink, pixel.Face, 4.5},
|
|
{pixel.Ink, pixel.Back, 4.5},
|
|
{pixel.Ink, pixel.Well, 4.5},
|
|
{pixel.AccentInk, pixel.Accent, 4.5},
|
|
{pixel.Faint, pixel.Face, 3},
|
|
{pixel.Edge, pixel.Back, 3},
|
|
}
|
|
for _, p := range pixel.Palettes {
|
|
for _, r := range rules {
|
|
if got := contrast(p.C(r.fg), p.C(r.bg)); got < r.min {
|
|
t.Errorf("%s: slot %d on %d contrast %.2f, want ≥ %.1f", p.Name, r.fg, r.bg, got, r.min)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPaletteColorsDistinctAndOpaque(t *testing.T) {
|
|
if len(pixel.Palettes) != 8 {
|
|
t.Fatalf("got %d palettes, want 8", len(pixel.Palettes))
|
|
}
|
|
for _, p := range pixel.Palettes {
|
|
seen := map[ui.Color]pixel.Slot{}
|
|
for s, c := range p.Colors {
|
|
if c.A != 255 {
|
|
t.Errorf("%s slot %d alpha %d", p.Name, s, c.A)
|
|
}
|
|
if prev, ok := seen[c]; ok {
|
|
t.Errorf("%s slots %d and %d share %v", p.Name, prev, s, c)
|
|
}
|
|
seen[c] = pixel.Slot(s)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPaletteBevelOrder(t *testing.T) {
|
|
for _, p := range pixel.Palettes {
|
|
face := luminance(p.C(pixel.Face))
|
|
if luminance(p.C(pixel.Lit)) <= face || luminance(p.C(pixel.Shade)) >= face {
|
|
t.Errorf("%s: Lit must be lighter and Shade darker than Face", p.Name)
|
|
}
|
|
if p.Night != (luminance(p.C(pixel.Back)) < luminance(p.C(pixel.Ink))) {
|
|
t.Errorf("%s: night palettes are dark, day palettes light", p.Name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFind(t *testing.T) {
|
|
seen := map[*pixel.Palette]bool{}
|
|
for s := pixel.Spring; s <= pixel.Winter; s++ {
|
|
for _, night := range []bool{false, true} {
|
|
p := pixel.Find(s, night)
|
|
if p.Season != s || p.Night != night {
|
|
t.Errorf("Find(%d, %v) = %s", s, night, p.Name)
|
|
}
|
|
seen[p] = true
|
|
}
|
|
}
|
|
if len(seen) != 8 {
|
|
t.Fatalf("Find reached %d palettes, want 8", len(seen))
|
|
}
|
|
}
|
|
|
|
func TestCycle(t *testing.T) {
|
|
band := []pixel.Slot{pixel.Info, pixel.Accent, pixel.Lit}
|
|
cases := []struct {
|
|
step int
|
|
want []pixel.Slot
|
|
}{
|
|
{0, []pixel.Slot{pixel.Info, pixel.Accent, pixel.Lit}},
|
|
{1, []pixel.Slot{pixel.Accent, pixel.Lit, pixel.Info}},
|
|
{-1, []pixel.Slot{pixel.Lit, pixel.Info, pixel.Accent}},
|
|
{7, []pixel.Slot{pixel.Accent, pixel.Lit, pixel.Info}},
|
|
{math.MaxInt, []pixel.Slot{pixel.Accent, pixel.Lit, pixel.Info}},
|
|
{math.MinInt, []pixel.Slot{pixel.Accent, pixel.Lit, pixel.Info}},
|
|
}
|
|
for _, c := range cases {
|
|
if got := pixel.Cycle(band, c.step); !slices.Equal(got, c.want) {
|
|
t.Errorf("Cycle(step %d) = %v, want %v", c.step, got, c.want)
|
|
}
|
|
}
|
|
if !slices.Equal(band, []pixel.Slot{pixel.Info, pixel.Accent, pixel.Lit}) {
|
|
t.Fatalf("Cycle changed its input: %v", band)
|
|
}
|
|
}
|