Check against duplicated entries for `ViewModelFactoryDsl`

* `ViewModelFactoryDsl` allows duplicated initializers, unnecessary keeping a reference to duplicates while the returned `InitializerViewModelFactory` ignores the duplicated entries. That can cause subtle bugs at runtime.
* To give immediate feedback, we now check against duplicated and throw an `IllegalArgumentException(message = "A `initializer` with the same `clazz` has already been added: $qualifiedName")`.
* In addition to those changes:
  * All tests now are using `this: CreationExtras` in their `initializer` to access the extras.
  * Different test values are using different keys.

RelNote: "`InitializerViewModelFactory` (including `viewModelFactory` builder function) will now throw an `IllegalArgumentException` if a `initializer` with the same `clazz: KClass<VM : ViewModel>` has already been added."
Fixes: b/326226169
Test: ViewModelInitializerTest
Change-Id: Ic3a36b87c170bd886e60fc264a352096be003c02
diff --git a/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/InitializerViewModelFactory.kt b/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/InitializerViewModelFactory.kt
index df164d3..a38409b 100644
--- a/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/InitializerViewModelFactory.kt
+++ b/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/InitializerViewModelFactory.kt
@@ -40,7 +40,7 @@
 public class InitializerViewModelFactoryBuilder
 public constructor() {
 
-    private val initializers = mutableListOf<ViewModelInitializer<*>>()
+    private val initializers = mutableMapOf<KClass<*>, ViewModelInitializer<*>>()
 
     /**
      * Associates the specified [initializer] with the given [ViewModel] class.
@@ -53,7 +53,10 @@
         clazz: KClass<T>,
         initializer: CreationExtras.() -> T,
     ) {
-        initializers += ViewModelInitializer(clazz, initializer)
+        require(clazz !in initializers) {
+            "A `initializer` with the same `clazz` has already been added: ${clazz.qualifiedName}."
+        }
+        initializers[clazz] = ViewModelInitializer(clazz, initializer)
     }
 
     /**
@@ -61,7 +64,7 @@
      * builder.
      */
     public fun build(): ViewModelProvider.Factory =
-        ViewModelProviders.createInitializerFactory(initializers)
+        ViewModelProviders.createInitializerFactory(initializers.values)
 }
 
 /**
diff --git a/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/internal/ViewModelProviders.kt b/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/internal/ViewModelProviders.kt
index c419e3f..03de848 100644
--- a/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/internal/ViewModelProviders.kt
+++ b/lifecycle/lifecycle-viewmodel/src/commonMain/kotlin/androidx/lifecycle/viewmodel/internal/ViewModelProviders.kt
@@ -55,7 +55,7 @@
         )
 
     internal fun createInitializerFactory(
-        initializers: List<ViewModelInitializer<*>>,
+        initializers: Collection<ViewModelInitializer<*>>,
     ): ViewModelProvider.Factory = InitializerViewModelFactory(*initializers.toTypedArray())
 
     internal fun createInitializerFactory(
diff --git a/lifecycle/lifecycle-viewmodel/src/commonTest/kotlin/androidx/lifecycle/viewmodel/ViewModelInitializerTest.kt b/lifecycle/lifecycle-viewmodel/src/commonTest/kotlin/androidx/lifecycle/viewmodel/ViewModelInitializerTest.kt
index 7214a33..5132a22 100644
--- a/lifecycle/lifecycle-viewmodel/src/commonTest/kotlin/androidx/lifecycle/viewmodel/ViewModelInitializerTest.kt
+++ b/lifecycle/lifecycle-viewmodel/src/commonTest/kotlin/androidx/lifecycle/viewmodel/ViewModelInitializerTest.kt
@@ -19,19 +19,25 @@
 import androidx.kruth.assertThat
 import androidx.lifecycle.ViewModel
 import kotlin.test.Test
+import kotlin.test.fail
 
 class ViewModelInitializerTest {
+
     @Test
-    fun testInitializerFactory() {
-        val key = object : CreationExtras.Key<String> {}
+    fun viewModelFactory_withUniqueInitializers_withCreationExtras_returnsViewModels() {
+        val key1 = object : CreationExtras.Key<String> {}
         val value1 = "test_value1"
-        val extras1 = MutableCreationExtras().apply { set(key, value1) }
+        val extras1 = MutableCreationExtras().apply { set(key1, value1) }
+
+        val key2 = object : CreationExtras.Key<String> {}
         val value2 = "test_value2"
-        val extras2 = MutableCreationExtras().apply { set(key, value2) }
+        val extras2 = MutableCreationExtras().apply { set(key2, value2) }
+
         val factory = viewModelFactory {
-            initializer { TestViewModel1(extras1[key]) }
-            initializer { TestViewModel2(extras2[key]) }
+            initializer<TestViewModel1> { TestViewModel1(get(key1)) }
+            initializer<TestViewModel2> { TestViewModel2(get(key2)) }
         }
+
         val viewModel1: TestViewModel1 = factory.create(TestViewModel1::class, extras1)
         val viewModel2: TestViewModel2 = factory.create(TestViewModel2::class, extras2)
         assertThat(viewModel1.value).isEqualTo(value1)
@@ -39,13 +45,26 @@
     }
 
     @Test
-    fun testInitializerFactoryNoInitializer() {
-        val key = object : CreationExtras.Key<String> {}
-        val value = "test_value"
-        val extras = MutableCreationExtras().apply { set(key, value) }
+    fun viewModelFactory_withDuplicatedInitializers_throwsException() {
+        try {
+            viewModelFactory {
+                initializer<TestViewModel1> { TestViewModel1(null) }
+                initializer<TestViewModel1> { TestViewModel1(null) }
+            }
+            fail("Expected `IllegalArgumentException` but no exception has been throw.")
+        } catch (e: IllegalArgumentException) {
+            assertThat(e).hasMessageThat().isEqualTo(
+                "A `initializer` with the same `clazz` has already been added: " +
+                    "${TestViewModel1::class.qualifiedName}."
+            )
+        }
+    }
+
+    @Test
+    fun viewModelFactory_noInitializers_throwsException() {
         val factory = viewModelFactory { }
         try {
-            factory.create(TestViewModel1::class, extras)
+            factory.create(TestViewModel1::class, CreationExtras.Empty)
         } catch (e: IllegalArgumentException) {
             assertThat(e).hasMessageThat().isEqualTo(
                 "No initializer set for given class ${TestViewModel1::class.qualifiedName}"