├── .gitignore ├── .travis.yml ├── README.md ├── pom.xml └── sonar-elixir-plugin ├── pom.xml └── src ├── main └── java │ └── eu │ └── arthepsy │ └── sonar │ └── plugins │ └── elixir │ ├── ElixirConfiguration.java │ ├── ElixirPlugin.java │ ├── language │ ├── Elixir.java │ ├── ElixirMeasureSensor.java │ └── ElixirParser.java │ └── rule │ └── ElixirQualityProfile.java └── test ├── java └── eu │ └── arthepsy │ └── sonar │ └── plugins │ └── elixir │ ├── ElixirConfigurationTest.java │ ├── ElixirPluginTest.java │ ├── language │ ├── ElixirMeasureSensorTest.java │ └── ElixirTest.java │ ├── rule │ └── ElixirQualityProfileTest.java │ └── util │ └── ClassDefinition.java └── resources └── test_doc.ex /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | 3 | # IntelliJ IDEA 4 | *.iws 5 | *.iml 6 | *.ipr 7 | .idea/ 8 | 9 | # Eclipse 10 | .classpath 11 | .project 12 | .settings 13 | 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: java 3 | jdk: 4 | - openjdk7 5 | - oraclejdk7 6 | - oraclejdk8 7 | 8 | after_success: 9 | - mvn clean test jacoco:report coveralls:report 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SonarQube Elixir Plugin 2 | =========== 3 | [![build status](https://travis-ci.org/arthepsy/sonar-elixir.svg?branch=master)](https://travis-ci.org/arthepsy/sonar-elixir/) 4 | [![Coverage Status](https://coveralls.io/repos/arthepsy/sonar-elixir/badge.svg?branch=master)](https://coveralls.io/r/arthepsy/sonar-elixir?branch=master) 5 | 6 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | org.codehaus.sonar-plugins 9 | parent 10 | 19 11 | 12 | 13 | 14 | sonar-elixir-plugin 15 | 16 | 17 | eu.arthepsy.sonar.plugins 18 | elixir 19 | 1.0-SNAPSHOT 20 | pom 21 | 22 | SonarQube Elixir 23 | 24 | 25 | ${dev.name} 26 | 27 | 28 | 29 | MIT 30 | http://opensource.org/licenses/MIT 31 | 32 | 33 | 34 | 35 | ${dev.nick} 36 | ${dev.name} 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | scm:git: 45 | scm:git: 46 | 47 | HEAD 48 | 49 | 50 | 51 | arthepsy 52 | Andris Raugulis 53 | moo@arthepsy.eu 54 | 4.5 55 | {0,date,yyyy-MM-dd HH:mm:ssa} 56 | UTF-8 57 | 58 | 59 | 60 | 61 | 62 | org.codehaus.sonar 63 | sonar-plugin-api 64 | ${sonar.version} 65 | provided 66 | 67 | 68 | org.codehaus.sonar 69 | sonar-core 70 | ${sonar.version} 71 | provided 72 | 73 | 74 | 75 | org.codehaus.sonar 76 | sonar-testing-harness 77 | ${sonar.version} 78 | test 79 | 80 | 81 | org.mockito 82 | mockito-all 83 | 1.10.19 84 | test 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | org.apache.maven.plugins 94 | maven-compiler-plugin 95 | 3.3 96 | 97 | 98 | -Xlint:unchecked 99 | -Xlint:deprecation 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | org.jacoco 108 | jacoco-maven-plugin 109 | 0.7.5.201505241946 110 | 111 | 112 | prepare-agent 113 | 114 | prepare-agent 115 | 116 | 117 | 118 | 119 | 120 | org.eluder.coveralls 121 | coveralls-maven-plugin 122 | 3.1.0 123 | 124 | 125 | 126 | com.mycila.maven-license-plugin 127 | maven-license-plugin 128 | 1.9.0 129 | 130 |
org/sonar/plugins/licenseheaders/MIT.txt
131 | 132 | 2015 133 | ${dev.name} 134 | ${dev.mail} 135 | 136 |
137 |
138 |
139 |
140 | 141 |
142 | -------------------------------------------------------------------------------- /sonar-elixir-plugin/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | eu.arthepsy.sonar.plugins 9 | elixir 10 | 1.0-SNAPSHOT 11 | 12 | 13 | eu.arthepsy.sonar.plugins 14 | sonar-elixir-plugin 15 | 1.0-SNAPSHOT 16 | sonar-plugin 17 | 18 | SonarQube Elixir plugin 19 | Enables analysis of JavaScript projects. 20 | 21 | 22 | eu.arthepsy.sonar.plugins.elixir.ElixirPlugin 23 | 24 | 25 | 26 | 27 | org.codehaus.sonar 28 | sonar-plugin-api 29 | 30 | 31 | org.codehaus.sonar 32 | sonar-core 33 | 34 | 35 | 36 | org.codehaus.sonar 37 | sonar-testing-harness 38 | test 39 | 40 | 41 | org.mockito 42 | mockito-all 43 | 44 | 45 | 46 | 47 | 48 | 49 | org.apache.maven.plugins 50 | maven-compiler-plugin 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /sonar-elixir-plugin/src/main/java/eu/arthepsy/sonar/plugins/elixir/ElixirConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarQube Elixir plugin 3 | * Copyright (C) 2015 Andris Raugulis 4 | * moo@arthepsy.eu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package eu.arthepsy.sonar.plugins.elixir; 25 | 26 | import com.google.common.collect.ImmutableList; 27 | import org.sonar.api.config.PropertyDefinition; 28 | 29 | import java.util.List; 30 | 31 | public final class ElixirConfiguration { 32 | public static final String LOG_PREFIX = "[elixir] "; 33 | 34 | public static List getPropertyDefinitions() { 35 | ImmutableList.Builder properties = ImmutableList.builder(); 36 | return properties.build(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /sonar-elixir-plugin/src/main/java/eu/arthepsy/sonar/plugins/elixir/ElixirPlugin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarQube Elixir plugin 3 | * Copyright (C) 2015 Andris Raugulis 4 | * moo@arthepsy.eu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package eu.arthepsy.sonar.plugins.elixir; 25 | 26 | import com.google.common.collect.ImmutableList; 27 | import eu.arthepsy.sonar.plugins.elixir.language.Elixir; 28 | import eu.arthepsy.sonar.plugins.elixir.language.ElixirMeasureSensor; 29 | import eu.arthepsy.sonar.plugins.elixir.rule.ElixirQualityProfile; 30 | import org.sonar.api.SonarPlugin; 31 | 32 | import java.util.List; 33 | 34 | public class ElixirPlugin extends SonarPlugin { 35 | 36 | @Override 37 | public List getExtensions() { 38 | ImmutableList.Builder builder = ImmutableList.builder(); 39 | builder.addAll(ElixirConfiguration.getPropertyDefinitions()); 40 | builder.add(Elixir.class); 41 | builder.add(ElixirQualityProfile.class); 42 | builder.add(ElixirMeasureSensor.class); 43 | return builder.build(); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /sonar-elixir-plugin/src/main/java/eu/arthepsy/sonar/plugins/elixir/language/Elixir.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarQube Elixir plugin 3 | * Copyright (C) 2015 Andris Raugulis 4 | * moo@arthepsy.eu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package eu.arthepsy.sonar.plugins.elixir.language; 25 | 26 | import org.sonar.api.resources.AbstractLanguage; 27 | 28 | public class Elixir extends AbstractLanguage { 29 | 30 | public static final String KEY = "elixir"; 31 | public static final String NAME = "Elixir"; 32 | public static final String[] FILE_SUFFIXES = {"ex", "exs"}; 33 | 34 | public Elixir() { 35 | super(KEY, NAME); 36 | } 37 | 38 | @Override 39 | public String[] getFileSuffixes() { 40 | return FILE_SUFFIXES; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /sonar-elixir-plugin/src/main/java/eu/arthepsy/sonar/plugins/elixir/language/ElixirMeasureSensor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarQube Elixir plugin 3 | * Copyright (C) 2015 Andris Raugulis 4 | * moo@arthepsy.eu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package eu.arthepsy.sonar.plugins.elixir.language; 25 | 26 | import eu.arthepsy.sonar.plugins.elixir.ElixirConfiguration; 27 | import org.apache.commons.lang.StringUtils; 28 | import org.slf4j.Logger; 29 | import org.slf4j.LoggerFactory; 30 | import org.sonar.api.batch.fs.InputFile; 31 | import org.sonar.api.batch.fs.FilePredicate; 32 | import org.sonar.api.batch.fs.FileSystem; 33 | import org.sonar.api.batch.Sensor; 34 | import org.sonar.api.batch.SensorContext; 35 | import org.sonar.api.measures.CoreMetrics; 36 | import org.sonar.api.resources.Project; 37 | import org.sonar.api.utils.ParsingUtils; 38 | 39 | import java.io.IOException; 40 | import java.nio.file.Files; 41 | import java.nio.file.Paths; 42 | import java.util.List; 43 | import java.util.regex.Matcher; 44 | import java.util.regex.Pattern; 45 | 46 | public class ElixirMeasureSensor implements Sensor { 47 | 48 | private static final Logger LOG = LoggerFactory.getLogger(ElixirMeasureSensor.class); 49 | private static final String LOG_PREFIX = ElixirConfiguration.LOG_PREFIX; 50 | 51 | private final FileSystem fileSystem; 52 | private final FilePredicate mainFilePredicate; 53 | 54 | 55 | public ElixirMeasureSensor(FileSystem fileSystem) { 56 | this.fileSystem = fileSystem; 57 | this.mainFilePredicate = fileSystem.predicates().and( 58 | fileSystem.predicates().hasType(InputFile.Type.MAIN), 59 | fileSystem.predicates().hasLanguage(Elixir.KEY)); 60 | } 61 | 62 | @Override 63 | public void analyse(Project project, SensorContext context) { 64 | LOG.info("[elixir] analyse"); 65 | for (InputFile file : fileSystem.inputFiles(mainFilePredicate )) { 66 | processMainFile(file, context); 67 | } 68 | } 69 | 70 | @Override 71 | public boolean shouldExecuteOnProject(Project project) { 72 | return fileSystem.hasFiles(mainFilePredicate); 73 | } 74 | 75 | private void processMainFile(InputFile inputFile, SensorContext context) { 76 | List lines; 77 | try { 78 | lines = Files.readAllLines(Paths.get(inputFile.absolutePath()), fileSystem.encoding()); 79 | } catch (IOException e) { 80 | LOG.warn(LOG_PREFIX + "could not process file: " + inputFile.toString()); 81 | return; 82 | } 83 | ElixirParser parser = new ElixirParser(); 84 | parser.parse(lines); 85 | 86 | LOG.debug(LOG_PREFIX + "processing file: " + inputFile.toString()); 87 | double linesOfCode = parser.getLineCount() - parser.getEmptyLineCount() - parser.getCommentLineCount(); 88 | context.saveMeasure(inputFile, CoreMetrics.LINES, (double)parser.getLineCount()); 89 | context.saveMeasure(inputFile, CoreMetrics.NCLOC, (double)linesOfCode); 90 | context.saveMeasure(inputFile, CoreMetrics.COMMENT_LINES, (double)parser.getCommentLineCount()); 91 | 92 | double publicApi = parser.getPublicFunctionCount() + parser.getClassCount(); 93 | double documentedApi = parser.getDocumentedPublicFunctionCount() + parser.getDocumentedClassCount(); 94 | double undocumentedApi = publicApi - documentedApi; 95 | double documentedApiDensity = (publicApi == 0 ? 100.0 : ParsingUtils.scaleValue(documentedApi / publicApi * 100, 2)); 96 | context.saveMeasure(inputFile, CoreMetrics.PUBLIC_API, publicApi); 97 | context.saveMeasure(inputFile, CoreMetrics.PUBLIC_UNDOCUMENTED_API, undocumentedApi); 98 | context.saveMeasure(inputFile, CoreMetrics.PUBLIC_DOCUMENTED_API_DENSITY, documentedApiDensity); 99 | 100 | double functionCount = parser.getPublicFunctionCount() + parser.getPrivateFunctionCount(); 101 | context.saveMeasure(inputFile, CoreMetrics.CLASSES, (double)parser.getClassCount()); 102 | context.saveMeasure(inputFile, CoreMetrics.FUNCTIONS, (double)(functionCount)); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /sonar-elixir-plugin/src/main/java/eu/arthepsy/sonar/plugins/elixir/language/ElixirParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarQube Elixir plugin 3 | * Copyright (C) 2015 Andris Raugulis 4 | * moo@arthepsy.eu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package eu.arthepsy.sonar.plugins.elixir.language; 25 | 26 | import org.apache.commons.lang.StringUtils; 27 | 28 | import java.util.List; 29 | import java.util.regex.Matcher; 30 | import java.util.regex.Pattern; 31 | 32 | public class ElixirParser { 33 | private int lineCount = 0; 34 | private int emptyLineCount = 0; 35 | private int commentLineCount = 0; 36 | private int classCount = 0; 37 | private int publicFunctionCount = 0; 38 | private int privateFunctionCount = 0; 39 | private int documentedClassCount = 0; 40 | private int documentedPrivateFunctionCount = 0; 41 | private int documentedPublicFunctionCount = 0; 42 | 43 | private final Pattern defPattern = Pattern.compile("^\\s*def(|p|module|struct)\\s(.*)$"); 44 | private final Matcher defMatcher = defPattern.matcher(""); 45 | private final Pattern heredocPattern = Pattern.compile("^.*\"\"\"\\s*$"); 46 | private final Matcher heredocMatcher = heredocPattern.matcher(""); 47 | private final Pattern docPattern = Pattern.compile("^\\s*@(doc|moduledoc|typedoc)([\"\\s].*)$"); 48 | private final Matcher docMatcher = docPattern.matcher(""); 49 | 50 | private boolean hasDoc = false; 51 | private boolean inClass = false; 52 | 53 | public ElixirParser() { } 54 | 55 | public int getLineCount() { return lineCount; } 56 | public int getEmptyLineCount() { return emptyLineCount; } 57 | public int getCommentLineCount() { return commentLineCount; } 58 | public int getClassCount() { return classCount; } 59 | public int getPublicFunctionCount() { return publicFunctionCount; } 60 | public int getPrivateFunctionCount() { return privateFunctionCount; } 61 | public int getDocumentedClassCount() { return documentedClassCount; } 62 | public int getDocumentedPublicFunctionCount() { return documentedPublicFunctionCount; } 63 | public int getDocumentedPrivateFunctionCount() { return documentedPrivateFunctionCount; } 64 | 65 | public void parse(List lines) { 66 | this.parseLines(lines); 67 | } 68 | 69 | private void parseLines(List lines) { 70 | hasDoc = false; 71 | inClass = false; 72 | 73 | lineCount = lines.size(); 74 | for (int i = 0; i < lineCount; i++) { 75 | String line = lines.get(i); 76 | if (StringUtils.isBlank(line)) { 77 | emptyLineCount++; 78 | } 79 | docMatcher.reset(line); 80 | boolean inDoc = docMatcher.find(); 81 | if (inDoc) { 82 | commentLineCount++; 83 | String docHead = docMatcher.group(2).trim(); 84 | if (! (StringUtils.equalsIgnoreCase(docHead, "false") || StringUtils.equalsIgnoreCase(docHead, "nil"))) { 85 | switch (docMatcher.group(1)) { 86 | case "doc": 87 | hasDoc = true; 88 | break; 89 | case "moduledoc": 90 | if (inClass) { 91 | documentedClassCount++; 92 | } 93 | break; 94 | case "typedoc": 95 | break; 96 | } 97 | } 98 | } 99 | heredocMatcher.reset(line); 100 | if (heredocMatcher.find()) { 101 | while (i < lineCount - 1) { 102 | if (inDoc) { 103 | commentLineCount++; 104 | } 105 | i++; 106 | line = lines.get(i); 107 | if (line.matches("^\\s*\"\"\"\\s*$")) { 108 | break; 109 | } 110 | } 111 | continue; 112 | } 113 | 114 | defMatcher.reset(line); 115 | if (defMatcher.find()) { 116 | switch (defMatcher.group(1)) { 117 | case "module": 118 | classCount++; 119 | inClass = true; 120 | break; 121 | case "": 122 | publicFunctionCount++; 123 | if (hasDoc) { 124 | documentedPublicFunctionCount++; 125 | } 126 | break; 127 | case "p": 128 | privateFunctionCount++; 129 | if (hasDoc) { 130 | documentedPrivateFunctionCount++; 131 | } 132 | break; 133 | } 134 | hasDoc = false; 135 | } 136 | if (line.matches("^\\s*#.*$")) { 137 | commentLineCount++; 138 | } 139 | } 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /sonar-elixir-plugin/src/main/java/eu/arthepsy/sonar/plugins/elixir/rule/ElixirQualityProfile.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarQube Elixir plugin 3 | * Copyright (C) 2015 Andris Raugulis 4 | * moo@arthepsy.eu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package eu.arthepsy.sonar.plugins.elixir.rule; 25 | 26 | import eu.arthepsy.sonar.plugins.elixir.language.Elixir; 27 | import org.sonar.api.profiles.ProfileDefinition; 28 | import org.sonar.api.profiles.RulesProfile; 29 | import org.sonar.api.utils.ValidationMessages; 30 | 31 | public class ElixirQualityProfile extends ProfileDefinition { 32 | private static final String DEFAULT_PROFILE = "Sonar way"; 33 | 34 | @Override 35 | public RulesProfile createProfile(ValidationMessages validationMessages) { 36 | final RulesProfile profile = RulesProfile.create(DEFAULT_PROFILE, Elixir.KEY); 37 | //parser.parse(profile); 38 | //parser.log(LoggerFactory.getLogger(ScapegoatQualityProfile.class), ScapegoatConfiguration.LOG_PREFIX); 39 | return profile; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /sonar-elixir-plugin/src/test/java/eu/arthepsy/sonar/plugins/elixir/ElixirConfigurationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarQube Elixir plugin 3 | * Copyright (C) 2015 Andris Raugulis 4 | * moo@arthepsy.eu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package eu.arthepsy.sonar.plugins.elixir; 25 | 26 | import eu.arthepsy.sonar.plugins.elixir.util.ClassDefinition; 27 | 28 | import org.junit.Test; 29 | 30 | import static org.fest.assertions.Assertions.assertThat; 31 | 32 | public class ElixirConfigurationTest { 33 | @Test 34 | public void testClassDefinition() { 35 | ClassDefinition.testFinalClassDefinition(ElixirConfiguration.class); 36 | } 37 | 38 | @Test 39 | public void testPropertyCount() { 40 | assertThat(ElixirConfiguration.getPropertyDefinitions().size()).isEqualTo(0); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /sonar-elixir-plugin/src/test/java/eu/arthepsy/sonar/plugins/elixir/ElixirPluginTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarQube Elixir plugin 3 | * Copyright (C) 2015 Andris Raugulis 4 | * moo@arthepsy.eu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package eu.arthepsy.sonar.plugins.elixir; 25 | 26 | import org.junit.Test; 27 | 28 | import static org.fest.assertions.Assertions.assertThat; 29 | 30 | public class ElixirPluginTest { 31 | @Test 32 | public void testExtensionCount() { 33 | assertThat(new ElixirPlugin().getExtensions().size()).isEqualTo(3); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /sonar-elixir-plugin/src/test/java/eu/arthepsy/sonar/plugins/elixir/language/ElixirMeasureSensorTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarQube Elixir plugin 3 | * Copyright (C) 2015 Andris Raugulis 4 | * moo@arthepsy.eu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package eu.arthepsy.sonar.plugins.elixir.language; 25 | 26 | import org.apache.commons.io.FileUtils; 27 | import org.apache.commons.io.IOUtils; 28 | import org.junit.Before; 29 | import org.junit.Rule; 30 | import org.junit.Test; 31 | import org.junit.rules.TemporaryFolder; 32 | import org.sonar.api.batch.fs.InputFile; 33 | import org.sonar.api.batch.fs.internal.DefaultFileSystem; 34 | import org.sonar.api.batch.fs.internal.DefaultInputFile; 35 | import org.sonar.api.batch.SensorContext; 36 | import org.sonar.api.component.ResourcePerspectives; 37 | import org.sonar.api.measures.CoreMetrics; 38 | import org.sonar.api.resources.Project; 39 | 40 | import java.io.File; 41 | import java.io.IOException; 42 | 43 | import static org.fest.assertions.Assertions.assertThat; 44 | import static org.mockito.Mockito.*; 45 | 46 | public class ElixirMeasureSensorTest { 47 | 48 | private final Project project = new Project("project"); 49 | private SensorContext context = mock(SensorContext.class); 50 | private DefaultFileSystem fileSystem; 51 | private ElixirMeasureSensor sensor; 52 | 53 | @Rule 54 | public TemporaryFolder temp = new TemporaryFolder(); 55 | private File baseDir; 56 | 57 | @Before 58 | public void prepare() throws IOException { 59 | baseDir = temp.newFolder(); 60 | fileSystem = new DefaultFileSystem(); 61 | fileSystem.setBaseDir(baseDir); 62 | sensor = new ElixirMeasureSensor(fileSystem); 63 | } 64 | 65 | @Test 66 | public void testDocAnnotation() throws IOException { 67 | String fileName = "test_doc.ex"; 68 | File source = new File(baseDir, fileName); 69 | FileUtils.write(source, IOUtils.toString(getClass().getResourceAsStream("/" + fileName))); 70 | DefaultInputFile inputFile = new DefaultInputFile(fileName).setLanguage(Elixir.KEY); 71 | inputFile.setAbsolutePath(new File(baseDir, inputFile.relativePath()).getAbsolutePath()); 72 | fileSystem.add(inputFile); 73 | 74 | assertThat(sensor.shouldExecuteOnProject(project)).isTrue(); 75 | 76 | sensor.analyse(project, context); 77 | 78 | verify(context).saveMeasure(any(InputFile.class), eq(CoreMetrics.LINES), eq(37.0)); 79 | verify(context).saveMeasure(any(InputFile.class), eq(CoreMetrics.NCLOC), eq(15.0)); 80 | verify(context).saveMeasure(any(InputFile.class), eq(CoreMetrics.COMMENT_LINES), eq(14.0)); 81 | verify(context).saveMeasure(any(InputFile.class), eq(CoreMetrics.CLASSES), eq(1.0)); 82 | verify(context).saveMeasure(any(InputFile.class), eq(CoreMetrics.FUNCTIONS), eq(6.0)); 83 | verify(context).saveMeasure(any(InputFile.class), eq(CoreMetrics.PUBLIC_API), eq(5.0)); 84 | verify(context).saveMeasure(any(InputFile.class), eq(CoreMetrics.PUBLIC_UNDOCUMENTED_API), eq(2.0)); 85 | } 86 | } -------------------------------------------------------------------------------- /sonar-elixir-plugin/src/test/java/eu/arthepsy/sonar/plugins/elixir/language/ElixirTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarQube Elixir plugin 3 | * Copyright (C) 2015 Andris Raugulis 4 | * moo@arthepsy.eu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package eu.arthepsy.sonar.plugins.elixir.language; 25 | 26 | import org.junit.Test; 27 | 28 | import static org.fest.assertions.Assertions.assertThat; 29 | 30 | public class ElixirTest { 31 | @Test 32 | public void test() { 33 | Elixir language = new Elixir(); 34 | assertThat(language.getKey()).isEqualTo("elixir"); 35 | assertThat(language.getName()).isEqualTo("Elixir"); 36 | assertThat(language.getFileSuffixes()).containsOnly("ex", "exs"); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /sonar-elixir-plugin/src/test/java/eu/arthepsy/sonar/plugins/elixir/rule/ElixirQualityProfileTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarQube Elixir plugin 3 | * Copyright (C) 2015 Andris Raugulis 4 | * moo@arthepsy.eu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package eu.arthepsy.sonar.plugins.elixir.rule; 25 | 26 | import org.junit.Before; 27 | import org.junit.Test; 28 | import org.mockito.Mockito; 29 | import org.sonar.api.profiles.RulesProfile; 30 | import org.sonar.api.utils.ValidationMessages; 31 | 32 | import static org.fest.assertions.Assertions.assertThat; 33 | 34 | public class ElixirQualityProfileTest { 35 | private ElixirQualityProfile profile; 36 | private ValidationMessages validationMessages; 37 | 38 | @Before 39 | public void prepare() { 40 | profile = Mockito.spy(new ElixirQualityProfile()); 41 | validationMessages = ValidationMessages.create(); 42 | } 43 | 44 | @Test 45 | public void testRulesCount() { 46 | RulesProfile rulesProfile = profile.createProfile(validationMessages); 47 | assertThat(rulesProfile.getActiveRules().size()).isEqualTo(0); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /sonar-elixir-plugin/src/test/java/eu/arthepsy/sonar/plugins/elixir/util/ClassDefinition.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SonarQube Elixir plugin 3 | * Copyright (C) 2015 Andris Raugulis 4 | * moo@arthepsy.eu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package eu.arthepsy.sonar.plugins.elixir.util; 25 | 26 | import static org.junit.Assert.fail; 27 | 28 | import java.lang.reflect.Constructor; 29 | import java.lang.reflect.InvocationTargetException; 30 | import java.lang.reflect.Method; 31 | import java.lang.reflect.Modifier; 32 | 33 | import static org.fest.assertions.Assertions.assertThat; 34 | 35 | public final class ClassDefinition { 36 | 37 | public static void testFinalClassDefinition(Class clazz) { 38 | testFinalClassDefinition(clazz, false); 39 | } 40 | 41 | public static void testFinalClassDefinition(Class clazz, Boolean privateConstructor) { 42 | assertThat(Modifier.isFinal(clazz.getModifiers())).isTrue(); 43 | final Constructor constructor; 44 | try { 45 | constructor = clazz.getDeclaredConstructor(); 46 | } catch (NoSuchMethodException e) { 47 | fail(e.getMessage()); 48 | return; 49 | } 50 | if (privateConstructor) { 51 | assertThat(Modifier.isPrivate(constructor.getModifiers())).isTrue(); 52 | } 53 | constructor.setAccessible(true); 54 | try { 55 | constructor.newInstance(); 56 | } catch (InstantiationException e) { 57 | fail(e.getMessage()); 58 | return; 59 | } catch (IllegalAccessException e) { 60 | fail(e.getMessage()); 61 | return; 62 | } catch (InvocationTargetException e) { 63 | fail(e.getMessage()); 64 | return; 65 | } 66 | constructor.setAccessible(false); 67 | for (final Method method: clazz.getMethods()) { 68 | if (method.getDeclaringClass().equals(clazz)) { 69 | assertThat(Modifier.isStatic(method.getModifiers())).isTrue(); 70 | } 71 | } 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /sonar-elixir-plugin/src/test/resources/test_doc.ex: -------------------------------------------------------------------------------- 1 | defmodule Docs do 2 | @moduledoc "This is docs module" 3 | 4 | @doc """ 5 | function doc1 6 | 7 | documentation 8 | """ 9 | def doc1() do 10 | end 11 | 12 | @doc false 13 | def doc2() do 14 | end 15 | 16 | @doc "doc3 function" 17 | def doc3() do 18 | end 19 | 20 | @doc "private function doc4" 21 | defp doc4() do 22 | end 23 | 24 | @doc nil 25 | def doc5() do 26 | end 27 | 28 | # very 29 | # very 30 | # private function doc6 31 | defp doc6() do 32 | end 33 | 34 | @typedoc "type doc example" 35 | @type doc7 :: any 36 | 37 | end 38 | --------------------------------------------------------------------------------