Improve usability of PublicApiTest:

* No need to manually create tests for new modules (scans list of modules)
* Pass test when used with "-Poverwrite.output=true"
diff --git a/binary-compatibility-validator/test/PublicApiTest.kt b/binary-compatibility-validator/test/PublicApiTest.kt
index 5fe5c1e..0384bf7 100644
--- a/binary-compatibility-validator/test/PublicApiTest.kt
+++ b/binary-compatibility-validator/test/PublicApiTest.kt
@@ -5,124 +5,62 @@
 package kotlinx.coroutines.experimental.tools
 
 import org.junit.*
-import org.junit.rules.*
+import org.junit.runner.*
+import org.junit.runners.*
 import java.io.*
+import java.util.*
 import java.util.jar.*
+import kotlin.collections.ArrayList
 
-class PublicApiTest {
+@RunWith(Parameterized::class)
+class PublicApiTest(
+    private val rootDir: String,
+    private val moduleName: String
+) {
+    companion object {
+        private val apiProps = ClassLoader.getSystemClassLoader()
+            .getResource("api.properties").openStream().use { Properties().apply { load(it) } }
+        private val nonPublicPackages = apiProps.getProperty("packages.internal")!!.split(" ")
 
-   /*
-    * How to add a test for your module kotlinx-coroutines-foo?
-    *
-    * Dump public declarations via PublicApiDump.kt and create file
-    * reference-public-api/kotlinx-coroutines-foo.txt with dumped declarations.
-    *
-    * Then add test:
-    *
-    * @Test
-    * fun kotlinxCorountesFoo() { // <- name pattern should match txt file from reference-public-api
-    *   snapshotAPIAndCompare($relative_path_to_module)
-    * }
-    */
-
-    @Rule
-    @JvmField
-    val testName = TestName()
-
-    @Test
-    fun kotlinxCoroutinesCore() {
-        snapshotAPIAndCompare("core/kotlinx-coroutines-core", nonPublicPackages = listOf(
-            "kotlinx.coroutines.experimental.internal",
-            "kotlinx.coroutines.experimental.scheduling"))
+        @Parameterized.Parameters(name = "{1}")
+        @JvmStatic
+        fun modules(): List<Array<Any>> {
+            val moduleRoots = apiProps.getProperty("module.roots").split(" ")
+            val moduleMarker = apiProps.getProperty("module.marker")!!
+            val moduleIgnore = apiProps.getProperty("module.ignore")!!.split(" ").toSet()
+            val modules = ArrayList<Array<Any>>()
+            for (rootDir in moduleRoots) {
+                File("../$rootDir").listFiles( FileFilter { it.isDirectory })?.forEach { dir ->
+                    if (dir.name !in moduleIgnore && File(dir, moduleMarker).exists()) {
+                        modules += arrayOf<Any>(rootDir, dir.name)
+                    }
+                }
+            }
+            return modules
+        }
     }
 
     @Test
-    fun kotlinxCoroutinesReactive() {
-        snapshotAPIAndCompare("reactive/kotlinx-coroutines-reactive")
-    }
-
-    @Test
-    fun kotlinxCoroutinesReactor() {
-        snapshotAPIAndCompare("reactive/kotlinx-coroutines-reactor")
-    }
-
-    @Test
-    fun kotlinxCoroutinesRx1() {
-        snapshotAPIAndCompare("reactive/kotlinx-coroutines-rx1")
-    }
-
-    @Test
-    fun kotlinxCoroutinesRx2() {
-        snapshotAPIAndCompare("reactive/kotlinx-coroutines-rx2")
-    }
-
-    @Test
-    fun kotlinxCoroutinesGuava() {
-        snapshotAPIAndCompare("integration/kotlinx-coroutines-guava")
-    }
-
-    @Test
-    fun kotlinxCoroutinesJdk8() {
-        snapshotAPIAndCompare("integration/kotlinx-coroutines-jdk8")
-    }
-
-
-    @Test
-    fun kotlinxCoroutinesNio() {
-        snapshotAPIAndCompare("integration/kotlinx-coroutines-nio")
-    }
-
-    @Test
-    fun kotlinxCoroutinesQuasar() {
-        snapshotAPIAndCompare("integration/kotlinx-coroutines-quasar")
-    }
-
-    @Test
-    fun kotlinxCoroutinesAndroid() {
-        snapshotAPIAndCompare("ui/kotlinx-coroutines-android")
-    }
-
-
-    @Test
-    fun kotlinxCoroutinesJavafx() {
-        snapshotAPIAndCompare("ui/kotlinx-coroutines-javafx")
-    }
-
-    @Test
-    fun kotlinxCoroutinesSwing() {
-        snapshotAPIAndCompare("ui/kotlinx-coroutines-swing")
-    }
-
-    private fun snapshotAPIAndCompare(basePath: String, jarPattern: String = basePath.substring(basePath.indexOf("/") + 1),
-                                      publicPackages: List<String> = emptyList(), nonPublicPackages: List<String> = emptyList()) {
-        val base = File("../$basePath/build/libs").absoluteFile.normalize()
-        val jarFile = getJarPath(base, jarPattern)
-        val kotlinJvmMappingsFiles = listOf(base.resolve("../visibilities.json"))
-
-        val publicPackagePrefixes = publicPackages.map { it.replace('.', '/') + '/' }
+    fun testApi() {
+        val libsDir = File("../$rootDir/$moduleName/build/libs").absoluteFile.normalize()
+        val jarFile = getJarPath(libsDir)
+        val kotlinJvmMappingsFiles = listOf(libsDir.resolve("../visibilities.json"))
         val visibilities =
                 kotlinJvmMappingsFiles
-                        .map { readKotlinVisibilities(it).filterKeys { name -> publicPackagePrefixes.none { name.startsWith(it) } } }
+                        .map { readKotlinVisibilities(it) }
                         .reduce { m1, m2 -> m1 + m2 }
-
         val api = getBinaryAPI(JarFile(jarFile), visibilities).filterOutNonPublic(nonPublicPackages)
-
-        val target = File("reference-public-api")
-                .resolve(testName.methodName.replaceCamelCaseWithDashedLowerCase() + ".txt")
-
-        api.dumpAndCompareWith(target)
+        api.dumpAndCompareWith(File("reference-public-api").resolve("$moduleName.txt"))
     }
 
-    private fun getJarPath(base: File, jarPattern: String, kotlinVersion: String? = null): File {
-        val versionPattern = kotlinVersion?.let { "-" + Regex.escape(it) } ?: ".+"
-        val regex = Regex("$jarPattern$versionPattern\\.jar")
-        val files = (base.listFiles() ?: throw Exception("Cannot list files in $base"))
+    private fun getJarPath(libsDir: File): File {
+        val regex = Regex("$moduleName-.+\\.jar")
+        val files = (libsDir.listFiles() ?: throw Exception("Cannot list files in $libsDir"))
             .filter { it.name.let {
                     it matches regex
                     && !it.endsWith("-sources.jar")
                     && !it.endsWith("-javadoc.jar")
                     && !it.endsWith("-tests.jar")} }
-
-        return files.singleOrNull() ?: throw Exception("No single file matching $regex in $base:\n${files.joinToString("\n")}")
+        return files.singleOrNull() ?: throw Exception("No single file matching $regex in $libsDir:\n${files.joinToString("\n")}")
     }
 }