pub mod fixtures;
pub mod helper;
#[cfg(test)]
mod tests {
use super::*;
use anyhow::Result;
#[cfg(feature = "test-fixtures")]
const CLAMPS_WITHOUT_AN_EXPLANATION: &[&str] = &[
"c-linux-small-change-struct-to-char",
"cpp-ladybird-refactor-variables-if-changes",
"cpp-tensorflow-switch-to-primitive-types",
"csharp-cyanfish-naps2-add-condition-to-if",
"csharp-jellyfin-add-function",
"go-lazygit-switch-to-strings",
"html-mozilla-firefox-firefox-remove-li-around-button",
"javascript-typescript-interesting-small-edit-refactor",
"json-excalidraw-excalidraw-change-translations-mostly-add",
"json-kiwix-kiwix-desktop-add-a-few-change-a-few",
"kotlin-jetbrains-kotlin-remove-one-comment-line",
"php-zetacomponents-consoletools-file-with-parse-errors-and-a-few-deletions",
"python-ansible-ansible-ridiculously-long-yaml-in-string-constant-and-actual-code-changes",
"python-portagefilelist-client-remove-one-import-and-update-one-const-string",
"scala-com-lihaoyi-mill-add-a-function-call",
"scala-com-lihaoyi-mill-small-refactoring",
"shellscript-scikit-learn-scikit-learn-string-to-regex",
"swift-apple-swift-argument-parser-small-change",
"swift-nextcloud-ios-move-function-and-refactor-logic",
"swift-nextcloud-ios-refactor-and-change",
"typescript-apache-echarts-envelop-2-lines-with-an-if-block",
"vimscript-neovim-neovim-test-debian-package-parsing-awful-string-matching",
"xml-gap-packages-toric-remove-two-attributes",
];
#[test]
#[cfg(feature = "test-fixtures")]
fn the_clamped_stubs_explain_their_limits() -> Result<()> {
let mut undocumented = Vec::new();
let mut stale_allowance = Vec::new();
for dataset in helper::DIFF_DATASETS {
let dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("src")
.join("test")
.join("fixtures")
.join(dataset);
if !dir.exists() {
continue;
}
for entry in std::fs::read_dir(&dir)? {
let path = entry?.path();
if path.extension().and_then(|e| e.to_str()) != Some("rs") {
continue;
}
let source = std::fs::read_to_string(&path)?;
if !source.contains("assert_matches_human_mapping_within_limit") {
continue;
}
let Some(name) = source
.split_once("assert_matches_human_mapping_within_limit(")
.and_then(|(_, rest)| rest.split_once('"'))
.and_then(|(_, rest)| rest.split_once('"'))
.map(|(name, _)| name.to_string())
else {
continue;
};
let call_at = source
.find("assert_matches_human_mapping_within_limit")
.unwrap_or(0);
let test_at = source[..call_at].rfind("#[test]").unwrap_or(0);
let explained = source[test_at..call_at]
.lines()
.any(|line| line.starts_with(" //"));
let allowed = CLAMPS_WITHOUT_AN_EXPLANATION.contains(&name.as_str());
match (explained, allowed) {
(false, false) => undocumented.push(name),
(true, true) => stale_allowance.push(name),
_ => {}
}
}
}
assert!(
undocumented.is_empty(),
"these clamped limits have no comment saying why omnidiff cannot do better. Write one, \
or tighten the limit until none is needed:\n {}",
undocumented.join("\n ")
);
assert!(
stale_allowance.is_empty(),
"these are now explained and must come off CLAMPS_WITHOUT_AN_EXPLANATION - the list \
only shrinks:\n {}",
stale_allowance.join("\n ")
);
Ok(())
}
#[test]
#[cfg(feature = "test-fixtures")]
fn every_fixture_stub_is_declared_in_its_dataset_module() -> Result<()> {
use anyhow::Context;
let fixtures = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("src")
.join("test")
.join("fixtures");
let mut orphaned = Vec::new();
let mut datasets_seen = 0usize;
for dataset in helper::DIFF_DATASETS {
let dir = fixtures.join(dataset);
if !dir.exists() {
continue;
}
let module_file = fixtures.join(format!("{dataset}.rs"));
let declarations = std::fs::read_to_string(&module_file)
.with_context(|| format!("reading {module_file:?}"))?;
datasets_seen += 1;
for entry in std::fs::read_dir(&dir)? {
let path = entry?.path();
if path.extension().and_then(|e| e.to_str()) != Some("rs") {
continue;
}
let Some(stem) = path.file_stem().and_then(|s| s.to_str()) else {
continue;
};
if !declarations.contains(&format!("mod {stem};")) {
orphaned.push(format!("{dataset}/{stem}.rs"));
}
}
}
assert!(
datasets_seen > 0,
"no fixture directories found - this check would pass vacuously"
);
orphaned.sort();
assert!(
orphaned.is_empty(),
"these fixture stubs are not declared in their dataset's module file, so none of \
their tests run. Add `#[cfg(test)] mod <name>;` to \
src/test/fixtures/<dataset>.rs:\n {}",
orphaned.join("\n ")
);
Ok(())
}
#[test]
#[cfg(feature = "test-fixtures")]
fn stub_mapping_limits_reads_both_call_shapes_and_skips_the_hand_written_stub() -> Result<()> {
let limits = helper::human_mapping::stub_mapping_limits()?;
assert!(
limits.len() > 400,
"expected a limit for most of the corpus, got {}",
limits.len()
);
assert_eq!(
limits.get("c-awslabs-aws-c-common-only-insert"),
Some(&(0, 0)),
"the exact call shape reads as a zero limit"
);
assert_eq!(
limits.get("c-sched-ext-scx-many-many-moves-some-deletes-some-adds"),
Some(&(3, 3)),
"the clamped call shape reads its two numbers"
);
assert_eq!(
limits.get("rust-hash-optimization"),
None,
"rust_hash_optimization.rs asserts specific mappings by hand rather than calling \
either helper, so it has no single limit to report and must not be guessed at"
);
Ok(())
}
#[test]
#[cfg(feature = "test-fixtures")]
fn the_quality_baseline_accuracy_columns_are_a_projection_of_the_stub_limits() -> Result<()> {
let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("research")
.join("data")
.join("quality")
.join("quality_baseline.csv");
if !path.exists() {
return Ok(());
}
let limits = helper::human_mapping::stub_mapping_limits()?;
let mut reader = csv::Reader::from_path(&path)?;
let mut disagreeing = Vec::new();
for record in reader.deserialize::<std::collections::HashMap<String, String>>() {
let record = record?;
let name = record.get("solution").cloned().unwrap_or_default();
let Some(&(total, visible)) = limits.get(&name) else {
continue;
};
let field = |key: &str| -> usize {
record
.get(key)
.and_then(|v| v.trim().parse().ok())
.unwrap_or_default()
};
if (field("mismatches"), field("visible_mismatches")) != (total, visible) {
disagreeing.push(format!(
"{name}: baseline {},{} vs stub limit {total},{visible}",
field("mismatches"),
field("visible_mismatches")
));
}
}
assert!(
disagreeing.is_empty(),
"quality_baseline.csv has drifted from the stub limits it is derived from; \
re-run `make update-quality-baseline`:\n {}",
disagreeing.join("\n ")
);
Ok(())
}
#[test]
fn handmade_test_code_loads() -> Result<()> {
let test_codes = helper::handmade_test_code()?;
assert!(!test_codes.is_empty());
Ok(())
}
#[test]
#[cfg(feature = "stats")]
fn handmade_git_repository_loads() -> Result<()> {
let test_git_repo_path = helper::handmade_git_repository()?;
assert!(test_git_repo_path.is_dir());
let git_dir = test_git_repo_path.join(".git");
assert!(git_dir.is_dir());
let repo = git2::Repository::open(&test_git_repo_path)?;
let head = repo.head()?;
let commit = head.peel_to_commit()?;
let mut revwalk = repo.revwalk()?;
revwalk.push(commit.id())?;
let commit_count = revwalk.count();
assert!(
commit_count >= 2,
"Expected at least 2 commits, found {}",
commit_count
);
let main_rs_path = test_git_repo_path.join("main.rs");
assert!(main_rs_path.is_file());
let content = std::fs::read_to_string(main_rs_path)?;
assert!(content.contains("Hello World"));
Ok(())
}
}