1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-12-25 04:17:59 +01:00

Depth: change internal representation and API, implement Comparable<Int>

This commit is contained in:
Heiko Schaefer 2023-07-14 21:08:13 +02:00
parent 95f5f58843
commit 65ff597f58
No known key found for this signature in database
GPG key ID: 4A849A1904CCBD7D
4 changed files with 57 additions and 52 deletions

View file

@ -7,16 +7,16 @@ package org.pgpainless.wot.network
/** /**
* Depth of a trust signature. * Depth of a trust signature.
*/ */
class Depth private constructor(val limit: Int?) : Comparable<Depth> { class Depth private constructor(private val limit: Int) : Comparable<Int> {
// Uses a byte for internal representation, like in the OpenPGP "Trust Signature" subpacket
companion object { companion object {
/** /**
* The target is trusted to an unlimited degree. * The target is trusted to an unlimited degree.
*/ */
@JvmStatic @JvmStatic
fun unconstrained() : Depth { fun unconstrained() = Depth(255)
return Depth(null)
}
/** /**
* The target is trusted to a limited degree. * The target is trusted to a limited degree.
@ -34,40 +34,35 @@ class Depth private constructor(val limit: Int?) : Comparable<Depth> {
*/ */
@JvmStatic @JvmStatic
fun auto(limit: Int): Depth { fun auto(limit: Int): Depth {
return if (limit == 255) { require(limit in 0..255) {
unconstrained() "Trust depth MUST be a value between 0 and 255."
} else {
limited(limit)
} }
return Depth(limit)
} }
} }
/** /**
* Return true, if the [Depth] is unconstrained. * Return true, if the [Depth] is unconstrained.
*/ */
fun isUnconstrained() : Boolean { fun isUnconstrained() = limit == 255
return limit == null
}
/** /**
* The value of this Depth, as used in OpenPGP. * The value of this Depth, as used in OpenPGP.
* *
* Unlimited is 255. * Unlimited is 255.
*/ */
fun value(): Int { fun value() = limit
return limit ?: 255
}
/** /**
* Decrease the trust depth by one and return the result. * Decrease the trust depth by `value` and return the result.
* If the [Depth] is unconstrained, the result will still be unconstrained. * If the [Depth] is unconstrained, the result will still be unconstrained.
* @throws IllegalArgumentException if the [Depth] cannot be decreased any further * @throws IllegalArgumentException if the [Depth] cannot be decreased any further
*/ */
fun decrease(value : Int) : Depth { fun decrease(value: Int): Depth {
return if (isUnconstrained()) { return if (isUnconstrained()) {
unconstrained() unconstrained()
} else { } else {
if (limit!! >= value) { if (limit >= value) {
limited(limit - value) limited(limit - value)
} else { } else {
throw IllegalArgumentException("Depth cannot be decreased.") throw IllegalArgumentException("Depth cannot be decreased.")
@ -78,20 +73,20 @@ class Depth private constructor(val limit: Int?) : Comparable<Depth> {
/** /**
* Return the minimum [Depth] of this and the other [Depth]. * Return the minimum [Depth] of this and the other [Depth].
*/ */
fun min(other: Depth) : Depth { fun min(other: Depth): Depth {
return if (compareTo(other) <= 0) { return if (limit > other.limit) {
this
} else {
other other
} else {
this
} }
} }
override fun compareTo(other: Depth): Int { override fun compareTo(other: Int): Int {
return when (Pair(isUnconstrained(), other.isUnconstrained())) { return if (isUnconstrained()) {
Pair(true, true) -> 0 // If this is unconstrained, it is bigger than `other`
Pair(true, false) -> 1 1
Pair(false, true) -> -1 } else {
else -> limit!!.compareTo(other.limit!!) limit.compareTo(other)
} }
} }
@ -103,11 +98,13 @@ class Depth private constructor(val limit: Int?) : Comparable<Depth> {
return limit == other.limit return limit == other.limit
} }
override fun toString() : String { override fun toString(): String {
return if (isUnconstrained()) { "unconstrained" } else { limit!!.toString() } return if (isUnconstrained()) {
"unconstrained"
} else {
limit.toString()
}
} }
override fun hashCode(): Int { override fun hashCode() = limit
return limit ?: 0 // TODO: 255?
}
} }

View file

@ -33,11 +33,11 @@ data class EdgeComponent(
) { ) {
override fun toString(): String { override fun toString(): String {
return if (trustDepth.limit == 0) return if (trustDepth > 0) {
"${issuer.fingerprint} certifies binding: $userId <-> ${target.fingerprint} [$trustAmount]"
else {
val scope = if (regexes.regexStrings.isEmpty()) "" else ", scope: $regexes" val scope = if (regexes.regexStrings.isEmpty()) "" else ", scope: $regexes"
"${issuer.fingerprint} delegates to ${target.fingerprint} [$trustAmount, depth $trustDepth$scope]" "${issuer.fingerprint} delegates to ${target.fingerprint} [$trustAmount, depth $trustDepth$scope]"
} else {
"${issuer.fingerprint} certifies binding: $userId <-> ${target.fingerprint} [$trustAmount]"
} }
} }
} }

View file

@ -97,7 +97,7 @@ class Path(
require(target.fingerprint == nComponent.issuer.fingerprint) { require(target.fingerprint == nComponent.issuer.fingerprint) {
"Cannot append edge to path: Path's tail is not issuer of the edge." "Cannot append edge to path: Path's tail is not issuer of the edge."
} }
require(residualDepth.isUnconstrained() || residualDepth.limit!! > 0) { require(residualDepth > 0) {
"Not enough depth." "Not enough depth."
} }

View file

@ -9,7 +9,10 @@ import org.junit.jupiter.api.assertThrows
import org.pgpainless.wot.network.Depth.Companion.auto import org.pgpainless.wot.network.Depth.Companion.auto
import org.pgpainless.wot.network.Depth.Companion.limited import org.pgpainless.wot.network.Depth.Companion.limited
import org.pgpainless.wot.network.Depth.Companion.unconstrained import org.pgpainless.wot.network.Depth.Companion.unconstrained
import kotlin.test.* import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
class DepthTest { class DepthTest {
@ -22,14 +25,15 @@ class DepthTest {
@Test @Test
fun `verify Depth#unconstrained() has null depth`() { fun `verify Depth#unconstrained() has null depth`() {
val depth = unconstrained() val depth = unconstrained()
assertNull(depth.limit) assert(depth.isUnconstrained())
assertEquals(depth.value(), 255)
} }
@Test @Test
fun `verify Depth#limited(2) initializes properly`() { fun `verify Depth#limited(2) initializes properly`() {
val limited = limited(2) val limited = limited(2)
assertNotNull(limited.limit) assert(!limited.isUnconstrained())
assertEquals(2, limited.limit) assertEquals(2, limited.value())
} }
@Test @Test
@ -50,7 +54,7 @@ class DepthTest {
val limited = limited(3) val limited = limited(3)
val decreased = limited.decrease(2) val decreased = limited.decrease(2)
assertFalse(decreased.isUnconstrained()) assertFalse(decreased.isUnconstrained())
assertEquals(1, decreased.limit) assertEquals(1, decreased.value())
} }
@Test @Test
@ -63,17 +67,21 @@ class DepthTest {
@Test @Test
fun `verify proper function of compareTo()`() { fun `verify proper function of compareTo()`() {
val unlimited = unconstrained() val unlimited = unconstrained()
val unlimited2 = unconstrained()
val depth2 = limited(2) val depth2 = limited(2)
val depth2_ = limited(2)
val depth5 = limited(5) val depth5 = limited(5)
assertEquals(0, unlimited.compareTo(unlimited2)) assertTrue(unlimited > 0)
assertTrue(unlimited.compareTo(depth2) > 0) assertTrue(unlimited > 255)
assertTrue(unlimited.compareTo(depth5) > 0) assertTrue(unlimited > 256)
assertTrue(depth2.compareTo(unlimited) < 0)
assertTrue(depth2.compareTo(depth5) < 0) assertTrue(depth2 > 0)
assertTrue(depth5.compareTo(depth2) > 0) assertTrue(depth2 > 1)
assertEquals(0, depth2.compareTo(depth2_)) assertFalse(depth2 > 2)
assertFalse(depth2 > 256)
assertTrue(depth5 > 1)
assertTrue(depth5 > 4)
assertFalse(depth5 > 5)
assertFalse(depth5 > 256)
} }
@Test @Test
@ -108,7 +116,7 @@ class DepthTest {
@Test @Test
fun `verify that Depth#auto(255) yields an unconstrained Depth`() { fun `verify that Depth#auto(255) yields an unconstrained Depth`() {
assertTrue { auto(255).isUnconstrained() } assertTrue { auto(255).isUnconstrained() }
assertNull(auto(255).limit) assertEquals(auto(255).value(), 255)
} }
@Test @Test
@ -117,7 +125,7 @@ class DepthTest {
assertFalse { auto(120).isUnconstrained() } assertFalse { auto(120).isUnconstrained() }
assertFalse { auto(254).isUnconstrained() } assertFalse { auto(254).isUnconstrained() }
assertNotNull(auto(42).limit) assertNotNull(auto(42).value())
} }
@Test @Test