use super::helpers::*;
use super::prelude::*;
use crc32c::crc32c;
#[test]
fn empty_log_no_sequence() {
let buf = vec![0u8; SECTOR_SIZE as usize * 4]; let log = Log::new(&buf).unwrap();
let guid = test_log_guid();
assert!(detect_active_sequence(&log, &guid).is_err());
}
#[test]
fn single_entry_self_tail() {
let guid = test_log_guid();
let entry = build_log_entry(1, 0, &[(true, 0x1000, 0)], 0xAA, &guid);
let buf = build_log_buffer(vec![entry]);
let log = Log::new(&buf).unwrap();
let active = detect_active_sequence(&log, &guid).unwrap();
assert_eq!(active.len(), 1);
assert_eq!(active.flushed_file_offset(), 0x1_0000_0000);
assert_eq!(active.last_file_offset(), 0x2_0000_0000);
}
#[test]
fn three_entry_sequence() {
let guid = test_log_guid();
let e1 = build_log_entry(1, 0, &[(true, 0x1000, 0)], 0xAA, &guid);
let e2 = build_log_entry(2, 0, &[(true, 0x2000, 0)], 0xBB, &guid);
let e3 = build_log_entry(3, 0, &[(true, 0x3000, 0)], 0xCC, &guid);
let buf = build_log_buffer(vec![e1, e2, e3]);
let log = Log::new(&buf).unwrap();
let active = detect_active_sequence(&log, &guid).unwrap();
assert_eq!(active.len(), 3);
let seqs: Vec<u64> = active
.entries()
.iter()
.map(|e| e.entry.header().sequence_number())
.collect();
assert_eq!(seqs, vec![1, 2, 3]);
}
#[test]
fn multiple_sequences_picks_newest() {
let guid = test_log_guid();
let e1 = build_log_entry(1, 0, &[(true, 0x1000, 0)], 0xAA, &guid);
let e2 = build_log_entry(2, 0, &[(true, 0x2000, 0)], 0xBB, &guid);
let e3 = build_log_entry(3, 0, &[(true, 0x3000, 0)], 0xCC, &guid);
let e10 = build_log_entry(10, 0, &[(true, 0x4000, 0)], 0xDD, &guid);
let e11 = build_log_entry(11, 0, &[(true, 0x5000, 0)], 0xEE, &guid);
let e12 = build_log_entry(12, 0, &[(true, 0x6000, 0)], 0xFF, &guid);
let mut entries = vec![e1, e2, e3, e10, e11, e12];
let e1_len = entries[0].len();
let e2_len = entries[1].len();
let e3_len = entries[2].len();
let e10_offset = e1_len + e2_len + e3_len;
let e12_idx = 5;
entries[e12_idx][12..16].copy_from_slice(
&u32::try_from(e10_offset)
.expect("offset fits u32")
.to_le_bytes(),
);
entries[e12_idx][4..8].copy_from_slice(&0u32.to_le_bytes());
let e12_crc = crc32c(&entries[e12_idx]);
entries[e12_idx][4..8].copy_from_slice(&e12_crc.to_le_bytes());
let buf = build_log_buffer(entries);
let log = Log::new(&buf).unwrap();
let active = detect_active_sequence(&log, &guid).unwrap();
let seqs: Vec<u64> = active
.entries()
.iter()
.map(|e| e.entry.header().sequence_number())
.collect();
assert_eq!(seqs, vec![10, 11, 12], "should pick newest sequence");
}
#[test]
fn guid_mismatch_entry_ignored() {
let guid = test_log_guid();
let other_guid = Guid::from_bytes([0xFFu8; 16]);
let e1 = build_log_entry(1, 0, &[(true, 0x1000, 0)], 0xAA, &guid);
let e2 = build_log_entry(2, 0, &[(true, 0x2000, 0)], 0xBB, &other_guid); let e3 = build_log_entry(3, 0, &[(true, 0x3000, 0)], 0xCC, &guid);
let buf = build_log_buffer(vec![e1, e2, e3]);
let log = Log::new(&buf).unwrap();
let active = detect_active_sequence(&log, &guid).unwrap();
assert_eq!(active.len(), 1);
assert_eq!(active.entries()[0].entry.header().sequence_number(), 1);
}
#[test]
fn checksum_failure_entry_ignored() {
let guid = test_log_guid();
let e1 = build_log_entry(1, 0, &[(true, 0x1000, 0)], 0xAA, &guid);
let mut e2 = build_log_entry(2, 0, &[(true, 0x2000, 0)], 0xBB, &guid);
e2[100] ^= 0xFF;
let buf = build_log_buffer(vec![e1, e2]);
let log = Log::new(&buf).unwrap();
let active = detect_active_sequence(&log, &guid).unwrap();
assert_eq!(active.len(), 1);
assert_eq!(active.entries()[0].entry.header().sequence_number(), 1);
}
#[test]
fn has_pending_log_zero_guid() {
let guid = test_log_guid();
let zero_guid = Guid::from_bytes([0u8; 16]);
let entry = build_log_entry(1, 0, &[(true, 0x1000, 0)], 0xAA, &guid);
let buf = build_log_buffer(vec![entry]);
let log = Log::new(&buf).unwrap();
assert!(!has_pending_log(&log, &zero_guid));
}
#[test]
fn has_pending_log_with_sequence() {
let guid = test_log_guid();
let entry = build_log_entry(1, 0, &[(true, 0x1000, 0)], 0xAA, &guid);
let buf = build_log_buffer(vec![entry]);
let log = Log::new(&buf).unwrap();
assert!(has_pending_log(&log, &guid));
}
#[test]
fn has_pending_log_empty_buffer() {
let guid = test_log_guid();
let buf = vec![0u8; SECTOR_SIZE as usize * 4];
let log = Log::new(&buf).unwrap();
assert!(!has_pending_log(&log, &guid));
}