diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b77fdd8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# Maven +target/ + +# IntelliJ IDEA +*.iws +*.iml +*.ipr +.idea/ + +# Eclipse +.classpath +.project +.settings + +# ---- Mac OS X +.DS_Store +Icon? +# Thumbnails +._* +# Files that might appear on external disk +.Spotlight-V100 +.Trashes + +# ---- Windows +# Windows image file caches +Thumbs.db +# Folder config file +Desktop.ini + +log.txt +*~ +*versionsBackup + +.sonar/ +.sonarlint/ +sonarlint.json diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..35a2a05 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,23 @@ +language: java + +jdk: + - oraclejdk8 + +addons: + sonarqube: true + +env: + global: + - secure: "CSzKqFmcrE0QC/wDQPirPPAWQBD0jsM8urbUjis/EEb00vjroI/uSNvDdzPyR0ZvMB6AaiZmYhyfXvVjw5doIyzEaI6pKiHFGvzoQAFfPI4Or1ST7AI3c2sD3mf1FQE3T+lvpoDmGj7gA+rLWsxzrqcfWiWbkggs7E3N2PxLhXGEu4o6gbkt8kiseIiRspIwZpg7ftqL7UGefWGaYFIlf9jX0Xd9ySpCBGbquWHK9+TdgKhhl+nBR7R1SbDgUABfJbhRyTQmR1oyuz+BxwZi5w6twoZsDYiCisIBdioBCmYZNShb+7EpMZLuKPMRkVhLvlJ6aI2taw+UPqlK7r14f9TDU57Hr2cEp/k4YDJZxkaOH8Cxc5OWY9CP1cuf9t0HoK9mwBTHjbxZ5Xm0+u4b0ydUsFq5h9lH7hh9/OHeXTPjBCW9hPyWoWa1JkYikk1WwunLV8TyA6jMBKQlHNjCSADoV7AeedldwCpfRIVOZYO+cewyMxfhBwqyJEOGjuEzpuoc7VyRJnpSoTf4TQkLbG5JeTp8cZOgCRwbEPcaVU0kwYBdXSm03WkTBEyCIC01h94yk3KczVUmbzopXs0uAGoFjXIs48RG38S3D3jKJ9vZN57iTf+8bw8ywUYfnbud5Hz/O9r/cTdsjNakdNeNTmzIpaZX87VGC3DItrbOfZg=" + - secure: "mx3sD7v64/4HdNe9RCPkJun3JQ57cDVZv7tMgcb7x0RUZAjSkyGb6lenzC7MirBmjEEe2kYHtsJ/0P6qa8VeqrEhVAOHtssk9UZAc37E9Nj5x60DY7n2xG91kg9ih2li8IoKFM1ywuC2jOd0SgKXllfEN97Z3tsgL2AQdSypsasaNzKXZMZmVdHyBngBzWSlPVhnpHlD3UR60ikQyVn8UEX/28KUVap/Alg4upwC8R1RRHUfZ9W9gyg77lADJAKkd/7QIVdECVKHy9RdR091aUfx7OOhhJzRTw+O2G6Fb6lJEtQ3NqGEPUM3tQ2wp7y1P10V+DPCqZtQMVZTqPp5NJsASSYqbLEzURZzMPNMECgjd+bQbdmOQUeCsCXEWlRQA7AmX7vX9tqLsE2fbwVKuxSRwieitZ5MLp3hFZeu2m0TaREezOc6iYqf7ob5aYoCia7/LMoFa+R9w8679e3+ilveJKErhWFuEFb81oC4XDt8+Ztet249JcypwcInFyz29pITLjeAJiMWUzm7RqfSTlMXLAXd4Z+a9pH6+yocnPhGJRSQ+hXo4NZK4s8U04bU1ejF5FrNfEFfbLKbyt/Cwl7LT8L28BQK6nbPIUBAtD20RWOu+bbH8PUvYgeESmdh0YxugdFyhXqt8pSOji5yg/oP7w0ECPrqDw8x1q+Lhz8=" + matrix: + - SQ_VERSION=LTS + - SQ_VERSION=LATEST_RELEASE + - SQ_VERSION=DEV + +cache: + directories: + - '$HOME/.m2/repository' + - '$HOME/.sonar/cache' + +script: ./travis.sh diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6600f1c --- /dev/null +++ b/LICENSE @@ -0,0 +1,165 @@ +GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/README.md b/README.md new file mode 100644 index 0000000..3737159 --- /dev/null +++ b/README.md @@ -0,0 +1,69 @@ +SonarQube Cucumber Gherkin Plugin +================================= + +[![Build Status](https://api.travis-ci.org/racodond/sonar-gherkin-plugin.svg?branch=master)](https://travis-ci.org/racodond/sonar-gherkin-plugin) +[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/hhh9gsp77hatvai1/branch/master?svg=true)](https://ci.appveyor.com/project/racodond/sonar-gherkin-plugin/branch/master) +[![Quality Gate](https://sonarqube.com/api/badges/gate?key=com.racodond.sonarqube.plugin.gherkin:gherkin)](https://sonarqube.com/overview?id=com.racodond.sonarqube.plugin.gherkin%3Agherkin) + +## Description +This plugin enables code QA analysis of [Cucumber Gherkin feature files](https://github.com/cucumber/cucumber/wiki/Gherkin) within [SonarQube](http://www.sonarqube.org): + + * Computes metrics: lines of code, comments lines, etc. + * Performs more than [15 checks](#available-checks) + * Provide the ability to write your own checks + +## Usage + +1. [Download and install](http://docs.sonarqube.org/display/SONAR/Setup+and+Upgrade) SonarQube +1. Install the Cucumber Gherkin plugin either by a [direct download](https://github.com/racodond/sonar-gherkin-plugin/releases) or through the [Update Center](http://docs.sonarqube.org/display/SONAR/Update+Center). +1. [Install your favorite analyzer](http://docs.sonarqube.org/display/SONAR/Analyzing+Source+Code#AnalyzingSourceCode-RunningAnalysis) (SonarQube Scanner, Maven, Ant, etc.) and analyze your code. Note that Java 8 is required to run an analysis. + +Plugin versions and compatibility with SonarQube versions: [http://docs.sonarqube.org/display/PLUG/Plugin+Version+Matrix](http://docs.sonarqube.org/display/PLUG/Plugin+Version+Matrix) + +## Metrics + +### Statements +Number of steps. + +### Functions +Number of scenarios and scenario outlines. + +### Classes +Number of features. + + +## Available Checks + +### Standard + + * "Examples" table should contain data + * "FIXME" tags should be handled + * "TODO" tags should be handled + * All comments should be formatted consistently + * Byte Order Mark (BOM) should not be used for UTF-8 files + * End-line characters should be consistent + * Features should not contain too many scenarios + * Features that do not define any scenario should be removed + * File names should comply with a naming convention + * Files should contain an empty new line at the end + * Files that do not define any feature should be removed + * Lines should not end with trailing whitespaces + * Only tags from the whitelist should be used + * Scenarios should not contain too many steps + * Source code should be properly indented + * Star (*) step prefix should not be used + * Tabulation characters should not be used + * Tags should comply with a naming convention + +### Templates + + * Regular expression on comment + + +## Custom Checks + +You're thinking of new valuable rules? Version 1.0 or greater provides an API to write your own custom checks. +A sample plugin with detailed explanations is available [here](https://github.com/racodond/sonar-gherkin-custom-rules-plugin). +If your custom rules may benefit the community, feel free to create a pull request in order to make the rule available in the Cucumber Gherkin plugin. + +You're thinking of new rules that may benefit the community but don't have the time or the skills to write them? Feel free to create an [issue](https://github.com/racodond/sonar-gherkin-plugin/issues) for your rules to be taken under consideration. diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..86b576d --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,30 @@ +version: "{build}" + +cache: + - C:\Users\appveyor\.m2 + +install: + - SET JAVA_HOME=C:\Program Files\Java\jdk1.8.0 + - SET PATH=C:\maven\apache-maven-3.3.9\bin;%JAVA_HOME%\bin;%PATH% + + - appveyor DownloadFile http://www.us.apache.org/dist/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.zip + - 7z x apache-maven-3.3.9-bin.zip -oC:\maven + +environment: + matrix: + - SQ_VERSION: "LTS" + - SQ_VERSION: "LATEST_RELEASE" + - SQ_VERSION: "DEV" + +platform: + - x86 + - x64 + +build_script: + - mvn clean install -DskipTests=true -Dmaven.javadoc.skip=true -B + +test_script: + - mvn clean install -B + - cd its + - mvn -B clean install -Dsonar.runtimeVersion=%SQ_VERSION% + diff --git a/gherkin-checks-testkit/pom.xml b/gherkin-checks-testkit/pom.xml new file mode 100644 index 0000000..cba2b2b --- /dev/null +++ b/gherkin-checks-testkit/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + + com.racodond.sonarqube.plugin.gherkin + gherkin + 1.0-SNAPSHOT + + + gherkin-checks-testkit + SonarQube Gherkin Analyzer :: Check Test Toolkit + + + + ${project.groupId} + gherkin-frontend + + + org.sonarsource.sonarqube + sonar-plugin-api + + + org.sonarsource.sslr-squid-bridge + sslr-squid-bridge + + + junit + junit + + + org.easytesting + fest-assert + + + + + + + org.jacoco + jacoco-maven-plugin + + ${sonar.jacoco.reportPath} + + + + + + \ No newline at end of file diff --git a/gherkin-checks-testkit/src/main/java/org/sonar/gherkin/checks/verifier/GherkinCheckVerifier.java b/gherkin-checks-testkit/src/main/java/org/sonar/gherkin/checks/verifier/GherkinCheckVerifier.java new file mode 100644 index 0000000..543df9e --- /dev/null +++ b/gherkin-checks-testkit/src/main/java/org/sonar/gherkin/checks/verifier/GherkinCheckVerifier.java @@ -0,0 +1,325 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks.verifier; + +import com.google.common.base.Charsets; +import com.google.common.base.Function; +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Ordering; +import org.sonar.gherkin.parser.GherkinParserBuilder; +import org.sonar.gherkin.visitors.CharsetAwareVisitor; +import org.sonar.gherkin.visitors.GherkinVisitorContext; +import org.sonar.plugins.gherkin.api.GherkinCheck; +import org.sonar.plugins.gherkin.api.tree.GherkinDocumentTree; +import org.sonar.plugins.gherkin.api.tree.SyntaxToken; +import org.sonar.plugins.gherkin.api.tree.SyntaxTrivia; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.SubscriptionVisitorCheck; +import org.sonar.plugins.gherkin.api.visitors.issue.*; +import org.sonar.squidbridge.checks.CheckMessagesVerifier; + +import javax.annotation.Nullable; +import java.io.File; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; + +import static org.fest.assertions.Assertions.assertThat; +import static org.junit.Assert.fail; + +/** + * To unit test checks. + */ +public class GherkinCheckVerifier extends SubscriptionVisitorCheck { + + private final List expectedIssues = new ArrayList<>(); + + /** + * Check issues + * + * @param check Check to test + * @param file File to test + *

+ * Example: + *

+   *                             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();
+   *                           
+ */ + public static CheckMessagesVerifier issues(GherkinCheck check, File file) { + return issues(check, file, Charsets.UTF_8); + } + + /** + * See {@link GherkinCheckVerifier#issues(GherkinCheck, File)} + * + * @param charset Charset of the file to test. + */ + public static CheckMessagesVerifier issues(GherkinCheck check, File file, Charset charset) { + if (check instanceof CharsetAwareVisitor) { + ((CharsetAwareVisitor) check).setCharset(charset); + } + return CheckMessagesVerifier.verify(TreeCheckTest.getIssues(file.getAbsolutePath(), check, charset)); + } + + /** + * To unit tests checks. Expected issues should be provided as comments in the source file. + * Expected issue details should be provided the line prior to the actual issue. + * For example: + *
+   * # Noncompliant {{Error message for the issue on the next line}}
+   * MyProperty=abc
+   *
+   * # Noncompliant [[sc=2;ec=6;secondary=+2,+4]] {{Error message}}
+   * ...
+   * 
+ *

+ * How to write these comments: + *

+ *

+ * Example of call: + *

+   * GherkinCheckVerifier.verify(new MyCheck(), myFile));
+   * 
+ */ + public static void verify(GherkinCheck check, File file) { + verify(check, file, Charsets.UTF_8); + } + + /** + * See {@link GherkinCheckVerifier#verify(GherkinCheck, 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); + GherkinVisitorContext context = new GherkinVisitorContext(propertiesTree, file); + + GherkinCheckVerifier checkVerifier = new GherkinCheckVerifier(); + checkVerifier.scanFile(context); + + List expectedIssues = checkVerifier.expectedIssues + .stream() + .sorted((i1, i2) -> Integer.compare(i1.line(), i2.line())) + .collect(Collectors.toList()); + + if (check instanceof CharsetAwareVisitor) { + ((CharsetAwareVisitor) check).setCharset(charset); + } + Iterator actualIssues = getActualIssues(check, context); + + for (TestIssue expected : expectedIssues) { + if (actualIssues.hasNext()) { + verifyIssue(expected, actualIssues.next()); + } else { + throw new AssertionError("Missing issue at line " + expected.line()); + } + } + + if (actualIssues.hasNext()) { + Issue issue = actualIssues.next(); + throw new AssertionError("Unexpected issue at line " + line(issue) + ": \"" + message(issue) + "\""); + } + } + + private static Iterator getActualIssues(GherkinCheck check, GherkinVisitorContext context) { + List issues = check.scanFile(context); + List sortedIssues = Ordering.natural().onResultOf(new IssueToLine()).sortedCopy(issues); + return sortedIssues.iterator(); + } + + private static void verifyIssue(TestIssue expected, Issue actual) { + if (line(actual) > expected.line()) { + fail("Missing issue at line " + expected.line()); + } + if (line(actual) < expected.line()) { + fail("Unexpected issue at line " + line(actual) + ": \"" + message(actual) + "\""); + } + if (expected.message() != null) { + assertThat(message(actual)).as("Bad message at line " + expected.line()).isEqualTo(expected.message()); + } + if (expected.effortToFix() != null) { + assertThat(actual.cost()).as("Bad effortToFix at line " + expected.line()).isEqualTo(expected.effortToFix()); + } + if (expected.startColumn() != null) { + assertThat(((PreciseIssue) actual).primaryLocation().startLineOffset() + 1).as("Bad start column at line " + expected.line()).isEqualTo(expected.startColumn()); + } + if (expected.endColumn() != null) { + assertThat(((PreciseIssue) actual).primaryLocation().endLineOffset() + 1).as("Bad end column at line " + expected.line()).isEqualTo(expected.endColumn()); + } + if (expected.endLine() != null) { + assertThat(((PreciseIssue) actual).primaryLocation().endLine()).as("Bad end line at line " + expected.line()).isEqualTo(expected.endLine()); + } + if (expected.secondaryLines() != null) { + assertThat(secondary(actual)).as("Bad secondary locations at line " + expected.line()).isEqualTo(expected.secondaryLines()); + } + } + + @Override + public List nodesToVisit() { + return ImmutableList.of(Tree.Kind.TOKEN); + } + + @Override + public void visitNode(Tree tree) { + SyntaxToken token = (SyntaxToken) tree; + for (SyntaxTrivia trivia : token.trivias()) { + + String text = trivia.text().substring(2).trim(); + String marker = "Noncompliant"; + + if (text.startsWith(marker)) { + TestIssue issue = issue(null, trivia.line() + 1); + String paramsAndMessage = text.substring(marker.length()).trim(); + if (paramsAndMessage.startsWith("[[")) { + int endIndex = paramsAndMessage.indexOf("]]"); + addParams(issue, paramsAndMessage.substring(2, endIndex)); + paramsAndMessage = paramsAndMessage.substring(endIndex + 2).trim(); + } + if (paramsAndMessage.startsWith("{{")) { + int endIndex = paramsAndMessage.indexOf("}}"); + String message = paramsAndMessage.substring(2, endIndex); + issue.message(message); + } + expectedIssues.add(issue); + } + } + } + + private static void addParams(TestIssue issue, String params) { + for (String param : Splitter.on(';').split(params)) { + int equalIndex = param.indexOf('='); + if (equalIndex == -1) { + throw new IllegalStateException("Invalid param at line 1: " + param); + } + String name = param.substring(0, equalIndex); + String value = param.substring(equalIndex + 1); + + if ("effortToFix".equalsIgnoreCase(name)) { + issue.effortToFix(Integer.valueOf(value)); + + } else if ("sc".equalsIgnoreCase(name)) { + issue.startColumn(Integer.valueOf(value)); + + } else if ("sl".equalsIgnoreCase(name)) { + issue.startLine(lineValue(issue.line() - 1, value)); + + } else if ("ec".equalsIgnoreCase(name)) { + issue.endColumn(Integer.valueOf(value)); + + } else if ("el".equalsIgnoreCase(name)) { + issue.endLine(lineValue(issue.line(), value)); + + } else if ("secondary".equalsIgnoreCase(name)) { + addSecondaryLines(issue, value); + + } else { + throw new IllegalStateException("Invalid param at line 1: " + name); + } + } + } + + private static void addSecondaryLines(TestIssue issue, String value) { + List secondaryLines = new ArrayList<>(); + if (!"".equals(value)) { + for (String secondary : Splitter.on(',').split(value)) { + secondaryLines.add(lineValue(issue.line(), secondary)); + } + } + issue.secondary(secondaryLines); + } + + private static int lineValue(int baseLine, String shift) { + if (shift.startsWith("+")) { + return baseLine + Integer.valueOf(shift.substring(1)); + } + if (shift.startsWith("-")) { + return baseLine - Integer.valueOf(shift.substring(1)); + } + return Integer.valueOf(shift); + } + + private static TestIssue issue(@Nullable String message, int lineNumber) { + return TestIssue.create(message, lineNumber); + } + + private static class IssueToLine implements Function { + @Override + public Integer apply(Issue issue) { + return line(issue); + } + } + + private static int line(Issue issue) { + if (issue instanceof PreciseIssue) { + return ((PreciseIssue) issue).primaryLocation().startLine(); + } else if (issue instanceof FileIssue) { + return 0; + } else if (issue instanceof LineIssue) { + return ((LineIssue) issue).line(); + } else { + throw new IllegalStateException("Unknown type of issue."); + } + } + + private static String message(Issue issue) { + if (issue instanceof PreciseIssue) { + return ((PreciseIssue) issue).primaryLocation().message(); + } else if (issue instanceof FileIssue) { + return ((FileIssue) issue).message(); + } else if (issue instanceof LineIssue) { + return ((LineIssue) issue).message(); + } else { + throw new IllegalStateException("Unknown type of issue."); + } + } + + private static List secondary(Issue issue) { + List result = new ArrayList<>(); + + if (issue instanceof PreciseIssue) { + result.addAll(((PreciseIssue) issue).secondaryLocations() + .stream() + .map(IssueLocation::startLine) + .collect(Collectors.toList())); + } else if (issue instanceof FileIssue) { + result.addAll(((FileIssue) issue).secondaryLocations() + .stream() + .map(IssueLocation::startLine) + .collect(Collectors.toList())); + } + return Ordering.natural().sortedCopy(result); + } + +} diff --git a/gherkin-checks-testkit/src/main/java/org/sonar/gherkin/checks/verifier/TestIssue.java b/gherkin-checks-testkit/src/main/java/org/sonar/gherkin/checks/verifier/TestIssue.java new file mode 100644 index 0000000..b52b78d --- /dev/null +++ b/gherkin-checks-testkit/src/main/java/org/sonar/gherkin/checks/verifier/TestIssue.java @@ -0,0 +1,112 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks.verifier; + +import com.google.common.primitives.Ints; + +import javax.annotation.Nullable; +import java.util.List; + +class TestIssue { + + private String message; + private int line; + private Integer effortToFix = null; + private Integer startColumn = null; + private Integer endColumn = null; + private Integer endLine = null; + private List secondaryLines = null; + + private TestIssue(@Nullable String message, int line) { + this.message = message; + this.line = line; + } + + public static TestIssue create(@Nullable String message, int lineNumber) { + return new TestIssue(message, lineNumber); + } + + public TestIssue message(String message) { + this.message = message; + return this; + } + + public TestIssue startColumn(int startColumn) { + this.startColumn = startColumn; + return this; + } + + public TestIssue endColumn(int endColumn) { + this.endColumn = endColumn; + return this; + } + + public TestIssue effortToFix(int effortToFix) { + this.effortToFix = effortToFix; + return this; + } + + public TestIssue startLine(int startLine) { + this.line = startLine; + return this; + } + + public TestIssue endLine(int endLine) { + this.endLine = endLine; + return this; + } + + public TestIssue secondary(int... lines) { + return secondary(Ints.asList(lines)); + } + + public TestIssue secondary(List secondaryLines) { + this.secondaryLines = secondaryLines; + return this; + } + + public int line() { + return line; + } + + public Integer startColumn() { + return startColumn; + } + + public Integer endLine() { + return endLine; + } + + public Integer endColumn() { + return endColumn; + } + + public String message() { + return message; + } + + public Integer effortToFix() { + return effortToFix; + } + + public List secondaryLines() { + return secondaryLines; + } +} diff --git a/gherkin-checks-testkit/src/main/java/org/sonar/gherkin/checks/verifier/TreeCheckTest.java b/gherkin-checks-testkit/src/main/java/org/sonar/gherkin/checks/verifier/TreeCheckTest.java new file mode 100644 index 0000000..9f98f42 --- /dev/null +++ b/gherkin-checks-testkit/src/main/java/org/sonar/gherkin/checks/verifier/TreeCheckTest.java @@ -0,0 +1,82 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks.verifier; + +import org.sonar.gherkin.parser.GherkinParserBuilder; +import org.sonar.gherkin.visitors.GherkinVisitorContext; +import org.sonar.plugins.gherkin.api.GherkinCheck; +import org.sonar.plugins.gherkin.api.tree.GherkinDocumentTree; +import org.sonar.plugins.gherkin.api.visitors.issue.FileIssue; +import org.sonar.plugins.gherkin.api.visitors.issue.Issue; +import org.sonar.plugins.gherkin.api.visitors.issue.LineIssue; +import org.sonar.plugins.gherkin.api.visitors.issue.PreciseIssue; +import org.sonar.squidbridge.api.CheckMessage; + +import java.io.File; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +class TreeCheckTest { + + private TreeCheckTest() { + } + + public static Collection getIssues(String relativePath, GherkinCheck check, Charset charset) { + File file = new File(relativePath); + + GherkinDocumentTree propertiesTree = (GherkinDocumentTree) GherkinParserBuilder.createParser(charset).parse(file); + GherkinVisitorContext context = new GherkinVisitorContext(propertiesTree, file); + List issues = check.scanFile(context); + + return getCheckMessages(issues); + } + + private static Collection getCheckMessages(List issues) { + List checkMessages = new ArrayList<>(); + for (Issue issue : issues) { + CheckMessage checkMessage; + if (issue instanceof FileIssue) { + FileIssue fileIssue = (FileIssue) issue; + checkMessage = new CheckMessage(fileIssue.check(), fileIssue.message()); + + } else if (issue instanceof LineIssue) { + LineIssue lineIssue = (LineIssue) issue; + checkMessage = new CheckMessage(lineIssue.check(), lineIssue.message()); + checkMessage.setLine(lineIssue.line()); + + } else { + PreciseIssue preciseIssue = (PreciseIssue) issue; + checkMessage = new CheckMessage(preciseIssue.check(), preciseIssue.primaryLocation().message()); + checkMessage.setLine(preciseIssue.primaryLocation().startLine()); + } + + if (issue.cost() != null) { + checkMessage.setCost(issue.cost()); + } + + checkMessages.add(checkMessage); + } + + return checkMessages; + } + +} diff --git a/gherkin-checks-testkit/src/main/java/org/sonar/gherkin/checks/verifier/package-info.java b/gherkin-checks-testkit/src/main/java/org/sonar/gherkin/checks/verifier/package-info.java new file mode 100644 index 0000000..a9b4e9d --- /dev/null +++ b/gherkin-checks-testkit/src/main/java/org/sonar/gherkin/checks/verifier/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +@ParametersAreNonnullByDefault +package org.sonar.gherkin.checks.verifier; + +import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/gherkin-checks/pom.xml b/gherkin-checks/pom.xml new file mode 100644 index 0000000..f47dcbd --- /dev/null +++ b/gherkin-checks/pom.xml @@ -0,0 +1,66 @@ + + + 4.0.0 + + + com.racodond.sonarqube.plugin.gherkin + gherkin + 1.0-SNAPSHOT + + + gherkin-checks + SonarQube Gherkin Analyzer :: Checks + + + + ${project.groupId} + gherkin-frontend + + + ${project.groupId} + gherkin-checks-testkit + + + org.sonarsource.sonarqube + sonar-plugin-api + + + com.google.guava + guava + + + commons-lang + commons-lang + + + junit + junit + test + + + org.hamcrest + hamcrest-all + test + + + org.mockito + mockito-all + test + + + + + + + org.jacoco + jacoco-maven-plugin + + ${sonar.jacoco.reportPath} + + + + + + + diff --git a/gherkin-checks/src/main/java/org/sonar/gherkin/checks/AllowedTagsCheck.java b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/AllowedTagsCheck.java new file mode 100644 index 0000000..997641b --- /dev/null +++ b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/AllowedTagsCheck.java @@ -0,0 +1,71 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Splitter; +import com.google.common.collect.Lists; +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.check.RuleProperty; +import org.sonar.plugins.gherkin.api.tree.GherkinDocumentTree; +import org.sonar.plugins.gherkin.api.tree.TagTree; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitorCheck; +import org.sonar.squidbridge.annotations.SqaleConstantRemediation; + +import java.util.List; + +@Rule( + key = "allowed-tags", + name = "Only tags from the whitelist should be used", + priority = Priority.MINOR, + tags = {Tags.CONVENTION}) +@SqaleConstantRemediation("5min") +public class AllowedTagsCheck extends DoubleDispatchVisitorCheck { + + private static final String DEFAULT = "smoke,nrt"; + private List listOfAllowedTags; + + @RuleProperty( + key = "allowedTags", + defaultValue = DEFAULT, + description = "Comma-separated list of allowed tags.") + private String allowedTags = DEFAULT; + + @Override + public void visitGherkinDocument(GherkinDocumentTree tree) { + listOfAllowedTags = Lists.newArrayList(Splitter.on(",").split(allowedTags)); + super.visitGherkinDocument(tree); + } + + @Override + public void visitTag(TagTree tree) { + if (!listOfAllowedTags.contains(tree.text())) { + addPreciseIssue(tree, "Remove this tag that is not in the whitelist."); + } + super.visitTag(tree); + } + + @VisibleForTesting + void setAllowedTags(String allowedTags) { + this.allowedTags = allowedTags; + } + +} diff --git a/gherkin-checks/src/main/java/org/sonar/gherkin/checks/BOMCheck.java b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/BOMCheck.java new file mode 100644 index 0000000..608382d --- /dev/null +++ b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/BOMCheck.java @@ -0,0 +1,57 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import com.google.common.base.Charsets; +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.gherkin.visitors.CharsetAwareVisitor; +import org.sonar.plugins.gherkin.api.tree.GherkinDocumentTree; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitorCheck; +import org.sonar.squidbridge.annotations.ActivatedByDefault; +import org.sonar.squidbridge.annotations.SqaleConstantRemediation; + +import java.nio.charset.Charset; + +@Rule( + key = "bom-utf8-files", + name = "Byte Order Mark (BOM) should not be used for UTF-8 files", + priority = Priority.MAJOR, + tags = {Tags.PITFALL}) +@SqaleConstantRemediation("5min") +@ActivatedByDefault +public class BOMCheck extends DoubleDispatchVisitorCheck implements CharsetAwareVisitor { + + private Charset charset; + + @Override + public void visitGherkinDocument(GherkinDocumentTree tree) { + if (Charsets.UTF_8.equals(charset) && tree.hasByteOrderMark()) { + addFileIssue("Remove the Byte Order Mark (BOM)."); + } + super.visitGherkinDocument(tree); + } + + @Override + public void setCharset(Charset charset) { + this.charset = charset; + } + +} diff --git a/gherkin-checks/src/main/java/org/sonar/gherkin/checks/CheckUtils.java b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/CheckUtils.java new file mode 100644 index 0000000..1960c04 --- /dev/null +++ b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/CheckUtils.java @@ -0,0 +1,37 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.sonar.check.Rule; + +public class CheckUtils { + + public static final String LINK_TO_JAVA_REGEX_PATTERN_DOC = "http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html"; + + private CheckUtils() { + } + + public static String paramsErrorMessage(Class clazz, String message) { + return "Check gherkin:" + ((Rule) clazz.getAnnotation(Rule.class)).key() + + " (" + ((Rule) clazz.getAnnotation(Rule.class)).name() + "): " + + message; + } + +} diff --git a/gherkin-checks/src/main/java/org/sonar/gherkin/checks/CommentContainsPatternChecker.java b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/CommentContainsPatternChecker.java new file mode 100644 index 0000000..5090efd --- /dev/null +++ b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/CommentContainsPatternChecker.java @@ -0,0 +1,56 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.apache.commons.lang.StringUtils; +import org.sonar.plugins.gherkin.api.tree.SyntaxTrivia; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitorCheck; + +public class +CommentContainsPatternChecker extends DoubleDispatchVisitorCheck { + + private final String pattern; + private final String message; + + public CommentContainsPatternChecker(String pattern, String message) { + this.pattern = pattern; + this.message = message; + } + + @Override + public void visitComment(SyntaxTrivia trivia) { + String comment = trivia.text(); + if (StringUtils.containsIgnoreCase(comment, pattern) && !isLetterAround(comment, pattern)) { + addPreciseIssue(trivia, message); + } + super.visitComment(trivia); + } + + private static boolean isLetterAround(String line, String pattern) { + int start = StringUtils.indexOfIgnoreCase(line, pattern); + int end = start + pattern.length(); + + boolean pre = start > 0 && Character.isLetter(line.charAt(start - 1)); + boolean post = end < line.length() - 1 && Character.isLetter(line.charAt(end)); + + return pre || post; + } + +} diff --git a/gherkin-checks/src/main/java/org/sonar/gherkin/checks/CommentConventionCheck.java b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/CommentConventionCheck.java new file mode 100644 index 0000000..8ed6ec3 --- /dev/null +++ b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/CommentConventionCheck.java @@ -0,0 +1,46 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.plugins.gherkin.api.tree.SyntaxTrivia; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitorCheck; +import org.sonar.squidbridge.annotations.ActivatedByDefault; +import org.sonar.squidbridge.annotations.SqaleConstantRemediation; + +@Rule( + key = "comment-convention", + name = "All comments should be formatted consistently", + priority = Priority.MINOR, + tags = {Tags.CONVENTION}) +@SqaleConstantRemediation("1min") +@ActivatedByDefault +public class CommentConventionCheck extends DoubleDispatchVisitorCheck { + + @Override + public void visitComment(SyntaxTrivia trivia) { + if (trivia.text().length() > 1 && !" ".equals(trivia.text().substring(1, 2))) { + addPreciseIssue(trivia, "Add a whitespace after the starting comment token."); + } + super.visitComment(trivia); + } + +} diff --git a/gherkin-checks/src/main/java/org/sonar/gherkin/checks/CommentRegularExpressionCheck.java b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/CommentRegularExpressionCheck.java new file mode 100644 index 0000000..20f7d9d --- /dev/null +++ b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/CommentRegularExpressionCheck.java @@ -0,0 +1,77 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.check.RuleProperty; +import org.sonar.plugins.gherkin.api.tree.SyntaxTrivia; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitorCheck; +import org.sonar.squidbridge.annotations.RuleTemplate; + +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +@Rule( + key = "comment-regular-expression", + name = "Regular expression on comment", + priority = Priority.MAJOR) +@RuleTemplate +public class CommentRegularExpressionCheck extends DoubleDispatchVisitorCheck { + + private static final String DEFAULT_REGULAR_EXPRESSION = ".*"; + private static final String DEFAULT_MESSAGE = "The regular expression matches this comment."; + + @RuleProperty( + key = "regularExpression", + description = "The regular expression. See " + CheckUtils.LINK_TO_JAVA_REGEX_PATTERN_DOC + " for detailed regular expression syntax.", + defaultValue = DEFAULT_REGULAR_EXPRESSION) + public String regularExpression = DEFAULT_REGULAR_EXPRESSION; + + @RuleProperty( + key = "message", + description = "The issue message", + defaultValue = DEFAULT_MESSAGE) + public String message = DEFAULT_MESSAGE; + + @Override + public void visitComment(SyntaxTrivia trivia) { + if (trivia.text().matches(regularExpression)) { + addPreciseIssue(trivia, message); + } + super.visitComment(trivia); + } + + @Override + public void validateParameters() { + try { + Pattern.compile(regularExpression); + } catch (PatternSyntaxException exception) { + throw new IllegalStateException(paramsErrorMessage(), exception); + } + } + + private String paramsErrorMessage() { + return CheckUtils.paramsErrorMessage( + this.getClass(), + "regularExpression parameter \"" + regularExpression + "\" is not a valid regular expression."); + } + +} diff --git a/gherkin-checks/src/main/java/org/sonar/gherkin/checks/EndLineCharactersCheck.java b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/EndLineCharactersCheck.java new file mode 100644 index 0000000..497511c --- /dev/null +++ b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/EndLineCharactersCheck.java @@ -0,0 +1,96 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.io.Files; +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.check.RuleProperty; +import org.sonar.gherkin.visitors.CharsetAwareVisitor; +import org.sonar.plugins.gherkin.api.tree.GherkinDocumentTree; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitorCheck; +import org.sonar.squidbridge.annotations.SqaleConstantRemediation; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.regex.Pattern; + +@Rule( + key = "end-line-characters", + name = "End-line characters should be consistent", + priority = Priority.MINOR, + tags = {Tags.CONVENTION}) +@SqaleConstantRemediation("5min") +public class EndLineCharactersCheck extends DoubleDispatchVisitorCheck implements CharsetAwareVisitor { + + private static final String DEFAULT_FORMAT = "LF"; + private Charset charset; + + @RuleProperty( + key = "End-line character", + description = "Allowed values: 'CR', 'CRLF', 'LF'", + defaultValue = DEFAULT_FORMAT) + private String endLineCharacters = DEFAULT_FORMAT; + + @Override + public void visitGherkinDocument(GherkinDocumentTree tree) { + if (fileContainsIllegalEndLineCharacters()) { + addFileIssue("Set all end-line characters to '" + endLineCharacters + "' in this file."); + } + super.visitGherkinDocument(tree); + } + + @Override + public void validateParameters() { + if (!Arrays.asList("CRLF", "CR", "LF").contains(endLineCharacters)) { + throw new IllegalStateException(paramsErrorMessage()); + } + } + + @Override + public void setCharset(Charset charset) { + this.charset = charset; + } + + @VisibleForTesting + void setEndLineCharacters(String endLineCharacters) { + this.endLineCharacters = endLineCharacters; + } + + private boolean fileContainsIllegalEndLineCharacters() { + try { + String fileContent = Files.toString(getContext().getFile(), charset); + return "CR".equals(endLineCharacters) && Pattern.compile("(?s)\n").matcher(fileContent).find() + || "LF".equals(endLineCharacters) && Pattern.compile("(?s)\r").matcher(fileContent).find() + || "CRLF".equals(endLineCharacters) && Pattern.compile("(?s)(\r(?!\n)|(? nodesToVisit() { + return ImmutableList.of( + Tree.Kind.FEATURE_DECLARATION, + Tree.Kind.BACKGROUND, + 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 + ); + } + + @Override + public void visitNode(Tree tree) { + checkAllPrefixesIndentation(tree); + checkAllDescriptionsIndentation(tree); + checkAllTagsIndentation(tree); + checkAllTablesIndentation(tree); + checkDocStringsIndentation(tree); + } + + @VisibleForTesting + void setIndentation(int indentation) { + this.indentation = indentation; + } + + private void checkAllDescriptionsIndentation(Tree tree) { + if (tree instanceof Descriptionable) { + int expectedIndentation; + int leftSiblingLine; + + switch (tree.getKind()) { + case FEATURE_DECLARATION: + expectedIndentation = indentation; + leftSiblingLine = ((FeatureDeclarationTree) tree).name().value().line(); + break; + + case BACKGROUND: + expectedIndentation = indentation * 2; + leftSiblingLine = ((BackgroundTree) tree).colon().line(); + break; + + case SCENARIO: + case SCENARIO_OUTLINE: + expectedIndentation = indentation * 2; + leftSiblingLine = ((BasicScenarioTree) tree).name().value().line(); + break; + + case EXAMPLES: + expectedIndentation = indentation * 3; + leftSiblingLine = ((ExamplesTree) tree).colon().line(); + break; + + default: + throw new IllegalStateException("Unsupported Descriptionable: " + tree.toString()); + } + + checkDescriptionLinesIndentation(((Descriptionable) tree).description(), expectedIndentation, leftSiblingLine); + } + } + + private void checkDescriptionLinesIndentation(@Nullable DescriptionTree description, int expectedIndentation, int leftSiblingLine) { + if (description != null) { + description.descriptionLines() + .stream() + .filter(d -> d.line() != leftSiblingLine) + .forEach(d -> checkIndentation(d, expectedIndentation)); + } + } + + private void checkAllPrefixesIndentation(Tree tree) { + if (tree instanceof PrefixTree) { + int expectedIndentation; + + switch (tree.getKind()) { + case FEATURE_PREFIX: + expectedIndentation = 0; + break; + + case BACKGROUND_PREFIX: + case SCENARIO_PREFIX: + case SCENARIO_OUTLINE_PREFIX: + expectedIndentation = indentation; + break; + + case EXAMPLES_PREFIX: + case STEP_PREFIX: + expectedIndentation = indentation * 2; + break; + + default: + throw new IllegalStateException("Unsupported PrefixTree: " + tree.toString()); + } + + checkIndentation(((PrefixTree) tree).keyword(), expectedIndentation); + } + } + + private void checkAllTagsIndentation(Tree tree) { + if (tree instanceof Taggable) { + int expectedIndentation; + + switch (tree.getKind()) { + case FEATURE_DECLARATION: + expectedIndentation = 0; + break; + + case BACKGROUND: + case SCENARIO: + case SCENARIO_OUTLINE: + expectedIndentation = indentation; + break; + + case EXAMPLES: + expectedIndentation = indentation * 2; + break; + + default: + throw new IllegalStateException("Unsupported Taggable: " + tree.toString()); + } + + checkTagsIndentation(((Taggable) tree).tags(), expectedIndentation); + } + + } + + private void checkTagsIndentation(List tags, int expectedIndentation) { + int previousTagLine = 0; + for (TagTree tag : tags) { + if (tag.prefix().line() != previousTagLine) { + checkIndentation(tag.prefix(), expectedIndentation); + previousTagLine = tag.prefix().line(); + } + } + } + + private void checkAllTablesIndentation(Tree tree) { + if (tree.is(Tree.Kind.TABLE)) { + ((TableTree) tree).rows().forEach(d -> checkIndentation(d, indentation * 3)); + } + } + + private void checkDocStringsIndentation(Tree tree) { + if (tree.is(Tree.Kind.DOC_STRING)) { + checkIndentation(((DocStringTree) tree).prefix(), indentation * 3); + checkIndentation(((DocStringTree) tree).suffix(), indentation * 3); + } + } + + private void checkIndentation(SyntaxToken token, int expectedIndentation) { + if (token.column() != expectedIndentation) { + addLineIssue( + token.line(), + "Indent this line at column " + expectedIndentation + " (currently indented at column " + token.column() + ")."); + } + } + +} diff --git a/gherkin-checks/src/main/java/org/sonar/gherkin/checks/MaxNumberScenariosCheck.java b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/MaxNumberScenariosCheck.java new file mode 100644 index 0000000..bbf19ff --- /dev/null +++ b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/MaxNumberScenariosCheck.java @@ -0,0 +1,66 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import com.google.common.annotations.VisibleForTesting; +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.check.RuleProperty; +import org.sonar.plugins.gherkin.api.tree.FeatureTree; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitorCheck; +import org.sonar.squidbridge.annotations.ActivatedByDefault; +import org.sonar.squidbridge.annotations.SqaleConstantRemediation; + +@Rule( + key = "max-number-scenarios", + name = "Features should not contain too many scenarios", + priority = Priority.MAJOR, + tags = {Tags.UNDERSTANDABILITY}) +@SqaleConstantRemediation("30min") +@ActivatedByDefault +public class MaxNumberScenariosCheck extends DoubleDispatchVisitorCheck { + + private static final int DEFAULT = 12; + + @RuleProperty( + key = "threshold", + defaultValue = DEFAULT + "", + description = "Maximum number of scenarios per feature.") + private int threshold = DEFAULT; + + @Override + public void visitFeature(FeatureTree tree) { + if (tree.allScenarios().size() > threshold) { + addPreciseIssue( + tree.declaration().prefix(), + "The number of scenarios (" + tree.allScenarios().size() + ") is greater that the maximum allowed (" + + threshold + "). Split the scenarios into different features."); + } + + super.visitFeature(tree); + } + + @VisibleForTesting + void setThreshold(int threshold) { + this.threshold = threshold; + } + + +} diff --git a/gherkin-checks/src/main/java/org/sonar/gherkin/checks/MaxNumberStepsCheck.java b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/MaxNumberStepsCheck.java new file mode 100644 index 0000000..499bf5a --- /dev/null +++ b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/MaxNumberStepsCheck.java @@ -0,0 +1,66 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import com.google.common.annotations.VisibleForTesting; +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.check.RuleProperty; +import org.sonar.plugins.gherkin.api.tree.FeatureTree; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitorCheck; +import org.sonar.squidbridge.annotations.ActivatedByDefault; +import org.sonar.squidbridge.annotations.SqaleConstantRemediation; + +@Rule( + key = "max-number-steps", + name = "Scenarios should not contain too many steps", + priority = Priority.MAJOR, + tags = {Tags.UNDERSTANDABILITY}) +@SqaleConstantRemediation("30min") +@ActivatedByDefault +public class MaxNumberStepsCheck extends DoubleDispatchVisitorCheck { + + private static final int DEFAULT = 12; + + @RuleProperty( + key = "threshold", + defaultValue = DEFAULT + "", + description = "Maximum number of steps per scenario.") + private int threshold = DEFAULT; + + @Override + public void visitFeature(FeatureTree tree) { + int numberOfBackgroundSteps = tree.background() != null ? tree.background().steps().size() : 0; + + tree.allScenarios() + .stream() + .filter(s -> s.steps().size() + numberOfBackgroundSteps > threshold) + .forEach(s -> addPreciseIssue(s.prefix(), "Reduce the number of steps (" + (s.steps().size() + numberOfBackgroundSteps) + ", greater than " + threshold + " allowed)")); + + super.visitFeature(tree); + } + + @VisibleForTesting + void setThreshold(int threshold) { + this.threshold = threshold; + } + + +} diff --git a/gherkin-checks/src/main/java/org/sonar/gherkin/checks/MissingNewlineAtEndOfFileCheck.java b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/MissingNewlineAtEndOfFileCheck.java new file mode 100644 index 0000000..78d9597 --- /dev/null +++ b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/MissingNewlineAtEndOfFileCheck.java @@ -0,0 +1,67 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.plugins.gherkin.api.tree.GherkinDocumentTree; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitorCheck; +import org.sonar.squidbridge.annotations.ActivatedByDefault; +import org.sonar.squidbridge.annotations.SqaleConstantRemediation; + +import java.io.IOException; +import java.io.RandomAccessFile; + +@Rule( + key = "empty-line-end-of-file", + name = "Files should contain an empty new line at the end", + priority = Priority.MINOR, + tags = {Tags.CONVENTION}) +@SqaleConstantRemediation("1min") +@ActivatedByDefault +public class MissingNewlineAtEndOfFileCheck extends DoubleDispatchVisitorCheck { + + @Override + public void visitGherkinDocument(GherkinDocumentTree tree) { + try (RandomAccessFile randomAccessFile = new RandomAccessFile(getContext().getFile(), "r")) { + if (!endsWithNewline(randomAccessFile)) { + addFileIssue("Add an empty new line at the end of this file."); + } + } catch (IOException e) { + throw new IllegalStateException("Check gherkin:" + this.getClass().getAnnotation(Rule.class).key() + + ": Error while reading " + getContext().getFile().getName(), e); + } + super.visitGherkinDocument(tree); + } + + private static boolean endsWithNewline(RandomAccessFile randomAccessFile) throws IOException { + if (randomAccessFile.length() < 1) { + return false; + } + randomAccessFile.seek(randomAccessFile.length() - 1); + byte[] chars = new byte[1]; + if (randomAccessFile.read(chars) < 1) { + return false; + } + String ch = new String(chars); + return "\n".equals(ch) || "\r".equals(ch); + } + +} diff --git a/gherkin-checks/src/main/java/org/sonar/gherkin/checks/NoFeatureCheck.java b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/NoFeatureCheck.java new file mode 100644 index 0000000..fd32acd --- /dev/null +++ b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/NoFeatureCheck.java @@ -0,0 +1,46 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.plugins.gherkin.api.tree.GherkinDocumentTree; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitorCheck; +import org.sonar.squidbridge.annotations.ActivatedByDefault; +import org.sonar.squidbridge.annotations.SqaleConstantRemediation; + +@Rule( + key = "no-feature", + name = "Files that do not define any feature should be removed", + priority = Priority.MAJOR, + tags = {Tags.PITFALL}) +@SqaleConstantRemediation("5min") +@ActivatedByDefault +public class NoFeatureCheck extends DoubleDispatchVisitorCheck { + + @Override + public void visitGherkinDocument(GherkinDocumentTree tree) { + if (tree.feature() == null) { + addFileIssue("Remove this file that does not define any feature."); + } + super.visitGherkinDocument(tree); + } + +} diff --git a/gherkin-checks/src/main/java/org/sonar/gherkin/checks/NoScenarioCheck.java b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/NoScenarioCheck.java new file mode 100644 index 0000000..8bd7d3b --- /dev/null +++ b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/NoScenarioCheck.java @@ -0,0 +1,46 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.plugins.gherkin.api.tree.FeatureTree; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitorCheck; +import org.sonar.squidbridge.annotations.ActivatedByDefault; +import org.sonar.squidbridge.annotations.SqaleConstantRemediation; + +@Rule( + key = "no-scenario", + name = "Features that do not define any scenario should be removed", + priority = Priority.MAJOR, + tags = {Tags.PITFALL}) +@SqaleConstantRemediation("5min") +@ActivatedByDefault +public class NoScenarioCheck extends DoubleDispatchVisitorCheck { + + @Override + public void visitFeature(FeatureTree tree) { + if (tree.allScenarios().isEmpty()) { + addPreciseIssue(tree.declaration().prefix(), "Remove this feature that does not define any scenario."); + } + super.visitFeature(tree); + } + +} diff --git a/gherkin-checks/src/main/java/org/sonar/gherkin/checks/ParsingErrorCheck.java b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/ParsingErrorCheck.java new file mode 100644 index 0000000..175ef97 --- /dev/null +++ b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/ParsingErrorCheck.java @@ -0,0 +1,36 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitorCheck; +import org.sonar.squidbridge.annotations.ActivatedByDefault; +import org.sonar.squidbridge.annotations.SqaleConstantRemediation; + +@Rule( + key = "S2260", + name = "Gherkin parser failure", + priority = Priority.CRITICAL, + tags = {Tags.BUG}) +@SqaleConstantRemediation("5min") +@ActivatedByDefault +public class ParsingErrorCheck extends DoubleDispatchVisitorCheck { +} diff --git a/gherkin-checks/src/main/java/org/sonar/gherkin/checks/StarStepPrefixCheck.java b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/StarStepPrefixCheck.java new file mode 100644 index 0000000..2711fbd --- /dev/null +++ b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/StarStepPrefixCheck.java @@ -0,0 +1,46 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.plugins.gherkin.api.tree.StepPrefixTree; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitorCheck; +import org.sonar.squidbridge.annotations.ActivatedByDefault; +import org.sonar.squidbridge.annotations.SqaleConstantRemediation; + +@Rule( + key = "star-step-prefix", + name = "Star (*) step prefix should not be used", + priority = Priority.MAJOR, + tags = {Tags.UNDERSTANDABILITY}) +@SqaleConstantRemediation("5min") +@ActivatedByDefault +public class StarStepPrefixCheck extends DoubleDispatchVisitorCheck { + + @Override + public void visitStepPrefix(StepPrefixTree tree) { + if ("*".equals(tree.text())) { + addPreciseIssue(tree, "Replace this star prefix with Given/When/Then."); + } + super.visitStepPrefix(tree); + } + +} diff --git a/gherkin-checks/src/main/java/org/sonar/gherkin/checks/TabCharacterCheck.java b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/TabCharacterCheck.java new file mode 100644 index 0000000..b848a77 --- /dev/null +++ b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/TabCharacterCheck.java @@ -0,0 +1,74 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import com.google.common.collect.ImmutableList; +import com.google.common.io.Files; +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.gherkin.visitors.CharsetAwareVisitor; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.SubscriptionVisitorCheck; +import org.sonar.squidbridge.annotations.ActivatedByDefault; +import org.sonar.squidbridge.annotations.SqaleConstantRemediation; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.List; + +@Rule( + key = "tab-character", + name = "Tabulation characters should not be used", + priority = Priority.MINOR, + tags = {Tags.CONVENTION}) +@SqaleConstantRemediation("2min") +@ActivatedByDefault +public class TabCharacterCheck extends SubscriptionVisitorCheck implements CharsetAwareVisitor { + + private Charset charset; + + @Override + public List nodesToVisit() { + return ImmutableList.of(Tree.Kind.GHERKIN_DOCUMENT); + } + + @Override + public void visitFile(Tree tree) { + List lines; + try { + lines = Files.readLines(getContext().getFile(), charset); + } catch (IOException e) { + throw new IllegalStateException("Check gherkin:" + this.getClass().getAnnotation(Rule.class).key() + + ": Error while reading " + getContext().getFile().getName(), e); + } + for (String line : lines) { + if (line.contains("\t")) { + addFileIssue("Replace all tab characters in this file by sequences of whitespaces."); + break; + } + } + } + + @Override + public void setCharset(Charset charset) { + this.charset = charset; + } + +} diff --git a/gherkin-checks/src/main/java/org/sonar/gherkin/checks/TagNameCheck.java b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/TagNameCheck.java new file mode 100644 index 0000000..4423c42 --- /dev/null +++ b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/TagNameCheck.java @@ -0,0 +1,75 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import com.google.common.annotations.VisibleForTesting; +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.check.RuleProperty; +import org.sonar.plugins.gherkin.api.tree.TagTree; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitorCheck; +import org.sonar.squidbridge.annotations.ActivatedByDefault; +import org.sonar.squidbridge.annotations.SqaleConstantRemediation; + +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +@Rule( + key = "tag-naming-convention", + name = "Tags should comply with a naming convention", + priority = Priority.MINOR, + tags = {Tags.CONVENTION}) +@SqaleConstantRemediation("5min") +@ActivatedByDefault +public class TagNameCheck extends DoubleDispatchVisitorCheck { + + private static final String DEFAULT = "^[a-z][-a-z0-9]*$"; + + @RuleProperty( + key = "format", + defaultValue = DEFAULT, + description = "Regular expression that tags should match. See " + CheckUtils.LINK_TO_JAVA_REGEX_PATTERN_DOC + " for detailed regular expression syntax.") + private String format = DEFAULT; + + @Override + public void visitTag(TagTree tree) { + if (!tree.text().matches(format)) { + addPreciseIssue(tree, "Rename this tag to match the regular expression: " + format); + } + super.visitTag(tree); + } + + @Override + public void validateParameters() { + try { + Pattern.compile(format); + } catch (PatternSyntaxException exception) { + throw new IllegalStateException( + CheckUtils.paramsErrorMessage(this.getClass(), "format parameter \"" + format + "\" is not a valid regular expression."), + exception); + } + } + + @VisibleForTesting + void setFormat(String format) { + this.format = format; + } + +} diff --git a/gherkin-checks/src/main/java/org/sonar/gherkin/checks/Tags.java b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/Tags.java new file mode 100644 index 0000000..269c311 --- /dev/null +++ b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/Tags.java @@ -0,0 +1,32 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +public final class Tags { + + public static final String BUG = "bug"; + public static final String CONVENTION = "convention"; + public static final String PITFALL = "pitfall"; + public static final String UNDERSTANDABILITY = "understandability"; + + private Tags() { + } + +} diff --git a/gherkin-checks/src/main/java/org/sonar/gherkin/checks/TodoTagPresenceCheck.java b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/TodoTagPresenceCheck.java new file mode 100644 index 0000000..2110a99 --- /dev/null +++ b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/TodoTagPresenceCheck.java @@ -0,0 +1,39 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.squidbridge.annotations.ActivatedByDefault; +import org.sonar.squidbridge.annotations.SqaleConstantRemediation; + +@Rule( + key = "S1135", + name = "\"TODO\" tags should be handled", + priority = Priority.INFO) +@SqaleConstantRemediation("15min") +@ActivatedByDefault +public class TodoTagPresenceCheck extends CommentContainsPatternChecker { + + public TodoTagPresenceCheck() { + super("TODO", "Complete the task associated to this TODO comment."); + } + +} diff --git a/gherkin-checks/src/main/java/org/sonar/gherkin/checks/TrailingWhitespaceCheck.java b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/TrailingWhitespaceCheck.java new file mode 100644 index 0000000..e34bff0 --- /dev/null +++ b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/TrailingWhitespaceCheck.java @@ -0,0 +1,71 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import com.google.common.io.Files; +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.gherkin.visitors.CharsetAwareVisitor; +import org.sonar.plugins.gherkin.api.tree.GherkinDocumentTree; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitorCheck; +import org.sonar.squidbridge.annotations.ActivatedByDefault; +import org.sonar.squidbridge.annotations.SqaleConstantRemediation; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.List; +import java.util.regex.Pattern; + +@Rule( + key = "S1131", + name = "Lines should not end with trailing whitespaces", + priority = Priority.MINOR, + tags = {Tags.CONVENTION}) +@SqaleConstantRemediation("1min") +@ActivatedByDefault +public class TrailingWhitespaceCheck extends DoubleDispatchVisitorCheck implements CharsetAwareVisitor { + + private static final String WHITESPACE = "\\t\\u000B\\f\\u0020\\u00A0\\uFEFF\\p{Zs}"; + private Charset charset; + + @Override + public void visitGherkinDocument(GherkinDocumentTree tree) { + List lines; + try { + lines = Files.readLines(getContext().getFile(), charset); + } catch (IOException e) { + throw new IllegalStateException("Check gherking:" + this.getClass().getAnnotation(Rule.class).key() + + ": Error while reading " + getContext().getFile().getName(), e); + } + for (int i = 0; i < lines.size(); i++) { + String line = lines.get(i); + if (line.length() > 0 && Pattern.matches("[" + WHITESPACE + "]", line.subSequence(line.length() - 1, line.length()))) { + addLineIssue(i + 1, "Remove the useless trailing whitespaces at the end of this line."); + } + } + super.visitGherkinDocument(tree); + } + + @Override + public void setCharset(Charset charset) { + this.charset = charset; + } + +} diff --git a/gherkin-checks/src/main/java/org/sonar/gherkin/checks/package-info.java b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/package-info.java new file mode 100644 index 0000000..9c4e378 --- /dev/null +++ b/gherkin-checks/src/main/java/org/sonar/gherkin/checks/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +@ParametersAreNonnullByDefault +package org.sonar.gherkin.checks; + +import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/S1131.html b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/S1131.html new file mode 100644 index 0000000..2a7298d --- /dev/null +++ b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/S1131.html @@ -0,0 +1,5 @@ +

+ Trailing whitespaces are simply useless and should not stay in code. They may generate noise when comparing + different versions of the same file. If you encounter issues from this rule, this probably means that you are not + using an automated code formatter - which you should if you have the opportunity to do so. +

diff --git a/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/S1134.html b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/S1134.html new file mode 100644 index 0000000..43f39dd --- /dev/null +++ b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/S1134.html @@ -0,0 +1,12 @@ +

+ FIXME tags are commonly used to mark places where a bug is suspected, but which the developer wants to + deal with later. Sometimes the developer will not have the time or will simply forget to get back to that tag. This + rule is meant to track those tags, and ensure that they do not go unnoticed. +

+ +

Noncompliant Code Example

+
+# FIXME: blabla
+Feature My feature...
+  Scenario My scenario...
+
diff --git a/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/S1135.html b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/S1135.html new file mode 100644 index 0000000..0747b7b --- /dev/null +++ b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/S1135.html @@ -0,0 +1,12 @@ +

+ TODO tags are commonly used to mark places where some more code is required, but which the developer + wants to implement later. Sometimes the developer will not have the time or will simply forget to get back to that + tag. This rule is meant to track those tags, and ensure that they do not go unnoticed. +

+ +

Noncompliant Code Example

+
+# TODO: blabla
+Feature My feature...
+  Scenario My scenario...
+
diff --git a/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/S1578.html b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/S1578.html new file mode 100644 index 0000000..f49dc9a --- /dev/null +++ b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/S1578.html @@ -0,0 +1,16 @@ +

+ Shared coding conventions allow teams to collaborate effectively. This rule checks that all file names match a + provided regular expression. +

+ +

Noncompliant Code Example

+With default regular expression: ^[a-z][-A-Za-z0-9]*.feature$ +
+MyFeature.feature
+
+ +

Compliant Solution

+With default regular expression: ^[a-z][-A-Za-z0-9]*.feature$ +
+my-feature.feature
+
diff --git a/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/S2260.html b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/S2260.html new file mode 100644 index 0000000..910cb57 --- /dev/null +++ b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/S2260.html @@ -0,0 +1,4 @@ +

+ When the parser fails, it is possible to record the failure as an issue on the file. This way, not only is it + possible to track the number of files that do not parse but also to easily find out why they do not parse. +

diff --git a/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/allowed-tags.html b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/allowed-tags.html new file mode 100644 index 0000000..9f3a4e2 --- /dev/null +++ b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/allowed-tags.html @@ -0,0 +1,16 @@ +

+ For tags to be usable, the list of allowed tags should be properly defined. This rule raises an issue each time a + tag that is not in the whitelist is found. +

+ +

Noncompliant Code Example

+With default value "smoke,nrt": +
+@non-regression-test
+
+ +

Compliant Solution

+With default value "smoke,nrt": +
+@nrt
+
diff --git a/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/bom-utf8-files.html b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/bom-utf8-files.html new file mode 100644 index 0000000..31baf3e --- /dev/null +++ b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/bom-utf8-files.html @@ -0,0 +1,11 @@ +

+ As stated in the Unicode specifications, use of a Byte Order Mark (BOM) is neither required nor recommended for + UTF-8 files. +

+ +

See

+ diff --git a/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/comment-convention.html b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/comment-convention.html new file mode 100644 index 0000000..bf26bec --- /dev/null +++ b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/comment-convention.html @@ -0,0 +1,11 @@ +

For readability reasons, the starting token # should be followed by a whitespace.

+ +

Noncompliant Code Example

+
+#My comments...
+
+ +

Compliant Solution

+
+# My comments...
+
diff --git a/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/comment-regular-expression.html b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/comment-regular-expression.html new file mode 100644 index 0000000..d74ad8f --- /dev/null +++ b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/comment-regular-expression.html @@ -0,0 +1,13 @@ +

+ This rule template can be used to create rules which will be triggered when a comment matches a given regular + expression. +

+

+ For example, one can create a rule with the regular expression ".*WTF.*" to match all comment + containing "WTF". Note that, in order to match WTF regardless of the case, the "(?i)" modifier can be + prepended to the expression, as in "(?i).*WTF.*". +

+

+ See Java + documentation for detailed regular expression syntax. +

diff --git a/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/empty-line-end-of-file.html b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/empty-line-end-of-file.html new file mode 100644 index 0000000..6fb97ef --- /dev/null +++ b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/empty-line-end-of-file.html @@ -0,0 +1,8 @@ +

Some tools such as Git work better when files end with an empty line.

+

This rule simply generates an issue if it is missing.

+

For example, a Git diff looks like:

+
++Then I should be a customer
+\ No newline at end of file
+
+

if the empty line is missing at the end of the file.

diff --git a/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/end-line-characters.html b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/end-line-characters.html new file mode 100644 index 0000000..8b38684 --- /dev/null +++ b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/end-line-characters.html @@ -0,0 +1 @@ +

End-line characters should be consistent in order to prevent polluting SCM history changelog for instance.

diff --git a/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/incomplete-examples-table.html b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/incomplete-examples-table.html new file mode 100644 index 0000000..12021c7 --- /dev/null +++ b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/incomplete-examples-table.html @@ -0,0 +1,96 @@ +

+ Having Scenario Outlines with Examples section containing no table will end up with the + execution of zero scenario; that is unlikely the expected behavior. Thus, each Examples section should + contain a table. +

+ +

Noncompliant Code Example

+
+Scenario Outline: Add product to cart
+  Given I am a customer
+  When I add <number> products to my cart
+  Then I should see <number> products in my cart
+
+    Examples:
+
+ +

Compliant Solution

+
+Scenario Outline: Add product to cart
+  Given I am a customer
+  When I add <number> products to my cart
+  Then I should see <number> products in my cart
+
+    Examples:
+      | number |
+      | 1      |
+      | 2      |
+
+ +

+ Having Scenario Outlines with Examples section containing a table with one single row will + end up with the execution of zero scenario; that is unlikely the expected behavior. Thus, each Examples + table should contain at least two rows. +

+ +

Noncompliant Code Example

+
+Scenario Outline: Add product to cart
+  Given I am a customer
+  When I add <number> products to my cart
+  Then I should see <number> products in my cart
+
+    Examples:
+      | number |
+
+ +

Compliant Solution

+
+Scenario Outline: Add product to cart
+  Given I am a customer
+  When I add <number> products to my cart
+  Then I should see <number> products in my cart
+
+    Examples:
+      | number |
+      | 1      |
+      | 2      |
+
+ +

+ Having Scenario Outlines with Examples section containing a table with two rows will + end up with the execution of a single scenario. Thus, either some data are missing or the Scenario + Outline can be safely converted to a Scenario. +

+ +

Noncompliant Code Example

+
+Scenario Outline: Add product to cart
+  Given I am a customer
+  When I add <number> products to my cart
+  Then I should see <number> products in my cart
+
+    Examples:
+      | number |
+      | 1      |
+
+ +

Compliant Solution

+
+Scenario Outline: Add product to cart
+  Given I am a customer
+  When I add <number> products to my cart
+  Then I should see <number> products in my cart
+
+    Examples:
+      | number |
+      | 1      |
+      | 2      |
+    
+OR   
+
+Scenario: Add product to cart
+  Given I am a customer
+  When I add 1 product to my cart
+  Then I should see 1 product in my cart
+
diff --git a/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/indentation.html b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/indentation.html new file mode 100644 index 0000000..def79ad --- /dev/null +++ b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/indentation.html @@ -0,0 +1,20 @@ +

For readability reasons, code should be properly indented

+ +

Noncompliant Code Example

+With default value: 2 +
+Feature: my feature...
+  Scenario: my scenario...
+    Given blabla...
+      When blabla...  # Noncompliant
+    Then blabla...
+
+ +

Compliant Solution

+
+Feature: my feature...
+  Scenario: my scenario...
+    Given blabla...
+    When blabla...
+    Then blabla...
+
diff --git a/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/max-number-scenarios.html b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/max-number-scenarios.html new file mode 100644 index 0000000..ee81358 --- /dev/null +++ b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/max-number-scenarios.html @@ -0,0 +1,4 @@ +

+ A feature should contain scenarios targeting a specific feature / use case. A feature defining too many scenarios is + likely to target several features / use cases and should be split into several features. +

diff --git a/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/max-number-steps.html b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/max-number-steps.html new file mode 100644 index 0000000..de1328c --- /dev/null +++ b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/max-number-steps.html @@ -0,0 +1,21 @@ +

+ For a scenario to remain readable and understandable, the number of its steps should remain limited. The default + threshold is 12 and it includes the number of steps in Background. +

+ +

Noncompliant Code Example

+With a custom threshold of 8: +
+Background:
+  Given ...
+  And ...
+  And ...
+
+Scenario: ...
+  Given ...
+  When ...
+  Then ...
+  And ...
+  And ...
+  And ...
+
diff --git a/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/no-feature.html b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/no-feature.html new file mode 100644 index 0000000..0ee4f79 --- /dev/null +++ b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/no-feature.html @@ -0,0 +1,16 @@ +

+ Having a file that does not define any feature is useless. It can either be safely removed or a feature should be + added. +

+ +

Noncompliant Code Example

+
+# Empty file
+
+ +

Compliant Solution

+
+Feature: My feature...
+  Scenario: My scenario #1
+    ...
+
diff --git a/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/no-scenario.html b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/no-scenario.html new file mode 100644 index 0000000..22760fb --- /dev/null +++ b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/no-scenario.html @@ -0,0 +1,16 @@ +

+ Having a feature that does not define any scenario is useless. It can either be safely removed or scenarios should + be added. +

+ +

Noncompliant Code Example

+
+Feature: My feature...
+
+ +

Compliant Solution

+
+Feature: My feature...
+  Scenario: My scenario #1
+    ...
+
diff --git a/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/star-step-prefix.html b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/star-step-prefix.html new file mode 100644 index 0000000..911e490 --- /dev/null +++ b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/star-step-prefix.html @@ -0,0 +1,20 @@ +

+ In order to improve understandability, Given/When/Then step prefix should be used instead of + *. +

+ +

Noncompliant Code Example

+
+Scenario: Add product to cart
+  * I am a customer
+  * I add a product to my cart
+  * I should see the product in my cart
+
+ +

Compliant Solution

+
+Scenario: Add product to cart
+  Given I am a customer
+  When I add a product to my cart
+  Then I should see the product in my cart
+
diff --git a/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/tab-character.html b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/tab-character.html new file mode 100644 index 0000000..0ca0d97 --- /dev/null +++ b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/tab-character.html @@ -0,0 +1,4 @@ +

+ Developers should not need to configure the tab width of their text editors in order to be able to read source code. + So the use of tabulation character must be banned. +

\ No newline at end of file diff --git a/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/tag-naming-convention.html b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/tag-naming-convention.html new file mode 100644 index 0000000..781c454 --- /dev/null +++ b/gherkin-checks/src/main/resources/org/sonar/l10n/gherkin/rules/gherkin/tag-naming-convention.html @@ -0,0 +1,17 @@ +

+ Shared coding conventions allow teams to collaborate effectively. This rule checks that all tags match a provided + regular expression. +

+ +

Noncompliant Code Example

+With default regular expression: ^[a-z][-a-z0-9]*$ +
+@MyTag
+
+ +

Compliant Solution

+With default regular expression: ^[a-z][-a-z0-9]*$ +
+@mytag
+@my-tag
+
diff --git a/gherkin-checks/src/test/java/org/sonar/gherkin/checks/AllowedTagsCheckTest.java b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/AllowedTagsCheckTest.java new file mode 100644 index 0000000..e82e88b --- /dev/null +++ b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/AllowedTagsCheckTest.java @@ -0,0 +1,39 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.junit.Test; +import org.sonar.gherkin.checks.verifier.GherkinCheckVerifier; + +public class AllowedTagsCheckTest { + + @Test + public void test_default_white_list() { + GherkinCheckVerifier.verify(new AllowedTagsCheck(), CheckTestUtils.getTestFile("allowed-tags/allowed-tags-default.feature")); + } + + @Test + public void test_default_custom_white_list() { + AllowedTagsCheck check = new AllowedTagsCheck(); + check.setAllowedTags("mytag,yourtag"); + GherkinCheckVerifier.verify(check, CheckTestUtils.getTestFile("allowed-tags/allowed-tags-custom.feature")); + } + +} diff --git a/gherkin-checks/src/test/java/org/sonar/gherkin/checks/BOMCheckTest.java b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/BOMCheckTest.java new file mode 100644 index 0000000..daf478f --- /dev/null +++ b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/BOMCheckTest.java @@ -0,0 +1,57 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import com.google.common.base.Charsets; +import org.junit.Test; +import org.sonar.gherkin.checks.verifier.GherkinCheckVerifier; + +public class BOMCheckTest { + + @Test + public void should_find_that_the_UTF8_file_starts_with_a_BOM_and_raise_an_issue() { + GherkinCheckVerifier.verify( + new BOMCheck(), + CheckTestUtils.getTestFile("bom/utf8-with-bom.feature"), + Charsets.UTF_8); + } + + @Test + public void should_find_that_the_UTF8_file_does_not_start_with_a_BOM_and_not_raise_any_issue() { + GherkinCheckVerifier.verify( + new BOMCheck(), + CheckTestUtils.getTestFile("bom/utf8.feature"), + Charsets.UTF_8); + } + + @Test + public void should_find_that_the_UTF16_files_start_with_a_BOM_but_not_raise_any_issue() { + GherkinCheckVerifier.verify( + new BOMCheck(), + CheckTestUtils.getTestFile("bom/utf16-be.feature"), + Charsets.UTF_16BE); + + GherkinCheckVerifier.verify( + new BOMCheck(), + CheckTestUtils.getTestFile("bom/utf16-le.feature"), + Charsets.UTF_16LE); + } + +} diff --git a/gherkin-checks/src/test/java/org/sonar/gherkin/checks/CheckTestUtils.java b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/CheckTestUtils.java new file mode 100644 index 0000000..6217597 --- /dev/null +++ b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/CheckTestUtils.java @@ -0,0 +1,33 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import java.io.File; + +public class CheckTestUtils { + + private CheckTestUtils() { + } + + public static File getTestFile(String relativePath) { + return new File("src/test/resources/checks/" + relativePath); + } + +} diff --git a/gherkin-checks/src/test/java/org/sonar/gherkin/checks/CommentConventionCheckTest.java b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/CommentConventionCheckTest.java new file mode 100644 index 0000000..752faf4 --- /dev/null +++ b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/CommentConventionCheckTest.java @@ -0,0 +1,34 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.junit.Test; +import org.sonar.gherkin.checks.verifier.GherkinCheckVerifier; + +public class CommentConventionCheckTest { + + @Test + public void test() { + GherkinCheckVerifier.issues(new CommentConventionCheck(), CheckTestUtils.getTestFile("comment-convention.feature")) + .next().atLine(2).withMessage("Add a whitespace after the starting comment token.") + .noMore(); + } + +} diff --git a/gherkin-checks/src/test/java/org/sonar/gherkin/checks/CommentRegularExpressionCheckTest.java b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/CommentRegularExpressionCheckTest.java new file mode 100644 index 0000000..b6cc642 --- /dev/null +++ b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/CommentRegularExpressionCheckTest.java @@ -0,0 +1,69 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.junit.Test; +import org.sonar.gherkin.checks.verifier.GherkinCheckVerifier; + +import java.io.File; + +import static org.fest.assertions.Assertions.assertThat; + +public class CommentRegularExpressionCheckTest { + + private final static File FILE = CheckTestUtils.getTestFile("comment-regular-expression.feature"); + private CommentRegularExpressionCheck check = new CommentRegularExpressionCheck(); + + @Test + public void should_match_some_comments_and_raise_some_issues() { + String message = "Stop annotating lines with WTF! Detail what is wrong instead."; + check.regularExpression = "(?i).*WTF.*"; + check.message = "Stop annotating lines with WTF! Detail what is wrong instead."; + + GherkinCheckVerifier.issues(check, FILE) + .next().atLine(2).withMessage(message) + .next().atLine(3).withMessage(message) + .noMore(); + } + + @Test + public void should_not_match_any_comments_and_not_raise_any_issues() { + check.regularExpression = "blabla"; + check.message = "blabla"; + + GherkinCheckVerifier.issues(check, FILE) + .noMore(); + } + + @Test + public void should_throw_an_illegal_state_exception_as_the_regular_expression_parameter_is_not_valid() { + try { + check.regularExpression = "("; + check.message = "blabla"; + + GherkinCheckVerifier.issues(check, FILE).noMore(); + + } catch (IllegalStateException e) { + assertThat(e.getMessage()).isEqualTo("Check gherkin:comment-regular-expression (Regular expression on comment): " + + "regularExpression parameter \"(\" is not a valid regular expression."); + } + } + +} diff --git a/gherkin-checks/src/test/java/org/sonar/gherkin/checks/EndLineCharactersCheckTest.java b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/EndLineCharactersCheckTest.java new file mode 100644 index 0000000..54f0357 --- /dev/null +++ b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/EndLineCharactersCheckTest.java @@ -0,0 +1,128 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.gherkin.checks.verifier.GherkinCheckVerifier; + +import java.io.File; + +import static org.fest.assertions.Assertions.assertThat; + +public class EndLineCharactersCheckTest { + + private EndLineCharactersCheck check = new EndLineCharactersCheck(); + + @Test + public void should_find_only_crlf_and_not_raise_any_issues() throws Exception { + check.setEndLineCharacters("CRLF"); + GherkinCheckVerifier.issues(check, getTestFileWithProperEndLineCharacters("\r\n")) + .noMore(); + } + + @Test + public void should_find_only_cr_and_not_raise_any_issues() throws Exception { + check.setEndLineCharacters("CR"); + GherkinCheckVerifier.issues(check, getTestFileWithProperEndLineCharacters("\r")) + .noMore(); + } + + @Test + public void should_find_only_lf_and_not_raise_any_issues() throws Exception { + check.setEndLineCharacters("LF"); + GherkinCheckVerifier.issues(check, getTestFileWithProperEndLineCharacters("\n")) + .noMore(); + } + + @Test + public void crlf_should_find_lf_and_raise_issues() throws Exception { + check.setEndLineCharacters("CRLF"); + GherkinCheckVerifier.issues(check, getTestFileWithProperEndLineCharacters("\n")) + .next().withMessage("Set all end-line characters to 'CRLF' in this file.") + .noMore(); + } + + @Test + public void crlf_should_find_cr_and_raise_issues() throws Exception { + check.setEndLineCharacters("CRLF"); + GherkinCheckVerifier.issues(check, getTestFileWithProperEndLineCharacters("\r")) + .next().withMessage("Set all end-line characters to 'CRLF' in this file.") + .noMore(); + } + + @Test + public void cr_should_find_crlf_and_raise_issues() throws Exception { + check.setEndLineCharacters("CR"); + GherkinCheckVerifier.issues(check, getTestFileWithProperEndLineCharacters("\r\n")) + .next().withMessage("Set all end-line characters to 'CR' in this file.") + .noMore(); + } + + @Test + public void cr_should_find_lf_and_raise_issues() throws Exception { + check.setEndLineCharacters("CR"); + GherkinCheckVerifier.issues(check, getTestFileWithProperEndLineCharacters("\n")) + .next().withMessage("Set all end-line characters to 'CR' in this file.") + .noMore(); + } + + @Test + public void lf_should_find_crlf_and_raise_issues() throws Exception { + check.setEndLineCharacters("LF"); + GherkinCheckVerifier.issues(check, getTestFileWithProperEndLineCharacters("\r\n")) + .next().withMessage("Set all end-line characters to 'LF' in this file.") + .noMore(); + } + + @Test + public void lf_should_find_cr_and_raise_issues() throws Exception { + check.setEndLineCharacters("LF"); + GherkinCheckVerifier.issues(check, getTestFileWithProperEndLineCharacters("\r")) + .next().withMessage("Set all end-line characters to 'LF' in this file.") + .noMore(); + } + + @Test + public void should_throw_an_illegal_state_exception_as_the_endLineCharacters_parameter_is_not_valid() throws Exception { + try { + check.setEndLineCharacters("abc"); + GherkinCheckVerifier.issues(check, getTestFileWithProperEndLineCharacters("\r")).noMore(); + } catch (IllegalStateException e) { + assertThat(e.getMessage()).isEqualTo("Check gherkin:end-line-characters (End-line characters should be consistent): " + + "endLineCharacters parameter is not valid.\nActual: 'abc'\nExpected: 'CR' or 'CRLF' or 'LF'"); + } + } + + private static File getTestFileWithProperEndLineCharacters(String endLineCharacter) throws Exception { + TemporaryFolder temporaryFolder = new TemporaryFolder(); + File testFile = temporaryFolder.newFile(); + Files.write( + Files.toString(CheckTestUtils.getTestFile("end-line-characters.feature"), Charsets.UTF_8) + .replaceAll("\\r\\n", "\n") + .replaceAll("\\r", "\n") + .replaceAll("\\n", endLineCharacter), + testFile, Charsets.UTF_8); + return testFile; + } + +} diff --git a/gherkin-checks/src/test/java/org/sonar/gherkin/checks/FileNameCheckTest.java b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/FileNameCheckTest.java new file mode 100644 index 0000000..912689a --- /dev/null +++ b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/FileNameCheckTest.java @@ -0,0 +1,70 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.junit.Test; +import org.sonar.gherkin.checks.verifier.GherkinCheckVerifier; + +import static org.fest.assertions.Assertions.assertThat; + +public class FileNameCheckTest { + + private FileNameCheck check = new FileNameCheck(); + + @Test + public void should_follow_the_default_naming_convention_and_not_raise_an_issue() { + GherkinCheckVerifier.issues(check, CheckTestUtils.getTestFile("file-name/file-name-ok.feature")) + .noMore(); + } + + @Test + public void should_not_follow_the_default_naming_convention_and_raise_an_issue() { + GherkinCheckVerifier.issues(check, CheckTestUtils.getTestFile("file-name/FileNameKO.feature")) + .next().withMessage("Rename this file to match the regular expression: ^[a-z][-A-Za-z0-9]*\\.feature$") + .noMore(); + } + + @Test + public void should_follow_a_custom_naming_convention_and_not_raise_an_issue() { + check.setFormat("^[a-z][-a-z]+\\.feature"); + GherkinCheckVerifier.issues(check, CheckTestUtils.getTestFile("file-name/file-name-custom-ok.feature")) + .noMore(); + } + + @Test + public void should_not_follow_a_custom_naming_convention_and_raise_an_issue() { + check.setFormat("^[a-z]+\\.feature$"); + GherkinCheckVerifier.issues(check, CheckTestUtils.getTestFile("file-name/file_name.kocustom.feature")) + .next().withMessage("Rename this file to match the regular expression: ^[a-z]+\\.feature$") + .noMore(); + } + + @Test + public void should_throw_an_illegal_state_exception_as_the_format_parameter_regular_expression_is_not_valid() { + try { + check.setFormat("("); + GherkinCheckVerifier.issues(check, CheckTestUtils.getTestFile("file-name/file-name-ok.feature")).noMore(); + } catch (IllegalStateException e) { + assertThat(e.getMessage()).isEqualTo("Check gherkin:S1578 (File names should comply with a naming convention): " + + "format parameter \"(\" is not a valid regular expression."); + } + } + +} diff --git a/gherkin-checks/src/test/java/org/sonar/gherkin/checks/FixmeTagPresenceCheckTest.java b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/FixmeTagPresenceCheckTest.java new file mode 100644 index 0000000..740d116 --- /dev/null +++ b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/FixmeTagPresenceCheckTest.java @@ -0,0 +1,32 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.junit.Test; +import org.sonar.gherkin.checks.verifier.GherkinCheckVerifier; + +public class FixmeTagPresenceCheckTest { + + @Test + public void should_contain_fixme_tags_and_raise_issues() { + GherkinCheckVerifier.verify(new FixmeTagPresenceCheck(), CheckTestUtils.getTestFile("fixme.feature")); + } + +} diff --git a/gherkin-checks/src/test/java/org/sonar/gherkin/checks/IncompleteExamplesTableCheckTest.java b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/IncompleteExamplesTableCheckTest.java new file mode 100644 index 0000000..0f44c35 --- /dev/null +++ b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/IncompleteExamplesTableCheckTest.java @@ -0,0 +1,32 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.junit.Test; +import org.sonar.gherkin.checks.verifier.GherkinCheckVerifier; + +public class IncompleteExamplesTableCheckTest { + + @Test + public void test() { + GherkinCheckVerifier.verify(new IncompleteExamplesTableCheck(), CheckTestUtils.getTestFile("incomplete-examples-table.feature")); + } + +} diff --git a/gherkin-checks/src/test/java/org/sonar/gherkin/checks/IndentationCheckTest.java b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/IndentationCheckTest.java new file mode 100644 index 0000000..d390828 --- /dev/null +++ b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/IndentationCheckTest.java @@ -0,0 +1,51 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.junit.Test; +import org.sonar.gherkin.checks.verifier.GherkinCheckVerifier; + +public class IndentationCheckTest { + + @Test + public void should_not_raise_any_issue_with_default_parameter_value() { + GherkinCheckVerifier.verify(new IndentationCheck(), CheckTestUtils.getTestFile("indentation/indentation-default-ok.feature")); + } + + @Test + public void should_raise_some_issues_with_default_parameter_value() { + GherkinCheckVerifier.verify(new IndentationCheck(), CheckTestUtils.getTestFile("indentation/indentation-default-ko.feature")); + } + + @Test + public void should_not_raise_any_issue_with_custom_parameter_value() { + IndentationCheck check = new IndentationCheck(); + check.setIndentation(4); + GherkinCheckVerifier.verify(check, CheckTestUtils.getTestFile("indentation/indentation-custom-ok.feature")); + } + + @Test + public void should_raise_some_issues_with_custom_parameter_value() { + IndentationCheck check = new IndentationCheck(); + check.setIndentation(4); + GherkinCheckVerifier.verify(check, CheckTestUtils.getTestFile("indentation/indentation-custom-ko.feature")); + } + +} diff --git a/gherkin-checks/src/test/java/org/sonar/gherkin/checks/MaxNumberScenariosCheckTest.java b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/MaxNumberScenariosCheckTest.java new file mode 100644 index 0000000..9aa8472 --- /dev/null +++ b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/MaxNumberScenariosCheckTest.java @@ -0,0 +1,51 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.junit.Test; +import org.sonar.gherkin.checks.verifier.GherkinCheckVerifier; + +public class MaxNumberScenariosCheckTest { + + @Test + public void should_not_raise_any_issue_because_the_number_of_scenarios_is_lower_than_the_default_threshold() { + GherkinCheckVerifier.verify(new MaxNumberScenariosCheck(), CheckTestUtils.getTestFile("max-number-scenarios/lower-than-default-threshold.feature")); + } + + @Test + public void should_raise_an_issue_because_the_number_of_scenarios_is_greater_than_the_default_threshold() { + GherkinCheckVerifier.verify(new MaxNumberScenariosCheck(), CheckTestUtils.getTestFile("max-number-scenarios/greater-than-default-threshold.feature")); + } + + @Test + public void should_not_raise_any_issue_because_the_number_of_scenarios_is_lower_than_the_custom_threshold() { + MaxNumberScenariosCheck check = new MaxNumberScenariosCheck(); + check.setThreshold(4); + GherkinCheckVerifier.verify(check, CheckTestUtils.getTestFile("max-number-scenarios/lower-than-custom-threshold.feature")); + } + + @Test + public void should_raise_an_issue_because_the_number_of_scenarios_is_greater_than_the_custom_threshold() { + MaxNumberScenariosCheck check = new MaxNumberScenariosCheck(); + check.setThreshold(4); + GherkinCheckVerifier.verify(check, CheckTestUtils.getTestFile("max-number-scenarios/greater-than-custom-threshold.feature")); + } + +} diff --git a/gherkin-checks/src/test/java/org/sonar/gherkin/checks/MaxNumberStepsCheckTest.java b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/MaxNumberStepsCheckTest.java new file mode 100644 index 0000000..f098bfa --- /dev/null +++ b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/MaxNumberStepsCheckTest.java @@ -0,0 +1,44 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.junit.Test; +import org.sonar.gherkin.checks.verifier.GherkinCheckVerifier; + +public class MaxNumberStepsCheckTest { + + @Test + public void test_with_no_background() { + GherkinCheckVerifier.verify(new MaxNumberStepsCheck(), CheckTestUtils.getTestFile("max-number-steps/max-number-steps-no-background.feature")); + } + + @Test + public void test_with_background() { + GherkinCheckVerifier.verify(new MaxNumberStepsCheck(), CheckTestUtils.getTestFile("max-number-steps/max-number-steps-background.feature")); + } + + @Test + public void test_custom_threshold() { + MaxNumberStepsCheck check = new MaxNumberStepsCheck(); + check.setThreshold(5); + GherkinCheckVerifier.verify(check, CheckTestUtils.getTestFile("max-number-steps/max-number-steps-custom-threshold.feature")); + } + +} diff --git a/gherkin-checks/src/test/java/org/sonar/gherkin/checks/MissingNewlineAtEndOfFileCheckTest.java b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/MissingNewlineAtEndOfFileCheckTest.java new file mode 100644 index 0000000..bb8a4fe --- /dev/null +++ b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/MissingNewlineAtEndOfFileCheckTest.java @@ -0,0 +1,40 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.junit.Test; +import org.sonar.gherkin.checks.verifier.GherkinCheckVerifier; + +public class MissingNewlineAtEndOfFileCheckTest { + + @Test + public void should_contain_an_empty_new_line_at_the_end_of_the_file_and_not_raise_issues() { + GherkinCheckVerifier.issues(new MissingNewlineAtEndOfFileCheck(), CheckTestUtils.getTestFile("new-line-end-of-file/new-line-end-of-file.feature")) + .noMore(); + } + + @Test + public void should_not_contain_an_empty_new_line_at_the_end_of_the_file_and_raise_an_issue() { + GherkinCheckVerifier.issues(new MissingNewlineAtEndOfFileCheck(), CheckTestUtils.getTestFile("new-line-end-of-file/no-new-line-end-of-file.feature")) + .next().withMessage("Add an empty new line at the end of this file.") + .noMore(); + } + +} diff --git a/gherkin-checks/src/test/java/org/sonar/gherkin/checks/NoFeatureCheckTest.java b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/NoFeatureCheckTest.java new file mode 100644 index 0000000..794d2bb --- /dev/null +++ b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/NoFeatureCheckTest.java @@ -0,0 +1,37 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.junit.Test; +import org.sonar.gherkin.checks.verifier.GherkinCheckVerifier; + +public class NoFeatureCheckTest { + + @Test + public void should_not_raise_any_issue_because_a_feature_is_defined() { + GherkinCheckVerifier.verify(new NoFeatureCheck(), CheckTestUtils.getTestFile("no-feature/feature.feature")); + } + + @Test + public void should_raise_an_issue_because_no_feature_is_defined() { + GherkinCheckVerifier.verify(new NoFeatureCheck(), CheckTestUtils.getTestFile("no-feature/no-feature.feature")); + } + +} diff --git a/gherkin-checks/src/test/java/org/sonar/gherkin/checks/NoScenarioCheckTest.java b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/NoScenarioCheckTest.java new file mode 100644 index 0000000..61f36a7 --- /dev/null +++ b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/NoScenarioCheckTest.java @@ -0,0 +1,42 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.junit.Test; +import org.sonar.gherkin.checks.verifier.GherkinCheckVerifier; + +public class NoScenarioCheckTest { + + @Test + public void should_not_raise_any_issue_because_a_scenario_is_defined() { + GherkinCheckVerifier.verify(new NoScenarioCheck(), CheckTestUtils.getTestFile("no-scenario/scenario.feature")); + } + + @Test + public void should_not_raise_any_issue_because_a_scenario_outline_is_defined() { + GherkinCheckVerifier.verify(new NoScenarioCheck(), CheckTestUtils.getTestFile("no-scenario/scenario-outline.feature")); + } + + @Test + public void should_raise_an_issue_because_no_scenario_is_defined() { + GherkinCheckVerifier.verify(new NoScenarioCheck(), CheckTestUtils.getTestFile("no-scenario/no-scenario.feature")); + } + +} diff --git a/gherkin-checks/src/test/java/org/sonar/gherkin/checks/StarStepPrefixCheckTest.java b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/StarStepPrefixCheckTest.java new file mode 100644 index 0000000..a67f76a --- /dev/null +++ b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/StarStepPrefixCheckTest.java @@ -0,0 +1,32 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.junit.Test; +import org.sonar.gherkin.checks.verifier.GherkinCheckVerifier; + +public class StarStepPrefixCheckTest { + + @Test + public void test() { + GherkinCheckVerifier.verify(new StarStepPrefixCheck(), CheckTestUtils.getTestFile("star-step-prefix.feature")); + } + +} diff --git a/gherkin-checks/src/test/java/org/sonar/gherkin/checks/TabCharacterCheckTest.java b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/TabCharacterCheckTest.java new file mode 100644 index 0000000..cefa065 --- /dev/null +++ b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/TabCharacterCheckTest.java @@ -0,0 +1,40 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.junit.Test; +import org.sonar.gherkin.checks.verifier.GherkinCheckVerifier; + +public class TabCharacterCheckTest { + + @Test + public void should_find_tab_characters_and_raise_an_issue() { + GherkinCheckVerifier.issues(new TabCharacterCheck(), CheckTestUtils.getTestFile("tab-character/tab-character.feature")) + .next().withMessage("Replace all tab characters in this file by sequences of whitespaces.") + .noMore(); + } + + @Test + public void should_not_find_tab_characters_and_not_raise_an_issue() { + GherkinCheckVerifier.issues(new TabCharacterCheck(), CheckTestUtils.getTestFile("tab-character/no-tab-character.feature")) + .noMore(); + } + +} diff --git a/gherkin-checks/src/test/java/org/sonar/gherkin/checks/TagNameCheckTest.java b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/TagNameCheckTest.java new file mode 100644 index 0000000..7fb4d6a --- /dev/null +++ b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/TagNameCheckTest.java @@ -0,0 +1,64 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.junit.Test; +import org.sonar.gherkin.checks.verifier.GherkinCheckVerifier; + +import static org.fest.assertions.Assertions.assertThat; + +public class TagNameCheckTest { + + private TagNameCheck check = new TagNameCheck(); + + @Test + public void all_tags_should_follow_the_default_naming_convention_and_not_raise_any_issue() { + GherkinCheckVerifier.verify(check, CheckTestUtils.getTestFile("tag-name/tag-name-ok.feature")); + } + + @Test + public void some_tags_should_not_follow_the_default_naming_convention_and_raise_some_issues() { + GherkinCheckVerifier.verify(check, CheckTestUtils.getTestFile("tag-name/tag-name-ko.feature")); + } + + @Test + public void all_tags_should_follow_a_custom_naming_convention_and_not_raise_any_issue() { + check.setFormat("^[a-z][-a-z]*$"); + GherkinCheckVerifier.verify(check, CheckTestUtils.getTestFile("tag-name/tag-name-custom-ok.feature")); + } + + @Test + public void some_tags_should_not_follow_a_custom_naming_convention_and_raise_some_issues() { + check.setFormat("^[a-z]+$"); + GherkinCheckVerifier.verify(check, CheckTestUtils.getTestFile("tag-name/tag-name-custom-ko.feature")); + } + + @Test + public void should_throw_an_illegal_state_exception_as_the_format_parameter_regular_expression_is_not_valid() { + try { + check.setFormat("("); + GherkinCheckVerifier.issues(check, CheckTestUtils.getTestFile("tag-name/tag-name-ok.feature")).noMore(); + } catch (IllegalStateException e) { + assertThat(e.getMessage()).isEqualTo("Check gherkin:tag-naming-convention (Tags should comply with a naming convention): " + + "format parameter \"(\" is not a valid regular expression."); + } + } + +} diff --git a/gherkin-checks/src/test/java/org/sonar/gherkin/checks/TodoTagPresenceCheckTest.java b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/TodoTagPresenceCheckTest.java new file mode 100644 index 0000000..b456604 --- /dev/null +++ b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/TodoTagPresenceCheckTest.java @@ -0,0 +1,32 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.junit.Test; +import org.sonar.gherkin.checks.verifier.GherkinCheckVerifier; + +public class TodoTagPresenceCheckTest { + + @Test + public void test() { + GherkinCheckVerifier.verify(new TodoTagPresenceCheck(), CheckTestUtils.getTestFile("todo.feature")); + } + +} diff --git a/gherkin-checks/src/test/java/org/sonar/gherkin/checks/TrailingWhitespaceCheckTest.java b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/TrailingWhitespaceCheckTest.java new file mode 100644 index 0000000..5cdeec8 --- /dev/null +++ b/gherkin-checks/src/test/java/org/sonar/gherkin/checks/TrailingWhitespaceCheckTest.java @@ -0,0 +1,32 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.junit.Test; +import org.sonar.gherkin.checks.verifier.GherkinCheckVerifier; + +public class TrailingWhitespaceCheckTest { + + @Test + public void test() { + GherkinCheckVerifier.verify(new TrailingWhitespaceCheck(), CheckTestUtils.getTestFile("trailing-whitespace.feature")); + } + +} diff --git a/gherkin-checks/src/test/resources/checks/allowed-tags/allowed-tags-custom.feature b/gherkin-checks/src/test/resources/checks/allowed-tags/allowed-tags-custom.feature new file mode 100644 index 0000000..dce52ff --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/allowed-tags/allowed-tags-custom.feature @@ -0,0 +1,16 @@ +# Noncompliant [[sc=1;ec=5]] {{Remove this tag that is not in the whitelist.}} +@nrt +Feature: My feature... + + # Noncompliant [[sc=3;ec=23]] {{Remove this tag that is not in the whitelist.}} + @non-regression-test + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + @mytag @yourtag + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/allowed-tags/allowed-tags-default.feature b/gherkin-checks/src/test/resources/checks/allowed-tags/allowed-tags-default.feature new file mode 100644 index 0000000..ed29374 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/allowed-tags/allowed-tags-default.feature @@ -0,0 +1,16 @@ +# Noncompliant [[sc=1;ec=7]] {{Remove this tag that is not in the whitelist.}} +@mytag +Feature: My feature... + + # Noncompliant [[sc=3;ec=23]] {{Remove this tag that is not in the whitelist.}} + @non-regression-test + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + @nrt @smoke + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/bom/utf16-be.feature b/gherkin-checks/src/test/resources/checks/bom/utf16-be.feature new file mode 100644 index 0000000..01ee708 Binary files /dev/null and b/gherkin-checks/src/test/resources/checks/bom/utf16-be.feature differ diff --git a/gherkin-checks/src/test/resources/checks/bom/utf16-le.feature b/gherkin-checks/src/test/resources/checks/bom/utf16-le.feature new file mode 100644 index 0000000..a5054ff Binary files /dev/null and b/gherkin-checks/src/test/resources/checks/bom/utf16-le.feature differ diff --git a/gherkin-checks/src/test/resources/checks/bom/utf8-with-bom.feature b/gherkin-checks/src/test/resources/checks/bom/utf8-with-bom.feature new file mode 100644 index 0000000..0f000c3 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/bom/utf8-with-bom.feature @@ -0,0 +1,12 @@ +# Noncompliant [[sl=0]] {{Remove the Byte Order Mark (BOM).}} +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/bom/utf8.feature b/gherkin-checks/src/test/resources/checks/bom/utf8.feature new file mode 100644 index 0000000..197f983 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/bom/utf8.feature @@ -0,0 +1,11 @@ +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/comment-convention.feature b/gherkin-checks/src/test/resources/checks/comment-convention.feature new file mode 100644 index 0000000..21639b3 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/comment-convention.feature @@ -0,0 +1,12 @@ +Feature: My feature... +#My comments +# My comments + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/comment-regular-expression.feature b/gherkin-checks/src/test/resources/checks/comment-regular-expression.feature new file mode 100644 index 0000000..5f6051b --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/comment-regular-expression.feature @@ -0,0 +1,13 @@ +Feature: My feature... + # WTF! + # wtf: abc + # Hello + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/custom-checks/forbidden-name-content.feature b/gherkin-checks/src/test/resources/checks/custom-checks/forbidden-name-content.feature new file mode 100644 index 0000000..00bad92 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/custom-checks/forbidden-name-content.feature @@ -0,0 +1,13 @@ +# Noncompliant [[sc=10;ec=27]] {{Remove this usage of "WTF".}} +Feature: WTF My feature... + + Scenario: Scenario #1 + Given blabla... + When blabla... + Then blabla... + + # Noncompliant [[sc=13;ec=28]] {{Remove this usage of "WTF".}} + Scenario: Scenario WTF #2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/custom-checks/forbidden-tag.feature b/gherkin-checks/src/test/resources/checks/custom-checks/forbidden-tag.feature new file mode 100644 index 0000000..d09bb99 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/custom-checks/forbidden-tag.feature @@ -0,0 +1,14 @@ +@bar +Feature: My feature... + + @foo + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + @mytag + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/end-line-characters.feature b/gherkin-checks/src/test/resources/checks/end-line-characters.feature new file mode 100644 index 0000000..197f983 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/end-line-characters.feature @@ -0,0 +1,11 @@ +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/file-name/FileNameKO.feature b/gherkin-checks/src/test/resources/checks/file-name/FileNameKO.feature new file mode 100644 index 0000000..197f983 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/file-name/FileNameKO.feature @@ -0,0 +1,11 @@ +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/file-name/file-name-custom-ok.feature b/gherkin-checks/src/test/resources/checks/file-name/file-name-custom-ok.feature new file mode 100644 index 0000000..197f983 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/file-name/file-name-custom-ok.feature @@ -0,0 +1,11 @@ +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/file-name/file-name-ok.feature b/gherkin-checks/src/test/resources/checks/file-name/file-name-ok.feature new file mode 100644 index 0000000..197f983 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/file-name/file-name-ok.feature @@ -0,0 +1,11 @@ +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/file-name/file_name.kocustom.feature b/gherkin-checks/src/test/resources/checks/file-name/file_name.kocustom.feature new file mode 100644 index 0000000..197f983 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/file-name/file_name.kocustom.feature @@ -0,0 +1,11 @@ +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/fixme.feature b/gherkin-checks/src/test/resources/checks/fixme.feature new file mode 100644 index 0000000..16269e8 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/fixme.feature @@ -0,0 +1,22 @@ +Feature: My feature... + + # Noncompliant {{Take the required action to fix the issue indicated by this comment.}} + # FIXME: blabla + + # Noncompliant {{Take the required action to fix the issue indicated by this comment.}} + #FIXME: blabla + + # Noncompliant {{Take the required action to fix the issue indicated by this comment.}} + #[[FIXME]] blabla + + # fixmeforthefirsttime + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/incomplete-examples-table.feature b/gherkin-checks/src/test/resources/checks/incomplete-examples-table.feature new file mode 100644 index 0000000..d6571e3 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/incomplete-examples-table.feature @@ -0,0 +1,25 @@ +Feature: My feature... + + Scenario Outline: Scenario 1 + Given blabla... + When blabla... + Then blabla... + # Noncompliant [[sc=5;ec=13]] {{Add a table to this "Examples" section.}} + Examples: + + Scenario Outline: Scenario 2 + Given blabla... + When blabla... + Then blabla... + Examples: + # Noncompliant [[sc=7;ec=15]] {{Add data rows to this table.}} + | test | + + Scenario Outline: Scenario 3 + Given blabla... + When blabla... + Then blabla... + Examples: + # Noncompliant [[sc=7;ec=15]] {{Add data rows to this table or convert this "Scenario Outline" to a standard "Scenario".}} + | test | + | 1 | diff --git a/gherkin-checks/src/test/resources/checks/indentation/indentation-custom-ko.feature b/gherkin-checks/src/test/resources/checks/indentation/indentation-custom-ko.feature new file mode 100644 index 0000000..ab30d9e --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/indentation/indentation-custom-ko.feature @@ -0,0 +1,60 @@ + # Noncompliant {{Indent this line at column 0 (currently indented at column 1).}} + @tag + # Noncompliant {{Indent this line at column 0 (currently indented at column 1).}} + Feature: My feature... + blabla... + # Noncompliant {{Indent this line at column 4 (currently indented at column 5).}} + blabla... + + # Noncompliant {{Indent this line at column 4 (currently indented at column 5).}} + Background: blabla... + blabla... + # Noncompliant {{Indent this line at column 8 (currently indented at column 7).}} + blabla... + # Noncompliant {{Indent this line at column 8 (currently indented at column 10).}} + Given blabla... + + # Noncompliant {{Indent this line at column 4 (currently indented at column 5).}} + @tag + # Noncompliant {{Indent this line at column 4 (currently indented at column 3).}} + Scenario: Scenario 1 + # Noncompliant {{Indent this line at column 8 (currently indented at column 9).}} + blabla... + blabla... + Given blabla... + When blabla... + Then blabla... + + @tag + # Noncompliant {{Indent this line at column 4 (currently indented at column 5).}} + @tag @tag + # Noncompliant {{Indent this line at column 4 (currently indented at column 3).}} + Scenario Outline: Scenario 2 + # Noncompliant {{Indent this line at column 8 (currently indented at column 7).}} + blabla... + blabla... + Given blabla... + When blabla... + | data | + # Noncompliant {{Indent this line at column 12 (currently indented at column 13).}} + | 2 | + Then blabla... + # Noncompliant {{Indent this line at column 12 (currently indented at column 13).}} + """string + blabla... + blabla... + """ + # Noncompliant [[sl=-1]] {{Indent this line at column 12 (currently indented at column 11).}} + + # Noncompliant {{Indent this line at column 8 (currently indented at column 9).}} + @tag @tag + # Noncompliant {{Indent this line at column 8 (currently indented at column 9).}} + Examples: blabla... + # Noncompliant {{Indent this line at column 12 (currently indented at column 13).}} + blabla... + blabla... + # Noncompliant {{Indent this line at column 12 (currently indented at column 11).}} + | data | + # Noncompliant {{Indent this line at column 12 (currently indented at column 13).}} + | 1 | + | 2 | diff --git a/gherkin-checks/src/test/resources/checks/indentation/indentation-custom-ok.feature b/gherkin-checks/src/test/resources/checks/indentation/indentation-custom-ok.feature new file mode 100644 index 0000000..b8a03a0 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/indentation/indentation-custom-ok.feature @@ -0,0 +1,40 @@ +@tag +@tag +Feature: My feature... + blabla... + blabla... + + Background: blabla... + blabla... + blabla... + Given blabla... + + @tag + Scenario: Scenario 1 + blabla... + blabla... + Given blabla... + When blabla... + Then blabla... + + @tag @tag + Scenario Outline: Scenario 2 + blabla... + blabla... + Given blabla... + When blabla... + | data | + | 2 | + Then blabla... + """string + blabla... + blabla... + """ + + @tag + @tag @tag + Examples: blabla... + blabla... + blabla... + | data | + | 1 | diff --git a/gherkin-checks/src/test/resources/checks/indentation/indentation-default-ko.feature b/gherkin-checks/src/test/resources/checks/indentation/indentation-default-ko.feature new file mode 100644 index 0000000..8dec47b --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/indentation/indentation-default-ko.feature @@ -0,0 +1,61 @@ +# Noncompliant {{Indent this line at column 0 (currently indented at column 1).}} + @tag +@tag + # Noncompliant {{Indent this line at column 0 (currently indented at column 2).}} + Feature: My feature... + # Noncompliant {{Indent this line at column 2 (currently indented at column 4).}} + blabla... + blabla... + + # Noncompliant {{Indent this line at column 2 (currently indented at column 1).}} + Background: blabla... + # Noncompliant {{Indent this line at column 4 (currently indented at column 2).}} + blabla... + blabla... + # Noncompliant {{Indent this line at column 4 (currently indented at column 5).}} + Given blabla... + + # Noncompliant {{Indent this line at column 2 (currently indented at column 4).}} + @tag + # Noncompliant {{Indent this line at column 2 (currently indented at column 3).}} + Scenario: Scenario 1 + blabla... + # Noncompliant {{Indent this line at column 4 (currently indented at column 7).}} + blabla... + Given blabla... + When blabla... + Then blabla... + + @tag + # Noncompliant {{Indent this line at column 2 (currently indented at column 4).}} + @tag + # Noncompliant {{Indent this line at column 2 (currently indented at column 3).}} + Scenario Outline: Scenario 2 + # Noncompliant {{Indent this line at column 4 (currently indented at column 5).}} + blabla... + blabla... + Given blabla... + When blabla... + | data | + # Noncompliant {{Indent this line at column 6 (currently indented at column 7).}} + | 2 | + Then blabla... + # Noncompliant {{Indent this line at column 6 (currently indented at column 7).}} + """string + blabla... + blabla... + """ + # Noncompliant [[sl=-1]] {{Indent this line at column 6 (currently indented at column 5).}} + + # Noncompliant {{Indent this line at column 4 (currently indented at column 5).}} + @tag + # Noncompliant {{Indent this line at column 4 (currently indented at column 5).}} + Examples: blabla... + blabla... + # Noncompliant {{Indent this line at column 6 (currently indented at column 7).}} + blabla... + # Noncompliant {{Indent this line at column 6 (currently indented at column 5).}} + | data | + # Noncompliant {{Indent this line at column 6 (currently indented at column 7).}} + | 1 | + | 2 | diff --git a/gherkin-checks/src/test/resources/checks/indentation/indentation-default-ok.feature b/gherkin-checks/src/test/resources/checks/indentation/indentation-default-ok.feature new file mode 100644 index 0000000..49f0e71 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/indentation/indentation-default-ok.feature @@ -0,0 +1,40 @@ +@tag +@tag1 +Feature: My feature... + blabla... + blabla... + + Background: blabla... + blabla... + blabla... + Given blabla... + + @tag @tag1 + Scenario: Scenario 1 + blabla... + blabla... + Given blabla... + When blabla... + Then blabla... + + @tag + Scenario Outline: Scenario 2 + blabla... + blabla... + Given blabla... + When blabla... + | data | + | 2 | + Then blabla... + """string + blabla... + blabla... + """ + + @tag + @tag @tag + Examples: blabla... + blabla... + blabla... + | data | + | 1 | diff --git a/gherkin-checks/src/test/resources/checks/max-number-scenarios/greater-than-custom-threshold.feature b/gherkin-checks/src/test/resources/checks/max-number-scenarios/greater-than-custom-threshold.feature new file mode 100644 index 0000000..2fba9b0 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/max-number-scenarios/greater-than-custom-threshold.feature @@ -0,0 +1,24 @@ +# Noncompliant [[sc=1;ec=8]] {{The number of scenarios (5) is greater that the maximum allowed (4). Split the scenarios into different features.}} +Feature: My feature... + + Background: + Given blabla... + + Scenario: scenario #1 + Given blabla... + + Scenario Outline: scenario #2 + Given blabla... + Examples: + | data | + | 1 | + | 2 | + + Scenario: scenario #3 + Given blabla... + + Scenario: scenario #4 + Given blabla... + + Scenario: scenario #5 + Given blabla... diff --git a/gherkin-checks/src/test/resources/checks/max-number-scenarios/greater-than-default-threshold.feature b/gherkin-checks/src/test/resources/checks/max-number-scenarios/greater-than-default-threshold.feature new file mode 100644 index 0000000..4756d3f --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/max-number-scenarios/greater-than-default-threshold.feature @@ -0,0 +1,48 @@ +# Noncompliant [[sc=1;ec=8]] {{The number of scenarios (13) is greater that the maximum allowed (12). Split the scenarios into different features.}} +Feature: My feature... + + Background: + Given blabla... + + Scenario: scenario #1 + Given blabla... + + Scenario Outline: scenario #2 + Given blabla... + Examples: + | data | + | 1 | + | 2 | + + Scenario: scenario #3 + Given blabla... + + Scenario: scenario #4 + Given blabla... + + Scenario: scenario #5 + Given blabla... + + Scenario: scenario #6 + Given blabla... + + Scenario: scenario #7 + Given blabla... + + Scenario: scenario #8 + Given blabla... + + Scenario: scenario #9 + Given blabla... + + Scenario: scenario #10 + Given blabla... + + Scenario: scenario #11 + Given blabla... + + Scenario: scenario #12 + Given blabla... + + Scenario: scenario #13 + Given blabla... diff --git a/gherkin-checks/src/test/resources/checks/max-number-scenarios/lower-than-custom-threshold.feature b/gherkin-checks/src/test/resources/checks/max-number-scenarios/lower-than-custom-threshold.feature new file mode 100644 index 0000000..6ee15da --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/max-number-scenarios/lower-than-custom-threshold.feature @@ -0,0 +1,20 @@ +Feature: My feature... + + Background: + Given blabla... + + Scenario: scenario #1 + Given blabla... + + Scenario Outline: scenario #2 + Given blabla... + Examples: + | data | + | 1 | + | 2 | + + Scenario: scenario #3 + Given blabla... + + Scenario: scenario #4 + Given blabla... diff --git a/gherkin-checks/src/test/resources/checks/max-number-scenarios/lower-than-default-threshold.feature b/gherkin-checks/src/test/resources/checks/max-number-scenarios/lower-than-default-threshold.feature new file mode 100644 index 0000000..0203f79 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/max-number-scenarios/lower-than-default-threshold.feature @@ -0,0 +1,44 @@ +Feature: My feature... + + Background: + Given blabla... + + Scenario: scenario #1 + Given blabla... + + Scenario Outline: scenario #2 + Given blabla... + Examples: + | data | + | 1 | + | 2 | + + Scenario: scenario #3 + Given blabla... + + Scenario: scenario #4 + Given blabla... + + Scenario: scenario #5 + Given blabla... + + Scenario: scenario #6 + Given blabla... + + Scenario: scenario #7 + Given blabla... + + Scenario: scenario #8 + Given blabla... + + Scenario: scenario #9 + Given blabla... + + Scenario: scenario #10 + Given blabla... + + Scenario: scenario #11 + Given blabla... + + Scenario: scenario #12 + Given blabla... diff --git a/gherkin-checks/src/test/resources/checks/max-number-steps/max-number-steps-background.feature b/gherkin-checks/src/test/resources/checks/max-number-steps/max-number-steps-background.feature new file mode 100644 index 0000000..9f10bcb --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/max-number-steps/max-number-steps-background.feature @@ -0,0 +1,28 @@ +Feature: My feature... + + Background: + Given blabla... + And blabla... + And blabla... + And blabla... + And blabla... + + Scenario: scenario #1 + Given blabla... + When blabla... + Then blabla... + And blabla... + And blabla... + And blabla... + And blabla... + + # Noncompliant [[sc=3;ec=11]] {{Reduce the number of steps (13, greater than 12 allowed)}} + Scenario: scenario #2 + Given blabla... + When blabla... + Then blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... diff --git a/gherkin-checks/src/test/resources/checks/max-number-steps/max-number-steps-custom-threshold.feature b/gherkin-checks/src/test/resources/checks/max-number-steps/max-number-steps-custom-threshold.feature new file mode 100644 index 0000000..7e8482b --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/max-number-steps/max-number-steps-custom-threshold.feature @@ -0,0 +1,18 @@ +Feature: My feature... + + Scenario: scenario #1 + Given blabla... + When blabla... + Then blabla... + And blabla... + And blabla... + + # Noncompliant [[sc=3;ec=11]] {{Reduce the number of steps (7, greater than 5 allowed)}} + Scenario: scenario #2 + Given blabla... + When blabla... + Then blabla... + And blabla... + And blabla... + And blabla... + And blabla... diff --git a/gherkin-checks/src/test/resources/checks/max-number-steps/max-number-steps-no-background.feature b/gherkin-checks/src/test/resources/checks/max-number-steps/max-number-steps-no-background.feature new file mode 100644 index 0000000..778fdff --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/max-number-steps/max-number-steps-no-background.feature @@ -0,0 +1,31 @@ +Feature: My feature... + + Scenario: scenario #1 + Given blabla... + When blabla... + Then blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... + + # Noncompliant [[sc=3;ec=11]] {{Reduce the number of steps (13, greater than 12 allowed)}} + Scenario: scenario #2 + Given blabla... + When blabla... + Then blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... diff --git a/gherkin-checks/src/test/resources/checks/new-line-end-of-file/new-line-end-of-file.feature b/gherkin-checks/src/test/resources/checks/new-line-end-of-file/new-line-end-of-file.feature new file mode 100644 index 0000000..197f983 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/new-line-end-of-file/new-line-end-of-file.feature @@ -0,0 +1,11 @@ +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/new-line-end-of-file/no-new-line-end-of-file.feature b/gherkin-checks/src/test/resources/checks/new-line-end-of-file/no-new-line-end-of-file.feature new file mode 100644 index 0000000..3db3cd6 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/new-line-end-of-file/no-new-line-end-of-file.feature @@ -0,0 +1,11 @@ +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... \ No newline at end of file diff --git a/gherkin-checks/src/test/resources/checks/no-feature/feature.feature b/gherkin-checks/src/test/resources/checks/no-feature/feature.feature new file mode 100644 index 0000000..18c0a2b --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/no-feature/feature.feature @@ -0,0 +1,5 @@ +Feature: My feature... + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/no-feature/no-feature.feature b/gherkin-checks/src/test/resources/checks/no-feature/no-feature.feature new file mode 100644 index 0000000..da05b93 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/no-feature/no-feature.feature @@ -0,0 +1 @@ +# Noncompliant [[sl=0]] {{Remove this file that does not define any feature.}} diff --git a/gherkin-checks/src/test/resources/checks/no-scenario/no-scenario.feature b/gherkin-checks/src/test/resources/checks/no-scenario/no-scenario.feature new file mode 100644 index 0000000..c76fabe --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/no-scenario/no-scenario.feature @@ -0,0 +1,2 @@ +# Noncompliant [[sc=1;ec=8]] {{Remove this feature that does not define any scenario.}} +Feature: My feature... diff --git a/gherkin-checks/src/test/resources/checks/no-scenario/scenario-outline.feature b/gherkin-checks/src/test/resources/checks/no-scenario/scenario-outline.feature new file mode 100644 index 0000000..0f8f8e9 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/no-scenario/scenario-outline.feature @@ -0,0 +1,9 @@ +Feature: My feature... + Scenario Outline: Scenario 1 + Given blabla... + When blabla... + Then blabla... + Examples: + | data | + | 1 | + | 2 | diff --git a/gherkin-checks/src/test/resources/checks/no-scenario/scenario.feature b/gherkin-checks/src/test/resources/checks/no-scenario/scenario.feature new file mode 100644 index 0000000..18c0a2b --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/no-scenario/scenario.feature @@ -0,0 +1,5 @@ +Feature: My feature... + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/star-step-prefix.feature b/gherkin-checks/src/test/resources/checks/star-step-prefix.feature new file mode 100644 index 0000000..a910b62 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/star-step-prefix.feature @@ -0,0 +1,12 @@ +Feature: My feature... + + Scenario: My scenario 1 + # Noncompliant [[sc=5;ec=6]] {{Replace this star prefix with Given/When/Then.}} + * blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/tab-character/no-tab-character.feature b/gherkin-checks/src/test/resources/checks/tab-character/no-tab-character.feature new file mode 100644 index 0000000..197f983 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/tab-character/no-tab-character.feature @@ -0,0 +1,11 @@ +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/tab-character/tab-character.feature b/gherkin-checks/src/test/resources/checks/tab-character/tab-character.feature new file mode 100644 index 0000000..87aaa1e --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/tab-character/tab-character.feature @@ -0,0 +1,11 @@ +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/tag-name/tag-name-custom-ko.feature b/gherkin-checks/src/test/resources/checks/tag-name/tag-name-custom-ko.feature new file mode 100644 index 0000000..92ccf8e --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/tag-name/tag-name-custom-ko.feature @@ -0,0 +1,14 @@ +# Noncompliant [[sc=1;ec=7]] {{Rename this tag to match the regular expression: ^[a-z]+$}} +@myTag +Feature: My feature... + + @tag + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/tag-name/tag-name-custom-ok.feature b/gherkin-checks/src/test/resources/checks/tag-name/tag-name-custom-ok.feature new file mode 100644 index 0000000..1e38448 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/tag-name/tag-name-custom-ok.feature @@ -0,0 +1,13 @@ +@my-tag +Feature: My feature... + + @tag + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/tag-name/tag-name-ko.feature b/gherkin-checks/src/test/resources/checks/tag-name/tag-name-ko.feature new file mode 100644 index 0000000..3dd4b88 --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/tag-name/tag-name-ko.feature @@ -0,0 +1,15 @@ +# Noncompliant [[sc=1;ec=7]] {{Rename this tag to match the regular expression: ^[a-z][-a-z0-9]*$}} +@myTag @my-tag +Feature: My feature... + + # Noncompliant [[sc=3;ec=10]] {{Rename this tag to match the regular expression: ^[a-z][-a-z0-9]*$}} + @myTag0 + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/tag-name/tag-name-ok.feature b/gherkin-checks/src/test/resources/checks/tag-name/tag-name-ok.feature new file mode 100644 index 0000000..f12915c --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/tag-name/tag-name-ok.feature @@ -0,0 +1,13 @@ +@mytag @my-tag +Feature: My feature... + + @my-tag1 + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/todo.feature b/gherkin-checks/src/test/resources/checks/todo.feature new file mode 100644 index 0000000..123d63e --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/todo.feature @@ -0,0 +1,22 @@ +Feature: My feature... + + # Noncompliant + # TODO: blabla + + # Noncompliant + #TODO: blabla + + # Noncompliant + #[[TODO]] blabla + + # todoforthefirsttime + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-checks/src/test/resources/checks/trailing-whitespace.feature b/gherkin-checks/src/test/resources/checks/trailing-whitespace.feature new file mode 100644 index 0000000..01f73ed --- /dev/null +++ b/gherkin-checks/src/test/resources/checks/trailing-whitespace.feature @@ -0,0 +1,14 @@ +# Noncompliant [[sl=3]] {{Remove the useless trailing whitespaces at the end of this line.}} +# Noncompliant [[sl=6]] {{Remove the useless trailing whitespaces at the end of this line.}} +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... + diff --git a/gherkin-frontend/pom.xml b/gherkin-frontend/pom.xml new file mode 100644 index 0000000..e96222e --- /dev/null +++ b/gherkin-frontend/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + + + com.racodond.sonarqube.plugin.gherkin + gherkin + 1.0-SNAPSHOT + + + gherkin-frontend + SonarQube Gherkin Analyzer :: Frontend + + + + org.sonarsource.sonarqube + sonar-plugin-api + provided + + + commons-lang + commons-lang + + + org.sonarsource.sslr + sslr-core + + + org.sonarsource.sslr-squid-bridge + sslr-squid-bridge + + + com.google.guava + guava + + + junit + junit + test + + + org.sonarsource.sslr + sslr-testing-harness + test + + + org.mockito + mockito-all + test + + + org.easytesting + fest-assert + test + + + + + + + org.jacoco + jacoco-maven-plugin + + ${sonar.jacoco.reportPath} + + + + + + diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/parser/GherkinGrammar.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/parser/GherkinGrammar.java new file mode 100644 index 0000000..13cc49d --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/parser/GherkinGrammar.java @@ -0,0 +1,181 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import com.sonar.sslr.api.typed.GrammarBuilder; +import org.sonar.gherkin.tree.impl.InternalSyntaxToken; +import org.sonar.plugins.gherkin.api.tree.*; + +public class GherkinGrammar { + + private final GrammarBuilder b; + private final TreeFactory f; + + public GherkinGrammar(GrammarBuilder b, TreeFactory f) { + this.b = b; + this.f = f; + } + + public GherkinDocumentTree GHERKIN_DOCUMENT() { + return b.nonterminal(GherkinLexicalGrammar.GHERKIN_DOCUMENT).is( + f.gherkinDocument( + b.optional(b.token(GherkinLexicalGrammar.BOM)), + b.optional(FEATURE()), + b.token(GherkinLexicalGrammar.EOF))); + } + + public FeatureTree FEATURE() { + return b.nonterminal(GherkinLexicalGrammar.FEATURE).is( + f.feature( + FEATURE_DECLARATION(), + b.optional(BACKGROUND()), + b.zeroOrMore( + b.firstOf( + SCENARIO_OUTLINE(), + SCENARIO())))); + } + + public FeatureDeclarationTree FEATURE_DECLARATION() { + return b.nonterminal(GherkinLexicalGrammar.FEATURE_DECLARATION).is( + f.featureDeclaration( + b.zeroOrMore(TAG()), + FEATURE_PREFIX(), + b.token(GherkinLexicalGrammar.COLON), + NAME(), + b.optional(DESCRIPTION()))); + } + + public BackgroundTree BACKGROUND() { + return b.nonterminal(GherkinLexicalGrammar.BACKGROUND).is( + f.background( + BACKGROUND_PREFIX(), + b.token(GherkinLexicalGrammar.COLON), + b.optional(DESCRIPTION()), + b.zeroOrMore(STEP()))); + } + + public ScenarioTree SCENARIO() { + return b.nonterminal(GherkinLexicalGrammar.SCENARIO).is( + f.scenario( + b.zeroOrMore(TAG()), + SCENARIO_PREFIX(), + b.token(GherkinLexicalGrammar.COLON), + NAME(), + b.optional(DESCRIPTION()), + b.zeroOrMore(STEP()))); + } + + public ScenarioOutlineTree SCENARIO_OUTLINE() { + return b.nonterminal(GherkinLexicalGrammar.SCENARIO_OUTLINE).is( + f.scenarioOutline( + b.zeroOrMore(TAG()), + SCENARIO_OUTLINE_PREFIX(), + b.token(GherkinLexicalGrammar.COLON), + NAME(), + b.optional(DESCRIPTION()), + b.zeroOrMore(STEP()), + EXAMPLES())); + } + + public ExamplesTree EXAMPLES() { + return b.nonterminal(GherkinLexicalGrammar.EXAMPLES).is( + f.examples( + b.zeroOrMore(TAG()), + EXAMPLES_PREFIX(), + b.token(GherkinLexicalGrammar.COLON), + b.optional(DESCRIPTION()), + b.optional(TABLE()))); + } + + public StepTree STEP() { + return b.nonterminal(GherkinLexicalGrammar.STEP).is( + f.step( + STEP_PREFIX(), + b.token(GherkinLexicalGrammar.STEP_SENTENCE), + b.optional( + b.firstOf( + TABLE(), + DOC_STRING())))); + } + + public TagTree TAG() { + return b.nonterminal(GherkinLexicalGrammar.TAG).is( + f.tag( + b.token(GherkinLexicalGrammar.TAG_PREFIX), + b.token(GherkinLexicalGrammar.TAG_LITERAL))); + } + + public DescriptionTree DESCRIPTION() { + return b.nonterminal(GherkinLexicalGrammar.DESCRIPTION).is( + f.description( + b.oneOrMore(b.token(GherkinLexicalGrammar.DESCRIPTION_SENTENCE)))); + } + + public FeaturePrefixTree FEATURE_PREFIX() { + return b.nonterminal(GherkinLexicalGrammar.FEATURE_PREFIX).is( + f.featurePrefix(b.token(GherkinLexicalGrammar.FEATURE_KEYWORD))); + } + + public BackgroundPrefixTree BACKGROUND_PREFIX() { + return b.nonterminal(GherkinLexicalGrammar.BACKGROUND_PREFIX).is( + f.backgroundPrefix(b.token(GherkinLexicalGrammar.BACKGROUND_KEYWORD))); + } + + public ScenarioPrefixTree SCENARIO_PREFIX() { + return b.nonterminal(GherkinLexicalGrammar.SCENARIO_PREFIX).is( + f.scenarioPrefix(b.token(GherkinLexicalGrammar.SCENARIO_KEYWORD))); + } + + public ScenarioOutlinePrefixTree SCENARIO_OUTLINE_PREFIX() { + return b.nonterminal(GherkinLexicalGrammar.SCENARIO_OUTLINE_PREFIX).is( + f.scenarioOutlinePrefix(b.token(GherkinLexicalGrammar.SCENARIO_OUTLINE_KEYWORD))); + } + + public ExamplesPrefixTree EXAMPLES_PREFIX() { + return b.nonterminal(GherkinLexicalGrammar.EXAMPLES_PREFIX).is( + f.examplesPrefix(b.token(GherkinLexicalGrammar.EXAMPLES_KEYWORD))); + } + + public StepPrefixTree STEP_PREFIX() { + return b.nonterminal(GherkinLexicalGrammar.STEP_PREFIX).is( + f.stepPrefix(b.token(GherkinLexicalGrammar.STEP_KEYWORD))); + } + + public NameTree NAME() { + return b.nonterminal(GherkinLexicalGrammar.NAME).is( + f.name(b.token(GherkinLexicalGrammar.NAME_LITERAL))); + } + + public DocStringTree DOC_STRING() { + return b.nonterminal(GherkinLexicalGrammar.DOC_STRING).is( + f.docString( + b.token(GherkinLexicalGrammar.DOC_STRING_PREFIX), + b.optional(b.token(GherkinLexicalGrammar.DOC_STRING_CONTENT_TYPE)), + b.zeroOrMore(b.token(GherkinLexicalGrammar.DOC_STRING_DATA_ROW)), + b.token(GherkinLexicalGrammar.DOC_STRING_SUFFIX))); + } + + public TableTree TABLE() { + return b.nonterminal(GherkinLexicalGrammar.TABLE).is( + f.table( + b.oneOrMore(b.token(GherkinLexicalGrammar.TABLE_DATA_ROW)))); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/parser/GherkinLexicalGrammar.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/parser/GherkinLexicalGrammar.java new file mode 100644 index 0000000..2cee4da --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/parser/GherkinLexicalGrammar.java @@ -0,0 +1,130 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import com.sonar.sslr.api.GenericTokenType; +import org.sonar.sslr.grammar.GrammarRuleKey; +import org.sonar.sslr.grammar.LexerlessGrammarBuilder; + +public enum GherkinLexicalGrammar implements GrammarRuleKey { + GHERKIN_DOCUMENT, + + FEATURE, + FEATURE_DECLARATION, + FEATURE_PREFIX, + FEATURE_KEYWORD, + + BACKGROUND, + BACKGROUND_PREFIX, + BACKGROUND_KEYWORD, + + SCENARIO, + SCENARIO_PREFIX, + SCENARIO_KEYWORD, + + SCENARIO_OUTLINE, + SCENARIO_OUTLINE_PREFIX, + SCENARIO_OUTLINE_KEYWORD, + + EXAMPLES, + EXAMPLES_PREFIX, + EXAMPLES_KEYWORD, + + STEP, + STEP_PREFIX, + STEP_KEYWORD, + STEP_SENTENCE, + + COLON, + + NAME, + NAME_LITERAL, + + DESCRIPTION, + DESCRIPTION_SENTENCE, + + TAG, + TAG_PREFIX, + TAG_LITERAL, + + DOC_STRING, + DOC_STRING_CONTENT_TYPE, + DOC_STRING_PREFIX, + DOC_STRING_SUFFIX, + DOC_STRING_DATA_ROW, + + TABLE, + TABLE_DATA_ROW, + + SPACING, + SPACING_NO_COMMENTS, + + BOM, + EOF; + + public static LexerlessGrammarBuilder createGrammar() { + LexerlessGrammarBuilder b = LexerlessGrammarBuilder.create(); + syntax(b); + b.setRootRule(GHERKIN_DOCUMENT); + return b; + } + + private static void syntax(LexerlessGrammarBuilder b) { + + String whitespaceRegex = "(? children, int startIndex, int endIndex) { + for (Object child : children) { + if (child instanceof InternalSyntaxToken) { + return child; + } + } + return new InternalSyntaxSpacing(startIndex, endIndex); + } + + @Override + public Object createTerminal(Input input, int startIndex, int endIndex, List trivias, TokenType type) { + char[] fileChars = input.input(); + boolean hasByteOrderMark = fileChars.length > 0 && fileChars[0] == BYTE_ORDER_MARK; + boolean isEof = GenericTokenType.EOF.equals(type); + LineColumnValue lineColumnValue = tokenPosition(input, startIndex, endIndex); + return new InternalSyntaxToken( + lineColumnValue.line, + column(hasByteOrderMark, lineColumnValue.line, lineColumnValue.column), + lineColumnValue.value, + createTrivias(trivias, hasByteOrderMark), + isEof, + isByteOrderMark(input, startIndex, endIndex)); + } + + private static List createTrivias(List trivias, boolean hasByteOrderMark) { + List result = new ArrayList<>(); + for (Trivia trivia : trivias) { + Token trivialToken = trivia.getToken(); + int column = column(hasByteOrderMark, trivialToken.getLine(), trivialToken.getColumn()); + result.add(InternalSyntaxTrivia.create(trivialToken.getValue(), trivialToken.getLine(), column)); + } + return result; + } + + private static int column(boolean hasByteOrderMark, int line, int column) { + if (hasByteOrderMark && line == 1) { + return column - 1; + } + return column; + } + + private static LineColumnValue tokenPosition(Input input, int startIndex, int endIndex) { + int[] lineAndColumn = input.lineAndColumnAt(startIndex); + String value = input.substring(startIndex, endIndex); + return new LineColumnValue(lineAndColumn[0], lineAndColumn[1] - 1, value); + } + + private static boolean isByteOrderMark(Input input, int startIndex, int endIndex) { + return (Character.toString(BYTE_ORDER_MARK)).equals(input.substring(startIndex, endIndex)); + } + + private static class LineColumnValue { + final int line; + final int column; + final String value; + + private LineColumnValue(int line, int column, String value) { + this.line = line; + this.column = column; + this.value = value; + } + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/parser/GherkinParser.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/parser/GherkinParser.java new file mode 100644 index 0000000..3af3750 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/parser/GherkinParser.java @@ -0,0 +1,56 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import com.google.common.collect.Lists; +import com.sonar.sslr.api.typed.ActionParser; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.sslr.grammar.GrammarRuleKey; +import org.sonar.sslr.grammar.LexerlessGrammarBuilder; + +import java.io.File; +import java.nio.charset.Charset; + +public class GherkinParser extends ActionParser { + + public GherkinParser(Charset charset, LexerlessGrammarBuilder grammarBuilder, Class grammarClass, + TreeFactory treeFactory, GherkinNodeBuilder nodeBuilder, GrammarRuleKey rootRule) { + super(charset, grammarBuilder, grammarClass, treeFactory, nodeBuilder, rootRule); + } + + @Override + public Tree parse(File file) { + return createParentLink(super.parse(file)); + } + + private static Tree createParentLink(Tree parent) { + if (!parent.isLeaf()) { + Lists.newArrayList(parent.childrenIterator()) + .stream() + .filter(nextTree -> nextTree != null) + .forEach(nextTree -> { + nextTree.setParent(parent); + createParentLink(nextTree); + }); + } + return parent; + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/parser/GherkinParserBuilder.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/parser/GherkinParserBuilder.java new file mode 100644 index 0000000..5a3eff9 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/parser/GherkinParserBuilder.java @@ -0,0 +1,51 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import com.google.common.annotations.VisibleForTesting; +import org.sonar.sslr.grammar.GrammarRuleKey; + +import java.nio.charset.Charset; + +public class GherkinParserBuilder { + + private GherkinParserBuilder() { + } + + public static GherkinParser createParser(Charset charset) { + return createParser(charset, GherkinLexicalGrammar.GHERKIN_DOCUMENT); + } + + @VisibleForTesting + public static GherkinParser createTestParser(Charset charset, GrammarRuleKey rootRule) { + return createParser(charset, rootRule); + } + + private static GherkinParser createParser(Charset charset, GrammarRuleKey rootRule) { + return new GherkinParser( + charset, + GherkinLexicalGrammar.createGrammar(), + GherkinGrammar.class, + new TreeFactory(), + new GherkinNodeBuilder(), + rootRule); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/parser/TreeFactory.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/parser/TreeFactory.java new file mode 100644 index 0000000..2fa677a --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/parser/TreeFactory.java @@ -0,0 +1,106 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import com.sonar.sslr.api.typed.Optional; +import org.sonar.gherkin.tree.impl.*; +import org.sonar.plugins.gherkin.api.tree.*; + +import java.util.List; + +public class TreeFactory { + + public GherkinDocumentTree gherkinDocument(Optional byteOrderMark, Optional feature, SyntaxToken eof) { + return new GherkinDocumentTreeImpl(byteOrderMark.orNull(), feature.orNull(), eof); + } + + public FeatureTree feature(FeatureDeclarationTree featureDeclaration, Optional background, Optional> allScenarios) { + return new FeatureTreeImpl(featureDeclaration, background.orNull(), allScenarios.orNull()); + } + + public FeatureDeclarationTree featureDeclaration(Optional> tags, PrefixTree prefix, SyntaxToken colon, NameTree name, Optional description) { + return new FeatureDeclarationTreeImpl(tags.orNull(), prefix, colon, name, description.orNull()); + } + + public BackgroundTree background(PrefixTree prefix, SyntaxToken colon, Optional description, Optional> steps) { + return new BackgroundTreeImpl(prefix, colon, description.orNull(), steps.orNull()); + } + + public ScenarioTree scenario(Optional> tags, PrefixTree prefix, SyntaxToken colon, NameTree name, Optional description, Optional> steps) { + return new ScenarioTreeImpl(tags.orNull(), prefix, colon, name, description.orNull(), steps.orNull()); + } + + public ScenarioOutlineTree scenarioOutline(Optional> tags, PrefixTree prefix, SyntaxToken colon, NameTree name, Optional description, Optional> steps, ExamplesTree examples) { + return new ScenarioOutlineTreeImpl(tags.orNull(), prefix, colon, name, description.orNull(), steps.orNull(), examples); + } + + public ExamplesTree examples(Optional> tags, PrefixTree prefix, SyntaxToken colon, Optional description, Optional table) { + return new ExamplesTreeImpl(tags.orNull(), prefix, colon, description.orNull(), table.orNull()); + } + + public StepTree step(PrefixTree prefix, SyntaxToken sentence, Optional data) { + return new StepTreeImpl(prefix, sentence, data.orNull()); + } + + public TagTree tag(SyntaxToken prefix, SyntaxToken value) { + return new TagTreeImpl(prefix, value); + } + + public DescriptionTree description(List descriptionLines) { + return new DescriptionTreeImpl(descriptionLines); + } + + public FeaturePrefixTree featurePrefix(SyntaxToken keyword) { + return new FeaturePrefixTreeImpl(keyword); + } + + public BackgroundPrefixTree backgroundPrefix(SyntaxToken keyword) { + return new BackgroundPrefixTreeImpl(keyword); + } + + public ScenarioPrefixTree scenarioPrefix(SyntaxToken keyword) { + return new ScenarioPrefixTreeImpl(keyword); + } + + public ScenarioOutlinePrefixTree scenarioOutlinePrefix(SyntaxToken keyword) { + return new ScenarioOutlinePrefixTreeImpl(keyword); + } + + public ExamplesPrefixTree examplesPrefix(SyntaxToken keyword) { + return new ExamplesPrefixTreeImpl(keyword); + } + + public StepPrefixTree stepPrefix(SyntaxToken keyword) { + return new StepPrefixTreeImpl(keyword); + } + + public NameTree name(SyntaxToken name) { + return new NameTreeImpl(name); + } + + public DocStringTree docString(SyntaxToken prefix, Optional contentType, Optional> data, SyntaxToken suffix) { + return new DocStringTreeImpl(prefix, contentType.orNull(), data.orNull(), suffix); + } + + public TableTree table(List rows) { + return new TableTreeImpl(rows); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/parser/package-info.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/parser/package-info.java new file mode 100644 index 0000000..be58033 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/parser/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +@ParametersAreNonnullByDefault +package org.sonar.gherkin.parser; + +import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/AbstractPrefixTreeImpl.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/AbstractPrefixTreeImpl.java new file mode 100644 index 0000000..fa4d83c --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/AbstractPrefixTreeImpl.java @@ -0,0 +1,52 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import com.google.common.collect.Iterators; +import org.sonar.plugins.gherkin.api.tree.PrefixTree; +import org.sonar.plugins.gherkin.api.tree.SyntaxToken; +import org.sonar.plugins.gherkin.api.tree.Tree; + +import java.util.Iterator; + +public abstract class AbstractPrefixTreeImpl extends GherkinTree implements PrefixTree { + + private final SyntaxToken keyword; + + public AbstractPrefixTreeImpl(SyntaxToken keyword) { + this.keyword = keyword; + } + + @Override + public Iterator childrenIterator() { + return Iterators.singletonIterator(keyword); + } + + @Override + public SyntaxToken keyword() { + return keyword; + } + + @Override + public String text() { + return keyword.text(); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/BackgroundPrefixTreeImpl.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/BackgroundPrefixTreeImpl.java new file mode 100644 index 0000000..67fbd9b --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/BackgroundPrefixTreeImpl.java @@ -0,0 +1,42 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import org.sonar.plugins.gherkin.api.tree.BackgroundPrefixTree; +import org.sonar.plugins.gherkin.api.tree.SyntaxToken; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +public class BackgroundPrefixTreeImpl extends AbstractPrefixTreeImpl implements BackgroundPrefixTree { + + public BackgroundPrefixTreeImpl(SyntaxToken keyword) { + super(keyword); + } + + @Override + public Kind getKind() { + return Kind.BACKGROUND_PREFIX; + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + visitor.visitBackgroundPrefix(this); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/BackgroundTreeImpl.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/BackgroundTreeImpl.java new file mode 100644 index 0000000..64b223a --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/BackgroundTreeImpl.java @@ -0,0 +1,88 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import com.google.common.collect.Iterators; +import org.sonar.plugins.gherkin.api.tree.*; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class BackgroundTreeImpl extends GherkinTree implements BackgroundTree { + + private final PrefixTree prefix; + private final SyntaxToken colon; + private final DescriptionTree description; + private final List steps; + + public BackgroundTreeImpl(PrefixTree prefix, SyntaxToken colon, @Nullable DescriptionTree description, @Nullable List steps) { + this.prefix = prefix; + this.colon = colon; + this.description = description; + + if (steps != null) { + this.steps = steps; + } else { + this.steps = new ArrayList<>(); + } + } + + @Override + public Kind getKind() { + return Kind.BACKGROUND; + } + + @Override + public Iterator childrenIterator() { + return Iterators.concat( + Iterators.forArray(prefix, colon, description), + steps.iterator()); + } + + @Override + public PrefixTree prefix() { + return prefix; + } + + @Override + public SyntaxToken colon() { + return colon; + } + + @Override + @Nullable + public DescriptionTree description() { + return description; + } + + @Override + public List steps() { + return steps; + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + visitor.visitBackground(this); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/DescriptionTreeImpl.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/DescriptionTreeImpl.java new file mode 100644 index 0000000..4ca8619 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/DescriptionTreeImpl.java @@ -0,0 +1,59 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import org.sonar.plugins.gherkin.api.tree.DescriptionTree; +import org.sonar.plugins.gherkin.api.tree.SyntaxToken; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; + +public class DescriptionTreeImpl extends GherkinTree implements DescriptionTree { + + private final List desriptionLines; + + public DescriptionTreeImpl(List descriptionLines) { + this.desriptionLines = descriptionLines; + } + + @Override + public Kind getKind() { + return Kind.DESCRIPTION; + } + + @Override + public Iterator childrenIterator() { + return desriptionLines.stream().map(t -> (Tree) t).collect(Collectors.toList()).iterator(); + } + + @Override + public List descriptionLines() { + return desriptionLines; + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + visitor.visitDescription(this); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/DocStringTreeImpl.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/DocStringTreeImpl.java new file mode 100644 index 0000000..a23d7ee --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/DocStringTreeImpl.java @@ -0,0 +1,92 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import com.google.common.collect.Iterators; +import org.sonar.plugins.gherkin.api.tree.DocStringTree; +import org.sonar.plugins.gherkin.api.tree.SyntaxToken; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class DocStringTreeImpl extends GherkinTree implements DocStringTree { + + private final SyntaxToken prefix; + private final SyntaxToken suffix; + private final SyntaxToken contentType; + private final List data; + + public DocStringTreeImpl(SyntaxToken prefix, @Nullable SyntaxToken contentType, @Nullable List data, SyntaxToken suffix) { + this.prefix = prefix; + this.contentType = contentType; + + if (data != null) { + this.data = data; + } else { + this.data = new ArrayList<>(); + } + + this.suffix = suffix; + } + + @Override + public Kind getKind() { + return Kind.DOC_STRING; + } + + @Override + public Iterator childrenIterator() { + return Iterators.concat( + Iterators.forArray(prefix, contentType), + data.iterator(), + Iterators.singletonIterator(suffix)); + } + + @Override + public List data() { + return data; + } + + @Override + public SyntaxToken prefix() { + return prefix; + } + + @Override + public SyntaxToken suffix() { + return suffix; + } + + @Override + @Nullable + public SyntaxToken contentType() { + return contentType; + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + visitor.visitDocString(this); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/ExamplesPrefixTreeImpl.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/ExamplesPrefixTreeImpl.java new file mode 100644 index 0000000..f492724 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/ExamplesPrefixTreeImpl.java @@ -0,0 +1,42 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import org.sonar.plugins.gherkin.api.tree.ExamplesPrefixTree; +import org.sonar.plugins.gherkin.api.tree.SyntaxToken; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +public class ExamplesPrefixTreeImpl extends AbstractPrefixTreeImpl implements ExamplesPrefixTree { + + public ExamplesPrefixTreeImpl(SyntaxToken keyword) { + super(keyword); + } + + @Override + public Kind getKind() { + return Kind.EXAMPLES_PREFIX; + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + visitor.visitExamplesPrefix(this); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/ExamplesTreeImpl.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/ExamplesTreeImpl.java new file mode 100644 index 0000000..7d7204f --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/ExamplesTreeImpl.java @@ -0,0 +1,96 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import com.google.common.collect.Iterators; +import org.sonar.plugins.gherkin.api.tree.*; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class ExamplesTreeImpl extends GherkinTree implements ExamplesTree { + + private final List tags; + private final PrefixTree prefix; + private final SyntaxToken colon; + private final DescriptionTree description; + private final TableTree table; + + public ExamplesTreeImpl(@Nullable List tags, PrefixTree prefix, SyntaxToken colon, @Nullable DescriptionTree description, @Nullable TableTree table) { + if (tags != null) { + this.tags = tags; + } else { + this.tags = new ArrayList<>(); + } + + this.prefix = prefix; + this.colon = colon; + this.description = description; + this.table = table; + } + + @Override + public Kind getKind() { + return Kind.EXAMPLES; + } + + @Override + public Iterator childrenIterator() { + return Iterators.concat( + tags.iterator(), + Iterators.forArray(prefix, colon, description, table)); + } + + @Override + public List tags() { + return tags; + } + + @Override + public PrefixTree prefix() { + return prefix; + } + + @Override + public SyntaxToken colon() { + return colon; + } + + @Override + @Nullable + public DescriptionTree description() { + return description; + } + + @Override + @Nullable + public TableTree table() { + return table; + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + visitor.visitExamples(this); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/FeatureDeclarationTreeImpl.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/FeatureDeclarationTreeImpl.java new file mode 100644 index 0000000..4e7fae4 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/FeatureDeclarationTreeImpl.java @@ -0,0 +1,95 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import com.google.common.collect.Iterators; +import org.sonar.plugins.gherkin.api.tree.*; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class FeatureDeclarationTreeImpl extends GherkinTree implements FeatureDeclarationTree { + + private final List tags; + private final PrefixTree prefix; + private final SyntaxToken colon; + private final NameTree name; + private final DescriptionTree description; + + public FeatureDeclarationTreeImpl(@Nullable List tags, PrefixTree prefix, SyntaxToken colon, NameTree name, @Nullable DescriptionTree description) { + if (tags != null) { + this.tags = tags; + } else { + this.tags = new ArrayList<>(); + } + + this.prefix = prefix; + this.colon = colon; + this.name = name; + this.description = description; + } + + @Override + public Kind getKind() { + return Kind.FEATURE_DECLARATION; + } + + @Override + public Iterator childrenIterator() { + return Iterators.concat( + tags.iterator(), + Iterators.forArray(prefix, colon, name, description)); + } + + @Override + public List tags() { + return tags; + } + + @Override + public PrefixTree prefix() { + return prefix; + } + + @Override + public SyntaxToken colon() { + return colon; + } + + @Override + public NameTree name() { + return name; + } + + @Override + @Nullable + public DescriptionTree description() { + return description; + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + visitor.visitFeatureDeclaration(this); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/FeaturePrefixTreeImpl.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/FeaturePrefixTreeImpl.java new file mode 100644 index 0000000..b13b0cf --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/FeaturePrefixTreeImpl.java @@ -0,0 +1,42 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import org.sonar.plugins.gherkin.api.tree.FeaturePrefixTree; +import org.sonar.plugins.gherkin.api.tree.SyntaxToken; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +public class FeaturePrefixTreeImpl extends AbstractPrefixTreeImpl implements FeaturePrefixTree { + + public FeaturePrefixTreeImpl(SyntaxToken keyword) { + super(keyword); + } + + @Override + public Kind getKind() { + return Kind.FEATURE_PREFIX; + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + visitor.visitFeaturePrefix(this); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/FeatureTreeImpl.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/FeatureTreeImpl.java new file mode 100644 index 0000000..c148ee1 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/FeatureTreeImpl.java @@ -0,0 +1,96 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import com.google.common.collect.Iterators; +import org.sonar.plugins.gherkin.api.tree.*; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class FeatureTreeImpl extends GherkinTree implements FeatureTree { + + private final FeatureDeclarationTree declaration; + private final BackgroundTree background; + private final List allScenarios; + private final List scenarios; + private final List scenarioOutlines; + + public FeatureTreeImpl(FeatureDeclarationTree declaration, @Nullable BackgroundTree background, @Nullable List allScenarios) { + this.declaration = declaration; + this.background = background; + + if (allScenarios != null) { + this.allScenarios = allScenarios; + } else { + this.allScenarios = new ArrayList<>(); + } + + this.scenarios = TreeListUtils.allElementsOfType(allScenarios, ScenarioTree.class); + this.scenarioOutlines = TreeListUtils.allElementsOfType(allScenarios, ScenarioOutlineTree.class); + } + + @Override + public Kind getKind() { + return Kind.FEATURE; + } + + @Override + public Iterator childrenIterator() { + return Iterators.concat( + Iterators.forArray(declaration, background), + allScenarios.iterator()); + } + + @Override + public FeatureDeclarationTree declaration() { + return declaration; + } + + @Override + @Nullable + public BackgroundTree background() { + return background; + } + + @Override + public List scenarios() { + return scenarios; + } + + @Override + public List scenarioOutlines() { + return scenarioOutlines; + } + + @Override + public List allScenarios() { + return allScenarios; + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + visitor.visitFeature(this); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/GherkinDocumentTreeImpl.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/GherkinDocumentTreeImpl.java new file mode 100644 index 0000000..a08950d --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/GherkinDocumentTreeImpl.java @@ -0,0 +1,70 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import com.google.common.collect.Iterators; +import org.sonar.plugins.gherkin.api.tree.GherkinDocumentTree; +import org.sonar.plugins.gherkin.api.tree.FeatureTree; +import org.sonar.plugins.gherkin.api.tree.SyntaxToken; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +import javax.annotation.Nullable; +import java.util.Iterator; + +public class GherkinDocumentTreeImpl extends GherkinTree implements GherkinDocumentTree { + + private final SyntaxToken byteOrderMark; + private final FeatureTree feature; + private final SyntaxToken eof; + + public GherkinDocumentTreeImpl(@Nullable SyntaxToken byteOrderMark, @Nullable FeatureTree feature, SyntaxToken eof) { + this.byteOrderMark = byteOrderMark; + this.feature = feature; + this.eof = eof; + } + + @Override + public Kind getKind() { + return Kind.GHERKIN_DOCUMENT; + } + + @Override + public Iterator childrenIterator() { + return Iterators.forArray(byteOrderMark, feature, eof); + } + + @Override + public boolean hasByteOrderMark() { + return byteOrderMark != null; + } + + @Override + @Nullable + public FeatureTree feature() { + return feature; + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + visitor.visitGherkinDocument(this); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/GherkinTree.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/GherkinTree.java new file mode 100644 index 0000000..4d07b2d --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/GherkinTree.java @@ -0,0 +1,89 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import org.sonar.plugins.gherkin.api.tree.SyntaxToken; +import org.sonar.plugins.gherkin.api.tree.Tree; + +import java.util.Iterator; + +public abstract class GherkinTree implements Tree { + + private Tree parent; + + @Override + public Tree parent() { + return parent; + } + + @Override + public void setParent(Tree parent) { + this.parent = parent; + } + + public int getLine() { + return getFirstToken().line(); + } + + @Override + public final boolean is(Kind... kind) { + if (getKind() != null) { + for (Kind kindIter : kind) { + if (getKind() == kindIter) { + return true; + } + } + } + return false; + } + + @Override + public boolean isLeaf() { + return false; + } + + public SyntaxToken getLastToken() { + SyntaxToken lastToken = null; + Iterator childrenIterator = childrenIterator(); + while (childrenIterator.hasNext()) { + GherkinTree child = (GherkinTree) childrenIterator.next(); + if (child != null) { + SyntaxToken childLastToken = child.getLastToken(); + if (childLastToken != null) { + lastToken = childLastToken; + } + } + } + return lastToken; + } + + public SyntaxToken getFirstToken() { + Iterator childrenIterator = childrenIterator(); + Tree child; + do { + if (childrenIterator.hasNext()) { + child = childrenIterator.next(); + } else { + throw new IllegalStateException("Tree has no non-null children " + getKind()); + } + } while (child == null); + return ((GherkinTree) child).getFirstToken(); + } +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/InternalSyntaxSpacing.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/InternalSyntaxSpacing.java new file mode 100644 index 0000000..4d0b784 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/InternalSyntaxSpacing.java @@ -0,0 +1,85 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import org.sonar.plugins.gherkin.api.tree.SyntaxSpacing; +import org.sonar.plugins.gherkin.api.tree.SyntaxTrivia; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +public class InternalSyntaxSpacing extends GherkinTree implements SyntaxSpacing { + + public InternalSyntaxSpacing(int startIndex, int endIndex) { + } + + @Override + public Kind getKind() { + return Kind.SPACING; + } + + @Override + public boolean isLeaf() { + return true; + } + + @Override + public Iterator childrenIterator() { + throw new UnsupportedOperationException(); + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + // Do nothing at the moment. Spacings are dropped anyway. + } + + @Override + public int column() { + return 0; + } + + @Override + public int line() { + return 0; + } + + @Override + public int endColumn() { + return 0; + } + + @Override + public int endLine() { + return 0; + } + + @Override + public String text() { + return ""; + } + + @Override + public List trivias() { + return Collections.emptyList(); + } +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/InternalSyntaxToken.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/InternalSyntaxToken.java new file mode 100644 index 0000000..728eadc --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/InternalSyntaxToken.java @@ -0,0 +1,129 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import org.sonar.plugins.gherkin.api.tree.SyntaxToken; +import org.sonar.plugins.gherkin.api.tree.SyntaxTrivia; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +import java.util.Iterator; +import java.util.List; + +public class InternalSyntaxToken extends GherkinTree implements SyntaxToken { + + private final int line; + private final int column; + private final String value; + private final boolean isEOF; + private final boolean isBOM; + private int endLine; + private int endColumn; + private final List trivias; + + public InternalSyntaxToken(int line, int column, String value, List trivias, boolean isEOF, boolean isBOM) { + this.value = value; + this.trivias = trivias; + this.line = line; + this.column = column; + this.isEOF = isEOF; + this.isBOM = isBOM; + calculateEndOffsets(); + } + + private void calculateEndOffsets() { + String[] lines = value.split("\r\n|\n|\r", -1); + endColumn = column + value.length(); + endLine = line + lines.length - 1; + + if (endLine != line) { + endColumn = lines[lines.length - 1].length(); + } + } + + @Override + public int endLine() { + return endLine; + } + + @Override + public int endColumn() { + return endColumn; + } + + @Override + public int line() { + return line; + } + + @Override + public int column() { + return column; + } + + @Override + public Kind getKind() { + return Kind.TOKEN; + } + + @Override + public boolean isLeaf() { + return true; + } + + public boolean isEOF() { + return isEOF; + } + + public boolean isBOM() { + return isBOM; + } + + @Override + public Iterator childrenIterator() { + throw new UnsupportedOperationException(); + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + visitor.visitToken(this); + } + + @Override + public SyntaxToken getFirstToken() { + return this; + } + + @Override + public SyntaxToken getLastToken() { + return this; + } + + @Override + public String text() { + return value; + } + + @Override + public List trivias() { + return trivias; + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/InternalSyntaxTrivia.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/InternalSyntaxTrivia.java new file mode 100644 index 0000000..1d20be8 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/InternalSyntaxTrivia.java @@ -0,0 +1,124 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import org.sonar.plugins.gherkin.api.tree.SyntaxToken; +import org.sonar.plugins.gherkin.api.tree.SyntaxTrivia; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +public class InternalSyntaxTrivia extends GherkinTree implements SyntaxTrivia { + + private final String comment; + private final int column; + private int startLine; + private int endLine; + private int endColumn; + + public InternalSyntaxTrivia(String comment, int startLine, int column) { + this.comment = comment; + this.startLine = startLine; + this.column = column; + calculateEndOffsets(); + } + + private void calculateEndOffsets() { + String[] lines = comment.split("\r\n|\n|\r", -1); + endColumn = column + comment.length(); + endLine = startLine + lines.length - 1; + + if (endLine != startLine) { + endColumn = lines[lines.length - 1].length(); + } + } + + @Override + public int endLine() { + return endLine; + } + + @Override + public int endColumn() { + return endColumn; + } + + @Override + public String text() { + return comment; + } + + @Override + public List trivias() { + return Collections.emptyList(); + } + + @Override + public int line() { + return startLine; + } + + @Override + public int column() { + return column; + } + + @Override + public Kind getKind() { + return Kind.TRIVIA; + } + + @Override + public boolean isLeaf() { + return true; + } + + @Override + public Iterator childrenIterator() { + throw new UnsupportedOperationException(); + } + + public static SyntaxTrivia create(String comment, int startLine, int column) { + return new InternalSyntaxTrivia(comment, startLine, column); + } + + @Override + public int getLine() { + return startLine; + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + visitor.visitComment(this); + } + + @Override + public SyntaxToken getFirstToken() { + return this; + } + + @Override + public SyntaxToken getLastToken() { + return this; + } +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/NameTreeImpl.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/NameTreeImpl.java new file mode 100644 index 0000000..8e96346 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/NameTreeImpl.java @@ -0,0 +1,63 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import com.google.common.collect.Iterators; +import org.sonar.plugins.gherkin.api.tree.SyntaxToken; +import org.sonar.plugins.gherkin.api.tree.NameTree; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +import java.util.Iterator; + +public class NameTreeImpl extends GherkinTree implements NameTree { + + private final SyntaxToken name; + + public NameTreeImpl(SyntaxToken name) { + this.name = name; + } + + @Override + public Kind getKind() { + return Kind.NAME; + } + + @Override + public Iterator childrenIterator() { + return Iterators.singletonIterator(name); + } + + @Override + public SyntaxToken value() { + return name; + } + + @Override + public String text() { + return name.text(); + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + visitor.visitName(this); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/ScenarioOutlinePrefixTreeImpl.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/ScenarioOutlinePrefixTreeImpl.java new file mode 100644 index 0000000..b700ba2 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/ScenarioOutlinePrefixTreeImpl.java @@ -0,0 +1,42 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import org.sonar.plugins.gherkin.api.tree.ScenarioOutlinePrefixTree; +import org.sonar.plugins.gherkin.api.tree.SyntaxToken; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +public class ScenarioOutlinePrefixTreeImpl extends AbstractPrefixTreeImpl implements ScenarioOutlinePrefixTree { + + public ScenarioOutlinePrefixTreeImpl(SyntaxToken keyword) { + super(keyword); + } + + @Override + public Kind getKind() { + return Kind.SCENARIO_OUTLINE_PREFIX; + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + visitor.visitScenarioOutlinePrefix(this); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/ScenarioOutlineTreeImpl.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/ScenarioOutlineTreeImpl.java new file mode 100644 index 0000000..6d52d06 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/ScenarioOutlineTreeImpl.java @@ -0,0 +1,117 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import com.google.common.collect.Iterators; +import org.sonar.plugins.gherkin.api.tree.*; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class ScenarioOutlineTreeImpl extends GherkinTree implements ScenarioOutlineTree { + + private final List tags; + private final PrefixTree prefix; + private final SyntaxToken colon; + private final NameTree name; + private final DescriptionTree description; + private final List steps; + private final ExamplesTree examples; + + public ScenarioOutlineTreeImpl(@Nullable List tags, PrefixTree prefix, SyntaxToken colon, NameTree name, @Nullable DescriptionTree description, @Nullable List steps, ExamplesTree examples) { + if (tags != null) { + this.tags = tags; + } else { + this.tags = new ArrayList<>(); + } + + this.prefix = prefix; + this.colon = colon; + this.name = name; + this.description = description; + + if (steps != null) { + this.steps = steps; + } else { + this.steps = new ArrayList<>(); + } + + this.examples = examples; + } + + @Override + public Kind getKind() { + return Kind.SCENARIO_OUTLINE; + } + + @Override + public Iterator childrenIterator() { + return Iterators.concat( + tags.iterator(), + Iterators.forArray(prefix, colon, name, description), + steps.iterator(), + Iterators.singletonIterator(examples)); + } + + @Override + public List tags() { + return tags; + } + + @Override + public PrefixTree prefix() { + return prefix; + } + + @Override + public SyntaxToken colon() { + return colon; + } + + @Override + public NameTree name() { + return name; + } + + @Override + @Nullable + public DescriptionTree description() { + return description; + } + + @Override + public List steps() { + return steps; + } + + @Override + public ExamplesTree examples() { + return examples; + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + visitor.visitScenarioOutline(this); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/ScenarioPrefixTreeImpl.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/ScenarioPrefixTreeImpl.java new file mode 100644 index 0000000..ff2f5dc --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/ScenarioPrefixTreeImpl.java @@ -0,0 +1,42 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import org.sonar.plugins.gherkin.api.tree.ScenarioPrefixTree; +import org.sonar.plugins.gherkin.api.tree.SyntaxToken; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +public class ScenarioPrefixTreeImpl extends AbstractPrefixTreeImpl implements ScenarioPrefixTree { + + public ScenarioPrefixTreeImpl(SyntaxToken keyword) { + super(keyword); + } + + @Override + public Kind getKind() { + return Kind.SCENARIO_PREFIX; + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + visitor.visitScenarioPrefix(this); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/ScenarioTreeImpl.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/ScenarioTreeImpl.java new file mode 100644 index 0000000..96a62c4 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/ScenarioTreeImpl.java @@ -0,0 +1,107 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import com.google.common.collect.Iterators; +import org.sonar.plugins.gherkin.api.tree.*; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class ScenarioTreeImpl extends GherkinTree implements ScenarioTree { + + private final List tags; + private final PrefixTree prefix; + private final SyntaxToken colon; + private final NameTree name; + private final DescriptionTree description; + private final List steps; + + public ScenarioTreeImpl(@Nullable List tags, PrefixTree prefix, SyntaxToken colon, NameTree name, @Nullable DescriptionTree description, @Nullable List steps) { + if (tags != null) { + this.tags = tags; + } else { + this.tags = new ArrayList<>(); + } + this.prefix = prefix; + this.colon = colon; + this.name = name; + this.description = description; + + if (steps != null) { + this.steps = steps; + } else { + this.steps = new ArrayList<>(); + } + } + + @Override + public Kind getKind() { + return Kind.SCENARIO; + } + + @Override + public Iterator childrenIterator() { + return Iterators.concat( + tags.iterator(), + Iterators.forArray(prefix, colon, name, description), + steps.iterator()); + } + + @Override + public List tags() { + return tags; + } + + @Override + public PrefixTree prefix() { + return prefix; + } + + @Override + public SyntaxToken colon() { + return colon; + } + + @Override + public NameTree name() { + return name; + } + + @Override + @Nullable + public DescriptionTree description() { + return description; + } + + @Override + public List steps() { + return steps; + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + visitor.visitScenario(this); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/StepPrefixTreeImpl.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/StepPrefixTreeImpl.java new file mode 100644 index 0000000..62d187f --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/StepPrefixTreeImpl.java @@ -0,0 +1,42 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import org.sonar.plugins.gherkin.api.tree.StepPrefixTree; +import org.sonar.plugins.gherkin.api.tree.SyntaxToken; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +public class StepPrefixTreeImpl extends AbstractPrefixTreeImpl implements StepPrefixTree { + + public StepPrefixTreeImpl(SyntaxToken keyword) { + super(keyword); + } + + @Override + public Kind getKind() { + return Kind.STEP_PREFIX; + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + visitor.visitStepPrefix(this); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/StepTreeImpl.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/StepTreeImpl.java new file mode 100644 index 0000000..5cafcb2 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/StepTreeImpl.java @@ -0,0 +1,93 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import com.google.common.collect.Iterators; +import org.sonar.plugins.gherkin.api.tree.*; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +import javax.annotation.Nullable; +import java.util.Iterator; + +public class StepTreeImpl extends GherkinTree implements StepTree { + + private final PrefixTree prefix; + private final SyntaxToken sentence; + private final DocStringTree docString; + private final TableTree table; + + public StepTreeImpl(PrefixTree prefix, SyntaxToken sentence, @Nullable Tree data) { + this.prefix = prefix; + this.sentence = sentence; + + if (data != null) { + if (data instanceof DocStringTree) { + docString = (DocStringTree) data; + table = null; + } else if (data instanceof TableTree) { + table = (TableTree) data; + docString = null; + } else { + throw new IllegalStateException("Unsupported data tree: " + data.toString()); + } + } else { + docString = null; + table = null; + } + } + + @Override + public Kind getKind() { + return Kind.STEP; + } + + @Override + public Iterator childrenIterator() { + return Iterators.forArray(prefix, sentence, docString, table); + } + + @Override + public PrefixTree prefix() { + return prefix; + } + + @Override + public SyntaxToken sentence() { + return sentence; + } + + @Override + @Nullable + public DocStringTree docString() { + return docString; + } + + @Override + @Nullable + public TableTree table() { + return table; + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + visitor.visitStep(this); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/TableTreeImpl.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/TableTreeImpl.java new file mode 100644 index 0000000..77e17d0 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/TableTreeImpl.java @@ -0,0 +1,59 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import org.sonar.plugins.gherkin.api.tree.SyntaxToken; +import org.sonar.plugins.gherkin.api.tree.TableTree; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; + +public class TableTreeImpl extends GherkinTree implements TableTree { + + private final List rows; + + public TableTreeImpl(List rows) { + this.rows = rows; + } + + @Override + public Kind getKind() { + return Kind.TABLE; + } + + @Override + public Iterator childrenIterator() { + return rows.stream().map(t -> (Tree) t).collect(Collectors.toList()).iterator(); + } + + @Override + public List rows() { + return rows; + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + visitor.visitTable(this); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/TagTreeImpl.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/TagTreeImpl.java new file mode 100644 index 0000000..2526d7d --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/TagTreeImpl.java @@ -0,0 +1,70 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import com.google.common.collect.Iterators; +import org.sonar.plugins.gherkin.api.tree.SyntaxToken; +import org.sonar.plugins.gherkin.api.tree.TagTree; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +import java.util.Iterator; + +public class TagTreeImpl extends GherkinTree implements TagTree { + + private final SyntaxToken prefix; + private final SyntaxToken value; + + public TagTreeImpl(SyntaxToken prefix, SyntaxToken value) { + this.prefix = prefix; + this.value = value; + } + + @Override + public Kind getKind() { + return Kind.TAG; + } + + @Override + public Iterator childrenIterator() { + return Iterators.forArray(prefix, value); + } + + @Override + public SyntaxToken prefix() { + return prefix; + } + + @Override + public SyntaxToken value() { + return value; + } + + @Override + public String text() { + return value.text().substring(0, value.text().length()); + } + + @Override + public void accept(DoubleDispatchVisitor visitor) { + visitor.visitTag(this); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/TreeListUtils.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/TreeListUtils.java new file mode 100644 index 0000000..f678b46 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/TreeListUtils.java @@ -0,0 +1,45 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.tree.impl; + +import org.sonar.plugins.gherkin.api.tree.Tree; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class TreeListUtils { + + private TreeListUtils() { + } + + public static List allElementsOfType(@Nullable List trees, Class treeType) { + if (trees != null) { + return trees.stream() + .filter(e -> treeType.isAssignableFrom(e.getClass())) + .map(treeType::cast) + .collect(Collectors.toList()); + } else { + return new ArrayList<>(); + } + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/package-info.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/package-info.java new file mode 100644 index 0000000..d8b6053 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/tree/impl/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +@ParametersAreNonnullByDefault +package org.sonar.gherkin.tree.impl; + +import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/CharsetAwareVisitor.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/CharsetAwareVisitor.java new file mode 100644 index 0000000..f107b93 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/CharsetAwareVisitor.java @@ -0,0 +1,28 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.visitors; + +import java.nio.charset.Charset; + +public interface CharsetAwareVisitor { + + void setCharset(Charset charset); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/GherkinVisitorContext.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/GherkinVisitorContext.java new file mode 100644 index 0000000..28b7e7b --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/GherkinVisitorContext.java @@ -0,0 +1,47 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.visitors; + +import org.sonar.plugins.gherkin.api.tree.GherkinDocumentTree; +import org.sonar.plugins.gherkin.api.visitors.TreeVisitorContext; + +import java.io.File; + +public class GherkinVisitorContext implements TreeVisitorContext { + + private final GherkinDocumentTree tree; + private final File file; + + public GherkinVisitorContext(GherkinDocumentTree tree, File file) { + this.tree = tree; + this.file = file; + } + + @Override + public GherkinDocumentTree getTopTree() { + return tree; + } + + @Override + public File getFile() { + return file; + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/Issues.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/Issues.java new file mode 100644 index 0000000..f3ce155 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/Issues.java @@ -0,0 +1,66 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.visitors; + +import org.sonar.plugins.gherkin.api.GherkinCheck; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.issue.*; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class Issues { + + private List issueList; + private GherkinCheck check; + + public Issues(GherkinCheck check) { + this.check = check; + this.issueList = new ArrayList<>(); + } + + public PreciseIssue addPreciseIssue(File file, Tree tree, String message) { + PreciseIssue issue = new PreciseIssue(check, new IssueLocation(file, tree, message)); + issueList.add(issue); + return issue; + } + + public FileIssue addFileIssue(File file, String message) { + FileIssue issue = new FileIssue(check, file, message); + issueList.add(issue); + return issue; + } + + public LineIssue addLineIssue(File file, int line, String message) { + LineIssue issue = new LineIssue(check, file, line, message); + issueList.add(issue); + return issue; + } + + public List getList() { + return issueList; + } + + public void reset() { + issueList.clear(); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/SyntaxHighlighterVisitor.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/SyntaxHighlighterVisitor.java new file mode 100644 index 0000000..b5780eb --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/SyntaxHighlighterVisitor.java @@ -0,0 +1,113 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.visitors; + +import com.google.common.collect.ImmutableList; +import org.sonar.api.batch.fs.FileSystem; +import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.batch.sensor.highlighting.NewHighlighting; +import org.sonar.api.batch.sensor.highlighting.TypeOfText; +import org.sonar.gherkin.tree.impl.InternalSyntaxToken; +import org.sonar.plugins.gherkin.api.tree.*; +import org.sonar.plugins.gherkin.api.visitors.SubscriptionVisitor; + +import java.util.ArrayList; +import java.util.List; + +public class SyntaxHighlighterVisitor extends SubscriptionVisitor { + + private final SensorContext sensorContext; + private final FileSystem fileSystem; + private NewHighlighting highlighting; + + public SyntaxHighlighterVisitor(SensorContext sensorContext) { + this.sensorContext = sensorContext; + fileSystem = sensorContext.fileSystem(); + } + + @Override + public List nodesToVisit() { + return ImmutableList.builder() + .add(Tree.Kind.TAG) + .add(Tree.Kind.FEATURE_PREFIX) + .add(Tree.Kind.BACKGROUND_PREFIX) + .add(Tree.Kind.SCENARIO_PREFIX) + .add(Tree.Kind.SCENARIO_OUTLINE_PREFIX) + .add(Tree.Kind.EXAMPLES_PREFIX) + .add(Tree.Kind.STEP_PREFIX) + .add(Tree.Kind.NAME) + .add(Tree.Kind.TOKEN) + .build(); + } + + @Override + public void visitFile(Tree tree) { + highlighting = sensorContext.newHighlighting().onFile(fileSystem.inputFile(fileSystem.predicates().is(getContext().getFile()))); + } + + @Override + public void leaveFile(Tree scriptTree) { + highlighting.save(); + } + + @Override + public void visitNode(Tree tree) { + List tokens = new ArrayList<>(); + TypeOfText code = null; + + if (tree.is(Tree.Kind.TAG)) { + tokens.add(((TagTree) tree).prefix()); + tokens.add(((TagTree) tree).value()); + code = TypeOfText.ANNOTATION; + + } else if (tree.is(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)) { + + tokens.add(((PrefixTree) tree).keyword()); + code = TypeOfText.KEYWORD; + + } else if (tree.is(Tree.Kind.NAME)) { + tokens.add(((NameTree) tree).value()); + code = TypeOfText.STRING; + + } else if (tree.is(Tree.Kind.TOKEN)) { + highlightComments((InternalSyntaxToken) tree); + } + + for (SyntaxToken token : tokens) { + highlight(token, code); + } + } + + private void highlightComments(InternalSyntaxToken token) { + for (SyntaxTrivia trivia : token.trivias()) { + highlight(trivia, TypeOfText.COMMENT); + } + } + + private void highlight(SyntaxToken token, TypeOfText type) { + highlighting.highlight(token.line(), token.column(), token.endLine(), token.endColumn(), type); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/ClassesVisitor.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/ClassesVisitor.java new file mode 100644 index 0000000..d317ec3 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/ClassesVisitor.java @@ -0,0 +1,51 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.visitors.metrics; + +import com.google.common.collect.ImmutableList; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.SubscriptionVisitor; + +import java.util.List; + +public class ClassesVisitor extends SubscriptionVisitor { + + private int classes; + + public ClassesVisitor(Tree tree) { + classes = 0; + scanTree(tree); + } + + @Override + public List nodesToVisit() { + return ImmutableList.of(Tree.Kind.FEATURE); + } + + @Override + public void visitNode(Tree tree) { + classes++; + } + + public int getNumberOfClasses() { + return classes; + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/CommentLinesVisitor.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/CommentLinesVisitor.java new file mode 100644 index 0000000..0db523d --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/CommentLinesVisitor.java @@ -0,0 +1,56 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.visitors.metrics; + +import com.google.common.collect.ImmutableList; +import org.sonar.plugins.gherkin.api.tree.SyntaxToken; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.SubscriptionVisitor; + +import java.util.List; + +public class CommentLinesVisitor extends SubscriptionVisitor { + + private int commentLines; + private GherkinCommentAnalyser commentAnalyser = new GherkinCommentAnalyser(); + + public CommentLinesVisitor(Tree tree) { + commentLines = 0; + scanTree(tree); + } + + @Override + public List nodesToVisit() { + return ImmutableList.of(Tree.Kind.TOKEN); + } + + @Override + public void visitNode(Tree tree) { + ((SyntaxToken) tree).trivias() + .stream() + .filter(t -> !commentAnalyser.isBlank(commentAnalyser.getContents(t.text()))) + .forEach(t -> commentLines++); + } + + public int getNumberOfCommentLines() { + return commentLines; + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/FunctionsVisitor.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/FunctionsVisitor.java new file mode 100644 index 0000000..010fb50 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/FunctionsVisitor.java @@ -0,0 +1,54 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.visitors.metrics; + +import com.google.common.collect.ImmutableList; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.SubscriptionVisitor; + +import java.util.List; + +public class FunctionsVisitor extends SubscriptionVisitor { + + private int functions; + + public FunctionsVisitor(Tree tree) { + functions = 0; + scanTree(tree); + } + + @Override + public List nodesToVisit() { + return ImmutableList.of( + Tree.Kind.BACKGROUND, + Tree.Kind.SCENARIO, + Tree.Kind.SCENARIO_OUTLINE); + } + + @Override + public void visitNode(Tree tree) { + functions++; + } + + public int getNumberOfFunctions() { + return functions; + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/GherkinCommentAnalyser.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/GherkinCommentAnalyser.java new file mode 100644 index 0000000..d4c1a8a --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/GherkinCommentAnalyser.java @@ -0,0 +1,45 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.visitors.metrics; + +import org.sonar.squidbridge.CommentAnalyser; + +public class GherkinCommentAnalyser extends CommentAnalyser { + + @Override + public boolean isBlank(String line) { + for (int i = 0; i < line.length(); i++) { + if (Character.isLetterOrDigit(line.charAt(i))) { + return false; + } + } + return true; + } + + @Override + public String getContents(String comment) { + if (comment.startsWith("#")) { + return comment.substring(1, comment.length()); + } else { + throw new IllegalArgumentException(); + } + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/LinesOfCodeVisitor.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/LinesOfCodeVisitor.java new file mode 100644 index 0000000..65e1d30 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/LinesOfCodeVisitor.java @@ -0,0 +1,57 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.visitors.metrics; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Sets; +import org.sonar.gherkin.tree.impl.InternalSyntaxToken; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.SubscriptionVisitor; + +import java.util.List; +import java.util.Set; + +public class LinesOfCodeVisitor extends SubscriptionVisitor { + + private Set linesOfCode = Sets.newHashSet(); + + public LinesOfCodeVisitor(Tree tree) { + linesOfCode.clear(); + scanTree(tree); + } + + @Override + public List nodesToVisit() { + return ImmutableList.of(Tree.Kind.TOKEN); + } + + @Override + public void visitNode(Tree tree) { + InternalSyntaxToken token = (InternalSyntaxToken) tree; + if (!token.isEOF() && !token.isBOM()) { + linesOfCode.add(token.line()); + } + } + + public int getNumberOfLinesOfCode() { + return linesOfCode.size(); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/MetricsVisitor.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/MetricsVisitor.java new file mode 100644 index 0000000..8589867 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/MetricsVisitor.java @@ -0,0 +1,81 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.visitors.metrics; + +import com.google.common.collect.ImmutableList; +import org.sonar.api.batch.fs.FileSystem; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Metric; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.SubscriptionVisitor; + +import java.io.Serializable; +import java.util.List; + +public class MetricsVisitor extends SubscriptionVisitor { + + private final SensorContext sensorContext; + private final FileSystem fileSystem; + private InputFile inputFile; + + public MetricsVisitor(SensorContext sensorContext) { + this.sensorContext = sensorContext; + this.fileSystem = sensorContext.fileSystem(); + } + + @Override + public List nodesToVisit() { + return ImmutableList.of(Tree.Kind.GHERKIN_DOCUMENT); + } + + @Override + public void visitFile(Tree tree) { + this.inputFile = fileSystem.inputFile(fileSystem.predicates().is(getContext().getFile())); + } + + @Override + public void leaveFile(Tree tree) { + LinesOfCodeVisitor linesOfCodeVisitor = new LinesOfCodeVisitor(tree); + saveMetricOnFile(CoreMetrics.NCLOC, linesOfCodeVisitor.getNumberOfLinesOfCode()); + + CommentLinesVisitor commentLinesVisitor = new CommentLinesVisitor(tree); + saveMetricOnFile(CoreMetrics.COMMENT_LINES, commentLinesVisitor.getNumberOfCommentLines()); + + StatementsVisitor statementsVisitor = new StatementsVisitor(tree); + saveMetricOnFile(CoreMetrics.STATEMENTS, statementsVisitor.getNumberOfStatements()); + + FunctionsVisitor functionsVisitor = new FunctionsVisitor(tree); + saveMetricOnFile(CoreMetrics.FUNCTIONS, functionsVisitor.getNumberOfFunctions()); + + ClassesVisitor classesVisitor = new ClassesVisitor(tree); + saveMetricOnFile(CoreMetrics.CLASSES, classesVisitor.getNumberOfClasses()); + } + + private void saveMetricOnFile(Metric metric, T value) { + sensorContext.newMeasure() + .withValue(value) + .forMetric(metric) + .on(inputFile) + .save(); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/StatementsVisitor.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/StatementsVisitor.java new file mode 100644 index 0000000..b6343c6 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/StatementsVisitor.java @@ -0,0 +1,51 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.visitors.metrics; + +import com.google.common.collect.ImmutableList; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.SubscriptionVisitor; + +import java.util.List; + +public class StatementsVisitor extends SubscriptionVisitor { + + private int statements; + + public StatementsVisitor(Tree tree) { + statements = 0; + scanTree(tree); + } + + @Override + public List nodesToVisit() { + return ImmutableList.of(Tree.Kind.STEP); + } + + @Override + public void visitNode(Tree tree) { + statements++; + } + + public int getNumberOfStatements() { + return statements; + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/package-info.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/package-info.java new file mode 100644 index 0000000..af4c687 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/metrics/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +@ParametersAreNonnullByDefault +package org.sonar.gherkin.visitors.metrics; + +import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/package-info.java b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/package-info.java new file mode 100644 index 0000000..fbf9a09 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/gherkin/visitors/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +@ParametersAreNonnullByDefault +package org.sonar.gherkin.visitors; + +import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/CustomGherkinRulesDefinition.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/CustomGherkinRulesDefinition.java new file mode 100644 index 0000000..a3d7a93 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/CustomGherkinRulesDefinition.java @@ -0,0 +1,61 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api; + +import com.google.common.collect.ImmutableList; +import org.sonar.api.ExtensionPoint; +import org.sonar.api.batch.BatchSide; +import org.sonar.api.server.rule.RulesDefinition; +import org.sonar.squidbridge.annotations.AnnotationBasedRulesDefinition; + +/** + * Extension point to create custom rule repository for Gherkin. + */ +@ExtensionPoint +@BatchSide +public abstract class CustomGherkinRulesDefinition implements RulesDefinition { + + /** + * Defines rule repository with check metadata from check classes' annotations. + * This method should be overridden if check metadata are provided via another format, + * e.g: XMl, JSON. + */ + @Override + public void define(Context context) { + NewRepository repo = context.createRepository(repositoryKey(), "gherkin").setName(repositoryName()); + new AnnotationBasedRulesDefinition(repo, "gherkin").addRuleClasses(false, ImmutableList.copyOf(checkClasses())); + repo.done(); + } + + /** + * Name of the custom rule repository. + */ + public abstract String repositoryName(); + + /** + * Key of the custom rule repository. + */ + public abstract String repositoryKey(); + + /** + * Array of the custom rules classes. + */ + public abstract Class[] checkClasses(); +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/GherkinCheck.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/GherkinCheck.java new file mode 100644 index 0000000..721f5a4 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/GherkinCheck.java @@ -0,0 +1,43 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api; + +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.TreeVisitorContext; +import org.sonar.plugins.gherkin.api.visitors.issue.FileIssue; +import org.sonar.plugins.gherkin.api.visitors.issue.Issue; +import org.sonar.plugins.gherkin.api.visitors.issue.LineIssue; +import org.sonar.plugins.gherkin.api.visitors.issue.PreciseIssue; + +import java.util.List; + +public interface GherkinCheck { + + PreciseIssue addPreciseIssue(Tree tree, String message); + + FileIssue addFileIssue(String message); + + LineIssue addLineIssue(int line, String message); + + List scanFile(TreeVisitorContext context); + + void validateParameters(); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/package-info.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/package-info.java new file mode 100644 index 0000000..4cb5444 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +@ParametersAreNonnullByDefault +package org.sonar.plugins.gherkin.api; + +import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/BackgroundPrefixTree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/BackgroundPrefixTree.java new file mode 100644 index 0000000..a295106 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/BackgroundPrefixTree.java @@ -0,0 +1,23 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +public interface BackgroundPrefixTree extends PrefixTree { +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/BackgroundTree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/BackgroundTree.java new file mode 100644 index 0000000..fa5e50b --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/BackgroundTree.java @@ -0,0 +1,32 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +import java.util.List; + +public interface BackgroundTree extends Tree, Descriptionable { + + PrefixTree prefix(); + + SyntaxToken colon(); + + List steps(); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/BasicScenarioTree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/BasicScenarioTree.java new file mode 100644 index 0000000..b6fbb82 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/BasicScenarioTree.java @@ -0,0 +1,34 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +import java.util.List; + +public interface BasicScenarioTree extends Tree, Taggable, Descriptionable { + + PrefixTree prefix(); + + SyntaxToken colon(); + + NameTree name(); + + List steps(); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/DescriptionTree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/DescriptionTree.java new file mode 100644 index 0000000..98f7860 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/DescriptionTree.java @@ -0,0 +1,28 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +import java.util.List; + +public interface DescriptionTree extends Tree { + + List descriptionLines(); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/Descriptionable.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/Descriptionable.java new file mode 100644 index 0000000..2c6c625 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/Descriptionable.java @@ -0,0 +1,29 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +import javax.annotation.Nullable; + +public interface Descriptionable { + + @Nullable + DescriptionTree description(); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/DocStringTree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/DocStringTree.java new file mode 100644 index 0000000..4ac24f5 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/DocStringTree.java @@ -0,0 +1,36 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +import javax.annotation.Nullable; +import java.util.List; + +public interface DocStringTree extends Tree { + + SyntaxToken prefix(); + + SyntaxToken suffix(); + + List data(); + + @Nullable + SyntaxToken contentType(); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/ExamplesPrefixTree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/ExamplesPrefixTree.java new file mode 100644 index 0000000..2439324 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/ExamplesPrefixTree.java @@ -0,0 +1,23 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +public interface ExamplesPrefixTree extends PrefixTree { +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/ExamplesTree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/ExamplesTree.java new file mode 100644 index 0000000..f88f9ee --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/ExamplesTree.java @@ -0,0 +1,33 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +import javax.annotation.Nullable; + +public interface ExamplesTree extends Tree, Taggable, Descriptionable { + + PrefixTree prefix(); + + SyntaxToken colon(); + + @Nullable + TableTree table(); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/FeatureDeclarationTree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/FeatureDeclarationTree.java new file mode 100644 index 0000000..245e604 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/FeatureDeclarationTree.java @@ -0,0 +1,30 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +public interface FeatureDeclarationTree extends Tree, Taggable, Descriptionable { + + PrefixTree prefix(); + + SyntaxToken colon(); + + NameTree name(); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/FeaturePrefixTree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/FeaturePrefixTree.java new file mode 100644 index 0000000..4cdabfa --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/FeaturePrefixTree.java @@ -0,0 +1,23 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +public interface FeaturePrefixTree extends PrefixTree { +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/FeatureTree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/FeatureTree.java new file mode 100644 index 0000000..ca9ec23 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/FeatureTree.java @@ -0,0 +1,38 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +import javax.annotation.Nullable; +import java.util.List; + +public interface FeatureTree extends Tree { + + FeatureDeclarationTree declaration(); + + @Nullable + BackgroundTree background(); + + List scenarioOutlines(); + + List scenarios(); + + List allScenarios(); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/GherkinDocumentTree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/GherkinDocumentTree.java new file mode 100644 index 0000000..3ce2aec --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/GherkinDocumentTree.java @@ -0,0 +1,31 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +import javax.annotation.Nullable; + +public interface GherkinDocumentTree extends Tree { + + boolean hasByteOrderMark(); + + @Nullable + FeatureTree feature(); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/NameTree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/NameTree.java new file mode 100644 index 0000000..f3a777c --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/NameTree.java @@ -0,0 +1,28 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +public interface NameTree extends Tree { + + SyntaxToken value(); + + String text(); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/PrefixTree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/PrefixTree.java new file mode 100644 index 0000000..7d684d6 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/PrefixTree.java @@ -0,0 +1,28 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +public interface PrefixTree extends Tree { + + SyntaxToken keyword(); + + String text(); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/ScenarioOutlinePrefixTree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/ScenarioOutlinePrefixTree.java new file mode 100644 index 0000000..cfff57b --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/ScenarioOutlinePrefixTree.java @@ -0,0 +1,23 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +public interface ScenarioOutlinePrefixTree extends PrefixTree { +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/ScenarioOutlineTree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/ScenarioOutlineTree.java new file mode 100644 index 0000000..bbf5a88 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/ScenarioOutlineTree.java @@ -0,0 +1,26 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +public interface ScenarioOutlineTree extends BasicScenarioTree { + + ExamplesTree examples(); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/ScenarioPrefixTree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/ScenarioPrefixTree.java new file mode 100644 index 0000000..c348b03 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/ScenarioPrefixTree.java @@ -0,0 +1,23 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +public interface ScenarioPrefixTree extends PrefixTree { +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/ScenarioTree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/ScenarioTree.java new file mode 100644 index 0000000..41fc9ea --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/ScenarioTree.java @@ -0,0 +1,23 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +public interface ScenarioTree extends BasicScenarioTree { +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/StepPrefixTree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/StepPrefixTree.java new file mode 100644 index 0000000..48a45e8 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/StepPrefixTree.java @@ -0,0 +1,23 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +public interface StepPrefixTree extends PrefixTree { +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/StepTree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/StepTree.java new file mode 100644 index 0000000..16427b0 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/StepTree.java @@ -0,0 +1,36 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +import javax.annotation.Nullable; + +public interface StepTree extends Tree { + + PrefixTree prefix(); + + SyntaxToken sentence(); + + @Nullable + DocStringTree docString(); + + @Nullable + TableTree table(); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/SyntaxSpacing.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/SyntaxSpacing.java new file mode 100644 index 0000000..6007795 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/SyntaxSpacing.java @@ -0,0 +1,38 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +import java.util.List; + +public interface SyntaxSpacing extends Tree { + + String text(); + + List trivias(); + + int line(); + + int column(); + + int endLine(); + + int endColumn(); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/SyntaxToken.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/SyntaxToken.java new file mode 100644 index 0000000..6a3e023 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/SyntaxToken.java @@ -0,0 +1,38 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +import java.util.List; + +public interface SyntaxToken extends Tree { + + String text(); + + List trivias(); + + int line(); + + int column(); + + int endLine(); + + int endColumn(); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/SyntaxTrivia.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/SyntaxTrivia.java new file mode 100644 index 0000000..fca93e8 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/SyntaxTrivia.java @@ -0,0 +1,23 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +public interface SyntaxTrivia extends SyntaxToken { +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/TableTree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/TableTree.java new file mode 100644 index 0000000..b18c73a --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/TableTree.java @@ -0,0 +1,28 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +import java.util.List; + +public interface TableTree extends Tree { + + List rows(); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/TagTree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/TagTree.java new file mode 100644 index 0000000..793a4d5 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/TagTree.java @@ -0,0 +1,30 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +public interface TagTree extends Tree { + + SyntaxToken prefix(); + + SyntaxToken value(); + + String text(); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/Taggable.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/Taggable.java new file mode 100644 index 0000000..a2da641 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/Taggable.java @@ -0,0 +1,28 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +import java.util.List; + +public interface Taggable { + + List tags(); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/Tree.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/Tree.java new file mode 100644 index 0000000..d98d376 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/Tree.java @@ -0,0 +1,81 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.tree; + +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; +import org.sonar.sslr.grammar.GrammarRuleKey; + +import javax.annotation.Nullable; +import java.util.Iterator; + +public interface Tree { + + boolean is(Kind... kind); + + void accept(DoubleDispatchVisitor visitor); + + Iterator childrenIterator(); + + @Nullable + Tree parent(); + + void setParent(Tree parent); + + boolean isLeaf(); + + Kind getKind(); + + enum Kind implements GrammarRuleKey { + + GHERKIN_DOCUMENT(GherkinDocumentTree.class), + FEATURE(FeatureTree.class), + FEATURE_DECLARATION(FeatureDeclarationTree.class), + BACKGROUND(BackgroundTree.class), + SCENARIO(ScenarioTree.class), + SCENARIO_OUTLINE(ScenarioOutlineTree.class), + EXAMPLES(ExamplesTree.class), + STEP(StepTree.class), + FEATURE_PREFIX(FeaturePrefixTree.class), + BACKGROUND_PREFIX(BackgroundPrefixTree.class), + SCENARIO_PREFIX(ScenarioPrefixTree.class), + SCENARIO_OUTLINE_PREFIX(ScenarioOutlinePrefixTree.class), + EXAMPLES_PREFIX(ExamplesPrefixTree.class), + STEP_PREFIX(StepPrefixTree.class), + TAG(TagTree.class), + NAME(TagTree.class), + DESCRIPTION(DescriptionTree.class), + TABLE(TableTree.class), + DOC_STRING(DocStringTree.class), + TOKEN(SyntaxToken.class), + TRIVIA(SyntaxTrivia.class), + SPACING(SyntaxSpacing.class); + + final Class associatedInterface; + + Kind(Class associatedInterface) { + this.associatedInterface = associatedInterface; + } + + public Class getAssociatedInterface() { + return associatedInterface; + } + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/package-info.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/package-info.java new file mode 100644 index 0000000..f0fc73c --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/tree/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +@ParametersAreNonnullByDefault +package org.sonar.plugins.gherkin.api.tree; + +import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/DoubleDispatchVisitor.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/DoubleDispatchVisitor.java new file mode 100644 index 0000000..11d54cd --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/DoubleDispatchVisitor.java @@ -0,0 +1,153 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.visitors; + +import com.google.common.base.Preconditions; +import org.sonar.plugins.gherkin.api.tree.*; + +import javax.annotation.Nullable; +import java.util.Iterator; +import java.util.List; + +public abstract class DoubleDispatchVisitor implements TreeVisitor { + + private TreeVisitorContext context = null; + + @Override + public TreeVisitorContext getContext() { + Preconditions.checkState(context != null, "this#scanTree(context) should be called to initialised the context before accessing it"); + return context; + } + + @Override + public final void scanTree(TreeVisitorContext context) { + this.context = context; + scan(context.getTopTree()); + } + + protected void scan(@Nullable Tree tree) { + if (tree != null) { + tree.accept(this); + } + } + + protected void scanChildren(Tree tree) { + Iterator childrenIterator = tree.childrenIterator(); + Tree child; + + while (childrenIterator.hasNext()) { + child = childrenIterator.next(); + if (child != null) { + child.accept(this); + } + } + } + + protected void scan(List trees) { + trees.forEach(this::scan); + } + + public void visitGherkinDocument(GherkinDocumentTree tree) { + scanChildren(tree); + } + + public void visitFeature(FeatureTree tree) { + scanChildren(tree); + } + + public void visitFeatureDeclaration(FeatureDeclarationTree tree) { + scanChildren(tree); + } + + public void visitBackground(BackgroundTree tree) { + scanChildren(tree); + } + + public void visitScenario(ScenarioTree tree) { + scanChildren(tree); + } + + public void visitScenarioOutline(ScenarioOutlineTree tree) { + scanChildren(tree); + } + + public void visitExamples(ExamplesTree tree) { + scanChildren(tree); + } + + public void visitStep(StepTree tree) { + scanChildren(tree); + } + + public void visitDescription(DescriptionTree tree) { + scanChildren(tree); + } + + public void visitTag(TagTree tree) { + scanChildren(tree); + } + + public void visitName(NameTree tree) { + scanChildren(tree); + } + + public void visitFeaturePrefix(FeaturePrefixTree tree) { + scanChildren(tree); + } + + public void visitBackgroundPrefix(BackgroundPrefixTree tree) { + scanChildren(tree); + } + + public void visitScenarioPrefix(ScenarioPrefixTree tree) { + scanChildren(tree); + } + + public void visitScenarioOutlinePrefix(ScenarioOutlinePrefixTree tree) { + scanChildren(tree); + } + + public void visitExamplesPrefix(ExamplesPrefixTree tree) { + scanChildren(tree); + } + + public void visitStepPrefix(StepPrefixTree tree) { + scanChildren(tree); + } + + public void visitTable(TableTree tree) { + scanChildren(tree); + } + + public void visitDocString(DocStringTree tree) { + scanChildren(tree); + } + + public void visitToken(SyntaxToken token) { + for (SyntaxTrivia syntaxTrivia : token.trivias()) { + syntaxTrivia.accept(this); + } + } + + public void visitComment(SyntaxTrivia commentToken) { + // no sub-tree + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/DoubleDispatchVisitorCheck.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/DoubleDispatchVisitorCheck.java new file mode 100644 index 0000000..110f19e --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/DoubleDispatchVisitorCheck.java @@ -0,0 +1,64 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.visitors; + +import org.sonar.gherkin.visitors.Issues; +import org.sonar.plugins.gherkin.api.GherkinCheck; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.issue.FileIssue; +import org.sonar.plugins.gherkin.api.visitors.issue.Issue; +import org.sonar.plugins.gherkin.api.visitors.issue.LineIssue; +import org.sonar.plugins.gherkin.api.visitors.issue.PreciseIssue; + +import java.util.List; + +public abstract class DoubleDispatchVisitorCheck extends DoubleDispatchVisitor implements GherkinCheck { + + private Issues issues = new Issues(this); + + @Override + public List scanFile(TreeVisitorContext context) { + validateParameters(); + issues.reset(); + scanTree(context); + return issues.getList(); + } + + @Override + public PreciseIssue addPreciseIssue(Tree tree, String message) { + return issues.addPreciseIssue(getContext().getFile(), tree, message); + } + + @Override + public FileIssue addFileIssue(String message) { + return issues.addFileIssue(getContext().getFile(), message); + } + + @Override + public LineIssue addLineIssue(int line, String message) { + return issues.addLineIssue(getContext().getFile(), line, message); + } + + @Override + public void validateParameters() { + // Default behavior: do nothing + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/SubscriptionVisitor.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/SubscriptionVisitor.java new file mode 100644 index 0000000..93ac481 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/SubscriptionVisitor.java @@ -0,0 +1,101 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.visitors; + +import com.google.common.base.Preconditions; +import org.sonar.gherkin.tree.impl.GherkinTree; +import org.sonar.plugins.gherkin.api.tree.Tree; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +public abstract class SubscriptionVisitor implements TreeVisitor { + + private TreeVisitorContext context; + private Collection nodesToVisit; + + public abstract List nodesToVisit(); + + public void visitNode(Tree tree) { + // Default behavior: do nothing. + } + + public void leaveNode(Tree tree) { + // Default behavior: do nothing. + } + + public void visitFile(Tree tree) { + // Default behavior: do nothing. + } + + public void leaveFile(Tree tree) { + // Default behavior: do nothing. + } + + @Override + public TreeVisitorContext getContext() { + Preconditions.checkState(context != null, "this#scanTree(context) should be called to initialised the context before accessing it"); + return context; + } + + @Override + public final void scanTree(TreeVisitorContext context) { + this.context = context; + visitFile(context.getTopTree()); + scanTree(context.getTopTree()); + leaveFile(context.getTopTree()); + } + + public void scanTree(Tree tree) { + nodesToVisit = nodesToVisit(); + visit(tree); + } + + private void visit(Tree tree) { + boolean isSubscribed = isSubscribed(tree); + if (isSubscribed) { + visitNode(tree); + } + visitChildren(tree); + if (isSubscribed) { + leaveNode(tree); + } + } + + protected boolean isSubscribed(Tree tree) { + return nodesToVisit.contains(tree.getKind()); + } + + private void visitChildren(Tree tree) { + GherkinTree gherkinTree = (GherkinTree) tree; + + if (!gherkinTree.isLeaf()) { + for (Iterator iter = gherkinTree.childrenIterator(); iter.hasNext(); ) { + Tree next = iter.next(); + + if (next != null) { + visit(next); + } + } + } + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/SubscriptionVisitorCheck.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/SubscriptionVisitorCheck.java new file mode 100644 index 0000000..624db8e --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/SubscriptionVisitorCheck.java @@ -0,0 +1,64 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.visitors; + +import org.sonar.gherkin.visitors.Issues; +import org.sonar.plugins.gherkin.api.GherkinCheck; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.issue.FileIssue; +import org.sonar.plugins.gherkin.api.visitors.issue.Issue; +import org.sonar.plugins.gherkin.api.visitors.issue.LineIssue; +import org.sonar.plugins.gherkin.api.visitors.issue.PreciseIssue; + +import java.util.List; + +public abstract class SubscriptionVisitorCheck extends SubscriptionVisitor implements GherkinCheck { + + private Issues issues = new Issues(this); + + @Override + public List scanFile(TreeVisitorContext context) { + validateParameters(); + issues.reset(); + scanTree(context); + return issues.getList(); + } + + @Override + public PreciseIssue addPreciseIssue(Tree tree, String message) { + return issues.addPreciseIssue(getContext().getFile(), tree, message); + } + + @Override + public FileIssue addFileIssue(String message) { + return issues.addFileIssue(getContext().getFile(), message); + } + + @Override + public LineIssue addLineIssue(int line, String message) { + return issues.addLineIssue(getContext().getFile(), line, message); + } + + @Override + public void validateParameters() { + // Default behavior: do nothing + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/TreeVisitor.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/TreeVisitor.java new file mode 100644 index 0000000..a35db30 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/TreeVisitor.java @@ -0,0 +1,28 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.visitors; + +public interface TreeVisitor { + + TreeVisitorContext getContext(); + + void scanTree(TreeVisitorContext context); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/TreeVisitorContext.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/TreeVisitorContext.java new file mode 100644 index 0000000..b4e0afc --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/TreeVisitorContext.java @@ -0,0 +1,38 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.visitors; + +import org.sonar.plugins.gherkin.api.tree.GherkinDocumentTree; + +import java.io.File; + +public interface TreeVisitorContext { + + /** + * @return the top tree node of the current file AST representation. + */ + GherkinDocumentTree getTopTree(); + + /** + * @return the current file + */ + File getFile(); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/issue/FileIssue.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/issue/FileIssue.java new file mode 100644 index 0000000..e7e25da --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/issue/FileIssue.java @@ -0,0 +1,85 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.visitors.issue; + +import org.sonar.plugins.gherkin.api.GherkinCheck; +import org.sonar.plugins.gherkin.api.tree.Tree; + +import javax.annotation.Nullable; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class FileIssue implements Issue { + + private final GherkinCheck check; + private final File file; + private Double cost; + private final String message; + private final List secondaryLocations; + + public FileIssue(GherkinCheck check, File file, String message) { + this.check = check; + this.file = file; + this.message = message; + this.secondaryLocations = new ArrayList<>(); + this.cost = null; + } + + public String message() { + return message; + } + + @Override + public GherkinCheck check() { + return check; + } + + public File file() { + return file; + } + + @Nullable + @Override + public Double cost() { + return cost; + } + + @Override + public Issue cost(double cost) { + this.cost = cost; + return this; + } + + public List secondaryLocations() { + return secondaryLocations; + } + + public FileIssue secondary(Tree tree, String message) { + secondaryLocations.add(new IssueLocation(file, tree, message)); + return this; + } + + public FileIssue secondary(File file, Tree tree, String message) { + secondaryLocations.add(new IssueLocation(file, tree, message)); + return this; + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/issue/Issue.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/issue/Issue.java new file mode 100644 index 0000000..29335ad --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/issue/Issue.java @@ -0,0 +1,35 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.visitors.issue; + +import org.sonar.plugins.gherkin.api.GherkinCheck; + +import javax.annotation.Nullable; + +public interface Issue { + + GherkinCheck check(); + + @Nullable + Double cost(); + + Issue cost(double cost); + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/issue/IssueLocation.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/issue/IssueLocation.java new file mode 100644 index 0000000..e5a1665 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/issue/IssueLocation.java @@ -0,0 +1,72 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.visitors.issue; + +import org.sonar.gherkin.tree.impl.GherkinTree; +import org.sonar.plugins.gherkin.api.tree.SyntaxToken; +import org.sonar.plugins.gherkin.api.tree.Tree; + +import javax.annotation.Nullable; +import java.io.File; + +public class IssueLocation { + + private final File file; + private final SyntaxToken firstToken; + private final SyntaxToken lastToken; + private final String message; + + public IssueLocation(File file, Tree tree, @Nullable String message) { + this(file, tree, tree, message); + } + + public IssueLocation(File file, Tree firstTree, Tree lastTree, @Nullable String message) { + this.file = file; + this.firstToken = ((GherkinTree) firstTree).getFirstToken(); + this.lastToken = ((GherkinTree) lastTree).getLastToken(); + this.message = message; + } + + public File file() { + return file; + } + + @Nullable + public String message() { + return message; + } + + public int startLine() { + return firstToken.line(); + } + + public int startLineOffset() { + return firstToken.column(); + } + + public int endLine() { + return lastToken.endLine(); + } + + public int endLineOffset() { + return lastToken.endColumn(); + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/issue/LineIssue.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/issue/LineIssue.java new file mode 100644 index 0000000..a682d63 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/issue/LineIssue.java @@ -0,0 +1,74 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.visitors.issue; + +import com.google.common.base.Preconditions; +import org.sonar.plugins.gherkin.api.GherkinCheck; + +import javax.annotation.Nullable; +import java.io.File; + +public class LineIssue implements Issue { + + private final GherkinCheck check; + private final File file; + private Double cost; + private final String message; + private final int line; + + public LineIssue(GherkinCheck check, File file, int line, String message) { + Preconditions.checkArgument(line > 0); + this.check = check; + this.file = file; + this.message = message; + this.line = line; + this.cost = null; + } + + public String message() { + return message; + } + + public int line() { + return line; + } + + @Override + public GherkinCheck check() { + return check; + } + + public File file() { + return file; + } + + @Nullable + @Override + public Double cost() { + return cost; + } + + @Override + public Issue cost(double cost) { + this.cost = cost; + return this; + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/issue/PreciseIssue.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/issue/PreciseIssue.java new file mode 100644 index 0000000..e909bf9 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/issue/PreciseIssue.java @@ -0,0 +1,79 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.visitors.issue; + +import org.sonar.plugins.gherkin.api.GherkinCheck; +import org.sonar.plugins.gherkin.api.tree.Tree; + +import javax.annotation.Nullable; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class PreciseIssue implements Issue { + + private GherkinCheck check; + private Double cost; + private IssueLocation primaryLocation; + private List secondaryLocations; + + public PreciseIssue(GherkinCheck check, IssueLocation primaryLocation) { + this.check = check; + this.primaryLocation = primaryLocation; + this.secondaryLocations = new ArrayList<>(); + this.cost = null; + } + + @Override + public GherkinCheck check() { + return check; + } + + @Nullable + @Override + public Double cost() { + return cost; + } + + @Override + public PreciseIssue cost(double cost) { + this.cost = cost; + return this; + } + + public IssueLocation primaryLocation() { + return primaryLocation; + } + + public List secondaryLocations() { + return secondaryLocations; + } + + public PreciseIssue secondary(Tree tree, String message) { + secondaryLocations.add(new IssueLocation(primaryLocation.file(), tree, message)); + return this; + } + + public PreciseIssue secondary(File file, Tree tree, String message) { + secondaryLocations.add(new IssueLocation(file, tree, message)); + return this; + } + +} diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/issue/package-info.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/issue/package-info.java new file mode 100644 index 0000000..b9f2888 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/issue/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +@ParametersAreNonnullByDefault +package org.sonar.plugins.gherkin.api.visitors.issue; + +import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/package-info.java b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/package-info.java new file mode 100644 index 0000000..1215329 --- /dev/null +++ b/gherkin-frontend/src/main/java/org/sonar/plugins/gherkin/api/visitors/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +@ParametersAreNonnullByDefault +package org.sonar.plugins.gherkin.api.visitors; + +import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/BackgroundPrefixTreeTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/BackgroundPrefixTreeTest.java new file mode 100644 index 0000000..f4f91f1 --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/BackgroundPrefixTreeTest.java @@ -0,0 +1,42 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import org.junit.Test; + +public class BackgroundPrefixTreeTest extends PrefixTreeTest { + + public BackgroundPrefixTreeTest() { + super(GherkinLexicalGrammar.BACKGROUND_PREFIX); + } + + @Test + public void backgroundPrefix() throws Exception { + checkParsed("Background", "Background"); + checkParsed(" Background", "Background"); + } + + @Test + public void notBackgroundPrefix() throws Exception { + checkNotParsed("background"); + checkNotParsed("BACKGROUND"); + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/BackgroundTreeTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/BackgroundTreeTest.java new file mode 100644 index 0000000..e011f02 --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/BackgroundTreeTest.java @@ -0,0 +1,69 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import org.junit.Test; +import org.sonar.plugins.gherkin.api.tree.BackgroundTree; + +import static org.fest.assertions.Assertions.assertThat; + +public class BackgroundTreeTest extends GherkinTreeTest { + + public BackgroundTreeTest() { + super(GherkinLexicalGrammar.BACKGROUND); + } + + @Test + public void background() throws Exception { + BackgroundTree tree; + + tree = checkParsed("Background:"); + assertThat(tree.steps()).hasSize(0); + assertThat(tree.description()).isNull(); + + tree = checkParsed("Background: blabla..."); + assertThat(tree.steps()).hasSize(0); + assertThat(tree.description()).isNotNull(); + + tree = checkParsed("Background: blabla...\nGiven ..."); + assertThat(tree.steps()).hasSize(1); + assertThat(tree.description()).isNotNull(); + + tree = checkParsed("Background:\nGiven ...\nAnd ..."); + assertThat(tree.steps()).hasSize(2); + assertThat(tree.description()).isNull(); + } + + @Test + public void notBackground() throws Exception { + checkNotParsed("Background"); + checkNotParsed("@mytag\nBackground:"); + } + + private BackgroundTree checkParsed(String toParse) { + BackgroundTree tree = (BackgroundTree) parser().parse(toParse); + assertThat(tree).isNotNull(); + assertThat(tree.prefix()).isNotNull(); + assertThat(tree.colon()).isNotNull(); + assertThat(tree.steps()).isNotNull(); + return tree; + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/DescriptionTreeTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/DescriptionTreeTest.java new file mode 100644 index 0000000..4949ebf --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/DescriptionTreeTest.java @@ -0,0 +1,47 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import org.junit.Test; +import org.sonar.plugins.gherkin.api.tree.DescriptionTree; + +import static org.fest.assertions.Assertions.assertThat; + +public class DescriptionTreeTest extends GherkinTreeTest { + + public DescriptionTreeTest() { + super(GherkinLexicalGrammar.DESCRIPTION); + } + + @Test + public void description() throws Exception { + checkParsed("blabla...", 1); + checkParsed("blabla...\nblabla...", 2); + checkParsed("blabla...\n\nblabla...", 2); + } + + private void checkParsed(String toParse, int size) { + DescriptionTree tree = (DescriptionTree) parser().parse(toParse); + assertThat(tree).isNotNull(); + assertThat(tree.descriptionLines()).isNotNull(); + assertThat(tree.descriptionLines().size()).isEqualTo(size); + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/DocStringTreeTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/DocStringTreeTest.java new file mode 100644 index 0000000..e89ac45 --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/DocStringTreeTest.java @@ -0,0 +1,83 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import org.junit.Test; +import org.sonar.plugins.gherkin.api.tree.DocStringTree; + +import static org.fest.assertions.Assertions.assertThat; + +public class DocStringTreeTest extends GherkinTreeTest { + + public DocStringTreeTest() { + super(GherkinLexicalGrammar.DOC_STRING); + } + + @Test + public void docString() throws Exception { + DocStringTree tree; + + tree = checkParsed("\"\"\"\n\"\"\""); + assertThat(tree.contentType()).isNull(); + assertThat(tree.data()).hasSize(0); + + tree = checkParsed(" \"\"\"\n \"\"\""); + assertThat(tree.contentType()).isNull(); + assertThat(tree.data()).hasSize(0); + + tree = checkParsed("\"\"\"\nblabla\n\"\"\""); + assertThat(tree.contentType()).isNull(); + assertThat(tree.data()).hasSize(1); + + tree = checkParsed("\"\"\"\nblabla\nblabla\n\"\"\""); + assertThat(tree.contentType()).isNull(); + assertThat(tree.data()).hasSize(2); + + tree = checkParsed("\"\"\"\n blabla\n blabla\n\"\"\""); + assertThat(tree.contentType()).isNull(); + assertThat(tree.data()).hasSize(2); + + tree = checkParsed("\"\"\"type\n blabla\n blabla\n\"\"\""); + assertThat(tree.contentType()).isNotNull(); + assertThat(tree.contentType().text()).isEqualTo("type"); + assertThat(tree.data()).hasSize(2); + + tree = checkParsed("\"\"\"type\n # blabla\n blabla\n\"\"\""); + assertThat(tree.contentType()).isNotNull(); + assertThat(tree.contentType().text()).isEqualTo("type"); + assertThat(tree.data()).hasSize(2); + } + + @Test + public void notDocString() throws Exception { + checkNotParsed("\"\""); + checkNotParsed("\"\"\"\"\"\""); + } + + private DocStringTree checkParsed(String toParse) { + DocStringTree tree = (DocStringTree) parser().parse(toParse); + assertThat(tree).isNotNull(); + assertThat(tree.prefix()).isNotNull(); + assertThat(tree.suffix()).isNotNull(); + assertThat(tree.data()).isNotNull(); + return tree; + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/ExamplesPrefixTreeTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/ExamplesPrefixTreeTest.java new file mode 100644 index 0000000..1fac98e --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/ExamplesPrefixTreeTest.java @@ -0,0 +1,42 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import org.junit.Test; + +public class ExamplesPrefixTreeTest extends PrefixTreeTest { + + public ExamplesPrefixTreeTest() { + super(GherkinLexicalGrammar.EXAMPLES_PREFIX); + } + + @Test + public void examplesPrefix() throws Exception { + checkParsed("Examples", "Examples"); + checkParsed(" Examples", "Examples"); + } + + @Test + public void notExamplesPrefix() throws Exception { + checkNotParsed("examples"); + checkNotParsed("EXAMPLES"); + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/ExamplesTreeTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/ExamplesTreeTest.java new file mode 100644 index 0000000..8fd26af --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/ExamplesTreeTest.java @@ -0,0 +1,79 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import org.junit.Test; +import org.sonar.plugins.gherkin.api.tree.ExamplesTree; + +import static org.fest.assertions.Assertions.assertThat; + +public class ExamplesTreeTest extends GherkinTreeTest { + + public ExamplesTreeTest() { + super(GherkinLexicalGrammar.EXAMPLES); + } + + @Test + public void examples() throws Exception { + ExamplesTree tree; + + tree = checkParsed("Examples:"); + assertThat(tree.tags()).hasSize(0); + assertThat(tree.description()).isNull(); + assertThat(tree.table()).isNull(); + + tree = checkParsed("@mytag @my-tag\nExamples:"); + assertThat(tree.tags()).hasSize(2); + assertThat(tree.description()).isNull(); + assertThat(tree.table()).isNull(); + + tree = checkParsed("@mytag @my-tag\nExamples:\nblabla...\nblabla..."); + assertThat(tree.tags()).hasSize(2); + assertThat(tree.description()).isNotNull(); + assertThat(tree.table()).isNull(); + + tree = checkParsed("@mytag @my-tag\nExamples:\nblabla...\nblabla...\n|d1|d2|"); + assertThat(tree.tags()).hasSize(2); + assertThat(tree.description()).isNotNull(); + assertThat(tree.table().rows()).hasSize(1); + + tree = checkParsed("@mytag @my-tag\nExamples:\n|d1|d2|\n|1|2|"); + assertThat(tree.tags()).hasSize(2); + assertThat(tree.description()).isNull(); + assertThat(tree.table().rows()).hasSize(2); + } + + @Test + public void notExamples() throws Exception { + checkNotParsed("Examples"); + checkNotParsed("Examples :"); + checkNotParsed("Examples :\n|aa"); + } + + private ExamplesTree checkParsed(String toParse) { + ExamplesTree tree = (ExamplesTree) parser().parse(toParse); + assertThat(tree).isNotNull(); + assertThat(tree.prefix()).isNotNull(); + assertThat(tree.colon()).isNotNull(); + assertThat(tree.tags()).isNotNull(); + return tree; + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/FeatureDeclarationTreeTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/FeatureDeclarationTreeTest.java new file mode 100644 index 0000000..a54188d --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/FeatureDeclarationTreeTest.java @@ -0,0 +1,68 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import org.junit.Test; +import org.sonar.plugins.gherkin.api.tree.FeatureDeclarationTree; + +import static org.fest.assertions.Assertions.assertThat; + +public class FeatureDeclarationTreeTest extends GherkinTreeTest { + + public FeatureDeclarationTreeTest() { + super(GherkinLexicalGrammar.FEATURE_DECLARATION); + } + + @Test + public void featureDeclaration() throws Exception { + FeatureDeclarationTree tree; + + tree = checkParsed("Feature: my feature"); + assertThat(tree.name().text()).isEqualTo("my feature"); + assertThat(tree.tags()).hasSize(0); + assertThat(tree.description()).isNull(); + + tree = checkParsed("Feature: my feature\nblabla...\nblabla..."); + assertThat(tree.name().text()).isEqualTo("my feature"); + assertThat(tree.tags()).hasSize(0); + assertThat(tree.description()).isNotNull(); + + tree = checkParsed("@mytag @my-tag\nFeature: my feature\nblabla...\nblabla..."); + assertThat(tree.name().text()).isEqualTo("my feature"); + assertThat(tree.tags()).hasSize(2); + assertThat(tree.description()).isNotNull(); + } + + @Test + public void notFeatureDeclaration() throws Exception { + checkNotParsed("feature"); + checkNotParsed("Feature"); + checkNotParsed("Feature:"); + } + + private FeatureDeclarationTree checkParsed(String toParse) { + FeatureDeclarationTree tree = (FeatureDeclarationTree) parser().parse(toParse); + assertThat(tree).isNotNull(); + assertThat(tree.tags()).isNotNull(); + assertThat(tree.name()).isNotNull(); + return tree; + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/FeaturePrefixTreeTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/FeaturePrefixTreeTest.java new file mode 100644 index 0000000..aca74ef --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/FeaturePrefixTreeTest.java @@ -0,0 +1,42 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import org.junit.Test; + +public class FeaturePrefixTreeTest extends PrefixTreeTest { + + public FeaturePrefixTreeTest() { + super(GherkinLexicalGrammar.FEATURE_PREFIX); + } + + @Test + public void featurePrefix() throws Exception { + checkParsed("Feature", "Feature"); + checkParsed(" Feature", "Feature"); + } + + @Test + public void notFeaturePrefix() throws Exception { + checkNotParsed("feature"); + checkNotParsed("FEATURE"); + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/FeatureTreeTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/FeatureTreeTest.java new file mode 100644 index 0000000..4b91c12 --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/FeatureTreeTest.java @@ -0,0 +1,121 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import org.junit.Test; +import org.sonar.plugins.gherkin.api.tree.FeatureTree; + +import static org.fest.assertions.Assertions.assertThat; + +public class FeatureTreeTest extends GherkinTreeTest { + + public FeatureTreeTest() { + super(GherkinLexicalGrammar.FEATURE); + } + + @Test + public void feature() throws Exception { + FeatureTree tree; + + tree = checkParsed("Feature: my feature"); + assertThat(tree.declaration().name().text()).isEqualTo("my feature"); + assertThat(tree.declaration().tags()).hasSize(0); + assertThat(tree.declaration().description()).isNull(); + assertThat(tree.background()).isNull(); + assertThat(tree.scenarioOutlines()).hasSize(0); + assertThat(tree.scenarios()).hasSize(0); + + tree = checkParsed("Feature: my feature\nblabla...\nblabla..."); + assertThat(tree.declaration().name().text()).isEqualTo("my feature"); + assertThat(tree.declaration().tags()).hasSize(0); + assertThat(tree.declaration().description()).isNotNull(); + assertThat(tree.background()).isNull(); + assertThat(tree.scenarioOutlines()).hasSize(0); + assertThat(tree.scenarios()).hasSize(0); + + tree = checkParsed("@mytag @my-tag\nFeature: my feature\nblabla...\nblabla..."); + assertThat(tree.declaration().name().text()).isEqualTo("my feature"); + assertThat(tree.declaration().tags()).hasSize(2); + assertThat(tree.declaration().description()).isNotNull(); + assertThat(tree.background()).isNull(); + assertThat(tree.scenarioOutlines()).hasSize(0); + assertThat(tree.scenarios()).hasSize(0); + + tree = checkParsed( + "@mytag @my-tag\n" + + "Feature:my feature\n" + + "blabla...\n" + + "blabla...\n" + + "Background:"); + assertThat(tree.declaration().name().text()).isEqualTo("my feature"); + assertThat(tree.declaration().tags()).hasSize(2); + assertThat(tree.declaration().description()).isNotNull(); + assertThat(tree.background()).isNotNull(); + assertThat(tree.scenarioOutlines()).hasSize(0); + assertThat(tree.scenarios()).hasSize(0); + + tree = checkParsed( + "@mytag @my-tag\n" + + "Feature:my feature\n" + + "blabla...\n" + + "blabla...\n" + + "Background:\n" + + "Given ...\n" + + "And ...\n" + + "\n" + + "Scenario: name1\n" + + "Scenario: name2\n" + + "Given ...\n" + + "And ...\n" + + "When ...\n" + + "Then ...\n" + + "Scenario Outline: name3\n" + + "* ...\n" + + "When ...\n" + + "Then ...\n" + + "\n" + + "@mytag\n" + + "Examples:\n" + + "|d1|\n"); + assertThat(tree.declaration().name().text()).isEqualTo("my feature"); + assertThat(tree.declaration().tags()).hasSize(2); + assertThat(tree.declaration().description()).isNotNull(); + assertThat(tree.background()).isNotNull(); + assertThat(tree.scenarioOutlines()).hasSize(1); + assertThat(tree.scenarios()).hasSize(2); + } + + @Test + public void notFeature() throws Exception { + checkNotParsed("feature"); + checkNotParsed("Feature"); + checkNotParsed("Feature:"); + } + + private FeatureTree checkParsed(String toParse) { + FeatureTree tree = (FeatureTree) parser().parse(toParse); + assertThat(tree).isNotNull(); + assertThat(tree.declaration()).isNotNull(); + assertThat(tree.scenarios()).isNotNull(); + assertThat(tree.scenarioOutlines()).isNotNull(); + return tree; + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/GherkinDocumentTreeTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/GherkinDocumentTreeTest.java new file mode 100644 index 0000000..c8c2eef --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/GherkinDocumentTreeTest.java @@ -0,0 +1,70 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import org.junit.Test; +import org.sonar.plugins.gherkin.api.tree.GherkinDocumentTree; + +import java.io.File; + +import static org.fest.assertions.Assertions.assertThat; + +public class GherkinDocumentTreeTest extends GherkinTreeTest { + + public GherkinDocumentTreeTest() { + super(GherkinLexicalGrammar.GHERKIN_DOCUMENT); + } + + @Test + public void gherkinDocument() throws Exception { + GherkinDocumentTree tree; + + tree = checkParsed(new File("src/test/resources/parser/empty.feature")); + assertThat(tree.feature()).isNull(); + + tree = checkParsed(new File("src/test/resources/parser/parse.feature")); + assertThat(tree.hasByteOrderMark()).isEqualTo(false); + assertThat(tree.feature()).isNotNull(); + assertThat(tree.feature().scenarioOutlines()).hasSize(1); + assertThat(tree.feature().scenarios()).hasSize(2); + assertThat(tree.feature().background()).isNotNull(); + + tree = checkParsed(new File("src/test/resources/parser/parse-bom.feature")); + assertThat(tree.hasByteOrderMark()).isEqualTo(true); + assertThat(tree.feature()).isNotNull(); + assertThat(tree.feature().scenarioOutlines()).hasSize(1); + assertThat(tree.feature().scenarios()).hasSize(2); + assertThat(tree.feature().background()).isNotNull(); + } + + @Test + public void notGherkinDocument() throws Exception { + checkNotParsed(new File("src/test/resources/parser/two-backgrounds.feature")); + } + + private GherkinDocumentTree checkParsed(File file) throws Exception { + GherkinDocumentTree tree = (GherkinDocumentTree) parser().parse(Files.toString(file, Charsets.UTF_8)); + assertThat(tree).isNotNull(); + return tree; + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/GherkinGrammarTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/GherkinGrammarTest.java new file mode 100644 index 0000000..5ddad3c --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/GherkinGrammarTest.java @@ -0,0 +1,35 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import com.google.common.base.Charsets; +import com.sonar.sslr.api.RecognitionException; +import org.junit.Test; + +public class GherkinGrammarTest { + + @Test(expected = RecognitionException.class) + public void parse_error() throws Exception { + GherkinParserBuilder + .createTestParser(Charsets.UTF_8, GherkinLexicalGrammar.GHERKIN_DOCUMENT) + .parse("blabla"); + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/GherkinTreeTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/GherkinTreeTest.java new file mode 100644 index 0000000..7e43fc5 --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/GherkinTreeTest.java @@ -0,0 +1,63 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import com.sonar.sslr.api.typed.ActionParser; +import org.sonar.gherkin.parser.GherkinLexicalGrammar; +import org.sonar.gherkin.parser.GherkinParserBuilder; +import org.sonar.plugins.gherkin.api.tree.Tree; + +import java.io.File; + +import static org.junit.Assert.fail; + +public abstract class GherkinTreeTest { + + private final ActionParser parser; + + public GherkinTreeTest(GherkinLexicalGrammar ruleKey) { + parser = GherkinParserBuilder.createTestParser(Charsets.UTF_8, ruleKey); + } + + public ActionParser parser() { + return parser; + } + + public void checkNotParsed(String toParse) { + try { + parser.parse(toParse); + } catch (Exception e) { + return; + } + fail("Did not throw a RecognitionException as expected."); + } + + public void checkNotParsed(File file) { + try { + parser.parse(Files.toString(file, Charsets.UTF_8)); + } catch (Exception e) { + return; + } + fail("Did not throw a RecognitionException as expected."); + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/NameTreeTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/NameTreeTest.java new file mode 100644 index 0000000..e20ed33 --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/NameTreeTest.java @@ -0,0 +1,47 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import org.junit.Test; +import org.sonar.plugins.gherkin.api.tree.NameTree; + +import static org.fest.assertions.Assertions.assertThat; + +public class NameTreeTest extends GherkinTreeTest { + + public NameTreeTest() { + super(GherkinLexicalGrammar.NAME); + } + + @Test + public void name() throws Exception { + checkParsed("abc", "abc"); + checkParsed("abc ", "abc "); + checkParsed(" abc", "abc"); + checkParsed("blabla... blabla...", "blabla... blabla..."); + } + + private void checkParsed(String toParse, String name) { + NameTree tree = (NameTree) parser().parse(toParse); + assertThat(tree).isNotNull(); + assertThat(tree.text()).isEqualTo(name); + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/PrefixTreeTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/PrefixTreeTest.java new file mode 100644 index 0000000..70f9f6a --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/PrefixTreeTest.java @@ -0,0 +1,40 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import org.sonar.plugins.gherkin.api.tree.PrefixTree; + +import static org.fest.assertions.Assertions.assertThat; + +public abstract class PrefixTreeTest extends GherkinTreeTest { + + public PrefixTreeTest(GherkinLexicalGrammar ruleKey) { + super(ruleKey); + } + + public void checkParsed(String toParse, String prefix) { + PrefixTree tree = (PrefixTree) parser().parse(toParse); + assertThat(tree).isNotNull(); + assertThat(tree.keyword()).isNotNull(); + assertThat(tree.text()).isNotNull(); + assertThat(tree.text()).isEqualTo(prefix); + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/ScenarioOutlinePrefixTreeTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/ScenarioOutlinePrefixTreeTest.java new file mode 100644 index 0000000..a30331c --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/ScenarioOutlinePrefixTreeTest.java @@ -0,0 +1,43 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import org.junit.Test; + +public class ScenarioOutlinePrefixTreeTest extends PrefixTreeTest { + + public ScenarioOutlinePrefixTreeTest() { + super(GherkinLexicalGrammar.SCENARIO_OUTLINE_PREFIX); + } + + @Test + public void scenarioOutlinePrefix() throws Exception { + checkParsed("Scenario Outline", "Scenario Outline"); + checkParsed(" Scenario Outline", "Scenario Outline"); + } + + @Test + public void notScenarioOutlinePrefix() throws Exception { + checkNotParsed("scenario outline"); + checkNotParsed("SCENARIO OUTLINE"); + checkNotParsed("Scenario Outline"); + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/ScenarioOutlineTreeTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/ScenarioOutlineTreeTest.java new file mode 100644 index 0000000..fe7a1c4 --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/ScenarioOutlineTreeTest.java @@ -0,0 +1,102 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import org.junit.Test; +import org.sonar.plugins.gherkin.api.tree.ScenarioOutlineTree; + +import static org.fest.assertions.Assertions.assertThat; + +public class ScenarioOutlineTreeTest extends GherkinTreeTest { + + public ScenarioOutlineTreeTest() { + super(GherkinLexicalGrammar.SCENARIO_OUTLINE); + } + + @Test + public void scenarioOutline() throws Exception { + ScenarioOutlineTree tree; + + tree = checkParsed("Scenario Outline: name...\nExamples:"); + assertThat(tree.steps()).hasSize(0); + assertThat(tree.tags()).hasSize(0); + assertThat(tree.description()).isNull(); + assertThat(tree.name().text()).isEqualTo("name..."); + assertThat(tree.examples().table()).isNull(); + + tree = checkParsed("Scenario Outline: name...\nblabla...\nExamples:"); + assertThat(tree.steps()).hasSize(0); + assertThat(tree.tags()).hasSize(0); + assertThat(tree.description()).isNotNull(); + assertThat(tree.name().text()).isEqualTo("name..."); + assertThat(tree.examples().table()).isNull(); + + tree = checkParsed("Scenario Outline: name...\nblabla...\nGiven blabla...\n\nExamples:"); + assertThat(tree.steps()).hasSize(1); + assertThat(tree.tags()).hasSize(0); + assertThat(tree.description()).isNotNull(); + assertThat(tree.name().text()).isEqualTo("name..."); + assertThat(tree.examples().table()).isNull(); + + tree = checkParsed("Scenario Outline: name...\nblabla...\nGiven blabla...\n\nExamples:\n|d1|d2|"); + assertThat(tree.steps()).hasSize(1); + assertThat(tree.tags()).hasSize(0); + assertThat(tree.description()).isNotNull(); + assertThat(tree.name().text()).isEqualTo("name..."); + assertThat(tree.examples().table().rows()).hasSize(1); + + tree = checkParsed("@mytag\nScenario Outline: name...\nblabla...\nGiven blabla...\n\nExamples:\n|d1|d2|"); + assertThat(tree.steps()).hasSize(1); + assertThat(tree.tags()).hasSize(1); + assertThat(tree.description()).isNotNull(); + assertThat(tree.name().text()).isEqualTo("name..."); + assertThat(tree.examples().table().rows()).hasSize(1); + + tree = checkParsed("@mytag\nScenario Outline: name...\nblabla...\nGiven blabla...\n\n@mytag\nExamples:\n|d1|d2|"); + assertThat(tree.steps()).hasSize(1); + assertThat(tree.tags()).hasSize(1); + assertThat(tree.description()).isNotNull(); + assertThat(tree.name().text()).isEqualTo("name..."); + assertThat(tree.examples().table().rows()).hasSize(1); + assertThat(tree.examples().tags()).hasSize(1); + } + + @Test + public void notScenarioOutline() throws Exception { + checkNotParsed("Scenario"); + checkNotParsed("Scenario Outline"); + checkNotParsed("Scenario Outline:"); + checkNotParsed("Scenario Outline: name..."); + checkNotParsed("Scenario Outline:\nExamples:"); + } + + private ScenarioOutlineTree checkParsed(String toParse) { + ScenarioOutlineTree tree = (ScenarioOutlineTree) parser().parse(toParse); + assertThat(tree).isNotNull(); + assertThat(tree.prefix()).isNotNull(); + assertThat(tree.colon()).isNotNull(); + assertThat(tree.steps()).isNotNull(); + assertThat(tree.tags()).isNotNull(); + assertThat(tree.name()).isNotNull(); + assertThat(tree.examples()).isNotNull(); + return tree; + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/ScenarioPrefixTreeTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/ScenarioPrefixTreeTest.java new file mode 100644 index 0000000..cb52259 --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/ScenarioPrefixTreeTest.java @@ -0,0 +1,42 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import org.junit.Test; + +public class ScenarioPrefixTreeTest extends PrefixTreeTest { + + public ScenarioPrefixTreeTest() { + super(GherkinLexicalGrammar.SCENARIO_PREFIX); + } + + @Test + public void scenarioPrefix() throws Exception { + checkParsed("Scenario", "Scenario"); + checkParsed(" Scenario", "Scenario"); + } + + @Test + public void notScenarioPrefix() throws Exception { + checkNotParsed("scenario"); + checkNotParsed("SCENARIO"); + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/ScenarioTreeTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/ScenarioTreeTest.java new file mode 100644 index 0000000..198e84b --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/ScenarioTreeTest.java @@ -0,0 +1,80 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import org.junit.Test; +import org.sonar.plugins.gherkin.api.tree.ScenarioTree; + +import static org.fest.assertions.Assertions.assertThat; + +public class ScenarioTreeTest extends GherkinTreeTest { + + public ScenarioTreeTest() { + super(GherkinLexicalGrammar.SCENARIO); + } + + @Test + public void scenario() throws Exception { + ScenarioTree tree; + + tree = checkParsed("Scenario: name..."); + assertThat(tree.steps()).hasSize(0); + assertThat(tree.tags()).hasSize(0); + assertThat(tree.description()).isNull(); + assertThat(tree.name().text()).isEqualTo("name..."); + + tree = checkParsed("@mytag @my-tag\nScenario: name..."); + assertThat(tree.steps()).hasSize(0); + assertThat(tree.tags()).hasSize(2); + assertThat(tree.description()).isNull(); + assertThat(tree.name().text()).isEqualTo("name..."); + + tree = checkParsed("@mytag @my-tag\nScenario: name...\nblabal...\nblabla..."); + assertThat(tree.steps()).hasSize(0); + assertThat(tree.tags()).hasSize(2); + assertThat(tree.description()).isNotNull(); + assertThat(tree.name().text()).isEqualTo("name..."); + + tree = checkParsed("@mytag @my-tag\nScenario: name...\nGiven ...\nWhen ..."); + assertThat(tree.steps()).hasSize(2); + assertThat(tree.tags()).hasSize(2); + assertThat(tree.description()).isNull(); + assertThat(tree.name().text()).isEqualTo("name..."); + } + + @Test + public void notScenario() throws Exception { + checkNotParsed("Scenario"); + checkNotParsed("Scenario:"); + checkNotParsed("Scenario : name..."); + } + + private ScenarioTree checkParsed(String toParse) { + ScenarioTree tree = (ScenarioTree) parser().parse(toParse); + assertThat(tree).isNotNull(); + assertThat(tree.prefix()).isNotNull(); + assertThat(tree.colon()).isNotNull(); + assertThat(tree.steps()).isNotNull(); + assertThat(tree.tags()).isNotNull(); + assertThat(tree.name()).isNotNull(); + return tree; + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/StepPrefixTreeTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/StepPrefixTreeTest.java new file mode 100644 index 0000000..8347083 --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/StepPrefixTreeTest.java @@ -0,0 +1,61 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import org.junit.Test; + +public class StepPrefixTreeTest extends PrefixTreeTest { + + public StepPrefixTreeTest() { + super(GherkinLexicalGrammar.STEP_PREFIX); + } + + @Test + public void stepPrefix() throws Exception { + checkParsed("Given", "Given"); + checkParsed(" Given", "Given"); + checkParsed("When", "When"); + checkParsed(" When", "When"); + checkParsed("Then", "Then"); + checkParsed(" Then", "Then"); + checkParsed("*", "*"); + checkParsed(" *", "*"); + checkParsed("And", "And"); + checkParsed(" And", "And"); + checkParsed("But", "But"); + checkParsed(" But", "But"); + } + + @Test + public void notStepPrefix() throws Exception { + checkNotParsed("given"); + checkNotParsed("GIVEN"); + checkNotParsed("when"); + checkNotParsed("WHEN"); + checkNotParsed("then"); + checkNotParsed("THEN"); + checkNotParsed("but"); + checkNotParsed("BUT"); + checkNotParsed("and"); + checkNotParsed("AND"); + checkNotParsed("blabla"); + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/StepTreeTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/StepTreeTest.java new file mode 100644 index 0000000..bd20c68 --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/StepTreeTest.java @@ -0,0 +1,87 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import org.junit.Test; +import org.sonar.plugins.gherkin.api.tree.StepTree; + +import static org.fest.assertions.Assertions.assertThat; + +public class StepTreeTest extends GherkinTreeTest { + + public StepTreeTest() { + super(GherkinLexicalGrammar.STEP); + } + + @Test + public void step() throws Exception { + StepTree tree; + + checkParsed("Given I am a customer", "Given", "I am a customer"); + checkParsed(" Given I am a customer", "Given", "I am a customer"); + checkParsed(" Given I am a customer ", "Given", "I am a customer "); + + checkParsed("When I add a product to my cart", "When", "I add a product to my cart"); + checkParsed(" When I add a product to my cart", "When", "I add a product to my cart"); + checkParsed(" When I add a product to my cart ", "When", "I add a product to my cart "); + + checkParsed("Then I should see the product in my cart", "Then", "I should see the product in my cart"); + checkParsed(" Then I should see the product in my cart", "Then", "I should see the product in my cart"); + checkParsed(" Then I should see the product in my cart ", "Then", "I should see the product in my cart "); + + checkParsed("* I should see the product in my cart", "*", "I should see the product in my cart"); + checkParsed(" * I should see the product in my cart", "*", "I should see the product in my cart"); + checkParsed(" * I should see the product in my cart ", "*", "I should see the product in my cart "); + + tree = checkParsed("Given I am a customer:\n\"\"\"\nblabla...\nblabla...\n\"\"\"", "Given", "I am a customer:"); + assertThat(tree.table()).isNull(); + assertThat(tree.docString()).isNotNull(); + assertThat(tree.docString().data()).hasSize(2); + + tree = checkParsed("Given I am a customer:\n| abc |\n|2|", "Given", "I am a customer:"); + assertThat(tree.table()).isNotNull(); + assertThat(tree.docString()).isNull(); + assertThat(tree.table().rows()).hasSize(2); + } + + @Test + public void notStep() throws Exception { + checkNotParsed("blabla..."); + checkNotParsed("GIVEN I am a customer"); + checkNotParsed("given I am a customer"); + checkNotParsed("WHEN I add a product to my cart"); + checkNotParsed("when I add a product to my cart"); + checkNotParsed("THEN I should see the product in my cart"); + checkNotParsed("then I should see the product in my cart"); + } + + private StepTree checkParsed(String toParse, String prefix, String sentence) { + StepTree tree = (StepTree) parser().parse(toParse); + assertThat(tree).isNotNull(); + assertThat(tree.prefix()).isNotNull(); + assertThat(tree.sentence()).isNotNull(); + assertThat(tree.prefix().keyword()).isNotNull(); + assertThat(tree.prefix().text()).isNotNull(); + assertThat(tree.prefix().text()).isEqualTo(prefix); + assertThat(tree.sentence().text()).isEqualTo(sentence); + return tree; + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/TableTreeTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/TableTreeTest.java new file mode 100644 index 0000000..e6ef8d9 --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/TableTreeTest.java @@ -0,0 +1,70 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import org.junit.Test; +import org.sonar.plugins.gherkin.api.tree.TableTree; + +import static org.fest.assertions.Assertions.assertThat; + +public class TableTreeTest extends GherkinTreeTest { + + public TableTreeTest() { + super(GherkinLexicalGrammar.TABLE); + } + + @Test + public void table() throws Exception { + TableTree tree; + + tree = checkParsed("||"); + assertThat(tree.rows()).hasSize(1); + + tree = checkParsed(" ||"); + assertThat(tree.rows()).hasSize(1); + + tree = checkParsed(" | |"); + assertThat(tree.rows()).hasSize(1); + + tree = checkParsed("| test|"); + assertThat(tree.rows()).hasSize(1); + + tree = checkParsed("| test| \n | 2 |"); + assertThat(tree.rows()).hasSize(2); + + tree = checkParsed("| test| \n | 2 | \n | sqfqsf|"); + assertThat(tree.rows()).hasSize(3); + } + + @Test + public void notTable() throws Exception { + checkNotParsed("abc"); + checkNotParsed("|abc"); + checkNotParsed("| abc"); + } + + private TableTree checkParsed(String toParse) { + TableTree tree = (TableTree) parser().parse(toParse); + assertThat(tree).isNotNull(); + assertThat(tree.rows()).isNotNull(); + return tree; + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/TagTreeTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/TagTreeTest.java new file mode 100644 index 0000000..067bfc3 --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/parser/TagTreeTest.java @@ -0,0 +1,53 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.parser; + +import org.junit.Test; +import org.sonar.plugins.gherkin.api.tree.TagTree; + +import static org.fest.assertions.Assertions.assertThat; + +public class TagTreeTest extends GherkinTreeTest { + + public TagTreeTest() { + super(GherkinLexicalGrammar.TAG); + } + + @Test + public void tag() throws Exception { + checkParsed("@mytag", "mytag"); + checkParsed("@my-tag ", "my-tag"); + checkParsed(" @my-tag ", "my-tag"); + } + + @Test + public void notTag() throws Exception { + checkNotParsed("@"); + checkNotParsed("@@mytag"); + checkNotParsed("mytag"); + } + + private void checkParsed(String toParse, String tag) { + TagTree tree = (TagTree) parser().parse(toParse); + assertThat(tree).isNotNull(); + assertThat(tree.text()).isEqualTo(tag); + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/visitors/SyntaxHighlighterVisitorTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/visitors/SyntaxHighlighterVisitorTest.java new file mode 100644 index 0000000..6aed816 --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/visitors/SyntaxHighlighterVisitorTest.java @@ -0,0 +1,161 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.visitors; + +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.internal.DefaultFileSystem; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.sensor.highlighting.TypeOfText; +import org.sonar.api.batch.sensor.internal.SensorContextTester; +import org.sonar.gherkin.parser.GherkinParserBuilder; +import org.sonar.plugins.gherkin.api.tree.GherkinDocumentTree; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.TreeVisitorContext; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.sonar.api.batch.sensor.highlighting.TypeOfText.*; + +public class SyntaxHighlighterVisitorTest { + + private SyntaxHighlighterVisitor highlighterVisitor; + private SensorContextTester sensorContext; + private File file; + private DefaultInputFile inputFile; + private TreeVisitorContext visitorContext; + + @Rule + public final TemporaryFolder tempFolder = new TemporaryFolder(); + + @Before + public void setUp() throws IOException { + DefaultFileSystem fileSystem = new DefaultFileSystem(tempFolder.getRoot()); + fileSystem.setEncoding(Charsets.UTF_8); + file = tempFolder.newFile(); + inputFile = new DefaultInputFile("moduleKey", file.getName()) + .setLanguage("gherkin") + .setType(InputFile.Type.MAIN); + fileSystem.add(inputFile); + + sensorContext = SensorContextTester.create(tempFolder.getRoot()); + sensorContext.setFileSystem(fileSystem); + visitorContext = mock(TreeVisitorContext.class); + highlighterVisitor = new SyntaxHighlighterVisitor(sensorContext); + when(visitorContext.getFile()).thenReturn(file); + } + + @Test + public void tag() throws Exception { + highlight("@my-tag\nFeature: my feature..."); + assertHighlighting(1, 0, 7, ANNOTATION); + } + + @Test + public void name() throws Exception { + highlight("@my-tag\nFeature: my feature..."); + assertHighlighting(2, 9, 13, STRING); + } + + @Test + public void feature_prefix() throws Exception { + highlight("Feature: my feature..."); + assertHighlighting(1, 0, 7, KEYWORD); + } + + @Test + public void background_prefix() throws Exception { + highlight("Feature: my feature...\nBackground:"); + assertHighlighting(2, 0, 10, KEYWORD); + } + + @Test + public void scenario_prefix() throws Exception { + highlight("Feature: my feature...\nScenario: my scenario..."); + assertHighlighting(2, 0, 8, KEYWORD); + } + + @Test + public void scenario_outline_prefix() throws Exception { + highlight("Feature: my feature...\nScenario Outline: my scenario...\nExamples:"); + assertHighlighting(2, 0, 16, KEYWORD); + } + + @Test + public void examples_prefix() throws Exception { + highlight("Feature: my feature...\nScenario Outline: my scenario...\nExamples:"); + assertHighlighting(3, 0, 8, KEYWORD); + } + + @Test + public void step_prefix() throws Exception { + highlight("Feature: my feature...\nScenario: my scenario...\nGiven blabla...\nWhen blabla...\nThen blabla...\n* blabla..."); + assertHighlighting(3, 0, 5, KEYWORD); + assertHighlighting(4, 0, 4, KEYWORD); + assertHighlighting(5, 0, 4, KEYWORD); + assertHighlighting(6, 0, 1, KEYWORD); + } + + @Test + public void comment1() throws Exception { + highlight("# blabla\nFeature: my feature..."); + assertHighlighting(1, 0, 8, COMMENT); + } + + @Test + public void comment2() throws Exception { + highlight("#blabla\nFeature: my feature..."); + assertHighlighting(1, 0, 7, COMMENT); + } + + @Test + public void byte_order_mark() throws Exception { + highlight("\ufeffFeature: my feature..."); + assertHighlighting(1, 0, 7, KEYWORD); + } + + private void highlight(String string) throws Exception { + inputFile.initMetadata(string); + Tree tree = GherkinParserBuilder.createParser(Charsets.UTF_8).parse(string); + when(visitorContext.getTopTree()).thenReturn((GherkinDocumentTree) tree); + + Files.write(string, file, Charsets.UTF_8); + highlighterVisitor.scanTree(visitorContext); + } + + private void assertHighlighting(int line, int column, int length, TypeOfText type) { + for (int i = column; i < column + length; i++) { + List typeOfTexts = sensorContext.highlightingTypeAt("moduleKey:" + file.getName(), line, i); + assertThat(typeOfTexts).hasSize(1); + assertThat(typeOfTexts.get(0)).isEqualTo(type); + } + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/visitors/metrics/GherkinCommentAnalyserTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/visitors/metrics/GherkinCommentAnalyserTest.java new file mode 100644 index 0000000..126e6f9 --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/visitors/metrics/GherkinCommentAnalyserTest.java @@ -0,0 +1,47 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.visitors.metrics; + +import org.junit.Test; + +import static org.fest.assertions.Assertions.assertThat; + +public class GherkinCommentAnalyserTest { + + private GherkinCommentAnalyser analyser = new GherkinCommentAnalyser(); + + @Test + public void content() { + assertThat(analyser.getContents("# comment")).isEqualTo(" comment"); + assertThat(analyser.getContents("#comment")).isEqualTo("comment"); + } + + @Test + public void blank() { + assertThat(analyser.isBlank(" ")).isTrue(); + assertThat(analyser.isBlank(" ")).isTrue(); + } + + @Test(expected = IllegalArgumentException.class) + public void unknown_type_of_comments() { + analyser.getContents(""); + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/visitors/metrics/MetricsTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/visitors/metrics/MetricsTest.java new file mode 100644 index 0000000..09d5097 --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/visitors/metrics/MetricsTest.java @@ -0,0 +1,55 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.visitors.metrics; + +import com.google.common.base.Charsets; +import org.junit.Test; +import org.sonar.gherkin.parser.GherkinParserBuilder; +import org.sonar.plugins.gherkin.api.tree.Tree; + +import java.io.File; + +import static org.fest.assertions.Assertions.assertThat; + +public class MetricsTest { + + @Test + public void metrics_UTF8_file() { + String path = "src/test/resources/metrics/metrics.feature"; + Tree tree = GherkinParserBuilder.createParser(Charsets.UTF_8).parse(new File(path)); + assertMetrics(tree); + } + + @Test + public void metrics_UTF8_file_with_BOM() { + String path = "src/test/resources/metrics/metrics-bom.feature"; + Tree tree = GherkinParserBuilder.createParser(Charsets.UTF_8).parse(new File(path)); + assertMetrics(tree); + } + + private void assertMetrics(Tree tree) { + assertThat(new LinesOfCodeVisitor(tree).getNumberOfLinesOfCode()).isEqualTo(22); + assertThat(new StatementsVisitor(tree).getNumberOfStatements()).isEqualTo(10); + assertThat(new CommentLinesVisitor(tree).getNumberOfCommentLines()).isEqualTo(2); + assertThat(new FunctionsVisitor(tree).getNumberOfFunctions()).isEqualTo(4); + assertThat(new ClassesVisitor(tree).getNumberOfClasses()).isEqualTo(1); + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/gherkin/visitors/metrics/MetricsVisitorTest.java b/gherkin-frontend/src/test/java/org/sonar/gherkin/visitors/metrics/MetricsVisitorTest.java new file mode 100644 index 0000000..761fecf --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/gherkin/visitors/metrics/MetricsVisitorTest.java @@ -0,0 +1,68 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.visitors.metrics; + +import com.google.common.base.Charsets; +import org.junit.Test; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.sensor.internal.SensorContextTester; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.gherkin.parser.GherkinParserBuilder; +import org.sonar.plugins.gherkin.api.tree.GherkinDocumentTree; +import org.sonar.plugins.gherkin.api.visitors.TreeVisitorContext; + +import java.io.File; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class MetricsVisitorTest { + + @Test + public void test() { + File moduleBaseDir = new File("src/test/resources/metrics/"); + SensorContextTester context = SensorContextTester.create(moduleBaseDir); + + DefaultInputFile inputFile = new DefaultInputFile("moduleKey", "metrics.feature") + .setModuleBaseDir(moduleBaseDir.toPath()) + .setLanguage("gherkin") + .setType(InputFile.Type.MAIN); + + context.fileSystem().add(inputFile); + + MetricsVisitor metricsVisitor = new MetricsVisitor(context); + + TreeVisitorContext treeVisitorContext = mock(TreeVisitorContext.class); + when(treeVisitorContext.getFile()).thenReturn(inputFile.file()); + when(treeVisitorContext.getTopTree()).thenReturn((GherkinDocumentTree) GherkinParserBuilder.createParser(Charsets.UTF_8).parse(inputFile.file())); + + metricsVisitor.scanTree(treeVisitorContext); + + String componentKey = "moduleKey:metrics.feature"; + assertThat(context.measure(componentKey, CoreMetrics.NCLOC).value()).isEqualTo(22); + assertThat(context.measure(componentKey, CoreMetrics.STATEMENTS).value()).isEqualTo(10); + assertThat(context.measure(componentKey, CoreMetrics.COMMENT_LINES).value()).isEqualTo(2); + assertThat(context.measure(componentKey, CoreMetrics.FUNCTIONS).value()).isEqualTo(4); + assertThat(context.measure(componentKey, CoreMetrics.CLASSES).value()).isEqualTo(1); + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/plugins/gherkin/api/CustomGherkinRulesDefinitionTest.java b/gherkin-frontend/src/test/java/org/sonar/plugins/gherkin/api/CustomGherkinRulesDefinitionTest.java new file mode 100644 index 0000000..983cca9 --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/plugins/gherkin/api/CustomGherkinRulesDefinitionTest.java @@ -0,0 +1,91 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api; + +import org.junit.Test; +import org.sonar.api.server.rule.RulesDefinition; +import org.sonar.check.Rule; +import org.sonar.check.RuleProperty; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitor; + +import static org.fest.assertions.Assertions.assertThat; + +public class CustomGherkinRulesDefinitionTest { + + private static final String REPOSITORY_NAME = "Custom Rule Repository"; + private static final String REPOSITORY_KEY = "CustomRuleRepository"; + + private static final String RULE_NAME = "This is my custom rule"; + private static final String RULE_KEY = "MyCustomRule"; + + @Test + public void test() { + MyCustomGherkinRulesDefinition rulesDefinition = new MyCustomGherkinRulesDefinition(); + RulesDefinition.Context context = new RulesDefinition.Context(); + rulesDefinition.define(context); + RulesDefinition.Repository repository = context.repository(REPOSITORY_KEY); + + assertThat(repository.name()).isEqualTo(REPOSITORY_NAME); + assertThat(repository.language()).isEqualTo("gherkin"); + assertThat(repository.rules()).hasSize(1); + + RulesDefinition.Rule customRule = repository.rule(RULE_KEY); + assertThat(customRule).isNotNull(); + assertThat(customRule.key()).isEqualTo(RULE_KEY); + assertThat(customRule.name()).isEqualTo(RULE_NAME); + + RulesDefinition.Param param = repository.rules().get(0).params().get(0); + assertThat(param.key()).isEqualTo("customParam"); + assertThat(param.description()).isEqualTo("Custom parameter"); + assertThat(param.defaultValue()).isEqualTo("Default value"); + } + + @Rule( + key = RULE_KEY, + name = RULE_NAME, + description = "desc", + tags = {"bug"}) + public class MyCustomRule extends DoubleDispatchVisitor { + @RuleProperty( + key = "customParam", + description = "Custom parameter", + defaultValue = "Default value") + public String customParam = "value"; + } + + public static class MyCustomGherkinRulesDefinition extends CustomGherkinRulesDefinition { + + @Override + public String repositoryName() { + return REPOSITORY_NAME; + } + + @Override + public String repositoryKey() { + return REPOSITORY_KEY; + } + + @Override + public Class[] checkClasses() { + return new Class[]{MyCustomRule.class}; + } + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/plugins/gherkin/api/visitors/IssueLocationTest.java b/gherkin-frontend/src/test/java/org/sonar/plugins/gherkin/api/visitors/IssueLocationTest.java new file mode 100644 index 0000000..7c456aa --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/plugins/gherkin/api/visitors/IssueLocationTest.java @@ -0,0 +1,54 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.visitors; + +import org.junit.Test; +import org.sonar.gherkin.tree.impl.InternalSyntaxToken; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.issue.IssueLocation; + +import java.io.File; +import java.util.Collections; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +public class IssueLocationTest { + + private static final File FILE = mock(File.class); + private static final String MESSAGE = "message"; + + @Test + public void several_lines_tokens() throws Exception { + String tokenValue = "blabla\\\nblabla..."; + + IssueLocation location = new IssueLocation(FILE, createToken(3, 2, tokenValue), MESSAGE); + assertThat(location.startLine()).isEqualTo(3); + assertThat(location.endLine()).isEqualTo(4); + assertThat(location.startLineOffset()).isEqualTo(2); + assertThat(location.endLineOffset()).isEqualTo(9); + assertThat(location.file()).isEqualTo(FILE); + } + + private Tree createToken(int line, int column, String tokenValue) { + return new InternalSyntaxToken(line, column, tokenValue, Collections.emptyList(), false, false); + } + +} diff --git a/gherkin-frontend/src/test/java/org/sonar/plugins/gherkin/api/visitors/IssueTest.java b/gherkin-frontend/src/test/java/org/sonar/plugins/gherkin/api/visitors/IssueTest.java new file mode 100644 index 0000000..f4c1f6e --- /dev/null +++ b/gherkin-frontend/src/test/java/org/sonar/plugins/gherkin/api/visitors/IssueTest.java @@ -0,0 +1,114 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin.api.visitors; + +import org.junit.Test; +import org.sonar.gherkin.tree.impl.InternalSyntaxToken; +import org.sonar.plugins.gherkin.api.GherkinCheck; +import org.sonar.plugins.gherkin.api.visitors.issue.FileIssue; +import org.sonar.plugins.gherkin.api.visitors.issue.IssueLocation; +import org.sonar.plugins.gherkin.api.visitors.issue.LineIssue; +import org.sonar.plugins.gherkin.api.visitors.issue.PreciseIssue; + +import java.io.File; +import java.util.Collections; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +public class IssueTest { + + private static final GherkinCheck CHECK = new DoubleDispatchVisitorCheck() { + }; + private static final String MESSAGE = "message"; + private static final InternalSyntaxToken TOKEN = new InternalSyntaxToken(5, 1, "value", Collections.emptyList(), false, false); + private static final File FILE = mock(File.class); + + @Test + public void test_file_issue() throws Exception { + FileIssue fileIssue = new FileIssue(CHECK, FILE, MESSAGE); + + assertThat(fileIssue.check()).isEqualTo(CHECK); + assertThat(fileIssue.cost()).isNull(); + assertThat(fileIssue.message()).isEqualTo(MESSAGE); + assertThat(fileIssue.file()).isEqualTo(FILE); + + fileIssue.cost(42); + assertThat(fileIssue.cost()).isEqualTo(42); + + fileIssue.secondary(FILE, TOKEN, "secondary message"); + assertThat(fileIssue.secondaryLocations()).hasSize(1); + assertThat(fileIssue.secondaryLocations().get(0).message()).isEqualTo("secondary message"); + assertThat(fileIssue.secondaryLocations().get(0).file()).isEqualTo(FILE); + + fileIssue.secondary(TOKEN, "new secondary message"); + assertThat(fileIssue.secondaryLocations()).hasSize(2); + assertThat(fileIssue.secondaryLocations().get(1).message()).isEqualTo("new secondary message"); + } + + @Test + public void test_line_issue() throws Exception { + LineIssue lineIssue = new LineIssue(CHECK, FILE, 42, MESSAGE); + + assertThat(lineIssue.check()).isEqualTo(CHECK); + assertThat(lineIssue.cost()).isNull(); + assertThat(lineIssue.message()).isEqualTo(MESSAGE); + assertThat(lineIssue.line()).isEqualTo(42); + assertThat(lineIssue.file()).isEqualTo(FILE); + + lineIssue.cost(42); + assertThat(lineIssue.cost()).isEqualTo(42); + } + + @Test(expected = IllegalArgumentException.class) + public void test_negative_line_issue() throws Exception { + new LineIssue(CHECK, FILE, -1, MESSAGE); + } + + @Test + public void test_precise_issue() throws Exception { + IssueLocation primaryLocation = new IssueLocation(FILE, TOKEN, MESSAGE); + PreciseIssue preciseIssue = new PreciseIssue(CHECK, primaryLocation); + + assertThat(preciseIssue.check()).isEqualTo(CHECK); + assertThat(preciseIssue.cost()).isNull(); + assertThat(preciseIssue.primaryLocation()).isEqualTo(primaryLocation); + assertThat(preciseIssue.secondaryLocations()).isEmpty(); + + preciseIssue.cost(42); + assertThat(preciseIssue.cost()).isEqualTo(42); + + assertThat(primaryLocation.startLine()).isEqualTo(5); + assertThat(primaryLocation.endLine()).isEqualTo(5); + assertThat(primaryLocation.startLineOffset()).isEqualTo(1); + assertThat(primaryLocation.endLineOffset()).isEqualTo(6); + assertThat(primaryLocation.message()).isEqualTo(MESSAGE); + + preciseIssue.secondary(FILE, TOKEN, "secondary message"); + assertThat(preciseIssue.secondaryLocations()).hasSize(1); + assertThat(preciseIssue.secondaryLocations().get(0).message()).isEqualTo("secondary message"); + assertThat(preciseIssue.secondaryLocations().get(0).file()).isEqualTo(FILE); + + preciseIssue.secondary(TOKEN, "new secondary message"); + assertThat(preciseIssue.secondaryLocations()).hasSize(2); + assertThat(preciseIssue.secondaryLocations().get(1).message()).isEqualTo("new secondary message"); + } + +} diff --git a/gherkin-frontend/src/test/resources/metrics/metrics-bom.feature b/gherkin-frontend/src/test/resources/metrics/metrics-bom.feature new file mode 100644 index 0000000..0d30677 --- /dev/null +++ b/gherkin-frontend/src/test/resources/metrics/metrics-bom.feature @@ -0,0 +1,30 @@ +Feature: My feature... + blaba... + blabla... + + # blabla... + #blabla... + + Background: + Given blabla... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + @tag + Scenario Outline: Scenario 2 + Given blabla... + When blabla... + Then blabla... + + Examples: + | var | + | 1 | + | 2 | + + Scenario: Scenario 3 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-frontend/src/test/resources/metrics/metrics.feature b/gherkin-frontend/src/test/resources/metrics/metrics.feature new file mode 100644 index 0000000..5e3d783 --- /dev/null +++ b/gherkin-frontend/src/test/resources/metrics/metrics.feature @@ -0,0 +1,30 @@ +Feature: My feature... + blaba... + blabla... + + # blabla... + #blabla... + + Background: + Given blabla... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + @tag + Scenario Outline: Scenario 2 + Given blabla... + When blabla... + Then blabla... + + Examples: + | var | + | 1 | + | 2 | + + Scenario: Scenario 3 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-frontend/src/test/resources/parser/empty.feature b/gherkin-frontend/src/test/resources/parser/empty.feature new file mode 100644 index 0000000..e9f5340 --- /dev/null +++ b/gherkin-frontend/src/test/resources/parser/empty.feature @@ -0,0 +1 @@ +#blabla... diff --git a/gherkin-frontend/src/test/resources/parser/parse-bom.feature b/gherkin-frontend/src/test/resources/parser/parse-bom.feature new file mode 100644 index 0000000..adc035d --- /dev/null +++ b/gherkin-frontend/src/test/resources/parser/parse-bom.feature @@ -0,0 +1,31 @@ +@mytag +Feature: My feature... + blaba... + blabla... + + # blabla... + #blabla... + + Background: + Given blabla... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + @tag + Scenario Outline: Scenario 2 + Given blabla... + When blabla... + Then blabla... + + Examples: + | var | + | 1 | + | 2 | + + Scenario: Scenario 3 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-frontend/src/test/resources/parser/parse.feature b/gherkin-frontend/src/test/resources/parser/parse.feature new file mode 100644 index 0000000..2d5ab23 --- /dev/null +++ b/gherkin-frontend/src/test/resources/parser/parse.feature @@ -0,0 +1,31 @@ +@mytag +Feature: My feature... + blaba... + blabla... + + # blabla... + #blabla... + + Background: + Given blabla... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + @tag + Scenario Outline: Scenario 2 + Given blabla... + When blabla... + Then blabla... + + Examples: + | var | + | 1 | + | 2 | + + Scenario: Scenario 3 + Given blabla... + When blabla... + Then blabla... diff --git a/gherkin-frontend/src/test/resources/parser/two-backgrounds.feature b/gherkin-frontend/src/test/resources/parser/two-backgrounds.feature new file mode 100644 index 0000000..57d3a83 --- /dev/null +++ b/gherkin-frontend/src/test/resources/parser/two-backgrounds.feature @@ -0,0 +1,33 @@ +Feature: My feature... + blaba... + blabla... + + # blabla... + #blabla... + + Background: + Given blabla... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Background: + Given blabla... + + @tag + Scenario Outline: Scenario 2 + Given blabla... + When blabla... + Then blabla... + + Examples: + | var | + | 1 | + | 2 | + + Scenario: Scenario 3 + Given blabla... + When blabla... + Then blabla... diff --git a/its/plugin/plugins/gherkin-custom-rules-plugin/pom.xml b/its/plugin/plugins/gherkin-custom-rules-plugin/pom.xml new file mode 100644 index 0000000..d362ba5 --- /dev/null +++ b/its/plugin/plugins/gherkin-custom-rules-plugin/pom.xml @@ -0,0 +1,54 @@ + + + 4.0.0 + + + com.racodond.sonarqube.plugin.gherkin + gherkin-its-plugin-plugins + 1.0-SNAPSHOT + + + gherkin-custom-rules-plugin + sonar-plugin + + SonarQube Gherkin Analyzer :: Integration Tests :: Plugin :: Plugins :: Custom Rules + + + + org.sonarsource.sonarqube + sonar-plugin-api + provided + + + com.racodond.sonarqube.plugin.gherkin + sonar-gherkin-plugin + sonar-plugin + + + + + + + org.sonarsource.sonar-packaging-maven-plugin + sonar-packaging-maven-plugin + 1.15 + true + + org.sonar.gherkin.MyGherkinCustomRulesPlugin + gherkin + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + + + diff --git a/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/java/org/sonar/gherkin/MyGherkinCustomRulesDefinition.java b/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/java/org/sonar/gherkin/MyGherkinCustomRulesDefinition.java new file mode 100644 index 0000000..91ac7e9 --- /dev/null +++ b/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/java/org/sonar/gherkin/MyGherkinCustomRulesDefinition.java @@ -0,0 +1,57 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin; + +import org.sonar.gherkin.checks.ForbiddenTagCheck; +import org.sonar.gherkin.checks.ForbiddenNameContentCheck; +import org.sonar.plugins.gherkin.api.CustomGherkinRulesDefinition; + +/** + * Extension point to define a Gherkin rule repository. + */ +public class MyGherkinCustomRulesDefinition extends CustomGherkinRulesDefinition { + + /** + * Provide the repository name. + */ + @Override + public String repositoryName() { + return "My Gherkin Custom Repository"; + } + + /** + * Provide the repository key. + */ + @Override + public String repositoryKey() { + return "custom-gherkin"; + } + + /** + * Provide the list of classes implementing rules. + */ + @Override + public Class[] checkClasses() { + return new Class[]{ + ForbiddenTagCheck.class, + ForbiddenNameContentCheck.class + }; + } +} diff --git a/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/java/org/sonar/gherkin/MyGherkinCustomRulesPlugin.java b/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/java/org/sonar/gherkin/MyGherkinCustomRulesPlugin.java new file mode 100644 index 0000000..6dcd9ca --- /dev/null +++ b/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/java/org/sonar/gherkin/MyGherkinCustomRulesPlugin.java @@ -0,0 +1,37 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin; + +import com.google.common.collect.ImmutableList; +import org.sonar.api.Plugin; + +/** + * Extension point to define a SonarQube plugin. + */ +public class MyGherkinCustomRulesPlugin implements Plugin { + + @Override + public void define(Context context) { + context.addExtensions( + ImmutableList.of( + MyGherkinCustomRulesDefinition.class)); + } + +} diff --git a/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/java/org/sonar/gherkin/checks/ForbiddenNameContentCheck.java b/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/java/org/sonar/gherkin/checks/ForbiddenNameContentCheck.java new file mode 100644 index 0000000..2747374 --- /dev/null +++ b/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/java/org/sonar/gherkin/checks/ForbiddenNameContentCheck.java @@ -0,0 +1,54 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import com.google.common.collect.ImmutableList; +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.plugins.gherkin.api.tree.NameTree; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.SubscriptionVisitorCheck; +import org.sonar.squidbridge.annotations.SqaleConstantRemediation; + +import java.util.List; + +@Rule( + key = "forbidden-name-content", + priority = Priority.CRITICAL, + name = "'WTF' should never appear in name", + tags = {"bug"}) +@SqaleConstantRemediation("5min") +public class ForbiddenNameContentCheck extends SubscriptionVisitorCheck { + + private static final String FORBIDDEN_NAME_CONTENT = "wtf"; + + @Override + public List nodesToVisit() { + return ImmutableList.of(Tree.Kind.NAME); + } + + @Override + public void visitNode(Tree tree) { + if (((NameTree) tree).text().toLowerCase().contains(FORBIDDEN_NAME_CONTENT)) { + addPreciseIssue(tree, "Remove this usage of \"WTF\"."); + } + } + +} diff --git a/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/java/org/sonar/gherkin/checks/ForbiddenTagCheck.java b/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/java/org/sonar/gherkin/checks/ForbiddenTagCheck.java new file mode 100644 index 0000000..278ef40 --- /dev/null +++ b/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/java/org/sonar/gherkin/checks/ForbiddenTagCheck.java @@ -0,0 +1,50 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import com.google.common.collect.ImmutableSet; +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.plugins.gherkin.api.tree.TagTree; +import org.sonar.plugins.gherkin.api.visitors.DoubleDispatchVisitorCheck; +import org.sonar.squidbridge.annotations.SqaleConstantRemediation; + +import java.util.Set; + +@Rule( + key = "forbidden-tag", + priority = Priority.MAJOR, + name = "Forbidden tag should not be used", + tags = {"convention"}) +@SqaleConstantRemediation("5min") +public class ForbiddenTagCheck extends DoubleDispatchVisitorCheck { + + private static final Set FORBIDDEN_TAGS = ImmutableSet.of("foo", "bar"); + + @Override + public void visitTag(TagTree tree) { + if (FORBIDDEN_TAGS.contains(tree.text().toLowerCase())) { + addPreciseIssue(tree, "Remove this usage of the forbidden \"" + tree.text() + "\" tag."); + } + // super method must be called in order to visit what is under the key node in the syntax tree + super.visitTag(tree); + } + +} diff --git a/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/java/org/sonar/gherkin/checks/package-info.java b/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/java/org/sonar/gherkin/checks/package-info.java new file mode 100644 index 0000000..9c4e378 --- /dev/null +++ b/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/java/org/sonar/gherkin/checks/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +@ParametersAreNonnullByDefault +package org.sonar.gherkin.checks; + +import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/java/org/sonar/gherkin/package-info.java b/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/java/org/sonar/gherkin/package-info.java new file mode 100644 index 0000000..9c82628 --- /dev/null +++ b/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/java/org/sonar/gherkin/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +@ParametersAreNonnullByDefault +package org.sonar.gherkin; + +import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/resources/org/sonar/l10n/gherkin/rules/custom-gherkin/forbidden-name-content.html b/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/resources/org/sonar/l10n/gherkin/rules/custom-gherkin/forbidden-name-content.html new file mode 100644 index 0000000..cba95e8 --- /dev/null +++ b/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/resources/org/sonar/l10n/gherkin/rules/custom-gherkin/forbidden-name-content.html @@ -0,0 +1,3 @@ +

+ "WTF" should not appear in names. +

diff --git a/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/resources/org/sonar/l10n/gherkin/rules/custom-gherkin/forbidden-tag.html b/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/resources/org/sonar/l10n/gherkin/rules/custom-gherkin/forbidden-tag.html new file mode 100644 index 0000000..df91588 --- /dev/null +++ b/its/plugin/plugins/gherkin-custom-rules-plugin/src/main/resources/org/sonar/l10n/gherkin/rules/custom-gherkin/forbidden-tag.html @@ -0,0 +1,7 @@ +

+ The following tags should not be used: +

+
    +
  • foo
  • +
  • bar
  • +
diff --git a/its/plugin/plugins/gherkin-custom-rules-plugin/src/test/java/org/sonar/gherkin/MyGherkinCustomRulesDefinitionTest.java b/its/plugin/plugins/gherkin-custom-rules-plugin/src/test/java/org/sonar/gherkin/MyGherkinCustomRulesDefinitionTest.java new file mode 100644 index 0000000..9fe725b --- /dev/null +++ b/its/plugin/plugins/gherkin-custom-rules-plugin/src/test/java/org/sonar/gherkin/MyGherkinCustomRulesDefinitionTest.java @@ -0,0 +1,49 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin; + +import org.junit.Test; +import org.sonar.api.server.rule.RulesDefinition; +import org.sonar.check.Rule; +import org.sonar.gherkin.checks.ForbiddenTagCheck; + +import static org.fest.assertions.Assertions.assertThat; + +public class MyGherkinCustomRulesDefinitionTest { + + @Test + public void test() { + MyGherkinCustomRulesDefinition rulesDefinition = new MyGherkinCustomRulesDefinition(); + + RulesDefinition.Context context = new RulesDefinition.Context(); + rulesDefinition.define(context); + + RulesDefinition.Repository repository = context.repository("custom-gherkin"); + + assertThat(repository.name()).isEqualTo("My Gherkin Custom Repository"); + assertThat(repository.language()).isEqualTo("gherkin"); + assertThat(repository.rules()).hasSize(2); + + RulesDefinition.Rule forbiddenKeysRule = repository.rule(ForbiddenTagCheck.class.getAnnotation(Rule.class).key()); + assertThat(forbiddenKeysRule).isNotNull(); + assertThat(forbiddenKeysRule.name()).isEqualTo(ForbiddenTagCheck.class.getAnnotation(Rule.class).name()); + } + +} diff --git a/its/plugin/plugins/gherkin-custom-rules-plugin/src/test/java/org/sonar/gherkin/MyGherkinCustomRulesPluginTest.java b/its/plugin/plugins/gherkin-custom-rules-plugin/src/test/java/org/sonar/gherkin/MyGherkinCustomRulesPluginTest.java new file mode 100644 index 0000000..82b9e80 --- /dev/null +++ b/its/plugin/plugins/gherkin-custom-rules-plugin/src/test/java/org/sonar/gherkin/MyGherkinCustomRulesPluginTest.java @@ -0,0 +1,45 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin; + +import org.junit.Test; +import org.sonar.api.Plugin; +import org.sonar.api.utils.Version; + +import static org.fest.assertions.Assertions.assertThat; + +public class MyGherkinCustomRulesPluginTest { + + @Test + public void should_get_the_right_version() { + Plugin.Context context = new Plugin.Context(Version.create(5, 6)); + new MyGherkinCustomRulesPlugin().define(context); + assertThat(context.getSonarQubeVersion().major()).isEqualTo(5); + assertThat(context.getSonarQubeVersion().minor()).isEqualTo(6); + } + + @Test + public void should_get_the_right_number_of_extensions() { + Plugin.Context context = new Plugin.Context(Version.create(5, 6)); + new MyGherkinCustomRulesPlugin().define(context); + assertThat(context.getExtensions()).hasSize(1); + } + +} diff --git a/its/plugin/plugins/gherkin-custom-rules-plugin/src/test/java/org/sonar/gherkin/checks/ForbiddenNameContentCheckTest.java b/its/plugin/plugins/gherkin-custom-rules-plugin/src/test/java/org/sonar/gherkin/checks/ForbiddenNameContentCheckTest.java new file mode 100644 index 0000000..305cacc --- /dev/null +++ b/its/plugin/plugins/gherkin-custom-rules-plugin/src/test/java/org/sonar/gherkin/checks/ForbiddenNameContentCheckTest.java @@ -0,0 +1,34 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.junit.Test; +import org.sonar.gherkin.checks.verifier.GherkinCheckVerifier; + +import java.io.File; + +public class ForbiddenNameContentCheckTest { + + @Test + public void test() { + GherkinCheckVerifier.verify(new ForbiddenNameContentCheck(), new File("src/test/resources/checks/forbidden-name-content.feature")); + } + +} diff --git a/its/plugin/plugins/gherkin-custom-rules-plugin/src/test/java/org/sonar/gherkin/checks/ForbiddenTagCheckTest.java b/its/plugin/plugins/gherkin-custom-rules-plugin/src/test/java/org/sonar/gherkin/checks/ForbiddenTagCheckTest.java new file mode 100644 index 0000000..6efd6bd --- /dev/null +++ b/its/plugin/plugins/gherkin-custom-rules-plugin/src/test/java/org/sonar/gherkin/checks/ForbiddenTagCheckTest.java @@ -0,0 +1,37 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.checks; + +import org.junit.Test; +import org.sonar.gherkin.checks.verifier.GherkinCheckVerifier; + +import java.io.File; + +public class ForbiddenTagCheckTest { + + @Test + public void test() { + GherkinCheckVerifier.issues(new ForbiddenTagCheck(), new File("src/test/resources/checks/forbidden-tag.feature")) + .next().atLine(1).withMessage("Remove this usage of the forbidden \"bar\" tag.") + .next().atLine(4).withMessage("Remove this usage of the forbidden \"foo\" tag.") + .noMore(); + } + +} diff --git a/its/plugin/plugins/gherkin-custom-rules-plugin/src/test/resources/checks/forbidden-name-content.feature b/its/plugin/plugins/gherkin-custom-rules-plugin/src/test/resources/checks/forbidden-name-content.feature new file mode 100644 index 0000000..00bad92 --- /dev/null +++ b/its/plugin/plugins/gherkin-custom-rules-plugin/src/test/resources/checks/forbidden-name-content.feature @@ -0,0 +1,13 @@ +# Noncompliant [[sc=10;ec=27]] {{Remove this usage of "WTF".}} +Feature: WTF My feature... + + Scenario: Scenario #1 + Given blabla... + When blabla... + Then blabla... + + # Noncompliant [[sc=13;ec=28]] {{Remove this usage of "WTF".}} + Scenario: Scenario WTF #2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/plugin/plugins/gherkin-custom-rules-plugin/src/test/resources/checks/forbidden-tag.feature b/its/plugin/plugins/gherkin-custom-rules-plugin/src/test/resources/checks/forbidden-tag.feature new file mode 100644 index 0000000..d09bb99 --- /dev/null +++ b/its/plugin/plugins/gherkin-custom-rules-plugin/src/test/resources/checks/forbidden-tag.feature @@ -0,0 +1,14 @@ +@bar +Feature: My feature... + + @foo + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + @mytag + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/plugin/plugins/pom.xml b/its/plugin/plugins/pom.xml new file mode 100644 index 0000000..9e2aecb --- /dev/null +++ b/its/plugin/plugins/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + + com.racodond.sonarqube.plugin.gherkin + gherkin-its-plugin + 1.0-SNAPSHOT + + + gherkin-its-plugin-plugins + SonarQube Gherkin Analyzer :: Integration Tests :: Plugin :: Plugins + pom + + + gherkin-custom-rules-plugin + + + diff --git a/its/plugin/pom.xml b/its/plugin/pom.xml new file mode 100644 index 0000000..77b99bc --- /dev/null +++ b/its/plugin/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + + + com.racodond.sonarqube.plugin.gherkin + gherkin-its + 1.0-SNAPSHOT + + + gherkin-its-plugin + SonarQube Gherkin Analyzer :: Integration Tests :: Plugin + pom + + + plugins + tests + + + diff --git a/its/plugin/projects/custom-rules/src/forbidden-name-content.feature b/its/plugin/projects/custom-rules/src/forbidden-name-content.feature new file mode 100644 index 0000000..1e4b933 --- /dev/null +++ b/its/plugin/projects/custom-rules/src/forbidden-name-content.feature @@ -0,0 +1,11 @@ +Feature: My feature... + + Scenario: Scenario #1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario WTF #2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/plugin/projects/custom-rules/src/forbidden-tag.feature b/its/plugin/projects/custom-rules/src/forbidden-tag.feature new file mode 100644 index 0000000..e2a355d --- /dev/null +++ b/its/plugin/projects/custom-rules/src/forbidden-tag.feature @@ -0,0 +1,12 @@ +@bar +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/plugin/projects/issues/src/dir/file2.feature b/its/plugin/projects/issues/src/dir/file2.feature new file mode 100644 index 0000000..3c08d07 --- /dev/null +++ b/its/plugin/projects/issues/src/dir/file2.feature @@ -0,0 +1,23 @@ +@mytag +Feature: My feature... + + # blabla... + # blabla... + @nrt + Scenario: Scenario #1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario #2 + Given blabla... + When blabla... + Then blabla... + + Scenario Outline: Scenario #2 + Given blabla... + When blabla... + Then blabla... + + Examples: + |d1| diff --git a/its/plugin/projects/issues/src/file1.feature b/its/plugin/projects/issues/src/file1.feature new file mode 100644 index 0000000..7fd41df --- /dev/null +++ b/its/plugin/projects/issues/src/file1.feature @@ -0,0 +1,18 @@ +@mytag @nrt +Feature: My feature... + + # blabla... + # blabla... + Scenario: Scenario #1 + Given blabla... + When blabla... + Then blabla... + + @nrt + Scenario Outline: Scenario #3 + Given blabla... + When blabla... + Then blabla... + + Examples: + |d1| diff --git a/its/plugin/projects/metrics/src/dir/file2.feature b/its/plugin/projects/metrics/src/dir/file2.feature new file mode 100644 index 0000000..23ded22 --- /dev/null +++ b/its/plugin/projects/metrics/src/dir/file2.feature @@ -0,0 +1,21 @@ +Feature: My feature... + + # blabla... + # blabla... + Scenario: Scenario #1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario #2 + Given blabla... + When blabla... + Then blabla... + + Scenario Outline: Scenario #2 + Given blabla... + When blabla... + Then blabla... + + Examples: + |d1| diff --git a/its/plugin/projects/metrics/src/file1.feature b/its/plugin/projects/metrics/src/file1.feature new file mode 100644 index 0000000..a95a69d --- /dev/null +++ b/its/plugin/projects/metrics/src/file1.feature @@ -0,0 +1,16 @@ +Feature: My feature... + + # blabla... + # blabla... + Scenario: Scenario #1 + Given blabla... + When blabla... + Then blabla... + + Scenario Outline: Scenario #3 + Given blabla... + When blabla... + Then blabla... + + Examples: + |d1| diff --git a/its/plugin/tests/pom.xml b/its/plugin/tests/pom.xml new file mode 100644 index 0000000..1f20bd2 --- /dev/null +++ b/its/plugin/tests/pom.xml @@ -0,0 +1,54 @@ + + + 4.0.0 + + + com.racodond.sonarqube.plugin.gherkin + gherkin-its-plugin + 1.0-SNAPSHOT + + + gherkin-its-plugin-tests + SonarQube Gherkin Analyzer :: Integration Tests :: Plugin :: Tests + + + + org.sonarsource.sonarqube + sonar-plugin-api + provided + + + org.sonarsource.orchestrator + sonar-orchestrator + test + + + org.easytesting + fest-assert + test + + + junit + junit + test + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + org/sonar/gherkin/its/Tests.java + + + + + + + + diff --git a/its/plugin/tests/src/test/java/org/sonar/gherkin/its/CustomRulesTest.java b/its/plugin/tests/src/test/java/org/sonar/gherkin/its/CustomRulesTest.java new file mode 100644 index 0000000..3ae7ddd --- /dev/null +++ b/its/plugin/tests/src/test/java/org/sonar/gherkin/its/CustomRulesTest.java @@ -0,0 +1,85 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.its; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.SonarScanner; +import org.junit.BeforeClass; +import org.junit.Test; +import org.sonar.wsclient.issue.Issue; +import org.sonar.wsclient.issue.IssueClient; +import org.sonar.wsclient.issue.IssueQuery; + +import java.io.File; +import java.util.List; + +import static org.fest.assertions.Assertions.assertThat; + +public class CustomRulesTest { + + @org.junit.ClassRule + public static Orchestrator orchestrator = Tests.ORCHESTRATOR; + + private static final String PROJECT_KEY = "custom-rules"; + private static IssueClient issueClient; + + @BeforeClass + public static void init() { + orchestrator.resetData(); + + SonarScanner build = Tests.createSonarScannerBuild() + .setProjectDir(new File("../projects/custom-rules/")) + .setProjectKey(PROJECT_KEY) + .setProjectName(PROJECT_KEY); + + orchestrator.getServer().provisionProject(PROJECT_KEY, PROJECT_KEY); + Tests.setProfile("gherkin-custom-rules-profile", PROJECT_KEY); + orchestrator.executeBuild(build); + + issueClient = orchestrator.getServer().wsClient().issueClient(); + } + + @Test + public void issues_against_rule_forbidden_tag() { + List issues = issueClient.find(IssueQuery.create().rules("custom-gherkin:forbidden-tag")).list(); + + assertThat(issues).hasSize(1); + + Issue issue = issues.get(0); + assertThat(issue.line()).isEqualTo(1); + assertThat(issue.message()).isEqualTo("Remove this usage of the forbidden \"bar\" tag."); + assertThat(issue.debt()).isEqualTo("5min"); + assertThat(issue.severity()).isEqualTo("MAJOR"); + } + + @Test + public void issues_against_rule_forbidden_name_content() { + List issues = issueClient.find(IssueQuery.create().rules("custom-gherkin:forbidden-name-content")).list(); + + assertThat(issues).hasSize(1); + + Issue issue = issues.get(0); + assertThat(issue.line()).isEqualTo(8); + assertThat(issue.message()).isEqualTo("Remove this usage of \"WTF\"."); + assertThat(issue.debt()).isEqualTo("5min"); + assertThat(issue.severity()).isEqualTo("CRITICAL"); + } + +} diff --git a/its/plugin/tests/src/test/java/org/sonar/gherkin/its/IssuesTest.java b/its/plugin/tests/src/test/java/org/sonar/gherkin/its/IssuesTest.java new file mode 100644 index 0000000..4930dc3 --- /dev/null +++ b/its/plugin/tests/src/test/java/org/sonar/gherkin/its/IssuesTest.java @@ -0,0 +1,69 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.its; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.SonarScanner; +import org.junit.Test; +import org.sonar.wsclient.issue.Issue; +import org.sonar.wsclient.issue.IssueQuery; + +import java.io.File; +import java.util.List; + +import static org.fest.assertions.Assertions.assertThat; + +public class IssuesTest { + + @org.junit.ClassRule + public static Orchestrator orchestrator = Tests.ORCHESTRATOR; + + private static final String PROJECT_KEY = "issues"; + + @org.junit.BeforeClass + public static void init() { + orchestrator.resetData(); + + SonarScanner build = Tests.createSonarScannerBuild() + .setProjectDir(new File("../projects/issues/")) + .setProjectKey(PROJECT_KEY) + .setProjectName(PROJECT_KEY); + + orchestrator.getServer().provisionProject(PROJECT_KEY, PROJECT_KEY); + Tests.setProfile("allowed-tags-only-profile", PROJECT_KEY); + orchestrator.executeBuild(build); + } + + @Test + public void issue_for_rule_allowed_tags() { + List issues = orchestrator.getServer().wsClient().issueClient().find(IssueQuery.create()).list(); + + assertThat(issues).hasSize(2); + + assertThat(issues.get(0).ruleKey()).isEqualTo("gherkin:allowed-tags"); + assertThat(issues.get(0).severity()).isEqualTo("MAJOR"); + assertThat(issues.get(0).line()).isEqualTo(1); + + assertThat(issues.get(1).ruleKey()).isEqualTo("gherkin:allowed-tags"); + assertThat(issues.get(1).severity()).isEqualTo("MAJOR"); + assertThat(issues.get(1).line()).isEqualTo(1); + } + +} diff --git a/its/plugin/tests/src/test/java/org/sonar/gherkin/its/MetricsTest.java b/its/plugin/tests/src/test/java/org/sonar/gherkin/its/MetricsTest.java new file mode 100644 index 0000000..1da719f --- /dev/null +++ b/its/plugin/tests/src/test/java/org/sonar/gherkin/its/MetricsTest.java @@ -0,0 +1,185 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.its; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.SonarScanner; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.sonar.wsclient.Sonar; +import org.sonar.wsclient.services.Measure; +import org.sonar.wsclient.services.Resource; +import org.sonar.wsclient.services.ResourceQuery; + +import java.io.File; + +import static org.fest.assertions.Assertions.assertThat; + +public class MetricsTest { + + @ClassRule + public static Orchestrator orchestrator = Tests.ORCHESTRATOR; + + private static final String PROJECT_KEY = "metrics"; + private static Sonar wsClient; + + @BeforeClass + public static void init() { + orchestrator.resetData(); + + SonarScanner build = Tests.createSonarScannerBuild() + .setProjectDir(new File("../projects/metrics/")) + .setProjectKey(PROJECT_KEY) + .setProjectName(PROJECT_KEY); + + orchestrator.getServer().provisionProject(PROJECT_KEY, PROJECT_KEY); + Tests.setProfile("empty-profile", PROJECT_KEY); + orchestrator.executeBuild(build); + + wsClient = orchestrator.getServer().getWsClient(); + } + + @Test + public void project_measures() { + assertThat(getProjectMeasure("lines").getIntValue()).isEqualTo(39); + assertThat(getProjectMeasure("ncloc").getIntValue()).isEqualTo(26); + assertThat(getProjectMeasure("classes").getIntValue()).isEqualTo(2); + assertThat(getProjectMeasure("functions").getIntValue()).isEqualTo(5); + assertThat(getProjectMeasure("statements").getIntValue()).isEqualTo(15); + assertThat(getProjectMeasure("files").getIntValue()).isEqualTo(2); + assertThat(getProjectMeasure("directories").getIntValue()).isEqualTo(2); + + assertThat(getProjectMeasure("comment_lines").getIntValue()).isEqualTo(4); + assertThat(getProjectMeasure("comment_lines_density").getValue()).isEqualTo(13.3); + + assertThat(getProjectMeasure("complexity")).isNull(); + assertThat(getProjectMeasure("complexity_in_functions")).isNull(); + assertThat(getProjectMeasure("function_complexity")).isNull(); + assertThat(getProjectMeasure("function_complexity_distribution")).isNull(); + assertThat(getProjectMeasure("file_complexity")).isNull(); + + assertThat(getProjectMeasure("duplicated_lines").getIntValue()).isEqualTo(0); + assertThat(getProjectMeasure("duplicated_files").getIntValue()).isEqualTo(0); + assertThat(getProjectMeasure("duplicated_blocks").getIntValue()).isEqualTo(0); + assertThat(getProjectMeasure("duplicated_lines_density").getValue()).isEqualTo(0.0); + + assertThat(getProjectMeasure("violations").getIntValue()).isEqualTo(0); + } + + @Test + public void dir_measures() { + assertThat(getDirMeasure("lines").getIntValue()).isEqualTo(22); + assertThat(getDirMeasure("ncloc").getIntValue()).isEqualTo(15); + assertThat(getDirMeasure("classes").getIntValue()).isEqualTo(1); + assertThat(getDirMeasure("functions").getIntValue()).isEqualTo(3); + assertThat(getDirMeasure("statements").getIntValue()).isEqualTo(9); + assertThat(getDirMeasure("files").getIntValue()).isEqualTo(1); + assertThat(getDirMeasure("directories").getIntValue()).isEqualTo(1); + + assertThat(getDirMeasure("comment_lines").getIntValue()).isEqualTo(2); + assertThat(getDirMeasure("comment_lines_density").getValue()).isEqualTo(11.8); + + assertThat(getDirMeasure("complexity")).isNull(); + assertThat(getDirMeasure("complexity_in_functions")).isNull(); + assertThat(getDirMeasure("function_complexity")).isNull(); + assertThat(getDirMeasure("function_complexity_distribution")).isNull(); + assertThat(getDirMeasure("file_complexity")).isNull(); + + assertThat(getDirMeasure("duplicated_lines").getIntValue()).isEqualTo(0); + assertThat(getDirMeasure("duplicated_files").getIntValue()).isEqualTo(0); + assertThat(getDirMeasure("duplicated_blocks").getIntValue()).isEqualTo(0); + assertThat(getDirMeasure("duplicated_lines_density").getValue()).isEqualTo(0.0); + + assertThat(getDirMeasure("violations").getIntValue()).isEqualTo(0); + } + + @Test + public void file1_measures() { + assertThat(getFile1Measure("lines").getIntValue()).isEqualTo(17); + assertThat(getFile1Measure("ncloc").getIntValue()).isEqualTo(11); + assertThat(getFile1Measure("classes").getIntValue()).isEqualTo(1); + assertThat(getFile1Measure("functions").getIntValue()).isEqualTo(2); + assertThat(getFile1Measure("statements").getIntValue()).isEqualTo(6); + + assertThat(getFile1Measure("comment_lines").getIntValue()).isEqualTo(2); + assertThat(getFile1Measure("comment_lines_density").getValue()).isEqualTo(15.4); + + assertThat(getFile1Measure("complexity")).isNull(); + assertThat(getFile1Measure("complexity_in_functions")).isNull(); + assertThat(getFile1Measure("function_complexity")).isNull(); + assertThat(getFile1Measure("function_complexity_distribution")).isNull(); + assertThat(getFile1Measure("file_complexity")).isNull(); + + assertThat(getFile1Measure("duplicated_lines")).isNull(); + assertThat(getFile1Measure("duplicated_blocks")).isNull(); + assertThat(getFile1Measure("duplicated_lines_density")).isNull(); + + assertThat(getFile1Measure("violations")).isNull(); + } + + @Test + public void file2_measures() { + assertThat(getFile2Measure("lines").getIntValue()).isEqualTo(22); + assertThat(getFile2Measure("ncloc").getIntValue()).isEqualTo(15); + assertThat(getFile2Measure("classes").getIntValue()).isEqualTo(1); + assertThat(getFile2Measure("functions").getIntValue()).isEqualTo(3); + assertThat(getFile2Measure("statements").getIntValue()).isEqualTo(9); + + assertThat(getFile2Measure("comment_lines").getIntValue()).isEqualTo(2); + assertThat(getFile2Measure("comment_lines_density").getValue()).isEqualTo(11.8); + + assertThat(getFile2Measure("complexity")).isNull(); + assertThat(getFile2Measure("complexity_in_functions")).isNull(); + assertThat(getFile2Measure("function_complexity")).isNull(); + assertThat(getFile2Measure("function_complexity_distribution")).isNull(); + assertThat(getFile2Measure("file_complexity")).isNull(); + + assertThat(getFile2Measure("duplicated_lines")).isNull(); + assertThat(getFile2Measure("duplicated_blocks")).isNull(); + assertThat(getFile2Measure("duplicated_lines_density")).isNull(); + + assertThat(getFile2Measure("violations")).isNull(); + } + + private Measure getProjectMeasure(String metricKey) { + Resource resource = wsClient.find(ResourceQuery.createForMetrics(PROJECT_KEY, metricKey)); + return resource == null ? null : resource.getMeasure(metricKey); + } + + private Measure getDirMeasure(String metricKey) { + Resource resource = wsClient.find(ResourceQuery.createForMetrics(PROJECT_KEY + ":src/dir", metricKey)); + return resource == null ? null : resource.getMeasure(metricKey); + } + + private Measure getFileMeasure(String metricKey, String fileKey) { + Resource resource = wsClient.find(ResourceQuery.createForMetrics(fileKey, metricKey)); + return resource == null ? null : resource.getMeasure(metricKey); + } + + private Measure getFile1Measure(String metricKey) { + return getFileMeasure(metricKey, PROJECT_KEY + ":src/file1.feature"); + } + + private Measure getFile2Measure(String metricKey) { + return getFileMeasure(metricKey, PROJECT_KEY + ":src/dir/file2.feature"); + } + +} diff --git a/its/plugin/tests/src/test/java/org/sonar/gherkin/its/Tests.java b/its/plugin/tests/src/test/java/org/sonar/gherkin/its/Tests.java new file mode 100644 index 0000000..03e8169 --- /dev/null +++ b/its/plugin/tests/src/test/java/org/sonar/gherkin/its/Tests.java @@ -0,0 +1,59 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.its; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.SonarScanner; +import com.sonar.orchestrator.locator.FileLocation; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +import java.io.File; + +@RunWith(Suite.class) +@Suite.SuiteClasses({ + CustomRulesTest.class, + MetricsTest.class, + IssuesTest.class, +}) +public class Tests { + + @org.junit.ClassRule + public static final Orchestrator ORCHESTRATOR = Orchestrator.builderEnv() + .addPlugin(FileLocation.byWildcardFilename(new File("../../../sonar-gherkin-plugin/target"), "sonar-gherkin-plugin-*-SNAPSHOT.jar")) + .addPlugin(FileLocation.byWildcardFilename(new File("../plugins/gherkin-custom-rules-plugin/target"), "gherkin-custom-rules-plugin-*-SNAPSHOT.jar")) + .restoreProfileAtStartup(FileLocation.ofClasspath("/org/sonar/gherkin/its/profiles/allowed-tags-only-profile.xml")) + .restoreProfileAtStartup(FileLocation.ofClasspath("/org/sonar/gherkin/its/profiles/empty-profile.xml")) + .restoreProfileAtStartup(FileLocation.ofClasspath("/org/sonar/gherkin/its/profiles/gherkin-custom-rules-profile.xml")) + .build(); + + public static SonarScanner createSonarScannerBuild() { + SonarScanner build = SonarScanner.create(); + build.setProjectVersion("1.0"); + build.setSourceEncoding("UTF-8"); + build.setSourceDirs("src"); + return build; + } + + public static void setProfile(String profileName, String projectKey) { + ORCHESTRATOR.getServer().associateProjectToQualityProfile(projectKey, "gherkin", profileName); + } + +} diff --git a/its/plugin/tests/src/test/resources/org/sonar/gherkin/its/profiles/allowed-tags-only-profile.xml b/its/plugin/tests/src/test/resources/org/sonar/gherkin/its/profiles/allowed-tags-only-profile.xml new file mode 100644 index 0000000..aca94cb --- /dev/null +++ b/its/plugin/tests/src/test/resources/org/sonar/gherkin/its/profiles/allowed-tags-only-profile.xml @@ -0,0 +1,16 @@ + + + allowed-tags-only-profile + gherkin + + + gherkin + allowed-tags + MAJOR + + allowedTags + smoke,nrt + + + + diff --git a/its/plugin/tests/src/test/resources/org/sonar/gherkin/its/profiles/empty-profile.xml b/its/plugin/tests/src/test/resources/org/sonar/gherkin/its/profiles/empty-profile.xml new file mode 100644 index 0000000..5cde9e2 --- /dev/null +++ b/its/plugin/tests/src/test/resources/org/sonar/gherkin/its/profiles/empty-profile.xml @@ -0,0 +1,6 @@ + + + empty-profile + gherkin + + diff --git a/its/plugin/tests/src/test/resources/org/sonar/gherkin/its/profiles/gherkin-custom-rules-profile.xml b/its/plugin/tests/src/test/resources/org/sonar/gherkin/its/profiles/gherkin-custom-rules-profile.xml new file mode 100644 index 0000000..58200a8 --- /dev/null +++ b/its/plugin/tests/src/test/resources/org/sonar/gherkin/its/profiles/gherkin-custom-rules-profile.xml @@ -0,0 +1,19 @@ + + + gherkin-custom-rules-profile + gherkin + + + custom-gherkin + forbidden-tag + MAJOR + + + + custom-gherkin + forbidden-name-content + CRITICAL + + + + diff --git a/its/pom.xml b/its/pom.xml new file mode 100644 index 0000000..7eef9b4 --- /dev/null +++ b/its/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + + + com.racodond.sonarqube.plugin.gherkin + gherkin + 1.0-SNAPSHOT + + + gherkin-its + SonarQube Gherkin Analyzer :: Integration Tests + pom + + Integration tests of the SonarQube Gherkin Analyzer + 2016 + + David RACODON + mailto:david.racodon@gmail.com + + + + GNU LGPL 3 + http://www.gnu.org/licenses/lgpl.txt + repo + + + + + + racodond + David RACODON + david.racodon@gmail.com + https://www.linkedin.com/pub/david-racodon/11/62/283 + + + + + plugin + ruling + + + diff --git a/its/ruling/pom.xml b/its/ruling/pom.xml new file mode 100644 index 0000000..6e505eb --- /dev/null +++ b/its/ruling/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + + com.racodond.sonarqube.plugin.gherkin + gherkin-its + 1.0-SNAPSHOT + + + gherkin-its-ruling + SonarQube Gherkin Analyzer :: Integration Tests :: Ruling + pom + + + tests + + + diff --git a/its/ruling/projects/custom/allowed-tags/allowed-tags-custom.feature b/its/ruling/projects/custom/allowed-tags/allowed-tags-custom.feature new file mode 100644 index 0000000..dce52ff --- /dev/null +++ b/its/ruling/projects/custom/allowed-tags/allowed-tags-custom.feature @@ -0,0 +1,16 @@ +# Noncompliant [[sc=1;ec=5]] {{Remove this tag that is not in the whitelist.}} +@nrt +Feature: My feature... + + # Noncompliant [[sc=3;ec=23]] {{Remove this tag that is not in the whitelist.}} + @non-regression-test + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + @mytag @yourtag + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/allowed-tags/allowed-tags-default.feature b/its/ruling/projects/custom/allowed-tags/allowed-tags-default.feature new file mode 100644 index 0000000..ed29374 --- /dev/null +++ b/its/ruling/projects/custom/allowed-tags/allowed-tags-default.feature @@ -0,0 +1,16 @@ +# Noncompliant [[sc=1;ec=7]] {{Remove this tag that is not in the whitelist.}} +@mytag +Feature: My feature... + + # Noncompliant [[sc=3;ec=23]] {{Remove this tag that is not in the whitelist.}} + @non-regression-test + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + @nrt @smoke + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/bom/utf16-be.feature b/its/ruling/projects/custom/bom/utf16-be.feature new file mode 100644 index 0000000..01ee708 Binary files /dev/null and b/its/ruling/projects/custom/bom/utf16-be.feature differ diff --git a/its/ruling/projects/custom/bom/utf16-le.feature b/its/ruling/projects/custom/bom/utf16-le.feature new file mode 100644 index 0000000..a5054ff Binary files /dev/null and b/its/ruling/projects/custom/bom/utf16-le.feature differ diff --git a/its/ruling/projects/custom/bom/utf8-with-bom.feature b/its/ruling/projects/custom/bom/utf8-with-bom.feature new file mode 100644 index 0000000..0f000c3 --- /dev/null +++ b/its/ruling/projects/custom/bom/utf8-with-bom.feature @@ -0,0 +1,12 @@ +# Noncompliant [[sl=0]] {{Remove the Byte Order Mark (BOM).}} +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/bom/utf8.feature b/its/ruling/projects/custom/bom/utf8.feature new file mode 100644 index 0000000..197f983 --- /dev/null +++ b/its/ruling/projects/custom/bom/utf8.feature @@ -0,0 +1,11 @@ +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/comment-convention.feature b/its/ruling/projects/custom/comment-convention.feature new file mode 100644 index 0000000..21639b3 --- /dev/null +++ b/its/ruling/projects/custom/comment-convention.feature @@ -0,0 +1,12 @@ +Feature: My feature... +#My comments +# My comments + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/comment-regular-expression.feature b/its/ruling/projects/custom/comment-regular-expression.feature new file mode 100644 index 0000000..5f6051b --- /dev/null +++ b/its/ruling/projects/custom/comment-regular-expression.feature @@ -0,0 +1,13 @@ +Feature: My feature... + # WTF! + # wtf: abc + # Hello + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/custom-checks/forbidden-name-content.feature b/its/ruling/projects/custom/custom-checks/forbidden-name-content.feature new file mode 100644 index 0000000..00bad92 --- /dev/null +++ b/its/ruling/projects/custom/custom-checks/forbidden-name-content.feature @@ -0,0 +1,13 @@ +# Noncompliant [[sc=10;ec=27]] {{Remove this usage of "WTF".}} +Feature: WTF My feature... + + Scenario: Scenario #1 + Given blabla... + When blabla... + Then blabla... + + # Noncompliant [[sc=13;ec=28]] {{Remove this usage of "WTF".}} + Scenario: Scenario WTF #2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/custom-checks/forbidden-tag.feature b/its/ruling/projects/custom/custom-checks/forbidden-tag.feature new file mode 100644 index 0000000..d09bb99 --- /dev/null +++ b/its/ruling/projects/custom/custom-checks/forbidden-tag.feature @@ -0,0 +1,14 @@ +@bar +Feature: My feature... + + @foo + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + @mytag + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/end-line-characters.feature b/its/ruling/projects/custom/end-line-characters.feature new file mode 100644 index 0000000..197f983 --- /dev/null +++ b/its/ruling/projects/custom/end-line-characters.feature @@ -0,0 +1,11 @@ +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/file-name/FileNameKO.feature b/its/ruling/projects/custom/file-name/FileNameKO.feature new file mode 100644 index 0000000..197f983 --- /dev/null +++ b/its/ruling/projects/custom/file-name/FileNameKO.feature @@ -0,0 +1,11 @@ +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/file-name/file-name-custom-ok.feature b/its/ruling/projects/custom/file-name/file-name-custom-ok.feature new file mode 100644 index 0000000..197f983 --- /dev/null +++ b/its/ruling/projects/custom/file-name/file-name-custom-ok.feature @@ -0,0 +1,11 @@ +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/file-name/file-name-ok.feature b/its/ruling/projects/custom/file-name/file-name-ok.feature new file mode 100644 index 0000000..197f983 --- /dev/null +++ b/its/ruling/projects/custom/file-name/file-name-ok.feature @@ -0,0 +1,11 @@ +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/file-name/file_name.kocustom.feature b/its/ruling/projects/custom/file-name/file_name.kocustom.feature new file mode 100644 index 0000000..197f983 --- /dev/null +++ b/its/ruling/projects/custom/file-name/file_name.kocustom.feature @@ -0,0 +1,11 @@ +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/fixme.feature b/its/ruling/projects/custom/fixme.feature new file mode 100644 index 0000000..16269e8 --- /dev/null +++ b/its/ruling/projects/custom/fixme.feature @@ -0,0 +1,22 @@ +Feature: My feature... + + # Noncompliant {{Take the required action to fix the issue indicated by this comment.}} + # FIXME: blabla + + # Noncompliant {{Take the required action to fix the issue indicated by this comment.}} + #FIXME: blabla + + # Noncompliant {{Take the required action to fix the issue indicated by this comment.}} + #[[FIXME]] blabla + + # fixmeforthefirsttime + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/incomplete-examples-table.feature b/its/ruling/projects/custom/incomplete-examples-table.feature new file mode 100644 index 0000000..d6571e3 --- /dev/null +++ b/its/ruling/projects/custom/incomplete-examples-table.feature @@ -0,0 +1,25 @@ +Feature: My feature... + + Scenario Outline: Scenario 1 + Given blabla... + When blabla... + Then blabla... + # Noncompliant [[sc=5;ec=13]] {{Add a table to this "Examples" section.}} + Examples: + + Scenario Outline: Scenario 2 + Given blabla... + When blabla... + Then blabla... + Examples: + # Noncompliant [[sc=7;ec=15]] {{Add data rows to this table.}} + | test | + + Scenario Outline: Scenario 3 + Given blabla... + When blabla... + Then blabla... + Examples: + # Noncompliant [[sc=7;ec=15]] {{Add data rows to this table or convert this "Scenario Outline" to a standard "Scenario".}} + | test | + | 1 | diff --git a/its/ruling/projects/custom/indentation/indentation-custom-ko.feature b/its/ruling/projects/custom/indentation/indentation-custom-ko.feature new file mode 100644 index 0000000..ab30d9e --- /dev/null +++ b/its/ruling/projects/custom/indentation/indentation-custom-ko.feature @@ -0,0 +1,60 @@ + # Noncompliant {{Indent this line at column 0 (currently indented at column 1).}} + @tag + # Noncompliant {{Indent this line at column 0 (currently indented at column 1).}} + Feature: My feature... + blabla... + # Noncompliant {{Indent this line at column 4 (currently indented at column 5).}} + blabla... + + # Noncompliant {{Indent this line at column 4 (currently indented at column 5).}} + Background: blabla... + blabla... + # Noncompliant {{Indent this line at column 8 (currently indented at column 7).}} + blabla... + # Noncompliant {{Indent this line at column 8 (currently indented at column 10).}} + Given blabla... + + # Noncompliant {{Indent this line at column 4 (currently indented at column 5).}} + @tag + # Noncompliant {{Indent this line at column 4 (currently indented at column 3).}} + Scenario: Scenario 1 + # Noncompliant {{Indent this line at column 8 (currently indented at column 9).}} + blabla... + blabla... + Given blabla... + When blabla... + Then blabla... + + @tag + # Noncompliant {{Indent this line at column 4 (currently indented at column 5).}} + @tag @tag + # Noncompliant {{Indent this line at column 4 (currently indented at column 3).}} + Scenario Outline: Scenario 2 + # Noncompliant {{Indent this line at column 8 (currently indented at column 7).}} + blabla... + blabla... + Given blabla... + When blabla... + | data | + # Noncompliant {{Indent this line at column 12 (currently indented at column 13).}} + | 2 | + Then blabla... + # Noncompliant {{Indent this line at column 12 (currently indented at column 13).}} + """string + blabla... + blabla... + """ + # Noncompliant [[sl=-1]] {{Indent this line at column 12 (currently indented at column 11).}} + + # Noncompliant {{Indent this line at column 8 (currently indented at column 9).}} + @tag @tag + # Noncompliant {{Indent this line at column 8 (currently indented at column 9).}} + Examples: blabla... + # Noncompliant {{Indent this line at column 12 (currently indented at column 13).}} + blabla... + blabla... + # Noncompliant {{Indent this line at column 12 (currently indented at column 11).}} + | data | + # Noncompliant {{Indent this line at column 12 (currently indented at column 13).}} + | 1 | + | 2 | diff --git a/its/ruling/projects/custom/indentation/indentation-custom-ok.feature b/its/ruling/projects/custom/indentation/indentation-custom-ok.feature new file mode 100644 index 0000000..b8a03a0 --- /dev/null +++ b/its/ruling/projects/custom/indentation/indentation-custom-ok.feature @@ -0,0 +1,40 @@ +@tag +@tag +Feature: My feature... + blabla... + blabla... + + Background: blabla... + blabla... + blabla... + Given blabla... + + @tag + Scenario: Scenario 1 + blabla... + blabla... + Given blabla... + When blabla... + Then blabla... + + @tag @tag + Scenario Outline: Scenario 2 + blabla... + blabla... + Given blabla... + When blabla... + | data | + | 2 | + Then blabla... + """string + blabla... + blabla... + """ + + @tag + @tag @tag + Examples: blabla... + blabla... + blabla... + | data | + | 1 | diff --git a/its/ruling/projects/custom/indentation/indentation-default-ko.feature b/its/ruling/projects/custom/indentation/indentation-default-ko.feature new file mode 100644 index 0000000..8dec47b --- /dev/null +++ b/its/ruling/projects/custom/indentation/indentation-default-ko.feature @@ -0,0 +1,61 @@ +# Noncompliant {{Indent this line at column 0 (currently indented at column 1).}} + @tag +@tag + # Noncompliant {{Indent this line at column 0 (currently indented at column 2).}} + Feature: My feature... + # Noncompliant {{Indent this line at column 2 (currently indented at column 4).}} + blabla... + blabla... + + # Noncompliant {{Indent this line at column 2 (currently indented at column 1).}} + Background: blabla... + # Noncompliant {{Indent this line at column 4 (currently indented at column 2).}} + blabla... + blabla... + # Noncompliant {{Indent this line at column 4 (currently indented at column 5).}} + Given blabla... + + # Noncompliant {{Indent this line at column 2 (currently indented at column 4).}} + @tag + # Noncompliant {{Indent this line at column 2 (currently indented at column 3).}} + Scenario: Scenario 1 + blabla... + # Noncompliant {{Indent this line at column 4 (currently indented at column 7).}} + blabla... + Given blabla... + When blabla... + Then blabla... + + @tag + # Noncompliant {{Indent this line at column 2 (currently indented at column 4).}} + @tag + # Noncompliant {{Indent this line at column 2 (currently indented at column 3).}} + Scenario Outline: Scenario 2 + # Noncompliant {{Indent this line at column 4 (currently indented at column 5).}} + blabla... + blabla... + Given blabla... + When blabla... + | data | + # Noncompliant {{Indent this line at column 6 (currently indented at column 7).}} + | 2 | + Then blabla... + # Noncompliant {{Indent this line at column 6 (currently indented at column 7).}} + """string + blabla... + blabla... + """ + # Noncompliant [[sl=-1]] {{Indent this line at column 6 (currently indented at column 5).}} + + # Noncompliant {{Indent this line at column 4 (currently indented at column 5).}} + @tag + # Noncompliant {{Indent this line at column 4 (currently indented at column 5).}} + Examples: blabla... + blabla... + # Noncompliant {{Indent this line at column 6 (currently indented at column 7).}} + blabla... + # Noncompliant {{Indent this line at column 6 (currently indented at column 5).}} + | data | + # Noncompliant {{Indent this line at column 6 (currently indented at column 7).}} + | 1 | + | 2 | diff --git a/its/ruling/projects/custom/indentation/indentation-default-ok.feature b/its/ruling/projects/custom/indentation/indentation-default-ok.feature new file mode 100644 index 0000000..49f0e71 --- /dev/null +++ b/its/ruling/projects/custom/indentation/indentation-default-ok.feature @@ -0,0 +1,40 @@ +@tag +@tag1 +Feature: My feature... + blabla... + blabla... + + Background: blabla... + blabla... + blabla... + Given blabla... + + @tag @tag1 + Scenario: Scenario 1 + blabla... + blabla... + Given blabla... + When blabla... + Then blabla... + + @tag + Scenario Outline: Scenario 2 + blabla... + blabla... + Given blabla... + When blabla... + | data | + | 2 | + Then blabla... + """string + blabla... + blabla... + """ + + @tag + @tag @tag + Examples: blabla... + blabla... + blabla... + | data | + | 1 | diff --git a/its/ruling/projects/custom/max-number-scenarios/greater-than-custom-threshold.feature b/its/ruling/projects/custom/max-number-scenarios/greater-than-custom-threshold.feature new file mode 100644 index 0000000..2fba9b0 --- /dev/null +++ b/its/ruling/projects/custom/max-number-scenarios/greater-than-custom-threshold.feature @@ -0,0 +1,24 @@ +# Noncompliant [[sc=1;ec=8]] {{The number of scenarios (5) is greater that the maximum allowed (4). Split the scenarios into different features.}} +Feature: My feature... + + Background: + Given blabla... + + Scenario: scenario #1 + Given blabla... + + Scenario Outline: scenario #2 + Given blabla... + Examples: + | data | + | 1 | + | 2 | + + Scenario: scenario #3 + Given blabla... + + Scenario: scenario #4 + Given blabla... + + Scenario: scenario #5 + Given blabla... diff --git a/its/ruling/projects/custom/max-number-scenarios/greater-than-default-threshold.feature b/its/ruling/projects/custom/max-number-scenarios/greater-than-default-threshold.feature new file mode 100644 index 0000000..4756d3f --- /dev/null +++ b/its/ruling/projects/custom/max-number-scenarios/greater-than-default-threshold.feature @@ -0,0 +1,48 @@ +# Noncompliant [[sc=1;ec=8]] {{The number of scenarios (13) is greater that the maximum allowed (12). Split the scenarios into different features.}} +Feature: My feature... + + Background: + Given blabla... + + Scenario: scenario #1 + Given blabla... + + Scenario Outline: scenario #2 + Given blabla... + Examples: + | data | + | 1 | + | 2 | + + Scenario: scenario #3 + Given blabla... + + Scenario: scenario #4 + Given blabla... + + Scenario: scenario #5 + Given blabla... + + Scenario: scenario #6 + Given blabla... + + Scenario: scenario #7 + Given blabla... + + Scenario: scenario #8 + Given blabla... + + Scenario: scenario #9 + Given blabla... + + Scenario: scenario #10 + Given blabla... + + Scenario: scenario #11 + Given blabla... + + Scenario: scenario #12 + Given blabla... + + Scenario: scenario #13 + Given blabla... diff --git a/its/ruling/projects/custom/max-number-scenarios/lower-than-custom-threshold.feature b/its/ruling/projects/custom/max-number-scenarios/lower-than-custom-threshold.feature new file mode 100644 index 0000000..6ee15da --- /dev/null +++ b/its/ruling/projects/custom/max-number-scenarios/lower-than-custom-threshold.feature @@ -0,0 +1,20 @@ +Feature: My feature... + + Background: + Given blabla... + + Scenario: scenario #1 + Given blabla... + + Scenario Outline: scenario #2 + Given blabla... + Examples: + | data | + | 1 | + | 2 | + + Scenario: scenario #3 + Given blabla... + + Scenario: scenario #4 + Given blabla... diff --git a/its/ruling/projects/custom/max-number-scenarios/lower-than-default-threshold.feature b/its/ruling/projects/custom/max-number-scenarios/lower-than-default-threshold.feature new file mode 100644 index 0000000..0203f79 --- /dev/null +++ b/its/ruling/projects/custom/max-number-scenarios/lower-than-default-threshold.feature @@ -0,0 +1,44 @@ +Feature: My feature... + + Background: + Given blabla... + + Scenario: scenario #1 + Given blabla... + + Scenario Outline: scenario #2 + Given blabla... + Examples: + | data | + | 1 | + | 2 | + + Scenario: scenario #3 + Given blabla... + + Scenario: scenario #4 + Given blabla... + + Scenario: scenario #5 + Given blabla... + + Scenario: scenario #6 + Given blabla... + + Scenario: scenario #7 + Given blabla... + + Scenario: scenario #8 + Given blabla... + + Scenario: scenario #9 + Given blabla... + + Scenario: scenario #10 + Given blabla... + + Scenario: scenario #11 + Given blabla... + + Scenario: scenario #12 + Given blabla... diff --git a/its/ruling/projects/custom/max-number-steps/max-number-steps-background.feature b/its/ruling/projects/custom/max-number-steps/max-number-steps-background.feature new file mode 100644 index 0000000..9f10bcb --- /dev/null +++ b/its/ruling/projects/custom/max-number-steps/max-number-steps-background.feature @@ -0,0 +1,28 @@ +Feature: My feature... + + Background: + Given blabla... + And blabla... + And blabla... + And blabla... + And blabla... + + Scenario: scenario #1 + Given blabla... + When blabla... + Then blabla... + And blabla... + And blabla... + And blabla... + And blabla... + + # Noncompliant [[sc=3;ec=11]] {{Reduce the number of steps (13, greater than 12 allowed)}} + Scenario: scenario #2 + Given blabla... + When blabla... + Then blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... diff --git a/its/ruling/projects/custom/max-number-steps/max-number-steps-custom-threshold.feature b/its/ruling/projects/custom/max-number-steps/max-number-steps-custom-threshold.feature new file mode 100644 index 0000000..7e8482b --- /dev/null +++ b/its/ruling/projects/custom/max-number-steps/max-number-steps-custom-threshold.feature @@ -0,0 +1,18 @@ +Feature: My feature... + + Scenario: scenario #1 + Given blabla... + When blabla... + Then blabla... + And blabla... + And blabla... + + # Noncompliant [[sc=3;ec=11]] {{Reduce the number of steps (7, greater than 5 allowed)}} + Scenario: scenario #2 + Given blabla... + When blabla... + Then blabla... + And blabla... + And blabla... + And blabla... + And blabla... diff --git a/its/ruling/projects/custom/max-number-steps/max-number-steps-no-background.feature b/its/ruling/projects/custom/max-number-steps/max-number-steps-no-background.feature new file mode 100644 index 0000000..778fdff --- /dev/null +++ b/its/ruling/projects/custom/max-number-steps/max-number-steps-no-background.feature @@ -0,0 +1,31 @@ +Feature: My feature... + + Scenario: scenario #1 + Given blabla... + When blabla... + Then blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... + + # Noncompliant [[sc=3;ec=11]] {{Reduce the number of steps (13, greater than 12 allowed)}} + Scenario: scenario #2 + Given blabla... + When blabla... + Then blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... + And blabla... diff --git a/its/ruling/projects/custom/new-line-end-of-file/new-line-end-of-file.feature b/its/ruling/projects/custom/new-line-end-of-file/new-line-end-of-file.feature new file mode 100644 index 0000000..197f983 --- /dev/null +++ b/its/ruling/projects/custom/new-line-end-of-file/new-line-end-of-file.feature @@ -0,0 +1,11 @@ +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/new-line-end-of-file/no-new-line-end-of-file.feature b/its/ruling/projects/custom/new-line-end-of-file/no-new-line-end-of-file.feature new file mode 100644 index 0000000..3db3cd6 --- /dev/null +++ b/its/ruling/projects/custom/new-line-end-of-file/no-new-line-end-of-file.feature @@ -0,0 +1,11 @@ +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... \ No newline at end of file diff --git a/its/ruling/projects/custom/no-feature/feature.feature b/its/ruling/projects/custom/no-feature/feature.feature new file mode 100644 index 0000000..18c0a2b --- /dev/null +++ b/its/ruling/projects/custom/no-feature/feature.feature @@ -0,0 +1,5 @@ +Feature: My feature... + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/no-feature/no-feature.feature b/its/ruling/projects/custom/no-feature/no-feature.feature new file mode 100644 index 0000000..da05b93 --- /dev/null +++ b/its/ruling/projects/custom/no-feature/no-feature.feature @@ -0,0 +1 @@ +# Noncompliant [[sl=0]] {{Remove this file that does not define any feature.}} diff --git a/its/ruling/projects/custom/no-scenario/no-scenario.feature b/its/ruling/projects/custom/no-scenario/no-scenario.feature new file mode 100644 index 0000000..c76fabe --- /dev/null +++ b/its/ruling/projects/custom/no-scenario/no-scenario.feature @@ -0,0 +1,2 @@ +# Noncompliant [[sc=1;ec=8]] {{Remove this feature that does not define any scenario.}} +Feature: My feature... diff --git a/its/ruling/projects/custom/no-scenario/scenario-outline.feature b/its/ruling/projects/custom/no-scenario/scenario-outline.feature new file mode 100644 index 0000000..0f8f8e9 --- /dev/null +++ b/its/ruling/projects/custom/no-scenario/scenario-outline.feature @@ -0,0 +1,9 @@ +Feature: My feature... + Scenario Outline: Scenario 1 + Given blabla... + When blabla... + Then blabla... + Examples: + | data | + | 1 | + | 2 | diff --git a/its/ruling/projects/custom/no-scenario/scenario.feature b/its/ruling/projects/custom/no-scenario/scenario.feature new file mode 100644 index 0000000..18c0a2b --- /dev/null +++ b/its/ruling/projects/custom/no-scenario/scenario.feature @@ -0,0 +1,5 @@ +Feature: My feature... + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/star-step-prefix.feature b/its/ruling/projects/custom/star-step-prefix.feature new file mode 100644 index 0000000..a910b62 --- /dev/null +++ b/its/ruling/projects/custom/star-step-prefix.feature @@ -0,0 +1,12 @@ +Feature: My feature... + + Scenario: My scenario 1 + # Noncompliant [[sc=5;ec=6]] {{Replace this star prefix with Given/When/Then.}} + * blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/tab-character/no-tab-character.feature b/its/ruling/projects/custom/tab-character/no-tab-character.feature new file mode 100644 index 0000000..197f983 --- /dev/null +++ b/its/ruling/projects/custom/tab-character/no-tab-character.feature @@ -0,0 +1,11 @@ +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/tab-character/tab-character.feature b/its/ruling/projects/custom/tab-character/tab-character.feature new file mode 100644 index 0000000..87aaa1e --- /dev/null +++ b/its/ruling/projects/custom/tab-character/tab-character.feature @@ -0,0 +1,11 @@ +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/tag-name/tag-name-custom-ko.feature b/its/ruling/projects/custom/tag-name/tag-name-custom-ko.feature new file mode 100644 index 0000000..92ccf8e --- /dev/null +++ b/its/ruling/projects/custom/tag-name/tag-name-custom-ko.feature @@ -0,0 +1,14 @@ +# Noncompliant [[sc=1;ec=7]] {{Rename this tag to match the regular expression: ^[a-z]+$}} +@myTag +Feature: My feature... + + @tag + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/tag-name/tag-name-custom-ok.feature b/its/ruling/projects/custom/tag-name/tag-name-custom-ok.feature new file mode 100644 index 0000000..1e38448 --- /dev/null +++ b/its/ruling/projects/custom/tag-name/tag-name-custom-ok.feature @@ -0,0 +1,13 @@ +@my-tag +Feature: My feature... + + @tag + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/tag-name/tag-name-ko.feature b/its/ruling/projects/custom/tag-name/tag-name-ko.feature new file mode 100644 index 0000000..3dd4b88 --- /dev/null +++ b/its/ruling/projects/custom/tag-name/tag-name-ko.feature @@ -0,0 +1,15 @@ +# Noncompliant [[sc=1;ec=7]] {{Rename this tag to match the regular expression: ^[a-z][-a-z0-9]*$}} +@myTag @my-tag +Feature: My feature... + + # Noncompliant [[sc=3;ec=10]] {{Rename this tag to match the regular expression: ^[a-z][-a-z0-9]*$}} + @myTag0 + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/tag-name/tag-name-ok.feature b/its/ruling/projects/custom/tag-name/tag-name-ok.feature new file mode 100644 index 0000000..f12915c --- /dev/null +++ b/its/ruling/projects/custom/tag-name/tag-name-ok.feature @@ -0,0 +1,13 @@ +@mytag @my-tag +Feature: My feature... + + @my-tag1 + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/todo.feature b/its/ruling/projects/custom/todo.feature new file mode 100644 index 0000000..123d63e --- /dev/null +++ b/its/ruling/projects/custom/todo.feature @@ -0,0 +1,22 @@ +Feature: My feature... + + # Noncompliant + # TODO: blabla + + # Noncompliant + #TODO: blabla + + # Noncompliant + #[[TODO]] blabla + + # todoforthefirsttime + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... diff --git a/its/ruling/projects/custom/trailing-whitespace.feature b/its/ruling/projects/custom/trailing-whitespace.feature new file mode 100644 index 0000000..01f73ed --- /dev/null +++ b/its/ruling/projects/custom/trailing-whitespace.feature @@ -0,0 +1,14 @@ +# Noncompliant [[sl=3]] {{Remove the useless trailing whitespaces at the end of this line.}} +# Noncompliant [[sl=6]] {{Remove the useless trailing whitespaces at the end of this line.}} +Feature: My feature... + + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... + diff --git a/its/ruling/tests/pom.xml b/its/ruling/tests/pom.xml new file mode 100644 index 0000000..efd3ec0 --- /dev/null +++ b/its/ruling/tests/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + + com.racodond.sonarqube.plugin.gherkin + gherkin-its-ruling + 1.0-SNAPSHOT + + + gherkin-its-ruling-tests + SonarQube Gherkin Analyzer :: Integration Tests :: Ruling :: Tests + + + + org.sonarsource.orchestrator + sonar-orchestrator + + + com.google.guava + guava + + + junit + junit + + + org.easytesting + fest-assert + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + org/sonar/gherkin/its/GherkinRulingTest.java + + + + + + + + diff --git a/its/ruling/tests/src/test/expected/gherkin-S1131.json b/its/ruling/tests/src/test/expected/gherkin-S1131.json new file mode 100644 index 0000000..a113c9f --- /dev/null +++ b/its/ruling/tests/src/test/expected/gherkin-S1131.json @@ -0,0 +1,6 @@ +{ +'project:custom/trailing-whitespace.feature':[ +3, +6, +], +} diff --git a/its/ruling/tests/src/test/expected/gherkin-S1134.json b/its/ruling/tests/src/test/expected/gherkin-S1134.json new file mode 100644 index 0000000..35f4656 --- /dev/null +++ b/its/ruling/tests/src/test/expected/gherkin-S1134.json @@ -0,0 +1,7 @@ +{ +'project:custom/fixme.feature':[ +4, +7, +10, +], +} diff --git a/its/ruling/tests/src/test/expected/gherkin-S1135.json b/its/ruling/tests/src/test/expected/gherkin-S1135.json new file mode 100644 index 0000000..b2aff7e --- /dev/null +++ b/its/ruling/tests/src/test/expected/gherkin-S1135.json @@ -0,0 +1,7 @@ +{ +'project:custom/todo.feature':[ +4, +7, +10, +], +} diff --git a/its/ruling/tests/src/test/expected/gherkin-S1578.json b/its/ruling/tests/src/test/expected/gherkin-S1578.json new file mode 100644 index 0000000..9d7ca4e --- /dev/null +++ b/its/ruling/tests/src/test/expected/gherkin-S1578.json @@ -0,0 +1,8 @@ +{ +'project:custom/file-name/FileNameKO.feature':[ +0, +], +'project:custom/file-name/file_name.kocustom.feature':[ +0, +], +} diff --git a/its/ruling/tests/src/test/expected/gherkin-S2260.json b/its/ruling/tests/src/test/expected/gherkin-S2260.json new file mode 100644 index 0000000..bef655e --- /dev/null +++ b/its/ruling/tests/src/test/expected/gherkin-S2260.json @@ -0,0 +1,8 @@ +{ +'project:custom/bom/utf16-be.feature':[ +1, +], +'project:custom/bom/utf16-le.feature':[ +1, +], +} diff --git a/its/ruling/tests/src/test/expected/gherkin-allowed-tags.json b/its/ruling/tests/src/test/expected/gherkin-allowed-tags.json new file mode 100644 index 0000000..f0855be --- /dev/null +++ b/its/ruling/tests/src/test/expected/gherkin-allowed-tags.json @@ -0,0 +1,71 @@ +{ +'project:custom/allowed-tags/allowed-tags-custom.feature':[ +6, +12, +12, +], +'project:custom/allowed-tags/allowed-tags-default.feature':[ +2, +6, +], +'project:custom/custom-checks/forbidden-tag.feature':[ +1, +4, +10, +], +'project:custom/indentation/indentation-custom-ko.feature':[ +2, +18, +28, +30, +30, +50, +50, +], +'project:custom/indentation/indentation-custom-ok.feature':[ +1, +2, +12, +20, +20, +34, +35, +35, +], +'project:custom/indentation/indentation-default-ko.feature':[ +2, +3, +19, +29, +31, +51, +], +'project:custom/indentation/indentation-default-ok.feature':[ +1, +2, +12, +12, +20, +34, +35, +35, +], +'project:custom/tag-name/tag-name-custom-ko.feature':[ +2, +5, +], +'project:custom/tag-name/tag-name-custom-ok.feature':[ +1, +4, +], +'project:custom/tag-name/tag-name-ko.feature':[ +2, +2, +6, +], +'project:custom/tag-name/tag-name-ok.feature':[ +1, +1, +4, +], +} diff --git a/its/ruling/tests/src/test/expected/gherkin-bom-utf8-files.json b/its/ruling/tests/src/test/expected/gherkin-bom-utf8-files.json new file mode 100644 index 0000000..4178cd7 --- /dev/null +++ b/its/ruling/tests/src/test/expected/gherkin-bom-utf8-files.json @@ -0,0 +1,5 @@ +{ +'project:custom/bom/utf8-with-bom.feature':[ +0, +], +} diff --git a/its/ruling/tests/src/test/expected/gherkin-comment-convention.json b/its/ruling/tests/src/test/expected/gherkin-comment-convention.json new file mode 100644 index 0000000..f0bc1d8 --- /dev/null +++ b/its/ruling/tests/src/test/expected/gherkin-comment-convention.json @@ -0,0 +1,13 @@ +{ +'project:custom/comment-convention.feature':[ +2, +], +'project:custom/fixme.feature':[ +7, +10, +], +'project:custom/todo.feature':[ +7, +10, +], +} diff --git a/its/ruling/tests/src/test/expected/gherkin-empty-line-end-of-file.json b/its/ruling/tests/src/test/expected/gherkin-empty-line-end-of-file.json new file mode 100644 index 0000000..22b98de --- /dev/null +++ b/its/ruling/tests/src/test/expected/gherkin-empty-line-end-of-file.json @@ -0,0 +1,5 @@ +{ +'project:custom/new-line-end-of-file/no-new-line-end-of-file.feature':[ +0, +], +} diff --git a/its/ruling/tests/src/test/expected/gherkin-incomplete-examples-table.json b/its/ruling/tests/src/test/expected/gherkin-incomplete-examples-table.json new file mode 100644 index 0000000..8aa2577 --- /dev/null +++ b/its/ruling/tests/src/test/expected/gherkin-incomplete-examples-table.json @@ -0,0 +1,13 @@ +{ +'project:custom/incomplete-examples-table.feature':[ +8, +16, +24, +], +'project:custom/indentation/indentation-custom-ok.feature':[ +39, +], +'project:custom/indentation/indentation-default-ok.feature':[ +39, +], +} diff --git a/its/ruling/tests/src/test/expected/gherkin-indentation.json b/its/ruling/tests/src/test/expected/gherkin-indentation.json new file mode 100644 index 0000000..63633aa --- /dev/null +++ b/its/ruling/tests/src/test/expected/gherkin-indentation.json @@ -0,0 +1,96 @@ +{ +'project:custom/indentation/indentation-custom-ko.feature':[ +2, +4, +5, +7, +10, +11, +13, +15, +18, +20, +22, +23, +24, +25, +26, +28, +30, +32, +34, +35, +36, +37, +38, +40, +41, +43, +46, +50, +52, +54, +55, +57, +59, +60, +], +'project:custom/indentation/indentation-custom-ok.feature':[ +4, +5, +7, +8, +9, +10, +12, +13, +14, +15, +16, +17, +18, +20, +21, +22, +23, +24, +25, +26, +27, +28, +29, +32, +34, +35, +36, +37, +38, +39, +40, +], +'project:custom/indentation/indentation-default-ko.feature':[ +2, +5, +7, +11, +13, +16, +19, +21, +24, +31, +33, +35, +41, +44, +47, +51, +53, +56, +58, +60, +], +'project:custom/tab-character/tab-character.feature':[ +4, +], +} diff --git a/its/ruling/tests/src/test/expected/gherkin-max-number-scenarios.json b/its/ruling/tests/src/test/expected/gherkin-max-number-scenarios.json new file mode 100644 index 0000000..e494c20 --- /dev/null +++ b/its/ruling/tests/src/test/expected/gherkin-max-number-scenarios.json @@ -0,0 +1,5 @@ +{ +'project:custom/max-number-scenarios/greater-than-default-threshold.feature':[ +2, +], +} diff --git a/its/ruling/tests/src/test/expected/gherkin-max-number-steps.json b/its/ruling/tests/src/test/expected/gherkin-max-number-steps.json new file mode 100644 index 0000000..6ef6ff5 --- /dev/null +++ b/its/ruling/tests/src/test/expected/gherkin-max-number-steps.json @@ -0,0 +1,8 @@ +{ +'project:custom/max-number-steps/max-number-steps-background.feature':[ +20, +], +'project:custom/max-number-steps/max-number-steps-no-background.feature':[ +18, +], +} diff --git a/its/ruling/tests/src/test/expected/gherkin-no-feature.json b/its/ruling/tests/src/test/expected/gherkin-no-feature.json new file mode 100644 index 0000000..c445383 --- /dev/null +++ b/its/ruling/tests/src/test/expected/gherkin-no-feature.json @@ -0,0 +1,5 @@ +{ +'project:custom/no-feature/no-feature.feature':[ +0, +], +} diff --git a/its/ruling/tests/src/test/expected/gherkin-no-scenario.json b/its/ruling/tests/src/test/expected/gherkin-no-scenario.json new file mode 100644 index 0000000..bd25c02 --- /dev/null +++ b/its/ruling/tests/src/test/expected/gherkin-no-scenario.json @@ -0,0 +1,5 @@ +{ +'project:custom/no-scenario/no-scenario.feature':[ +2, +], +} diff --git a/its/ruling/tests/src/test/expected/gherkin-star-step-prefix.json b/its/ruling/tests/src/test/expected/gherkin-star-step-prefix.json new file mode 100644 index 0000000..9d54bc7 --- /dev/null +++ b/its/ruling/tests/src/test/expected/gherkin-star-step-prefix.json @@ -0,0 +1,5 @@ +{ +'project:custom/star-step-prefix.feature':[ +5, +], +} diff --git a/its/ruling/tests/src/test/expected/gherkin-tab-character.json b/its/ruling/tests/src/test/expected/gherkin-tab-character.json new file mode 100644 index 0000000..ef52464 --- /dev/null +++ b/its/ruling/tests/src/test/expected/gherkin-tab-character.json @@ -0,0 +1,5 @@ +{ +'project:custom/tab-character/tab-character.feature':[ +0, +], +} diff --git a/its/ruling/tests/src/test/expected/gherkin-tag-naming-convention.json b/its/ruling/tests/src/test/expected/gherkin-tag-naming-convention.json new file mode 100644 index 0000000..368db12 --- /dev/null +++ b/its/ruling/tests/src/test/expected/gherkin-tag-naming-convention.json @@ -0,0 +1,9 @@ +{ +'project:custom/tag-name/tag-name-custom-ko.feature':[ +2, +], +'project:custom/tag-name/tag-name-ko.feature':[ +2, +6, +], +} diff --git a/its/ruling/tests/src/test/java/org/sonar/gherkin/its/GherkinRulingTest.java b/its/ruling/tests/src/test/java/org/sonar/gherkin/its/GherkinRulingTest.java new file mode 100644 index 0000000..51aed7d --- /dev/null +++ b/its/ruling/tests/src/test/java/org/sonar/gherkin/its/GherkinRulingTest.java @@ -0,0 +1,72 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.its; + +import com.google.common.io.Files; +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.SonarScanner; +import com.sonar.orchestrator.locator.FileLocation; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; + +import java.io.File; +import java.nio.charset.StandardCharsets; + +import static org.fest.assertions.Assertions.assertThat; + +public class GherkinRulingTest { + + @ClassRule + public static Orchestrator orchestrator = Orchestrator.builderEnv() + .addPlugin(FileLocation.byWildcardMavenFilename(new File("../../../sonar-gherkin-plugin/target"), "sonar-gherkin-plugin-*-SNAPSHOT.jar")) + .setOrchestratorProperty("litsVersion", "0.6") + .addPlugin("lits") + .build(); + + @Before + public void setUp() throws Exception { + ProfileGenerator.generateProfile(orchestrator); + } + + @Test + public void test() throws Exception { + File litsDifferencesFile = FileLocation.of("target/differences").getFile(); + orchestrator.getServer().provisionProject("project", "project"); + orchestrator.getServer().associateProjectToQualityProfile("project", "gherkin", "rules"); + SonarScanner build = SonarScanner.create(FileLocation.of("../projects").getFile()) + .setProjectKey("project") + .setProjectName("project") + .setProjectVersion("1.0") + .setLanguage("gherkin") + .setSourceDirs("./") + .setSourceEncoding("UTF-8") + .setProperty("sonar.analysis.mode", "preview") + .setProperty("sonar.issuesReport.html.enable", "true") + .setProperty("dump.old", FileLocation.of("src/test/expected").getFile().getAbsolutePath()) + .setProperty("dump.new", FileLocation.of("target/actual").getFile().getAbsolutePath()) + .setProperty("lits.differences", litsDifferencesFile.getAbsolutePath()) + .setProperty("sonar.cpd.skip", "true"); + orchestrator.executeBuild(build); + + assertThat(Files.toString(litsDifferencesFile, StandardCharsets.UTF_8)).isEmpty(); + } + +} diff --git a/its/ruling/tests/src/test/java/org/sonar/gherkin/its/ProfileGenerator.java b/its/ruling/tests/src/test/java/org/sonar/gherkin/its/ProfileGenerator.java new file mode 100644 index 0000000..f8aa0ba --- /dev/null +++ b/its/ruling/tests/src/test/java/org/sonar/gherkin/its/ProfileGenerator.java @@ -0,0 +1,107 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.gherkin.its; + +import com.google.common.base.Charsets; +import com.google.common.base.Throwables; +import com.google.common.collect.ImmutableListMultimap; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Multimap; +import com.google.common.io.Files; +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.locator.FileLocation; +import org.sonar.wsclient.internal.HttpRequestFactory; +import org.sonar.wsclient.jsonsimple.JSONValue; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +public class ProfileGenerator { + + private static Multimap parameters = ImmutableListMultimap.builder() + .build(); + + public static void generateProfile(Orchestrator orchestrator) { + try { + StringBuilder sb = new StringBuilder() + .append("") + .append("rules") + .append("gherkin") + .append(""); + + Set ruleKeys = getRuleKeysFromRepository(orchestrator); + + for (String key : ruleKeys) { + sb.append("") + .append("gherkin") + .append("").append(key).append("") + .append("INFO"); + + Collection parameters = ProfileGenerator.parameters.get(key); + if (!parameters.isEmpty()) { + sb.append(""); + for (Parameter parameter : parameters) { + sb.append("") + .append("").append(parameter.parameterKey).append("") + .append("").append(parameter.parameterValue).append("") + .append(""); + } + sb.append(""); + } + + sb.append(""); + } + sb.append("") + .append(""); + + File file = File.createTempFile("profile", ".xml"); + Files.write(sb, file, Charsets.UTF_8); + orchestrator.getServer().restoreProfile(FileLocation.of(file)); + file.delete(); + } catch (IOException e) { + throw Throwables.propagate(e); + } + } + + private static Set getRuleKeysFromRepository(Orchestrator orchestrator) { + Set ruleKeys = new HashSet<>(); + String json = new HttpRequestFactory(orchestrator.getServer().getUrl()) + .get("/api/rules/search", ImmutableMap.of("languages", "gherkin", "repositories", "gherkin", "ps", "1000")); + @SuppressWarnings("unchecked") + List jsonRules = (List) ((Map) JSONValue.parse(json)).get("rules"); + for (Map jsonRule : jsonRules) { + String key = ((String) jsonRule.get("key")).substring(8); + ruleKeys.add(key); + } + return ruleKeys; + } + + private static class Parameter { + String parameterKey; + String parameterValue; + + public Parameter(String parameterKey, String parameterValue) { + this.parameterKey = parameterKey; + this.parameterValue = parameterValue; + } + } + +} diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..3fad9d7 --- /dev/null +++ b/pom.xml @@ -0,0 +1,327 @@ + + + 4.0.0 + + + org.sonarsource.parent + parent + 36 + + + com.racodond.sonarqube.plugin.gherkin + gherkin + 1.0-SNAPSHOT + pom + + SonarQube Gherkin Analyzer + Enables analysis of Cucumber Gherkin features files in SonarQube + https://github.com/racodond/sonar-gherkin-plugin + 2016 + + David RACODON + mailto:david.racodon@gmail.com + + + + GNU LGPL 3 + http://www.gnu.org/licenses/lgpl.txt + repo + + + + + + racodond + David RACODON + david.racodon@gmail.com + https://www.linkedin.com/pub/david-racodon/11/62/283 + + + + + sonar-gherkin-plugin + gherkin-frontend + gherkin-checks + gherkin-checks-testkit + + + + scm:git@github.com:racodond/sonar-gherkin-plugin.git + scm:git@github.com:racodond/sonar-gherkin-plugin.git + https://github.com/racodond/sonar-gherkin-plugin + HEAD + + + GitHub Issues + https://github.com/racodond/sonar-gherkin-plugin/issues + + + Travis CI + https://travis-ci.org/racodond/sonar-gherkin-plugin + + + + SonarQube Gherkin Analyzer + David RACODON + david.racodon@gmail.com + 5.6 + 1.21 + ${project.basedir}/../target/jacoco.exec + + + + + + ${project.groupId} + gherkin-frontend + ${project.version} + + + ${project.groupId} + gherkin-checks + ${project.version} + + + ${project.groupId} + gherkin-checks-testkit + ${project.version} + + + ${project.groupId} + sonar-gherkin-plugin + ${project.version} + sonar-plugin + + + org.sonarsource.sonarqube + sonar-plugin-api + ${sonar.version} + + + org.sonarsource.sonarqube + sonar-testing-harness + ${sonar.version} + + + org.sonarsource.orchestrator + sonar-orchestrator + 3.12 + + + com.oracle + ojdbc6 + + + + + org.sonarsource.sslr + sslr-core + ${sslr.version} + + + com.google.guava + guava + + + + + org.sonarsource.sslr + sslr-xpath + ${sslr.version} + + + org.sonarsource.sslr + sslr-toolkit + ${sslr.version} + + + commons-lang + commons-lang + 2.6 + + + org.sonarsource.sslr + sslr-testing-harness + ${sslr.version} + + + org.sonarsource.sslr-squid-bridge + sslr-squid-bridge + 2.6.1 + + + org.codehaus.sonar.sslr + sslr-core + + + org.codehaus.sonar + sonar-plugin-api + + + org.codehaus.sonar.sslr + sslr-xpath + + + org.slf4j + jcl-over-slf4j + + + + + com.google.guava + guava + 19.0 + + + junit + junit + 4.10 + + + org.mockito + mockito-all + 1.9.0 + + + org.hamcrest + hamcrest-all + 1.1 + + + org.easytesting + fest-assert + 1.4 + + + org.slf4j + slf4j-api + 1.7.5 + + + org.slf4j + jcl-over-slf4j + 1.7.5 + + + org.slf4j + slf4j-log4j12 + 1.7.5 + + + ch.qos.logback + logback-classic + 1.0.13 + + + + + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + + org.jacoco + jacoco-maven-plugin + 0.7.6.201602180812 + + ${sonar.jacoco.reportPath} + true + + + + agent + + prepare-agent + + + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ossrh + https://oss.sonatype.org/ + true + + + + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + + attach-sources + + jar-no-fork + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + + attach-javadocs + + jar + + + + + + + + + + ossrh + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + + + + + + + diff --git a/sonar-gherkin-plugin/pom.xml b/sonar-gherkin-plugin/pom.xml new file mode 100644 index 0000000..bc062f3 --- /dev/null +++ b/sonar-gherkin-plugin/pom.xml @@ -0,0 +1,120 @@ + + + 4.0.0 + + + com.racodond.sonarqube.plugin.gherkin + gherkin + 1.0-SNAPSHOT + + + sonar-gherkin-plugin + sonar-plugin + + SonarQube Gherkin Analyzer :: SonarQube Plugin + Enables analysis of Cucumber Gherkin feature files. + https://github.com/racodond/sonar-gherkin-plugin + + + gherkin + Gherkin + org.sonar.plugins.gherkin.GherkinPlugin + true + + + + + ${project.groupId} + gherkin-frontend + + + ${project.groupId} + gherkin-checks + + + org.sonarsource.sonarqube + sonar-plugin-api + provided + + + junit + junit + test + + + org.sonarsource.sonarqube + sonar-testing-harness + test + + + org.easytesting + fest-assert + test + + + + + + + org.apache.maven.plugins + maven-shade-plugin + + + package + + shade + + + false + true + false + + + cglib:cglib-nodep + + ** + + + + + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + enforce-plugin-size + + enforce + + verify + + + + 2000000 + 1800000 + + ${project.build.directory}/${project.build.finalName}.jar + + + + + + + + + + org.jacoco + jacoco-maven-plugin + + ${sonar.jacoco.reportPath} + + + + + + diff --git a/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/GherkinChecks.java b/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/GherkinChecks.java new file mode 100644 index 0000000..8e77e89 --- /dev/null +++ b/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/GherkinChecks.java @@ -0,0 +1,98 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import org.sonar.api.batch.rule.CheckFactory; +import org.sonar.api.batch.rule.Checks; +import org.sonar.api.rule.RuleKey; +import org.sonar.plugins.gherkin.api.CustomGherkinRulesDefinition; +import org.sonar.plugins.gherkin.api.GherkinCheck; +import org.sonar.plugins.gherkin.api.visitors.TreeVisitor; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +public class GherkinChecks { + + private final CheckFactory checkFactory; + private Set> checksByRepository = Sets.newHashSet(); + + private GherkinChecks(CheckFactory checkFactory) { + this.checkFactory = checkFactory; + } + + public static GherkinChecks createGherkinChecks(CheckFactory checkFactory) { + return new GherkinChecks(checkFactory); + } + + public GherkinChecks addChecks(String repositoryKey, Iterable checkClass) { + checksByRepository.add(checkFactory + .create(repositoryKey) + .addAnnotatedChecks(checkClass)); + + return this; + } + + public GherkinChecks addCustomChecks(@Nullable CustomGherkinRulesDefinition[] customRulesDefinitions) { + if (customRulesDefinitions != null) { + + for (CustomGherkinRulesDefinition rulesDefinition : customRulesDefinitions) { + addChecks(rulesDefinition.repositoryKey(), Lists.newArrayList(rulesDefinition.checkClasses())); + } + } + return this; + } + + public List all() { + List allVisitors = Lists.newArrayList(); + + for (Checks checks : checksByRepository) { + allVisitors.addAll(checks.all()); + } + + return allVisitors; + } + + public List visitorChecks() { + return all() + .stream() + .filter(c -> c instanceof TreeVisitor) + .map(c -> (TreeVisitor) c).collect(Collectors.toList()); + } + + @Nullable + public RuleKey ruleKeyFor(GherkinCheck check) { + RuleKey ruleKey; + + for (Checks checks : checksByRepository) { + ruleKey = checks.ruleKey(check); + + if (ruleKey != null) { + return ruleKey; + } + } + return null; + } + +} diff --git a/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/GherkinLanguage.java b/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/GherkinLanguage.java new file mode 100644 index 0000000..83325a7 --- /dev/null +++ b/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/GherkinLanguage.java @@ -0,0 +1,37 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin; + +import org.sonar.api.resources.AbstractLanguage; + +public class GherkinLanguage extends AbstractLanguage { + + public static final String KEY = "gherkin"; + + public GherkinLanguage() { + super(KEY, "Gherkin"); + } + + @Override + public String[] getFileSuffixes() { + return new String[] {"feature"}; + } + +} diff --git a/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/GherkinPlugin.java b/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/GherkinPlugin.java new file mode 100644 index 0000000..0201b59 --- /dev/null +++ b/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/GherkinPlugin.java @@ -0,0 +1,35 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin; + +import org.sonar.api.Plugin; + +public class GherkinPlugin implements Plugin { + + @Override + public void define(Context context) { + context.addExtensions( + GherkinLanguage.class, + GherkinSquidSensor.class, + GherkinProfile.class, + GherkinRulesDefinition.class); + } + +} diff --git a/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/GherkinProfile.java b/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/GherkinProfile.java new file mode 100644 index 0000000..3e94ae5 --- /dev/null +++ b/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/GherkinProfile.java @@ -0,0 +1,48 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin; + +import org.sonar.api.profiles.ProfileDefinition; +import org.sonar.api.profiles.RulesProfile; +import org.sonar.api.rules.RuleFinder; +import org.sonar.api.utils.ValidationMessages; +import org.sonar.squidbridge.annotations.AnnotationBasedProfileBuilder; + +public class GherkinProfile extends ProfileDefinition { + + private static final String SONARQUBE_WAY_PROFILE_NAME = "SonarQube Way"; + private final RuleFinder ruleFinder; + + public GherkinProfile(RuleFinder ruleFinder) { + this.ruleFinder = ruleFinder; + } + + @Override + public RulesProfile createProfile(ValidationMessages messages) { + AnnotationBasedProfileBuilder annotationBasedProfileBuilder = new AnnotationBasedProfileBuilder(ruleFinder); + return annotationBasedProfileBuilder.build( + GherkinRulesDefinition.REPOSITORY_KEY, + SONARQUBE_WAY_PROFILE_NAME, + GherkinLanguage.KEY, + GherkinRulesDefinition.getChecks(), + messages); + } + +} diff --git a/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/GherkinRulesDefinition.java b/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/GherkinRulesDefinition.java new file mode 100644 index 0000000..2222bab --- /dev/null +++ b/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/GherkinRulesDefinition.java @@ -0,0 +1,70 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin; + +import com.google.common.collect.ImmutableList; +import org.sonar.api.server.rule.RulesDefinition; +import org.sonar.gherkin.checks.*; +import org.sonar.squidbridge.annotations.AnnotationBasedRulesDefinition; + +import java.util.Collection; + +public class GherkinRulesDefinition implements RulesDefinition { + + public static final String REPOSITORY_KEY = "gherkin"; + private static final String REPOSITORY_NAME = "SonarQube"; + + @Override + public void define(Context context) { + NewRepository repository = context + .createRepository(REPOSITORY_KEY, GherkinLanguage.KEY) + .setName(REPOSITORY_NAME); + + new AnnotationBasedRulesDefinition(repository, GherkinLanguage.KEY).addRuleClasses(false, getChecks()); + repository.done(); + } + + @SuppressWarnings("rawtypes") + public static Collection getChecks() { + return ImmutableList.of( + AllowedTagsCheck.class, + BOMCheck.class, + CommentConventionCheck.class, + CommentRegularExpressionCheck.class, + EndLineCharactersCheck.class, + FileNameCheck.class, + FixmeTagPresenceCheck.class, + IncompleteExamplesTableCheck.class, + IndentationCheck.class, + MaxNumberScenariosCheck.class, + MaxNumberStepsCheck.class, + MissingNewlineAtEndOfFileCheck.class, + NoFeatureCheck.class, + NoScenarioCheck.class, + ParsingErrorCheck.class, + StarStepPrefixCheck.class, + TabCharacterCheck.class, + TagNameCheck.class, + TodoTagPresenceCheck.class, + TrailingWhitespaceCheck.class + ); + } + +} diff --git a/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/GherkinSquidSensor.java b/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/GherkinSquidSensor.java new file mode 100644 index 0000000..ff5e29a --- /dev/null +++ b/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/GherkinSquidSensor.java @@ -0,0 +1,206 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin; + +import com.google.common.base.Throwables; +import com.google.common.collect.Lists; +import com.sonar.sslr.api.RecognitionException; +import com.sonar.sslr.api.typed.ActionParser; +import org.sonar.api.batch.fs.FilePredicate; +import org.sonar.api.batch.fs.FileSystem; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.InputFile.Type; +import org.sonar.api.batch.rule.CheckFactory; +import org.sonar.api.batch.sensor.Sensor; +import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.batch.sensor.SensorDescriptor; +import org.sonar.api.batch.sensor.issue.NewIssue; +import org.sonar.api.batch.sensor.issue.NewIssueLocation; +import org.sonar.api.rule.RuleKey; +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; +import org.sonar.gherkin.parser.GherkinParserBuilder; +import org.sonar.gherkin.visitors.CharsetAwareVisitor; +import org.sonar.gherkin.visitors.GherkinVisitorContext; +import org.sonar.gherkin.visitors.SyntaxHighlighterVisitor; +import org.sonar.gherkin.visitors.metrics.MetricsVisitor; +import org.sonar.plugins.gherkin.api.CustomGherkinRulesDefinition; +import org.sonar.plugins.gherkin.api.GherkinCheck; +import org.sonar.plugins.gherkin.api.tree.GherkinDocumentTree; +import org.sonar.plugins.gherkin.api.tree.Tree; +import org.sonar.plugins.gherkin.api.visitors.TreeVisitor; +import org.sonar.plugins.gherkin.api.visitors.issue.Issue; +import org.sonar.gherkin.checks.ParsingErrorCheck; +import org.sonar.squidbridge.ProgressReport; +import org.sonar.squidbridge.api.AnalysisException; + +import javax.annotation.Nullable; +import java.io.File; +import java.io.InterruptedIOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class GherkinSquidSensor implements Sensor { + + private static final Logger LOG = Loggers.get(GherkinSquidSensor.class); + + private final FileSystem fileSystem; + private final GherkinChecks checks; + private final ActionParser parser; + private final FilePredicate mainFilePredicate; + private IssueSaver issueSaver; + private RuleKey parsingErrorRuleKey = null; + + public GherkinSquidSensor(FileSystem fileSystem, CheckFactory checkFactory) { + this(fileSystem, checkFactory, null); + } + + public GherkinSquidSensor(FileSystem fileSystem, CheckFactory checkFactory, @Nullable CustomGherkinRulesDefinition[] customRulesDefinition) { + this.fileSystem = fileSystem; + + this.mainFilePredicate = fileSystem.predicates().and( + fileSystem.predicates().hasType(Type.MAIN), + fileSystem.predicates().hasLanguage(GherkinLanguage.KEY)); + + this.parser = GherkinParserBuilder.createParser(fileSystem.encoding()); + + this.checks = GherkinChecks.createGherkinChecks(checkFactory) + .addChecks(GherkinRulesDefinition.REPOSITORY_KEY, GherkinRulesDefinition.getChecks()) + .addCustomChecks(customRulesDefinition); + } + + @Override + public void describe(SensorDescriptor descriptor) { + descriptor + .onlyOnLanguage(GherkinLanguage.KEY) + .name("Gherkin Squid Sensor") + .onlyOnFileType(Type.MAIN); + } + + @Override + public void execute(SensorContext sensorContext) { + List treeVisitors = Lists.newArrayList(); + treeVisitors.addAll(checks.visitorChecks()); + treeVisitors.add(new SyntaxHighlighterVisitor(sensorContext)); + treeVisitors.add(new MetricsVisitor(sensorContext)); + + setParsingErrorCheckIfActivated(treeVisitors); + + ProgressReport progressReport = new ProgressReport("Report about progress of Gherkin analyzer", TimeUnit.SECONDS.toMillis(10)); + progressReport.start(Lists.newArrayList(fileSystem.files(mainFilePredicate))); + + issueSaver = new IssueSaver(sensorContext, checks); + List issues = new ArrayList<>(); + + boolean success = false; + try { + for (InputFile inputFile : fileSystem.inputFiles(mainFilePredicate)) { + issues.addAll(analyzeFile(sensorContext, inputFile, treeVisitors)); + progressReport.nextFile(); + } + saveSingleFileIssues(issues); + success = true; + } finally { + stopProgressReport(progressReport, success); + } + } + + private List analyzeFile(SensorContext sensorContext, InputFile inputFile, List visitors) { + try { + GherkinDocumentTree gherkinDocument = (GherkinDocumentTree) parser.parse(new File(inputFile.absolutePath())); + return scanFile(inputFile, gherkinDocument, visitors); + + } catch (RecognitionException e) { + checkInterrupted(e); + LOG.error("Unable to parse file: " + inputFile.absolutePath()); + LOG.error(e.getMessage()); + processRecognitionException(e, sensorContext, inputFile); + + } catch (Exception e) { + checkInterrupted(e); + throw new AnalysisException("Unable to analyse file: " + inputFile.absolutePath(), e); + } + return new ArrayList<>(); + } + + private List scanFile(InputFile inputFile, GherkinDocumentTree gherkinDocument, List visitors) { + GherkinVisitorContext context = new GherkinVisitorContext(gherkinDocument, inputFile.file()); + List issues = new ArrayList<>(); + for (TreeVisitor visitor : visitors) { + if (visitor instanceof CharsetAwareVisitor) { + ((CharsetAwareVisitor) visitor).setCharset(fileSystem.encoding()); + } + if (visitor instanceof GherkinCheck) { + issues.addAll(((GherkinCheck) visitor).scanFile(context)); + } else { + visitor.scanTree(context); + } + } + return issues; + } + + private void saveSingleFileIssues(List issues) { + for (Issue issue : issues) { + issueSaver.saveIssue(issue); + } + } + + private void processRecognitionException(RecognitionException e, SensorContext sensorContext, InputFile inputFile) { + if (parsingErrorRuleKey != null) { + NewIssue newIssue = sensorContext.newIssue(); + + NewIssueLocation primaryLocation = newIssue.newLocation() + .message(e.getMessage()) + .on(inputFile) + .at(inputFile.selectLine(e.getLine())); + + newIssue + .forRule(parsingErrorRuleKey) + .at(primaryLocation) + .save(); + } + } + + private void setParsingErrorCheckIfActivated(List treeVisitors) { + for (TreeVisitor check : treeVisitors) { + if (check instanceof ParsingErrorCheck) { + parsingErrorRuleKey = checks.ruleKeyFor((GherkinCheck) check); + break; + } + } + } + + private static void stopProgressReport(ProgressReport progressReport, boolean success) { + if (success) { + progressReport.stop(); + } else { + progressReport.cancel(); + } + } + + private static void checkInterrupted(Exception e) { + Throwable cause = Throwables.getRootCause(e); + if (cause instanceof InterruptedException || cause instanceof InterruptedIOException) { + throw new AnalysisException("Analysis cancelled", e); + } + } + +} diff --git a/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/IssueSaver.java b/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/IssueSaver.java new file mode 100644 index 0000000..80d6427 --- /dev/null +++ b/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/IssueSaver.java @@ -0,0 +1,160 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin; + +import com.google.common.base.Preconditions; +import org.sonar.api.batch.fs.FileSystem; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.TextRange; +import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.batch.sensor.issue.NewIssue; +import org.sonar.api.batch.sensor.issue.NewIssueLocation; +import org.sonar.api.rule.RuleKey; +import org.sonar.plugins.gherkin.api.GherkinCheck; +import org.sonar.plugins.gherkin.api.visitors.issue.*; + +import java.util.Optional; + +public class IssueSaver { + + private final SensorContext sensorContext; + private final GherkinChecks checks; + private final FileSystem fileSystem; + + public IssueSaver(SensorContext sensorContext, GherkinChecks checks) { + this.sensorContext = sensorContext; + this.fileSystem = sensorContext.fileSystem(); + this.checks = checks; + } + + public Optional getCheck(Class type) { + return checks.all() + .stream() + .filter(r -> type.isAssignableFrom(r.getClass())) + .map(type::cast) + .findFirst(); + } + + public void saveIssue(Issue issue) { + if (issue instanceof FileIssue) { + saveFileIssue((FileIssue) issue); + } else if (issue instanceof LineIssue) { + saveLineIssue((LineIssue) issue); + } else { + savePreciseIssue((PreciseIssue) issue); + } + } + + private void savePreciseIssue(PreciseIssue issue) { + NewIssue newIssue = sensorContext.newIssue(); + InputFile primaryFile = Preconditions.checkNotNull(fileSystem.inputFile(fileSystem.predicates().is(issue.primaryLocation().file()))); + + newIssue + .forRule(ruleKey(issue.check())) + .at(newLocation(primaryFile, newIssue, issue.primaryLocation())); + + if (issue.cost() != null) { + newIssue.gap(issue.cost()); + } + + InputFile secondaryFile; + for (IssueLocation secondary : issue.secondaryLocations()) { + secondaryFile = fileSystem.inputFile(fileSystem.predicates().is(secondary.file())); + if (secondaryFile == null) { + secondaryFile = primaryFile; + } + newIssue.addLocation(newLocation(secondaryFile, newIssue, secondary)); + } + + newIssue.save(); + } + + private void saveFileIssue(FileIssue issue) { + NewIssue newIssue = sensorContext.newIssue(); + InputFile primaryFile = Preconditions.checkNotNull(fileSystem.inputFile(fileSystem.predicates().is(issue.file()))); + + NewIssueLocation primaryLocation = newIssue.newLocation() + .message(issue.message()) + .on(primaryFile); + + newIssue + .forRule(ruleKey(issue.check())) + .at(primaryLocation); + + if (issue.cost() != null) { + newIssue.gap(issue.cost()); + } + + InputFile secondaryFile; + for (IssueLocation secondary : issue.secondaryLocations()) { + secondaryFile = fileSystem.inputFile(fileSystem.predicates().is(secondary.file())); + if (secondaryFile == null) { + secondaryFile = primaryFile; + } + newIssue.addLocation(newLocation(secondaryFile, newIssue, secondary)); + } + + newIssue.save(); + } + + private void saveLineIssue(LineIssue issue) { + NewIssue newIssue = sensorContext.newIssue(); + InputFile primaryFile = Preconditions.checkNotNull(fileSystem.inputFile(fileSystem.predicates().is(issue.file()))); + + NewIssueLocation primaryLocation = newIssue.newLocation() + .message(issue.message()) + .on(primaryFile) + .at(primaryFile.selectLine(issue.line())); + + newIssue + .forRule(ruleKey(issue.check())) + .at(primaryLocation); + + if (issue.cost() != null) { + newIssue.gap(issue.cost()); + } + + newIssue.save(); + } + + private NewIssueLocation newLocation(InputFile inputFile, NewIssue issue, IssueLocation location) { + TextRange range = inputFile.newRange( + location.startLine(), location.startLineOffset(), location.endLine(), location.endLineOffset()); + + NewIssueLocation newLocation = issue.newLocation() + .on(inputFile) + .at(range); + + if (location.message() != null) { + newLocation.message(location.message()); + } + return newLocation; + } + + private RuleKey ruleKey(GherkinCheck check) { + Preconditions.checkNotNull(check); + RuleKey ruleKey = checks.ruleKeyFor(check); + if (ruleKey == null) { + throw new IllegalStateException("No rule key found for a rule"); + } + return ruleKey; + } + +} diff --git a/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/package-info.java b/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/package-info.java new file mode 100644 index 0000000..5b735bc --- /dev/null +++ b/sonar-gherkin-plugin/src/main/java/org/sonar/plugins/gherkin/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +@ParametersAreNonnullByDefault +package org.sonar.plugins.gherkin; + +import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/sonar-gherkin-plugin/src/test/java/org/sonar/plugins/gherkin/GherkinLanguageTest.java b/sonar-gherkin-plugin/src/test/java/org/sonar/plugins/gherkin/GherkinLanguageTest.java new file mode 100644 index 0000000..a0d59d2 --- /dev/null +++ b/sonar-gherkin-plugin/src/test/java/org/sonar/plugins/gherkin/GherkinLanguageTest.java @@ -0,0 +1,43 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin; + +import org.junit.Test; +import org.sonar.plugins.gherkin.GherkinLanguage; + +import static org.fest.assertions.Assertions.assertThat; + +public class GherkinLanguageTest { + + @Test + public void language_key_and_name() { + GherkinLanguage gherkinLanguage = new GherkinLanguage(); + assertThat(gherkinLanguage.getKey()).isEqualTo("gherkin"); + assertThat(gherkinLanguage.getName()).isEqualTo("Gherkin"); + } + + @Test + public void file_suffix() { + GherkinLanguage gherkinLanguage = new GherkinLanguage(); + assertThat(gherkinLanguage.getFileSuffixes()).hasSize(1); + assertThat(gherkinLanguage.getFileSuffixes()[0]).isEqualTo("feature"); + } + +} diff --git a/sonar-gherkin-plugin/src/test/java/org/sonar/plugins/gherkin/GherkinPluginTest.java b/sonar-gherkin-plugin/src/test/java/org/sonar/plugins/gherkin/GherkinPluginTest.java new file mode 100644 index 0000000..f276704 --- /dev/null +++ b/sonar-gherkin-plugin/src/test/java/org/sonar/plugins/gherkin/GherkinPluginTest.java @@ -0,0 +1,45 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin; + +import org.junit.Test; +import org.sonar.api.Plugin; +import org.sonar.api.utils.Version; + +import static org.fest.assertions.Assertions.assertThat; + +public class GherkinPluginTest { + + @Test + public void should_get_the_right_version() { + Plugin.Context context = new Plugin.Context(Version.create(5, 6)); + new GherkinPlugin().define(context); + assertThat(context.getSonarQubeVersion().major()).isEqualTo(5); + assertThat(context.getSonarQubeVersion().minor()).isEqualTo(6); + } + + @Test + public void should_get_the_right_number_of_extensions() { + Plugin.Context context = new Plugin.Context(Version.create(5, 6)); + new GherkinPlugin().define(context); + assertThat(context.getExtensions()).hasSize(4); + } + +} diff --git a/sonar-gherkin-plugin/src/test/java/org/sonar/plugins/gherkin/GherkinProfileTest.java b/sonar-gherkin-plugin/src/test/java/org/sonar/plugins/gherkin/GherkinProfileTest.java new file mode 100644 index 0000000..e14cfac --- /dev/null +++ b/sonar-gherkin-plugin/src/test/java/org/sonar/plugins/gherkin/GherkinProfileTest.java @@ -0,0 +1,61 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin; + +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.sonar.api.profiles.RulesProfile; +import org.sonar.api.rules.Rule; +import org.sonar.api.rules.RuleFinder; +import org.sonar.api.utils.ValidationMessages; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class GherkinProfileTest { + + @Test + public void should_create_sonarqube_way_profile() { + ValidationMessages validation = ValidationMessages.create(); + GherkinProfile definition = new GherkinProfile(universalRuleFinder()); + RulesProfile profile = definition.createProfile(validation); + + assertThat(profile.getName()).isEqualTo("SonarQube Way"); + assertThat(profile.getLanguage()).isEqualTo("gherkin"); + assertThat(profile.getActiveRulesByRepository("gherkin")).hasSize(17); + assertThat(validation.hasErrors()).isFalse(); + } + + private RuleFinder universalRuleFinder() { + RuleFinder ruleFinder = mock(RuleFinder.class); + when(ruleFinder.findByKey(anyString(), anyString())).thenAnswer(new Answer() { + @Override + public Rule answer(InvocationOnMock iom) throws Throwable { + return Rule.create((String) iom.getArguments()[0], (String) iom.getArguments()[1], (String) iom.getArguments()[1]); + } + }); + + return ruleFinder; + } + +} diff --git a/sonar-gherkin-plugin/src/test/java/org/sonar/plugins/gherkin/GherkinRulesDefinitionTest.java b/sonar-gherkin-plugin/src/test/java/org/sonar/plugins/gherkin/GherkinRulesDefinitionTest.java new file mode 100644 index 0000000..1c43f7c --- /dev/null +++ b/sonar-gherkin-plugin/src/test/java/org/sonar/plugins/gherkin/GherkinRulesDefinitionTest.java @@ -0,0 +1,47 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin; + +import org.junit.Test; +import org.sonar.api.server.rule.RulesDefinition; +import org.sonar.check.Rule; +import org.sonar.gherkin.checks.TabCharacterCheck; + +import static org.fest.assertions.Assertions.assertThat; + +public class GherkinRulesDefinitionTest { + + @Test + public void test() { + GherkinRulesDefinition rulesDefinition = new GherkinRulesDefinition(); + RulesDefinition.Context context = new RulesDefinition.Context(); + rulesDefinition.define(context); + RulesDefinition.Repository repository = context.repository("gherkin"); + + assertThat(repository.name()).isEqualTo("SonarQube"); + assertThat(repository.language()).isEqualTo("gherkin"); + assertThat(repository.rules()).hasSize(20); + + RulesDefinition.Rule lineLengthRule = repository.rule(TabCharacterCheck.class.getAnnotation(Rule.class).key()); + assertThat(lineLengthRule).isNotNull(); + assertThat(lineLengthRule.name()).isEqualTo(TabCharacterCheck.class.getAnnotation(Rule.class).name()); + } + +} diff --git a/sonar-gherkin-plugin/src/test/java/org/sonar/plugins/gherkin/GherkinSquidSensorTest.java b/sonar-gherkin-plugin/src/test/java/org/sonar/plugins/gherkin/GherkinSquidSensorTest.java new file mode 100644 index 0000000..efc8402 --- /dev/null +++ b/sonar-gherkin-plugin/src/test/java/org/sonar/plugins/gherkin/GherkinSquidSensorTest.java @@ -0,0 +1,169 @@ +/* + * SonarQube Gherkin Analyzer + * Copyright (C) 2016-2016 David RACODON + * david.racodon@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.gherkin; + +import com.google.common.base.Charsets; +import org.junit.Test; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.fs.internal.FileMetadata; +import org.sonar.api.batch.rule.ActiveRules; +import org.sonar.api.batch.rule.CheckFactory; +import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; +import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor; +import org.sonar.api.batch.sensor.internal.SensorContextTester; +import org.sonar.api.batch.sensor.issue.Issue; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.rule.RuleKey; +import org.sonar.check.Rule; +import org.sonar.gherkin.checks.CommentConventionCheck; +import org.sonar.gherkin.checks.MissingNewlineAtEndOfFileCheck; + +import java.io.File; +import java.nio.charset.Charset; +import java.util.Collection; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +public class GherkinSquidSensorTest { + + private final File baseDir = new File("src/test/resources"); + private final SensorContextTester context = SensorContextTester.create(baseDir); + private CheckFactory checkFactory = new CheckFactory(mock(ActiveRules.class)); + + @Test + public void should_create_a_valid_sensor_descriptor() { + DefaultSensorDescriptor descriptor = new DefaultSensorDescriptor(); + createGherkinSquidSensor().describe(descriptor); + assertThat(descriptor.name()).isEqualTo("Gherkin Squid Sensor"); + assertThat(descriptor.languages()).containsOnly("gherkin"); + assertThat(descriptor.type()).isEqualTo(InputFile.Type.MAIN); + } + + @Test + public void should_execute_and_compute_valid_measures_on_UTF8_file() { + String relativePath = "my-feature.feature"; + inputFile(relativePath, Charsets.UTF_8); + createGherkinSquidSensor().execute(context); + assertMeasure("moduleKey:" + relativePath); + } + + @Test + public void should_execute_and_compute_valid_measures_on_UTF8_with_BOM_file() { + String relativePath = "my-feature-bom.feature"; + inputFile(relativePath, Charsets.UTF_8); + createGherkinSquidSensor().execute(context); + assertMeasure("moduleKey:" + relativePath); + } + + private void assertMeasure(String key) { + assertThat(context.measure(key, CoreMetrics.NCLOC).value()).isEqualTo(9); + assertThat(context.measure(key, CoreMetrics.STATEMENTS).value()).isEqualTo(6); + assertThat(context.measure(key, CoreMetrics.COMMENT_LINES).value()).isEqualTo(2); + assertThat(context.measure(key, CoreMetrics.FUNCTIONS).value()).isEqualTo(2); + assertThat(context.measure(key, CoreMetrics.CLASSES).value()).isEqualTo(1); + } + + @Test + public void should_execute_and_save_issues_on_UTF8_with_BOM_file() { + inputFile("my-feature-bom.feature", Charsets.UTF_8); + + ActiveRules activeRules = (new ActiveRulesBuilder()) + .create(RuleKey.of(GherkinRulesDefinition.REPOSITORY_KEY, CommentConventionCheck.class.getAnnotation(Rule.class).key())) + .activate() + .create(RuleKey.of(GherkinRulesDefinition.REPOSITORY_KEY, MissingNewlineAtEndOfFileCheck.class.getAnnotation(Rule.class).key())) + .activate() + .build(); + checkFactory = new CheckFactory(activeRules); + + createGherkinSquidSensor().execute(context); + + assertThat(context.allIssues()).hasSize(3); + } + + @Test + public void should_execute_and_save_issues_on_UTF8_file() { + inputFile("my-feature.feature", Charsets.UTF_8); + + ActiveRules activeRules = (new ActiveRulesBuilder()) + .create(RuleKey.of(GherkinRulesDefinition.REPOSITORY_KEY, CommentConventionCheck.class.getAnnotation(Rule.class).key())) + .activate() + .create(RuleKey.of(GherkinRulesDefinition.REPOSITORY_KEY, MissingNewlineAtEndOfFileCheck.class.getAnnotation(Rule.class).key())) + .activate() + .build(); + checkFactory = new CheckFactory(activeRules); + + createGherkinSquidSensor().execute(context); + + assertThat(context.allIssues()).hasSize(3); + } + + @Test + public void should_raise_an_issue_because_the_parsing_error_rule_is_activated() { + String relativePath = "parsing-error.feature"; + inputFile(relativePath, Charsets.UTF_8); + + ActiveRules activeRules = (new ActiveRulesBuilder()) + .create(RuleKey.of(GherkinRulesDefinition.REPOSITORY_KEY, "S2260")) + .activate() + .build(); + + checkFactory = new CheckFactory(activeRules); + + context.setActiveRules(activeRules); + createGherkinSquidSensor().execute(context); + Collection issues = context.allIssues(); + assertThat(issues).hasSize(1); + Issue issue = issues.iterator().next(); + assertThat(issue.primaryLocation().textRange().start().line()).isEqualTo(1); + } + + @Test + public void should_not_raise_any_issue_because_the_parsing_error_rule_is_not_activated() { + String relativePath = "parsing-error.feature"; + inputFile(relativePath, Charsets.UTF_8); + + ActiveRules activeRules = new ActiveRulesBuilder().build(); + checkFactory = new CheckFactory(activeRules); + + context.setActiveRules(activeRules); + createGherkinSquidSensor().execute(context); + Collection issues = context.allIssues(); + assertThat(issues).hasSize(0); + } + + private GherkinSquidSensor createGherkinSquidSensor() { + return new GherkinSquidSensor(context.fileSystem(), checkFactory, null); + } + + private void inputFile(String relativePath, Charset charset) { + DefaultInputFile inputFile = new DefaultInputFile("moduleKey", relativePath) + .setModuleBaseDir(baseDir.toPath()) + .setType(InputFile.Type.MAIN) + .setLanguage(GherkinLanguage.KEY); + + context.fileSystem().setEncoding(charset); + context.fileSystem().add(inputFile); + + inputFile.initMetadata(new FileMetadata().readMetadata(inputFile.file(), charset)); + } + +} diff --git a/sonar-gherkin-plugin/src/test/resources/my-feature-bom.feature b/sonar-gherkin-plugin/src/test/resources/my-feature-bom.feature new file mode 100644 index 0000000..60ddcfb --- /dev/null +++ b/sonar-gherkin-plugin/src/test/resources/my-feature-bom.feature @@ -0,0 +1,13 @@ +Feature: My feature... + + #blabla... + #blabla... + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... \ No newline at end of file diff --git a/sonar-gherkin-plugin/src/test/resources/my-feature.feature b/sonar-gherkin-plugin/src/test/resources/my-feature.feature new file mode 100644 index 0000000..ac00046 --- /dev/null +++ b/sonar-gherkin-plugin/src/test/resources/my-feature.feature @@ -0,0 +1,13 @@ +Feature: My feature... + + #blabla... + #blabla... + Scenario: Scenario 1 + Given blabla... + When blabla... + Then blabla... + + Scenario: Scenario 2 + Given blabla... + When blabla... + Then blabla... \ No newline at end of file diff --git a/sonar-gherkin-plugin/src/test/resources/parsing-error.feature b/sonar-gherkin-plugin/src/test/resources/parsing-error.feature new file mode 100644 index 0000000..e8d2801 --- /dev/null +++ b/sonar-gherkin-plugin/src/test/resources/parsing-error.feature @@ -0,0 +1 @@ +Background: diff --git a/travis.sh b/travis.sh new file mode 100755 index 0000000..bd77d56 --- /dev/null +++ b/travis.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +mvn -B clean install + +if [ "$TRAVIS_PULL_REQUEST" != "false" ] && [ "$SQ_VERSION" == "LTS" ]; then + mvn -B sonar:sonar \ + -Dsonar.host.url=https://sonarqube.com \ + -Dsonar.analysis.mode=preview \ + -Dsonar.github.pullRequest=$TRAVIS_PULL_REQUEST \ + -Dsonar.github.repository=$TRAVIS_REPO_SLUG \ + -Dsonar.github.oauth=$GITHUB_TOKEN \ + -Dsonar.login=$SONAR_TOKEN + +elif [ "$TRAVIS_BRANCH" == "master" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$SQ_VERSION" == "LTS" ]; then + mvn -B sonar:sonar -Dsonar.host.url=https://sonarqube.com -Dsonar.login=$SONAR_TOKEN +fi + +cd its +mvn -B clean install -Dsonar.runtimeVersion=$SQ_VERSION