use semlith::Semlith;
use std::path::Path;
fn home() -> &'static Path {
static HOME: std::sync::OnceLock<tempfile::TempDir> = std::sync::OnceLock::new();
let dir = HOME.get_or_init(|| tempfile::tempdir().unwrap());
unsafe {
std::env::set_var("SEMLITH_HOME", dir.path());
std::env::set_var(semlith::cache::CAP_ENV, "256");
}
dir.path()
}
fn repository(at: &Path, files: usize) {
for f in 0..files {
let mut text = String::new();
for g in 0..8 {
text.push_str(&format!(
"/// Returns the {g}th measure of widget {f}, in millimetres, after the\n\
/// calibration the bench applies to every widget of this family: the\n\
/// scale is squared, offset by the widget's own constant, and the\n\
/// result is clamped so a mis-read gauge cannot report a negative.\n\
pub fn widget_{f}_measure_{g}(scale: f64) -> f64 {{\n \
let base = {f}.0 * {g}.5 + scale;\n \
let squared = base * base - {g}.0;\n \
let offset = squared + {f}.25 * {g}.125;\n \
offset.max(0.0)\n}}\n\n"
));
}
std::fs::write(at.join(format!("widget_{f}.rs")), text).unwrap();
}
}
fn index(store: &Path, root: &Path) -> semlith::IndexReport {
let mut s = Semlith::open(store, None).unwrap();
s.quiet = true;
s.index_paths(&[root.to_path_buf()], |_, _| {}).unwrap()
}
#[test]
#[ignore = "downloads an embedding model on first run"]
fn an_edit_re_embeds_only_what_changed_and_a_worktree_almost_nothing() {
home();
let repo = tempfile::tempdir().unwrap();
let store = tempfile::tempdir().unwrap();
repository(repo.path(), 20);
let first = index(store.path(), repo.path());
assert!(first.chunks >= 100, "{} chunks", first.chunks);
let embedded_first = first.cache_lookups - first.cache_hits;
for f in 0..5 {
let path = repo.path().join(format!("widget_{f}.rs"));
let text = std::fs::read_to_string(&path)
.unwrap()
.replace(&format!("{f}.0 * 3.5"), &format!("{f}.0 * 3.75"));
assert!(text.contains("3.75"));
std::fs::write(&path, text).unwrap();
}
let edited = index(store.path(), repo.path());
assert_eq!(edited.indexed, 5, "five files changed");
let embedded_edit = edited.cache_lookups - edited.cache_hits;
assert!(
embedded_edit * 5 <= edited.cache_lookups,
"an edit of one function in five files re-embedded {embedded_edit} of {} chunks",
edited.cache_lookups
);
let worktree = tempfile::tempdir().unwrap();
repository(worktree.path(), 20);
for f in 0..5 {
std::fs::copy(
repo.path().join(format!("widget_{f}.rs")),
worktree.path().join(format!("widget_{f}.rs")),
)
.unwrap();
}
let second = tempfile::tempdir().unwrap();
let other = index(second.path(), worktree.path());
let embedded_other = other.cache_lookups - other.cache_hits;
assert!(
embedded_other * 10 < other.cache_lookups,
"a second worktree re-embedded {embedded_other} of {} chunks",
other.cache_lookups
);
assert!(embedded_first > embedded_edit);
}
#[test]
#[ignore = "downloads an embedding model on first run"]
fn a_cached_vector_is_the_vector_the_cache_was_given_and_compaction_leaves_it() {
home();
let repo = tempfile::tempdir().unwrap();
repository(repo.path(), 6);
let a = tempfile::tempdir().unwrap();
let b = tempfile::tempdir().unwrap();
index(a.path(), repo.path());
let second = index(b.path(), repo.path());
assert_eq!(
second.cache_hits, second.cache_lookups,
"all from the cache"
);
let read = |dir: &Path| std::fs::read(dir.join("exact.f32")).unwrap();
let (ea, eb) = (read(a.path()), read(b.path()));
let record = 8 + 384 * 4;
assert_eq!(ea.len(), eb.len());
for (ra, rb) in ea.chunks(record).zip(eb.chunks(record)) {
assert_eq!(
&ra[8..],
&rb[8..],
"a cached vector differs from the one embedded"
);
}
let before = semlith::cache::stats();
let mut s = Semlith::open(a.path(), None).unwrap();
s.compact(&semlith::compact::CompactOptions::default())
.unwrap();
let after = semlith::cache::stats();
assert_eq!(before.rows, after.rows, "compaction touched the cache");
}