use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use tegdb::log::STORAGE_FORMAT_VERSION;
use tegdb::storage_engine::StorageEngine;
use tempfile::TempDir;
#[test]
fn test_current_header_version() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.teg");
let mut engine = StorageEngine::new(db_path.clone()).unwrap();
engine.set(b"key1", b"value1".to_vec()).unwrap();
engine.flush().unwrap();
drop(engine);
let mut file = File::open(&db_path).unwrap();
let mut header = vec![0u8; 64];
file.read_exact(&mut header).unwrap();
let version = u16::from_be_bytes([header[6], header[7]]);
assert_eq!(
version, STORAGE_FORMAT_VERSION,
"New databases should use the current storage version"
);
let valid_data_end = u64::from_be_bytes([
header[21], header[22], header[23], header[24], header[25], header[26], header[27],
header[28],
]);
assert!(
valid_data_end >= 64,
"valid_data_end should be at least header size"
);
assert!(
valid_data_end < 1024,
"valid_data_end should be reasonable for small test"
);
let engine = StorageEngine::new(db_path).unwrap();
let value = engine.get(b"key1").unwrap();
assert_eq!(value.as_ref(), b"value1");
}
#[test]
fn test_version_1_rejected() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test_v1.teg");
let mut file = OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.read(true)
.open(&db_path)
.unwrap();
let mut header = vec![0u8; 64];
header[0..6].copy_from_slice(b"TEGDB\0");
header[6..8].copy_from_slice(&1u16.to_be_bytes());
header[8..12].copy_from_slice(&0u32.to_be_bytes());
header[12..16].copy_from_slice(&1024u32.to_be_bytes());
header[16..20].copy_from_slice(&(256 * 1024u32).to_be_bytes());
header[20] = 1u8;
file.write_all(&header).unwrap();
let key = b"test_key";
let value = b"test_value";
let key_len = key.len() as u32;
let value_len = value.len() as u32;
file.write_all(&key_len.to_be_bytes()).unwrap();
file.write_all(&value_len.to_be_bytes()).unwrap();
file.write_all(key).unwrap();
file.write_all(value).unwrap();
file.sync_all().unwrap();
drop(file);
let result = StorageEngine::new(db_path);
assert!(result.is_err(), "Version 1 files should be rejected");
}
#[test]
fn test_invalid_magic_rejected() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test_bad.teg");
let mut file = File::create(&db_path).unwrap();
let mut header = vec![0u8; 64];
header[0..6].copy_from_slice(b"BADMAG"); header[6..8].copy_from_slice(&2u16.to_be_bytes());
header[20] = 1u8; file.write_all(&header).unwrap();
drop(file);
let result = StorageEngine::new(db_path);
assert!(result.is_err(), "Should reject invalid magic");
}
#[test]
fn test_unsupported_version_rejected() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test_v99.teg");
let mut file = File::create(&db_path).unwrap();
let mut header = vec![0u8; 64];
header[0..6].copy_from_slice(b"TEGDB\0");
header[6..8].copy_from_slice(&99u16.to_be_bytes()); header[20] = 1u8; file.write_all(&header).unwrap();
drop(file);
let result = StorageEngine::new(db_path);
assert!(result.is_err(), "Should reject unsupported version");
}
#[test]
fn test_valid_data_end_updates() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.teg");
let engine = StorageEngine::new(db_path.clone()).unwrap();
drop(engine);
let mut file = File::open(&db_path).unwrap();
let mut header = vec![0u8; 64];
file.read_exact(&mut header).unwrap();
let initial_end = u64::from_be_bytes([
header[21], header[22], header[23], header[24], header[25], header[26], header[27],
header[28],
]);
assert_eq!(initial_end, 64);
drop(file);
let mut engine = StorageEngine::new(db_path.clone()).unwrap();
engine.set(b"key1", b"value1".to_vec()).unwrap();
engine.flush().unwrap();
drop(engine);
let mut file = File::open(&db_path).unwrap();
let mut header = vec![0u8; 64];
file.read_exact(&mut header).unwrap();
let after_insert_end = u64::from_be_bytes([
header[21], header[22], header[23], header[24], header[25], header[26], header[27],
header[28],
]);
assert!(
after_insert_end > initial_end,
"valid_data_end should increase after insert"
);
}