mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-28 03:58:45 -06:00
test(ui): CJK interface tests skip without craft-fonts (#4706)
* test(ui): CJK interface tests skip without craft-fonts * test(ui): a build that requires craft-fonts never skips the CJK interface tests
This commit is contained in:
@@ -530,6 +530,10 @@ fn combine_follows_the_order_shown_in_the_grid() {
|
||||
|
||||
#[test]
|
||||
fn long_and_unusual_names_are_shortened_on_the_card_but_kept_whole() {
|
||||
if crate::support::skip_without_glyphs("long_and_unusual_names_are_shortened_on_the_card_but_kept_whole", "en", "日本語のファイル名.pdf")
|
||||
{
|
||||
return;
|
||||
}
|
||||
let long = "Überweisungsbestätigung für das dritte Quartal 2026 – Endfassung (unterschrieben).pdf";
|
||||
let mut h = grid_of(vec![(long, fixture(1)), ("日本語のファイル名.pdf", fixture(1)), ("a&b <c> 'd'.pdf", fixture(1))], vec2(1400.0, 900.0));
|
||||
// The card's label is the whole name; only the drawing is shortened.
|
||||
|
||||
@@ -623,6 +623,9 @@ fn palette_ime_idle_frames_and_reopen_do_not_interrupt_composition() {
|
||||
|
||||
#[test]
|
||||
fn palette_ime_chinese_preedit_commit_and_cancel_remain_uninterrupted() {
|
||||
if crate::support::skip_without_glyphs("palette_ime_chinese_preedit_commit_and_cancel_remain_uninterrupted", "en", "你") {
|
||||
return;
|
||||
}
|
||||
let mut h = harness();
|
||||
let mut interruptions = Vec::new();
|
||||
h.state_mut().run_command("view.palette");
|
||||
|
||||
@@ -335,6 +335,9 @@ fn a_picture_on_the_clipboard_is_pasted_onto_the_page() {
|
||||
/// written to the page as `?` (or lost).
|
||||
#[test]
|
||||
fn text_the_standard_fonts_cant_draw_stays_in_the_editor() {
|
||||
if crate::support::skip_without_glyphs("text_the_standard_fonts_cant_draw_stays_in_the_editor", "en", "Hello 世界") {
|
||||
return;
|
||||
}
|
||||
let _gpu = gpu();
|
||||
let mut h = harness();
|
||||
assert!(h.state_mut().execute("edit.text"));
|
||||
@@ -372,6 +375,9 @@ fn text_the_standard_fonts_cant_draw_stays_in_the_editor() {
|
||||
/// is left blocking Save out of sight.
|
||||
#[test]
|
||||
fn a_kept_draft_goes_with_its_deleted_page() {
|
||||
if crate::support::skip_without_glyphs("a_kept_draft_goes_with_its_deleted_page", "en", "日本語") {
|
||||
return;
|
||||
}
|
||||
let mut h = harness();
|
||||
assert!(h.state_mut().apply_edit(pdfcraft_engine::Edit::InsertBlankPage { at: 1, width: 612.0, height: 792.0 }));
|
||||
h.run_steps(2);
|
||||
|
||||
@@ -504,6 +504,9 @@ fn language_switch_preserves_document_and_command_ids() {
|
||||
assert_eq!(documents[0]["dirty"], true);
|
||||
let commands = ok(&mut h, &c, "ui.commands", json!({}));
|
||||
for code in ["ja", "zh-hans", "fr", "de", "uk", "lt", "en"] {
|
||||
if crate::support::skip_without_glyphs(&format!("language_switch_preserves_document_and_command_ids ({code})"), code, "") {
|
||||
continue;
|
||||
}
|
||||
ok(&mut h, &c, "ui.set", json!({ "key": "language", "value": code }));
|
||||
h.run_steps(2);
|
||||
let state = ok(&mut h, &c, "ui.state", json!({}));
|
||||
@@ -908,6 +911,9 @@ fn state_and_view_options() {
|
||||
|
||||
#[test]
|
||||
fn japanese_controls_and_search_keep_command_ids() {
|
||||
if crate::support::skip_without_glyphs("japanese_controls_and_search_keep_command_ids", "ja", "") {
|
||||
return;
|
||||
}
|
||||
let (mut h, c) = harness();
|
||||
ok(&mut h, &c, "ui.set", json!({ "key": "language", "value": "ja" }));
|
||||
assert_eq!(ok(&mut h, &c, "ui.state", json!({}))["language"], "ja");
|
||||
@@ -1002,6 +1008,9 @@ fn ukrainian_preferences_and_search_keep_command_ids() {
|
||||
|
||||
#[test]
|
||||
fn preferences_menu_and_shortcut_allow_switching_interface_languages() {
|
||||
if crate::support::skip_without_glyphs("preferences_menu_and_shortcut_allow_switching_interface_languages", "ja", "") {
|
||||
return;
|
||||
}
|
||||
let (mut h, c) = harness();
|
||||
ok(&mut h, &c, "ui.set", json!({ "key": "language", "value": "ja" }));
|
||||
ok(&mut h, &c, "ui.click", json!({ "label": "メニュー" }));
|
||||
@@ -1044,6 +1053,9 @@ fn preferences_menu_and_shortcut_allow_switching_interface_languages() {
|
||||
|
||||
#[test]
|
||||
fn japanese_dialogs_errors_and_custom_action_names() {
|
||||
if crate::support::skip_without_glyphs("japanese_dialogs_errors_and_custom_action_names", "ja", "") {
|
||||
return;
|
||||
}
|
||||
let (mut h, c) = harness();
|
||||
ok(&mut h, &c, "ui.set", json!({"key": "language", "value": "ja"}));
|
||||
for (dialog, label) in [
|
||||
@@ -1084,6 +1096,9 @@ fn japanese_dialogs_errors_and_custom_action_names() {
|
||||
|
||||
#[test]
|
||||
fn simplified_chinese_about_tabs_and_credit_controls() {
|
||||
if crate::support::skip_without_glyphs("simplified_chinese_about_tabs_and_credit_controls", "zh-hans", "") {
|
||||
return;
|
||||
}
|
||||
let (mut h, c) = harness();
|
||||
let documents = ok(&mut h, &c, "ui.state", json!({}))["documents"].clone();
|
||||
ok(&mut h, &c, "ui.set", json!({"key": "language", "value": "zh-hans"}));
|
||||
@@ -1113,6 +1128,9 @@ fn simplified_chinese_about_tabs_and_credit_controls() {
|
||||
|
||||
#[test]
|
||||
fn simplified_chinese_signature_prompts_and_errors_keep_document_state() {
|
||||
if crate::support::skip_without_glyphs("simplified_chinese_signature_prompts_and_errors_keep_document_state", "zh-hans", "") {
|
||||
return;
|
||||
}
|
||||
let (mut h, c) = harness();
|
||||
let documents = ok(&mut h, &c, "ui.state", json!({}))["documents"].clone();
|
||||
ok(&mut h, &c, "ui.set", json!({"key": "language", "value": "zh-hans"}));
|
||||
@@ -1721,6 +1739,9 @@ fn control_quit_retains_inactive_fill_sign_typing_after_cancel() {
|
||||
|
||||
#[test]
|
||||
fn control_quit_retains_blocked_content_typing_after_cancel() {
|
||||
if crate::support::skip_without_glyphs("control_quit_retains_blocked_content_typing_after_cancel", "en", "Keep 世界") {
|
||||
return;
|
||||
}
|
||||
let (mut h, c) = harness();
|
||||
ok(&mut h, &c, "ui.command", json!({"id":"edit.text"}));
|
||||
h.run_steps(3);
|
||||
|
||||
@@ -133,6 +133,13 @@ fn month_names_follow_the_date_language_or_else_the_interface_language() {
|
||||
|
||||
#[test]
|
||||
fn a_date_the_pdf_cannot_hold_is_refused_with_a_warning_first() {
|
||||
if crate::support::skip_without_glyphs(
|
||||
"a_date_the_pdf_cannot_hold_is_refused_with_a_warning_first",
|
||||
"en",
|
||||
"日曜日月曜日火曜日水曜日木曜日金曜日土曜日",
|
||||
) {
|
||||
return;
|
||||
}
|
||||
let mut h = Harness::builder().with_size(egui::vec2(1400.0, 900.0)).build_eframe(|_cc| {
|
||||
let mut app = PdfCraftApp::new();
|
||||
app.set_option("language", "en").unwrap();
|
||||
|
||||
@@ -1087,6 +1087,9 @@ fn save_prompt_fits_the_smallest_window_whatever_the_name() {
|
||||
let size = egui::vec2(820.0, 520.0);
|
||||
for name in names {
|
||||
let start: String = name.chars().take(10).collect();
|
||||
if support::skip_without_glyphs(&format!("save_prompt_fits_the_smallest_window_whatever_the_name ({start}…)"), "en", &name) {
|
||||
continue;
|
||||
}
|
||||
let mut h = Harness::builder().with_size(size).build_eframe(move |_cc| {
|
||||
let mut app = PdfCraftApp::new();
|
||||
app.set_option("language", "en").unwrap();
|
||||
@@ -3575,6 +3578,9 @@ fn an_applied_paragraph_keeps_its_edited_look_until_the_page_is_redrawn() {
|
||||
/// as a form field does; the editor used to close with the error and the typing was lost.
|
||||
#[test]
|
||||
fn a_paragraph_whose_edit_fails_stays_open_with_its_typing() {
|
||||
if crate::support::skip_without_glyphs("a_paragraph_whose_edit_fails_stays_open_with_its_typing", "en", "Top ก") {
|
||||
return;
|
||||
}
|
||||
let bytes = source_font_fixture_with_text("BT /F1 24 Tf 20 220 Td (Top) Tj ET BT /F2 24 Tf 20 120 Td (Bottom) Tj ET");
|
||||
let mut h = Harness::builder().with_size(egui::vec2(1400.0, 900.0)).build_eframe(move |_cc| {
|
||||
let mut app = PdfCraftApp::new();
|
||||
|
||||
@@ -963,6 +963,9 @@ impl Drop for AttachmentDir {
|
||||
|
||||
#[test]
|
||||
fn attachment_save_preserves_bytes_metadata_and_selected_destination() {
|
||||
if crate::support::skip_without_glyphs("attachment_save_preserves_bytes_metadata_and_selected_destination", "en", "user chosen 資料.bin") {
|
||||
return;
|
||||
}
|
||||
let dir = AttachmentDir::new();
|
||||
let chosen = dir.0.join("user chosen 資料.bin");
|
||||
let original = attachment_fixture();
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
//! State-based waits for native preparation, which completes between UI frames, and pointer
|
||||
//! input in the frames the platform delivers it in ([`input`]).
|
||||
//! input in the frames the platform delivers it in ([`input`]), and the skip for tests whose text
|
||||
//! the interface fonts cannot draw ([`skip_without_glyphs`]).
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use egui::FontId;
|
||||
use egui::epaint::text::{Fonts, TextOptions};
|
||||
use egui_kittest::Harness;
|
||||
use pdfcraft_ui_egui::PdfCraftApp;
|
||||
use pdfcraft_ui_egui::{PdfCraftApp, i18n, theme};
|
||||
|
||||
pub mod input;
|
||||
|
||||
@@ -45,3 +50,35 @@ pub fn wait_until(h: &mut Harness<'static, PdfCraftApp>, what: &str, ready: impl
|
||||
h.state().toast
|
||||
);
|
||||
}
|
||||
|
||||
/// Whether the test `name` must skip because the interface fonts lack a glyph for a character it
|
||||
/// draws: one in `text` or in the catalog of the interface `language`. egui 0.37 test harnesses
|
||||
/// panic on a missing glyph, and Japanese, Chinese and Thai faces come only from the optional
|
||||
/// craft-fonts build input or a face installed on this machine. Prints the skip line.
|
||||
///
|
||||
/// The fonts are those the app installs for `language` and for the default CJK preference: a
|
||||
/// switch to Chinese installs its fonts for the next frame, so the first frame in Chinese draws
|
||||
/// with the fonts of the language before it.
|
||||
///
|
||||
/// A build that requires craft-fonts (`CRAFT_FONTS_REQUIRED=1`, as the CI gate sets) never skips:
|
||||
/// a missing glyph there is a failure.
|
||||
pub fn skip_without_glyphs(name: &str, language: &str, text: &str) -> bool {
|
||||
if std::env::var("CRAFT_FONTS_REQUIRED").as_deref() == Ok("1") {
|
||||
return false;
|
||||
}
|
||||
let catalog = i18n::LANGUAGES.iter().find(|l| l.code == language).map_or("", |l| l.source);
|
||||
let translations = catalog.lines().filter(|l| !l.starts_with('#')).filter_map(|l| l.split('\t').nth(2));
|
||||
let chars: BTreeSet<char> = std::iter::once(text).chain(translations).flat_map(str::chars).filter(|c| !c.is_control()).collect();
|
||||
let cjk = theme::CjkPreference::for_language(language);
|
||||
let missing = [theme::CjkPreference::Default, cjk].into_iter().find_map(|cjk| {
|
||||
let defs = theme::installed_font_definitions(cjk);
|
||||
let families: Vec<FontId> = defs.families.keys().map(|f| FontId::new(13.0, f.clone())).collect();
|
||||
let mut fonts = Fonts::new(TextOptions::default(), defs);
|
||||
chars.iter().copied().find(|c| families.iter().any(|id| !fonts.has_glyphs(id, &c.to_string())))
|
||||
});
|
||||
let Some(missing) = missing else {
|
||||
return false;
|
||||
};
|
||||
eprintln!("skipping {name}: no interface font draws {missing:?} (set CRAFT_FONTS_DIR to a craft-fonts checkout with a face for it)");
|
||||
true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user