test(daemon): restore attention pane coverage
- commit
- 8138266bbb2a3dd42f2c5d7f01ec88d951a87f7a
- author
- brice · · 2026-07-15 04:32 UTC
- parent
- d3b9acc
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
1 file · +25 -4
M internal/usecase/daemon/attention_test.go +25 -4
| @@ -14,6 +14,7 @@ import ( | |||
| 14 | 14 | "github.com/bnema/vev/internal/ports" | |
| 15 | 15 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 16 | 16 | "github.com/bnema/vev/internal/usecase/keys" | |
| 17 | + | "github.com/bnema/vev/internal/usecase/layout" | |
| 17 | 18 | "github.com/bnema/vev/internal/usecase/ui" | |
| 18 | 19 | "github.com/bnema/vev/pkg/renderer" | |
| 19 | 20 | ) | |
| @@ -380,19 +381,39 @@ func TestComposeFrameAttentionFrameChangeDamagesOnlyBars(t *testing.T) { | |||
| 380 | 381 | sess.mu.Unlock() | |
| 381 | 382 | ||
| 382 | 383 | tb := sess.tabs[0] | |
| 384 | + | pane := tb.focusedPane() | |
| 385 | + | pane.screen.Write([]byte("ATTENTION-PANE-CONTENT")) | |
| 383 | 386 | bars := d.barStateFor(sess, "") | |
| 384 | - | area := domain.Rect{Width: tb.focusedPane().screen.Frame.Width, Height: tb.focusedPane().screen.Frame.Height} | |
| 385 | - | state := capturedRenderState{reset: true, layout: capturedTabLayout{area: area, valid: true}, bars: bars} | |
| 387 | + | area := domain.Rect{Width: pane.screen.Frame.Width, Height: pane.screen.Frame.Height} | |
| 388 | + | placement := layout.Placement{ID: pane.id, Content: area} | |
| 389 | + | state := capturedRenderState{ | |
| 390 | + | reset: true, | |
| 391 | + | layout: capturedTabLayout{area: area, focus: pane.id, placements: []layout.Placement{placement}, valid: true}, | |
| 392 | + | panes: []capturedPaneRenderState{{ | |
| 393 | + | id: pane.id, frame: pane.screen.Frame.Clone(), placement: placement, focused: true, | |
| 394 | + | damage: []renderer.Damage{renderer.FullRedraw()}, | |
| 395 | + | }}, | |
| 396 | + | bars: bars, | |
| 397 | + | } | |
| 386 | 398 | out := composeFrame(state, composeCacheInput{}) | |
| 387 | 399 | require.Equal(t, []renderer.Damage{renderer.FullRedraw()}, out.damage) | |
| 388 | - | tb.focusedPane().screen.ClearDamage() | |
| 400 | + | require.Len(t, state.panes, 1) | |
| 401 | + | require.Contains(t, rowText(out.frame.Row(1)), "ATTENTION-PANE-CONTENT") | |
| 402 | + | firstContent := rowText(out.frame.Row(1)) | |
| 389 | 403 | ||
| 404 | + | // The pane was included in the warmed cache; it has no new damage when the | |
| 405 | + | // attention pulse advances, so the subsequent compose must retain it. | |
| 390 | 406 | bars.attentionFrame++ | |
| 391 | 407 | state.reset, state.bars = false, bars | |
| 408 | + | state.panes[0].damage = nil | |
| 392 | 409 | out = composeFrame(state, out.cache) | |
| 393 | 410 | damage := out.damage | |
| 411 | + | require.Len(t, state.panes, 1, "pane state must remain present when it has no damage") | |
| 412 | + | require.Empty(t, state.panes[0].damage) | |
| 413 | + | require.Equal(t, firstContent, rowText(out.frame.Row(1)), "unchanged pane content must remain in the composed frame") | |
| 414 | + | require.Contains(t, rowText(out.frame.Row(1)), "ATTENTION-PANE-CONTENT") | |
| 394 | 415 | require.NotEmpty(t, damage) | |
| 395 | - | lastRow := tb.focusedPane().screen.Frame.Height + 1 | |
| 416 | + | lastRow := pane.screen.Frame.Height + 1 | |
| 396 | 417 | for _, dmg := range damage { | |
| 397 | 418 | require.Contains(t, []int{0, lastRow}, dmg.Y, "expected damage confined to bar rows, got y=%d", dmg.Y) | |
| 398 | 419 | } | |
| @@ -14,6 +14,7 @@ import ( | |||||
| 14 | "github.com/bnema/vev/internal/ports" | 14 | "github.com/bnema/vev/internal/ports" | ||
| 15 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | 15 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | ||
| 16 | "github.com/bnema/vev/internal/usecase/keys" | 16 | "github.com/bnema/vev/internal/usecase/keys" | ||
| 17 | + | "github.com/bnema/vev/internal/usecase/layout" | |||
| 17 | "github.com/bnema/vev/internal/usecase/ui" | 18 | "github.com/bnema/vev/internal/usecase/ui" | ||
| 18 | "github.com/bnema/vev/pkg/renderer" | 19 | "github.com/bnema/vev/pkg/renderer" | ||
| 19 | ) | 20 | ) | ||
| @@ -380,19 +381,39 @@ func TestComposeFrameAttentionFrameChangeDamagesOnlyBars(t *testing.T) { | |||||
| 380 | sess.mu.Unlock() | 381 | sess.mu.Unlock() | ||
| 381 | 382 | ||||
| 382 | tb := sess.tabs[0] | 383 | tb := sess.tabs[0] | ||
| 384 | + | pane := tb.focusedPane() | |||
| 385 | + | pane.screen.Write([]byte("ATTENTION-PANE-CONTENT")) | |||
| 383 | bars := d.barStateFor(sess, "") | 386 | bars := d.barStateFor(sess, "") | ||
| 384 | - | area := domain.Rect{Width: tb.focusedPane().screen.Frame.Width, Height: tb.focusedPane().screen.Frame.Height} | 387 | + | area := domain.Rect{Width: pane.screen.Frame.Width, Height: pane.screen.Frame.Height} |
| 385 | - | state := capturedRenderState{reset: true, layout: capturedTabLayout{area: area, valid: true}, bars: bars} | 388 | + | placement := layout.Placement{ID: pane.id, Content: area} |
| 389 | + | state := capturedRenderState{ | |||
| 390 | + | reset: true, | |||
| 391 | + | layout: capturedTabLayout{area: area, focus: pane.id, placements: []layout.Placement{placement}, valid: true}, | |||
| 392 | + | panes: []capturedPaneRenderState{{ | |||
| 393 | + | id: pane.id, frame: pane.screen.Frame.Clone(), placement: placement, focused: true, | |||
| 394 | + | damage: []renderer.Damage{renderer.FullRedraw()}, | |||
| 395 | + | }}, | |||
| 396 | + | bars: bars, | |||
| 397 | + | } | |||
| 386 | out := composeFrame(state, composeCacheInput{}) | 398 | out := composeFrame(state, composeCacheInput{}) | ||
| 387 | require.Equal(t, []renderer.Damage{renderer.FullRedraw()}, out.damage) | 399 | require.Equal(t, []renderer.Damage{renderer.FullRedraw()}, out.damage) | ||
| 388 | - | tb.focusedPane().screen.ClearDamage() | 400 | + | require.Len(t, state.panes, 1) |
| 401 | + | require.Contains(t, rowText(out.frame.Row(1)), "ATTENTION-PANE-CONTENT") | |||
| 402 | + | firstContent := rowText(out.frame.Row(1)) | |||
| 389 | 403 | ||||
| 404 | + | // The pane was included in the warmed cache; it has no new damage when the | |||
| 405 | + | // attention pulse advances, so the subsequent compose must retain it. | |||
| 390 | bars.attentionFrame++ | 406 | bars.attentionFrame++ | ||
| 391 | state.reset, state.bars = false, bars | 407 | state.reset, state.bars = false, bars | ||
| 408 | + | state.panes[0].damage = nil | |||
| 392 | out = composeFrame(state, out.cache) | 409 | out = composeFrame(state, out.cache) | ||
| 393 | damage := out.damage | 410 | damage := out.damage | ||
| 411 | + | require.Len(t, state.panes, 1, "pane state must remain present when it has no damage") | |||
| 412 | + | require.Empty(t, state.panes[0].damage) | |||
| 413 | + | require.Equal(t, firstContent, rowText(out.frame.Row(1)), "unchanged pane content must remain in the composed frame") | |||
| 414 | + | require.Contains(t, rowText(out.frame.Row(1)), "ATTENTION-PANE-CONTENT") | |||
| 394 | require.NotEmpty(t, damage) | 415 | require.NotEmpty(t, damage) | ||
| 395 | - | lastRow := tb.focusedPane().screen.Frame.Height + 1 | 416 | + | lastRow := pane.screen.Frame.Height + 1 |
| 396 | for _, dmg := range damage { | 417 | for _, dmg := range damage { | ||
| 397 | require.Contains(t, []int{0, lastRow}, dmg.Y, "expected damage confined to bar rows, got y=%d", dmg.Y) | 418 | require.Contains(t, []int{0, lastRow}, dmg.Y, "expected damage confined to bar rows, got y=%d", dmg.Y) | ||
| 398 | } | 419 | } | ||