Unlucky Launcher v0.2.0
CI / runtime smoke (macos arm64, probe) (push) Skipped
CI / fmt (rustfmt --check) (push) Canceled after 0s
CI / clippy (ubuntu-latest) (push) Canceled after 0s
CI / clippy (windows-latest) (push) Canceled after 0s
CI / test (ubuntu-latest) (push) Canceled after 0s
CI / test (windows-latest) (push) Canceled after 0s
CI / build release (ubuntu-latest) (push) Canceled after 0s
CI / build release (windows-latest) (push) Canceled after 0s
CI / runtime smoke (ubuntu x64, xvfb) (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
CI / runtime smoke (macos arm64, probe) (push) Skipped
CI / fmt (rustfmt --check) (push) Canceled after 0s
CI / clippy (ubuntu-latest) (push) Canceled after 0s
CI / clippy (windows-latest) (push) Canceled after 0s
CI / test (ubuntu-latest) (push) Canceled after 0s
CI / test (windows-latest) (push) Canceled after 0s
CI / build release (ubuntu-latest) (push) Canceled after 0s
CI / build release (windows-latest) (push) Canceled after 0s
CI / runtime smoke (ubuntu x64, xvfb) (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
首个 iced + Material 3 Expressive 版本的源码快照。 完整历史与日常提交在 dev 分支;main 只放阶段性快照。
This commit is contained in:
commit
8a8e5ca0c0
1079 files changed
+208035
No files matched your search
@@ -0,0 +1,130 @@
|
||||
//! 内容库状态机的守门测试(M109;复审 P1-2 的补课)。
|
||||
//!
|
||||
//! 从 `state.rs` 拆出(那个文件贴 400 行硬上限)。钉的是**翻页判据**:
|
||||
//! `has_more` 必须读「最近一页是否装满」,不能读累计条数——否则第 2 页之后恒真。
|
||||
|
||||
use crate::dto::{
|
||||
AppEvent, ContentHit, ContentKind, ContentQuery, ContentResults, ContentSource, CoreEvent,
|
||||
};
|
||||
|
||||
use super::AppState;
|
||||
|
||||
fn hit(index: usize) -> ContentHit {
|
||||
ContentHit {
|
||||
id: format!("p{index}"),
|
||||
slug: format!("p{index}"),
|
||||
title: format!("Project {index}"),
|
||||
summary: "s".to_string(),
|
||||
author: "a".to_string(),
|
||||
downloads: 0,
|
||||
updated: "2026-01-01".to_string(),
|
||||
source: ContentSource::Modrinth,
|
||||
game_versions: vec!["1.20.1".to_string()],
|
||||
loaders: vec!["fabric".to_string()],
|
||||
icon: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// 造一页结果:`offset` 是游标,`count` 是这一页实际回来几条。
|
||||
fn page(offset: u32, count: u32) -> ContentResults {
|
||||
let mut query = ContentQuery::first(ContentKind::Mod);
|
||||
query.offset = offset;
|
||||
ContentResults {
|
||||
query,
|
||||
hits: (0..count)
|
||||
.map(|index| hit(offset as usize + index as usize))
|
||||
.collect(),
|
||||
total: 999,
|
||||
curseforge: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn apply(state: &mut AppState, results: ContentResults) {
|
||||
state.apply(AppEvent::Core(CoreEvent::ContentResults(Box::new(results))));
|
||||
}
|
||||
|
||||
/// 复审 P1-2 的第一条:装满一页 ⇒ 还有更多;下一(末)页不满 ⇒ 没有了。
|
||||
#[test]
|
||||
fn a_short_last_page_clears_has_more() {
|
||||
let mut state = AppState::new();
|
||||
let limit = ContentQuery::first(ContentKind::Mod).limit;
|
||||
|
||||
apply(&mut state, page(0, limit));
|
||||
assert!(state.content.last_page_filled, "首页装满 ⇒ 还有下一页");
|
||||
assert_eq!(
|
||||
state.content.results.as_ref().map_or(0, |r| r.hits.len()),
|
||||
limit as usize
|
||||
);
|
||||
|
||||
// 末页只回来 3 条:累计 23 条「够一页了」,但**这一页**没装满 ⇒ 没有更多
|
||||
apply(&mut state, page(limit, 3));
|
||||
assert!(
|
||||
!state.content.last_page_filled,
|
||||
"末页不满 ⇒ 不许说还有更多(判据不能读累计条数)"
|
||||
);
|
||||
assert_eq!(
|
||||
state.content.results.as_ref().map_or(0, |r| r.hits.len()),
|
||||
limit as usize + 3,
|
||||
"命中项仍然要累加"
|
||||
);
|
||||
}
|
||||
|
||||
/// 复审 P1-2 的第二条:再点一次,回来的空页仍然是「没有更多」。
|
||||
#[test]
|
||||
fn an_empty_last_page_keeps_has_more_false() {
|
||||
let mut state = AppState::new();
|
||||
let limit = ContentQuery::first(ContentKind::Mod).limit;
|
||||
|
||||
apply(&mut state, page(0, limit));
|
||||
apply(&mut state, page(limit, 0));
|
||||
assert!(!state.content.last_page_filled, "空页 ⇒ 没有更多");
|
||||
|
||||
// 用户又点了一次「加载更多」:空页不会把状态翻回真
|
||||
apply(&mut state, page(limit + limit, 0));
|
||||
assert!(
|
||||
!state.content.last_page_filled,
|
||||
"再点一次空页 ⇒ 仍然没有更多"
|
||||
);
|
||||
assert_eq!(
|
||||
state.content.results.as_ref().map_or(0, |r| r.hits.len()),
|
||||
limit as usize,
|
||||
"空页不改变列表内容"
|
||||
);
|
||||
}
|
||||
|
||||
/// 换条件(offset 回到 0)时把「最近一页装满」清掉:不然新条件的第一帧就会画「没有更多了」。
|
||||
#[test]
|
||||
fn changing_the_query_resets_the_page_flag() {
|
||||
let mut state = AppState::new();
|
||||
let limit = ContentQuery::first(ContentKind::Mod).limit;
|
||||
|
||||
apply(&mut state, page(0, limit));
|
||||
assert!(state.content.last_page_filled);
|
||||
|
||||
let mut query = ContentQuery::first(ContentKind::Mod);
|
||||
query.text = "sodium".to_string();
|
||||
state.set_content_query(query);
|
||||
assert!(!state.content.last_page_filled, "换条件 ⇒ 清掉上一批的判据");
|
||||
assert!(state.content.pending);
|
||||
assert!(
|
||||
state.content.results.is_none(),
|
||||
"换条件要清列表(不然加载态画旧命中项)"
|
||||
);
|
||||
}
|
||||
|
||||
/// 迟到的一批不许改写判据(用户已经换了条件)。
|
||||
#[test]
|
||||
fn a_stale_batch_does_not_touch_the_page_flag() {
|
||||
let mut state = AppState::new();
|
||||
let limit = ContentQuery::first(ContentKind::Mod).limit;
|
||||
|
||||
apply(&mut state, page(0, limit));
|
||||
let mut query = ContentQuery::first(ContentKind::Mod);
|
||||
query.text = "sodium".to_string();
|
||||
state.set_content_query(query);
|
||||
|
||||
// 旧条件的一页这时才回来:既不改结果,也不改「还有更多」
|
||||
apply(&mut state, page(limit, 5));
|
||||
assert!(!state.content.last_page_filled);
|
||||
assert!(state.content.results.is_none(), "迟到的一批被丢掉");
|
||||
}
|
||||
Reference in new issue
Block a user