/******************************************************************************* * Copyright (c) 2014 Bruno Medeiros and other Contributors. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Bruno Medeiros - initial API and implementation *******************************************************************************/ package dtool.engine.operations; import static dtool.engine.analysis.NE_LanguageIntrinsics_SemanticsTest.PRIMITIVE_TYPES; import static dtool.engine.analysis.NamedElement_CommonTest.COMMON_PROPERTIES; import static melnorme.lang.tooling.EProtection.PUBLIC; import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue; import static melnorme.utilbox.misc.ArrayUtil.concat; import org.junit.Test; import dtool.engine.operations.DeeSymbolCompletionResult.ECompletionResultStatus; import dtool.engine.tests.DefUnitResultsChecker; import melnorme.lang.tooling.CompletionProposalKind; import melnorme.lang.tooling.EAttributeFlag; import melnorme.lang.tooling.EProtection; import melnorme.lang.tooling.ElementAttributes; import melnorme.lang.tooling.ToolCompletionProposal; import melnorme.lang.tooling.ast.SourceRange; import melnorme.lang.tooling.completion.LangToolCompletionProposal; import melnorme.utilbox.collections.ArrayList2; import melnorme.utilbox.collections.Indexable; import melnorme.utilbox.misc.Location; public class CompletionOperation_Test extends CommonDToolOperation_Test { protected DeeSymbolCompletionResult doOperation(Location filePath, int offset) throws Exception { return dtoolEngine.doCodeCompletion(filePath.path, offset, null, testsDubPath()); } public static final Location MODULE_FilePath = BUNDLE_FOO__SRC_FOLDER.resolve_valid("completion_test.d"); public static final String MODULE_Contents = readStringFromFile(MODULE_FilePath); protected final String[] COMPLETION_TEST_MEMBERS = array("Foo", "bar", "abc1", "abc2"); protected final String[] FOO_MEMBERS = concat(COMMON_PROPERTIES, "xx1", "xx2", "intOther", "inzzz"); @Test public void testBasic() throws Exception { testBasic$(); } public void testBasic$() throws Exception { testCodeCompletion(MODULE_FilePath, indexOf(MODULE_Contents, "/*CC1*/"), 0, "abc1", "abc2" ); testCodeCompletion(MODULE_FilePath, indexOf(MODULE_Contents, "abc/*CC1*/"), 3, concat(PRIMITIVE_TYPES, COMPLETION_TEST_MEMBERS) ); // Boundary condition, offset = 0 && offset = length testCodeCompletion(MODULE_FilePath, 0, 0, concat(PRIMITIVE_TYPES, COMPLETION_TEST_MEMBERS) ); testCodeCompletion(MODULE_FilePath, MODULE_Contents.length(), 0, concat(PRIMITIVE_TYPES, COMPLETION_TEST_MEMBERS) ); testCodeCompletion(BUNDLE_FOO__SRC_FOLDER.resolve("empty_module.d"), 0, 0, concat(PRIMITIVE_TYPES, "empty_module") ); /* ----------------- ----------------- */ // Test qualified ref testCodeCompletion(MODULE_FilePath, indexOf(MODULE_Contents, "/*CC2*/"), 0, "xx1", "xx2" ); testCodeCompletion(MODULE_FilePath, indexOf(MODULE_Contents, "xx/*CC2*/"), 2, FOO_MEMBERS ); // Test qualified ref - odd case before dot testCodeCompletion(MODULE_FilePath, indexOf(MODULE_Contents, "/*CC_beforeDot*/"), 0, concat(PRIMITIVE_TYPES, COMPLETION_TEST_MEMBERS) ); testCodeCompletion(MODULE_FilePath, indexOf(MODULE_Contents, ". /*CC_afterDot*/"), 0, concat(PRIMITIVE_TYPES, COMPLETION_TEST_MEMBERS) ); // Test qualified ref - odd case after dot testCodeCompletion(MODULE_FilePath, indexOf(MODULE_Contents, "/*CC_afterDot*/"), 0, FOO_MEMBERS ); testCodeCompletion(MODULE_FilePath, indexOf(MODULE_Contents, " /*CC_afterDot*/"), 0, FOO_MEMBERS ); // Test qualified ref - missing qualifier testCodeCompletion(MODULE_FilePath, indexOf(MODULE_Contents, "/*CC_afterDot2*/"), 0, FOO_MEMBERS ); // Test completion under primitive testCodeCompletion(MODULE_FilePath, indexOf(MODULE_Contents, "/*CC_keywords_1*/"), 0, "int", "intVar" ); testCodeCompletion(MODULE_FilePath, indexOf(MODULE_Contents, "t/*CC_keywords_1*/"), 1, "int", "intVar", "incredible" ); testCodeCompletion(MODULE_FilePath, indexOf(MODULE_Contents, "nt/*CC_keywords_1*/"), 2, "int", "intVar", "incredible", "ifloat", "idouble", "ireal" ); testCodeCompletion(MODULE_FilePath, indexOf(MODULE_Contents, "int/*CC_keywords_1*/"), 3, concat(PRIMITIVE_TYPES, concat(COMPLETION_TEST_MEMBERS, "intVar", "incredible")) ); // Test completion under keyword testCodeCompletion(MODULE_FilePath, indexOf(MODULE_Contents, "/*CC_keywords_2*/"), 0, "int", "intVar", "incredible" ); testCodeCompletion(MODULE_FilePath, indexOf(MODULE_Contents, "in/*CC_keywords_2*/"), 2, concat(PRIMITIVE_TYPES, concat(COMPLETION_TEST_MEMBERS, "intVar", "incredible")) ); // Test completion under primitive - in qualified testCodeCompletion(MODULE_FilePath, indexOf(MODULE_Contents, "/*CC_keywords_q1*/"), 0, "intOther" ); testCodeCompletion(MODULE_FilePath, indexOf(MODULE_Contents, "int/*CC_keywords_q1*/"), 3, FOO_MEMBERS ); // Test completion under keyword - in qualified testCodeCompletion(MODULE_FilePath, indexOf(MODULE_Contents, "/*CC_keywords_q2*/"), 0, "intOther", "inzzz", "init" ); testCodeCompletion(MODULE_FilePath, indexOf(MODULE_Contents, "in/*CC_keywords_q2*/"), 2, FOO_MEMBERS ); } protected void testCodeCompletion(Location modulePath, int offset, int replaceLength, String... expectedResults) throws Exception { testCodeCompletion(modulePath, offset, ECompletionResultStatus.RESULT_OK, replaceLength, expectedResults); } protected void testCodeCompletion(Location modulePath, int offset, ECompletionResultStatus resultStatus, int replaceLength, String... expectedResults) throws Exception { DeeSymbolCompletionResult opResult = doOperation(modulePath, offset); assertTrue(opResult.resultCode == resultStatus); assertTrue(opResult.getReplaceLength() == replaceLength); DefUnitResultsChecker checker = new DefUnitResultsChecker(opResult.results); checker.removeIgnoredElements(true, false, false); checker.removeStdLibObjectDefUnits(); checker.checkResults(expectedResults); } @Test public void testNameMatching() throws Exception { testNameMatching$(); } public void testNameMatching$() throws Exception { // Test case insensitive matching testCodeCompletion(MODULE_FilePath, indexOf(MODULE_Contents, "/*CC1-b*/"), 0, "abc1", "abc2" ); testCodeCompletion(MODULE_FilePath, indexOf(MODULE_Contents, "/*CC1-c*/"), 0, "abc1", "abc2" ); } /* ----------------- ----------------- */ public static ElementAttributes att(EAttributeFlag... flags) { return new ElementAttributes(null, flags); } public static ElementAttributes att(EProtection protection, EAttributeFlag... flags) { return new ElementAttributes(protection, flags); } @Test public void testCompletionProposals() throws Exception { testCompletionProposals$(); } public void testCompletionProposals$() throws Exception { final Location MODULE_FilePath = BUNDLE_FOO__SRC_FOLDER.resolve_valid("completion_test2.d"); final String MODULE_Contents = readStringFromFile(MODULE_FilePath); // Test overload and fullReplaceString/subElements int offset; offset = MODULE_Contents.indexOf("/*N*/"); testCodeCompletionProposals(MODULE_FilePath, offset, list( proposal(offset-4, 4, "void", "void", CompletionProposalKind.NATIVE, att(), null, "void") ) ); offset = MODULE_Contents.indexOf("/*CC_1*/"); testCodeCompletionProposals(MODULE_FilePath, offset, list( proposal(offset-3, 3, "foo", "foo() : void", CompletionProposalKind.FUNCTION, att(PUBLIC), "_dummy2", "foo()"), proposal(offset-3, 3, "foo", "foo(int a) : void", CompletionProposalKind.FUNCTION, att(PUBLIC), "_dummy2", "foo(a)", sr(4, 1)), proposal(offset-3, 3, "foo", "foo(int a, string str) : void", CompletionProposalKind.FUNCTION, att(PUBLIC), "_dummy2", "foo(a, str)", sr(4, 1), sr(7, 3)), proposal(offset-3, 3, "fooTemplateFn", "fooTemplateFn(T) (T param) : int", CompletionProposalKind.FUNCTION, att(PUBLIC, EAttributeFlag.TEMPLATED), "_dummy2", "fooTemplateFn(param)", sr(14, 5)) ) ); } protected SourceRange sr(int offset, int length) { return new SourceRange(offset, length); } public ToolCompletionProposal proposal(int replaceOffset, int replaceLength, String replaceString, String label, CompletionProposalKind kind, ElementAttributes attributes, String moduleName, String fullReplaceString, SourceRange... sourceSubElements) { return new ToolCompletionProposal(replaceOffset, replaceLength, replaceString, label, kind, attributes, null, moduleName, null, fullReplaceString, ArrayList2.create(sourceSubElements), null) { @Override protected boolean subclassEquals(LangToolCompletionProposal _other) { return true; // Hack because we don't want to check namedElement } }; } protected void testCodeCompletionProposals(Location modulePath, int offset, Indexable<ToolCompletionProposal> expectedResult) throws Exception { DeeSymbolCompletionResult opResult = doOperation(modulePath, offset); ArrayList2<ToolCompletionProposal> langResult = opResult.convertToCompletionResult(); assertAreEqual(expectedResult, langResult); } }