test erweiterungen
This commit is contained in:
parent
ba836ee30f
commit
1910b0def2
|
|
@ -1,38 +1,64 @@
|
|||
import * as assert from 'assert';
|
||||
import * as vscode from 'vscode';
|
||||
import { BuiltInCompletion } from '../../providers/completions/BuiltInCompletion';
|
||||
import { SnippetCompletion } from '../../providers/completions/SnippetCompletion';
|
||||
import { LocalContextCompletion } from '../../providers/completions/LocalContextCompletion';
|
||||
|
||||
// Hilfsfunktion simuliert ein vscode.TextDocument
|
||||
function createMockDoc(text: string): any {
|
||||
const lines = text.split('\n');
|
||||
return {
|
||||
getText: () => text,
|
||||
lineAt: (i: number) => ({ text: lines[i] })
|
||||
};
|
||||
}
|
||||
|
||||
suite('Completion Provider Test Suite', () => {
|
||||
test('BuiltInCompletion: Reagiert auf "log."', () => {
|
||||
const strategy = new BuiltInCompletion();
|
||||
// Wir faken Document und Position, da wir nur linePrefix brauchen
|
||||
const result = strategy.provideCompletions(null as any, null as any, ' log.');
|
||||
|
||||
assert.ok(result !== undefined);
|
||||
assert.strictEqual(result.length, 4); // debug, info, warn, error
|
||||
assert.strictEqual(result[0].label, 'debug');
|
||||
});
|
||||
|
||||
test('BuiltInCompletion: Ignoriert normalen Text', () => {
|
||||
const strategy = new BuiltInCompletion();
|
||||
const result = strategy.provideCompletions(null as any, null as any, ' my_var');
|
||||
|
||||
assert.strictEqual(result, undefined);
|
||||
});
|
||||
|
||||
test('SnippetCompletion: Liefert Snippets für normalen Text', () => {
|
||||
test('SnippetCompletion: Kontext-Check (Kein if außerhalb des Bodys)', () => {
|
||||
const strategy = new SnippetCompletion();
|
||||
const result = strategy.provideCompletions(null as any, null as any, ' i');
|
||||
|
||||
// Simuliert, dass wir im "metadata" Block tippen
|
||||
const docText = `pattern Test 1.0\nmetadata\n `;
|
||||
const mockDoc = createMockDoc(docText);
|
||||
const position = new vscode.Position(2, 4); // Zeile 2, Cursor am Ende
|
||||
|
||||
const result = strategy.provideCompletions(mockDoc, position, ' ');
|
||||
|
||||
assert.ok(result !== undefined);
|
||||
const hasIf = result.some(item => item.label === 'if');
|
||||
assert.ok(hasIf, "Muss 'if' Snippet vorschlagen");
|
||||
assert.strictEqual(hasIf, false, "Darf kein 'if' im metadata Block vorschlagen");
|
||||
});
|
||||
|
||||
test('SnippetCompletion: Blockiert Snippets nach Punkt', () => {
|
||||
test('SnippetCompletion: Vorschläge im Body korrekt', () => {
|
||||
const strategy = new SnippetCompletion();
|
||||
const result = strategy.provideCompletions(null as any, null as any, ' discovery.r');
|
||||
|
||||
assert.strictEqual(result, undefined, "Darf keine Block-Snippets in Namespaces anzeigen");
|
||||
// Simuliert, dass wir im "body" tippen
|
||||
const docText = `pattern Test 1.0\nbody\n `;
|
||||
const mockDoc = createMockDoc(docText);
|
||||
const position = new vscode.Position(2, 4);
|
||||
|
||||
const result = strategy.provideCompletions(mockDoc, position, ' ');
|
||||
|
||||
assert.ok(result !== undefined);
|
||||
const hasIf = result.some(item => item.label === 'if');
|
||||
assert.strictEqual(hasIf, true, "Muss 'if' im Body vorschlagen");
|
||||
});
|
||||
|
||||
test('LocalContextCompletion: Erkennt lokale defines in Namespaces', async () => {
|
||||
const strategy = new LocalContextCompletion();
|
||||
|
||||
const docText = `definitions my_tools 1.0\n define doWork(host)\n end define;\nend definitions;`;
|
||||
const mockDoc = createMockDoc(docText);
|
||||
const position = new vscode.Position(4, 0);
|
||||
|
||||
const result = await strategy.provideCompletions(mockDoc, position, 'do');
|
||||
|
||||
assert.ok(result !== undefined);
|
||||
const funcItem = result.find(item => item.label === 'my_tools.doWork');
|
||||
assert.ok(funcItem !== undefined, "Muss die Methode inkl. Namespace extrahieren");
|
||||
|
||||
// Prüft, ob das generierte Snippet das Auto-Semikolon und den $0 Cursor hat
|
||||
const snippet = funcItem?.insertText as vscode.SnippetString;
|
||||
assert.ok(snippet.value.includes('my_tools.doWork(${1:params});$0'));
|
||||
});
|
||||
});
|
||||
|
|
@ -5,65 +5,71 @@ import { SyntaxRule } from '../../core/rules/SyntaxRule';
|
|||
import { BlockRule } from '../../core/rules/BlockRule';
|
||||
|
||||
suite('Linter Test Suite', () => {
|
||||
test('SyntaxRule: Warnt bei "=" Zuweisung außerhalb von Bedingungen', () => {
|
||||
test('SyntaxRule: Ignoriert URLs und Sonderzeichen in Strings', () => {
|
||||
const rule = new SyntaxRule();
|
||||
const ctx = new LinterContext();
|
||||
ctx.activePhaseName = 'body'; // Kontext setzen, damit der strict-mode nicht meckert
|
||||
ctx.activePhaseName = 'body'; // Erlaubte Zone
|
||||
|
||||
const rawLine = " my_var = 123;";
|
||||
// HIER GEFIXT: Wir übergeben ein Array als 5. Argument
|
||||
const rawLine = ' log.debug("https://example.com/api?q=1//test");';
|
||||
rule.checkLine(rawLine.trim(), rawLine, 0, ctx, [rawLine]);
|
||||
|
||||
const diag = ctx.diagnostics.find(d => d.message.includes("':=' für Zuweisungen"));
|
||||
assert.ok(diag !== undefined, "Fehler für falsche Zuweisung erwartet");
|
||||
});
|
||||
|
||||
test('SyntaxRule: Akzeptiert "=" als Vergleich in Bedingungen', () => {
|
||||
const rule = new SyntaxRule();
|
||||
const ctx = new LinterContext();
|
||||
ctx.activePhaseName = 'body';
|
||||
|
||||
const rawLine = " if my_var = 123 then";
|
||||
rule.checkLine(rawLine.trim(), rawLine, 0, ctx, [rawLine]);
|
||||
|
||||
// Darf keinen Fehler werfen, da inConditionBlock automatisch auf true geht
|
||||
// Darf keinen Fehler werfen (weder fehlendes Semikolon noch kaputter Kommentar)
|
||||
assert.strictEqual(ctx.diagnostics.length, 0);
|
||||
});
|
||||
|
||||
test('SyntaxRule: Findet fehlendes Semikolon', () => {
|
||||
test('SyntaxRule: Erfasst TODOs als Information', () => {
|
||||
const rule = new SyntaxRule();
|
||||
const ctx = new LinterContext();
|
||||
|
||||
const rawLine = ' // TODO: Diese Funktion refactoren';
|
||||
rule.checkLine(rawLine.trim(), rawLine, 0, ctx, [rawLine]);
|
||||
|
||||
assert.strictEqual(ctx.diagnostics.length, 1);
|
||||
assert.strictEqual(ctx.diagnostics[0].severity, vscode.DiagnosticSeverity.Information);
|
||||
assert.ok(ctx.diagnostics[0].message.includes("TODO: Diese Funktion refactoren"));
|
||||
});
|
||||
|
||||
test('SyntaxRule: Multi-Line if-Bedingung ohne Semikolon-Fehler', () => {
|
||||
const rule = new SyntaxRule();
|
||||
const ctx = new LinterContext();
|
||||
ctx.activePhaseName = 'body';
|
||||
|
||||
const rawLine = " my_var := 123";
|
||||
rule.checkLine(rawLine.trim(), rawLine, 0, ctx, [rawLine]);
|
||||
// Zeile 1: or-Umbruch
|
||||
rule.checkLine('if x = 1 or', 'if x = 1 or', 0, ctx, []);
|
||||
assert.strictEqual(ctx.diagnostics.length, 0);
|
||||
assert.strictEqual(ctx.inConditionBlock, true);
|
||||
|
||||
const diag = ctx.diagnostics.find(d => d.message.includes("Fehlendes Semikolon"));
|
||||
assert.ok(diag !== undefined, "Fehler für fehlendes Semikolon erwartet");
|
||||
// Zeile 2: then-Abschluss
|
||||
rule.checkLine('y = 2 then', 'y = 2 then', 1, ctx, []);
|
||||
assert.strictEqual(ctx.diagnostics.length, 0, "'then' darf kein Semikolon am Ende verlangen!");
|
||||
assert.strictEqual(ctx.inConditionBlock, false);
|
||||
});
|
||||
|
||||
test('BlockRule: Erzwingt Module-Header', () => {
|
||||
const rule = new BlockRule();
|
||||
test('SyntaxRule: Akzeptiert Zuweisungen in erlaubten Zonen (z.B. metadata)', () => {
|
||||
const rule = new SyntaxRule();
|
||||
const ctx = new LinterContext();
|
||||
ctx.inModuleMetadata = true; // Wir sind im Modul-Metadata
|
||||
|
||||
const rawLine = "pattern Test 1.0";
|
||||
const rawLine = " origin := 'Custom';";
|
||||
rule.checkLine(rawLine.trim(), rawLine, 0, ctx, [rawLine]);
|
||||
|
||||
assert.strictEqual(ctx.diagnostics.length, 1);
|
||||
assert.ok(ctx.diagnostics[0].message.includes("tpl 1.x module"));
|
||||
assert.strictEqual(ctx.diagnostics.length, 0, "Zuweisungen müssen in metadata erlaubt sein");
|
||||
});
|
||||
|
||||
test('BlockRule: Findet fehlendes Pattern-Log im Body', () => {
|
||||
test('BlockRule: if/for/while Stack-Tracking', () => {
|
||||
const rule = new BlockRule();
|
||||
const ctx = new LinterContext();
|
||||
ctx.hasModuleDef = true;
|
||||
ctx.inBlock = 'pattern';
|
||||
ctx.currentPatternName = 'TestPattern';
|
||||
|
||||
const lines = ['body', ' x := 1;', 'end body;'];
|
||||
rule.checkLine('body', 'body', 0, ctx, lines);
|
||||
// Öffnet Block
|
||||
rule.checkLine('if true then', 'if true then', 0, ctx, []);
|
||||
assert.strictEqual(ctx.openControlBlocks.length, 1);
|
||||
assert.strictEqual(ctx.openControlBlocks[0].type, 'if');
|
||||
|
||||
const logDiag = ctx.diagnostics.find(d => d.code === 'missing_log_start');
|
||||
assert.ok(logDiag !== undefined, "Erwartet Fehler für fehlendes Log-Statement");
|
||||
// Schließt falschen Block (end for statt end if)
|
||||
rule.checkLine('end for;', 'end for;', 1, ctx, []);
|
||||
assert.strictEqual(ctx.diagnostics.length, 1);
|
||||
assert.ok(ctx.diagnostics[0].message.includes("Falsches Ende"));
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue