501 lines
20 KiB
Rust
501 lines
20 KiB
Rust
use ely_gpui_component::forms::TextInput;
|
|
use ely_lok::sheet::{self, Scale, csv::Column};
|
|
|
|
use super::data::{asked, cells, quiet, run};
|
|
use super::*;
|
|
use crate::output::Format;
|
|
|
|
/// The active tab's kernel read, after its input.
|
|
fn read<T>(
|
|
cx: &mut TestAppContext,
|
|
book: &Entity<Book>,
|
|
parse: fn(&str) -> std::io::Result<T>,
|
|
command: &str,
|
|
) -> T {
|
|
quiet(cx, book);
|
|
cx.update(|app| {
|
|
let book = book.read(app);
|
|
let tab = book.active_tab().expect("a tab");
|
|
let mut worker = book.core.worker.lock().expect("the worker lock");
|
|
parse(&worker.values(&tab.doc, command).expect("the read")).expect("parses")
|
|
})
|
|
}
|
|
|
|
fn type_in(
|
|
cx: &mut TestAppContext,
|
|
book: &Entity<Book>,
|
|
field: fn(&Dialog) -> &Entity<TextInput>,
|
|
text: &str,
|
|
) {
|
|
cx.update(|app| {
|
|
let input = field(book.read(app).dialog.as_ref().expect("a dialog")).clone();
|
|
input.update(app, |input, cx| input.set_text(text, cx));
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn a_csv_opens_through_its_choices_and_keeps_codes() {
|
|
let dir = tempfile::tempdir().expect("a temp dir");
|
|
let mut cx = TestAppContext::single();
|
|
let Some((window, book)) = book(&mut cx, dir.path()) else {
|
|
eprintln!("SKIP: no LOK build");
|
|
return;
|
|
};
|
|
let path = dir.path().join("accounts.txt");
|
|
let mut text = "Account;Amount\n".to_string();
|
|
text.push_str(&"123;2\n".repeat(18_000));
|
|
text.push_str("007;1.5\n");
|
|
std::fs::write(&path, text).expect("writes");
|
|
update(&mut cx, &book, |book, cx| book.ask_import(path.clone(), cx));
|
|
asked(&cx, &book, |dialog| matches!(dialog, Dialog::Import(pending) if !pending.reading));
|
|
cx.update(|app| match book.read(app).dialog.as_ref() {
|
|
Some(Dialog::Import(pending)) => {
|
|
assert_eq!(pending.how.separator, ';', "the guessed separator");
|
|
assert_eq!(pending.how.columns, [Column::Text, Column::Standard]);
|
|
}
|
|
_ => unreachable!("an import dialog"),
|
|
});
|
|
update(&mut cx, &book, |book, cx| book.import_asked(cx));
|
|
settle(&cx, |app| {
|
|
book.read(app).active_tab().is_some_and(|tab| tab.name == "accounts.txt")
|
|
});
|
|
assert_eq!(cells(&mut cx, &book, "A18002"), "007", "the zero stays");
|
|
assert_eq!(cells(&mut cx, &book, "B18002"), "1.5");
|
|
let saved = dir.path().join("accounts.xlsx");
|
|
let id = cx.update(|app| book.read(app).core.tabs[0].id);
|
|
cx.update_window(window.into(), |_, window, app| {
|
|
book.update(app, |book, cx| book.write_as(id, saved.clone(), None, window, cx))
|
|
})
|
|
.expect("the window lives");
|
|
settle(&cx, |app| book.read(app).core.tabs[0].name == "accounts.xlsx");
|
|
update(&mut cx, &book, |book, cx| {
|
|
book.close_tab(id, cx);
|
|
book.open_file(saved.clone(), cx);
|
|
});
|
|
settle(&cx, |app| sheet_names(app, &book).len() == 1);
|
|
assert_eq!(cells(&mut cx, &book, "A18002"), "007", "XLSX keeps it");
|
|
}
|
|
|
|
#[test]
|
|
fn a_wrong_encoding_blocks_the_import() {
|
|
let dir = tempfile::tempdir().expect("a temp dir");
|
|
let mut cx = TestAppContext::single();
|
|
let Some((_window, book)) = book(&mut cx, dir.path()) else {
|
|
eprintln!("SKIP: no LOK build");
|
|
return;
|
|
};
|
|
let path = dir.path().join("latin.csv");
|
|
std::fs::write(&path, b"Name\nCaf\xe9\n").expect("writes");
|
|
update(&mut cx, &book, |book, cx| book.ask_import(path.clone(), cx));
|
|
asked(&cx, &book, |dialog| matches!(dialog, Dialog::Import(pending) if !pending.reading));
|
|
update(&mut cx, &book, |book, cx| {
|
|
if let Some(Dialog::Import(pending)) = &mut book.dialog {
|
|
pending.how.encoding = ely_lok::sheet::csv::Encoding::Utf8;
|
|
}
|
|
book.scan_import(cx);
|
|
});
|
|
asked(&cx, &book, |dialog| matches!(dialog, Dialog::Import(pending) if !pending.reading));
|
|
update(&mut cx, &book, |book, cx| book.import_asked(cx));
|
|
assert!(cx.update(|app| book.read(app).dialog.is_some()), "broken bytes stay out");
|
|
assert!(cx.update(|app| book.read(app).core.loading.is_empty()));
|
|
}
|
|
|
|
#[test]
|
|
fn exports_write_the_shown_sheet_as_text() {
|
|
let dir = tempfile::tempdir().expect("a temp dir");
|
|
let mut cx = TestAppContext::single();
|
|
let Some((_window, book)) = book(&mut cx, dir.path()) else {
|
|
eprintln!("SKIP: no LOK build");
|
|
return;
|
|
};
|
|
blank(&mut cx, &book);
|
|
run(&mut cx, &book, "cell.enter", &["=1+2"]);
|
|
run(&mut cx, &book, "cell.goto", &["B1"]);
|
|
run(&mut cx, &book, "cell.enter", &["a;b"]);
|
|
let id = cx.update(|app| book.read(app).core.tabs[0].id);
|
|
for (format, name, text) in [
|
|
(Format::Csv, "out.csv", "3,a;b\n"),
|
|
(Format::Tsv, "out.tsv", "3\ta;b\n"),
|
|
] {
|
|
let path = dir.path().join(name);
|
|
update(&mut cx, &book, |book, cx| book.export_to(id, path.clone(), format, cx));
|
|
settle(&cx, |_| path.exists());
|
|
quiet(&cx, &book);
|
|
assert_eq!(std::fs::read_to_string(&path).expect("reads"), text);
|
|
}
|
|
let pdf = dir.path().join("out.pdf");
|
|
update(&mut cx, &book, |book, cx| book.export_to(id, pdf.clone(), Format::Pdf, cx));
|
|
settle(&cx, |_| pdf.exists());
|
|
quiet(&cx, &book);
|
|
assert!(std::fs::read(&pdf).expect("reads").starts_with(b"%PDF"));
|
|
}
|
|
|
|
fn area(dialog: &Dialog) -> &Entity<TextInput> {
|
|
match dialog {
|
|
Dialog::Page { fields, .. } => &fields.area,
|
|
_ => unreachable!("a page dialog"),
|
|
}
|
|
}
|
|
|
|
fn rows(dialog: &Dialog) -> &Entity<TextInput> {
|
|
match dialog {
|
|
Dialog::Page { fields, .. } => &fields.rows,
|
|
_ => unreachable!("a page dialog"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn page_setup_applies_titles_area_and_page() {
|
|
let dir = tempfile::tempdir().expect("a temp dir");
|
|
let mut cx = TestAppContext::single();
|
|
let Some((_window, book)) = book(&mut cx, dir.path()) else {
|
|
eprintln!("SKIP: no LOK build");
|
|
return;
|
|
};
|
|
blank(&mut cx, &book);
|
|
update(&mut cx, &book, |book, cx| book.ask_page(cx));
|
|
asked(&cx, &book, |dialog| matches!(dialog, Dialog::Page { .. }));
|
|
type_in(&mut cx, &book, area, "A1:");
|
|
update(&mut cx, &book, |book, cx| book.page_asked(cx));
|
|
asked(&cx, &book, |dialog| matches!(dialog, Dialog::Page { .. }));
|
|
type_in(&mut cx, &book, area, "a1:c4");
|
|
type_in(&mut cx, &book, rows, "1");
|
|
update(&mut cx, &book, |book, cx| {
|
|
if let Some(Dialog::Page {
|
|
landscape, scale, ..
|
|
}) = &mut book.dialog
|
|
{
|
|
(*landscape, *scale) = (true, Scale::Fit(1, 0));
|
|
}
|
|
book.page_asked(cx)
|
|
});
|
|
let layout = read(&mut cx, &book, sheet::print_layout, sheet::LAYOUT);
|
|
assert_eq!(layout.areas, ["$A$1:$C$4"]);
|
|
assert_eq!(layout.rows, Some((1, 1)));
|
|
assert_eq!((layout.landscape, layout.scale), (true, Scale::Fit(1, 0)));
|
|
}
|
|
|
|
fn password(dialog: &Dialog) -> &Entity<TextInput> {
|
|
match dialog {
|
|
Dialog::Protect { protecting, .. } => &protecting.password,
|
|
_ => unreachable!("a protect dialog"),
|
|
}
|
|
}
|
|
|
|
fn confirm(dialog: &Dialog) -> &Entity<TextInput> {
|
|
match dialog {
|
|
Dialog::Protect { protecting, .. } => &protecting.confirm,
|
|
_ => unreachable!("a protect dialog"),
|
|
}
|
|
}
|
|
|
|
fn protected(cx: &mut TestAppContext, book: &Entity<Book>) -> bool {
|
|
read(cx, book, sheet::protection, sheet::PROTECTION).protected
|
|
}
|
|
|
|
#[test]
|
|
fn a_wrong_password_leaves_the_sheet_protected() {
|
|
let dir = tempfile::tempdir().expect("a temp dir");
|
|
let mut cx = TestAppContext::single();
|
|
let Some((_window, book)) = book(&mut cx, dir.path()) else {
|
|
eprintln!("SKIP: no LOK build");
|
|
return;
|
|
};
|
|
blank(&mut cx, &book);
|
|
let ask = |cx: &mut TestAppContext| {
|
|
update(cx, &book, |book, cx| book.ask_protect(cx));
|
|
asked(cx, &book, |dialog| matches!(dialog, Dialog::Protect { .. }));
|
|
};
|
|
ask(&mut cx);
|
|
type_in(&mut cx, &book, password, "pw");
|
|
type_in(&mut cx, &book, confirm, "px");
|
|
update(&mut cx, &book, |book, cx| book.protect_asked(cx));
|
|
assert!(cx.update(|app| book.read(app).dialog.is_some()), "a mismatch stays");
|
|
type_in(&mut cx, &book, confirm, "pw");
|
|
update(&mut cx, &book, |book, cx| book.protect_asked(cx));
|
|
assert!(protected(&mut cx, &book));
|
|
ask(&mut cx);
|
|
type_in(&mut cx, &book, password, "no");
|
|
update(&mut cx, &book, |book, cx| book.protect_asked(cx));
|
|
cx.run_until_parked();
|
|
assert!(protected(&mut cx, &book), "still protected");
|
|
ask(&mut cx);
|
|
type_in(&mut cx, &book, password, "pw");
|
|
update(&mut cx, &book, |book, cx| book.protect_asked(cx));
|
|
cx.run_until_parked();
|
|
assert!(!protected(&mut cx, &book));
|
|
}
|
|
|
|
#[test]
|
|
fn a_new_link_names_its_unrefreshed_source() {
|
|
let dir = tempfile::tempdir().expect("a temp dir");
|
|
let mut cx = TestAppContext::single();
|
|
let Some((_window, book)) = book(&mut cx, dir.path()) else {
|
|
eprintln!("SKIP: no LOK build");
|
|
return;
|
|
};
|
|
let source = dir.path().join("source.ods");
|
|
blank(&mut cx, &book);
|
|
run(&mut cx, &book, "cell.enter", &["7"]);
|
|
let name = cx.update(|app| sheet_names(app, &book)[0].clone());
|
|
cx.update(|app| {
|
|
let book = book.read(app);
|
|
let tab = book.active_tab().expect("a tab");
|
|
let mut worker = book.core.worker.lock().expect("the worker lock");
|
|
tab.doc
|
|
.save_as(&mut worker, &ely_lok::file_url(&source), "ods")
|
|
.expect("the source");
|
|
});
|
|
settle(&cx, |app| book.read(app).active_tab().is_some_and(|tab| tab.extra.linked.is_some()));
|
|
run(&mut cx, &book, "cell.goto", &["B1"]);
|
|
let formula = format!("='{}/[source.ods]{name}'!A1", dir.path().display());
|
|
run(&mut cx, &book, "cell.enter", &[&formula]);
|
|
let url = ely_lok::file_url(&source);
|
|
settle(&cx, |app| {
|
|
book.read(app)
|
|
.active_tab()
|
|
.is_some_and(|tab| tab.extra.links == [url.clone()])
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn the_checked_bytes_import_even_if_the_file_changes() {
|
|
let dir = tempfile::tempdir().expect("a temp dir");
|
|
let mut cx = TestAppContext::single();
|
|
let Some((_window, book)) = book(&mut cx, dir.path()) else {
|
|
eprintln!("SKIP: no LOK build");
|
|
return;
|
|
};
|
|
let path = dir.path().join("codes.csv");
|
|
std::fs::write(&path, "Account\n00123\n").expect("writes");
|
|
update(&mut cx, &book, |book, cx| book.ask_import(path.clone(), cx));
|
|
asked(&cx, &book, |dialog| matches!(dialog, Dialog::Import(pending) if !pending.reading));
|
|
std::fs::write(&path, b"Account\n999\nA\xffB\n").expect("rewrites");
|
|
update(&mut cx, &book, |book, cx| book.import_asked(cx));
|
|
settle(&cx, |app| book.read(app).active_tab().is_some());
|
|
assert_eq!(cells(&mut cx, &book, "A2"), "00123", "what was checked");
|
|
}
|
|
|
|
#[test]
|
|
fn a_closed_dialogs_scan_never_lands_in_the_next() {
|
|
let dir = tempfile::tempdir().expect("a temp dir");
|
|
let mut cx = TestAppContext::single();
|
|
let Some((_window, book)) = book(&mut cx, dir.path()) else {
|
|
eprintln!("SKIP: no LOK build");
|
|
return;
|
|
};
|
|
let pending = |name: &str, text: &str| {
|
|
Box::new(crate::text::Pending::new(dir.path().join(name), text.into(), false))
|
|
};
|
|
// Either order: one of them lands the old scan last.
|
|
for old_first in [true, false] {
|
|
let (old, next) = (pending("old.csv", "Old\n00123\n"), pending("next.csv", "Next,Amount\n1,2\n"));
|
|
update(&mut cx, &book, |book, cx| {
|
|
let (first, second) = match old_first {
|
|
true => (Dialog::Import(old), Dialog::Import(next)),
|
|
false => (Dialog::Import(next), Dialog::Import(old)),
|
|
};
|
|
book.dialog = Some(first);
|
|
book.scan_import(cx);
|
|
let first = book.dialog.replace(second);
|
|
book.scan_import(cx);
|
|
if !old_first {
|
|
book.dialog = first;
|
|
}
|
|
});
|
|
cx.run_until_parked();
|
|
cx.update(|app| match book.read(app).dialog.as_ref() {
|
|
Some(Dialog::Import(pending)) => {
|
|
assert_eq!(pending.rows[0], ["Next", "Amount"], "old first {old_first}");
|
|
assert_eq!(pending.how.columns, [Column::Standard, Column::Standard]);
|
|
}
|
|
_ => unreachable!("an import dialog"),
|
|
});
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn the_preview_reads_what_the_kernel_imports() {
|
|
let dir = tempfile::tempdir().expect("a temp dir");
|
|
let mut cx = TestAppContext::single();
|
|
let Some((_window, book)) = book(&mut cx, dir.path()) else {
|
|
eprintln!("SKIP: no LOK build");
|
|
return;
|
|
};
|
|
let path = dir.path().join("odd.csv");
|
|
let text = "Id,Code\n \"00123\",1\n\ny,-12345678901234567890\n";
|
|
std::fs::write(&path, text).expect("writes");
|
|
update(&mut cx, &book, |book, cx| book.ask_import(path.clone(), cx));
|
|
asked(&cx, &book, |dialog| matches!(dialog, Dialog::Import(pending) if !pending.reading));
|
|
let preview = cx.update(|app| match book.read(app).dialog.as_ref() {
|
|
Some(Dialog::Import(pending)) => pending.rows.clone(),
|
|
_ => unreachable!("an import dialog"),
|
|
});
|
|
update(&mut cx, &book, |book, cx| book.import_asked(cx));
|
|
settle(&cx, |app| book.read(app).active_tab().is_some());
|
|
// Row 4 lines up only if the empty line counted.
|
|
for (at, row) in preview.iter().enumerate().filter(|(_, row)| row.len() == 2) {
|
|
for (column, value) in ["A", "B"].iter().zip(row) {
|
|
let cell = format!("{column}{}", at + 1);
|
|
assert_eq!(&cells(&mut cx, &book, &cell), value, "{cell} as previewed");
|
|
}
|
|
}
|
|
assert_eq!(preview[3][1], "-12345678901234567890");
|
|
}
|
|
|
|
#[test]
|
|
fn text_files_wait_their_turn_for_the_import_dialog() {
|
|
let dir = tempfile::tempdir().expect("a temp dir");
|
|
let mut cx = TestAppContext::single();
|
|
let Some((_window, book)) = book(&mut cx, dir.path()) else {
|
|
eprintln!("SKIP: no LOK build");
|
|
return;
|
|
};
|
|
let paths = ["a.csv", "b.csv"].map(|name| dir.path().join(name));
|
|
for (path, text) in paths.iter().zip(["first\n", "second\n"]) {
|
|
std::fs::write(path, text).expect("writes");
|
|
}
|
|
// Another dialog is open; neither import may replace it.
|
|
update(&mut cx, &book, |book, cx| {
|
|
book.dialog = Some(Dialog::Merge { tab: 0 });
|
|
for path in &paths {
|
|
book.ask_import(path.clone(), cx);
|
|
}
|
|
});
|
|
settle(&cx, |app| book.read(app).imports.len() == 2);
|
|
cx.update(|app| assert!(matches!(book.read(app).dialog, Some(Dialog::Merge { .. }))));
|
|
update(&mut cx, &book, |book, cx| {
|
|
book.dialog = None;
|
|
cx.notify();
|
|
});
|
|
for opened in 1..=2 {
|
|
asked(&cx, &book, |dialog| matches!(dialog, Dialog::Import(pending) if !pending.reading));
|
|
update(&mut cx, &book, |book, cx| book.import_asked(cx));
|
|
settle(&cx, |app| book.read(app).core.tabs.len() == opened);
|
|
}
|
|
let mut names = cx.update(|app| book.read(app).core.tabs.iter().map(|tab| tab.name.clone()).collect::<Vec<_>>());
|
|
names.sort();
|
|
assert_eq!(names, ["a.csv", "b.csv"], "both files open");
|
|
}
|
|
|
|
#[test]
|
|
fn an_import_waits_behind_a_dialog_that_displaces_it() {
|
|
let dir = tempfile::tempdir().expect("a temp dir");
|
|
let mut cx = TestAppContext::single();
|
|
let Some((window, book)) = book(&mut cx, dir.path()) else {
|
|
eprintln!("SKIP: no LOK build");
|
|
return;
|
|
};
|
|
blank(&mut cx, &book);
|
|
let path = dir.path().join("wait.csv");
|
|
std::fs::write(&path, "Id,Ignored\n1E3,hidden\n").expect("writes");
|
|
update(&mut cx, &book, |book, cx| book.ask_import(path.clone(), cx));
|
|
asked(&cx, &book, |dialog| matches!(dialog, Dialog::Import(pending) if !pending.reading));
|
|
update(&mut cx, &book, |book, _| {
|
|
if let Some(Dialog::Import(pending)) = &mut book.dialog {
|
|
pending.how.columns = vec![Column::Text, Column::Skip];
|
|
}
|
|
});
|
|
window
|
|
.update(&mut cx, |_, window, cx| {
|
|
book.update(cx, |book, cx| book.on_export(&ely_ui::commands::Export, window, cx))
|
|
})
|
|
.expect("the window");
|
|
asked(&cx, &book, |dialog| matches!(dialog, Dialog::Export { .. }));
|
|
update(&mut cx, &book, |book, cx| {
|
|
book.dialog = None;
|
|
cx.notify();
|
|
});
|
|
asked(&cx, &book, |dialog| matches!(dialog, Dialog::Import(pending) if pending.path.ends_with("wait.csv")));
|
|
cx.run_until_parked();
|
|
update(&mut cx, &book, |book, cx| book.import_asked(cx));
|
|
settle(&cx, |app| book.read(app).active_tab().is_some_and(|tab| tab.name == "wait.csv"));
|
|
// Text keeps `1E3`; the skipped column stays empty.
|
|
assert_eq!(cells(&mut cx, &book, "A2:B2").trim_end(), "1E3");
|
|
}
|
|
|
|
#[test]
|
|
fn closing_a_tab_takes_its_dialog_and_frees_the_import() {
|
|
let dir = tempfile::tempdir().expect("a temp dir");
|
|
let mut cx = TestAppContext::single();
|
|
let Some((window, book)) = book(&mut cx, dir.path()) else {
|
|
eprintln!("SKIP: no LOK build");
|
|
return;
|
|
};
|
|
blank(&mut cx, &book);
|
|
window
|
|
.update(&mut cx, |_, window, cx| {
|
|
book.update(cx, |book, cx| book.on_export(&ely_ui::commands::Export, window, cx))
|
|
})
|
|
.expect("the window");
|
|
asked(&cx, &book, |dialog| matches!(dialog, Dialog::Export { .. }));
|
|
let id = cx.update(|app| book.read(app).core.tabs[0].id);
|
|
update(&mut cx, &book, |book, cx| book.close_tab(id, cx));
|
|
let path = dir.path().join("after.csv");
|
|
std::fs::write(&path, "Name\nx\n").expect("writes");
|
|
update(&mut cx, &book, |book, cx| book.ask_import(path.clone(), cx));
|
|
asked(&cx, &book, |dialog| matches!(dialog, Dialog::Import(_)));
|
|
}
|
|
|
|
#[test]
|
|
fn a_whole_column_print_area_still_applies() {
|
|
let dir = tempfile::tempdir().expect("a temp dir");
|
|
let mut cx = TestAppContext::single();
|
|
let Some((_window, book)) = book(&mut cx, dir.path()) else {
|
|
eprintln!("SKIP: no LOK build");
|
|
return;
|
|
};
|
|
blank(&mut cx, &book);
|
|
update(&mut cx, &book, |book, cx| book.ask_page(cx));
|
|
asked(&cx, &book, |dialog| matches!(dialog, Dialog::Page { .. }));
|
|
type_in(&mut cx, &book, area, "A:D");
|
|
update(&mut cx, &book, |book, cx| book.page_asked(cx));
|
|
let layout = read(&mut cx, &book, sheet::print_layout, sheet::LAYOUT);
|
|
assert_eq!(layout.areas.len(), 1, "set: {:?}", layout.areas);
|
|
// The kernel's own text comes back into the dialog.
|
|
update(&mut cx, &book, |book, cx| book.ask_page(cx));
|
|
asked(&cx, &book, |dialog| matches!(dialog, Dialog::Page { .. }));
|
|
let shown = cx.update(|app| match book.read(app).dialog.as_ref() {
|
|
Some(dialog) => area(dialog).read(app).text().to_string(),
|
|
None => unreachable!("a page dialog"),
|
|
});
|
|
assert_eq!(shown, layout.areas[0]);
|
|
update(&mut cx, &book, |book, cx| {
|
|
if let Some(Dialog::Page { landscape, .. }) = &mut book.dialog {
|
|
*landscape = true;
|
|
}
|
|
book.page_asked(cx)
|
|
});
|
|
let layout = read(&mut cx, &book, sheet::print_layout, sheet::LAYOUT);
|
|
assert!(layout.landscape, "applied with {shown}");
|
|
}
|
|
|
|
#[test]
|
|
fn the_default_encoding_follows_the_apps_language() {
|
|
use ely_gpui_component::i18n::I18n;
|
|
use ely_lok::sheet::csv::Encoding;
|
|
let dir = tempfile::tempdir().expect("a temp dir");
|
|
let mut cx = TestAppContext::single();
|
|
let Some((_window, book)) = book(&mut cx, dir.path()) else {
|
|
eprintln!("SKIP: no LOK build");
|
|
return;
|
|
};
|
|
let path = dir.path().join("gb.csv");
|
|
// 你好 in GB18030: not UTF-8.
|
|
std::fs::write(&path, [0xC4, 0xE3, 0xBA, 0xC3, b'\n']).expect("writes");
|
|
for (tag, expected) in [("zh-CN", Encoding::Gb18030), ("en-US", Encoding::Windows1252)] {
|
|
cx.update(|app| I18n::set_locale(tag, app));
|
|
update(&mut cx, &book, |book, cx| book.ask_import(path.clone(), cx));
|
|
asked(&cx, &book, |dialog| matches!(dialog, Dialog::Import(_)));
|
|
let found = cx.update(|app| match book.read(app).dialog.as_ref() {
|
|
Some(Dialog::Import(pending)) => pending.how.encoding,
|
|
_ => unreachable!("an import dialog"),
|
|
});
|
|
assert_eq!(found, expected, "{tag}");
|
|
update(&mut cx, &book, |book, cx| {
|
|
book.dialog = None;
|
|
cx.notify();
|
|
});
|
|
}
|
|
}
|