diff --git a/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/OCLintParser.java b/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/OCLintParser.java deleted file mode 100644 index f7d5500f..00000000 --- a/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/OCLintParser.java +++ /dev/null @@ -1,72 +0,0 @@ -/** - * backelite-sonar-objective-c-plugin - Enables analysis of Objective-C projects into SonarQube. - * Copyright © 2012 OCTO Technology, Backelite (${email}) - * - * 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, see . - */ -package org.sonar.plugins.objectivec.violations.oclint; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; - -import javax.xml.stream.XMLStreamException; - -import org.slf4j.LoggerFactory; -import org.sonar.api.batch.SensorContext; -import org.sonar.api.batch.fs.FileSystem; -import org.sonar.api.component.ResourcePerspectives; -import org.sonar.api.resources.Project; -import org.sonar.api.utils.StaxParser; - -final class OCLintParser { - - private final Project project; - private final SensorContext context; - private final ResourcePerspectives resourcePerspectives; - private final FileSystem fileSystem; - - public OCLintParser(final Project p, final SensorContext c, final ResourcePerspectives resourcePerspectives, final FileSystem fileSystem) { - project = p; - context = c; - this.resourcePerspectives = resourcePerspectives; - this.fileSystem = fileSystem; - } - - public void parseReport(final File file) { - - try { - final InputStream reportStream = new FileInputStream(file); - parseReport(reportStream); - reportStream.close(); - } catch (final IOException e) { - LoggerFactory.getLogger(getClass()).error("Error processing file named {}", file, e); - } - - } - - public void parseReport(final InputStream inputStream) { - - try { - final StaxParser parser = new StaxParser( - new OCLintXMLStreamHandler(project, context, resourcePerspectives, fileSystem)); - parser.parse(inputStream); - } catch (final XMLStreamException e) { - LoggerFactory.getLogger(getClass()).error( - "Error while parsing XML stream.", e); - } - } - -} diff --git a/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/OCLintReportParser.java b/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/OCLintReportParser.java new file mode 100644 index 00000000..c4dfdefb --- /dev/null +++ b/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/OCLintReportParser.java @@ -0,0 +1,104 @@ +/** + * backelite-sonar-objective-c-plugin - Enables analysis of Objective-C projects into SonarQube. + * Copyright © 2012 OCTO Technology, Backelite (${email}) + * + * 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, see . + */ +package org.sonar.plugins.objectivec.violations.oclint; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import javax.annotation.Nonnull; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +final class OCLintReportParser { + private static final Logger LOGGER = LoggerFactory.getLogger(OCLintReportParser.class); + + private static final String VIOLATION = "violation"; + private static final String PATH = "path"; + private static final String START_LINE = "startline"; + private static final String RULE = "rule"; + private static final String MESSAGE = "message"; + + @Nonnull + private static NodeList getViolationElements(@Nonnull Document document) { + return document.getElementsByTagName(VIOLATION); + } + + @Nonnull + List parse(@Nonnull final File xmlFile) { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + + try { + DocumentBuilder builder = factory.newDocumentBuilder(); + Document document = builder.parse(xmlFile); + + return parse(document); + } catch (final FileNotFoundException e){ + LOGGER.error("OCLint report not found {}", xmlFile, e); + } catch (final ParserConfigurationException e) { + LOGGER.error("Error parsing file named {}", xmlFile, e); + } catch (final IOException | SAXException e) { + LOGGER.error("Error processing file named {}", xmlFile, e); + } + + return Collections.emptyList(); + } + + @Nonnull + List parse(@Nonnull final Document document) { + List violations = new ArrayList<>(); + + NodeList violationElements = getViolationElements(document); + for (int i = 0; i < violationElements.getLength(); i++) { + Node node = violationElements.item(i); + if (isNotElement(node)) { + continue; + } + + Element element = (Element) node; + violations.add(buildViolation(element)); + } + + return violations; + } + + private boolean isNotElement(@Nonnull Node item) { + return item.getNodeType() != Node.ELEMENT_NODE; + } + + @Nonnull + private Violation buildViolation(@Nonnull Element element) { + return Violation.builder() + .setPath(element.getAttribute(PATH)) + .setStartLine(Integer.parseInt(element.getAttribute(START_LINE))) + .setRule(element.getAttribute(RULE)) + .setMessage(element.getAttribute(MESSAGE)) + .build(); + } +} diff --git a/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/OCLintRulesDefinition.java b/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/OCLintRulesDefinition.java index f9cd192c..6499e889 100644 --- a/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/OCLintRulesDefinition.java +++ b/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/OCLintRulesDefinition.java @@ -26,6 +26,7 @@ import org.sonar.plugins.objectivec.core.ObjectiveC; import org.sonar.squidbridge.rules.SqaleXmlLoader; +import javax.annotation.Nonnull; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -47,7 +48,7 @@ public class OCLintRulesDefinition implements RulesDefinition { private static final String RULES_FILE = "/org/sonar/plugins/oclint/rules.txt"; @Override - public void define(Context context) { + public void define(@Nonnull Context context) { NewRepository repository = context .createRepository(REPOSITORY_KEY, ObjectiveC.KEY) @@ -73,7 +74,7 @@ private void loadRules(NewRepository repository) throws IOException { final List listLines = IOUtils.readLines(reader); String previousLine = null; - Map rule = new HashMap(); + Map rule = new HashMap<>(); boolean inDescription = false; for (String line : listLines) { @@ -86,7 +87,7 @@ private void loadRules(NewRepository repository) throws IOException { // Remove the rule name from the description of the previous // rule if (rule.get("description") != null) { - String description = rule.get("description").toString(); + String description = rule.get("description"); final int index = description.lastIndexOf(previousLine); if (index > 0) { rule.put("description", description.substring(0, index)); @@ -107,10 +108,10 @@ private void loadRules(NewRepository repository) throws IOException { inDescription = true; // Create rule when last filed found - RulesDefinition.NewRule newRule = repository.createRule(rule.get("key").toString()); - newRule.setName(rule.get("name").toString()); - newRule.setSeverity(rule.get("severity").toString()); - newRule.setHtmlDescription(rule.get("description").toString()); + RulesDefinition.NewRule newRule = repository.createRule(rule.get("key")); + newRule.setName(rule.get("name")); + newRule.setSeverity(rule.get("severity")); + newRule.setHtmlDescription(rule.get("description")); } else if (line.matches("Severity:.*")) { inDescription = false; @@ -119,7 +120,7 @@ private void loadRules(NewRepository repository) throws IOException { } else { if (inDescription) { line = ruleDescriptionLink(line); - String description = (String)rule.get("description"); + String description = rule.get("description"); rule.put("description", description + "
" + line); } } diff --git a/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/OCLintSensor.java b/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/OCLintSensor.java index 13bb0af9..7333d79f 100644 --- a/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/OCLintSensor.java +++ b/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/OCLintSensor.java @@ -18,66 +18,77 @@ package org.sonar.plugins.objectivec.violations.oclint; import java.io.File; +import java.util.ArrayList; +import java.util.List; import org.apache.tools.ant.DirectoryScanner; +import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.sonar.api.batch.Sensor; -import org.sonar.api.batch.SensorContext; import org.sonar.api.batch.fs.FileSystem; -import org.sonar.api.component.ResourcePerspectives; +import org.sonar.api.batch.sensor.Sensor; +import org.sonar.api.batch.sensor.SensorDescriptor; import org.sonar.api.config.Settings; -import org.sonar.api.resources.Project; import org.sonar.plugins.objectivec.ObjectiveCPlugin; import org.sonar.plugins.objectivec.core.ObjectiveC; +import javax.annotation.Nonnull; + public final class OCLintSensor implements Sensor { public static final String REPORT_PATH_KEY = ObjectiveCPlugin.PROPERTY_PREFIX + ".oclint.report"; public static final String DEFAULT_REPORT_PATH = "sonar-reports/*oclint.xml"; + private static final Logger LOGGER = LoggerFactory.getLogger(OCLintSensor.class); + private static final String NAME = "OCLint violation sensor"; + + private final OCLintReportParser parser = new OCLintReportParser(); private final Settings conf; private final FileSystem fileSystem; - private final ResourcePerspectives resourcePerspectives; - public OCLintSensor(final FileSystem fileSystem, final Settings config, final ResourcePerspectives resourcePerspectives) { + public OCLintSensor(final FileSystem fileSystem, final Settings config) { this.conf = config; this.fileSystem = fileSystem; - this.resourcePerspectives = resourcePerspectives; } - public boolean shouldExecuteOnProject(final Project project) { - - return project.isRoot() && fileSystem.languages().contains(ObjectiveC.KEY); - + @Override + public void describe(@Nonnull SensorDescriptor descriptor) { + descriptor.name(NAME); + descriptor.onlyOnLanguage(ObjectiveC.KEY); } - public void analyse(final Project project, final SensorContext context) { + @Override + public void execute(@Nonnull org.sonar.api.batch.sensor.SensorContext context) { final String projectBaseDir = fileSystem.baseDir().getPath(); - final OCLintParser parser = new OCLintParser(project, context, resourcePerspectives, fileSystem); - - parseReportIn(projectBaseDir, parser); + parseReportIn(projectBaseDir, OCLintViolationPersistor.create(context)); } - private void parseReportIn(final String baseDir, final OCLintParser parser) { - + private void parseReportIn(final String baseDir, OCLintViolationPersistor persistor) { DirectoryScanner scanner = new DirectoryScanner(); - scanner.setIncludes(new String[]{reportPath()}); + scanner.setIncludes(new String[]{buildReportPath()}); scanner.setBasedir(baseDir); scanner.setCaseSensitive(false); scanner.scan(); String[] files = scanner.getIncludedFiles(); + List violations = new ArrayList<>(); + for(String filename : files) { - LoggerFactory.getLogger(getClass()).info("Processing OCLint report {}", filename); - parser.parseReport(new File(filename)); + LOGGER.info("Processing OCLint report {}", filename); + + violations.addAll(parser.parse(new File(filename))); } + + persistor.saveViolations(violations); } - private String reportPath() { + private String buildReportPath() { String reportPath = conf.getString(REPORT_PATH_KEY); + if (reportPath == null) { + LOGGER.debug("No value specified for \"" + REPORT_PATH_KEY + "\" using default path"); reportPath = DEFAULT_REPORT_PATH; } + return reportPath; } } diff --git a/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/OCLintViolationPersistor.java b/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/OCLintViolationPersistor.java new file mode 100644 index 00000000..d95aa49f --- /dev/null +++ b/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/OCLintViolationPersistor.java @@ -0,0 +1,79 @@ +/** + * backelite-sonar-objective-c-plugin - Enables analysis of Objective-C projects into SonarQube. + * Copyright © 2012 OCTO Technology, Backelite (${email}) + * + * 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, see . + */ +package org.sonar.plugins.objectivec.violations.oclint; + +import org.sonar.api.batch.fs.FilePredicate; +import org.sonar.api.batch.fs.FileSystem; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.batch.sensor.issue.NewIssue; +import org.sonar.api.batch.sensor.issue.NewIssueLocation; +import org.sonar.api.rule.RuleKey; + +import javax.annotation.Nonnull; +import java.io.File; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +final class OCLintViolationPersistor { + private final SensorContext context; + private final FileSystem fileSystem; + + private OCLintViolationPersistor(@Nonnull final SensorContext context, @Nonnull final FileSystem fileSystem) { + this.context = context; + this.fileSystem = fileSystem; + } + + @Nonnull + static OCLintViolationPersistor create(@Nonnull final SensorContext context) { + return new OCLintViolationPersistor(context, context.fileSystem()); + } + + void saveViolations(@Nonnull List violations) { + violations.stream() + .collect(Collectors.groupingBy(Violation::getPath)) + .forEach(this::saveViolationsGroupedByFile); + } + + private void saveViolationsGroupedByFile(@Nonnull String absoluteFilePath, @Nonnull List violations) { + Optional value = buildInputFile(absoluteFilePath); + value.ifPresent(inputFile -> { + for (Violation violation : violations) { + RuleKey rule = RuleKey.of(OCLintRulesDefinition.REPOSITORY_KEY, violation.getRule()); + NewIssue newIssue = context.newIssue().forRule(rule); + + NewIssueLocation location = newIssue.newLocation() + .on(inputFile) + .at(inputFile.selectLine(violation.getStartLine())) + .message(violation.getMessage()); + + newIssue.at(location) + .save(); + } + }); + } + + @Nonnull + private Optional buildInputFile(@Nonnull String absoluteFilePath) { + File file = new File(absoluteFilePath); + FilePredicate predicate = fileSystem.predicates().hasAbsolutePath(file.getAbsolutePath()); + + return Optional.ofNullable(fileSystem.inputFile(predicate)); + } +} diff --git a/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/OCLintXMLStreamHandler.java b/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/OCLintXMLStreamHandler.java deleted file mode 100644 index 28c51030..00000000 --- a/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/OCLintXMLStreamHandler.java +++ /dev/null @@ -1,112 +0,0 @@ -/** - * backelite-sonar-objective-c-plugin - Enables analysis of Objective-C projects into SonarQube. - * Copyright © 2012 OCTO Technology, Backelite (${email}) - * - * 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, see . - */ -package org.sonar.plugins.objectivec.violations.oclint; - -import java.io.File; - -import javax.xml.stream.XMLStreamException; - -import org.codehaus.staxmate.in.SMHierarchicCursor; -import org.codehaus.staxmate.in.SMInputCursor; -import org.slf4j.LoggerFactory; -import org.sonar.api.batch.SensorContext; -import org.sonar.api.batch.fs.FileSystem; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.component.ResourcePerspectives; -import org.sonar.api.issue.Issuable; -import org.sonar.api.issue.Issue; -import org.sonar.api.resources.Project; -import org.sonar.api.rule.RuleKey; -import org.sonar.api.utils.StaxParser.XmlStreamHandler; - -final class OCLintXMLStreamHandler implements XmlStreamHandler { - private static final int PMD_MINIMUM_PRIORITY = 5; - private final Project project; - private final SensorContext context; - private final ResourcePerspectives resourcePerspectives; - private final FileSystem fileSystem; - - public OCLintXMLStreamHandler(final Project p, final SensorContext c, final ResourcePerspectives resourcePerspectives, final FileSystem fileSystem) { - project = p; - context = c; - this.resourcePerspectives = resourcePerspectives; - this.fileSystem = fileSystem; - } - - public void stream(final SMHierarchicCursor rootCursor) throws XMLStreamException { - - final SMInputCursor file = rootCursor.advance().childElementCursor("file"); - while (null != file.getNext()) { - collectIssuesFor(file); - } - } - - private void collectIssuesFor(final SMInputCursor file) throws XMLStreamException { - - final String filePath = file.getAttrValue("name"); - LoggerFactory.getLogger(getClass()).debug("Collection violations for {}", filePath); - final InputFile inputFile = findResource(filePath); - if (fileExists(inputFile)) { - LoggerFactory.getLogger(getClass()).debug("File {} was found in the project.", filePath); - collectFileIssues(inputFile, file); - } - } - - private void collectFileIssues(final InputFile inputFile, final SMInputCursor file) throws XMLStreamException { - - final SMInputCursor line = file.childElementCursor("violation"); - - while (null != line.getNext()) { - recordViolation(inputFile, line); - } - } - - private InputFile findResource(final String filePath) { - - File file = new File(filePath); - return fileSystem.inputFile(fileSystem.predicates().hasAbsolutePath(file.getAbsolutePath())); - - } - - private void recordViolation(InputFile inputFile, final SMInputCursor line) throws XMLStreamException { - - Issuable issuable = resourcePerspectives.as(Issuable.class, inputFile); - - if (issuable != null) { - - Issue issue = issuable.newIssueBuilder() - .ruleKey(RuleKey.of(OCLintRulesDefinition.REPOSITORY_KEY, line.getAttrValue("rule"))) - .line(Integer.valueOf(line.getAttrValue("beginline"))) - .message(line.getElemStringValue()) - .build(); - - issuable.addIssue(issue); - - - } - } - - private boolean fileExists(InputFile file) { - if (file == null) { - return false; - } - - return context.getResource(file) != null; - } - -} diff --git a/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/Violation.java b/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/Violation.java new file mode 100644 index 00000000..544e649a --- /dev/null +++ b/sonar-objective-c-plugin/src/main/java/org/sonar/plugins/objectivec/violations/oclint/Violation.java @@ -0,0 +1,125 @@ +/** + * backelite-sonar-objective-c-plugin - Enables analysis of Objective-C projects into SonarQube. + * Copyright © 2012 OCTO Technology, Backelite (${email}) + * + * 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, see . + */ +package org.sonar.plugins.objectivec.violations.oclint; + +import javax.annotation.Nonnull; +import java.util.Objects; + +final class Violation { + private final String path; + private final int startLine; + private final String rule; + private final String message; + + Violation(Builder builder) { + this.path = builder.path; + this.startLine = builder.startLine; + this.rule = builder.rule; + this.message = builder.message; + } + + @Nonnull + public String getPath() { + return path; + } + + public int getStartLine() { + return startLine; + } + + @Nonnull + public String getRule() { + return rule; + } + + @Nonnull + public String getMessage() { + return message; + } + + @Nonnull + static Builder builder() { + return new Builder(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof Violation)) { + return false; + } + + Violation violation = (Violation) o; + return startLine == violation.startLine && + Objects.equals(path, violation.path) && + Objects.equals(rule, violation.rule) && + Objects.equals(message, violation.message); + } + + @Override + public int hashCode() { + return Objects.hash( + path, + startLine, + rule, + message + ); + } + + static class Builder { + private String path = ""; + private int startLine; + private String rule = ""; + private String message = ""; + + private Builder() { + } + + @Nonnull + Builder setPath(@Nonnull String path) { + this.path = path; + return this; + } + + @Nonnull + Builder setStartLine(int startLine) { + this.startLine = startLine; + return this; + } + + @Nonnull + Builder setRule(@Nonnull String rule) { + this.rule = rule; + return this; + } + + @Nonnull + Builder setMessage(@Nonnull String message) { + this.message = message; + return this; + } + + @Nonnull + Violation build() { + return new Violation(this); + } + } +} diff --git a/sonar-objective-c-plugin/src/test/java/org/sonar/plugins/objectivec/violations/oclint/OCLintReportParserTest.java b/sonar-objective-c-plugin/src/test/java/org/sonar/plugins/objectivec/violations/oclint/OCLintReportParserTest.java new file mode 100644 index 00000000..2c992a34 --- /dev/null +++ b/sonar-objective-c-plugin/src/test/java/org/sonar/plugins/objectivec/violations/oclint/OCLintReportParserTest.java @@ -0,0 +1,105 @@ +/** + * backelite-sonar-objective-c-plugin - Enables analysis of Objective-C projects into SonarQube. + * Copyright © 2012 OCTO Technology, Backelite (${email}) + * + * 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, see . + */ +package org.sonar.plugins.objectivec.violations.oclint; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +import javax.annotation.Nonnull; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +@RunWith(JUnit4.class) +public class OCLintReportParserTest { + private final Path resourcePath = Paths.get("src", "test", "resources", "oclint"); + + private DocumentBuilder builder; + private OCLintReportParser parser; + + @Before + public void setUp() throws Exception { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + builder = factory.newDocumentBuilder(); + + parser = new OCLintReportParser(); + } + + @Test + public void parse_withEmptyDocument() throws Exception { + Path documentPath = Paths.get(resourcePath.toString(), "empty.xml"); + Document document = builder.parse(documentPath.toFile()); + + List actual = parser.parse(document); + + assertTrue(actual.isEmpty()); + } + + @Test + public void parse_withSampleDocument() throws IOException, SAXException { + Path documentPath = Paths.get(resourcePath.toString(), "oclint.xml"); + Document document = builder.parse(documentPath.toFile()); + List expected = buildExpectedViolationsForSample(); + + List actual = parser.parse(document); + + assertEquals(expected, actual); + } + + @Nonnull + private List buildExpectedViolationsForSample() { + List expected = new ArrayList<>(); + Violation violation; + + violation = Violation.builder() + .setPath("RASqlite/RASqlite.m") + .setStartLine(281) + .setRule("deep nested block") + .setMessage("Block depth of 6 exceeds limit of 5") + .build(); + expected.add(violation); + + violation = Violation.builder() + .setPath("RASqlite/RASqlite.m") + .setStartLine(305) + .setRule("ivar assignment outside accessors or init") + .build(); + expected.add(violation); + + violation = Violation.builder() + .setPath("RASqlite/RASqlite.m") + .setStartLine(707) + .setRule("unused method parameter") + .setMessage("The parameter 'commit' is unused.") + .build(); + expected.add(violation); + + return expected; + } +} diff --git a/sonar-objective-c-plugin/src/test/java/org/sonar/plugins/objectivec/violations/oclint/OCLintSensorTest.java b/sonar-objective-c-plugin/src/test/java/org/sonar/plugins/objectivec/violations/oclint/OCLintSensorTest.java new file mode 100644 index 00000000..cff50db0 --- /dev/null +++ b/sonar-objective-c-plugin/src/test/java/org/sonar/plugins/objectivec/violations/oclint/OCLintSensorTest.java @@ -0,0 +1,64 @@ +/** + * backelite-sonar-objective-c-plugin - Enables analysis of Objective-C projects into SonarQube. + * Copyright © 2012 OCTO Technology, Backelite (${email}) + * + * 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, see . + */ +package org.sonar.plugins.objectivec.violations.oclint; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.sonar.api.batch.fs.internal.DefaultFileSystem; +import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor; +import org.sonar.api.config.MapSettings; +import org.sonar.api.config.Settings; +import org.sonar.plugins.objectivec.core.ObjectiveC; + +import java.io.File; +import java.io.IOException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +@RunWith(JUnit4.class) +public class OCLintSensorTest { + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + private OCLintSensor sensor; + + @Before + public void prepare() throws IOException { + File baseDirectory = temporaryFolder.newFolder(); + + DefaultFileSystem fileSystem = new DefaultFileSystem(baseDirectory.toPath()); + Settings settings = new MapSettings(); + + sensor = new OCLintSensor(fileSystem, settings); + } + + @Test + public void describe() { + DefaultSensorDescriptor descriptor = new DefaultSensorDescriptor(); + + sensor.describe(descriptor); + + assertEquals("OCLint violation sensor", descriptor.name()); + assertTrue(descriptor.languages().contains(ObjectiveC.KEY)); + } +} diff --git a/sonar-objective-c-plugin/src/test/resources/oclint/empty.xml b/sonar-objective-c-plugin/src/test/resources/oclint/empty.xml new file mode 100644 index 00000000..04b5dc0d --- /dev/null +++ b/sonar-objective-c-plugin/src/test/resources/oclint/empty.xml @@ -0,0 +1,15 @@ + + + 2018-02-10T08:50:19Z + + 0 + 0 + 0 + 0 + 0 + + + + + + diff --git a/sonar-objective-c-plugin/src/test/resources/oclint/oclint.xml b/sonar-objective-c-plugin/src/test/resources/oclint/oclint.xml new file mode 100644 index 00000000..1a2bbdb9 --- /dev/null +++ b/sonar-objective-c-plugin/src/test/resources/oclint/oclint.xml @@ -0,0 +1,21 @@ + + + 2018-02-10T08:50:19Z + + 9 + 6 + 0 + 1 + 2 + + + + + + + + + + + +