mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-10-24 06:23:06 +08:00
One request pins the change (merge base .. HEAD), builds the graph and the runnable test registry of exactly the HEAD snapshot, seeds the graph from the change, walks what depends on it and answers which tests to run (cbm.test_impact). Missing or doubtful evidence never narrows: it becomes a run-all answer that names why. Snapshot (classified ledger -> frozen graph -> registry): - one shared language classifier for discovery and pinned blobs (raw bytes on every platform); the classified ledger feeds the frozen build, which indexes exactly the listed files and records partial parses as per-file PARSE_GAP instead of refusing the graph; - the pinned tree skips symlinks and submodule links (counted), as discovery never indexes them; - the test model scopes uncertainty to the suites of its file (they run whole), reads line splices where they occur, treats a mid-file `#ifndef X` + `#define X` as an ordinary condition, and no longer reads a plain identifier named like a macro as an invocation. On this repository the registry is now narrowable and matches a text census exactly (8,365 cases, 141 runner suites). Seeding and reach (port of the measured replay, rule B): - hunk -> overlapping definitions, comment-only hunks dropped, pure deletions -> enclosing definition, no-definition hunks -> whole file, deleted names found by text, header changes propagated through the include closure and the headers' macros (pastes included), file-level escalation for unclassifiable header lines; - inbound fixpoint walk over CALLS, ASYNC_CALLS, USAGE, CALL_REFERENCE, READS (+ routes); cases, suites and the runner's entry points are sinks; a reached runner main runs everything (RUNNER_REACHED); - a parse gap whose text names a reached definition reaches the definition around it (or its file); - macro-registered tests run their suites whole; cases and suites map to graph nodes by their start line. The line patterns reproduce the reference regexes exactly on 1,383,850 lines of this repository and 37,167,926 kernel lines; on 24 replayed changes the engine selects at least what the reference selected (13 identical, the rest only conservative supersets on the same graph). Also: - configured test declarations that cannot be mapped degrade their file (no configured roles, a test_declarations diagnostic) instead of aborting the whole index; - the selector keeps other runners' suites out of the selection, and the result codec judges the model by narrowability like the selector; - a change to .codebase-memory.json runs everything (built-in rule); - .codebase-memory.json with the c-cbm preset and this repository's rules. Gate fixes (suites, lint-ci, Windows cross-compile): - the request runs on its own thread with a default-size stack (daemon tool calls run on 256 KiB threads, where the in-process build died); - a request-supplied config_path is no longer followed by an unlink of an uninitialized path buffer; - the inventory's frame-local reader no longer stays reachable from the caller's source after the filter call; - FILE_ID_INFO needs _WIN32_WINNT >= 0x0602; the pinned-tree header pins it before any system header (toolchains defaulting lower failed); - memory-core ratchet: the win_utf8 converters gain core-backed `_in(cls, ...)` forms over one implementation (the legacy names keep the C library for unmigrated callers), the Git facts module uses them, and the Windows spawn path releases everything through one failure exit; pipeline, extraction and config allocations that this work touched moved to the core in matched pairs; baselines tightened; - the branch's C files formatted with the project's clang-format. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
389 lines
18 KiB
C
389 lines
18 KiB
C
/*
|
|
* test_test_impact_classify.c — the classified ledger of a pinned HEAD
|
|
* inventory (src/mcp/test_impact_classify.c), on real git snapshots.
|
|
*
|
|
* The ledger must give every kept file the language discovery gives the same
|
|
* bytes; a read it cannot make is an error, never a default language.
|
|
*/
|
|
#include "test_test_impact_inventory_internal.h"
|
|
|
|
#include "discover/discover.h"
|
|
#include "discover/userconfig.h"
|
|
#include "mcp/test_impact_classify.h"
|
|
|
|
typedef struct {
|
|
const char *path;
|
|
const char *content;
|
|
} tic_file_t;
|
|
|
|
/* A HEAD commit holding exactly `files`, its pinned tree and its inventory. */
|
|
static bool tic_snapshot(if_native *n, const tic_file_t *files, size_t count,
|
|
cbm_test_impact_inventory_t **inventory) {
|
|
if (!ni_start(n) || !ni_reset_input(n)) {
|
|
return false;
|
|
}
|
|
for (size_t i = 0; i < count; i++) {
|
|
if (!if_text(&n->input, files[i].path, files[i].content)) {
|
|
return false;
|
|
}
|
|
}
|
|
n->input.limits.max_probe_prefix_bytes = CBM_LANGUAGE_PROBE_MAX;
|
|
return ni_commit_input(n) && ni_prepare(n, inventory);
|
|
}
|
|
|
|
static const cbm_test_impact_classified_t *tic_row(const cbm_test_impact_ledger_t *ledger,
|
|
const if_native *n, const char *path) {
|
|
size_t count = 0;
|
|
const cbm_test_impact_classified_t *rows = cbm_test_impact_ledger_rows(ledger, &count);
|
|
for (size_t i = 0; i < count; i++) {
|
|
if (strcmp(n->input.paths[rows[i].file_index], path) == 0) {
|
|
return &rows[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* The language discovery's rule gives the same bytes. */
|
|
static CBMLanguage tic_expected(const char *path, const char *content) {
|
|
const char *slash = strrchr(path, '/');
|
|
const char *name = slash ? slash + 1 : path;
|
|
size_t len = strlen(content);
|
|
size_t probe = cbm_language_probe_bytes(name);
|
|
size_t head = len < probe ? len : probe;
|
|
return cbm_language_classify(name, (const unsigned char *)content, head, len > head, true);
|
|
}
|
|
|
|
static const tic_file_t TIC_FILES[] = {
|
|
{".gitignore", "drop.c\n"},
|
|
{"a.m", "#import <Foundation/Foundation.h>\n@interface A\n@end\n"},
|
|
{"b.m", "% matlab\nx = 1;\n"},
|
|
{"c.cls", "Class Demo.Person Extends %Persistent\n{\n}\n"},
|
|
{"d.xml", "<?xml version=\"1.0\"?>\n<Export generator=\"IRIS\">\n"},
|
|
{"drop.c", "int dropped;\n"},
|
|
{"package.json", "{}\n"},
|
|
{"plain", "no shebang here\n"},
|
|
{"sub/data.json", "{\"k\": 1}\n"},
|
|
{"tool", "#!/usr/bin/env python3\nprint(1)\n"},
|
|
{"x.go", "package x\n"},
|
|
};
|
|
|
|
TEST(test_impact_classify_gives_discovery_languages) {
|
|
if_native n = {0};
|
|
cbm_test_impact_inventory_t *inventory = NULL;
|
|
cbm_test_impact_ledger_t *ledger = NULL;
|
|
int result = 1;
|
|
size_t nfiles = sizeof(TIC_FILES) / sizeof(TIC_FILES[0]);
|
|
NI_CHECK(tic_snapshot(&n, TIC_FILES, nfiles, &inventory));
|
|
cbm_inventory_error_t error;
|
|
NI_CHECK(cbm_test_impact_classify(inventory, n.input.tree, NULL, &n.input.control, &ledger,
|
|
&error) == CBM_INVENTORY_OK);
|
|
NI_CHECK(ledger && error.status == CBM_INVENTORY_OK);
|
|
size_t count = 0;
|
|
const cbm_test_impact_classified_t *rows = cbm_test_impact_ledger_rows(ledger, &count);
|
|
/* Every kept file once, in file-index order; the ignored one is absent. */
|
|
NI_CHECK(count == nfiles - 1);
|
|
for (size_t i = 1; i < count; i++) {
|
|
NI_CHECK(rows[i - 1].file_index < rows[i].file_index);
|
|
}
|
|
NI_CHECK(tic_row(ledger, &n, "drop.c") == NULL);
|
|
for (size_t i = 0; i < nfiles; i++) {
|
|
if (strcmp(TIC_FILES[i].path, "drop.c") == 0) {
|
|
continue;
|
|
}
|
|
const cbm_test_impact_classified_t *row = tic_row(ledger, &n, TIC_FILES[i].path);
|
|
NI_CHECK(row != NULL);
|
|
NI_CHECK(row->language == tic_expected(TIC_FILES[i].path, TIC_FILES[i].content));
|
|
}
|
|
/* Spot values, so a wrong shared rule cannot pass by agreeing with itself. */
|
|
NI_CHECK(tic_row(ledger, &n, "a.m")->language == CBM_LANG_OBJC);
|
|
NI_CHECK(tic_row(ledger, &n, "b.m")->language == CBM_LANG_MATLAB);
|
|
NI_CHECK(tic_row(ledger, &n, "c.cls")->language == CBM_LANG_OBJECTSCRIPT_UDL);
|
|
NI_CHECK(tic_row(ledger, &n, "d.xml")->language == CBM_LANG_OBJECTSCRIPT_EXPORT);
|
|
NI_CHECK(tic_row(ledger, &n, "package.json")->language == CBM_LANG_COUNT);
|
|
NI_CHECK(tic_row(ledger, &n, "plain")->language == CBM_LANG_COUNT);
|
|
NI_CHECK(tic_row(ledger, &n, "sub/data.json")->language == CBM_LANG_JSON);
|
|
NI_CHECK(tic_row(ledger, &n, "tool")->language == CBM_LANG_PYTHON);
|
|
NI_CHECK(tic_row(ledger, &n, "x.go")->language == CBM_LANG_GO);
|
|
/* Only names that need content were read: a.m b.m c.cls d.xml, and the
|
|
* shebang probe for the names without a language (.gitignore plain tool). */
|
|
cbm_test_impact_classify_usage_t usage;
|
|
NI_CHECK(cbm_test_impact_ledger_usage(ledger, &usage));
|
|
NI_CHECK(usage.verified_file_reads == 7);
|
|
NI_CHECK(memcmp(cbm_test_impact_ledger_manifest(ledger),
|
|
cbm_test_impact_inventory_view(inventory)->manifest_sha256, 32) == 0);
|
|
result = 0;
|
|
done:
|
|
cbm_test_impact_ledger_free(ledger);
|
|
return ni_finish(&n, inventory, result);
|
|
}
|
|
|
|
/* Reads and the probe length are charged to what the inventory's limits leave
|
|
* after the filter. Running out is a LIMIT for the whole pass, with no ledger,
|
|
* and never a default language for the files that were not read. */
|
|
TEST(test_impact_classify_limits_are_errors_not_defaults) {
|
|
if_native n = {0};
|
|
cbm_test_impact_inventory_t *inventory = NULL;
|
|
cbm_test_impact_ledger_t *ledger = (cbm_test_impact_ledger_t *)(uintptr_t)1;
|
|
int result = 1;
|
|
NI_CHECK(tic_snapshot(&n, TIC_FILES, sizeof(TIC_FILES) / sizeof(TIC_FILES[0]), &inventory));
|
|
cbm_test_impact_inventory_usage_t used;
|
|
NI_CHECK(cbm_test_impact_inventory_usage(inventory, &used));
|
|
cbm_inventory_error_t error;
|
|
|
|
/* One read fewer than the seven probes need. The limits live in the
|
|
* inventory, so a tighter one needs a fresh inventory. */
|
|
cbm_test_impact_inventory_free(inventory);
|
|
inventory = NULL;
|
|
n.input.limits.max_verified_file_reads = used.filter.verified_file_reads_reserved + 6;
|
|
NI_CHECK(ni_prepare(&n, &inventory));
|
|
NI_CHECK(cbm_test_impact_classify(inventory, n.input.tree, NULL, &n.input.control, &ledger,
|
|
&error) == CBM_INVENTORY_LIMIT);
|
|
NI_CHECK(ledger == NULL && error.status == CBM_INVENTORY_LIMIT);
|
|
/* Exactly enough is fine. */
|
|
cbm_test_impact_inventory_free(inventory);
|
|
inventory = NULL;
|
|
n.input.limits.max_verified_file_reads = used.filter.verified_file_reads_reserved + 7;
|
|
NI_CHECK(ni_prepare(&n, &inventory));
|
|
NI_CHECK(cbm_test_impact_classify(inventory, n.input.tree, NULL, &n.input.control, &ledger,
|
|
&error) == CBM_INVENTORY_OK);
|
|
cbm_test_impact_ledger_free(ledger);
|
|
ledger = NULL;
|
|
|
|
/* A probe longer than the probe limit: the shebang probe needs 255. */
|
|
cbm_test_impact_inventory_free(inventory);
|
|
inventory = NULL;
|
|
n.input.limits.max_probe_prefix_bytes = 254;
|
|
NI_CHECK(ni_prepare(&n, &inventory));
|
|
NI_CHECK(cbm_test_impact_classify(inventory, n.input.tree, NULL, &n.input.control, &ledger,
|
|
&error) == CBM_INVENTORY_LIMIT);
|
|
NI_CHECK(ledger == NULL);
|
|
|
|
/* Arguments. */
|
|
NI_CHECK(cbm_test_impact_classify(NULL, n.input.tree, NULL, &n.input.control, &ledger,
|
|
&error) == CBM_INVENTORY_INVALID);
|
|
NI_CHECK(cbm_test_impact_classify(inventory, NULL, NULL, &n.input.control, &ledger, &error) ==
|
|
CBM_INVENTORY_INVALID);
|
|
NI_CHECK(cbm_test_impact_classify(inventory, n.input.tree, NULL, &n.input.control, NULL,
|
|
&error) == CBM_INVENTORY_INVALID);
|
|
result = 0;
|
|
done:
|
|
if (ledger != (cbm_test_impact_ledger_t *)(uintptr_t)1) {
|
|
cbm_test_impact_ledger_free(ledger);
|
|
}
|
|
return ni_finish(&n, inventory, result);
|
|
}
|
|
|
|
/* The snapshot's language config decides, passed explicitly: the process-wide
|
|
* config another index may have installed takes no part. */
|
|
TEST(test_impact_classify_uses_the_given_config) {
|
|
if_native n = {0};
|
|
cbm_test_impact_inventory_t *inventory = NULL;
|
|
cbm_test_impact_ledger_t *with = NULL;
|
|
cbm_test_impact_ledger_t *without = NULL;
|
|
cbm_userconfig_t *config = NULL;
|
|
int result = 1;
|
|
static const tic_file_t files[] = {{"script.foo", "x = 1\n"}};
|
|
NI_CHECK(tic_snapshot(&n, files, 1, &inventory));
|
|
/* A config that maps .foo to Python, from a project file in a scratch dir. */
|
|
char dir[512];
|
|
snprintf(dir, sizeof(dir), "%s/cbm-classify-config-XXXXXX", cbm_tmpdir());
|
|
NI_CHECK(cbm_mkdtemp(dir) != NULL);
|
|
char file[600];
|
|
snprintf(file, sizeof(file), "%s/.codebase-memory.json", dir);
|
|
static const char project[] = "{\"extra_extensions\":{\".foo\":\"python\"}}";
|
|
NI_CHECK(ni_write(&n, file, project, sizeof(project) - 1));
|
|
config = cbm_userconfig_load(dir);
|
|
remove(file);
|
|
th_rmtree(dir);
|
|
NI_CHECK(config != NULL);
|
|
NI_CHECK(cbm_userconfig_lookup(config, ".foo") == CBM_LANG_PYTHON);
|
|
const cbm_userconfig_t *installed = cbm_get_user_lang_config();
|
|
cbm_inventory_error_t error;
|
|
NI_CHECK(cbm_test_impact_classify(inventory, n.input.tree, config, &n.input.control, &with,
|
|
&error) == CBM_INVENTORY_OK);
|
|
NI_CHECK(cbm_test_impact_classify(inventory, n.input.tree, NULL, &n.input.control, &without,
|
|
&error) == CBM_INVENTORY_OK);
|
|
NI_CHECK(cbm_get_user_lang_config() == installed);
|
|
NI_CHECK(tic_row(with, &n, "script.foo")->language == CBM_LANG_PYTHON);
|
|
NI_CHECK(tic_row(without, &n, "script.foo")->language == CBM_LANG_COUNT);
|
|
result = 0;
|
|
done:
|
|
cbm_test_impact_ledger_free(with);
|
|
cbm_test_impact_ledger_free(without);
|
|
cbm_userconfig_free(config);
|
|
return ni_finish(&n, inventory, result);
|
|
}
|
|
|
|
/* A blob that cannot be read fails the pass: no ledger, the native error, and
|
|
* the index of the file. A default language here would index a different
|
|
* graph than the one the selection claims to use. */
|
|
TEST(test_impact_classify_read_failure_is_an_error) {
|
|
if_native n = {0};
|
|
cbm_test_impact_inventory_t *inventory = NULL;
|
|
cbm_test_impact_ledger_t *ledger = (cbm_test_impact_ledger_t *)(uintptr_t)1;
|
|
int result = 1;
|
|
NI_CHECK(tic_snapshot(&n, TIC_FILES, sizeof(TIC_FILES) / sizeof(TIC_FILES[0]), &inventory));
|
|
#if defined(CBM_ENABLE_TEST_SEAMS) && CBM_ENABLE_TEST_SEAMS
|
|
NI_CHECK(cbm_pinned_tree_test_set_read_fault(n.input.tree, CBM_PINNED_TREE_READ_FAULT_READ));
|
|
cbm_inventory_error_t error;
|
|
NI_CHECK(cbm_test_impact_classify(inventory, n.input.tree, NULL, &n.input.control, &ledger,
|
|
&error) == CBM_INVENTORY_IO);
|
|
NI_CHECK(ledger == NULL && error.status == CBM_INVENTORY_IO);
|
|
/* The first survivor that needs its content is .gitignore, file 0. */
|
|
NI_CHECK(error.file_index == 0);
|
|
/* A started failed read leaves the tree disposal-only, as for the filter. */
|
|
NI_CHECK(!cbm_pinned_tree_view(n.input.tree));
|
|
result = 0;
|
|
#else
|
|
fprintf(stderr, "classification read faults require canonical CBM_ENABLE_TEST_SEAMS\n");
|
|
#endif
|
|
done:
|
|
if (ledger != (cbm_test_impact_ledger_t *)(uintptr_t)1) {
|
|
cbm_test_impact_ledger_free(ledger);
|
|
}
|
|
return ni_finish(&n, inventory, result);
|
|
}
|
|
|
|
/* The inventory and the tree must describe the same snapshot. */
|
|
TEST(test_impact_classify_refuses_another_snapshot) {
|
|
if_native first = {0};
|
|
if_native second = {0};
|
|
cbm_test_impact_inventory_t *inventory = NULL;
|
|
cbm_test_impact_inventory_t *other = NULL;
|
|
cbm_test_impact_ledger_t *ledger = (cbm_test_impact_ledger_t *)(uintptr_t)1;
|
|
int result = 1;
|
|
static const tic_file_t files[] = {{"x.go", "package x\n"}};
|
|
NI_CHECK(tic_snapshot(&first, TIC_FILES, sizeof(TIC_FILES) / sizeof(TIC_FILES[0]), &inventory));
|
|
NI_CHECK(tic_snapshot(&second, files, 1, &other));
|
|
cbm_inventory_error_t error;
|
|
NI_CHECK(cbm_test_impact_classify(inventory, second.input.tree, NULL, &first.input.control,
|
|
&ledger, &error) == CBM_INVENTORY_CHANGED);
|
|
NI_CHECK(ledger == NULL);
|
|
/* Each with its own tree is fine. */
|
|
NI_CHECK(cbm_test_impact_classify(other, second.input.tree, NULL, &second.input.control,
|
|
&ledger, &error) == CBM_INVENTORY_OK);
|
|
result = 0;
|
|
done:
|
|
if (ledger != (cbm_test_impact_ledger_t *)(uintptr_t)1) {
|
|
cbm_test_impact_ledger_free(ledger);
|
|
}
|
|
result = ni_finish(&second, other, result);
|
|
return ni_finish(&first, inventory, result);
|
|
}
|
|
|
|
/* ── The runnable registry of the same snapshot ─────────────────── */
|
|
|
|
static const tic_file_t TIC_SUITE_FILES[] = {
|
|
{"README.md", "# readme\n"},
|
|
{"src/x.c", "int x(void) { return 1; }\n"},
|
|
{"tests/test_alpha.c", "TEST(a1) {\n PASS();\n}\nSUITE(alpha) {\n RUN_TEST(a1);\n}\n"},
|
|
{"tests/test_main.c", "int main(void) {\n RUN_SELECTED_SUITE(alpha);\n return 0;\n}\n"},
|
|
};
|
|
|
|
static const char TIC_C_CBM[] = "{\"test_impact\":{\"version\":1,\"tests\":{\"presets\":"
|
|
"{\"c-cbm\":true}}}}";
|
|
|
|
/* The registry reads the snapshot's own test sources under the snapshot's
|
|
* declarations: the runner suite, the case and its registration. */
|
|
TEST(test_impact_registry_reads_the_snapshot_tests) {
|
|
if_native n = {0};
|
|
cbm_test_impact_inventory_t *inventory = NULL;
|
|
cbm_test_impact_ledger_t *ledger = NULL;
|
|
cbm_test_declarations_t *declarations = NULL;
|
|
cbm_test_model_t *model = NULL;
|
|
int result = 1;
|
|
NI_CHECK(tic_snapshot(&n, TIC_SUITE_FILES, sizeof(TIC_SUITE_FILES) / sizeof(TIC_SUITE_FILES[0]),
|
|
&inventory));
|
|
cbm_inventory_error_t error;
|
|
NI_CHECK(cbm_test_impact_classify(inventory, n.input.tree, NULL, &n.input.control, &ledger,
|
|
&error) == CBM_INVENTORY_OK);
|
|
declarations = cbm_test_declarations_parse(TIC_C_CBM, sizeof(TIC_C_CBM) - 1, false);
|
|
NI_CHECK(declarations != NULL);
|
|
NI_CHECK(cbm_test_impact_registry(ledger, inventory, n.input.tree, declarations,
|
|
&n.input.control, &model, &error) == CBM_INVENTORY_OK);
|
|
NI_CHECK(model && error.status == CBM_INVENTORY_OK);
|
|
NI_CHECK(cbm_test_model_complete(model));
|
|
int count = 0;
|
|
const cbm_test_runner_suite_t *runner = cbm_test_model_runner_suites(model, &count);
|
|
NI_CHECK(count == 1 && strcmp(runner[0].name, "alpha") == 0);
|
|
const cbm_test_case_t *cases = cbm_test_model_cases(model, &count);
|
|
NI_CHECK(count == 1 && strcmp(cases[0].name, "a1") == 0 &&
|
|
strcmp(cases[0].file, "tests/test_alpha.c") == 0);
|
|
const cbm_test_registration_t *regs = cbm_test_model_registrations(model, &count);
|
|
NI_CHECK(count == 1 && strcmp(regs[0].suite, "alpha") == 0 && strcmp(regs[0].test, "a1") == 0 &&
|
|
regs[0].resolved);
|
|
result = 0;
|
|
done:
|
|
cbm_test_model_free(model);
|
|
cbm_test_declarations_free(declarations);
|
|
cbm_test_impact_ledger_free(ledger);
|
|
return ni_finish(&n, inventory, result);
|
|
}
|
|
|
|
/* Without conventions the registry names no test at all, and a registry that
|
|
* cannot read every source it needs is an error, never a smaller registry. */
|
|
TEST(test_impact_registry_names_nothing_it_cannot_read) {
|
|
if_native n = {0};
|
|
cbm_test_impact_inventory_t *inventory = NULL;
|
|
cbm_test_impact_ledger_t *ledger = NULL;
|
|
cbm_test_declarations_t *absent = NULL;
|
|
cbm_test_declarations_t *c_cbm = NULL;
|
|
cbm_test_model_t *model = NULL;
|
|
int result = 1;
|
|
size_t nfiles = sizeof(TIC_SUITE_FILES) / sizeof(TIC_SUITE_FILES[0]);
|
|
NI_CHECK(tic_snapshot(&n, TIC_SUITE_FILES, nfiles, &inventory));
|
|
cbm_inventory_error_t error;
|
|
NI_CHECK(cbm_test_impact_classify(inventory, n.input.tree, NULL, &n.input.control, &ledger,
|
|
&error) == CBM_INVENTORY_OK);
|
|
absent = cbm_test_declarations_parse(NULL, 0, true);
|
|
NI_CHECK(absent != NULL);
|
|
NI_CHECK(cbm_test_impact_registry(ledger, inventory, n.input.tree, absent, &n.input.control,
|
|
&model, &error) == CBM_INVENTORY_OK);
|
|
int count = -1;
|
|
(void)cbm_test_model_cases(model, &count);
|
|
NI_CHECK(count == 0);
|
|
cbm_test_model_free(model);
|
|
model = NULL;
|
|
|
|
/* Three C sources to read; the reads the filter and the ledger left over
|
|
* are cut to two. The limits live in the inventory, so a fresh one. */
|
|
cbm_test_impact_classify_usage_t spent;
|
|
NI_CHECK(cbm_test_impact_ledger_usage(ledger, &spent));
|
|
cbm_test_impact_inventory_usage_t used;
|
|
NI_CHECK(cbm_test_impact_inventory_usage(inventory, &used));
|
|
cbm_test_impact_ledger_free(ledger);
|
|
ledger = NULL;
|
|
cbm_test_impact_inventory_free(inventory);
|
|
inventory = NULL;
|
|
n.input.limits.max_verified_file_reads =
|
|
used.filter.verified_file_reads_reserved + spent.verified_file_reads + 2;
|
|
NI_CHECK(ni_prepare(&n, &inventory));
|
|
NI_CHECK(cbm_test_impact_classify(inventory, n.input.tree, NULL, &n.input.control, &ledger,
|
|
&error) == CBM_INVENTORY_OK);
|
|
c_cbm = cbm_test_declarations_parse(TIC_C_CBM, sizeof(TIC_C_CBM) - 1, false);
|
|
NI_CHECK(c_cbm != NULL);
|
|
model = (cbm_test_model_t *)(uintptr_t)1;
|
|
NI_CHECK(cbm_test_impact_registry(ledger, inventory, n.input.tree, c_cbm, &n.input.control,
|
|
&model, &error) == CBM_INVENTORY_LIMIT);
|
|
NI_CHECK(model == NULL && error.status == CBM_INVENTORY_LIMIT);
|
|
result = 0;
|
|
done:
|
|
if (model != (cbm_test_model_t *)(uintptr_t)1) {
|
|
cbm_test_model_free(model);
|
|
}
|
|
cbm_test_declarations_free(absent);
|
|
cbm_test_declarations_free(c_cbm);
|
|
cbm_test_impact_ledger_free(ledger);
|
|
return ni_finish(&n, inventory, result);
|
|
}
|
|
|
|
SUITE(test_impact_classify) {
|
|
RUN_TEST(test_impact_registry_reads_the_snapshot_tests);
|
|
RUN_TEST(test_impact_registry_names_nothing_it_cannot_read);
|
|
RUN_TEST(test_impact_classify_gives_discovery_languages);
|
|
RUN_TEST(test_impact_classify_limits_are_errors_not_defaults);
|
|
RUN_TEST(test_impact_classify_uses_the_given_config);
|
|
RUN_TEST(test_impact_classify_read_failure_is_an_error);
|
|
RUN_TEST(test_impact_classify_refuses_another_snapshot);
|
|
}
|