From a08dca8fe215bb6e9ddd1e553488241e78601a08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Gil=20Herrera?= Date: Thu, 28 May 2015 14:43:45 +0200 Subject: [PATCH 01/19] add Sensor for Lizard report. Parser for Lizard report (xml) created and measure persistor class created to save the measures of the lizard repor. --- .../plugins/objectivec/ObjectiveCPlugin.java | 11 +- .../complexity/LizardMeasurePersistor.java | 64 +++++++ .../complexity/LizardReportParser.java | 179 ++++++++++++++++++ .../objectivec/complexity/LizardSensor.java | 91 +++++++++ 4 files changed, 343 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java create mode 100644 src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java create mode 100644 src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java diff --git a/src/main/java/org/sonar/plugins/objectivec/ObjectiveCPlugin.java b/src/main/java/org/sonar/plugins/objectivec/ObjectiveCPlugin.java index 8fa3b673..3debe84a 100644 --- a/src/main/java/org/sonar/plugins/objectivec/ObjectiveCPlugin.java +++ b/src/main/java/org/sonar/plugins/objectivec/ObjectiveCPlugin.java @@ -25,6 +25,7 @@ import org.sonar.api.Properties; import org.sonar.api.Property; import org.sonar.api.SonarPlugin; +import org.sonar.plugins.objectivec.complexity.LizardSensor; import org.sonar.plugins.objectivec.coverage.CoberturaSensor; import org.sonar.plugins.objectivec.colorizer.ObjectiveCColorizerFormat; import org.sonar.plugins.objectivec.core.ObjectiveC; @@ -53,11 +54,17 @@ public List> getExtensions() { ObjectiveCSquidSensor.class, ObjectiveCProfile.class, + SurefireSensor.class, + CoberturaSensor.class, + OCLintRuleRepository.class, - OCLintSensor.class, OCLintProfile.class, - OCLintProfileImporter.class + OCLintSensor.class, + OCLintProfile.class, + OCLintProfileImporter.class, + + LizardSensor.class ); } diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java new file mode 100644 index 00000000..fdfa2078 --- /dev/null +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java @@ -0,0 +1,64 @@ +/* + * Sonar Objective-C Plugin + * Copyright (C) 2012 OCTO Technology + * dev@sonar.codehaus.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.objectivec.complexity; + +import org.slf4j.LoggerFactory; +import org.sonar.api.batch.SensorContext; +import org.sonar.api.measures.Measure; +import org.sonar.api.resources.Project; + +import java.io.File; +import java.util.List; +import java.util.Map; + +/** + * Created by agilherr on 28/05/15. + */ +@SuppressWarnings("deprecation") +public class LizardMeasurePersistor { + + private final Project project; + private final SensorContext context; + + public LizardMeasurePersistor(final Project p, final SensorContext c) { + project = p; + context = c; + } + + public void saveMeasures(final Map> measures) { + for (Map.Entry> entry : measures.entrySet()) { + final org.sonar.api.resources.File objcfile = org.sonar.api.resources.File.fromIOFile(new File(project.getFileSystem().getBasedir(), entry.getKey()), project); + if (fileExists(context, objcfile)) { + for (Measure measure : entry.getValue()) { + try { + context.saveMeasure(objcfile, measure); + } catch (Exception e) { + LoggerFactory.getLogger(getClass()).error(" Exception -> {} -> {}", entry.getKey(), measure.getMetric().getName()); + } + } + } + } + } + + private boolean fileExists(final SensorContext context, + final org.sonar.api.resources.File file) { + return context.getResource(file) != null; + } +} diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java new file mode 100644 index 00000000..20b4f9d6 --- /dev/null +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java @@ -0,0 +1,179 @@ +/* + * Sonar Objective-C Plugin + * Copyright (C) 2012 OCTO Technology + * dev@sonar.codehaus.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.objectivec.complexity; + +import org.slf4j.LoggerFactory; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Measure; +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.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Created by agilherr on 28/05/15. + */ +public class LizardReportParser { + + private static final String MEASURE = "measure"; + private static final String MEASURE_TYPE = "type"; + private static final String MEASURE_ITEM = "item"; + private static final String FILE_MEASURE = "file"; + private static final String FUNCTION_MEASURE = "Function"; + private static final String NAME = "name"; + private static final String VALUE = "value"; + private static final int CYCLOMATIC_COMPLEXITY_INDEX = 2; + private static final int FUNCTIONS_INDEX = 3; + + public Map> parseReport(final File xmlFile) { + Map> result = null; + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + + try { + DocumentBuilder builder = factory.newDocumentBuilder(); + Document document = builder.parse(xmlFile); + result = parseFile(document); + } catch (final IOException e) { + LoggerFactory.getLogger(getClass()).error("Error processing file named {}", xmlFile, e); + } catch (ParserConfigurationException e) { + LoggerFactory.getLogger(getClass()).error("Error processing file named {}", xmlFile, e); + } catch (SAXException e) { + LoggerFactory.getLogger(getClass()).error("Error processing file named {}", xmlFile, e); + } + + return result; + } + + public Map> parseFile(Document document) { + final Map> reportMeasures = new HashMap>(); + final List functions = new ArrayList(); + + NodeList nodeList = document.getElementsByTagName(MEASURE); + + for (int i = 0; i < nodeList.getLength(); i++) { + Node node = nodeList.item(i); + + if (node.getNodeType() == Node.ELEMENT_NODE) { + Element element = (Element) node; + if (element.getAttribute(MEASURE_TYPE).equalsIgnoreCase(FILE_MEASURE)) { + NodeList itemList = element.getElementsByTagName(MEASURE_ITEM); + addComplexityPerFileMeasure(itemList, reportMeasures); + } else if(element.getAttribute(MEASURE_TYPE).equalsIgnoreCase(FUNCTION_MEASURE)) { + NodeList itemList = element.getElementsByTagName(MEASURE_ITEM); + collectFunctions(itemList, functions); + } + } + } + + addComplexityPerFunctionMeasure(reportMeasures, functions); + + return reportMeasures; + } + + private void addComplexityPerFileMeasure(NodeList itemList, Map> reportMeasures){ + for (int i = 0; i < itemList.getLength(); i++) { + Node item = itemList.item(i); + + if (item.getNodeType() == Node.ELEMENT_NODE) { + Element itemElement = (Element) item; + String fileName = itemElement.getAttribute(NAME); + NodeList values = itemElement.getElementsByTagName(VALUE); + int fileComplexity = Integer.parseInt(values.item(CYCLOMATIC_COMPLEXITY_INDEX).getTextContent()); + int numberOfFunctions = Integer.parseInt(values.item(FUNCTIONS_INDEX).getTextContent()); + + List list = new ArrayList(); + //list.add(new Measure(CoreMetrics.COMPLEXITY).setIntValue(fileComplexity)); + list.add(new Measure(CoreMetrics.FILE_COMPLEXITY).setIntValue(fileComplexity)); + //list.add(new Measure(CoreMetrics.FUNCTIONS).setIntValue(numberOfFunctions));//TODO throws exception while saving + + reportMeasures.put(fileName, list); + } + } + } + + private void collectFunctions(NodeList itemList, List functions) { + for (int i = 0; i < itemList.getLength(); i++) { + Node item = itemList.item(i); + + if (item.getNodeType() == Node.ELEMENT_NODE) { + Element itemElement = (Element) item; + String name = itemElement.getAttribute(NAME); + String measure = itemElement.getElementsByTagName(VALUE).item(CYCLOMATIC_COMPLEXITY_INDEX).getTextContent(); + functions.add(new ObjCFunction(name, Integer.parseInt(measure))); + } + } + } + + private void addComplexityPerFunctionMeasure(Map> reportMeasures, List functions){ + for (Map.Entry> entry : reportMeasures.entrySet()) { + int count = 0; + for (ObjCFunction func : functions) { + if (func.getName().contains(entry.getKey())) { + count++; + } + } + + int complex = 0; + for (Measure m : entry.getValue()){ + if (m.getMetric().getKey().equalsIgnoreCase(CoreMetrics.FILE_COMPLEXITY.getKey())){ + complex = m.getIntValue(); + break; + } + } + + double complexMean = 0; + if (count != 0) { + complexMean = (double)complex/(double)count; + } + + entry.getValue().add(new Measure(CoreMetrics.FUNCTION_COMPLEXITY, complexMean)); + } + } + + private class ObjCFunction { + private String name; + private int cyclomaticComplexity; + + public ObjCFunction(String name, int cyclomaticComplexity) { + this.name = name; + this.cyclomaticComplexity = cyclomaticComplexity; + } + + public String getName() { + return name; + } + + public int getCyclomaticComplexity() { + return cyclomaticComplexity; + } + + } +} diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java new file mode 100644 index 00000000..89aaaff3 --- /dev/null +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java @@ -0,0 +1,91 @@ +/* + * Sonar Objective-C Plugin + * Copyright (C) 2012 OCTO Technology + * dev@sonar.codehaus.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ + +package org.sonar.plugins.objectivec.complexity; + +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.config.Settings; +import org.sonar.api.measures.Measure; +import org.sonar.api.resources.Project; +import org.sonar.plugins.objectivec.ObjectiveCPlugin; +import org.sonar.plugins.objectivec.core.ObjectiveC; + +import java.io.File; +import java.util.List; +import java.util.Map; + +/** + * Created by agilherr on 28/05/15. + */ +@SuppressWarnings("deprecation") +public class LizardSensor implements Sensor { + + public static final String REPORT_PATH_KEY = ObjectiveCPlugin.PROPERTY_PREFIX + + ".lizard.report"; + public static final String DEFAULT_REPORT_PATH = "sonar-reports/lizard-report.xml"; + + private final Settings conf; + private final FileSystem fileSystem; + + public LizardSensor(final FileSystem moduleFileSystem, final Settings config) { + this.conf = config; + this.fileSystem = moduleFileSystem; + } + + @Override + public boolean shouldExecuteOnProject(Project project) { + return project.isRoot() && fileSystem.languages().contains(ObjectiveC.KEY); + } + + @Override + public void analyse(Project project, SensorContext sensorContext) { + final String projectBaseDir = project.getFileSystem().getBasedir().getPath(); + Map> measures = parseReportsIn(projectBaseDir, new LizardReportParser()); + + for (Map.Entry> entry: measures.entrySet()) { + String[] filePath = entry.getKey().split("/"); + LoggerFactory.getLogger(getClass()).info("{}", filePath[filePath.length - 1]); + for (Measure measure : entry.getValue()) { + LoggerFactory.getLogger(getClass()).info(" {} = {}", measure.getMetric().getName(), measure.getValue()); + } + } + + new LizardMeasurePersistor(project, sensorContext).saveMeasures(measures); + } + + //key = file name, + private Map> parseReportsIn(final String baseDir, LizardReportParser parser) { + final StringBuilder reportFileName = new StringBuilder(baseDir); + reportFileName.append("/").append(reportPath()); + LoggerFactory.getLogger(getClass()).info("Processing complexity report "); + return parser.parseReport(new File(reportFileName.toString())); + } + + private String reportPath() { + String reportPath = conf.getString(REPORT_PATH_KEY); + if (reportPath == null) { + reportPath = DEFAULT_REPORT_PATH; + } + return reportPath; + } +} From 8065fe5f313cda91079f853a7517a1c9e8528da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Gil=20Herrera?= Date: Thu, 28 May 2015 16:45:21 +0200 Subject: [PATCH 02/19] lizard sensor saves file complexity and function complexity but those values are displayed as 0 in the dashboard. Trying to savin complexity throws exception -> Can not add the same measure twice on org.sonar.api.resources.File ... --- .../complexity/LizardMeasurePersistor.java | 33 ++++++++++++++++--- .../complexity/LizardReportParser.java | 15 ++++++--- .../objectivec/complexity/LizardSensor.java | 2 +- 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java index fdfa2078..86952f6a 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java @@ -21,10 +21,11 @@ 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.measures.Measure; import org.sonar.api.resources.Project; -import java.io.File; import java.util.List; import java.util.Map; @@ -36,13 +37,36 @@ public class LizardMeasurePersistor { private final Project project; private final SensorContext context; + private final FileSystem fileSystem; - public LizardMeasurePersistor(final Project p, final SensorContext c) { - project = p; - context = c; + public LizardMeasurePersistor(final Project p, final SensorContext c, final FileSystem fileSystem) { + this.project = p; + this.context = c; + this.fileSystem = fileSystem; } public void saveMeasures(final Map> measures) { + + for (InputFile file : fileSystem.inputFiles(fileSystem.predicates().all())) { + //LoggerFactory.getLogger(getClass()).info("Inputfile {} \n {}", file.absolutePath(), file.relativePath()); + for (Map.Entry> entry : measures.entrySet()){ + String path = entry.getKey(); + String name = file.relativePath(); + if (path.equalsIgnoreCase(name)){ + //LoggerFactory.getLogger(getClass()).info("Save Measures for inputfile"); + for (Measure measure : entry.getValue()){ + try { + context.saveMeasure(file, measure); + } catch (Exception e) { + LoggerFactory.getLogger(getClass()).error(" Exception -> {} -> {} \n {}", entry.getKey(), measure.getMetric().getName(), e.getMessage()); + } + } + break; + } + } + } + + /* for (Map.Entry> entry : measures.entrySet()) { final org.sonar.api.resources.File objcfile = org.sonar.api.resources.File.fromIOFile(new File(project.getFileSystem().getBasedir(), entry.getKey()), project); if (fileExists(context, objcfile)) { @@ -55,6 +79,7 @@ public void saveMeasures(final Map> measures) { } } } + */ } private boolean fileExists(final SensorContext context, diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java index 20b4f9d6..09d95c47 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java @@ -22,6 +22,7 @@ import org.slf4j.LoggerFactory; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Measure; +import org.sonar.api.measures.Metric; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -106,13 +107,16 @@ private void addComplexityPerFileMeasure(NodeList itemList, Map list = new ArrayList(); - //list.add(new Measure(CoreMetrics.COMPLEXITY).setIntValue(fileComplexity)); - list.add(new Measure(CoreMetrics.FILE_COMPLEXITY).setIntValue(fileComplexity)); - //list.add(new Measure(CoreMetrics.FUNCTIONS).setIntValue(numberOfFunctions));//TODO throws exception while saving + Metric complexityMetric = CoreMetrics.COMPLEXITY; + complexityMetric.setDomain("complexity"); + list.add(new Measure(CoreMetrics.COMPLEXITY).setIntValue(complexity)); + list.add(new Measure(CoreMetrics.FUNCTIONS).setIntValue(numberOfFunctions));//TODO throws exception while saving + list.add(new Measure(CoreMetrics.FILE_COMPLEXITY, fileComplexity)); reportMeasures.put(fileName, list); } @@ -135,9 +139,11 @@ private void collectFunctions(NodeList itemList, List functions) { private void addComplexityPerFunctionMeasure(Map> reportMeasures, List functions){ for (Map.Entry> entry : reportMeasures.entrySet()) { int count = 0; + int complexityInFunctions = 0; for (ObjCFunction func : functions) { if (func.getName().contains(entry.getKey())) { count++; + complexityInFunctions += func.getCyclomaticComplexity(); } } @@ -154,6 +160,7 @@ private void addComplexityPerFunctionMeasure(Map> reportMe complexMean = (double)complex/(double)count; } + entry.getValue().add(new Measure(CoreMetrics.COMPLEXITY_IN_FUNCTIONS).setIntValue(complexityInFunctions)); entry.getValue().add(new Measure(CoreMetrics.FUNCTION_COMPLEXITY, complexMean)); } } diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java index 89aaaff3..4025c6c4 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java @@ -70,7 +70,7 @@ public void analyse(Project project, SensorContext sensorContext) { } } - new LizardMeasurePersistor(project, sensorContext).saveMeasures(measures); + new LizardMeasurePersistor(project, sensorContext, fileSystem).saveMeasures(measures); } //key = file name, From e9148834749a8de76ea003615ac25a423959ec5a Mon Sep 17 00:00:00 2001 From: Andres Gil Herrera Date: Thu, 28 May 2015 20:01:14 +0200 Subject: [PATCH 03/19] properties for lizard and lizard report is now generated by run-sonar.sh --- sample/sonar-project.properties | 4 ++++ src/main/shell/run-sonar.sh | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/sample/sonar-project.properties b/sample/sonar-project.properties index 41ed559f..58797447 100644 --- a/sample/sonar-project.properties +++ b/sample/sonar-project.properties @@ -48,6 +48,10 @@ sonar.sourceEncoding=UTF-8 # Change it only if you generate the file on your own # sonar.objectivec.oclint.report=sonar-reports/oclint.xml +# Lizard report generated by run-sonar.sh is stored in sonar-reports/lizard-report.xml +# Change it only if you generate the file on your own +# sonar.objectivec.lizard.report=sonar-reports/lizard-report.xml + # Paths to exclude from coverage report (tests, 3rd party libraries etc.) # sonar.objectivec.excludedPathsFromCoverage=pattern1,pattern2 sonar.objectivec.excludedPathsFromCoverage=.*Tests.* diff --git a/src/main/shell/run-sonar.sh b/src/main/shell/run-sonar.sh index f82d33ef..8267fb93 100755 --- a/src/main/shell/run-sonar.sh +++ b/src/main/shell/run-sonar.sh @@ -117,6 +117,7 @@ function runCommand() { vflag="" nflag="" oclint="on" +lizard="on" while [ $# -gt 0 ] do case "$1" in @@ -293,6 +294,17 @@ else echo 'Skipping OCLint (test purposes only!)' fi +if [ "$lizard" = "on" ]; then + + # Lizard + echo -n 'Running Lizard...' + + # Run Lizard with xml output option and write the output in sonar-reports/lizard-report.xml + runCommand lizard --xml "$srcDirs" > sonar-reports/lizard-report.xml +else + echo 'Skipping Lizard (test purposes only!)' +fi + # SonarQube echo -n 'Running SonarQube using SonarQube Runner' runCommand /dev/stdout sonar-runner From 5b52843c0a3341e34f57545e6083424a9e4e20e9 Mon Sep 17 00:00:00 2001 From: Andres Gil Herrera Date: Fri, 29 May 2015 00:04:08 +0200 Subject: [PATCH 04/19] ObjectiveCSquidSensor does not save functions and complexity as it would actually do because it was causing that saving comlexity and functions for files throw exception. Lizard measure now saves the measures succesfully --- .../objectivec/ObjectiveCSquidSensor.java | 4 +-- .../complexity/LizardMeasurePersistor.java | 29 ++++++++++++------- .../complexity/LizardReportParser.java | 3 +- .../objectivec/complexity/LizardSensor.java | 4 ++- src/main/shell/run-sonar.sh | 2 +- 5 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/sonar/plugins/objectivec/ObjectiveCSquidSensor.java b/src/main/java/org/sonar/plugins/objectivec/ObjectiveCSquidSensor.java index 43bbb5e9..9c9b3f0e 100644 --- a/src/main/java/org/sonar/plugins/objectivec/ObjectiveCSquidSensor.java +++ b/src/main/java/org/sonar/plugins/objectivec/ObjectiveCSquidSensor.java @@ -102,9 +102,9 @@ private void saveMeasures(File sonarFile, SourceFile squidFile) { context.saveMeasure(sonarFile, CoreMetrics.FILES, squidFile.getDouble(ObjectiveCMetric.FILES)); context.saveMeasure(sonarFile, CoreMetrics.LINES, squidFile.getDouble(ObjectiveCMetric.LINES)); context.saveMeasure(sonarFile, CoreMetrics.NCLOC, squidFile.getDouble(ObjectiveCMetric.LINES_OF_CODE)); - context.saveMeasure(sonarFile, CoreMetrics.FUNCTIONS, squidFile.getDouble(ObjectiveCMetric.FUNCTIONS)); + //context.saveMeasure(sonarFile, CoreMetrics.FUNCTIONS, squidFile.getDouble(ObjectiveCMetric.FUNCTIONS)); context.saveMeasure(sonarFile, CoreMetrics.STATEMENTS, squidFile.getDouble(ObjectiveCMetric.STATEMENTS)); - context.saveMeasure(sonarFile, CoreMetrics.COMPLEXITY, squidFile.getDouble(ObjectiveCMetric.COMPLEXITY)); + //context.saveMeasure(sonarFile, CoreMetrics.COMPLEXITY, squidFile.getDouble(ObjectiveCMetric.COMPLEXITY)); context.saveMeasure(sonarFile, CoreMetrics.COMMENT_LINES, squidFile.getDouble(ObjectiveCMetric.COMMENT_LINES)); } diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java index 86952f6a..919f21a6 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java @@ -20,12 +20,14 @@ package org.sonar.plugins.objectivec.complexity; import org.slf4j.LoggerFactory; +import org.sonar.api.batch.DecoratorContext; import org.sonar.api.batch.SensorContext; import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.measures.Measure; import org.sonar.api.resources.Project; +import java.io.File; import java.util.List; import java.util.Map; @@ -35,18 +37,25 @@ @SuppressWarnings("deprecation") public class LizardMeasurePersistor { - private final Project project; - private final SensorContext context; - private final FileSystem fileSystem; + private Project project; + private SensorContext sensorContext; + private DecoratorContext decoratorContext; + private FileSystem fileSystem; + + public LizardMeasurePersistor(final Project p, final DecoratorContext c) { + this.project = p; + this.decoratorContext = c; + this.fileSystem = fileSystem; + } public LizardMeasurePersistor(final Project p, final SensorContext c, final FileSystem fileSystem) { this.project = p; - this.context = c; + this.sensorContext = c; this.fileSystem = fileSystem; } public void saveMeasures(final Map> measures) { - +/* for (InputFile file : fileSystem.inputFiles(fileSystem.predicates().all())) { //LoggerFactory.getLogger(getClass()).info("Inputfile {} \n {}", file.absolutePath(), file.relativePath()); for (Map.Entry> entry : measures.entrySet()){ @@ -56,7 +65,7 @@ public void saveMeasures(final Map> measures) { //LoggerFactory.getLogger(getClass()).info("Save Measures for inputfile"); for (Measure measure : entry.getValue()){ try { - context.saveMeasure(file, measure); + sensorContext.saveMeasure(file, measure); } catch (Exception e) { LoggerFactory.getLogger(getClass()).error(" Exception -> {} -> {} \n {}", entry.getKey(), measure.getMetric().getName(), e.getMessage()); } @@ -66,20 +75,20 @@ public void saveMeasures(final Map> measures) { } } - /* + */ for (Map.Entry> entry : measures.entrySet()) { final org.sonar.api.resources.File objcfile = org.sonar.api.resources.File.fromIOFile(new File(project.getFileSystem().getBasedir(), entry.getKey()), project); - if (fileExists(context, objcfile)) { + if (fileExists(sensorContext, objcfile)) { for (Measure measure : entry.getValue()) { try { - context.saveMeasure(objcfile, measure); + sensorContext.saveMeasure(objcfile, measure); } catch (Exception e) { LoggerFactory.getLogger(getClass()).error(" Exception -> {} -> {}", entry.getKey(), measure.getMetric().getName()); } } } } - */ + } private boolean fileExists(final SensorContext context, diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java index 09d95c47..9a313062 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java @@ -115,7 +115,7 @@ private void addComplexityPerFileMeasure(NodeList itemList, Map functions) { for (int i = 0; i < itemList.getLength(); i++) { Node item = itemList.item(i); - if (item.getNodeType() == Node.ELEMENT_NODE) { Element itemElement = (Element) item; String name = itemElement.getAttribute(NAME); diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java index 4025c6c4..b66afb90 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java @@ -62,6 +62,7 @@ public void analyse(Project project, SensorContext sensorContext) { final String projectBaseDir = project.getFileSystem().getBasedir().getPath(); Map> measures = parseReportsIn(projectBaseDir, new LizardReportParser()); + /* for (Map.Entry> entry: measures.entrySet()) { String[] filePath = entry.getKey().split("/"); LoggerFactory.getLogger(getClass()).info("{}", filePath[filePath.length - 1]); @@ -69,8 +70,9 @@ public void analyse(Project project, SensorContext sensorContext) { LoggerFactory.getLogger(getClass()).info(" {} = {}", measure.getMetric().getName(), measure.getValue()); } } + */ - new LizardMeasurePersistor(project, sensorContext, fileSystem).saveMeasures(measures); + new LizardMeasurePersistor(project, sensorContext, fileSystem).saveMeasuresForSensor(measures); } //key = file name, diff --git a/src/main/shell/run-sonar.sh b/src/main/shell/run-sonar.sh index 8267fb93..e4e9f68b 100755 --- a/src/main/shell/run-sonar.sh +++ b/src/main/shell/run-sonar.sh @@ -300,7 +300,7 @@ if [ "$lizard" = "on" ]; then echo -n 'Running Lizard...' # Run Lizard with xml output option and write the output in sonar-reports/lizard-report.xml - runCommand lizard --xml "$srcDirs" > sonar-reports/lizard-report.xml + lizard --xml "$srcDirs" > sonar-reports/lizard-report.xml else echo 'Skipping Lizard (test purposes only!)' fi From d42fe0163475b5b6c2036812f6373cd24f79bc8d Mon Sep 17 00:00:00 2001 From: Andres Gil Herrera Date: Fri, 29 May 2015 00:05:59 +0200 Subject: [PATCH 05/19] resolve little refactoring error --- .../org/sonar/plugins/objectivec/complexity/LizardSensor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java index b66afb90..7a9a4686 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java @@ -72,7 +72,7 @@ public void analyse(Project project, SensorContext sensorContext) { } */ - new LizardMeasurePersistor(project, sensorContext, fileSystem).saveMeasuresForSensor(measures); + new LizardMeasurePersistor(project, sensorContext, fileSystem).saveMeasures(measures); } //key = file name, From 5013d75b982e2c755fd4397cba150abe8f3aa715 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Gil=20Herrera?= Date: Wed, 3 Jun 2015 16:48:22 +0200 Subject: [PATCH 06/19] tests --- .../objectivec/ObjectiveCSquidSensor.java | 5 + .../complexity/LizardMeasurePersistor.java | 36 +--- .../complexity/LizardReportParser.java | 5 +- .../objectivec/complexity/LizardSensor.java | 18 +- .../complexity/LizardReportParserTest.java | 160 ++++++++++++++++++ .../complexity/LizardSensorTest.java | 79 +++++++++ 6 files changed, 253 insertions(+), 50 deletions(-) create mode 100644 src/test/java/org/sonar/plugins/objectivec/complexity/LizardReportParserTest.java create mode 100644 src/test/java/org/sonar/plugins/objectivec/complexity/LizardSensorTest.java diff --git a/src/main/java/org/sonar/plugins/objectivec/ObjectiveCSquidSensor.java b/src/main/java/org/sonar/plugins/objectivec/ObjectiveCSquidSensor.java index 9c9b3f0e..8b59781e 100644 --- a/src/main/java/org/sonar/plugins/objectivec/ObjectiveCSquidSensor.java +++ b/src/main/java/org/sonar/plugins/objectivec/ObjectiveCSquidSensor.java @@ -102,6 +102,11 @@ private void saveMeasures(File sonarFile, SourceFile squidFile) { context.saveMeasure(sonarFile, CoreMetrics.FILES, squidFile.getDouble(ObjectiveCMetric.FILES)); context.saveMeasure(sonarFile, CoreMetrics.LINES, squidFile.getDouble(ObjectiveCMetric.LINES)); context.saveMeasure(sonarFile, CoreMetrics.NCLOC, squidFile.getDouble(ObjectiveCMetric.LINES_OF_CODE)); + /** + * Saving the same measure more than one for a file throws an exception and that is why + * CoreMetrics.FUNCTIONS and CoreMetrics.COMPLEXITY are not allowed to be saved here, In order for the + * LizardSensor to be able to to its job and save the values for those metrics. + */ //context.saveMeasure(sonarFile, CoreMetrics.FUNCTIONS, squidFile.getDouble(ObjectiveCMetric.FUNCTIONS)); context.saveMeasure(sonarFile, CoreMetrics.STATEMENTS, squidFile.getDouble(ObjectiveCMetric.STATEMENTS)); //context.saveMeasure(sonarFile, CoreMetrics.COMPLEXITY, squidFile.getDouble(ObjectiveCMetric.COMPLEXITY)); diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java index 919f21a6..af19c023 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java @@ -32,50 +32,20 @@ import java.util.Map; /** - * Created by agilherr on 28/05/15. + * @author Andres Gil Herrera + * @since 28/05/15. */ -@SuppressWarnings("deprecation") public class LizardMeasurePersistor { private Project project; private SensorContext sensorContext; - private DecoratorContext decoratorContext; - private FileSystem fileSystem; - public LizardMeasurePersistor(final Project p, final DecoratorContext c) { - this.project = p; - this.decoratorContext = c; - this.fileSystem = fileSystem; - } - - public LizardMeasurePersistor(final Project p, final SensorContext c, final FileSystem fileSystem) { + public LizardMeasurePersistor(final Project p, final SensorContext c) { this.project = p; this.sensorContext = c; - this.fileSystem = fileSystem; } public void saveMeasures(final Map> measures) { -/* - for (InputFile file : fileSystem.inputFiles(fileSystem.predicates().all())) { - //LoggerFactory.getLogger(getClass()).info("Inputfile {} \n {}", file.absolutePath(), file.relativePath()); - for (Map.Entry> entry : measures.entrySet()){ - String path = entry.getKey(); - String name = file.relativePath(); - if (path.equalsIgnoreCase(name)){ - //LoggerFactory.getLogger(getClass()).info("Save Measures for inputfile"); - for (Measure measure : entry.getValue()){ - try { - sensorContext.saveMeasure(file, measure); - } catch (Exception e) { - LoggerFactory.getLogger(getClass()).error(" Exception -> {} -> {} \n {}", entry.getKey(), measure.getMetric().getName(), e.getMessage()); - } - } - break; - } - } - } - - */ for (Map.Entry> entry : measures.entrySet()) { final org.sonar.api.resources.File objcfile = org.sonar.api.resources.File.fromIOFile(new File(project.getFileSystem().getBasedir(), entry.getKey()), project); if (fileExists(sensorContext, objcfile)) { diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java index 9a313062..e7c68d54 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java @@ -40,7 +40,8 @@ import java.util.Map; /** - * Created by agilherr on 28/05/15. + * @author Andres Gil Herrera + * @since 28/05/15 */ public class LizardReportParser { @@ -112,8 +113,6 @@ private void addComplexityPerFileMeasure(NodeList itemList, Map list = new ArrayList(); - Metric complexityMetric = CoreMetrics.COMPLEXITY; - complexityMetric.setDomain("complexity"); list.add(new Measure(CoreMetrics.COMPLEXITY).setIntValue(complexity)); list.add(new Measure(CoreMetrics.FUNCTIONS).setIntValue(numberOfFunctions)); list.add(new Measure(CoreMetrics.FILE_COMPLEXITY, fileComplexity)); diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java index 7a9a4686..30f3e512 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java @@ -35,7 +35,8 @@ import java.util.Map; /** - * Created by agilherr on 28/05/15. + * @author Andres Gil Herrera + * @since 28/05/15 */ @SuppressWarnings("deprecation") public class LizardSensor implements Sensor { @@ -61,21 +62,10 @@ public boolean shouldExecuteOnProject(Project project) { public void analyse(Project project, SensorContext sensorContext) { final String projectBaseDir = project.getFileSystem().getBasedir().getPath(); Map> measures = parseReportsIn(projectBaseDir, new LizardReportParser()); - - /* - for (Map.Entry> entry: measures.entrySet()) { - String[] filePath = entry.getKey().split("/"); - LoggerFactory.getLogger(getClass()).info("{}", filePath[filePath.length - 1]); - for (Measure measure : entry.getValue()) { - LoggerFactory.getLogger(getClass()).info(" {} = {}", measure.getMetric().getName(), measure.getValue()); - } - } - */ - - new LizardMeasurePersistor(project, sensorContext, fileSystem).saveMeasures(measures); + new LizardMeasurePersistor(project, sensorContext).saveMeasures(measures); } - //key = file name, + //key = file name private Map> parseReportsIn(final String baseDir, LizardReportParser parser) { final StringBuilder reportFileName = new StringBuilder(baseDir); reportFileName.append("/").append(reportPath()); diff --git a/src/test/java/org/sonar/plugins/objectivec/complexity/LizardReportParserTest.java b/src/test/java/org/sonar/plugins/objectivec/complexity/LizardReportParserTest.java new file mode 100644 index 00000000..de60e7cb --- /dev/null +++ b/src/test/java/org/sonar/plugins/objectivec/complexity/LizardReportParserTest.java @@ -0,0 +1,160 @@ +/* + * Sonar Objective-C Plugin + * Copyright (C) 2012 OCTO Technology + * dev@sonar.codehaus.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ + +package org.sonar.plugins.objectivec.complexity; + +import org.apache.log4j.spi.LoggerFactory; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Measure; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * @author Andres Gil Herrera + * @since 03/06/15. + */ +public class LizardReportParserTest { + + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + private File correctFile; + private File incorrectFile; + + @Before + public void setup() throws IOException { + correctFile = createCorrectFile(); + incorrectFile = folder.newFile("incorrectFile.xml"); + } + + public File createCorrectFile() throws IOException { + File xmlFile = folder.newFile("correctFile.xml"); + BufferedWriter out = new BufferedWriter(new FileWriter(xmlFile)); + //header + out.write(""); + out.write(""); + //root object and measure + out.write(""); + //items for function + out.write(""); + out.write("2151"); + out.write(""); + out.write("3205"); + //average and close funciton measure + out.write(""); + out.write(""); + out.write(""); + //open file measure and add the labels + out.write(""); + //items for file + out.write(""); + out.write("1200"); + out.write(""); + out.write("286862"); + //add averages + out.write(""); + //add sum + out.write(""); + //close measures and root object + out.write(""); + + out.close(); + + return xmlFile; + } + + @Test + public void parseReportShouldReturnMapWhenXMLFileIsCorrect() { + LizardReportParser parser = new LizardReportParser(); + + assertNotNull("correct file is null", correctFile); + + Map> report = parser.parseReport(correctFile); + + assertNotNull("report is null", report); + + assertTrue("Key is not there", report.containsKey("VW_R_App/Controller/Accelerate/VWRAccelerationViewController.h")); + List list1 = report.get("VW_R_App/Controller/Accelerate/VWRAccelerationViewController.h"); + assertEquals(0, list1.size()); + + /*for (Measure measure : list1) { + + String s = measure.getMetric().getKey(); + + if (s.equals(CoreMetrics.FUNCTIONS_KEY)) { + assertEquals("Header Functions has a wrong value", Integer.valueOf(0), measure.getIntValue()); + } else if (s.equals(CoreMetrics.COMPLEXITY_KEY)) { + assertEquals("Header Complexity has a wrong value", Integer.valueOf(0), measure.getIntValue()); + } else if (s.equals(CoreMetrics.FILE_COMPLEXITY_KEY)) { + assertEquals("Header File Complexity has a wrong value", Double.valueOf(0.0d), measure.getValue()); + } else if (s.equals(CoreMetrics.COMPLEXITY_IN_FUNCTIONS_KEY)) { + assertEquals("Header Complexity in Functions has a wrong value", Integer.valueOf(0), measure.getIntValue()); + } else if (s.equals(CoreMetrics.FUNCTION_COMPLEXITY)) { + assertEquals("Header Functions Complexity has a wrong value", Double.valueOf(0.0d), measure.getValue()); + } + + }*/ + + assertTrue("Key is not there", report.containsKey("VW_R_App/Controller/Accelerate/VWRAccelerationViewController.m")); + + + List list2 = report.get("VW_R_App/Controller/Accelerate/VWRAccelerationViewController.h"); + + /*for (Measure measure : list2) { + + org.slf4j.LoggerFactory.getLogger(getClass()).info("{}", measure); + + String s = measure.getMetric().getKey(); + + if (s.equals(CoreMetrics.FUNCTIONS_KEY)) { + assertEquals("MFile Functions has a wrong value", Integer.valueOf(2), measure.getIntValue()); + } else if (s.equals(CoreMetrics.COMPLEXITY_KEY)) { + assertEquals("MFile Complexity has a wrong value", Integer.valueOf(6), measure.getIntValue()); + } else if (s.equals(CoreMetrics.FILE_COMPLEXITY_KEY)) { + assertEquals("MFile File Complexity has a wrong value", Double.valueOf(6.0d), measure.getValue()); + } else if (s.equals(CoreMetrics.COMPLEXITY_IN_FUNCTIONS_KEY)) { + assertEquals("MFile Complexity in Functions has a wrong value", Integer.valueOf(6), measure.getIntValue()); + } else if (s.equals(CoreMetrics.FUNCTION_COMPLEXITY)) { + assertEquals("MFile Functions Complexity has a wrong value", 3.0d, measure.getValue(), 0.0d); + } + + }*/ + + } + + @Test + public void parseReportShouldReturnEmptyMapWhenXMLFileIsIncorrect() { + + } + +} diff --git a/src/test/java/org/sonar/plugins/objectivec/complexity/LizardSensorTest.java b/src/test/java/org/sonar/plugins/objectivec/complexity/LizardSensorTest.java new file mode 100644 index 00000000..15774fa9 --- /dev/null +++ b/src/test/java/org/sonar/plugins/objectivec/complexity/LizardSensorTest.java @@ -0,0 +1,79 @@ +/* + * Sonar Objective-C Plugin + * Copyright (C) 2012 OCTO Technology + * dev@sonar.codehaus.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ + +package org.sonar.plugins.objectivec.complexity; + +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.batch.fs.FileSystem; +import org.sonar.api.config.Settings; +import org.sonar.api.resources.Project; +import org.sonar.plugins.objectivec.core.ObjectiveC; + +import java.util.SortedSet; +import java.util.TreeSet; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * @author Andres Gil Herrera + * @since 03/06/15. + */ +public class LizardSensorTest { + + private Settings settings; + + @Before + public void setUp() { + settings = new Settings(); + } + + @Test + public void shouldExecuteOnProjectShouldBeTrueWhenProjectIsObjc() { + final Project project = new Project("Test"); + + FileSystem fileSystem = mock(FileSystem.class); + SortedSet languages = new TreeSet(); + languages.add(ObjectiveC.KEY); + when(fileSystem.languages()).thenReturn(languages); + + final LizardSensor testedSensor = new LizardSensor(fileSystem, settings); + + assertTrue(testedSensor.shouldExecuteOnProject(project)); + } + + @Test + public void shouldExecuteOnProjectShouldBeFalseWhenProjectIsSomethingElse() { + final Project project = new Project("Test"); + + FileSystem fileSystem = mock(FileSystem.class); + SortedSet languages = new TreeSet(); + languages.add("Test"); + when(fileSystem.languages()).thenReturn(languages); + + final LizardSensor testedSensor = new LizardSensor(fileSystem, settings); + + assertFalse(testedSensor.shouldExecuteOnProject(project)); + } + +} From 7091d1650c985dcd803dd2f88cb81da5ab7cbeae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Gil=20Herrera?= Date: Thu, 4 Jun 2015 15:26:18 +0200 Subject: [PATCH 07/19] tests finished --- .../complexity/LizardReportParser.java | 23 +++-- src/main/shell/run-sonar.sh | 3 +- .../complexity/LizardReportParserTest.java | 97 ++++++++++++------- 3 files changed, 77 insertions(+), 46 deletions(-) diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java index e7c68d54..37e4a39a 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java @@ -145,21 +145,20 @@ private void addComplexityPerFunctionMeasure(Map> reportMe } } - int complex = 0; - for (Measure m : entry.getValue()){ - if (m.getMetric().getKey().equalsIgnoreCase(CoreMetrics.FILE_COMPLEXITY.getKey())){ - complex = m.getIntValue(); - break; + if (count != 0) { + entry.getValue().add(new Measure(CoreMetrics.COMPLEXITY_IN_FUNCTIONS).setIntValue(complexityInFunctions)); + + double complex = 0; + for (Measure m : entry.getValue()){ + if (m.getMetric().getKey().equalsIgnoreCase(CoreMetrics.FILE_COMPLEXITY.getKey())){ + complex = m.getValue(); + break; + } } - } - double complexMean = 0; - if (count != 0) { - complexMean = (double)complex/(double)count; + double complexMean = complex/(double)count; + entry.getValue().add(new Measure(CoreMetrics.FUNCTION_COMPLEXITY, complexMean)); } - - entry.getValue().add(new Measure(CoreMetrics.COMPLEXITY_IN_FUNCTIONS).setIntValue(complexityInFunctions)); - entry.getValue().add(new Measure(CoreMetrics.FUNCTION_COMPLEXITY, complexMean)); } } diff --git a/src/main/shell/run-sonar.sh b/src/main/shell/run-sonar.sh index e4e9f68b..6024e5b0 100755 --- a/src/main/shell/run-sonar.sh +++ b/src/main/shell/run-sonar.sh @@ -165,7 +165,8 @@ srcDirs=''; readParameter srcDirs 'sonar.sources' appScheme=''; readParameter appScheme 'sonar.objectivec.appScheme' # The name of your test scheme in Xcode -testScheme=''; readParameter testScheme 'sonar.objectivec.testScheme' +testScheme=''; readParameter testScheme ' +c.testScheme' # The file patterns to exclude from coverage report excludedPathsFromCoverage=''; readParameter excludedPathsFromCoverage 'sonar.objectivec.excludedPathsFromCoverage' diff --git a/src/test/java/org/sonar/plugins/objectivec/complexity/LizardReportParserTest.java b/src/test/java/org/sonar/plugins/objectivec/complexity/LizardReportParserTest.java index de60e7cb..7365340b 100644 --- a/src/test/java/org/sonar/plugins/objectivec/complexity/LizardReportParserTest.java +++ b/src/test/java/org/sonar/plugins/objectivec/complexity/LizardReportParserTest.java @@ -20,7 +20,6 @@ package org.sonar.plugins.objectivec.complexity; -import org.apache.log4j.spi.LoggerFactory; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -35,9 +34,7 @@ import java.util.List; import java.util.Map; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; /** * @author Andres Gil Herrera @@ -54,7 +51,7 @@ public class LizardReportParserTest { @Before public void setup() throws IOException { correctFile = createCorrectFile(); - incorrectFile = folder.newFile("incorrectFile.xml"); + incorrectFile = createIncorrectFile(); } public File createCorrectFile() throws IOException { @@ -93,6 +90,42 @@ public File createCorrectFile() throws IOException { return xmlFile; } + public File createIncorrectFile() throws IOException { + File xmlFile = folder.newFile("incorrectFile.xml"); + BufferedWriter out = new BufferedWriter(new FileWriter(xmlFile)); + //header + out.write(""); + out.write(""); + //root object and measure + out.write(""); + //items for function + out.write(""); + out.write("2151"); + out.write(""); + out.write("3205"); + //average and close funciton measure + out.write(""); + out.write(""); + out.write(""); + //open file measure and add the labels + out.write(""); + //items for file 3th value tag has no closing tag + out.write(""); + out.write("1200"); + out.write(""); + out.write("286862"); + //add averages + out.write(""); + //add sum + out.write(""); + //close measures and root object no close tag for measure + out.write(""); + + out.close(); + + return xmlFile; + } + @Test public void parseReportShouldReturnMapWhenXMLFileIsCorrect() { LizardReportParser parser = new LizardReportParser(); @@ -105,55 +138,53 @@ public void parseReportShouldReturnMapWhenXMLFileIsCorrect() { assertTrue("Key is not there", report.containsKey("VW_R_App/Controller/Accelerate/VWRAccelerationViewController.h")); List list1 = report.get("VW_R_App/Controller/Accelerate/VWRAccelerationViewController.h"); - assertEquals(0, list1.size()); - - /*for (Measure measure : list1) { + assertEquals(3, list1.size()); + for (Measure measure : list1) { String s = measure.getMetric().getKey(); if (s.equals(CoreMetrics.FUNCTIONS_KEY)) { - assertEquals("Header Functions has a wrong value", Integer.valueOf(0), measure.getIntValue()); + assertEquals("Header Functions has a wrong value", 0, measure.getIntValue().intValue()); } else if (s.equals(CoreMetrics.COMPLEXITY_KEY)) { - assertEquals("Header Complexity has a wrong value", Integer.valueOf(0), measure.getIntValue()); + assertEquals("Header Complexity has a wrong value", 0, measure.getIntValue().intValue()); } else if (s.equals(CoreMetrics.FILE_COMPLEXITY_KEY)) { - assertEquals("Header File Complexity has a wrong value", Double.valueOf(0.0d), measure.getValue()); + assertEquals("Header File Complexity has a wrong value", 0.0d, measure.getValue().doubleValue(), 0.0d); } else if (s.equals(CoreMetrics.COMPLEXITY_IN_FUNCTIONS_KEY)) { - assertEquals("Header Complexity in Functions has a wrong value", Integer.valueOf(0), measure.getIntValue()); - } else if (s.equals(CoreMetrics.FUNCTION_COMPLEXITY)) { - assertEquals("Header Functions Complexity has a wrong value", Double.valueOf(0.0d), measure.getValue()); + assertEquals("Header Complexity in Functions has a wrong value", 0, measure.getIntValue().intValue()); + } else if (s.equals(CoreMetrics.FUNCTION_COMPLEXITY_KEY)) { + assertEquals("Header Functions Complexity has a wrong value", 0.0d, measure.getValue().doubleValue(), 0.0d); } - - }*/ + } assertTrue("Key is not there", report.containsKey("VW_R_App/Controller/Accelerate/VWRAccelerationViewController.m")); - - List list2 = report.get("VW_R_App/Controller/Accelerate/VWRAccelerationViewController.h"); - - /*for (Measure measure : list2) { - - org.slf4j.LoggerFactory.getLogger(getClass()).info("{}", measure); - + List list2 = report.get("VW_R_App/Controller/Accelerate/VWRAccelerationViewController.m"); + assertEquals(5, list2.size()); + for (Measure measure : list2) { String s = measure.getMetric().getKey(); if (s.equals(CoreMetrics.FUNCTIONS_KEY)) { - assertEquals("MFile Functions has a wrong value", Integer.valueOf(2), measure.getIntValue()); + assertEquals("MFile Functions has a wrong value", 2, measure.getIntValue().intValue()); } else if (s.equals(CoreMetrics.COMPLEXITY_KEY)) { - assertEquals("MFile Complexity has a wrong value", Integer.valueOf(6), measure.getIntValue()); + assertEquals("MFile Complexity has a wrong value", 6, measure.getIntValue().intValue()); } else if (s.equals(CoreMetrics.FILE_COMPLEXITY_KEY)) { - assertEquals("MFile File Complexity has a wrong value", Double.valueOf(6.0d), measure.getValue()); + assertEquals("MFile File Complexity has a wrong value", 6.0d, measure.getValue().doubleValue(), 0.0d); } else if (s.equals(CoreMetrics.COMPLEXITY_IN_FUNCTIONS_KEY)) { - assertEquals("MFile Complexity in Functions has a wrong value", Integer.valueOf(6), measure.getIntValue()); - } else if (s.equals(CoreMetrics.FUNCTION_COMPLEXITY)) { - assertEquals("MFile Functions Complexity has a wrong value", 3.0d, measure.getValue(), 0.0d); + assertEquals("MFile Complexity in Functions has a wrong value", 6, measure.getIntValue().intValue()); + } else if (s.equals(CoreMetrics.FUNCTION_COMPLEXITY_KEY)) { + assertEquals("MFile Functions Complexity has a wrong value", 3.0d, measure.getValue().doubleValue(), 0.0d); } - - }*/ - + } } @Test - public void parseReportShouldReturnEmptyMapWhenXMLFileIsIncorrect() { + public void parseReportShouldReturnNullWhenXMLFileIsIncorrect() { + LizardReportParser parser = new LizardReportParser(); + + assertNotNull("correct file is null", incorrectFile); + + Map> report = parser.parseReport(incorrectFile); + assertNull("report is not null", report); } From 1dfc0c378b0d421113384e259ad59cdb9220dbc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Gil=20Herrera?= Date: Fri, 5 Jun 2015 09:32:50 +0200 Subject: [PATCH 08/19] saving the file complexity distribution was moved from ObjectiveCSquidSensor to LizardMeasurePersistor --- .../objectivec/ObjectiveCSquidSensor.java | 15 ++++------ .../complexity/LizardMeasurePersistor.java | 28 +++++++++++++++++++ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/sonar/plugins/objectivec/ObjectiveCSquidSensor.java b/src/main/java/org/sonar/plugins/objectivec/ObjectiveCSquidSensor.java index 8b59781e..a8ce9226 100644 --- a/src/main/java/org/sonar/plugins/objectivec/ObjectiveCSquidSensor.java +++ b/src/main/java/org/sonar/plugins/objectivec/ObjectiveCSquidSensor.java @@ -53,7 +53,6 @@ public class ObjectiveCSquidSensor implements Sensor { private final Number[] FUNCTIONS_DISTRIB_BOTTOM_LIMITS = {1, 2, 4, 6, 8, 10, 12, 20, 30}; - private final Number[] FILES_DISTRIB_BOTTOM_LIMITS = {0, 5, 10, 20, 30, 60, 90}; private final AnnotationCheckFactory annotationCheckFactory; @@ -91,7 +90,11 @@ private void save(Collection squidSourceFiles) { File sonarFile = File.fromIOFile(new java.io.File(squidFile.getKey()), project); - saveFilesComplexityDistribution(sonarFile, squidFile); + /* + * Distribution is saved in the Lizard sensor and therefore it is not possible to save the complexity + * distribution here. The method was moved to LizardMeasurePersistor. + */ + //saveFilesComplexityDistribution(sonarFile, squidFile); saveFunctionsComplexityDistribution(sonarFile, squidFile); saveMeasures(sonarFile, squidFile); saveViolations(sonarFile, squidFile); @@ -103,7 +106,7 @@ private void saveMeasures(File sonarFile, SourceFile squidFile) { context.saveMeasure(sonarFile, CoreMetrics.LINES, squidFile.getDouble(ObjectiveCMetric.LINES)); context.saveMeasure(sonarFile, CoreMetrics.NCLOC, squidFile.getDouble(ObjectiveCMetric.LINES_OF_CODE)); /** - * Saving the same measure more than one for a file throws an exception and that is why + * Saving the same measure more than once for a file throws an exception and that is why * CoreMetrics.FUNCTIONS and CoreMetrics.COMPLEXITY are not allowed to be saved here, In order for the * LizardSensor to be able to to its job and save the values for those metrics. */ @@ -122,12 +125,6 @@ private void saveFunctionsComplexityDistribution(File sonarFile, SourceFile squi context.saveMeasure(sonarFile, complexityDistribution.build().setPersistenceMode(PersistenceMode.MEMORY)); } - private void saveFilesComplexityDistribution(File sonarFile, SourceFile squidFile) { - RangeDistributionBuilder complexityDistribution = new RangeDistributionBuilder(CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION, FILES_DISTRIB_BOTTOM_LIMITS); - complexityDistribution.add(squidFile.getDouble(ObjectiveCMetric.COMPLEXITY)); - context.saveMeasure(sonarFile, complexityDistribution.build().setPersistenceMode(PersistenceMode.MEMORY)); - } - private void saveViolations(File sonarFile, SourceFile squidFile) { Collection messages = squidFile.getCheckMessages(); if (messages != null) { diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java index af19c023..f0c80f15 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java @@ -24,10 +24,20 @@ import org.sonar.api.batch.SensorContext; import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Measure; +import org.sonar.api.measures.PersistenceMode; +import org.sonar.api.measures.RangeDistributionBuilder; import org.sonar.api.resources.Project; +import org.sonar.objectivec.api.ObjectiveCMetric; +import org.sonar.squidbridge.api.SourceCode; +import org.sonar.squidbridge.api.SourceFile; +import org.sonar.squidbridge.api.SourceFunction; +import org.sonar.squidbridge.indexer.QueryByParent; +import org.sonar.squidbridge.indexer.QueryByType; import java.io.File; +import java.util.Collection; import java.util.List; import java.util.Map; @@ -37,6 +47,9 @@ */ public class LizardMeasurePersistor { + private final Number[] FUNCTIONS_DISTRIB_BOTTOM_LIMITS = {1, 2, 4, 6, 8, 10, 12, 20, 30}; + private final Number[] FILES_DISTRIB_BOTTOM_LIMITS = {0, 5, 10, 20, 30, 60, 90}; + private Project project; private SensorContext sensorContext; @@ -56,9 +69,24 @@ public void saveMeasures(final Map> measures) { LoggerFactory.getLogger(getClass()).error(" Exception -> {} -> {}", entry.getKey(), measure.getMetric().getName()); } } + saveFilesComplexityDistribution(objcfile); } } + } + + /*private void saveFunctionsComplexityDistribution(org.sonar.api.resources.File sonarFile, SourceFile squidFile) { + Collection squidFunctionsInFile = scanner.getIndex().search(new QueryByParent(squidFile), new QueryByType(SourceFunction.class)); + RangeDistributionBuilder complexityDistribution = new RangeDistributionBuilder(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION, FUNCTIONS_DISTRIB_BOTTOM_LIMITS); + for (SourceCode squidFunction : squidFunctionsInFile) { + complexityDistribution.add(squidFunction.getDouble(ObjectiveCMetric.COMPLEXITY)); + } + context.saveMeasure(sonarFile, complexityDistribution.build().setPersistenceMode(PersistenceMode.MEMORY)); + }*/ + private void saveFilesComplexityDistribution(org.sonar.api.resources.File sonarFile) { + RangeDistributionBuilder complexityDistribution = new RangeDistributionBuilder(CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION, FILES_DISTRIB_BOTTOM_LIMITS); + complexityDistribution.add(sensorContext.getMeasure(sonarFile, CoreMetrics.FILE_COMPLEXITY).getValue()); + sensorContext.saveMeasure(sonarFile, complexityDistribution.build().setPersistenceMode(PersistenceMode.MEMORY)); } private boolean fileExists(final SensorContext context, From 282ebe6d52ce84735564c0d5260dad1d30cd89b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Gil=20Herrera?= Date: Fri, 5 Jun 2015 10:31:34 +0200 Subject: [PATCH 09/19] File/Function Complexity distribution functionality moved from ObjectiveCSquidSensor to LizardReportParser. --- .../objectivec/ObjectiveCSquidSensor.java | 22 +++----- .../complexity/LizardMeasurePersistor.java | 17 +------ .../complexity/LizardReportParser.java | 51 ++++++++++++------- .../complexity/LizardReportParserTest.java | 4 +- 4 files changed, 43 insertions(+), 51 deletions(-) diff --git a/src/main/java/org/sonar/plugins/objectivec/ObjectiveCSquidSensor.java b/src/main/java/org/sonar/plugins/objectivec/ObjectiveCSquidSensor.java index a8ce9226..a901ba9b 100644 --- a/src/main/java/org/sonar/plugins/objectivec/ObjectiveCSquidSensor.java +++ b/src/main/java/org/sonar/plugins/objectivec/ObjectiveCSquidSensor.java @@ -52,8 +52,6 @@ public class ObjectiveCSquidSensor implements Sensor { - private final Number[] FUNCTIONS_DISTRIB_BOTTOM_LIMITS = {1, 2, 4, 6, 8, 10, 12, 20, 30}; - private final AnnotationCheckFactory annotationCheckFactory; private Project project; @@ -92,10 +90,10 @@ private void save(Collection squidSourceFiles) { /* * Distribution is saved in the Lizard sensor and therefore it is not possible to save the complexity - * distribution here. The method was moved to LizardMeasurePersistor. + * distribution here. The functionality has been moved to LizardParser. */ //saveFilesComplexityDistribution(sonarFile, squidFile); - saveFunctionsComplexityDistribution(sonarFile, squidFile); + //saveFunctionsComplexityDistribution(sonarFile, squidFile); saveMeasures(sonarFile, squidFile); saveViolations(sonarFile, squidFile); } @@ -106,9 +104,10 @@ private void saveMeasures(File sonarFile, SourceFile squidFile) { context.saveMeasure(sonarFile, CoreMetrics.LINES, squidFile.getDouble(ObjectiveCMetric.LINES)); context.saveMeasure(sonarFile, CoreMetrics.NCLOC, squidFile.getDouble(ObjectiveCMetric.LINES_OF_CODE)); /** - * Saving the same measure more than once for a file throws an exception and that is why - * CoreMetrics.FUNCTIONS and CoreMetrics.COMPLEXITY are not allowed to be saved here, In order for the - * LizardSensor to be able to to its job and save the values for those metrics. + * Saving the same measure more than once per file throws exception. That is why + * CoreMetrics.FUNCTIONS and CoreMetrics.COMPLEXITY are not allowed to be saved here. In order for the + * LizardSensor to be able to to its job and save the values for those metrics the functionality has been + * moved to Lizard classes. */ //context.saveMeasure(sonarFile, CoreMetrics.FUNCTIONS, squidFile.getDouble(ObjectiveCMetric.FUNCTIONS)); context.saveMeasure(sonarFile, CoreMetrics.STATEMENTS, squidFile.getDouble(ObjectiveCMetric.STATEMENTS)); @@ -116,15 +115,6 @@ private void saveMeasures(File sonarFile, SourceFile squidFile) { context.saveMeasure(sonarFile, CoreMetrics.COMMENT_LINES, squidFile.getDouble(ObjectiveCMetric.COMMENT_LINES)); } - private void saveFunctionsComplexityDistribution(File sonarFile, SourceFile squidFile) { - Collection squidFunctionsInFile = scanner.getIndex().search(new QueryByParent(squidFile), new QueryByType(SourceFunction.class)); - RangeDistributionBuilder complexityDistribution = new RangeDistributionBuilder(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION, FUNCTIONS_DISTRIB_BOTTOM_LIMITS); - for (SourceCode squidFunction : squidFunctionsInFile) { - complexityDistribution.add(squidFunction.getDouble(ObjectiveCMetric.COMPLEXITY)); - } - context.saveMeasure(sonarFile, complexityDistribution.build().setPersistenceMode(PersistenceMode.MEMORY)); - } - private void saveViolations(File sonarFile, SourceFile squidFile) { Collection messages = squidFile.getCheckMessages(); if (messages != null) { diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java index f0c80f15..89317936 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java @@ -64,31 +64,16 @@ public void saveMeasures(final Map> measures) { if (fileExists(sensorContext, objcfile)) { for (Measure measure : entry.getValue()) { try { + LoggerFactory.getLogger(getClass()).debug("Save measure {} for file {}", measure.getMetric().getName(), objcfile.getName()); sensorContext.saveMeasure(objcfile, measure); } catch (Exception e) { LoggerFactory.getLogger(getClass()).error(" Exception -> {} -> {}", entry.getKey(), measure.getMetric().getName()); } } - saveFilesComplexityDistribution(objcfile); } } } - /*private void saveFunctionsComplexityDistribution(org.sonar.api.resources.File sonarFile, SourceFile squidFile) { - Collection squidFunctionsInFile = scanner.getIndex().search(new QueryByParent(squidFile), new QueryByType(SourceFunction.class)); - RangeDistributionBuilder complexityDistribution = new RangeDistributionBuilder(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION, FUNCTIONS_DISTRIB_BOTTOM_LIMITS); - for (SourceCode squidFunction : squidFunctionsInFile) { - complexityDistribution.add(squidFunction.getDouble(ObjectiveCMetric.COMPLEXITY)); - } - context.saveMeasure(sonarFile, complexityDistribution.build().setPersistenceMode(PersistenceMode.MEMORY)); - }*/ - - private void saveFilesComplexityDistribution(org.sonar.api.resources.File sonarFile) { - RangeDistributionBuilder complexityDistribution = new RangeDistributionBuilder(CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION, FILES_DISTRIB_BOTTOM_LIMITS); - complexityDistribution.add(sensorContext.getMeasure(sonarFile, CoreMetrics.FILE_COMPLEXITY).getValue()); - sensorContext.saveMeasure(sonarFile, complexityDistribution.build().setPersistenceMode(PersistenceMode.MEMORY)); - } - private boolean fileExists(final SensorContext context, final org.sonar.api.resources.File file) { return context.getResource(file) != null; diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java index 37e4a39a..e6a017cc 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java @@ -20,9 +20,7 @@ package org.sonar.plugins.objectivec.complexity; import org.slf4j.LoggerFactory; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.measures.Measure; -import org.sonar.api.measures.Metric; +import org.sonar.api.measures.*; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -45,6 +43,9 @@ */ public class LizardReportParser { + private final Number[] FUNCTIONS_DISTRIB_BOTTOM_LIMITS = {1, 2, 4, 6, 8, 10, 12, 20, 30}; + private final Number[] FILES_DISTRIB_BOTTOM_LIMITS = {0, 5, 10, 20, 30, 60, 90}; + private static final String MEASURE = "measure"; private static final String MEASURE_TYPE = "type"; private static final String MEASURE_ITEM = "item"; @@ -74,7 +75,7 @@ public Map> parseReport(final File xmlFile) { return result; } - public Map> parseFile(Document document) { + private Map> parseFile(Document document) { final Map> reportMeasures = new HashMap>(); final List functions = new ArrayList(); @@ -87,7 +88,7 @@ public Map> parseFile(Document document) { Element element = (Element) node; if (element.getAttribute(MEASURE_TYPE).equalsIgnoreCase(FILE_MEASURE)) { NodeList itemList = element.getElementsByTagName(MEASURE_ITEM); - addComplexityPerFileMeasure(itemList, reportMeasures); + addComplexityFileMeasures(itemList, reportMeasures); } else if(element.getAttribute(MEASURE_TYPE).equalsIgnoreCase(FUNCTION_MEASURE)) { NodeList itemList = element.getElementsByTagName(MEASURE_ITEM); collectFunctions(itemList, functions); @@ -95,12 +96,12 @@ public Map> parseFile(Document document) { } } - addComplexityPerFunctionMeasure(reportMeasures, functions); + addComplexityFunctionMeasures(reportMeasures, functions); return reportMeasures; } - private void addComplexityPerFileMeasure(NodeList itemList, Map> reportMeasures){ + private void addComplexityFileMeasures(NodeList itemList, Map> reportMeasures){ for (int i = 0; i < itemList.getLength(); i++) { Node item = itemList.item(i); @@ -112,16 +113,22 @@ private void addComplexityPerFileMeasure(NodeList itemList, Map list = new ArrayList(); - list.add(new Measure(CoreMetrics.COMPLEXITY).setIntValue(complexity)); - list.add(new Measure(CoreMetrics.FUNCTIONS).setIntValue(numberOfFunctions)); - list.add(new Measure(CoreMetrics.FILE_COMPLEXITY, fileComplexity)); - - reportMeasures.put(fileName, list); + reportMeasures.put(fileName, buildMeasureList(complexity, fileComplexity, numberOfFunctions)); } } } + private List buildMeasureList(int complexity, double fileComplexity, int numberOfFunctions){ + List list = new ArrayList(); + list.add(new Measure(CoreMetrics.COMPLEXITY).setIntValue(complexity)); + list.add(new Measure(CoreMetrics.FUNCTIONS).setIntValue(numberOfFunctions)); + list.add(new Measure(CoreMetrics.FILE_COMPLEXITY, fileComplexity)); + RangeDistributionBuilder complexityDistribution = new RangeDistributionBuilder(CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION, FILES_DISTRIB_BOTTOM_LIMITS); + complexityDistribution.add(fileComplexity); + list.add(complexityDistribution.build().setPersistenceMode(PersistenceMode.MEMORY)); + return list; + } + private void collectFunctions(NodeList itemList, List functions) { for (int i = 0; i < itemList.getLength(); i++) { Node item = itemList.item(i); @@ -134,20 +141,22 @@ private void collectFunctions(NodeList itemList, List functions) { } } - private void addComplexityPerFunctionMeasure(Map> reportMeasures, List functions){ + private void addComplexityFunctionMeasures(Map> reportMeasures, List functions){ for (Map.Entry> entry : reportMeasures.entrySet()) { + + RangeDistributionBuilder complexityDistribution = new RangeDistributionBuilder(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION, FUNCTIONS_DISTRIB_BOTTOM_LIMITS); int count = 0; int complexityInFunctions = 0; + for (ObjCFunction func : functions) { if (func.getName().contains(entry.getKey())) { + complexityDistribution.add(func.getCyclomaticComplexity()); count++; complexityInFunctions += func.getCyclomaticComplexity(); } } if (count != 0) { - entry.getValue().add(new Measure(CoreMetrics.COMPLEXITY_IN_FUNCTIONS).setIntValue(complexityInFunctions)); - double complex = 0; for (Measure m : entry.getValue()){ if (m.getMetric().getKey().equalsIgnoreCase(CoreMetrics.FILE_COMPLEXITY.getKey())){ @@ -157,11 +166,19 @@ private void addComplexityPerFunctionMeasure(Map> reportMe } double complexMean = complex/(double)count; - entry.getValue().add(new Measure(CoreMetrics.FUNCTION_COMPLEXITY, complexMean)); + entry.getValue().addAll(buildFuncionMeasuresList(complexMean, complexityInFunctions, complexityDistribution)); } } } + public List buildFuncionMeasuresList(double complexMean, int complexityInFunctions, RangeDistributionBuilder builder){ + List list = new ArrayList(); + list.add(new Measure(CoreMetrics.FUNCTION_COMPLEXITY, complexMean)); + list.add(new Measure(CoreMetrics.COMPLEXITY_IN_FUNCTIONS).setIntValue(complexityInFunctions)); + list.add(builder.build().setPersistenceMode(PersistenceMode.MEMORY)); + return list; + } + private class ObjCFunction { private String name; private int cyclomaticComplexity; diff --git a/src/test/java/org/sonar/plugins/objectivec/complexity/LizardReportParserTest.java b/src/test/java/org/sonar/plugins/objectivec/complexity/LizardReportParserTest.java index 7365340b..0fe88dca 100644 --- a/src/test/java/org/sonar/plugins/objectivec/complexity/LizardReportParserTest.java +++ b/src/test/java/org/sonar/plugins/objectivec/complexity/LizardReportParserTest.java @@ -138,7 +138,7 @@ public void parseReportShouldReturnMapWhenXMLFileIsCorrect() { assertTrue("Key is not there", report.containsKey("VW_R_App/Controller/Accelerate/VWRAccelerationViewController.h")); List list1 = report.get("VW_R_App/Controller/Accelerate/VWRAccelerationViewController.h"); - assertEquals(3, list1.size()); + assertEquals(4, list1.size()); for (Measure measure : list1) { String s = measure.getMetric().getKey(); @@ -159,7 +159,7 @@ public void parseReportShouldReturnMapWhenXMLFileIsCorrect() { assertTrue("Key is not there", report.containsKey("VW_R_App/Controller/Accelerate/VWRAccelerationViewController.m")); List list2 = report.get("VW_R_App/Controller/Accelerate/VWRAccelerationViewController.m"); - assertEquals(5, list2.size()); + assertEquals(7, list2.size()); for (Measure measure : list2) { String s = measure.getMetric().getKey(); From 0871e46c178f3a83e3058a0fe6a72b56504e6a53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Gil=20Herrera?= Date: Fri, 5 Jun 2015 10:43:43 +0200 Subject: [PATCH 10/19] changed one script line that was unintentionally modified --- src/main/shell/run-sonar.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/shell/run-sonar.sh b/src/main/shell/run-sonar.sh index 6024e5b0..e4e9f68b 100755 --- a/src/main/shell/run-sonar.sh +++ b/src/main/shell/run-sonar.sh @@ -165,8 +165,7 @@ srcDirs=''; readParameter srcDirs 'sonar.sources' appScheme=''; readParameter appScheme 'sonar.objectivec.appScheme' # The name of your test scheme in Xcode -testScheme=''; readParameter testScheme ' -c.testScheme' +testScheme=''; readParameter testScheme 'sonar.objectivec.testScheme' # The file patterns to exclude from coverage report excludedPathsFromCoverage=''; readParameter excludedPathsFromCoverage 'sonar.objectivec.excludedPathsFromCoverage' From 6df19c10e755eb98c830053f5ff692f346bd70da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Gil=20Herrera?= Date: Fri, 5 Jun 2015 10:46:18 +0200 Subject: [PATCH 11/19] constants from LizardMeasurePersistor deleted --- .../plugins/objectivec/complexity/LizardMeasurePersistor.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java index 89317936..30d4eab7 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java @@ -47,9 +47,6 @@ */ public class LizardMeasurePersistor { - private final Number[] FUNCTIONS_DISTRIB_BOTTOM_LIMITS = {1, 2, 4, 6, 8, 10, 12, 20, 30}; - private final Number[] FILES_DISTRIB_BOTTOM_LIMITS = {0, 5, 10, 20, 30, 60, 90}; - private Project project; private SensorContext sensorContext; From 9b39d535c8547f76d0a27ce78d6769efb763b380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Gil=20Herrera?= Date: Fri, 5 Jun 2015 10:59:25 +0200 Subject: [PATCH 12/19] dependency for xml parser and optimize imports in LizardMeasurePersistor.java --- pom.xml | 5 +++++ .../complexity/LizardMeasurePersistor.java | 13 ------------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index 8cf7bd1e..3df5fc60 100644 --- a/pom.xml +++ b/pom.xml @@ -182,6 +182,11 @@ sonar-surefire-plugin 2.7 + + xml-apis + xml-apis + 1.0.b2 + diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java index 30d4eab7..909feaa4 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java @@ -20,24 +20,11 @@ package org.sonar.plugins.objectivec.complexity; import org.slf4j.LoggerFactory; -import org.sonar.api.batch.DecoratorContext; import org.sonar.api.batch.SensorContext; -import org.sonar.api.batch.fs.FileSystem; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Measure; -import org.sonar.api.measures.PersistenceMode; -import org.sonar.api.measures.RangeDistributionBuilder; import org.sonar.api.resources.Project; -import org.sonar.objectivec.api.ObjectiveCMetric; -import org.sonar.squidbridge.api.SourceCode; -import org.sonar.squidbridge.api.SourceFile; -import org.sonar.squidbridge.api.SourceFunction; -import org.sonar.squidbridge.indexer.QueryByParent; -import org.sonar.squidbridge.indexer.QueryByType; import java.io.File; -import java.util.Collection; import java.util.List; import java.util.Map; From 2606f7b55136b5a043f374e274298832fa6e7192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Gil=20Herrera?= Date: Fri, 5 Jun 2015 11:13:31 +0200 Subject: [PATCH 13/19] loggs --- .../plugins/objectivec/complexity/LizardMeasurePersistor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java index 909feaa4..5e049ff1 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java @@ -48,7 +48,7 @@ public void saveMeasures(final Map> measures) { if (fileExists(sensorContext, objcfile)) { for (Measure measure : entry.getValue()) { try { - LoggerFactory.getLogger(getClass()).debug("Save measure {} for file {}", measure.getMetric().getName(), objcfile.getName()); + LoggerFactory.getLogger(getClass()).debug("Save measure {} for file {}", measure.getMetric().getName(), objcfile); sensorContext.saveMeasure(objcfile, measure); } catch (Exception e) { LoggerFactory.getLogger(getClass()).error(" Exception -> {} -> {}", entry.getKey(), measure.getMetric().getName()); From f8bf77ca2a68ede21211f39d4d3142afd64bb552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Gil=20Herrera?= Date: Fri, 5 Jun 2015 12:44:50 +0200 Subject: [PATCH 14/19] tests updated --- .../complexity/LizardReportParserTest.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/test/java/org/sonar/plugins/objectivec/complexity/LizardReportParserTest.java b/src/test/java/org/sonar/plugins/objectivec/complexity/LizardReportParserTest.java index 0fe88dca..d58d788b 100644 --- a/src/test/java/org/sonar/plugins/objectivec/complexity/LizardReportParserTest.java +++ b/src/test/java/org/sonar/plugins/objectivec/complexity/LizardReportParserTest.java @@ -63,9 +63,9 @@ public File createCorrectFile() throws IOException { //root object and measure out.write(""); //items for function - out.write(""); + out.write(""); out.write("2151"); - out.write(""); + out.write(""); out.write("3205"); //average and close funciton measure out.write(""); @@ -74,9 +74,9 @@ public File createCorrectFile() throws IOException { //open file measure and add the labels out.write(""); //items for file - out.write(""); + out.write(""); out.write("1200"); - out.write(""); + out.write(""); out.write("286862"); //add averages out.write(""); @@ -99,9 +99,9 @@ public File createIncorrectFile() throws IOException { //root object and measure out.write(""); //items for function - out.write(""); + out.write(""); out.write("2151"); - out.write(""); + out.write(""); out.write("3205"); //average and close funciton measure out.write(""); @@ -110,9 +110,9 @@ public File createIncorrectFile() throws IOException { //open file measure and add the labels out.write(""); //items for file 3th value tag has no closing tag - out.write(""); + out.write(""); out.write("1200"); - out.write(""); + out.write(""); out.write("286862"); //add averages out.write(""); @@ -136,8 +136,8 @@ public void parseReportShouldReturnMapWhenXMLFileIsCorrect() { assertNotNull("report is null", report); - assertTrue("Key is not there", report.containsKey("VW_R_App/Controller/Accelerate/VWRAccelerationViewController.h")); - List list1 = report.get("VW_R_App/Controller/Accelerate/VWRAccelerationViewController.h"); + assertTrue("Key is not there", report.containsKey("App/Controller/Accelerate/AccelerationViewController.h")); + List list1 = report.get("App/Controller/Accelerate/AccelerationViewController.h"); assertEquals(4, list1.size()); for (Measure measure : list1) { @@ -156,9 +156,9 @@ public void parseReportShouldReturnMapWhenXMLFileIsCorrect() { } } - assertTrue("Key is not there", report.containsKey("VW_R_App/Controller/Accelerate/VWRAccelerationViewController.m")); + assertTrue("Key is not there", report.containsKey("App/Controller/Accelerate/AccelerationViewController.m")); - List list2 = report.get("VW_R_App/Controller/Accelerate/VWRAccelerationViewController.m"); + List list2 = report.get("App/Controller/Accelerate/AccelerationViewController.m"); assertEquals(7, list2.size()); for (Measure measure : list2) { String s = measure.getMetric().getKey(); From 0f31327f94c1fe33e04e98d1ad5f1bca75865d9c Mon Sep 17 00:00:00 2001 From: Andres Gil Herrera Date: Sun, 14 Jun 2015 08:22:21 +0200 Subject: [PATCH 15/19] comments --- .../complexity/LizardMeasurePersistor.java | 12 +++++ .../complexity/LizardReportParser.java | 48 +++++++++++++++++++ .../objectivec/complexity/LizardSensor.java | 24 +++++++++- .../complexity/LizardReportParserTest.java | 16 +++++++ .../complexity/LizardSensorTest.java | 6 +++ 5 files changed, 105 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java index 5e049ff1..709e5e8d 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java @@ -29,6 +29,8 @@ import java.util.Map; /** + * This class is used to save the measures created by the lizardReportParser in the sonar database + * * @author Andres Gil Herrera * @since 28/05/15. */ @@ -42,6 +44,10 @@ public LizardMeasurePersistor(final Project p, final SensorContext c) { this.sensorContext = c; } + /** + * + * @param measures Map containing as key the name of the file and as value a list containing the measures for that file + */ public void saveMeasures(final Map> measures) { for (Map.Entry> entry : measures.entrySet()) { final org.sonar.api.resources.File objcfile = org.sonar.api.resources.File.fromIOFile(new File(project.getFileSystem().getBasedir(), entry.getKey()), project); @@ -58,6 +64,12 @@ public void saveMeasures(final Map> measures) { } } + /** + * + * @param context context of the sensor + * @param file file to prove for + * @return true if the resource is indexed and false if not + */ private boolean fileExists(final SensorContext context, final org.sonar.api.resources.File file) { return context.getResource(file) != null; diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java index e6a017cc..3752b61d 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java @@ -38,6 +38,10 @@ import java.util.Map; /** + * This class parses xml Reports form the tool Lizard in order to extract this measures: + * COMPLEXITY, FUNCTIONS, FUNCTION_COMPLEXITY, FUNCTION_COMPLEXITY_DISTRIBUTION, + * FILE_COMPLEXITY, FUNCTION_COMPLEXITY_DISTRIBUTION, COMPLEXITY_IN_FUNCTIONS + * * @author Andres Gil Herrera * @since 28/05/15 */ @@ -56,6 +60,11 @@ public class LizardReportParser { private static final int CYCLOMATIC_COMPLEXITY_INDEX = 2; private static final int FUNCTIONS_INDEX = 3; + /** + * + * @param xmlFile lizard xml report + * @return Map containing as key the name of the file and as value a list containing the measures for that file + */ public Map> parseReport(final File xmlFile) { Map> result = null; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); @@ -75,6 +84,11 @@ public Map> parseReport(final File xmlFile) { return result; } + /** + * + * @param document Document object representing the lizard report + * @return Map containing as key the name of the file and as value a list containing the measures for that file + */ private Map> parseFile(Document document) { final Map> reportMeasures = new HashMap>(); final List functions = new ArrayList(); @@ -101,6 +115,12 @@ private Map> parseFile(Document document) { return reportMeasures; } + /** + * This method extracts the values for COMPLEXITY, FUNCTIONS, FILE_COMPLEXITY + * + * @param itemList list of all items from a + * @param reportMeasures map to save the measures for each file + */ private void addComplexityFileMeasures(NodeList itemList, Map> reportMeasures){ for (int i = 0; i < itemList.getLength(); i++) { Node item = itemList.item(i); @@ -118,6 +138,13 @@ private void addComplexityFileMeasures(NodeList itemList, Map buildMeasureList(int complexity, double fileComplexity, int numberOfFunctions){ List list = new ArrayList(); list.add(new Measure(CoreMetrics.COMPLEXITY).setIntValue(complexity)); @@ -129,6 +156,11 @@ private List buildMeasureList(int complexity, double fileComplexity, in return list; } + /** + * + * @param itemList NodeList of all items in a tag + * @param functions list to save the functions in the NodeList as ObjCFunction objects. + */ private void collectFunctions(NodeList itemList, List functions) { for (int i = 0; i < itemList.getLength(); i++) { Node item = itemList.item(i); @@ -141,6 +173,12 @@ private void collectFunctions(NodeList itemList, List functions) { } } + /** + * + * @param reportMeasures map to save the measures for the different files + * @param functions list of ObjCFunction to extract the information needed to create + * FUNCTION_COMPLEXITY_DISTRIBUTION, FUNCTION_COMPLEXITY, COMPLEXITY_IN_FUNCTIONS + */ private void addComplexityFunctionMeasures(Map> reportMeasures, List functions){ for (Map.Entry> entry : reportMeasures.entrySet()) { @@ -171,6 +209,13 @@ private void addComplexityFunctionMeasures(Map> reportMeas } } + /** + * + * @param complexMean average complexity per function in a file + * @param complexityInFunctions Entire complexity in functions + * @param builder Builder ready to build FUNCTION_COMPLEXITY_DISTRIBUTION + * @return list of Measures containing FUNCTION_COMPLEXITY_DISTRIBUTION, FUNCTION_COMPLEXITY and COMPLEXITY_IN_FUNCTIONS + */ public List buildFuncionMeasuresList(double complexMean, int complexityInFunctions, RangeDistributionBuilder builder){ List list = new ArrayList(); list.add(new Measure(CoreMetrics.FUNCTION_COMPLEXITY, complexMean)); @@ -179,6 +224,9 @@ public List buildFuncionMeasuresList(double complexMean, int complexity return list; } + /** + * helper class to process the information the functions contained in a Lizard report + */ private class ObjCFunction { private String name; private int cyclomaticComplexity; diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java index 30f3e512..83dff372 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java @@ -35,6 +35,9 @@ import java.util.Map; /** + * This sensor searches for the report generated from the tool Lizard + * in order to save complexity metrics. + * * @author Andres Gil Herrera * @since 28/05/15 */ @@ -53,11 +56,21 @@ public LizardSensor(final FileSystem moduleFileSystem, final Settings config) { this.fileSystem = moduleFileSystem; } + /** + * + * @param project + * @return true if the project is root the root project and uses Objective-C + */ @Override public boolean shouldExecuteOnProject(Project project) { return project.isRoot() && fileSystem.languages().contains(ObjectiveC.KEY); } + /** + * + * @param project + * @param sensorContext + */ @Override public void analyse(Project project, SensorContext sensorContext) { final String projectBaseDir = project.getFileSystem().getBasedir().getPath(); @@ -65,7 +78,12 @@ public void analyse(Project project, SensorContext sensorContext) { new LizardMeasurePersistor(project, sensorContext).saveMeasures(measures); } - //key = file name + /** + * + * @param baseDir base directory of the project to search the report + * @param parser LizardReportParser to parse the report + * @return Map containing as key the name of the file and as value a list containing the measures for that file + */ private Map> parseReportsIn(final String baseDir, LizardReportParser parser) { final StringBuilder reportFileName = new StringBuilder(baseDir); reportFileName.append("/").append(reportPath()); @@ -73,6 +91,10 @@ private Map> parseReportsIn(final String baseDir, LizardRe return parser.parseReport(new File(reportFileName.toString())); } + /** + * + * @return the default report path or the one specified in the sonar-project.properties + */ private String reportPath() { String reportPath = conf.getString(REPORT_PATH_KEY); if (reportPath == null) { diff --git a/src/test/java/org/sonar/plugins/objectivec/complexity/LizardReportParserTest.java b/src/test/java/org/sonar/plugins/objectivec/complexity/LizardReportParserTest.java index d58d788b..43bc8518 100644 --- a/src/test/java/org/sonar/plugins/objectivec/complexity/LizardReportParserTest.java +++ b/src/test/java/org/sonar/plugins/objectivec/complexity/LizardReportParserTest.java @@ -54,6 +54,11 @@ public void setup() throws IOException { incorrectFile = createIncorrectFile(); } + /** + * + * @return dummy lizard xml report to test the parser + * @throws IOException + */ public File createCorrectFile() throws IOException { File xmlFile = folder.newFile("correctFile.xml"); BufferedWriter out = new BufferedWriter(new FileWriter(xmlFile)); @@ -90,6 +95,11 @@ public File createCorrectFile() throws IOException { return xmlFile; } + /** + * + * @return corrupted dummy lizard report to test the parser + * @throws IOException + */ public File createIncorrectFile() throws IOException { File xmlFile = folder.newFile("incorrectFile.xml"); BufferedWriter out = new BufferedWriter(new FileWriter(xmlFile)); @@ -126,6 +136,9 @@ public File createIncorrectFile() throws IOException { return xmlFile; } + /** + * this test case test that the parser extract all measures right + */ @Test public void parseReportShouldReturnMapWhenXMLFileIsCorrect() { LizardReportParser parser = new LizardReportParser(); @@ -177,6 +190,9 @@ public void parseReportShouldReturnMapWhenXMLFileIsCorrect() { } } + /** + * this method test that the parser shoud not return anything if the xml report is corrupted + */ @Test public void parseReportShouldReturnNullWhenXMLFileIsIncorrect() { LizardReportParser parser = new LizardReportParser(); diff --git a/src/test/java/org/sonar/plugins/objectivec/complexity/LizardSensorTest.java b/src/test/java/org/sonar/plugins/objectivec/complexity/LizardSensorTest.java index 15774fa9..55748d17 100644 --- a/src/test/java/org/sonar/plugins/objectivec/complexity/LizardSensorTest.java +++ b/src/test/java/org/sonar/plugins/objectivec/complexity/LizardSensorTest.java @@ -48,6 +48,9 @@ public void setUp() { settings = new Settings(); } + /** + * this method tests that the sensor should be executed when a project is a root project and uses objective c + */ @Test public void shouldExecuteOnProjectShouldBeTrueWhenProjectIsObjc() { final Project project = new Project("Test"); @@ -62,6 +65,9 @@ public void shouldExecuteOnProjectShouldBeTrueWhenProjectIsObjc() { assertTrue(testedSensor.shouldExecuteOnProject(project)); } + /** + * this method tests that the sensor does not get executed when a project dont uses objective c + */ @Test public void shouldExecuteOnProjectShouldBeFalseWhenProjectIsSomethingElse() { final Project project = new Project("Test"); From 42ba9655e8af7a744c2f1bc6e0b464502d465383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Gil=20Herrera?= Date: Thu, 18 Jun 2015 10:29:49 +0200 Subject: [PATCH 16/19] run lizard just if turned on AND installed --- src/main/shell/run-sonar.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/shell/run-sonar.sh b/src/main/shell/run-sonar.sh index e4e9f68b..cd7f8ee6 100755 --- a/src/main/shell/run-sonar.sh +++ b/src/main/shell/run-sonar.sh @@ -295,12 +295,16 @@ else fi if [ "$lizard" = "on" ]; then + if hash lizard 2>/dev/null; then + # Lizard + echo -n 'Running Lizard...' - # Lizard - echo -n 'Running Lizard...' + # Run Lizard with xml output option and write the output in sonar-reports/lizard-report.xml + lizard --xml "$srcDirs" > sonar-reports/lizard-report.xml + else + echo 'Skipping Lizard (not installed!)' + fi - # Run Lizard with xml output option and write the output in sonar-reports/lizard-report.xml - lizard --xml "$srcDirs" > sonar-reports/lizard-report.xml else echo 'Skipping Lizard (test purposes only!)' fi From 253f26895a4bfc989c735b57beae67a8606b5c54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Gil=20Herrera?= Date: Tue, 30 Jun 2015 09:41:59 +0200 Subject: [PATCH 17/19] small changes that do not break the excecution of the sunar runner if the lizard report is not found, allowing the execution of the plugin without lizard --- .../objectivec/complexity/LizardMeasurePersistor.java | 5 +++++ .../objectivec/complexity/LizardReportParser.java | 9 ++++++--- .../plugins/objectivec/complexity/LizardSensor.java | 1 + 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java index 709e5e8d..eeee8279 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardMeasurePersistor.java @@ -49,6 +49,11 @@ public LizardMeasurePersistor(final Project p, final SensorContext c) { * @param measures Map containing as key the name of the file and as value a list containing the measures for that file */ public void saveMeasures(final Map> measures) { + + if (measures == null) { + return; + } + for (Map.Entry> entry : measures.entrySet()) { final org.sonar.api.resources.File objcfile = org.sonar.api.resources.File.fromIOFile(new File(project.getFileSystem().getBasedir(), entry.getKey()), project); if (fileExists(sensorContext, objcfile)) { diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java index 3752b61d..3a4daf5a 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardReportParser.java @@ -31,6 +31,7 @@ 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.HashMap; @@ -73,11 +74,13 @@ public Map> parseReport(final File xmlFile) { DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse(xmlFile); result = parseFile(document); + } catch (final FileNotFoundException e){ + LoggerFactory.getLogger(getClass()).error("Lizard Report not found {}", xmlFile, e); } catch (final IOException e) { LoggerFactory.getLogger(getClass()).error("Error processing file named {}", xmlFile, e); - } catch (ParserConfigurationException e) { - LoggerFactory.getLogger(getClass()).error("Error processing file named {}", xmlFile, e); - } catch (SAXException e) { + } catch (final ParserConfigurationException e) { + LoggerFactory.getLogger(getClass()).error("Error parsing file named {}", xmlFile, e); + } catch (final SAXException e) { LoggerFactory.getLogger(getClass()).error("Error processing file named {}", xmlFile, e); } diff --git a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java index 83dff372..7e1a03aa 100644 --- a/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java +++ b/src/main/java/org/sonar/plugins/objectivec/complexity/LizardSensor.java @@ -75,6 +75,7 @@ public boolean shouldExecuteOnProject(Project project) { public void analyse(Project project, SensorContext sensorContext) { final String projectBaseDir = project.getFileSystem().getBasedir().getPath(); Map> measures = parseReportsIn(projectBaseDir, new LizardReportParser()); + LoggerFactory.getLogger(getClass()).info("Saving results of complexity analysis"); new LizardMeasurePersistor(project, sensorContext).saveMeasures(measures); } From b832b7be76bbc98e6d5a7119788cfc1acf794390 Mon Sep 17 00:00:00 2001 From: Andres Date: Tue, 30 Jun 2015 13:45:43 +0200 Subject: [PATCH 18/19] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b2dde7f1..5387ac7b 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Find below an example of an iOS SonarQube dashboard: ###Features -- [ ] Complexity +- [x] Complexity - [ ] Design - [x] Documentation - [x] Duplications @@ -45,6 +45,7 @@ In the worst case, the Maven repository with all snapshots and releases is avail - [xctool](https://github.com/facebook/xctool) ([HomeBrew](http://brew.sh) installed and ```brew install xctool```). If you are using Xcode 6, make sure to update xctool (```brew upgrade xctool```) to a version > 0.2.2. - [OCLint](http://docs.oclint.org/en/dev/intro/installation.html) installed. Version 0.8.1 recommended ([HomeBrew](http://brew.sh) installed and ```brew install https://gist.githubusercontent.com/TonyAnhTran/e1522b93853c5a456b74/raw/157549c7a77261e906fb88bc5606afd8bd727a73/oclint.rb```). - [gcovr](http://gcovr.com) installed +- [lizard](https://github.com/terryyin/lizard) installed ###Installation (once for all your Objective-C projects) - Install [the plugin](http://bit.ly/18A7OkE) through the Update Center (of SonarQube) or download it into the $SONARQUBE_HOME/extensions/plugins directory @@ -76,6 +77,7 @@ If you still have *run-sonar.sh* file in each of your project (not recommended), * **Mete Balci** ###History +- v0.4.1 (2015/05): added support for Lizard to implement complexity metrics. - v0.4.0 (2015/01): support for SonarQube >= 4.3 (4.x & 5.x) - v0.3.1 (2013/10): fix release - v0.3 (2013/10): added support for OCUnit tests and test coverage From d9eb2c7631834ae4845f931a5364ea7aaaf491c6 Mon Sep 17 00:00:00 2001 From: Andres Date: Sat, 25 Aug 2018 10:44:08 +0200 Subject: [PATCH 19/19] Update README.md --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 5387ac7b..821c0257 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Find below an example of an iOS SonarQube dashboard: Example iOS SonarQube dashboard

-###Features +### Features - [x] Complexity - [ ] Design @@ -24,12 +24,12 @@ Find below an example of an iOS SonarQube dashboard: For more details, see the list of [SonarQube metrics](https://github.com/octo-technology/sonar-objective-c/wiki/Features) implemented or pending. -###Compatibility +### Compatibility - Use 0.3.x releases for SonarQube < 4.3 - Use 0.4.x releases for SonarQube >= 4.3 (4.x and 5.x) -###Download +### Download The latest version is the 0.4.0 and it's available [here](http://bit.ly/18A7OkE). The latest SonarQube 3.x release is the 0.3.1, and it's available [here](http://bit.ly/1fSwd5I). @@ -38,7 +38,7 @@ You can also download the latest build of the plugin from [Cloudbees](https://rf In the worst case, the Maven repository with all snapshots and releases is available here: http://repository-rfelden.forge.cloudbees.com/ -###Prerequisites +### Prerequisites - a Mac with Xcode... - [SonarQube](http://docs.codehaus.org/display/SONAR/Setup+and+Upgrade) and [SonarQube Runner](http://docs.codehaus.org/display/SONAR/Installing+and+Configuring+SonarQube+Runner) installed ([HomeBrew](http://brew.sh) installed and ```brew install sonar-runner```) @@ -47,28 +47,28 @@ In the worst case, the Maven repository with all snapshots and releases is avail - [gcovr](http://gcovr.com) installed - [lizard](https://github.com/terryyin/lizard) installed -###Installation (once for all your Objective-C projects) +### Installation (once for all your Objective-C projects) - Install [the plugin](http://bit.ly/18A7OkE) through the Update Center (of SonarQube) or download it into the $SONARQUBE_HOME/extensions/plugins directory - Copy [run-sonar.sh](https://rawgithub.com/octo-technology/sonar-objective-c/master/src/main/shell/run-sonar.sh) somewhere in your PATH - Restart the SonarQube server. -###Configuration (once per project) +### Configuration (once per project) - Copy [sonar-project.properties](https://rawgithub.com/octo-technology/sonar-objective-c/master/sample/sonar-project.properties) in your Xcode project root folder (along your .xcodeproj file) - Edit the *sonar-project.properties* file to match your Xcode iOS/MacOS project **The good news is that you don't have to modify your Xcode project to enable SonarQube!**. Ok, there might be one needed modification if you don't have a specific scheme for your test target, but that's all. -###Analysis +### Analysis - Run the script ```run-sonar.sh``` in your Xcode project root folder - Enjoy or file an issue! -###Update (once per plugin update) +### Update (once per plugin update) - Install the [latest plugin](http://bit.ly/18A7OkE) version - Copy [run-sonar.sh](https://rawgithub.com/octo-technology/sonar-objective-c/master/src/main/shell/run-sonar.sh) somewhere in your PATH If you still have *run-sonar.sh* file in each of your project (not recommended), you will need to update all those files. -###Credits +### Credits * **Cyril Picat** * **Gilles Grousset** * **Denis Bregeon** @@ -76,7 +76,7 @@ If you still have *run-sonar.sh* file in each of your project (not recommended), * **Romain Felden** * **Mete Balci** -###History +### History - v0.4.1 (2015/05): added support for Lizard to implement complexity metrics. - v0.4.0 (2015/01): support for SonarQube >= 4.3 (4.x & 5.x) - v0.3.1 (2013/10): fix release @@ -84,7 +84,7 @@ If you still have *run-sonar.sh* file in each of your project (not recommended), - v0.2 (2013/10): added OCLint checks as SonarQube violations - v0.0.1 (2012/09): v0 with basic metrics such as nb lines of code, nb lines of comment, nb of files, duplications -###License +### License SonarQube Plugin for Objective C is released under the GNU LGPL 3 license: http://www.gnu.org/licenses/lgpl.txt