feat(scheduler-core): implement REPL breakpoints and state inspection (task 12.2)

Adds the interactive simulation REPL's breakpoint and state-inspection
commands (Req 5 AC 22): `break <event_type> [key=value ...]` / `info
break` / `delete <id>|all` on event and decision types, and `info
session/job/queue/worker/resource/summary`.

repl.c (370 lines after task 12.1) couldn't hold this task's full
surface under the project's 800-line cap, so it's split three ways
(matching the snapshot.c/snapshot_wire.c/snapshot_load.c precedent):
repl.c (execution control + dispatch), repl_break.c (matching/CRUD +
the three new driver-facing hooks), repl_info.c (info dumps), sharing
state via repl_internal.h. sim_loop.c gained 3 new bare hook calls
(repl.h inline wrappers, same pattern as task 12.1's two) at the
points design.md's pseudocode requires -- per decoded event before it
joins the batch, per session boundary, and per drained decision --
landing sim_loop.c at exactly 800/800 lines.

Two real bugs found and fixed during development (bug-1506, bug-1507):
an uninitialized xstr_table left breakpoint filter fields silently
NULL instead of failing loud, and repl_breakpoint_free() called a bare
free() on an RTTI-refcounted makeString() string, corrupting the heap.

Review found one gap: `info job` printed only a resreq presence flag
instead of the actual resreq text, when format_resreq() already
existed in this repo for exactly this purpose. Fixed to match.

Scheduler suite: 35/35 clean (was 34/34). RED-phase evidence (2 real
bugs plus 2 synthetic probes, all reverted with confirmed zero
residue) recorded in tasks.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JPPXeKSUXUqcqvzNXY1rzJ
This commit is contained in:
Rongsong Shen 2026-08-07 09:46:16 +00:00
parent 02f7f48ff9
commit 2fecea3592
Signed by: rshen
SSH key fingerprint: SHA256:8Vf2pZ3h6rJa7EhGK+WaAQ9Mta/apZvteW6g9U/WKKk
18 changed files with 3067 additions and 212 deletions

View file

@ -551,6 +551,15 @@ sched_sim_isolation_test = executable(
'-DXCE_SIM_REPL_H_PATH="'
+ (meson.current_source_dir() / '..' / 'include' / 'repl.h')
+ '"',
'-DXCE_SIM_REPL_BREAK_C_PATH="'
+ (meson.current_source_dir() / '..' / 'src' / 'repl_break.c')
+ '"',
'-DXCE_SIM_REPL_INFO_C_PATH="'
+ (meson.current_source_dir() / '..' / 'src' / 'repl_info.c')
+ '"',
'-DXCE_SIM_REPL_INTERNAL_H_PATH="'
+ (meson.current_source_dir() / '..' / 'src' / 'repl_internal.h')
+ '"',
'-DXCE_SIM_LIB_PATH="'
+ sched_sim_isolation_lib.full_path()
+ '"'],
@ -660,7 +669,13 @@ sched_sim_equivalence_test = executable(
# (core.c, core_clock.c, core_events.c, core_session.c, decision.c, plugin.c,
# plugins/builtin_fcfs.c, recording.c, recording_session.c, sim.c, sim_loop.c,
# sim_record.c, sim_verify.c, snapshot.c/snapshot_wire.c/snapshot_load.c) PLUS
# the new ../src/repl.c under test. Needs libedit_dep (parent meson.build)
# ../src/repl.c under test. Also pulls in ../src/repl_break.c/repl_info.c
# (task 12.2's 800-line-cap split of repl.c -- repl_internal.h's own "Why a
# split at all") -- required at link time since sim_loop.c's new breakpoint
# hooks (repl.h) reference symbols repl_break.c defines, even though this
# file's own tests exercise only the execution-control slice; task 12.2's
# own breakpoint/inspection tests live in the sibling
# test_repl_breakpoints_inspection.c. Needs libedit_dep (parent meson.build)
# at link time -- repl.c's real readline()/add_history() calls are pulled
# into this TU by the white-box #include.
sched_repl_execution_control_test = executable(
@ -670,6 +685,29 @@ sched_repl_execution_control_test = executable(
dependencies: [scheduler_test_deps, libedit_dep],
install: false)
# Contract test for the interactive simulation REPL's breakpoint and
# state-inspection slice (scheduler-core spec, task 12.2, Req 5 AC 22
# "Breakpoints"/"State inspection"): setting a breakpoint on a specific
# event type and field value pauses the REPL exactly when a matching event
# is about to be processed, and each `info` command reports state matching
# a snapshot dump of the same moment. Same white-box #include pattern as
# sched_repl_execution_control_test above (core.c, core_clock.c,
# core_events.c, core_session.c, decision.c, plugin.c,
# plugins/builtin_fcfs.c, recording.c, recording_session.c, sim.c,
# sim_loop.c, sim_record.c, sim_verify.c,
# snapshot.c/snapshot_wire.c/snapshot_load.c, repl.c, repl_break.c,
# repl_info.c). Split into its own file rather than appended to
# test_repl_execution_control.c -- that file was already 644 lines after
# task 12.1, and this task's own fixture/assertion surface (breakpoints on
# multiple event kinds plus five separate `info` dumps) does not fit
# alongside it under this project's 800-line cap.
sched_repl_breakpoints_inspection_test = executable(
'sched_repl_breakpoints_inspection_test',
['test_repl_breakpoints_inspection.c'],
include_directories:[incdir],
dependencies: [scheduler_test_deps, libedit_dep],
install: false)
# Register as meson tests so `meson test --suite scheduler` runs them all.
# detect_leaks=0 matches the suite convention (fixtures are not torn down).
test('scheduler test', scheduler_test, suite: 'scheduler',
@ -763,3 +801,6 @@ test('scheduler sim equivalence test',
test('scheduler repl execution control test',
sched_repl_execution_control_test, suite: 'scheduler',
env: ['ASAN_OPTIONS=detect_leaks=0'])
test('scheduler repl breakpoints inspection test',
sched_repl_breakpoints_inspection_test, suite: 'scheduler',
env: ['ASAN_OPTIONS=detect_leaks=0'])

File diff suppressed because it is too large Load diff

View file

@ -94,6 +94,8 @@
#include "../src/recording.c"
#include "../src/recording_session.c"
#include "../src/repl.c"
#include "../src/repl_break.c"
#include "../src/repl_info.c"
#include "../src/sim.c"
#include "../src/sim_loop.c"
#include "../src/sim_record.c"

View file

@ -46,13 +46,16 @@
* White-box #include of the same TU set test_sim_verify.c uses (see that
* file's own header comment) -- core.c/core_clock.c/core_events.c/
* core_session.c/decision.c/plugin.c/plugins/builtin_fcfs.c/recording.c/
* recording_session.c/sim.c/sim_loop.c/sim_record.c/sim_verify.c/
* recording_session.c/repl.c/sim.c/sim_loop.c/sim_record.c/sim_verify.c/
* snapshot.c/snapshot_load.c/snapshot_wire.c. sim_verify.c AND
* recording_session.c/sim_record.c are all required at link time
* recording_session.c/sim_record.c/repl.c are all required at link time
* (sched_sim_driver_run() externs sim_decision_eq()/sim_log_mismatch() and
* sched_record_session_ctx_new()/_finalize()/sim_record_write_header_and_
* snapshot()/sim_record_write_event() unconditionally) even though this
* file never sets --sim-verify or --sim-output, same reason
* snapshot()/sim_record_write_event() unconditionally, and repl.h's task
* 12.1 inline wrappers -- pulled in transitively by sim_loop.c's own
* `#include "repl.h"` -- reference xce_repl_start()/
* xce_repl_post_session_check() unconditionally too) even though this file
* never sets --sim-verify/--sim-output/--interactive, same reason
* test_sim_event_loop.c's own header comment documents.
*/
#include <errno.h>
@ -83,6 +86,9 @@
#include "../src/plugins/builtin_fcfs.c"
#include "../src/recording.c"
#include "../src/recording_session.c"
#include "../src/repl.c"
#include "../src/repl_break.c"
#include "../src/repl_info.c"
#include "../src/sim.c"
#include "../src/sim_loop.c"
#include "../src/sim_record.c"

View file

@ -100,9 +100,11 @@
* recording.c, recording_events.c, recording_session.c, snapshot.c,
* snapshot_wire.c) and test_sim_record_output.c's own set (core.c,
* core_clock.c, core_events.c, core_session.c, decision.c, plugin.c,
* plugins/builtin_fcfs.c, recording.c, recording_session.c, sim.c,
* plugins/builtin_fcfs.c, recording.c, recording_session.c, repl.c, sim.c,
* sim_loop.c, sim_record.c, sim_verify.c, snapshot.c, snapshot_load.c,
* snapshot_wire.c) -- no prior test file combines both the normal-mode
* snapshot_wire.c -- repl.c added by task 12.1, required at link time by
* sim_loop.c's own repl.h inline wrappers) -- no prior test file combines
* both the normal-mode
* driver stack and the full simulation stack in one TU; this task is the
* first to genuinely need both halves of the pipeline live simultaneously.
* Verified no static-symbol collisions exist across the combined file set
@ -153,6 +155,9 @@
#include "../src/recording.c"
#include "../src/recording_events.c"
#include "../src/recording_session.c"
#include "../src/repl.c"
#include "../src/repl_break.c"
#include "../src/repl_info.c"
#include "../src/sim.c"
#include "../src/sim_loop.c"
#include "../src/sim_record.c"

View file

@ -66,7 +66,12 @@
* sched_record_session_ctx_new()/_finalize()/sim_record_write_header_and_
* snapshot()/sim_record_write_event() as extern functions, undefined
* references at link time otherwise, even though this file never sets
* --sim-output either) PLUS
* --sim-output either) PLUS ../src/repl.c (task 12.1's sibling file -- same
* reasoning again: sim_loop.c now `#include`s repl.h, whose task 12.1
* inline wrappers unconditionally reference xce_repl_start()/
* xce_repl_post_session_check() as extern functions, undefined references
* at link time otherwise, even though this file never sets --interactive)
* PLUS
* ../src/snapshot.c/snapshot_wire.c/snapshot_load.c (task 8.1, needed by
* both the fixture-building and sim.c's own snapshot load).
*/
@ -96,6 +101,9 @@
#include "../src/plugins/builtin_fcfs.c"
#include "../src/recording.c"
#include "../src/recording_session.c"
#include "../src/repl.c"
#include "../src/repl_break.c"
#include "../src/repl_info.c"
#include "../src/sim.c"
#include "../src/sim_loop.c"
#include "../src/sim_record.c"

View file

@ -4,27 +4,30 @@
* 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 + sim_record.c + repl.c/repl.h
* together (task 11.1 + task 11.2's sibling file + task 11.5's sibling
* file, the --sim-output writer + task 12.1's sibling files, the
* interactive REPL) -- 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). sim_verify.c (task 11.4)
* is likewise out of scope here -- it is never compiled into
* clause. Scope: sim.h + sim.c + sim_loop.c + sim_record.c + repl.c/repl.h/
* repl_break.c/repl_info.c/repl_internal.h together (task 11.1 + task
* 11.2's sibling file + task 11.5's sibling file, the --sim-output writer +
* task 12.1's REPL files + task 12.2's own repl_break.c/repl_info.c/
* repl_internal.h, its 800-line-cap split of repl.c -- see repl_internal.h's
* own "Why a split at all" section) -- 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). 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. repl.c/repl.h are
* added here per task 12.1's own text (extending this exact 3-file
* precedent to a 5-file one) -- the REPL reads/writes stdin/stdout and
* touches xce_sched_sim_driver_t directly, the same category of
* driver-level code this guard already covers.
* not part of task 11.4's own text and is left as-is. repl.c/repl.h were
* added per task 12.1's own text (extending this exact 3-file precedent to
* a 5-file one); repl_break.c/repl_info.c/repl_internal.h extend it again
* (task 12.2, to an 8-file one) -- all touch xce_sched_sim_driver_t
* directly or read/write stdin/stdout, the same category of driver-level
* code this guard already covers.
*
* 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
* snapshot):
*
* 1. Source-text scan of sim.h/sim.c/sim_loop.c/sim_record.c/repl.c/
* repl.h: no #include of
* repl.h/repl_break.c/repl_info.c/repl_internal.h: no #include of
* client.h/netio.h/xceapi.h/delay.h/idgen.h/xce/cluster.h; no call-site
* substring matching a symbol exported only by those libraries (the
* exact FORBIDDEN_SYMBOLS list test_core_isolation.c already
@ -97,9 +100,21 @@
#error \
"XCE_SIM_REPL_H_PATH must be defined by meson.build to repl.h's absolute path"
#endif
#ifndef XCE_SIM_REPL_BREAK_C_PATH
#error \
"XCE_SIM_REPL_BREAK_C_PATH must be defined by meson.build to repl_break.c's absolute path"
#endif
#ifndef XCE_SIM_REPL_INFO_C_PATH
#error \
"XCE_SIM_REPL_INFO_C_PATH must be defined by meson.build to repl_info.c's absolute path"
#endif
#ifndef XCE_SIM_REPL_INTERNAL_H_PATH
#error \
"XCE_SIM_REPL_INTERNAL_H_PATH must be defined by meson.build to repl_internal.h'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+sim_record.c+repl.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+repl.c+repl_break.c+repl_info.c's isolated static_library() archive"
#endif
/* Forbidden headers (design.md "Allowed Dependencies", same list
@ -369,12 +384,15 @@ 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* record = read_whole_file(XCE_SIM_RECORD_C_PATH);
char* repl_c = read_whole_file(XCE_SIM_REPL_C_PATH);
char* repl_h = read_whole_file(XCE_SIM_REPL_H_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);
char* repl_c = read_whole_file(XCE_SIM_REPL_C_PATH);
char* repl_h = read_whole_file(XCE_SIM_REPL_H_PATH);
char* repl_break_c = read_whole_file(XCE_SIM_REPL_BREAK_C_PATH);
char* repl_info_c = read_whole_file(XCE_SIM_REPL_INFO_C_PATH);
char* repl_int_h = read_whole_file(XCE_SIM_REPL_INTERNAL_H_PATH);
TEST_ASSERT_NOT_NULL_MESSAGE(h, XCE_SIM_H_PATH);
TEST_ASSERT_NOT_NULL_MESSAGE(c, XCE_SIM_C_PATH);
@ -382,6 +400,9 @@ static void test_sim_source_paths_are_readable(void)
TEST_ASSERT_NOT_NULL_MESSAGE(record, XCE_SIM_RECORD_C_PATH);
TEST_ASSERT_NOT_NULL_MESSAGE(repl_c, XCE_SIM_REPL_C_PATH);
TEST_ASSERT_NOT_NULL_MESSAGE(repl_h, XCE_SIM_REPL_H_PATH);
TEST_ASSERT_NOT_NULL_MESSAGE(repl_break_c, XCE_SIM_REPL_BREAK_C_PATH);
TEST_ASSERT_NOT_NULL_MESSAGE(repl_info_c, XCE_SIM_REPL_INFO_C_PATH);
TEST_ASSERT_NOT_NULL_MESSAGE(repl_int_h, XCE_SIM_REPL_INTERNAL_H_PATH);
free(h);
free(c);
@ -389,22 +410,31 @@ static void test_sim_source_paths_are_readable(void)
free(record);
free(repl_c);
free(repl_h);
free(repl_break_c);
free(repl_info_c);
free(repl_int_h);
}
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* record_raw = read_whole_file(XCE_SIM_RECORD_C_PATH);
char* repl_c_raw = read_whole_file(XCE_SIM_REPL_C_PATH);
char* repl_h_raw = read_whole_file(XCE_SIM_REPL_H_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* repl_c_raw = read_whole_file(XCE_SIM_REPL_C_PATH);
char* repl_h_raw = read_whole_file(XCE_SIM_REPL_H_PATH);
char* repl_break_c_raw = read_whole_file(XCE_SIM_REPL_BREAK_C_PATH);
char* repl_info_c_raw = read_whole_file(XCE_SIM_REPL_INFO_C_PATH);
char* repl_int_h_raw = read_whole_file(XCE_SIM_REPL_INTERNAL_H_PATH);
char* h;
char* c;
char* loop;
char* record;
char* repl_c;
char* repl_h;
char* repl_break_c;
char* repl_info_c;
char* repl_int_h;
TEST_ASSERT_NOT_NULL(h_raw);
TEST_ASSERT_NOT_NULL(c_raw);
@ -412,19 +442,28 @@ static void test_sim_never_includes_forbidden_headers(void)
TEST_ASSERT_NOT_NULL(record_raw);
TEST_ASSERT_NOT_NULL(repl_c_raw);
TEST_ASSERT_NOT_NULL(repl_h_raw);
TEST_ASSERT_NOT_NULL(repl_break_c_raw);
TEST_ASSERT_NOT_NULL(repl_info_c_raw);
TEST_ASSERT_NOT_NULL(repl_int_h_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);
repl_c = strip_c_comments(repl_c_raw);
repl_h = strip_c_comments(repl_h_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);
repl_c = strip_c_comments(repl_c_raw);
repl_h = strip_c_comments(repl_h_raw);
repl_break_c = strip_c_comments(repl_break_c_raw);
repl_info_c = strip_c_comments(repl_info_c_raw);
repl_int_h = strip_c_comments(repl_int_h_raw);
TEST_ASSERT_NOT_NULL(h);
TEST_ASSERT_NOT_NULL(c);
TEST_ASSERT_NOT_NULL(loop);
TEST_ASSERT_NOT_NULL(record);
TEST_ASSERT_NOT_NULL(repl_c);
TEST_ASSERT_NOT_NULL(repl_h);
TEST_ASSERT_NOT_NULL(repl_break_c);
TEST_ASSERT_NOT_NULL(repl_info_c);
TEST_ASSERT_NOT_NULL(repl_int_h);
assert_no_forbidden_includes(h, "sim.h");
assert_no_forbidden_includes(c, "sim.c");
@ -432,6 +471,9 @@ static void test_sim_never_includes_forbidden_headers(void)
assert_no_forbidden_includes(record, "sim_record.c");
assert_no_forbidden_includes(repl_c, "repl.c");
assert_no_forbidden_includes(repl_h, "repl.h");
assert_no_forbidden_includes(repl_break_c, "repl_break.c");
assert_no_forbidden_includes(repl_info_c, "repl_info.c");
assert_no_forbidden_includes(repl_int_h, "repl_internal.h");
free(h_raw);
free(c_raw);
@ -439,28 +481,40 @@ static void test_sim_never_includes_forbidden_headers(void)
free(record_raw);
free(repl_c_raw);
free(repl_h_raw);
free(repl_break_c_raw);
free(repl_info_c_raw);
free(repl_int_h_raw);
free(h);
free(c);
free(loop);
free(record);
free(repl_c);
free(repl_h);
free(repl_break_c);
free(repl_info_c);
free(repl_int_h);
}
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* record_raw = read_whole_file(XCE_SIM_RECORD_C_PATH);
char* repl_c_raw = read_whole_file(XCE_SIM_REPL_C_PATH);
char* repl_h_raw = read_whole_file(XCE_SIM_REPL_H_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* repl_c_raw = read_whole_file(XCE_SIM_REPL_C_PATH);
char* repl_h_raw = read_whole_file(XCE_SIM_REPL_H_PATH);
char* repl_break_c_raw = read_whole_file(XCE_SIM_REPL_BREAK_C_PATH);
char* repl_info_c_raw = read_whole_file(XCE_SIM_REPL_INFO_C_PATH);
char* repl_int_h_raw = read_whole_file(XCE_SIM_REPL_INTERNAL_H_PATH);
char* h;
char* c;
char* loop;
char* record;
char* repl_c;
char* repl_h;
char* repl_break_c;
char* repl_info_c;
char* repl_int_h;
TEST_ASSERT_NOT_NULL(h_raw);
TEST_ASSERT_NOT_NULL(c_raw);
@ -468,19 +522,28 @@ static void test_sim_never_calls_forbidden_symbols(void)
TEST_ASSERT_NOT_NULL(record_raw);
TEST_ASSERT_NOT_NULL(repl_c_raw);
TEST_ASSERT_NOT_NULL(repl_h_raw);
TEST_ASSERT_NOT_NULL(repl_break_c_raw);
TEST_ASSERT_NOT_NULL(repl_info_c_raw);
TEST_ASSERT_NOT_NULL(repl_int_h_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);
repl_c = strip_c_comments(repl_c_raw);
repl_h = strip_c_comments(repl_h_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);
repl_c = strip_c_comments(repl_c_raw);
repl_h = strip_c_comments(repl_h_raw);
repl_break_c = strip_c_comments(repl_break_c_raw);
repl_info_c = strip_c_comments(repl_info_c_raw);
repl_int_h = strip_c_comments(repl_int_h_raw);
TEST_ASSERT_NOT_NULL(h);
TEST_ASSERT_NOT_NULL(c);
TEST_ASSERT_NOT_NULL(loop);
TEST_ASSERT_NOT_NULL(record);
TEST_ASSERT_NOT_NULL(repl_c);
TEST_ASSERT_NOT_NULL(repl_h);
TEST_ASSERT_NOT_NULL(repl_break_c);
TEST_ASSERT_NOT_NULL(repl_info_c);
TEST_ASSERT_NOT_NULL(repl_int_h);
assert_no_forbidden_symbols(h, "sim.h");
assert_no_forbidden_symbols(c, "sim.c");
@ -488,6 +551,9 @@ static void test_sim_never_calls_forbidden_symbols(void)
assert_no_forbidden_symbols(record, "sim_record.c");
assert_no_forbidden_symbols(repl_c, "repl.c");
assert_no_forbidden_symbols(repl_h, "repl.h");
assert_no_forbidden_symbols(repl_break_c, "repl_break.c");
assert_no_forbidden_symbols(repl_info_c, "repl_info.c");
assert_no_forbidden_symbols(repl_int_h, "repl_internal.h");
free(h_raw);
free(c_raw);
@ -495,12 +561,18 @@ static void test_sim_never_calls_forbidden_symbols(void)
free(record_raw);
free(repl_c_raw);
free(repl_h_raw);
free(repl_break_c_raw);
free(repl_info_c_raw);
free(repl_int_h_raw);
free(h);
free(c);
free(loop);
free(record);
free(repl_c);
free(repl_h);
free(repl_break_c);
free(repl_info_c);
free(repl_int_h);
}
/*
@ -544,15 +616,14 @@ 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 + 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
* actually calls. Same technique and same any_undefined_seen
* vacuous-pass guard as test_core_isolation.c's
* test_core_object_has_no_forbidden_undefined_symbols().
* build-time/link-time proof: sim.c + sim_loop.c + sim_record.c + repl.c +
* repl_break.c + repl_info.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 actually
* calls. Same technique and same any_undefined_seen vacuous-pass guard as
* test_core_isolation.c's test_core_object_has_no_forbidden_undefined_symbols().
*/
static void test_sim_object_has_no_forbidden_undefined_symbols(void)
{
@ -575,8 +646,9 @@ 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 four member objects,
* sim.c.o, sim_loop.c.o, sim_record.c.o, and repl.c.o). */
* some nm versions print (this archive has six member objects,
* sim.c.o, sim_loop.c.o, sim_record.c.o, repl.c.o, repl_break.c.o,
* and repl_info.c.o). */
if (sscanf(line, "%511s %c", symbol, &type) != 2) {
continue;
}

View file

@ -40,9 +40,10 @@
* already establish.
*
* White-box #include of the same TU set test_sim_verify.c uses (see that
* file's own header comment) PLUS ../src/recording_session.c (the
* scheduler_t-free session-accumulator entry points sim_loop.c now calls)
* PLUS the new ../src/sim_record.c (the code under test).
* file's own header comment, now including task 12.1's repl.c too) PLUS
* ../src/recording_session.c (the scheduler_t-free session-accumulator
* entry points sim_loop.c now calls) PLUS the new ../src/sim_record.c (the
* code under test).
*/
#include <errno.h>
#include <limits.h>
@ -72,6 +73,9 @@
#include "../src/plugins/builtin_fcfs.c"
#include "../src/recording.c"
#include "../src/recording_session.c"
#include "../src/repl.c"
#include "../src/repl_break.c"
#include "../src/repl_info.c"
#include "../src/sim.c"
#include "../src/sim_loop.c"
#include "../src/sim_record.c"

View file

@ -59,10 +59,10 @@
*
* White-box #include of the same TU set test_sim_event_loop.c uses (see
* that file's own header comment, including task 11.5's
* recording_session.c/sim_record.c -- required at link time by
* sched_sim_driver_run()'s unconditional externs regardless of whether
* --sim-output is ever set in a given test) PLUS ../src/sim_verify.c (the
* code under test).
* recording_session.c/sim_record.c AND task 12.1's repl.c -- all required at
* link time by sched_sim_driver_run()'s/repl.h's unconditional externs
* regardless of whether --sim-output/--interactive is ever set in a given
* test) PLUS ../src/sim_verify.c (the code under test).
*/
#include <errno.h>
#include <limits.h>
@ -93,6 +93,9 @@
#include "../src/plugins/builtin_fcfs.c"
#include "../src/recording.c"
#include "../src/recording_session.c"
#include "../src/repl.c"
#include "../src/repl_break.c"
#include "../src/repl_info.c"
#include "../src/sim.c"
#include "../src/sim_loop.c"
#include "../src/sim_record.c"