test(core): every surviving mutant killed or argued equivalent
Max-testing pass, step 8. The final mutation run left 112 survivors (89% caught). Three agents triaged them by file, by the playbook's table: spec the boundary then test it, a law rather than one more pinned value, assert the real value, never weaken a test. Every expected value is hand-computed. - reports.rs (35): 28 killed, chiefly cash flow (inclusive start date, each line's sign and label, a loss on disposal moving to investing, financing designation), general ledger and members' equity date boundaries, and the balanced() checks (a real report nudged by a cent must stop balancing). 7 equivalent: four >/>= after an early return on zero; two in dead code (removed in this commit); one sign of a zero cleaned on output. - ledger.rs, kernel.rs, journal.rs, money.rs (52, plus one new): 49 killed, including every replay_* mutant at the core level (ids, accumulation, status, vendor tags, out-of-order refusal), FX rates, 0%/100% deductible boundaries, a dividend sweep with no income, the legacy member rounding at close, a bill paid on its own date, a liability-account reconciliation, mixed-currency entries (via serde), ISO 4217 minor units, Display/Debug. 3 equivalent: zero refused before a </<= check; a period whose end is in a closed period refused earlier; columns(0). - schedules, tax, analysis, payouts, assets, form1099 (25): 23 killed (schedule length 1-600, recurring end on its start, frequency parsing and stepping, cost of goods in tax net, a zero payout, disposal on the purchase date, quarter starts, labels); 2 equivalent (zero adds zero; days_held is provably >= 1). Two small production cleanups the triage surfaced: kernel::columns(0) returned a negative-zero credit that would print "-0" (regression a_zero_movement_has_no_negative_zero_column, shown to fail before); and cash_flow computed a book value it never used. Spec lines added where a boundary wasn't specified (cash flow's inclusive start and line signs, members' equity start date, payout with no deposit, disposal on the purchase date, bill paid on its own date). `just mutants` now runs core and store tests (the store's replay tests), not the whole workspace, which rebuilt the viewer for every mutant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWVo7x3UHw5kwCUaWxiejX
This commit is contained in:
1 parent
b2b49267db
commit
bf3f5b4cdb
15 files changed
+989
-5
No files matched your search
@@ -6,7 +6,8 @@
|
||||
|
||||
use chrono::NaiveDate;
|
||||
use ledger_core::analysis::{
|
||||
Interval, balance_history, balance_series, flows_by_interval, pnl_by_interval,
|
||||
Interval, accounts_of_type, balance_history, balance_series, flows_by_interval, interval_start,
|
||||
pnl_by_interval,
|
||||
};
|
||||
use ledger_core::{AccountType, Currency, Ledger, Money, Side};
|
||||
use rust_decimal::Decimal;
|
||||
@@ -79,3 +80,36 @@ fn balances_pnl_and_flows_over_time() {
|
||||
let io: Vec<(Decimal, Decimal)> = both.iter().map(|f| (f.2, f.3)).collect();
|
||||
assert_eq!(io, [(dec(5000), dec(300)), (dec(1200), dec(0))]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn intervals_start_on_calendar_boundaries() {
|
||||
for (day, want) in [
|
||||
(d(2, 14), d(1, 1)),
|
||||
(d(5, 31), d(4, 1)),
|
||||
(d(11, 30), d(10, 1)),
|
||||
] {
|
||||
assert_eq!(interval_start(day, Interval::Quarter), want, "{day}");
|
||||
assert_eq!(interval_start(day, Interval::Year), d(1, 1), "{day}");
|
||||
}
|
||||
assert_eq!(interval_start(d(11, 30), Interval::Month), d(11, 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn accounts_of_type_picks_from_the_chart_in_order() {
|
||||
let mut l = Ledger::new(Currency::USD);
|
||||
let mut a = |c: &str, t| l.add_account(c, c, t, None, false).unwrap();
|
||||
let cash = a("1000", AccountType::Asset);
|
||||
let card = a("2100", AccountType::Liability);
|
||||
let rent = a("6600", AccountType::Expense);
|
||||
let bank = a("1010", AccountType::Asset);
|
||||
let assets = accounts_of_type(&l, &[AccountType::Asset]);
|
||||
assert_eq!(assets.len(), 2);
|
||||
assert!(assets.contains(&cash) && assets.contains(&bank));
|
||||
let mut cash_like = accounts_of_type(&l, &[AccountType::Asset, AccountType::Liability]);
|
||||
cash_like.sort();
|
||||
let mut want = vec![cash, card, bank];
|
||||
want.sort();
|
||||
assert_eq!(cash_like, want);
|
||||
assert!(!cash_like.contains(&rent));
|
||||
assert!(accounts_of_type(&l, &[AccountType::Revenue]).is_empty());
|
||||
}
|
||||
Reference in new issue
Block a user