图库: 书库点图改按文件名定位(修 P1 截断错位)+ 册间衔接根锁定(M18 评审 r1)
P1-1(会静默开错图):取消「书库从列表推导图片下标」。 - 新增 mr_reader_open_dir_at_name(dir, name):阅读器打开目录册后,在**自己刚枚举出的 全量目录册**(mr_dir_book,与翻页同一份枚举)里按 basename 定位起始页(先精确, 再大小写不敏感兜底;找不到退回续读/首页)。书库点击只传文件名。 - 删除 mr_library_image_index(不再有跨枚举的隐式契约)。 - 截断提示文案改为「仅显示前 2000 项(图片可在阅读器中翻到)」。 - 修复前(cb02722 探针,2100 张 4 位名夹具):rows=2000/truncated=1/ library_images=2000/reader_pages=2100/**mismatched=590**(首行 p1412 → 打开 p1411); 评审夹具为 1995/2000。修复后:2000 个可见图片行按名定位 **0 mismatch**, 2100 页全量可翻;26 次真实 UI 点开(首尾各 3 + 20 个确定性伪随机)逐张命中。 连带处理(评审 r1): 1. 删掉 reader_page_enter 的 c->view 死写(reopen 判定用 activity active/depth); 顺手删掉 library_page_create 里同款死写。 2. 阅读器册间衔接根锁定:新增 mr_path_within_root + mr_book_adjacent_rooted, book_switch 用浏览根(默认 MR_ROOT_DIR,测试可注入)钳制相邻册; 根外的兄弟册按「没有相邻册」处理。test_cont_adjacent A7 验证「明文 _ex 会越根、 rooted 拒绝、根内翻册不受影响」;test_mode_switch_host H6 验证条漫末页不越根。 3. test_reader_perf 不再依赖顶栏 tap 命中时序:模式切换改走测试钩子 mr_reader_test_toggle_mode()(与顶栏动作同一个 mode_set),负载下稳定。 4. page_cache 注释去掉「缩略图缓存/缩略图线程」过时描述(只改文字)。 回归:run_tests.sh(library 81 / nav 74 / lazy 57 / perf 25 / … / open_book 含 2100 用例) 与 run_webtoon_tests.sh(含 A7/H6)全 PASS;交叉构建零警告。
This commit is contained in:
1 parent
64336f95d9
commit
4befbfe14c
17 files changed
+523
-112
No files matched your search
@@ -1,12 +1,15 @@
|
||||
/* test_browse_lazy.c — 浏览行模型 / 零 IO 行合成 / 图片下标一致性(纯 C,无 SDK)。
|
||||
/* test_browse_lazy.c — 浏览行模型 / 零 IO 行合成 / 书库行与阅读器目录册同序(纯 C,无 SDK)。
|
||||
*
|
||||
* 文件名沿用历史(旧的「懒判定」已随 M18 文件管理器模型删除);本测试现在覆盖:
|
||||
* L1 行合成 O(1):mr_library_row_at 纯内存(IO 计数不变)、截断提示行;
|
||||
* L2 **书库→阅读器下标记号契约**:mr_library_image_index 数出的下标 == 阅读器目录册
|
||||
* (logic/reader/page_source.c: mr_dir_book_init)里同一张图的下标。
|
||||
* L2 **书库行与阅读器目录册同源**:书库图片行的名称序列 == 阅读器目录册
|
||||
* (logic/reader/page_source.c: mr_dir_book_init)的页名序列(同过滤器/同比较器)。
|
||||
* 点图现在由阅读器按文件名自己定位下标,书库不再推导下标;本用例守住「两边枚举一致」。
|
||||
* 夹具含大小写混排(A.jpg/a.jpg)、数字序号(img2/img10)、大写扩展名(IMG3.JPG)、
|
||||
* 前导零(page01/page1)、夹在图片之间的档案册与普通文件;
|
||||
* L3 扫描期副标题:每行都有内容(不再是占位「…」,渲染期不做格式化)。
|
||||
* L3 扫描期副标题:每行都有内容(不再是占位「…」,渲染期不做格式化);
|
||||
* L4 截断安全(评审 P1-1):2100 张图(默认 cap=2000)时,2000 个可见图片行按文件名
|
||||
* 都能定位到同一文件(0 mismatch),被截掉的图仍在阅读器页表里可翻到。
|
||||
*
|
||||
* 编译(在 tuku/ 下):
|
||||
* gcc -Wall -Wextra -O1 -I. -I../sdk -DMR_LIBRARY_TEST_HOOKS \
|
||||
@@ -137,8 +140,8 @@ static void test_rows_zero_io(const char *root)
|
||||
mr_library_free(&lib);
|
||||
}
|
||||
|
||||
/* ---- L2:书库图片下标 == 阅读器目录册下标 ---- */
|
||||
static void test_image_index_matches_reader(const char *dir)
|
||||
/* ---- L2:书库图片行名称序列 == 阅读器目录册页名序列 ---- */
|
||||
static void test_library_rows_match_reader(const char *dir)
|
||||
{
|
||||
mr_library lib;
|
||||
memset(&lib, 0, sizeof lib);
|
||||
@@ -149,25 +152,15 @@ static void test_image_index_matches_reader(const char *dir)
|
||||
int pages = mr_dir_book_init(&db, dir, 720, fake_load, fake_unload, NULL);
|
||||
CHECK(pages > 0, "reader dir book pages=%d", pages);
|
||||
|
||||
/* 书库里的图片行按出现顺序,其下标必须依次是 0..n-1(无空洞/无重排)。 */
|
||||
int expect = 0;
|
||||
for (int i = 0; i < lib.count; i++) {
|
||||
if (lib.items[i].kind != MR_LIB_KIND_IMAGE) continue;
|
||||
int idx = mr_library_image_index(&lib, i);
|
||||
CHECK(idx == expect, "image row %s index=%d (want %d)",
|
||||
lib.items[i].name, idx, expect);
|
||||
expect++;
|
||||
}
|
||||
CHECK(expect == pages, "library images=%d vs reader pages=%d", expect, pages);
|
||||
if (expect != pages) {
|
||||
mr_library_free(&lib);
|
||||
mr_dir_book_free(&db);
|
||||
return;
|
||||
}
|
||||
int images = 0;
|
||||
for (int i = 0; i < lib.count; i++)
|
||||
if (lib.items[i].kind == MR_LIB_KIND_IMAGE) images++;
|
||||
CHECK(images == pages, "library images=%d vs reader pages=%d", images, pages);
|
||||
|
||||
/* 逐张对齐:书库第 k 张图 == 阅读器目录册第 k 页(下标即起始页)。 */
|
||||
/* 逐张对齐:书库第 k 张图 == 阅读器目录册第 k 页(同过滤器/同自然序)。
|
||||
* 点图时阅读器按文件名重新定位下标,所以「名字集合 + 顺序」一致就是契约。 */
|
||||
int k = 0;
|
||||
for (int i = 0; i < lib.count; i++) {
|
||||
for (int i = 0; i < lib.count && k < pages; i++) {
|
||||
if (lib.items[i].kind != MR_LIB_KIND_IMAGE) continue;
|
||||
char page_path[MR_PATH_MAX];
|
||||
mr_dir_book_path(&db, k, page_path, (int)sizeof page_path);
|
||||
@@ -176,17 +169,90 @@ static void test_image_index_matches_reader(const char *dir)
|
||||
k++;
|
||||
}
|
||||
|
||||
/* 档案册/目录不占图片下标。 */
|
||||
/* 目录/档案册不是页:它们的名字不能出现在阅读器页名里。 */
|
||||
for (int i = 0; i < lib.count; i++) {
|
||||
if (lib.items[i].kind == MR_LIB_KIND_IMAGE) continue;
|
||||
CHECK(mr_library_image_index(&lib, i) == -1,
|
||||
"non-image %s has no image index", lib.items[i].name);
|
||||
int found = 0;
|
||||
for (int j = 0; j < pages; j++)
|
||||
if (db.names[j] && strcmp(db.names[j], lib.items[i].name) == 0) found = 1;
|
||||
CHECK(found == 0, "non-image %s is not a reader page", lib.items[i].name);
|
||||
}
|
||||
|
||||
mr_dir_book_free(&db);
|
||||
mr_library_free(&lib);
|
||||
}
|
||||
|
||||
/* ---- L4:2100 张图(默认 cap)——列表截断但按名定位 2000/2000 不错位 ---- */
|
||||
static void test_cap_name_lookup(const char *root)
|
||||
{
|
||||
char big[MR_PATH_MAX], p[MR_PATH_MAX];
|
||||
joinp(big, sizeof big, root, "big");
|
||||
CHECK(mkdir_p(big) == 0, "mkdir big");
|
||||
for (int i = 1; i <= 2100; i++) {
|
||||
snprintf(p, sizeof p, "%s/p%04d.jpg", big, i);
|
||||
if (touch_file(p) != 0) { CHECK(0, "big image %s", p); return; }
|
||||
}
|
||||
|
||||
mr_library lib;
|
||||
memset(&lib, 0, sizeof lib);
|
||||
int n = mr_library_scan(&lib, big, MR_LIB_MAX_DEPTH);
|
||||
CHECK(n == MR_LIB_SCAN_MAX, "big dir lists cap rows (%d)", n);
|
||||
CHECK(lib.truncated == 1 && lib.count == MR_LIB_SCAN_MAX, "big dir truncated at cap");
|
||||
|
||||
mr_dir_book db;
|
||||
memset(&db, 0, sizeof db);
|
||||
CHECK(mr_dir_book_init(&db, big, 720, fake_load, fake_unload, NULL) == 2100,
|
||||
"reader enumerates all 2100 pages");
|
||||
|
||||
/* 书库不再推导下标;点击传文件名。这里验证 2000 个可见图片行按名定位
|
||||
* 都能命中**同一个文件**(0 mismatch),被截掉的 100 张也仍在页表里。 */
|
||||
int checked = 0, mismatch = 0;
|
||||
for (int i = 0; i < lib.count; i++) {
|
||||
if (lib.items[i].kind != MR_LIB_KIND_IMAGE) continue;
|
||||
checked++;
|
||||
int idx = -1;
|
||||
for (int j = 0; j < db.count; j++)
|
||||
if (db.names[j] && strcmp(db.names[j], lib.items[i].name) == 0) { idx = j; break; }
|
||||
char page[MR_PATH_MAX];
|
||||
mr_dir_book_path(&db, idx, page, (int)sizeof page);
|
||||
if (idx < 0 || strcmp(page, lib.items[i].path) != 0) mismatch++;
|
||||
}
|
||||
CHECK(checked == MR_LIB_SCAN_MAX, "checked %d library image rows", checked);
|
||||
CHECK(mismatch == 0, "name lookup mismatch=%d (want 0)", mismatch);
|
||||
|
||||
/* 被截掉的图(列表外的那 100 张)在阅读器页表里仍存在(可翻到)。
|
||||
* 截断发生在 readdir 顺序(非自然序),不假定是哪 100 张,按集合差验证。 */
|
||||
int missing = 0, missing_idx = -1;
|
||||
char missing_name[MR_NAME_MAX] = "";
|
||||
for (int j = 0; j < db.count; j++) {
|
||||
int in_list = 0;
|
||||
for (int i = 0; i < lib.count; i++)
|
||||
if (strcmp(lib.items[i].name, db.names[j]) == 0) { in_list = 1; break; }
|
||||
if (!in_list) {
|
||||
if (missing == 0) {
|
||||
missing_idx = j;
|
||||
snprintf(missing_name, sizeof missing_name, "%s", db.names[j]);
|
||||
}
|
||||
missing++;
|
||||
}
|
||||
}
|
||||
CHECK(missing == 2100 - MR_LIB_SCAN_MAX, "truncated-out images=%d (want 100)", missing);
|
||||
char want_path[MR_PATH_MAX], page[MR_PATH_MAX];
|
||||
snprintf(want_path, sizeof want_path, "%s/%s", big, missing_name);
|
||||
mr_dir_book_path(&db, missing_idx, page, (int)sizeof page);
|
||||
CHECK(missing_idx >= 0 && strcmp(page, want_path) == 0,
|
||||
"truncated-out %s is still reader page %d", missing_name, missing_idx);
|
||||
|
||||
mr_library_row row;
|
||||
CHECK(mr_library_row_at(&lib, lib.count, &row) == 1 && row.disabled == 1 &&
|
||||
strstr(row.subtitle, "2000") && strstr(row.subtitle, "阅读器"),
|
||||
"truncation row keeps images discoverable: %s",
|
||||
row.subtitle ? row.subtitle : "");
|
||||
|
||||
mr_dir_book_free(&db);
|
||||
mr_library_free(&lib);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char tmpl[] = "./mr_rows_XXXXXX";
|
||||
@@ -219,7 +285,8 @@ int main(void)
|
||||
|
||||
test_rows_zero_io(root);
|
||||
joinp(p, sizeof p, root, "mixed");
|
||||
test_image_index_matches_reader(p);
|
||||
test_library_rows_match_reader(p);
|
||||
test_cap_name_lookup(root);
|
||||
|
||||
rm_rf(root);
|
||||
printf("%s: %d passed, %d failed\n", g_fail ? "FAIL" : "PASS", g_pass, g_fail);
|
||||
|
||||
Reference in new issue
Block a user