diff --git a/MODULE.bazel b/MODULE.bazel
index 03fce0c..4150050 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -24,6 +24,9 @@ maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
maven.install(
name = "rules_android_lint_deps",
artifacts = [
+ # Testing
+ "org.assertj:assertj-core:3.24.2",
+ "junit:junit:4.13.2",
# Worker Dependencies
# TODO(bencodes) Remove these and use the worker impl. that Bazel defines internally
"com.squareup.moshi:moshi:1.15.0",
diff --git a/rules/BUILD.bazel b/rules/BUILD.bazel
index d3f5f63..ab4af5d 100644
--- a/rules/BUILD.bazel
+++ b/rules/BUILD.bazel
@@ -35,11 +35,17 @@ bzl_library(
srcs = ["defs.bzl"],
visibility = ["//visibility:public"],
deps = [
- "//rules/private:collect_aar_outputs_aspect",
+ ":collect_aar_outputs_aspect",
"@bazel_skylib//lib:dicts",
],
)
+bzl_library(
+ name = "collect_aar_outputs_aspect",
+ srcs = ["collect_aar_outputs_aspect.bzl"],
+ visibility = ["//visibility:public"],
+)
+
bzl_library(
name = "extensions",
srcs = ["extensions.bzl"],
@@ -52,9 +58,3 @@ bzl_library(
srcs = ["toolchain.bzl"],
visibility = ["//visibility:public"],
)
-
-py_binary(
- name = "test_runner_executable",
- srcs = ["test_runner_executable.py"],
- visibility = ["//visibility:public"],
-)
diff --git a/rules/collect_aar_outputs_aspect.bzl b/rules/collect_aar_outputs_aspect.bzl
index 8f02348..854f251 100644
--- a/rules/collect_aar_outputs_aspect.bzl
+++ b/rules/collect_aar_outputs_aspect.bzl
@@ -1,10 +1,3 @@
-"""Aspect that collects the AAR outputs.
-
-Lint needs access to the raw archived aar outputs. This aspect collects them all from the dependences,
-exports, and associates of the target. It then wraps them up in an AndroidLintAARInfo provider so that
-Lint targets have access to them.
-"""
-
AndroidLintAARInfo = provider(
"A provider to collect all aars from transitive dependencies",
fields = {
diff --git a/rules/defs.bzl b/rules/defs.bzl
index 6b7ba0c..1a708f7 100644
--- a/rules/defs.bzl
+++ b/rules/defs.bzl
@@ -3,7 +3,7 @@ load(
_dicts = "dicts",
)
load(
- "//rules/private:collect_aar_outputs_aspect.bzl",
+ "//rules:collect_aar_outputs_aspect.bzl",
_AndroidLintAARInfo = "AndroidLintAARInfo",
_collect_aar_outputs_aspect = "collect_aar_outputs_aspect",
)
@@ -27,12 +27,12 @@ _AUTOMATIC_EXEC_GROUPS_ENABLED = dict(
_ATTRS = dict(
_lint_wrapper = attr.label(
- default = "//rules/private/cli:lint_wrapper",
+ default = "//src/cli:cli",
executable = True,
cfg = "exec",
),
_test_runner_executable = attr.label(
- default = "//rules:test_runner_executable",
+ default = "//src:test_runner_executable",
executable = True,
cfg = "exec",
),
diff --git a/rules/private/BUILD.bazel b/rules/private/BUILD.bazel
deleted file mode 100644
index 58e111c..0000000
--- a/rules/private/BUILD.bazel
+++ /dev/null
@@ -1,7 +0,0 @@
-load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
-
-bzl_library(
- name = "collect_aar_outputs_aspect",
- srcs = ["collect_aar_outputs_aspect.bzl"],
- visibility = ["//visibility:public"],
-)
diff --git a/rules/private/collect_aar_outputs_aspect.bzl b/rules/private/collect_aar_outputs_aspect.bzl
deleted file mode 100644
index 854f251..0000000
--- a/rules/private/collect_aar_outputs_aspect.bzl
+++ /dev/null
@@ -1,34 +0,0 @@
-AndroidLintAARInfo = provider(
- "A provider to collect all aars from transitive dependencies",
- fields = {
- "aars": "depset of aars",
- },
-)
-
-def _collect_aar_outputs_aspect(_, ctx):
- deps = getattr(ctx.rule.attr, "deps", [])
- exports = getattr(ctx.rule.attr, "exports", [])
- associates = getattr(ctx.rule.attr, "associates", [])
- transitive_aar_depsets = []
- for dep in deps + exports + associates:
- if AndroidLintAARInfo in dep:
- transitive_aar_depsets.append(dep[AndroidLintAARInfo].aars)
-
- direct_aars = None
- if hasattr(ctx.rule.attr, "aar"):
- aar = ctx.rule.attr.aar.files.to_list()[0]
- direct_aars = [aar]
-
- return [
- AndroidLintAARInfo(
- aars = depset(
- direct = direct_aars,
- transitive = transitive_aar_depsets,
- ),
- ),
- ]
-
-collect_aar_outputs_aspect = aspect(
- implementation = _collect_aar_outputs_aspect,
- attr_aspects = ["aar", "deps", "exports", "associates"],
-)
diff --git a/src/BUILD.bazel b/src/BUILD.bazel
new file mode 100644
index 0000000..2b392ce
--- /dev/null
+++ b/src/BUILD.bazel
@@ -0,0 +1,5 @@
+py_binary(
+ name = "test_runner_executable",
+ srcs = ["test_runner_executable.py"],
+ visibility = ["//visibility:public"],
+)
diff --git a/rules/private/cli/AndroidLintAction.kt b/src/cli/AndroidLintAction.kt
similarity index 100%
rename from rules/private/cli/AndroidLintAction.kt
rename to src/cli/AndroidLintAction.kt
diff --git a/rules/private/cli/AndroidLintActionArgs.kt b/src/cli/AndroidLintActionArgs.kt
similarity index 100%
rename from rules/private/cli/AndroidLintActionArgs.kt
rename to src/cli/AndroidLintActionArgs.kt
diff --git a/rules/private/cli/AndroidLintBaselineSanitizer.kt b/src/cli/AndroidLintBaselineSanitizer.kt
similarity index 100%
rename from rules/private/cli/AndroidLintBaselineSanitizer.kt
rename to src/cli/AndroidLintBaselineSanitizer.kt
diff --git a/rules/private/cli/AndroidLintProject.kt b/src/cli/AndroidLintProject.kt
similarity index 100%
rename from rules/private/cli/AndroidLintProject.kt
rename to src/cli/AndroidLintProject.kt
diff --git a/rules/private/cli/AndroidLintRunner.kt b/src/cli/AndroidLintRunner.kt
similarity index 100%
rename from rules/private/cli/AndroidLintRunner.kt
rename to src/cli/AndroidLintRunner.kt
diff --git a/rules/private/cli/AndroidLintWrapperUtils.kt b/src/cli/AndroidLintWrapperUtils.kt
similarity index 100%
rename from rules/private/cli/AndroidLintWrapperUtils.kt
rename to src/cli/AndroidLintWrapperUtils.kt
diff --git a/rules/private/cli/BUILD b/src/cli/BUILD
similarity index 94%
rename from rules/private/cli/BUILD
rename to src/cli/BUILD
index 8b1ca6b..f397f2b 100644
--- a/rules/private/cli/BUILD
+++ b/src/cli/BUILD
@@ -3,12 +3,26 @@ load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
load("@rules_kotlin//kotlin:lint.bzl", "ktlint_fix", "ktlint_test")
java_binary(
- name = "lint_wrapper",
+ name = "cli",
main_class = "com.rules.android.lint.cli.AndroidLintAction",
visibility = ["//visibility:public"],
runtime_deps = [":lint"],
)
+kt_jvm_library(
+ name = "lint",
+ srcs = glob(["*.kt"]),
+ visibility = ["//visibility:public"],
+ deps = [
+ "//src/worker",
+ "@rules_android_lint_deps//:com_android_tools_lint_lint",
+ "@rules_android_lint_deps//:com_android_tools_lint_lint_api",
+ "@rules_android_lint_deps//:com_android_tools_lint_lint_checks",
+ "@rules_android_lint_deps//:com_android_tools_lint_lint_model",
+ "@rules_android_lint_deps//:com_xenomachina_kotlin_argparser",
+ ],
+)
+
ktlint_test(
name = "lint_ktlint_test",
srcs = glob(["*.kt"]),
@@ -22,17 +36,3 @@ ktlint_fix(
config = "//:editorconfig",
visibility = ["//visibility:private"],
)
-
-kt_jvm_library(
- name = "lint",
- srcs = glob(["*.kt"]),
- visibility = ["//visibility:public"],
- deps = [
- "//rules/private/worker",
- "@rules_android_lint_deps//:com_android_tools_lint_lint",
- "@rules_android_lint_deps//:com_android_tools_lint_lint_api",
- "@rules_android_lint_deps//:com_android_tools_lint_lint_checks",
- "@rules_android_lint_deps//:com_android_tools_lint_lint_model",
- "@rules_android_lint_deps//:com_xenomachina_kotlin_argparser",
- ],
-)
diff --git a/rules/test_runner_executable.py b/src/test_runner_executable.py
similarity index 100%
rename from rules/test_runner_executable.py
rename to src/test_runner_executable.py
diff --git a/rules/private/worker/BUILD b/src/worker/BUILD
similarity index 100%
rename from rules/private/worker/BUILD
rename to src/worker/BUILD
diff --git a/rules/private/worker/InvocationWorker.kt b/src/worker/InvocationWorker.kt
similarity index 100%
rename from rules/private/worker/InvocationWorker.kt
rename to src/worker/InvocationWorker.kt
diff --git a/rules/private/worker/PersistentWorker.kt b/src/worker/PersistentWorker.kt
similarity index 100%
rename from rules/private/worker/PersistentWorker.kt
rename to src/worker/PersistentWorker.kt
diff --git a/rules/private/worker/PersistentWorkerCpuTimeBasedGcScheduler.kt b/src/worker/PersistentWorkerCpuTimeBasedGcScheduler.kt
similarity index 100%
rename from rules/private/worker/PersistentWorkerCpuTimeBasedGcScheduler.kt
rename to src/worker/PersistentWorkerCpuTimeBasedGcScheduler.kt
diff --git a/rules/private/worker/WorkRequest.kt b/src/worker/WorkRequest.kt
similarity index 100%
rename from rules/private/worker/WorkRequest.kt
rename to src/worker/WorkRequest.kt
diff --git a/rules/private/worker/WorkResponse.kt b/src/worker/WorkResponse.kt
similarity index 100%
rename from rules/private/worker/WorkResponse.kt
rename to src/worker/WorkResponse.kt
diff --git a/rules/private/worker/Worker.kt b/src/worker/Worker.kt
similarity index 100%
rename from rules/private/worker/Worker.kt
rename to src/worker/Worker.kt
diff --git a/rules/private/worker/WorkerIO.kt b/src/worker/WorkerIO.kt
similarity index 100%
rename from rules/private/worker/WorkerIO.kt
rename to src/worker/WorkerIO.kt
diff --git a/rules/private/worker/WorkerJsonMessageProcessor.kt b/src/worker/WorkerJsonMessageProcessor.kt
similarity index 100%
rename from rules/private/worker/WorkerJsonMessageProcessor.kt
rename to src/worker/WorkerJsonMessageProcessor.kt
diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel
index 6fba512..602c6be 100644
--- a/tests/BUILD.bazel
+++ b/tests/BUILD.bazel
@@ -6,7 +6,7 @@ test_suite(
name = "tests",
tests = [
":versions_test",
- "//tests/private/cli:tests",
- "//tests/private/worker:tests",
+ "//tests/src/cli:tests",
+ "//tests/src/worker:tests",
],
)
diff --git a/tests/private/cli/BUILD b/tests/private/cli/BUILD
deleted file mode 100644
index e0cfdc1..0000000
--- a/tests/private/cli/BUILD
+++ /dev/null
@@ -1,6 +0,0 @@
-load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test")
-load("@rules_kotlin//kotlin:lint.bzl", "ktlint_fix", "ktlint_test")
-
-test_suite(
- name = "tests",
-)
diff --git a/tests/private/worker/BUILD b/tests/private/worker/BUILD
deleted file mode 100644
index e0cfdc1..0000000
--- a/tests/private/worker/BUILD
+++ /dev/null
@@ -1,6 +0,0 @@
-load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test")
-load("@rules_kotlin//kotlin:lint.bzl", "ktlint_fix", "ktlint_test")
-
-test_suite(
- name = "tests",
-)
diff --git a/tests/src/cli/AndroidLintActionArgsTest.kt b/tests/src/cli/AndroidLintActionArgsTest.kt
new file mode 100644
index 0000000..fe2ceb0
--- /dev/null
+++ b/tests/src/cli/AndroidLintActionArgsTest.kt
@@ -0,0 +1,76 @@
+package com.rules.android.lint.cli
+
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import java.nio.file.Paths
+
+@RunWith(JUnit4::class)
+class AndroidLintActionArgsTest {
+
+ @Test
+ fun `does parse all arguments`() {
+ val parseArgs = AndroidLintActionArgs.parseArgs(
+ args = listOf(
+ "--module-name",
+ "test_module_name",
+ "--label",
+ "test",
+ "--src",
+ "path/to/Foo.kt",
+ "--output",
+ "output.jar",
+ "--project-config-output",
+ "project.xml",
+ "--resource",
+ "path/to/resource/strings.xml",
+ "--android-manifest",
+ "AndroidManifest.xml",
+ "--baseline-file",
+ "lib_lint_baseline.xml",
+ "--config-file",
+ "lint_config.xml",
+ "--custom-rule",
+ "custom_rule.jar",
+ "--classpath",
+ "classpath.jar",
+ "--classpath",
+ "classpath.aar",
+ "--autofix",
+ "--regenerate-baseline-files",
+ "--warnings-as-errors",
+ "--enable-check",
+ "custom-check",
+ "--disable-check",
+ "custom-disabled-check",
+ "--compile-sdk-version",
+ "1.6",
+ "--java-language-level",
+ "1.7",
+ "--kotlin-language-level",
+ "1.8",
+ ),
+ )
+
+ assertThat(parseArgs.moduleName).isEqualTo("test_module_name")
+ assertThat(parseArgs.label).isEqualTo("test")
+ assertThat(parseArgs.srcs).containsExactly(Paths.get("path/to/Foo.kt"))
+ assertThat(parseArgs.output).isEqualTo(Paths.get("output.jar"))
+ assertThat(parseArgs.projectConfigOutput).isEqualTo(Paths.get("project.xml"))
+ assertThat(parseArgs.resources).containsExactly(Paths.get("path/to/resource/strings.xml"))
+ assertThat(parseArgs.baselineFile).isEqualTo(Paths.get("lib_lint_baseline.xml"))
+ assertThat(parseArgs.config).isEqualTo(Paths.get("lint_config.xml"))
+ assertThat(parseArgs.customChecks).containsExactly(Paths.get("custom_rule.jar"))
+ assertThat(parseArgs.classpath)
+ .containsExactly(Paths.get("classpath.jar"), Paths.get("classpath.aar"))
+ assertThat(parseArgs.autofix).isTrue
+ assertThat(parseArgs.regenerateBaselineFile).isTrue
+ assertThat(parseArgs.warningsAsErrors).isTrue
+ assertThat(parseArgs.enableChecks).containsExactly("custom-check")
+ assertThat(parseArgs.disableChecks).containsExactly("custom-disabled-check")
+ assertThat(parseArgs.compileSdkVersion).isEqualTo("1.6")
+ assertThat(parseArgs.javaLanguageLevel).isEqualTo("1.7")
+ assertThat(parseArgs.kotlinLanguageLevel).isEqualTo("1.8")
+ }
+}
diff --git a/tests/src/cli/AndroidLintActionTest.kt b/tests/src/cli/AndroidLintActionTest.kt
new file mode 100644
index 0000000..e891def
--- /dev/null
+++ b/tests/src/cli/AndroidLintActionTest.kt
@@ -0,0 +1,13 @@
+package com.rules.android.lint.cli
+
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class AndroidLintActionTest {
+ @Test
+ fun `empty test case`() {
+ // TODO(bencodes) Add some tests for AndroidLintAction
+ }
+}
diff --git a/tests/src/cli/AndroidLintProjectTest.kt b/tests/src/cli/AndroidLintProjectTest.kt
new file mode 100644
index 0000000..3fbe89d
--- /dev/null
+++ b/tests/src/cli/AndroidLintProjectTest.kt
@@ -0,0 +1,56 @@
+package com.rules.android.lint.cli
+
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import java.nio.file.Path
+
+@RunWith(JUnit4::class)
+class AndroidLintProjectTest {
+
+ @Rule
+ @JvmField
+ var tmpDirectory = TemporaryFolder()
+
+ private fun TemporaryFolder.newPath(name: String): Path = this.newFile(name).toPath()
+
+ @Test
+ fun `test asXMLString does produce correct project file content`() {
+ assertThat(
+ createProjectXMLString(
+ moduleName = "test_module_name",
+ srcs = listOf(tmpDirectory.newPath("Foo.kt")),
+ resources = listOf(tmpDirectory.newPath("foo.xml")),
+ androidManifest = tmpDirectory.newPath("AndroidManifest.xml"),
+ classpathJars = listOf(tmpDirectory.newPath("Foo.jar")),
+ classpathAars = listOf(tmpDirectory.newPath("Foo.aar")),
+ classpathExtractedAarDirectories = listOf(
+ Pair(
+ tmpDirectory.newPath("Bar.aar"),
+ tmpDirectory.newFolder("tmp/unpacked_aars/bar/").toPath(),
+ ),
+ ),
+ customLintChecks = listOf(tmpDirectory.newPath("tmp/unpacked_aars/bar/lint.jar")),
+ ),
+ ).isEqualTo(
+ """
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """.trimIndent().replace("{root}", tmpDirectory.root.absolutePath),
+ )
+ }
+}
diff --git a/tests/src/cli/BUILD b/tests/src/cli/BUILD
new file mode 100644
index 0000000..c2196ea
--- /dev/null
+++ b/tests/src/cli/BUILD
@@ -0,0 +1,58 @@
+load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test")
+load("@rules_kotlin//kotlin:lint.bzl", "ktlint_fix", "ktlint_test")
+
+kt_jvm_test(
+ name = "AndroidLintActionArgsTest",
+ srcs = ["AndroidLintActionArgsTest.kt"],
+ associates = ["//src/cli:lint"],
+ test_class = "com.rules.android.lint.cli.AndroidLintActionArgsTest",
+ deps = [
+ "@rules_android_lint_deps//:junit_junit",
+ "@rules_android_lint_deps//:org_assertj_assertj_core",
+ ],
+)
+
+kt_jvm_test(
+ name = "AndroidLintActionTest",
+ srcs = ["AndroidLintActionTest.kt"],
+ associates = ["//src/cli:lint"],
+ test_class = "com.rules.android.lint.cli.AndroidLintActionTest",
+ deps = [
+ "@rules_android_lint_deps//:junit_junit",
+ "@rules_android_lint_deps//:org_assertj_assertj_core",
+ ],
+)
+
+kt_jvm_test(
+ name = "AndroidLintProjectTest",
+ srcs = ["AndroidLintProjectTest.kt"],
+ associates = ["//src/cli:lint"],
+ test_class = "com.rules.android.lint.cli.AndroidLintProjectTest",
+ deps = [
+ "@rules_android_lint_deps//:junit_junit",
+ "@rules_android_lint_deps//:org_assertj_assertj_core",
+ ],
+)
+
+ktlint_test(
+ name = "lint_ktlint_test",
+ srcs = glob(["*.kt"]),
+ config = "//:editorconfig",
+ visibility = ["//visibility:private"],
+)
+
+ktlint_fix(
+ name = "lint_ktlint_fix",
+ srcs = glob(["*.kt"]),
+ config = "//:editorconfig",
+ visibility = ["//visibility:private"],
+)
+
+test_suite(
+ name = "tests",
+ tests = [
+ ":AndroidLintActionArgsTest",
+ ":AndroidLintActionTest",
+ ":AndroidLintProjectTest",
+ ],
+)
diff --git a/tests/src/worker/BUILD b/tests/src/worker/BUILD
new file mode 100644
index 0000000..1f69beb
--- /dev/null
+++ b/tests/src/worker/BUILD
@@ -0,0 +1,32 @@
+load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test")
+load("@rules_kotlin//kotlin:lint.bzl", "ktlint_fix", "ktlint_test")
+
+kt_jvm_test(
+ name = "WorkerIOTest",
+ srcs = ["WorkerIOTest.kt"],
+ associates = ["//src/worker"],
+ test_class = "com.rules.android.lint.worker.WorkerIOTest",
+ deps = [
+ "@rules_android_lint_deps//:junit_junit",
+ "@rules_android_lint_deps//:org_assertj_assertj_core",
+ ],
+)
+
+kt_jvm_test(
+ name = "WorkerJsonMessageProcessorTest",
+ srcs = ["WorkerJsonMessageProcessorTest.kt"],
+ associates = ["//src/worker"],
+ test_class = "com.rules.android.lint.worker.WorkerJsonMessageProcessorTest",
+ deps = [
+ "@rules_android_lint_deps//:junit_junit",
+ "@rules_android_lint_deps//:org_assertj_assertj_core",
+ ],
+)
+
+test_suite(
+ name = "tests",
+ tests = [
+ ":WorkerIOTest",
+ ":WorkerJsonMessageProcessorTest",
+ ],
+)
diff --git a/tests/src/worker/WorkerIOTest.kt b/tests/src/worker/WorkerIOTest.kt
new file mode 100644
index 0000000..a5e86a1
--- /dev/null
+++ b/tests/src/worker/WorkerIOTest.kt
@@ -0,0 +1,97 @@
+package com.rules.android.lint.worker
+
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import java.io.ByteArrayInputStream
+import java.io.ByteArrayOutputStream
+import java.io.PrintStream
+import java.nio.charset.StandardCharsets
+
+@RunWith(JUnit4::class)
+class WorkerIOTest {
+
+ @Test
+ @Throws(Exception::class)
+ fun testWorkerIO_doesWrapSystemStreams() {
+ // Save the original streams
+ val originalInputStream = System.`in`
+ val originalOutputStream = System.out
+ val originalErrorStream = System.err
+
+ // Swap in the test streams to assert against
+ val byteArrayInputStream = ByteArrayInputStream(ByteArray(0))
+ val outputBuffer = PrintStream(ByteArrayOutputStream(), true)
+ val errorBuffer = PrintStream(ByteArrayOutputStream(), true)
+ System.setIn(byteArrayInputStream)
+ System.setOut(outputBuffer)
+ System.setErr(errorBuffer)
+
+ try {
+ WorkerIO().use { io ->
+ // Redirect the system streams
+ io.redirectSystemStreams()
+
+ // Assert that the WorkerIO returns the correct wrapped streams and the System instance
+ // has been swapped out with the wrapped one. System.in should be untouched.
+ assertThat(System.`in`).isSameAs(byteArrayInputStream)
+
+ assertThat(io.output).isSameAs(outputBuffer)
+ assertThat(System.out).isSameAs(errorBuffer)
+
+ assertThat(io.err).isSameAs(errorBuffer)
+ assertThat(System.err).isSameAs(errorBuffer)
+ }
+ } finally {
+ // Swap back in the original streams
+ System.setIn(originalInputStream)
+ System.setOut(originalOutputStream)
+ System.setErr(originalErrorStream)
+
+ outputBuffer.close()
+ errorBuffer.close()
+ byteArrayInputStream.close()
+ }
+ }
+
+ @Test
+ @Throws(Exception::class)
+ fun testWorkerIO_doesWriteSystemOutToSystemError() {
+ // Save the original streams
+ val originalInputStream = System.`in`
+ val originalOutputStream = System.out
+ val originalErrorStream = System.err
+
+ // Swap in the test streams to assert against
+ val byteArrayInputStream = ByteArrayInputStream(ByteArray(0))
+ val byteArrayOutputStream = ByteArrayOutputStream()
+ val outputBuffer = PrintStream(byteArrayOutputStream, true)
+ System.setIn(byteArrayInputStream)
+ System.setOut(outputBuffer)
+ System.setErr(outputBuffer)
+ try {
+ WorkerIO().use { io ->
+ // Redirect the system streams
+ io.redirectSystemStreams()
+ var captured = String(byteArrayOutputStream.toByteArray(), StandardCharsets.UTF_8)
+ assertThat(captured).isEmpty()
+
+ // Assert that the standard out/error stream redirect to our own streams
+ println("This is a standard out message!")
+ System.err.println("This is a standard error message!")
+ captured = String(byteArrayOutputStream.toByteArray(), StandardCharsets.UTF_8)
+ byteArrayOutputStream.reset()
+ assertThat(captured)
+ .isEqualTo("This is a standard out message!\nThis is a standard error message!\n")
+ }
+ } finally {
+ // Swap back in the original streams
+ System.setIn(originalInputStream)
+ System.setOut(originalOutputStream)
+ System.setErr(originalErrorStream)
+ outputBuffer.close()
+ byteArrayInputStream.close()
+ }
+ }
+}
diff --git a/tests/src/worker/WorkerJsonMessageProcessorTest.kt b/tests/src/worker/WorkerJsonMessageProcessorTest.kt
new file mode 100644
index 0000000..170dc97
--- /dev/null
+++ b/tests/src/worker/WorkerJsonMessageProcessorTest.kt
@@ -0,0 +1,65 @@
+package com.rules.android.lint.worker
+
+import okio.Buffer
+import org.assertj.core.api.Assertions.assertThat
+import org.assertj.core.api.Assertions.fail
+import org.junit.After
+import org.junit.Test
+
+
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4::class)
+class WorkerJsonMessageProcessorTest {
+
+ private val jsonBuffer = Buffer()
+ private val processor = WorkerJsonMessageProcessor(
+ inputStream = jsonBuffer.inputStream(),
+ outputStream = jsonBuffer.outputStream(),
+ )
+
+ @After
+ fun reset() {
+ jsonBuffer.close()
+ }
+
+ @Test
+ fun doesEncodeWorkResponseJsonCorrectly() {
+ processor.writeWorkResponse(WorkResponse(requestId = 110, exitCode = 100, output = "foo"))
+
+ val json = jsonBuffer.readString(Charsets.UTF_8)
+ assertThat(json).isEqualTo("{\"requestId\":110,\"exitCode\":100,\"output\":\"foo\"}")
+ }
+
+ @Test
+ fun doesParseWorkRequestJsonCorrectly() {
+ jsonBuffer.writeString("{\"requestId\": 100, \"arguments\": [\"foo\"]}", Charsets.UTF_8)
+
+ val workRequest = processor.readWorkRequest()
+ assertThat(workRequest).isNotNull
+ assertThat(workRequest.requestId).isEqualTo(100)
+ assertThat(workRequest.arguments).containsExactly("foo")
+ }
+
+ @Test
+ fun doesDefaultRequestIDToZeroWhenNotPresent() {
+ jsonBuffer.writeString("{\"arguments\": []}", Charsets.UTF_8)
+
+ val workRequest = processor.readWorkRequest()
+ assertThat(workRequest).isNotNull
+ assertThat(workRequest.requestId).isEqualTo(0)
+ }
+
+ @Test
+ fun doesCrashWhenArgumentsNotPresent() {
+ jsonBuffer.writeString("{\"requestId\": 100}", Charsets.UTF_8)
+
+ try {
+ processor.readWorkRequest()
+ fail("readNextWorkRequest is expected to fail when arguments not provided!")
+ } catch (e: Exception) {
+ assertThat(e).hasMessage("Required value 'arguments' missing at \$")
+ }
+ }
+}