Files
wehub-resource-sync 70cb81e982
CI / Test (macos-latest, stable) (push) Has been cancelled
CI / Test (ubuntu-latest, stable) (push) Has been cancelled
CI / Test (windows-latest, stable) (push) Has been cancelled
CI / Lint (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:45:24 +08:00

269 lines
7.5 KiB
Rust

//! Integration tests for Memvid lifecycle operations.
//! Tests: create, open, open_read_only, commit, stats, verify
use memvid_core::{Memvid, PutOptions, VerificationStatus};
use std::fs;
use tempfile::TempDir;
/// Test basic create and open lifecycle.
#[test]
fn create_and_open() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("test.mv2");
// Create new memory
{
let mut mem = Memvid::create(&path).unwrap();
mem.commit().unwrap();
}
// Open existing memory
{
let _mem = Memvid::open(&path).unwrap();
}
// Open read-only
{
let _mem = Memvid::open_read_only(&path).unwrap();
}
assert!(path.exists(), "MV2 file should exist");
}
/// Test that create handles existing file.
/// Note: The current implementation allows creating even if file exists,
/// this tests that behavior (may change in future versions).
#[test]
fn create_handles_existing_file() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("test.mv2");
// Create first time
{
let mut mem = Memvid::create(&path).unwrap();
let opts = PutOptions {
uri: Some("mv2://doc1".to_string()),
..Default::default()
};
mem.put_bytes_with_options(b"First content", opts).unwrap();
mem.commit().unwrap();
}
// Create second time - this tests current behavior
// (Either it fails OR it creates a new file - both are valid implementations)
let result = Memvid::create(&path);
if let Ok(mut mem) = result {
// If create succeeds, the old data should be gone (new file)
// let mut mem = result.unwrap();
mem.commit().unwrap();
// Reopen and verify it's empty (new file was created)
let mem = Memvid::open_read_only(&path).unwrap();
let stats = mem.stats().unwrap();
assert_eq!(stats.frame_count, 0, "New file should be empty");
}
// If it fails, that's also valid behavior
}
/// Test that open fails if file doesn't exist.
#[test]
fn open_fails_if_not_exists() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("nonexistent.mv2");
let result = Memvid::open(&path);
assert!(result.is_err(), "Open should fail if file doesn't exist");
}
/// Test stats on empty memory.
#[test]
fn stats_empty_memory() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("test.mv2");
{
let mut mem = Memvid::create(&path).unwrap();
mem.commit().unwrap();
}
let mem = Memvid::open_read_only(&path).unwrap();
let stats = mem.stats().unwrap();
assert_eq!(stats.frame_count, 0, "Empty memory should have 0 frames");
}
/// Test stats after adding content.
#[test]
fn stats_with_content() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("test.mv2");
{
let mut mem = Memvid::create(&path).unwrap();
for i in 0..5 {
let content = format!("Test content {}", i);
let opts = PutOptions {
uri: Some(format!("mv2://doc{}", i)),
title: Some(format!("Document {}", i)),
..Default::default()
};
mem.put_bytes_with_options(content.as_bytes(), opts)
.unwrap();
}
mem.commit().unwrap();
}
let mem = Memvid::open_read_only(&path).unwrap();
let stats = mem.stats().unwrap();
assert_eq!(stats.frame_count, 5, "Should have 5 frames");
}
/// Test verify on healthy file.
#[test]
fn verify_healthy_file() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("test.mv2");
{
let mut mem = Memvid::create(&path).unwrap();
let opts = PutOptions {
uri: Some("mv2://test".to_string()),
title: Some("Test".to_string()),
..Default::default()
};
mem.put_bytes_with_options(b"Test content", opts).unwrap();
mem.commit().unwrap();
}
let report = Memvid::verify(&path, false).unwrap();
assert_eq!(
report.overall_status,
VerificationStatus::Passed,
"Healthy file should verify as passed"
);
}
/// Test verify detects corruption (footer zeroed).
/// Note: With severe corruption, verify may return an error instead of a report.
#[test]
fn verify_detects_corruption() {
use std::io::{Seek, SeekFrom, Write};
let dir = TempDir::new().unwrap();
let path = dir.path().join("test.mv2");
// Create valid file
{
let mut mem = Memvid::create(&path).unwrap();
let opts = PutOptions {
uri: Some("mv2://test".to_string()),
..Default::default()
};
mem.put_bytes_with_options(b"Test content", opts).unwrap();
mem.commit().unwrap();
}
// Corrupt the footer (zero last 16 bytes)
{
let mut file = fs::OpenOptions::new().write(true).open(&path).unwrap();
let len = file.metadata().unwrap().len();
if len > 16 {
file.seek(SeekFrom::End(-16)).unwrap();
file.write_all(&[0u8; 16]).unwrap();
file.flush().unwrap();
}
}
// With severe corruption, verify may error out entirely
// or return a failed status - both are valid responses
let result = Memvid::verify(&path, false);
match result {
Ok(report) => {
assert_ne!(
report.overall_status,
VerificationStatus::Passed,
"Corrupted file should not verify as passed"
);
}
Err(_) => {
// Error is also a valid response to severe corruption
}
}
}
/// Test multiple commits preserve data.
#[test]
fn multiple_commits_preserve_data() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("test.mv2");
// First commit
{
let mut mem = Memvid::create(&path).unwrap();
let opts = PutOptions {
uri: Some("mv2://doc1".to_string()),
..Default::default()
};
mem.put_bytes_with_options(b"First document", opts).unwrap();
mem.commit().unwrap();
}
// Second commit
{
let mut mem = Memvid::open(&path).unwrap();
let opts = PutOptions {
uri: Some("mv2://doc2".to_string()),
..Default::default()
};
mem.put_bytes_with_options(b"Second document", opts)
.unwrap();
mem.commit().unwrap();
}
// Verify both documents exist
let mem = Memvid::open_read_only(&path).unwrap();
let stats = mem.stats().unwrap();
assert_eq!(
stats.frame_count, 2,
"Should have 2 frames after multiple commits"
);
}
/// Test commit without changes is a no-op.
#[test]
fn commit_without_changes() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("test.mv2");
{
let mut mem = Memvid::create(&path).unwrap();
let opts = PutOptions {
uri: Some("mv2://doc1".to_string()),
..Default::default()
};
mem.put_bytes_with_options(b"Content", opts).unwrap();
mem.commit().unwrap();
}
let size_before = fs::metadata(&path).unwrap().len();
// Open and commit without changes
{
let mut mem = Memvid::open(&path).unwrap();
mem.commit().unwrap();
}
let size_after = fs::metadata(&path).unwrap().len();
// Size should be approximately the same (may differ slightly due to timestamp updates)
assert!(
(size_after as i64 - size_before as i64).abs() < 1024,
"Commit without changes should not significantly change file size"
);
}