Skip to content

Commit

Permalink
Rewriting AndroidLintParser parser #101
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasbjerre committed Sep 27, 2020
1 parent c41fa9d commit d2e8ca2
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 71 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ Changelog of Violations lib.
## Unreleased
### GitHub [#101](https://github.com/tomasbjerre/violations-lib/issues/101) Replace the regexp xml-parsing with STL xml parser

**Rewriting FindbugsParser parser**


[c41fa9da64086e5](https://github.com/tomasbjerre/violations-lib/commit/c41fa9da64086e5) Tomas Bjerre *2020-09-27 09:32:45*

**Rewriting CPPCheckParser parser**


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,50 +7,72 @@
import static se.bjurr.violations.lib.reports.Parser.ANDROIDLINT;
import static se.bjurr.violations.lib.util.ViolationParserUtils.findIntegerAttribute;
import static se.bjurr.violations.lib.util.ViolationParserUtils.getAttribute;
import static se.bjurr.violations.lib.util.ViolationParserUtils.getChunks;

import java.util.List;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;
import se.bjurr.violations.lib.ViolationsLogger;
import se.bjurr.violations.lib.model.SEVERITY;
import se.bjurr.violations.lib.model.Violation;
import se.bjurr.violations.lib.util.ViolationParserUtils;

public class AndroidLintParser implements ViolationsParser {

@Override
public Set<Violation> parseReportOutput(
final String string, final ViolationsLogger violationsLogger) throws Exception {
final String content, final ViolationsLogger violationsLogger) throws Exception {
final Set<Violation> violations = new TreeSet<>();
final List<String> issues = getChunks(string, "<issue", "</issue>");
for (final String issueChunk : issues) {
/** Only ever going to be one location. */
final String location = getChunks(issueChunk, "<location", "/>").get(0);

final String filename = getAttribute(location, "file");
final Optional<Integer> line = findIntegerAttribute(location, "line");
final Optional<Integer> charAttrib = findIntegerAttribute(location, "column");
final String severity = getAttribute(issueChunk, "severity");

final String id = getAttribute(issueChunk, "id");
final String message = getAttribute(issueChunk, "message");
final String summary = getAttribute(issueChunk, "summary").trim();
final String explanation = getAttribute(issueChunk, "explanation");

final String category = getAttribute(issueChunk, "category");

violations.add( //
violationBuilder()
.setParser(ANDROIDLINT)
.setStartLine(line.orElse(0))
.setColumn(charAttrib.orElse(null))
.setFile(filename)
.setSeverity(this.toSeverity(severity))
.setRule(id)
.setCategory(category)
.setMessage(summary + "\n" + message + "\n" + explanation) //
.build());
try (InputStream input = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8))) {
final XMLStreamReader xmlr = ViolationParserUtils.createXmlReader(input);
String severity = null;
String id = null;
String message = null;
String summary = null;
String explanation = null;
String category = null;
String filename = null;
Optional<Integer> line = null;
Optional<Integer> charAttrib = null;
while (xmlr.hasNext()) {
final int eventType = xmlr.next();
if (eventType == XMLStreamConstants.START_ELEMENT) {
if (xmlr.getLocalName().equalsIgnoreCase("issue")) {
severity = getAttribute(xmlr, "severity");
id = getAttribute(xmlr, "id");
message = getAttribute(xmlr, "message");
summary = getAttribute(xmlr, "summary").trim();
explanation = getAttribute(xmlr, "explanation");
category = getAttribute(xmlr, "category");
}
if (xmlr.getLocalName().equalsIgnoreCase("location")) {
filename = getAttribute(xmlr, "file");
line = findIntegerAttribute(xmlr, "line");
charAttrib = findIntegerAttribute(xmlr, "column");
}
}
if (eventType == XMLStreamConstants.END_ELEMENT) {
if (xmlr.getLocalName().equalsIgnoreCase("issue")) {
final Violation violation =
violationBuilder()
.setParser(ANDROIDLINT)
.setStartLine(line.orElse(0))
.setColumn(charAttrib.orElse(null))
.setFile(filename)
.setSeverity(this.toSeverity(severity))
.setRule(id)
.setCategory(category)
.setMessage(summary + "\n" + message + "\n" + explanation) //
.build();
violations.add(violation);
}
}
}
}
return violations;
}
Expand Down
76 changes: 35 additions & 41 deletions src/test/java/se/bjurr/violations/lib/AndroidLintTest.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package se.bjurr.violations.lib;

import static org.assertj.core.api.Assertions.assertThat;
import static se.bjurr.violations.lib.TestUtils.getRootFolder;
import static se.bjurr.violations.lib.ViolationsApi.violationsApi;
import static se.bjurr.violations.lib.model.SEVERITY.ERROR;
Expand All @@ -11,59 +10,54 @@
import java.util.Set;
import org.junit.Test;
import se.bjurr.violations.lib.model.Violation;
import se.bjurr.violations.lib.util.ViolationAsserter;

/** Created by matthew on 27/04/16. */
public class AndroidLintTest {

@Test
public void testThatViolationsCanBeParsed() {

String rootFolder = getRootFolder();
final String rootFolder = getRootFolder();

Set<Violation> actual =
final Set<Violation> actual =
violationsApi() //
.withPattern(".*/androidlint/.*\\.xml$") //
.inFolder(rootFolder) //
.findAll(ANDROIDLINT) //
.violations();

assertThat(actual) //
.containsOnly( //
violationBuilder() //
.setParser(ANDROIDLINT) //
.setFile("app/src/main/res/layout/fragment_main.xml") //
.setSource(null) //
.setStartLine(10) //
.setEndLine(10) //
.setColumn(9) //
.setRule("ScrollViewSize") //
.setCategory("Correctness") //
.setMessage(
"ScrollView size validation\n"
+ "This LinearLayout should use `android:layout_height=\"wrap_content\"`\n"
+ "ScrollView children must set their `layout_width` or `layout_height` attributes to `wrap_content` rather than `fill_parent` or `match_parent` in the scrolling dimension") //
.setSeverity(WARN) //
.build(), //
violationBuilder() //
.setParser(ANDROIDLINT) //
.setFile(
".gradle/caches/modules-2/files-2.1/com.squareup.okio/okio/1.4.0/5b72bf48563ea8410e650de14aa33ff69a3e8c35/okio-1.4.0.jar") //
.setSource(null) //
.setStartLine(0) //
.setEndLine(0) //
.setColumn(null) //
.setRule("InvalidPackage") //
.setCategory("Correctness") //
.setMessage(
"Package not included in Android\n"
+ "Invalid package reference in library; not included in Android: `java.nio.file`. Referenced from `okio.Okio`.\n"
+ "This check scans through libraries looking for calls to APIs that are not included in Android.\n"
+ " \n"
+ " When you create Android projects, the classpath is set up such that you can only access classes in the API packages that are included in Android. However, if you add other projects to your libs/ folder, there is no guarantee that those .jar files were built with an Android specific classpath, and in particular, they could be accessing unsupported APIs such as java.applet.\n"
+ " \n"
+ " This check scans through library jars and looks for references to API packages that are not included in Android and flags these. This is only an error if your code calls one of the library classes which wind up referencing the unsupported package.") //
.setSeverity(ERROR) //
.build() //
);
final Violation v1 =
violationBuilder()
.setParser(ANDROIDLINT)
.setFile("app/src/main/res/layout/fragment_main.xml")
.setSource(null)
.setStartLine(10)
.setEndLine(10)
.setColumn(9)
.setRule("ScrollViewSize")
.setCategory("Correctness")
.setMessage("ScrollView size validation")
.setSeverity(WARN) //
.build();

final Violation v2 =
violationBuilder()
.setParser(ANDROIDLINT)
.setFile(
".gradle/caches/modules-2/files-2.1/com.squareup.okio/okio/1.4.0/5b72bf48563ea8410e650de14aa33ff69a3e8c35/okio-1.4.0.jar")
.setSource(null)
.setStartLine(0)
.setEndLine(0)
.setColumn(null)
.setRule("InvalidPackage")
.setCategory("Correctness")
.setMessage("Package not included in Android")
.setSeverity(ERROR) //
.build();

ViolationAsserter.assertThat(actual) //
.contains(v1, 1) //
.contains(v2, 0);
}
}

0 comments on commit d2e8ca2

Please sign in to comment.