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.
*/
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 {
/**
* The target is trusted to an unlimited degree.
*/
@JvmStatic
fun unconstrained() : Depth {
return Depth(null)
}
fun unconstrained() = Depth(255)
/**
* The target is trusted to a limited degree.
@ -34,40 +34,35 @@ class Depth private constructor(val limit: Int?) : Comparable<Depth> {
*/
@JvmStatic
fun auto(limit: Int): Depth {
return if (limit == 255) {
unconstrained()
} else {
limited(limit)
require(limit in 0..255) {
"Trust depth MUST be a value between 0 and 255."
}
return Depth(limit)
}
}
/**
* Return true, if the [Depth] is unconstrained.
*/
fun isUnconstrained() : Boolean {
return limit == null
}
fun isUnconstrained() = limit == 255
/**
* The value of this Depth, as used in OpenPGP.
*
* Unlimited is 255.
*/
fun value(): Int {
return limit ?: 255
}
fun value() = limit
/**
* 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.
* @throws IllegalArgumentException if the [Depth] cannot be decreased any further
*/
fun decrease(value : Int) : Depth {
fun decrease(value: Int): Depth {
return if (isUnconstrained()) {
unconstrained()
} else {
if (limit!! >= value) {
if (limit >= value) {
limited(limit - value)
} else {
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].
*/
fun min(other: Depth) : Depth {
return if (compareTo(other) <= 0) {
this
} else {
fun min(other: Depth): Depth {
return if (limit > other.limit) {
other
} else {
this
}
}
override fun compareTo(other: Depth): Int {
return when (Pair(isUnconstrained(), other.isUnconstrained())) {
Pair(true, true) -> 0
Pair(true, false) -> 1
Pair(false, true) -> -1
else -> limit!!.compareTo(other.limit!!)
override fun compareTo(other: Int): Int {
return if (isUnconstrained()) {
// If this is unconstrained, it is bigger than `other`
1
} else {
limit.compareTo(other)
}
}
@ -103,11 +98,13 @@ class Depth private constructor(val limit: Int?) : Comparable<Depth> {
return limit == other.limit
}
override fun toString() : String {
return if (isUnconstrained()) { "unconstrained" } else { limit!!.toString() }
override fun toString(): String {
return if (isUnconstrained()) {
"unconstrained"
} else {
limit.toString()
}
}
override fun hashCode(): Int {
return limit ?: 0 // TODO: 255?
}
override fun hashCode() = limit
}

View File

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

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