From afca5e7a1bc4a92159ce3c7664a02de3d1577f02 Mon Sep 17 00:00:00 2001 From: jycr Date: Fri, 7 Jul 2023 13:47:04 +0200 Subject: [PATCH 1/2] refactor: Uses standard org.sonar.check.Rule annotation --- CONTRIBUTING.md | 2 +- commons-ios/pom.xml | 2 +- .../src/main/java/io/ecocode/ios/Const.java | 10 +- .../io/ecocode/ios/checks/ReportIssue.java | 9 +- .../ios/checks/ReportIssueRecorder.java | 6 +- .../java/io/ecocode/ios/checks/RuleCheck.java | 72 +++----- .../ios/rules/JSONRulesDefinition.java | 97 ----------- .../io/ecocode/ios/rules/RepositoryRule.java | 68 -------- .../ecocode/ios/rules/RepositoryRuleDebt.java | 37 ----- .../ios/rules/RepositoryRuleParser.java | 69 -------- .../io/ecocode/ios/checks/RuleCheckTest.java | 17 +- .../ios/rules/JSONRulesDefinitionTest.java | 47 ------ .../ios/rules/ReportIssueRecorderTest.java | 2 +- .../ios/rules/RepositoryRuleParserTest.java | 60 ------- pom.xml | 18 ++ swift-lang/pom.xml | 13 +- .../ios/swift/EcoCodeSwiftProfile.java | 3 +- .../swift/EcoCodeSwiftRulesDefinition.java | 57 ++++++- .../ios/swift/EcoCodeSwiftVisitor.java | 3 +- .../main/java/io/ecocode/ios/swift/Swift.java | 4 - .../geolocalisation/ThriftyGeolocation.java | 14 +- .../idleness/IdleTimerDisabledCheck.java | 12 +- .../checks/idleness/RigidAlarmCheck.java | 12 +- .../MotionSensorUpdateRateCheck.java | 14 +- .../checks/power/ChargeAwarenessCheck.java | 13 +- .../checks/power/SaveModeAwarenessCheck.java | 12 +- .../sobriety/BrightnessOverrideCheck.java | 13 +- .../LocationUpdatesDisabledCheck.java | 12 +- .../swift/checks/sobriety/TorchFreeCheck.java | 15 +- .../main/resources/ecocode-swift-rules.json | 155 ------------------ .../{ => io/ecocode/rules/swift}/EIDL001.html | 0 .../io/ecocode/rules/swift/EIDL001.json | 18 ++ .../{ => io/ecocode/rules/swift}/EIDL002.html | 0 .../io/ecocode/rules/swift/EIDL002.json | 18 ++ .../{ => io/ecocode/rules/swift}/EPOW001.html | 0 .../io/ecocode/rules/swift/EPOW001.json | 18 ++ .../{ => io/ecocode/rules/swift}/EPOW002.html | 0 .../io/ecocode/rules/swift/EPOW002.json | 18 ++ .../{ => io/ecocode/rules/swift}/ESOB001.html | 0 .../io/ecocode/rules/swift/ESOB001.json | 18 ++ .../{ => io/ecocode/rules/swift}/ESOB002.html | 0 .../io/ecocode/rules/swift/ESOB002.json | 18 ++ .../{ => io/ecocode/rules/swift}/ESOB003.html | 0 .../io/ecocode/rules/swift/ESOB003.json | 18 ++ .../{ => io/ecocode/rules/swift}/ESOB005.html | 0 .../io/ecocode/rules/swift/ESOB005.json | 18 ++ .../{ => io/ecocode/rules/swift}/ESOB006.html | 0 .../io/ecocode/rules/swift/ESOB006.json | 18 ++ .../EcoCodeSwiftRulesDefinitionTest.java | 84 ++++++++++ .../ThriftyGeolocationCheckTest.java | 1 + 50 files changed, 416 insertions(+), 699 deletions(-) rename swift-lang/src/main/java/io/ecocode/ios/swift/RegisterRule.java => commons-ios/src/main/java/io/ecocode/ios/Const.java (81%) delete mode 100644 commons-ios/src/main/java/io/ecocode/ios/rules/JSONRulesDefinition.java delete mode 100644 commons-ios/src/main/java/io/ecocode/ios/rules/RepositoryRule.java delete mode 100644 commons-ios/src/main/java/io/ecocode/ios/rules/RepositoryRuleDebt.java delete mode 100644 commons-ios/src/main/java/io/ecocode/ios/rules/RepositoryRuleParser.java delete mode 100644 commons-ios/src/test/java/io/ecocode/ios/rules/JSONRulesDefinitionTest.java delete mode 100644 commons-ios/src/test/java/io/ecocode/ios/rules/RepositoryRuleParserTest.java delete mode 100644 swift-lang/src/main/resources/ecocode-swift-rules.json rename swift-lang/src/main/resources/{ => io/ecocode/rules/swift}/EIDL001.html (100%) create mode 100644 swift-lang/src/main/resources/io/ecocode/rules/swift/EIDL001.json rename swift-lang/src/main/resources/{ => io/ecocode/rules/swift}/EIDL002.html (100%) create mode 100644 swift-lang/src/main/resources/io/ecocode/rules/swift/EIDL002.json rename swift-lang/src/main/resources/{ => io/ecocode/rules/swift}/EPOW001.html (100%) create mode 100644 swift-lang/src/main/resources/io/ecocode/rules/swift/EPOW001.json rename swift-lang/src/main/resources/{ => io/ecocode/rules/swift}/EPOW002.html (100%) create mode 100644 swift-lang/src/main/resources/io/ecocode/rules/swift/EPOW002.json rename swift-lang/src/main/resources/{ => io/ecocode/rules/swift}/ESOB001.html (100%) create mode 100644 swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB001.json rename swift-lang/src/main/resources/{ => io/ecocode/rules/swift}/ESOB002.html (100%) create mode 100644 swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB002.json rename swift-lang/src/main/resources/{ => io/ecocode/rules/swift}/ESOB003.html (100%) create mode 100644 swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB003.json rename swift-lang/src/main/resources/{ => io/ecocode/rules/swift}/ESOB005.html (100%) create mode 100644 swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB005.json rename swift-lang/src/main/resources/{ => io/ecocode/rules/swift}/ESOB006.html (100%) create mode 100644 swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB006.json create mode 100644 swift-lang/src/test/java/io/ecocode/ios/swift/EcoCodeSwiftRulesDefinitionTest.java diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 51ea944..860b5e2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,4 +43,4 @@ In order to implement a check for the rule, create a Check class inherited from Have a look at `swift-lang/src/main/java/io/ecocode/ios/swift/checks/idleness/IdleTimerDisabledCheck` to learn more about the implementation. -Don't forget to add the `@RegisterRule` annotation to the check in order to register it to the AST visitor. \ No newline at end of file +Don't forget to add the `@org.sonar.check.Rule` annotation to the check in order to register it to the AST visitor. diff --git a/commons-ios/pom.xml b/commons-ios/pom.xml index b8ca2b0..5fe6de1 100644 --- a/commons-ios/pom.xml +++ b/commons-ios/pom.xml @@ -31,4 +31,4 @@ - \ No newline at end of file + diff --git a/swift-lang/src/main/java/io/ecocode/ios/swift/RegisterRule.java b/commons-ios/src/main/java/io/ecocode/ios/Const.java similarity index 81% rename from swift-lang/src/main/java/io/ecocode/ios/swift/RegisterRule.java rename to commons-ios/src/main/java/io/ecocode/ios/Const.java index 22eb270..aed6f85 100644 --- a/swift-lang/src/main/java/io/ecocode/ios/swift/RegisterRule.java +++ b/commons-ios/src/main/java/io/ecocode/ios/Const.java @@ -15,11 +15,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package io.ecocode.ios.swift; +package io.ecocode.ios; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; +public class Const { + public static final String SWIFT_REPOSITORY_KEY = "ecoCode-swift"; -@Retention(RetentionPolicy.RUNTIME) -public @interface RegisterRule { + private Const() { + } } diff --git a/commons-ios/src/main/java/io/ecocode/ios/checks/ReportIssue.java b/commons-ios/src/main/java/io/ecocode/ios/checks/ReportIssue.java index 09c99fc..a73bb85 100644 --- a/commons-ios/src/main/java/io/ecocode/ios/checks/ReportIssue.java +++ b/commons-ios/src/main/java/io/ecocode/ios/checks/ReportIssue.java @@ -31,18 +31,11 @@ public class ReportIssue { public ReportIssue(String ruleId, String message, @Nullable String filePath, @Nullable Integer lineNumber) { this.ruleId = ruleId; - this.message = message; + this.message = Objects.requireNonNull(message); this.filePath = filePath; this.lineNumber = lineNumber; } - public ReportIssue(String ruleId, String message) { - this.ruleId = ruleId; - this.message = message; - this.filePath = null; - this.lineNumber = null; - } - public String getRuleId() { return ruleId; } diff --git a/commons-ios/src/main/java/io/ecocode/ios/checks/ReportIssueRecorder.java b/commons-ios/src/main/java/io/ecocode/ios/checks/ReportIssueRecorder.java index 2eee2dd..a8b96be 100644 --- a/commons-ios/src/main/java/io/ecocode/ios/checks/ReportIssueRecorder.java +++ b/commons-ios/src/main/java/io/ecocode/ios/checks/ReportIssueRecorder.java @@ -34,12 +34,13 @@ public class ReportIssueRecorder { private static final Logger LOGGER = Loggers.get(ReportIssueRecorder.class); private final SensorContext sensorContext; + private static final String REPOSITORY_KEY = "ecoCode-swift"; public ReportIssueRecorder(SensorContext sensorContext) { this.sensorContext = sensorContext; } - public void recordIssues(List issues, String repository) { + public void recordIssues(List issues) { final FileSystem fs = sensorContext.fileSystem(); final FilePredicates predicates = fs.predicates(); @@ -51,7 +52,7 @@ public void recordIssues(List issues, String repository) { // The issue to be record NewIssue sonarIssue = sensorContext .newIssue() - .forRule(RuleKey.of(repository, issue.getRuleId())); + .forRule(RuleKey.of(REPOSITORY_KEY, issue.getRuleId())); // The location of the issue to be record NewIssueLocation sonarIssueLocation = sonarIssue.newLocation() .message(issue.getMessage()); @@ -86,7 +87,6 @@ public void recordIssues(List issues, String repository) { // Associating the location to the issue and saving it. sonarIssue.at(sonarIssueLocation).save(); } - } } } diff --git a/commons-ios/src/main/java/io/ecocode/ios/checks/RuleCheck.java b/commons-ios/src/main/java/io/ecocode/ios/checks/RuleCheck.java index c3d97b8..310cf09 100644 --- a/commons-ios/src/main/java/io/ecocode/ios/checks/RuleCheck.java +++ b/commons-ios/src/main/java/io/ecocode/ios/checks/RuleCheck.java @@ -17,68 +17,48 @@ */ package io.ecocode.ios.checks; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + import io.ecocode.ios.antlr.AntlrContext; import io.ecocode.ios.antlr.ParseTreeItemVisitor; -import io.ecocode.ios.rules.RepositoryRule; -import io.ecocode.ios.rules.RepositoryRuleParser; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.sensor.SensorContext; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; +import org.sonar.check.Rule; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import static java.lang.String.format; +import static java.util.Optional.ofNullable; public abstract class RuleCheck implements ParseTreeItemVisitor { - private static final Logger LOGGER = Loggers.get(RuleCheck.class); - protected String ruleId; - protected String rulesPath; - protected String repositoryKey; private class Issue { - protected Issue(String ruleId, int startIndex) { + + protected Issue(String ruleId, int startIndex, String message) { this.ruleId = ruleId; this.startIndex = startIndex; + this.message = Objects.requireNonNull(message); } - protected String ruleId; - protected int startIndex; + final String ruleId; + final int startIndex; + final String message; } - private List issues = new ArrayList<>(); + private final List issues = new ArrayList<>(); - private static List rules = new ArrayList<>(); - public static RepositoryRule getRepositoryRule(String ruleId, String rulesPath) throws IOException { - if (rules.isEmpty()) { - RepositoryRuleParser repositoryRuleParser = new RepositoryRuleParser(); - rules = repositoryRuleParser.parse(rulesPath); - } - Optional rule = rules.stream().filter(r -> r.getKey().equals(ruleId)).findFirst(); - if (rule.isPresent()) { - return rule.get(); - } else { - return null; - } + protected RuleCheck() { + this.ruleId = ofNullable(this.getClass().getAnnotation(Rule.class)) + .orElseThrow(() -> new IllegalArgumentException("Please add @org.sonar.check.Rule to: " + this.getClass())) + .key(); } - protected RuleCheck(String ruleId, String rulesPath, String repositoryKey) { - this.ruleId = ruleId; - this.rulesPath = rulesPath; - this.repositoryKey = repositoryKey; - } - - protected void recordIssue(String ruleId, int startIndex) { - issues.add(new Issue(ruleId, startIndex)); + protected void recordIssue(int startIndex, String message) { + issues.add(new Issue(this.ruleId, startIndex, message)); } @Override public void fillContext(SensorContext context, AntlrContext antlrContext) { - final InputFile file = antlrContext.getFile(); if (file == null) { return; @@ -90,22 +70,12 @@ public void fillContext(SensorContext context, AntlrContext antlrContext) { // Compute location int[] loc = antlrContext.getLineAndColumn(i.startIndex); // Retrieve rule data - try { - RepositoryRule rule = RuleCheck.getRepositoryRule(i.ruleId, rulesPath); - if (rule != null) { - reportIssues.add(new ReportIssue(i.ruleId, rule.getDescription(), file.toString(), loc[0])); - } else { - LOGGER.warn(format("Failed to identify rule %s", i.ruleId)); - } - - } catch (IOException e) { - LOGGER.warn(format("Failed to identify rule %s", i.ruleId),e); - } + reportIssues.add(new ReportIssue(i.ruleId, i.message, file.toString(), loc[0])); } // Record ReportIssueRecorder recorder = new ReportIssueRecorder(context); - recorder.recordIssues(reportIssues, repositoryKey); + recorder.recordIssues(reportIssues); // Clear issues for next file issues.clear(); diff --git a/commons-ios/src/main/java/io/ecocode/ios/rules/JSONRulesDefinition.java b/commons-ios/src/main/java/io/ecocode/ios/rules/JSONRulesDefinition.java deleted file mode 100644 index 93822d8..0000000 --- a/commons-ios/src/main/java/io/ecocode/ios/rules/JSONRulesDefinition.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * ecoCode iOS plugin - Help the earth, adopt this green plugin for your applications - * Copyright © 2023 green-code-initiative (https://www.ecocode.io/) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package io.ecocode.ios.rules; - -import org.apache.commons.io.IOUtils; -import org.sonar.api.rules.RuleType; -import org.sonar.api.server.rule.RulesDefinition; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.List; - -public abstract class JSONRulesDefinition implements RulesDefinition { - - - private static final Logger LOGGER = Loggers.get(JSONRulesDefinition.class); - - private final String repositoryKey; - private final String repositoryName; - private final String language; - - private final String jsonResourcePath; - - protected JSONRulesDefinition(String repositoryKey, String repositoryName, String language, String jsonResourcePath) { - this.repositoryKey = repositoryKey; - this.repositoryName = repositoryName; - this.language = language; - this.jsonResourcePath = jsonResourcePath; - } - - @Override - public void define(Context context) { - NewRepository repository = context.createRepository(this.repositoryKey, this.language).setName(this.repositoryName); - RepositoryRuleParser repositoryRuleParser = new RepositoryRuleParser(); - try { - List repositoryRules = repositoryRuleParser.parse(jsonResourcePath); - for (RepositoryRule r : repositoryRules) { - - String type = r.getType(); - if (type == null) { - type = "CODE_SMELL"; - LOGGER.warn(String.format("Rule %s has no type, using CODE_SMELL as default", r.getKey())); - } - - String severity = r.getSeverity(); - if (severity == null) { - severity = "MAJOR"; - LOGGER.warn(String.format("Rule %s has no severity, using MAJOR as default", r.getKey())); - } - - // Read description from JSON - // But overrides it .html description of the rule is found in resources - String description = r.getDescription(); - InputStream dis = getClass().getResourceAsStream(String.format("/%s.html", r.getKey())); - if (dis != null) { - description = IOUtils.toString(dis, StandardCharsets.UTF_8); - } - - NewRule nr = repository.createRule(r.getKey()) - .setName(r.getName()) - .setSeverity(severity) - .setType(RuleType.valueOf(type)) - .setTags(r.getTags().toArray(new String[0])) - .setHtmlDescription(description); - - if (r.getDebt() != null) { - nr.setDebtRemediationFunction(nr.debtRemediationFunctions().constantPerIssue(r.getDebt().getOffset())); - } else { - LOGGER.warn(String.format("Rule %s has no debt information", r.getKey())); - } - - } - } catch (IOException e) { - LOGGER.error(String.format("Failed to load %s rules", this.repositoryName), e); - } - - repository.done(); - } -} diff --git a/commons-ios/src/main/java/io/ecocode/ios/rules/RepositoryRule.java b/commons-ios/src/main/java/io/ecocode/ios/rules/RepositoryRule.java deleted file mode 100644 index 9912de3..0000000 --- a/commons-ios/src/main/java/io/ecocode/ios/rules/RepositoryRule.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * ecoCode iOS plugin - Help the earth, adopt this green plugin for your applications - * Copyright © 2023 green-code-initiative (https://www.ecocode.io/) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package io.ecocode.ios.rules; - -import java.util.List; - -public final class RepositoryRule { - - private final String key; - private final String name; - private final String severity; - private final String description; - private final String type; - private final RepositoryRuleDebt debt; - - private final List tags; - - public RepositoryRule(final String key, final String name, final String severity, final String description, final String type, final RepositoryRuleDebt debt, final List tags) { - this.key = key; - this.name = name; - this.severity = severity; - this.description = description; - this.type = type; - this.debt = debt; - this.tags = tags; - } - - public String getKey() { - return key; - } - - public String getName() { - return name; - } - - public String getSeverity() { - return severity; - } - - public String getDescription() { - return description; - } - - public String getType() { - return type; - } - - public RepositoryRuleDebt getDebt() { - return debt; - } - - public List getTags() {return tags;} -} diff --git a/commons-ios/src/main/java/io/ecocode/ios/rules/RepositoryRuleDebt.java b/commons-ios/src/main/java/io/ecocode/ios/rules/RepositoryRuleDebt.java deleted file mode 100644 index 3d9b491..0000000 --- a/commons-ios/src/main/java/io/ecocode/ios/rules/RepositoryRuleDebt.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * ecoCode iOS plugin - Help the earth, adopt this green plugin for your applications - * Copyright © 2023 green-code-initiative (https://www.ecocode.io/) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package io.ecocode.ios.rules; - -public final class RepositoryRuleDebt { - - private final String function; - private final String offset; - - public RepositoryRuleDebt(final String function, final String offset) { - this.function = function; - this.offset = offset; - } - - public String getFunction() { - return function; - } - - public String getOffset() { - return offset; - } -} diff --git a/commons-ios/src/main/java/io/ecocode/ios/rules/RepositoryRuleParser.java b/commons-ios/src/main/java/io/ecocode/ios/rules/RepositoryRuleParser.java deleted file mode 100644 index 5d053ff..0000000 --- a/commons-ios/src/main/java/io/ecocode/ios/rules/RepositoryRuleParser.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * ecoCode iOS plugin - Help the earth, adopt this green plugin for your applications - * Copyright © 2023 green-code-initiative (https://www.ecocode.io/) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package io.ecocode.ios.rules; - -import org.sonarsource.analyzer.commons.internal.json.simple.JSONArray; -import org.sonarsource.analyzer.commons.internal.json.simple.JSONObject; -import org.sonarsource.analyzer.commons.internal.json.simple.JSONValue; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; - -public class RepositoryRuleParser { - - public List parse(String resourceName) throws IOException { - - // Appends starting / if not set - if (!resourceName.startsWith("/")) { - resourceName = "/" + resourceName; - } - - InputStream is = getClass().getResourceAsStream(resourceName); - if (is == null) { - throw new IOException(String.format("JSON rule file not found in resources at %s", resourceName)); - } - - Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8); - List repositoryRules = new ArrayList<>(); - JSONArray jsonRules = (JSONArray) JSONValue.parse(reader); - if (jsonRules != null) { - for (Object obj : jsonRules) { - JSONObject jsonRule = (JSONObject) obj; - JSONObject jsonDebt = (JSONObject) jsonRule.get("debt"); - RepositoryRuleDebt debt = null; - if (jsonDebt != null) { - debt = new RepositoryRuleDebt((String) jsonDebt.get("function"), (String) jsonDebt.get("offset")); - } - RepositoryRule repositoryRule = new RepositoryRule( - (String) jsonRule.get("key"), - (String) jsonRule.get("name"), - (String) jsonRule.get("severity"), - (String) jsonRule.get("description"), - (String) jsonRule.get("type"), - debt, (List)jsonRule.get("tags")); - repositoryRules.add(repositoryRule); - } - } - return repositoryRules; - } -} diff --git a/commons-ios/src/test/java/io/ecocode/ios/checks/RuleCheckTest.java b/commons-ios/src/test/java/io/ecocode/ios/checks/RuleCheckTest.java index 46ccf3e..77e8a20 100644 --- a/commons-ios/src/test/java/io/ecocode/ios/checks/RuleCheckTest.java +++ b/commons-ios/src/test/java/io/ecocode/ios/checks/RuleCheckTest.java @@ -23,6 +23,7 @@ import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.internal.TestInputFileBuilder; import org.sonar.api.batch.sensor.internal.SensorContextTester; +import org.sonar.check.Rule; import java.io.File; import java.io.IOException; @@ -34,6 +35,14 @@ public class RuleCheckTest { + @Rule(key = "rule1") + private static class TestRule extends RuleCheck { + @Override + public void apply(ParseTree tree) { + this.recordIssue(0, "Lorem ipsum"); + } + } + private static final String TEST_ROOT = "src/test/resources"; private static final int LINE_COUNT = 100; @@ -62,13 +71,7 @@ public int[] getLineAndColumn(int global) { } }; - RuleCheck ruleCheck = new RuleCheck("rule1", "/rules/rules.json", "repositoryKey") { - - @Override - public void apply(ParseTree tree) { - this.recordIssue(this.ruleId, 0); - } - }; + RuleCheck ruleCheck = new TestRule(); ruleCheck.apply(null); diff --git a/commons-ios/src/test/java/io/ecocode/ios/rules/JSONRulesDefinitionTest.java b/commons-ios/src/test/java/io/ecocode/ios/rules/JSONRulesDefinitionTest.java deleted file mode 100644 index 4723a7c..0000000 --- a/commons-ios/src/test/java/io/ecocode/ios/rules/JSONRulesDefinitionTest.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * ecoCode iOS plugin - Help the earth, adopt this green plugin for your applications - * Copyright © 2023 green-code-initiative (https://www.ecocode.io/) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package io.ecocode.ios.rules; - -import io.ecocode.ios.rules.JSONRulesDefinition; -import org.junit.Test; -import org.sonar.api.server.rule.RulesDefinition; - -import static org.assertj.core.api.Assertions.assertThat; - -public class JSONRulesDefinitionTest { - - @Test - public void define() { - - JSONRulesDefinition rulesDefinition = new JSONRulesDefinition("rep_key", "rep_name", "lang", "/rules/rules.json") {}; - - - RulesDefinition.Context context = new RulesDefinition.Context(); - rulesDefinition.define(context); - - RulesDefinition.Repository repository = context.repository("rep_key"); - assertThat(repository).isNotNull(); - assertThat(repository.name()).isEqualTo("rep_name"); - assertThat(repository.language()).isEqualTo("lang"); - assertThat(repository.rules()).isNotEmpty(); - assertThat(repository.rules().get(0).tags()).isNotEmpty(); - assertThat(repository.rules().get(0).htmlDescription()).isEqualTo("

Test description from HTML file

"); - assertThat(repository.rules().get(1).htmlDescription()).isEqualTo("This is rule 2."); - - } -} diff --git a/commons-ios/src/test/java/io/ecocode/ios/rules/ReportIssueRecorderTest.java b/commons-ios/src/test/java/io/ecocode/ios/rules/ReportIssueRecorderTest.java index 52a55be..b5dc1ad 100644 --- a/commons-ios/src/test/java/io/ecocode/ios/rules/ReportIssueRecorderTest.java +++ b/commons-ios/src/test/java/io/ecocode/ios/rules/ReportIssueRecorderTest.java @@ -53,7 +53,7 @@ public void recordIssues() { issues.add(new ReportIssue("ruleId", "message", testFile.path().toString(), 3)); ReportIssueRecorder recorder = new ReportIssueRecorder(context); - recorder.recordIssues(issues, "TestRepo"); + recorder.recordIssues(issues); assertThat(context.allIssues()).hasSize(1); diff --git a/commons-ios/src/test/java/io/ecocode/ios/rules/RepositoryRuleParserTest.java b/commons-ios/src/test/java/io/ecocode/ios/rules/RepositoryRuleParserTest.java deleted file mode 100644 index f02aeb0..0000000 --- a/commons-ios/src/test/java/io/ecocode/ios/rules/RepositoryRuleParserTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * ecoCode iOS plugin - Help the earth, adopt this green plugin for your applications - * Copyright © 2023 green-code-initiative (https://www.ecocode.io/) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package io.ecocode.ios.rules; - -import io.ecocode.ios.rules.RepositoryRule; -import io.ecocode.ios.rules.RepositoryRuleParser; -import org.junit.Test; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -public class RepositoryRuleParserTest { - - @Test - public void parse() throws Throwable { - - RepositoryRuleParser parser = new RepositoryRuleParser(); - List repositoryRules = parser.parse("/rules/rules.json"); - assertThat(repositoryRules).hasSize(2); - - RepositoryRule repositoryRule1 = repositoryRules.get(0); - assertThat(repositoryRule1.getKey()).isEqualTo("rule1"); - assertThat(repositoryRule1.getName()).isEqualTo("Rule 1"); - assertThat(repositoryRule1.getDescription()).isEqualTo("This is rule 1."); - assertThat(repositoryRule1.getSeverity()).isEqualTo("MINOR"); - assertThat(repositoryRule1.getDebt()).isNotNull(); - assertThat(repositoryRule1.getDebt().getFunction()).isEqualTo("CONSTANT_ISSUE"); - assertThat(repositoryRule1.getDebt().getOffset()).isEqualTo("5min"); - assertThat(repositoryRule1.getTags()).hasSize(2); - assertThat(repositoryRule1.getTags().get(0)).isEqualTo("tag1"); - assertThat(repositoryRule1.getTags().get(1)).isEqualTo("tag2"); - - RepositoryRule repositoryRule2 = repositoryRules.get(1); - assertThat(repositoryRule2.getKey()).isEqualTo("rule2"); - assertThat(repositoryRule2.getName()).isEqualTo("Rule 2"); - assertThat(repositoryRule2.getDescription()).isEqualTo("This is rule 2."); - assertThat(repositoryRule2.getSeverity()).isEqualTo("MAJOR"); - assertThat(repositoryRule2.getDebt()).isNotNull(); - assertThat(repositoryRule2.getDebt().getFunction()).isEqualTo("CONSTANT_ISSUE"); - assertThat(repositoryRule2.getDebt().getOffset()).isEqualTo("15min"); - assertThat(repositoryRule2.getTags()).hasSize(1); - assertThat(repositoryRule2.getTags().get(0)).isEqualTo("tag1"); - } -} diff --git a/pom.xml b/pom.xml index 43a43a6..e7805fb 100644 --- a/pom.xml +++ b/pom.xml @@ -142,6 +142,24 @@ + + + + org.junit.jupiter + junit-jupiter + 5.9.3 + test + + + + org.assertj + assertj-core + 3.24.2 + test + + + + diff --git a/swift-lang/pom.xml b/swift-lang/pom.xml index 316013c..ba704b6 100644 --- a/swift-lang/pom.xml +++ b/swift-lang/pom.xml @@ -22,6 +22,17 @@ 0.9.12 + + org.junit.jupiter + junit-jupiter + test + + + + org.assertj + assertj-core + test + - \ No newline at end of file + diff --git a/swift-lang/src/main/java/io/ecocode/ios/swift/EcoCodeSwiftProfile.java b/swift-lang/src/main/java/io/ecocode/ios/swift/EcoCodeSwiftProfile.java index b1e32f3..dbc0498 100644 --- a/swift-lang/src/main/java/io/ecocode/ios/swift/EcoCodeSwiftProfile.java +++ b/swift-lang/src/main/java/io/ecocode/ios/swift/EcoCodeSwiftProfile.java @@ -17,6 +17,7 @@ */ package io.ecocode.ios.swift; +import io.ecocode.ios.Const; import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition; import org.sonarsource.analyzer.commons.BuiltInQualityProfileJsonLoader; @@ -24,7 +25,7 @@ public class EcoCodeSwiftProfile implements BuiltInQualityProfilesDefinition { @Override public void define(Context context) { NewBuiltInQualityProfile ecoCodeProfile = context.createBuiltInQualityProfile(Swift.PROFILE_NAME, Swift.KEY); - BuiltInQualityProfileJsonLoader.load(ecoCodeProfile, Swift.REPOSITORY_KEY, Swift.PROFILE_PATH); + BuiltInQualityProfileJsonLoader.load(ecoCodeProfile, Const.SWIFT_REPOSITORY_KEY, Swift.PROFILE_PATH); ecoCodeProfile.done(); } } diff --git a/swift-lang/src/main/java/io/ecocode/ios/swift/EcoCodeSwiftRulesDefinition.java b/swift-lang/src/main/java/io/ecocode/ios/swift/EcoCodeSwiftRulesDefinition.java index 849e2ad..d16f1e9 100644 --- a/swift-lang/src/main/java/io/ecocode/ios/swift/EcoCodeSwiftRulesDefinition.java +++ b/swift-lang/src/main/java/io/ecocode/ios/swift/EcoCodeSwiftRulesDefinition.java @@ -17,11 +17,60 @@ */ package io.ecocode.ios.swift; -import io.ecocode.ios.rules.JSONRulesDefinition; +import java.util.ArrayList; +import java.util.List; -public class EcoCodeSwiftRulesDefinition extends JSONRulesDefinition { +import io.ecocode.ios.Const; +import io.ecocode.ios.swift.checks.geolocalisation.ThriftyGeolocation; +import io.ecocode.ios.swift.checks.idleness.IdleTimerDisabledCheck; +import io.ecocode.ios.swift.checks.idleness.RigidAlarmCheck; +import io.ecocode.ios.swift.checks.motionsensor.MotionSensorUpdateRateCheck; +import io.ecocode.ios.swift.checks.power.ChargeAwarenessCheck; +import io.ecocode.ios.swift.checks.power.SaveModeAwarenessCheck; +import io.ecocode.ios.swift.checks.sobriety.BrightnessOverrideCheck; +import io.ecocode.ios.swift.checks.sobriety.LocationUpdatesDisabledCheck; +import io.ecocode.ios.swift.checks.sobriety.TorchFreeCheck; +import org.sonar.api.SonarRuntime; +import org.sonar.api.server.rule.RulesDefinition; +import org.sonarsource.analyzer.commons.RuleMetadataLoader; - public EcoCodeSwiftRulesDefinition() { - super(Swift.REPOSITORY_KEY, Swift.REPOSITORY_NAME, Swift.KEY, Swift.RULES_PATH); +public class EcoCodeSwiftRulesDefinition implements RulesDefinition { + private static final String RESOURCE_BASE_PATH = "io/ecocode/rules/swift"; + + private static final String NAME = Swift.REPOSITORY_NAME; + private static final String LANGUAGE = Swift.KEY; + private static final List> CHECK_CLASSES = List.of( + // geolocatisation + ThriftyGeolocation.class, + // idleness + IdleTimerDisabledCheck.class, + RigidAlarmCheck.class, + // motionsensor + MotionSensorUpdateRateCheck.class, + // power + ChargeAwarenessCheck.class, + SaveModeAwarenessCheck.class, + // sobriety + BrightnessOverrideCheck.class, + LocationUpdatesDisabledCheck.class, + TorchFreeCheck.class + ); + + private final SonarRuntime sonarRuntime; + + public EcoCodeSwiftRulesDefinition(SonarRuntime sonarRuntime) { + this.sonarRuntime = sonarRuntime; + } + + @Override + public void define(Context context) { + NewRepository repository = context.createRepository(Const.SWIFT_REPOSITORY_KEY, LANGUAGE).setName(NAME); + RuleMetadataLoader ruleMetadataLoader = new RuleMetadataLoader(RESOURCE_BASE_PATH, sonarRuntime); + ruleMetadataLoader.addRulesByAnnotatedClass(repository, new ArrayList<>(CHECK_CLASSES)); + repository.done(); + } + + public String repositoryKey() { + return Const.SWIFT_REPOSITORY_KEY; } } diff --git a/swift-lang/src/main/java/io/ecocode/ios/swift/EcoCodeSwiftVisitor.java b/swift-lang/src/main/java/io/ecocode/ios/swift/EcoCodeSwiftVisitor.java index ae0bdf2..afff151 100644 --- a/swift-lang/src/main/java/io/ecocode/ios/swift/EcoCodeSwiftVisitor.java +++ b/swift-lang/src/main/java/io/ecocode/ios/swift/EcoCodeSwiftVisitor.java @@ -25,6 +25,7 @@ import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; +import org.sonar.check.Rule; import java.lang.annotation.Annotation; import java.util.ArrayList; @@ -46,7 +47,7 @@ public EcoCodeSwiftVisitor() { Annotation[] annotations = clazz.getAnnotations(); for (Annotation annotation : annotations) { - if (annotation instanceof RegisterRule) { + if (annotation instanceof Rule) { try { checks.add(clazz.getDeclaredConstructor().newInstance()); } catch (Exception e) { diff --git a/swift-lang/src/main/java/io/ecocode/ios/swift/Swift.java b/swift-lang/src/main/java/io/ecocode/ios/swift/Swift.java index ad352bb..c8e2709 100644 --- a/swift-lang/src/main/java/io/ecocode/ios/swift/Swift.java +++ b/swift-lang/src/main/java/io/ecocode/ios/swift/Swift.java @@ -24,9 +24,5 @@ private Swift() {} public static final String KEY = "swift"; public static final String PROFILE_NAME = "ecoCode"; public static final String REPOSITORY_NAME = "ecoCode"; - public static final String REPOSITORY_KEY = "ecoCode-swift"; public static final String PROFILE_PATH = "ecocode_swift_profile.json"; - - public static final String RULES_PATH = "ecocode-swift-rules.json"; - } diff --git a/swift-lang/src/main/java/io/ecocode/ios/swift/checks/geolocalisation/ThriftyGeolocation.java b/swift-lang/src/main/java/io/ecocode/ios/swift/checks/geolocalisation/ThriftyGeolocation.java index b6d0af6..418d3c3 100644 --- a/swift-lang/src/main/java/io/ecocode/ios/swift/checks/geolocalisation/ThriftyGeolocation.java +++ b/swift-lang/src/main/java/io/ecocode/ios/swift/checks/geolocalisation/ThriftyGeolocation.java @@ -18,24 +18,20 @@ package io.ecocode.ios.swift.checks.geolocalisation; import io.ecocode.ios.checks.RuleCheck; -import io.ecocode.ios.swift.RegisterRule; -import io.ecocode.ios.swift.Swift; import io.ecocode.ios.swift.antlr.generated.Swift5Parser; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNodeImpl; +import org.sonar.check.Rule; import static io.ecocode.ios.swift.checks.CheckHelper.isImportExisting; -@RegisterRule +@Rule(key = "ESOB002") public class ThriftyGeolocation extends RuleCheck { - Swift5Parser.Import_declarationContext importTree = null; + private static final String DEFAULT_ISSUE_MESSAGE = "Adapt location accuracy and type to applications needs."; + private Swift5Parser.Import_declarationContext importTree = null; private boolean geolocationUpdated = false; protected boolean importExist = false; - public ThriftyGeolocation() { - super("ESOB002", Swift.RULES_PATH, Swift.REPOSITORY_KEY); - } - @Override public void apply(ParseTree tree) { if (isImportExisting(tree, "CLLocationManager")) { @@ -51,7 +47,7 @@ public void apply(ParseTree tree) { if (tree instanceof TerminalNodeImpl && tree.getText().equals("")) { if (importExist && !geolocationUpdated) { - this.recordIssue(ruleId, importTree.getStart().getStartIndex()); + this.recordIssue(importTree.getStart().getStartIndex(), DEFAULT_ISSUE_MESSAGE); } importExist = false; geolocationUpdated = false; diff --git a/swift-lang/src/main/java/io/ecocode/ios/swift/checks/idleness/IdleTimerDisabledCheck.java b/swift-lang/src/main/java/io/ecocode/ios/swift/checks/idleness/IdleTimerDisabledCheck.java index 9cd194a..7ebdf85 100644 --- a/swift-lang/src/main/java/io/ecocode/ios/swift/checks/idleness/IdleTimerDisabledCheck.java +++ b/swift-lang/src/main/java/io/ecocode/ios/swift/checks/idleness/IdleTimerDisabledCheck.java @@ -17,21 +17,17 @@ */ package io.ecocode.ios.swift.checks.idleness; -import io.ecocode.ios.swift.RegisterRule; -import io.ecocode.ios.swift.Swift; import io.ecocode.ios.swift.antlr.generated.Swift5Parser; import io.ecocode.ios.checks.RuleCheck; import org.antlr.v4.runtime.tree.ParseTree; +import org.sonar.check.Rule; /** * Check the use of "UIApplication.shared.isIdleTimerDisabled" and triggers when set to true. */ -@RegisterRule +@Rule(key = "EIDL001") public class IdleTimerDisabledCheck extends RuleCheck { - - public IdleTimerDisabledCheck() { - super("EIDL001", Swift.RULES_PATH, Swift.REPOSITORY_KEY); - } + private static final String DEFAULT_ISSUE_MESSAGE = "Do not disable idle timer, unless absolutely necessary."; @Override public void apply(ParseTree tree) { @@ -39,7 +35,7 @@ public void apply(ParseTree tree) { if (tree instanceof Swift5Parser.ExpressionContext) { Swift5Parser.ExpressionContext id = (Swift5Parser.ExpressionContext) tree; if (id.getText().equals("UIApplication.shared.isIdleTimerDisabled=true")) { - this.recordIssue(ruleId, id.getStart().getStartIndex()); + this.recordIssue(id.getStart().getStartIndex(), DEFAULT_ISSUE_MESSAGE); } } } diff --git a/swift-lang/src/main/java/io/ecocode/ios/swift/checks/idleness/RigidAlarmCheck.java b/swift-lang/src/main/java/io/ecocode/ios/swift/checks/idleness/RigidAlarmCheck.java index 2690e6f..1a76ad2 100644 --- a/swift-lang/src/main/java/io/ecocode/ios/swift/checks/idleness/RigidAlarmCheck.java +++ b/swift-lang/src/main/java/io/ecocode/ios/swift/checks/idleness/RigidAlarmCheck.java @@ -17,28 +17,24 @@ */ package io.ecocode.ios.swift.checks.idleness; -import io.ecocode.ios.swift.RegisterRule; -import io.ecocode.ios.swift.Swift; import io.ecocode.ios.swift.antlr.generated.Swift5Parser; import io.ecocode.ios.checks.RuleCheck; import org.antlr.v4.runtime.tree.ParseTree; +import org.sonar.check.Rule; /** * Check the presence of the class "Timer". */ -@RegisterRule +@Rule(key = "EIDL002") public class RigidAlarmCheck extends RuleCheck { - - public RigidAlarmCheck() { - super("EIDL002", Swift.RULES_PATH, Swift.REPOSITORY_KEY); - } + private static final String DEFAULT_ISSUE_MESSAGE = "Setting a tolerance for timers will allow them to fire later than the scheduled fire date."; @Override public void apply(ParseTree tree) { if (tree instanceof Swift5Parser.IdentifierContext) { Swift5Parser.IdentifierContext id = (Swift5Parser.IdentifierContext) tree; if (id.getText().equals("Timer")) { - this.recordIssue(ruleId, id.getStart().getStartIndex()); + this.recordIssue(id.getStart().getStartIndex(), DEFAULT_ISSUE_MESSAGE); } } } diff --git a/swift-lang/src/main/java/io/ecocode/ios/swift/checks/motionsensor/MotionSensorUpdateRateCheck.java b/swift-lang/src/main/java/io/ecocode/ios/swift/checks/motionsensor/MotionSensorUpdateRateCheck.java index eeff613..e51a4e4 100644 --- a/swift-lang/src/main/java/io/ecocode/ios/swift/checks/motionsensor/MotionSensorUpdateRateCheck.java +++ b/swift-lang/src/main/java/io/ecocode/ios/swift/checks/motionsensor/MotionSensorUpdateRateCheck.java @@ -18,29 +18,25 @@ package io.ecocode.ios.swift.checks.motionsensor; import io.ecocode.ios.checks.RuleCheck; -import io.ecocode.ios.swift.RegisterRule; -import io.ecocode.ios.swift.Swift; import io.ecocode.ios.swift.antlr.generated.Swift5Parser; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNodeImpl; +import org.sonar.check.Rule; import java.util.Arrays; import java.util.List; import static io.ecocode.ios.swift.checks.CheckHelper.isImportExisting; -@RegisterRule +@Rule(key="ESOB003") public class MotionSensorUpdateRateCheck extends RuleCheck { - Swift5Parser.Import_declarationContext importTree = null; + private static final String DEFAULT_ISSUE_MESSAGE = "Set appropriate motion sensor update rates for the application's needs"; + private Swift5Parser.Import_declarationContext importTree = null; private boolean sensorRateUpdated = false; private boolean importExist = false; private final List sensorRateUpdateExpressions = Arrays.asList("desiredAccuracy", "activityType", "requestLocation", "magnetometerUpdateInterval"); - public MotionSensorUpdateRateCheck() { - super("ESOB003", Swift.RULES_PATH, Swift.REPOSITORY_KEY); - } - @Override public void apply(ParseTree tree) { if (isImportExisting(tree, "CoreMotion")) { @@ -54,7 +50,7 @@ public void apply(ParseTree tree) { if (tree instanceof TerminalNodeImpl && tree.getText().equals("")) { if (importExist && !sensorRateUpdated) { - this.recordIssue(ruleId, importTree.getStart().getStartIndex()); + this.recordIssue(importTree.getStart().getStartIndex(), DEFAULT_ISSUE_MESSAGE); } importExist = false; sensorRateUpdated = false; diff --git a/swift-lang/src/main/java/io/ecocode/ios/swift/checks/power/ChargeAwarenessCheck.java b/swift-lang/src/main/java/io/ecocode/ios/swift/checks/power/ChargeAwarenessCheck.java index 99b987c..8678680 100644 --- a/swift-lang/src/main/java/io/ecocode/ios/swift/checks/power/ChargeAwarenessCheck.java +++ b/swift-lang/src/main/java/io/ecocode/ios/swift/checks/power/ChargeAwarenessCheck.java @@ -17,11 +17,10 @@ */ package io.ecocode.ios.swift.checks.power; -import io.ecocode.ios.swift.RegisterRule; -import io.ecocode.ios.swift.Swift; import io.ecocode.ios.swift.antlr.generated.Swift5Parser; import io.ecocode.ios.checks.RuleCheck; import org.antlr.v4.runtime.tree.ParseTree; +import org.sonar.check.Rule; import java.util.List; @@ -30,13 +29,9 @@ * or `UIDevice.batteryLevelDidChangeNotification` or `UIDevice.batteryStateDidChangeNotification`. * If found, reports a (positive) issue. */ -@RegisterRule +@Rule(key = "EPOW001") public class ChargeAwarenessCheck extends RuleCheck { - - public ChargeAwarenessCheck() { - super("EPOW001", Swift.RULES_PATH, Swift.REPOSITORY_KEY); - } - + private static final String DEFAULT_ISSUE_MESSAGE = "Monitoring power changes and customizing behavior depending on battery level is a good practice"; private static final String PROPERTY_BATTERY_LEVEL = "UIDevice.current.batteryLevel"; private static final String PROPERTY_BATTERY_STATE = "UIDevice.current.batteryState"; private static final String CONSTANT_BATTERY_LEVEL_NOTIFICATION = "UIDevice.batteryLevelDidChangeNotification"; @@ -54,7 +49,7 @@ public void apply(ParseTree tree) { if (tree instanceof Swift5Parser.Postfix_expressionContext) { Swift5Parser.Postfix_expressionContext id = (Swift5Parser.Postfix_expressionContext) tree; if (EXPRESSIONS_TO_CHECK.contains(id.getText())) { - this.recordIssue(ruleId, id.getStart().getStartIndex()); + this.recordIssue(id.getStart().getStartIndex(), DEFAULT_ISSUE_MESSAGE); } } } diff --git a/swift-lang/src/main/java/io/ecocode/ios/swift/checks/power/SaveModeAwarenessCheck.java b/swift-lang/src/main/java/io/ecocode/ios/swift/checks/power/SaveModeAwarenessCheck.java index 912bbc2..8cc3ac2 100644 --- a/swift-lang/src/main/java/io/ecocode/ios/swift/checks/power/SaveModeAwarenessCheck.java +++ b/swift-lang/src/main/java/io/ecocode/ios/swift/checks/power/SaveModeAwarenessCheck.java @@ -18,19 +18,15 @@ package io.ecocode.ios.swift.checks.power; import io.ecocode.ios.checks.RuleCheck; -import io.ecocode.ios.swift.RegisterRule; -import io.ecocode.ios.swift.Swift; import io.ecocode.ios.swift.antlr.generated.Swift5Parser; import org.antlr.v4.runtime.tree.ParseTree; +import org.sonar.check.Rule; import java.util.List; -@RegisterRule +@Rule(key = "EPOW002") public class SaveModeAwarenessCheck extends RuleCheck { - public SaveModeAwarenessCheck() { - super("EPOW002", Swift.RULES_PATH, Swift.REPOSITORY_KEY); - } - + private static final String DEFAULT_ISSUE_MESSAGE = "Taking into account when the device is entering or exiting the power save mode is a good practice"; private static final String PROCESS_INFO = "ProcessInfo.processInfo.isLowPowerModeEnabled"; private static final String POWER_STATE_NOTIFICATION_FULL = "Notification.Name.NSProcessInfoPowerStateDidChange"; private static final String POWER_STATE_NOTIFICATION_SHORT = ".NSProcessInfoPowerStateDidChange"; @@ -46,7 +42,7 @@ public void apply(ParseTree tree) { if (tree instanceof Swift5Parser.Postfix_expressionContext) { Swift5Parser.Postfix_expressionContext id = (Swift5Parser.Postfix_expressionContext) tree; if (EXPRESSIONS_TO_CHECK.contains(id.getText())) { - this.recordIssue(ruleId, id.getStart().getStartIndex()); + this.recordIssue(id.getStart().getStartIndex(), DEFAULT_ISSUE_MESSAGE); } } } diff --git a/swift-lang/src/main/java/io/ecocode/ios/swift/checks/sobriety/BrightnessOverrideCheck.java b/swift-lang/src/main/java/io/ecocode/ios/swift/checks/sobriety/BrightnessOverrideCheck.java index 2e6fc47..3984d16 100644 --- a/swift-lang/src/main/java/io/ecocode/ios/swift/checks/sobriety/BrightnessOverrideCheck.java +++ b/swift-lang/src/main/java/io/ecocode/ios/swift/checks/sobriety/BrightnessOverrideCheck.java @@ -17,29 +17,24 @@ */ package io.ecocode.ios.swift.checks.sobriety; -import io.ecocode.ios.swift.RegisterRule; -import io.ecocode.ios.swift.Swift; import io.ecocode.ios.swift.antlr.generated.Swift5Parser; import io.ecocode.ios.checks.RuleCheck; import org.antlr.v4.runtime.tree.ParseTree; +import org.sonar.check.Rule; /** * Check the use of "UIScreen.main.brightness" and triggers when set. */ -@RegisterRule +@Rule(key = "ESOB005") public class BrightnessOverrideCheck extends RuleCheck { - - public BrightnessOverrideCheck() { - super("ESOB005", Swift.RULES_PATH, Swift.REPOSITORY_KEY); - } - + private static final String DEFAULT_ISSUE_MESSAGE = "Do not force Brightness in your code, unless absolutely necessary"; @Override public void apply(ParseTree tree) { if (tree instanceof Swift5Parser.ExpressionContext) { Swift5Parser.ExpressionContext id = (Swift5Parser.ExpressionContext) tree; if (id.getText().contains("UIScreen.main.brightness")) { - this.recordIssue(ruleId, id.getStart().getStartIndex()); + this.recordIssue(id.getStart().getStartIndex(), DEFAULT_ISSUE_MESSAGE); } } } diff --git a/swift-lang/src/main/java/io/ecocode/ios/swift/checks/sobriety/LocationUpdatesDisabledCheck.java b/swift-lang/src/main/java/io/ecocode/ios/swift/checks/sobriety/LocationUpdatesDisabledCheck.java index e2ad5d5..97e5812 100644 --- a/swift-lang/src/main/java/io/ecocode/ios/swift/checks/sobriety/LocationUpdatesDisabledCheck.java +++ b/swift-lang/src/main/java/io/ecocode/ios/swift/checks/sobriety/LocationUpdatesDisabledCheck.java @@ -18,27 +18,23 @@ package io.ecocode.ios.swift.checks.sobriety; import io.ecocode.ios.checks.RuleCheck; -import io.ecocode.ios.swift.RegisterRule; -import io.ecocode.ios.swift.Swift; import io.ecocode.ios.swift.antlr.generated.Swift5Parser; import org.antlr.v4.runtime.tree.ParseTree; +import org.sonar.check.Rule; /** * Check the use of "CLLocationManager#pausesLocationUpdatesAutomatically" and triggers when set to false. */ -@RegisterRule +@Rule(key = "ESOB001") public class LocationUpdatesDisabledCheck extends RuleCheck { - public LocationUpdatesDisabledCheck() { - super("ESOB001", Swift.RULES_PATH, Swift.REPOSITORY_KEY); - } - + private static final String DEFAULT_ISSUE_MESSAGE = "Do not disable location updates pause, unless absolutely necessary"; @Override public void apply(ParseTree tree) { if (tree instanceof Swift5Parser.ExpressionContext) { Swift5Parser.ExpressionContext id = (Swift5Parser.ExpressionContext) tree; if (id.getText().contains(".pausesLocationUpdatesAutomatically=false")) { - this.recordIssue(ruleId, id.getStart().getStartIndex()); + this.recordIssue(id.getStart().getStartIndex(), DEFAULT_ISSUE_MESSAGE); } } } diff --git a/swift-lang/src/main/java/io/ecocode/ios/swift/checks/sobriety/TorchFreeCheck.java b/swift-lang/src/main/java/io/ecocode/ios/swift/checks/sobriety/TorchFreeCheck.java index 162c965..29d6649 100644 --- a/swift-lang/src/main/java/io/ecocode/ios/swift/checks/sobriety/TorchFreeCheck.java +++ b/swift-lang/src/main/java/io/ecocode/ios/swift/checks/sobriety/TorchFreeCheck.java @@ -17,22 +17,17 @@ */ package io.ecocode.ios.swift.checks.sobriety; -import io.ecocode.ios.swift.RegisterRule; -import io.ecocode.ios.swift.Swift; import io.ecocode.ios.swift.antlr.generated.Swift5Parser; import io.ecocode.ios.checks.RuleCheck; import org.antlr.v4.runtime.tree.ParseTree; +import org.sonar.check.Rule; /** * Check the use of "AVCaptureTorchMode.on", "setTorchModeOn(level: Float)", or "torchMode = .on" and triggers when set to true. */ -@RegisterRule +@Rule(key = "ESOB006") public class TorchFreeCheck extends RuleCheck { - - public TorchFreeCheck() { - super("ESOB006", Swift.RULES_PATH, Swift.REPOSITORY_KEY); - } - + private static final String DEFAULT_ISSUE_MESSAGE = "Usage of `AVCaptureDevice#torchMode` or `AVCaptureDevice#setTorchModeOn(level:)` must absolutely be avoided"; @Override public void apply(ParseTree tree) { @@ -42,8 +37,8 @@ public void apply(ParseTree tree) { if (expressionText.contains("AVCaptureTorchMode.on") || expressionText.contains("setTorchModeOn") || expressionText.contains("torchMode=.on")) { - this.recordIssue(ruleId, id.getStart().getStartIndex()); + this.recordIssue(id.getStart().getStartIndex(), DEFAULT_ISSUE_MESSAGE); } } } -} \ No newline at end of file +} diff --git a/swift-lang/src/main/resources/ecocode-swift-rules.json b/swift-lang/src/main/resources/ecocode-swift-rules.json deleted file mode 100644 index 6cc61d8..0000000 --- a/swift-lang/src/main/resources/ecocode-swift-rules.json +++ /dev/null @@ -1,155 +0,0 @@ -[ - { - "key": "EIDL001", - "name": "Idle timer disabled", - "severity": "MAJOR", - "description": "Do not disable idle timer, unless absolutely necessary.", - "debt": { - "function": "CONSTANT_ISSUE", - "offset": "5min" - }, - "tags": [ - "ecocode", - "environment", - "sobriety", - "eco-design" - ], - "type": "CODE_SMELL" - }, - { - "key": "EIDL002", - "name": "Rigid Alarm", - "severity": "MAJOR", - "description": "Setting a tolerance for timers will allow them to fire later than the scheduled fire date.", - "debt": { - "function": "CONSTANT_ISSUE", - "offset": "1min" - }, - "tags": [ - "ecocode", - "environment", - "idleness", - "eco-design" - ], - "type": "CODE_SMELL" - }, - { - "key": "EPOW001", - "name": "Charge Awareness", - "severity": "INFO", - "description": "Monitoring power changes and customizing behavior depending on battery level is a good practice.", - "debt": { - "function": "CONSTANT_ISSUE", - "offset": "0min" - }, - "tags": [ - "ecocode", - "environment", - "power", - "eco-design" - ], - "type": "CODE_SMELL" - }, - { - "key": "EPOW002", - "name": "Save Mode Awareness", - "severity": "INFO", - "description": "Taking into account when the device is entering or exiting the power save mode is a good practice.", - "debt": { - "function": "CONSTANT_ISSUE", - "offset": "0min" - }, - "tags": [ - "ecocode", - "environment", - "power", - "eco-design" - ], - "type": "CODE_SMELL" - }, - { - "key": "ESOB001", - "name": "Location updates pause disabled", - "severity": "MAJOR", - "description": "Do not disable location updates pause, unless absolutely necessary.", - "debt": { - "function": "CONSTANT_ISSUE", - "offset": "5min" - }, - "tags": [ - "ecocode", - "environment", - "sobriety", - "eco-design" - ], - "type": "CODE_SMELL" - }, - { - "key": "ESOB002", - "name": "Thrifty Geolocation", - "severity": "MAJOR", - "description": "Adapt location accuracy and type to applications needs.", - "debt": { - "function": "CONSTANT_ISSUE", - "offset": "5min" - }, - "tags": [ - "ecocode", - "environment", - "sobriety", - "eco-design" - ], - "type": "CODE_SMELL" - }, - { - "key": "ESOB003", - "name": "Motion Sensor Update Rate", - "severity": "MAJOR", - "description": "Set appropriate motion sensor update rates for the application's needs", - "debt": { - "function": "CONSTANT_ISSUE", - "offset": "5min" - }, - "tags": [ - "ecocode", - "environment", - "sobriety", - "eco-design" - ], - "type": "CODE_SMELL" - }, - { - "key": "ESOB005", - "name": "Brightness Override disabled", - "severity": "MAJOR", - "description": "Do not force Brightness in your code, unless absolutely necessary.", - "debt": { - "function": "CONSTANT_ISSUE", - "offset": "5min" - }, - "tags": [ - "ecocode", - "environment", - "sobriety", - "eco-design" - ], - "type": "CODE_SMELL" - }, - { - "key": "ESOB006", - "name": "Sobriety: Torch Free", - "severity": "MAJOR", - "description": "Usage of `AVCaptureDevice#torchMode` or `AVCaptureDevice#setTorchModeOn(level:)` must absolutely be avoided. These methods can be used to access the device's flashlight, which can be a potential security risk and should only be used when necessary.", - "debt": { - "function": "CONSTANT_ISSUE", - "offset": "5min" - }, - "tags": [ - "sobriety", - "environment", - "ecocode", - "eco-design" - ], - "type": "CODE_SMELL" - } -] diff --git a/swift-lang/src/main/resources/EIDL001.html b/swift-lang/src/main/resources/io/ecocode/rules/swift/EIDL001.html similarity index 100% rename from swift-lang/src/main/resources/EIDL001.html rename to swift-lang/src/main/resources/io/ecocode/rules/swift/EIDL001.html diff --git a/swift-lang/src/main/resources/io/ecocode/rules/swift/EIDL001.json b/swift-lang/src/main/resources/io/ecocode/rules/swift/EIDL001.json new file mode 100644 index 0000000..17511b7 --- /dev/null +++ b/swift-lang/src/main/resources/io/ecocode/rules/swift/EIDL001.json @@ -0,0 +1,18 @@ +{ + "key": "EIDL001", + "title": "Idle timer disabled", + "defaultSeverity": "Major", + "description": "Do not disable idle timer, unless absolutely necessary.", + "status": "ready", + "remediation": { + "func": "Constant/Issue", + "constantCost": "5min" + }, + "tags": [ + "ecocode", + "environment", + "sobriety", + "eco-design" + ], + "type": "CODE_SMELL" +} diff --git a/swift-lang/src/main/resources/EIDL002.html b/swift-lang/src/main/resources/io/ecocode/rules/swift/EIDL002.html similarity index 100% rename from swift-lang/src/main/resources/EIDL002.html rename to swift-lang/src/main/resources/io/ecocode/rules/swift/EIDL002.html diff --git a/swift-lang/src/main/resources/io/ecocode/rules/swift/EIDL002.json b/swift-lang/src/main/resources/io/ecocode/rules/swift/EIDL002.json new file mode 100644 index 0000000..a88e270 --- /dev/null +++ b/swift-lang/src/main/resources/io/ecocode/rules/swift/EIDL002.json @@ -0,0 +1,18 @@ +{ + "key": "EIDL002", + "title": "Rigid Alarm", + "defaultSeverity": "Major", + "description": "Setting a tolerance for timers will allow them to fire later than the scheduled fire date.", + "status": "ready", + "remediation": { + "func": "Constant/Issue", + "constantCost": "1min" + }, + "tags": [ + "ecocode", + "environment", + "idleness", + "eco-design" + ], + "type": "CODE_SMELL" +} diff --git a/swift-lang/src/main/resources/EPOW001.html b/swift-lang/src/main/resources/io/ecocode/rules/swift/EPOW001.html similarity index 100% rename from swift-lang/src/main/resources/EPOW001.html rename to swift-lang/src/main/resources/io/ecocode/rules/swift/EPOW001.html diff --git a/swift-lang/src/main/resources/io/ecocode/rules/swift/EPOW001.json b/swift-lang/src/main/resources/io/ecocode/rules/swift/EPOW001.json new file mode 100644 index 0000000..f5293e9 --- /dev/null +++ b/swift-lang/src/main/resources/io/ecocode/rules/swift/EPOW001.json @@ -0,0 +1,18 @@ +{ + "key": "EPOW001", + "title": "Charge Awareness", + "defaultSeverity": "Info", + "description": "Monitoring power changes and customizing behavior depending on battery level is a good practice.", + "status": "ready", + "remediation": { + "func": "Constant/Issue", + "constantCost": "0min" + }, + "tags": [ + "ecocode", + "environment", + "power", + "eco-design" + ], + "type": "CODE_SMELL" +} diff --git a/swift-lang/src/main/resources/EPOW002.html b/swift-lang/src/main/resources/io/ecocode/rules/swift/EPOW002.html similarity index 100% rename from swift-lang/src/main/resources/EPOW002.html rename to swift-lang/src/main/resources/io/ecocode/rules/swift/EPOW002.html diff --git a/swift-lang/src/main/resources/io/ecocode/rules/swift/EPOW002.json b/swift-lang/src/main/resources/io/ecocode/rules/swift/EPOW002.json new file mode 100644 index 0000000..c42ae41 --- /dev/null +++ b/swift-lang/src/main/resources/io/ecocode/rules/swift/EPOW002.json @@ -0,0 +1,18 @@ +{ + "key": "EPOW002", + "title": "Save Mode Awareness", + "defaultSeverity": "Info", + "description": "Taking into account when the device is entering or exiting the power save mode is a good practice.", + "status": "ready", + "remediation": { + "func": "Constant/Issue", + "constantCost": "0min" + }, + "tags": [ + "ecocode", + "environment", + "power", + "eco-design" + ], + "type": "CODE_SMELL" +} diff --git a/swift-lang/src/main/resources/ESOB001.html b/swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB001.html similarity index 100% rename from swift-lang/src/main/resources/ESOB001.html rename to swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB001.html diff --git a/swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB001.json b/swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB001.json new file mode 100644 index 0000000..2081b2f --- /dev/null +++ b/swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB001.json @@ -0,0 +1,18 @@ +{ + "key": "ESOB001", + "title": "Location updates pause disabled", + "defaultSeverity": "Major", + "description": "Do not disable location updates pause, unless absolutely necessary.", + "status": "ready", + "remediation": { + "func": "Constant/Issue", + "constantCost": "5min" + }, + "tags": [ + "ecocode", + "environment", + "sobriety", + "eco-design" + ], + "type": "CODE_SMELL" +} diff --git a/swift-lang/src/main/resources/ESOB002.html b/swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB002.html similarity index 100% rename from swift-lang/src/main/resources/ESOB002.html rename to swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB002.html diff --git a/swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB002.json b/swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB002.json new file mode 100644 index 0000000..6096531 --- /dev/null +++ b/swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB002.json @@ -0,0 +1,18 @@ +{ + "key": "ESOB002", + "title": "Thrifty Geolocation", + "defaultSeverity": "Major", + "description": "Adapt location accuracy and type to applications needs.", + "status": "ready", + "remediation": { + "func": "Constant/Issue", + "constantCost": "5min" + }, + "tags": [ + "ecocode", + "environment", + "sobriety", + "eco-design" + ], + "type": "CODE_SMELL" +} diff --git a/swift-lang/src/main/resources/ESOB003.html b/swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB003.html similarity index 100% rename from swift-lang/src/main/resources/ESOB003.html rename to swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB003.html diff --git a/swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB003.json b/swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB003.json new file mode 100644 index 0000000..a583a00 --- /dev/null +++ b/swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB003.json @@ -0,0 +1,18 @@ +{ + "key": "ESOB003", + "title": "Motion Sensor Update Rate", + "defaultSeverity": "Major", + "description": "Set appropriate motion sensor update rates for the application's needs", + "status": "ready", + "remediation": { + "func": "Constant/Issue", + "constantCost": "5min" + }, + "tags": [ + "ecocode", + "environment", + "sobriety", + "eco-design" + ], + "type": "CODE_SMELL" +} diff --git a/swift-lang/src/main/resources/ESOB005.html b/swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB005.html similarity index 100% rename from swift-lang/src/main/resources/ESOB005.html rename to swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB005.html diff --git a/swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB005.json b/swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB005.json new file mode 100644 index 0000000..a647f93 --- /dev/null +++ b/swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB005.json @@ -0,0 +1,18 @@ +{ + "key": "ESOB005", + "title": "Brightness Override disabled", + "defaultSeverity": "Major", + "description": "Do not force Brightness in your code, unless absolutely necessary.", + "status": "ready", + "remediation": { + "func": "Constant/Issue", + "constantCost": "5min" + }, + "tags": [ + "ecocode", + "environment", + "sobriety", + "eco-design" + ], + "type": "CODE_SMELL" +} diff --git a/swift-lang/src/main/resources/ESOB006.html b/swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB006.html similarity index 100% rename from swift-lang/src/main/resources/ESOB006.html rename to swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB006.html diff --git a/swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB006.json b/swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB006.json new file mode 100644 index 0000000..b7b102b --- /dev/null +++ b/swift-lang/src/main/resources/io/ecocode/rules/swift/ESOB006.json @@ -0,0 +1,18 @@ +{ + "key": "ESOB006", + "title": "Sobriety: Torch Free", + "defaultSeverity": "Major", + "description": "Usage of `AVCaptureDevice#torchMode` or `AVCaptureDevice#setTorchModeOn(level:)` must absolutely be avoided. These methods can be used to access the device's flashlight, which can be a potential security risk and should only be used when necessary.", + "status": "ready", + "remediation": { + "func": "Constant/Issue", + "constantCost": "5min" + }, + "tags": [ + "sobriety", + "environment", + "ecocode", + "eco-design" + ], + "type": "CODE_SMELL" +} diff --git a/swift-lang/src/test/java/io/ecocode/ios/swift/EcoCodeSwiftRulesDefinitionTest.java b/swift-lang/src/test/java/io/ecocode/ios/swift/EcoCodeSwiftRulesDefinitionTest.java new file mode 100644 index 0000000..1b06552 --- /dev/null +++ b/swift-lang/src/test/java/io/ecocode/ios/swift/EcoCodeSwiftRulesDefinitionTest.java @@ -0,0 +1,84 @@ +/* + * ecoCode iOS plugin - Help the earth, adopt this green plugin for your applications + * Copyright © 2023 green-code-initiative (https://www.ecocode.io/) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package io.ecocode.ios.swift; + +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.sonar.api.SonarRuntime; +import org.sonar.api.rules.RuleType; +import org.sonar.api.server.debt.DebtRemediationFunction.Type; +import org.sonar.api.server.rule.RulesDefinition; +import org.sonar.api.server.rule.RulesDefinition.Rule; +import org.sonar.api.utils.Version; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + + +class EcoCodeSwiftRulesDefinitionTest { + + private RulesDefinition.Repository repository; + private RulesDefinition.Context context; + + @BeforeEach + void init() { + final SonarRuntime sonarRuntime = mock(SonarRuntime.class); + doReturn(Version.create(0, 0)).when(sonarRuntime).getApiVersion(); + EcoCodeSwiftRulesDefinition rulesDefinition = new EcoCodeSwiftRulesDefinition(sonarRuntime); + RulesDefinition.Context context = new RulesDefinition.Context(); + rulesDefinition.define(context); + repository = context.repository(rulesDefinition.repositoryKey()); + } + + @Test + @DisplayName("Test repository metadata") + void testMetadata() { + assertThat(repository.name()).isEqualTo("ecoCode"); + assertThat(repository.language()).isEqualTo("swift"); + assertThat(repository.key()).isEqualTo("ecoCode-swift"); + } + + @Test + void testRegistredRules() { + assertThat(repository.rules()).hasSize(9); + } + + @Test + void assertRuleProperties() { + Rule rule = repository.rule("EIDL001"); + assertThat(rule).isNotNull(); + assertThat(rule.name()).isEqualTo("Idle timer disabled"); + assertThat(rule.debtRemediationFunction().type()).isEqualTo(Type.CONSTANT_ISSUE); + assertThat(rule.debtRemediationFunction().baseEffort()).isEqualTo("5min"); + assertThat(rule.type()).isEqualTo(RuleType.CODE_SMELL); + } + + @Test + void testAllRuleParametersHaveDescription() { + SoftAssertions assertions = new SoftAssertions(); + repository.rules().stream() + .flatMap(rule -> rule.params().stream()) + .forEach(param -> assertions.assertThat(param.description()).as("description for " + param.key()).isNotEmpty()); + assertions.assertAll(); + } + +} diff --git a/swift-lang/src/test/java/io/ecocode/ios/swift/checks/geolocalisation/ThriftyGeolocationCheckTest.java b/swift-lang/src/test/java/io/ecocode/ios/swift/checks/geolocalisation/ThriftyGeolocationCheckTest.java index f06b7a8..a7f3b22 100644 --- a/swift-lang/src/test/java/io/ecocode/ios/swift/checks/geolocalisation/ThriftyGeolocationCheckTest.java +++ b/swift-lang/src/test/java/io/ecocode/ios/swift/checks/geolocalisation/ThriftyGeolocationCheckTest.java @@ -35,6 +35,7 @@ public void Geo_trigger() { Optional issue = context.allIssues().stream().findFirst(); issue.ifPresent(i -> { assertThat(i.ruleKey().rule()).isEqualTo("ESOB002"); + assertThat(i.ruleKey().repository()).isEqualTo("ecoCode-swift"); IssueLocation location = i.primaryLocation(); assertThat(location.textRange().start().line()).isEqualTo(1); From d7106148687a5d8315d143e54cea38854243e9df Mon Sep 17 00:00:00 2001 From: jycr Date: Tue, 11 Jul 2023 11:35:26 +0200 Subject: [PATCH 2/2] Adds additional information for installation --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8fcad26..b4228ee 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,9 @@ ecoCode iOS SonarQube plugin is an "eco-responsibility" static code analyzer for Ready to use binaries are available [from GitHub](https://github.com/green-code-initiative/ecoCode-ios/releases). -🚀 Quickstart +NB: To work, `ecocode-ios` needs `Swift` language support in SonarQube. For *SonarQube Community Edition* (which does not support Swift language), you need to install an additional plugin like [sonar-apple](https://github.com/insideapp-oss/sonar-apple). + +🚀 Development Quickstart ------------- ### Requirements