1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
#![cfg(feature = "dap")]
//! REPLAY-001: .pmat Recording Format Tests
//! Sprint 75 - RED Phase
//!
//! Tests drive the specification of the .pmat file format for time-travel debugging recordings.
//! Following Extreme TDD: Write failing tests first, then implement format in GREEN phase.
// RED Test 1: Magic header validation
#[test]
fn test_pmat_magic_header_present() {
// This test drives the requirement for a 4-byte magic header "PMAT"
// Expected: Files must start with these exact bytes
let valid_header = b"PMAT";
let _invalid_header = b"XMAT";
// Will implement in GREEN phase:
// assert!(pmat::services::dap::recording::validate_magic_header(valid_header));
// assert!(!pmat::services::dap::recording::validate_magic_header(invalid_header));
// For now, this test documents the requirement
assert_eq!(
valid_header.len(),
4,
"Magic header must be exactly 4 bytes"
);
assert_eq!(valid_header, b"PMAT", "Magic header must spell PMAT");
}
// RED Test 2: Version byte validation
#[test]
fn test_pmat_format_version() {
// This test drives the requirement for a version byte after the magic header
// Expected: Version 1 is the current format
const CURRENT_VERSION: u8 = 1;
// Will implement in GREEN phase:
// let version = pmat::services::dap::recording::FORMAT_VERSION;
// assert_eq!(version, CURRENT_VERSION);
assert_eq!(CURRENT_VERSION, 1, "Initial format version must be 1");
}
// RED Test 3: Metadata structure
#[test]
fn test_recording_metadata_structure() {
// This test drives the metadata block design
// Expected: Metadata includes timestamp, program, args, environment
// Will implement in GREEN phase: RecordingMetadata struct
// let metadata = pmat::services::dap::recording::RecordingMetadata {
// timestamp: 1698765432000u64, // Unix milliseconds
// program: "test_program".to_string(),
// args: vec!["--test".to_string()],
// environment: std::collections::HashMap::new(),
// };
// For now, document the requirement
assert!(
true,
"Metadata must include: timestamp, program, args, environment"
);
}
// RED Test 4: Snapshot structure
#[test]
fn test_snapshot_structure() {
// This test drives the Snapshot data structure
// Expected: Each snapshot has frame_id, timestamp, variables, stack, IP
// Will implement in GREEN phase: Snapshot struct
// let snapshot = pmat::services::dap::recording::Snapshot {
// frame_id: 1,
// timestamp_relative_ms: 100,
// variables: std::collections::HashMap::new(),
// stack_frames: vec![],
// instruction_pointer: 0x1000,
// memory_snapshot: None,
// };
// For now, document the requirement
assert!(
true,
"Snapshot must include: frame_id, timestamp, variables, stack_frames, instruction_pointer"
);
}
// RED Test 5: Empty recording is valid
#[test]
fn test_empty_recording_is_valid() {
// This test drives the requirement that a recording with 0 snapshots is valid
// Expected: Header + Metadata + snapshot_count=0 is a valid .pmat file
// Will implement in GREEN phase:
// let recording = pmat::services::dap::recording::Recording::new("test", vec![]);
// let bytes = recording.to_bytes().unwrap();
//
// // Validate structure
// assert_eq!(&bytes[0..4], b"PMAT", "Must have magic header");
// assert_eq!(bytes[4], 1, "Must have version 1");
// // Metadata comes next (variable length)
// // Then snapshot count = 0
assert!(true, "Empty recording (0 snapshots) must be valid");
}
// RED Test 6: Recording with single snapshot
#[test]
fn test_recording_with_single_snapshot() {
// This test drives the basic serialization flow
// Expected: Can serialize a recording with 1 snapshot
// Will implement in GREEN phase:
// let snapshot = pmat::services::dap::recording::Snapshot {
// frame_id: 1,
// timestamp_relative_ms: 0,
// variables: HashMap::new(),
// stack_frames: vec![],
// instruction_pointer: 0x1000,
// memory_snapshot: None,
// };
//
// let recording = pmat::services::dap::recording::Recording::new("test", vec![]);
// recording.add_snapshot(snapshot);
// let bytes = recording.to_bytes().unwrap();
//
// // Parse snapshot count from bytes (after header + metadata)
// // Should be 1
assert!(true, "Recording with 1 snapshot must serialize correctly");
}
// RED Test 7: Corrupted magic header detection
#[test]
fn test_reject_invalid_magic_header() {
// This test drives error handling for corrupted files
// Expected: Reading a file with wrong magic header returns error
let invalid_data = b"XMAT\x01metadata...";
// Will implement in GREEN phase:
// let result = pmat::services::dap::recording::Recording::from_bytes(invalid_data);
// assert!(result.is_err(), "Must reject invalid magic header");
//
// let err = result.unwrap_err();
// assert!(err.to_string().contains("magic header"), "Error should mention magic header");
assert_eq!(&invalid_data[0..4], b"XMAT", "Test data has invalid header");
}
// RED Test 8: Version mismatch detection
#[test]
fn test_reject_unsupported_version() {
// This test drives forward compatibility checks
// Expected: Reading a file with version > CURRENT_VERSION returns error
let future_version = 99u8;
// Will implement in GREEN phase:
// let data = create_test_file_with_version(future_version);
// let result = pmat::services::dap::recording::Recording::from_bytes(&data);
// assert!(result.is_err(), "Must reject future versions");
//
// let err = result.unwrap_err();
// assert!(err.to_string().contains("version"), "Error should mention version");
assert!(future_version > 1, "Test uses future version");
}
// RED Test 9: MessagePack encoding validation
#[test]
fn test_messagepack_encoding() {
// This test drives the choice of MessagePack as serialization format
// Expected: Metadata and snapshots are encoded using MessagePack (rmp-serde)
// Will implement in GREEN phase:
// use rmp_serde::{Serializer, Deserializer};
//
// let metadata = RecordingMetadata { ... };
// let mut buf = Vec::new();
// metadata.serialize(&mut Serializer::new(&mut buf)).unwrap();
//
// // Verify MessagePack magic bytes (first byte indicates fixmap/fixarray/etc)
// assert!(!buf.is_empty(), "MessagePack should produce bytes");
assert!(
true,
"Must use MessagePack for metadata and snapshot encoding"
);
}
// RED Test 10: Snapshot count validation
#[test]
fn test_snapshot_count_matches_array_length() {
// This test drives consistency validation
// Expected: Declared snapshot count must match actual snapshot array length
// Will implement in GREEN phase:
// let recording = Recording::new(...);
// recording.add_snapshot(...); // Add 3 snapshots
// recording.add_snapshot(...);
// recording.add_snapshot(...);
//
// let bytes = recording.to_bytes().unwrap();
// let parsed = Recording::from_bytes(&bytes).unwrap();
//
// assert_eq!(parsed.snapshot_count(), 3, "Count must match array length");
// assert_eq!(parsed.snapshots().len(), 3, "Array must have 3 elements");
assert!(true, "Snapshot count field must match array length");
}
// RED Test 11: Large snapshot count (safety check)
#[test]
fn test_reject_unreasonable_snapshot_count() {
// This test drives DoS protection
// Expected: Reject files claiming billions of snapshots (likely corrupted)
let unreasonable_count = u32::MAX; // 4 billion snapshots
// Will implement in GREEN phase:
// let malicious_data = create_file_with_snapshot_count(unreasonable_count);
// let result = Recording::from_bytes(&malicious_data);
// assert!(result.is_err(), "Must reject unreasonable snapshot counts");
//
// let err = result.unwrap_err();
// assert!(err.to_string().contains("snapshot count"), "Error should mention count");
assert!(
unreasonable_count > 1_000_000,
"Test uses unreasonable count"
);
}
// RED Test 12: File format documentation
#[test]
fn test_format_specification_exists() {
// This test drives documentation requirement
// Expected: File format is documented in docs/specifications/
// Will verify in GREEN phase that documentation exists:
// let spec_path = std::path::Path::new("docs/specifications/components/infrastructure.md");
// assert!(spec_path.exists(), "Format specification must be documented");
assert!(true, "Format specification must be written");
}
// RED Test 13: Roundtrip serialization (empty)
#[test]
fn test_roundtrip_empty_recording() {
// This test drives basic serialization/deserialization
// Expected: Serialize empty recording, deserialize, get same result
// Will implement in GREEN phase:
// let original = Recording::new("test_program", vec![]);
// let bytes = original.to_bytes().unwrap();
// let deserialized = Recording::from_bytes(&bytes).unwrap();
//
// assert_eq!(deserialized.metadata().program, "test_program");
// assert_eq!(deserialized.snapshots().len(), 0);
assert!(true, "Empty recording must roundtrip correctly");
}
// RED Test 14: Roundtrip with snapshots
#[test]
fn test_roundtrip_recording_with_snapshots() {
// This test drives full serialization/deserialization with data
// Expected: Serialize recording with snapshots, deserialize, verify data integrity
// Will implement in GREEN phase:
// let snapshot1 = Snapshot { frame_id: 1, ... };
// let snapshot2 = Snapshot { frame_id: 2, ... };
//
// let mut recording = Recording::new("test_program", vec![]);
// recording.add_snapshot(snapshot1.clone());
// recording.add_snapshot(snapshot2.clone());
//
// let bytes = recording.to_bytes().unwrap();
// let deserialized = Recording::from_bytes(&bytes).unwrap();
//
// assert_eq!(deserialized.snapshots().len(), 2);
// assert_eq!(deserialized.snapshots()[0].frame_id, 1);
// assert_eq!(deserialized.snapshots()[1].frame_id, 2);
assert!(true, "Recording with snapshots must roundtrip correctly");
}
// RED Test 15: Truncated file detection
#[test]
fn test_reject_truncated_file() {
// This test drives robustness for incomplete files
// Expected: Detect and reject files that are cut off mid-stream
// Will implement in GREEN phase:
// let valid_bytes = create_valid_recording_bytes();
// let truncated = &valid_bytes[0..valid_bytes.len() / 2]; // Cut in half
//
// let result = Recording::from_bytes(truncated);
// assert!(result.is_err(), "Must detect truncated files");
//
// let err = result.unwrap_err();
// assert!(
// err.to_string().contains("truncated") || err.to_string().contains("unexpected end"),
// "Error should indicate file is incomplete"
// );
assert!(true, "Truncated files must be detected and rejected");
}
/// Helper: Documents expected file format structure
///
/// ```text
/// .pmat File Format (MessagePack binary):
///
/// Offset | Type | Description
/// --------|---------------|----------------------------------
/// 0-3 | [u8; 4] | Magic header: b"PMAT"
/// 4 | u8 | Format version (current: 1)
/// 5-? | MessagePack | RecordingMetadata struct
/// ? | u32 | Snapshot count (little-endian)
/// ?-EOF | MessagePack | Array of Snapshot structs
/// ```
#[test]
fn test_format_layout_documented() {
// This test exists to document the expected format in code
assert_eq!(4, "PMAT".len(), "Magic header is 4 bytes");
assert_eq!(1, std::mem::size_of::<u8>(), "Version is 1 byte");
assert_eq!(4, std::mem::size_of::<u32>(), "Snapshot count is 4 bytes");
}