1package ansi
2
3import (
4 "math"
5 "reflect"
6 "testing"
7)
8
9func TestBuildDamagePlan(t *testing.T) {
10 tests := []struct {
11 name string
12 frame Frame
13 damage []Damage
14 want []Span
15 full bool
16 }{
17 {
18 name: "merges reverse overlaps",
19 frame: NewFrame(10, 2),
20 damage: []Damage{
21 {Kind: DamageText, X: 4, Y: 0, Width: 5, Height: 1},
22 {Kind: DamageText, X: 0, Y: 0, Width: 5, Height: 1},
23 },
24 want: []Span{{Y: 0, X: 0, Width: 9}},
25 },
26 {
27 name: "merges text and clear",
28 frame: NewFrame(10, 1),
29 damage: []Damage{
30 {Kind: DamageClear, X: 5, Y: 0, Width: 4, Height: 1},
31 {Kind: DamageText, X: 0, Y: 0, Width: 5, Height: 1},
32 },
33 want: []Span{{Y: 0, X: 0, Width: 9}},
34 },
35 {
36 name: "orders multi-row spans",
37 frame: NewFrame(10, 3),
38 damage: []Damage{
39 {Kind: DamageText, X: 5, Y: 2, Width: 2, Height: 1},
40 {Kind: DamageText, X: 4, Y: 0, Width: 2, Height: 2},
41 {Kind: DamageText, X: 1, Y: 0, Width: 2, Height: 2},
42 {Kind: DamageScrollUp, X: 0, Y: 0, Width: 10, Height: 3, Count: 1},
43 },
44 want: []Span{
45 {Y: 0, X: 1, Width: 2}, {Y: 0, X: 4, Width: 2},
46 {Y: 1, X: 1, Width: 2}, {Y: 1, X: 4, Width: 2},
47 {Y: 2, X: 5, Width: 2},
48 },
49 },
50 {
51 name: "clamps rectangles",
52 frame: NewFrame(10, 3),
53 damage: []Damage{
54 {Kind: DamageText, X: -2, Y: -1, Width: 5, Height: 3},
55 {Kind: DamageClear, X: 8, Y: 1, Width: 5, Height: 3},
56 },
57 want: []Span{{Y: 0, X: 0, Width: 3}, {Y: 1, X: 0, Width: 3}, {Y: 1, X: 8, Width: 2}, {Y: 2, X: 8, Width: 2}},
58 },
59 {
60 name: "does not mutate input",
61 frame: NewFrame(10, 2),
62 damage: []Damage{
63 {Kind: DamageText, X: 5, Y: 1, Width: 2, Height: 1},
64 {Kind: DamageText, X: 1, Y: 0, Width: 2, Height: 1},
65 },
66 want: []Span{{Y: 0, X: 1, Width: 2}, {Y: 1, X: 5, Width: 2}},
67 },
68 {
69 name: "exceeding budget requests full redraw",
70 frame: NewFrame(1, maxPlannedDamageSpans+1),
71 damage: []Damage{{Kind: DamageText, X: 0, Y: 0, Width: 1, Height: maxPlannedDamageSpans + 1}},
72 want: nil,
73 full: true,
74 },
75 }
76
77 for _, tt := range tests {
78 t.Run(tt.name, func(t *testing.T) {
79 original := append([]Damage(nil), tt.damage...)
80 got, full := buildDamagePlan(tt.frame, tt.damage, nil)
81 if full != tt.full || !reflect.DeepEqual(got, tt.want) {
82 t.Fatalf("buildDamagePlan() = %#v, full = %v; want %#v, %v", got, full, tt.want, tt.full)
83 }
84 if !reflect.DeepEqual(tt.damage, original) {
85 t.Fatalf("buildDamagePlan mutated damage: got %#v, want %#v", tt.damage, original)
86 }
87 })
88 }
89}
90
91func TestClampRectRejectsOverflowingBounds(t *testing.T) {
92 frame := NewFrame(10, 10)
93 if _, _, _, _, ok := clampRect(frame, math.MaxInt-1, 0, 4, 1); ok {
94 t.Fatal("clampRect accepted overflowing x bound")
95 }
96 if _, _, _, _, ok := clampRect(frame, 0, math.MaxInt-1, 1, 4); ok {
97 t.Fatal("clampRect accepted overflowing y bound")
98 }
99}