Files
MeowOS-For-R3P2/patch_v2/reader_app/test/seg_smoke.c
T
AskaEth f40abbd494 feat: M6.43 — reader分段流式读取(Phase1,只txt) + 面板前台管理/返回回桌面按钮
- reader分段(只txt): core/seg.{h,c} 512KB码位对齐切段(尾字完整)+manifest+按需读单段; book.c rd_book_open只布局每页所在段(治CPU100%/返回无效) load_seg只读当前段(非txt原路径); reader.c 进度实时保存(翻页/刮擦/字号/编码dirty+on_tick节流落盘+退出即时写,锚点存段号,崩溃不丢进度); rdtxt.c fread替代fgetc(去开书扫描卡顿); Phase2(双段拼接+4%释放)留待
- 面板: /api/ams/bg加fg/fg_count(后台保持向后兼容)+POST /api/ams/:pkg/killfg(前台救命:优先am kill,launcher拒则pid直信号SIGTERM->SIGKILL绕过门控)+前端/#/bg前台组'终止'绿徽标+确认弹窗(一键清仍只后台不误杀前台); POST /api/input/gesture(返回=左缘右滑/回桌面=底部上滑,注入滑动轨迹复用SDK手势)+前端屏幕控制页加返回/回桌面MD3按钮

0warning;宿主test_reader_core 72-0/seg_smoke 19-0/loaders_smoke/book_smoke/formats_smoke PASS;面板selftest/node check PASS
2026-11-04 19:47:10 +08:00

145 lines
6.0 KiB
C

/* test/seg_smoke.c — os.meow.reader 分段流式缓存宿主单测(纯 C,无 SDK/Freetype)。
*
* 覆盖:
* S1 UTF-8 大文件按 ~512KB 切段:段数>1、每段为合法 UTF-8(码位对齐,不切在字符中间)、
* 拼接后 == 原文件字节。
* S2 GBK(GB18030) 大文件切段:每段 raw 在完整双字节边界、逐段 rd_to_utf8 拼接 == 整文件
* 一次转换(边界不把双字节对拆开)。
* S3 幂等:同 (size,mtime,enc) 再次 build 段数不变、不重写。
* S4 每段原始字节长与 rdseg_load 读回一致。
*/
#include "seg.h"
#include "rdenc.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int g_pass = 0, g_fail = 0;
#define CHECK(cond, msg) do { if (cond) { g_pass++; } else { g_fail++; printf("FAIL %s:%d %s\n", __FILE__, __LINE__, msg); } } while (0)
/* 生成一个 utf8 大文件:CJK 3 字节 + ASCII + 换行,填充到 > 512KB */
static void write_utf8_big(const char *path)
{
FILE *f = fopen(path, "wb");
const uint8_t cjk[] = { 0xE4, 0xBD, 0xA0, 0xE5, 0xA5, 0xBD }; /* 你好 */
size_t total = 0;
while (total < RDSEG_SIZE + 100000) {
for (int i = 0; i < 16; i++) { fwrite(cjk, 1, sizeof cjk, f); total += sizeof cjk; }
const char *line = "这是一段用于验证分段对齐的中文正文,English words 123.\n";
size_t ll = strlen(line); fwrite(line, 1, ll, f); total += ll;
}
fclose(f);
}
/* 生成一个 GBK 大文件:双字节对(你好世界)重复,填到 > 512KB */
static void write_gbk_big(const char *path)
{
FILE *f = fopen(path, "wb");
const uint8_t gbk[] = { 0xC4, 0xE3, 0xBA, 0xC3, 0xCA, 0xC0, 0xBD, 0xE7 }; /* 你好世界 */
size_t total = 0;
while (total < RDSEG_SIZE + 100000) {
for (int i = 0; i < 16; i++) { fwrite(gbk, 1, sizeof gbk, f); total += sizeof gbk; }
fputc('\n', f); total += 1;
}
fclose(f);
}
static void test_align_utf8(const char *seg_dir, const char *path)
{
/* 每段合法 UTF-8 */
int n = rdseg_n(seg_dir);
CHECK(n >= 2, "utf8 segs >= 2");
for (int i = 0; i < n; i++) {
size_t rl = 0;
CHECK(rdseg_rawlen(seg_dir, i, &rl) == 0 && rl > 0, "utf8 rawlen>0");
uint8_t *b = (uint8_t *)malloc(rl ? rl : 1);
size_t got = 0;
CHECK(rdseg_load(seg_dir, i, b, rl, &got) == 0 && got == rl, "utf8 load==rawlen");
CHECK(rd_utf8_validate(b, got) == 1, "utf8 seg valid (no mid-char split)");
free(b);
}
/* 拼接后 == 原文件字节 */
size_t fz = 0;
FILE *src = fopen(path, "rb"); fseek(src, 0, SEEK_END); fz = (size_t)ftell(src); fseek(src, 0, SEEK_SET);
uint8_t *full = (uint8_t *)malloc(fz ? fz : 1);
(void)!fread(full, 1, fz, src); fclose(src);
size_t o = 0, ok = 1;
for (int i = 0; i < n; i++) {
size_t rl = 0; rdseg_rawlen(seg_dir, i, &rl);
uint8_t *b = (uint8_t *)malloc(rl ? rl : 1);
size_t got = 0; rdseg_load(seg_dir, i, b, rl, &got);
if (o + got > fz || memcmp(full + o, b, got) != 0) ok = 0;
o += got; free(b);
}
CHECK(ok && o == fz, "utf8 concat == original bytes");
free(full);
}
static void test_gbk_roundtrip(const char *seg_dir, const char *path)
{
int n = rdseg_n(seg_dir);
CHECK(n >= 2, "gbk segs >= 2");
/* 整文件一次转换(金标准) */
FILE *src = fopen(path, "rb"); fseek(src, 0, SEEK_END); long fz = ftell(src); fseek(src, 0, SEEK_SET);
uint8_t *raw = (uint8_t *)malloc((size_t)fz ? (size_t)fz : 1);
(void)!fread(raw, 1, (size_t)fz, src); fclose(src);
uint8_t *full = (uint8_t *)malloc((size_t)fz * 2 + 64);
size_t fl = 0;
int rc = rd_gb18030_to_utf8(raw, (size_t)fz, full, (size_t)fz * 2 + 64, &fl);
CHECK(rc == RD_ENC_OK, "gbk full convert ok");
free(raw);
/* 逐段转换拼接 */
uint8_t *concat = (uint8_t *)malloc((size_t)fz * 2 + 64);
size_t o = 0, ok = 1;
for (int i = 0; i < n; i++) {
size_t rl = 0; rdseg_rawlen(seg_dir, i, &rl);
uint8_t *b = (uint8_t *)malloc(rl ? rl : 1);
size_t got = 0; rdseg_load(seg_dir, i, b, rl, &got);
uint8_t *u8 = (uint8_t *)malloc(got * 2 + 64);
size_t ul = 0;
if (rd_gb18030_to_utf8(b, got, u8, got * 2 + 64, &ul) != RD_ENC_OK) ok = 0;
if (o + ul > (size_t)fz * 2 + 64) ok = 0;
if (ok) { memcpy(concat + o, u8, ul); o += ul; }
free(u8); free(b);
}
CHECK(ok && o == fl && memcmp(concat, full, fl) == 0, "gbk per-seg convert concat == full convert");
free(concat); free(full);
}
int main(void)
{
rdseg_set_base("/tmp/meow_seg_base");
char dir[600];
const char *u8 = "/tmp/seg_u8.txt", *gbk = "/tmp/seg_gbk.txt";
write_utf8_big(u8); write_gbk_big(gbk);
/* UTF-8 */
CHECK(rdseg_dir_for(u8, dir, sizeof dir) == 0, "utf8 dir_for");
int n = rdseg_build(u8, RD_ENC_UTF8, dir);
CHECK(n >= 2, "utf8 build nsegs>=2");
test_align_utf8(dir, u8);
/* 幂等:同键再建段数不变 */
CHECK(rdseg_build(u8, RD_ENC_UTF8, dir) == n, "utf8 build idempotent");
/* GBK */
CHECK(rdseg_dir_for(gbk, dir, sizeof dir) == 0, "gbk dir_for");
n = rdseg_build(gbk, RD_ENC_GB18030, dir);
CHECK(n >= 2, "gbk build nsegs>=2");
test_gbk_roundtrip(dir, gbk);
/* 大文件不切(清空再建,确保得到多个段也覆盖单段路径) */
{
char small[600]; rdseg_set_base("/tmp/meow_seg_base2");
const char *tiny = "/tmp/seg_tiny.txt";
FILE *f = fopen(tiny, "wb"); fwrite("hello 你好 world\n", 1, strlen("hello 你好 world\n"), f); fclose(f);
CHECK(rdseg_dir_for(tiny, small, sizeof small) == 0, "tiny dir");
int tn = rdseg_build(tiny, RD_ENC_UTF8, small);
CHECK(tn == 1, "tiny build nsegs==1");
size_t rl = 0; CHECK(rdseg_rawlen(small, 0, &rl) == 0 && rl == strlen("hello 你好 world\n"), "tiny rawlen");
}
remove(u8); remove(gbk); remove("/tmp/seg_tiny.txt");
printf("seg_smoke: %d pass, %d fail\n", g_pass, g_fail);
return g_fail ? 1 : 0;
}