test(theme): table-drive the dimmer palette cases
- commit
- f593fc16cae52e609f966e931e8b3c7db3df9c9a
- author
- brice · · 2026-07-24 12:23 UTC
- parent
- 1c0bc79
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
1 file · +91 -70
M internal/usecase/theme/theme_test.go +91 -70
| @@ -468,80 +468,101 @@ func TestDimmerUsesReportedPalette(t *testing.T) { | |||
| 468 | 468 | dimmer := NewDimmer(baseTheme) | |
| 469 | 469 | dimBG := func(raw renderer.RGB) renderer.RGB { return blendPercent(raw, background, dimmer.backgroundPercent) } | |
| 470 | 470 | dimFG := func(raw, bg renderer.RGB) renderer.RGB { return blendPercent(raw, bg, dimmer.foregroundPercent) } | |
| 471 | + | ptr := func(c renderer.RGB) *renderer.RGB { return &c } | |
| 471 | 472 | ||
| 472 | - | t.Run("indexed foreground blends from the reported palette color when known", func(t *testing.T) { | |
| 473 | - | style := renderer.Style{Foreground: 2, Background: -1} | |
| 474 | - | got := NewDimmer(withPalette).Dim(style) | |
| 475 | - | ||
| 476 | - | dimmedBG := dimBG(background) | |
| 477 | - | require.Equal(t, dimmedBG, got.BackgroundRGB) | |
| 478 | - | require.Equal(t, dimFG(reportedSlot2, dimmedBG), got.ForegroundRGB) | |
| 479 | - | require.NotEqual(t, dimFG(xterm256Color(2), dimmedBG), got.ForegroundRGB, "must not use the xterm table when the palette is known") | |
| 480 | - | }) | |
| 481 | - | ||
| 482 | - | t.Run("indexed foreground falls back to xterm when the palette bit is unknown", func(t *testing.T) { | |
| 483 | - | style := renderer.Style{Foreground: 2, Background: -1} | |
| 484 | - | got := NewDimmer(unknownBits).Dim(style) | |
| 485 | - | ||
| 486 | - | dimmedBG := dimBG(background) | |
| 487 | - | require.Equal(t, dimFG(xterm256Color(2), dimmedBG), got.ForegroundRGB) | |
| 488 | - | }) | |
| 489 | - | ||
| 490 | - | t.Run("indexed foreground falls back to xterm when UsePalette is disabled", func(t *testing.T) { | |
| 491 | - | style := renderer.Style{Foreground: 2, Background: -1} | |
| 492 | - | got := NewDimmer(paletteDisabled).Dim(style) | |
| 493 | - | ||
| 494 | - | dimmedBG := dimBG(background) | |
| 495 | - | require.Equal(t, dimFG(xterm256Color(2), dimmedBG), got.ForegroundRGB) | |
| 496 | - | }) | |
| 497 | - | ||
| 498 | - | t.Run("indexed background blends from the reported palette color when known", func(t *testing.T) { | |
| 499 | - | style := renderer.Style{Foreground: -1, Background: 4} | |
| 500 | - | got := NewDimmer(withPalette).Dim(style) | |
| 501 | - | ||
| 502 | - | dimmedBG := dimBG(reportedSlot4) | |
| 503 | - | require.Equal(t, dimmedBG, got.BackgroundRGB) | |
| 504 | - | require.Equal(t, dimFG(foreground, dimmedBG), got.ForegroundRGB) | |
| 505 | - | }) | |
| 506 | - | ||
| 507 | - | t.Run("indexed background falls back to xterm when the palette bit is unknown", func(t *testing.T) { | |
| 508 | - | style := renderer.Style{Foreground: -1, Background: 4} | |
| 509 | - | got := NewDimmer(unknownBits).Dim(style) | |
| 510 | - | ||
| 511 | - | dimmedBG := dimBG(xterm256Color(4)) | |
| 512 | - | require.Equal(t, dimmedBG, got.BackgroundRGB) | |
| 513 | - | }) | |
| 514 | - | ||
| 515 | - | t.Run("indexed underline blends from the reported palette color when known", func(t *testing.T) { | |
| 516 | - | style := renderer.Style{ | |
| 517 | - | Foreground: -1, Background: -1, | |
| 518 | - | HasUnderlineColor: true, UnderlineColor: 6, | |
| 519 | - | } | |
| 520 | - | got := NewDimmer(withPalette).Dim(style) | |
| 521 | - | ||
| 522 | - | dimmedBG := dimBG(background) | |
| 523 | - | require.True(t, got.HasUnderlineColorRGB) | |
| 524 | - | require.Equal(t, dimFG(reportedSlot6, dimmedBG), got.UnderlineColorRGB) | |
| 525 | - | }) | |
| 526 | - | ||
| 527 | - | t.Run("indexed underline falls back to xterm when the palette bit is unknown", func(t *testing.T) { | |
| 528 | - | style := renderer.Style{ | |
| 529 | - | Foreground: -1, Background: -1, | |
| 530 | - | HasUnderlineColor: true, UnderlineColor: 6, | |
| 531 | - | } | |
| 532 | - | got := NewDimmer(unknownBits).Dim(style) | |
| 473 | + | underlined := renderer.Style{ | |
| 474 | + | Foreground: -1, Background: -1, | |
| 475 | + | HasUnderlineColor: true, UnderlineColor: 6, | |
| 476 | + | } | |
| 533 | 477 | ||
| 534 | - | dimmedBG := dimBG(background) | |
| 535 | - | require.Equal(t, dimFG(xterm256Color(6), dimmedBG), got.UnderlineColorRGB) | |
| 536 | - | }) | |
| 478 | + | cases := []struct { | |
| 479 | + | name string | |
| 480 | + | theme Theme | |
| 481 | + | style renderer.Style | |
| 482 | + | // Raw colors Dim's blends must start from; expected values are | |
| 483 | + | // derived from them with the same blend math Dim uses. | |
| 484 | + | fgSource renderer.RGB | |
| 485 | + | bgSource renderer.RGB | |
| 486 | + | underlineSource *renderer.RGB // nil when the style has no underline color | |
| 487 | + | forbidFGSource *renderer.RGB // a raw color Dim must NOT have blended from | |
| 488 | + | }{ | |
| 489 | + | { | |
| 490 | + | name: "indexed foreground blends from the reported palette color when known", | |
| 491 | + | theme: withPalette, | |
| 492 | + | style: renderer.Style{Foreground: 2, Background: -1}, | |
| 493 | + | fgSource: reportedSlot2, | |
| 494 | + | bgSource: background, | |
| 495 | + | forbidFGSource: ptr(xterm256Color(2)), | |
| 496 | + | }, | |
| 497 | + | { | |
| 498 | + | name: "indexed foreground falls back to xterm when the palette bit is unknown", | |
| 499 | + | theme: unknownBits, | |
| 500 | + | style: renderer.Style{Foreground: 2, Background: -1}, | |
| 501 | + | fgSource: xterm256Color(2), | |
| 502 | + | bgSource: background, | |
| 503 | + | }, | |
| 504 | + | { | |
| 505 | + | name: "indexed foreground falls back to xterm when UsePalette is disabled", | |
| 506 | + | theme: paletteDisabled, | |
| 507 | + | style: renderer.Style{Foreground: 2, Background: -1}, | |
| 508 | + | fgSource: xterm256Color(2), | |
| 509 | + | bgSource: background, | |
| 510 | + | }, | |
| 511 | + | { | |
| 512 | + | name: "indexed background blends from the reported palette color when known", | |
| 513 | + | theme: withPalette, | |
| 514 | + | style: renderer.Style{Foreground: -1, Background: 4}, | |
| 515 | + | fgSource: foreground, | |
| 516 | + | bgSource: reportedSlot4, | |
| 517 | + | }, | |
| 518 | + | { | |
| 519 | + | name: "indexed background falls back to xterm when the palette bit is unknown", | |
| 520 | + | theme: unknownBits, | |
| 521 | + | style: renderer.Style{Foreground: -1, Background: 4}, | |
| 522 | + | fgSource: foreground, | |
| 523 | + | bgSource: xterm256Color(4), | |
| 524 | + | }, | |
| 525 | + | { | |
| 526 | + | name: "indexed underline blends from the reported palette color when known", | |
| 527 | + | theme: withPalette, | |
| 528 | + | style: underlined, | |
| 529 | + | fgSource: foreground, | |
| 530 | + | bgSource: background, | |
| 531 | + | underlineSource: ptr(reportedSlot6), | |
| 532 | + | }, | |
| 533 | + | { | |
| 534 | + | name: "indexed underline falls back to xterm when the palette bit is unknown", | |
| 535 | + | theme: unknownBits, | |
| 536 | + | style: underlined, | |
| 537 | + | fgSource: foreground, | |
| 538 | + | bgSource: background, | |
| 539 | + | underlineSource: ptr(xterm256Color(6)), | |
| 540 | + | }, | |
| 541 | + | { | |
| 542 | + | name: "256-cube index is untouched by a reported palette", | |
| 543 | + | theme: withPalette, | |
| 544 | + | style: renderer.Style{Foreground: 196, Background: -1}, | |
| 545 | + | fgSource: xterm256Color(196), | |
| 546 | + | bgSource: background, | |
| 547 | + | }, | |
| 548 | + | } | |
| 537 | 549 | ||
| 538 | - | t.Run("256-cube index is untouched by a reported palette", func(t *testing.T) { | |
| 539 | - | style := renderer.Style{Foreground: 196, Background: -1} | |
| 540 | - | got := NewDimmer(withPalette).Dim(style) | |
| 550 | + | for _, tc := range cases { | |
| 551 | + | t.Run(tc.name, func(t *testing.T) { | |
| 552 | + | got := NewDimmer(tc.theme).Dim(tc.style) | |
| 541 | 553 | ||
| 542 | - | dimmedBG := dimBG(background) | |
| 543 | - | require.Equal(t, dimFG(xterm256Color(196), dimmedBG), got.ForegroundRGB) | |
| 544 | - | }) | |
| 554 | + | dimmedBG := dimBG(tc.bgSource) | |
| 555 | + | require.Equal(t, dimmedBG, got.BackgroundRGB) | |
| 556 | + | require.Equal(t, dimFG(tc.fgSource, dimmedBG), got.ForegroundRGB) | |
| 557 | + | if tc.forbidFGSource != nil { | |
| 558 | + | require.NotEqual(t, dimFG(*tc.forbidFGSource, dimmedBG), got.ForegroundRGB, "must not use the xterm table when the palette is known") | |
| 559 | + | } | |
| 560 | + | if tc.underlineSource != nil { | |
| 561 | + | require.True(t, got.HasUnderlineColorRGB) | |
| 562 | + | require.Equal(t, dimFG(*tc.underlineSource, dimmedBG), got.UnderlineColorRGB) | |
| 563 | + | } | |
| 564 | + | }) | |
| 565 | + | } | |
| 545 | 566 | } | |
| 546 | 567 | ||
| 547 | 568 | func TestStyleHelpersFallbackAndThemed(t *testing.T) { | |
| @@ -468,80 +468,101 @@ func TestDimmerUsesReportedPalette(t *testing.T) { | |||||
| 468 | dimmer := NewDimmer(baseTheme) | 468 | dimmer := NewDimmer(baseTheme) | ||
| 469 | dimBG := func(raw renderer.RGB) renderer.RGB { return blendPercent(raw, background, dimmer.backgroundPercent) } | 469 | dimBG := func(raw renderer.RGB) renderer.RGB { return blendPercent(raw, background, dimmer.backgroundPercent) } | ||
| 470 | dimFG := func(raw, bg renderer.RGB) renderer.RGB { return blendPercent(raw, bg, dimmer.foregroundPercent) } | 470 | dimFG := func(raw, bg renderer.RGB) renderer.RGB { return blendPercent(raw, bg, dimmer.foregroundPercent) } | ||
| 471 | + | ptr := func(c renderer.RGB) *renderer.RGB { return &c } | |||
| 471 | 472 | ||||
| 472 | - | t.Run("indexed foreground blends from the reported palette color when known", func(t *testing.T) { | 473 | + | underlined := renderer.Style{ |
| 473 | - | style := renderer.Style{Foreground: 2, Background: -1} | 474 | + | Foreground: -1, Background: -1, |
| 474 | - | got := NewDimmer(withPalette).Dim(style) | 475 | + | HasUnderlineColor: true, UnderlineColor: 6, |
| 475 | - | 476 | + | } | |
| 476 | - | dimmedBG := dimBG(background) | |||
| 477 | - | require.Equal(t, dimmedBG, got.BackgroundRGB) | |||
| 478 | - | require.Equal(t, dimFG(reportedSlot2, dimmedBG), got.ForegroundRGB) | |||
| 479 | - | require.NotEqual(t, dimFG(xterm256Color(2), dimmedBG), got.ForegroundRGB, "must not use the xterm table when the palette is known") | |||
| 480 | - | }) | |||
| 481 | - | ||||
| 482 | - | t.Run("indexed foreground falls back to xterm when the palette bit is unknown", func(t *testing.T) { | |||
| 483 | - | style := renderer.Style{Foreground: 2, Background: -1} | |||
| 484 | - | got := NewDimmer(unknownBits).Dim(style) | |||
| 485 | - | ||||
| 486 | - | dimmedBG := dimBG(background) | |||
| 487 | - | require.Equal(t, dimFG(xterm256Color(2), dimmedBG), got.ForegroundRGB) | |||
| 488 | - | }) | |||
| 489 | - | ||||
| 490 | - | t.Run("indexed foreground falls back to xterm when UsePalette is disabled", func(t *testing.T) { | |||
| 491 | - | style := renderer.Style{Foreground: 2, Background: -1} | |||
| 492 | - | got := NewDimmer(paletteDisabled).Dim(style) | |||
| 493 | - | ||||
| 494 | - | dimmedBG := dimBG(background) | |||
| 495 | - | require.Equal(t, dimFG(xterm256Color(2), dimmedBG), got.ForegroundRGB) | |||
| 496 | - | }) | |||
| 497 | - | ||||
| 498 | - | t.Run("indexed background blends from the reported palette color when known", func(t *testing.T) { | |||
| 499 | - | style := renderer.Style{Foreground: -1, Background: 4} | |||
| 500 | - | got := NewDimmer(withPalette).Dim(style) | |||
| 501 | - | ||||
| 502 | - | dimmedBG := dimBG(reportedSlot4) | |||
| 503 | - | require.Equal(t, dimmedBG, got.BackgroundRGB) | |||
| 504 | - | require.Equal(t, dimFG(foreground, dimmedBG), got.ForegroundRGB) | |||
| 505 | - | }) | |||
| 506 | - | ||||
| 507 | - | t.Run("indexed background falls back to xterm when the palette bit is unknown", func(t *testing.T) { | |||
| 508 | - | style := renderer.Style{Foreground: -1, Background: 4} | |||
| 509 | - | got := NewDimmer(unknownBits).Dim(style) | |||
| 510 | - | ||||
| 511 | - | dimmedBG := dimBG(xterm256Color(4)) | |||
| 512 | - | require.Equal(t, dimmedBG, got.BackgroundRGB) | |||
| 513 | - | }) | |||
| 514 | - | ||||
| 515 | - | t.Run("indexed underline blends from the reported palette color when known", func(t *testing.T) { | |||
| 516 | - | style := renderer.Style{ | |||
| 517 | - | Foreground: -1, Background: -1, | |||
| 518 | - | HasUnderlineColor: true, UnderlineColor: 6, | |||
| 519 | - | } | |||
| 520 | - | got := NewDimmer(withPalette).Dim(style) | |||
| 521 | - | ||||
| 522 | - | dimmedBG := dimBG(background) | |||
| 523 | - | require.True(t, got.HasUnderlineColorRGB) | |||
| 524 | - | require.Equal(t, dimFG(reportedSlot6, dimmedBG), got.UnderlineColorRGB) | |||
| 525 | - | }) | |||
| 526 | - | ||||
| 527 | - | t.Run("indexed underline falls back to xterm when the palette bit is unknown", func(t *testing.T) { | |||
| 528 | - | style := renderer.Style{ | |||
| 529 | - | Foreground: -1, Background: -1, | |||
| 530 | - | HasUnderlineColor: true, UnderlineColor: 6, | |||
| 531 | - | } | |||
| 532 | - | got := NewDimmer(unknownBits).Dim(style) | |||
| 533 | 477 | ||||
| 534 | - | dimmedBG := dimBG(background) | 478 | + | cases := []struct { |
| 535 | - | require.Equal(t, dimFG(xterm256Color(6), dimmedBG), got.UnderlineColorRGB) | 479 | + | name string |
| 536 | - | }) | 480 | + | theme Theme |
| 481 | + | style renderer.Style | |||
| 482 | + | // Raw colors Dim's blends must start from; expected values are | |||
| 483 | + | // derived from them with the same blend math Dim uses. | |||
| 484 | + | fgSource renderer.RGB | |||
| 485 | + | bgSource renderer.RGB | |||
| 486 | + | underlineSource *renderer.RGB // nil when the style has no underline color | |||
| 487 | + | forbidFGSource *renderer.RGB // a raw color Dim must NOT have blended from | |||
| 488 | + | }{ | |||
| 489 | + | { | |||
| 490 | + | name: "indexed foreground blends from the reported palette color when known", | |||
| 491 | + | theme: withPalette, | |||
| 492 | + | style: renderer.Style{Foreground: 2, Background: -1}, | |||
| 493 | + | fgSource: reportedSlot2, | |||
| 494 | + | bgSource: background, | |||
| 495 | + | forbidFGSource: ptr(xterm256Color(2)), | |||
| 496 | + | }, | |||
| 497 | + | { | |||
| 498 | + | name: "indexed foreground falls back to xterm when the palette bit is unknown", | |||
| 499 | + | theme: unknownBits, | |||
| 500 | + | style: renderer.Style{Foreground: 2, Background: -1}, | |||
| 501 | + | fgSource: xterm256Color(2), | |||
| 502 | + | bgSource: background, | |||
| 503 | + | }, | |||
| 504 | + | { | |||
| 505 | + | name: "indexed foreground falls back to xterm when UsePalette is disabled", | |||
| 506 | + | theme: paletteDisabled, | |||
| 507 | + | style: renderer.Style{Foreground: 2, Background: -1}, | |||
| 508 | + | fgSource: xterm256Color(2), | |||
| 509 | + | bgSource: background, | |||
| 510 | + | }, | |||
| 511 | + | { | |||
| 512 | + | name: "indexed background blends from the reported palette color when known", | |||
| 513 | + | theme: withPalette, | |||
| 514 | + | style: renderer.Style{Foreground: -1, Background: 4}, | |||
| 515 | + | fgSource: foreground, | |||
| 516 | + | bgSource: reportedSlot4, | |||
| 517 | + | }, | |||
| 518 | + | { | |||
| 519 | + | name: "indexed background falls back to xterm when the palette bit is unknown", | |||
| 520 | + | theme: unknownBits, | |||
| 521 | + | style: renderer.Style{Foreground: -1, Background: 4}, | |||
| 522 | + | fgSource: foreground, | |||
| 523 | + | bgSource: xterm256Color(4), | |||
| 524 | + | }, | |||
| 525 | + | { | |||
| 526 | + | name: "indexed underline blends from the reported palette color when known", | |||
| 527 | + | theme: withPalette, | |||
| 528 | + | style: underlined, | |||
| 529 | + | fgSource: foreground, | |||
| 530 | + | bgSource: background, | |||
| 531 | + | underlineSource: ptr(reportedSlot6), | |||
| 532 | + | }, | |||
| 533 | + | { | |||
| 534 | + | name: "indexed underline falls back to xterm when the palette bit is unknown", | |||
| 535 | + | theme: unknownBits, | |||
| 536 | + | style: underlined, | |||
| 537 | + | fgSource: foreground, | |||
| 538 | + | bgSource: background, | |||
| 539 | + | underlineSource: ptr(xterm256Color(6)), | |||
| 540 | + | }, | |||
| 541 | + | { | |||
| 542 | + | name: "256-cube index is untouched by a reported palette", | |||
| 543 | + | theme: withPalette, | |||
| 544 | + | style: renderer.Style{Foreground: 196, Background: -1}, | |||
| 545 | + | fgSource: xterm256Color(196), | |||
| 546 | + | bgSource: background, | |||
| 547 | + | }, | |||
| 548 | + | } | |||
| 537 | 549 | ||||
| 538 | - | t.Run("256-cube index is untouched by a reported palette", func(t *testing.T) { | 550 | + | for _, tc := range cases { |
| 539 | - | style := renderer.Style{Foreground: 196, Background: -1} | 551 | + | t.Run(tc.name, func(t *testing.T) { |
| 540 | - | got := NewDimmer(withPalette).Dim(style) | 552 | + | got := NewDimmer(tc.theme).Dim(tc.style) |
| 541 | 553 | ||||
| 542 | - | dimmedBG := dimBG(background) | 554 | + | dimmedBG := dimBG(tc.bgSource) |
| 543 | - | require.Equal(t, dimFG(xterm256Color(196), dimmedBG), got.ForegroundRGB) | 555 | + | require.Equal(t, dimmedBG, got.BackgroundRGB) |
| 544 | - | }) | 556 | + | require.Equal(t, dimFG(tc.fgSource, dimmedBG), got.ForegroundRGB) |
| 557 | + | if tc.forbidFGSource != nil { | |||
| 558 | + | require.NotEqual(t, dimFG(*tc.forbidFGSource, dimmedBG), got.ForegroundRGB, "must not use the xterm table when the palette is known") | |||
| 559 | + | } | |||
| 560 | + | if tc.underlineSource != nil { | |||
| 561 | + | require.True(t, got.HasUnderlineColorRGB) | |||
| 562 | + | require.Equal(t, dimFG(*tc.underlineSource, dimmedBG), got.UnderlineColorRGB) | |||
| 563 | + | } | |||
| 564 | + | }) | |||
| 565 | + | } | |||
| 545 | } | 566 | } | ||
| 546 | 567 | ||||
| 547 | func TestStyleHelpersFallbackAndThemed(t *testing.T) { | 568 | func TestStyleHelpersFallbackAndThemed(t *testing.T) { | ||