/******************************************************************************* * Copyright (c) 2017 itemis 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: * Tamas Miklossy (itemis AG) - initial API and implementation *******************************************************************************/ package org.eclipse.gef.dot.tests; import java.lang.reflect.InvocationTargetException; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.gef.dot.internal.ui.language.internal.DotActivator; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.Color; import org.eclipse.ui.actions.WorkspaceModifyOperation; import org.eclipse.xtext.junit4.ui.AbstractEditorTest; import org.eclipse.xtext.junit4.ui.util.IResourcesSetupUtil; import org.eclipse.xtext.ui.XtextProjectHelper; import org.eclipse.xtext.ui.editor.XtextEditor; import org.eclipse.xtext.util.StringInputStream; import org.junit.Test; @SuppressWarnings("restriction") public class DotHighlightingTests extends AbstractEditorTest { private final String TEST_PROJECT = "dottestproject"; @Override public void setUp() throws Exception { super.setUp(); createTestProjectWithXtextNature(); } @Override protected String getEditorId() { return DotActivator.ORG_ECLIPSE_GEF_DOT_INTERNAL_LANGUAGE_DOT; } // lexical highlighting test cases @Test public void numbers() { String text = DotTestGraphs.EDGE_ARROWSIZE_GLOBAL; StyledText textWidget = getTextWidget(text); test(textWidget, "1.5", SWT.NORMAL, 125, 125, 125); } @Test public void quotedAttributeValue() { String text = DotTestGraphs.QUOTED_LABELS; StyledText textWidget = getTextWidget(text); test(textWidget, "node 1", SWT.NORMAL, 255, 0, 0); } @Test public void unquotedAttributeValue() { String text = DotTestGraphs.GRAPH_LAYOUT_DOT; StyledText textWidget = getTextWidget(text); test(textWidget, "dot", SWT.NORMAL, 153, 76, 0); } @Test public void compassPt() { String text = DotTestGraphs.PORTS; StyledText textWidget = getTextWidget(text); test(textWidget, "ne", SWT.NORMAL, 153, 76, 0); test(textWidget, "_", SWT.NORMAL, 153, 76, 0); } @Test public void htmlLabel() { String text = DotTestGraphs .NODE_LABEL_HTML_LIKE( DotTestHtmlLabels.FONT_TAG_CONTAINS_TABLE_TAG) .toString(); StyledText textWidget = getTextWidget(text); // test highlighting of Html tag test(textWidget, "<", SWT.NORMAL, 63, 127, 127); test(textWidget, "<font", SWT.NORMAL, 63, 127, 127); test(textWidget, "<table>", SWT.NORMAL, 63, 127, 127); test(textWidget, "<tr>", SWT.NORMAL, 63, 127, 127); test(textWidget, "<td>", SWT.NORMAL, 63, 127, 127); test(textWidget, "</td>", SWT.NORMAL, 63, 127, 127); test(textWidget, "</tr>", SWT.NORMAL, 63, 127, 127); test(textWidget, "</table>", SWT.NORMAL, 63, 127, 127); test(textWidget, "</font>", SWT.NORMAL, 63, 127, 127); // test highlighting of Html attribute name test(textWidget, "color", SWT.NORMAL, 127, 0, 127); // test highlighting of Html attribute equal sign test(textWidget, "=", SWT.NORMAL, 0, 0, 0); // test highlighting of Html attribute value test(textWidget, "\"green\"", SWT.ITALIC, 42, 0, 255); // test highlighting of Html content test(textWidget, "text", SWT.NORMAL, 0, 0, 0); // test highlighting of Html comment test(textWidget, "<!--", SWT.NORMAL, 63, 95, 191); test(textWidget, "Html label with custom font", SWT.NORMAL, 63, 95, 191); test(textWidget, "-->", SWT.NORMAL, 63, 95, 191); } @Test public void comments() { String text = DotTestGraphs.EMPTY_WITH_COMMENTS; StyledText textWidget = getTextWidget(text); test(textWidget, "// This is a C++-style single line comment.", SWT.NORMAL, 63, 127, 95); test(textWidget, "/*", SWT.NORMAL, 63, 127, 95); test(textWidget, "* This is a C++-style", SWT.NORMAL, 63, 127, 95); test(textWidget, "* multi line comment.", SWT.NORMAL, 63, 127, 95); test(textWidget, "*/", SWT.NORMAL, 63, 127, 95); test(textWidget, "# This is considered as a line output from C-preprocessor and discarded.", SWT.NORMAL, 63, 127, 95); } @Test public void keywords() { String text = DotTestGraphs.KEYWORDS; StyledText textWidget = getTextWidget(text); test(textWidget, "strict", SWT.BOLD, 0, 0, 0); test(textWidget, "digraph", SWT.BOLD, 0, 0, 0); test(textWidget, "\tgraph", SWT.BOLD, 0, 0, 0); test(textWidget, "node", SWT.BOLD, 0, 0, 0); test(textWidget, "edge", SWT.BOLD, 0, 0, 0); test(textWidget, "subgraph", SWT.BOLD, 0, 0, 0); } // semantic highlighting test cases @Test public void graphName() { String text = DotTestGraphs.EXTRACTED_01; StyledText textWidget = getTextWidget(text); test(textWidget, "name", SWT.NORMAL, 0, 0, 0); } @Test public void nodeName() { String text = DotTestGraphs.ONE_NODE; StyledText textWidget = getTextWidget(text); test(textWidget, "1", SWT.NORMAL, 0, 0, 0); } @Test public void port() { String text = DotTestGraphs.PORTS; StyledText textWidget = getTextWidget(text); test(textWidget, "portID", SWT.NORMAL, 0, 153, 76); test(textWidget, "portID2", SWT.NORMAL, 0, 153, 76); } @Test public void attributeName() { String text = DotTestGraphs.GRAPH_LAYOUT_DOT; StyledText textWidget = getTextWidget(text); test(textWidget, "layout", SWT.NORMAL, 0, 76, 153); } @Test public void edgeOperatorDirected() { String text = DotTestGraphs.ONE_DIRECTED_EDGE; StyledText textWidget = getTextWidget(text); test(textWidget, "->", SWT.NORMAL, 0, 153, 0); } @Test public void edgeOperatorUnDirected() { String text = DotTestGraphs.ONE_EDGE; StyledText textWidget = getTextWidget(text); test(textWidget, "--", SWT.NORMAL, 0, 153, 0); } private StyledText getTextWidget(String content) { XtextEditor editor = null; try { editor = openEditor(createTestFile(content)); } catch (Exception e) { e.printStackTrace(); fail(e.getMessage()); } // wait for the Xtext framework to apply the semantic highlighting, // since the semantic highlighting stage is executed asynchronously in // the background // TODO: replace the hard-coded sleep value with a proper wait // condition try { sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } StyledText textWidget = editor.getInternalSourceViewer() .getTextWidget(); return textWidget; } private void test(StyledText textWidget, String subString, int expectedFontStyle, int expectedR, int expectedG, int expectedB) { String content = textWidget.getText(); int startPosition = content.indexOf(subString); for (int i = 0; i < subString.length(); i++) { int currentPosition = startPosition + i; StyleRange styleRange = textWidget .getStyleRangeAtOffset(currentPosition); String character = textWidget.getContent() .getTextRange(currentPosition, 1); // skipping the whitespace characters if (character.equals(" ") || character.equals("\t")) { continue; } assertEquals( "Expected font style does not correspond to the actual font style on character " + character, expectedFontStyle, styleRange.fontStyle); assertEquals( "Expected foreground color does not correspond to the actual foreground color on character " + character, new Color(null, expectedR, expectedG, expectedB), getActualColor(styleRange.foreground)); } } private Color getActualColor(Color color) { // the default color is black return color == null ? new Color(null, 0, 0, 0) : color; } /** * The implementation of the following helper methods is mainly taken from * the org.eclipse.xtext.junit4.ui.util.IResourcesSetupUtil java class. */ private IFile createTestFile(String content) throws Exception { return createFile(TEST_PROJECT + "/test.dot", content); } private void createTestProjectWithXtextNature() throws Exception { IProject project = IResourcesSetupUtil.createProject(TEST_PROJECT); IResourcesSetupUtil.addNature(project, XtextProjectHelper.NATURE_ID); } private static IFile createFile(String wsRelativePath, String s) throws CoreException, InvocationTargetException, InterruptedException { return createFile(new Path(wsRelativePath), s); } private static IFile createFile(IPath wsRelativePath, final String s) throws CoreException, InvocationTargetException, InterruptedException { final IFile file = root().getFile(wsRelativePath); new WorkspaceModifyOperation() { @Override protected void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException, InterruptedException { create(file.getParent()); file.delete(true, monitor()); file.create(new StringInputStream(s), true, monitor()); } }.run(monitor()); return file; } private static IWorkspaceRoot root() { return ResourcesPlugin.getWorkspace().getRoot(); } private static IProgressMonitor monitor() { return new NullProgressMonitor(); } private static void create(final IContainer container) throws CoreException, InvocationTargetException, InterruptedException { new WorkspaceModifyOperation() { @Override protected void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException, InterruptedException { if (!container.exists()) { create(container.getParent()); if (container instanceof IFolder) { ((IFolder) container).create(true, true, monitor()); } else { IProject iProject = (IProject) container; createProject(iProject); } } } }.run(monitor()); } private static IProject createProject(IProject project) throws CoreException { if (!project.exists()) project.create(monitor()); project.open(monitor()); return project; } }