Add basic tests for AppInitializer.

Test: Added unit tests.
Change-Id: I59d08c67613886f9e4594467f7196ba50c3485a2
diff --git a/startup/startup-runtime/src/androidTest/java/androidx/startup/AppInitializerTest.kt b/startup/startup-runtime/src/androidTest/java/androidx/startup/AppInitializerTest.kt
new file mode 100644
index 0000000..080c831
--- /dev/null
+++ b/startup/startup-runtime/src/androidTest/java/androidx/startup/AppInitializerTest.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.startup
+
+import android.content.Context
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import org.hamcrest.CoreMatchers.`is`
+import org.hamcrest.CoreMatchers.containsString
+import org.hamcrest.Matchers.containsInAnyOrder
+import org.junit.Assert.assertThat
+import org.junit.Assert.fail
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class AppInitializerTest {
+
+    private lateinit var context: Context
+
+    @Before
+    fun setUp() {
+        context = ApplicationProvider.getApplicationContext()
+    }
+
+    @Test
+    fun basicInitializationTest() {
+        val initializing = mutableSetOf<Class<*>>()
+        val initialized = mutableSetOf<Class<*>>()
+        val components = listOf<Class<*>>(InitializerNoDependencies::class.java)
+        AppInitializer.initialize(context, components, initializing, initialized)
+        assertThat(initializing.size, `is`(0))
+        assertThat(initialized.size, `is`(1))
+        assertThat<Collection<Class<*>>>(
+            initialized,
+            containsInAnyOrder<Class<*>>(*components.toTypedArray())
+        )
+    }
+
+    @Test
+    fun initializationWithDependencies() {
+        val initializing = mutableSetOf<Class<*>>()
+        val initialized = mutableSetOf<Class<*>>()
+        val components = listOf<Class<*>>(InitializerWithDependency::class.java)
+        AppInitializer.initialize(context, components, initializing, initialized)
+        assertThat(initializing.size, `is`(0))
+        assertThat(initialized.size, `is`(2))
+        assertThat<Collection<Class<*>>>(
+            initialized,
+            containsInAnyOrder<Class<*>>(
+                InitializerNoDependencies::class.java,
+                InitializerWithDependency::class.java
+            )
+        )
+    }
+
+    @Test
+    fun initializationWithCyclicDependencies() {
+        val initializing = mutableSetOf<Class<*>>()
+        val initialized = mutableSetOf<Class<*>>()
+        val components = listOf<Class<*>>(CyclicDependencyInitializer::class.java)
+        try {
+            AppInitializer.initialize(context, components, initializing, initialized)
+            fail()
+        } catch (exception: IllegalStateException) {
+            assertThat(exception.localizedMessage, containsString("Cycle detected."))
+        }
+    }
+}
diff --git a/startup/startup-runtime/src/androidTest/java/androidx/startup/CyclicDependencyInitializer.kt b/startup/startup-runtime/src/androidTest/java/androidx/startup/CyclicDependencyInitializer.kt
new file mode 100644
index 0000000..2fd28c3
--- /dev/null
+++ b/startup/startup-runtime/src/androidTest/java/androidx/startup/CyclicDependencyInitializer.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.startup
+
+import android.content.Context
+import android.util.Log
+
+/**
+ * Initializer with cyclic dependencies.
+ */
+class CyclicDependencyInitializer : ComponentInitializer<Unit> {
+    override fun create(context: Context) {
+        Log.i(TAG, "Initialized")
+    }
+
+    override fun dependencies(): List<Class<out ComponentInitializer<*>>> {
+        return listOf(CyclicDependencyInitializer::class.java)
+    }
+
+    companion object {
+        const val TAG = "CyclicDependencies"
+    }
+}
diff --git a/startup/startup-runtime/src/androidTest/java/androidx/startup/InitializerNoDependencies.kt b/startup/startup-runtime/src/androidTest/java/androidx/startup/InitializerNoDependencies.kt
new file mode 100644
index 0000000..2556d93
--- /dev/null
+++ b/startup/startup-runtime/src/androidTest/java/androidx/startup/InitializerNoDependencies.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.startup
+
+import android.content.Context
+import android.util.Log
+
+/**
+ * Initializer with no dependencies.
+ */
+class InitializerNoDependencies : ComponentInitializer<Unit> {
+    override fun create(context: Context) {
+        Log.i(TAG, "Initialized")
+    }
+
+    override fun dependencies(): List<Class<out ComponentInitializer<*>>> = emptyList()
+
+    companion object {
+        const val TAG = "NoDependencies"
+    }
+}
diff --git a/startup/startup-runtime/src/androidTest/java/androidx/startup/InitializerWithDependency.kt b/startup/startup-runtime/src/androidTest/java/androidx/startup/InitializerWithDependency.kt
new file mode 100644
index 0000000..94dc024
--- /dev/null
+++ b/startup/startup-runtime/src/androidTest/java/androidx/startup/InitializerWithDependency.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.startup
+
+import android.content.Context
+import android.util.Log
+
+/**
+ * Initializer with a dependency on [InitializerNoDependencies].
+ */
+class InitializerWithDependency : ComponentInitializer<Unit> {
+    override fun create(context: Context) {
+        Log.i(TAG, "Initialized")
+    }
+
+    override fun dependencies(): List<Class<out ComponentInitializer<*>>> {
+        return listOf(InitializerNoDependencies::class.java)
+    }
+
+    companion object {
+        const val TAG = "HasDependencies"
+    }
+}
diff --git a/startup/startup-runtime/src/main/java/androidx/startup/AppInitializer.kt b/startup/startup-runtime/src/main/java/androidx/startup/AppInitializer.kt
index 180f31f..56bf4b4 100644
--- a/startup/startup-runtime/src/main/java/androidx/startup/AppInitializer.kt
+++ b/startup/startup-runtime/src/main/java/androidx/startup/AppInitializer.kt
@@ -17,6 +17,7 @@
 package androidx.startup
 
 import android.content.Context
+import androidx.annotation.VisibleForTesting
 
 /**
  * An [AppInitializer] can be used to initialize all discovered [ComponentInitializer]s.
@@ -32,8 +33,8 @@
             initialize(context, components, mutableSetOf(), mutableSetOf())
         }
 
-        @Suppress("UNCHECKED_CAST")
-        private fun initialize(
+        @VisibleForTesting
+        internal fun initialize(
             context: Context,
             components: List<Class<*>>,
             initializing: MutableSet<Class<*>>,
diff --git a/startup/startup-runtime/src/main/java/androidx/startup/InitializationProvider.kt b/startup/startup-runtime/src/main/java/androidx/startup/InitializationProvider.kt
index 741848d..c5c3ada 100644
--- a/startup/startup-runtime/src/main/java/androidx/startup/InitializationProvider.kt
+++ b/startup/startup-runtime/src/main/java/androidx/startup/InitializationProvider.kt
@@ -51,7 +51,7 @@
         ).metaData
 
         val startup = context.getString(R.string.androidx_startup)
-        if (metadata.size() > 0) {
+        if (metadata != null && metadata.size() > 0) {
             val components = mutableListOf<Class<*>>()
             metadata.keySet().forEach { key ->
                 val value = metadata.getString(key, null)