Skip to content

Commit cc4cfcc

Browse files
committed
Updates ViewRegistry tests
1 parent e8a9f5c commit cc4cfcc

File tree

6 files changed

+294
-103
lines changed

6 files changed

+294
-103
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
@file:OptIn(WorkflowUiExperimentalApi::class)
2+
3+
package com.squareup.workflow1.ui
4+
5+
import android.content.Context
6+
import android.view.View
7+
import android.view.ViewGroup
8+
import com.google.common.truth.Truth.assertThat
9+
import com.squareup.workflow1.ui.ViewRegistry.Entry
10+
import org.junit.Test
11+
import org.mockito.kotlin.doReturn
12+
import org.mockito.kotlin.eq
13+
import org.mockito.kotlin.mock
14+
import kotlin.reflect.KClass
15+
import kotlin.test.assertFailsWith
16+
17+
internal class AndroidViewEnvironmentTest {
18+
19+
@OptIn(WorkflowUiExperimentalApi::class)
20+
@Test fun missingBindingMessage_isUseful() {
21+
val emptyReg = object : ViewRegistry {
22+
override val keys: Set<KClass<*>> = emptySet()
23+
override fun <RenderingT : Any> getEntryFor(
24+
renderingType: KClass<out RenderingT>
25+
): Entry<RenderingT>? = null
26+
}
27+
val env = ViewEnvironment(mapOf(ViewRegistry to emptyReg))
28+
29+
val fooScreen = object : Screen {
30+
override fun toString() = "FooScreen"
31+
}
32+
33+
val error = assertFailsWith<IllegalArgumentException> {
34+
env.buildView(fooScreen, mock())
35+
}
36+
assertThat(error.message).isEqualTo(
37+
"A ScreenViewFactory should have been registered to display " +
38+
"FooScreen, or that class should implement AndroidScreen."
39+
)
40+
}
41+
42+
@Test fun `buildView honors AndroidScreen`() {
43+
val registry = ViewRegistry()
44+
val env = ViewEnvironment(mapOf(ViewRegistry to registry))
45+
val screen = MyAndroidScreen()
46+
47+
env.buildView(screen, mock())
48+
assertThat(screen.viewFactory.called).isTrue()
49+
}
50+
51+
@Test fun `buildView prefers registry entries to AndroidViewRendering`() {
52+
val registry = ViewRegistry(overrideViewRenderingFactory)
53+
val env = ViewEnvironment(mapOf(ViewRegistry to registry))
54+
55+
val screen = MyAndroidScreen()
56+
env.buildView(screen, mock())
57+
assertThat(screen.viewFactory.called).isFalse()
58+
assertThat(overrideViewRenderingFactory.called).isTrue()
59+
}
60+
61+
private class TestViewFactory<T : Screen>(
62+
override val type: KClass<in T>
63+
) : ScreenViewFactory<T> {
64+
var called = false
65+
66+
override fun buildView(
67+
initialRendering: T,
68+
initialViewEnvironment: ViewEnvironment,
69+
contextForNewView: Context,
70+
container: ViewGroup?
71+
): View {
72+
called = true
73+
74+
return mock {
75+
on {
76+
getTag(eq(R.id.view_show_rendering_function))
77+
} doReturn (ShowRenderingTag(initialRendering, initialViewEnvironment, { _, _ -> }))
78+
}
79+
}
80+
}
81+
82+
private class MyAndroidScreen : AndroidScreen<MyAndroidScreen> {
83+
override val viewFactory = TestViewFactory(MyAndroidScreen::class)
84+
}
85+
86+
private val overrideViewRenderingFactory = TestViewFactory(MyAndroidScreen::class)
87+
}
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
@file:Suppress("DEPRECATION")
2+
3+
package com.squareup.workflow1.ui
4+
5+
import android.content.Context
6+
import android.view.View
7+
import android.view.ViewGroup
8+
import com.google.common.truth.Truth.assertThat
9+
import com.squareup.workflow1.ui.ViewRegistry.Entry
10+
import org.junit.Test
11+
import org.mockito.kotlin.doReturn
12+
import org.mockito.kotlin.eq
13+
import org.mockito.kotlin.mock
14+
import kotlin.reflect.KClass
15+
import kotlin.test.assertFailsWith
16+
import kotlin.test.assertTrue
17+
18+
@OptIn(WorkflowUiExperimentalApi::class)
19+
internal class LegacyAndroidViewRegistryTest {
20+
21+
@OptIn(WorkflowUiExperimentalApi::class)
22+
@Test fun missingBindingMessage_isUseful() {
23+
val emptyReg = object : ViewRegistry {
24+
override val keys: Set<KClass<*>> = emptySet()
25+
override fun <RenderingT : Any> getEntryFor(
26+
renderingType: KClass<out RenderingT>
27+
): Entry<RenderingT>? = null
28+
}
29+
30+
val error = assertFailsWith<IllegalArgumentException> {
31+
emptyReg.buildView("render this, bud")
32+
}
33+
assertThat(error.message).isEqualTo(
34+
"A ViewFactory should have been registered to display " +
35+
"render this, bud, or that class should implement AndroidViewRendering.")
36+
}
37+
38+
@Test fun `getFactoryFor delegates to composite registries`() {
39+
val fooFactory = TestViewFactory(FooRendering::class)
40+
val barFactory = TestViewFactory(BarRendering::class)
41+
val bazFactory = TestViewFactory(BazRendering::class)
42+
val fooBarRegistry = TestRegistry(
43+
mapOf(
44+
FooRendering::class to fooFactory,
45+
BarRendering::class to barFactory
46+
)
47+
)
48+
val bazRegistry = TestRegistry(factories = mapOf(BazRendering::class to bazFactory))
49+
val registry = fooBarRegistry + bazRegistry
50+
51+
assertThat(registry.getEntryFor(FooRendering::class))
52+
.isSameInstanceAs(fooFactory)
53+
assertThat(registry.getEntryFor(BarRendering::class))
54+
.isSameInstanceAs(barFactory)
55+
assertThat(registry.getEntryFor(BazRendering::class))
56+
.isSameInstanceAs(bazFactory)
57+
}
58+
59+
@Test fun `getFactoryFor returns null on missing registry`() {
60+
val fooRegistry = TestRegistry(setOf(FooRendering::class))
61+
val registry = ViewRegistry() + fooRegistry
62+
63+
assertThat(registry.getEntryFor(BarRendering::class)).isNull()
64+
}
65+
66+
@Test fun `keys includes all composite registries' keys`() {
67+
val fooBarRegistry = TestRegistry(setOf(FooRendering::class, BarRendering::class))
68+
val bazRegistry = TestRegistry(setOf(BazRendering::class))
69+
val registry = fooBarRegistry + bazRegistry
70+
71+
assertThat(registry.keys).containsExactly(
72+
FooRendering::class,
73+
BarRendering::class,
74+
BazRendering::class
75+
)
76+
}
77+
78+
@Test fun `keys from bindings`() {
79+
val factory1 = TestViewFactory(FooRendering::class)
80+
val factory2 = TestViewFactory(BarRendering::class)
81+
val registry = ViewRegistry(factory1, factory2)
82+
83+
assertThat(registry.keys).containsExactly(factory1.type, factory2.type)
84+
}
85+
86+
@Test fun `constructor throws on duplicates`() {
87+
val factory1 = TestViewFactory(FooRendering::class)
88+
val factory2 = TestViewFactory(FooRendering::class)
89+
90+
val error = assertFailsWith<IllegalStateException> {
91+
ViewRegistry(factory1, factory2)
92+
}
93+
assertThat(error).hasMessageThat()
94+
.endsWith("must not have duplicate entries.")
95+
assertThat(error).hasMessageThat()
96+
.contains(FooRendering::class.java.name)
97+
}
98+
99+
@Test fun `getFactoryFor works`() {
100+
val fooFactory = TestViewFactory(FooRendering::class)
101+
val registry = ViewRegistry(fooFactory)
102+
103+
val factory = registry.getEntryFor(FooRendering::class)
104+
assertThat(factory).isSameInstanceAs(fooFactory)
105+
}
106+
107+
@Test fun `getFactoryFor returns null on missing binding`() {
108+
val fooFactory = TestViewFactory(FooRendering::class)
109+
val registry = ViewRegistry(fooFactory)
110+
111+
assertThat(registry.getEntryFor(BarRendering::class)).isNull()
112+
}
113+
114+
@Test fun `buildView honors AndroidViewRendering`() {
115+
val registry = ViewRegistry()
116+
registry.buildView(ViewRendering)
117+
assertThat(ViewRendering.viewFactory.called).isTrue()
118+
}
119+
120+
@Test fun `buildView prefers registry entries to AndroidViewRendering`() {
121+
val registry = ViewRegistry(overrideViewRenderingFactory)
122+
registry.buildView(ViewRendering)
123+
assertThat(ViewRendering.viewFactory.called).isFalse()
124+
assertThat(overrideViewRenderingFactory.called).isTrue()
125+
}
126+
127+
@Test fun `ViewRegistry with no arguments infers type`() {
128+
val registry = ViewRegistry()
129+
assertTrue(registry.keys.isEmpty())
130+
}
131+
132+
private object FooRendering
133+
private object BarRendering
134+
private object BazRendering
135+
136+
private object ViewRendering : AndroidViewRendering<ViewRendering> {
137+
override val viewFactory: TestViewFactory<ViewRendering> = TestViewFactory(ViewRendering::class)
138+
}
139+
private val overrideViewRenderingFactory = TestViewFactory(ViewRendering::class)
140+
141+
private class TestRegistry(private val factories: Map<KClass<*>, ViewFactory<*>>) : ViewRegistry {
142+
constructor(keys: Set<KClass<*>>) : this(keys.associateWith { TestViewFactory(it) })
143+
144+
override val keys: Set<KClass<*>> get() = factories.keys
145+
146+
@Suppress("UNCHECKED_CAST")
147+
override fun <RenderingT : Any> getEntryFor(
148+
renderingType: KClass<out RenderingT>
149+
): Entry<RenderingT> = factories.getValue(renderingType) as Entry<RenderingT>
150+
}
151+
152+
@OptIn(WorkflowUiExperimentalApi::class)
153+
private fun <R : Any> ViewRegistry.buildView(rendering: R): View =
154+
buildView(rendering, ViewEnvironment(mapOf(ViewRegistry to this)), mock())
155+
156+
@OptIn(WorkflowUiExperimentalApi::class)
157+
private class TestViewFactory<R : Any>(override val type: KClass<R>) : ViewFactory<R> {
158+
var called = false
159+
160+
override fun buildView(
161+
initialRendering: R,
162+
initialViewEnvironment: ViewEnvironment,
163+
contextForNewView: Context,
164+
container: ViewGroup?
165+
): View {
166+
called = true
167+
return mock {
168+
on {
169+
getTag(eq(com.squareup.workflow1.ui.R.id.view_show_rendering_function))
170+
} doReturn (ShowRenderingTag(initialRendering, initialViewEnvironment, { _, _ -> }))
171+
}
172+
}
173+
}
174+
}

workflow-ui/core-android/src/test/java/com/squareup/workflow1/ui/TestViewFactory.kt

Lines changed: 0 additions & 34 deletions
This file was deleted.

workflow-ui/core-android/src/test/java/com/squareup/workflow1/ui/ViewRegistryTest.kt

Lines changed: 0 additions & 28 deletions
This file was deleted.
Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,30 +17,30 @@ internal class CompositeViewRegistryTest {
1717
fooBarRegistry + barBazRegistry
1818
}
1919
assertThat(error).hasMessageThat()
20-
.startsWith("Must not have duplicate entries: ")
20+
.startsWith("Must not have duplicate entries: ")
2121
assertThat(error).hasMessageThat()
22-
.contains(BarRendering::class.java.name)
22+
.contains(BarRendering::class.java.name)
2323
}
2424

2525
@Test fun `getFactoryFor delegates to composite registries`() {
26-
val fooFactory = TestViewFactory(FooRendering::class)
27-
val barFactory = TestViewFactory(BarRendering::class)
28-
val bazFactory = TestViewFactory(BazRendering::class)
26+
val fooFactory = TestEntry(FooRendering::class)
27+
val barFactory = TestEntry(BarRendering::class)
28+
val bazFactory = TestEntry(BazRendering::class)
2929
val fooBarRegistry = TestRegistry(
30-
mapOf(
31-
FooRendering::class to fooFactory,
32-
BarRendering::class to barFactory
33-
)
30+
mapOf(
31+
FooRendering::class to fooFactory,
32+
BarRendering::class to barFactory
33+
)
3434
)
3535
val bazRegistry = TestRegistry(factories = mapOf(BazRendering::class to bazFactory))
3636
val registry = fooBarRegistry + bazRegistry
3737

3838
assertThat(registry.getEntryFor(FooRendering::class))
39-
.isSameInstanceAs(fooFactory)
39+
.isSameInstanceAs(fooFactory)
4040
assertThat(registry.getEntryFor(BarRendering::class))
41-
.isSameInstanceAs(barFactory)
41+
.isSameInstanceAs(barFactory)
4242
assertThat(registry.getEntryFor(BazRendering::class))
43-
.isSameInstanceAs(bazFactory)
43+
.isSameInstanceAs(bazFactory)
4444
}
4545

4646
@Test fun `getFactoryFor returns null on missing registry`() {
@@ -56,19 +56,23 @@ internal class CompositeViewRegistryTest {
5656
val registry = fooBarRegistry + bazRegistry
5757

5858
assertThat(registry.keys).containsExactly(
59-
FooRendering::class,
60-
BarRendering::class,
61-
BazRendering::class
59+
FooRendering::class,
60+
BarRendering::class,
61+
BazRendering::class
6262
)
6363
}
6464

65+
private class TestEntry<T : Any>(
66+
override val type: KClass<in T>
67+
) : Entry<T>
68+
6569
private object FooRendering
6670
private object BarRendering
6771
private object BazRendering
6872

6973
@Suppress("DEPRECATION")
70-
private class TestRegistry(private val factories: Map<KClass<*>, ViewFactory<*>>) : ViewRegistry {
71-
constructor(keys: Set<KClass<*>>) : this(keys.associateWith { TestViewFactory(it) })
74+
private class TestRegistry(private val factories: Map<KClass<*>, Entry<*>>) : ViewRegistry {
75+
constructor(keys: Set<KClass<*>>) : this(keys.associateWith { TestEntry(it) })
7276

7377
override val keys: Set<KClass<*>> get() = factories.keys
7478

0 commit comments

Comments
 (0)