mirror of
https://github.com/taigrr/colorhash.git
synced 2026-04-02 03:08:48 -07:00
test: improve coverage to 98.2%, add staticcheck to CI
- Fix comment typos (Intensty → Intensity) - Add tests for createStringerPalette modes (background fill, smart mode) - Add tests for ColorString variants, BytesToColor determinism - Add tests for GetBackgroundColor mid-tone edge case - Add tests for GenerateOKLCHPalette negative/large inputs - Add Go 1.25 to CI matrix for compatibility testing - Add staticcheck lint step to CI - Fix goimports formatting in hash_test.go
This commit is contained in:
7
.github/workflows/ci.yml
vendored
7
.github/workflows/ci.yml
vendored
@@ -14,13 +14,18 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go-version: ['1.26']
|
go-version: ['1.25', '1.26']
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v5
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go-version }}
|
go-version: ${{ matrix.go-version }}
|
||||||
- run: go vet ./...
|
- run: go vet ./...
|
||||||
|
- name: staticcheck
|
||||||
|
if: matrix.go-version == '1.26'
|
||||||
|
run: |
|
||||||
|
go install honnef.co/go/tools/cmd/staticcheck@latest
|
||||||
|
staticcheck ./...
|
||||||
- run: go test -race -coverprofile=coverage.txt ./...
|
- run: go test -race -coverprofile=coverage.txt ./...
|
||||||
- name: Upload coverage
|
- name: Upload coverage
|
||||||
if: matrix.go-version == '1.26'
|
if: matrix.go-version == '1.26'
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ var (
|
|||||||
OnCyan = ColorString("\033[46m%s\033[0m")
|
OnCyan = ColorString("\033[46m%s\033[0m")
|
||||||
OnWhite = ColorString("\033[47m%s\033[0m")
|
OnWhite = ColorString("\033[47m%s\033[0m")
|
||||||
|
|
||||||
// High Intensty
|
// High Intensity
|
||||||
IBlack = ColorString("\033[0;90m%s\033[0m")
|
IBlack = ColorString("\033[0;90m%s\033[0m")
|
||||||
IRed = ColorString("\033[0;91m%s\033[0m")
|
IRed = ColorString("\033[0;91m%s\033[0m")
|
||||||
IGreen = ColorString("\033[0;92m%s\033[0m")
|
IGreen = ColorString("\033[0;92m%s\033[0m")
|
||||||
@@ -62,7 +62,7 @@ var (
|
|||||||
ICyan = ColorString("\033[0;96m%s\033[0m")
|
ICyan = ColorString("\033[0;96m%s\033[0m")
|
||||||
IWhite = ColorString("\033[0;97m%s\033[0m")
|
IWhite = ColorString("\033[0;97m%s\033[0m")
|
||||||
|
|
||||||
// Bold High Intensty
|
// Bold High Intensity
|
||||||
BIBlack = ColorString("\033[1;90m%s\033[0m")
|
BIBlack = ColorString("\033[1;90m%s\033[0m")
|
||||||
BIRed = ColorString("\033[1;91m%s\033[0m")
|
BIRed = ColorString("\033[1;91m%s\033[0m")
|
||||||
BIGreen = ColorString("\033[1;92m%s\033[0m")
|
BIGreen = ColorString("\033[1;92m%s\033[0m")
|
||||||
@@ -72,7 +72,7 @@ var (
|
|||||||
BICyan = ColorString("\033[1;96m%s\033[0m")
|
BICyan = ColorString("\033[1;96m%s\033[0m")
|
||||||
BIWhite = ColorString("\033[1;97m%s\033[0m")
|
BIWhite = ColorString("\033[1;97m%s\033[0m")
|
||||||
|
|
||||||
// High Intensty backgrounds
|
// High Intensity backgrounds
|
||||||
OnIBlack = ColorString("\033[0;100m%s\033[0m")
|
OnIBlack = ColorString("\033[0;100m%s\033[0m")
|
||||||
OnIRed = ColorString("\033[0;101m%s\033[0m")
|
OnIRed = ColorString("\033[0;101m%s\033[0m")
|
||||||
OnIGreen = ColorString("\033[0;102m%s\033[0m")
|
OnIGreen = ColorString("\033[0;102m%s\033[0m")
|
||||||
|
|||||||
104
hash_test.go
104
hash_test.go
@@ -12,8 +12,8 @@ import (
|
|||||||
type testPalette []color.Color
|
type testPalette []color.Color
|
||||||
|
|
||||||
func (p testPalette) ToPalette() color.Palette { return color.Palette(p) }
|
func (p testPalette) ToPalette() color.Palette { return color.Palette(p) }
|
||||||
func (p testPalette) Get(i int) color.Color { return p[i] }
|
func (p testPalette) Get(i int) color.Color { return p[i] }
|
||||||
func (p testPalette) Len() int { return len(p) }
|
func (p testPalette) Len() int { return len(p) }
|
||||||
|
|
||||||
func newTestPalette() testPalette {
|
func newTestPalette() testPalette {
|
||||||
return testPalette{
|
return testPalette{
|
||||||
@@ -153,6 +153,106 @@ func TestStringerPalette(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateStringerPaletteBackgroundFill(t *testing.T) {
|
||||||
|
palette := newTestPalette()
|
||||||
|
sp := createStringerPalette(true, false, palette)
|
||||||
|
if len(sp) != len(palette) {
|
||||||
|
t.Fatalf("expected %d entries, got %d", len(palette), len(sp))
|
||||||
|
}
|
||||||
|
result := sp.GetString("test-bg")
|
||||||
|
if result == "" {
|
||||||
|
t.Fatal("GetString with background fill returned empty string")
|
||||||
|
}
|
||||||
|
if result == "test-bg" {
|
||||||
|
t.Fatal("GetString with background fill did not wrap with escape codes")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateStringerPaletteDisableSmart(t *testing.T) {
|
||||||
|
palette := newTestPalette()
|
||||||
|
sp := createStringerPalette(false, true, palette)
|
||||||
|
if len(sp) != len(palette) {
|
||||||
|
t.Fatalf("expected %d entries, got %d", len(palette), len(sp))
|
||||||
|
}
|
||||||
|
result := sp.GetString("test-nosmart")
|
||||||
|
if result == "" {
|
||||||
|
t.Fatal("GetString with smart mode disabled returned empty string")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateStringerPaletteMultipleSets(t *testing.T) {
|
||||||
|
p1 := newTestPalette()
|
||||||
|
p2 := testPalette{
|
||||||
|
simplecolor.FromRGBA(100, 100, 100, 255),
|
||||||
|
simplecolor.FromRGBA(200, 200, 200, 255),
|
||||||
|
}
|
||||||
|
sp := createStringerPalette(false, false, p1, p2)
|
||||||
|
if len(sp) != len(p1)+len(p2) {
|
||||||
|
t.Fatalf("expected %d entries, got %d", len(p1)+len(p2), len(sp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetBackgroundColorMidTone(t *testing.T) {
|
||||||
|
// A mid-tone color to exercise the luminance threshold
|
||||||
|
mid := simplecolor.FromRGBA(128, 128, 128, 255)
|
||||||
|
bg := GetBackgroundColor(mid)
|
||||||
|
// Should return a valid color (either black or white)
|
||||||
|
r, g, b, _ := bg.RGBA()
|
||||||
|
isBlack := r == 0 && g == 0 && b == 0
|
||||||
|
isWhite := r == 255 && g == 255 && b == 255
|
||||||
|
if !isBlack && !isWhite {
|
||||||
|
t.Errorf("expected black or white background, got (%d,%d,%d)", r, g, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestColorStringVariants(t *testing.T) {
|
||||||
|
variants := []struct {
|
||||||
|
name string
|
||||||
|
fn ColorStringer
|
||||||
|
}{
|
||||||
|
{"Green", Green},
|
||||||
|
{"Yellow", Yellow},
|
||||||
|
{"Purple", Purple},
|
||||||
|
{"Magenta", Magenta},
|
||||||
|
{"BBlue", BBlue},
|
||||||
|
{"UCyan", UCyan},
|
||||||
|
{"OnRed", OnRed},
|
||||||
|
{"IBlue", IBlue},
|
||||||
|
{"BICyan", BICyan},
|
||||||
|
{"OnIGreen", OnIGreen},
|
||||||
|
}
|
||||||
|
for _, v := range variants {
|
||||||
|
t.Run(v.name, func(t *testing.T) {
|
||||||
|
result := v.fn("test")
|
||||||
|
if result == "" {
|
||||||
|
t.Fatalf("%s returned empty string", v.name)
|
||||||
|
}
|
||||||
|
if result == "test" {
|
||||||
|
t.Fatalf("%s did not apply escape codes", v.name)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHashBytesEmpty(t *testing.T) {
|
||||||
|
h := HashBytes(bytes.NewReader([]byte{}))
|
||||||
|
if h < 0 {
|
||||||
|
t.Errorf("HashBytes with empty input returned negative: %d", h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBytesToColorDeterministic(t *testing.T) {
|
||||||
|
palette := newTestPalette()
|
||||||
|
input := []byte("consistent-bytes")
|
||||||
|
c1 := BytesToColor(palette, bytes.NewReader(input))
|
||||||
|
c2 := BytesToColor(palette, bytes.NewReader(input))
|
||||||
|
r1, g1, b1, a1 := c1.RGBA()
|
||||||
|
r2, g2, b2, a2 := c2.RGBA()
|
||||||
|
if r1 != r2 || g1 != g2 || b1 != b2 || a1 != a2 {
|
||||||
|
t.Error("BytesToColor is not deterministic")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDifferentInputsDifferentColors(t *testing.T) {
|
func TestDifferentInputsDifferentColors(t *testing.T) {
|
||||||
palette := newTestPalette()
|
palette := newTestPalette()
|
||||||
type rgba struct{ r, g, b, a uint32 }
|
type rgba struct{ r, g, b, a uint32 }
|
||||||
|
|||||||
@@ -55,6 +55,27 @@ func TestGenerateOKLCHPaletteSingle(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGenerateOKLCHPaletteNegative(t *testing.T) {
|
||||||
|
palette := GenerateOKLCHPalette(-5, 0.7, 0.15)
|
||||||
|
if len(palette) != 0 {
|
||||||
|
t.Errorf("expected empty palette for negative n, got %d colors", len(palette))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerateOKLCHPaletteLarge(t *testing.T) {
|
||||||
|
palette := GenerateOKLCHPalette(360, 0.7, 0.15)
|
||||||
|
if len(palette) != 360 {
|
||||||
|
t.Fatalf("expected 360 colors, got %d", len(palette))
|
||||||
|
}
|
||||||
|
// Hue step should be ~1° for 360 colors
|
||||||
|
c0 := palette[0].ToOKLCH()
|
||||||
|
c1 := palette[1].ToOKLCH()
|
||||||
|
step := c1.H - c0.H
|
||||||
|
if math.Abs(step-1.0) > 1.0 {
|
||||||
|
t.Errorf("expected ~1° hue step, got %f°", step)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGenerateOKLCHPaletteDistinct(t *testing.T) {
|
func TestGenerateOKLCHPaletteDistinct(t *testing.T) {
|
||||||
palette := GenerateOKLCHPalette(6, 0.7, 0.15)
|
palette := GenerateOKLCHPalette(6, 0.7, 0.15)
|
||||||
// All colors should be distinct
|
// All colors should be distinct
|
||||||
|
|||||||
Reference in New Issue
Block a user