From 5247fb4b48329d1525e7b2537a81c29ddfb102fe Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Tue, 6 Dec 2022 22:40:01 +0100 Subject: [PATCH] =?utf8?q?=F0=9F=9A=A7=20Add=20no-negative=20identity=20fi?= =?utf8?q?lter?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This mirrors exactly what the IdentityManager already does but it adds a test! --- .../sone/freenet/wot/NoNegativeIdentityFilter.kt | 37 +++++++++ .../freenet/wot/NoNegativeIdentityFilterTest.kt | 87 ++++++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 src/main/kotlin/net/pterodactylus/sone/freenet/wot/NoNegativeIdentityFilter.kt create mode 100644 src/test/kotlin/net/pterodactylus/sone/freenet/wot/NoNegativeIdentityFilterTest.kt diff --git a/src/main/kotlin/net/pterodactylus/sone/freenet/wot/NoNegativeIdentityFilter.kt b/src/main/kotlin/net/pterodactylus/sone/freenet/wot/NoNegativeIdentityFilter.kt new file mode 100644 index 0000000..44468f2 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/freenet/wot/NoNegativeIdentityFilter.kt @@ -0,0 +1,37 @@ +package net.pterodactylus.sone.freenet.wot + +/** + * Filter for identities that retains only those remote identities that do + * not have a single negative trust value (explicit or implicit) from any own + * identity. + */ +class NoNegativeIdentityFilter { + + fun filter(identities: Map>) = + identities.run { + val identitiesWithTrust = values.flatten() + .groupBy { it.id } + .mapValues { (_, identities) -> + identities.reduce { accIdentity, identity -> + identity.trust.forEach { (ownIdentity: OwnIdentity?, trust: Trust?) -> + accIdentity.setTrust(ownIdentity, trust) + } + accIdentity + } + } + + mapValues { (_, trustedIdentities) -> + trustedIdentities.filter { trustedIdentity -> + identitiesWithTrust[trustedIdentity.id]!!.trust.all { it.value.hasZeroOrPositiveTrust() } + } + } + } + +} + +private fun Trust.hasZeroOrPositiveTrust() = + if (explicit == null) { + implicit == null || implicit >= 0 + } else { + explicit >= 0 + } diff --git a/src/test/kotlin/net/pterodactylus/sone/freenet/wot/NoNegativeIdentityFilterTest.kt b/src/test/kotlin/net/pterodactylus/sone/freenet/wot/NoNegativeIdentityFilterTest.kt new file mode 100644 index 0000000..05c627c --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/freenet/wot/NoNegativeIdentityFilterTest.kt @@ -0,0 +1,87 @@ +package net.pterodactylus.sone.freenet.wot + +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.containsInAnyOrder +import org.hamcrest.Matchers.empty +import org.junit.Test + +class NoNegativeIdentityFilterTest { + + @Test + fun `filter retains all identities with an explicit trust larger than or equal to 0`() { + val allIdentities = mapOf( + ownIdentity1.trust(identityA to trustExplicitely(50), identityB to trustExplicitely(0), identityC to trustExplicitely(-50)) + ) + val filteredIdentities = filter.filter(allIdentities) + assertThat(filteredIdentities[ownIdentity1]!!, containsInAnyOrder(identityA, identityB)) + } + + @Test + fun `filter retains all identities with an implicit trust larger than or equal to 0`() { + val allIdentities = mapOf( + ownIdentity1.trust(identityA to trustImplicitely(50), identityB to trustImplicitely(0), identityC to trustImplicitely(-50)) + ) + val filteredIdentities = filter.filter(allIdentities) + assertThat(filteredIdentities[ownIdentity1]!!, containsInAnyOrder(identityA, identityB)) + } + + @Test + fun `filter retains all identities with an explicit trust larger than or equal to 0 from all local identities that know that remote identity`() { + val allIdentities = mapOf( + ownIdentity1.trust(identityA to trustExplicitely(50), identityB to trustExplicitely(0)), + ownIdentity2.trust(identityA to trustExplicitely(50), identityC to trustExplicitely(0)) + ) + val filteredIdentities = filter.filter(allIdentities) + assertThat(filteredIdentities[ownIdentity1]!!, containsInAnyOrder(identityA, identityB)) + assertThat(filteredIdentities[ownIdentity2]!!, containsInAnyOrder(identityA, identityC)) + } + + @Test + fun `filter retains all identities with an implicit trust larger than or equal to 0 from all local identities that know that remote identity`() { + val allIdentities = mapOf( + ownIdentity1.trust(identityA to trustImplicitely(50), identityB to trustImplicitely(0)), + ownIdentity2.trust(identityA to trustImplicitely(50), identityC to trustImplicitely(0)) + ) + val filteredIdentities = filter.filter(allIdentities) + assertThat(filteredIdentities[ownIdentity1]!!, containsInAnyOrder(identityA, identityB)) + assertThat(filteredIdentities[ownIdentity2]!!, containsInAnyOrder(identityA, identityC)) + } + + @Test + fun `strict filter removes all identities that have an explicit negative value for any of the local identities`() { + val allIdentities = mapOf( + ownIdentity1.trust(identityA to trustExplicitely(50), identityB to trustExplicitely(50)), + ownIdentity2.trust(identityB to trustExplicitely(-50)) + ) + val filteredIdentities = filter.filter(allIdentities) + assertThat(filteredIdentities[ownIdentity1]!!, containsInAnyOrder(identityA)) + assertThat(filteredIdentities[ownIdentity2]!!, empty()) + } + + @Test + fun `strict filter removes all identities that have an implicit negative value for any of the local identities`() { + val allIdentities = mapOf( + ownIdentity1.trust(identityA to trustExplicitely(50), identityB to trustExplicitely(50)), + ownIdentity2.trust(identityB to trustImplicitely(-50)) + ) + val filteredIdentities = filter.filter(allIdentities) + assertThat(filteredIdentities[ownIdentity1]!!, containsInAnyOrder(identityA)) + assertThat(filteredIdentities[ownIdentity2]!!, empty()) + } + + private val filter = NoNegativeIdentityFilter() + private val ownIdentity1 = createOwnIdentity("1") + private val ownIdentity2 = createOwnIdentity("2") + private val identityA = createIdentity("A") + private val identityB = createIdentity("B") + private val identityC = createIdentity("C") + +} + +private fun OwnIdentity.trust(vararg identityTrust: Pair) = + this to identityTrust.map { (identity, trust) -> identity.copy().setTrust(this, trust) }.toSet() + +private fun Identity.copy() = DefaultIdentity(id, nickname, requestUri).apply { + contexts = this@copy.contexts + properties = this@copy.properties +} -- 2.7.4