/* * vlibc — syslog.h test (todo 36). * * Coverage (what is observable without a syslog daemon or a /dev/log * reader): * * 1. mask semantics: setlogmask returns the PREVIOUS mask, starts from the * default LOG_UPTO(LOG_DEBUG) == 0xff, and a 0 mask suppresses every * severity (only the return value and the no-crash property are * observable here — see 4); * 2. basic call sequence openlog/syslog/closelog with %d and %m in the * format, plus a priority carrying an out-of-range high facility bit * (masked away to the openlog facility — the defined failure); * 3. every severity 0..7 goes through the mask-and-format path once; * 4. LOG_PERROR: with the option set, the composed line — including the * PID under LOG_PID and the strerror text of %m — is written to * standard error. The evidence run captures stderr (2>&1) and greps * for "vlibc-test[pid]: ..." to confirm the wire format; * 5. repeated openlog/syslog/closelog cycles: each openlog(LOG_NDELAY) * opens the socket and each closelog closes it again (rc-level check — * a leaked descriptor would surface as a failing openlog only after * thousands of cycles, so the assertion is deliberately weak); * 6. -f mode: setlogmask(0) then syslog(LOG_DEBUG, ...) — suppressed, and * must not crash even though the message was filtered. * * No host headers: is vlibc's own (-Iinclude shadows the system * one), errno comes from vlibc's , and every diagnostic goes * through the raw SYS_write helpers from . Compiled * with -DVLIBC_LEVEL=2 so the whole (entirely L2) header is exercised. * * Not part of the library proper; compiled manually for this todo (the * tests/ + make check wiring is owned by a later todo). */ #include #include #include #if VLIBC_LEVEL_GE(2) /* The default mask the first setlogmask call must report back. */ #define TEST_DEFAULT_MASK LOG_UPTO(LOG_DEBUG) /* * This test must run FIRST: it observes the initial mask (0xff) that no * earlier setlogmask call has disturbed, then walks it down and restores it. */ static int test_mask_roundtrip(void) { /* Initial default: everything logged (LOG_UPTO(LOG_DEBUG) == 0xff). */ TEST_ASSERT_EQ(setlogmask(LOG_MASK(LOG_ERR)), TEST_DEFAULT_MASK); /* LOG_MASK(LOG_ERR) is 1<<3 == 8; the previous 0xff comes back. */ TEST_ASSERT_EQ(setlogmask(LOG_MASK(LOG_INFO)), LOG_MASK(LOG_ERR)); /* A zero mask means "log nothing", and returns the previous mask. */ TEST_ASSERT_EQ(setlogmask(0), LOG_MASK(LOG_INFO)); /* Restore the all-open default for every later test. */ TEST_ASSERT_EQ(setlogmask(TEST_DEFAULT_MASK), 0); return 0; } static int test_basic_sequence(void) { setlogmask(TEST_DEFAULT_MASK); openlog("vlibc-test", LOG_PID | LOG_NDELAY, LOG_USER); /* Plain numeric conversion through the vsnprintf core. */ syslog(LOG_INFO, "hello %d", 42); /* %m expands to the strerror text of the current errno. */ errno = ENOENT; syslog(LOG_ERR, "io failure: %m"); /* A facility bit above LOG_FACMASK is masked away (defined failure). */ syslog(LOG_ERR | (1 << 12), "high facility bit masked"); syslog(LOG_ERR | (1 << 20) | LOG_INFO, "very high facility bit masked"); closelog(); return 0; } static int test_every_severity(void) { int sev; setlogmask(TEST_DEFAULT_MASK); openlog("vlibc-test", LOG_NDELAY, LOG_USER); for (sev = LOG_EMERG; sev <= LOG_DEBUG; sev++) { syslog(sev, "severity %d", sev); } closelog(); return 0; } /* * The wire-format path: under LOG_PERROR the composed line is written raw to * standard error. Nothing is asserted here (the test harness cannot capture * fd 2); the evidence run redirects stderr and greps for the expected text. */ static int test_perror_output(void) { setlogmask(TEST_DEFAULT_MASK); errno = ENOENT; openlog("vlibc-test", LOG_PERROR | LOG_PID | LOG_NDELAY, LOG_USER); syslog(LOG_ERR, "perror-check %d %m", 7); closelog(); return 0; } static int test_open_close_cycles(void) { int i; setlogmask(TEST_DEFAULT_MASK); for (i = 0; i < 8; i++) { openlog("cycle", LOG_PID | LOG_NDELAY, LOG_USER); syslog(LOG_WARNING, "cycle %d", i); closelog(); } return 0; } /* * Failure-mode complement of the mask tests: with the mask at 0 even the * most severe message is filtered before any formatting or output — the * observable contract is the return value and the absence of a crash. */ static int test_mask_zero_suppresses(void) { TEST_ASSERT_EQ(setlogmask(0), TEST_DEFAULT_MASK); openlog("vlibc-test", LOG_PERROR | LOG_NDELAY, LOG_USER); syslog(LOG_EMERG, "must be suppressed"); syslog(LOG_DEBUG, "must be suppressed too"); closelog(); setlogmask(TEST_DEFAULT_MASK); return 0; } static const struct vlibc_test tests[] = { {"mask-roundtrip", test_mask_roundtrip}, {"basic-sequence", test_basic_sequence}, {"every-severity", test_every_severity}, {"perror-output", test_perror_output}, {"open-close-cycles", test_open_close_cycles}, {"mask-zero-suppresses", test_mask_zero_suppresses}, }; /* * Own main (not TEST_MAIN): supports the -f failure mode. Everything else * follows the TEST_MAIN contract — same output shape, 0 on all-pass. */ int main(int argc, char **argv) { const size_t count = sizeof tests / sizeof tests[0]; size_t passed = 0; size_t i; if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'f' && argv[1][2] == '\0') { /* The failure QA: mask 0 must suppress even LOG_DEBUG without harm. */ int before = vlibc_test_failures; vlibc_test_say(1, "RUN mask-zero-debug: "); TEST_ASSERT_EQ(setlogmask(0), TEST_DEFAULT_MASK); syslog(LOG_DEBUG, "suppressed by zero mask"); setlogmask(TEST_DEFAULT_MASK); if (vlibc_test_failures == before) { vlibc_test_say(1, "PASS\n"); vlibc_test_say(1, "SUMMARY: 1/1 passed, 0 assertion failure(s)\n"); return 0; } vlibc_test_say(1, "FAIL\n"); return 1; } for (i = 0; i < count; i++) { int before = vlibc_test_failures; vlibc_test_say(1, "RUN "); vlibc_test_say(1, tests[i].name); vlibc_test_say(1, ": "); if (tests[i].run() == 0 && vlibc_test_failures == before) { vlibc_test_say(1, "PASS\n"); passed++; } else { vlibc_test_say(1, "FAIL\n"); } } vlibc_test_say(1, "SUMMARY: "); vlibc_test_say_dec(1, (unsigned long)passed); vlibc_test_say(1, "/"); vlibc_test_say_dec(1, (unsigned long)count); vlibc_test_say(1, " passed, "); vlibc_test_say_dec(1, (unsigned long)vlibc_test_failures); vlibc_test_say(1, " assertion failure(s)\n"); return passed == count ? 0 : 1; } #else /* !VLIBC_LEVEL_GE(2) */ /* * Level 1: is entirely level 2 (XSI), so there is nothing to * run. Keep the TU compilable at any configured profile. */ int main(void) { vlibc_test_say(1, "SKIP: is level 2, not available here\n"); return 0; } #endif /* VLIBC_LEVEL_GE(2) */