Files
inav/docs/javascript_programming/TESTING_GUIDE.md
T
admin dac37fd077
Make sure docs are updated / settings_md (push) Canceled after 0s
Build firmware / test (push) Canceled after 0s
Build firmware / build-SITL-Windows (push) Canceled after 0s
Build firmware / build-SITL-Mac (push) Canceled after 0s
Build firmware / build-SITL-Linux (push) Canceled after 0s
Build firmware / build-SITL-Linux-arm64 (push) Canceled after 0s
Build firmware / upload-artifacts (push) Canceled after 0s
Build firmware / build-single-target (push) Canceled after 0s
Build firmware / build (9) (push) Canceled after 0s
Build firmware / build (8) (push) Canceled after 0s
Build firmware / build (7) (push) Canceled after 0s
Build firmware / build (6) (push) Canceled after 0s
Build firmware / build (5) (push) Canceled after 0s
Build firmware / build (4) (push) Canceled after 0s
Build firmware / build (3) (push) Canceled after 0s
Build firmware / build (2) (push) Canceled after 0s
Build firmware / build (14) (push) Canceled after 0s
Build firmware / build (13) (push) Canceled after 0s
Build firmware / build (12) (push) Canceled after 0s
Build firmware / build (11) (push) Canceled after 0s
Build firmware / build (10) (push) Canceled after 0s
Build firmware / build (1) (push) Canceled after 0s
Build firmware / build (0) (push) Canceled after 0s
Build firmware / detect (push) Canceled after 0s
Build pre-release / build (push) Canceled after 0s
Build pre-release / Release (push) Canceled after 0s
Sync inav to Gitea
2026-08-03 16:37:40 +08:00

268 lines
6.7 KiB
Markdown

# Transpiler Testing Guide
This guide explains how to test changes to the INAV JavaScript transpiler to ensure all components work together correctly.
## Overview
The transpiler has 4 main components that must stay in sync:
1. **Parser** (`transpiler/parser.js`) - Parses JavaScript code into AST
2. **Analyzer** (`transpiler/analyzer.js`) - Validates syntax and checks for errors
3. **Codegen** (`transpiler/codegen.js`) - Generates INAV CLI commands from AST
4. **Decompiler** (`transpiler/decompiler.js`) - Converts CLI commands back to JavaScript
## When Adding a New Feature
When implementing a new operation, function, or syntax feature, you must update:
### 1. Analyzer (transpiler/analyzer.js)
- Add validation for new syntax patterns
- Update property access validation if needed
- Add warnings for unsupported variations
Example: For RC channel states, added validation for `rc[0-17]` with `.low/.mid/.high` properties
### 2. Codegen (transpiler/codegen.js)
- Add code generation for the new feature
- Handle the new AST node types
- Generate correct INAV operation codes
Example: For RC channel states, added handler in `generateCondition()` to detect `rc[n].low` and generate LOW operation (4)
### 3. Decompiler (transpiler/decompiler.js)
- Add reverse mapping from operation codes to JavaScript
- Ensure generated code matches expected syntax
Example: For RC channel states, map operations 4/5/6 to `.low/.mid/.high` properties
### 4. Diagnostics (optional, editor/diagnostics.js)
- Add helpful warnings for common mistakes
- Suggest correct syntax alternatives
## Round-Trip Testing
The most reliable way to test transpiler changes is round-trip testing:
JavaScript → CLI commands → JavaScript
### Basic Test Template
```javascript
import { Transpiler } from './transpiler/index.js';
import { Decompiler } from './transpiler/decompiler.js';
const testCode = `
// Your test code here
if (inav.flight.altitude > 100) {
inav.gvar[0] = 1;
}
`;
console.log('=== Original JavaScript ===\n');
console.log(testCode);
// Transpile
const transpiler = new Transpiler();
const transpileResult = transpiler.transpile(testCode);
console.log('\n=== Generated CLI Commands ===\n');
transpileResult.commands.forEach(cmd => console.log(cmd));
// Parse commands to LC format for decompiler
const logicConditions = transpileResult.commands.map((cmd) => {
const parts = cmd.split(/\s+/);
return {
index: parseInt(parts[1]),
enabled: parseInt(parts[2]),
activatorId: parseInt(parts[3]),
operation: parseInt(parts[4]),
operandAType: parseInt(parts[5]),
operandAValue: parseInt(parts[6]),
operandBType: parseInt(parts[7]),
operandBValue: parseInt(parts[8]),
flags: parseInt(parts[9])
};
});
// Decompile
const decompiler = new Decompiler();
const decompileResult = decompiler.decompile(logicConditions);
console.log('\n=== Decompiled JavaScript ===\n');
console.log(decompileResult.code);
if (decompileResult.success) {
console.log('\n✅ Round-trip successful!');
} else {
console.error('\n❌ Decompilation failed:', decompileResult.error);
}
```
### Running Tests
```bash
cd /path/to/inav-configurator/js/transpiler
# Create your test file
nano test_feature.js
# Run the test
node test_feature.js
# Clean up after testing
rm test_feature.js
```
## Test Cases to Verify
When making changes, test these scenarios:
### 1. Basic Functionality
```javascript
if (inav.flight.altitude > 100) {
inav.gvar[0] = 1;
}
```
Expected: 2 commands (condition + action)
### 2. Error Handling
```javascript
// Invalid syntax - should produce helpful error
if (inav.flight.invalidProperty > 100) {
inav.gvar[0] = 1;
}
```
Expected: Error with suggestion for correct property
### 3. Edge Cases
```javascript
// Test boundary values
if (inav.rc[0].low) { // Channel 0 (first)
inav.gvar[0] = 1;
}
if (inav.rc[17].high) { // Channel 17 (last valid)
inav.gvar[1] = 1;
}
```
Expected: Valid generation for both
### 4. Complex Combinations
```javascript
// Test multiple operations together
if (xor(inav.rc[0].low, inav.flight.armed)) {
inav.gvar[0] = Math.max(100, inav.flight.altitude);
}
```
Expected: Proper nesting of operations
## Common Issues
### Analyzer Rejects Valid Syntax
**Problem**: Analyzer validation is too strict
**Solution**: Update `checkPropertyAccess()` or relevant validation method
**Example**: RC channels needed special handling for array syntax `rc[n]`
### Codegen Produces Wrong Operation Code
**Problem**: Operation constant name incorrect or not imported
**Solution**: Check `OPERATION.*` constants match `inav_constants.js`
**Example**: MODULUS was incorrectly `OPERATION.MOD` instead of `OPERATION.MODULUS`
### Decompiler Output Doesn't Match Input
**Problem**: Decompiler reverse mapping incomplete
**Solution**: Add case for new operation in decompiler
**Example**: LOW/MID/HIGH operations needed to map to `.low/.mid/.high` properties
### Line Numbers Off in Errors
**Problem**: Auto-import adds lines before parsing
**Solution**: Track lineOffset and adjust all error/warning line numbers
**Fixed**: Session 1 of 2025-11-25
## Verification Checklist
Before committing changes:
- [ ] Analyzer validates new syntax without false positives
- [ ] Codegen generates correct operation codes
- [ ] Decompiler correctly reverses the operation
- [ ] Round-trip test passes (JS → CLI → JS)
- [ ] Error messages are helpful and accurate
- [ ] Edge cases are handled (boundary values, empty inputs)
- [ ] Documentation updated (OPERATIONS_REFERENCE.md, API definitions)
## Example: Adding a New Operation
Let's say you want to add support for a new INAV operation `FOOBAR (operation 99)`:
**1. Check if operation exists in firmware**
```javascript
// Look in transpiler/inav_constants.js
const OPERATION = {
// ...
FOOBAR: 99, // Check this exists
// ...
};
```
**2. Update Codegen**
```javascript
// In transpiler/codegen.js
case 'CallExpression': {
const funcName = condition.callee?.name;
if (funcName === 'foobar') {
// Generate FOOBAR operation
const resultIndex = this.lcIndex;
this.commands.push(
`logic ${this.lcIndex} 1 ${activatorId} ${OPERATION.FOOBAR} ...`
);
this.lcIndex++;
return resultIndex;
}
}
```
**3. Update Decompiler**
```javascript
// In transpiler/decompiler.js
case OPERATION.FOOBAR:
return 'foobar()';
```
**4. Update Analyzer (if needed)**
```javascript
// In transpiler/analyzer.js
// Add validation for foobar() usage
```
**5. Test Round-Trip**
```javascript
const testCode = `
if (foobar()) {
inav.gvar[0] = 1;
}
`;
// Run round-trip test...
```
**6. Update Documentation**
- Add to OPERATIONS_REFERENCE.md
- Add usage examples
- Update API definitions if needed
## Last Updated
2025-11-25 - Created after implementing RC channel state detection and completing all INAV operations