Files
wanderbooks/crates/ledger-gui/tests/scripts.rs
T
swaitsandClaude Opus 5.5 2c29d48ab9 P3: the IIF in plain ASCII with every change listed, and the CPA package as of one day (defects 7, 21)
The CPA package's general-journal.iif now holds every posted entry through
as_of (closing entries left out, D-36), written as plain ASCII with CR LF,
DOCNUM the entry id, QuickBooks Desktop's field limits and subaccount types
honoured, and every character written differently listed in the export's
warnings and the README (grouped by substitution, TINs masked). The 1099
worksheet stops at as_of too. PDFs print CJK, Arabic, Hebrew, Thai and
Devanagari (Noto fallbacks, OFL), and so does the viewer. has_full_tin reads
Unicode separators.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3gXMVt7XJPi6ens1or9Dj
2026-10-21 09:35:32 -06:00

101 lines
3.6 KiB
Rust

//! Names in other scripts show as written (P3 review round 2): the viewer
//! falls back on the PDFs' own Noto fonts (`ledger_import::fonts`), so an
//! account named in Chinese, Arabic, Hebrew, Thai or Hindi is drawn with
//! its own letters, never as empty boxes.
//!
//! ```text
//! GOAL: the owner reads every name the books hold, in any script.
//! SOURCE: DECISION (lead, P3 review round 2, 2026-10-20).
//! ```
//!
//! Set `SHOT_DIR` to also save the Accounts page as `scripts.png` there,
//! to look at.
use egui_kittest::Harness;
use ledger_core::{AccountType, Currency, Money, Side};
use ledger_gui::nav::Route;
use ledger_gui::{App, Source, data};
use ledger_store::Store;
use rust_decimal::Decimal;
use std::path::PathBuf;
/// A test's dir, removed when the test ends, pass or panic.
struct TestDir(PathBuf);
impl Drop for TestDir {
fn drop(&mut self) {
let _ = std::fs::remove_dir_all(&self.0);
}
}
/// The names, each its own script.
const NAMES: [&str; 5] = ["北京 办公室", "مكتب الرياض", "שכר דירה", "ค่าเช่า", "किराया"];
#[test]
fn account_names_in_other_scripts_show_as_written() {
let dir =
TestDir(std::env::temp_dir().join(format!("ledger-gui-scripts-{}", std::process::id())));
let _ = std::fs::remove_dir_all(&dir.0);
let data_dir = dir.0.join("books-data");
let mut s = Store::create(&data_dir, Currency::USD).unwrap();
let cash = s
.add_account("1000", "Checking", AccountType::Asset, None, false)
.unwrap();
// Each account with a payment on it, so the page lists it.
for (i, name) in NAMES.iter().enumerate() {
let id = s
.add_account(&format!("6{i}00"), name, AccountType::Expense, None, false)
.unwrap();
let day = chrono::NaiveDate::from_ymd_opt(2026, 10, 1 + i as u32).unwrap();
let e = s.create_entry(day, name).unwrap();
let m = Money::new(Decimal::new(10_000 * (i as i64 + 1), 2), Currency::USD);
s.add_line(e, id, Side::Debit, m).unwrap();
s.add_line(e, cash, Side::Credit, m).unwrap();
s.attach_receipt(Some(e), "r.pdf", "application/pdf", b"%PDF r", None)
.unwrap();
s.post_entry(e).unwrap();
}
drop(s);
let books = data::load_once(&Source {
data_dir,
today: Some(chrono::NaiveDate::from_ymd_opt(2026, 10, 20).unwrap()),
})
.unwrap();
let mut h = Harness::builder()
.with_size(egui::vec2(1100.0, 640.0))
.build_eframe(|cc| App::with_books(&cc.egui_ctx, books, false, Route::Accounts));
h.run_steps(4);
let ctx = h.ctx.clone();
h.state_mut().settle(&ctx);
h.run_steps(4);
if let Ok(out) = std::env::var("SHOT_DIR") {
let out = PathBuf::from(out);
std::fs::create_dir_all(&out).unwrap();
h.render().unwrap().save(out.join("scripts.png")).unwrap();
}
// Every text the page painted.
fn walk(s: &egui::Shape, out: &mut Vec<String>) {
match s {
egui::Shape::Text(t) => out.push(t.galley.text().to_string()),
egui::Shape::Vec(v) => v.iter().for_each(|s| walk(s, out)),
_ => {}
}
}
let mut painted = Vec::new();
for c in &h.output().shapes {
walk(&c.shape, &mut painted);
}
for name in NAMES {
assert!(
painted.iter().any(|t| t.contains(name)),
"{name} is on the Accounts page: {painted:?}"
);
for c in name.chars().filter(|c| !c.is_whitespace()) {
assert!(
ctx.fonts_mut(|f| f.has_glyph(&egui::FontId::proportional(14.0), c)),
"{c} of {name} has a glyph"
);
}
}
}