use super::*;
use crate::test_support::{decode_wal_block, encode_wal_block, kv_schema};
use crate::{BatchAppender, ZSetBatch};
use gnitz_wire::TypeCode;
#[test]
fn a_string_cell_pointing_past_the_blob_is_refused() {
let schema = kv_schema(TypeCode::String);
let mut batch = ZSetBatch::new(&schema);
BatchAppender::new(&mut batch)
.add_row(1, 1)
.str_val("a value well past the inline cell");
let mut forged = batch.clone();
forged.payload[0].bytes[8..16].copy_from_slice(&u64::MAX.to_le_bytes());
match decode_wal_block(&encode_wal_block(&forged), &schema) {
Err(ProtocolError::DecodeError(m)) => assert!(m.contains("not in canonical form"), "{m}"),
other => panic!("expected a decode error, got {other:?}"),
}
}
#[test]
fn own_regions_are_appended_with_their_long_cells_rebased() {
let schema = kv_schema(TypeCode::String);
let mut batch = ZSetBatch::new(&schema);
BatchAppender::new(&mut batch)
.add_row(1, 1)
.str_val("ab")
.add_row(2, -1)
.str_val("a value well past the inline cell");
let regions = batch.wire_regions();
let mut sink = batch.clone();
append_own_regions(&mut sink, ®ions, &schema).unwrap();
assert_eq!(sink.len(), 4);
assert_eq!(sink.weights, [1, -1, 1, -1]);
let cells = sink.payload[0].bytes.as_chunks::<16>().0;
let content = |i: usize| gnitz_wire::german_string_content(&cells[i], &sink.blob);
assert_eq!(content(1), content(3));
assert_eq!(content(3), b"a value well past the inline cell");
assert_eq!(content(2), b"ab");
let short = ®ions[..regions.len() - 1];
assert!(append_own_regions(&mut ZSetBatch::new(&schema), short, &schema).is_err());
}
#[test]
fn a_zero_row_block_is_refused() {
let schema = kv_schema(TypeCode::I64);
match decode_wal_block(&encode_wal_block(&ZSetBatch::new(&schema)), &schema) {
Err(ProtocolError::DecodeError(m)) => assert!(m.contains("block holds no rows"), "{m}"),
other => panic!("expected a decode error, got {other:?}"),
}
}
#[test]
fn a_region_list_that_does_not_lay_out_its_schema_is_refused() {
let schema = kv_schema(TypeCode::I64);
let mut batch = ZSetBatch::new(&schema);
BatchAppender::new(&mut batch).add_row(1, 1).i64_val(7);
let regions = batch.wire_regions();
let decode = |regions: &[&[u8]]| append_regions(&mut ZSetBatch::new(&schema), regions, &schema, true);
decode(®ions).expect("the batch's own regions decode");
let short = ®ions[..regions.len() - 1];
let mut ragged = regions.to_vec();
ragged[gnitz_wire::REG_PAYLOAD_START] = &[0; 4];
for (case, list) in [
("a region short", short),
("a ragged region", &ragged[..]),
("no regions", &[]),
] {
assert!(matches!(decode(list), Err(ProtocolError::DecodeError(_))), "{case}");
}
}
#[test]
fn a_null_bit_under_a_not_null_column_is_a_decode_error() {
let schema = kv_schema(TypeCode::I64);
let mut b = ZSetBatch::new(&schema);
{
let mut a = BatchAppender::new(&mut b);
a.add_row(1, 1).i64_val(7);
a.add_row(2, 1).i64_val(8);
}
b.nulls[1] = 1;
match decode_wal_block(&encode_wal_block(&b), &schema) {
Err(ProtocolError::DecodeError(m)) => assert!(m.contains("NOT NULL column 'v'"), "{m}"),
other => panic!("expected a NOT NULL decode error, got {other:?}"),
}
}