-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Problem
`SharedFrame` is the most critical data structure in Drift — it sits between the RDP session actor and the GPU renderer. It has zero tests.
Tests to write
Basic correctness
```rust
#[test]
fn test_update_full_and_publish() {
let sf = SharedFrame::new(2, 2);
let data = vec![255u8; 2 * 2 * 4]; // 2x2 white RGBA
sf.update_full(2, 2, &data);
let snapshot = sf.publish().expect("should be dirty");
assert_eq!(snapshot.width, 2);
assert_eq!(snapshot.height, 2);
assert_eq!(snapshot.data, data);
}
#[test]
fn test_publish_returns_none_when_clean() {
let sf = SharedFrame::new(2, 2);
assert!(sf.publish().is_none()); // not dirty after creation... wait, it IS dirty
// Actually: new() sets dirty = false, so first publish returns None
// Need to verify this behavior
}
```
Dirty rect update
```rust
#[test]
fn test_update_rect_partial() {
let sf = SharedFrame::new(4, 4); // 4x4 black frame
// Write a 2x2 red square at (1, 1)
let red = vec![255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255];
sf.update_rect(1, 1, 2, 2, &red, 2 * 4);
let snap = sf.publish().unwrap();
// Verify pixel at (1,1) is red
let offset = (1 * 4 + 1) * 4; // row 1, col 1
assert_eq!(&snap.data[offset..offset+4], &[255, 0, 0, 255]);
// Verify pixel at (0,0) is still black
assert_eq!(&snap.data[0..4], &[0, 0, 0, 0]);
}
```
Batched writes
```rust
#[test]
fn test_begin_write_batches() {
let sf = SharedFrame::new(4, 4);
{
let mut guard = sf.begin_write();
guard.update_rect(0, 0, 2, 2, &vec![1u8; 16], 8);
guard.update_rect(2, 2, 2, 2, &vec![2u8; 16], 8);
} // guard drops, lock released
sf.mark_dirty();
let snap = sf.publish().unwrap();
assert_eq!(snap.data[0], 1); // first rect
assert_eq!(snap.data[(2*4+2)*4], 2); // second rect
}
```
Zero-copy verification
```rust
#[test]
fn test_publish_reuses_allocation() {
let sf = SharedFrame::new(2, 2);
sf.update_full(2, 2, &vec![1u8; 16]);
let snap1 = sf.publish().unwrap();
let ptr1 = snap1.data.as_ptr();
drop(snap1); // release the Arc
sf.update_full(2, 2, &vec![2u8; 16]);
let snap2 = sf.publish().unwrap();
let ptr2 = snap2.data.as_ptr();
// The allocation should be reused (same pointer)
assert_eq!(ptr1, ptr2, "should reuse allocation via Arc::try_unwrap");
}
```
Concurrent access
```rust
#[test]
fn test_concurrent_writer_and_publisher() {
let sf = SharedFrame::new(100, 100);
let sf_writer = sf.clone();
let sf_reader = sf.clone();
let writer = std::thread::spawn(move || {
for i in 0..1000u8 {
sf_writer.update_full(100, 100, &vec![i; 100 * 100 * 4]);
}
});
let reader = std::thread::spawn(move || {
let mut count = 0;
for _ in 0..2000 {
if sf_reader.publish().is_some() {
count += 1;
}
}
count
});
writer.join().unwrap();
let published = reader.join().unwrap();
assert!(published > 0, "should have published at least some frames");
}
```
Edge cases
- `update_rect` with out-of-bounds coordinates (should clamp, not crash)
- `update_full` with wrong-sized data (should skip, not crash)
- Resolution change mid-stream (old snapshot kept, new buffer allocated)
- `wait_for_frame` timeout behavior
Files to create
- `src-tauri/src/renderer/shared_frame_test.rs` or `#[cfg(test)] mod tests` in `shared_frame.rs`