fix(reader): M27 r3 评审整改 — cap 边界截断/默认副题不变/提示两行且 6s 消失/版本号
对应评审 P2-1、P3-7、P3-1、P3-2、P3-10、P3-9: - P2-1:scan_dir 在目录边界遇 cap 时探测子树(count_books_under)再置 truncated; 同目录内超限逻辑不变。新增两条断言:cap 卡边界 → truncated=1;恰好装满且后续为空目录 → 不误报 - P3-7:shelf_book 拆 sub(默认副题,与 base 逐字一致)/sub_folder(folder 模式前置子路径); list 按模式选,宫格始终用 base;断言 format 副题逐字等于 base - P3-1:超量+超深合并提示拆两行绘制(610 起,不再被 480px 右缘切掉) - P3-2:提示 6s 到期自动消失(app.c 书架前台时调 shelf_on_tick) - P3-10:app.json version 0.1.1 / version_code 2 - P3-9:shelf_scan_bench.c 头部注明 /proc/uptime 10ms 分辨率、只适合真机
This commit is contained in:
1 parent
63ead3ec1e
commit
e0a82a3d47
8 files changed
+129
-44
No files matched your search
@@ -8,7 +8,8 @@
|
||||
* G4 空目录不产生段头;depth 3/4 收录,depth > SHELF_SCAN_MAX_DEPTH 计数且不出书
|
||||
* G5 Books/ 根下的书归「未分类」;字面名为「未分类」的目录与根组是两个不同键
|
||||
* G6 UTF-8 安全截断(中文目录名不切出半个字符)
|
||||
* G7 超上限不静默:truncated=1;行数上限(段头 ≤ 书数 ⇒ 2N 必够)
|
||||
* G7 超上限不静默:truncated=1(含「cap 卡在目录边界」与「恰好装满不误报」两种);
|
||||
* 行数上限(段头 ≤ 书数 ⇒ 2N 必够)
|
||||
* G8 进度不受分组影响:path 不变、rdprog_load 前后同值、ts 两种模式一致
|
||||
*/
|
||||
#include "shelf_model.h"
|
||||
@@ -165,11 +166,17 @@ static void test_scan_and_modes(const char *root, const char *tmproot)
|
||||
CHECK(strcmp(b1->path, want) == 0, "path 仍是完整绝对路径");
|
||||
}
|
||||
|
||||
/* 副题:第一级之后的子路径(分类/作品)必须可见 */
|
||||
CHECK(bdp && strstr(bdp->sub, "01、玄幻/01、斗破") != NULL, "副题含 01、玄幻/01、斗破");
|
||||
CHECK(b5 && strstr(b5->sub, "sub") != NULL, "副题含 sub");
|
||||
CHECK(b3 && strncmp(b3->sub, "TXT", 3) == 0, "一级目录书的副题无多余子路径");
|
||||
CHECK(b4 && strncmp(b4->sub, "TXT", 3) == 0, "根下书副题无多余子路径");
|
||||
/* 副题:format 模式必须与 base 逐字一致;子路径只在 folder 副题里出现 */
|
||||
CHECK(bdp && strcmp(bdp->sub, "TXT · 5B") == 0 && strstr(bdp->sub, "/") == NULL,
|
||||
"format 副题与 base 逐字一致(不含子路径)");
|
||||
CHECK(bdp && strstr(bdp->sub_folder, "01、玄幻/01、斗破") != NULL,
|
||||
"folder 副题含 01、玄幻/01、斗破");
|
||||
CHECK(b5 && strcmp(b5->sub, "MOBI · 4B") == 0, "MOBI 副题与 base 逐字一致");
|
||||
CHECK(b5 && strstr(b5->sub_folder, "sub") != NULL, "folder 副题含 sub");
|
||||
CHECK(b3 && strcmp(b3->sub, "TXT · 5B") == 0 && strcmp(b3->sub_folder, b3->sub) == 0,
|
||||
"一级目录书两种副题相同(无多余子路径)");
|
||||
CHECK(b4 && strcmp(b4->sub, "TXT · 4B") == 0 && strcmp(b4->sub_folder, b4->sub) == 0,
|
||||
"根下书两种副题相同");
|
||||
|
||||
/* G2 format 模式(改动前行为):格式段头 + 最近阅读优先 + 全局书名排序 */
|
||||
shelf_row rows[128];
|
||||
@@ -208,6 +215,32 @@ static void test_scan_and_modes(const char *root, const char *tmproot)
|
||||
int ns = shelf_scan_books(root, small, 2, ts_of, &rep2);
|
||||
CHECK(ns == 2 && rep2.truncated == 1, "超上限时 truncated=1(不静默)");
|
||||
|
||||
/* P2-1:cap 正好卡在目录边界(A/d1 填满,A/d2 被丢)也必须置 truncated */
|
||||
char rootc[400];
|
||||
snprintf(rootc, sizeof rootc, "%s/capbound", tmproot);
|
||||
snprintf(p, sizeof p, "%s/A/d1", rootc); mkdirs(p);
|
||||
snprintf(p, sizeof p, "%s/A/d2", rootc); mkdirs(p);
|
||||
snprintf(p, sizeof p, "%s/A/d1/0.txt", rootc); write_file(p, "0");
|
||||
snprintf(p, sizeof p, "%s/A/d1/1.txt", rootc); write_file(p, "1");
|
||||
snprintf(p, sizeof p, "%s/A/d2/0.txt", rootc); write_file(p, "0");
|
||||
snprintf(p, sizeof p, "%s/A/d2/1.txt", rootc); write_file(p, "1");
|
||||
shelf_book cb[2];
|
||||
shelf_scan_report rep6;
|
||||
int ncb = shelf_scan_books(rootc, cb, 2, NULL, &rep6);
|
||||
CHECK(ncb == 2 && rep6.truncated == 1, "cap 卡在目录边界时 truncated=1(不静默)");
|
||||
|
||||
/* 反向:恰好装满且后面没有书(只剩空目录)不能误报 truncated */
|
||||
char rootd[400];
|
||||
snprintf(rootd, sizeof rootd, "%s/capok", tmproot);
|
||||
snprintf(p, sizeof p, "%s/A", rootd); mkdirs(p);
|
||||
snprintf(p, sizeof p, "%s/A/0.txt", rootd); write_file(p, "0");
|
||||
snprintf(p, sizeof p, "%s/A/1.txt", rootd); write_file(p, "1");
|
||||
snprintf(p, sizeof p, "%s/Empty", rootd); mkdirs(p);
|
||||
shelf_book cb2[2];
|
||||
shelf_scan_report rep7;
|
||||
int ncb2 = shelf_scan_books(rootd, cb2, 2, NULL, &rep7);
|
||||
CHECK(ncb2 == 2 && rep7.truncated == 0, "恰好装满且后续为空目录 → 不误报 truncated");
|
||||
|
||||
/* 不存在的根:root_missing=1 */
|
||||
shelf_scan_report rep3;
|
||||
char nope[400]; snprintf(nope, sizeof nope, "%s/no_such_dir", tmproot);
|
||||
@@ -228,10 +261,12 @@ static void test_scan_and_modes(const char *root, const char *tmproot)
|
||||
dump_rows(rows, nd2, mb2, got, sizeof got);
|
||||
CHECK(strcmp(got, "S:a|B:1(a/b)|B:2(a/c)|") == 0, "a/b 与 a/c 同组 a(一个段头)");
|
||||
CHECK(nd2 == 3, "a/b + a/c = 1 段头 + 2 书");
|
||||
CHECK(find_book(mb2, nm2, "1") && strstr(find_book(mb2, nm2, "1")->sub, "b") != NULL,
|
||||
"a/b 的副题含 b");
|
||||
CHECK(find_book(mb2, nm2, "2") && strstr(find_book(mb2, nm2, "2")->sub, "c") != NULL,
|
||||
"a/c 的副题含 c");
|
||||
CHECK(find_book(mb2, nm2, "1") && strstr(find_book(mb2, nm2, "1")->sub_folder, "b · TXT") != NULL,
|
||||
"a/b 的 folder 副题含 b");
|
||||
CHECK(find_book(mb2, nm2, "2") && strstr(find_book(mb2, nm2, "2")->sub_folder, "c · TXT") != NULL,
|
||||
"a/c 的 folder 副题含 c");
|
||||
CHECK(find_book(mb2, nm2, "1") && strcmp(find_book(mb2, nm2, "1")->sub, "TXT · 1B") == 0,
|
||||
"a/b 的 format 副题仍与 base 一致");
|
||||
|
||||
/* G5.2 字面名「未分类」的目录与根组是两个独立键(不按显示名合并) */
|
||||
char root2[400], mini[420];
|
||||
|
||||
@@ -4,7 +4,14 @@
|
||||
* progress = 每本书调 rdprog_load(生产路径,含 rdprog_dir 的 mkdir 循环 + fopen);
|
||||
* noop = 不读进度(基线,只测 readdir/stat/快照)。
|
||||
* 进度目录由 MEOW_DATA_DIR 决定(同 App:剥 /data → .../progress);未设则 /tmp/m27bench_data。
|
||||
* 输出每轮 scan / build_rows(format+folder) 毫秒,末行 RESULT 汇总 min/avg。
|
||||
* 输出每轮 scan / build_rows(format+folder) 微秒,末行 RESULT 汇总 min/avg/depth_skipped。
|
||||
*
|
||||
* ⚠ 计时精度:本工具用 /proc/uptime(整数、10ms 分辨率),因为 zig mipsel musl 的
|
||||
* time64/浮点 ABI 在真机上不可用(见 patch_v2/sdk/CLOCK_ABI.md)。因此:
|
||||
* - 真机:适合(扫描 595 本几十 ms 量级);
|
||||
* - 宿主:只能看到 0us / 10ms 的粗值,不可用于亚毫秒结论;宿主请改用 clock_gettime
|
||||
* 另写临时程序,或直接读函数的返回值。(M27 r1 报文里的 0.4ms/1.3ms 是切换前用
|
||||
* clock_gettime+double 的宿主临时版本测的,不是本工具输出的。)
|
||||
*/
|
||||
#include "shelf_model.h"
|
||||
#include "progress.h"
|
||||
|
||||
Reference in new issue
Block a user