93 lines
4.3 KiB
C
93 lines
4.3 KiB
C
/* SPDX-License-Identifier: AGPL-3.0-or-later */
|
|
/* Copyright (C) 2026 David (Corey) Herrera */
|
|
/**
|
|
* @file test_tt_name_list.c
|
|
* @brief The FILTER and the SELECTOR disagree about the empty list and agree about everything
|
|
* else — which is the whole contract, and the one this backend has already paid for.
|
|
*
|
|
* `pn_tt_name_list_contains()` answers **true** for an unset list: an unset knob does not
|
|
* restrict. `pn_tt_name_list_selects()` answers **false**: an unset knob arms nothing. The two
|
|
* calls read identically at a call site, so nothing but a test can tell them apart — and using
|
|
* the filter to arm `PN_TT_RED=residency_await_early` armed that red arm on EVERY run, refused
|
|
* every descriptor of every family at token 0 with "completed_count does not match the number
|
|
* enqueued", and cost four card sessions and a cross-agent bisect that landed on the wrong
|
|
* commit. Silicon, 2026-08-25.
|
|
*
|
|
* No device, no allocation, no I/O.
|
|
*
|
|
* @status Green off-hardware.
|
|
* @issues None
|
|
* @todo None
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "../src/accel/tt/pn_tt_name_list.h"
|
|
|
|
static int checks_run;
|
|
static int checks_failed;
|
|
|
|
static void check(int condition, const char *what)
|
|
{
|
|
checks_run++;
|
|
if (condition) {
|
|
printf(" ok %s\n", what);
|
|
} else {
|
|
checks_failed++;
|
|
printf(" FAIL %s\n", what);
|
|
}
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
printf("tt name list — the filter and the selector, and where they must differ\n");
|
|
|
|
/* THE ASYMMETRY. This pair is the entire reason the second function exists. */
|
|
check(pn_tt_name_list_contains(NULL, "residency_await_early"),
|
|
"FILTER: an unset list CONTAINS every name — an unset knob does not restrict");
|
|
check(!pn_tt_name_list_selects(NULL, "residency_await_early"),
|
|
"SELECTOR: an unset list SELECTS nothing — an unset knob arms nothing");
|
|
check(pn_tt_name_list_contains("", "x"), "FILTER: an EMPTY list contains every name");
|
|
check(!pn_tt_name_list_selects("", "x"), "SELECTOR: an EMPTY list selects nothing");
|
|
|
|
/* AND THE RED ARM ITSELF, spelled the way the caller spells it. A regression that flips
|
|
* this back to the filter fails here by name. */
|
|
check(!pn_tt_name_list_selects(NULL, "residency_await_early") &&
|
|
!pn_tt_name_list_selects("", "residency_await_early"),
|
|
"RED ARM: `residency_await_early` is NOT armed when PN_TT_RED is unset or empty");
|
|
check(pn_tt_name_list_selects("residency_await_early", "residency_await_early"),
|
|
"RED ARM: it IS armed when named alone");
|
|
check(pn_tt_name_list_selects("gdn_decay_raw,residency_await_early", "residency_await_early"),
|
|
"RED ARM: and when named in a list");
|
|
check(!pn_tt_name_list_selects("gdn_decay_raw,attn_group", "residency_await_early"),
|
|
"RED ARM: and NOT when the list names other arms");
|
|
|
|
/* ON A NON-EMPTY LIST THE TWO MUST NOT DIVERGE. If they do, the selector has grown its own
|
|
* matcher and the pair can disagree about a membership as well as about the empty list. */
|
|
{
|
|
static const char *const lists[] = { "a", "a,b", "b,a", "render,render-widen",
|
|
"aa", "a,,b", ",a" };
|
|
static const char *const names[] = { "a", "b", "render", "render-widen", "aa", "" };
|
|
unsigned li, ni;
|
|
int agree = 1;
|
|
|
|
for (li = 0; li < sizeof(lists) / sizeof(lists[0]); li++)
|
|
for (ni = 0; ni < sizeof(names) / sizeof(names[0]); ni++)
|
|
if (pn_tt_name_list_contains(lists[li], names[ni]) !=
|
|
pn_tt_name_list_selects(lists[li], names[ni]))
|
|
agree = 0;
|
|
check(agree, "on every NON-EMPTY list the filter and the selector agree exactly");
|
|
}
|
|
|
|
/* The whole-word rule the filter documents must survive in the selector. */
|
|
check(!pn_tt_name_list_selects("render-widen", "render"),
|
|
"SELECTOR: `render` does not take `render-widen` — compared WHOLE");
|
|
check(!pn_tt_name_list_selects("residency_await", "residency_await_early"),
|
|
"SELECTOR: a PREFIX of the arm's name does not arm it");
|
|
check(!pn_tt_name_list_selects("x", NULL) && !pn_tt_name_list_selects("x", ""),
|
|
"SELECTOR: a NULL or empty name is never selected");
|
|
|
|
printf("\n%d/%d checks failed\n", checks_failed, checks_run);
|
|
return checks_failed == 0 ? 0 : 1;
|
|
}
|