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:
parent
3a6b503f07
commit
05320e777b
8 changed files with 257 additions and 147 deletions
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue