All tests are in codeagent-engine/crates/codeagent-core/src/. 454 tests, 0 failures.
| ID | Test | What it checks |
|---|---|---|
| T-001 | test_csharp_extracts_namespace |
namespace Foo {} → Module node with symbol_key = "Foo:module" |
| T-002 | test_csharp_extracts_class_with_method |
Class + method both extracted; method symbol_key includes param count and types |
| T-003 | test_csharp_overload_distinct_symbol_keys |
Two methods with same name but different param lists → distinct symbol_key values |
| T-004 | test_csharp_extracts_interface |
interface IFoo {} → Interface node |
| T-005 | test_csharp_extracts_property |
public int Prop { get; set; } → Property node |
| T-006 | test_csharp_generated_flag_propagated |
Node from a file matching a generated-glob pattern has generated = 1 |
| T-007 | test_csharp_parse_status_on_invalid_syntax |
Malformed C# does not panic; file node still emitted with parse_status = 'syntactic_only' |
| T-008 | test_csharp_extracts_enum |
enum Status { … } → NodeType::Type with symbol_key = "Status:type" |
| T-009 | test_csharp_extracts_struct |
struct Point { … } routed through handle_class → Class node |
| T-010 | test_csharp_nested_class_qualified_name |
Nested class receives fully-qualified name Outer.Inner:class; type-stack propagates correctly |
| T-011 | test_csharp_extracts_constructor |
Constructor symbol_key includes param count, e.g. Widget.Widget:constructor:1(string) |
| T-013 | test_csharp_deeply_nested_generics_signature_truncated |
Parameter signature with deeply-nested generics truncated at configured max_signature_length; stored value ends with "..." |
| T-420 | test_csharp_reference_count_defaults_to_zero_in_phase1 |
Phase 1 tree-sitter indexing sets reference_count = 0 for all method nodes (not computed until semantic enrichment) |
| T-395 | test_aspnet_basic_api_controller_httpget |
Basic [ApiController] + [HttpGet] produces api_endpoints row with GET method |
| T-396 | test_aspnet_all_http_methods |
[HttpGet/Post/Put/Delete/Patch] each produce correct http_method values |
| T-397 | test_aspnet_route_resolution_with_controller_token |
[Route("api/[controller]")] + [HttpGet("{id}")] resolves to api/users/{id} |
| T-398 | test_aspnet_auth_extraction |
[Authorize(Policy="Admin")] and [AllowAnonymous] produce correct auth_policy |
| T-399 | test_aspnet_from_body_parameter |
[FromBody] parameter type extracted as request_body_type |
| T-400 | test_aspnet_response_type_from_action_result |
ActionResult and Task<ActionResult> unwrapped to response_type |
| T-401 | test_aspnet_non_controller_class_no_endpoints |
Class without [ApiController] or ControllerBase produces no api_endpoints |
| T-402 | test_aspnet_class_without_api_controller_attribute_no_endpoints |
Class without [ApiController] attribute and not inheriting ControllerBase produces no endpoints |
| T-403 | test_aspnet_controller_base_inheritance_without_attribute |
Class inheriting ControllerBase (no [ApiController]) still detected as controller |
| T-404 | test_resolve_route_template_combinations |
Unit test for route template resolution helper with various inputs |
| T-405 | test_extract_response_type_from_return_type |
Unit test for response type extraction from Task<ActionResult> strings |
| T-406 | test_unwrap_generic |
Unit test for generic type unwrapping helper |
| ID | Test | What it checks |
|---|---|---|
| T-014 | test_ts_extracts_exported_function |
export function foo() → node with export_scope = "module", stored as node_type = 'method' |
| T-015 | test_ts_extracts_interface |
export interface IService {} → Interface node |
| T-016 | test_ts_non_exported_function_has_file_scope |
Non-exported function extracted with export_scope = "file" |
| T-017 | test_ts_symbol_key_contains_file_id_segment |
Phase 1 TS symbol_key contains the file_id segment for module-scoped symbols |
| T-018 | test_tsx_file_parses_without_error |
.tsx file with JSX parses without error |
| T-019 | test_ts_file_node_emitted |
Indexing a .ts file produces a file node |
| T-020 | test_ts_arrow_function_extracted_as_method |
const double = (n: number) => … → node_type = 'method' |
| T-021 | test_ts_class_method_extracted |
Class extracted + body method extracted as node_type = 'method' |
| T-022 | test_ts_type_alias_extracted |
type UserId = string → NodeType::Type |
| T-023 | test_ts_enum_extracted |
enum Direction { … } → NodeType::Type |
| T-421 | test_ts_reference_count_defaults_to_zero_in_phase1 |
Phase 1 tree-sitter indexing sets reference_count = 0 for all method nodes (not computed until semantic enrichment) |
| T-422 | test_ts_same_named_exports_in_different_files_distinct_keys |
Two identically-named exported functions in different files produce distinct identity keys (file_id segment differs) |
| T-431 | test_ts_interface_body_walked |
Interface method and property signatures extracted as child nodes |
| ID | Test | What it checks |
|---|---|---|
| T-025 | test_migration_from_empty |
Empty DB → migrate to CURRENT_SCHEMA_VERSION |
| T-026 | test_migration_idempotent |
Running run_migrations() twice is a no-op |
| T-027 | test_downgrade_rejected |
DB at higher schema version → CoreError::SchemaTooNew |
| T-028 | test_quick_check_passes_on_valid_db |
PRAGMA quick_check succeeds on a freshly migrated DB |
| T-029 | test_schema_tables_exist |
All expected tables are present after migration 001 |
| T-030 | test_primary_span_partial_unique_index_exists |
idx_node_spans_one_primary partial unique index exists |
| T-031 | test_node_identity_map_table_exists |
node_identity_map table present after migration 002 |
| T-032 | test_node_identity_map_index_exists |
idx_node_identity_map_old index exists after migration 002 |
| T-033 | test_node_identity_map_insert_and_query |
Row with BLOB(16) UUID columns can be inserted and queried back |
| T-034 | test_schema_version_is_4 |
CURRENT_SCHEMA_VERSION == 4; DB reaches version 4 after all migrations (api_endpoints added by migration 004) |
| ID | Test | What it checks |
|---|---|---|
| T-036 | test_root_project_creation_and_idempotency |
ensure_root_project() creates self-referential project node; second call is a no-op |
| T-037 | test_upsert_node_insert |
New node round-trips all fields via upsert_node() |
| T-039 | test_c_sharp_overload_identity |
Two C# overloads coexist without a UNIQUE constraint violation |
| T-040 | test_multi_span_chunk_hash_ordering |
Multi-span chunk_hash is order-independent (sorted by bytes ASC) |
| T-041 | test_fts_insert_and_search |
After sync_fts_insert(), FTS MATCH query on name returns that node |
| T-042 | test_fts_delete_on_node_removal |
After sync_fts_delete(), FTS query returns no results |
| T-043 | test_fts_prefix_search |
3-character prefix query (Pro*) returns the matching node |
| T-044 | test_fts_update_replaces_old_name |
Re-inserting with a new display_name removes old name from FTS index |
| T-045 | test_fts_dotted_name_is_single_token |
. is a tokenchar: AuthSvc.Login is one FTS token; plain AuthSvc does NOT match it |
| T-046 | test_fts_at_verbatim_identifier_preserved |
@ is a tokenchar: @event is indexed and matchable as a single token |
| T-047 | test_fts_underscore_identifier_preserved |
_ is a tokenchar: MY_CONST is indexed as one token |
| T-048 | test_fts_dollar_identifier_preserved |
$ is a tokenchar: $scope is indexed as one token including the $ prefix |
| T-423 | test_upsert_nodes_in_tx_panics_above_500 |
debug_assert fires when caller passes >500 nodes to upsert_nodes_in_tx (bounded write transactions invariant) |
| T-424 | test_multi_project_same_symbol_name_coexists |
Identical symbol_key in two distinct projects coexists without UNIQUE violation (project_id differentiates) |
| T-425 | test_parse_status_stays_syntactic_only_when_enrichment_skipped |
Node inserted with parse_status=syntactic_only retains that value until explicit upgrade to full |
| ID | Test | What it checks |
|---|---|---|
| T-049 | test_edge_insert_and_query |
Edge inserted and retrieved by get_outgoing_edges() / get_incoming_edges() |
| T-050 | test_on_delete_cascade_for_edges |
Deleting the source node cascade-deletes its edges |
| T-051 | test_replace_semantic_edges_removes_stale |
replace_semantic_edges_in_tx() removes old exact edges and inserts the new set |
| T-052 | test_replace_semantic_edges_preserves_out_of_scope_edges |
Approximate edges from nodes outside the scope survive the replacement |
| T-053 | test_replace_semantic_edges_upgrades_approximate_to_exact |
Approximate edge for (A→B) upgraded to exact when semantic pass confirms the same edge |
| T-054 | test_replace_semantic_edges_empty_new_set_removes_exact |
Empty new-edge slice removes all exact and approximate edges from the scope |
| T-055 | test_delete_outgoing_edges_by_type_selects_only_matching_type |
delete_outgoing_edges_by_type(Calls) leaves References edges untouched |
| T-056 | test_upsert_edge_insert_or_ignore_no_duplicate |
Calling upsert_edge twice produces exactly one row |
| ID | Test | What it checks |
|---|---|---|
| T-057 | test_insert_span_roundtrip |
Span inserted via insert_span() is retrievable with all fields correct |
| T-058 | test_replace_spans_replaces_old |
replace_spans() removes prior spans for a node and inserts the new set |
| T-059 | test_primary_span_flag |
After replace_spans(), exactly one span has is_primary = 1 |
| T-060 | test_reassign_primary_span |
reassign_primary_span() flips the primary flag correctly without touching other nodes |
| T-061 | test_replace_spans_on_empty_slice |
replace_spans() with an empty slice leaves no spans for the node |
| T-426 | test_node_spans_file_id_cascade_deletes_orphaned_spans |
Directly deleting a file node CASCADE-deletes its node_spans rows (safety net independent of explicit deletion algorithm) |
| ID | Test | What it checks |
|---|---|---|
| T-062 | test_delete_file_removes_single_span_nodes |
Deleting a file removes all single-span nodes and their spans; journals each deleted node; edges cascade-delete |
| T-063 | test_delete_file_preserves_multi_span_node |
Multi-span node not hard-deleted when only one of its files is removed; primary span reassigned |
| T-064 | test_deletion_is_in_single_transaction |
Entire deletion sequence (spans → nodes → file node) executes atomically |
| T-065 | test_journal_sweep |
sweep_deletion_journal() removes entries older than the configured TTL |
| T-066 | test_journal_node_direct_roundtrip |
journal_node() writes all fields (including chunk_fingerprint bytes) to deletion_log |
| T-067 | test_delete_symbol_journals_and_removes_node |
delete_symbol() writes a journal entry first, then hard-deletes the node |
| T-068 | test_delete_file_no_orphaned_fts_rows |
After file deletion, fts_nodes has no rows for any deleted symbol's node_id |
| ID | Test | What it checks |
|---|---|---|
| T-069 | test_creates_before_deletes_ordering |
ChangeBatch always yields creates/modifications before deletes regardless of event order |
| T-070 | test_deduplication_keeps_latest |
Multiple events for the same path are collapsed to the most recent |
| ID | Test | What it checks |
|---|---|---|
| T-072 | test_decision_matrix_calls_source_changed |
Calls + SourceNodeChanged → RecomputeViaSemantic |
| T-073 | test_decision_matrix_calls_target_body_only |
Calls + TargetBodyOnly → NoAction |
| T-074 | test_decision_matrix_calls_node_id_preserved |
Calls + TargetNodeIdPreserved → NodeIdPreserved |
| T-075 | test_decision_matrix_calls_node_id_replaced |
Calls + TargetNodeIdReplaced → CascadeRemoved |
| T-076 | test_decision_matrix_contains_child_changed |
Contains + ContainerChildChanged → RecomputeFromAst |
| T-077 | test_decision_matrix_contains_method_body_only |
Contains + MethodBodyOnly → NoAction |
| T-078 | test_decision_matrix_imports_source_changed |
Imports + SourceNodeChanged → RecomputeFromAst |
| T-079 | test_decision_matrix_semantic_context_recompute |
Any edge + SemanticContextChanged → RecomputeSemanticEdges |
| T-080 | test_needs_reindex_hash_changed |
needs_reindex() returns true when chunk_hash differs |
| T-081 | test_decision_matrix_references_source_changed |
References + SourceNodeChanged → RecomputeViaSemantic |
| T-082 | test_decision_matrix_references_target_body_only |
References + TargetBodyOnly → NoAction |
| T-083 | test_decision_matrix_references_target_node_id_replaced |
References + TargetNodeIdReplaced → CascadeRemoved |
| T-084 | test_decision_matrix_inherits_declaration_header_changed |
Inherits + DeclarationHeaderChanged → RecomputeViaSemantic |
| T-085 | test_decision_matrix_inherits_base_type_changed |
Inherits + BaseTypeChanged → NoAction |
| T-086 | test_decision_matrix_implements_declaration_header_changed |
Implements + DeclarationHeaderChanged → RecomputeViaSemantic |
| T-087 | test_decision_matrix_implements_base_type_changed |
Implements + BaseTypeChanged → NoAction |
| T-088 | test_decision_matrix_overrides_declaration_header_changed |
Overrides + DeclarationHeaderChanged → RecomputeViaSemantic |
| T-089 | test_decision_matrix_overrides_base_type_changed |
Overrides + BaseTypeChanged → NoAction |
| T-090 | test_decision_matrix_accepts_source_changed |
Accepts + SourceNodeChanged → RecomputeViaSemantic (+ ProbableIfStructural) |
| T-091 | test_decision_matrix_accepts_target_body_only |
Accepts + TargetBodyOnly → NoAction |
| T-092 | test_decision_matrix_extends_source_changed |
Extends + SourceNodeChanged → RecomputeViaSemantic |
| T-093 | test_decision_matrix_extends_target_body_only |
Extends + TargetBodyOnly → NoAction |
| T-094 | test_decision_matrix_default_fallback_is_no_action |
Any unspecified (edge_type, change_type) pair → NoAction |
| ID | Test | What it checks |
|---|---|---|
| T-095 | test_resolve_project_id_exact_dir |
File inside a project directory resolves to that project |
| T-096 | test_resolve_project_id_falls_back_to_root |
File with no matching project resolves to the root |
| T-097 | test_resolve_project_id_most_specific_wins |
File under nested projects resolves to the most deeply nested one |
| T-098 | test_detect_csproj_project |
Directory with a .csproj file detected as a CSharp project |
| T-099 | test_detect_package_json_project |
package.json → TypeScript project with correct display_name |
| T-100 | test_detect_tsconfig_only_project |
tsconfig.json with no package.json → detected as TS project |
| T-101 | test_detect_skips_node_modules |
node_modules/ subtrees not walked during detection |
| T-102 | test_detect_nested_csproj_projects |
Two .csproj at different depths → two distinct detected projects |
| T-103 | test_ensure_projects_in_db_idempotent |
Calling ensure_projects_in_db twice returns the same ProjectId both times |
| ID | Test | What it checks |
|---|---|---|
| T-104 | test_to_posix_forward_slashes |
Windows backslashes converted to forward slashes |
| T-105 | test_normalize_relative_path |
Leading separators stripped; backslashes converted |
| T-106 | test_detect_language |
.cs → CSharp; .ts/.tsx → TypeScript; others → None |
| T-107 | test_is_generated |
Files matching configured glob patterns flagged as generated |
| T-108 | test_is_semantic_context_file |
.csproj, tsconfig.json, package.json identified as semantic context files |
| T-109 | test_glob_match |
Glob pattern matching works for common patterns |
| T-110 | ✅ test_symlink_outside_repo_root_rejected |
Symlink pointing outside repo root → path rejected by verify_within_repo_root() |
| T-111 | ✅ test_symlink_inside_repo_root_accepted_when_follow_enabled |
Symlink within repo root indexed when follow_symlinks = true; skipped when false |
| ID | Test | What it checks |
|---|---|---|
| T-112 | test_language_roundtrip |
Language::as_str() / from_str() / Display consistent; unknown string → None |
| T-113 | test_node_type_roundtrip |
All 10 NodeType variants round-trip through as_str() → from_str() |
| T-114 | test_edge_type_roundtrip |
All 9 EdgeType variants round-trip |
| T-115 | test_edge_type_is_source_driven |
Calls, References, Overrides, Extends → true; other 5 → false |
| T-116 | test_edge_confidence_roundtrip |
All 3 EdgeConfidence variants round-trip |
| T-117 | test_parse_status_roundtrip |
All 3 ParseStatus variants round-trip |
| T-118 | test_access_modifier_roundtrip |
All 7 AccessModifier variants (incl. ProtectedInternal, Exported, Unexported) round-trip |
| T-119 | test_export_scope_roundtrip |
All 3 ExportScope variants round-trip |
| T-121 | test_content_hash_to_hex_all_zeroes |
All-zero hash → 64-char hex of "00"×32 |
| T-122 | test_content_hash_to_hex_known_value |
Known byte values produce expected hex characters |
| T-123 | test_content_hash_from_bytes_roundtrip |
as_bytes() → from_bytes() returns original ContentHash |
| T-124 | test_content_hash_from_bytes_wrong_length |
31, 33, and 0-byte slices all return None |
| T-125 | test_content_hash_serde_roundtrip |
serde_json serialize → deserialize produces identical ContentHash; form is 64-char hex |
| T-126 | test_node_id_from_bytes_roundtrip |
NodeId::as_bytes() → from_bytes() round-trips |
| T-127 | test_node_id_from_bytes_wrong_length |
15 and 17-byte slices return None |
| T-128 | test_file_id_and_project_id_roundtrip |
FileId and ProjectId both round-trip; wrong-length slices return None |
| T-129 | test_node_id_to_string_repr_is_uuid_format |
to_string_repr() produces canonical 8-4-4-4-12 UUID format |
| ID | Test | What it checks |
|---|---|---|
| T-130 | test_build_embedding_text_no_boilerplate |
Symbol embedding text omits constant boilerplate |
| T-131 | test_build_file_embedding_text |
File embedding text includes path, filename, and language |
| T-132 | test_build_embedding_text_all_none_optionals |
All-None → output is just "qualified_name node_type" |
| T-133 | test_build_embedding_text_empty_string_optionals_skipped |
Empty "" optional strings produce no extra tokens |
| T-134 | test_build_embedding_text_doc_comment_truncated_at_200 |
Doc comments > 200 chars are truncated |
| T-135 | test_build_file_embedding_text_no_slash_in_path |
Path with no / still extracts the filename correctly |
| T-136 | test_build_file_embedding_text_empty_summary_omitted |
Empty import/export summary not included |
| T-137 | test_build_file_embedding_text_doc_comment_truncated |
File doc comment truncated to 200 chars |
| ID | Test | What it checks |
|---|---|---|
| T-138 | test_get_node_roundtrip |
Node written to DB → retrieved with all fields intact |
| T-139 | test_get_node_not_found |
get_node() returns None for an unknown NodeId |
| T-140 | test_get_neighbors_outgoing |
get_neighbors() returns correct outgoing edges and their target nodes |
| T-141 | test_get_neighbors_incoming |
get_neighbors() returns correct incoming edges and their source nodes |
| T-142 | test_get_source |
get_source() returns the primary span content for a node |
| T-143 | test_get_outline |
get_outline() returns all child nodes of a file, ordered by line number |
| T-144 | test_filter_nodes_sql |
filter_nodes() applies language, type, and text search filters correctly |
| T-145 | test_get_node_by_qualified_name |
Node looked up by qualified_name |
| T-146 | test_filter_nodes_fts_returns_bm25_rank |
FTS query in filter_nodes() populates rank field; results ordered best-first |
| ID | Test | What it checks |
|---|---|---|
| T-149 | test_csharp_unavailable_when_safe_mode_true |
safe_mode = true blocks C# even when the extractor path is set |
| T-150 | test_csharp_available_when_safe_mode_false_and_path_set |
safe_mode = false + path set → C# available |
| T-151 | test_csharp_unavailable_when_no_extractor_path |
csharp_extractor_path = None → C# unavailable regardless of safe_mode |
| T-152 | test_typescript_available_regardless_of_safe_mode |
TypeScript availability not gated by safe_mode |
| T-153 | test_typescript_unavailable_when_no_extractor_path |
typescript_extractor_path = None → TypeScript unavailable |
| T-154 | test_default_config_both_languages_unavailable |
Default config (safe_mode=true, no paths) → both languages unavailable |
| T-432 | test_parse_tfm_major_valid |
TFM major version parsing succeeds for net8.0 and net10.0 |
| T-433 | test_parse_tfm_major_rejects_invalid |
TFM parsing rejects netstandard and invalid formats |
| T-434 | test_resolve_dll_picks_highest_available_runtime |
DLL resolution selects highest TFM with installed runtime |
| T-435 | test_resolve_dll_falls_back_when_no_runtime_matches |
DLL resolution returns original path if no matching runtime |
| T-436 | test_resolve_dll_not_under_tfm_dir_returns_as_is |
Non-TFM DLL paths returned unchanged |
| T-437 | test_resolve_non_dll_returns_as_is |
Non-DLL files returned as-is by resolver |
| T-155 | ✅ test_ipc_handshake_version_mismatch_triggers_fallback |
Protocol version mismatch during handshake → graceful fallback to syntactic-only mode |
| T-156 | ✅ test_ipc_request_deadline_enforced |
IPC request that exceeds deadline → Timeout error code returned promptly |
| T-157 | ✅ test_ipc_child_process_crash_clears_slot |
Child process exiting clears the slot so next request re-spawns |
| T-158 | ✅ test_nuget_restore_blocked_when_allow_nuget_restore_false |
allow_nuget_restore = false → NuGet restore command not sent even when safe_mode = false |
| T-251 | ✅ test_ipc_backpressure_error_when_child_queue_full |
Bounded semaphore at capacity → next request returns structured backpressure error rather than blocking indefinitely |
| T-252 | ✅ test_ipc_cancel_inflight_request_does_not_write_edges |
Cancelling a request mid-flight prevents any edges from that enrichment request being committed |
| T-253 | ✅ test_ipc_deadline_timeout_respects_max_retries |
IPC request exceeding deadline is retried up to the configured max-retries then returns a structured timeout error |
| ID | Test | What it checks |
|---|---|---|
| T-159 | test_rpc_request_new_has_jsonrpc_2_0_field |
RpcRequest::new() sets jsonrpc = "2.0" |
| T-160 | test_rpc_notification_has_empty_id |
RpcRequest::notification() produces empty id string |
| T-161 | test_rpc_request_serializes_to_valid_json_rpc_2_0 |
Serialized JSON has correct jsonrpc, method, id fields |
| T-162 | test_rpc_request_no_params_omitted_in_json |
params: None omitted via skip_serializing_if |
| T-163 | test_ipc_error_code_from_code_all_variants |
All 5 IpcErrorCode variants decode from their integer codes |
| T-164 | test_ipc_error_code_unknown_returns_none |
Unrecognised codes return None |
| T-165 | test_parse_result_extracts_analyze_file_result |
parse_result<AnalyzeFileResult>() deserializes valid response |
| T-166 | test_parse_result_returns_error_on_rpc_error_field |
parse_result returns Err when response has error field |
| T-167 | test_parse_result_returns_error_when_no_result_and_no_error |
parse_result returns Err when both fields absent |
| T-168 | test_handshake_params_serde_roundtrip |
HandshakeParams serializes and deserializes losslessly |
| T-169 | test_analyze_file_params_project_file_omitted_when_none |
project_file: None omitted from AnalyzeFileParams JSON |
| T-170 | test_analyze_file_params_project_file_present_when_some |
project_file: Some(_) present in AnalyzeFileParams JSON |
| T-171 | test_rpc_error_data_omitted_when_none |
data: None omitted from RpcError JSON |
| T-407 | test_semantic_node_with_api_endpoint_deserializes |
SemanticNode JSON with api_endpoint field deserializes correctly |
| T-408 | test_semantic_node_without_api_endpoint_backward_compat |
SemanticNode JSON missing api_endpoint deserializes as None |
| T-409 | test_semantic_node_api_endpoint_omitted_in_serialization_when_none |
Serializing SemanticNode with api_endpoint=None omits the field |
| ID | Test | What it checks |
|---|---|---|
| T-172 | test_csharp_reconciliation_in_place |
Roslyn-provided symbol_key replaces tree-sitter key in-place |
| T-173 | test_csharp_reconciliation_noop_if_same_key |
Reconciling with identical key makes no DB change |
| T-174 | test_csharp_reconciliation_conflict_falls_back_to_identity_map |
UNIQUE conflict → old node deleted; surviving node gets new key; node_identity_map entry written |
| T-175 | test_ts_export_scope_upgrade |
upgrade_ts_export_scope() updates export_scope and symbol_key in-place |
| ID | Test | What it checks |
|---|---|---|
| T-254 | ✅ test_semantic_enrichment_failure_preserves_existing_edges |
When enrichment returns an error for a scope, existing edges (exact or approximate) survive unchanged; no partial replacement occurs |
| ID | Test | What it checks |
|---|---|---|
| T-177 | test_rename_detector_no_deletes_returns_empty |
Batch with no deletes → empty rename result set |
| T-178 | test_rename_detector_no_creates_returns_empty |
Batch with deletes but no creates → empty rename result set |
| T-179 | test_parse_git_rename_basic |
"R95\told.cs\tnew.cs" parses to one rename pair |
| T-180 | test_parse_git_rename_not_in_batch_filtered_out |
Rename line referencing paths not in the batch excluded |
| T-181 | test_parse_git_rename_ignores_non_rename_lines |
M, A, D status lines ignored |
| T-182 | test_parse_git_rename_multiple_renames |
Multiple rename lines all parsed correctly |
| T-183 | test_parse_git_rename_malformed_line_skipped |
Malformed R lines skipped silently |
| T-184 | test_fingerprint_rename_detected_via_deletion_log |
Deletion log entry with matching fingerprint → rename detected |
| T-185 | test_fingerprint_rename_not_detected_when_no_journal_entry |
No journal entry → no fingerprint match |
| T-438 | test_rename_class_and_file_detected_via_fingerprint |
Fingerprint detects simultaneous class and file rename |
| T-186 | ✅ test_symbol_level_rename_preserves_node_id |
Method rename (same body, new name) → node_identity_map entry written; node_id preserved or remapped |
| T-187 | ✅ test_rename_and_body_change_is_not_detected |
Rename + substantial body rewrite → similarity < threshold → treated as delete+create |
| T-188 | ✅ test_file_rename_preserves_embeddings |
File-level rename → node_id preserved; vec_nodes embedding row retained |
| T-255 | ✅ test_rename_detector_ambiguous_candidates_resolved_deterministically |
Two deleted nodes with similar fingerprints and one created node → either no match (preferred) or highest-score with deterministic tie-breaker; result stable across runs |
| T-257 | ✅ test_git_diff_failure_falls_back_to_fingerprint |
Git unavailable or errors → rename detector continues with fingerprint-only mode without failing the batch |
| ID | Test | What it checks |
|---|---|---|
| T-189 | test_jaccard_identical |
Identical fingerprints → similarity 1.0 |
| T-190 | test_jaccard_empty |
Empty fingerprint sets → similarity 0.0 |
| T-191 | test_jaccard_disjoint |
Completely different sets → similarity 0.0 |
| T-192 | test_jaccard_half_overlap |
Half-overlapping sets → Jaccard ≈ 0.33 (intersection=2, union=6) |
| T-193 | test_renamed_method_high_similarity |
Method with only its name changed → Jaccard ≥ 0.80 |
| T-194 | test_fingerprint_roundtrip |
fingerprint_to_bytes() / fingerprint_from_bytes() round-trip losslessly |
| T-195 | test_fingerprint_unchanged_file_similarity_is_1 |
Same file content both times → Jaccard = 1.0 |
| T-196 | test_fingerprint_completely_rewritten_is_below_threshold |
Completely different content → similarity < 0.20 |
| ID | Test | What it checks |
|---|---|---|
| T-200 | test_hash_embedding_provider_dimensionality |
HashEmbeddingProvider reports dimensionality() == 384 |
| T-201 | test_hash_embedding_provider_unit_norm |
SHA-256-based embedding is L2-normalised (‖v‖ ≈ 1.0) |
| T-202 | test_hash_embedding_provider_deterministic |
Same text always produces identical embedding vector |
| T-203 | test_hash_embedding_provider_different_texts_differ |
Two distinct texts produce different embeddings |
| T-204 | test_hash_embedding_provider_batch_matches_single |
embed_batch results match embed_single results element-by-element |
| T-205 | test_hash_embedding_provider_model_id |
model_id() returns "test-hash-model" for default constructor |
| T-207 | test_hash_embedding_provider_custom_model_id |
with_model_id() constructor overrides the model ID |
| ID | Test | What it checks |
|---|---|---|
| T-206 | test_embedding_stored_in_vec_nodes |
After indexing a node, vec_nodes contains a row with the node's 384-dim embedding (stored as 1 536 LE bytes) |
| T-208 | test_embedding_model_change_triggers_re_embedding |
handle_model_change() with a new model ID clears all vec_nodes rows and updates _metadata.embedding_model |
| T-258 | test_embedding_model_unchanged_returns_false |
handle_model_change() with the same model ID returns false and leaves vec_nodes untouched |
| T-259 | test_insert_or_replace_overwrites_existing_embedding |
Calling insert_or_replace_embedding twice for the same node results in exactly one row |
| T-262 | test_delete_embedding_removes_row |
delete_embedding() removes the row for the given node_id |
| T-263 | test_delete_embedding_is_noop_when_absent |
delete_embedding() with an absent node_id does not error |
| T-264 | test_vec_nodes_table_created_by_ensure |
ensure_vec_nodes_table() creates the vec_nodes table (verified via sqlite_master) |
| T-265 | test_ensure_vec_nodes_table_is_idempotent |
Calling ensure_vec_nodes_table() twice does not error |
| T-439 | test_vector_search_brute_force_empty_table |
Empty vec_nodes table returns no results |
| T-440 | test_vector_search_brute_force_limit |
Vector search respects limit parameter |
| ID | Test | What it checks |
|---|---|---|
| T-209 | ✅ test_vector_channel_returns_ranked_results |
Vector similarity search returns ranked results with correct ordering |
| T-210 | ✅ test_bm25_channel_returns_ranked_results |
BM25 channel returns the expected node for a known-good keyword query |
| T-211 | ✅ test_qualified_name_channel_exact_match |
Qualified-name channel returns exact match with rank=1, score=1.0 |
| T-212 | ✅ test_token_budget_truncation |
Result set serialised to context never exceeds token budget; truncated flag set |
| T-213 | ✅ test_retrieve_end_to_end |
Full retrieve() pipeline returns results from independent channels |
| T-271 | ✅ test_build_fts_query_escapes_special_chars |
FTS5 operators escaped and wildcard appended; no panic or query error |
| T-272 | ✅ test_qualified_name_channel_no_match |
Qualified-name channel returns empty for non-existent name |
| T-273 | ✅ test_looks_like_qualified_name |
Query analysis routes dot-separated identifiers to qname lookup |
| T-274 | ✅ test_vector_search_brute_force_roundtrip |
Brute-force cosine search returns results ordered by distance |
| T-276 | ✅ test_context_preserves_score_order |
Results with scores are ordered deterministically in context assembly |
| T-277 | ✅ test_token_budget_no_truncation |
Token budget with enough room fits all results; truncated=false |
| T-441 | test_bm25_channel_empty_query |
BM25 search with empty FTS query returns empty results |
| T-442 | test_build_fts_query_empty |
Empty query string produces empty FTS query |
| T-443 | test_build_fts_query_qualified_name_quoted |
Qualified names wrapped in quotes for FTS phrase matching |
| T-444 | test_build_fts_query_simple_words |
Simple words converted to OR-joined tokens with wildcards |
| T-445 | test_context_entry_has_metadata |
Context entry contains node type, public api, and signatures |
| T-446 | test_estimate_tokens_non_zero |
Token estimation produces non-zero positive result |
| T-447 | test_retrieve_cross_cutting_doubles_channel_k |
Cross-cutting queries double the per-channel result limit |
| T-448 | test_retrieve_no_results |
Non-existent queries return empty results |
| T-449 | test_retrieve_qualified_name_triggers_qname_channel |
Qualified name queries rank qname channel matches first |
| ID | Test | What it checks |
|---|---|---|
| T-216 | ✅ test_rrf_merge_multi_channel |
RRF score for a node in two channels is higher than a node in one channel |
| T-217 | ✅ test_generated_node_penalty |
Nodes with generated = true receive the configured generated_penalty multiplier |
| T-218 | ✅ test_failed_parse_excluded |
Nodes with parse_status = Failed are excluded from results entirely |
| T-220 | ✅ test_cross_cutting_diversity_penalty |
Cross-cutting mode diversity penalty reduces score for 2nd+ node from same file |
| T-221 | ✅ test_targeted_intent_qualified_symbol |
Dot-qualified symbol and file path queries classified as targeted intent |
| T-222 | ✅ test_cross_cutting_intent |
"All usages of …" style query classified as cross_cutting intent |
| T-223 | ✅ test_exploratory_intent |
Broad "how does X work" query classified as exploratory intent |
| T-224 | ✅ test_eval_produces_valid_metrics |
Eval harness produces valid NDCG and MRR metrics in [0,1] range |
| T-225 | ✅ test_eval_negative_queries |
Queries referencing non-existent symbols produce 0 metrics |
| T-278 | ✅ test_qname_match_ranks_first |
Qualified-name exact match always ranked first regardless of RRF base score |
| T-279 | ✅ test_public_api_boost |
Public API boost applied additively after base RRF score computation |
| T-280 | ✅ test_fallback_is_targeted |
Ambiguous queries without clear signals default to targeted intent |
| T-281 | ✅ test_syntactic_only_penalty |
Syntactic-only nodes penalized below full-parse nodes |
| T-450 | test_targeted_intent_file_path |
File paths classified as targeted intent |
| T-451 | test_targeted_takes_priority_over_cross_cutting_when_symbol_present |
Dot-qualified symbols take priority over quantifiers |
| ID | Test | What it checks |
|---|---|---|
| T-282 | ✅ test_ndcg_at_k |
NDCG@k computed on hardcoded relevance list matches expected values; perfect ranking yields 1.0 |
| T-283 | ✅ test_mrr |
MRR computed on hardcoded ranked result list matches expected value (1/rank) |
| T-284 | test_precision_at_k |
Precision@k matches expected values for known result sets |
| T-452 | test_recall_at_k |
Recall@k matches expected values for known result sets |
| T-285 | ✅ test_load_eval_dataset_roundtrip |
Eval dataset loads from JSON and round-trips correctly; archetype serde verified |
| T-453 | test_ndcg_no_relevant_nodes |
NDCG@k returns 0.0 with empty relevance set |
| T-454 | test_mrr_first_is_relevant |
MRR equals 1.0 when first result is relevant |
| T-455 | test_mrr_no_relevant |
MRR equals 0.0 when no relevant nodes found |
| T-456 | test_precision_k_zero |
Precision@k returns 0.0 when k is zero |
| T-457 | test_recall_no_relevant |
Recall@k returns 0.0 when no relevant nodes exist |
| T-458 | test_load_eval_dataset_missing_file |
Missing eval dataset file returns error |
| T-459 | test_query_archetype_serde_roundtrip |
All QueryArchetype enums serialize and deserialize correctly |
| T-460 | test_eval_empty_dataset |
Empty eval dataset produces zero metrics |
| ID | Test | What it checks |
|---|---|---|
| T-461 | test_resolve_sandboxed_allows_valid_path |
Valid paths inside repo root are resolved successfully |
| T-462 | test_resolve_sandboxed_empty_path_returns_root |
Empty path resolves to repository root |
| T-463 | test_resolve_sandboxed_nonexistent_path |
Nonexistent paths return error |
| T-464 | test_resolve_sandboxed_rejects_dotdot |
Paths containing .. are rejected as escaping sandbox |
| ID | Test | What it checks |
|---|---|---|
| T-226 | ✅ test_list_directory_returns_files_and_dirs |
list_directory at repo root returns known files and subdirectories with correct types |
| T-227 | ✅ test_list_directory_rejects_path_escape |
list_directory with ../ path returns path_escape error |
| T-228 | ✅ test_read_file_returns_content |
read_file for a known file returns its full content with correct line count |
| T-229 | ✅ test_read_file_line_range |
read_file with line_start and line_end returns only the specified lines |
| T-230 | ✅ test_read_file_rejects_binary |
read_file on a binary file returns binary_file error with detected MIME type |
| T-231 | ✅ test_read_file_truncates_large_content |
read_file on a file exceeding max lines returns truncated: true |
| T-232 | ✅ test_get_directory_tree_respects_depth |
get_directory_tree with depth=1 returns only immediate children |
| T-233 | ✅ test_get_directory_tree_respects_gitignore |
get_directory_tree excludes paths matched by .gitignore |
| ID | Test | What it checks |
|---|---|---|
| T-286 | ✅ test_search_symbols_returns_ranked_results |
search_symbols with FTS query returns BM25-ranked results with expected fields |
| T-287 | ✅ test_lookup_symbol_by_qualified_name |
lookup_symbol returns exact match(es) for a known qualified name |
| T-260 | ✅ test_search_symbols_filters_by_type_and_language |
search_symbols with node_type and language filters restricts results correctly |
| T-410 | test_search_api_endpoints_returns_results |
search_api_endpoints returns endpoint+method JSON with all fields |
| T-411 | test_search_api_endpoints_filters_by_route |
search_api_endpoints with route_pattern returns matching endpoints only |
| T-412 | test_search_api_endpoints_empty_filters_returns_all |
search_api_endpoints with no filters returns all endpoints up to limit |
| ID | Test | What it checks |
|---|---|---|
| T-261 | ✅ test_get_symbol_returns_full_metadata |
get_symbol returns all node fields including access modifier and return type |
| T-288 | ✅ test_get_callers_returns_incoming_call_edges |
get_callers returns nodes with Calls edges pointing to the target |
| T-289 | ✅ test_get_file_outline_returns_symbols_in_order |
get_file_outline returns symbols ordered by line number |
| T-290 | ✅ test_get_implementations_returns_implements_and_extends |
get_implementations returns both Implements and Extends incoming edges |
| T-465 | test_get_symbol_invalid_uuid |
Invalid UUID node_id returns INVALID_PARAMETER error |
| T-413 | test_get_symbol_includes_api_endpoint |
get_symbol for an action method includes api_endpoint field with metadata |
| T-414 | test_get_symbol_omits_api_endpoint_when_absent |
get_symbol for a non-endpoint method omits api_endpoint field |
| T-415 | test_get_file_outline_includes_api_endpoint |
get_file_outline includes api_endpoint on action methods, omits on helpers |
| ID | Test | What it checks |
|---|---|---|
| T-291 | ✅ test_index_files_triggers_pipeline |
index_files with valid paths runs the ingest pipeline and updates the graph |
| T-292 | ✅ test_get_status_returns_accurate_counts |
get_status returns correct indexed_files, indexed_symbols, and watcher_active |
| T-466 | test_index_files_rejects_empty_paths |
Empty paths array is rejected with INVALID_PARAMETER |
| T-467 | test_index_files_rejects_too_many_paths |
More than 100 paths rejected with INVALID_PARAMETER |
| ID | Test | What it checks |
|---|---|---|
| T-293 | test_default_logs_exclude_prompt_and_source |
With default log config, debug_content_logging defaults to false — prevents leaking content |
| T-294 | test_debug_content_logging_gated_by_opt_in |
Content logging only enabled when explicitly set via config flag; defaults to off |
| ID | Test | What it checks |
|---|---|---|
| T-469 | test_ipc_child_exited_is_retryable |
IpcChildExited classified as retryable (respawn will fix it) |
| T-470 | test_ipc_timeout_is_retryable |
IpcTimeout classified as retryable (temporary overload) |
| T-471 | test_ipc_oom_restart_is_retryable |
IPC error with code -32104 (OomRestart) classified as retryable |
| T-472 | test_ipc_version_mismatch_is_not_retryable |
IpcVersionMismatch classified as non-retryable (fundamental incompatibility) |
| T-473 | test_cancelled_is_not_retryable |
Cancelled classified as non-retryable (explicit cancellation) |
| T-474 | test_ipc_semantic_unavailable_is_not_retryable |
IPC error -32100 classified as non-retryable (deterministic) |
| T-475 | test_ipc_project_load_failed_is_not_retryable |
IPC error -32101 classified as non-retryable (deterministic) |
| T-476 | test_ipc_plugin_blocked_is_not_retryable |
IPC error -32102 classified as non-retryable (safe mode) |
| T-477 | test_non_ipc_errors_are_not_retryable |
Non-IPC errors (NotInitialized, WriteQueueFull, etc.) all classified as non-retryable |
| T-478 | test_ipc_retry_defaults |
Default ipc_max_retries=2 and ipc_retry_base_delay_ms=500 |
| T-479 | test_ipc_retry_config_from_json |
JSON config overrides for retry fields parse correctly |
| T-480 | test_ipc_retry_config_defaults_when_omitted |
Missing retry fields in JSON default to expected values |
| T-481 | test_ipc_retry_zero_disables_retry |
Setting ipc_max_retries=0 disables retry |
| ID | Test | What it checks |
|---|---|---|
| T-234 | test_large_file_creates_file_node_and_metadata |
1 000-method file → file node emitted; method spans have file_path and line numbers |
| T-235 | test_cyclic_call_graph_traversal_terminates |
A→B→C→A call graph → WITH RECURSIVE query terminates via UNION dedup; returns bounded results |
| T-236 | test_2000_near_identical_methods_indexed |
2 000 methods with near-identical bodies indexed; FTS search returns bounded results |
| T-237 | test_wal_concurrent_read_write_no_data_loss |
Concurrent writer + 4 read connections under load; all reads observe consistent snapshots (#[ignore]) |
| T-238 | test_mixed_encoding_bom_stripped_before_hashing |
UTF-8 BOM stripped before parsing/hashing; chunk_hash matches BOM-free equivalent |
| T-239 | test_generated_code_glob_applies_penalty |
Generated node gets generated = 1; retrieval score receives multiplicative ×0.3 penalty |
| T-240 | test_rename_class_and_file_uuid_reused |
Class + file renamed → journal entry + node_identity_map links old→new (unit + integration) |
| T-241 | test_10k_file_write_throughput |
Index 10 000 files via writer; completes within 60s (#[ignore]) |
| T-295 | test_reader_pool_connections_set_required_pragmas |
Every reader pool connection has foreign_keys = ON, busy_timeout = 5000, and correct mmap_size |
| T-296 | test_disk_full_returns_structured_error |
Write failure on read-only file → structured CoreError with meaningful message |
| T-297 | test_mcp_tool_error_returns_structured_json |
MCP tool error → ErrorData with NOT_FOUND code and descriptive message |
| T-427 | test_cancellation_rolls_back_uncommitted_writes |
Writer thread rolls back uncommitted transaction when CancellationToken fires before COMMIT; no partial results persisted |
| T-428 | test_writer_connection_has_foreign_keys_on |
Writer connection has PRAGMA foreign_keys = ON (complements T-295 which tests reader pool) |
| ID | Test | What it checks |
|---|---|---|
| T-300 | test_cs_fixture_file_nodes |
6 .cs files → 6 file nodes |
| T-301 | test_cs_fixture_module_nodes |
2 namespaces deduplicated across 6 files → 2 module nodes |
| T-302 | test_cs_fixture_class_nodes |
User, Address (struct), UserService → 3 class nodes |
| T-303 | test_cs_fixture_interface_nodes |
IEntity, IUserService → 2 interface nodes |
| T-304 | test_cs_fixture_type_nodes |
Status enum → 1 type node |
| T-305 | test_cs_fixture_constructor_nodes |
User(string), User(string,string) → 2 constructor nodes |
| T-306 | test_cs_fixture_method_nodes |
12 method nodes across all files |
| T-307 | test_cs_fixture_property_nodes |
7 property nodes across all files |
| ID | Test | What it checks |
|---|---|---|
| T-308 | test_ts_fixture_file_nodes |
6 .ts files → 6 file nodes |
| T-309 | test_ts_fixture_type_nodes |
UserId, UserRole, Status → 3 type nodes |
| T-310 | test_ts_fixture_interface_nodes |
IEntity, IUserService → 2 interface nodes (body not walked) |
| T-311 | test_ts_fixture_class_nodes |
User, UserServiceImpl → 2 class nodes |
| T-312 | test_ts_fixture_method_nodes |
12 method nodes (class methods + top-level functions) |
| T-313 | test_ts_fixture_property_nodes |
6 property nodes (class fields + constants) |
| ID | Test | What it checks |
|---|---|---|
| T-314 | test_cs_fixture_qualified_names |
User and UserService have fully-qualified symbol keys with namespace prefix |
| T-315 | test_cs_fixture_overloaded_methods_distinct_keys |
GetDisplayName(0) and GetDisplayName(1) have distinct symbol keys |
| T-316 | test_cs_fixture_overloaded_constructors_distinct_keys |
User(string) and User(string,string) have distinct symbol keys |
| T-317 | test_cs_fixture_struct_is_class_node |
Address struct stored as class node |
| T-318 | test_cs_fixture_enum_is_type_node |
Status enum stored as type node |
| ID | Test | What it checks |
|---|---|---|
| T-319 | test_cs_fixture_namespace_contains_class |
Module(SampleApp.Models) → Contains → User, Address, IEntity, Status |
| T-320 | test_cs_fixture_class_contains_methods |
Class(User) → Contains → GetDisplayName, Validate |
| T-321 | test_ts_fixture_file_contains_symbols |
File(utils.ts) → Contains → formatName, capitalize, internalHelper, MAX_USERS |
| T-322 | test_ts_fixture_class_contains_methods |
Class(User) → Contains → constructor, getDisplayName, toJSON |
| ID | Test | What it checks |
|---|---|---|
| T-323 | test_cs_fixture_fts_search_finds_user |
FTS query "User" returns User class |
| T-324 | test_ts_fixture_fts_search_finds_function |
FTS query "formatName" returns the function |
| T-325 | test_cs_fixture_fts_by_qualified_name |
FTS query "SampleApp.Models"* returns namespace members |
| ID | Test | What it checks |
|---|---|---|
| T-326 | test_cs_fixture_delete_file_removes_symbols |
Delete Address.cs → class + 3 properties + file gone; others remain |
| T-327 | test_cs_fixture_delete_preserves_shared_namespace |
Delete Status.cs → SampleApp.Models module survives (span from Address.cs) |
| T-328 | test_ts_fixture_delete_file_removes_symbols |
Delete utils.ts → 4 symbols + file gone; other files unaffected |
| ID | Test | What it checks |
|---|---|---|
| T-329 | test_cs_fixture_detects_csproj |
detect_projects() finds SampleApp.csproj with language=CSharp |
| T-330 | test_ts_fixture_detects_package_json |
detect_projects() finds package.json with display_name=sample-ts-app |
| ID | Test | What it checks |
|---|---|---|
| T-331 | test_cs_fixture_outline_user_file |
get_outline() for User.cs returns class, properties, constructors, methods |
| T-332 | test_ts_fixture_outline_utils_file |
get_outline() for utils.ts returns formatName, capitalize, internalHelper, MAX_USERS |
| ID | Test | What it checks |
|---|---|---|
| T-333 | test_cs_fixture_private_method_not_public_api |
User.Validate has is_public_api=false |
| T-334 | test_cs_fixture_static_method |
UserService.Create has is_static=true |
| T-335 | test_cs_fixture_async_method |
UserService.RefreshAsync has is_async=true |
| T-336 | test_ts_fixture_export_scope_module |
formatName has export_scope=module |
| T-337 | test_ts_fixture_export_scope_file |
internalHelper has export_scope=file |
| ID | Test | What it checks |
|---|---|---|
| T-338 | test_ts_fixture_reindex_idempotent |
TS fixture indexed twice → same node count (deterministic FileId) |
| T-468 | test_cs_fixture_reindex_idempotent |
Re-indexing same C# fixture produces identical node count |
| ID | Test | What it checks |
|---|---|---|
| T-429 | test_project_detection_before_indexing_assigns_correct_project_id |
Running detect_projects + ensure_projects_in_db before indexing assigns detected project_id (not root) to symbols |
| ID | Test | What it checks |
|---|---|---|
| T-339 | test_oss_trpc_typescript_indexing |
tRPC repo indexes with low error rate; node census meets thresholds; FTS finds key symbols; no duplicate symbol keys |
| T-340 | test_oss_hotchocolate_csharp_indexing |
Hot Chocolate repo indexes with low error rate; node census meets thresholds; FTS finds key symbols; no duplicate symbol keys |
| T-341 | test_oss_trpc_idempotent_reindex |
Re-indexing tRPC produces identical node count as first pass |
| T-342 | test_oss_hotchocolate_idempotent_reindex |
Re-indexing Hot Chocolate produces identical node count as first pass |
| ID | Test | What it checks |
|---|---|---|
| T-343 | test_oss_trpc_lookup_symbol_by_qualified_name |
Lookup discovered method by qualified name returns correct node with matching language |
| T-344 | test_oss_trpc_file_outline_ordered_by_line |
File outline is non-empty, ordered by line_start, excludes file and project nodes |
| T-345 | test_oss_trpc_fts_search_known_name |
FTS search for discovered method display name returns results with rank |
| T-346 | test_oss_trpc_neighbors_contains |
Container node has non-empty outgoing contains edges, all typed Contains |
| T-347 | test_oss_trpc_neighbors_implements |
Interface has incoming implements edges (skips gracefully if none in Phase 1 TS) |
| T-348 | test_oss_hc_lookup_symbol_by_qualified_name |
Lookup discovered C# method by qualified name returns correct node |
| T-349 | test_oss_hc_file_outline_ordered_by_line |
C# file outline is non-empty, ordered by line_start, excludes file and project nodes |
| T-350 | test_oss_hc_fts_search_known_name |
FTS search for discovered C# method display name returns results with rank |
| T-351 | test_oss_hc_neighbors_contains |
C# container has non-empty outgoing contains edges |
| T-352 | test_oss_hc_neighbors_implements |
C# interface has incoming implements edges (skips if none) |
| ID | Test | What it checks |
|---|---|---|
| T-353 | test_oss_trpc_multihop_interface_methods |
2-hop: interface → implementors → their methods (skips if no implements) |
| T-354 | test_oss_trpc_multihop_callers_file |
3-hop: method → callers → caller file_path (skips if no calls edges) |
| T-355 | test_oss_trpc_transitive_contains |
Transitive closure from module: result >= direct children, no duplicate node IDs |
| T-356 | test_oss_trpc_fts_common_terms_bounded |
FTS search for 5 common terms each returns <=50 results in <5s |
| T-357 | test_oss_trpc_outline_all_files_no_panics |
Outline up to 200 files with no panics, <5000 symbols per file |
| T-358 | test_oss_trpc_filter_combined_criteria |
Combined filter: language + node_type + FTS query returns matching results |
| T-359 | test_oss_hc_multihop_interface_methods |
2-hop: C# interface → implementors → methods; asserts non-empty |
| T-360 | test_oss_hc_multihop_callers_file |
3-hop: C# method → callers → file_path |
| T-361 | test_oss_hc_transitive_contains |
Transitive closure from C# namespace: result >= direct children, no dupes |
| T-362 | test_oss_hc_fts_common_terms_bounded |
FTS search for 5 common C# terms each returns <=50 results in <5s |
| T-363 | test_oss_hc_outline_all_files_no_panics |
Outline up to 500 C# files with no panics, <5000 symbols per file |
| T-364 | test_oss_hc_filter_combined_criteria |
Combined filter: C# language + Class + FTS query returns matching results |
| ID | Test | What it checks |
|---|---|---|
| T-365 | test_oss_trpc_benchmarks |
5 benchmarks (symbol lookup, FTS, neighbors, outline, transitive) on tRPC DB |
| T-366 | test_oss_hc_benchmarks |
5 benchmarks (symbol lookup, FTS, neighbors, outline, transitive) on HC DB |
| ID | Test | What it checks |
|---|---|---|
| T-482 | test_oss_trpc_pipeline_benchmark |
Full tRPC pipeline: initial index + idempotent reindex with content-hash skip; integrity checks (dup edges, FTS, orphans) |
| T-483 | test_oss_hc_pipeline_benchmark |
Full HC pipeline: initial index + idempotent reindex + touched-file reindex (60 files across 10 projects exercises minimal solution reload); integrity checks and node stability across 3 passes |
| T-484 | test_oss_rust_analyzer_pipeline_benchmark |
Full rust-analyzer pipeline (Rust, ~1435 .rs files, ~50 crates): initial index + idempotent reindex with content-hash skip; node census (methods, structs, traits, modules), integrity checks, semantic enrichment when extractor available |
| ID | Test | What it checks |
|---|---|---|
| T-367 | test_pagerank_star_topology |
Star graph: hub node called by 5 callers ranks highest |
| T-368 | test_pagerank_linear_chain |
Chain A→B→C: B (both in-degree and out-degree) outranks A |
| T-369 | test_pagerank_isolated_node |
Isolated node (no edges) does not appear in edge-based PageRank results |
| T-370 | test_pagerank_empty_graph |
Empty graph (no edges) returns empty results |
| T-371 | test_pagerank_summary_returns_nodes |
get_pagerank_summary returns full Node objects with display names and positive scores |
| ID | Test | What it checks |
|---|---|---|
| T-372 | test_dead_code_uncalled_method |
Method with zero incoming Calls/References is detected as dead code |
| T-373 | test_dead_code_constructor_excluded |
Constructor excluded from dead code by default (entry point) |
| T-374 | test_dead_code_public_api_filtering |
Public API method excluded by default, included when include_public_api=true |
| T-375 | test_dead_code_override_excluded |
Override method excluded from dead code (interface implementations are not dead) |
| T-376 | test_dead_code_called_method_not_dead |
Method called by another method is NOT flagged as dead code |
| T-377 | test_dead_code_cross_file |
Method in file A with no callers from any file is detected as dead |
| T-378 | test_count_dead_code_matches |
count_dead_code returns same count as find_dead_code().len() |
| ID | Test | What it checks |
|---|---|---|
| T-379 | test_init_creates_directory_and_config |
Creates .codeagent/ dir, config.json, index.db, and .claude/settings.json |
| T-380 | test_init_idempotent |
Running init twice does not duplicate hooks or corrupt config |
| T-381 | test_init_preserves_existing_settings |
Preserves existing .claude/settings.json content while adding hooks |
| T-382 | test_init_gitignore_entry |
Adds .codeagent/index.db to .gitignore without duplicating on re-run |
| ID | Test | What it checks |
|---|---|---|
| T-430 | ✅ test_cli_commands_produce_valid_json |
All CLI subcommands that output JSON produce valid JSON (requires subprocess invocation or refactoring command logic into testable functions) |
| ID | Test | What it checks |
|---|---|---|
| T-383 | test_migration_004_creates_api_endpoints_table |
Migration 004 creates api_endpoints table in SQLite |
| T-384 | test_upsert_and_get_roundtrip |
Upsert an endpoint then read it back with all fields matching |
| T-385 | test_upsert_replaces_existing_row |
Upsert same node_id twice replaces old row; only one row exists |
| T-386 | test_search_by_http_method |
search_api_endpoints with http_method=GET returns only GET endpoints |
| T-387 | test_search_by_route_pattern |
search_api_endpoints with route_pattern substring matches correct routes |
| T-388 | test_search_by_controller_id |
search_api_endpoints with controller_id filter returns only that controller's endpoints |
| T-389 | test_delete_api_endpoints_for_file |
Deleting endpoints for a file path removes correct rows, preserves others |
| T-390 | test_on_delete_cascade_removes_endpoint |
Deleting a node hard-removes its api_endpoints row via ON DELETE CASCADE |
| T-391 | test_get_api_endpoints_for_file |
Batch load returns all endpoints for nodes in a given file |
| T-392 | test_search_limit_capped_at_50 |
Requesting limit=100 is capped to 50 rows returned |
| T-393 | test_get_nonexistent_endpoint_returns_none |
Looking up a random node_id returns None |
| T-394 | test_api_style_roundtrip |
All ApiStyle variants round-trip through as_str/from_str |
| ID | Test | What it checks |
|---|---|---|
| T-242 | ✅ test_pipeline_full_index_csharp |
Full ingest of a small C# project → correct nodes, edges, and FTS entries in DB |
| T-243 | ✅ test_pipeline_incremental_update |
Modify one file → only changed nodes updated; chunk_hash comparison skips unchanged |
| T-244 | ✅ test_pipeline_semantic_enrichment_csharp |
C# semantic pass via Roslyn extractor → parse_status = 'full', exact edges present |
| T-245 | ✅ test_pipeline_semantic_enrichment_typescript |
TS semantic pass via TS LS extractor → parse_status = 'full', exact edges present |
| T-246 | ✅ test_pipeline_semantic_context_invalidation |
.csproj change → semantic edges for affected project recomputed atomically |
| T-247 | ✅ test_pipeline_rename_detection_end_to_end |
Delete + create within debounce window → rename detected; node_id preserved |
| T-248 | ✅ test_pipeline_delete_file_journals_and_cleans_up |
Delete file → nodes hard-deleted; deletion journal written; FTS + edges removed |
| Area | Reason deferred |
|---|---|
ingest/pipeline |
Requires file-based SQLite, start_writer_thread, DbReaderPool, #[tokio::test], and IpcManager stubs. High setup cost — deferred to a dedicated pipeline-integration phase. |
embedding/onnx — EmbeddingModel::load() / embed_batch() |
Requires real ONNX model and tokenizer files at a fixed path. Suitable for an integration test suite, not unit tests. |
adapters/csharp — Roslyn enrichment path |
Phase 2b Roslyn path not yet exercised; requires Roslyn LSP fixture data. |
adapters/typescript — TS Language Service path |
Phase 2b TS Language Service path not yet exercised. |