Skip to content

Commit

Permalink
Fix #204. Go to step definition from a feature file.
Browse files Browse the repository at this point in the history
  • Loading branch information
qvdk committed Nov 19, 2018
1 parent f980f0c commit a4b4204
Show file tree
Hide file tree
Showing 6 changed files with 266 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package cucumber.eclipse.editor.editors;


import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;

import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Region;
import org.junit.Before;
import org.junit.Test;

import cucumber.eclipse.steps.integration.Step;

public class StepHyperlinkTest {

private StepHyperlink stepHyperlink;
IRegion region;

@Before
public void setUp() {
region = new Region(0, 10);
Step step = new Step();
step.setText("Given I have a cat");
stepHyperlink = new StepHyperlink(region, step);
}

@Test
public void shouldHaveATypeLabel() {
assertThat(stepHyperlink.getTypeLabel(), equalTo("Gherkin step"));
}

@Test
public void shouldHaveAnAlternateText() {
assertThat(stepHyperlink.getHyperlinkText(), equalTo("Open step definition"));
}

@Test
public void shouldReturnTheExpectedRegion() {
assertThat(stepHyperlink.getHyperlinkRegion(), equalTo(region));
}

// should have UI automate test to validate the step hyperlink open.
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package cucumber.eclipse.editor.editors;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;

import java.util.Arrays;
Expand Down Expand Up @@ -180,4 +182,18 @@ private Step createStep(String text) {
return s;
}

@Test
public void shouldReturnExpressionWithoutStartingKeyword() {
String statement = stepMatcher.getTextStatement("en", "Given I have a cat");
assertThat(statement, equalTo("I have a cat"));

statement = stepMatcher.getTextStatement("en", "When I carress him");
assertThat(statement, equalTo("I carress him"));

statement = stepMatcher.getTextStatement("en", "Then he purrs");
assertThat(statement, equalTo("he purrs"));

statement = stepMatcher.getTextStatement("en", "And I am happy");
assertThat(statement, equalTo("I am happy"));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package cucumber.eclipse.editor.editors;

import org.eclipse.jface.preference.IPreferenceStore;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;

import org.eclipse.core.resources.IMarker;
Expand All @@ -10,6 +13,7 @@
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.hyperlink.IHyperlinkDetector;
import org.eclipse.jface.text.presentation.IPresentationReconciler;
import org.eclipse.jface.text.presentation.PresentationReconciler;
import org.eclipse.jface.text.quickassist.IQuickAssistAssistant;
Expand Down Expand Up @@ -161,4 +165,13 @@ public IReconciler getReconciler(ISourceViewer sourceViewer) {
public int getTabWidth(ISourceViewer sourceViewer) {
return 2;
}

@Override
public IHyperlinkDetector[] getHyperlinkDetectors(ISourceViewer sourceViewer) {
IHyperlinkDetector[] hyperlinkDetectors = super.getHyperlinkDetectors(sourceViewer);
StepHyperlinkDetector stepHyperlinkDetector = new StepHyperlinkDetector(this.editor);
IHyperlinkDetector[] gherkinHyperlinkDetectors = Arrays.copyOf(hyperlinkDetectors, hyperlinkDetectors.length + 1);
gherkinHyperlinkDetectors[hyperlinkDetectors.length] = stepHyperlinkDetector;
return gherkinHyperlinkDetectors;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package cucumber.eclipse.editor.editors;

import java.util.HashMap;

import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.hyperlink.IHyperlink;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;

import cucumber.eclipse.steps.integration.Step;

public class StepHyperlink implements IHyperlink {

private IRegion region;
private Step step;

public StepHyperlink(IRegion region, Step step) {
this.region = region;
this.step = step;
}

@Override
public IRegion getHyperlinkRegion() {
return this.region;
}

@Override
public String getHyperlinkText() {
return "Open step definition";
}

@Override
public String getTypeLabel() {
return "Gherkin step";
}

@Override
public void open() {
IResource file = this.step.getSource();
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();

HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put(IMarker.LINE_NUMBER, step.getLineNumber());
IMarker marker;
try {
marker = file.createMarker(IMarker.TEXT);
marker.setAttributes(map);
IDE.openEditor(page, marker);
marker.delete();
} catch (CoreException e) {
e.printStackTrace();
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package cucumber.eclipse.editor.editors;

import java.util.List;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.hyperlink.IHyperlink;
import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.texteditor.ITextEditor;

import cucumber.eclipse.editor.markers.MarkerIds;
import cucumber.eclipse.editor.markers.MarkerManager;
import cucumber.eclipse.editor.steps.IStepProvider;
import cucumber.eclipse.steps.integration.Step;
import gherkin.lexer.LexingError;
import gherkin.parser.Parser;

public class StepHyperlinkDetector implements IHyperlinkDetector {

private Editor editor;

public StepHyperlinkDetector(Editor editor) {
this.editor = editor;
}

@Override
public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) {
if (region == null || textViewer == null) {
return null;
}

IDocument document = textViewer.getDocument();
if (document == null) {
return null;
}

int offset = region.getOffset();
int lineStartOffset = 0;

IRegion lineInfo = null;
String currentLine = null;
try {
lineInfo = document.getLineInformationOfOffset(offset);
lineStartOffset = lineInfo.getOffset();
currentLine = document.get(lineStartOffset, lineInfo.getLength());
} catch (BadLocationException e) {
return null;
}

IStepProvider stepProvider = this.editor.getStepProvider();
Set<Step> steps = stepProvider.getStepsInEncompassingProject();

StepMatcher stepMatcher = new StepMatcher();
String language = DocumentUtil.getDocumentLanguage(document);

// hack to support scenario outline examples
int currentLineNumber = textViewer.getTextWidget().getLineAtOffset(offset) + 1;
List<String> resolvedStepsExpressions = resolveLineStep(editor, currentLineNumber);
Step step = null;
for (String variant : resolvedStepsExpressions) {
step = stepMatcher.matchSteps(language, steps, variant);
if(step != null) {
break;
}
}

if (step == null) {
return null;
}

// define the hyperlink region
String textStatement = stepMatcher.getTextStatement(language, currentLine);
int statementStartOffset = lineStartOffset + currentLine.indexOf(textStatement);

IRegion stepRegion = new Region(statementStartOffset, textStatement.length());

return new IHyperlink[] { new StepHyperlink(stepRegion, step) };
}

// go through all examples of current scenario outline and generate step strings with replaced variables values
protected static List<String> resolveLineStep(IEditorPart editorPart, int currentLineNumber) {
ITextEditor editor = (ITextEditor) editorPart;

IDocument document = editor.getDocumentProvider().getDocument(editorPart.getEditorInput());

IFileEditorInput fileEditorInput = (IFileEditorInput) editorPart.getEditorInput();
IFile featureFile = fileEditorInput.getFile();
MarkerManager markerManager = new MarkerManager();
PopupMenuFindStepFormatter findStepFormatter = new PopupMenuFindStepFormatter(currentLineNumber);
Parser p = new Parser(findStepFormatter, false);
try {
p.parse(document.get(), "", 0);
} catch (LexingError l) {
markerManager.add(MarkerIds.LEXING_ERROR, featureFile, IMarker.SEVERITY_ERROR, l.getLocalizedMessage(), 1, 0, 0);
}
return findStepFormatter.getResolvedStepNames();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,39 @@ class StepMatcher {
private Pattern groupPatternNonParameterMatch = Pattern.compile("(\\(\\?:.+?\\))");
private Pattern groupPattern = Pattern.compile("(\\(.+?\\))");

public String getTextStatement(String language, String expression) {
Matcher matcher = getBasicStatementMatcher(language, expression);
if(matcher == null) {
return null;
}
if(matcher.matches()) {
return matcher.group(1);
}
return null;
}

public Step matchSteps(String languageCode, Set<Step> steps, String currentLine) {

//System.out.println("StepMatcher matchSteps() steps = " + steps);
Pattern cukePattern = getLanguageKeyWordMatcher(languageCode);
/**
* Get a matcher to ensure text starts with a basic step keyword : Given, When,
* Then, etc
*
* @param language the document language
* @param text the text to match
* @return a matcher
*/
private Matcher getBasicStatementMatcher(String language, String text) {
Pattern cukePattern = getLanguageKeyWordMatcher(language);

if (cukePattern == null)
return null;

Matcher matcher = cukePattern.matcher(currentLine);
return cukePattern.matcher(text.trim());
}

public Step matchSteps(String languageCode, Set<Step> steps, String currentLine) {

//System.out.println("StepMatcher matchSteps() steps = " + steps);

Matcher matcher = getBasicStatementMatcher(languageCode, currentLine);

if (matcher.matches()) {

Expand Down

0 comments on commit a4b4204

Please sign in to comment.