Notice how the text code here is highlighted as XML so you can instantly see if there's a problem.
Notice also the line above the xml() call -- there's a "manifest()" method. That one not only lets you pass in a specific manifest file; there are also DSL methods to quickly configure default manifest files with various attributes, such as one with a given minSdkVersion as shown here.
There's also a DSL for constructing Java files -- and you normally don't have to type in the path to where the Java source file should be, since it's implied by the package statement and the class name:
So, the basic approach is to just inline your source files right into the test. It keeps all the data together, which makes it easier to see what's going on in your test anyway.
Second, note that in version 2.3 (of Studio, Gradle, etc) there is a brand new lint test DSL. This has a number of advantages:
(1) You don't have to extend AbstractCheckTest -- so you can now write your tests as JUnit4 instead of JUnit3.
(2) There is a new DSL which lets you configure a lot of stuff for each test -- so you no longer need to override method for the whole test case (which then affected all the tests).
For example, you can configure, for each test, which specific issues to check (if your detector detects more than one issue), you can decide whether you'll allow compilation errors,
you can override the SDK home location, etc, etc.
(3) There's a fluent API so it's easier to write the test. Basically you create a lint test context, then on that one configure your project's files (and it's much easier to create multi-project tests too), you configure the tests, and then you run the tests, and then you get to assert things about the test result.
(4) There's also support for mocking the Gradle model now, so it's much easier to write tests for detectors which are operating on builder model objects.
Here are some sample tests from the 2.3 unit tests:
public void testNoGroupWarningWithPlugin15() throws Exception {
lint().files(
manifest().minSdk(14),
xml("res/drawable/foo.xml", ""
+ "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " android:height=\"76dp\"\n"
+ " android:width=\"76dp\"\n"
+ " android:viewportHeight=\"48\"\n"
+ " android:viewportWidth=\"48\">\n"
+ "\n"
+ " <group />"
+ "\n"
+ "</vector>"
+ ""),
gradle(""
+ "buildscript {\n"
+ " dependencies {\n"
+ " classpath 'com.android.tools.build:gradle:1.5.0-alpha1'\n"
+ " }\n"
+ "}\n"))
.run()
.expectClean();
}
...
public void testPlayServiceConsistencyNonIncremental() throws Exception {
String expected = ""
+ "build.gradle: Error: All com.google.android.gms libraries must use the exact same version specification (mixing versions can lead to runtime crashes). Found versions 7.5.0, 7.3.0. Examples include com.google.android.gms:play-services-wearable:7.5.0 and com.google.android.gms:play-services-location:7.3.0 [GradleCompatible]\n"
+ "1 errors, 0 warnings\n";
lint().files(
gradle(""
+ "apply plugin: 'android'\n"
+ "\n"
+ "dependencies {\n"
+ " compile 'com.google.android.gms:play-services-wearable:7.5.0'\n"
+ " compile 'com.google.android.gms:play-services-location:7.3.0'\n"
+ "}\n"))
.issues(COMPATIBILITY)
.sdkHome(getMockSupportLibraryInstallation())
.run()
.expect(expected);
}
Let me know if you have any questions.
Thanks a lot Tor, this is really helpful!!!
One additional question I have is how to pass in a class file for the ClassScanner in the same fashion? Will those inline java files get compiled into class files when we run the tests?
dependencies {
compile 'com.android.tools.lint:lint-api:24.3.1'
compile 'com.android.tools.lint:lint-checks:24.3.1'
testCompile 'junit:junit:4.11'
testCompile 'com.android.tools.lint:lint:24.3.1'
testCompile 'com.android.tools.lint:lint-tests:24.3.1'
testCompile 'com.android.tools:testutils:24.3.1'
}
jar {
manifest {
attributes("Lint-Registry": "com.pinterest.lint.PinterestIssueRegistry")
}
}--
You received this message because you are subscribed to the Google Groups "lint-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lint-dev+u...@googlegroups.com.
To post to this group, send email to lint...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lint-dev/1baf13a1-e613-49bd-8275-12412865aa00%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
public class XmlDetectorTest extends LintDetectorTest {
@Override
protected Detector getDetector() {
return new BrioXmlDetector();
}
@Override
protected List<Issue> getIssues() {
List<Issue> issuesList = new ArrayList<Issue>();
issuesList.add(BrioXmlDetector.ISSUE_SYNTAX);
issuesList.add(BrioXmlDetector.ISSUE_UNIQUE);
issuesList.add(BrioXmlDetector.ISSUE_STR_REF);
return issuesList;
}
public void testTest() throws Exception {
String msg = lintProject(manifest().minSdk(10), xml("res/layout/sample.xml", ""
+ "<TextView xmlns:android=\"http://schemas.android.com/apk/res/android\">\n"
+ " brio:layout_width=\"hello\"\n"
+ " brio:layout_marginTop=\"4bt\">\n"
+ "</TextView>\n")
);
System.out.print("test msg : " + msg);
}
}
ok, It worked and my detector has been picked up and I see expected error messages eventually!!! it was due to an extra ">" in my xml file
which returned early in my detector logic and somehow I also put the break point in a wrong place.
I am all set for xml detector now, trying java and class detectors .... Thanks a lot, Tor!!!
ok, It worked and my detector has been picked up and I see expected error messages eventually!!! it was due to an extra ">" in my xml file
which returned early in my detector logic and somehow I also put the break point in a wrong place.
I am all set for xml detector now, trying java and class detectors .... Thanks a lot, Tor!!!
--
You received this message because you are subscribed to the Google Groups "lint-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lint-dev+u...@googlegroups.com.
To post to this group, send email to lint...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lint-dev/44f9c916-2675-4524-9ddb-7270a91b1198%40googlegroups.com.
public void testXml() throws Exception {
lintProject(manifest().minSdk(10),
xml("res/layout/sample.xml", ""
+ "<TextView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " brio:layout_width=\"hello\"\n"
+ " brio:layout_marginTop=\"4bt\">\n"
+ "</TextView>\n"));
}
public class TestJavaDetector extends Detector implements Detector.JavaPsiScanner {
private static final String IS_ADDED_METHOD = "isAdded";
public static final Issue ISSUE_IS_ADDED = Issue.create(
"UnsupportedMethodInFragment",
"Fragment contains unsupported method calls",
"Fragment should not call isAdded()",
Category.CORRECTNESS, 6, Severity.ERROR,
new Implementation(TestJavaDetector.class, Scope.JAVA_FILE_SCOPE));
public TestJavaDetector() {
}
// ---- Implements JavaPsiScanner ----
@Override
public List<String> getApplicableMethodNames() {
return Arrays.asList(IS_ADDED_METHOD);
}
@Override
public void visitMethod(
@NonNull JavaContext context,
@Nullable JavaElementVisitor visitor,
@NonNull PsiMethodCallExpression call,
@NonNull PsiMethod method) {
context.report(ISSUE_IS_ADDED, method, context.getLocation(method), "report error");
}
}
public void testJava() throws Exception {
String msg = lintProject(manifest().minSdk(10),
java("src/test/java/test/pkg/RequestParams.java", ""
+ "package test.pkg;\n"
+ "public interface RequestParams {}\n"),
java("src/test/java/test/pkg/SampleRequestParams.java", ""
+ "package test.pkg;\n"
+ "\n"
+ "public class SampleRequestParams implements RequestParams {\n"
+ " public SampleRequestParams() {\n"
+ " isAdded();"
+ " }\n"
+ "\n"
+ " public int hashCode() {\n"
+ " return 1;\n"
+ " }\n"
+ "\n"+ " public void isAdded() {}\n"
+ "}\n"));
System.out.print("test msg : " + msg);
}
test msg : src/test/java/test/pkg/SampleRequestParams.java:10: Error: report error [UnsupportedMethodInFragment]public void isAdded() {}~~~~~~~~~~~~~~~~~~~~~~~~1 errors, 0 warningsProcess finished with exit code 0
--
You received this message because you are subscribed to the Google Groups "lint-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lint-dev+u...@googlegroups.com.
To post to this group, send email to lint...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lint-dev/98bb6315-9586-494e-a8ee-9d8fe85adeec%40googlegroups.com.
public class SimpleClassDetector extends Detector implements Detector.ClassScanner {
public static final Issue ISSUE_SIMPLE_CLASS_CHECK = Issue.create(
"SimpleIssueClassCheck",
"A sample issue for class check",
"This class has errors",
Category.CORRECTNESS,
6,
Severity.ERROR,
new Implementation(SimpleClassDetector.class, Scope.CLASS_FILE_SCOPE));
@Override
public void checkClass(@NonNull ClassContext context, @NonNull ClassNode classNode) {
context.report(ISSUE_SIMPLE_CLASS_CHECK, context.getLocation(classNode), "report error");
}
}
public void testClass() throws Exception {
final String msg = lintProject(manifest().minSdk(10),
base64("classes/RequestParams.class",
"yv66vgAAADQABwcABQcABgEAClNvdXJjZUZpbGUBABJSZXF1ZXN0UGFyYW1z"
+ "LmphdmEBAA1SZXF1ZXN0UGFyYW1zAQAQamF2YS9sYW5nL09iamVjdAYBAAEA"
+ "AgAAAAAAAAABAAMAAAACAAQ="),
base64("classes/SampleRequestParams.class",
"yv66vgAAADQAEQoAAwANBwAOBwAPBwAQAQAGPGluaXQ+AQADKClWAQAEQ29k"
+ "ZQEAD0xpbmVOdW1iZXJUYWJsZQEACGhhc2hDb2RlAQADKClJAQAKU291cmNl"
+ "RmlsZQEAGFNhbXBsZVJlcXVlc3RQYXJhbXMuamF2YQwABQAGAQATU2FtcGxl"
+ "UmVxdWVzdFBhcmFtcwEAEGphdmEvbGFuZy9PYmplY3QBAA1SZXF1ZXN0UGFy"
+ "YW1zACEAAgADAAEABAAAAAIAAQAFAAYAAQAHAAAAHQABAAEAAAAFKrcAAbEA"
+ "AAABAAgAAAAGAAEAAAABAAEACQAKAAEABwAAABoAAQABAAAAAgSsAAAAAQAI"
+ "AAAABgABAAAAAwABAAsAAAACAAw="));

To view this discussion on the web visit https://groups.google.com/d/msgid/lint-dev/e4c74a31-686e-41b3-8433-dff57f5afa2a%40googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lint-dev/ae090189-188e-4f67-a5a0-00730dbe7ed6%40googlegroups.com.
Finally had it work and thanks for all the suggestions. Btw, are the builtin checks open source? It would be great to study some as examples.
Thanks,
Lin
To unsubscribe from this group and stop receiving emails from it, send an email to lint-dev+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lint-dev/ae090189-188e-4f67-a5a0-00730dbe7ed6%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "lint-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lint-dev+u...@googlegroups.com.
To post to this group, send email to lint...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lint-dev/CAB5eP36y1EwRY%2B1bswd2eMLRD9rj%2BR-VBc5434ojbvGu5XxSHw%40mail.gmail.com.
public void testJavaClass() throws Exception {
String errorMsg = lintProjectWithDefaultManifest(
java(""
+ "package test.pkg;\n"
+ "public interface RequestParams {}\n"),
java(""
+ "package test.pkg;\n"
+ "\n"
+ "public class SampleRequestParams implements RequestParams {\n"
+ " public SampleRequestParams() {\n"
+ " }\n"
+ "\n"
+ " public int hashCode() {\n"
+ " return 1;\n"
+ " }\n"
+ "}\n"));
Assert.assertEquals(errorMsg, ""
+ "src/test/pkg/SampleRequestParams.java:3: Error: sample error "
+ "[IssueDummyClassCheck]\n"
+ "public class SampleRequestParams implements RequestParams {\n"
+ "^\n"
+ "1 errors, 0 warnings\n");
}
public class DummyJavaClassDetector extends Detector implements Detector.JavaPsiScanner {
public static final Issue ISSUE_DUMMY_CLASS_CHECK = Issue.create(
"IssueDummyClassCheck",
"A sample issue for class check",
"This class has errors",
Category.CORRECTNESS,
6,
Severity.ERROR,
new Implementation(DummyJavaClassDetector.class, Scope.JAVA_FILE_SCOPE));
/**
* Provide the classes this detector cares about by listing its super classes or implemented
* interfaces.
*/
@Override
public List<String> applicableSuperClasses() {
return Arrays.asList("java.lang.Object", "test.pkg.SampleRequestParams");
}
/**
* Investigate a class node with the given {@code context}
*/
public void checkClass(@NonNull JavaContext context, @NonNull PsiClass declaration) {
context.report(ISSUE_DUMMY_CLASS_CHECK, context.getLocation(declaration), "sample error");
}
}
To unsubscribe from this group and stop receiving emails from it, send an email to lint-dev+unsubscribe@googlegroups.com.
To post to this group, send email to lint...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lint-dev/ae090189-188e-4f67-a5a0-00730dbe7ed6%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "lint-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lint-dev+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lint-dev/ae090189-188e-4f67-a5a0-00730dbe7ed6%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "lint-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lint-dev+u...@googlegroups.com.
To post to this group, send email to lint...@googlegroups.com.