Skip to content

Commit 476d375

Browse files
committed
Ignore derived ::missed projects when resolving stores
1 parent 5665e99 commit 476d375

4 files changed

Lines changed: 41 additions & 11 deletions

File tree

src/mcp/mcp.c

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1565,10 +1565,27 @@ static bool db_internal_project_name(const char *full_path, char *name_out, size
15651565
cbm_project_t *projs = NULL;
15661566
int n = 0;
15671567
bool ok = false;
1568-
if (cbm_store_list_projects(st, &projs, &n) == CBM_STORE_OK && n == 1 && projs[0].name &&
1569-
projs[0].name[0]) {
1570-
snprintf(name_out, name_sz, "%s", projs[0].name);
1571-
ok = true;
1568+
if (cbm_store_list_projects(st, &projs, &n) == CBM_STORE_OK) {
1569+
const char *base_project = NULL;
1570+
int base_count = 0;
1571+
static const char missed_suffix[] = "::missed";
1572+
for (int i = 0; i < n; i++) {
1573+
const char *candidate = projs[i].name;
1574+
if (!candidate || !candidate[0]) {
1575+
continue;
1576+
}
1577+
size_t len = strlen(candidate);
1578+
size_t suffix_len = sizeof(missed_suffix) - SKIP_ONE;
1579+
if (len >= suffix_len && strcmp(candidate + len - suffix_len, missed_suffix) == 0) {
1580+
continue; /* derived coverage graph, not a separately addressable project */
1581+
}
1582+
base_project = candidate;
1583+
base_count++;
1584+
}
1585+
if (base_count == 1 && strlen(base_project) < name_sz) {
1586+
snprintf(name_out, name_sz, "%s", base_project);
1587+
ok = true;
1588+
}
15721589
}
15731590
cbm_store_free_projects(projs, n);
15741591
if (ok && out_store) {

src/store/store.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2013,6 +2013,10 @@ static void cov_rebuild_shadow_graph(cbm_store_t *s, const char *project) {
20132013
sqlite3_finalize(del);
20142014
}
20152015
}
2016+
/* The projects row is derived too. Remove it before rebuilding so a run
2017+
* whose current coverage has no failures does not leave a stale
2018+
* <project>::missed entry behind. It is re-created below when needed. */
2019+
(void)cbm_store_delete_project(s, covproj);
20162020

20172021
cbm_coverage_row_t *rows = NULL;
20182022
int count = 0;
@@ -2035,8 +2039,8 @@ static void cov_rebuild_shadow_graph(cbm_store_t *s, const char *project) {
20352039
}
20362040

20372041
/* nodes.project has an FK to projects(name) (enforced: foreign_keys=ON),
2038-
* so the shadow project needs its row. Invisible to list_projects, which
2039-
* scans the cache directory for .db files, not this table. */
2042+
* so the shadow project needs its row. list_projects scans DB files and
2043+
* explicitly ignores the ::missed internal row when resolving each file. */
20402044
if (cbm_store_upsert_project(s, covproj, "") != CBM_STORE_OK) {
20412045
cbm_store_free_coverage(rows, count);
20422046
return;

tests/test_mcp.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4449,6 +4449,14 @@ TEST(tool_resolve_store_by_internal_name_issue704) {
44494449

44504450
/* (1) control: filename == internal name */
44514451
ASSERT_TRUE(issue704_make_db(cache, "alpha704.db", "alpha704", "alphaFunc704"));
4452+
/* Coverage materializes a second internal projects row in the same DB.
4453+
* list_projects must ignore this derived graph and still advertise alpha. */
4454+
char alpha_path[700];
4455+
snprintf(alpha_path, sizeof(alpha_path), "%s/alpha704.db", cache);
4456+
cbm_store_t *alpha_store = cbm_store_open_path(alpha_path);
4457+
ASSERT_NOT_NULL(alpha_store);
4458+
ASSERT_EQ(cbm_store_upsert_project(alpha_store, "alpha704::missed", ""), CBM_STORE_OK);
4459+
cbm_store_close(alpha_store);
44524460

44534461
/* (2) DRIFT: build beta704.db (internal "beta704") then rename the file to
44544462
* gamma704.db, so filename "gamma704" != internal "beta704". */
@@ -4526,18 +4534,16 @@ TEST(tool_resolve_store_by_internal_name_issue704) {
45264534
} else {
45274535
cbm_unsetenv("CBM_CACHE_DIR");
45284536
}
4529-
char a_path[700];
4530-
snprintf(a_path, sizeof(a_path), "%s/alpha704.db", cache);
45314537
char corrupt_path[720];
45324538
snprintf(corrupt_path, sizeof(corrupt_path), "%s.corrupt", ghost_path);
4533-
cbm_unlink(a_path);
4539+
cbm_unlink(alpha_path);
45344540
cbm_unlink(gamma_path);
45354541
cbm_unlink(ghost_path);
45364542
cbm_unlink(corrupt_path); /* ghost may be quarantined by resolve_store */
45374543
char side[740];
4538-
snprintf(side, sizeof(side), "%s-wal", a_path);
4544+
snprintf(side, sizeof(side), "%s-wal", alpha_path);
45394545
cbm_unlink(side);
4540-
snprintf(side, sizeof(side), "%s-shm", a_path);
4546+
snprintf(side, sizeof(side), "%s-shm", alpha_path);
45414547
cbm_unlink(side);
45424548
snprintf(side, sizeof(side), "%s-wal", gamma_path);
45434549
cbm_unlink(side);

tests/test_store_nodes.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1663,6 +1663,9 @@ TEST(store_coverage_roundtrip_prune_shadow) {
16631663
ASSERT_EQ(cbm_store_find_nodes_by_label(s, "test::missed", "File", &nodes, &nc), CBM_STORE_OK);
16641664
ASSERT_EQ(nc, 0);
16651665
cbm_store_free_nodes(nodes, nc);
1666+
cbm_project_t shadow = {0};
1667+
ASSERT(cbm_store_get_project(s, "test::missed", &shadow) != CBM_STORE_OK);
1668+
cbm_project_free_fields(&shadow);
16661669

16671670
cbm_store_close(s);
16681671
PASS();

0 commit comments

Comments
 (0)