Okay, this is excellent! Seeing your existing ast_repository tests for cfg_generator_test.exs, runtime_correlator_test.exs, instrumentation_mapper_test.exs, parser_enhanced_test.exs, file_watcher_test.exs, project_populator_test.exs, enhanced_repository_test.exs, repository_test.exs, and synchronizer_test.exs (plus the module_data_integration_test.exs) confirms that you've made substantial progress on the scaffolding for Prompt 6 and related components.
Your existing tests cover:
- CFGGenerator: Basic CFG structures, conditionals, case statements, implicit returns, nested conditionals, try-catch, comprehensions (though multi-clause is noted as TODO). Node/edge analysis and complexity metrics.
- RuntimeCorrelator: Lifecycle, event correlation (function entry/exit, batch), metadata, chains, cleanup, metrics.
- InstrumentationMapper: Point mapping for simple modules, instrumentation levels, complex ASTs, unique ID generation, priority sorting, strategy selection, configuration.
- ParserEnhanced: Node ID assignment, instrumentation point extraction, correlation index building, integration with Repository/RuntimeCorrelator.
- FileWatcher: Lifecycle, change detection (new, modified, deleted), ignoring non-Elixir files, debouncing.
- ProjectPopulator: File discovery, AST parsing, metadata extraction, project population workflow, performance, error handling.
- EnhancedRepository & Repository: Lifecycle, module/function storage & retrieval (enhanced and basic), indexing (by file path), performance.
- Synchronizer: Lifecycle, file sync (new, modified, deleted), batch sync, error handling.
- ModuleDataIntegration: Real AST pattern detection (GenServer, Phoenix Controller/LiveView, Ecto Schema), attribute extraction.
The Key Gap (and where to focus before Prompt 7):
While these tests are a fantastic start and show a lot of foundational work, the critical piece for Prompts 7 & 8 is the correctness and depth of the actual graph generation (CFG, DFG, CPG) and the data they contain. The current cfg_generator_test.exs tests the structure of CFGData and some high-level properties (like cyclomatic complexity calculation, which is a good heuristic). However, it doesn't deeply validate that the graph itself accurately represents all control flow paths for various Elixir constructs. Similar depth will be needed for DFG and CPG.
Detailed Document for Expanding Tests (Focusing on Solidifying Prompt 6 before Prompt 7):
Here's a plan to expand your tests, primarily focusing on ensuring the analysis components from Prompt 6 are robust. This will make implementing Prompts 7 & 8 much smoother.
Goal: Ensure the correctness, robustness, and completeness of CFG, DFG, and CPG generation (Prompt 6) and related data structures (Prompt 3) before building advanced query systems or runtime integrations.
I. Enhance cfg_generator_test.exs (Control Flow Graph Validation)
- A. Core Elixir Constructs - Detailed Path Validation:
- For each test case (simple, conditional, case, try-catch, comprehension, multi-clause):
- Manually define expected nodes and edges: For simple inputs, you can manually draw the CFG.
- Assert specific node existence: Check for entry, exit, conditional, loop, assignment nodes with expected content/metadata.
- Assert specific edge existence: Verify that edges connect the correct nodes (e.g.,
if_condition -> true_branch_start,if_condition -> false_branch_start,true_branch_end -> merge_node,false_branch_end -> merge_node). - Path Traversal Tests:
- Implement a helper in
CFGGenerator(or test helpers) to find all possible paths from entry to any exit node. - For each test case, assert that the set of execution paths found matches your manually derived expected paths.
- Example: For
if x > 0, do: :a, else: :b, expect two paths:(entry -> cond -> :a -> exit)and(entry -> cond -> :b -> exit).
- Implement a helper in
- For each test case (simple, conditional, case, try-catch, comprehension, multi-clause):
- B. Advanced Control Flow:
withstatements:- Test simple
with(one clause). - Test
withwith multiple clauses. - Test
withclauses that haveelseblocks. - Ensure correct CFG for successful paths and early-exit paths from
else.
- Test simple
unlessstatements: Test similar toif.- Short-circuiting operators (
&&,||):- These create implicit branches. Test that the CFG reflects this.
- Example:
a() && b()should show a path whereb()is not called ifa()is false.
- Exception Handling Deep Dive:
- Test
try/rescue/catch/afterwith all combinations. - Verify paths through
rescueclauses. - Verify paths through
catchclauses. - Verify
afterblock is always executed (multiple entry points toafter, multiple exits fromafter).
- Test
- Loops (Comprehensions - detailed):
- Test
forwith simple generators. - Test
forwith multiple generators. - Test
forwith filters. - Ensure the loop body and filter conditions are nodes in the CFG.
- Test
- Multi-clause Functions (Revisit TODO):
- Test functions with 2-3 clauses with simple pattern matches.
- Test functions with clauses that have guards.
- The CFG should represent each clause head as a decision point (or a sequence of them) leading to the respective clause body.
- C. Elixir-Specific Features:
- Pipe Operator (
|>):- Test simple pipes:
a |> b |> c. The CFG should show sequential execution. - Test pipes with anonymous functions:
data |> Enum.map(&(&1 * 2)).
- Test simple pipes:
- Anonymous Functions (
fn ... end):- Test CFG generation for the body of anonymous functions.
- Ensure the anonymous function itself is a node (e.g., a "function definition" node) in the parent's CFG.
- Pipe Operator (
- D. Unreachable Code Detection (Refine):
- Test more scenarios for
unreachable_code(e.g., afterraise, code after an unconditionalcondclause). - Assert that specific nodes you know are unreachable are correctly identified in
cfg.path_analysis.unreachable_nodes.
- Test more scenarios for
II. Create and Enhance dfg_generator_test.exs (Data Flow Graph Validation)
- A. Core Data Flow Concepts:
- Variable Definitions (Defs):
- Test simple assignments:
x = 1,y = "hello". - Test pattern match assignments:
{a, b} = {1, 2},%{key: val} = map. - Verify a DFG node is created for each variable definition and
DFGData.variablesis populated.
- Test simple assignments:
- Variable Uses (Uses):
- Test variables used in expressions:
z = x + y. - Test variables used as function arguments:
do_something(x). - Verify DFG edges from defs to uses.
- Test variables used in expressions:
- Variable Mutations (Re-defs):
- Test
x = 1; x = x + 1. - Verify
DFGData.mutationsis populated. - Verify DFG edges reflect the new definition and the use of the old value.
- Test
- Variable Definitions (Defs):
- B. Data Flow Through Control Structures:
- Conditionals (
if,case,cond):- Test how variables defined inside branches flow out (or don't).
- Test how variables defined before the conditional are used inside branches.
- Verify generation of Phi nodes (or equivalent logic) for variables that have different definitions reaching a common point after the conditional.
- Example:
if c, do: (x = 1), else: (x = 2); y = x. The use ofxiny=xdepends on two definitions.
- Loops (Comprehensions):
- Track data flow into the comprehension generator (
item <- list). - Track data flow from the generator variable (
item) into the body. - Track data flow from the body expression to the resulting collection.
- Test variables captured from the outer scope.
- Track data flow into the comprehension generator (
- Conditionals (
- C. Data Flow with Function Calls:
- Test data flow of arguments into function calls.
- Test data flow of return values from function calls into assignments.
- (Inter-procedural DFG is advanced and might be out of scope for initial robust testing, but simple call/return flow is key).
- D. Elixir-Specific Data Flow:
- Pipe Operator (
|>):- Verify correct data flow:
a |> b(arg1) |> c()meansaflows tob, result ofbflows toc.
- Verify correct data flow:
- Anonymous Functions:
- Test variables captured by closures.
- Test data flow of arguments into the anonymous function and its return value out.
- Pipe Operator (
- E. Advanced DFG Analysis (from test descriptions):
- Variable Lifetime Analysis:
- For simple functions, manually determine expected birth/death lines for variables.
- Assert
dfg.variable_lifetimesmatches. - Test with variables that are live across control flow branches.
- Unused Variable Detection:
- Create functions with clearly unused variables.
- Assert they are correctly listed in
dfg.unused_variables.
- Variable Shadowing:
- Create functions where inner scopes shadow outer variables (e.g., in
case,fn). - Assert
dfg.shadowed_variablescorrectly identifies these.
- Create functions where inner scopes shadow outer variables (e.g., in
- Optimization Hints (Common Subexpression, Dead Code):
- Create specific code patterns that should trigger these hints.
- Assert the hints are generated.
- Variable Lifetime Analysis:
III. Create and Enhance cpg_builder_test.exs (Code Property Graph Validation)
- A. Basic CPG Structure:
- For simple functions where CFG and DFG are validated:
- Verify
CPGDatastruct is created. - Assert
cpg.control_flow_graphandcpg.data_flow_graphcontain the expected CFG/DFG data. - Assert
cpg.unified_nodescontains nodes referencing both CFG and DFG node IDs. - Assert
cpg.unified_edgescontains both control flow and data flow edges.
- Verify
- For simple functions where CFG and DFG are validated:
- B. Unified Node Representation:
- Pick sample AST nodes (e.g., an assignment, a function call).
- Verify the corresponding
unified_nodein the CPG has correctast_type,cfg_node_id,dfg_node_id, and any relevant CFG/DFG metadata.
- C. Querying CPG (Simple Forms):
- Even before Prompt 7's full query builder, you can test basic CPG queries internally if
CPGBuilderhas helper functions. - "Find all DFG nodes associated with CFG node X."
- "Find the AST snippet for CFG node Y."
- Even before Prompt 7's full query builder, you can test basic CPG queries internally if
- D. Advanced CPG Analysis (from test descriptions - initial validation):
- Path-Sensitive Analysis:
- For a function with a simple
if, check ifcpg.path_sensitive_analysis.execution_pathsshows two distinct paths. - Verify constraints associated with each path (e.g.,
x > 10on one,x <= 10on another).
- For a function with a simple
- Security Analysis (Taint Flows - very basic):
- Create a function
def vuln(input), do: "SELECT * FROM " <> input. - Verify if
cpg.security_analysis.taint_flowsidentifiesinputas a source and the string concatenation as a taint propagation. (This is advanced, so start simple).
- Create a function
- Alias Analysis:
- For
x = data; y = x;, verifycpg.alias_analysis.aliasesshowsyaliasesx.
- For
- Path-Sensitive Analysis:
- E. Code Quality & Performance Analysis (from test descriptions):
- Verify these fields are populated in
CPGData(even if the logic is heuristic-based for now). code_smells: Create code that should trigger a smell (e.g., long parameter list) and check.maintainability_metrics: Check they are present and numeric.refactoring_opportunities: Create an obvious duplication and see if it's flagged.performance_analysis: Create a nested loop and check ifcomplexity_issuesis populated.
- Verify these fields are populated in
IV. Test Enhancements for Other ast_repository Components:
parser_enhanced_test.exs:- Add tests for
assign_node_idson more complex ASTs fromSampleASTs(e.g.,complex_module_ast,mixed_function_types_ast). - Ensure
extract_instrumentation_pointscorrectly identifies points in these complex ASTs and that theast_node_idon these points matches an ID assigned byassign_node_ids. - Verify that
build_correlation_indexcorrectly maps these points.
- Add tests for
instrumentation_mapper_test.exs:- Test
map_instrumentation_pointswith more diverse AST inputs, including those with nested structures, anonymous functions, and complex control flow. Ensure the generatedast_node_ids are unique and consistent. - Verify that the
priorityassigned to different types of instrumentation points (function boundaries, expression traces, variable captures) makes sense for common Elixir patterns.
- Test
enhanced_repository_test.exs&repository_test.exs:- Ensure tests for storing and retrieving
EnhancedModuleDataandEnhancedFunctionDataalso validate that the embedded CFGData, DFGData, etc., are correctly persisted and retrieved. - Add tests for querying based on new indexed fields (complexity, dependencies if added).
- Ensure tests for storing and retrieving
General Testing Principles for This Phase:
- Clarity on AI's Role: For tests of AI-generated components (like CFG/DFG/CPG generators), be clear about what you're testing:
- Is the AI-generated code structurally sound and callable? (Basic tests)
- Does it produce semantically correct output for a variety of inputs? (Deep validation tests)
- Small, Focused Unit Tests: Break down the validation of complex components like graph generators into small tests for specific language features.
- Visual Inspection: For graph structures (CFG, DFG), for small examples, manually drawing the graph and comparing it to what your code (or AI-generated code) produces can be invaluable. You might even write test helpers to output graphs in a format like DOT for visualization.
- Use
SampleASTs: Leverage yourSampleASTsfixture for consistent, complex inputs. Expand it if necessary. - Error Handling: Test how each component handles malformed ASTs or unexpected inputs. They should fail gracefully or return error tuples, not crash.
- Performance Baselines: While full optimization is Prompt 9, get initial performance numbers for your key analysis functions (CFG/DFG/CPG generation). This will inform if the AI-generated approach is fundamentally viable or needs a complete rethink.
By thoroughly testing and validating the components of Prompt 6, particularly the graph generators, you'll build a much more reliable foundation for the exciting features planned in Prompts 7 and 8. This upfront investment in testing will pay off significantly.