/*******************************************************************************
* Copyright (c) 2017 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is 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
*
* Contributor:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.ws.ui.bot.test.websocket;
import org.apache.commons.lang.StringUtils;
import org.eclipse.swt.SWT;
import org.jboss.reddeer.eclipse.jdt.ui.ProjectExplorer;
import org.jboss.reddeer.eclipse.ui.dialogs.ExplorerItemPropertyDialog;
import org.jboss.reddeer.eclipse.ui.views.contentoutline.OutlineView;
import org.jboss.reddeer.jface.text.contentassist.ContentAssistant;
import org.jboss.reddeer.swt.api.TreeItem;
import org.jboss.reddeer.swt.impl.button.CheckBox;
import org.jboss.reddeer.swt.impl.label.DefaultLabel;
import org.jboss.reddeer.swt.impl.styledtext.DefaultStyledText;
import org.jboss.reddeer.swt.keyboard.KeyboardFactory;
import org.jboss.reddeer.workbench.impl.editor.Marker;
import org.jboss.reddeer.workbench.impl.editor.TextEditor;
import java.util.*;
import static org.jboss.tools.ws.ui.bot.test.utils.ClassHelper.*;
import static org.jboss.tools.ws.ui.bot.test.utils.ProjectHelper.createClass;
import static org.jboss.tools.ws.ui.bot.test.websocket.NameBindingTest.Constants.CLASS_NAME_ANNOTATION;
import static org.jboss.tools.ws.ui.bot.test.websocket.NameBindingTest.Constants.CLASS_NAME_FILTER;
import static org.jboss.tools.ws.ui.bot.test.websocket.StubMethodsTest.Constants.*;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
class WebSocketHelper {
/**
* Shell with this label is used. Initialized in first usage (requires opened editor).
*/
private static String CORRECT_CONTENT_ASSISTANT_LABEL = null;
static void callAllStubProposals(TextEditor editor) {
Set<String> remainingProposals = new HashSet<>(EXPECTED_PROPOSALS);
for (String proposal : EXPECTED_PROPOSALS) {
//Call proposal
ContentAssistant contentAssistant = openContentAssistant(editor);
contentAssistant.chooseProposal(proposal);
//Update tmp collection
remainingProposals.remove(proposal);
//Asserts
assertNoMarkerError(editor.getMarkers());
assertThereAreOnlySpecifiedStubProposals(editor, remainingProposals);
assertOutlineViewContainsNewMethod(editor, proposal);
}
}
//ASSERTS:
private static void assertNoMarkerError(List<Marker> markers) {
for (Marker marker : markers) {
if (marker.getText().contains("error")) {
fail("There is an error in the markers! " + marker.getText());
}
}
}
/**
* Stub proposal should be in current proposals if and only if
* collection shouldBe contains it.
*
* @param editor
* @param shouldBe
*/
static void assertThereAreOnlySpecifiedStubProposals(
TextEditor editor, Collection<String> shouldBe) {
//Preparing collections
List<String> proposals = new ArrayList<>(EXPECTED_PROPOSALS);
proposals.removeAll(shouldBe);
List<String> shouldNotBe = proposals;
ContentAssistant contentAssistant = openContentAssistant(editor);
List<String> actualProposals = contentAssistant.getProposals();
contentAssistant.close();
//check
assertTrue("There are not all expected proposals!", actualProposals.containsAll(shouldBe));
assertTrue("There are proposals those should not be there!", Collections.disjoint(actualProposals, shouldNotBe));
}
private static void assertOutlineViewContainsNewMethod(TextEditor editor, String proposal) {
String newMethodName = proposal.split("[(]")[0];
for (TreeItem outlineItem : new OutlineView().outlineElements()) {
if (SERVER_CLASS_NAME.equals(outlineItem.getText()) || CLIENT_CLASS_NAME.equals(outlineItem.getText())) {
for(TreeItem classItem : outlineItem.getItems()){
if (classItem.getText().startsWith(newMethodName)) {
//OK
editor.activate();
return;
}
}
fail("New method not found in Class. Method: " + newMethodName);
}
}
fail("Class not found in Outline View!");
}
//Open ContentAssistant methods:
/**
* In first call methods finds ContentAssistant with StubMethodsTest.Constants.EXPECTED_PROPOSALS
* and remembers its label in CORRECT_CONTENT_ASSISTANT_LABEL.
*
* @return opened content assistant
*/
static ContentAssistant openContentAssistant(TextEditor editor) {
//first call
if (CORRECT_CONTENT_ASSISTANT_LABEL == null) {
findCorrectContentAssistantLabel(editor);
}
//finding the correct content assistant
ContentAssistant contentAssistant = editor.openContentAssistant();
String labelValue = new DefaultLabel(contentAssistant).getText();
while (!CORRECT_CONTENT_ASSISTANT_LABEL.equals(labelValue)) {
KeyboardFactory.getKeyboard().invokeKeyCombination(SWT.CTRL, SWT.SPACE);
labelValue = new DefaultLabel(contentAssistant).getText();
}
return contentAssistant;
}
private static void findCorrectContentAssistantLabel(TextEditor editor) {
ContentAssistant contentAssistant = editor.openContentAssistant();
//studio behavior fix
KeyboardFactory.getKeyboard().invokeKeyCombination(SWT.ESC);
contentAssistant = editor.openContentAssistant();
String labelValue = new DefaultLabel(contentAssistant).getText();
while (!contentAssistant.getProposals().containsAll(EXPECTED_PROPOSALS)) {
KeyboardFactory.getKeyboard().invokeKeyCombination(SWT.CTRL, SWT.SPACE);
labelValue = new DefaultLabel(contentAssistant).getText();
}
CORRECT_CONTENT_ASSISTANT_LABEL = labelValue;
contentAssistant.close();
}
//Prepare class methods:
static TextEditor prepareClass(String className) {
switch (className) {
case SERVER_CLASS_NAME:
return prepareClass(SERVER_CLASS_NAME,
"import javax.websocket.server.ServerEndpoint;",
"@ServerEndpoint(\"/test/\")");
case CLIENT_CLASS_NAME:
return prepareClass(CLIENT_CLASS_NAME,
"import javax.websocket.ClientEndpoint;",
"@ClientEndpoint");
default:
throw new RuntimeException("Unknown class to prepare!");
}
}
private static TextEditor prepareClass(
String className, String importCommand, String annotation) {
TextEditor editor = createClass(PROJECT_NAME, PROJECT_PACKAGE, className);
DefaultStyledText text = new DefaultStyledText();
text.insertText(1, 0, System.lineSeparator());
text.insertText(2, 0, importCommand);
text.insertText(3, 0, System.lineSeparator());
text.insertText(3, 0, annotation);
//set cursor position at the first line in the class, column 0
int firstLineInClassIndex = getClassDefinitionLine(editor) + 1;
editor.setCursorPosition(firstLineInClassIndex, 0);
return editor;
}
//Prefixes methods:
static List<String> filterStubProposalsWithPrefix(String prefix) {
List<String> matches = new ArrayList<>();
for (String proposal : EXPECTED_PROPOSALS) {
if (proposal.startsWith(prefix))
matches.add(proposal);
}
return matches;
}
static void setPrefixIntoFirstClassLine(TextEditor editor, String prefix) {
int firstLineInClassIndex = getClassDefinitionLine(editor) + 1;
new DefaultStyledText().insertText(firstLineInClassIndex, 0, prefix);
//jump to the end of the line
editor.setCursorPosition(firstLineInClassIndex, editor.getTextAtLine(firstLineInClassIndex).length());
}
static void clearFirstClassLine(TextEditor editor) {
delFirstClassLine(editor);
int firstLineInClassIndex = getClassDefinitionLine(editor) + 1;
new DefaultStyledText().insertText(firstLineInClassIndex, 0, System.lineSeparator());
}
static void delFirstClassLine(TextEditor editor) {
int firstLineInClassIndex = getClassDefinitionLine(editor) + 1;
editor.selectLine(firstLineInClassIndex);
KeyboardFactory.getKeyboard().invokeKeyCombination(SWT.DEL);
}
static int countImports(TextEditor editor) {
return StringUtils.countMatches(editor.getText(), "import ");
}
static void enableJAXRSSupport(String projectName) {
ProjectExplorer pe = new ProjectExplorer();
ExplorerItemPropertyDialog dialog = new ExplorerItemPropertyDialog(pe.getProject(projectName));
dialog.open();
dialog.select("JAX-RS");
new CheckBox().toggle(true);
dialog.ok();
}
static TextEditor prepareCustomAnnotationEditor(String projectName) {
TextEditor annotationEditor = createClass(projectName,
NameBindingTest.Constants.PROJECT_PACKAGE, NameBindingTest.Constants.CLASS_NAME_ANNOTATION);
//replace 'class' with '@interface'
String replacedCode = new DefaultStyledText().getText().replaceAll("public class", "public @interface");
new DefaultStyledText().setText(replacedCode);
addClassAnnotation(annotationEditor, "@NameBinding", "import javax.ws.rs.NameBinding;");
addClassAnnotation(annotationEditor, "@Target({ ElementType.TYPE, ElementType.METHOD })", "import java.lang.annotation.Target;");
addImport(annotationEditor, "import java.lang.annotation.ElementType;");
addClassAnnotation(annotationEditor, "@Retention(value = RetentionPolicy.RUNTIME)", "import java.lang.annotation.Retention;");
addImport(annotationEditor, "import java.lang.annotation.RetentionPolicy;");
annotationEditor.save();
return annotationEditor;
}
static TextEditor prepareAppEditor(String projectName) {
TextEditor appEditor = createClass(projectName,
NameBindingTest.Constants.PROJECT_PACKAGE, NameBindingTest.Constants.CLASS_NAME_APP);
//add 'extends' def part
String replacedCode = new DefaultStyledText().getText()
.replaceAll("public class " + NameBindingTest.Constants.CLASS_NAME_APP,
"public class " + NameBindingTest.Constants.CLASS_NAME_APP + " extends Application");
new DefaultStyledText().setText(replacedCode);
addImport(appEditor, "import javax.ws.rs.core.Application;");
addClassAnnotation(appEditor, "@ApplicationPath(\"/app\")", "import javax.ws.rs.ApplicationPath;");
addClassAnnotation(appEditor, "@" + CLASS_NAME_ANNOTATION);
appEditor.save();
return appEditor;
}
static TextEditor prepareFilterEditor(String projectName) {
TextEditor filterEditor = createClass(projectName,
NameBindingTest.Constants.PROJECT_PACKAGE, NameBindingTest.Constants.CLASS_NAME_FILTER);
//add 'implements' def part
String replacedCode = new DefaultStyledText().getText()
.replaceAll("public class " + CLASS_NAME_FILTER,
"public class " + CLASS_NAME_FILTER + " implements ContainerResponseFilter");
new DefaultStyledText().setText(replacedCode);
addImport(filterEditor, "import javax.ws.rs.container.ContainerResponseFilter;");
addClassAnnotation(filterEditor, "@Provider", "import javax.ws.rs.ext.Provider;");
addClassAnnotation(filterEditor, "@" + CLASS_NAME_ANNOTATION);
replacedCode = new DefaultStyledText().getText()
.replaceAll("implements ContainerResponseFilter \\{",
"implements ContainerResponseFilter {\n" +
"\t@Override\n" +
"\tpublic void filter(ContainerRequestContext requestContext,\n" +
" ContainerResponseContext responseContext)\n" +
"\t\t\tthrows IOException {\n" +
"\t\t// ...\n" +
"\t}");
new DefaultStyledText().setText(replacedCode);
addImport(filterEditor, "import javax.ws.rs.container.ContainerRequestContext;");
addImport(filterEditor, "import javax.ws.rs.container.ContainerResponseContext;");
addImport(filterEditor, "import java.io.IOException;");
filterEditor.save();
return filterEditor;
}
}