]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-16610 added example plugin to test education topics in SonarQube
authorLukasz Jarocki <lukasz.jarocki@sonarsource.com>
Wed, 20 Jul 2022 12:08:09 +0000 (14:08 +0200)
committersonartech <sonartech@sonarsource.com>
Thu, 21 Jul 2022 20:03:05 +0000 (20:03 +0000)
20 files changed:
plugins/sonar-education-plugin/build.gradle [new file with mode: 0644]
plugins/sonar-education-plugin/src/main/java/org/sonar/education/EducationBuiltInQualityProfileDefinition.java [new file with mode: 0644]
plugins/sonar-education-plugin/src/main/java/org/sonar/education/EducationLanguage.java [new file with mode: 0644]
plugins/sonar-education-plugin/src/main/java/org/sonar/education/EducationPlugin.java [new file with mode: 0644]
plugins/sonar-education-plugin/src/main/java/org/sonar/education/EducationRulesDefinition.java [new file with mode: 0644]
plugins/sonar-education-plugin/src/main/java/org/sonar/education/sensors/EducationPrinciplesSensor.java [new file with mode: 0644]
plugins/sonar-education-plugin/src/main/java/org/sonar/education/sensors/EducationRuleSensor.java [new file with mode: 0644]
plugins/sonar-education-plugin/src/main/java/org/sonar/education/sensors/EducationWithContextsSensor.java [new file with mode: 0644]
plugins/sonar-education-plugin/src/main/java/org/sonar/education/sensors/EducationWithDetectedContextSensor.java [new file with mode: 0644]
plugins/sonar-education-plugin/src/main/java/org/sonar/education/sensors/EducationWithSingleContextSensor.java [new file with mode: 0644]
plugins/sonar-education-plugin/src/test/java/org/sonar/education/EducationBuiltInQualityProfileDefinitionTest.java [new file with mode: 0644]
plugins/sonar-education-plugin/src/test/java/org/sonar/education/EducationLanguageTest.java [new file with mode: 0644]
plugins/sonar-education-plugin/src/test/java/org/sonar/education/EducationPluginTest.java [new file with mode: 0644]
plugins/sonar-education-plugin/src/test/java/org/sonar/education/EducationRulesDefinitionTest.java [new file with mode: 0644]
plugins/sonar-education-plugin/src/test/java/org/sonar/education/sensors/EducationPrinciplesSensorTest.java [new file with mode: 0644]
plugins/sonar-education-plugin/src/test/java/org/sonar/education/sensors/EducationSensorTest.java [new file with mode: 0644]
plugins/sonar-education-plugin/src/test/java/org/sonar/education/sensors/EducationWithContextsSensorTest.java [new file with mode: 0644]
plugins/sonar-education-plugin/src/test/java/org/sonar/education/sensors/EducationWithDetectedContextSensorTest.java [new file with mode: 0644]
plugins/sonar-education-plugin/src/test/java/org/sonar/education/sensors/EducationWithSingleContextSensorTest.java [new file with mode: 0644]
settings.gradle

diff --git a/plugins/sonar-education-plugin/build.gradle b/plugins/sonar-education-plugin/build.gradle
new file mode 100644 (file)
index 0000000..71bad64
--- /dev/null
@@ -0,0 +1,43 @@
+configurations {
+    testImplementation.extendsFrom(compileOnly)
+}
+
+dependencies {
+    compileOnly 'org.sonarsource.api.plugin:sonar-plugin-api'
+
+    testCompile 'junit:junit'
+    testCompile 'org.assertj:assertj-core'
+    testCompile 'org.mockito:mockito-core'
+    testCompile project(':sonar-plugin-api-impl')
+}
+
+jar {
+    manifest {
+        attributes(
+                'Plugin-Key': 'education',
+                'Plugin-Version': project.version,
+                'Plugin-Class': 'org.sonar.education.EducationPlugin',
+                'Plugin-ChildFirstClassLoader': 'false',
+                'Sonar-Version': project.version,
+                'SonarLint-Supported': 'true',
+                'Plugin-Name': 'Education'
+        )
+    }
+    into('META-INF/lib') {
+        from configurations.compileClasspath
+    }
+}
+
+artifactoryPublish.skip = false
+
+publishing {
+    publications {
+        mavenJava(MavenPublication) {
+            from components.java
+            if (release) {
+                artifact sourcesJar
+                artifact javadocJar
+            }
+        }
+    }
+}
diff --git a/plugins/sonar-education-plugin/src/main/java/org/sonar/education/EducationBuiltInQualityProfileDefinition.java b/plugins/sonar-education-plugin/src/main/java/org/sonar/education/EducationBuiltInQualityProfileDefinition.java
new file mode 100644 (file)
index 0000000..14a36f8
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT 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.education;
+
+import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
+
+import static org.sonar.education.EducationRulesDefinition.EDUCATION_KEY;
+import static org.sonar.education.EducationRulesDefinition.EDUCATION_RULE_REPOSITORY_KEY;
+import static org.sonar.education.sensors.EducationPrinciplesSensor.EDUCATION_WITH_GENERIC_CONCEPTS_RULE_KEY;
+import static org.sonar.education.sensors.EducationWithContextsSensor.EDUCATION_WITH_CONTEXTS_RULE_KEY;
+import static org.sonar.education.sensors.EducationWithDetectedContextSensor.EDUCATION_WITH_DETECTED_CONTEXT_RULE_KEY;
+import static org.sonar.education.sensors.EducationWithSingleContextSensor.EDUCATION_WITH_SINGLE_CONTEXT_RULE_KEY;
+
+public class EducationBuiltInQualityProfileDefinition implements BuiltInQualityProfilesDefinition {
+  @Override
+  public void define(Context context) {
+    NewBuiltInQualityProfile profile = context.createBuiltInQualityProfile("Built in QP for Education", EDUCATION_KEY);
+    profile.setDefault(true);
+    profile.activateRule(EDUCATION_RULE_REPOSITORY_KEY, EDUCATION_WITH_GENERIC_CONCEPTS_RULE_KEY);
+    profile.activateRule(EDUCATION_RULE_REPOSITORY_KEY, EDUCATION_WITH_SINGLE_CONTEXT_RULE_KEY);
+    profile.activateRule(EDUCATION_RULE_REPOSITORY_KEY, EDUCATION_WITH_CONTEXTS_RULE_KEY);
+    profile.activateRule(EDUCATION_RULE_REPOSITORY_KEY, EDUCATION_WITH_DETECTED_CONTEXT_RULE_KEY);
+    profile.done();
+  }
+}
diff --git a/plugins/sonar-education-plugin/src/main/java/org/sonar/education/EducationLanguage.java b/plugins/sonar-education-plugin/src/main/java/org/sonar/education/EducationLanguage.java
new file mode 100644 (file)
index 0000000..5487da0
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT 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.education;
+
+import org.sonar.api.resources.Language;
+
+public class EducationLanguage implements Language {
+
+  @Override
+  public String getKey() {
+    return EducationRulesDefinition.EDUCATION_KEY;
+  }
+
+  @Override
+  public String getName() {
+    return "Education";
+  }
+
+  @Override
+  public String[] getFileSuffixes() {
+    return new String[]{".edu"};
+  }
+}
diff --git a/plugins/sonar-education-plugin/src/main/java/org/sonar/education/EducationPlugin.java b/plugins/sonar-education-plugin/src/main/java/org/sonar/education/EducationPlugin.java
new file mode 100644 (file)
index 0000000..6cae271
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT 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.education;
+
+import org.sonar.education.sensors.EducationWithContextsSensor;
+import org.sonar.education.sensors.EducationWithDetectedContextSensor;
+import org.sonar.education.sensors.EducationPrinciplesSensor;
+import org.sonar.education.sensors.EducationWithSingleContextSensor;
+import org.sonar.api.Plugin;
+
+public class EducationPlugin implements Plugin {
+  @Override
+  public void define(Context context) {
+    context.addExtensions(
+      EducationRulesDefinition.class,
+      EducationLanguage.class,
+      EducationWithContextsSensor.class,
+      EducationWithDetectedContextSensor.class,
+      EducationPrinciplesSensor.class,
+      EducationWithSingleContextSensor.class,
+      EducationBuiltInQualityProfileDefinition.class);
+
+  }
+}
diff --git a/plugins/sonar-education-plugin/src/main/java/org/sonar/education/EducationRulesDefinition.java b/plugins/sonar-education-plugin/src/main/java/org/sonar/education/EducationRulesDefinition.java
new file mode 100644 (file)
index 0000000..7988761
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT 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.education;
+
+import org.sonar.api.server.rule.RuleDescriptionSection;
+import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.education.sensors.EducationPrinciplesSensor;
+import org.sonar.education.sensors.EducationWithContextsSensor;
+import org.sonar.education.sensors.EducationWithDetectedContextSensor;
+
+import static org.sonar.education.sensors.EducationWithSingleContextSensor.EDUCATION_WITH_SINGLE_CONTEXT_RULE_KEY;
+import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.ASSESS_THE_PROBLEM_SECTION_KEY;
+import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.HOW_TO_FIX_SECTION_KEY;
+import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.INTRODUCTION_SECTION_KEY;
+import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.RESOURCES_SECTION_KEY;
+import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.ROOT_CAUSE_SECTION_KEY;
+
+public class EducationRulesDefinition implements RulesDefinition {
+
+  public static final String EDUCATION_RULE_REPOSITORY_KEY = "edu";
+  public static final String EDUCATION_KEY = "education";
+
+  private static final String IGNORED_FAKE_SECTION = "fake_section_to_be_ignored";
+
+  public static final String[] CONTEXTS = {"spring", "hibernate", "apache-commons", "vaadin", "mybatis"};
+
+  private static final String HTML_LOREM_IPSUM = "<a href=\"https://google.com\">Lorem</a> ipsum dolor sit amet, consectetur adipiscing " +
+    "elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco " +
+    "laboris nisi ut aliquip ex ea commodo consequat.<br />Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu " +
+    "fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
+
+  @Override
+  public void define(Context context) {
+    NewRepository repo = context.createRepository(EDUCATION_RULE_REPOSITORY_KEY, EDUCATION_KEY);
+
+    createRuleWithDescriptionSectionsAndEducationPrinciples(repo);
+    createRuleWithDescriptionSectionsAndSingleContext(repo);
+    createRuleWithDescriptionSectionsAndMultipleContexts(repo);
+    createRuleWithDescriptionSectionsAndMultipleContextsIncludingOneDetected(repo);
+
+    repo.done();
+  }
+
+  private void createRuleWithDescriptionSectionsAndEducationPrinciples(NewRepository repo) {
+    String[] educationPrinciples = {"defense_in_depth", "least_trust_principle"};
+    String ruleKey = EducationPrinciplesSensor.EDUCATION_WITH_GENERIC_CONCEPTS_RULE_KEY;
+    NewRule ruleWithSingleContext = repo.createRule(ruleKey).setName("Rule with description sections and education principles")
+      .addTags(EDUCATION_KEY);
+
+    ruleWithSingleContext
+      .setHtmlDescription(String.format("This rule contains description sections. To trigger an issue using this rule you need to " +
+          "scan any text file with a line containing %s key word. This rule also contains 2 education principles - %s and %s",
+        ruleKey, educationPrinciples[0], educationPrinciples[1]))
+      .addEducationPrincipleKeys(educationPrinciples);
+
+    addNonContextualizedDescriptionSections(ruleWithSingleContext);
+    descriptionSection(HOW_TO_FIX_SECTION_KEY);
+  }
+
+  private void createRuleWithDescriptionSectionsAndSingleContext(NewRepository repo) {
+    String ruleKey = EDUCATION_WITH_SINGLE_CONTEXT_RULE_KEY;
+    NewRule ruleWithSingleContext = repo.createRule(ruleKey).setName("Rule with description sections and single " +
+        "contexts for 'how to fix'")
+      .addTags(EDUCATION_KEY);
+
+    ruleWithSingleContext
+      .setHtmlDescription(String.format("This rule contains description sections and single context for 'how to fix' section. To " +
+        "trigger an issue using this rule you need to scan any text file with a line containing %s key word.", ruleKey));
+
+    addNonContextualizedDescriptionSections(ruleWithSingleContext);
+
+    ruleWithSingleContext.addDescriptionSection(descriptionHowToFixSectionWithContext(CONTEXTS[0]));
+  }
+
+  private void createRuleWithDescriptionSectionsAndMultipleContexts(NewRepository repo) {
+    NewRule ruleWithMultipleContexts = repo.createRule(EducationWithContextsSensor.EDUCATION_WITH_CONTEXTS_RULE_KEY)
+      .setName("Rule with description sections and multiple contexts for 'how to fix'")
+      .addTags(EDUCATION_KEY);
+
+    ruleWithMultipleContexts
+      .setHtmlDescription(String.format("This rule contains description sections and multiple contexts for 'how to fix' section. To trigger " +
+          "an issue using this rule you need to scan any text file with a line containing %s keyword.",
+        EducationWithContextsSensor.EDUCATION_WITH_CONTEXTS_RULE_KEY));
+
+    addNonContextualizedDescriptionSections(ruleWithMultipleContexts);
+
+    for (String context : CONTEXTS) {
+      ruleWithMultipleContexts.addDescriptionSection(descriptionHowToFixSectionWithContext(context));
+    }
+  }
+
+  private void createRuleWithDescriptionSectionsAndMultipleContextsIncludingOneDetected(NewRepository repo) {
+    NewRule ruleWithMultipleContexts = repo.createRule(EducationWithDetectedContextSensor.EDUCATION_WITH_DETECTED_CONTEXT_RULE_KEY)
+      .setName("Rule with description sections and multiple contexts (including one detected) for 'how to fix'")
+      .addTags(EDUCATION_KEY);
+
+    ruleWithMultipleContexts
+      .setHtmlDescription(String.format("This rule contains description sections and multiple contexts (including one detected) for " +
+          "'how to fix' section. To trigger an issue using this rule you need to scan any text file with a line containing %s keyword.",
+        EducationWithDetectedContextSensor.EDUCATION_WITH_DETECTED_CONTEXT_RULE_KEY));
+
+    addNonContextualizedDescriptionSections(ruleWithMultipleContexts);
+
+    for (String context : CONTEXTS) {
+      ruleWithMultipleContexts.addDescriptionSection(descriptionHowToFixSectionWithContext(context));
+    }
+  }
+
+  private static void addNonContextualizedDescriptionSections(NewRule newRule) {
+    newRule.addDescriptionSection(descriptionSection(INTRODUCTION_SECTION_KEY))
+      .addDescriptionSection(descriptionSection(ROOT_CAUSE_SECTION_KEY))
+      .addDescriptionSection(descriptionSection(ASSESS_THE_PROBLEM_SECTION_KEY))
+      .addDescriptionSection(descriptionSection(RESOURCES_SECTION_KEY))
+      .addDescriptionSection(descriptionSection(IGNORED_FAKE_SECTION));
+  }
+
+  private static RuleDescriptionSection descriptionHowToFixSectionWithContext(String context) {
+    var ruleContext = new org.sonar.api.server.rule.Context(context, context);
+    return RuleDescriptionSection.builder()
+      .sectionKey(HOW_TO_FIX_SECTION_KEY)
+      .context(ruleContext)
+      .htmlContent(String.format("%s: %s", HOW_TO_FIX_SECTION_KEY, HTML_LOREM_IPSUM))
+      .build();
+  }
+
+  private static RuleDescriptionSection descriptionSection(String sectionKey) {
+    return RuleDescriptionSection.builder()
+      .sectionKey(sectionKey)
+      .htmlContent(String.format("%s: %s", sectionKey, HTML_LOREM_IPSUM))
+      .build();
+  }
+}
diff --git a/plugins/sonar-education-plugin/src/main/java/org/sonar/education/sensors/EducationPrinciplesSensor.java b/plugins/sonar-education-plugin/src/main/java/org/sonar/education/sensors/EducationPrinciplesSensor.java
new file mode 100644 (file)
index 0000000..66a759f
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT 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.education.sensors;
+
+import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.rule.ActiveRules;
+
+public class EducationPrinciplesSensor extends EducationRuleSensor {
+
+  public static final String EDUCATION_WITH_GENERIC_CONCEPTS_RULE_KEY = "EDUCATION";
+
+  public EducationPrinciplesSensor(FileSystem fs, ActiveRules activeRules) {
+    super(fs, activeRules, EDUCATION_WITH_GENERIC_CONCEPTS_RULE_KEY);
+  }
+}
diff --git a/plugins/sonar-education-plugin/src/main/java/org/sonar/education/sensors/EducationRuleSensor.java b/plugins/sonar-education-plugin/src/main/java/org/sonar/education/sensors/EducationRuleSensor.java
new file mode 100644 (file)
index 0000000..72be37b
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT 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.education.sensors;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.rule.ActiveRules;
+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.rule.RuleKey;
+
+import static org.sonar.education.EducationRulesDefinition.EDUCATION_KEY;
+import static org.sonar.education.EducationRulesDefinition.EDUCATION_RULE_REPOSITORY_KEY;
+
+public abstract class EducationRuleSensor implements Sensor {
+
+  private final FileSystem fs;
+  private final ActiveRules activeRules;
+  private final String ruleKeyName;
+  private final String tag;
+
+  EducationRuleSensor(FileSystem fs, ActiveRules activeRules, String ruleKey) {
+    this.fs = fs;
+    this.activeRules = activeRules;
+    this.ruleKeyName = ruleKey;
+    this.tag = ruleKey;
+  }
+
+  @Override
+  public void describe(SensorDescriptor descriptor) {
+    descriptor
+      .name("Education sensor for " + tag)
+      .createIssuesForRuleRepository(EDUCATION_RULE_REPOSITORY_KEY);
+  }
+
+  @Override
+  public void execute(SensorContext context) {
+    RuleKey ruleKey = RuleKey.of(EDUCATION_RULE_REPOSITORY_KEY, ruleKeyName);
+    if (activeRules.find(ruleKey) == null) {
+      return;
+    }
+    for (InputFile inputFile : fs.inputFiles(fs.predicates().hasLanguage(EDUCATION_KEY))) {
+      processFile(inputFile, context, ruleKey);
+    }
+  }
+
+  protected String getDetectedContext() {
+    return null;
+  }
+
+  protected void processFile(InputFile inputFile, SensorContext context, RuleKey ruleKey) {
+    try {
+      int[] lineCounter = {1};
+      try (InputStreamReader isr = new InputStreamReader(inputFile.inputStream(), inputFile.charset());
+           BufferedReader reader = new BufferedReader(isr)) {
+        reader.lines().forEachOrdered(lineStr -> {
+          int startIndex = -1;
+          while ((startIndex = lineStr.indexOf(tag, startIndex + 1)) != -1) {
+            NewIssue newIssue = context.newIssue();
+            newIssue
+              .forRule(ruleKey)
+              .at(newIssue.newLocation()
+                .on(inputFile)
+                .at(inputFile.newRange(lineCounter[0], startIndex, lineCounter[0], startIndex + tag.length())))
+              .setRuleDescriptionContextKey(getDetectedContext())
+              .save();
+          }
+          lineCounter[0]++;
+        });
+      }
+    } catch (IOException e) {
+      throw new IllegalStateException("Fail to process " + inputFile, e);
+    }
+  }
+}
diff --git a/plugins/sonar-education-plugin/src/main/java/org/sonar/education/sensors/EducationWithContextsSensor.java b/plugins/sonar-education-plugin/src/main/java/org/sonar/education/sensors/EducationWithContextsSensor.java
new file mode 100644 (file)
index 0000000..00e9365
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT 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.education.sensors;
+
+import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.rule.ActiveRules;
+
+public class EducationWithContextsSensor extends EducationRuleSensor {
+
+  public static final String EDUCATION_WITH_CONTEXTS_RULE_KEY = "CONTEXTS";
+
+  public EducationWithContextsSensor(FileSystem fs, ActiveRules activeRules) {
+    super(fs, activeRules, EDUCATION_WITH_CONTEXTS_RULE_KEY);
+  }
+}
diff --git a/plugins/sonar-education-plugin/src/main/java/org/sonar/education/sensors/EducationWithDetectedContextSensor.java b/plugins/sonar-education-plugin/src/main/java/org/sonar/education/sensors/EducationWithDetectedContextSensor.java
new file mode 100644 (file)
index 0000000..1163dec
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT 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.education.sensors;
+
+import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.rule.ActiveRules;
+
+import static org.sonar.education.EducationRulesDefinition.CONTEXTS;
+
+public class EducationWithDetectedContextSensor extends EducationRuleSensor {
+
+  public static final String EDUCATION_WITH_DETECTED_CONTEXT_RULE_KEY = "DETECTED_CONTEXT";
+
+  public EducationWithDetectedContextSensor(FileSystem fs, ActiveRules activeRules) {
+    super(fs, activeRules, EDUCATION_WITH_DETECTED_CONTEXT_RULE_KEY);
+  }
+
+  @Override
+  protected String getDetectedContext() {
+    return CONTEXTS[0];
+  }
+}
diff --git a/plugins/sonar-education-plugin/src/main/java/org/sonar/education/sensors/EducationWithSingleContextSensor.java b/plugins/sonar-education-plugin/src/main/java/org/sonar/education/sensors/EducationWithSingleContextSensor.java
new file mode 100644 (file)
index 0000000..45e2f76
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT 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.education.sensors;
+
+import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.rule.ActiveRules;
+
+public class EducationWithSingleContextSensor extends EducationRuleSensor {
+
+  public static final String EDUCATION_WITH_SINGLE_CONTEXT_RULE_KEY = "SINGLE_CONTEXT";
+
+  public EducationWithSingleContextSensor(FileSystem fs, ActiveRules activeRules) {
+    super(fs, activeRules, EDUCATION_WITH_SINGLE_CONTEXT_RULE_KEY);
+  }
+}
diff --git a/plugins/sonar-education-plugin/src/test/java/org/sonar/education/EducationBuiltInQualityProfileDefinitionTest.java b/plugins/sonar-education-plugin/src/test/java/org/sonar/education/EducationBuiltInQualityProfileDefinitionTest.java
new file mode 100644 (file)
index 0000000..abb44b7
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT 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.education;
+
+import org.junit.Test;
+import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class EducationBuiltInQualityProfileDefinitionTest {
+
+  private final EducationBuiltInQualityProfileDefinition underTest = new EducationBuiltInQualityProfileDefinition();
+
+  @Test
+  public void define_definesAtLeast4rules() {
+    BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
+
+    underTest.define(context);
+
+    BuiltInQualityProfilesDefinition.BuiltInQualityProfile profile = context.profile("education", "Built in QP for Education");
+    assertThat(profile.isDefault()).isTrue();
+    assertThat(profile.rules()).hasSizeGreaterThanOrEqualTo(4);
+  }
+}
diff --git a/plugins/sonar-education-plugin/src/test/java/org/sonar/education/EducationLanguageTest.java b/plugins/sonar-education-plugin/src/test/java/org/sonar/education/EducationLanguageTest.java
new file mode 100644 (file)
index 0000000..623c335
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT 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.education;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class EducationLanguageTest {
+
+  private final EducationLanguage underTest = new EducationLanguage();
+
+  @Test
+  public void getFileSuffixes_notEmpty() {
+    String[] fileSuffixes = underTest.getFileSuffixes();
+
+    assertThat(fileSuffixes).isNotEmpty();
+  }
+
+  @Test
+  public void getName_notEmpty() {
+    String name = underTest.getName();
+
+    assertThat(name).isNotEmpty();
+  }
+
+  @Test
+  public void getKey_notEmpty() {
+    String key = underTest.getKey();
+
+    assertThat(key).isNotEmpty();
+  }
+}
diff --git a/plugins/sonar-education-plugin/src/test/java/org/sonar/education/EducationPluginTest.java b/plugins/sonar-education-plugin/src/test/java/org/sonar/education/EducationPluginTest.java
new file mode 100644 (file)
index 0000000..f601997
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT 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.education;
+
+import org.junit.Test;
+import org.sonar.api.Plugin;
+import org.sonar.api.SonarEdition;
+import org.sonar.api.SonarQubeSide;
+import org.sonar.api.SonarRuntime;
+import org.sonar.api.internal.PluginContextImpl;
+import org.sonar.api.internal.SonarRuntimeImpl;
+import org.sonar.api.utils.Version;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class EducationPluginTest {
+
+  @Test
+  public void define_addSomeExtensionsForSonarQube() {
+    SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(Version.parse("9.5"), SonarQubeSide.SCANNER, SonarEdition.COMMUNITY);
+    Plugin.Context context = new PluginContextImpl.Builder().setSonarRuntime(runtime).build();
+    EducationPlugin plugin = new EducationPlugin();
+
+    plugin.define(context);
+
+    assertThat(context.getExtensions()).isNotEmpty();
+  }
+}
diff --git a/plugins/sonar-education-plugin/src/test/java/org/sonar/education/EducationRulesDefinitionTest.java b/plugins/sonar-education-plugin/src/test/java/org/sonar/education/EducationRulesDefinitionTest.java
new file mode 100644 (file)
index 0000000..233bba8
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT 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.education;
+
+import java.util.List;
+import org.junit.Test;
+import org.sonar.api.server.rule.RulesDefinition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class EducationRulesDefinitionTest {
+
+  @Test
+  public void define_addsRuleDefinitions() {
+    EducationRulesDefinition educationRulesDefinition = new EducationRulesDefinition();
+
+    RulesDefinition.Context context = new RulesDefinition.Context();
+
+    educationRulesDefinition.define(context);
+
+    List<RulesDefinition.Repository> repositories = context.repositories();
+    assertThat(repositories).hasSize(1);
+
+    RulesDefinition.Repository repository = context.repositories().get(0);
+    List<RulesDefinition.Rule> rules = repository.rules();
+    assertThat(rules).hasSizeGreaterThanOrEqualTo(4);
+  }
+}
diff --git a/plugins/sonar-education-plugin/src/test/java/org/sonar/education/sensors/EducationPrinciplesSensorTest.java b/plugins/sonar-education-plugin/src/test/java/org/sonar/education/sensors/EducationPrinciplesSensorTest.java
new file mode 100644 (file)
index 0000000..8e9c9ef
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT 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.education.sensors;
+
+import java.io.IOException;
+import org.junit.Test;
+import org.sonar.api.batch.fs.internal.DefaultFileSystem;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.sensor.internal.SensorContextTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.education.sensors.EducationPrinciplesSensor.EDUCATION_WITH_GENERIC_CONCEPTS_RULE_KEY;
+
+public class EducationPrinciplesSensorTest extends EducationSensorTest {
+
+  @Test
+  public void processFile_givenCorrectTagPassed_oneSecurityHotspotWithContextsIsRaised() throws IOException {
+    DefaultInputFile inputFile = newTestFile(EDUCATION_WITH_GENERIC_CONCEPTS_RULE_KEY);
+
+    DefaultFileSystem fs = new DefaultFileSystem(temp.newFolder());
+    fs.add(inputFile);
+
+    SensorContextTester sensorContextTester = SensorContextTester.create(temp.newFolder().toPath());
+    var sensor = new EducationPrinciplesSensor(fs, activeRules);
+
+    sensor.execute(sensorContextTester);
+
+    assertThat(sensorContextTester.allIssues()).hasSize(1);
+  }
+}
diff --git a/plugins/sonar-education-plugin/src/test/java/org/sonar/education/sensors/EducationSensorTest.java b/plugins/sonar-education-plugin/src/test/java/org/sonar/education/sensors/EducationSensorTest.java
new file mode 100644 (file)
index 0000000..f8ac452
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT 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.education.sensors;
+
+import java.nio.charset.Charset;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
+import org.sonar.api.batch.rule.ActiveRule;
+import org.sonar.api.batch.rule.ActiveRules;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.education.EducationRulesDefinition.EDUCATION_KEY;
+
+public class EducationSensorTest {
+
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  protected final ActiveRules activeRules = mock(ActiveRules.class);
+
+  @Before
+  public void before() {
+    when(activeRules.find(any())).thenReturn(mock(ActiveRule.class));
+  }
+
+  protected DefaultInputFile newTestFile(String content) {
+    return new TestInputFileBuilder("foo", "hello.edu")
+      .setLanguage(EDUCATION_KEY)
+      .setContents(content)
+      .setCharset(Charset.defaultCharset())
+      .build();
+  }
+}
diff --git a/plugins/sonar-education-plugin/src/test/java/org/sonar/education/sensors/EducationWithContextsSensorTest.java b/plugins/sonar-education-plugin/src/test/java/org/sonar/education/sensors/EducationWithContextsSensorTest.java
new file mode 100644 (file)
index 0000000..55d6856
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT 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.education.sensors;
+
+import java.io.IOException;
+import org.junit.Test;
+import org.sonar.api.batch.fs.internal.DefaultFileSystem;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.sensor.internal.SensorContextTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.education.sensors.EducationWithContextsSensor.EDUCATION_WITH_CONTEXTS_RULE_KEY;
+
+public class EducationWithContextsSensorTest extends EducationSensorTest {
+
+  @Test
+  public void processFile_givenCorrectTagPassed_oneSecurityHotspotWithContextsIsRaised() throws IOException {
+    DefaultInputFile inputFile = newTestFile(EDUCATION_WITH_CONTEXTS_RULE_KEY);
+
+    DefaultFileSystem fs = new DefaultFileSystem(temp.newFolder());
+    fs.add(inputFile);
+
+    SensorContextTester sensorContextTester = SensorContextTester.create(temp.newFolder().toPath());
+    var sensor = new EducationWithContextsSensor(fs, activeRules);
+
+    sensor.execute(sensorContextTester);
+
+    assertThat(sensorContextTester.allIssues()).hasSize(1);
+  }
+}
diff --git a/plugins/sonar-education-plugin/src/test/java/org/sonar/education/sensors/EducationWithDetectedContextSensorTest.java b/plugins/sonar-education-plugin/src/test/java/org/sonar/education/sensors/EducationWithDetectedContextSensorTest.java
new file mode 100644 (file)
index 0000000..e3b6c81
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT 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.education.sensors;
+
+import java.io.IOException;
+import org.junit.Test;
+import org.sonar.api.batch.fs.internal.DefaultFileSystem;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.sensor.internal.SensorContextTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.education.sensors.EducationWithDetectedContextSensor.EDUCATION_WITH_DETECTED_CONTEXT_RULE_KEY;
+
+public class EducationWithDetectedContextSensorTest extends EducationSensorTest {
+
+  @Test
+  public void processFile_givenCorrectTagPassed_oneSecurityHotspotWithContextsIsRaised() throws IOException {
+    DefaultInputFile inputFile = newTestFile(EDUCATION_WITH_DETECTED_CONTEXT_RULE_KEY);
+
+    DefaultFileSystem fs = new DefaultFileSystem(temp.newFolder());
+    fs.add(inputFile);
+
+    SensorContextTester sensorContextTester = SensorContextTester.create(temp.newFolder().toPath());
+    var sensor = new EducationWithDetectedContextSensor(fs, activeRules);
+
+    sensor.execute(sensorContextTester);
+
+    assertThat(sensorContextTester.allIssues()).hasSize(1);
+  }
+}
diff --git a/plugins/sonar-education-plugin/src/test/java/org/sonar/education/sensors/EducationWithSingleContextSensorTest.java b/plugins/sonar-education-plugin/src/test/java/org/sonar/education/sensors/EducationWithSingleContextSensorTest.java
new file mode 100644 (file)
index 0000000..7b56e15
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT 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.education.sensors;
+
+import java.io.IOException;
+import org.junit.Test;
+import org.sonar.api.batch.fs.internal.DefaultFileSystem;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.sensor.internal.SensorContextTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.education.sensors.EducationWithSingleContextSensor.EDUCATION_WITH_SINGLE_CONTEXT_RULE_KEY;
+
+public class EducationWithSingleContextSensorTest extends EducationSensorTest {
+
+  @Test
+  public void processFile_givenCorrectTagPassed_oneSecurityHotspotWithContextsIsRaised() throws IOException {
+    DefaultInputFile inputFile = newTestFile(EDUCATION_WITH_SINGLE_CONTEXT_RULE_KEY);
+
+    DefaultFileSystem fs = new DefaultFileSystem(temp.newFolder());
+    fs.add(inputFile);
+
+    SensorContextTester sensorContextTester = SensorContextTester.create(temp.newFolder().toPath());
+    var sensor = new EducationWithSingleContextSensor(fs, activeRules);
+
+    sensor.execute(sensorContextTester);
+
+    assertThat(sensorContextTester.allIssues()).hasSize(1);
+  }
+}
index b1998de61aa3169fe3ddf85d109dbef4d373385f..6980a920f6c9d24b8b107276911cf5cf8a912960 100644 (file)
@@ -13,6 +13,7 @@ pluginManagement {
 rootProject.name = 'sonarqube'
 
 include 'plugins:sonar-xoo-plugin'
+include 'plugins:sonar-education-plugin'
 
 include 'server:sonar-auth-common'
 include 'server:sonar-auth-bitbucket'