diff --git a/com.avaloq.tools.ddk.check.ui.test/META-INF/MANIFEST.MF b/com.avaloq.tools.ddk.check.ui.test/META-INF/MANIFEST.MF index 3cc79a7664..1f471ede7b 100644 --- a/com.avaloq.tools.ddk.check.ui.test/META-INF/MANIFEST.MF +++ b/com.avaloq.tools.ddk.check.ui.test/META-INF/MANIFEST.MF @@ -22,7 +22,10 @@ Require-Bundle: com.avaloq.tools.ddk.check.ui, org.objectweb.asm;resolution:=optional, junit-jupiter-api, junit-jupiter-engine, - junit-platform-suite-api + junit-platform-suite-api, + com.avaloq.tools.ddk.xtext.ui, + com.avaloq.tools.ddk.check.runtime.core, + org.hamcrest Export-Package: com.avaloq.tools.ddk.check.ui.test, com.avaloq.tools.ddk.check.ui.test.util, com.avaloq.tools.ddk.check diff --git a/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/AbstractCheckQuickfixTest.java b/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/AbstractCheckQuickfixTest.java index ef55d7d63f..6667e56c88 100644 --- a/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/AbstractCheckQuickfixTest.java +++ b/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/AbstractCheckQuickfixTest.java @@ -11,7 +11,6 @@ package com.avaloq.tools.ddk.check.ui.test.quickfix; import com.avaloq.tools.ddk.check.ui.test.util.CheckXtextTestUtil; -import com.avaloq.tools.ddk.xtext.test.jupiter.AbstractQuickFixTest; import com.avaloq.tools.ddk.xtext.test.jupiter.AbstractXtextTestUtil; diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/jupiter/AbstractQuickFixTest.java b/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/AbstractQuickFixTest.java similarity index 97% rename from com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/jupiter/AbstractQuickFixTest.java rename to com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/AbstractQuickFixTest.java index aa740921e4..676b19e94e 100644 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/jupiter/AbstractQuickFixTest.java +++ b/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/AbstractQuickFixTest.java @@ -1,455 +1,455 @@ -/******************************************************************************* - * Copyright (c) 2025 Avaloq Group AG and others. - * 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.test.jupiter; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.xtext.resource.XtextSyntaxDiagnostic; -import org.eclipse.xtext.ui.editor.model.edit.IModificationContext; -import org.eclipse.xtext.ui.editor.model.edit.IssueModificationContext; -import org.eclipse.xtext.ui.editor.quickfix.IssueResolution; -import org.eclipse.xtext.ui.editor.quickfix.IssueResolutionProvider; -import org.eclipse.xtext.validation.Issue; -import org.hamcrest.MatcherAssert; -import org.hamcrest.text.IsEqualCompressingWhiteSpace; - -import com.avaloq.tools.ddk.check.runtime.quickfix.ICoreModificationContext; -import com.avaloq.tools.ddk.check.runtime.ui.quickfix.CoreIssueModificationContext; -import com.avaloq.tools.ddk.check.runtime.ui.quickfix.IssueResolutionWrapper; -import com.avaloq.tools.ddk.xtext.ui.util.UiThreadDispatcher; -import com.google.common.base.Function; -import com.google.common.base.Predicates; -import com.google.common.collect.Iterables; -import com.google.common.collect.Ordering; - - -/** - * Test existence and application of QuickFixes for a given language. - * Subclasses provide a validation test file which contains the model the test is based on. - * The name of the quick fix test file must be provided in the method getQuickFixFileName(). - * Besides overriding the abstract method getQuickFixFileName(), subclasses have to implement - * the test method itself which tests for existence and resolutions of the diagnostic issues. - */ -@SuppressWarnings({"PMD.UseObjectForClearerAPI", "nls"}) -public abstract class AbstractQuickFixTest extends AbstractXtextEditorTest { - - private IssueResolutionProvider getIssueResolutionProvider() { - return getXtextTestUtil().get(IssueResolutionProvider.class); - } - - /** - * Results of the diagnostic, a list of Issue. - * - * @return the list of issues - */ - private List getIssueList() { - return getXtextTestUtil().getIssues(getDocument()); - } - - /** - * Set up test by opening a text editor with the validation test file and triggering validation. - */ - @Override - protected void beforeAllTests() { - super.beforeAllTests(); - closeEditor(getEditor(), false); - } - - @Override - protected void beforeEachTest() { - super.beforeEachTest(); - if (getTestSource() != null) { - openEditor(getTestSourceFileName()); - } - } - - @Override - protected void afterEachTest() { - super.afterEachTest(); - closeEditor(getEditor(), false); - } - - /** - * Assert that the diagnostic result (issueList) contains an Issue of the given issueCode. - * - * @param issueCode - * the code of the expected issue, may be {@code null} - */ - protected void assertHasIssue(final String issueCode) { - assertFalse(issuesWith(issueCode).isEmpty(), "Issue " + issueCode + " is empty"); - } - - /** - * Assert that diagnostic result (issueList) contains a QuickFix of the given issueCode. - * - * @param issueCode - * the code of the issue for which a quickfix is expected to exist, may be {@code null} - */ - protected void assertHasQuickFix(final String issueCode) { - assertFalse(resolutionsFor(issueCode).isEmpty(), "No resolutions found for issue " + issueCode); - } - - /** - * Assert that diagnostic result (issueList) contains a QuickFix of the given issueCode. - * - * @param issueCode - * the code of the issue for which a quickfix is expected to exist, may be {@code null} - * @param quickfixLabel - * the label of the quickfix, may be {@code null} - */ - protected void assertHasQuickFix(final String issueCode, final String quickfixLabel) { - assertFalse(resolutionsFor(issueCode, quickfixLabel).isEmpty(), "No resolutions found for issue " + issueCode); - } - - /** - * Assert that diagnostic result (issueList) contains the exact number of the given quickfix label in the proposal of the given issueCode. - * - * @param issueCode - * the code of the issue for which a quickfix is expected to exist, may be {@code null} - * @param quickfixLabel - * the label of the quickfix, may be {@code null} - * @param numberOfQuickfixProposal - * the number of expected quickfix proposal, must not be {@code null} - */ - protected void assertHasQuickFix(final String issueCode, final String quickfixLabel, final int numberOfQuickfixProposal) { - assertEquals(resolutionsFor(issueCode, quickfixLabel).size(), numberOfQuickfixProposal, "Number of resolutions found for issue " + issueCode - + " does not match the expected number of quickfix proposal"); - } - - /** - * Assert that diagnostic result (issueList) of a given source does not contain a QuickFix of the given issueCode. - * - * @param sourceFileName - * the source file name, must not be {@code null} - * @param sourceFileContent - * the source file content, must not be {@code null} - * @param issueCode - * the issue code for which no QuickFix must exist, must not be {@code null} - */ - protected void assertNoQuickFix(final String sourceFileName, final String sourceFileContent, final String issueCode) { - assertNoQuickFix(sourceFileName, sourceFileContent, issueCode, null); - } - - /** - * Assert that diagnostic result (issueList) of a given source does not contain a QuickFix of the given issueCode. - * - * @param sourceFileName - * the source file name, must not be {@code null} - * @param sourceFileContent - * the source file content, must not be {@code null} - * @param issueCode - * the issue code for which no QuickFix must exist, must not be {@code null} - * @param quickfixLabel - * the quickfix label, may be {@code null} - */ - protected void assertNoQuickFix(final String sourceFileName, final String sourceFileContent, final String issueCode, final String quickfixLabel) { - createTestSource(sourceFileName, sourceFileContent); - openEditor(sourceFileName); - try { - assertTrue(resolutionsFor(issueCode, quickfixLabel).isEmpty(), "No resolutions expected for issue " + issueCode + " on source " + sourceFileName); - } finally { - closeEditor(getEditor(), false); - } - } - - /** - * Assert that application of the quick fixes for the given issueCode resolve the problem. - * - * @param issueCode - * the code of the issue that should have been fixed, may be {@code null} - */ - protected void assertQuickFixSuccessful(final String issueCode) { - assertQuickFixSuccessful(issueCode, null); - } - - /** - * Assert that application of the quick fixes for the given issueCode and label resolve the problem. - * - * @param issueCode - * the code of the issue that should have been fixed, may be {@code null} - * @param quickfixLabel - * the label of the quickfix, may be {@code null} - */ - protected void assertQuickFixSuccessful(final String issueCode, final String quickfixLabel) { - for (final IssueResolution issueResolution : sortResolutionsByOffsetDecreasing(resolutionsFor(issueCode, quickfixLabel))) { - UiThreadDispatcher.dispatchAndWait(new Runnable() { - @Override - public void run() { - issueResolution.apply(); - } - }); - } - waitForValidation(); - assertTrue(resolutionsFor(issueCode, quickfixLabel).isEmpty(), "Resolutions for issue " + issueCode + " with quickfix " + quickfixLabel + "are not empty"); - } - - /** - * Sort issue resolutions by offset in document decreasing. - * - * @param resolutions - * resolutions to sort - * @return a copy of {@code resolutions} sorted by offset in document decreasing - */ - protected List sortResolutionsByOffsetDecreasing(final List resolutions) { - - final Function getLocationFunction = new Function() { - - @Override - public Integer apply(final IssueResolution from) { - if (from != null) { - if (from instanceof IssueResolutionWrapper) { - ICoreModificationContext context = ((IssueResolutionWrapper) from).getCoreModificationContext(); - if (context instanceof CoreIssueModificationContext) { - return ((CoreIssueModificationContext) context).getIssue().getOffset(); - } - } else { - IModificationContext context = from.getModificationContext(); - if (context instanceof IssueModificationContext) { - return ((IssueModificationContext) context).getIssue().getOffset(); - } - } - } - return Integer.MIN_VALUE; - } - }; - Ordering ordering = Ordering.natural().onResultOf(getLocationFunction).reverse(); - return new ArrayList(ordering.sortedCopy(resolutions)); - } - - /** - * Assert that the test source has no syntax error. - */ - protected void assertNoSyntaxError() { - assertFalse(Iterables.any(getTestSource().getXtextResource().getErrors(), Predicates.instanceOf(XtextSyntaxDiagnostic.class)), "The source has syntax errors"); - } - - /** - * Assert that application of the target quickfix was successful and the text of the resulting document equals the expected text. - * The method ensures that there is one and only one quickfix for the given issue code with the given label. - * - * @param issueCode - * the code of the issue that should have been fixed, may be {@code null} - * @param quickfixLabel - * the label of the quick fix that should be applied, may be {@code null} - * @param sourceFileName - * the name of the source being tested - * @param sourceContent - * the content of the source being tested - * @param expectedContent - * the name of the file containing the expected result after applying the quick fix - */ - protected void assertQuickFixExistsAndSuccessfulInKernelSource(final String issueCode, final String quickfixLabel, final String sourceFileName, final String sourceContent, final String expectedContent) { - assertQuickFixExistsAndSuccessful(issueCode, quickfixLabel, sourceFileName, sourceContent, expectedContent, false); - } - - /** - * Assert that application of the target quickfix was successful and the text of the resulting document equals the expected text (ignoring formatting). - * The method ensures that there is one and only one quickfix for the given issue code with the given label. - * - * @param issueCode - * the code of the issue that should have been fixed, may be {@code null} - * @param quickfixLabel - * the label of the quick fix that should be applied, may be {@code null} - * @param sourceFileName - * the name of the source being tested - * @param sourceContent - * the content of the source being tested - * @param expectedContent - * the name of the file containing the expected result after applying the quick fix - */ - protected void assertQuickFixExistsAndSuccessfulInKernelSourceIgnoreFormatting(final String issueCode, final String quickfixLabel, final String sourceFileName, final String sourceContent, final String expectedContent) { - assertQuickFixExistsAndSuccessful(issueCode, quickfixLabel, sourceFileName, sourceContent, expectedContent, true); - } - - /** - * Assert that application of the target quickfix was successful and the text of the resulting document equals the expected text. - * The method ensures that there is one and only one quickfix for the given issue code with the given label. - * - * @param issueCode - * the code of the issue that should have been fixed, may be {@code null} - * @param quickfixLabel - * the label of the quick fix that should be applied, may be {@code null} - * @param sourceFileName - * the name of the source being tested - * @param sourceContent - * the content of the source being tested - * @param expectedContent - * the name of the file containing the expected result after applying the quick fix - */ - protected void assertQuickFixExistsAndSuccessfulInCustomerSource(final String issueCode, final String quickfixLabel, final String sourceFileName, final String sourceContent, final String expectedContent) { - assertQuickFixExistsAndSuccessful(issueCode, quickfixLabel, CUSTOMER_SOURCE_PREFIX.concat(sourceFileName), sourceContent, expectedContent, false); - } - - /** - * Assert that application of the target quickfix was successful and the text of the resulting document equals the expected text (ignoring formatting). - * The method ensures that there is one and only one quickfix for the given issue code with the given label. - * - * @param issueCode - * the code of the issue that should have been fixed, may be {@code null} - * @param quickfixLabel - * the label of the quick fix that should be applied, may be {@code null} - * @param sourceFileName - * the name of the source being tested - * @param sourceContent - * the content of the source being tested - * @param expectedContent - * the name of the file containing the expected result after applying the quick fix - */ - protected void assertQuickFixExistsAndSuccessfulInCustomerSourceIgnoreFormatting(final String issueCode, final String quickfixLabel, final String sourceFileName, final String sourceContent, final String expectedContent) { - assertQuickFixExistsAndSuccessful(issueCode, quickfixLabel, CUSTOMER_SOURCE_PREFIX.concat(sourceFileName), sourceContent, expectedContent, true); - } - - /** - * Assert that application of the target quickfix was successful and the text of the resulting document equals the expected text. - * The method ensures that there is one and only one quickfix for the given issue code with the given label. - * - * @param issueCode - * the code of the issue that should have been fixed, may be {@code null} - * @param quickfixLabel - * the label of the quick fix that should be applied, may be {@code null} - * @param sourceFileName - * the name of the source being tested - * @param sourceContent - * the content of the source being tested - * @param expectedContent - * the name of the file containing the expected result after applying the quick fix - * @param ignoreFormatting - * ignore formatting - */ - private void assertQuickFixExistsAndSuccessful(final String issueCode, final String quickfixLabel, final String sourceFileName, final String sourceContent, final String expectedContent, final boolean ignoreFormatting) { - createTestSource(sourceFileName, sourceContent); - openEditor(sourceFileName); - assertQuickFixExistsAndSuccessful(issueCode, quickfixLabel, expectedContent, ignoreFormatting); - closeEditor(getEditor(), false); - } - - /** - * Assert that application of the target quickfix was successful and the text of the resulting document equals the expected text. - * The method ensures that there is one and only one quickfix for the given issue code with the given label. - * - * @param issueCode - * the code of the issue that should have been fixed, may be {@code null} - * @param quickfixLabel - * the label of the quick fix that should be applied, may be {@code null} - * @param expectedContent - * the name of the file containing the expected result after applying the quick fix - * @param ignoreFormatting - * ignore formatting - */ - private void assertQuickFixExistsAndSuccessful(final String issueCode, final String quickfixLabel, final String expectedContent, final boolean ignoreFormatting) { - // Assert amount of quickfixes - int resolutionCount = resolutionsFor(issueCode, quickfixLabel).size(); - assertEquals(resolutionCount, 1, String.format("There must be exactly one quickfix with label '%s' for issue '%s', but found '%d'.", quickfixLabel, issueCode, resolutionCount)); - // Apply quickfix - UiThreadDispatcher.dispatchAndWait(new Runnable() { - @Override - public void run() { - List resolutions = resolutionsFor(issueCode, quickfixLabel); - if (!resolutions.isEmpty()) { - resolutions.get(0).apply(); - } - } - }); - waitForValidation(); - assertTrue(resolutionsFor(issueCode, quickfixLabel).isEmpty(), "Resolutions for issue " + issueCode + " with quickfix " + quickfixLabel + "are not empty"); - String actualContent = getDocument().get(); - assertQuickFixProducesExpectedOutput(expectedContent, actualContent, ignoreFormatting); - } - - /** - * Assert that quick fix produces expected output. - * - * @param expectedContent - * the expected content - * @param actualContent - * the actual content - * @param ignoreFormatting - * the ignore formatting - */ - private void assertQuickFixProducesExpectedOutput(final String expectedContent, final String actualContent, final boolean ignoreFormatting) { - String message = "Quickfix didn't produce the expected output."; - String expected = expectedContent.replaceAll(CR_LF, LF); - String actual = actualContent.replaceAll(CR_LF, LF); - if (ignoreFormatting) { - MatcherAssert.assertThat(message, actual, IsEqualCompressingWhiteSpace.equalToCompressingWhiteSpace(expected)); - } else { - assertEquals(expected, actual, message); - } - } - - /** - * Finds all issues with a specific issue code. - * - * @param issueCode - * to filter for, may be {@code null} - * @return {@link List} of issues with a specific code - */ - private List issuesWith(final String issueCode) { - List issues = new ArrayList(); - if (issueCode == null) { - return issues; - } - for (Issue issue : getIssueList()) { - if (issueCode.equals(issue.getCode())) { - issues.add(issue); - } - } - return issues; - } - - /** - * Finds all resolutions for issues with a specific issue code. - * - * @param issueCode - * to find resolutions for, may be {@code null} - * @return {@link List} of resolutions for issues with a specific code - */ - private List resolutionsFor(final String issueCode) { - return resolutionsFor(issueCode, null); - } - - /** - * Finds all resolutions for issues with a specific issue code. - * - * @param issueCode - * to find resolutions for, may be {@code null} - * @param quickfixLabel - * to find resolutions for, may be {@code null} - * @return {@link List} of resolutions for issues with a specific code - */ - private List resolutionsFor(final String issueCode, final String quickfixLabel) { - final List resolutions = new ArrayList(); - - for (final Issue issue : issuesWith(issueCode)) { - UiThreadDispatcher.dispatchAndWait(new Runnable() { - @Override - public void run() { - if (quickfixLabel == null) { - resolutions.addAll(getIssueResolutionProvider().getResolutions(issue)); - } else { - for (IssueResolution r : getIssueResolutionProvider().getResolutions(issue)) { - if (quickfixLabel.equals(r.getLabel())) { - resolutions.add(r); - } - } - } - } - }); - } - - return resolutions; - } -} +/******************************************************************************* + * Copyright (c) 2025 Avaloq Group AG and others. + * 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: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.check.ui.test.quickfix; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.xtext.resource.XtextSyntaxDiagnostic; +import org.eclipse.xtext.ui.editor.model.edit.IModificationContext; +import org.eclipse.xtext.ui.editor.model.edit.IssueModificationContext; +import org.eclipse.xtext.ui.editor.quickfix.IssueResolution; +import org.eclipse.xtext.ui.editor.quickfix.IssueResolutionProvider; +import org.eclipse.xtext.validation.Issue; +import org.hamcrest.MatcherAssert; +import org.hamcrest.text.IsEqualCompressingWhiteSpace; + +import com.avaloq.tools.ddk.check.runtime.quickfix.ICoreModificationContext; +import com.avaloq.tools.ddk.check.runtime.ui.quickfix.CoreIssueModificationContext; +import com.avaloq.tools.ddk.check.runtime.ui.quickfix.IssueResolutionWrapper; +import com.avaloq.tools.ddk.xtext.ui.util.UiThreadDispatcher; +import com.google.common.base.Function; +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; +import com.google.common.collect.Ordering; + + +/** + * Test existence and application of QuickFixes for a given language. + * Subclasses provide a validation test file which contains the model the test is based on. + * The name of the quick fix test file must be provided in the method getQuickFixFileName(). + * Besides overriding the abstract method getQuickFixFileName(), subclasses have to implement + * the test method itself which tests for existence and resolutions of the diagnostic issues. + */ +@SuppressWarnings({"PMD.UseObjectForClearerAPI", "nls"}) +public abstract class AbstractQuickFixTest extends AbstractXtextEditorTest { + + private IssueResolutionProvider getIssueResolutionProvider() { + return getXtextTestUtil().get(IssueResolutionProvider.class); + } + + /** + * Results of the diagnostic, a list of Issue. + * + * @return the list of issues + */ + private List getIssueList() { + return getXtextTestUtil().getIssues(getDocument()); + } + + /** + * Set up test by opening a text editor with the validation test file and triggering validation. + */ + @Override + protected void beforeAllTests() { + super.beforeAllTests(); + closeEditor(getEditor(), false); + } + + @Override + protected void beforeEachTest() { + super.beforeEachTest(); + if (getTestSource() != null) { + openEditor(getTestSourceFileName()); + } + } + + @Override + protected void afterEachTest() { + super.afterEachTest(); + closeEditor(getEditor(), false); + } + + /** + * Assert that the diagnostic result (issueList) contains an Issue of the given issueCode. + * + * @param issueCode + * the code of the expected issue, may be {@code null} + */ + protected void assertHasIssue(final String issueCode) { + assertFalse(issuesWith(issueCode).isEmpty(), "Issue " + issueCode + " is empty"); + } + + /** + * Assert that diagnostic result (issueList) contains a QuickFix of the given issueCode. + * + * @param issueCode + * the code of the issue for which a quickfix is expected to exist, may be {@code null} + */ + protected void assertHasQuickFix(final String issueCode) { + assertFalse(resolutionsFor(issueCode).isEmpty(), "No resolutions found for issue " + issueCode); + } + + /** + * Assert that diagnostic result (issueList) contains a QuickFix of the given issueCode. + * + * @param issueCode + * the code of the issue for which a quickfix is expected to exist, may be {@code null} + * @param quickfixLabel + * the label of the quickfix, may be {@code null} + */ + protected void assertHasQuickFix(final String issueCode, final String quickfixLabel) { + assertFalse(resolutionsFor(issueCode, quickfixLabel).isEmpty(), "No resolutions found for issue " + issueCode); + } + + /** + * Assert that diagnostic result (issueList) contains the exact number of the given quickfix label in the proposal of the given issueCode. + * + * @param issueCode + * the code of the issue for which a quickfix is expected to exist, may be {@code null} + * @param quickfixLabel + * the label of the quickfix, may be {@code null} + * @param numberOfQuickfixProposal + * the number of expected quickfix proposal, must not be {@code null} + */ + protected void assertHasQuickFix(final String issueCode, final String quickfixLabel, final int numberOfQuickfixProposal) { + assertEquals(resolutionsFor(issueCode, quickfixLabel).size(), numberOfQuickfixProposal, "Number of resolutions found for issue " + issueCode + + " does not match the expected number of quickfix proposal"); + } + + /** + * Assert that diagnostic result (issueList) of a given source does not contain a QuickFix of the given issueCode. + * + * @param sourceFileName + * the source file name, must not be {@code null} + * @param sourceFileContent + * the source file content, must not be {@code null} + * @param issueCode + * the issue code for which no QuickFix must exist, must not be {@code null} + */ + protected void assertNoQuickFix(final String sourceFileName, final String sourceFileContent, final String issueCode) { + assertNoQuickFix(sourceFileName, sourceFileContent, issueCode, null); + } + + /** + * Assert that diagnostic result (issueList) of a given source does not contain a QuickFix of the given issueCode. + * + * @param sourceFileName + * the source file name, must not be {@code null} + * @param sourceFileContent + * the source file content, must not be {@code null} + * @param issueCode + * the issue code for which no QuickFix must exist, must not be {@code null} + * @param quickfixLabel + * the quickfix label, may be {@code null} + */ + protected void assertNoQuickFix(final String sourceFileName, final String sourceFileContent, final String issueCode, final String quickfixLabel) { + createTestSource(sourceFileName, sourceFileContent); + openEditor(sourceFileName); + try { + assertTrue(resolutionsFor(issueCode, quickfixLabel).isEmpty(), "No resolutions expected for issue " + issueCode + " on source " + sourceFileName); + } finally { + closeEditor(getEditor(), false); + } + } + + /** + * Assert that application of the quick fixes for the given issueCode resolve the problem. + * + * @param issueCode + * the code of the issue that should have been fixed, may be {@code null} + */ + protected void assertQuickFixSuccessful(final String issueCode) { + assertQuickFixSuccessful(issueCode, null); + } + + /** + * Assert that application of the quick fixes for the given issueCode and label resolve the problem. + * + * @param issueCode + * the code of the issue that should have been fixed, may be {@code null} + * @param quickfixLabel + * the label of the quickfix, may be {@code null} + */ + protected void assertQuickFixSuccessful(final String issueCode, final String quickfixLabel) { + for (final IssueResolution issueResolution : sortResolutionsByOffsetDecreasing(resolutionsFor(issueCode, quickfixLabel))) { + UiThreadDispatcher.dispatchAndWait(new Runnable() { + @Override + public void run() { + issueResolution.apply(); + } + }); + } + waitForValidation(); + assertTrue(resolutionsFor(issueCode, quickfixLabel).isEmpty(), "Resolutions for issue " + issueCode + " with quickfix " + quickfixLabel + "are not empty"); + } + + /** + * Sort issue resolutions by offset in document decreasing. + * + * @param resolutions + * resolutions to sort + * @return a copy of {@code resolutions} sorted by offset in document decreasing + */ + protected List sortResolutionsByOffsetDecreasing(final List resolutions) { + + final Function getLocationFunction = new Function() { + + @Override + public Integer apply(final IssueResolution from) { + if (from != null) { + if (from instanceof IssueResolutionWrapper) { + ICoreModificationContext context = ((IssueResolutionWrapper) from).getCoreModificationContext(); + if (context instanceof CoreIssueModificationContext) { + return ((CoreIssueModificationContext) context).getIssue().getOffset(); + } + } else { + IModificationContext context = from.getModificationContext(); + if (context instanceof IssueModificationContext) { + return ((IssueModificationContext) context).getIssue().getOffset(); + } + } + } + return Integer.MIN_VALUE; + } + }; + Ordering ordering = Ordering.natural().onResultOf(getLocationFunction).reverse(); + return new ArrayList(ordering.sortedCopy(resolutions)); + } + + /** + * Assert that the test source has no syntax error. + */ + protected void assertNoSyntaxError() { + assertFalse(Iterables.any(getTestSource().getXtextResource().getErrors(), Predicates.instanceOf(XtextSyntaxDiagnostic.class)), "The source has syntax errors"); + } + + /** + * Assert that application of the target quickfix was successful and the text of the resulting document equals the expected text. + * The method ensures that there is one and only one quickfix for the given issue code with the given label. + * + * @param issueCode + * the code of the issue that should have been fixed, may be {@code null} + * @param quickfixLabel + * the label of the quick fix that should be applied, may be {@code null} + * @param sourceFileName + * the name of the source being tested + * @param sourceContent + * the content of the source being tested + * @param expectedContent + * the name of the file containing the expected result after applying the quick fix + */ + protected void assertQuickFixExistsAndSuccessfulInKernelSource(final String issueCode, final String quickfixLabel, final String sourceFileName, final String sourceContent, final String expectedContent) { + assertQuickFixExistsAndSuccessful(issueCode, quickfixLabel, sourceFileName, sourceContent, expectedContent, false); + } + + /** + * Assert that application of the target quickfix was successful and the text of the resulting document equals the expected text (ignoring formatting). + * The method ensures that there is one and only one quickfix for the given issue code with the given label. + * + * @param issueCode + * the code of the issue that should have been fixed, may be {@code null} + * @param quickfixLabel + * the label of the quick fix that should be applied, may be {@code null} + * @param sourceFileName + * the name of the source being tested + * @param sourceContent + * the content of the source being tested + * @param expectedContent + * the name of the file containing the expected result after applying the quick fix + */ + protected void assertQuickFixExistsAndSuccessfulInKernelSourceIgnoreFormatting(final String issueCode, final String quickfixLabel, final String sourceFileName, final String sourceContent, final String expectedContent) { + assertQuickFixExistsAndSuccessful(issueCode, quickfixLabel, sourceFileName, sourceContent, expectedContent, true); + } + + /** + * Assert that application of the target quickfix was successful and the text of the resulting document equals the expected text. + * The method ensures that there is one and only one quickfix for the given issue code with the given label. + * + * @param issueCode + * the code of the issue that should have been fixed, may be {@code null} + * @param quickfixLabel + * the label of the quick fix that should be applied, may be {@code null} + * @param sourceFileName + * the name of the source being tested + * @param sourceContent + * the content of the source being tested + * @param expectedContent + * the name of the file containing the expected result after applying the quick fix + */ + protected void assertQuickFixExistsAndSuccessfulInCustomerSource(final String issueCode, final String quickfixLabel, final String sourceFileName, final String sourceContent, final String expectedContent) { + assertQuickFixExistsAndSuccessful(issueCode, quickfixLabel, CUSTOMER_SOURCE_PREFIX.concat(sourceFileName), sourceContent, expectedContent, false); + } + + /** + * Assert that application of the target quickfix was successful and the text of the resulting document equals the expected text (ignoring formatting). + * The method ensures that there is one and only one quickfix for the given issue code with the given label. + * + * @param issueCode + * the code of the issue that should have been fixed, may be {@code null} + * @param quickfixLabel + * the label of the quick fix that should be applied, may be {@code null} + * @param sourceFileName + * the name of the source being tested + * @param sourceContent + * the content of the source being tested + * @param expectedContent + * the name of the file containing the expected result after applying the quick fix + */ + protected void assertQuickFixExistsAndSuccessfulInCustomerSourceIgnoreFormatting(final String issueCode, final String quickfixLabel, final String sourceFileName, final String sourceContent, final String expectedContent) { + assertQuickFixExistsAndSuccessful(issueCode, quickfixLabel, CUSTOMER_SOURCE_PREFIX.concat(sourceFileName), sourceContent, expectedContent, true); + } + + /** + * Assert that application of the target quickfix was successful and the text of the resulting document equals the expected text. + * The method ensures that there is one and only one quickfix for the given issue code with the given label. + * + * @param issueCode + * the code of the issue that should have been fixed, may be {@code null} + * @param quickfixLabel + * the label of the quick fix that should be applied, may be {@code null} + * @param sourceFileName + * the name of the source being tested + * @param sourceContent + * the content of the source being tested + * @param expectedContent + * the name of the file containing the expected result after applying the quick fix + * @param ignoreFormatting + * ignore formatting + */ + private void assertQuickFixExistsAndSuccessful(final String issueCode, final String quickfixLabel, final String sourceFileName, final String sourceContent, final String expectedContent, final boolean ignoreFormatting) { + createTestSource(sourceFileName, sourceContent); + openEditor(sourceFileName); + assertQuickFixExistsAndSuccessful(issueCode, quickfixLabel, expectedContent, ignoreFormatting); + closeEditor(getEditor(), false); + } + + /** + * Assert that application of the target quickfix was successful and the text of the resulting document equals the expected text. + * The method ensures that there is one and only one quickfix for the given issue code with the given label. + * + * @param issueCode + * the code of the issue that should have been fixed, may be {@code null} + * @param quickfixLabel + * the label of the quick fix that should be applied, may be {@code null} + * @param expectedContent + * the name of the file containing the expected result after applying the quick fix + * @param ignoreFormatting + * ignore formatting + */ + private void assertQuickFixExistsAndSuccessful(final String issueCode, final String quickfixLabel, final String expectedContent, final boolean ignoreFormatting) { + // Assert amount of quickfixes + int resolutionCount = resolutionsFor(issueCode, quickfixLabel).size(); + assertEquals(resolutionCount, 1, String.format("There must be exactly one quickfix with label '%s' for issue '%s', but found '%d'.", quickfixLabel, issueCode, resolutionCount)); + // Apply quickfix + UiThreadDispatcher.dispatchAndWait(new Runnable() { + @Override + public void run() { + List resolutions = resolutionsFor(issueCode, quickfixLabel); + if (!resolutions.isEmpty()) { + resolutions.get(0).apply(); + } + } + }); + waitForValidation(); + assertTrue(resolutionsFor(issueCode, quickfixLabel).isEmpty(), "Resolutions for issue " + issueCode + " with quickfix " + quickfixLabel + "are not empty"); + String actualContent = getDocument().get(); + assertQuickFixProducesExpectedOutput(expectedContent, actualContent, ignoreFormatting); + } + + /** + * Assert that quick fix produces expected output. + * + * @param expectedContent + * the expected content + * @param actualContent + * the actual content + * @param ignoreFormatting + * the ignore formatting + */ + private void assertQuickFixProducesExpectedOutput(final String expectedContent, final String actualContent, final boolean ignoreFormatting) { + String message = "Quickfix didn't produce the expected output."; + String expected = expectedContent.replaceAll(CR_LF, LF); + String actual = actualContent.replaceAll(CR_LF, LF); + if (ignoreFormatting) { + MatcherAssert.assertThat(message, actual, IsEqualCompressingWhiteSpace.equalToCompressingWhiteSpace(expected)); + } else { + assertEquals(expected, actual, message); + } + } + + /** + * Finds all issues with a specific issue code. + * + * @param issueCode + * to filter for, may be {@code null} + * @return {@link List} of issues with a specific code + */ + private List issuesWith(final String issueCode) { + List issues = new ArrayList(); + if (issueCode == null) { + return issues; + } + for (Issue issue : getIssueList()) { + if (issueCode.equals(issue.getCode())) { + issues.add(issue); + } + } + return issues; + } + + /** + * Finds all resolutions for issues with a specific issue code. + * + * @param issueCode + * to find resolutions for, may be {@code null} + * @return {@link List} of resolutions for issues with a specific code + */ + private List resolutionsFor(final String issueCode) { + return resolutionsFor(issueCode, null); + } + + /** + * Finds all resolutions for issues with a specific issue code. + * + * @param issueCode + * to find resolutions for, may be {@code null} + * @param quickfixLabel + * to find resolutions for, may be {@code null} + * @return {@link List} of resolutions for issues with a specific code + */ + private List resolutionsFor(final String issueCode, final String quickfixLabel) { + final List resolutions = new ArrayList(); + + for (final Issue issue : issuesWith(issueCode)) { + UiThreadDispatcher.dispatchAndWait(new Runnable() { + @Override + public void run() { + if (quickfixLabel == null) { + resolutions.addAll(getIssueResolutionProvider().getResolutions(issue)); + } else { + for (IssueResolution r : getIssueResolutionProvider().getResolutions(issue)) { + if (quickfixLabel.equals(r.getLabel())) { + resolutions.add(r); + } + } + } + } + }); + } + + return resolutions; + } +} \ No newline at end of file diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/jupiter/AbstractXtextEditorTest.java b/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/AbstractXtextEditorTest.java similarity index 83% rename from com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/jupiter/AbstractXtextEditorTest.java rename to com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/AbstractXtextEditorTest.java index 29a544bd67..04a8d0a2c7 100644 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/jupiter/AbstractXtextEditorTest.java +++ b/com.avaloq.tools.ddk.check.ui.test/src/com/avaloq/tools/ddk/check/ui/test/quickfix/AbstractXtextEditorTest.java @@ -1,203 +1,243 @@ -/******************************************************************************* - * Copyright (c) 2025 Avaloq Group AG and others. - * 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.test.jupiter; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import org.eclipse.emf.common.util.WrappedException; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.PlatformUI; -import org.eclipse.xtext.resource.XtextResource; -import org.eclipse.xtext.ui.editor.XtextEditor; -import org.eclipse.xtext.ui.editor.XtextSourceViewer; -import org.eclipse.xtext.ui.editor.model.IXtextDocument; -import org.eclipse.xtext.ui.editor.reconciler.XtextReconciler; -import org.eclipse.xtext.util.concurrent.IUnitOfWork; - -import com.avaloq.tools.ddk.xtext.test.TestSource; -import com.avaloq.tools.ddk.xtext.test.XtextTestSource; - - -/** - * AbstractXtextEditorTest provides convenient setup and access functionality for tests that require an xtext editor. - */ -@SuppressWarnings("nls") -public abstract class AbstractXtextEditorTest extends AbstractXtextMarkerBasedTest { - - private static final String EDITOR_MUST_NOT_BE_DIRTY = "Editor must not be dirty - this indicates state carried over"; - private static final String EDITOR_HAS_NO_DOCUMENT = "Editor has no document"; - private static final String EDITOR_COULD_NOT_BE_OPENED_WITH_URI = "Editor could not be opened with URI: "; - - protected static final String CR_LF = "\r\n"; - protected static final String LF = "\n"; - - @Override - protected void beforeAllTests() { - super.beforeAllTests(); - // For Xtend-based tests there is no default test source associated with the test class - TestSource testSource = getTestSource(); - if (testSource != null) { - openEditor(testSource); - } - } - - @Override - protected void afterAllTests() { - closeOpenEditor(); - super.afterAllTests(); - } - - @Override - protected void beforeApplyAssertions(final XtextTestSource testSource) { - super.beforeApplyAssertions(testSource); - openEditor(testSource); - } - - @Override - protected void afterValidate() { - closeOpenEditor(); - super.afterValidate(); - } - - /** - * Opens the editor with the given test source. - * - * @param testSource - * the test source to open, not {@code null} - */ - private void openEditor(final TestSource testSource) { - // if openEditor returns NULL, then one possible cause might be that the Activator - // has not been set correctly in the presentation plug-in MANIFEST of that grammar. - XtextEditor editor = getXtextTestUtil().openEditor(testSource.getUri()); - assertNotNull(editor, EDITOR_COULD_NOT_BE_OPENED_WITH_URI + testSource.getUri()); - getTestInformation().putTestObject(XtextEditor.class, editor); - assertNotNull(getDocument(), EDITOR_HAS_NO_DOCUMENT); - assertFalse(getEditor().isDirty(), EDITOR_MUST_NOT_BE_DIRTY); - } - - /** - * Open editor of the test source with a given file name. - * - * @param fileName - * file name of the source to open editor for, must not be {@code null} - */ - protected void openEditor(final String fileName) { - openEditor(getTestSource(fileName)); - } - - /** - * Closes the currently open editor. - */ - private void closeOpenEditor() { - final XtextEditor editor = getEditor(); - if (editor != null) { - closeEditor(editor, false); - } - } - - /** - * Returns the editor. - * - * @return the editor - */ - protected XtextEditor getEditor() { - return (XtextEditor) getTestInformation().getTestObject(XtextEditor.class); - } - - /** - * Closes the given editor-part - contrary to {@link org.eclipse.ui.texteditor.AbstractTextEditor#close(boolean)} this call is blocking! - * - * @param editor - * the editor to close - * @param save - * true if should save before close, false otherwise - */ - protected void closeEditor(final IEditorPart editor, final boolean save) { - Object editorJobs = getTestUtil().getEditorJobFamily(editor); - PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() { - @Override - public void run() { - PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().closeEditor(editor, save); - } - }); - if (editorJobs != null) { - waitForJobsOfFamily(editorJobs); - } - } - - /** - * Returns the viewer. - * - * @return the viewer - */ - protected XtextSourceViewer getViewer() { - return (XtextSourceViewer) getEditor().getInternalSourceViewer(); - } - - /** - * Returns the document. - * - * @return the document - */ - protected IXtextDocument getDocument() { - return getEditor().getDocument(); - } - - /** - * Insert the given value at offset in {@link #getDocument()}. - * - * @param offset - * the offset - * @param value - * the value - */ - protected void insertAtOffset(final int offset, final String value) { - PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() { - @Override - public void run() { - // the modify() is invoked to ensure a (fast-only) re-validation of the document is triggered - getDocument().modify(new IUnitOfWork() { - @Override - public java.lang.Void exec(final XtextResource state) { - try { - getDocument().replace(offset, 0, value); - } catch (BadLocationException e) { - throw new WrappedException("Could not insert \"" + value + "\" at affset " + offset, e); - } - return null; - } - }); - } - }); - } - - /** - * Test that the editor does not allow "Save as...". - * - * @deprecated Provide this test method in an appropriate test class for the editor under test, if the editor shall not allow "Save as...". - */ - @Deprecated - public void testSaveAsDisallowed() { - final XtextEditor editor = getEditor(); - assertFalse(editor.isSaveAsAllowed(), "Editor must not allow 'Save as...'"); - } - - @Override - protected void waitForValidation() { - // Editor tests frequently work by modifying the document. We first need to wait for the reconciler to run, otherwise we may - // actually get results from before a document change is reflected in the document's resource, leading to spurious errors. - // Note that the XtextReconciler runs with a delay of 500ms. - waitForJobsOfFamily(XtextReconciler.class.getName()); - super.waitForValidation(); - } -} +/******************************************************************************* + * Copyright (c) 2025 Avaloq Group AG and others. + * 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: + * Avaloq Group AG - initial API and implementation + *******************************************************************************/ +package com.avaloq.tools.ddk.check.ui.test.quickfix; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.common.util.WrappedException; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.intro.IIntroPart; +import org.eclipse.xtext.resource.XtextResource; +import org.eclipse.xtext.ui.editor.GlobalURIEditorOpener; +import org.eclipse.xtext.ui.editor.XtextEditor; +import org.eclipse.xtext.ui.editor.XtextSourceViewer; +import org.eclipse.xtext.ui.editor.model.IXtextDocument; +import org.eclipse.xtext.ui.editor.reconciler.XtextReconciler; +import org.eclipse.xtext.util.concurrent.IUnitOfWork; + +import com.avaloq.tools.ddk.xtext.test.TestSource; +import com.avaloq.tools.ddk.xtext.test.XtextTestSource; +import com.avaloq.tools.ddk.xtext.test.jupiter.AbstractXtextMarkerBasedTest; +import com.avaloq.tools.ddk.xtext.ui.util.Function; +import com.avaloq.tools.ddk.xtext.ui.util.UiThreadDispatcher; + + +/** + * AbstractXtextEditorTest provides convenient setup and access functionality for tests that require an xtext editor. + */ +@SuppressWarnings("nls") +public abstract class AbstractXtextEditorTest extends AbstractXtextMarkerBasedTest { + + private static final String EDITOR_MUST_NOT_BE_DIRTY = "Editor must not be dirty - this indicates state carried over"; + private static final String EDITOR_HAS_NO_DOCUMENT = "Editor has no document"; + private static final String EDITOR_COULD_NOT_BE_OPENED_WITH_URI = "Editor could not be opened with URI: "; + + protected static final String CR_LF = "\r\n"; + protected static final String LF = "\n"; + + @Override + protected void beforeAllTests() { + super.beforeAllTests(); + // For Xtend-based tests there is no default test source associated with the test class + TestSource testSource = getTestSource(); + if (testSource != null) { + openEditor(testSource); + } + } + + @Override + protected void afterAllTests() { + closeOpenEditor(); + super.afterAllTests(); + } + + @Override + protected void beforeApplyAssertions(final XtextTestSource testSource) { + super.beforeApplyAssertions(testSource); + openEditor(testSource); + } + + @Override + protected void afterValidate() { + closeOpenEditor(); + super.afterValidate(); + } + + /** + * Closes the welcome page if it is open. + */ + protected void closeWelcomePage() { + UiThreadDispatcher.dispatchAndWait(new Runnable() { + @Override + public void run() { + IIntroPart intro = PlatformUI.getWorkbench().getIntroManager().getIntro(); + if (intro != null) { + PlatformUI.getWorkbench().getIntroManager().closeIntro(intro); + } + } + }); + } + + /** + * Opens an editor for a specific {@link URI}. + * + * @param uri + * to open editor for + * @return editor opened + */ + public XtextEditor openEditor(final URI uri) { + XtextEditor editor = UiThreadDispatcher.dispatchAndWait(new Function() { + @Override + public XtextEditor run() { + closeWelcomePage(); + return (XtextEditor) getXtextTestUtil().get(GlobalURIEditorOpener.class).open(uri, false); + } + }); + waitForEditorJobs(editor); + return editor; + } + + /** + * Opens the editor with the given test source. + * + * @param testSource + * the test source to open, not {@code null} + */ + private void openEditor(final TestSource testSource) { + // if openEditor returns NULL, then one possible cause might be that the Activator + // has not been set correctly in the presentation plug-in MANIFEST of that grammar. + XtextEditor editor = openEditor(testSource.getUri()); + assertNotNull(editor, EDITOR_COULD_NOT_BE_OPENED_WITH_URI + testSource.getUri()); + getTestInformation().putTestObject(XtextEditor.class, editor); + assertNotNull(getDocument(), EDITOR_HAS_NO_DOCUMENT); + assertFalse(getEditor().isDirty(), EDITOR_MUST_NOT_BE_DIRTY); + } + + /** + * Open editor of the test source with a given file name. + * + * @param fileName + * file name of the source to open editor for, must not be {@code null} + */ + protected void openEditor(final String fileName) { + openEditor(getTestSource(fileName)); + } + + /** + * Closes the currently open editor. + */ + private void closeOpenEditor() { + final XtextEditor editor = getEditor(); + if (editor != null) { + closeEditor(editor, false); + } + } + + /** + * Returns the editor. + * + * @return the editor + */ + protected XtextEditor getEditor() { + return (XtextEditor) getTestInformation().getTestObject(XtextEditor.class); + } + + /** + * Closes the given editor-part - contrary to {@link org.eclipse.ui.texteditor.AbstractTextEditor#close(boolean)} this call is blocking! + * + * @param editor + * the editor to close + * @param save + * true if should save before close, false otherwise + */ + protected void closeEditor(final IEditorPart editor, final boolean save) { + Object editorJobs = getTestUtil().getEditorJobFamily(editor); + PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() { + @Override + public void run() { + PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().closeEditor(editor, save); + } + }); + if (editorJobs != null) { + waitForJobsOfFamily(editorJobs); + } + } + + /** + * Returns the viewer. + * + * @return the viewer + */ + protected XtextSourceViewer getViewer() { + return (XtextSourceViewer) getEditor().getInternalSourceViewer(); + } + + /** + * Returns the document. + * + * @return the document + */ + protected IXtextDocument getDocument() { + return getEditor().getDocument(); + } + + /** + * Insert the given value at offset in {@link #getDocument()}. + * + * @param offset + * the offset + * @param value + * the value + */ + protected void insertAtOffset(final int offset, final String value) { + PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() { + @Override + public void run() { + // the modify() is invoked to ensure a (fast-only) re-validation of the document is triggered + getDocument().modify(new IUnitOfWork() { + @Override + public java.lang.Void exec(final XtextResource state) { + try { + getDocument().replace(offset, 0, value); + } catch (BadLocationException e) { + throw new WrappedException("Could not insert \"" + value + "\" at affset " + offset, e); + } + return null; + } + }); + } + }); + } + + /** + * Test that the editor does not allow "Save as...". + * + * @deprecated Provide this test method in an appropriate test class for the editor under test, if the editor shall not allow "Save as...". + */ + @Deprecated + public void testSaveAsDisallowed() { + final XtextEditor editor = getEditor(); + assertFalse(editor.isSaveAsAllowed(), "Editor must not allow 'Save as...'"); + } + + @Override + protected void waitForValidation() { + // Editor tests frequently work by modifying the document. We first need to wait for the reconciler to run, otherwise we may + // actually get results from before a document change is reflected in the document's resource, leading to spurious errors. + // Note that the XtextReconciler runs with a delay of 500ms. + waitForJobsOfFamily(XtextReconciler.class.getName()); + super.waitForValidation(); + } +} \ No newline at end of file diff --git a/com.avaloq.tools.ddk.runtime.feature/feature.xml b/com.avaloq.tools.ddk.runtime.feature/feature.xml index 66e38cd53c..084ae3804e 100644 --- a/com.avaloq.tools.ddk.runtime.feature/feature.xml +++ b/com.avaloq.tools.ddk.runtime.feature/feature.xml @@ -37,13 +37,6 @@ version="0.0.0" unpack="false"/> - - - - - - - - diff --git a/com.avaloq.tools.ddk.xtext.common.ui/.project b/com.avaloq.tools.ddk.xtext.common.ui/.project deleted file mode 100644 index 765cdb4dea..0000000000 --- a/com.avaloq.tools.ddk.xtext.common.ui/.project +++ /dev/null @@ -1,99 +0,0 @@ - - - com.avaloq.tools.ddk.xtext.common.ui - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.pde.ManifestBuilder - - - - - org.eclipse.pde.SchemaBuilder - - - - - org.eclipse.xtext.ui.shared.xtextBuilder - - - - - net.sf.eclipsecs.core.CheckstyleBuilder - - - - - net.sourceforge.pmd.eclipse.plugin.pmdBuilder - - - - - edu.umd.cs.findbugs.plugin.eclipse.findbugsBuilder - - - - - - org.eclipse.jdt.core.javanature - org.eclipse.pde.PluginNature - org.eclipse.xtext.ui.shared.xtextNature - net.sourceforge.pmd.eclipse.plugin.pmdNature - net.sf.eclipsecs.core.CheckstyleNature - edu.umd.cs.findbugs.plugin.eclipse.findbugsNature - - - - .checkstyle - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.checkstyle - - - .fbprefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.fbprefs - - - .pmd - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.pmd - - - .settings/edu.umd.cs.findbugs.plugin.eclipse.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/edu.umd.cs.findbugs.plugin.eclipse.prefs - - - .settings/org.eclipse.core.resources.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.core.resources.prefs - - - .settings/org.eclipse.core.runtime.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.core.runtime.prefs - - - .settings/org.eclipse.jdt.core.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.jdt.core.prefs - - - .settings/org.eclipse.jdt.ui.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.jdt.ui.prefs - - - .settings/org.eclipse.pde.core.prefs - 1 - PARENT-1-PROJECT_LOC/ddk-configuration/.settings/org.eclipse.pde.core.prefs - - - diff --git a/com.avaloq.tools.ddk.xtext.common.ui/.settings/.gitignore b/com.avaloq.tools.ddk.xtext.common.ui/.settings/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/com.avaloq.tools.ddk.xtext.common.ui/META-INF/MANIFEST.MF b/com.avaloq.tools.ddk.xtext.common.ui/META-INF/MANIFEST.MF deleted file mode 100644 index 69f2ae182f..0000000000 --- a/com.avaloq.tools.ddk.xtext.common.ui/META-INF/MANIFEST.MF +++ /dev/null @@ -1,10 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: com.avaloq.tools.ddk.xtext.common.ui -Bundle-SymbolicName: com.avaloq.tools.ddk.xtext.common.ui;singleton:=true -Bundle-Version: 17.1.0.qualifier -Bundle-Vendor: Avaloq Group AG -Bundle-RequiredExecutionEnvironment: JavaSE-21 -Export-Package: com.avaloq.tools.ddk.xtext.common.ui.contentassist -Require-Bundle: org.eclipse.xtext.ui -Automatic-Module-Name: com.avaloq.tools.ddk.xtext.common.ui diff --git a/com.avaloq.tools.ddk.xtext.common.ui/build.properties b/com.avaloq.tools.ddk.xtext.common.ui/build.properties deleted file mode 100644 index 41eb6ade2b..0000000000 --- a/com.avaloq.tools.ddk.xtext.common.ui/build.properties +++ /dev/null @@ -1,4 +0,0 @@ -source.. = src/ -output.. = bin/ -bin.includes = META-INF/,\ - . diff --git a/com.avaloq.tools.ddk.xtext.common.ui/pom.xml b/com.avaloq.tools.ddk.xtext.common.ui/pom.xml deleted file mode 100644 index c15b008193..0000000000 --- a/com.avaloq.tools.ddk.xtext.common.ui/pom.xml +++ /dev/null @@ -1,12 +0,0 @@ - - 4.0.0 - - ddk-parent - com.avaloq.tools.ddk - 17.1.0-SNAPSHOT - ../ddk-parent - - - com.avaloq.tools.ddk.xtext.common.ui - eclipse-plugin - \ No newline at end of file diff --git a/com.avaloq.tools.ddk.xtext.common.ui/src/com/avaloq/tools/ddk/xtext/common/ui/contentassist/TemplatesFirstCompletionProposalComparator.java b/com.avaloq.tools.ddk.xtext.common.ui/src/com/avaloq/tools/ddk/xtext/common/ui/contentassist/TemplatesFirstCompletionProposalComparator.java deleted file mode 100644 index 6ef843d728..0000000000 --- a/com.avaloq.tools.ddk.xtext.common.ui/src/com/avaloq/tools/ddk/xtext/common/ui/contentassist/TemplatesFirstCompletionProposalComparator.java +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.common.ui.contentassist; - -import org.eclipse.jface.text.contentassist.ICompletionProposal; -import org.eclipse.jface.text.templates.TemplateProposal; -import org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalComparator; - - -/** - * Comparator for Contentassist ordering. - * If templates exists always display them first in alphabetical order. - */ -public class TemplatesFirstCompletionProposalComparator implements ICompletionProposalComparator { - - @Override - @SuppressWarnings({"rawtypes", "unchecked"}) - public int compare(final ICompletionProposal o1, final ICompletionProposal o2) { - - // Template sorting by relevance and then alphabetically by name - if (o1 instanceof TemplateProposal && o2 instanceof TemplateProposal) { - TemplateProposal t1 = (TemplateProposal) o1; - TemplateProposal t2 = (TemplateProposal) o2; - if (t1.getRelevance() == t2.getRelevance()) { - return o1.getDisplayString().compareTo(o2.getDisplayString()); - } - return ((Integer) t1.getRelevance()).compareTo(t1.getRelevance()); - } - // Templates always first - if (o1 instanceof TemplateProposal) { - return -1; - } else if (o2 instanceof TemplateProposal) { - return 1; - } - // Fallback - if ((o1 instanceof Comparable) && (o2 instanceof Comparable)) { - return ((Comparable) o1).compareTo(o2); - } - return o1.getDisplayString().compareTo(o2.getDisplayString()); - } -} diff --git a/com.avaloq.tools.ddk.xtext.test.core/META-INF/MANIFEST.MF b/com.avaloq.tools.ddk.xtext.test.core/META-INF/MANIFEST.MF index 30f314e304..d729535bed 100644 --- a/com.avaloq.tools.ddk.xtext.test.core/META-INF/MANIFEST.MF +++ b/com.avaloq.tools.ddk.xtext.test.core/META-INF/MANIFEST.MF @@ -6,8 +6,6 @@ Bundle-Version: 17.1.0.qualifier Bundle-Vendor: Avaloq Group AG Bundle-RequiredExecutionEnvironment: JavaSE-21 Require-Bundle: com.avaloq.tools.ddk.xtext, - com.avaloq.tools.ddk.xtext.common.ui, - com.avaloq.tools.ddk.xtext.ui, com.avaloq.tools.ddk.typesystem, com.avaloq.tools.ddk.test.core, com.avaloq.tools.ddk.test.ui, @@ -42,15 +40,5 @@ Export-Package: com.avaloq.tools.ddk.xtext.test, com.avaloq.tools.ddk.xtext.test.modelinference, com.avaloq.tools.ddk.xtext.test.resource, com.avaloq.tools.ddk.xtext.test.scoping, - com.avaloq.tools.ddk.xtext.test.ui, - com.avaloq.tools.ddk.xtext.test.ui.contentassist, - com.avaloq.tools.ddk.xtext.test.ui.folding, - com.avaloq.tools.ddk.xtext.test.ui.hover, - com.avaloq.tools.ddk.xtext.test.ui.hyperlinking, - com.avaloq.tools.ddk.xtext.test.ui.labeling, - com.avaloq.tools.ddk.xtext.test.ui.occurrences, - com.avaloq.tools.ddk.xtext.test.ui.outline, - com.avaloq.tools.ddk.xtext.test.ui.quickfix, - com.avaloq.tools.ddk.xtext.test.ui.syntaxcoloring, com.avaloq.tools.ddk.xtext.test.validation Automatic-Module-Name: com.avaloq.tools.ddk.xtext.test.core diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/AbstractUtilTest.java b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/AbstractUtilTest.java deleted file mode 100644 index 9a75c7f12d..0000000000 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/AbstractUtilTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.test; - -import static java.util.Collections.singleton; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IStorage; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.Path; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.xtext.resource.IResourceDescription; -import org.eclipse.xtext.resource.IResourceDescription.Delta; -import org.eclipse.xtext.ui.resource.IStorage2UriMapper; -import org.eclipse.xtext.ui.resource.Storage2UriMapperImpl; -import org.eclipse.xtext.util.Pair; -import org.eclipse.xtext.util.Tuples; - - -/** - * A base class for util test classes, which prepares common required mocks. - */ -@SuppressWarnings("nls") -public abstract class AbstractUtilTest extends AbstractXtextTest { - - public static final String TEST_PROJECT_NAME = "TestProjectName"; - private static final String DUMMY_PATH = TEST_PROJECT_NAME + "/TEST/"; - - // CHECKSTYLE:CHECK-OFF VisibilityModifierCheck - protected static Delta delta; - protected static IResourceDescription oldDesc; - protected static IResourceDescription newDesc; - protected static URI uriCorrect; - protected static Resource resource; - protected static IStorage2UriMapper mapperCorrect; - protected static IFile file; - - // CHECKSTYLE:CHECK-ON VisibilityModifierCheck - - /** - * Prepare mocks for all tests. - */ - public static void prepareMocksBase() { - oldDesc = mock(IResourceDescription.class); - newDesc = mock(IResourceDescription.class); - delta = mock(Delta.class); - resource = mock(Resource.class); - uriCorrect = mock(URI.class); - when(uriCorrect.isPlatformResource()).thenReturn(true); - when(uriCorrect.isFile()).thenReturn(true); - when(uriCorrect.toFileString()).thenReturn(DUMMY_PATH); - when(uriCorrect.toPlatformString(true)).thenReturn(DUMMY_PATH); - when(delta.getNew()).thenReturn(newDesc); - when(delta.getOld()).thenReturn(oldDesc); - when(delta.getUri()).thenReturn(uriCorrect); - when(resource.getURI()).thenReturn(uriCorrect); - file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(uriCorrect.toPlatformString(true))); - Iterable> storages = singleton(Tuples. create(file, file.getProject())); - mapperCorrect = mock(Storage2UriMapperImpl.class); - when(mapperCorrect.getStorages(uriCorrect)).thenReturn(storages); - } - -} diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/AbstractXtextTestUtil.java b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/AbstractXtextTestUtil.java index b56948946a..435a3f253b 100644 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/AbstractXtextTestUtil.java +++ b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/AbstractXtextTestUtil.java @@ -28,8 +28,6 @@ import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.util.Diagnostician; import org.eclipse.emf.ecore.util.EcoreUtil; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.intro.IIntroPart; import org.eclipse.xtext.diagnostics.AbstractDiagnostic; import org.eclipse.xtext.nodemodel.ICompositeNode; import org.eclipse.xtext.nodemodel.ILeafNode; @@ -39,8 +37,6 @@ import org.eclipse.xtext.resource.XtextResource; import org.eclipse.xtext.resource.XtextResourceSet; import org.eclipse.xtext.serializer.ISerializer; -import org.eclipse.xtext.ui.editor.GlobalURIEditorOpener; -import org.eclipse.xtext.ui.editor.XtextEditor; import org.eclipse.xtext.ui.editor.model.IXtextDocument; import org.eclipse.xtext.ui.testing.util.ResourceLoadHelper; import org.eclipse.xtext.util.StringInputStream; @@ -52,8 +48,6 @@ import com.avaloq.tools.ddk.xtext.test.model.ModelUtil; import com.avaloq.tools.ddk.xtext.test.validation.ValidationHelper; -import com.avaloq.tools.ddk.xtext.ui.util.Function; -import com.avaloq.tools.ddk.xtext.ui.util.UiThreadDispatcher; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.google.common.collect.Iterables; @@ -85,25 +79,6 @@ public abstract class AbstractXtextTestUtil extends AbstractTestUtil implements @Deprecated protected abstract Injector getInjector(); - /** - * Opens an editor for a specific {@link URI}. - * - * @param uri - * to open editor for - * @return editor opened - */ - public XtextEditor openEditor(final URI uri) { - XtextEditor editor = UiThreadDispatcher.dispatchAndWait(new Function() { - @Override - public XtextEditor run() { - closeWelcomePage(); - return (XtextEditor) get(GlobalURIEditorOpener.class).open(uri, false); - } - }); - waitForEditorJobs(editor); - return editor; - } - /** * Parses the given instance and returns the model representation. * @@ -219,21 +194,6 @@ public Diagnostician getDiagnostician() { return get(Diagnostician.class); } - /** - * Closes the welcome page if it is open. - */ - protected void closeWelcomePage() { - UiThreadDispatcher.dispatchAndWait(new Runnable() { - @Override - public void run() { - IIntroPart intro = PlatformUI.getWorkbench().getIntroManager().getIntro(); - if (intro != null) { - PlatformUI.getWorkbench().getIntroManager().closeIntro(intro); - } - } - }); - } - /** * Gets the first instance of given type containing a given structural feature with given value using a given context object. * diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/AcfContentAssistProcessorTestBuilder.java b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/AcfContentAssistProcessorTestBuilder.java index e1afd919f9..ecec77f6ac 100644 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/AcfContentAssistProcessorTestBuilder.java +++ b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/AcfContentAssistProcessorTestBuilder.java @@ -14,6 +14,7 @@ import static org.junit.Assert.assertNotNull; import java.text.MessageFormat; +import java.util.concurrent.atomic.AtomicReference; import org.eclipse.emf.common.util.WrappedException; import org.eclipse.jface.text.BadLocationException; @@ -21,6 +22,7 @@ import org.eclipse.jface.text.contentassist.IContentAssistProcessor; import org.eclipse.jface.text.contentassist.IContentAssistant; import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.xtext.resource.XtextResource; import org.eclipse.xtext.ui.editor.XtextSourceViewerConfiguration; @@ -35,8 +37,6 @@ import org.eclipse.xtext.util.Tuples; import org.junit.Assert; -import com.avaloq.tools.ddk.xtext.ui.util.Function; -import com.avaloq.tools.ddk.xtext.ui.util.UiThreadDispatcher; import com.google.inject.Injector; @@ -131,35 +131,32 @@ public AcfContentAssistProcessorTestBuilder applyText(final String expectedDispl */ @Override public ICompletionProposal[] computeCompletionProposals(final String currentModelToParse, final int cursorPosition) throws Exception { - Pair result = UiThreadDispatcher.dispatchAndWait(new Function>() { - @Override - public Pair run() { - final XtextResource xtextResource = loadHelper.getResourceFor(new StringInputStream(currentModelToParse)); - final IXtextDocument xtextDocument = getDocument(xtextResource, currentModelToParse); - return internalComputeCompletionProposals(cursorPosition, xtextDocument); - } + AtomicReference> result = new AtomicReference<>(); + + Display.getDefault().syncExec(() -> { + final XtextResource xtextResource = loadHelper.getResourceFor(new StringInputStream(currentModelToParse)); + final IXtextDocument xtextDocument = getDocument(xtextResource, currentModelToParse); + result.set(internalComputeCompletionProposals(cursorPosition, xtextDocument)); }); - if (result.getSecond() != null) { - throw result.getSecond(); + if (result.get().getSecond() != null) { + throw result.get().getSecond(); } - return result.getFirst(); + return result.get().getFirst(); } /** * {@inheritDoc} Code copied from parent. Override required to run in UI because of getSourceViewer, which creates a new Shell. */ public ICompletionProposal[] computeCompletionProposals(final XtextTestSource testSource, final int cursorPosition) { - Pair result = UiThreadDispatcher.dispatchAndWait(new Function>() { - @Override - public Pair run() { - final IXtextDocument xtextDocument = getDocument(testSource.getXtextResource(), testSource.getContent()); - return internalComputeCompletionProposals(cursorPosition, xtextDocument); - } + AtomicReference> result = new AtomicReference<>(); + Display.getDefault().syncExec(() -> { + final IXtextDocument xtextDocument = getDocument(testSource.getXtextResource(), testSource.getContent()); + result.set(internalComputeCompletionProposals(cursorPosition, xtextDocument)); }); - if (result.getSecond() != null) { - throw new WrappedException("Error computing completion proposals.", result.getSecond()); + if (result.get().getSecond() != null) { + throw new WrappedException("Error computing completion proposals.", result.get().getSecond()); } - return result.getFirst(); + return result.get().getFirst(); } /** @@ -167,38 +164,36 @@ public Pair run() { */ @Override public ContentAssistProcessorTestBuilder assertMatchString(final String matchString) throws Exception { - BadLocationException exception = UiThreadDispatcher.dispatchAndWait(new Function() { - @Override - public BadLocationException run() { - String currentModelToParse = getModel(); - final XtextResource xtextResource = loadHelper.getResourceFor(new StringInputStream(currentModelToParse)); - final IXtextDocument xtextDocument = getDocument(xtextResource, currentModelToParse); - XtextSourceViewerConfiguration configuration = get(XtextSourceViewerConfiguration.class); - Shell shell = new Shell(); - try { - ISourceViewer sourceViewer = getSourceViewer(shell, xtextDocument, configuration); - IContentAssistant contentAssistant = configuration.getContentAssistant(sourceViewer); - String contentType = xtextDocument.getContentType(currentModelToParse.length()); - if (contentAssistant.getContentAssistProcessor(contentType) != null) { - ContentAssistContext.Factory factory = get(ContentAssistContext.Factory.class); - ContentAssistContext[] contexts = factory.create(sourceViewer, currentModelToParse.length(), xtextResource); - for (ContentAssistContext context : contexts) { - Assert.assertTrue("matchString = '" + matchString + "', actual: '" + context.getPrefix() + "'", "".equals(context.getPrefix()) - || matchString.equals(context.getPrefix())); - } - } else { - Assert.fail("No content assistant for content type " + contentType); + AtomicReference exception = new AtomicReference<>(); + + Display.getDefault().syncExec(() -> { + String currentModelToParse = getModel(); + final XtextResource xtextResource = loadHelper.getResourceFor(new StringInputStream(currentModelToParse)); + final IXtextDocument xtextDocument = getDocument(xtextResource, currentModelToParse); + XtextSourceViewerConfiguration configuration = get(XtextSourceViewerConfiguration.class); + Shell shell = new Shell(); + try { + ISourceViewer sourceViewer = getSourceViewer(shell, xtextDocument, configuration); + IContentAssistant contentAssistant = configuration.getContentAssistant(sourceViewer); + String contentType = xtextDocument.getContentType(currentModelToParse.length()); + if (contentAssistant.getContentAssistProcessor(contentType) != null) { + ContentAssistContext.Factory factory = get(ContentAssistContext.Factory.class); + ContentAssistContext[] contexts = factory.create(sourceViewer, currentModelToParse.length(), xtextResource); + for (ContentAssistContext context : contexts) { + Assert.assertTrue("matchString = '" + matchString + "', actual: '" + context.getPrefix() + "'", "".equals(context.getPrefix()) + || matchString.equals(context.getPrefix())); } - } catch (BadLocationException e) { - return e; - } finally { - shell.dispose(); + } else { + Assert.fail("No content assistant for content type " + contentType); } - return null; + } catch (BadLocationException e) { + exception.set(e); + } finally { + shell.dispose(); } }); - if (exception != null) { - throw exception; + if (exception.get() != null) { + throw exception.get(); } return this; } diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/jupiter/AbstractXtextTestUtil.java b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/jupiter/AbstractXtextTestUtil.java index 1cfcb716cb..57b13d38ff 100644 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/jupiter/AbstractXtextTestUtil.java +++ b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/jupiter/AbstractXtextTestUtil.java @@ -28,8 +28,6 @@ import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.util.Diagnostician; import org.eclipse.emf.ecore.util.EcoreUtil; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.intro.IIntroPart; import org.eclipse.xtext.diagnostics.AbstractDiagnostic; import org.eclipse.xtext.nodemodel.ICompositeNode; import org.eclipse.xtext.nodemodel.ILeafNode; @@ -39,8 +37,6 @@ import org.eclipse.xtext.resource.XtextResource; import org.eclipse.xtext.resource.XtextResourceSet; import org.eclipse.xtext.serializer.ISerializer; -import org.eclipse.xtext.ui.editor.GlobalURIEditorOpener; -import org.eclipse.xtext.ui.editor.XtextEditor; import org.eclipse.xtext.ui.editor.model.IXtextDocument; import org.eclipse.xtext.ui.testing.util.ResourceLoadHelper; import org.eclipse.xtext.util.StringInputStream; @@ -53,8 +49,6 @@ import com.avaloq.tools.ddk.xtext.test.AbstractTestUtil; import com.avaloq.tools.ddk.xtext.test.model.ModelUtil; import com.avaloq.tools.ddk.xtext.test.validation.ValidationHelper; -import com.avaloq.tools.ddk.xtext.ui.util.Function; -import com.avaloq.tools.ddk.xtext.ui.util.UiThreadDispatcher; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.google.common.collect.Iterables; @@ -86,25 +80,6 @@ public abstract class AbstractXtextTestUtil extends AbstractTestUtil implements @Deprecated protected abstract Injector getInjector(); - /** - * Opens an editor for a specific {@link URI}. - * - * @param uri - * to open editor for - * @return editor opened - */ - public XtextEditor openEditor(final URI uri) { - XtextEditor editor = UiThreadDispatcher.dispatchAndWait(new Function() { - @Override - public XtextEditor run() { - closeWelcomePage(); - return (XtextEditor) get(GlobalURIEditorOpener.class).open(uri, false); - } - }); - waitForEditorJobs(editor); - return editor; - } - /** * Parses the given instance and returns the model representation. * @@ -220,21 +195,6 @@ public Diagnostician getDiagnostician() { return get(Diagnostician.class); } - /** - * Closes the welcome page if it is open. - */ - protected void closeWelcomePage() { - UiThreadDispatcher.dispatchAndWait(new Runnable() { - @Override - public void run() { - IIntroPart intro = PlatformUI.getWorkbench().getIntroManager().getIntro(); - if (intro != null) { - PlatformUI.getWorkbench().getIntroManager().closeIntro(intro); - } - } - }); - } - /** * Gets the first instance of given type containing a given structural feature with given value using a given context object. * diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/AbstractUiTest.java b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/AbstractUiTest.java deleted file mode 100644 index e1c1a95f4e..0000000000 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/AbstractUiTest.java +++ /dev/null @@ -1,210 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.test.ui; - -import static org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable.asyncExec; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.eclipse.core.resources.IFile; -import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotEditor; -import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable; -import org.eclipse.swtbot.swt.finder.results.Result; -import org.eclipse.swtbot.swt.finder.results.VoidResult; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.part.FileEditorInput; -import org.junit.Rule; -import org.junit.rules.Timeout; -import org.junit.runner.RunWith; - -import com.avaloq.tools.ddk.test.ui.swtbot.SwtWorkbenchBot; -import com.avaloq.tools.ddk.test.ui.swtbot.util.SwtBotUtil; -import com.avaloq.tools.ddk.xtext.test.AbstractTest; -import com.avaloq.tools.ddk.xtext.test.junit.runners.SwtBotRecordingXtextTestRunner; -import com.avaloq.tools.ddk.xtext.ui.util.UiAssert; - - -/** - * Base class for testing a running instance of {@link IEditorPart} at the UI-level.
- * Does not open any editor before all tests run.
- * Provides an instance of {@link SwtWorkbenchBot} via {@link #getBot()}.
- * Provides an instance of {@link IEditorPart} via {@link #openEditor(IFile, String, boolean)} for opening an editor of arbitrary kind based on input and editor - * ID.
- * Provides {@link #closeEditor(IEditorPart, boolean)} for closing the running editor instance. - */ -@RunWith(SwtBotRecordingXtextTestRunner.class) -public abstract class AbstractUiTest extends AbstractTest { - - /** Class-wide logger. */ - private static final Logger LOGGER = LogManager.getLogger(AbstractUiTest.class); - private static final int TEST_TIMEOUT = 600000; // 10 minutes timeout for each test - - /** - * Enforces the junit {@link Timeout} rule for each UI test. - */ - @Rule - // CHECKSTYLE:CHECK-OFF VisibilityModifier - public Timeout globalTimeout = Timeout.millis(TEST_TIMEOUT); - - // CHECKSTYLE:CHECK-ON VisibilityModifier - - /** - * Initialize the {@link org.eclipse.swtbot.swt.finder.SWTBot}. - */ - protected void initializeSWTBot() { - getTestInformation().putTestObject(SwtWorkbenchBot.class, SwtBotUtil.initializeBot()); - } - - /** - * The default implementation returns the name of the source model calling {@link getTestSourceModelName} and adds the default file extension for the grammar - * of this test. A test class needs to override this, if the name of the main test source file differs from the default. - * - * @return the name of the main test source file - */ - @Override - protected String getTestSourceFileName() { - return this.getTestSourceModelName() + '.' + getFileExtension(); - } - - @Override - protected void beforeAllTests() { - super.beforeAllTests(); - initializeSWTBot(); - getBot().closeWelcomePage(); - } - - /** - * Get the file extension to use for test source files. - * - * @return the file extension. - */ - protected abstract String getFileExtension(); - - /** - * Get an SWT Workbench bot. - * - * @return the bot - */ - public SwtWorkbenchBot getBot() { - return (SwtWorkbenchBot) getTestInformation().getTestObject(SwtWorkbenchBot.class); - } - - /** - * Attempts to open and return the {@link IEditorPart} with the given ID for the given input file. - * - * @param file - * the input file - * @param editorId - * the editor ID - * @param activate - * true to activate the editor, false otherwise - * @return the editor part or null - */ - protected IEditorPart openEditor(final IFile file, final String editorId, final boolean activate) { - UiAssert.isNotUiThread(); - IEditorPart editor = UIThreadRunnable.syncExec(getBot().getDisplay(), new Result() { - @Override - public IEditorPart run() { - try { - IWorkbench workbench = PlatformUI.getWorkbench(); - IWorkbenchPage activePage = workbench.getActiveWorkbenchWindow().getActivePage(); - final int matchFlags = IWorkbenchPage.MATCH_ID | IWorkbenchPage.MATCH_INPUT; - final IEditorInput input = new FileEditorInput(file); - IEditorPart editor = activePage.openEditor(input, editorId, activate, matchFlags); - editor.setFocus(); - return editor; - } catch (PartInitException e) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug(e.getMessage(), e); - } - } - return null; - } - }); - - waitForEditorJobs(editor); - return editor; - - } - - /** - * Closes the given editor-part. - * - * @param editor - * the editor to close - * @param save - * true if should save before close, false otherwise - */ - protected void closeEditor(final IEditorPart editor, final boolean save) { - UiAssert.isNotUiThread(); - Object editorJobs = getTestUtil().getEditorJobFamily(editor); - UIThreadRunnable.syncExec(getBot().getDisplay(), new VoidResult() { - @Override - public void run() { - PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().closeEditor(editor, save); - } - }); - if (editorJobs != null) { - waitForJobsOfFamily(editorJobs); - } - } - - /** - * Opens the editor asynchronously. - * - * @param file - * the file - * @param editorId - * the editor id - * @param activate - * true to activate, false otherwise - */ - protected void openEditorAsync(final IFile file, final String editorId, final boolean activate) { - asyncExec(new VoidResult() { - @Override - public void run() { - try { - IWorkbench workbench = PlatformUI.getWorkbench(); - IWorkbenchPage activePage = workbench.getActiveWorkbenchWindow().getActivePage(); - final int matchFlags = IWorkbenchPage.MATCH_ID | IWorkbenchPage.MATCH_INPUT; - final IEditorInput input = new FileEditorInput(file); - IEditorPart editor = activePage.openEditor(input, editorId, activate, matchFlags); - editor.setFocus(); - waitForEditorJobs(editor); - } catch (PartInitException e) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug(e.getMessage(), e); - } - } - } - }); - } - - /** - * @param editorId - * the editor id - * @return true if the editor being tested is open, false otherwise - */ - protected boolean isEditorOpen(final String editorId) { - for (SWTBotEditor e : getBot().editors()) { - if (e.getReference().getId().equals(editorId)) { - return true; - } - } - return false; - } - -} diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/AbstractXtextEditorTest.java b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/AbstractXtextEditorTest.java deleted file mode 100644 index fb5d47e746..0000000000 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/AbstractXtextEditorTest.java +++ /dev/null @@ -1,204 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.test.ui; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; - -import org.eclipse.emf.common.util.WrappedException; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.PlatformUI; -import org.eclipse.xtext.resource.XtextResource; -import org.eclipse.xtext.ui.editor.XtextEditor; -import org.eclipse.xtext.ui.editor.XtextSourceViewer; -import org.eclipse.xtext.ui.editor.model.IXtextDocument; -import org.eclipse.xtext.ui.editor.reconciler.XtextReconciler; -import org.eclipse.xtext.util.concurrent.IUnitOfWork; - -import com.avaloq.tools.ddk.xtext.test.AbstractXtextMarkerBasedTest; -import com.avaloq.tools.ddk.xtext.test.TestSource; -import com.avaloq.tools.ddk.xtext.test.XtextTestSource; - - -/** - * AbstractXtextEditorTest provides convenient setup and access functionality for tests that require an xtext editor. - */ -@SuppressWarnings("nls") -public abstract class AbstractXtextEditorTest extends AbstractXtextMarkerBasedTest { - - private static final String EDITOR_MUST_NOT_BE_DIRTY = "Editor must not be dirty - this indicates state carried over"; - private static final String EDITOR_HAS_NO_DOCUMENT = "Editor has no document"; - private static final String EDITOR_COULD_NOT_BE_OPENED_WITH_URI = "Editor could not be opened with URI: "; - - protected static final String CR_LF = "\r\n"; - protected static final String LF = "\n"; - - @Override - protected void beforeAllTests() { - super.beforeAllTests(); - // For Xtend-based tests there is no default test source associated with the test class - TestSource testSource = getTestSource(); - if (testSource != null) { - openEditor(testSource); - } - } - - @Override - protected void afterAllTests() { - closeOpenEditor(); - super.afterAllTests(); - } - - @Override - protected void beforeApplyAssertions(final XtextTestSource testSource) { - super.beforeApplyAssertions(testSource); - openEditor(testSource); - } - - @Override - protected void afterValidate() { - closeOpenEditor(); - super.afterValidate(); - } - - /** - * Opens the editor with the given test source. - * - * @param testSource - * the test source to open, not {@code null} - */ - private void openEditor(final TestSource testSource) { - // if openEditor returns NULL, then one possible cause might be that the Activator - // has not been set correctly in the presentation plug-in MANIFEST of that grammar. - XtextEditor editor = getXtextTestUtil().openEditor(testSource.getUri()); - assertNotNull(EDITOR_COULD_NOT_BE_OPENED_WITH_URI + testSource.getUri(), editor); - getTestInformation().putTestObject(XtextEditor.class, editor); - assertNotNull(EDITOR_HAS_NO_DOCUMENT, getDocument()); - assertFalse(EDITOR_MUST_NOT_BE_DIRTY, getEditor().isDirty()); - } - - /** - * Open editor of the test source with a given file name. - * - * @param fileName - * file name of the source to open editor for, must not be {@code null} - */ - protected void openEditor(final String fileName) { - openEditor(getTestSource(fileName)); - } - - /** - * Closes the currently open editor. - */ - private void closeOpenEditor() { - final XtextEditor editor = getEditor(); - if (editor != null) { - closeEditor(editor, false); - } - } - - /** - * Returns the editor. - * - * @return the editor - */ - protected XtextEditor getEditor() { - return (XtextEditor) getTestInformation().getTestObject(XtextEditor.class); - } - - /** - * Closes the given editor-part - contrary to {@link org.eclipse.ui.texteditor.AbstractTextEditor#close(boolean)} this call is blocking! - * - * @param editor - * the editor to close - * @param save - * true if should save before close, false otherwise - */ - protected void closeEditor(final IEditorPart editor, final boolean save) { - Object editorJobs = getTestUtil().getEditorJobFamily(editor); - PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() { - @Override - public void run() { - PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().closeEditor(editor, save); - } - }); - if (editorJobs != null) { - waitForJobsOfFamily(editorJobs); - } - } - - /** - * Returns the viewer. - * - * @return the viewer - */ - protected XtextSourceViewer getViewer() { - return (XtextSourceViewer) getEditor().getInternalSourceViewer(); - } - - /** - * Returns the document. - * - * @return the document - */ - protected IXtextDocument getDocument() { - return getEditor().getDocument(); - } - - /** - * Insert the given value at offset in {@link #getDocument()}. - * - * @param offset - * the offset - * @param value - * the value - */ - protected void insertAtOffset(final int offset, final String value) { - PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() { - @Override - public void run() { - // the modify() is invoked to ensure a (fast-only) re-validation of the document is triggered - getDocument().modify(new IUnitOfWork() { - @Override - public java.lang.Void exec(final XtextResource state) { - try { - getDocument().replace(offset, 0, value); - } catch (BadLocationException e) { - throw new WrappedException("Could not insert \"" + value + "\" at affset " + offset, e); - } - return null; - } - }); - } - }); - } - - /** - * Test that the editor does not allow "Save as...". - * - * @deprecated Provide this test method in an appropriate test class for the editor under test, if the editor shall not allow "Save as...". - */ - @Deprecated - public void testSaveAsDisallowed() { - final XtextEditor editor = getEditor(); - assertFalse("Editor must not allow 'Save as...'", editor.isSaveAsAllowed()); - } - - @Override - protected void waitForValidation() { - // Editor tests frequently work by modifying the document. We first need to wait for the reconciler to run, otherwise we may - // actually get results from before a document change is reflected in the document's resource, leading to spurious errors. - // Note that the XtextReconciler runs with a delay of 500ms. - waitForJobsOfFamily(XtextReconciler.class.getName()); - super.waitForValidation(); - } -} diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/AbstractXtextEditorUiTest.java b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/AbstractXtextEditorUiTest.java deleted file mode 100644 index 18ce0e80d5..0000000000 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/AbstractXtextEditorUiTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.test.ui; - -import org.junit.runner.RunWith; - -import com.avaloq.tools.ddk.test.ui.swtbot.SwtWorkbenchBot; -import com.avaloq.tools.ddk.test.ui.swtbot.util.SwtBotUtil; -import com.avaloq.tools.ddk.xtext.test.junit.runners.SwtBotRecordingXtextTestRunner; - - -/** - * AbstractXtextEditorUITest extends AbstractXtextEditorTest by providing SWT bot functionalities. - */ -@RunWith(SwtBotRecordingXtextTestRunner.class) -public abstract class AbstractXtextEditorUiTest extends AbstractXtextEditorTest { - - /** - * Initialize the {@link org.eclipse.swtbot.swt.finder.SWTBot}. - */ - public void initializeSWTBot() { - getTestInformation().putTestObject(SwtWorkbenchBot.class, SwtBotUtil.initializeBot()); - } - - @Override - protected void beforeAllTests() { - super.beforeAllTests(); - initializeSWTBot(); - getBot().closeWelcomePage(); - } - - public SwtWorkbenchBot getBot() { - return (SwtWorkbenchBot) getTestInformation().getTestObject(SwtWorkbenchBot.class); - } - -} diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/AbstractXtextUiTest.java b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/AbstractXtextUiTest.java deleted file mode 100644 index 6bd19b19b1..0000000000 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/AbstractXtextUiTest.java +++ /dev/null @@ -1,128 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.test.ui; - -import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotEclipseEditor; -import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotEditor; -import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable; -import org.eclipse.swtbot.swt.finder.results.Result; -import org.eclipse.swtbot.swt.finder.waits.DefaultCondition; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IFileEditorInput; -import org.eclipse.xtext.ui.editor.GlobalURIEditorOpener; -import org.junit.runner.RunWith; - -import com.avaloq.tools.ddk.test.ui.swtbot.SwtWorkbenchBot; -import com.avaloq.tools.ddk.test.ui.swtbot.util.SwtBotUtil; -import com.avaloq.tools.ddk.xtext.test.AbstractXtextTest; -import com.avaloq.tools.ddk.xtext.test.junit.runners.SwtBotRecordingXtextTestRunner; -import com.avaloq.tools.ddk.xtext.ui.util.UiAssert; - - -/** - * Base class for testing a running instance of {@link IEditorPart} at the UI-level.
- * Does not open any editor before all tests run.
- * Provides an instance of {@link SwtWorkbenchBot} via {@link #getBot()}.
- * Provides an instance of {@link IEditorPart} via {@link #openEditor(org.eclipse.core.resources.IFile, String, boolean)} for opening an editor of arbitrary - * kind based on input and editor - * ID.
- * Provides {@link #closeEditor(IEditorPart, boolean)} for closing the running editor instance. - */ -@RunWith(SwtBotRecordingXtextTestRunner.class) -public abstract class AbstractXtextUiTest extends AbstractXtextTest { - - private static final long EDITOR_ENABLED_TIMEOUT = 30000L; - - /** - * Initialize the {@link org.eclipse.swtbot.swt.finder.SWTBot}. - */ - public void initializeSWTBot() { - getTestInformation().putTestObject(SwtWorkbenchBot.class, SwtBotUtil.initializeBot()); - } - - @Override - protected void beforeAllTests() { - super.beforeAllTests(); - initializeSWTBot(); - getBot().closeWelcomePage(); - getBot().resetActivePerspective(); - IEditorPart editor = openEditor(getTestSource().getUri(), true); - SWTBotEditor swtBotEditor = getBot().editorByTitle(editor.getTitle()); - getTestInformation().putTestObject(SWTBotEclipseEditor.class, new AcfSwtBotEclipseEditor(swtBotEditor.getReference(), getBot())); - } - - public SwtWorkbenchBot getBot() { - return (SwtWorkbenchBot) getTestInformation().getTestObject(SwtWorkbenchBot.class); - } - - @Override - protected void afterAllTests() { - final SWTBotEclipseEditor editor = getEditor(); - if (editor != null) { - final IEditorPart editorPart = editor.getReference().getEditor(false); - Object editorJobs = getTestUtil().getEditorJobFamily(editorPart); - editor.close(); - if (editorJobs != null) { - waitForJobsOfFamily(editorJobs); - } - } - super.afterAllTests(); - } - - /** - * Opens an {@link IEditorPart} for a provided {@link org.eclipse.emf.common.util.URI}. - * - * @param uri - * {@link org.eclipse.emf.common.util.URI} to open editor for - * @param activate - * true if focus is to be set to the opened editor - * @return {@link IEditorPart} created - */ - private IEditorPart openEditor(final org.eclipse.emf.common.util.URI uri, final boolean activate) { - UiAssert.isNotUiThread(); - final IEditorPart editorPart = UIThreadRunnable.syncExec(getBot().getDisplay(), new Result() { - @Override - public IEditorPart run() { - IEditorPart editor = getXtextTestUtil().get(GlobalURIEditorOpener.class).open(uri, activate); - editor.setFocus(); - return editor; - } - }); - - waitForEditorJobs(editorPart); - - getBot().waitUntil(new DefaultCondition() { - @Override - public boolean test() { - if (editorPart.getEditorSite() != null && editorPart.getEditorInput() != null) { - IEditorInput input = editorPart.getEditorInput(); - if (input instanceof IFileEditorInput) { - return !((IFileEditorInput) input).getFile().isReadOnly(); - } - } - return false; - } - - @Override - public String getFailureMessage() { - return "Editor must be initialized."; //$NON-NLS-1$ - } - }, EDITOR_ENABLED_TIMEOUT); - - return editorPart; - } - - public SWTBotEclipseEditor getEditor() { - return (SWTBotEclipseEditor) getTestInformation().getTestObject(SWTBotEclipseEditor.class); - } - -} diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/AcfSwtBotEclipseEditor.java b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/AcfSwtBotEclipseEditor.java deleted file mode 100644 index b3e483e3fe..0000000000 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/AcfSwtBotEclipseEditor.java +++ /dev/null @@ -1,67 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.test.ui; - -import org.eclipse.osgi.util.NLS; -import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot; -import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotEclipseEditor; -import org.eclipse.swtbot.swt.finder.utils.Position; -import org.eclipse.swtbot.swt.finder.waits.DefaultCondition; -import org.eclipse.ui.IEditorReference; - - -/** - * Customization of {@link SWTBotEclipseEditor}. - */ -public class AcfSwtBotEclipseEditor extends SWTBotEclipseEditor { - - public AcfSwtBotEclipseEditor(final IEditorReference editorReference, final SWTWorkbenchBot bot) { - super(editorReference, bot); - } - - @Override - public void navigateTo(final int line, final int column) { - super.navigateTo(line, column); - waitUntilCursorIsOnPosition(line, column); - } - - @Override - public void navigateTo(final Position position) { - super.navigateTo(position); - waitUntilCursorIsOnPosition(position.line, position.column); - } - - /** - * Synchronously wait until the cursor is on the given position. - * - * @param line - * line number - * @param column - * column number - */ - private void waitUntilCursorIsOnPosition(final int line, final int column) { - bot.waitUntil(new DefaultCondition() { - - @Override - public boolean test() { - Position position = cursorPosition(); - return isActive() && position.line == line && position.column == column; - } - - @Override - public String getFailureMessage() { - return NLS.bind("The cursor should be on the position ({0}, {1}) and the editor should have focus.", line, column); //$NON-NLS-1$ - } - - }); - } - -} diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/contentassist/AbstractContentAssistUiTest.java b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/contentassist/AbstractContentAssistUiTest.java deleted file mode 100644 index 95d4e6fb46..0000000000 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/contentassist/AbstractContentAssistUiTest.java +++ /dev/null @@ -1,262 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.test.ui.contentassist; - -import java.util.Arrays; -import java.util.List; - -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.ITextViewer; -import org.eclipse.jface.text.contentassist.ICompletionProposal; -import org.eclipse.jface.text.contentassist.IContentAssistProcessor; -import org.eclipse.jface.text.contentassist.IContentAssistant; -import org.eclipse.jface.text.templates.TemplateProposal; -import org.eclipse.xtext.nodemodel.ICompositeNode; -import org.eclipse.xtext.nodemodel.ILeafNode; -import org.eclipse.xtext.nodemodel.INode; -import org.eclipse.xtext.ui.editor.XtextSourceViewerConfiguration; -import org.eclipse.xtext.ui.editor.contentassist.CompletionProposalComputer; -import org.eclipse.xtext.ui.editor.contentassist.CompletionProposalComputer.State; -import org.junit.Assert; - -import com.avaloq.tools.ddk.xtext.common.ui.contentassist.TemplatesFirstCompletionProposalComparator; -import com.avaloq.tools.ddk.xtext.resource.Messages; -import com.avaloq.tools.ddk.xtext.test.ui.AbstractXtextEditorTest; -import com.avaloq.tools.ddk.xtext.ui.util.UiThreadDispatcher; -import com.google.common.base.Function; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; - - -/** - * Abstract class for content assist tests. - */ -@SuppressWarnings("nls") -public abstract class AbstractContentAssistUiTest extends AbstractXtextEditorTest { - - private static final String EDITOR_HAS_NO_VIEWER = "Editor has no viewer."; - - /** The Constant NO_OFFSET_FOUND returned when no offset found for given token. */ - private static final int NO_OFFSET_FOUND = -1; - - private ICompletionProposal[] getCompletionProposals() { - return (ICompletionProposal[]) getTestInformation().getTestObject(ICompletionProposal.class); - } - - @Override - protected void beforeAllTests() { - super.beforeAllTests(); - closeEditor(getEditor(), false); - } - - @Override - protected void beforeEachTest() { - super.beforeEachTest(); - if (getTestSource() != null) { - openEditor(getTestSourceFileName()); - } - } - - @Override - protected void afterEachTest() { - super.afterEachTest(); - closeEditor(getEditor(), false); - } - - /** - * Evaluates completion proposals in a UI thread. - * - * @param offset - * the offset at which completion proposals should be evaluated - */ - private void evaluateCompletionProposals(final int offset) { - UiThreadDispatcher.dispatchAndWait(new Runnable() { - @Override - public void run() { - getTestInformation().putTestObject(ICompletionProposal.class, getDocument().readOnly(createCompletionProposalComputer(offset))); - } - }); - } - - /** - * Gets the completion proposal display strings. - * - * @param proposals - * the proposals - * @return the completion proposal display strings - */ - private List getCompletionProposalDisplayStrings(final ICompletionProposal... proposals) { - return Lists.newArrayList(Iterables.transform(Arrays.asList(proposals), new Function() { - @Override - public String apply(final ICompletionProposal from) { - return from.getDisplayString(); - } - })); - } - - /** - * Compares two lists of Strings alphabetically. - * - * @param contentassistProposals - * expected list of proposals - * @param offset - * offset in test file - */ - protected void assertContentAssist(final List contentassistProposals, final int offset) { - evaluateCompletionProposals(offset); - Arrays.sort(getCompletionProposals(), new TemplatesFirstCompletionProposalComparator()); - Assert.assertEquals("Same length", contentassistProposals.size(), getCompletionProposals().length); - for (int i = 0; i < contentassistProposals.size(); i++) { - Assert.assertEquals("Same displayed string", contentassistProposals.get(i), getCompletionProposals()[i].getDisplayString()); - } - } - - /** - * Assert that application of the target {@link TemplateProposal} was successful and the text of the resulting document equals the expected text. - * - * @param sourceFileName - * the name of the source being tested, must not be {@code null} - * @param contentassistProposal - * the display string of the content assist proposal, must not be {@code null} - * @param expectedContent - * the expected document content after application of the {@link TemplateProposal}, must not be {@code null} - * @param offset - * offset in test file - */ - protected void assertTemplateProposalExistsAndSuccessful(final String sourceFileName, final String contentassistProposal, final String expectedContent, final int offset) { - assertTemplateProposalExistsAndSuccessful(sourceFileName, null, contentassistProposal, expectedContent, offset); - } - - /** - * Assert that application of the target {@link TemplateProposal} was successful and the text of the resulting document equals the expected text. - * Creates a test source with the given {@code sourceFileName} and {@code sourceContent}. - * - * @param sourceFileName - * the name of the source being tested, must not be {@code null} - * @param sourceContent - * the source content, may be {@code null} - * @param contentassistProposal - * the display string of the content assist proposal, must not be {@code null} - * @param expectedContent - * the expected document content after application of the {@link TemplateProposal}, must not be {@code null} - * @param offset - * offset in test file - */ - @SuppressWarnings("PMD.UseObjectForClearerAPI") - protected void assertTemplateProposalExistsAndSuccessful(final String sourceFileName, final String sourceContent, final String contentassistProposal, final String expectedContent, final int offset) { - if (sourceContent == null) { - Assert.assertNotNull(String.format("There must be an existing test source with the file name '%s'.", sourceFileName), getTestSource(sourceFileName)); - } else { - createTestSource(sourceFileName, sourceContent); - } - openEditor(sourceFileName); - evaluateCompletionProposals(offset); - ICompletionProposal[] completionProposals = getCompletionProposals(); - - TemplateProposal templateProposal = null; - for (int i = 0; i < completionProposals.length && templateProposal == null; i++) { - ICompletionProposal proposal = completionProposals[i]; - String displayString = proposal.getDisplayString(); - if (proposal instanceof TemplateProposal && contentassistProposal.equals(displayString)) { - templateProposal = (TemplateProposal) proposal; - } - } - - Assert.assertNotNull(String.format("Template proposal '%s' must be found.", contentassistProposal), templateProposal); - String actualContent = applyTemplateProposal(templateProposal, offset); - - Assert.assertEquals("Editor content must match expected result.", expectedContent.replaceAll(CR_LF, LF), actualContent.replaceAll(CR_LF, LF)); - closeEditor(getEditor(), false); - } - - /** - * Apply template proposal. - * - * @param templateProposal - * the template proposal, must not be {@code null} - * @param offset - * offset in test file - * @return the document text after application of the template proposal, never {@code null} - */ - private String applyTemplateProposal(final TemplateProposal templateProposal, final int offset) { - // Apply proposal - UiThreadDispatcher.dispatchAndWait(new Runnable() { - @Override - public void run() { - Assert.assertNotNull(EDITOR_HAS_NO_VIEWER, getViewer()); - templateProposal.apply(getViewer(), ' ', 0, offset); - } - }); - - waitForValidation(); - return getDocument().get(); - } - - /** - * Assert proposals at offset exist. - * - * @param offset - * the offset - * @param proposals - * the proposals - */ - protected void assertProposalsAtOffsetExist(final int offset, final String... proposals) { - evaluateCompletionProposals(offset); - final List result = getCompletionProposalDisplayStrings(getCompletionProposals()); - for (final String s : proposals) { - Assert.assertTrue(Messages.bind("Expected proposal \"{0}\" but found \"{1}\"", s, result), result.contains(s)); - } - } - - /** - * Helper function to find the correct CompletionProposalComputer for the given offset. - * - * @param offset - * offset in test file - * @return language and offset specific content assist proposal computer - */ - private CompletionProposalComputer createCompletionProposalComputer(final int offset) { - XtextSourceViewerConfiguration configuration = getEditor().getXtextSourceViewerConfiguration(); - IContentAssistant contentAssistant = configuration.getContentAssistant(getViewer()); - IContentAssistProcessor contentAssistProcessor; - try { - contentAssistProcessor = contentAssistant.getContentAssistProcessor(getDocument().getContentType(offset)); - } catch (BadLocationException e) { - contentAssistProcessor = getTestUtil().get(IContentAssistProcessor.class); - } - if (contentAssistProcessor == null) { - contentAssistProcessor = getTestUtil().get(IContentAssistProcessor.class); - } - return new CompletionProposalComputer((State) contentAssistProcessor, (ITextViewer) getViewer(), offset); - } - - /** - * Gets the total offset for given token. - * - * @param parserNode - * the parser node - * @param name - * the name - * @return the total offset for given token - */ - protected int getTotalOffsetForToken(final ICompositeNode parserNode, final String name) { - int result = NO_OFFSET_FOUND; - for (final INode n : parserNode.getChildren()) { - if (n instanceof ILeafNode && name.equals(n.getText())) { - result = n.getTotalOffset(); - } else if (n instanceof ICompositeNode) { - result = getTotalOffsetForToken((ICompositeNode) n, name); - } - } - return result; - } - -} diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/folding/AbstractFoldingTest.java b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/folding/AbstractFoldingTest.java deleted file mode 100644 index ed168df674..0000000000 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/folding/AbstractFoldingTest.java +++ /dev/null @@ -1,106 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.test.ui.folding; - -import static org.junit.Assert.fail; - -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Set; - -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.Position; -import org.eclipse.xtext.ui.editor.folding.DefaultFoldedPosition; -import org.eclipse.xtext.ui.editor.folding.FoldedPosition; -import org.eclipse.xtext.ui.editor.folding.IFoldingRegionProvider; -import org.junit.Assert; - -import com.avaloq.tools.ddk.test.core.BugTest; -import com.avaloq.tools.ddk.xtext.test.ui.AbstractXtextEditorTest; -import com.google.common.base.Function; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; - - -/** - * Base class for folding tests. - */ -@SuppressWarnings("nls") -public abstract class AbstractFoldingTest extends AbstractXtextEditorTest { - - /** - * Checks that the folding region of the document under test are located at the expected positions. - * - * @param expectedPositions - * the offsets and lengths of the folding regions - */ - protected void assertFoldingRegions(final Set expectedPositions) { - Comparator comparator = new Comparator() { - @Override - public int compare(final Position p1, final Position p2) { - return Integer.signum(p1.getOffset() - p2.getOffset()); - } - }; - - final List expectedList = Lists.newArrayList(expectedPositions); - Collection foldingRegions = getXtextTestUtil().get(IFoldingRegionProvider.class).getFoldingRegions(getDocument()); - final List actualPositions = Lists.newArrayList(Iterables.transform(foldingRegions, new Function() { - @Override - public Position apply(final FoldedPosition from) { - return new Position(from.offset, from.length); - } - })); - - List unmatchedExpectedPositions = Lists.newArrayList(Iterables.filter(expectedPositions, new Predicate() { - @Override - public boolean apply(final Position p) { - return !actualPositions.contains(p); - } - })); - if (!unmatchedExpectedPositions.isEmpty()) { - Collections.sort(unmatchedExpectedPositions, comparator); - - List unmatchedActualPositions = Lists.newArrayList(Iterables.filter(actualPositions, new Predicate() { - @Override - public boolean apply(final Position p) { - return !expectedList.contains(p); - } - })); - Collections.sort(unmatchedActualPositions, comparator); - // CHECKSTYLE:OFF MagicNumber - StringBuffer message = new StringBuffer(100); - // CHECKSTYLE:ON - message.append("Unmatched Expected Positions:").append(unmatchedExpectedPositions).append('\n'); - message.append("Unmatched Actual Positions:").append(unmatchedActualPositions); - Assert.assertTrue(message.toString(), unmatchedExpectedPositions.isEmpty()); - } - } - - /** - * Verifies that FoldedPositions are valid. - * If the assertion fails that is probably due to an ITextRegion.EMPTY_REGION being provided for the object's significant text region. - */ - @BugTest("ACF-2605") - public void testFoldedPositions() { - Collection foldingRegions = getXtextTestUtil().get(IFoldingRegionProvider.class).getFoldingRegions(getDocument()); - for (DefaultFoldedPosition foldedPosition : Iterables.filter(foldingRegions, DefaultFoldedPosition.class)) { - try { - Assert.assertFalse("Illegal significant region for FoldedPosition " + foldedPosition, foldedPosition.computeCaptionOffset(getDocument()) < 0); - /* If the above assertion fails that is probably due to an ITextRegion.EMPTY_REGION being provided for the object's significant text region. */ - } catch (BadLocationException e) { - fail("Bad location for FoldedPosition: " + e.getMessage()); - } - } - } -} diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/hover/AbstractHoverTest.java b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/hover/AbstractHoverTest.java deleted file mode 100644 index 6e5703d433..0000000000 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/hover/AbstractHoverTest.java +++ /dev/null @@ -1,220 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.test.ui.hover; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.eclipse.emf.common.util.BasicEList; -import org.eclipse.emf.common.util.EList; -import org.eclipse.emf.ecore.ENamedElement; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EReference; -import org.eclipse.emf.ecore.EStructuralFeature; -import org.eclipse.xtext.ui.editor.hover.IEObjectHoverProvider; -import org.junit.Assert; - -import com.avaloq.tools.ddk.xtext.test.AbstractXtextTest; - - -/** - * Base class for hover tests. - */ -@SuppressWarnings("nls") -public abstract class AbstractHoverTest extends AbstractXtextTest { - - /** - * Set up the test by indexing the labels. - */ - @Override - protected void beforeAllTests() { - super.beforeAllTests(); - getTestInformation().putTestObject(AbstractHoverTest.class, new HashMap>()); // NOPMD LooseCoupling - buildHoverMap(getSemanticModel()); - } - - /** - * Returns {@link IEObjectHoverProvider} for hover functionality of the editor. - * - * @return the {@link IEObjectHoverProvider} class for hover functionality, never {@code null} - */ - protected IEObjectHoverProvider getHoverProvider() { - return getXtextTestUtil().get(IEObjectHoverProvider.class); - } - - /** - * Directory of semantic nodes indexed by the class of the represented semantic model node. - * - * @return directory of semantic nodes indexed by the class of the represented semantic model node, or {@code null} if none was set up - */ - @SuppressWarnings("unchecked") - protected Map> getHoverMap() { // NOPMD LooseCoupling - Object obj = getTestInformation().getTestObject(AbstractHoverTest.class); - if (obj instanceof Map) { - return (Map>) obj; // NOPMD LooseCoupling - } else { - return null; // NOPMD ReturnEmptyCollectionRatherThanNull - } - } - - /** - * Adds an element with a hover to the hover map. If there is no valid map, the method ends without adding anything. - * - * @param element - * the element of the model, must not be {@code null} - * @param hover - * the hover string of the element, must not be {@code null} - */ - private void addToHoverMap(final Object element, final String hover) { - Map> hoverMap = getHoverMap(); // NOPMD LooseCoupling - - if (hoverMap == null) { - return; - } - - if (!hoverMap.containsKey(element)) { - hoverMap.put(element, new ArrayList()); - } - hoverMap.get(element).add(hover); - } - - /** - * Build a directory of node hovers indexed by the {@link EObject}. - * - * @param model - * the model for which to build the hover map, must not be {@code null} - */ - private void buildHoverMap(final EObject model) { - // All contained features - List features = model.eClass().getEAllStructuralFeatures(); - for (EStructuralFeature feature : features) { - if (feature instanceof EReference && model.eIsSet(feature)) { - EList children = getFeatureValues(model, feature); - boolean referenceAdded = false; - IEObjectHoverProvider hoverProvider = getHoverProvider(); - for (EObject childModelElement : children) { - if (!childModelElement.eIsProxy()) { - buildHoverMap(childModelElement); - Object element = childModelElement.eClass(); - Object hover = hoverProvider.getHoverInfo(childModelElement, null, null).getInfo(); - if (element != null && hover != null) { - addToHoverMap(element, hover.toString()); - // also add the hover using the reference feature as key - if (!referenceAdded) { - addToHoverMap(feature, hover.toString()); - referenceAdded = true; - } - } - } - } - } - } - } - - /** - * Returns values of the given feature. - * - * @param model - * the model which the given feature belongs to, must not be {@code null} - * @param feature - * the feature of the model with one of many values, must not be {@code null} - * @return the values of the feature, never {@code null} - */ - @SuppressWarnings("unchecked") - private EList getFeatureValues(final EObject model, final EStructuralFeature feature) { - EList values = new BasicEList(); - if (feature.isMany()) { - values.addAll((EList) model.eGet(feature)); - } else { - values.add((EObject) model.eGet(feature, false)); - } - - return values; - } - - /** - * Tests whether there exists a hover for given element and that it contains given first line. - * - * @param element - * element of the model with hover, must not be {@code null} - * @param firstLine - * string which represents a first line of the hover of a given element, must not be {@code null} - */ - protected void assertHover(final ENamedElement element, final String firstLine) { - assertElementExistInHoverMap(element); - Assert.assertTrue("Element '" + element.toString() + "' must have first line of hover '" + firstLine + "'. " + "\n\nHoverMap contains:\n" - + getHoverMap().get(element), hasTextOnFirstLine(getHoverMap().get(element), firstLine)); - } - - /** - * Tests whether there exists a hover for a given element and that the first line does not contain the given text. - * - * @param element - * element of the model with hover, must not be {@code null} - * @param text - * string that must not be contained in the first line of the hover text, must not be {@code null} - */ - protected void assertHoverDoesNotContainText(final ENamedElement element, final String text) { - assertElementExistInHoverMap(element); - Assert.assertFalse("Element '" + element.toString() + "' first line of hover must not have '" + text + "'. " + "\n\nHoverMap contains:\n" - + getHoverMap().get(element), hasTextOnFirstLine(getHoverMap().get(element), text)); - } - - /** - * Assert that the element given exist in the hover map. - * - * @param element - * element of the model with hover, must not be {@code null} - */ - private void assertElementExistInHoverMap(final ENamedElement element) { - Assert.assertTrue("Element '" + element.toString() + "' must exist.", getHoverMap().containsKey(element)); - } - - /** - * Cleans the given string from HTML tags. - *

- * NOTE: The regular expression used to remove tags also matches strings with "<" and ">" characters (e.g. "Value is < 10 and > 0"). - *

- * - * @param text - * a string containing HTML tags, must not be {@code null} - * @return the string without HTML tags, never {@code null} - */ - private String removeHTMLTags(final String text) { - Pattern pattern = Pattern.compile("\\<[^>]*>"); //$NON-NLS-1$ - Matcher matcher = pattern.matcher(text); - return matcher.replaceAll(""); - } - - /** - * Checks whether there exist a hover containing the given text on the first line. - * - * @param hoverList - * a list of hovers for particular element type, must not be {@code null} - * @param textOnFirstLine - * a string representing the first line (or part) of the hover text, must not be {@code null} - * @return true, if there exists a hover from the list which contains the given text in the first line - */ - private boolean hasTextOnFirstLine(final List hoverList, final String textOnFirstLine) { - for (String hover : hoverList) { - String plainHover = removeHTMLTags(hover); - if (plainHover.contains(textOnFirstLine)) { - return true; - } - } - - return false; - } -} diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/hyperlinking/AbstractHyperlinkHelperTest.java b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/hyperlinking/AbstractHyperlinkHelperTest.java deleted file mode 100644 index bed12cbdd2..0000000000 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/hyperlinking/AbstractHyperlinkHelperTest.java +++ /dev/null @@ -1,214 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.test.ui.hyperlinking; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.NoSuchElementException; - -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.jface.text.hyperlink.IHyperlink; -import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable; -import org.eclipse.swtbot.swt.finder.results.Result; -import org.eclipse.xtext.nodemodel.ILeafNode; -import org.eclipse.xtext.nodemodel.util.NodeModelUtils; -import org.eclipse.xtext.resource.XtextResource; -import org.eclipse.xtext.ui.editor.hyperlinking.IHyperlinkHelper; -import org.eclipse.xtext.ui.editor.hyperlinking.XtextHyperlink; -import org.hamcrest.CoreMatchers; -import org.hamcrest.MatcherAssert; -import org.junit.Assert; - -import com.avaloq.tools.ddk.xtext.test.ui.AbstractXtextEditorTest; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; -import com.google.common.collect.Sets; - - -/** - * Base class for hyperlink helper tests. - */ -@SuppressWarnings("nls") -public abstract class AbstractHyperlinkHelperTest extends AbstractXtextEditorTest { - - private static final String OFFSET_MUST_BE_EQUAL = "Offset must be equal"; - private static final String NUMBER_OF_HYPERLINKS_MUST_BE_EQUAL = "Number of hyperlinks must be equal"; - /** The Constant LEAF_NOT_FOUND_VALUE is returned when a leaf node is not found. */ - protected static final int LEAF_NOT_FOUND_VALUE = -1; - - /** - * Checks if there is exactly one hyperlink at the specified offset. - * - * @param offset - * the position at which to look for a hyperlink - */ - protected void assertOffsetHasHyperlink(final int offset) { - Assert.assertEquals(OFFSET_MUST_BE_EQUAL, 1, getOffsetHyperlinks(offset).size()); - } - - /** - * Checks that there is no hyperlink at the specified offset. - * - * @param offset - * the position at which to look for hyperlinks - */ - protected void assertOffsetHasNoHyperlink(final int offset) { - Assert.assertEquals(OFFSET_MUST_BE_EQUAL, 0, getOffsetHyperlinks(offset).size()); - } - - /** - * Checks if there is exactly one hyperlink on the object marked by the given tag. - * - * @param tag - * The tag for which to find the offset where the hyperlink should be - */ - protected void assertHasHyperlink(final int tag) { - assertHasHyperlinks(tag, 1); - } - - /** - * Checks that there is no hyperlink on the object marked by the given tag. - * - * @param tag - * The tag for which to find the offset where the hyperlink should be - */ - protected void assertNoHyperlink(final int tag) { - assertHasHyperlinks(tag, 0); - } - - /** - * Checks if there is a given number of hyperlinks on the object marked by the given tag. - * - * @param tag - * the tag marking the object where the hyperlinks should be - * @param numberOfHyperlinks - * number of expected hyperlinks - */ - protected void assertHasHyperlinks(final int tag, final int numberOfHyperlinks) { - Assert.assertEquals(NUMBER_OF_HYPERLINKS_MUST_BE_EQUAL, numberOfHyperlinks, getHyperlinks(tag).size()); - } - - /** - * Checks if there is a hyperlink on the object marked by the given tag and that it points to the target URI. - * - * @param tag - * the tag marking the object where the hyperlink should be - * @param target - * the target URI pointed to by the hyperlink of the given tag - */ - protected void assertHasHyperlinks(final int tag, final URI target) { - Collection actualTargets = Sets.newLinkedHashSet(); - for (IHyperlink hyperlink : getHyperlinks(tag)) { - if (hyperlink instanceof XtextHyperlink) { - actualTargets.add(((XtextHyperlink) hyperlink).getURI()); - } - } - MatcherAssert.assertThat("The target must have items", actualTargets, CoreMatchers.hasItem(target)); - } - - /** - * Checks if there is a given number of hyperlinks in the specified source on the object marked by the given tag. - * - * @param resource - * the resource in which to look for hyperlinks, must not be {@code null} - * @param tag - * the tag marking the object where the hyperlinks should be - * @param numberOfHyperlinks - * number of expected hyperlinks - */ - protected void assertHasHyperlinks(final XtextResource resource, final int tag, final int numberOfHyperlinks) { - Assert.assertEquals(NUMBER_OF_HYPERLINKS_MUST_BE_EQUAL, numberOfHyperlinks, getHyperlinks(resource, tag).size()); - } - - /** - * Retrieves the hyperlinks found at a given offset. - * - * @param offset - * the position at which to look for hyperlinks - * @return a list of hyperlinks, never {@code null} - */ - protected List getOffsetHyperlinks(final int offset) { - return getOffsetHyperlinks(getXtextTestResource(), offset); - } - - /** - * Retrieves the hyperlinks found on the object marked by the given tag. - * - * @param tag - * the tag marking the object where the hyperlinks should be - * @return a list of hyperlinks, never {@code null} - */ - protected List getHyperlinks(final int tag) { - return getHyperlinks((XtextResource) getObjectForTag(tag).eResource(), tag); - } - - /** - * Retrieves the hyperlinks found in a given source at a given offset. - * - * @param resource - * the resource in which to look for hyperlinks, must not be {@code null} - * @param offset - * the position at which to look for hyperlinks - * @return a list of hyperlinks, never {@code null} - */ - protected List getOffsetHyperlinks(final XtextResource resource, final int offset) { - IHyperlink[] hyperlinks = UIThreadRunnable.syncExec(new Result() { - @Override - public IHyperlink[] run() { - return getTestUtil().get(IHyperlinkHelper.class).createHyperlinksByOffset(resource, offset, true); - } - }); - return hyperlinks != null ? Arrays.asList(hyperlinks) : new ArrayList(); - } - - /** - * Retrieves the hyperlinks found on the object marked by the given tag in the given source. - * - * @param resource - * the resource in which to look for hyperlinks, must not be {@code null} - * @param tag - * tag marking the object where the hyperlinks should be - * @return a list of hyperlinks, never {@code null} - */ - protected List getHyperlinks(final XtextResource resource, final int tag) { - return getOffsetHyperlinks(resource, getOffsetForTag(tag)); - } - - /** - * Gets the offset for given text by analyzing the parse tree and looking for leaf nodes having - * a text attribute matching given value. Returns the first instance found and an error value if - * no match found. - * - * @param model - * the model - * @param text - * the text - * @return the offset for text - */ - protected int getOffsetForText(final EObject model, final String text) { - Iterable parseTreeNodes = NodeModelUtils.getNode(model).getLeafNodes(); - - try { - ILeafNode result = Iterables.find(parseTreeNodes, new Predicate() { - @Override - public boolean apply(final ILeafNode input) { - return text.equals(input.getText()); - } - }); - return result.getOffset(); - } catch (NoSuchElementException e) { - return LEAF_NOT_FOUND_VALUE; - } - } -} diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/labeling/AbstractLabelingTest.java b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/labeling/AbstractLabelingTest.java deleted file mode 100644 index e5b728d927..0000000000 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/labeling/AbstractLabelingTest.java +++ /dev/null @@ -1,175 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.test.ui.labeling; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.eclipse.emf.common.util.BasicEList; -import org.eclipse.emf.common.util.EList; -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.ENamedElement; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EReference; -import org.eclipse.emf.ecore.EStructuralFeature; -import org.eclipse.jface.viewers.ILabelProvider; -import org.eclipse.xtext.util.Pair; -import org.eclipse.xtext.util.Tuples; -import org.junit.Assert; -import org.junit.Test; - -import com.avaloq.tools.ddk.xtext.test.AbstractXtextTest; - - -/** - * Test labels of a given input file which is read in during setUpLabelTest(). - */ -@SuppressWarnings("nls") -public abstract class AbstractLabelingTest extends AbstractXtextTest { - /** - * Returns a list of pairs with the expected {@link ENamedElement} and the corresponding label string. - * - * @return a list of pairs with the expected {@link ENamedElement} and the corresponding label string - */ - // TODO : make abstract when refactoring all tests (and change from Object to ENamedElement everywhere in this class). remove the suppresswarnings - @SuppressWarnings({"PMD.EmptyMethodInAbstractClassShouldBeAbstract", "PMD.ReturnEmptyCollectionRatherThanNull"}) - protected List> getExpectedElementLabels() { - return null; - } - - /** - * Tests that the expected elements and their labels are exactly identical to all elements of the default test resource. - */ - @Test - public void testLabels() { - if (getExpectedElementLabels() == null) { - return; // TODO: remove this check once all tests have been refactored - } - for (Pair elementLabel : getExpectedElementLabels()) { - if (elementLabel.getFirst() instanceof EClass) { - // TODO: remove this once all tests have been refactored - assertHasLabel(((EClass) elementLabel.getFirst()).getInstanceClass(), elementLabel.getSecond()); - } else { - assertHasLabel(elementLabel.getFirst(), elementLabel.getSecond()); - } - } - // assertLabelMapConsistsOf(getExpectedElementLabels()); // TODO : revisit and enable this once all tests have been refactored - } - - /** - * Set up the test by indexing the labels. - * - * @throws Exception - */ - @Override - protected void beforeAllTests() { - super.beforeAllTests(); - getTestInformation().putTestObject(AbstractLabelingTest.class, new HashMap>()); // NOPMD LooseCoupling - buildLabelMap(getSemanticModel()); - } - - private ILabelProvider getLabelProvider() { - return getXtextTestUtil().get(ILabelProvider.class); - } - - /** - * Directory of semantic nodes indexed by the class of the represented semantic model node. - * - * @return directory of semantic nodes indexed by the class of the represented semantic model node - */ - - @SuppressWarnings({"unchecked", "PMD.ReturnEmptyCollectionRatherThanNull"}) - private Map> getLabelMap() { // NOPMD LooseCoupling - Object obj = getTestInformation().getTestObject(AbstractLabelingTest.class); - if (obj instanceof Map) { - return (Map>) obj; // NOPMD LooseCoupling - } else { - return null; - } - } - - /** - * Assert that there exists a node for the given Class having the given label. - * - * @param element - * the element - * @param label - * the expected label - */ - protected void assertHasLabel(final Object element, final String label) { - Assert.assertTrue("Element '" + element.toString() + "' must exist.", getLabelMap().containsKey(element)); - Assert.assertTrue("Element '" + element.toString() + "' must have label '" + label + "'. LabelMap contains: " - + getLabelMap().get(element), getLabelMap().get(element).contains(label)); - } - - /** - * Adds an element with a label to the label map. - * - * @param element - * the element - * @param label - * the label string - */ - private void addToLabelMap(final Object element, final String label) { - if (!getLabelMap().containsKey(element)) { - getLabelMap().put(element, new ArrayList()); - } - getLabelMap().get(element).add(label); - } - - /** - * Build a directory of node labels indexed by the {@link ENamedElement}. - * - * @param model - * the model for which to build the label map - */ - @SuppressWarnings("unchecked") - private void buildLabelMap(final EObject model) { - // Allow testing root container level - String rootLabel = getLabelProvider().getText(model); - addToLabelMap(model.eClass().getInstanceClass(), rootLabel); - // All contained features - List features = model.eClass().getEAllStructuralFeatures(); - for (EStructuralFeature feature : features) { - if (!model.eIsSet(feature)) { - continue; - } - if (feature instanceof EReference) { - EList children = new BasicEList(); - if (feature.isMany()) { - children.addAll((EList) model.eGet(feature)); - } else { - children.add((EObject) model.eGet(feature, false)); - } - boolean referenceAdded = false; - for (EObject childModelElement : children) { - if (!childModelElement.eIsProxy() && model.equals(childModelElement.eContainer())) { // ignore crossreferenced objects - buildLabelMap(childModelElement); - Object element = childModelElement.eClass().getInstanceClass(); // TODO : change to EClass once all tests are refactored - String label = getLabelProvider().getText(childModelElement); - addToLabelMap(element, label); - // also add the label using the reference feature as key - if (!referenceAdded) { - addToLabelMap(feature, label); - referenceAdded = true; - } - } - } - } else { - // TODO : what to do with unbounded EAttribute? -> decide also in LabelProvider - String label = getLabelProvider().getText(Tuples.create(model, feature)); - addToLabelMap(feature, label); - } - } - } -} diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/occurrences/AbstractOccurrencesTest.java b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/occurrences/AbstractOccurrencesTest.java deleted file mode 100644 index a1e70d99c8..0000000000 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/occurrences/AbstractOccurrencesTest.java +++ /dev/null @@ -1,243 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.test.ui.occurrences; - -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertSame; - -import java.util.Set; - -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.emf.common.util.WrappedException; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.IDocument; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotEclipseEditor; -import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotEditor; -import org.eclipse.swtbot.swt.finder.keyboard.Keystrokes; -import org.eclipse.swtbot.swt.finder.waits.DefaultCondition; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.texteditor.IDocumentProvider; -import org.eclipse.ui.texteditor.ITextEditor; -import org.eclipse.xtext.ui.editor.occurrences.Messages; -import org.junit.After; -import org.junit.Before; - -import com.avaloq.tools.ddk.test.core.util.JobChangeListener; -import com.avaloq.tools.ddk.xtext.test.ui.AbstractXtextUiTest; -import com.google.common.collect.Sets; - - -/** - * Tests xtext editor occurrences. - */ -public abstract class AbstractOccurrencesTest extends AbstractXtextUiTest { - - private static final char SEMANTIC_MARKER_CODE = 's'; - private static final char CURSOR_MARKER_CODE = 'c'; - private static final char NOSEMANTIC_MARKER_CODE = 'n'; - private static final char MARKER = '#'; - private static final int TIMEOUT_FOR_MARKING = 4000; - private static final Color NO_COLOR = null; - private final JobChangeListener jobChangeListener = new JobChangeListener(); - - /** - * Mark cursor position. - * - * @return the cursor marker, never {@code null} - */ - public String cursor() { - return String.valueOf(MARKER) + CURSOR_MARKER_CODE + MARKER; - } - - /** - * Mark position for semantic occurrence. - * - * @return the semantic occurrence marker, never {@code null} - */ - public String semantic() { - return String.valueOf(MARKER) + SEMANTIC_MARKER_CODE + MARKER; - } - - /** - * Mark position for no semantic occurrence. - * - * @return the marker with no semantic occurrence, never {@code null} - */ - public String noSemantic() { - return String.valueOf(MARKER) + NOSEMANTIC_MARKER_CODE + MARKER; - } - - /** - * Stores occurrences to be checked. - */ - private static final class OccurrencesToCheck { - private int cursorOffset; - private final Set semanticMarkers = Sets.newHashSet(); - private final Set noSemanticMarkers = Sets.newHashSet(); - - /** - * Set where the cursor should be placed to test occurrences. - * - * @param offset - * cursor offset - */ - void setCursor(final int offset) { - this.cursorOffset = offset; - } - - /** - * Semantic occurrences. - * - * @param offset - * cursor offset - */ - void addSemanticOccurrence(final int offset) { - semanticMarkers.add(offset); - } - - /** - * No semantic occurrences. - * - * @param offset - * cursor offset - */ - void addNoSemanticOccurence(final int offset) { - noSemanticMarkers.add(offset); - } - } - - /** - * {@inheritDoc} - */ - @Override - protected void addKernelSourceToWorkspace(final String sourceFileName, final CharSequence sourceContent) { - - OccurrencesToCheck occurrences = (OccurrencesToCheck) getTestInformation().getTestObject(OccurrencesToCheck.class); - if (occurrences == null) { - occurrences = new OccurrencesToCheck(); - getTestInformation().putTestObject(OccurrencesToCheck.class, occurrences); - } - StringBuilder content = new StringBuilder(); - int pos = 0; - int originalLength = sourceContent.length(); - while (pos < originalLength) { - char ch = sourceContent.charAt(pos++); - if (ch == MARKER && pos < originalLength - 2 && sourceContent.charAt(pos + 1) == MARKER) { - ch = sourceContent.charAt(pos); - if (ch == SEMANTIC_MARKER_CODE) { - occurrences.addSemanticOccurrence(content.length()); - } else if (ch == NOSEMANTIC_MARKER_CODE) { - occurrences.addNoSemanticOccurence(content.length()); - } else if (ch == CURSOR_MARKER_CODE) { - if (occurrences.cursorOffset != 0) { - throw new WrappedException("Cursor can be set only once", null); //$NON-NLS-1$ - } - occurrences.setCursor(content.length()); - } else { - throw new WrappedException("Invalid marker in the test", null); //$NON-NLS-1$ - } - pos += 2; - ch = sourceContent.charAt(pos++); - } - content.append(ch); - } - super.addKernelSourceToWorkspace(sourceFileName, content); - - } - - /** - * Sets up the {@link JobChangeListener}. - */ - @Before - public void setUpJobListener() { - Job.getJobManager().addJobChangeListener(jobChangeListener); - } - - /** - * Tears down the {@link JobChangeListener}. - */ - @After - public void tearDownJobListener() { - Job.getJobManager().removeJobChangeListener(jobChangeListener); - jobChangeListener.reset(); - } - - private final DefaultCondition occurenceJobCondition = new DefaultCondition() { - @Override - public boolean test() { - return jobChangeListener.isJobDone(Messages.OccurrenceMarker_MarkOccurrenceJob_title); - } - - @Override - public String getFailureMessage() { - return "Error waiting for occurrences"; //$NON-NLS-1$ - } - }; - - /** - * Tests occurrences. - * - * @throws BadLocationException - * if thrown means bad test - */ - public void testOccurrences() throws BadLocationException { - // Occurrence job starts after we open an editor, need to wait - getBot().waitUntil(occurenceJobCondition, TIMEOUT_FOR_MARKING); - SWTBotEditor editorBot = getBot().activeEditor(); - SWTBotEclipseEditor eBot = editorBot.toTextEditor(); - - OccurrencesToCheck occurrencesMap = (OccurrencesToCheck) getTestInformation().getTestObject(OccurrencesToCheck.class); - - IEditorPart editorPart = editorBot.getReference().getEditor(true); - ITextEditor editor = editorPart.getAdapter(ITextEditor.class); - IDocumentProvider provider = editor.getDocumentProvider(); - IDocument document = provider.getDocument(editorPart.getEditorInput()); - int cursorLine = document.getLineOfOffset(occurrencesMap.cursorOffset); - int cursorColumn = occurrencesMap.cursorOffset - document.getLineOffset(cursorLine); - - // Reset the listener and trigger the second occurrence job - jobChangeListener.reset(); - eBot.navigateTo(cursorLine, cursorColumn); - eBot.pressShortcut(Keystrokes.LEFT); - getBot().waitUntil(occurenceJobCondition, TIMEOUT_FOR_MARKING); - - for (int offset : occurrencesMap.semanticMarkers) { - Color color = getColorAtOffset(eBot, document, offset); - assertNotSame("Semantical reference selection colored", color, NO_COLOR); //$NON-NLS-1$ - } - - for (int offset : occurrencesMap.noSemanticMarkers) { - Color color = getColorAtOffset(eBot, document, offset); - assertSame("No semantical reference selection should not be colored", color, NO_COLOR); //$NON-NLS-1$ - } - } - - /** - * Returns background color at the given offset in the given document. - * - * @param eBot - * editor bot, may be {@code null} - * @param document - * document, may be {@code null} - * @param offset - * offset in the document - * @return color, may be {@code null} - * @throws BadLocationException - * if offset is not valid for the document - */ - private Color getColorAtOffset(final SWTBotEclipseEditor eBot, final IDocument document, final int offset) throws BadLocationException { - int line = document.getLineOfOffset(offset); - int column = offset - document.getLineOffset(line); - return eBot.getStyle(line, column).background; - } - -} diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/outline/AbstractOutlineTest.java b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/outline/AbstractOutlineTest.java deleted file mode 100644 index 4aed592467..0000000000 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/outline/AbstractOutlineTest.java +++ /dev/null @@ -1,268 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.test.ui.outline; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; - -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.ENamedElement; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EStructuralFeature; -import org.eclipse.osgi.util.NLS; -import org.eclipse.xtext.ui.editor.outline.IOutlineNode; -import org.eclipse.xtext.ui.editor.outline.IOutlineTreeProvider; -import org.eclipse.xtext.ui.editor.outline.impl.EObjectNode; -import org.eclipse.xtext.ui.editor.outline.impl.EStructuralFeatureNode; -import org.eclipse.xtext.util.concurrent.IUnitOfWork; -import org.junit.Assert; -import org.junit.Test; - -import com.avaloq.tools.ddk.xtext.test.ui.AbstractXtextEditorTest; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; - - -/** - * Test the outline structure of an input file. - */ -@SuppressWarnings("nls") -public abstract class AbstractOutlineTest extends AbstractXtextEditorTest { - /** - * Returns a list of the elements expected in the outline of the default test resource. - * - * @return a list of the expected elements - */ - // TODO : make this abstract once all tests have been refactored (and change all Object to ENamedElement in this class) - protected List getExpectedElements() { - return null; // NOPMD ReturnEmptyCollectionRatherThanNull - } - - /** - * Tests that the outline of the default test resource contains exactly the expected elements. - */ - @Test - public void testOutline() { - if (getExpectedElements() == null) { - return; // TODO: remove this once all tests have been refactored - } - for (ENamedElement element : getExpectedElements()) { - assertHasOutlineNode(element); - } - // assertOutlineNodeTreeConsistsOf(getExpectedElements()); // TODO : enable this once all tests have been refactored - } - - /** - * Returns a directory of outline nodes indexed by the class of the represented semantic model node. - * - * @return directory of outline nodes indexed by the class of the represented semantic model node - */ - @SuppressWarnings({"unchecked", "PMD.ReturnEmptyCollectionRatherThanNull"}) - private Map> getOutlineMap() { // NOPMD LooseCoupling - Object obj = getTestInformation().getTestObject(IOutlineNode.class); - if (obj instanceof Map) { - return (Map>) obj; // NOPMD LooseCoupling - } else { - return null; - } - } - - /** - * Set up the test by reading the input file and generating the outline tree. - */ - @Override - protected final void beforeAllTests() { - super.beforeAllTests(); - IOutlineTreeProvider provider = getXtextTestUtil().get(IOutlineTreeProvider.class); - getTestInformation().putTestObject(IOutlineNode.class, new HashMap>()); // NOPMD LooseCoupling - buildOutlineMap(provider.createRoot(getDocument())); - } - - /** - * Assert that the outline tree has nodes for the given class. - * - * @param object - * the object for which outline nodes are expected. - */ - protected void assertHasOutlineNode(final Object object) { - Object key = object; - if (object instanceof EClass) { - key = ((EClass) object).getInstanceClass(); - } - Assert.assertTrue("Outline must contain element '" + object.toString() + "'.", getOutlineMap().containsKey(key)); - Assert.assertFalse("Outline must contain element '" + object.toString() + "'.", getOutlineMap().get(key).isEmpty()); - } - - /** - * Asserts that the outline tree has any node with the given name. - * - * @param nodeName - * the name of the node expected in the outline. - * @return the {@link IOutlineNode} with the given name, {@code null} if it does not exist - */ - protected IOutlineNode assertHasOutlineNode(final String nodeName) { - return assertHasOutlineNode(nodeName, null); - } - - /** - * Asserts that the outline tree has a node with the given name and type. - * - * @param nodeName - * the name of the node expected in the outline. - * @param nodeType - * the type of the node expected in the outline. - * @return the {@link IOutlineNode} with the given name, {@code null} if it does not exist - */ - protected IOutlineNode assertHasOutlineNode(final String nodeName, final String nodeType) { - IOutlineTreeProvider provider = getXtextTestUtil().get(IOutlineTreeProvider.class); - IOutlineNode field = findNode(provider.createRoot(getDocument()), nodeName, nodeType); - Assert.assertNotNull("Outline must contain element '" + nodeName + "'.", field); - return field; - } - - /** - * Asserts that the outline tree has a node with the given name, type and parent. - * - * @param nodeName - * the name of the node expected in the outline. - * @param nodeType - * the type of the node expected in the outline, may be {@code null} if only the name of the node is to be tested - * @param parentName - * the name of the parent - */ - protected void assertHasOutlineNode(final String nodeName, final String nodeType, final String parentName) { - IOutlineNode field = assertHasOutlineNode(nodeName, nodeType); - IOutlineNode parent = field.getParent(); - Assert.assertEquals("The element '" + nodeName + "' doesn't belong to the '" + parentName + "' group.", parentName, parent.getText().toString()); - } - - /** - * Recursively searches for a node with the given name and type. - * - * @param node - * a root node of a subtree where the desired node is searched for - * @param nodeName - * the name of the node to search, must not be {@code null} - * @param nodeType - * the name of the type of the node to search, may be {@code null} if only the name of the node is to be tested - * @return - * a node with the given name and type (if specified). If such a node is not found, returns null. - */ - private IOutlineNode findNode(final IOutlineNode node, final String nodeName, final String nodeType) { - IOutlineNode fieldNode = null; - String[] textParts = node.getText().toString().split(":"); - - if (nodeName.equals(textParts[0].trim()) && (nodeType == null || (textParts.length > 1 && nodeType.equals(textParts[1].trim())))) { - fieldNode = node; - } else { - List children = node.getChildren(); - for (IOutlineNode child : children) { - fieldNode = findNode(child, nodeName, nodeType); - if (fieldNode != null) { - break; - } - } - } - - return fieldNode; - } - - /** - * Inspects the outline nodes and checks that given condition applies to at least one of the represented model objects. - * - * @param - * the generic type - * @param clazz - * the clazz - * @param predicate - * the predicate - */ - protected void assertEObjectInOutlineNodesExists(final Class clazz, final Predicate predicate) { - final List result = Lists.newArrayList(); - for (final IOutlineNode n : getOutlineMap().get(clazz)) { - result.add(n.readOnly(new IUnitOfWork() { - @Override - @SuppressWarnings("unchecked") - public T exec(final EObject state) throws Exception { // NOPMD - return (T) state; - } - })); - } - try { - Assert.assertNotNull(NLS.bind("At least one outline node represents an object of type \"{0}\"", clazz.getName()), Iterables.find(result, predicate)); - } catch (NoSuchElementException e) { - Assert.fail(NLS.bind("Could not find an object of type \"{0}\" in outline", clazz.getName())); - } - } - - /** - * Assert that the outline tree consists only of classes contained in the given array of Classes. - * - * @param classes - * the array of classes which constitute the entire outline tree. - */ - protected void assertOutlineNodeTreeConsistsOf(final Object... classes) { - List outlineMapKeySet = new ArrayList(getOutlineMap().keySet()); - outlineMapKeySet.removeAll(Arrays.asList(classes)); - // assert that only EStructuralFeatures remain - for (Object object : outlineMapKeySet) { - Assert.assertTrue("All remaining objects in outlineMap must be of type EStructuralFeature. Found: " + object, object instanceof EStructuralFeature); - } - } - - /** - * Add the given outline node to the outline map. - * - * @param node - * IOutlineNode to add. - */ - private void addToOutlineMap(final IOutlineNode node) { - EStructuralFeature eFeature = null; - if (node instanceof EObjectNode) { - eFeature = ((EObjectNode) node).getEObject(getTestSource().getXtextResource()).eContainingFeature(); - // TODO : remove the following part once all tests have been refactored - Class nodeClazz = ((EObjectNode) node).getEClass().getInstanceClass(); - if (!getOutlineMap().containsKey(nodeClazz)) { - getOutlineMap().put(nodeClazz, new ArrayList()); - } - getOutlineMap().get(nodeClazz).add(node); - } else if (node instanceof EStructuralFeatureNode) { - eFeature = ((EStructuralFeatureNode) node).getEStructuralFeature(); - } - if (eFeature == null) { - return; - } - if (!getOutlineMap().containsKey(eFeature)) { - getOutlineMap().put(eFeature, new ArrayList()); - } - getOutlineMap().get(eFeature).add(node); - } - - /** - * Traverse the outline tree node recursively and build up the outlineMap. - * - * @param node - * the outline tree node to traverse. - */ - private void buildOutlineMap(final IOutlineNode node) { - addToOutlineMap(node); - // add node's children - List children = node.getChildren(); - for (IOutlineNode child : children) { - buildOutlineMap(child); - } - } -} diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/outline/AbstractOutlineViewTest.java b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/outline/AbstractOutlineViewTest.java deleted file mode 100644 index 6d9e3ee9dc..0000000000 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/outline/AbstractOutlineViewTest.java +++ /dev/null @@ -1,59 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.test.ui.outline; - -import static org.junit.Assert.assertNotNull; - -import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotView; -import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem; - -import com.avaloq.tools.ddk.test.ui.swtbot.util.SwtBotViewUtil; -import com.avaloq.tools.ddk.xtext.test.ui.AbstractXtextUiTest; - - -/** - * An abstract base class to test the outline view on the UI level. - */ -public abstract class AbstractOutlineViewTest extends AbstractXtextUiTest { - - /** - * Expands the given {@link SWTBotTreeItem} if it is not expanded already. - * - * @param treeItem - * the tree item to be expanded - */ - protected void expandIfNotExpanded(final SWTBotTreeItem treeItem) { - if (!treeItem.isExpanded()) { - treeItem.expand(); - } - } - - /** - * Opens the outline view of the currently active editor. - * - * @return the {@link SWTBotView} representing the outline view - * @throw WidgetNotFoundException if there is no active editor - */ - @SuppressWarnings("nls") - // CHECKSTYLE:CONSTANTS-OFF - protected SWTBotView openOutlineViewOfActiveEditor() { - getBot().menu("Window").menu("Show View").menu("Outline").click(); - SWTBotView outlineView = getBot().viewById("org.eclipse.ui.views.ContentOutline"); - assertNotNull("outline view present", outlineView); - - SwtBotViewUtil.waitUntilViewIsLoaded(outlineView); - outlineView.setFocus(); - - return outlineView; - } - // CHECKSTYLE:CONSTANTS-ON - -} diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/quickfix/AbstractQuickFixTest.java b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/quickfix/AbstractQuickFixTest.java deleted file mode 100644 index 67c11897d1..0000000000 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/quickfix/AbstractQuickFixTest.java +++ /dev/null @@ -1,457 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.test.ui.quickfix; - -import static org.junit.Assert.assertEquals; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.xtext.resource.XtextSyntaxDiagnostic; -import org.eclipse.xtext.ui.editor.model.edit.IModificationContext; -import org.eclipse.xtext.ui.editor.model.edit.IssueModificationContext; -import org.eclipse.xtext.ui.editor.quickfix.IssueResolution; -import org.eclipse.xtext.ui.editor.quickfix.IssueResolutionProvider; -import org.eclipse.xtext.validation.Issue; -import org.hamcrest.MatcherAssert; -import org.hamcrest.text.IsEqualCompressingWhiteSpace; -import org.junit.Assert; - -import com.avaloq.tools.ddk.check.runtime.quickfix.ICoreModificationContext; -import com.avaloq.tools.ddk.check.runtime.ui.quickfix.CoreIssueModificationContext; -import com.avaloq.tools.ddk.check.runtime.ui.quickfix.IssueResolutionWrapper; -import com.avaloq.tools.ddk.xtext.test.ui.AbstractXtextEditorTest; -import com.avaloq.tools.ddk.xtext.ui.util.UiThreadDispatcher; -import com.google.common.base.Function; -import com.google.common.base.Predicates; -import com.google.common.collect.Iterables; -import com.google.common.collect.Ordering; - - -/** - * Test existence and application of QuickFixes for a given language. - * Subclasses provide a validation test file which contains the model the test is based on. - * The name of the quick fix test file must be provided in the method getQuickFixFileName(). - * Besides overriding the abstract method getQuickFixFileName(), subclasses have to implement - * the test method itself which tests for existence and resolutions of the diagnostic issues. - */ -@SuppressWarnings({"PMD.UseObjectForClearerAPI", "nls"}) -public abstract class AbstractQuickFixTest extends AbstractXtextEditorTest { - - private IssueResolutionProvider getIssueResolutionProvider() { - return getXtextTestUtil().get(IssueResolutionProvider.class); - } - - /** - * Results of the diagnostic, a list of Issue. - * - * @return the list of issues - */ - private List getIssueList() { - return getXtextTestUtil().getIssues(getDocument()); - } - - /** - * Set up test by opening a text editor with the validation test file and triggering validation. - */ - @Override - protected void beforeAllTests() { - super.beforeAllTests(); - closeEditor(getEditor(), false); - } - - @Override - protected void beforeEachTest() { - super.beforeEachTest(); - if (getTestSource() != null) { - openEditor(getTestSourceFileName()); - } - } - - @Override - protected void afterEachTest() { - super.afterEachTest(); - closeEditor(getEditor(), false); - } - - /** - * Assert that the diagnostic result (issueList) contains an Issue of the given issueCode. - * - * @param issueCode - * the code of the expected issue, may be {@code null} - */ - protected void assertHasIssue(final String issueCode) { - Assert.assertFalse("Issue " + issueCode + " is empty", issuesWith(issueCode).isEmpty()); - } - - /** - * Assert that diagnostic result (issueList) contains a QuickFix of the given issueCode. - * - * @param issueCode - * the code of the issue for which a quickfix is expected to exist, may be {@code null} - */ - protected void assertHasQuickFix(final String issueCode) { - Assert.assertFalse("No resolutions found for issue " + issueCode, resolutionsFor(issueCode).isEmpty()); - } - - /** - * Assert that diagnostic result (issueList) contains a QuickFix of the given issueCode. - * - * @param issueCode - * the code of the issue for which a quickfix is expected to exist, may be {@code null} - * @param quickfixLabel - * the label of the quickfix, may be {@code null} - */ - protected void assertHasQuickFix(final String issueCode, final String quickfixLabel) { - Assert.assertFalse("No resolutions found for issue " + issueCode, resolutionsFor(issueCode, quickfixLabel).isEmpty()); - } - - /** - * Assert that diagnostic result (issueList) contains the exact number of the given quickfix label in the proposal of the given issueCode. - * - * @param issueCode - * the code of the issue for which a quickfix is expected to exist, may be {@code null} - * @param quickfixLabel - * the label of the quickfix, may be {@code null} - * @param numberOfQuickfixProposal - * the number of expected quickfix proposal, must not be {@code null} - */ - protected void assertHasQuickFix(final String issueCode, final String quickfixLabel, final int numberOfQuickfixProposal) { - Assert.assertEquals("Number of resolutions found for issue " + issueCode - + " does not match the expected number of quickfix proposal", resolutionsFor(issueCode, quickfixLabel).size(), numberOfQuickfixProposal); - } - - /** - * Assert that diagnostic result (issueList) of a given source does not contain a QuickFix of the given issueCode. - * - * @param sourceFileName - * the source file name, must not be {@code null} - * @param sourceFileContent - * the source file content, must not be {@code null} - * @param issueCode - * the issue code for which no QuickFix must exist, must not be {@code null} - */ - protected void assertNoQuickFix(final String sourceFileName, final String sourceFileContent, final String issueCode) { - assertNoQuickFix(sourceFileName, sourceFileContent, issueCode, null); - } - - /** - * Assert that diagnostic result (issueList) of a given source does not contain a QuickFix of the given issueCode. - * - * @param sourceFileName - * the source file name, must not be {@code null} - * @param sourceFileContent - * the source file content, must not be {@code null} - * @param issueCode - * the issue code for which no QuickFix must exist, must not be {@code null} - * @param quickfixLabel - * the quickfix label, may be {@code null} - */ - protected void assertNoQuickFix(final String sourceFileName, final String sourceFileContent, final String issueCode, final String quickfixLabel) { - createTestSource(sourceFileName, sourceFileContent); - openEditor(sourceFileName); - try { - Assert.assertTrue("No resolutions expected for issue " + issueCode + " on source " + sourceFileName, resolutionsFor(issueCode, quickfixLabel).isEmpty()); - } finally { - closeEditor(getEditor(), false); - } - } - - /** - * Assert that application of the quick fixes for the given issueCode resolve the problem. - * - * @param issueCode - * the code of the issue that should have been fixed, may be {@code null} - */ - protected void assertQuickFixSuccessful(final String issueCode) { - assertQuickFixSuccessful(issueCode, null); - } - - /** - * Assert that application of the quick fixes for the given issueCode and label resolve the problem. - * - * @param issueCode - * the code of the issue that should have been fixed, may be {@code null} - * @param quickfixLabel - * the label of the quickfix, may be {@code null} - */ - protected void assertQuickFixSuccessful(final String issueCode, final String quickfixLabel) { - for (final IssueResolution issueResolution : sortResolutionsByOffsetDecreasing(resolutionsFor(issueCode, quickfixLabel))) { - UiThreadDispatcher.dispatchAndWait(new Runnable() { - @Override - public void run() { - issueResolution.apply(); - } - }); - } - waitForValidation(); - Assert.assertTrue("Resolutions for issue " + issueCode + " with quickfix " + quickfixLabel - + "are not empty", resolutionsFor(issueCode, quickfixLabel).isEmpty()); - } - - /** - * Sort issue resolutions by offset in document decreasing. - * - * @param resolutions - * resolutions to sort - * @return a copy of {@code resolutions} sorted by offset in document decreasing - */ - protected List sortResolutionsByOffsetDecreasing(final List resolutions) { - - final Function getLocationFunction = new Function() { - - @Override - public Integer apply(final IssueResolution from) { - if (from != null) { - if (from instanceof IssueResolutionWrapper) { - ICoreModificationContext context = ((IssueResolutionWrapper) from).getCoreModificationContext(); - if (context instanceof CoreIssueModificationContext) { - return ((CoreIssueModificationContext) context).getIssue().getOffset(); - } - } else { - IModificationContext context = from.getModificationContext(); - if (context instanceof IssueModificationContext) { - return ((IssueModificationContext) context).getIssue().getOffset(); - } - } - } - return Integer.MIN_VALUE; - } - }; - Ordering ordering = Ordering.natural().onResultOf(getLocationFunction).reverse(); - return new ArrayList(ordering.sortedCopy(resolutions)); - } - - /** - * Assert that the test source has no syntax error. - */ - protected void assertNoSyntaxError() { - Assert.assertFalse("The source has syntax errors", Iterables.any(getTestSource().getXtextResource().getErrors(), Predicates.instanceOf(XtextSyntaxDiagnostic.class))); - } - - /** - * Assert that application of the target quickfix was successful and the text of the resulting document equals the expected text. - * The method ensures that there is one and only one quickfix for the given issue code with the given label. - * - * @param issueCode - * the code of the issue that should have been fixed, may be {@code null} - * @param quickfixLabel - * the label of the quick fix that should be applied, may be {@code null} - * @param sourceFileName - * the name of the source being tested - * @param sourceContent - * the content of the source being tested - * @param expectedContent - * the name of the file containing the expected result after applying the quick fix - */ - protected void assertQuickFixExistsAndSuccessfulInKernelSource(final String issueCode, final String quickfixLabel, final String sourceFileName, final String sourceContent, final String expectedContent) { - assertQuickFixExistsAndSuccessful(issueCode, quickfixLabel, sourceFileName, sourceContent, expectedContent, false); - } - - /** - * Assert that application of the target quickfix was successful and the text of the resulting document equals the expected text (ignoring formatting). - * The method ensures that there is one and only one quickfix for the given issue code with the given label. - * - * @param issueCode - * the code of the issue that should have been fixed, may be {@code null} - * @param quickfixLabel - * the label of the quick fix that should be applied, may be {@code null} - * @param sourceFileName - * the name of the source being tested - * @param sourceContent - * the content of the source being tested - * @param expectedContent - * the name of the file containing the expected result after applying the quick fix - */ - protected void assertQuickFixExistsAndSuccessfulInKernelSourceIgnoreFormatting(final String issueCode, final String quickfixLabel, final String sourceFileName, final String sourceContent, final String expectedContent) { - assertQuickFixExistsAndSuccessful(issueCode, quickfixLabel, sourceFileName, sourceContent, expectedContent, true); - } - - /** - * Assert that application of the target quickfix was successful and the text of the resulting document equals the expected text. - * The method ensures that there is one and only one quickfix for the given issue code with the given label. - * - * @param issueCode - * the code of the issue that should have been fixed, may be {@code null} - * @param quickfixLabel - * the label of the quick fix that should be applied, may be {@code null} - * @param sourceFileName - * the name of the source being tested - * @param sourceContent - * the content of the source being tested - * @param expectedContent - * the name of the file containing the expected result after applying the quick fix - */ - protected void assertQuickFixExistsAndSuccessfulInCustomerSource(final String issueCode, final String quickfixLabel, final String sourceFileName, final String sourceContent, final String expectedContent) { - assertQuickFixExistsAndSuccessful(issueCode, quickfixLabel, CUSTOMER_SOURCE_PREFIX.concat(sourceFileName), sourceContent, expectedContent, false); - } - - /** - * Assert that application of the target quickfix was successful and the text of the resulting document equals the expected text (ignoring formatting). - * The method ensures that there is one and only one quickfix for the given issue code with the given label. - * - * @param issueCode - * the code of the issue that should have been fixed, may be {@code null} - * @param quickfixLabel - * the label of the quick fix that should be applied, may be {@code null} - * @param sourceFileName - * the name of the source being tested - * @param sourceContent - * the content of the source being tested - * @param expectedContent - * the name of the file containing the expected result after applying the quick fix - */ - protected void assertQuickFixExistsAndSuccessfulInCustomerSourceIgnoreFormatting(final String issueCode, final String quickfixLabel, final String sourceFileName, final String sourceContent, final String expectedContent) { - assertQuickFixExistsAndSuccessful(issueCode, quickfixLabel, CUSTOMER_SOURCE_PREFIX.concat(sourceFileName), sourceContent, expectedContent, true); - } - - /** - * Assert that application of the target quickfix was successful and the text of the resulting document equals the expected text. - * The method ensures that there is one and only one quickfix for the given issue code with the given label. - * - * @param issueCode - * the code of the issue that should have been fixed, may be {@code null} - * @param quickfixLabel - * the label of the quick fix that should be applied, may be {@code null} - * @param sourceFileName - * the name of the source being tested - * @param sourceContent - * the content of the source being tested - * @param expectedContent - * the name of the file containing the expected result after applying the quick fix - * @param ignoreFormatting - * ignore formatting - */ - private void assertQuickFixExistsAndSuccessful(final String issueCode, final String quickfixLabel, final String sourceFileName, final String sourceContent, final String expectedContent, final boolean ignoreFormatting) { - createTestSource(sourceFileName, sourceContent); - openEditor(sourceFileName); - assertQuickFixExistsAndSuccessful(issueCode, quickfixLabel, expectedContent, ignoreFormatting); - closeEditor(getEditor(), false); - } - - /** - * Assert that application of the target quickfix was successful and the text of the resulting document equals the expected text. - * The method ensures that there is one and only one quickfix for the given issue code with the given label. - * - * @param issueCode - * the code of the issue that should have been fixed, may be {@code null} - * @param quickfixLabel - * the label of the quick fix that should be applied, may be {@code null} - * @param expectedContent - * the name of the file containing the expected result after applying the quick fix - * @param ignoreFormatting - * ignore formatting - */ - private void assertQuickFixExistsAndSuccessful(final String issueCode, final String quickfixLabel, final String expectedContent, final boolean ignoreFormatting) { - // Assert amount of quickfixes - int resolutionCount = resolutionsFor(issueCode, quickfixLabel).size(); - Assert.assertEquals(String.format("There must be exactly one quickfix with label '%s' for issue '%s', but found '%d'.", quickfixLabel, issueCode, resolutionCount), resolutionCount, 1); - // Apply quickfix - UiThreadDispatcher.dispatchAndWait(new Runnable() { - @Override - public void run() { - List resolutions = resolutionsFor(issueCode, quickfixLabel); - if (!resolutions.isEmpty()) { - resolutions.get(0).apply(); - } - } - }); - waitForValidation(); - Assert.assertTrue("Resolutions for issue " + issueCode + " with quickfix " + quickfixLabel - + "are not empty", resolutionsFor(issueCode, quickfixLabel).isEmpty()); - String actualContent = getDocument().get(); - assertQuickFixProducesExpectedOutput(expectedContent, actualContent, ignoreFormatting); - } - - /** - * Assert that quick fix produces expected output. - * - * @param expectedContent - * the expected content - * @param actualContent - * the actual content - * @param ignoreFormatting - * the ignore formatting - */ - private void assertQuickFixProducesExpectedOutput(final String expectedContent, final String actualContent, final boolean ignoreFormatting) { - String message = "Quickfix didn't produce the expected output."; - String expected = expectedContent.replaceAll(CR_LF, LF); - String actual = actualContent.replaceAll(CR_LF, LF); - if (ignoreFormatting) { - MatcherAssert.assertThat(message, actual, IsEqualCompressingWhiteSpace.equalToCompressingWhiteSpace(expected)); - } else { - assertEquals(message, expected, actual); - } - } - - /** - * Finds all issues with a specific issue code. - * - * @param issueCode - * to filter for, may be {@code null} - * @return {@link List} of issues with a specific code - */ - private List issuesWith(final String issueCode) { - List issues = new ArrayList(); - if (issueCode == null) { - return issues; - } - for (Issue issue : getIssueList()) { - if (issueCode.equals(issue.getCode())) { - issues.add(issue); - } - } - return issues; - } - - /** - * Finds all resolutions for issues with a specific issue code. - * - * @param issueCode - * to find resolutions for, may be {@code null} - * @return {@link List} of resolutions for issues with a specific code - */ - private List resolutionsFor(final String issueCode) { - return resolutionsFor(issueCode, null); - } - - /** - * Finds all resolutions for issues with a specific issue code. - * - * @param issueCode - * to find resolutions for, may be {@code null} - * @param quickfixLabel - * to find resolutions for, may be {@code null} - * @return {@link List} of resolutions for issues with a specific code - */ - private List resolutionsFor(final String issueCode, final String quickfixLabel) { - final List resolutions = new ArrayList(); - - for (final Issue issue : issuesWith(issueCode)) { - UiThreadDispatcher.dispatchAndWait(new Runnable() { - @Override - public void run() { - if (quickfixLabel == null) { - resolutions.addAll(getIssueResolutionProvider().getResolutions(issue)); - } else { - for (IssueResolution r : getIssueResolutionProvider().getResolutions(issue)) { - if (quickfixLabel.equals(r.getLabel())) { - resolutions.add(r); - } - } - } - } - }); - } - - return resolutions; - } -} diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/syntaxcoloring/AbstractSyntaxColoringTest.java b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/syntaxcoloring/AbstractSyntaxColoringTest.java deleted file mode 100644 index 9374361ffb..0000000000 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/ui/syntaxcoloring/AbstractSyntaxColoringTest.java +++ /dev/null @@ -1,350 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.test.ui.syntaxcoloring; - -import java.util.NoSuchElementException; - -import org.eclipse.emf.ecore.EObject; -import org.eclipse.jface.text.TextAttribute; -import org.eclipse.swt.SWT; -import org.eclipse.swt.custom.StyleRange; -import org.eclipse.swt.custom.StyledText; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.graphics.RGB; -import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot; -import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable; -import org.eclipse.swtbot.swt.finder.results.Result; -import org.eclipse.swtbot.swt.finder.waits.DefaultCondition; -import org.eclipse.xtext.nodemodel.ILeafNode; -import org.eclipse.xtext.nodemodel.util.NodeModelUtils; -import org.eclipse.xtext.ui.editor.XtextEditor; -import org.eclipse.xtext.ui.editor.utils.EditorUtils; -import org.eclipse.xtext.ui.editor.utils.TextStyle; - -import com.avaloq.tools.ddk.xtext.test.ui.AbstractXtextEditorUiTest; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; - - -/** - * Base class for syntax coloring tests. - */ -public abstract class AbstractSyntaxColoringTest extends AbstractXtextEditorUiTest { - private static final String STYLE_ASSERTION_FAILURE_MESSAGE = "The text style at the offset %d must match the expected style."; //$NON-NLS-1$ - - /** The Constant LEAF_NOT_FOUND_VALUE is returned when a leaf node is not found. */ - protected static final int LEAF_NOT_FOUND_VALUE = -1; - - public static final TextStyle TEXT_STYLE_DEFAULT = new TextStyle(); - public static final TextStyle TEXT_STYLE_ERROR = new TextStyle(); - public static final TextStyle TEXT_STYLE_NUMBER = new TextStyle(); - public static final TextStyle TEXT_STYLE_STRING = new TextStyle(); - public static final TextStyle TEXT_STYLE_COMMENT = new TextStyle(); - public static final TextStyle TEXT_STYLE_KEYWORD = new TextStyle(); - public static final TextStyle TEXT_STYLE_PUNCTUATION = new TextStyle(); - - static { - // CHECKSTYLE:OFF - // default - // TEXT_STYLE_DEFAULT.setBackgroundColor(new RGB(255, 255, 255)); - // TEXT_STYLE_DEFAULT.setColor(new RGB(0, 0, 0)); - // error - // TEXT_STYLE_ERROR.setColor(new RGB(255, 0, 0)); - // number - TEXT_STYLE_NUMBER.setColor(new RGB(125, 125, 125)); - // string - TEXT_STYLE_STRING.setColor(new RGB(42, 0, 255)); - // comment - TEXT_STYLE_COMMENT.setColor(new RGB(63, 127, 95)); - // keyword - TEXT_STYLE_KEYWORD.setColor(new RGB(127, 0, 85)); - TEXT_STYLE_KEYWORD.setStyle(SWT.BOLD); - // punctuation - // CHECKSTYLE:ON - } - - /** - * Support for syntax coloring assertions. - */ - private class AbstractSyntaxColoringAssertion extends AbstractModelAssertion { - - /** The syntax coloring text style to check. */ - private final TextStyle textStyle; - - /** - * Constructor. - */ - protected AbstractSyntaxColoringAssertion(final TextStyle textStyle) { - this.textStyle = textStyle; - } - - @Override - public void apply(final EObject root, final Integer pos) { - assertTextStyle(pos, textStyle); - } - - } - - /** - * Checks the given offset for the given {@link TextStyle}. - * - * @param editor - * the {@link XtextEditor} - * @param offset - * the position to check - * @param textAttribute - * the expected {@link TextStyle} - */ - public void assertTextAttribute(final XtextEditor editor, final int offset, final TextAttribute textAttribute) { - getBot().waitUntil(new DefaultCondition() { - @Override - public boolean test() { - return areEqualStyleRanges(createStyleRange(offset, 1, textAttribute), getStyleRange(editor, offset)); - } - - @Override - public String getFailureMessage() { - return String.format(STYLE_ASSERTION_FAILURE_MESSAGE, offset); - } - }); - } - - /** - * Checks the given offset for the given {@link TextStyle}. - * - * @param editor - * the {@link XtextEditor} - * @param offset - * the position to check - * @param textStyle - * the expected {@link TextStyle} - */ - public void assertTextStyle(final XtextEditor editor, final int offset, final TextStyle textStyle) { - assertTextStyle(editor, offset, textStyle, getBot()); - } - - /** - * Checks the given offset for the given {@link TextStyle}. - * - * @param editor - * the {@link XtextEditor} - * @param offset - * the position to check - * @param textStyle - * the expected {@link TextStyle} - * @param bot - * instance of swt bot - */ - public static void assertTextStyle(final XtextEditor editor, final int offset, final TextStyle textStyle, final SWTWorkbenchBot bot) { - bot.waitUntil(new DefaultCondition() { - @Override - public boolean test() { - return areEqualStyleRanges(createStyleRange(offset, 1, createTextAttribute(textStyle)), getStyleRange(editor, offset)); - } - - @Override - public String getFailureMessage() { - return String.format(STYLE_ASSERTION_FAILURE_MESSAGE, offset); - } - }); - } - - /** - * Checks if the two given {@link StyleRange}s are equal, with respect to start, length, font, style, and colors. Underlines are ignored. - * - * @param styleRangeA - * the first {@link StyleRange} - * @param styleRangeB - * the second {@link StyleRange} - * @return {@code true} if the given {@link StyleRange}s are equal, {@code false} otherwise - */ - @SuppressWarnings("PMD.CompareObjectsWithEquals") - public static boolean areEqualStyleRanges(final StyleRange styleRangeA, final StyleRange styleRangeB) { - if (styleRangeA == styleRangeB) { - return true; - } - boolean result = styleRangeA != null && styleRangeB != null; - result &= styleRangeA.start == styleRangeB.start; - result &= styleRangeA.length == styleRangeB.length; - result &= styleRangeA.fontStyle == styleRangeB.fontStyle; - result &= areEqualTextStyles(styleRangeA, styleRangeB); - return result; - } - - /** - * Checks if the two given {@link org.eclipse.swt.graphics.TextStyle}s are equal, with respect to colors, font. Underlines and other attributes are ignored. - * - * @param textStyleA - * the first {@link org.eclipse.swt.graphics.TextStyle} - * @param textStyleB - * the second {@link org.eclipse.swt.graphics.TextStyle} - * @return {@code true} if the given {@link org.eclipse.swt.graphics.TextStyle}s are equal, {@code false} otherwise - */ - @SuppressWarnings("PMD.CompareObjectsWithEquals") - public static boolean areEqualTextStyles(final org.eclipse.swt.graphics.TextStyle textStyleA, final org.eclipse.swt.graphics.TextStyle textStyleB) { - if (textStyleA == textStyleB) { - return true; - } - if (textStyleA == null || textStyleB == null) { - return false; - } - if (textStyleA.foreground != null) { - if (!textStyleA.foreground.equals(textStyleB.foreground)) { - return false; - } - } else if (textStyleB.foreground != null) { - return false; - } - if (textStyleA.font != null) { - if (!textStyleA.font.equals(textStyleB.font)) { - return false; - } - } else if (textStyleB.font != null) { - return false; - } - return true; - } - - /** - * Retrieves the {@link StyleRange} found at a given offset in the given {@link XtextEditor}. - * - * @param editor - * the {@link XtextEditor} - * @param offset - * the position for which to retrieve the {@link StyleRange} - * @return the {@link StyleRange} found at the given offset - */ - public static StyleRange getStyleRange(final XtextEditor editor, final int offset) { - StyleRange styleRange = UIThreadRunnable.syncExec(new Result() { - @Override - public StyleRange run() { - StyledText styledText = editor.getInternalSourceViewer().getTextWidget(); - return styledText.getStyleRangeAtOffset(offset); - } - }); - if (styleRange == null) { - // if no style range was found, then the default style is used - return createStyleRange(offset, 1, createTextAttribute(TEXT_STYLE_DEFAULT)); - } - return styleRange; - } - - /** - * Gets the offset for given text by analyzing the parse tree and looking for leaf nodes having - * a text attribute matching given value. Returns the first instance found and an error value if - * no match found. - * - * @param model - * the model - * @param text - * the text - * @return the offset for text - */ - public static int getOffsetForText(final EObject model, final String text) { - Iterable parseTreeNodes = NodeModelUtils.getNode(model).getLeafNodes(); - - try { - ILeafNode result = Iterables.find(parseTreeNodes, new Predicate() { - @Override - public boolean apply(final ILeafNode input) { - return text.equals(input.getText()); - } - }); - return result.getOffset(); - } catch (NoSuchElementException e) { - return LEAF_NOT_FOUND_VALUE; - } - } - - /** - * Creates a {@link StyleRange} from the given parameters. - * - * @param offset - * the offset - * @param length - * the length of the range - * @param textAttribute - * the {@link TextAttribute} - * @return a {@link StyleRange} from the given parameters - */ - public static StyleRange createStyleRange(final int offset, final int length, final TextAttribute textAttribute) { - int style = textAttribute.getStyle(); - int fontStyle = style & (SWT.ITALIC | SWT.BOLD | SWT.NORMAL); - StyleRange styleRange = new StyleRange(offset, length, textAttribute.getForeground(), textAttribute.getBackground(), fontStyle); - styleRange.strikeout = (style & TextAttribute.STRIKETHROUGH) != 0; - styleRange.underline = (style & TextAttribute.UNDERLINE) != 0; - styleRange.font = textAttribute.getFont(); - return styleRange; - } - - /** - * Creates a {@link TextAttribute} from the given {@link TextStyle}. - * - * @param textStyle - * a {@link TextStyle} - * @return a {@link TextAttribute} from the given {@link TextStyle} - */ - public static TextAttribute createTextAttribute(final TextStyle textStyle) { - int style = textStyle.getStyle(); - Font fontFromFontData = EditorUtils.fontFromFontData(textStyle.getFontData()); - return new TextAttribute(EditorUtils.colorFromRGB(textStyle.getColor()), EditorUtils.colorFromRGB(textStyle.getBackgroundColor()), style, fontFromFontData); - } - - /** - * Registers a new marker with the given text style. - *

- * The object at the position that will be assigned by the marker in the test file is expected to be styled as the given parameter. - *

- * - * @param textStyle - * text style that is expected on the EObject at the position of the marker, not {@code null} - * @return - * unique marker that can be used in the input string to mark a position that should be validated, never {@code null} - */ - protected String textStyle(final TextStyle textStyle) { - return addAssertion(new AbstractSyntaxColoringAssertion(textStyle)); - } - - /** - * Checks the given offset for the given {@link TextAttribute}. - * - * @param offset - * the position to check - * @param textAttribute - * the expected {@link TextAttribute} - */ - protected void assertTextAttribute(final int offset, final TextAttribute textAttribute) { - assertTextAttribute(getEditor(), offset, textAttribute); - } - - /** - * Checks the given offset for the given {@link TextStyle}. - * - * @param offset - * the position to check - * @param textStyle - * the expected {@link TextStyle} - */ - protected void assertTextStyle(final int offset, final TextStyle textStyle) { - assertTextStyle(getEditor(), offset, textStyle); - } - - /** - * Retrieves the {@link StyleRange} found at a given offset. - * - * @param offset - * the position for which to retrieve the {@link StyleRange} - * @return the {@link StyleRange} found at a given offset - */ - protected StyleRange getStyleRange(final int offset) { - return getStyleRange(getEditor(), offset); - } -} diff --git a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/validation/AbstractValidValidationTest.java b/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/validation/AbstractValidValidationTest.java deleted file mode 100644 index ffddb3abbb..0000000000 --- a/com.avaloq.tools.ddk.xtext.test.core/src/com/avaloq/tools/ddk/xtext/test/validation/AbstractValidValidationTest.java +++ /dev/null @@ -1,99 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 Avaloq Group AG and others. - * 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: - * Avaloq Group AG - initial API and implementation - *******************************************************************************/ -package com.avaloq.tools.ddk.xtext.test.validation; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.fail; - -import org.eclipse.emf.ecore.EObject; -import org.eclipse.xtext.testing.validation.AssertableDiagnostics.Pred; -import org.eclipse.xtext.testing.validation.ValidatorTester; - -import com.avaloq.tools.ddk.xtext.test.AbstractXtextTestUtil; -import com.avaloq.tools.ddk.xtext.validation.AbstractDeclarativeValidValidator; -import com.google.common.collect.Iterables; -import com.google.inject.Injector; - - -/** - * Base class for valid validation tests. - */ -@SuppressWarnings("nls") -public abstract class AbstractValidValidationTest extends AbstractValidationTest { - /** The tester. */ - private ValidatorTester tester; - - protected abstract Class getValidator(); - - /** - * Returns the validation tester generated for this test. - * - * @return the validation tester generated for this test - */ - @SuppressWarnings({"rawtypes", "unchecked"}) - protected ValidatorTester getTester() { - if (tester == null) { - AbstractXtextTestUtil testUtil = getTestUtil(); - tester = new ValidatorTester(testUtil.get(getValidator()), testUtil.get(Injector.class)); - } - return tester; - } - - // -------------------------------------------------------------------------- - // Validation methods - // -------------------------------------------------------------------------- - - /** - * Validate element against issue codes. - * Test will fail if the validator did NOT fail with any of the issue codes. - * i.e. this test expects a validation issue - * - * @param element - * the element - * @param issueCodes - * the issue codes - */ - protected void validate(final EObject element, final String... issueCodes) { - for (String issueCode : issueCodes) { - getTester().validate(element).assertAny(d -> new Pred(null, null, issueCode, null).apply(d)); - } - } - - /** - * Validate element against issue codes. - * Test will fail if the validator did fail with any of the issue codes. - * i.e. this test does not expect a validation issue - * - * @param element - * the element - * @param issueCodes - * the issue codes - */ - protected void validateNot(final EObject element, final String... issueCodes) { - for (String issueCode : issueCodes) { - if (!Iterables.isEmpty(Iterables.filter(getTester().validate(element).getAllDiagnostics(), d -> new Pred(null, null, issueCode, null).apply(d)))) { - fail("predicate found"); - } - } - } - - /** - * Validate element has no issues. - * Test will fail if any issue found for element. - * - * @param element - * the element - */ - protected void validateOK(final EObject element) { - assertFalse("Element " + element.toString() + " has validation errors.", getTester().validate(element).getAllDiagnostics().iterator().hasNext()); - } - -} diff --git a/ddk-configuration/working-set/ddk.wst b/ddk-configuration/working-set/ddk.wst index f030521d24..2999948cc7 100644 --- a/ddk-configuration/working-set/ddk.wst +++ b/ddk-configuration/working-set/ddk.wst @@ -23,7 +23,6 @@ - diff --git a/ddk-parent/pom.xml b/ddk-parent/pom.xml index 72171c223b..e279c45d77 100644 --- a/ddk-parent/pom.xml +++ b/ddk-parent/pom.xml @@ -69,7 +69,6 @@ ../com.avaloq.tools.ddk.xtext.check.generator ../com.avaloq.tools.ddk.xtext.common.types ../com.avaloq.tools.ddk.xtext.common.types.ui - ../com.avaloq.tools.ddk.xtext.common.ui ../com.avaloq.tools.ddk.xtext.export ../com.avaloq.tools.ddk.xtext.export.generator ../com.avaloq.tools.ddk.xtext.export.test