feat(scheduler-sim-discrete-clock): remove the REPL speed parameter (task 2.2)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-09-29 04:53:20 +00:00
parent 3a6b503f07
commit 05320e777b
Signed by untrusted user: rshen
GPG key ID: 80533536B0EB651C
8 changed files with 257 additions and 147 deletions

View file

@ -250,9 +250,9 @@ static void repl_print_banner(const xce_sched_sim_driver_t* sim)
* flat, independently hand-padded list into four labeled sections --
* Execution Control, Breakpoints, State Inspection (now including `info
* config`, moved here next to its `info` siblings per Req 7.3), and
* Snapshot & Parameters (now including `set units`, alongside `set speed`/
* `set output`/`set verify`) -- each line rendered through the SAME
* `FIELD_FMT` fixed-field-width format, so a future command addition can't
* Snapshot & Parameters (now including `set units`, alongside `set output`/
* `set verify`; `set speed` was removed by scheduler-sim-discrete-clock)
* -- each line rendered through the SAME `FIELD_FMT` fixed-field-width format, so a future command addition can't
* silently break alignment the way `info config`'s old hand-counted append
* did (Req 7.2). `FIELD_FMT`'s "%-38s" width is sized to the longest
* command/argument field below ("break <EVENT_TYPE> [key=value ...]", 34
@ -311,7 +311,6 @@ static void repl_print_help(void)
fprintf(stdout, "\nSnapshot & Parameters:\n");
fprintf(stdout, FIELD_FMT, "snapshot [FILE]",
"Write a standalone snapshot.");
fprintf(stdout, FIELD_FMT, "set speed <N>", "Set simulation speed.");
fprintf(stdout, FIELD_FMT, "set output <FILE>|off",
"Start/stop writing decisions.");
fprintf(stdout, FIELD_FMT, "set verify on|off",

View file

@ -20,8 +20,8 @@
* `info resource`/`info summary`/`info break`/`info config`, and the
* `repl_cmd_info()` dispatcher repl.c's repl_dispatch() hands off to
* (repl_internal.h's own extern declaration). `info config` is the
* read-only counterpart to repl_params.c's `set speed`/`set output`/
* `set verify` -- grouped here with every other `info` dump rather than in
* read-only counterpart to repl_params.c's `set output`/`set verify` --
* grouped here with every other `info` dump rather than in
* repl_params.c, per this file's own domain-ownership scope.
*
* Every dump below reads core->jobs/queues/workers/resmgr the SAME way
@ -1768,14 +1768,12 @@ static void repl_info_session(xce_sched_sim_driver_t* sim)
/*
* repl_info_config - AC 22's "info config": "Show current sim parameters:
* speed=N, output=<path or \"off\">, verify=on|off, events_processed=N,
* current_ts=<logical_time>, sessions=N." Read-only counterpart to
* repl_params.c's `set speed`/`set output`/`set verify` (task 12.3) --
* reads sim->sim_speed_num (the driver-level shadow copy sim.h's own doc
* comment says exists precisely "for the REPL/diagnostics to read without
* reaching into core", kept in sync with the real core.speed_num/speed_den
* atomics by every `set speed` call, repl_params.c's repl_set_speed()),
* sim->record_file/rs->output_path (repl_params.c's own output_path field
* output=<path or \"off\">, verify=on|off, events_processed=N,
* current_ts=<logical_time>, sessions=N." (The speed item was removed with
* the REPL speed parameter, scheduler-sim-discrete-clock Req 3.4: the
* simulator clock moves only at recorded timestamps.) Read-only
* counterpart to repl_params.c's `set output`/`set verify` (task 12.3) --
* reads sim->record_file/rs->output_path (repl_params.c's own output_path field
* doc comment explains the "path unknown" fallback for a --sim-output
* stream this REPL session never itself opened), sim->verify, and the SAME
* rs->event_index/rs->session_count `info session` already reports
@ -1798,9 +1796,9 @@ static void repl_info_config(xce_sched_sim_driver_t* sim)
repl_format_ts_human(xce_core_now(&(sim->core)), ts_human,
sizeof(ts_human));
fprintf(stdout, "[sim] config: speed=%llu output=%s verify=%s "
fprintf(stdout, "[sim] config: output=%s verify=%s "
"events_processed=%llu current_ts=%llu (%s) sessions=%llu\n",
(unsigned long long)sim->sim_speed_num, output_desc,
output_desc,
sim->verify ? "on" : "off",
(unsigned long long)((rs != NULL) ? rs->event_index : 0),
(unsigned long long)xce_core_now(&(sim->core)), ts_human,

View file

@ -21,7 +21,7 @@
* (CLAUDE.md/coding-style.md). Split along the same domain boundaries
* task 8.1 already used for snapshot.c/snapshot_wire.c/snapshot_load.c
* (that file's own "Three-file split" header section is the precedent).
* Task 12.3 (snapshot capture + `set speed`/`set output`/`set verify`)
* Task 12.3 (snapshot capture + `set output`/`set verify`)
* adds a FOURTH file, repl_params.c, for the identical reason: neither
* repl_break.c nor repl_info.c had enough remaining headroom under the
* 800-line cap to absorb this task's own real chunk of new logic (both
@ -46,7 +46,7 @@
* domain-wise with every other `info` dump, matching this file's own
* "Owns" doc comment).
* - repl_params.c (task 12.3): the `snapshot [FILE]` and `set
* speed|output|verify ...` command handlers -- mutating the simulation
* output|verify|units ...` command handlers -- mutating the simulation
* parameters `info config` (repl_info.c) reports.
*
* `struct xce_sched_repl_state_s` (the full definition of sim.h's opaque

View file

@ -19,7 +19,7 @@
* gets its own file, matching task 12.2's own precedent for the identical
* problem.
*
* Owns: the `snapshot [FILE]` and `set speed|output|verify ...` command
* Owns: the `snapshot [FILE]` and `set output|verify|units ...` command
* handlers (repl_cmd_snapshot()/repl_cmd_set(), repl_internal.h's own
* extern declarations; repl.c's repl_dispatch() hands off to both). `info
* config` -- the read-only counterpart that reports the SAME parameters
@ -41,11 +41,10 @@
* own file header comment for the precedent this follows). Neither command
* hand-rolls capnp encoding.
*
* `set speed`'s atomic_store_explicit()/memory_order_release calls need no
* `#include <stdatomic.h>` of their own -- core.h (pulled in transitively
* via repl.h -> sim.h -> core.h) already includes it, the SAME reason
* sim.c's own sim_set_virtual_clock() (the function this file's
* repl_set_speed() mirrors) needs no direct include either.
* `set speed` is no longer a parameter (scheduler-sim-discrete-clock, Req
* 3.1-3.3): the simulator clock moves only at recorded timestamps, so
* repl_cmd_set() answers it with a fixed removal message and changes
* nothing.
*/
extern int sim_record_write_header_and_snapshot(FILE* f, xce_sched_core_t* core,
@ -168,64 +167,9 @@ bool repl_cmd_snapshot(xce_sched_sim_driver_t* sim, const char* line)
}
/* ------------------------------------------------------------------------
* set speed|output|verify ...
* set output|verify|units ...
* ---------------------------------------------------------------------- */
/*
* repl_set_speed - AC 22's "set speed <N>": mutates BOTH
* sim->sim_speed_num/sim_speed_den (the driver-level shadow copy sim.h's
* own doc comment says exists "for the REPL/diagnostics to read without
* reaching into `core`" -- `info config`'s own speed= field, repl_info.c,
* reads these) AND sim->core.speed_num/speed_den -- the atomic pair
* core_clock.c's xce_core_now() actually consults, FRESH, on every single
* call (no caching) -- via the SAME two atomic_store_explicit() calls
* sim_set_virtual_clock() (sim.c, Req 5 AC 13 Step 4) already performs at
* startup for the identical pair. Mutating only the shadow copy would leave
* `info config` and reality disagreeing forever; sim_loop.c needs no new
* call site for this to take effect -- xce_core_now() is already called
* throughout its event loop on every iteration, so the very next call
* observes the new speed.
*
* `N` = 0 (freeze / "as-fast-as-possible", AC 22's own table wording) is
* accepted here, unlike `step`'s N (repl_cmd_step(), repl.c), which
* rejects N<=0 -- speed=0 is a legitimate, documented mode (core.h's own
* speed_num/speed_den field doc comment: "discrete-simulation freezes via
* speed_num=0"), not a user error.
*
* Deliberately does NOT re-anchor virtual_clock_base/real_clock_base:
* those are only ever re-anchored by sim_advance_virtual_clock()
* (sim_loop.c) at each event/session-boundary jump, and the REPL only ever
* regains control AT one of those jump points (the pre-replay pause, a
* post-session pause, or a breakpoint hit) -- so leaving them untouched
* here introduces no discontinuity in xce_core_now()'s reported value.
*/
static bool repl_set_speed(xce_sched_sim_driver_t* sim, const char* value)
{
char* endptr;
uint64_t n;
if (value[0] == '\0') {
fprintf(stdout, "[sim] set speed: usage: set speed <N>\n");
return false;
}
n = strtoull(value, &endptr, 10);
if (*endptr != '\0') {
fprintf(stdout, "[sim] set speed: '%s' is not a valid non-negative integer\n",
value);
return false;
}
atomic_store_explicit(&(sim->core.speed_num), n, memory_order_release);
atomic_store_explicit(&(sim->core.speed_den), 1, memory_order_release);
sim->sim_speed_num = n;
sim->sim_speed_den = 1;
fprintf(stdout, "[sim] speed set to %llu\n", (unsigned long long)n);
return false;
}
/*
* repl_set_output_off - AC 22's "set output off": "Close the current
* output file. info config confirms the path and event count at close
@ -345,8 +289,8 @@ static bool repl_set_output_file(xce_sched_sim_driver_t* sim, const char* path)
* raw|human|both": selects the operator's resource-value display mode
* (rs->units_mode), read by the (task 8, not yet implemented) `info
* worker`/`info resource` table renderer. Same per-key
* usage-message-on-invalid-value pattern repl_set_speed()/`set verify`
* (above) already establish -- an unrecognized VALUE is rejected with a
* usage-message-on-invalid-value pattern `set verify` (in repl_cmd_set(),
* below) already establishes -- an unrecognized VALUE is rejected with a
* units-specific usage message and leaves the current mode unchanged, never
* the generic "unrecognized parameter" message repl_cmd_set() falls through
* to below (that message fires only for an unrecognized KEY; `units` IS a
@ -386,26 +330,34 @@ static bool repl_set_units(xce_sched_sim_driver_t* sim, const char* value)
}
/*
* repl_cmd_set - Req 5 AC 22's "set ..." family: "set speed <N>" /
* "set output <FILE>|off" / "set verify on|off" / "set units
* raw|human|both" (the last added by scheduler-sim-repl-verbosity's task
* 7.2, Req 6.2/6.3). `line` re-tokenized via repl_split_tokens() (repl.c),
* same as break/delete/info.
* repl_cmd_set - Req 5 AC 22's "set ..." family: "set output <FILE>|off" /
* "set verify on|off" / "set units raw|human|both" (the last added by
* scheduler-sim-repl-verbosity's task 7.2, Req 6.2/6.3). `line`
* re-tokenized via repl_split_tokens() (repl.c), same as break/delete/info.
*
* "set speed" (with or without a value) was removed by
* scheduler-sim-discrete-clock (Req 3.1-3.3): it is checked BEFORE the
* argument-count check so a bare `set speed` gets the removal message, not
* the usage text, and it returns to the prompt without touching the clock
* or the core speed setting.
*/
bool repl_cmd_set(xce_sched_sim_driver_t* sim, const char* line)
{
char tokens[XCE_REPL_MAX_TOKENS][XCE_REPL_TOKEN_LEN];
int ntok = repl_split_tokens(line, tokens, XCE_REPL_MAX_TOKENS);
if ((ntok >= 2) && (strcmp(tokens[1], "speed") == 0)) {
fprintf(stdout, "[sim] set speed: the speed parameter was removed; "
"the simulator clock moves only at recorded timestamps\n");
return false;
}
if (ntok < 3) {
fprintf(stdout, "[sim] set: usage: set speed <N> | set output <FILE>|off | "
fprintf(stdout, "[sim] set: usage: set output <FILE>|off | "
"set verify on|off | set units raw|human|both\n");
return false;
}
if (strcmp(tokens[1], "speed") == 0) {
return repl_set_speed(sim, tokens[2]);
}
if (strcmp(tokens[1], "output") == 0) {
if (strcmp(tokens[2], "off") == 0) {
return repl_set_output_off(sim);

View file

@ -5,8 +5,8 @@
* into four labeled sections, aligns every command's description to one
* consistent column position throughout (not independently hand-padded per
* line), lists `info config` together with the other `info` subcommands in
* the state-inspection section, lists `set units` alongside `set speed`/
* `set output`/`set verify` in the snapshot-and-parameters section, and
* the state-inspection section, lists `set units` alongside `set output`/
* `set verify` in the snapshot-and-parameters section, and
* enumerates the complete set of valid `break <EVENT_TYPE>` values on its
* `break` line. `break`'s own unrecognized-event-type error message
* (Requirement 7.5) is NOT covered here -- that lives in the sibling
@ -552,8 +552,9 @@ static const char* BP_KIND_TOKENS[] = {
/* command's line falling within its correct section's bounds -- including */
/* `info config` landing inside State Inspection next to its `info` */
/* siblings (Requirement 7.3), and `set units` landing inside Snapshot & */
/* Parameters next to `set speed`/`set output`/`set verify` (Requirement */
/* 7.1/7.4's section-organization half). */
/* Parameters next to `set output`/`set verify` (Requirement 7.1/7.4's */
/* section-organization half), and no `set speed` line anywhere (the REPL */
/* speed parameter was removed, scheduler-sim-discrete-clock Req 3.3). */
/* ---------------------------------------------------------------------- */
static void test_help_groups_commands_into_four_labeled_sections_in_order(
@ -646,13 +647,13 @@ static void test_help_groups_commands_into_four_labeled_sections_in_order(
}
}
/* Snapshot & Parameters: snapshot/set speed/set output/set verify/set
/* Snapshot & Parameters: snapshot/set output/set verify/set
* units, all after Snapshot & Parameters's own label (last section, so
* only a lower bound applies). `set units`'s exact argument spelling is
* deliberately not pinned here -- only its existence and placement. */
{
const char* fields[] = {
"snapshot [FILE]", "set speed <N>", "set output <FILE>|off",
"snapshot [FILE]", "set output <FILE>|off",
"set verify on|off", "set units",
};
size_t i;
@ -669,6 +670,11 @@ static void test_help_groups_commands_into_four_labeled_sections_in_order(
}
}
TEST_ASSERT_NULL_MESSAGE(strstr(captured, "set speed"),
"help must not list the removed `set speed` "
"parameter (scheduler-sim-discrete-clock Req "
"3.3)");
free(captured);
printf("test_help_groups_commands_into_four_labeled_sections_in_order: "
@ -708,7 +714,6 @@ static void test_help_uses_one_consistent_column_width_throughout(void)
"info summary",
"info config",
"snapshot [FILE]",
"set speed <N>",
"set output <FILE>|off",
"set verify on|off",
};

View file

@ -13,7 +13,7 @@
* definitions, this same file (unmodified) becomes the GREEN-phase proof.
* `set units` parsing (also part of Requirement 6.2/6.3) is covered
* separately in test_repl_snapshot_params.c, alongside that file's existing
* `set speed`/`set output`/`set verify` tests -- this file covers ONLY the
* `set output`/`set verify` tests -- this file covers ONLY the
* two pure classification/scaling functions.
*
* Declaring the functions under test: same rationale as

View file

@ -15,18 +15,19 @@
* reloaded core state (snapshot_ts, the pushed job) matches what the
* child's session actually produced.
*
* The remaining tests cover `set speed`/`set output`/`set verify`/
* `info config` and the auto-generated `snapshot` filename, at the same
* The remaining tests cover `set output`/`set verify`/`info config`, the
* removed `set speed` parameter (scheduler-sim-discrete-clock, Req 3.1-3.5:
* it prints a removal message and changes nothing) and the auto-generated
* `snapshot` filename, at the same
* "unit-level precision where possible, integration-level proof for the
* one Observable that needs it" split test_repl_execution_control.c's own
* header comment establishes.
*
* `set units raw|human|both` (scheduler-sim-repl-verbosity spec, task 7.1,
* Requirement 6.2/6.3) is added below, alongside the existing `set speed`/
* `set output`/`set verify` tests, per design.md's File Structure Plan
* Requirement 6.2/6.3) is added below, alongside the existing `set output`/
* `set verify` tests, per that spec's design.md File Structure Plan
* ("test_repl_snapshot_params.c -- extended with `set units raw|human|both`
* parsing/validation tests ... alongside its existing `set speed`/`set
* output`/`set verify` tests"). THIS SLICE IS RED-PHASE ONLY: neither
* parsing/validation tests ... alongside its existing `set ...` tests"). THIS SLICE IS RED-PHASE ONLY: neither
* xce_sched_repl_state_s's `units_mode` field nor repl_cmd_set()'s `units`
* branch exists yet (task 7.2, a separate later task, adds both) -- see
* that test group's own header comment further below for the exact
@ -880,42 +881,195 @@ static void test_snapshot_auto_generates_filename_from_event_index(void)
}
/* ---------------------------------------------------------------------- */
/* Test: `set speed <N>` mutates BOTH the driver-level shadow copy AND the */
/* atomic core.speed_num/speed_den pair xce_core_now() actually reads. */
/* Test: `set speed` (with or without a value) prints the removal message, */
/* hands control back to the prompt and leaves the simulation clock and */
/* the core speed atoms untouched (scheduler-sim-discrete-clock, Req 3.1, */
/* 3.2, 1.5). */
/* ---------------------------------------------------------------------- */
static void test_set_speed_updates_shadow_and_core_atomics(void)
#define SET_SPEED_REMOVED_MSG \
"[sim] set speed: the speed parameter was removed; the simulator " \
"clock moves only at recorded timestamps"
static xce_sched_sim_driver_t g_speed_sim;
static bool g_speed_handled;
static const char* g_speed_line;
static void run_set_speed_line(void)
{
g_speed_handled = repl_cmd_set(&g_speed_sim, g_speed_line);
}
static void assert_set_speed_removed(const char* line)
{
char* captured;
memset(&g_speed_sim, 0, sizeof(g_speed_sim));
atomic_store_explicit(&(g_speed_sim.core.virtual_clock_base), 5000ULL,
memory_order_release);
atomic_store_explicit(&(g_speed_sim.core.real_clock_base), 0ULL,
memory_order_release);
atomic_store_explicit(&(g_speed_sim.core.speed_num), 0ULL,
memory_order_release);
atomic_store_explicit(&(g_speed_sim.core.speed_den), 1ULL,
memory_order_release);
g_speed_line = line;
g_speed_handled = true;
captured = capture_stdout_around(run_set_speed_line);
TEST_ASSERT_FALSE_MESSAGE(g_speed_handled,
"`set speed` must return to the prompt");
TEST_ASSERT_NOT_NULL_MESSAGE(strstr(captured, SET_SPEED_REMOVED_MSG),
"`set speed` must print the removal "
"message");
TEST_ASSERT_NULL_MESSAGE(strstr(captured, "usage"),
"`set speed` must not fall through to the "
"`set` usage message");
TEST_ASSERT_NULL_MESSAGE(strstr(captured, "speed set to"),
"`set speed` must not report a new speed");
TEST_ASSERT_EQUAL_UINT64_MESSAGE(5000ULL,
xce_core_now(&(g_speed_sim.core)),
"`set speed` must not move the "
"simulation clock");
TEST_ASSERT_EQUAL_UINT64(
0ULL, atomic_load_explicit(&(g_speed_sim.core.speed_num),
memory_order_acquire));
TEST_ASSERT_EQUAL_UINT64(
1ULL, atomic_load_explicit(&(g_speed_sim.core.speed_den),
memory_order_acquire));
TEST_ASSERT_EQUAL_UINT64(
5000ULL, atomic_load_explicit(&(g_speed_sim.core.virtual_clock_base),
memory_order_acquire));
free(captured);
}
static void test_set_speed_prints_removal_message_and_changes_nothing(void)
{
assert_set_speed_removed("set speed 7");
assert_set_speed_removed("set speed");
printf("test_set_speed_prints_removal_message_and_changes_nothing: "
"PASS\n");
}
/* ---------------------------------------------------------------------- */
/* Test: the bare `set` usage message no longer offers a speed setting */
/* (Req 3.3) and still lists output/verify/units (Req 3.5). */
/* ---------------------------------------------------------------------- */
static xce_sched_sim_driver_t g_usage_sim;
static void run_set_bare(void) { (void)repl_cmd_set(&g_usage_sim, "set"); }
static void test_set_usage_omits_speed(void)
{
char* captured;
memset(&g_usage_sim, 0, sizeof(g_usage_sim));
captured = capture_stdout_around(run_set_bare);
TEST_ASSERT_NOT_NULL(strstr(captured, "[sim] set: usage: "
"set output <FILE>|off | "
"set verify on|off | "
"set units raw|human|both"));
TEST_ASSERT_NULL_MESSAGE(strstr(captured, "speed"),
"the `set` usage message must not mention "
"speed");
free(captured);
printf("test_set_usage_omits_speed: PASS\n");
}
/* ---------------------------------------------------------------------- */
/* Test: a scripted interactive REPL run (`set speed 7`, `info config`, */
/* `quit`) keeps reading after `set speed`, prints the removal message and */
/* the config line, and exits 0 through `quit` (Req 3.1, 3.2, 3.4). */
/* ---------------------------------------------------------------------- */
static void child_run_repl_script(const char* replay_path,
const char* script_path,
const char* capture_path)
{
xce_sched_sim_driver_t sim;
bool handled;
sched_sim_args_t args;
if (freopen(script_path, "r", stdin) == NULL) {
_exit(120);
}
if (freopen(capture_path, "w", stdout) == NULL) {
_exit(121);
}
memset(&sim, 0, sizeof(sim));
memset(&args, 0, sizeof(args));
args.replay_path = replay_path;
args.sim_start_ts = SCHED_SIM_START_TS_LATEST;
args.interactive = true;
handled = repl_cmd_set(&sim, "set speed 7");
TEST_ASSERT_FALSE_MESSAGE(handled, "`set` never hands control back");
TEST_ASSERT_EQUAL_UINT64(7ULL, sim.sim_speed_num);
TEST_ASSERT_EQUAL_UINT64(1ULL, sim.sim_speed_den);
TEST_ASSERT_EQUAL_UINT64(
7ULL, atomic_load_explicit(&(sim.core.speed_num), memory_order_acquire));
TEST_ASSERT_EQUAL_UINT64(
1ULL, atomic_load_explicit(&(sim.core.speed_den), memory_order_acquire));
(void)sched_sim_driver_run(&sim, &args);
/* speed=0 (freeze / as-fast-as-possible) is a legitimate value, unlike
* `step`'s N (which rejects <= 0). */
handled = repl_cmd_set(&sim, "set speed 0");
TEST_ASSERT_FALSE(handled);
TEST_ASSERT_EQUAL_UINT64(0ULL, sim.sim_speed_num);
TEST_ASSERT_EQUAL_UINT64(
0ULL, atomic_load_explicit(&(sim.core.speed_num), memory_order_acquire));
/* Unreachable in a correct implementation -- "quit" calls exit(0). */
fflush(stdout);
_exit(111);
}
/* Malformed input must be rejected AND leave state unchanged. */
handled = repl_cmd_set(&sim, "set speed abc");
TEST_ASSERT_FALSE(handled);
TEST_ASSERT_EQUAL_UINT64_MESSAGE(0ULL, sim.sim_speed_num,
"a malformed `set speed` argument must "
"not change the current speed");
static void test_scripted_repl_set_speed_then_info_config_then_quit(void)
{
char replay_path[PATH_MAX];
char aux_dir[PATH_MAX];
char script_path[PATH_MAX];
char capture_path[PATH_MAX];
FILE* f;
pid_t pid;
int status;
char* captured;
char* cfg_line;
printf("test_set_speed_updates_shadow_and_core_atomics: PASS\n");
f = write_header_and_snapshot(replay_path, sizeof(replay_path),
"_setspeedscript");
TEST_ASSERT_NOT_NULL(f);
append_queue_update_event(f, 1000ULL, "normal");
append_replay_session(f, 2000ULL);
append_end_of_stream_marker(f);
fclose(f);
make_tmp_dir(aux_dir, sizeof(aux_dir), "_setspeedscriptaux");
snprintf(script_path, sizeof(script_path), "%s/script.txt", aux_dir);
snprintf(capture_path, sizeof(capture_path), "%s/capture.out", aux_dir);
write_text_file(script_path, "set speed 7\ninfo config\nquit\n");
pid = fork();
TEST_ASSERT_TRUE_MESSAGE(pid >= 0, "fork() must succeed");
if (pid == 0) {
child_run_repl_script(replay_path, script_path, capture_path);
_exit(112); /* unreachable */
}
TEST_ASSERT_EQUAL_INT_MESSAGE(pid, waitpid(pid, &status, 0),
"waitpid must reap the REPL child");
TEST_ASSERT_TRUE_MESSAGE(WIFEXITED(status),
"the REPL child must exit normally via quit's "
"exit(0)");
TEST_ASSERT_EQUAL_INT_MESSAGE(0, WEXITSTATUS(status),
"quit's exit(0) is the only correct exit "
"path");
captured = read_whole_file(capture_path);
TEST_ASSERT_NOT_NULL_MESSAGE(strstr(captured, SET_SPEED_REMOVED_MSG),
"the scripted `set speed 7` must print the "
"removal message");
cfg_line = strstr(captured, "[sim] config:");
TEST_ASSERT_NOT_NULL_MESSAGE(cfg_line,
"the REPL must keep reading after `set "
"speed` and run `info config`");
TEST_ASSERT_NULL_MESSAGE(strstr(cfg_line, "speed="),
"`info config` must not report a speed item");
free(captured);
printf("test_scripted_repl_set_speed_then_info_config_then_quit: "
"PASS\n");
}
/* ---------------------------------------------------------------------- */
@ -1041,15 +1195,13 @@ static void test_set_output_opens_writes_preamble_and_off_closes(void)
/* */
/* Direct struct inspection (rs->units_mode) observes the setting rather */
/* than routing through `info config`: today `info config` reports only */
/* speed/output/verify/events_processed/current_ts/sessions
/* output/verify/events_processed/current_ts/sessions
* (test_info_config_reports_current_parameters below), it does not report
* units_mode, and design.md's Traceability table never lists `info config`
* as a Resource Value Formatter dependency -- extending it is out of this
* task's scope (that belongs to task 8, the table-layout task). Direct
* struct access is the same technique
* test_set_speed_updates_shadow_and_core_atomics/
* test_set_verify_toggles_flag already use for their own driver-state
* fields (sim.sim_speed_num, sim.verify) above.
* struct access is the same technique test_set_verify_toggles_flag
* already uses for its own driver-state field (sim.verify) above.
*/
static void test_set_units_raw_human_both_update_display_mode(void)
@ -1122,8 +1274,7 @@ static void test_set_units_invalid_value_rejected_like_existing_pattern(void)
TEST_ASSERT_NOT_NULL_MESSAGE(
strstr(captured, "set units"),
"an unrecognized `set units` value must be rejected with a "
"units-specific usage message -- matching `set speed`'s "
"\"[sim] set speed: usage: set speed <N>\" and `set verify`'s "
"units-specific usage message -- matching `set verify`'s "
"\"[sim] set verify: usage: set verify on|off\" per-key "
"usage-error pattern (repl_params.c), NOT the generic \"[sim] set: "
"unrecognized parameter 'units'\" message that fires today for an "
@ -1132,8 +1283,8 @@ static void test_set_units_invalid_value_rejected_like_existing_pattern(void)
TEST_ASSERT_EQUAL_MESSAGE(
XCE_REPL_UNITS_BOTH, g_units_invalid_sim.repl_state->units_mode,
"a rejected `set units` value must leave the current display mode "
"unchanged -- same discipline `set speed`/`set verify`'s own "
"malformed-input tests already establish for their own fields");
"unchanged -- same discipline `set verify`'s own "
"malformed-input test already establishes for its own field");
free(captured);
printf("test_set_units_invalid_value_rejected_like_existing_pattern: "
@ -1141,9 +1292,9 @@ static void test_set_units_invalid_value_rejected_like_existing_pattern(void)
}
/* ---------------------------------------------------------------------- */
/* Test: `info config` reports speed/output/verify/events_processed/ */
/* current_ts/sessions, both while output is off and while it is active */
/* with a known path. */
/* Test: `info config` reports output/verify/events_processed/current_ts/ */
/* sessions and no speed item (scheduler-sim-discrete-clock, Req 3.4), */
/* both while output is off and while it is active with a known path. */
/* ---------------------------------------------------------------------- */
static xce_sched_sim_driver_t g_cfg_sim;
@ -1169,7 +1320,9 @@ static void test_info_config_reports_current_parameters(void)
g_cfg_sim.record_file = NULL;
captured = capture_stdout_around(run_info_config);
TEST_ASSERT_NOT_NULL(strstr(captured, "speed=3"));
TEST_ASSERT_NULL_MESSAGE(strstr(captured, "speed="),
"info config must not report a speed item "
"(the REPL speed parameter was removed)");
TEST_ASSERT_NOT_NULL(strstr(captured, "output=off"));
TEST_ASSERT_NOT_NULL(strstr(captured, "verify=on"));
TEST_ASSERT_NOT_NULL(strstr(captured, "events_processed=7"));
@ -1209,7 +1362,8 @@ static void test_help_lists_snapshot_and_set_commands(void)
char* captured = capture_stdout_around(run_print_help);
TEST_ASSERT_NOT_NULL(strstr(captured, "snapshot"));
TEST_ASSERT_NOT_NULL(strstr(captured, "set speed"));
TEST_ASSERT_NULL_MESSAGE(strstr(captured, "speed"),
"help must not offer a speed setting");
TEST_ASSERT_NOT_NULL(strstr(captured, "set output"));
TEST_ASSERT_NOT_NULL(strstr(captured, "set verify"));
TEST_ASSERT_NOT_NULL(strstr(captured, "info config"));
@ -1224,7 +1378,9 @@ int main(void)
RUN_TEST(test_snapshot_written_file_is_loadable_by_fresh_sim_start);
RUN_TEST(test_snapshot_auto_generates_filename_from_event_index);
RUN_TEST(test_set_speed_updates_shadow_and_core_atomics);
RUN_TEST(test_set_speed_prints_removal_message_and_changes_nothing);
RUN_TEST(test_set_usage_omits_speed);
RUN_TEST(test_scripted_repl_set_speed_then_info_config_then_quit);
RUN_TEST(test_set_verify_toggles_flag);
RUN_TEST(test_set_output_opens_writes_preamble_and_off_closes);
RUN_TEST(test_set_units_raw_human_both_update_display_mode);