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 Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· 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 | |||
| 51 | 51 | ## Ports and mocks | |
| 52 | 52 | ||
| 53 | 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 | 55 | - Tests should prefer generated `portsmocks.MockX` with `.EXPECT()`. | |
| 56 | 56 | - Hand-written fakes are okay only when mocks make the test harder to understand. | |
| 57 | 57 | - 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 mocks | 51 | ## 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 | |||
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "bytes" | |
| 5 | + | "errors" | |
| 5 | 6 | "math" | |
| 6 | 7 | "strings" | |
| 7 | 8 | "testing" | |
| @@ -126,7 +127,7 @@ func TestRemotePreviewRejectsControlRunes(t *testing.T) { | |||
| 126 | 127 | for _, control := range []rune{'\x01', '\x1b', '\x7f', '\u0085'} { | |
| 127 | 128 | preview := valid | |
| 128 | 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 | 131 | t.Fatalf("control rune %U: ValidateRemotePreview() error = %v, want %v", control, err, protocol.ErrInvalidRemotePreview) | |
| 131 | 132 | } | |
| 132 | 133 | 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 := valid | 128 | 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) { | |||
| 34 | 34 | if err != nil { | |
| 35 | 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 | 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 | 47 | func TestRemotePreviewCodecRejectsMalformedBoundsAndGarbage(t *testing.T) { | |
| 43 | 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 | 49 | payload := MarshalRemotePreview(preview) | |
| 45 | 50 | 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) | |
| 51 | 52 | if _, err := UnmarshalRemotePreview(append(append([]byte(nil), payload...), 1)); err == nil { | |
| 52 | 53 | t.Fatal("trailing garbage unexpectedly decoded") | |
| 53 | 54 | } | |
| @@ -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 | } | ||