use super::*;
use rusqlite::params;
use tga::core::config::TeamConfig;
use crate::commands::aliases::tests::{insert_author, insert_commit};
fn config_with_domain(domain: &str) -> Config {
Config {
team: Some(TeamConfig {
members: vec![],
aliases: std::collections::HashMap::new(),
canonical_domain: Some(domain.to_string()),
}),
..Config::default()
}
}
fn db_with_one_hit_and_one_near_miss() -> Database {
let db = Database::open_in_memory().expect("open");
insert_author(&db, "Bob", "alt@example.com");
insert_author(&db, "Bob", "bob@example.com");
insert_author(&db, "Carol", "carol@example.com");
insert_author(&db, "Carolyn", "carolyn@example.com");
db
}
#[test]
fn auto_accept_only_merges_high() {
let mut db = Database::open_in_memory().expect("open");
let alt = insert_author(&db, "Bob", "alt@example.com");
let bob = insert_author(&db, "Bob", "bob@example.com");
insert_commit(&db, "sha-bob", bob);
insert_commit(&db, "sha-alt", alt);
let cfg = Config::default();
run(&cfg, &mut db, 0.85, true, None).expect("run");
let bob_exists: i64 = db
.connection()
.query_row(
"SELECT COUNT(*) FROM authors WHERE canonical_email = 'bob@example.com'",
[],
|r| r.get(0),
)
.expect("count");
assert_eq!(
bob_exists, 0,
"auto-accept should have removed bob@example.com"
);
let n: i64 = db
.connection()
.query_row(
"SELECT COUNT(*) FROM commits WHERE author_id = ?1",
params![alt],
|r| r.get(0),
)
.expect("count");
assert_eq!(n, 2);
}
#[test]
fn suggest_without_auto_accept_never_merges() {
let mut db = Database::open_in_memory().expect("open");
insert_author(&db, "Bob", "alt@example.com");
insert_author(&db, "Bob", "bob@example.com");
let cfg = Config::default();
run(&cfg, &mut db, 0.85, false, None).expect("run");
let rows: i64 = db
.connection()
.query_row("SELECT COUNT(*) FROM authors", [], |r| r.get(0))
.expect("count");
assert_eq!(rows, 2, "both identities must survive a suggest-only run");
}
#[test]
fn config_canonical_domain_threads_through() {
let mut db = Database::open_in_memory().expect("open");
insert_author(&db, "Z", "z@duettoresearh.com");
insert_author(&db, "Z", "z@duettoresearch.com");
let cfg = config_with_domain("duettoresearch.com");
run(&cfg, &mut db, 0.5, false, None).expect("run");
}
#[test]
fn the_review_file_lists_only_near_miss_pairs() {
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join("nested").join("identity-review.tsv");
let mut db = db_with_one_hit_and_one_near_miss();
let mut stdout: Vec<u8> = Vec::new();
run_to(
&Config::default(),
&mut db,
0.85,
false,
Some(&path),
&mut stdout,
)
.expect("run");
let written = std::fs::read_to_string(&path).expect("review file");
let lines: Vec<&str> = written.lines().collect();
assert_eq!(
lines[0], "src\tdst\treason\tconfidence\tconfirmed",
"header names the columns #6993 asks for"
);
assert_eq!(
lines.len(),
2,
"exactly one near-miss row belongs in the file, got: {written}"
);
assert_eq!(
lines[1], "carolyn@example.com\tcarol@example.com\tedit-distance 2 on local-part\t0.78\tno",
"the near-miss row carries both identities, the reason, the score, and confirmed=no"
);
assert!(
!written.contains("bob@example.com"),
"the above-threshold pair must not leak into the review file: {written}"
);
let printed = String::from_utf8(stdout).expect("utf8");
assert!(
printed.contains("bob@example.com → alt@example.com"),
"the above-threshold pair is still printed: {printed}"
);
assert!(
!printed.contains("carolyn@example.com → carol@example.com"),
"a near miss must not be printed as a suggestion: {printed}"
);
}
#[test]
fn no_review_file_is_written_without_the_flag() {
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join("identity-review.tsv");
let mut db = db_with_one_hit_and_one_near_miss();
let mut stdout: Vec<u8> = Vec::new();
run_to(&Config::default(), &mut db, 0.85, false, None, &mut stdout).expect("run");
assert!(
!path.exists(),
"no review file may be written without --review-file"
);
let printed = String::from_utf8(stdout).expect("utf8");
assert!(
!printed.contains("near-miss"),
"an unflagged run says nothing about a review file: {printed}"
);
}
#[test]
fn an_empty_near_miss_set_still_writes_the_header() {
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join("identity-review.tsv");
let mut db = Database::open_in_memory().expect("open");
insert_author(&db, "Bob", "alt@example.com");
insert_author(&db, "Bob", "bob@example.com");
let mut stdout: Vec<u8> = Vec::new();
run_to(
&Config::default(),
&mut db,
0.85,
false,
Some(&path),
&mut stdout,
)
.expect("run");
let written = std::fs::read_to_string(&path).expect("review file");
assert_eq!(written, format!("{REVIEW_HEADER}\n"));
}