detached 7052600

test(protocol): strengthen moved codec coverage

commit
7052600f2c8b94f8274b384202bce0f5377ed015
author
brice · · 2026-08-28 09:11 UTC
committer
brice · · 2026-08-28 14:56 UTC
parent
4bb15ab
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
3 files · +10 -8
M AGENTS.md +1 -1
@@ -51,7 +51,7 @@ Before touching daemon teardown paths, read the lock-ordering notes at the top o
5151 ## Ports and mocks
5252
5353 - Define application cross-layer interfaces in `internal/ports`; raw frame carriage interfaces live in `internal/protocol/wire`.
54-- Adapters implement ports and raw carriage contracts; use cases consume only application ports.
54+- Adapters implement ports and raw carriage contracts; use cases consume application connections through `internal/ports` and typed semantic values from `internal/protocol`, never raw carriage contracts.
5555 - Tests should prefer generated `portsmocks.MockX` with `.EXPECT()`.
5656 - Hand-written fakes are okay only when mocks make the test harder to understand.
5757 - After changing a port, run `make mocks` and commit the generated updates.
@@ -51,7 +51,7 @@ Before touching daemon teardown paths, read the lock-ordering notes at the top o
51 ## Ports and mocks51 ## Ports and mocks
52 52
53 - Define application cross-layer interfaces in `internal/ports`; raw frame carriage interfaces live in `internal/protocol/wire`.53 - Define application cross-layer interfaces in `internal/ports`; raw frame carriage interfaces live in `internal/protocol/wire`.
54-- Adapters implement ports and raw carriage contracts; use cases consume only application ports.54+- Adapters implement ports and raw carriage contracts; use cases consume application connections through `internal/ports` and typed semantic values from `internal/protocol`, never raw carriage contracts.
55 - Tests should prefer generated `portsmocks.MockX` with `.EXPECT()`.55 - Tests should prefer generated `portsmocks.MockX` with `.EXPECT()`.
56 - Hand-written fakes are okay only when mocks make the test harder to understand.56 - Hand-written fakes are okay only when mocks make the test harder to understand.
57 - After changing a port, run `make mocks` and commit the generated updates.57 - After changing a port, run `make mocks` and commit the generated updates.
M internal/protocol/wire/remote_preview_hardening_test.go +2 -1
@@ -2,6 +2,7 @@ package wire
22
33 import (
44 "bytes"
5+ "errors"
56 "math"
67 "strings"
78 "testing"
@@ -126,7 +127,7 @@ func TestRemotePreviewRejectsControlRunes(t *testing.T) {
126127 for _, control := range []rune{'\x01', '\x1b', '\x7f', '\u0085'} {
127128 preview := valid
128129 preview.Cells = []renderer.Cell{{Rune: control}}
129- if err := protocol.ValidateRemotePreview(preview); err != protocol.ErrInvalidRemotePreview {
130+ if err := protocol.ValidateRemotePreview(preview); !errors.Is(err, protocol.ErrInvalidRemotePreview) {
130131 t.Fatalf("control rune %U: ValidateRemotePreview() error = %v, want %v", control, err, protocol.ErrInvalidRemotePreview)
131132 }
132133 if MarshalRemotePreview(preview) != nil {
@@ -2,6 +2,7 @@ package wire
2 2
3 import (3 import (
4 "bytes"4 "bytes"
5+ "errors"
5 "math"6 "math"
6 "strings"7 "strings"
7 "testing"8 "testing"
@@ -126,7 +127,7 @@ func TestRemotePreviewRejectsControlRunes(t *testing.T) {
126 for _, control := range []rune{'\x01', '\x1b', '\x7f', '\u0085'} {127 for _, control := range []rune{'\x01', '\x1b', '\x7f', '\u0085'} {
127 preview := valid128 preview := valid
128 preview.Cells = []renderer.Cell{{Rune: control}}129 preview.Cells = []renderer.Cell{{Rune: control}}
129- if err := protocol.ValidateRemotePreview(preview); err != protocol.ErrInvalidRemotePreview {130+ if err := protocol.ValidateRemotePreview(preview); !errors.Is(err, protocol.ErrInvalidRemotePreview) {
130 t.Fatalf("control rune %U: ValidateRemotePreview() error = %v, want %v", control, err, protocol.ErrInvalidRemotePreview)131 t.Fatalf("control rune %U: ValidateRemotePreview() error = %v, want %v", control, err, protocol.ErrInvalidRemotePreview)
131 }132 }
132 if MarshalRemotePreview(preview) != nil {133 if MarshalRemotePreview(preview) != nil {
M internal/protocol/wire/remote_preview_test.go +7 -6
@@ -34,20 +34,21 @@ func TestRemotePreviewCodecPreservesWideStyledCells(t *testing.T) {
3434 if err != nil {
3535 t.Fatal(err)
3636 }
37- if len(got.Cells) != len(preview.Cells) || !got.Cells[0].Equal(preview.Cells[0]) || !got.Cells[1].Equal(preview.Cells[1]) {
37+ if len(got.Cells) != len(preview.Cells) {
3838 t.Fatalf("cells = %#v, want %#v", got.Cells, preview.Cells)
3939 }
40+ for i := range preview.Cells {
41+ if !got.Cells[i].Equal(preview.Cells[i]) {
42+ t.Fatalf("cell %d = %#v, want %#v", i, got.Cells[i], preview.Cells[i])
43+ }
44+ }
4045 }
4146
4247 func TestRemotePreviewCodecRejectsMalformedBoundsAndGarbage(t *testing.T) {
4348 preview := protocol.RemotePreview{Version: protocol.RemotePreviewSchemaVersion, Status: protocol.RemotePreviewOK, LifecycleID: previewTargetForTest().LifecycleID, TabID: "tab-1", Revision: 1, Width: 1, Height: 1, Cells: []renderer.Cell{{Rune: 'x'}}}
4449 payload := MarshalRemotePreview(preview)
4550 require.NotNil(t, payload)
46- for i := 0; i < len(payload); i++ {
47- if _, err := UnmarshalRemotePreview(payload[:i]); err == nil {
48- t.Fatalf("prefix %d unexpectedly decoded", i)
49- }
50- }
51+ assertAllPrefixesFail(t, payload, UnmarshalRemotePreview)
5152 if _, err := UnmarshalRemotePreview(append(append([]byte(nil), payload...), 1)); err == nil {
5253 t.Fatal("trailing garbage unexpectedly decoded")
5354 }
@@ -34,20 +34,21 @@ func TestRemotePreviewCodecPreservesWideStyledCells(t *testing.T) {
34 if err != nil {34 if err != nil {
35 t.Fatal(err)35 t.Fatal(err)
36 }36 }
37- if len(got.Cells) != len(preview.Cells) || !got.Cells[0].Equal(preview.Cells[0]) || !got.Cells[1].Equal(preview.Cells[1]) {37+ if len(got.Cells) != len(preview.Cells) {
38 t.Fatalf("cells = %#v, want %#v", got.Cells, preview.Cells)38 t.Fatalf("cells = %#v, want %#v", got.Cells, preview.Cells)
39 }39 }
40+ for i := range preview.Cells {
41+ if !got.Cells[i].Equal(preview.Cells[i]) {
42+ t.Fatalf("cell %d = %#v, want %#v", i, got.Cells[i], preview.Cells[i])
43+ }
44+ }
40 }45 }
41 46
42 func TestRemotePreviewCodecRejectsMalformedBoundsAndGarbage(t *testing.T) {47 func TestRemotePreviewCodecRejectsMalformedBoundsAndGarbage(t *testing.T) {
43 preview := protocol.RemotePreview{Version: protocol.RemotePreviewSchemaVersion, Status: protocol.RemotePreviewOK, LifecycleID: previewTargetForTest().LifecycleID, TabID: "tab-1", Revision: 1, Width: 1, Height: 1, Cells: []renderer.Cell{{Rune: 'x'}}}48 preview := protocol.RemotePreview{Version: protocol.RemotePreviewSchemaVersion, Status: protocol.RemotePreviewOK, LifecycleID: previewTargetForTest().LifecycleID, TabID: "tab-1", Revision: 1, Width: 1, Height: 1, Cells: []renderer.Cell{{Rune: 'x'}}}
44 payload := MarshalRemotePreview(preview)49 payload := MarshalRemotePreview(preview)
45 require.NotNil(t, payload)50 require.NotNil(t, payload)
46- for i := 0; i < len(payload); i++ {51+ assertAllPrefixesFail(t, payload, UnmarshalRemotePreview)
47- if _, err := UnmarshalRemotePreview(payload[:i]); err == nil {
48- t.Fatalf("prefix %d unexpectedly decoded", i)
49- }
50- }
51 if _, err := UnmarshalRemotePreview(append(append([]byte(nil), payload...), 1)); err == nil {52 if _, err := UnmarshalRemotePreview(append(append([]byte(nil), payload...), 1)); err == nil {
52 t.Fatal("trailing garbage unexpectedly decoded")53 t.Fatal("trailing garbage unexpectedly decoded")
53 }54 }

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close