`pages/content.rs::section_switcher` 把 `on_content` 写死成 `true`,而下载页也调它, 于是版本管理页的页头把「内容库」画成选中、「版本管理」画成未选中。 改成由调用方给位置:下载页传 false、内容库页自己传 true;并加一条源码层面的调用点断言 (iced 的 Element 不可内省,判据只有一行,写错必红)。 不是 M229 引入的缺陷(M109 就有),按复审要求单独提交,不与收官换肤混在一起。
120 lines
4.3 KiB
Rust
120 lines
4.3 KiB
Rust
//! 内容库页的守门(M109):演示数据、四类内容、页面自留状态的默认值。
|
|
//!
|
|
//! 视图模型的判定在 `model/tests.rs`,栏几何在 `layout.rs`,这里只管「演示数据真的装得满」——
|
|
//! 出图靠它,装不满就说明 `demo()` 与 `Content` 的字段对不上。
|
|
|
|
use unlucky_i18n::Lang;
|
|
use unlucky_presenter::dto::ContentKind;
|
|
|
|
use super::model::{PageState, Status};
|
|
use super::{demo, Content};
|
|
|
|
#[test]
|
|
fn the_page_state_starts_on_mods_with_nothing_selected() {
|
|
let page = PageState::default();
|
|
assert_eq!(page.kind, ContentKind::Mod);
|
|
assert!(page.selected.is_none());
|
|
assert!(page.target.is_none());
|
|
assert!(page.draft.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn every_kind_gets_a_full_demo_screen() {
|
|
// 四种内容各出一屏(状态矩阵的前 8 张靠这一条)
|
|
for kind in ContentKind::ALL {
|
|
let model: Content = demo(kind, Lang::En);
|
|
assert_eq!(model.kind, kind, "{} 的演示数据换了类型", kind.slug());
|
|
assert_eq!(model.status, Status::Ready, "{}", kind.slug());
|
|
assert_eq!(model.hits.len(), 4, "{} 的命中项不足", kind.slug());
|
|
assert!(
|
|
model.selected.is_some(),
|
|
"演示数据要选中一条(详情面板才有内容)"
|
|
);
|
|
assert!(model.total > 0);
|
|
assert!(model.has_more, "演示数据要能画「加载更多」");
|
|
// 整合包**不**在这一条里断(它天生不可装:`ContentKind::Modpack.dir()` 是 `None`),
|
|
// 由下一条用例专钉。
|
|
if kind != ContentKind::Modpack {
|
|
assert!(
|
|
model.can_install(),
|
|
"默认那一屏应当是「能装」的({})",
|
|
kind.slug()
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn the_modpack_screen_is_browsable_but_never_installable() {
|
|
// 整合包:检索能看,装入一律禁用(M111 未落地)——演示图上必须看得到原因
|
|
let model = demo(ContentKind::Modpack, Lang::En);
|
|
assert!(model.selected.is_some());
|
|
assert!(!model.can_install());
|
|
assert_eq!(
|
|
model.blocker_reasons(Lang::En.catalog()).len(),
|
|
1,
|
|
"整合包只有一条原因(导入管线未落地)"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn the_installable_kinds_block_only_when_the_target_disagrees() {
|
|
for kind in [
|
|
ContentKind::Mod,
|
|
ContentKind::Resourcepack,
|
|
ContentKind::Shader,
|
|
] {
|
|
let model = demo(kind, Lang::En);
|
|
assert!(
|
|
model.blocker_reasons(Lang::En.catalog()).is_empty(),
|
|
"{} 的默认演示项应当可装",
|
|
kind.slug()
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn the_demo_selection_is_always_one_of_the_hits() {
|
|
for kind in ContentKind::ALL {
|
|
let model = demo(kind, Lang::En);
|
|
let selected = model.selected.clone().expect("有选中项");
|
|
assert!(
|
|
model.hits.iter().any(|hit| hit.id == selected),
|
|
"{} 的选中项不在命中列表里(详情面板会是空的)",
|
|
kind.slug()
|
|
);
|
|
}
|
|
}
|
|
|
|
/// M191:「全部成功」那一屏(默认态)**没有**重试面板——出图与判据同源,不是手搓的。
|
|
#[test]
|
|
fn the_default_demo_screen_has_no_retry_surface() {
|
|
for kind in ContentKind::ALL {
|
|
let model = demo(kind, Lang::En);
|
|
assert!(
|
|
model.retry.is_none(),
|
|
"{} 默认态不该有重试面板",
|
|
kind.slug()
|
|
);
|
|
}
|
|
}
|
|
|
|
/// M229 复审 F3 的回归门:页头一级切换的选中态由**调用方所在页**决定,不是写死「内容库」。
|
|
///
|
|
/// 抓得住:`download.rs` 又传回 `true`(下载页页头的「内容库」被画成选中,正是 F3 的现场)。
|
|
/// 抓不住:像素长什么样(那要截图);iced 的 `Element` 不可内省,所以这条从源码层面钉住调用点——
|
|
/// 判据只有一行,读的人也不会误解。
|
|
#[test]
|
|
fn the_download_header_marks_versions_selected_not_content() {
|
|
let download = include_str!("../download.rs");
|
|
assert!(
|
|
download.contains("section_switcher(ui, catalog, false)"),
|
|
"下载页是「版本管理」那一侧,必须传 false(传 true = F3 复发)"
|
|
);
|
|
let content_view = include_str!("view.rs");
|
|
assert!(
|
|
content_view.contains("section_switcher(ui, catalog, true)"),
|
|
"内容库页自己那一份必须传 true"
|
|
);
|
|
}
|