feat(scheduler-sim-discrete-clock): --sim-speed deprecation-warning helper and discrete-clock test binary (task 1.1)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-09-29 04:23:46 +00:00
parent 4b6872d053
commit 4f653d8fbe
Signed by untrusted user: rshen
GPG key ID: 80533536B0EB651C
6 changed files with 232 additions and 2 deletions

View file

@ -2333,3 +2333,23 @@ sched_alloc_from_stamp_test = executable(
test('scheduler alloc from stamp test',
sched_alloc_from_stamp_test, suite: 'scheduler',
env: ['ASAN_OPTIONS=detect_leaks=0'])
# scheduler-sim-discrete-clock spec (task 1.1, Req 2.3-2.5): unit tests for
# the --sim-speed deprecation warning (../src/cli_compat.c), and -- in later
# tasks -- the discrete-clock and end-to-end command-line tests. Sources are
# the test file and cli_compat.c ONLY: the white-box sim #includes live in
# the test file itself (listing sim sources here too would define every
# symbol twice). XCE_SCHEDULER_BIN points the end-to-end tests at the built
# xce_scheduler, which `depends: scheduler` guarantees is built first.
sched_sim_discrete_clock_test = executable(
'sched_sim_discrete_clock_test',
['test_sim_discrete_clock.c', '../src/cli_compat.c'],
include_directories:[incdir],
dependencies: [scheduler_test_deps, libedit_dep],
c_args: ['-DXCE_SCHEDULER_BIN="' + scheduler.full_path() + '"'],
install: false)
test('scheduler sim discrete clock test',
sched_sim_discrete_clock_test, suite: 'scheduler',
env: ['ASAN_OPTIONS=detect_leaks=0'],
depends: scheduler)

View file

@ -0,0 +1,161 @@
/*
* test_sim_discrete_clock.c - tests for the scheduler-sim-discrete-clock
* spec.
*
* Task 1.1 (Requirements 2.3, 2.4, 2.5; design.md, Components: CliCompat,
* Testing Strategy: Unit (CliCompat)): sched_cli_warn_deprecated_options()
* logs exactly one warning naming the quoted --sim-speed value, stating it
* is deprecated, has no effect and will be removed, for ANY value (numeric,
* non-numeric, negative, empty), and logs nothing when the option was not
* given (NULL).
*
* This binary deliberately never calls mylog_init(): without it, tlog's
* early-print path writes WARN lines to stdout, which the test-local
* capture_stdout_around() below captures.
*
* XCE_SCHEDULER_BIN (compile-time, from the scheduler executable's
* full_path() in testsuite/meson.build) is used by the end-to-end tests
* later tasks add to this file.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <unity/unity.h>
#include "cli_compat.h"
#if !defined(XCE_SCHEDULER_BIN)
#error "XCE_SCHEDULER_BIN must be defined by testsuite/meson.build"
#endif
void setUp(void) { return; }
void tearDown(void) { return; }
/* ---------------------------------------------------------------------- */
/* Fixture helpers -- test-local copy of the dup()/dup2() stdout capture */
/* used by test_repl_help.c (each test file carries its own copy). */
/* ---------------------------------------------------------------------- */
static const char* g_warn_value;
static void call_warn_helper(void)
{
sched_cli_warn_deprecated_options(g_warn_value);
}
static char* capture_stdout_around(void (*fn)(void))
{
char tmp[] = "/tmp/xce_simclock_stdoutcap_XXXXXX";
int fd = mkstemp(tmp);
int saved_stdout;
off_t len;
char* buf;
TEST_ASSERT_TRUE_MESSAGE(fd >= 0, "mkstemp for stdout capture must "
"succeed");
fflush(stdout);
saved_stdout = dup(STDOUT_FILENO);
TEST_ASSERT_TRUE_MESSAGE(saved_stdout >= 0, "dup(STDOUT_FILENO) must "
"succeed");
TEST_ASSERT_TRUE_MESSAGE(dup2(fd, STDOUT_FILENO) >= 0,
"dup2 redirect of STDOUT_FILENO must succeed");
fn();
fflush(stdout);
dup2(saved_stdout, STDOUT_FILENO);
close(saved_stdout);
len = lseek(fd, 0, SEEK_CUR);
TEST_ASSERT_TRUE(len >= 0);
buf = (char*)calloc(1, (size_t)len + 1);
TEST_ASSERT_NOT_NULL(buf);
if (len > 0) {
TEST_ASSERT_EQUAL_INT64((int64_t)len, (int64_t)pread(fd, buf,
(size_t)len, 0));
}
close(fd);
unlink(tmp);
return buf;
}
static int count_lines(const char* s)
{
int n = 0;
for (; *s != '\0'; s++) {
if (*s == '\n') {
n++;
}
}
return n;
}
/* Asserts the captured output is exactly one line naming the quoted value
* and carrying every required phrase. */
static void assert_one_warning_for(const char* value)
{
char* out;
char quoted[64];
g_warn_value = value;
out = capture_stdout_around(call_warn_helper);
snprintf(quoted, sizeof(quoted), "\"%s\"", value);
TEST_ASSERT_EQUAL_INT_MESSAGE(1, count_lines(out),
"exactly one warning line expected");
TEST_ASSERT_NOT_NULL_MESSAGE(strstr(out, quoted),
"warning must name the quoted value");
TEST_ASSERT_NOT_NULL_MESSAGE(strstr(out, "--sim-speed"),
"warning must name --sim-speed");
TEST_ASSERT_NOT_NULL_MESSAGE(strstr(out, "deprecated"),
"warning must say deprecated");
TEST_ASSERT_NOT_NULL_MESSAGE(strstr(out, "no effect"),
"warning must say no effect");
TEST_ASSERT_NOT_NULL_MESSAGE(strstr(out, "will be removed"),
"warning must say will be removed");
free(out);
}
/* ---------------------------------------------------------------------- */
/* CliCompat (Requirements 2.3, 2.4, 2.5) */
/* ---------------------------------------------------------------------- */
static void test_warn_numeric_zero_value(void) { assert_one_warning_for("0"); }
static void test_warn_non_numeric_value(void) { assert_one_warning_for("abc"); }
static void test_warn_negative_value(void) { assert_one_warning_for("-1"); }
static void test_warn_empty_value(void) { assert_one_warning_for(""); }
static void test_no_warning_when_option_absent(void)
{
char* out;
g_warn_value = NULL;
out = capture_stdout_around(call_warn_helper);
TEST_ASSERT_EQUAL_STRING_MESSAGE("", out,
"NULL (option not given) must log "
"nothing");
free(out);
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_warn_numeric_zero_value);
RUN_TEST(test_warn_non_numeric_value);
RUN_TEST(test_warn_negative_value);
RUN_TEST(test_warn_empty_value);
RUN_TEST(test_no_warning_when_option_absent);
return UNITY_END();
}