use std::{panic::catch_unwind, sync::Arc};
use arrow_array::{Int32Array, RecordBatch};
use arrow_schema::Schema;
use reifydb_codec::{
frame::{decode::decode_frames, encode::encode_frames, options::EncodeOptions},
wire::RawChangePayload,
};
use reifydb_value::value::{
diff_type::DiffType,
frame::frame::Frame,
value_type::{ValueType, field::named},
};
fn frame(op: Option<DiffType>) -> Frame {
let (field, array) = named("a", ValueType::Int4.into(), Arc::new(Int32Array::from(vec![7])));
let mut frame = Frame::from(RecordBatch::try_new(Arc::new(Schema::new(vec![field])), vec![array]).unwrap());
frame.op = op;
frame
}
fn encode(op: Option<DiffType>) -> Vec<u8> {
encode_frames(&[frame(op)], &EncodeOptions::default()).unwrap()
}
#[test]
fn an_unknown_rbcf_frame_op_is_a_decode_error_not_an_absent_op() {
let without_op = encode(None);
let mut bytes = encode(Some(DiffType::Insert));
let op_at: Vec<usize> = (0..bytes.len()).filter(|at| bytes[*at] != without_op[*at]).collect();
assert_eq!(op_at.len(), 1, "the op must live in exactly one header byte");
bytes[op_at[0]] = 9;
let result = decode_frames(&bytes).map(|frames| frames[0].op);
assert!(result.is_err(), "expected a decode error, got {result:?}");
}
#[test]
fn a_corrupt_raw_change_payload_is_not_read_as_zero_frames() {
let mut bytes = encode(Some(DiffType::Insert));
bytes.truncate(bytes.len() / 2);
assert!(
decode_frames(&bytes).is_err(),
"the truncated payload must be undecodable for this test to mean anything"
);
let result = catch_unwind(|| RawChangePayload::Rbcf(bytes).into_frames().map(|f| f.len()));
assert!(!matches!(result, Ok(Ok(0))), "a corrupt change payload decoded as zero frames");
}