//! 设置页「更新」分组(M159)的断言:注册表位置、四条状态各有各的句子。 //! //! 为什么只测「词表 + 判据」而不测控件:iced 的 `Element` 没有内省接口(`tests/mod.rs` 顶部那条 //! 写过理由),上屏文本只能从**取词的那一个入口**取。这里守的是「四种结论的句子不是同一句」 //! ——正是 mission 里「检查失败不等于已是最新」那条硬要求的最小可测形态。 use unlucky_i18n::{Catalog, Key, Lang}; use super::super::update::{GROUP as UPDATE_GROUP_META, UPDATE_GROUP}; use super::super::{GROUPS, SELECTED}; use crate::pages::update::UpdateStatus; use crate::pages::{Screen, Update}; /// 更新组**必须是最后一组**:加组只追加不重排,插到中间会让 `APPEARANCE_GROUP` / `GENERAL_GROUP` /// 两个下标一起失效。 #[test] fn the_update_group_sits_at_the_end_of_the_registry() { assert_eq!(GROUPS.len(), UPDATE_GROUP + 1, "更新组之后不该还有别的组"); assert_eq!(GROUPS[UPDATE_GROUP].name, UPDATE_GROUP_META.name); assert_eq!(GROUPS[UPDATE_GROUP].name, "Updates"); assert!(SELECTED < GROUPS.len()); } /// 四种结论的句子**互不相同**,且「失败」那一句必须把原因带出来。 /// /// 抓得住:把「检查失败」写成「已是最新」(那是 mission 明令禁止的撒谎:断网时会说「你是最新」)。 /// 抓不住:句子翻得顺不顺、颜色对不对(那是人读与截图的事)。 #[test] fn the_four_outcomes_read_differently() { let catalog = Lang::ZhCn.catalog(); let up_to_date = catalog.render(Key::SettingsUpdateUpToDate, &[("version", "0.2.2")]); let available = catalog.render( Key::SettingsUpdateAvailable, &[("version", "0.2.3"), ("size", "21.0 MB")], ); let missing = catalog.render(Key::SettingsUpdateMissingArtifact, &[("version", "0.2.3")]); let failed = catalog.render( Key::SettingsUpdateFailed, &[("reason", "取更新清单失败:连接被重置")], ); let all = [&up_to_date, &available, &missing, &failed]; for (index, left) in all.iter().enumerate() { for right in all.iter().skip(index + 1) { assert_ne!(left, right, "两条结论说的是同一句话:{left} / {right}"); } } assert!( failed.contains("连接被重置"), "失败那一句必须带出原因,实际:{failed}" ); assert!( !failed.contains("0.2.2"), "失败那一句不该冒出当前版本号(读起来像「已是最新」):{failed}" ); } /// 页面视图模型与 presenter 的判据同序:就位 > 进行中 > 失败(仅主动查) > 有新版本。 /// /// 两处各算一次(presenter 判据 + 页面视图),顺序必须一致,否则同一份状态在提示条与设置页上 /// 会各说一套。这里只钉页面这一侧的顺序;presenter 那一侧在 `presenter` 的 `dto::update` 单测里。 #[test] fn the_banner_priority_is_ready_then_applying_then_failure_then_available() { let mut update = Update { current_version: "0.2.2".to_string(), channel: "stable".to_string(), auto_check: true, status: UpdateStatus::Failed { reason: "连不上".to_string(), retryable: true, }, checked_at: String::new(), applying: true, ready: None, dismissed: false, silent: false, }; assert!(matches!( update.banner(), Some(crate::pages::Banner::Applying) )); update.applying = false; assert!(matches!( update.banner(), Some(crate::pages::Banner::Failed { .. }) )); update.status = UpdateStatus::Available { version: "0.2.3".to_string(), size: 1024, notes: String::new(), forced: false, }; assert!(matches!( update.banner(), Some(crate::pages::Banner::Available { .. }) )); update.ready = Some("0.2.3".to_string()); assert!(matches!( update.banner(), Some(crate::pages::Banner::Ready { .. }) )); } /// 演示模型里更新组能画(`pages_demo` 的 harness 路径):`Model.update` 有默认值,不是 `None` 才画。 #[test] fn the_demo_model_carries_an_update_snapshot() { let model = crate::pages::demo_model(Screen::Settings, 1180.0); assert_eq!(model.update, crate::pages::update::demo()); assert!( model.update.available().is_some(), "演示快照要带一个可装的版本" ); // 其它页不掺演示更新状态(实例页/下载页的基线图不该多出一条提示条)。 assert_eq!( crate::pages::demo_model(Screen::Instances, 1180.0).update, Update::default() ); let catalog: Catalog = Lang::En.catalog(); assert!(!catalog.text(Key::SettingsGroupUpdate).is_empty()); }