Skip to content

Commit 5fc45af

Browse files
Merge pull request #2442 from sensei-hacker/transpiler_docs_tests
transpiler: more tests
2 parents c38fdc8 + 362f4f7 commit 5fc45af

File tree

3 files changed

+238
-0
lines changed

3 files changed

+238
-0
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/**
2+
* Test: Decompiler Terminal Condition Index
3+
*
4+
* Verifies that the decompiler shows the correct (terminal) condition index
5+
* in the "// Condition can be read by logicCondition[N]" comment.
6+
*
7+
* Run with: node js/transpiler/tests/decompiler_terminal_index_test.js
8+
*/
9+
10+
import { Decompiler } from '../transpiler/decompiler.js';
11+
12+
// Test case: Chained logic conditions (from original INAV config)
13+
// First chain: 0 -> 1 -> 2 (terminal is 2)
14+
// Second chain: 19 -> 20 -> 21 -> 22 (terminal is 22)
15+
const testLogicConditions = [
16+
// First chain: mixerTransitionActive && isArmed && groundSpeed > 1111
17+
{ index: 0, enabled: 1, activatorId: -1, operation: 1, operandAType: 2, operandAValue: 39, operandBType: 0, operandBValue: 1, flags: 0 },
18+
{ index: 1, enabled: 1, activatorId: 0, operation: 1, operandAType: 2, operandAValue: 17, operandBType: 0, operandBValue: 1, flags: 0 },
19+
{ index: 2, enabled: 1, activatorId: 1, operation: 2, operandAType: 2, operandAValue: 9, operandBType: 0, operandBValue: 1111, flags: 0 },
20+
// Gap (disabled conditions 3-18)
21+
...Array.from({ length: 16 }, (_, i) => ({ index: i + 3, enabled: 0, activatorId: -1, operation: 0, operandAType: 0, operandAValue: 0, operandBType: 0, operandBValue: 0, flags: 0 })),
22+
// Second chain: activeMixerProfile && isArmed && isAutoLaunch === 0 && airSpeed < 1111
23+
{ index: 19, enabled: 1, activatorId: -1, operation: 1, operandAType: 2, operandAValue: 38, operandBType: 0, operandBValue: 1, flags: 0 },
24+
{ index: 20, enabled: 1, activatorId: 19, operation: 1, operandAType: 2, operandAValue: 17, operandBType: 0, operandBValue: 1, flags: 0 },
25+
{ index: 21, enabled: 1, activatorId: 20, operation: 1, operandAType: 2, operandAValue: 18, operandBType: 0, operandBValue: 0, flags: 0 },
26+
{ index: 22, enabled: 1, activatorId: 21, operation: 3, operandAType: 2, operandAValue: 11, operandBType: 0, operandBValue: 1111, flags: 0 },
27+
];
28+
29+
function runTest() {
30+
console.log('=== Decompiler Terminal Index Test ===\n');
31+
32+
const decompiler = new Decompiler();
33+
const result = decompiler.decompile(testLogicConditions);
34+
35+
console.log('Test: Decompile chained conditions and verify terminal indices\n');
36+
37+
let passed = true;
38+
39+
// Test 1: Decompilation should succeed
40+
if (!result.success) {
41+
console.log('FAIL: Decompilation failed:', result.error);
42+
passed = false;
43+
} else {
44+
console.log('PASS: Decompilation succeeded');
45+
}
46+
47+
// Test 2: First chain should reference logicCondition[2] (not 0)
48+
if (!result.code.includes('logicCondition[2]')) {
49+
console.log('FAIL: First chain should reference logicCondition[2]');
50+
passed = false;
51+
} else {
52+
console.log('PASS: First chain references logicCondition[2]');
53+
}
54+
55+
// Test 3: Second chain should reference logicCondition[22] (not 19)
56+
if (!result.code.includes('logicCondition[22]')) {
57+
console.log('FAIL: Second chain should reference logicCondition[22]');
58+
passed = false;
59+
} else {
60+
console.log('PASS: Second chain references logicCondition[22]');
61+
}
62+
63+
// Test 4: Should NOT reference the first condition indices (0 or 19) for readable conditions
64+
const wrongRefs = result.code.match(/logicCondition\[(0|19)\]/g);
65+
if (wrongRefs && wrongRefs.length > 0) {
66+
console.log('FAIL: Should not reference first condition indices:', wrongRefs);
67+
passed = false;
68+
} else {
69+
console.log('PASS: Does not reference first condition indices incorrectly');
70+
}
71+
72+
console.log('\n--- Generated Code ---');
73+
console.log(result.code);
74+
75+
console.log('\n=== Test Result: ' + (passed ? 'PASSED' : 'FAILED') + ' ===\n');
76+
77+
if (!passed) {
78+
process.exit(1);
79+
}
80+
}
81+
82+
runTest();
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/**
2+
* Test: OR Condition Handling
3+
*
4+
* Verifies that OR conditions use explicit OR operations (not chained activators).
5+
*
6+
* Run with: node js/transpiler/tests/or_condition_test.js
7+
*/
8+
9+
import { Transpiler } from '../index.js';
10+
11+
// Test case: Code with OR conditions
12+
const testCode = `const { flight, gvar } = inav;
13+
14+
if (flight.isArmed === 1 || flight.groundSpeed > 100) {
15+
gvar[0] = 1;
16+
}`;
17+
18+
function runTest() {
19+
console.log('=== OR Condition Test ===\n');
20+
21+
const transpiler = new Transpiler();
22+
const result = transpiler.transpile(testCode);
23+
24+
console.log('Test: Transpile if statements with OR conditions');
25+
console.log('Expected: Should use explicit OR operation\n');
26+
27+
let passed = true;
28+
29+
// Test 1: Transpilation should succeed
30+
if (!result.success) {
31+
console.log('FAIL: Transpilation failed with error:', result.error);
32+
passed = false;
33+
} else {
34+
console.log('PASS: Transpilation succeeded');
35+
}
36+
37+
// Test 2: Should produce output commands
38+
if (result.commands.length === 0) {
39+
console.log('FAIL: No commands generated');
40+
passed = false;
41+
} else {
42+
console.log(`PASS: Generated ${result.commands.length} logic commands`);
43+
}
44+
45+
// Test 3: Should contain an OR operation (operation 8)
46+
const hasOrOp = result.commands.some(cmd => {
47+
const parts = cmd.split(' ');
48+
return parts[4] === '8'; // Operation 8 is OR
49+
});
50+
51+
if (!hasOrOp) {
52+
console.log('FAIL: No OR operation found in output');
53+
passed = false;
54+
} else {
55+
console.log('PASS: OR operation found in output');
56+
}
57+
58+
// Test 4: No errors in warnings
59+
if (result.warnings?.errors?.length > 0) {
60+
console.log('FAIL: Errors in warnings:', result.warnings.errors);
61+
passed = false;
62+
} else {
63+
console.log('PASS: No errors in warnings');
64+
}
65+
66+
console.log('\n--- Generated Commands ---');
67+
result.commands.forEach((cmd, i) => console.log(` ${i}: ${cmd}`));
68+
69+
console.log('\n=== Test Result: ' + (passed ? 'PASSED' : 'FAILED') + ' ===\n');
70+
71+
if (!passed) {
72+
process.exit(1);
73+
}
74+
}
75+
76+
runTest();
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/**
2+
* Test: Readable Logic Conditions (Empty Body If Statements)
3+
*
4+
* This tests the fix for the transpiler empty output bug where if statements
5+
* with only comments in the body (readable conditions) were being discarded.
6+
*
7+
* Run with: node js/transpiler/tests/readable_condition_test.js
8+
*/
9+
10+
import { Transpiler } from '../index.js';
11+
12+
// Test case: Decompiled code with readable conditions
13+
const testCode = `const { flight, override, rc, gvar } = inav;
14+
15+
if (flight.mixerTransitionActive === 1 && flight.isArmed === 1 && flight.groundSpeed > 1111) {
16+
// Condition can be read by logicCondition[0]
17+
}
18+
19+
if (flight.activeMixerProfile === 1 && flight.isArmed === 1 && flight.isAutoLaunch === 0 && flight.airSpeed < 1111) {
20+
// Condition can be read by logicCondition[19]
21+
}`;
22+
23+
function runTest() {
24+
console.log('=== Readable Condition Test ===\n');
25+
26+
const transpiler = new Transpiler();
27+
const result = transpiler.transpile(testCode);
28+
29+
console.log('Test: Transpile if statements with only comments in body');
30+
console.log('Expected: Should produce logic conditions (not empty)\n');
31+
32+
let passed = true;
33+
34+
// Test 1: Transpilation should succeed
35+
if (!result.success) {
36+
console.log('FAIL: Transpilation failed with error:', result.error);
37+
passed = false;
38+
} else {
39+
console.log('PASS: Transpilation succeeded');
40+
}
41+
42+
// Test 2: Should produce some output commands
43+
if (result.commands.length === 0) {
44+
console.log('FAIL: No commands generated (empty output)');
45+
passed = false;
46+
} else {
47+
console.log(`PASS: Generated ${result.commands.length} logic commands`);
48+
}
49+
50+
// Test 3: Should have the expected number of conditions using chained activators
51+
// First condition: 3 comparisons chained = 3 logic conditions
52+
// Second condition: 4 comparisons chained = 4 logic conditions
53+
// Total: 7 logic conditions (matches original INAV output)
54+
const expectedCommands = 7;
55+
if (result.commands.length !== expectedCommands) {
56+
console.log(`FAIL: Expected exactly ${expectedCommands} commands (chained activators), got ${result.commands.length}`);
57+
passed = false;
58+
} else {
59+
console.log(`PASS: Generated optimal ${result.commands.length} commands (chained activators)`);
60+
}
61+
62+
// Test 4: No errors in warnings
63+
if (result.warnings?.errors?.length > 0) {
64+
console.log('FAIL: Errors in warnings:', result.warnings.errors);
65+
passed = false;
66+
} else {
67+
console.log('PASS: No errors in warnings');
68+
}
69+
70+
console.log('\n--- Generated Commands ---');
71+
result.commands.forEach((cmd, i) => console.log(` ${i}: ${cmd}`));
72+
73+
console.log('\n=== Test Result: ' + (passed ? 'PASSED' : 'FAILED') + ' ===\n');
74+
75+
if (!passed) {
76+
process.exit(1);
77+
}
78+
}
79+
80+
runTest();

0 commit comments

Comments
 (0)