Skip to content

Commit

Permalink
Fix #41, Fix #42, Fix #43 Support all Gherkin dialects (i18n)
Browse files Browse the repository at this point in the history
Fix #41, Fix #42, Fix #43 Support all Gherkin dialects (i18n)
  • Loading branch information
racodond authored Dec 19, 2016
1 parent a4deac7 commit 7f2bd93
Show file tree
Hide file tree
Showing 86 changed files with 4,278 additions and 432 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,17 @@ public class GherkinCheckVerifier extends SubscriptionVisitorCheck {

/**
* Check issues
* Example:
* <pre>
* GherkinCheckVerifier.issues(new MyCheck(), myFile)
* .next().atLine(2).withMessage("This is message for line 2.")
* .next().atLine(3).withMessage("This is message for line 3.").withCost(2.)
* .next().atLine(8)
* .noMore();
* </pre>
*
* @param check Check to test
* @param file File to test
* <p>
* Example:
* <pre>
* GherkinCheckVerifier.issues(new MyCheck(), myFile)
* .next().atLine(2).withMessage("This is message for line 2.")
* .next().atLine(3).withMessage("This is message for line 3.").withCost(2.)
* .next().atLine(8)
* .noMore();
* </pre>
*/
public static CheckMessagesVerifier issues(GherkinCheck check, File file) {
return issues(check, file, Charsets.UTF_8);
Expand Down Expand Up @@ -123,7 +122,7 @@ public static void verify(GherkinCheck check, File file) {
* @param charset Charset of the file to test.
*/
public static void verify(GherkinCheck check, File file, Charset charset) {
GherkinDocumentTree propertiesTree = (GherkinDocumentTree) GherkinParserBuilder.createParser(charset).parse(file);
GherkinDocumentTree propertiesTree = (GherkinDocumentTree) GherkinParserBuilder.createTestParser(charset).parse(file);
GherkinVisitorContext context = new GherkinVisitorContext(propertiesTree, file);

GherkinCheckVerifier checkVerifier = new GherkinCheckVerifier();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ private TreeCheckTest() {
public static Collection<CheckMessage> getIssues(String relativePath, GherkinCheck check, Charset charset) {
File file = new File(relativePath);

GherkinDocumentTree propertiesTree = (GherkinDocumentTree) GherkinParserBuilder.createParser(charset).parse(file);
GherkinDocumentTree propertiesTree = (GherkinDocumentTree) GherkinParserBuilder.createTestParser(charset).parse(file);
GherkinVisitorContext context = new GherkinVisitorContext(propertiesTree, file);
List<Issue> issues = check.scanFile(context);

Expand Down
2 changes: 1 addition & 1 deletion gherkin-checks/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
</dependency>
<dependency>
<groupId>org.languagetool</groupId>
<artifactId>language-en</artifactId>
<artifactId>language-all</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@ private int findLastCommonGivenStepRank() {

search:
for (int i = 0; i < allSteps.get(0).size(); i++) {
if (allSteps.get(0).get(i).type() == StepTree.StepType.GIVEN) {
if (allSteps.get(0).get(i).semanticType() == StepTree.SemanticStepType.GIVEN) {
for (int j = 1; j < allSteps.size(); j++) {
if (allSteps.get(j).size() <= i
|| allSteps.get(j).get(i).type() != StepTree.StepType.GIVEN
|| allSteps.get(j).get(i).semanticType() != StepTree.SemanticStepType.GIVEN
|| !allSteps.get(j).get(i).sentence().text().equals(allSteps.get(0).get(i).sentence().text())) {
break search;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ private void checkAllStepTypes(BasicScenarioTree tree) {
int thens = 0;

for (StepTree step : Stream.concat(backgroundSteps.stream(), tree.steps().stream()).collect(Collectors.toList())) {
switch (step.type()) {
switch (step.semanticType()) {
case GIVEN:
givens++;
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public class GivenStepRegularExpressionCheck extends DoubleDispatchVisitorCheck

@Override
public void visitStep(StepTree tree) {
if (tree.type() == StepTree.StepType.GIVEN
if (tree.semanticType() == StepTree.SemanticStepType.GIVEN
&& !tree.sentence().text().matches(regularExpression)) {
addPreciseIssue(tree.sentence(), "Update the sentence to match the following regular expression: " + regularExpression);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.sonar.check.RuleProperty;
import org.sonar.plugins.gherkin.api.tree.*;
import org.sonar.plugins.gherkin.api.visitors.SubscriptionVisitorCheck;
import org.sonar.plugins.gherkin.api.visitors.issue.PreciseIssue;
import org.sonar.squidbridge.annotations.ActivatedByDefault;
import org.sonar.squidbridge.annotations.SqaleConstantRemediation;

Expand Down Expand Up @@ -57,16 +58,14 @@ public List<Tree.Kind> nodesToVisit() {
Tree.Kind.SCENARIO,
Tree.Kind.SCENARIO_OUTLINE,
Tree.Kind.EXAMPLES,
Tree.Kind.STEP,
Tree.Kind.FEATURE_PREFIX,
Tree.Kind.BACKGROUND_PREFIX,
Tree.Kind.SCENARIO_PREFIX,
Tree.Kind.SCENARIO_OUTLINE_PREFIX,
Tree.Kind.EXAMPLES_PREFIX,
Tree.Kind.STEP_PREFIX,
Tree.Kind.TABLE,
Tree.Kind.DOC_STRING,
Tree.Kind.NAME
Tree.Kind.DOC_STRING
);
}

Expand All @@ -80,15 +79,18 @@ public void visitNode(Tree tree) {
checkAllTagsIndentation(tree);
}

if (tree instanceof Prefixable && tree instanceof Nameable) {
checkAllNamesIndentation(tree);
}

if (tree instanceof PrefixTree) {
checkAllPrefixesIndentation((PrefixTree) tree);
} else if (tree.is(Tree.Kind.DOC_STRING)) {
checkDocStringsIndentation((DocStringTree) tree);
checkAllDocStringsIndentation((DocStringTree) tree);
} else if (tree.is(Tree.Kind.TABLE)) {
checkAllTablesIndentation((TableTree) tree);
} else if (tree.is(Tree.Kind.NAME)) {
checkNameIndentation((NameTree) tree);
}

}

@VisibleForTesting
Expand Down Expand Up @@ -192,51 +194,19 @@ private void checkAllTablesIndentation(TableTree tree) {
tree.rows().forEach(d -> checkIndentation(d, indentation * 3));
}

private void checkDocStringsIndentation(DocStringTree tree) {
private void checkAllDocStringsIndentation(DocStringTree tree) {
checkIndentation(tree.prefix(), indentation * 3);
checkIndentation(tree.suffix(), indentation * 3);
}

private void checkNameIndentation(NameTree tree) {
int expectedIndentation = -1;

switch (tree.parent().getKind()) {
case FEATURE_DECLARATION:
if (((FeatureDeclarationTree) tree.parent()).prefix().keyword().column() == 0) {
expectedIndentation = 9;
}
break;

case BACKGROUND:
if (((BackgroundTree) tree.parent()).prefix().keyword().column() == indentation) {
expectedIndentation = indentation + 12;
}
break;

case SCENARIO:
if (((ScenarioTree) tree.parent()).prefix().keyword().column() == indentation) {
expectedIndentation = indentation + 10;
}
break;

case SCENARIO_OUTLINE:
if (((ScenarioOutlineTree) tree.parent()).prefix().keyword().column() == indentation) {
expectedIndentation = indentation + 18;
}
break;

case EXAMPLES:
if (((ExamplesTree) tree.parent()).prefix().keyword().column() == indentation * 2) {
expectedIndentation = indentation * 2 + 10;
}
break;

default:
throw new IllegalStateException("Unsupported NameTree: " + tree.toString());
}
private void checkAllNamesIndentation(Tree tree) {
NameTree nameTree = ((Nameable) tree).name();
SyntaxToken columnTree = ((Prefixable) tree).colon();

if (expectedIndentation >= 0) {
checkIndentation(tree.value(), expectedIndentation);
if (nameTree != null
&& columnTree.endColumn() + 1 != nameTree.value().column()) {
PreciseIssue issue = addPreciseIssue(nameTree, "Leave one single whitespace between the name and the column.");
issue.secondary(columnTree, "");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public List<Tree.Kind> nodesToVisit() {
public void visitNode(Tree tree) {
List<StepTree> whenSteps = ((BasicScenarioTree) tree).steps()
.stream()
.filter(s -> s.type() == StepTree.StepType.WHEN)
.filter(s -> s.semanticType() == StepTree.SemanticStepType.WHEN)
.collect(Collectors.toList());

if (whenSteps.size() > 1) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public class OnlyGivenStepsInBackgroundCheck extends DoubleDispatchVisitorCheck
public void visitBackground(BackgroundTree tree) {
tree.steps()
.stream()
.filter(s -> s.type() != StepTree.StepType.GIVEN)
.filter(s -> s.semanticType() != StepTree.SemanticStepType.GIVEN)
.forEach(s -> addPreciseIssue(s, "Move this non-Given step out of Background."));

super.visitBackground(tree);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.languagetool.JLanguageTool;
import org.languagetool.language.AmericanEnglish;
import org.languagetool.language.BritishEnglish;
import org.languagetool.language.English;
import org.languagetool.Languages;
import org.languagetool.rules.spelling.SpellingCheckRule;
import org.sonar.check.Priority;
import org.sonar.check.Rule;
Expand Down Expand Up @@ -53,11 +51,18 @@ public class SpellingCheck extends SubscriptionVisitorCheck {
private static final String DEFAULT_WORDS_TO_IGNORE = "";
private static final String DEFAULT_RULES_TO_IGNORE = "EN_QUOTES";

private static final String EN_US_LANGUAGE = "en_US";
private static final String EN_GB_LANGUAGE = "en_GB";
private static final String DEFAULT_LANGUAGE = "en-US";
private static final Set<String> SUPPORTED_LANGUAGES = ImmutableSet.of("ast-ES", "be-BY", "br-FR", "ca-ES",
"ca-ES-valencia", "da-DK", "de", "de-AT", "de-CH", "de-DE", "de-DE-x-simple-language", "el-GR", "en", "en-AU",
"en-CA", "en-GB", "en-NZ", "en-US", "en-ZA", "eo", "es", "fa", "fr", "gl-ES", "is-IS", "it", "ja-JP", "km-KH",
"lt-LT", "ml-IN", "nl", "pl-PL", "pt", "pt-BR", "pt-PT", "ro-RO", "ru-RU", "sk-SK", "sl-SI", "sv", "ta-IN",
"tl-PH", "uk-UA", "zh-CN");

private static final String SUPPORTED_LANGUAGES_AS_STRING = "ast-ES, be-BY, br-FR, ca-ES, ca-ES-valencia, da-DK, "
+ "de, de-AT, de-CH, de-DE, de-DE-x-simple-language, el-GR, en, en-AU, en-CA, en-GB, en-NZ, en-US, en-ZA, eo, "
+ "es, fa, fr, gl-ES, is-IS, it, ja-JP, km-KH, lt-LT, ml-IN, nl, pl-PL, pt, pt-BR, pt-PT, ro-RO, ru-RU, sk-SK, "
+ "sl-SI, sv, ta-IN, tl-PH, uk-UA, zh-CN";

private static final String DEFAULT_LANGUAGE = EN_US_LANGUAGE;
private static final Set<String> SUPPORTED_LANGUAGES = ImmutableSet.of(EN_US_LANGUAGE, EN_GB_LANGUAGE);
private JLanguageTool languageTool;

@RuleProperty(
Expand All @@ -74,7 +79,7 @@ public class SpellingCheck extends SubscriptionVisitorCheck {

@RuleProperty(
key = "language",
description = "The language to be applied by the spell checker. Supported values are: '" + EN_US_LANGUAGE + "', '" + EN_GB_LANGUAGE + "'.",
description = "The language of the feature files. Supported values are: " + SUPPORTED_LANGUAGES_AS_STRING,
defaultValue = DEFAULT_LANGUAGE)
private String language = DEFAULT_LANGUAGE;

Expand Down Expand Up @@ -106,31 +111,16 @@ private void checkSpellingMistakes(String text, SyntaxToken token) {
token,
m.getFromPos(),
m.getToPos(),
"[" + m.getRule().getId() + "] " + m.getMessage()
+ ". Suggested correction(s): " + m.getSuggestedReplacements() + "."));
"[" + m.getRule().getId() + "] " + m.getMessage() + "."
+ (!m.getSuggestedReplacements().isEmpty() ? " Suggested correction(s): " + m.getSuggestedReplacements() + "." : "")));

} catch (IOException e) {
throw new IllegalStateException("Spell checker failed", e);
}
}

private JLanguageTool createLanguageTool() {
English dictionary;

switch (language) {
case EN_US_LANGUAGE:
dictionary = new AmericanEnglish();
break;

case EN_GB_LANGUAGE:
dictionary = new BritishEnglish();
break;

default:
throw new IllegalStateException("Unsupported spell check language: " + language);
}

JLanguageTool jLanguageTool = new JLanguageTool(dictionary);
JLanguageTool jLanguageTool = new JLanguageTool(Languages.getLanguageForShortName(language));

Arrays.stream(rulesToIgnore.split(",")).forEach(jLanguageTool::disableRule);

Expand All @@ -152,7 +142,7 @@ public void validateParameters() {
private String languageParamErrorMessage() {
return CheckUtils.paramErrorMessage(
this.getClass(),
"language parameter \"" + language + "\" is not valid. Allowed values are '" + EN_US_LANGUAGE + "' and '" + EN_GB_LANGUAGE + "'.");
"language parameter \"" + language + "\" is not valid. Allowed values are: " + SUPPORTED_LANGUAGES_AS_STRING);
}

@VisibleForTesting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

import org.sonar.check.Priority;
import org.sonar.check.Rule;
import org.sonar.plugins.gherkin.api.tree.StepPrefixTree;
import org.sonar.plugins.gherkin.api.tree.StepTree;
import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitorCheck;
import org.sonar.squidbridge.annotations.ActivatedByDefault;
import org.sonar.squidbridge.annotations.SqaleConstantRemediation;
Expand All @@ -36,11 +36,11 @@
public class StarStepPrefixCheck extends DoubleDispatchVisitorCheck {

@Override
public void visitStepPrefix(StepPrefixTree tree) {
if ("*".equals(tree.text())) {
addPreciseIssue(tree, "Replace this star prefix with one of the Given/When/Then prefixes.");
public void visitStep(StepTree tree) {
if (tree.syntacticType() == StepTree.SyntacticStepType.STAR) {
addPreciseIssue(tree.prefix(), "Replace this star prefix with one of the Given/When/Then prefixes.");
}
super.visitStepPrefix(tree);
super.visitStep(tree);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public class StepOfUnknownTypeCheck extends DoubleDispatchVisitorCheck {

@Override
public void visitStep(StepTree tree) {
if (tree.type() == StepTree.StepType.UNKNOWN) {
if (tree.semanticType() == StepTree.SemanticStepType.UNKNOWN) {
addPreciseIssue(tree.prefix(), "Update the prefix of this unknown type step.");
}
super.visitStep(tree);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,32 +53,32 @@ public void visitScenarioOutline(ScenarioOutlineTree tree) {

private void checkStepOrder(List<StepTree> steps) {

if (steps.size() < 2 || steps.stream().filter(s -> s.type() == StepTree.StepType.UNKNOWN).count() != 0) {
if (steps.size() < 2 || steps.stream().filter(s -> s.semanticType() == StepTree.SemanticStepType.UNKNOWN).count() != 0) {
return;
}

StepTree.StepType previousStepType = steps.get(0).type();
StepTree.SemanticStepType previousStepType = steps.get(0).semanticType();

search:
for (int i = 1; i < steps.size(); i++) {

switch (steps.get(i).type()) {
switch (steps.get(i).semanticType()) {
case GIVEN:
if (previousStepType != StepTree.StepType.GIVEN) {
if (previousStepType != StepTree.SemanticStepType.GIVEN) {
addPreciseIssue(steps.get(i).prefix(), "Unexpected Given step. Reorder the steps of this scenario.");
break search;
}
break;

case WHEN:
if (previousStepType != StepTree.StepType.GIVEN && previousStepType != StepTree.StepType.WHEN) {
if (previousStepType != StepTree.SemanticStepType.GIVEN && previousStepType != StepTree.SemanticStepType.WHEN) {
addPreciseIssue(steps.get(i).prefix(), "Unexpected When step. Reorder the steps of this scenario.");
break search;
}
break;

case THEN:
if (previousStepType != StepTree.StepType.WHEN && previousStepType != StepTree.StepType.THEN) {
if (previousStepType != StepTree.SemanticStepType.WHEN && previousStepType != StepTree.SemanticStepType.THEN) {
addPreciseIssue(steps.get(i).prefix(), "Unexpected Then step. Reorder the steps of this scenario.");
break search;
}
Expand All @@ -88,7 +88,7 @@ private void checkStepOrder(List<StepTree> steps) {
break;
}

previousStepType = steps.get(i).type();
previousStepType = steps.get(i).semanticType();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public class ThenStepRegularExpressionCheck extends DoubleDispatchVisitorCheck {

@Override
public void visitStep(StepTree tree) {
if (tree.type() == StepTree.StepType.THEN
if (tree.semanticType() == StepTree.SemanticStepType.THEN
&& !tree.sentence().text().matches(regularExpression)) {
addPreciseIssue(tree.sentence(), "Update the sentence to match the following regular expression: " + regularExpression);
}
Expand Down
Loading

0 comments on commit 7f2bd93

Please sign in to comment.