Files
yhf c8bfef090a chore: 发布V1.1.26版本,修复Sink角色切换初始化残留问题
1. 更新所有文件版本号至V1.1.26,同步固件版本寄存器值
2. 修复Sink角色往返时初始化上下文残留问题,切换回Sink时重新执行完整初始化
3. 优化Sink配置生效逻辑,同角色仅复制PC可写配置,保留运行状态
4. 增加初始化阶段入队标记,避免沿用旧成功结果跳过未执行命令
5. 停止入队失败时由北向轮询重试,不依赖On_work或通道使能
6. 新增Sink初始化回归测试套件,覆盖14种场景验证流程正确性
2026-09-17 12:01:50 +08:00

63 lines
3.7 KiB
JavaScript

// 使用真实 Sink 实现及 COM 生效函数;仅替换时钟、继电器和南向传输。
// node tests/sink_init/run.cjs [gcc路径]。临时编译产物不写入固件工程。
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const cp = require('node:child_process');
const root = path.resolve(__dirname, '../..');
const app = path.join(root, 'apps/chrg/applications');
const cc = process.argv[2] || process.env.CC || 'gcc';
if (path.isAbsolute(cc)) process.env.PATH = path.dirname(cc) + path.delimiter + process.env.PATH;
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'chrg-sink-test-'));
const source = fs.readFileSync(path.join(app, 'thread/chrg_comm.c'), 'utf8');
function definition(name) {
const pattern = new RegExp('static\\s+[\\w]+\\s+' + name + '\\s*\\([^;{]*\\)\\s*\\{', 'g');
const match = pattern.exec(source);
if (!match) return '';
let depth = 1, end = pattern.lastIndex;
while (depth && end < source.length) {
if (source[end] === '{') depth++;
if (source[end] === '}') depth--;
end++;
}
return source.slice(match.index, end);
}
const type = source.match(/typedef struct\s*\{[^}]*\}\s*chrg_param_diff_t;/)[0];
const functions = ['chrg_comm_get_param_diff', 'chrg_comm_sink_config_equal',
'chrg_comm_copy_sink_config', 'chrg_comm_handle_sink_load_current',
'chrg_sink_diff_send_reg', 'chrg_comm_apply_sink_effect', 'chrg_mb_write_sys'];
const roll = fs.readFileSync(path.join(app, 'thread/chrg_roll_nor.c'), 'utf8');
const dispatch = roll.slice(roll.indexOf('void chrg_roll_nor_thread_entry'))
.match(/if \(\(pSW->id == ID_SOURCE\)[\s\S]+?state_work_ret = chrg_sink_work[\s\S]+?\n\t\t\t\}/)[0];
const unit = '#include "' + path.join(app, 'utils/chrg_sink.c').replaceAll('\\', '/') + '"\n' +
'#include "chrg_thread.h"\n#define LOG_E(...) ((void)0)\n' +
'static rt_uint8_t g_shadow_dirty[4], last_pd_pro[4];\n#define SOURCE_PD_STATE_UNKNOWN 255\n' +
'static eMBException chrg_comm_apply_source_effect(rt_uint8_t ch, struct chrg_switch_t *p, const struct chrg_switch_t *s);\n' +
type + '\n' + functions.map(definition).join('\n') + '\n' +
'static int poll_state(struct chrg_switch_t *pSW) { int idx=0, state_work_ret=0;\n' + dispatch + '\nreturn state_work_ret; }\n' +
fs.readFileSync(path.join(__dirname, 'cases.c'), 'utf8');
const scenarios = ['duplicate_exit', 'preserve_runtime', 'busy_changed_config',
'recover_init', 'stop_during_init', 'first_submit_failure', 'stage_submit_failure',
'failed_batch_retry', 'complete_then_restart', 'duplicate_version',
'busy_version', 'stop_submit_retry', 'rest_submit_failure', 'role_roundtrip'];
try {
fs.writeFileSync(path.join(dir, 'test.c'), unit);
const exe = path.join(dir, process.platform === 'win32' ? 'test.exe' : 'test');
const args = ['-std=c99', '-O0', '-ffunction-sections', '-fdata-sections',
'-Werror=implicit-function-declaration', '-Wl,--gc-sections',
'-I' + __dirname, ...['utils', 'thread', 'bsp'].map(p => '-I' + path.join(app, p)),
path.join(dir, 'test.c'), '-o', exe];
const build = cp.spawnSync(cc, args, {encoding: 'utf8'});
if (build.status !== 0) throw Error(build.stderr || String(build.error || build.status));
let failed = 0;
for (const name of scenarios) {
const run = cp.spawnSync(exe, [name], {encoding: 'utf8'});
console.log((run.status === 0 ? 'PASS ' : 'FAIL ') + name);
if (run.status !== 0) { failed++; console.log(run.stdout + run.stderr); }
}
console.log(`${scenarios.length - failed}/${scenarios.length} passed`);
process.exitCode = failed ? 1 : 0;
} finally {
fs.rmSync(dir, {recursive: true, force: true});
}