* collect_usage_sources: index the fixture once, find the IRepository node, * walk all USAGE edges that target it, and write the source file_paths * (up to `cap`) into `out`. DISTINCT-file (set) semantics match the petclinic * oracle ("exactly 7 user files"): one file may legitimately contribute several * USAGE edges from different source nodes (a method-scoped reference sources * from the M
| 209 | * Returns -1 on setup failure. |
| 210 | */ |
| 211 | static int collect_usage_sources_n(const RFile *files, int nfiles, char **out, int cap) { |
| 212 | RProj lp; |
| 213 | cbm_store_t *store = rh_index_files(&lp, files, nfiles); |
| 214 | if (!store) { |
| 215 | return -1; |
| 216 | } |
| 217 | |
| 218 | /* Locate the IRepository node by name. */ |
| 219 | cbm_node_t *candidates = NULL; |
| 220 | int ncand = 0; |
| 221 | int rc = cbm_store_find_nodes_by_name(store, lp.project, "IRepository", |
| 222 | &candidates, &ncand); |
| 223 | if (rc != CBM_STORE_OK || ncand == 0) { |
| 224 | cbm_store_free_nodes(candidates, ncand); |
| 225 | rh_cleanup(&lp, store); |
| 226 | return -1; |
| 227 | } |
| 228 | |
| 229 | /* Pick the Interface / Class node (label check). */ |
| 230 | int64_t target_id = 0; |
| 231 | for (int i = 0; i < ncand; i++) { |
| 232 | const char *lbl = candidates[i].label ? candidates[i].label : ""; |
| 233 | if (strcmp(lbl, "Interface") == 0 || strcmp(lbl, "Class") == 0) { |
| 234 | target_id = candidates[i].id; |
| 235 | break; |
| 236 | } |
| 237 | } |
| 238 | cbm_store_free_nodes(candidates, ncand); |
| 239 | |
| 240 | if (!target_id) { |
| 241 | rh_cleanup(&lp, store); |
| 242 | return -1; |
| 243 | } |
| 244 | |
| 245 | /* Walk inbound USAGE edges. */ |
| 246 | cbm_edge_t *edges = NULL; |
| 247 | int nedges = 0; |
| 248 | rc = cbm_store_find_edges_by_target_type(store, target_id, "USAGE", &edges, &nedges); |
| 249 | if (rc != CBM_STORE_OK) { |
| 250 | rh_cleanup(&lp, store); |
| 251 | return -1; |
| 252 | } |
| 253 | |
| 254 | int found = 0; |
| 255 | for (int i = 0; i < nedges && found < cap; i++) { |
| 256 | cbm_node_t src_node; |
| 257 | if (cbm_store_find_node_by_id(store, edges[i].source_id, &src_node) != CBM_STORE_OK) { |
| 258 | continue; |
| 259 | } |
| 260 | if (!src_node.file_path || !src_node.file_path[0]) { |
| 261 | continue; |
| 262 | } |
| 263 | /* Set semantics: skip a file_path already collected. */ |
| 264 | int dup = 0; |
| 265 | for (int j = 0; j < found; j++) { |
| 266 | if (strcmp(out[j], src_node.file_path) == 0) { |
| 267 | dup = 1; |
| 268 | break; |
no test coverage detected