Analysis Date: October 10, 2025
Scope: Node query functions (get_node, get_parent, has_node, find_child) and signal system (signal, emit_signal)
Test Suites Analyzed: Unit (runtime), Unit (compiler), Integration (examples), Headless (test harness)
Key Findings:
| Feature | Unit (Runtime) | Unit (Compiler) | Integration (Examples) | Headless | Edge Cases Covered |
|---|---|---|---|---|---|
| get_node() | |||||
| Basic usage | ✅ test_call_get_node_function |
✅ test_get_node_valid |
✅ node_query_basic.ferris |
✅ Implicit in Phase 2 | Simple child path |
| Wrong arg count | ❌ | ✅ test_get_node_wrong_arg_count |
❌ | ❌ | 0, 2+ args |
| Wrong arg type | ❌ | ✅ test_get_node_wrong_arg_type |
❌ | ❌ | Non-string arg |
| Missing node | ⚠️ test_node_query_error_handling |
❌ | ⚠️ node_query_error_demo.ferris |
⚠️ Error demo | Basic case only |
| No callback set | ✅ test_node_query_without_callback |
❌ | ❌ | ❌ | Returns SelfObject |
| Nested paths | ❌ | ❌ | ⚠️ node_query_error_handling.ferris |
❌ | “UI/HUD/HealthBar” |
| Relative paths | ❌ | ❌ | ❌ | ❌ | GAP |
| Absolute paths | ❌ | ❌ | ❌ | ❌ | GAP |
| Special chars in path | ❌ | ❌ | ❌ | ❌ | GAP |
| Very long paths | ❌ | ❌ | ❌ | ❌ | GAP |
| Empty string path | ❌ | ❌ | ❌ | ❌ | GAP |
| Unicode in path | ❌ | ❌ | ❌ | ❌ | GAP |
| Path with spaces | ❌ | ❌ | ❌ | ❌ | GAP |
| get_parent() | |||||
| Basic usage | ✅ test_call_get_parent_function |
✅ test_get_parent_valid |
✅ node_query_basic.ferris |
✅ Implicit | Returns parent |
| With args (error) | ❌ | ✅ test_get_parent_with_args |
❌ | ❌ | Expects 0 args |
| No callback set | ❌ | ❌ | ❌ | ❌ | GAP |
| At root node | ❌ | ❌ | ❌ | ❌ | GAP |
| has_node() | |||||
| Basic usage (exists) | ✅ test_call_has_node_function |
✅ test_has_node_valid |
✅ node_query_validation.ferris |
✅ Implicit | Returns true |
| Node doesn’t exist | ⚠️ Same test | ❌ | ⚠️ Same example | ❌ | Returns false |
| Wrong arg count | ❌ | ✅ test_has_node_wrong_arg_count |
❌ | ❌ | 0, 2+ args |
| Wrong arg type | ❌ | ✅ test_has_node_wrong_arg_type |
❌ | ❌ | Non-string arg |
| No callback set | ❌ | ❌ | ❌ | ❌ | GAP |
| Nested paths | ❌ | ❌ | ⚠️ Optional in validation example | ❌ | “Enemies/Boss” |
| Edge case paths | ❌ | ❌ | ❌ | ❌ | GAP |
| find_child() | |||||
| Basic usage | ✅ test_call_find_child_function |
✅ test_find_child_valid |
✅ node_query_search.ferris |
✅ Implicit | Recursive search |
| Wrong arg count | ❌ | ✅ test_find_child_wrong_arg_count |
❌ | ❌ | 0, 2+ args |
| Wrong arg type | ❌ | ✅ test_find_child_wrong_arg_type |
❌ | ❌ | Non-string arg |
| No callback set | ❌ | ❌ | ❌ | ❌ | GAP |
| Not found | ❌ | ❌ | ❌ | ❌ | GAP |
| Multiple matches | ❌ | ❌ | ❌ | ❌ | GAP (returns first?) |
| Deep nesting | ❌ | ❌ | ⚠️ Implied in example | ❌ | Performance? |
| Case sensitivity | ❌ | ❌ | ❌ | ❌ | GAP |
Summary:
| Feature | Unit (Runtime) | Unit (Compiler) | Integration (Examples) | Headless | Edge Cases Covered |
|---|---|---|---|---|---|
| signal Declaration | |||||
| No params | ✅ test_signal_declaration_in_program |
✅ test_signal_no_params |
✅ signals.ferris |
❌ | Basic declaration |
| With params | ✅ test_register_signal |
✅ test_signal_declaration_valid |
✅ signals.ferris |
❌ | Typed parameters |
| Duplicate signal | ❌ | ✅ test_signal_duplicate_name_error |
❌ | ❌ | Error E401 |
| Undefined type | ❌ | ✅ test_signal_undefined_type_error |
❌ | ❌ | Error E402 |
| Invalid syntax | ❌ | ✅ Multiple parser tests | ❌ | ❌ | Missing parens, semicolon |
| Signal ordering | ❌ | ❌ | ⚠️ signals.ferris shows top | ❌ | Must be at top? |
| Many signals | ❌ | ❌ | ❌ | ❌ | GAP |
| emit_signal() | |||||
| Basic emission | ✅ test_emit_signal_in_function |
✅ test_emit_signal_valid |
✅ signals.ferris |
❌ | With params |
| No params | ✅ test_emit_signal_with_no_params |
⚠️ Implied | ✅ signals.ferris |
❌ | player_died |
| Builtin exists | ✅ test_emit_signal_builtin_exists |
❌ | ❌ | ❌ | Function available |
| Callback invoked | ✅ test_signal_emitter_callback_invoked |
❌ | ❌ | ❌ | Callback mechanism |
| All param types | ✅ test_signal_emitter_callback_all_types |
❌ | ⚠️ signals.ferris | ❌ | i32, f32, bool, String, Vector2 |
| No callback set | ✅ test_signal_emitter_without_callback |
❌ | ❌ | ❌ | Returns Nil |
| Error handling | ✅ test_signal_emitter_error_handling |
❌ | ❌ | ❌ | Callback errors |
| No signal name | ✅ test_emit_signal_error_no_signal_name |
❌ | ❌ | ❌ | Error E501 |
| Invalid name type | ✅ test_emit_signal_error_invalid_signal_name_type |
❌ | ❌ | ❌ | Error E502 |
| Undefined signal | ❌ | ✅ test_emit_signal_undefined_error |
❌ | ❌ | Error E403 |
| Param count mismatch | ❌ | ✅ test_emit_signal_param_count_mismatch |
❌ | ❌ | Error E404 |
| Param type mismatch | ❌ | ✅ test_emit_signal_param_type_mismatch |
❌ | ❌ | Error E405 |
| Type coercion | ❌ | ✅ test_emit_signal_type_coercion |
❌ | ❌ | i32→f32 |
| Emit from lifecycle | ❌ | ❌ | ⚠️ signals.ferris (_ready, _process) | ❌ | Common pattern |
| Emit in conditional | ❌ | ❌ | ⚠️ signals.ferris (if health<=0) | ❌ | Common pattern |
| Emit in loop | ❌ | ❌ | ❌ | ❌ | GAP |
| Multiple emissions | ❌ | ❌ | ⚠️ signals.ferris (multiple funcs) | ❌ | Chaining behavior |
| Signal name as variable | ❌ | ❌ | ❌ | ❌ | GAP |
| Very long signal name | ❌ | ❌ | ❌ | ❌ | GAP |
| Unicode in signal name | ❌ | ❌ | ❌ | ❌ | GAP |
Summary:
Current: Only test simple child paths like “Player”, “UI”, nested like “UI/HUD/HealthBar”
Missing:
"../Sibling", "./Child""/root/Main/Player""UI/""/Player""""My Player""Player-1", "UI@2""玩家", "Игрок""...""NotRelative../Child"Impact: High - Path handling is core functionality, security risk if not validated
Recommendation: Add dedicated test suite for path edge cases
Current: Only test_node_query_without_callback in runtime
Missing:
get_node() without callback (should return SelfObject)get_parent() without callbackhas_node() without callback (should return false?)find_child() without callbackImpact: Medium - Affects developer experience, could cause confusion
Recommendation: Test each node query function with/without callback
Current: Basic error tests exist, but error propagation not tested
Missing:
get_node() stops execution?Impact: Medium - Affects debugging experience
Recommendation: Add error propagation integration tests
Current: No performance tests
Missing:
find_child() on deep trees (100+ levels)find_child() on wide trees (1000+ siblings)Impact: Medium - Could cause performance issues in production
Recommendation: Add performance benchmarks, not just correctness tests
Current: Good coverage of basic signal operations
Missing:
let name = "health_changed"; emit_signal(name, ...)Impact: Low-Medium - Less common but could cause issues
Recommendation: Add signal edge case test suite
Current: Examples show basic usage patterns
Missing:
get_parent().get_node() - not supported?)Impact: Medium - Real-world usage patterns
Recommendation: Add integration test scenarios
Current: Compiler tests cover basic type checking
Missing:
Impact: Low - Type system is stable, but interactions not tested
Recommendation: Add type system integration tests
Current approach relies on:
Create a living document that systematically tracks test coverage:
File: docs/testing/TEST_MATRIX_NODE_QUERIES_SIGNALS.md
Structure:
## Test Matrix: Node Queries
| Scenario | Description | Input | Expected Output | Unit Test | Integration Test | Headless Test | Status |
|----------|-------------|-------|-----------------|-----------|------------------|---------------|--------|
| NQ-001 | Basic get_node | "Player" | Node object | ✅ test_call_get_node_function | ✅ node_query_basic | ✅ Implicit | PASS |
| NQ-002 | Missing node | "Missing" | Error E603 | ⚠️ test_node_query_error_handling | ✅ node_query_error_demo | ⚠️ Error demo | PASS |
| NQ-003 | Empty path | "" | Error E602? | ❌ | ❌ | ❌ | TODO |
| NQ-004 | Relative path | "../Sibling" | Node or error | ❌ | ❌ | ❌ | TODO |
...
Benefits:
Phase 1: Create Initial Matrix (1-2 hours)
Phase 2: Add Edge Cases (2-3 hours)
Phase 3: Integrate into Workflow (ongoing)
Phase 4: Automate (future)
Code coverage shows which lines run, not which scenarios are tested.
Strategies for discovering untested edge cases:
For each input parameter, test:
Example: get_node(path: String)
"""A""A" * 1000"🚀🎮""Player\0Hacker"Group inputs into classes that should behave similarly, test one from each:
Example: Node paths
"Player", "Enemy""UI/HUD", "World/Level1/Boss""../Sibling", "./Child""/root/Main", "/root""", "///", ".", ".."Test how features behave in different system states:
Example: Node queries
_ready() called_ready()_process()Based on experience, guess where errors might occur:
Common patterns:
Test combinations of inputs (not just individual inputs):
Example: emit_signal()
Define properties that should always hold, test with random inputs:
Example: has_node() property
Property: If has_node(path) returns true, then get_node(path) should succeed
Test: Generate 1000 random valid paths, verify property holds
Change code slightly, verify tests catch the bug:
Example: Change if args.len() == 1 to if args.len() <= 1
Test every example in documentation:
Example: If docs say “paths can be relative”, test relative paths
Test realistic user scenarios:
Example:
As a game developer
I want to query nodes by name
So I can access them in my script
Scenarios:
- Simple access in _ready
- Access in _process (performance?)
- Access after dynamic spawn
- Access after node rename/move
Test for potential security issues:
Example: Path injection
"../../../etc/passwd""__internal__""A" * 1000000get_node() without callbackhas_node() for missing nodenode_query_error_demo.ferrisfind_child() on deep/wide treesNode Queries:
Signals:
Near-term Goals (6 months):
Long-term Goals (1 year):
Current State:
Recommendations:
Next Action: Create ✅ COMPLETEDTEST_MATRIX_NODE_QUERIES_SIGNALS.md to begin systematic tracking.
1. Created Test Matrix Document ✅
TEST_MATRIX_NODE_QUERIES_SIGNALS.md2. Implemented Top 5 Missing Edge Case Tests ✅
Added 5 new runtime tests to crates/runtime/src/lib.rs:
test_get_node_empty_string - Validates that get_node(“”) returns Error E603test_get_parent_without_callback - Validates Error E606 when no callback settest_has_node_without_callback - Validates Error E609 when no callback settest_has_node_empty_string - Validates callback rejection of empty pathstest_emit_signal_name_as_variable - Documents that signal names must be string literals (Error E205)Test Results:
running 85 tests (was 80)
test result: ok. 85 passed; 0 failed
3. Updated Test Matrix with New Coverage ✅
Coverage improvements:
Key Findings from New Tests:
get_node() (E603)Immediate (Next Sprint):
Short-term:
Long-term: