diff --git a/CHANGELOG.md b/CHANGELOG.md index c6b234b..15260eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## 0.3.1 +* Add `hashCode()` and `equals` in `IpInterface` + ## 0.3.0 * Add methods in `IpAddressAndPrefix` interface for parsing `ByteArray` representing address and subnet mask in X509 `IpAddressName` * `fromX509Octets` diff --git a/cidre/api/android/cidre.api b/cidre/api/android/cidre.api index 84573ab..a191d38 100644 --- a/cidre/api/android/cidre.api +++ b/cidre/api/android/cidre.api @@ -210,6 +210,7 @@ public abstract class at/asitplus/cidre/IpFamily$RegexSpec { public abstract class at/asitplus/cidre/IpInterface : at/asitplus/cidre/IpAddressAndPrefix { public static final field Companion Lat/asitplus/cidre/IpInterface$Companion; public synthetic fun (ILat/asitplus/cidre/IpNetwork;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun equals (Ljava/lang/Object;)Z public fun getAddress ()Lat/asitplus/cidre/IpAddress; public fun getFamily ()Lat/asitplus/cidre/IpFamily; public fun getHostMask ()[B @@ -217,6 +218,7 @@ public abstract class at/asitplus/cidre/IpInterface : at/asitplus/cidre/IpAddres public final fun getNetwork ()Lat/asitplus/cidre/IpNetwork; public fun getNumberOfHostBits-pVg5ArA ()I public fun getPrefix-pVg5ArA ()I + public fun hashCode ()I public fun isLinkLocal ()Z public fun isLoopback ()Z public fun isMulticast ()Z diff --git a/cidre/api/cidre.klib.api b/cidre/api/cidre.klib.api index 37c4a33..97f2bac 100644 --- a/cidre/api/cidre.klib.api +++ b/cidre/api/cidre.klib.api @@ -331,6 +331,8 @@ sealed class <#A: kotlin/Number, #B: at.asitplus.cidre.byteops/CidrNumber<#B>> a open val prefix // at.asitplus.cidre/IpInterface.prefix|{}prefix[0] open fun (): kotlin/UInt // at.asitplus.cidre/IpInterface.prefix.|(){}[0] + open fun equals(kotlin/Any?): kotlin/Boolean // at.asitplus.cidre/IpInterface.equals|equals(kotlin.Any?){}[0] + open fun hashCode(): kotlin/Int // at.asitplus.cidre/IpInterface.hashCode|hashCode(){}[0] open fun toString(): kotlin/String // at.asitplus.cidre/IpInterface.toString|toString(){}[0] open fun toX509Octets(): kotlin/ByteArray // at.asitplus.cidre/IpInterface.toX509Octets|toX509Octets(){}[0] diff --git a/cidre/api/jvm/cidre.api b/cidre/api/jvm/cidre.api index 4bc3fb8..7d67b23 100644 --- a/cidre/api/jvm/cidre.api +++ b/cidre/api/jvm/cidre.api @@ -201,6 +201,7 @@ public abstract class at/asitplus/cidre/IpFamily$RegexSpec { public abstract class at/asitplus/cidre/IpInterface : at/asitplus/cidre/IpAddressAndPrefix { public static final field Companion Lat/asitplus/cidre/IpInterface$Companion; public synthetic fun (ILat/asitplus/cidre/IpNetwork;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun equals (Ljava/lang/Object;)Z public fun getAddress ()Lat/asitplus/cidre/IpAddress; public fun getFamily ()Lat/asitplus/cidre/IpFamily; public fun getHostMask ()[B @@ -208,6 +209,7 @@ public abstract class at/asitplus/cidre/IpInterface : at/asitplus/cidre/IpAddres public final fun getNetwork ()Lat/asitplus/cidre/IpNetwork; public fun getNumberOfHostBits-pVg5ArA ()I public fun getPrefix-pVg5ArA ()I + public fun hashCode ()I public fun isLinkLocal ()Z public fun isLoopback ()Z public fun isMulticast ()Z diff --git a/cidre/src/commonMain/kotlin/at/asitplus/cidre/IpInterface.kt b/cidre/src/commonMain/kotlin/at/asitplus/cidre/IpInterface.kt index 15f640d..f89f2d4 100644 --- a/cidre/src/commonMain/kotlin/at/asitplus/cidre/IpInterface.kt +++ b/cidre/src/commonMain/kotlin/at/asitplus/cidre/IpInterface.kt @@ -13,9 +13,28 @@ constructor(override val prefix: Prefix, val network: IpNetwork) : IpAddressAndPrefix by network { override fun toString(): String = "$address/$prefix" - override fun toX509Octets(): ByteArray = super.toX509Octets() + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as IpInterface<*, *> + + if (prefix != other.prefix) return false + if (network != other.network) return false + if (address != other.address) return false + + return true + } + + override fun hashCode(): Int { + var result = prefix.hashCode() + result = 31 * result + network.hashCode() + result = 31 * result + address.hashCode() + return result + } + companion object { @Suppress("UNCHECKED_CAST") internal fun > unsafe( diff --git a/cidre/src/jvmTest/kotlin/IpInterfaceEqualsTest.kt b/cidre/src/jvmTest/kotlin/IpInterfaceEqualsTest.kt new file mode 100644 index 0000000..31236c8 --- /dev/null +++ b/cidre/src/jvmTest/kotlin/IpInterfaceEqualsTest.kt @@ -0,0 +1,47 @@ +import at.asitplus.cidre.IpInterface +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotEquals + +class IpInterfaceEqualsTest { + + @Test + fun `IPv4 equals and hashCode`() { + val ip1 = IpInterface.V4("192.168.1.1/24") + val ip2 = IpInterface.V4("192.168.1.1/24") + val ip3 = IpInterface.V4("192.168.1.2/24") + val ip4 = IpInterface.V4("192.168.1.1/16") + + assertEquals(ip1, ip2, "Should be equal") + assertNotEquals(ip1, ip3, "Different addresses should not be equal") + assertNotEquals(ip1, ip4, "Different prefixes should not be equal") + + assertEquals(ip1.hashCode(), ip2.hashCode(), "Equal objects must have equal hashCodes") + assertNotEquals(ip1.hashCode(), ip3.hashCode(), "Should have different hashCodes") + assertNotEquals(ip1.hashCode(), ip4.hashCode(), "Should have different hashCodes") + } + + @Test + fun `IPv6 equals and hashCode`() { + val ip1 = IpInterface.V6("2001:db8::1/64") + val ip2 = IpInterface.V6("2001:db8::1/64") + val ip3 = IpInterface.V6("2001:db8::2/64") + val ip4 = IpInterface.V6("2001:db8::1/48") + + assertEquals(ip1, ip2, "Should be equal") + assertNotEquals(ip1, ip3, "Different addresses should not be equal") + assertNotEquals(ip1, ip4, "Different prefixes should not be equal") + + assertEquals(ip1.hashCode(), ip2.hashCode(), "Equal objects must have equal hashCodes") + assertNotEquals(ip1.hashCode(), ip3.hashCode(), "Should have different hashCodes") + assertNotEquals(ip1.hashCode(), ip4.hashCode(), "Should have different hashCodes") + } + + @Test + fun `IPv4 and IPv6 are not equal`() { + val ipv4 = IpInterface.V4("192.168.1.1/24") + val ipv6 = IpInterface.V6("2001:db8::1/64") + + assertNotEquals>(ipv4, ipv6, "IPv4 and IPv6 should never be equal") + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 78a8a66..d8244c6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ kotlin.mpp.enableCInteropCommonization=true kotlin.mpp.stability.nowarn=true kotlin.native.ignoreDisabledTargets=true -artifactVersion = 0.3.0 +artifactVersion = 0.3.1 org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled android.experimental.lint.version=8.9.3 android.lint.useK2Uast=true \ No newline at end of file