Commit 13b9a166 authored by Sebastian Kaspari's avatar Sebastian Kaspari Committed by Christian Sadilek
Browse files

ObserverRegistry: Add more test cases.

parent 5bd226d3
......@@ -5,6 +5,7 @@
package mozilla.components.support.base.observer
import android.view.View
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.Lifecycle.Event.ON_DESTROY
import androidx.lifecycle.Lifecycle.Event.ON_PAUSE
import androidx.lifecycle.Lifecycle.Event.ON_RESUME
......@@ -22,6 +23,7 @@ import java.util.WeakHashMap
*
* ObserverRegistry is thread-safe.
*/
@Suppress("TooManyFunctions")
class ObserverRegistry<T> : Observable<T> {
private val observers = mutableSetOf<T>()
private val lifecycleObservers = WeakHashMap<T, LifecycleBoundObserver<T>>()
......@@ -90,7 +92,7 @@ class ObserverRegistry<T> : Observable<T> {
lifecycleObservers[observer]?.remove()
viewObservers[observer]?.remove()
// Remove lifecyle/view observers from map
// Remove lifecycle/view observers from map
lifecycleObservers.remove(observer)
viewObservers.remove(observer)
}
......@@ -109,10 +111,7 @@ class ObserverRegistry<T> : Observable<T> {
}
// If any of our sets and maps is not empty now then this would be a serious bug.
check(observers.isEmpty())
check(pausedObservers.isEmpty())
check(lifecycleObservers.isEmpty())
check(viewObservers.isEmpty())
checkInternalCollectionsAreEmpty()
}
@Synchronized
......@@ -152,6 +151,15 @@ class ObserverRegistry<T> : Observable<T> {
return observers.isNotEmpty() || viewObservers.isNotEmpty()
}
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
internal fun checkInternalCollectionsAreEmpty(): Boolean {
check(observers.isEmpty())
check(pausedObservers.isEmpty())
check(lifecycleObservers.isEmpty())
check(viewObservers.isEmpty())
return true
}
/**
* LifecycleObserver implementation to bind an observer to a Lifecycle.
*/
......
......@@ -71,6 +71,8 @@ class ObserverRegistryTest {
}
assertFalse(observer.notified)
assertTrue(registry.checkInternalCollectionsAreEmpty())
}
@Test
......@@ -112,6 +114,8 @@ class ObserverRegistryTest {
}
assertFalse(observer.notified)
assertTrue(registry.checkInternalCollectionsAreEmpty())
}
@Test
......@@ -130,6 +134,8 @@ class ObserverRegistryTest {
}
assertFalse(observer.notified)
assertTrue(registry.checkInternalCollectionsAreEmpty())
}
@Test
......@@ -152,6 +158,8 @@ class ObserverRegistryTest {
observer.notified = false
registry.notifyObservers { somethingChanged() }
assertFalse(observer.notified)
assertTrue(registry.checkInternalCollectionsAreEmpty())
}
@Test
......@@ -221,6 +229,8 @@ class ObserverRegistryTest {
assertFalse(observer2.notified)
assertFalse(observer3.notified)
assertFalse(observer4.notified)
assertTrue(registry.checkInternalCollectionsAreEmpty())
}
@Test
......@@ -240,6 +250,8 @@ class ObserverRegistryTest {
registry.unregisterObservers()
assertFalse(registry.isObserved())
assertTrue(registry.checkInternalCollectionsAreEmpty())
}
@Test
......@@ -248,7 +260,9 @@ class ObserverRegistryTest {
val observer = "Observer"
registry.unregister(observer)
assertFalse(registry.isObserved())
assertTrue(registry.checkInternalCollectionsAreEmpty())
}
@Test
......@@ -261,6 +275,7 @@ class ObserverRegistryTest {
registry.unregister(observer)
assertFalse(registry.isObserved())
assertTrue(registry.checkInternalCollectionsAreEmpty())
}
@Test
......@@ -273,6 +288,7 @@ class ObserverRegistryTest {
registry.unregister(observer)
assertFalse(registry.isObserved())
assertTrue(registry.checkInternalCollectionsAreEmpty())
}
@Test
......@@ -354,6 +370,8 @@ class ObserverRegistryTest {
}
assertFalse(observer.notified)
assertTrue(registry.checkInternalCollectionsAreEmpty())
}
@Test
......@@ -369,6 +387,25 @@ class ObserverRegistryTest {
registry.unregisterObservers()
verify(view).removeOnAttachStateChangeListener(any())
assertTrue(registry.checkInternalCollectionsAreEmpty())
}
@Test
fun `unregisterObserver will remove attach listener`() {
val view: View = mock()
doReturn(true).`when`(view).isAttachedToWindow
val registry = ObserverRegistry<TestObserver>()
val observer = TestObserver()
registry.register(observer, view)
verify(view).addOnAttachStateChangeListener(any())
registry.unregister(observer)
verify(view).removeOnAttachStateChangeListener(any())
assertTrue(registry.checkInternalCollectionsAreEmpty())
}
@Test
......@@ -514,7 +551,7 @@ class ObserverRegistryTest {
@Test
fun `isObserved is true if observers is empty`() {
val registry = spy(ObserverRegistry<TestIntObserver>())
val registry = ObserverRegistry<TestIntObserver>()
val observer = TestIntObserver()
assertFalse(registry.isObserved())
......@@ -528,6 +565,27 @@ class ObserverRegistryTest {
assertFalse(registry.isObserved())
}
@Test
fun `isObserved is true if there is still a view observer that may register an observer for a view`() {
val registry = ObserverRegistry<TestIntObserver>()
val observer: TestIntObserver = mock()
val view: View = mock()
doReturn(false).`when`(view).isAttachedToWindow
registry.register(observer, view)
// observer is not registered since the view is not attached yet
registry.notifyObservers { somethingChanged(42) }
verify(observer, never()).somethingChanged(42)
// But it still counts as being observed
assertTrue(registry.isObserved())
registry.unregister(observer)
assertFalse(registry.isObserved())
}
private class TestObserver {
var notified: Boolean = false
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment