aboutsummaryrefslogtreecommitdiff
path: root/plugin/test/indentation.test.js
blob: 1a9d91eece99a571a0b9d14c3ba4199b67af1ced (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

'use strict';

const assert = require('node:assert/strict');
const { test } = require('node:test');
const { lineDepths, indentationEdits } = require('../src/indentation');

test('nested branches and each implemented block use one Tab per level', () => {
	const lines = [
		'PROCEDURE Demo()', 'FOR I <- 1 TO 3', 'IF X THEN',
		'WHILE Y DO', 'OUTPUT X', 'ENDWHILE', 'ELSE',
		'REPEAT', 'OUTPUT Y', 'UNTIL Done', 'ENDIF', 'NEXT I', 'ENDPROCEDURE',
		'FUNCTION Value() RETURNS INTEGER', 'RETURN 1', 'ENDFUNCTION',
		'TYPE Record', 'DECLARE X : INTEGER', 'ENDTYPE'
	];
	assert.deepEqual(lineDepths(lines), [0, 1, 2, 3, 4, 3, 2, 3, 4, 3, 2, 1, 0, 0, 1, 0, 0, 1, 0]);
});

test('split THEN/DO, single-line TYPE, comments and strings do not add extra levels', () => {
	const lines = [
		'TYPE Season = (Spring, Summer)', 'TYPE Ptr = ^INTEGER', 'IF Ready',
		'THEN // IF DO', 'WHILE Check("DO")', 'DO', 'OUTPUT "ENDIF // IF THEN"',
		"OUTPUT 'E' // ENDWHILE", 'ENDWHILE', 'ENDIF', 'IFValue <- 1', 'if X then'
	];
	assert.deepEqual(lineDepths(lines), [0, 0, 0, 0, 1, 1, 2, 2, 1, 0, 0, 0]);
});

test('try and catch bodies nest with existing blocks and THROW keeps their depth', () => {
	const lines = [
		'PROCEDURE Demo()', 'TRY', 'IF Ready THEN', 'THROW', 'ENDIF',
		'CATCH', 'TRY', 'THROW', 'CATCH', 'WHILE Ready DO', 'THROW',
		'ENDWHILE', 'ENDTRY', 'ENDTRY', 'OUTPUT "Done"', 'ENDPROCEDURE'
	];
	assert.deepEqual(lineDepths(lines), [0, 1, 2, 3, 2, 1, 2, 3, 2, 3, 4, 3, 2, 1, 1, 0]);
	assert.deepEqual(lineDepths([
		'CATCH', 'ENDTRY', 'try', 'TRYValue <- 1', 'TRY // CATCH ENDTRY',
		'// ENDTRY', 'OUTPUT "CATCH ENDTRY"', 'CATCH // TRY', 'THROW',
		'ENDTRY', 'OUTPUT "Done"'
	]), [0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0]);
});

test('catch selection uses earlier TRY context and formatting is idempotent', () => {
	const lines = ['IF Ready THEN', '  TRY', ' THROW', '    CATCH',
		' OUTPUT "Caught"', '   ENDTRY', 'ENDIF'];
	const edits = indentationEdits(lines, 3, 5);
	assert.deepEqual(edits, [
		{ line: 3, length: 4, text: '\t' },
		{ line: 4, length: 1, text: '\t\t' },
		{ line: 5, length: 3, text: '\t' }
	]);
	for (const edit of edits) lines[edit.line] = edit.text + lines[edit.line].slice(edit.length);
	assert.equal(lines[1], '  TRY');
	assert.equal(lines[2], ' THROW');
	assert.equal(lines[4], '\t\tOUTPUT "Caught"');
	assert.deepEqual(indentationEdits(lines, 3, 5), []);
});

test('range formatting reads earlier context, preserves text and is idempotent', () => {
	const lines = ['IF X THEN', '   WHILE Y DO', ' OUTPUT "x"  // keep spaces', ' ENDWHILE', 'ENDIF'];
	const edits = indentationEdits(lines, 2, 3);
	assert.deepEqual(edits, [
		{ line: 2, length: 1, text: '\t\t' }, { line: 3, length: 1, text: '\t' }
	]);
	for (const edit of edits) lines[edit.line] = edit.text + lines[edit.line].slice(edit.length);
	assert.equal(lines[2], '\t\tOUTPUT "x"  // keep spaces');
	assert.equal(lines[1], '   WHILE Y DO');
	assert.deepEqual(indentationEdits(lines, 2, 3), []);
	assert.deepEqual(indentationEdits(['ENDIF', 'UNTIL X', 'NEXT I'], 0, 2), []);
});

test('blank lines are empty when formatted and indented at the caret after Enter', () => {
	for (const header of [['IF X THEN'], ['TRY'], ['TRY', 'THROW', 'CATCH']]) {
		const lines = [...header, '   '];
		const line = header.length;
		assert.deepEqual(indentationEdits(lines, line, line), [{ line, length: 3, text: '' }]);
		assert.deepEqual(indentationEdits(lines, line, line, true), [{ line, length: 3, text: '\t' }]);
	}
});