feat(scheduler-core): implement what-if branching and simulation output recording (task 11.5)
Add sim_record.c (scheduler_t-free .replay writer: ReplayHeader + loaded SnapshotEntry once, then per-event pass-through and per-session ReplaySession finalization) and wire --sim-alt-events event-source selection into sim_loop.c's drain loop, coexisting with task 11.2's stdout default and task 11.4's --sim-verify. Extract scheduler_t-free halves out of recording_session.c's begin/end so sim-side code can reuse the decision-encoding path without gaining an xce_scheduler_t* dependency, preserving Req 5 AC 17 isolation. Per Req 5 AC 16/19.
This commit is contained in:
parent
a6083d803e
commit
564408e967
14 changed files with 1750 additions and 91 deletions
|
|
@ -4,10 +4,15 @@
|
|||
* or structural check confirms no controller-facing symbol is reachable
|
||||
* from the simulation driver's compiled object" -- plus the AC's own
|
||||
* "confirmed by the struct definition itself, not runtime checks alone"
|
||||
* clause. Scope: sim.h + sim.c + sim_loop.c together (task 11.1 + task
|
||||
* 11.2's sibling file) -- NOT a re-audit of core.c (task 4.1's own
|
||||
* clause. Scope: sim.h + sim.c + sim_loop.c + sim_record.c together (task
|
||||
* 11.1 + task 11.2's sibling file + task 11.5's sibling file, the
|
||||
* --sim-output writer) -- NOT a re-audit of core.c (task 4.1's own
|
||||
* territory, test_core_isolation.c) and NOT plugin.c/builtin_fcfs.c (shared
|
||||
* normal-mode infra, out of this task's boundary).
|
||||
* normal-mode infra, out of this task's boundary). sim_verify.c (task 11.4)
|
||||
* is likewise out of scope here -- it is never compiled into
|
||||
* sched_sim_isolation_lib below and carries no isolation-sensitive logic of
|
||||
* its own (pure struct comparison, no I/O); extending this guard to it was
|
||||
* not part of task 11.4's own text and is left as-is.
|
||||
*
|
||||
* Three layers, extending test_core_isolation.c's two-layer pattern (same
|
||||
* genre: source-text scans of the real, current on-disk files, not a frozen
|
||||
|
|
@ -74,9 +79,13 @@
|
|||
#error \
|
||||
"XCE_SIM_LOOP_C_PATH must be defined by meson.build to sim_loop.c's absolute path"
|
||||
#endif
|
||||
#ifndef XCE_SIM_RECORD_C_PATH
|
||||
#error \
|
||||
"XCE_SIM_RECORD_C_PATH must be defined by meson.build to sim_record.c's absolute path"
|
||||
#endif
|
||||
#ifndef XCE_SIM_LIB_PATH
|
||||
#error \
|
||||
"XCE_SIM_LIB_PATH must be defined by meson.build to the absolute path of sim.c+sim_loop.c's isolated static_library() archive"
|
||||
"XCE_SIM_LIB_PATH must be defined by meson.build to the absolute path of sim.c+sim_loop.c+sim_record.c's isolated static_library() archive"
|
||||
#endif
|
||||
|
||||
/* Forbidden headers (design.md "Allowed Dependencies", same list
|
||||
|
|
@ -346,81 +355,100 @@ void tearDown(void) { return; }
|
|||
* failure mode this whole test exists to avoid). */
|
||||
static void test_sim_source_paths_are_readable(void)
|
||||
{
|
||||
char* h = read_whole_file(XCE_SIM_H_PATH);
|
||||
char* c = read_whole_file(XCE_SIM_C_PATH);
|
||||
char* loop = read_whole_file(XCE_SIM_LOOP_C_PATH);
|
||||
char* h = read_whole_file(XCE_SIM_H_PATH);
|
||||
char* c = read_whole_file(XCE_SIM_C_PATH);
|
||||
char* loop = read_whole_file(XCE_SIM_LOOP_C_PATH);
|
||||
char* record = read_whole_file(XCE_SIM_RECORD_C_PATH);
|
||||
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(h, XCE_SIM_H_PATH);
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(c, XCE_SIM_C_PATH);
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(loop, XCE_SIM_LOOP_C_PATH);
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(record, XCE_SIM_RECORD_C_PATH);
|
||||
|
||||
free(h);
|
||||
free(c);
|
||||
free(loop);
|
||||
free(record);
|
||||
}
|
||||
|
||||
static void test_sim_never_includes_forbidden_headers(void)
|
||||
{
|
||||
char* h_raw = read_whole_file(XCE_SIM_H_PATH);
|
||||
char* c_raw = read_whole_file(XCE_SIM_C_PATH);
|
||||
char* loop_raw = read_whole_file(XCE_SIM_LOOP_C_PATH);
|
||||
char* h_raw = read_whole_file(XCE_SIM_H_PATH);
|
||||
char* c_raw = read_whole_file(XCE_SIM_C_PATH);
|
||||
char* loop_raw = read_whole_file(XCE_SIM_LOOP_C_PATH);
|
||||
char* record_raw = read_whole_file(XCE_SIM_RECORD_C_PATH);
|
||||
char* h;
|
||||
char* c;
|
||||
char* loop;
|
||||
char* record;
|
||||
|
||||
TEST_ASSERT_NOT_NULL(h_raw);
|
||||
TEST_ASSERT_NOT_NULL(c_raw);
|
||||
TEST_ASSERT_NOT_NULL(loop_raw);
|
||||
TEST_ASSERT_NOT_NULL(record_raw);
|
||||
|
||||
h = strip_c_comments(h_raw);
|
||||
c = strip_c_comments(c_raw);
|
||||
loop = strip_c_comments(loop_raw);
|
||||
h = strip_c_comments(h_raw);
|
||||
c = strip_c_comments(c_raw);
|
||||
loop = strip_c_comments(loop_raw);
|
||||
record = strip_c_comments(record_raw);
|
||||
TEST_ASSERT_NOT_NULL(h);
|
||||
TEST_ASSERT_NOT_NULL(c);
|
||||
TEST_ASSERT_NOT_NULL(loop);
|
||||
TEST_ASSERT_NOT_NULL(record);
|
||||
|
||||
assert_no_forbidden_includes(h, "sim.h");
|
||||
assert_no_forbidden_includes(c, "sim.c");
|
||||
assert_no_forbidden_includes(loop, "sim_loop.c");
|
||||
assert_no_forbidden_includes(record, "sim_record.c");
|
||||
|
||||
free(h_raw);
|
||||
free(c_raw);
|
||||
free(loop_raw);
|
||||
free(record_raw);
|
||||
free(h);
|
||||
free(c);
|
||||
free(loop);
|
||||
free(record);
|
||||
}
|
||||
|
||||
static void test_sim_never_calls_forbidden_symbols(void)
|
||||
{
|
||||
char* h_raw = read_whole_file(XCE_SIM_H_PATH);
|
||||
char* c_raw = read_whole_file(XCE_SIM_C_PATH);
|
||||
char* loop_raw = read_whole_file(XCE_SIM_LOOP_C_PATH);
|
||||
char* h_raw = read_whole_file(XCE_SIM_H_PATH);
|
||||
char* c_raw = read_whole_file(XCE_SIM_C_PATH);
|
||||
char* loop_raw = read_whole_file(XCE_SIM_LOOP_C_PATH);
|
||||
char* record_raw = read_whole_file(XCE_SIM_RECORD_C_PATH);
|
||||
char* h;
|
||||
char* c;
|
||||
char* loop;
|
||||
char* record;
|
||||
|
||||
TEST_ASSERT_NOT_NULL(h_raw);
|
||||
TEST_ASSERT_NOT_NULL(c_raw);
|
||||
TEST_ASSERT_NOT_NULL(loop_raw);
|
||||
TEST_ASSERT_NOT_NULL(record_raw);
|
||||
|
||||
h = strip_c_comments(h_raw);
|
||||
c = strip_c_comments(c_raw);
|
||||
loop = strip_c_comments(loop_raw);
|
||||
h = strip_c_comments(h_raw);
|
||||
c = strip_c_comments(c_raw);
|
||||
loop = strip_c_comments(loop_raw);
|
||||
record = strip_c_comments(record_raw);
|
||||
TEST_ASSERT_NOT_NULL(h);
|
||||
TEST_ASSERT_NOT_NULL(c);
|
||||
TEST_ASSERT_NOT_NULL(loop);
|
||||
TEST_ASSERT_NOT_NULL(record);
|
||||
|
||||
assert_no_forbidden_symbols(h, "sim.h");
|
||||
assert_no_forbidden_symbols(c, "sim.c");
|
||||
assert_no_forbidden_symbols(loop, "sim_loop.c");
|
||||
assert_no_forbidden_symbols(record, "sim_record.c");
|
||||
|
||||
free(h_raw);
|
||||
free(c_raw);
|
||||
free(loop_raw);
|
||||
free(record_raw);
|
||||
free(h);
|
||||
free(c);
|
||||
free(loop);
|
||||
free(record);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -464,8 +492,9 @@ static void test_sim_driver_struct_has_no_forbidden_fields(void)
|
|||
|
||||
/*
|
||||
* test_sim_object_has_no_forbidden_undefined_symbols - the literal
|
||||
* build-time/link-time proof: sim.c + sim_loop.c, compiled together in
|
||||
* isolation into sched_sim_isolation_lib (meson.build), must not reference
|
||||
* build-time/link-time proof: sim.c + sim_loop.c + sim_record.c, compiled
|
||||
* together in isolation into sched_sim_isolation_lib (meson.build), must
|
||||
* not reference
|
||||
* (as an undefined external symbol in the compiled archive) anything
|
||||
* matching the forbidden prefixes above. Independent of what any header
|
||||
* transitively declares -- reflects only what this driver's compiled code
|
||||
|
|
@ -494,8 +523,8 @@ static void test_sim_object_has_no_forbidden_undefined_symbols(void)
|
|||
/* posix format for an undefined symbol: "<name> U" (no
|
||||
* value/size columns). Skip anything that doesn't parse as
|
||||
* exactly that -- e.g. a blank line, or an archive member header
|
||||
* some nm versions print (this archive has two member objects,
|
||||
* sim.c.o and sim_loop.c.o). */
|
||||
* some nm versions print (this archive has three member objects,
|
||||
* sim.c.o, sim_loop.c.o, and sim_record.c.o). */
|
||||
if (sscanf(line, "%511s %c", symbol, &type) != 2) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue