plaxtony
Version:
Static code analysis of SC2 Galaxy Script
279 lines • 17.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const store_1 = require("../src/service/store");
const provider_1 = require("../src/service/provider");
const diagnostics_1 = require("../src/service/diagnostics");
const navigation_1 = require("../src/service/navigation");
const completions_1 = require("../src/service/completions");
const signatures_1 = require("../src/service/signatures");
const hover_1 = require("../src/service/hover");
const references_1 = require("../src/service/references");
const utils_1 = require("../src/service/utils");
const helpers_1 = require("./helpers");
const lsp = require("vscode-languageserver");
const chai_1 = require("chai");
const path = require("path");
require("mocha");
describe('Service', () => {
describe('Utils', () => {
const sourceFile = helpers_1.mockupSourceFile(path.join('service', 'navigation', 'declarations.galaxy'));
it('getPositionOfLineAndCharacter', () => {
chai_1.assert.equal(utils_1.getPositionOfLineAndCharacter(sourceFile, 0, 0), 0);
chai_1.assert.equal(utils_1.getPositionOfLineAndCharacter(sourceFile, 0, 20), 20);
chai_1.assert.equal(utils_1.getPositionOfLineAndCharacter(sourceFile, 1, 0), 21);
chai_1.assert.equal(utils_1.getPositionOfLineAndCharacter(sourceFile, 6, 20), 91);
});
it('findPrecedingToken', () => {
chai_1.assert.equal(utils_1.findPrecedingToken(16, sourceFile).name, 'decl_struct');
chai_1.assert.equal(utils_1.findPrecedingToken(1, sourceFile).kind, 51 /* StructKeyword */);
chai_1.assert.equal(utils_1.findPrecedingToken(20, sourceFile).kind, 4 /* OpenBraceToken */);
chai_1.assert.equal(utils_1.findPrecedingToken(0, sourceFile), undefined);
});
it('findPrecedingToken "incomplete_if_identifier"', () => {
const sourceFile = helpers_1.mockupSourceFile(path.join('type_checker', 'find', 'incomplete_if_identifier.galaxy'));
const t = utils_1.findPrecedingToken(utils_1.getPositionOfLineAndCharacter(sourceFile, 2, 25), sourceFile);
chai_1.assert.equal(t.kind, 113 /* Identifier */, `not expected ${t.kindName}`);
chai_1.assert.equal(t.name, 'UserDataGetFixed');
});
});
describe('Diagnostics', () => {
const store = new store_1.Store();
it('should report about parse errors', () => {
const diagnosticsProvider = provider_1.createProvider(diagnostics_1.DiagnosticsProvider, store);
const document = helpers_1.mockupTextDocument(path.join('service', 'diagnostics_parse_error.galaxy'));
store.updateDocument(document);
diagnosticsProvider.subscribe(document.uri);
const diagnostics = diagnosticsProvider.provideDiagnostics(document.uri);
chai_1.assert.isAtLeast(diagnostics.length, 1);
chai_1.assert.equal(diagnostics[0].message, 'Expected SemicolonToken, found CloseBraceToken');
});
});
describe('Navigation', () => {
const fixturesPath = 'tests/fixtures/service/navigation';
it('should provide symbols navigation per document', () => {
const store = new store_1.Store();
const navigation = provider_1.createProvider(navigation_1.NavigationProvider, store);
const document = helpers_1.mockupTextDocument('service', 'navigation', 'declarations.galaxy');
store.updateDocument(document);
const symbolDeclarations = navigation.getDocumentSymbols(document.uri);
chai_1.assert.lengthOf(symbolDeclarations, 4);
chai_1.assert.equal(symbolDeclarations[0].name.name, 'decl_struct');
chai_1.assert.equal(symbolDeclarations[1].name.name, 'decl_var_string');
chai_1.assert.equal(symbolDeclarations[2].name.name, 'decl_var_const_static_string');
chai_1.assert.equal(symbolDeclarations[3].name.name, 'main');
});
it('should provide symbols navigation per workspace', async () => {
const store = await helpers_1.mockupStoreFromDirectory(fixturesPath);
const navigation = provider_1.createProvider(navigation_1.NavigationProvider, store);
const symbolDeclarations = navigation.getWorkspaceSymbols();
chai_1.assert.lengthOf(symbolDeclarations, 7);
});
});
describe('Completions', () => {
const document = helpers_1.mockupTextDocument('service', 'navigation', 'funcs.galaxy');
const documentStruct = helpers_1.mockupTextDocument('service', 'completion', 'struct.galaxy');
const documentCompletions = helpers_1.mockupTextDocument('service', 'completion', 'completion.galaxy');
const documentTrigger = helpers_1.mockupTextDocument('service', 'completion', 'trigger.galaxy');
const store = helpers_1.mockupStore(document, helpers_1.mockupTextDocument('service', 'navigation', 'declarations.galaxy'), documentStruct, documentCompletions, documentTrigger);
const completionsProvider = provider_1.createProvider(completions_1.CompletionsProvider, store);
completionsProvider.config.functionExpand = 2 /* ArgumentsNull */;
function getCompletionsAt(doc, line, char) {
return completionsProvider.getCompletionsAt(doc.uri, utils_1.getPositionOfLineAndCharacter(store.documents.get(doc.uri), line, char));
}
it('should provide globaly declared symbols', () => {
const completions = completionsProvider.getCompletionsAt(document.uri, 0);
chai_1.assert.isAbove(completions.items.length, 0);
chai_1.assert.isDefined(completions.items.find((item) => {
return item.label === 'decl_var_string';
}));
});
it('should provide localy declared symbols', () => {
const completions = completionsProvider.getCompletionsAt(document.uri, 51);
chai_1.assert.isAbove(completions.items.length, 0);
chai_1.assert.isDefined(completions.items.find((item) => {
return item.label === 'local';
}));
});
it('should provide struct scoped symbols', () => {
let completionsList;
completionsList = getCompletionsAt(documentStruct, 14, 9);
chai_1.assert.lengthOf(completionsList.items, 3);
completionsList = getCompletionsAt(documentStruct, 14, 10);
chai_1.assert.lengthOf(completionsList.items, 3);
completionsList = getCompletionsAt(documentStruct, 15, 13);
chai_1.assert.lengthOf(completionsList.items, 1);
completionsList = getCompletionsAt(documentStruct, 15, 14);
chai_1.assert.lengthOf(completionsList.items, 1);
completionsList = getCompletionsAt(documentStruct, 15, 12);
chai_1.assert.lengthOf(completionsList.items, 3);
completionsList = getCompletionsAt(documentStruct, 16, 21);
chai_1.assert.lengthOf(completionsList.items, 1);
chai_1.assert.equal(completionsList.items[0].label, 'submember');
chai_1.assert.equal(completionsList.items[0].kind, lsp.CompletionItemKind.Property);
chai_1.assert.equal(completionsProvider.resolveCompletion(completionsList.items[0]).detail, 'string submember;');
completionsList = getCompletionsAt(documentStruct, 17, 18);
chai_1.assert.notEqual(completionsList.items.length, 1);
});
it('string', () => {
const completions = getCompletionsAt(documentCompletions, 2, 12);
chai_1.assert.equal(completions.items.length, 0);
});
it('filter suggestions basing on preceding indentifier', () => {
const completions = getCompletionsAt(documentCompletions, 3, 9);
chai_1.assert.equal(completions.items.length, 2);
});
it('expand functions', () => {
const completions = getCompletionsAt(documentCompletions, 3, 9);
chai_1.assert.equal(completionsProvider.resolveCompletion(completions.items[0]).insertText, 'completion_test(${1:0});$0');
});
it('trigger handle function definitions', () => {
let completions = getCompletionsAt(documentTrigger, 24, 19);
chai_1.assert.equal(completions.items.length, 2);
chai_1.assert.equal(completions.items[0].label, 'on_t1');
chai_1.assert.isTrue(completionsProvider.resolveCompletion(completions.items[0]).insertText === undefined);
completions = getCompletionsAt(documentTrigger, 25, 22);
chai_1.assert.equal(completions.items.length, 0);
completions = getCompletionsAt(documentTrigger, 26, 19);
chai_1.assert.equal(completions.items.length, 2);
});
});
describe('Signatures', () => {
const document = helpers_1.mockupTextDocument('service', 'call.galaxy');
const docSignature = helpers_1.mockupTextDocument('service', 'signature', 'signature.galaxy');
const docFnref = helpers_1.mockupTextDocument('service', 'signature', 'funcref.galaxy');
const store = helpers_1.mockupStore(document, helpers_1.mockupTextDocument('service', 'navigation', 'funcs.galaxy'), docSignature, docFnref);
const srcFnref = store.documents.get(docFnref.uri);
const signaturesProvider = provider_1.createProvider(signatures_1.SignaturesProvider, store);
let signature;
it('should provide signature help for global functions', () => {
chai_1.assert.lengthOf(signaturesProvider.getSignatureAt(document.uri, 28).signatures, 1);
});
it('should identify active parameter', () => {
chai_1.assert.equal(signaturesProvider.getSignatureAt(document.uri, 29).activeParameter, 0, 'no whitespace 1');
chai_1.assert.equal(signaturesProvider.getSignatureAt(document.uri, 30).activeParameter, 1, 'no whitespace 2');
chai_1.assert.equal(signaturesProvider.getSignatureAt(document.uri, 49).activeParameter, 0, 'no whitespace 0 - sec');
chai_1.assert.equal(signaturesProvider.getSignatureAt(document.uri, 50).activeParameter, 1, 'right after comma token, before whitespace');
chai_1.assert.equal(signaturesProvider.getSignatureAt(document.uri, 51).activeParameter, 1, 'after whitespace and comma');
chai_1.assert.equal(signaturesProvider.getSignatureAt(document.uri, 71).activeParameter, 1, 'after comma empty param');
});
it('should properly identify bounds in nested calls', () => {
signature = signaturesProvider.getSignatureAt(docSignature.uri, 115);
chai_1.assert.lengthOf(signature.signatures, 1);
chai_1.assert.equal(signature.signatures[0].label, 'string name_me(int id)');
signature = signaturesProvider.getSignatureAt(docSignature.uri, 116);
chai_1.assert.lengthOf(signature.signatures, 1);
chai_1.assert.equal(signature.signatures[0].label, 'int randomize()');
signature = signaturesProvider.getSignatureAt(docSignature.uri, 117);
chai_1.assert.lengthOf(signature.signatures, 1);
chai_1.assert.equal(signature.signatures[0].label, 'string name_me(int id)');
});
context('should provide signature help when cursor at: ', () => {
it('end of binary expr, before ")"', () => {
chai_1.assert.lengthOf(signaturesProvider.getSignatureAt(docSignature.uri, 137).signatures, 1);
});
it('begining of prefix expr, after "("', () => {
chai_1.assert.lengthOf(signaturesProvider.getSignatureAt(docSignature.uri, 152).signatures, 1);
});
it('whitespace, inbetween "(" and ")"', () => {
chai_1.assert.lengthOf(signaturesProvider.getSignatureAt(docSignature.uri, 172).signatures, 1);
chai_1.assert.lengthOf(signaturesProvider.getSignatureAt(docSignature.uri, 171).signatures, 1);
});
it('whitespace, inbetween "," and prefixed expr of numeric literal', () => {
chai_1.assert.lengthOf(signaturesProvider.getSignatureAt(docSignature.uri, 189).signatures, 1);
});
it('prefixed expr of numeric literal, inbetween operand and literal', () => {
chai_1.assert.lengthOf(signaturesProvider.getSignatureAt(docSignature.uri, 195).signatures, 1);
});
});
it('funcref', () => {
signature = signaturesProvider.getSignatureAt(docFnref.uri, utils_1.getPositionOfLineAndCharacter(srcFnref, 13, 9));
chai_1.assert.isDefined(signature);
chai_1.assert.equal(signature.signatures[0].label, 'void fprototype(int a, string b)');
});
it('funcref in struct', () => {
signature = signaturesProvider.getSignatureAt(docFnref.uri, utils_1.getPositionOfLineAndCharacter(srcFnref, 14, 16));
chai_1.assert.isDefined(signature);
});
it('funcref in structref', () => {
signature = signaturesProvider.getSignatureAt(docFnref.uri, utils_1.getPositionOfLineAndCharacter(srcFnref, 15, 16));
chai_1.assert.isDefined(signature);
});
});
describe('Hover', () => {
const hoverDoc = helpers_1.mockupTextDocument('service', 'hover', 'hover.galaxy');
const store = helpers_1.mockupStore(hoverDoc);
const hoverProvider = provider_1.createProvider(hover_1.HoverProvider, store);
it('parameter', () => {
const info = hoverProvider.getHoverAt({ textDocument: hoverDoc, position: { line: 8, character: 4 } });
chai_1.assert.isDefined(info);
const contents = info.contents;
chai_1.assert.isAtLeast(contents.length, 1);
chai_1.assert.equal(contents[0], '```galaxy\nint a\n```');
// assert.isAtLeast(contents.length, 2)
// assert.equal(contents[1], 'parameter of *print_num*');
});
it('local var', () => {
const info = hoverProvider.getHoverAt({ textDocument: hoverDoc, position: { line: 9, character: 4 } });
chai_1.assert.isDefined(info);
const contents = info.contents;
chai_1.assert.isAtLeast(contents.length, 1);
chai_1.assert.equal(contents[0], '```galaxy\nstring b\n```');
// assert.isAtLeast(contents.length, 2)
// assert.equal(contents[1], 'local variable');
});
it('global constant', () => {
const info = hoverProvider.getHoverAt({ textDocument: hoverDoc, position: { line: 17, character: 14 } });
chai_1.assert.isDefined(info);
const contents = info.contents;
chai_1.assert.isAtLeast(contents.length, 1);
chai_1.assert.equal(contents[0], '```galaxy\nconst int c_test = 0\n```');
// assert.isAtLeast(contents.length, 2)
// assert.equal(contents[1], 'global constant');
});
it('function', () => {
const info = hoverProvider.getHoverAt({ textDocument: hoverDoc, position: { line: 17, character: 4 } });
chai_1.assert.isDefined(info);
const contents = info.contents;
chai_1.assert.isAtLeast(contents.length, 1);
chai_1.assert.equal(contents[0], '```galaxy\nvoid print_num(int a)\n```');
});
it('struct property', () => {
const info = hoverProvider.getHoverAt({ textDocument: hoverDoc, position: { line: 18, character: 9 } });
chai_1.assert.isDefined(info);
const contents = info.contents;
chai_1.assert.isAtLeast(contents.length, 1);
chai_1.assert.equal(contents[0], '```galaxy\nint a\n```');
chai_1.assert.isAtLeast(contents.length, 2);
chai_1.assert.equal(contents[1], 'property of `info_t`');
});
it('struct', () => {
const info = hoverProvider.getHoverAt({ textDocument: hoverDoc, position: { line: 0, character: 7 } });
chai_1.assert.isDefined(info);
const contents = info.contents;
chai_1.assert.isAtLeast(contents.length, 1);
chai_1.assert.equal(contents[0], '```galaxy\nstruct info_t {\n\tint a;\n}\n```');
});
});
describe('References', () => {
const refsDoc = helpers_1.mockupTextDocument('service', 'definition', 'refs.galaxy');
const headerDoc = helpers_1.mockupTextDocument('service', 'definition', 'header.galaxy');
const store = helpers_1.mockupStore(headerDoc, refsDoc);
const referenceProvider = provider_1.createProvider(references_1.ReferencesProvider, store);
it('local variable', () => {
const result = referenceProvider.onReferences({ textDocument: refsDoc, position: { line: 9, character: 9 }, context: null });
chai_1.assert.isDefined(result);
chai_1.assert.equal(result.length, 2);
chai_1.assert.equal(result[0].range.start.line, 9);
chai_1.assert.equal(result[1].range.start.line, 14);
});
it('struct property', () => {
const result = referenceProvider.onReferences({ textDocument: refsDoc, position: { line: 16, character: 10 }, context: null });
chai_1.assert.isDefined(result);
chai_1.assert.equal(result.length, 2);
chai_1.assert.equal(result[0].uri, headerDoc.uri);
chai_1.assert.equal(result[0].range.start.line, 6);
chai_1.assert.equal(result[1].range.start.line, 16);
});
});
});
//# sourceMappingURL=service.js.map