mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-09 09:11:00 +08:00
test(pipeline): verify incremental parity across 13 languages
Incremental behavior previously lacked one table-driven oracle covering every supported parser/LSP language family. That left exact-upsert and scoped-LSP fallback routing vulnerable to language-specific drift even when individual fixtures passed. Add run_incremental_language_oracle_case in tests/test_pipeline.c. Each synthetic fixture performs a full fast index, edits source to add a callable symbol, runs incremental indexing, asserts the publication kind and fallback reason, and compares the resulting canonical graph with a fresh fast rebuild. Cover Go, C, C++, CUDA, and Python exact publication plus JavaScript, TypeScript, TSX, PHP, C#, Java, Kotlin, and Rust scoped_lsp_gap full fallback. The helper releases pipelines, configuration, and project storage through one cleanup path; ordinary passes and failures remove fixtures, while CBM_TEST_ARTIFACT_DIR retains failed fixtures inside the runner-owned cache. Verification: the ASan/UBSan test runner passed incremental_cross_lsp_language_matrix_matches_fresh_rebuild (13 cases) and eight adjacent exact, C-header fallback, Python/JavaScript scoped-LSP, delete, rename, overlay publish-failure, and overlay extraction-failure tests. git clang-format reported no changed-line edits and git diff --cached --check passed. Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
This commit is contained in:
@@ -13795,6 +13795,177 @@ TEST(incremental_javascript_scoped_lsp_gap_reports_full_rebuild_not_cap_overflow
|
||||
PASS();
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const char *filename;
|
||||
const char *initial_source;
|
||||
const char *updated_source;
|
||||
cbm_pipeline_publish_kind_t expected_publish_kind;
|
||||
} incremental_language_oracle_case_t;
|
||||
|
||||
static int run_incremental_language_oracle_case(const incremental_language_oracle_case_t *tc,
|
||||
char *err, size_t err_sz) {
|
||||
char root[CBM_PATH_MAX];
|
||||
const char *cache = cbm_resolve_cache_dir();
|
||||
int n = snprintf(root, sizeof(root), "%s/cbm-incr-language-%s-XXXXXX", cache, tc->name);
|
||||
if (n < 0 || (size_t)n >= sizeof(root) || !cbm_mkdtemp(root)) {
|
||||
snprintf(err, err_sz, "%s: fixture directory creation failed", tc->name);
|
||||
return CBM_STORE_ERR;
|
||||
}
|
||||
|
||||
int rc = CBM_STORE_ERR;
|
||||
char source_path[CBM_PATH_MAX];
|
||||
char db_path[CBM_PATH_MAX];
|
||||
char *project = NULL;
|
||||
cbm_config_t *cfg = NULL;
|
||||
cbm_pipeline_t *pipeline = NULL;
|
||||
n = snprintf(source_path, sizeof(source_path), "%s/%s", root, tc->filename);
|
||||
if (n < 0 || (size_t)n >= sizeof(source_path) ||
|
||||
th_write_file(source_path, tc->initial_source) != 0) {
|
||||
snprintf(err, err_sz, "%s: initial source write failed", tc->name);
|
||||
goto cleanup;
|
||||
}
|
||||
n = snprintf(db_path, sizeof(db_path), "%s/graph.db", root);
|
||||
if (n < 0 || (size_t)n >= sizeof(db_path)) {
|
||||
snprintf(err, err_sz, "%s: database path overflow", tc->name);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cfg = incremental_test_config(root);
|
||||
if (!cfg || cbm_config_set(cfg, CBM_CONFIG_INCREMENTAL_DERIVED_REFRESH,
|
||||
CBM_CONFIG_INCREMENTAL_DERIVED_REFRESH_EAGER) != 0) {
|
||||
snprintf(err, err_sz, "%s: incremental config setup failed", tc->name);
|
||||
goto cleanup;
|
||||
}
|
||||
pipeline = cbm_pipeline_new(root, db_path, CBM_MODE_FAST);
|
||||
if (!pipeline) {
|
||||
snprintf(err, err_sz, "%s: initial pipeline allocation failed", tc->name);
|
||||
goto cleanup;
|
||||
}
|
||||
cbm_pipeline_apply_config(pipeline, cfg);
|
||||
if (cbm_pipeline_run(pipeline) != 0) {
|
||||
snprintf(err, err_sz, "%s: initial full publication failed", tc->name);
|
||||
goto cleanup;
|
||||
}
|
||||
project = cbm_strdup(cbm_pipeline_project_name(pipeline));
|
||||
cbm_pipeline_free(pipeline);
|
||||
pipeline = NULL;
|
||||
if (!project) {
|
||||
snprintf(err, err_sz, "%s: project name allocation failed", tc->name);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (th_write_file(source_path, tc->updated_source) != 0) {
|
||||
snprintf(err, err_sz, "%s: updated source write failed", tc->name);
|
||||
goto cleanup;
|
||||
}
|
||||
pipeline = cbm_pipeline_new(root, db_path, CBM_MODE_FAST);
|
||||
if (!pipeline) {
|
||||
snprintf(err, err_sz, "%s: incremental pipeline allocation failed", tc->name);
|
||||
goto cleanup;
|
||||
}
|
||||
cbm_pipeline_apply_config(pipeline, cfg);
|
||||
if (cbm_pipeline_run(pipeline) != 0) {
|
||||
snprintf(err, err_sz, "%s: incremental publication failed", tc->name);
|
||||
goto cleanup;
|
||||
}
|
||||
cbm_pipeline_publish_kind_t actual_kind = cbm_pipeline_publish_kind(pipeline);
|
||||
const char *actual_reason = cbm_pipeline_publish_reason(pipeline);
|
||||
if (actual_kind != tc->expected_publish_kind) {
|
||||
snprintf(err, err_sz, "%s: publish kind=%d reason=%s, expected=%d", tc->name, actual_kind,
|
||||
actual_reason ? actual_reason : "", tc->expected_publish_kind);
|
||||
goto cleanup;
|
||||
}
|
||||
if (actual_kind == CBM_PIPELINE_PUBLISH_FULL &&
|
||||
(!actual_reason || strcmp(actual_reason, "scoped_lsp_gap") != 0)) {
|
||||
snprintf(err, err_sz, "%s: full fallback reason=%s, expected=scoped_lsp_gap", tc->name,
|
||||
actual_reason ? actual_reason : "");
|
||||
goto cleanup;
|
||||
}
|
||||
cbm_pipeline_free(pipeline);
|
||||
pipeline = NULL;
|
||||
|
||||
rc =
|
||||
pipeline_compare_current_db_to_fresh_fast_rebuild(root, db_path, project, cfg, err, err_sz);
|
||||
if (rc != 0 && (!err || err[0] == '\0')) {
|
||||
snprintf(err, err_sz, "%s: incremental graph differed from fresh rebuild", tc->name);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
cbm_pipeline_free(pipeline);
|
||||
free(project);
|
||||
cbm_config_close(cfg);
|
||||
const char *artifact_dir = getenv("CBM_TEST_ARTIFACT_DIR");
|
||||
if (rc != 0 && artifact_dir && artifact_dir[0] != '\0') {
|
||||
printf(" [incremental-language-artifact] %s\n", root);
|
||||
} else {
|
||||
th_rmtree(root);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
TEST(incremental_cross_lsp_language_matrix_matches_fresh_rebuild) {
|
||||
static const incremental_language_oracle_case_t cases[] = {
|
||||
{"go", "sample.go", "package sample\n\nfunc Value() int { return 1 }\n",
|
||||
"package sample\n\nfunc Value() int { return 2 }\nfunc Added() int { return Value() }\n",
|
||||
CBM_PIPELINE_PUBLISH_INCREMENTAL_EXACT},
|
||||
{"c", "sample.c", "int matrix_value(void) { return 1; }\n",
|
||||
"int matrix_value(void) { return 2; }\nint matrix_added(void) { return matrix_value(); "
|
||||
"}\n",
|
||||
CBM_PIPELINE_PUBLISH_INCREMENTAL_EXACT},
|
||||
{"cpp", "sample.cpp", "int matrix_value() { return 1; }\n",
|
||||
"int matrix_value() { return 2; }\nint matrix_added() { return matrix_value(); }\n",
|
||||
CBM_PIPELINE_PUBLISH_INCREMENTAL_EXACT},
|
||||
{"cuda", "sample.cu", "__device__ int matrix_value() { return 1; }\n",
|
||||
"__device__ int matrix_value() { return 2; }\n"
|
||||
"__device__ int matrix_added() { return matrix_value(); }\n",
|
||||
CBM_PIPELINE_PUBLISH_INCREMENTAL_EXACT},
|
||||
{"python", "sample.py", "def matrix_value():\n return 1\n",
|
||||
"def matrix_value():\n return 2\n\ndef matrix_added():\n return matrix_value()\n",
|
||||
CBM_PIPELINE_PUBLISH_INCREMENTAL_EXACT},
|
||||
{"javascript", "sample.js", "export function matrixValue() { return 1; }\n",
|
||||
"export function matrixValue() { return 2; }\n"
|
||||
"export function matrixAdded() { return matrixValue(); }\n",
|
||||
CBM_PIPELINE_PUBLISH_FULL},
|
||||
{"typescript", "sample.ts", "export function matrixValue(): number { return 1; }\n",
|
||||
"export function matrixValue(): number { return 2; }\n"
|
||||
"export function matrixAdded(): number { return matrixValue(); }\n",
|
||||
CBM_PIPELINE_PUBLISH_FULL},
|
||||
{"tsx", "sample.tsx", "export function MatrixValue(): number { return 1; }\n",
|
||||
"export function MatrixValue(): number { return 2; }\n"
|
||||
"export function MatrixAdded(): number { return MatrixValue(); }\n",
|
||||
CBM_PIPELINE_PUBLISH_FULL},
|
||||
{"php", "sample.php", "<?php function matrix_value() { return 1; }\n",
|
||||
"<?php function matrix_value() { return 2; }\n"
|
||||
"function matrix_added() { return matrix_value(); }\n",
|
||||
CBM_PIPELINE_PUBLISH_FULL},
|
||||
{"csharp", "Sample.cs", "class MatrixType { static int Value() { return 1; } }\n",
|
||||
"class MatrixType { static int Value() { return 2; } "
|
||||
"static int Added() { return Value(); } }\n",
|
||||
CBM_PIPELINE_PUBLISH_FULL},
|
||||
{"java", "MatrixType.java", "class MatrixType { static int value() { return 1; } }\n",
|
||||
"class MatrixType { static int value() { return 2; } "
|
||||
"static int added() { return value(); } }\n",
|
||||
CBM_PIPELINE_PUBLISH_FULL},
|
||||
{"kotlin", "Sample.kt", "fun matrixValue(): Int = 1\n",
|
||||
"fun matrixValue(): Int = 2\nfun matrixAdded(): Int = matrixValue()\n",
|
||||
CBM_PIPELINE_PUBLISH_FULL},
|
||||
{"rust", "sample.rs", "pub fn matrix_value() -> i32 { 1 }\n",
|
||||
"pub fn matrix_value() -> i32 { 2 }\n"
|
||||
"pub fn matrix_added() -> i32 { matrix_value() }\n",
|
||||
CBM_PIPELINE_PUBLISH_FULL},
|
||||
};
|
||||
char err[CBM_SZ_8K];
|
||||
for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
|
||||
err[0] = '\0';
|
||||
int rc = run_incremental_language_oracle_case(&cases[i], err, sizeof(err));
|
||||
if (rc != 0) {
|
||||
FAIL(err[0] ? err : "incremental language oracle failed");
|
||||
}
|
||||
}
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST(incremental_exact_python_receiver_type_gap_matches_full_rebuild) {
|
||||
enum { PIPELINE_EXACT_ONE_PATH = 1 };
|
||||
if (setup_incremental_repo() != 0) {
|
||||
@@ -17455,6 +17626,7 @@ SUITE(pipeline) {
|
||||
RUN_TEST(incremental_overlay_publish_small_deltas_keeps_canonical_base_visible);
|
||||
RUN_TEST(incremental_exact_python_scoped_lsp_gap_matches_full_rebuild);
|
||||
RUN_TEST(incremental_javascript_scoped_lsp_gap_reports_full_rebuild_not_cap_overflow);
|
||||
RUN_TEST(incremental_cross_lsp_language_matrix_matches_fresh_rebuild);
|
||||
RUN_TEST(incremental_exact_python_receiver_type_gap_matches_full_rebuild);
|
||||
RUN_TEST(pipeline_persisted_python_defs_feed_scoped_cross_lsp);
|
||||
RUN_TEST(pipeline_store_backed_lsp_cross_uses_import_scope_defs);
|
||||
|
||||
Reference in New Issue
Block a user