gt:     RulesDefinition.Rule rule = repository.rule(ruleKey);
context: /*
   * 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.api.server.rule;
  
  import com.google.common.collect.ImmutableList;
  import com.google.common.collect.ImmutableSet;
  import com.google.common.collect.Ordering;
  import com.tngtech.java.junit.dataprovider.DataProvider;
  import com.tngtech.java.junit.dataprovider.DataProviderRunner;
  import com.tngtech.java.junit.dataprovider.UseDataProvider;
  import java.net.URL;
  import java.util.List;
  import java.util.Set;
  import java.util.stream.Collectors;
  import org.junit.Assume;
  import org.junit.Rule;
  import org.junit.Test;
  import org.junit.runner.RunWith;
  import org.sonar.api.impl.server.RulesDefinitionContext;
  import org.sonar.api.rule.RuleKey;
  import org.sonar.api.rule.RuleScope;
  import org.sonar.api.rule.RuleStatus;
  import org.sonar.api.rule.Severity;
  import org.sonar.api.rules.RuleType;
  import org.sonar.api.server.debt.DebtRemediationFunction;
  import org.sonar.api.utils.log.LogTester;
  
  import static org.assertj.core.api.Assertions.assertThat;
  import static org.assertj.core.api.Assertions.assertThatThrownBy;
  import static org.junit.Assert.fail;
  
  @RunWith(DataProviderRunner.class)
  public class RulesDefinitionTest {
  
    RulesDefinition.Context context = new RulesDefinitionContext();
  
    @Rule
    public LogTester logTester = new LogTester();
  
    @Test
    public void define_repositories() {
      assertThat(context.repositories()).isEmpty();
  
      context.createRepository("findbugs", "java").setName("Findbugs").done();
      context.createRepository("checkstyle", "java").done();
  
      assertThat(context.repositories()).hasSize(2);
      RulesDefinition.Repository findbugs = context.repository("findbugs");
      assertThat(findbugs).isNotNull();
      assertThat(findbugs.key()).isEqualTo("findbugs");
      assertThat(findbugs.language()).isEqualTo("java");
      assertThat(findbugs.name()).isEqualTo("Findbugs");
      assertThat(findbugs.rules()).isEmpty();
      RulesDefinition.Repository checkstyle = context.repository("checkstyle");
      assertThat(checkstyle).isNotNull();
      assertThat(checkstyle.key()).isEqualTo("checkstyle");
      assertThat(checkstyle.language()).isEqualTo("java");
  
      // default name is key
      assertThat(checkstyle.name()).isEqualTo("checkstyle");
      assertThat(checkstyle.rules()).isEmpty();
      assertThat(context.repository("unknown")).isNull();
    }
  
    @Test
    public void override_sonaranalyzer_repositories_name() {
      context.createRepository("k", "java").setName("SonarAnalyzer").done();
      RulesDefinition.Repository repo = context.repository("k");
      assertThat(repo).isNotNull();
      assertThat(repo.name()).isEqualTo("SonarQube");
    }
  
    @Test
    public void define_rules() {
      RulesDefinition.NewRepository newRepo = context.createRepository("findbugs", "java");
      newRepo.createRule("NPE")
        .setName("Detect NPE")
        .setHtmlDescription("Detect <code>java.lang.NullPointerException</code>")
        .setSeverity(Severity.BLOCKER)
        .setInternalKey("/something")
        .setStatus(RuleStatus.BETA)
        .setTags("one", "two")
        .setScope(RuleScope.ALL)
        .addOwaspTop10(RulesDefinition.OwaspTop10.A1, RulesDefinition.OwaspTop10.A3)
        .addCwe(1, 2, 123)
        .addTags("two", "three", "four");
  
      newRepo.createRule("ABC").setName("ABC").setMarkdownDescription("ABC");
      newRepo.done();
  
      RulesDefinition.Repository repo = context.repository("findbugs");
      assertThat(repo.rules()).hasSize(2);
      assertThat(repo.isExternal()).isFalse();
  
      RulesDefinition.Rule rule = repo.rule("NPE");
      assertThat(rule).isNotNull();
      assertThat(rule.scope()).isEqualTo(RuleScope.ALL);
      assertThat(rule.key()).isEqualTo("NPE");
      assertThat(rule.name()).isEqualTo("Detect NPE");
      assertThat(rule.severity()).isEqualTo(Severity.BLOCKER);
      assertThat(rule.htmlDescription()).isEqualTo("Detect <code>java.lang.NullPointerException</code>");
      assertThat(rule.markdownDescription()).isNull();
      assertThat(rule.tags()).containsOnly("one", "two", "three", "four");
      assertThat(rule.securityStandards()).containsOnly("cwe:1", "cwe:123", "cwe:2", "owaspTop10:a1", "owaspTop10:a3");
      assertThat(rule.params()).isEmpty();
      assertThat(rule.internalKey()).isEqualTo("/something");
      assertThat(rule.template()).isFalse();
      assertThat(rule.status()).isEqualTo(RuleStatus.BETA);
      assertThat(rule.toString()).hasToString("[repository=findbugs, key=NPE]");
      assertThat(rule.repository()).isSameAs(repo);
  
      RulesDefinition.Rule otherRule = repo.rule("ABC");
      assertThat(otherRule.htmlDescription()).isNull();
      assertThat(otherRule.markdownDescription()).isEqualTo("ABC");
    }
  
    @Test
    public void define_rules_with_remediation_function() {
      RulesDefinition.NewRepository newRepo = context.createRepository("common-java", "java");
      RulesDefinition.NewRule newRule = newRepo.createRule("InsufficientBranchCoverage")
        .setName("Insufficient condition coverage")
        .setHtmlDescription("Insufficient condition coverage by unit tests")
        .setSeverity(Severity.MAJOR)
        .setGapDescription("Effort to test one uncovered branch");
      newRule.setDebtRemediationFunction(newRule.debtRemediationFunctions().linearWithOffset("1h", "10min"));
      newRepo.done();
  
      RulesDefinition.Repository repo = context.repository("common-java");
      assertThat(repo.rules()).hasSize(1);
  
      RulesDefinition.Rule rule = repo.rule("InsufficientBranchCoverage");
      assertThat(rule.debtRemediationFunction().type()).isEqualTo(DebtRemediationFunction.Type.LINEAR_OFFSET);
      assertThat(rule.debtRemediationFunction().gapMultiplier()).isEqualTo("1h");
      assertThat(rule.debtRemediationFunction().baseEffort()).isEqualTo("10min");
      assertThat(rule.gapDescription()).isEqualTo("Effort to test one uncovered branch");
    }
  
    @Test
    public void define_rule_with_default_fields() {
      RulesDefinition.NewRepository newFindbugs = context.createRepository("findbugs", "java");
      newFindbugs.createRule("NPE").setName("NPE").setHtmlDescription("NPE");
      newFindbugs.done();
  
      RulesDefinition.Rule rule = context.repository("findbugs").rule("NPE");
      assertThat(rule.key()).isEqualTo("NPE");
      assertThat(rule.severity()).isEqualTo(Severity.MAJOR);
      assertThat(rule.params()).isEmpty();
      assertThat(rule.internalKey()).isNull();
      assertThat(rule.status()).isEqualTo(RuleStatus.defaultStatus());
      assertThat(rule.tags()).isEmpty();
      assertThat(rule.securityStandards()).isEmpty();
      assertThat(rule.debtRemediationFunction()).isNull();
    }
  
    @Test
    public void define_external_rules() {
      RulesDefinition.NewRepository newRepo = context.createExternalRepository("eslint", "js");
      newRepo.createRule("NPE")
        .setName("Detect NPE")
        .setHtmlDescription("Detect <code>java.lang.NullPointerException</code>")
        .setSeverity(Severity.BLOCKER)
        .setInternalKey("/something")
        .setStatus(RuleStatus.BETA)
        .setTags("one", "two")
        .setScope(RuleScope.ALL)
        .addOwaspTop10(RulesDefinition.OwaspTop10.A1, RulesDefinition.OwaspTop10.A3)
        .addCwe(1, 2, 123)
        .addTags("two", "three", "four");
  
      newRepo.createRule("ABC").setName("ABC").setMarkdownDescription("ABC");
      newRepo.done();
  
      assertThat(context.repository("eslint")).isNull();
      RulesDefinition.Repository repo = context.repository("external_eslint");
      assertThat(repo.rules()).hasSize(2);
      assertThat(repo.isExternal()).isTrue();
  
      RulesDefinition.Rule rule = repo.rule("NPE");
      assertThat(rule).isNotNull();
      assertThat(rule.scope()).isEqualTo(RuleScope.ALL);
      assertThat(rule.key()).isEqualTo("NPE");
      assertThat(rule.name()).isEqualTo("Detect NPE");
      assertThat(rule.severity()).isEqualTo(Severity.BLOCKER);
      assertThat(rule.htmlDescription()).isEqualTo("Detect <code>java.lang.NullPointerException</code>");
      assertThat(rule.markdownDescription()).isNull();
      assertThat(rule.tags()).containsOnly("one", "two", "three", "four");
      assertThat(rule.securityStandards()).containsOnly("cwe:1", "cwe:123", "cwe:2", "owaspTop10:a1", "owaspTop10:a3");
      assertThat(rule.params()).isEmpty();
      assertThat(rule.internalKey()).isEqualTo("/something");
      assertThat(rule.template()).isFalse();
      assertThat(rule.status()).isEqualTo(RuleStatus.BETA);
      assertThat(rule.toString()).hasToString("[repository=external_eslint, key=NPE]");
      assertThat(rule.repository()).isSameAs(repo);
  
      RulesDefinition.Rule otherRule = repo.rule("ABC");
      assertThat(otherRule.htmlDescription()).isNull();
      assertThat(otherRule.markdownDescription()).isEqualTo("ABC");
    }
  
    @Test
    public void define_rule_parameters() {
      RulesDefinition.NewRepository newFindbugs = context.createRepository("findbugs", "java");
      RulesDefinition.NewRule newNpe = newFindbugs.createRule("NPE").setName("NPE").setHtmlDescription("NPE");
      newNpe.createParam("level").setDefaultValue("LOW").setName("Level").setDescription("The level").setType(RuleParamType.INTEGER);
      newNpe.createParam("effort");
      newFindbugs.done();
  
      RulesDefinition.Rule rule = context.repository("findbugs").rule("NPE");
      assertThat(rule.params()).hasSize(2);
  
      RulesDefinition.Param level = rule.param("level");
      assertThat(level).isNotNull();
      assertThat(level.key()).isEqualTo("level");
      assertThat(level.name()).isEqualTo("Level");
      assertThat(level.description()).isEqualTo("The level");
      assertThat(level.defaultValue()).isEqualTo("LOW");
      assertThat(level.type()).isEqualTo(RuleParamType.INTEGER);
  
      RulesDefinition.Param effort = rule.param("effort");
      assertThat(effort.key()).isEqualTo("effort").isEqualTo(effort.name());
      assertThat(effort.description()).isNull();
      assertThat(effort.defaultValue()).isNull();
      assertThat(effort.type()).isEqualTo(RuleParamType.STRING);
    }
  
    @Test
    public void define_rule_parameter_with_empty_default_value() {
      RulesDefinition.NewRepository newFindbugs = context.createRepository("findbugs", "java");
      RulesDefinition.NewRule newNpe = newFindbugs.createRule("NPE").setName("NPE").setHtmlDescription("NPE");
      newNpe.createParam("level").setDefaultValue("").setName("Level").setDescription("The level").setType(RuleParamType.INTEGER);
      newFindbugs.done();
  
      RulesDefinition.Rule rule = context.repository("findbugs").rule("NPE");
      assertThat(rule.params()).hasSize(1);
  
      RulesDefinition.Param level = rule.param("level");
      assertThat(level.key()).isEqualTo("level");
      assertThat(level.name()).isEqualTo("Level");
      assertThat(level.description()).isEqualTo("The level");
      // Empty value is converted in null value
      assertThat(level.defaultValue()).isNull();
      assertThat(level.type()).isEqualTo(RuleParamType.INTEGER);
    }
  
    @Test
    @UseDataProvider("nullOrEmpty")
    public void addDeprecatedRuleKey_fails_with_IAE_if_repository_is_null_or_empty(String nullOrEmpty) {
      RulesDefinition.NewRepository newRepository = context.createRepository("foo", "bar");
      RulesDefinition.NewRule newRule = newRepository.createRule("doh");
  
      assertThatThrownBy(() -> newRule.addDeprecatedRuleKey(nullOrEmpty, "oldKey"))
        .isInstanceOf(IllegalArgumentException.class)
        .hasMessage("Repository must be set");
    }
  
    @Test
    @UseDataProvider("nullOrEmpty")
    public void addDeprecatedRuleKey_fails_with_IAE_if_key_is_null_or_empty(String nullOrEmpty) {
      RulesDefinition.NewRepository newRepository = context.createRepository("foo", "bar");
      RulesDefinition.NewRule newRule = newRepository.createRule("doh");
  
      assertThatThrownBy(() -> newRule.addDeprecatedRuleKey("oldRepo", nullOrEmpty))
        .isInstanceOf(IllegalArgumentException.class)
        .hasMessage("Rule must be set");
    }
  
    @DataProvider
    public static Object[][] nullOrEmpty() {
      return new Object[][]{
        {null},
        {""}
      };
    }
  
    @Test
    public void getDeprecatedKeys_returns_empty_if_addDeprecatedKeys_never_called() {
      String repositoryKey = "foo";
      String ruleKey = "doh";
      RulesDefinition.NewRepository newRepository = context.createRepository(repositoryKey, "bar");
      newRepository.createRule(ruleKey)
        .setName("doh rule")
        .setHtmlDescription("doh description");
      newRepository.done();
      RulesDefinition.Repository repository = context.repository(repositoryKey);
  