Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/smooth casting (closes #122) #127

Merged
merged 7 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,60 @@ sealed class Asn1Element(
return result
}

/**
* Convenience function to cast this element to an [Asn1Primitive]
* @throws Asn1StructuralException if this element is not a primitive
*/
@Throws(Asn1StructuralException::class)
fun asPrimitive() = thisAs<Asn1Primitive>()

/**
* Convenience function to cast this element to an [Asn1Structure]
* @throws Asn1StructuralException if this element is not a structure
*/
@Throws(Asn1StructuralException::class)
fun asStructure() = thisAs<Asn1Structure>()

/**
* Convenience function to cast this element to an [Asn1Sequence]
* @throws Asn1StructuralException if this element is not a sequence
*/
@Throws(Asn1StructuralException::class)
fun asSequence() = thisAs<Asn1Sequence>()

/**
* Convenience function to cast this element to an [Asn1Set]
* @throws Asn1StructuralException if this element is not a set
*/
@Throws(Asn1StructuralException::class)
fun asSet() = thisAs<Asn1Set>()

/**
* Convenience function to cast this element to an [Asn1Tagged]
* @throws Asn1StructuralException if this element is not an explicitly tagged structure
*/
@Throws(Asn1StructuralException::class)
fun asTagged() = thisAs<Asn1Tagged>()

/**
* Convenience function to cast this element to an [Asn1EncapsulatingOctetString]
* @throws Asn1StructuralException if this element is not an octet string containing a valid ASN.1 structure
*/
@Throws(Asn1StructuralException::class)
fun asEncapsulatingOctetString() = thisAs<Asn1EncapsulatingOctetString>()

/**
* Convenience function to cast this element to an [Asn1PrimitiveOctetString]
* @throws Asn1StructuralException if this element is not an octet string containing raw data
*/
@Throws(Asn1StructuralException::class)
fun asPrimitiveOctetString() = thisAs<Asn1PrimitiveOctetString>()

@Throws(Asn1StructuralException::class)
private inline fun <reified T : Asn1Element> thisAs(): T =
(this as? T)
?: throw Asn1StructuralException("${this::class.simpleName} cannot be reinterpreted as ${T::class.simpleName}.")

@Serializable
@ConsistentCopyVisibility
data class Tag private constructor(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ open class Asn1Exception(message: String?, cause: Throwable?) : Throwable(messag
class Asn1TagMismatchException(val expected: Asn1Element.Tag, val actual: Asn1Element.Tag, detailedMessage: String? = null) :
Asn1Exception((detailedMessage?.let { "$it " } ?: "") + "Expected tag $expected, is: $actual")

class Asn1StructuralException(message: String) : Asn1Exception(message)
class Asn1StructuralException(message: String, cause: Throwable? = null) : Asn1Exception(message, cause)

class Asn1OidException(message: String, val oid: ObjectIdentifier) : Asn1Exception(message)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package at.asitplus.signum.indispensable

import at.asitplus.signum.indispensable.asn1.Asn1
import at.asitplus.signum.indispensable.asn1.Asn1PrimitiveOctetString
import at.asitplus.signum.indispensable.asn1.Asn1StructuralException
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.FreeSpec
import io.kotest.matchers.shouldBe

class CastingTest : FreeSpec({

"Primitive" {
shouldThrow<Asn1StructuralException> { Asn1.Int(0).asSet() }
shouldThrow<Asn1StructuralException> { Asn1.Int(0).asTagged() }
shouldThrow<Asn1StructuralException> { Asn1.Int(0).asStructure() }
shouldThrow<Asn1StructuralException> { Asn1.Int(0).asSequence() }
shouldThrow<Asn1StructuralException> { Asn1.Int(0).asPrimitiveOctetString() }
shouldThrow<Asn1StructuralException> { Asn1.Int(0).asEncapsulatingOctetString() }
Asn1.Int(0).let { it.asPrimitive() shouldBe it }
}

"Set" {
shouldThrow<Asn1StructuralException> { Asn1.Set { +Asn1.Null() }.asSequence() }
shouldThrow<Asn1StructuralException> { Asn1.Set { +Asn1.Null() }.asTagged() }
shouldThrow<Asn1StructuralException> { Asn1.Set { +Asn1.Null() }.asPrimitiveOctetString() }
shouldThrow<Asn1StructuralException> { Asn1.Set { +Asn1.Null() }.asEncapsulatingOctetString() }

Asn1.Set { +Asn1.Null() }.let { it.asStructure() shouldBe it }
Asn1.Set { +Asn1.Null() }.let { it.asSet() shouldBe it }
}

"OctetString ENCAPSULATING" {
shouldThrow<Asn1StructuralException> { Asn1.OctetStringEncapsulating { +Asn1.Null() }.asSet() }
shouldThrow<Asn1StructuralException> { Asn1.OctetStringEncapsulating { +Asn1.Null() }.asTagged() }
shouldThrow<Asn1StructuralException> { Asn1.OctetStringEncapsulating { +Asn1.Null() }.asPrimitiveOctetString() }
shouldThrow<Asn1StructuralException> { Asn1.OctetStringEncapsulating { +Asn1.Null() }.asSequence() }

Asn1.OctetStringEncapsulating { +Asn1.Null() }.let { it.asEncapsulatingOctetString() shouldBe it }
Asn1.OctetStringEncapsulating { +Asn1.Null() }.let { it.asStructure() shouldBe it }
}


"OctetString PRIMITIVE" {
shouldThrow<Asn1StructuralException> { Asn1PrimitiveOctetString(byteArrayOf()).asSet() }
shouldThrow<Asn1StructuralException> { Asn1PrimitiveOctetString(byteArrayOf()).asStructure() }
shouldThrow<Asn1StructuralException> { Asn1PrimitiveOctetString(byteArrayOf()).asSequence() }
shouldThrow<Asn1StructuralException> { Asn1PrimitiveOctetString(byteArrayOf()).asTagged() }
shouldThrow<Asn1StructuralException> { Asn1PrimitiveOctetString(byteArrayOf()).asEncapsulatingOctetString() }
Asn1PrimitiveOctetString(byteArrayOf()).let { it.asPrimitiveOctetString() shouldBe it }
Asn1PrimitiveOctetString(byteArrayOf()).let { it.asPrimitive() shouldBe it }
}


"Custom Structure" {
shouldThrow<Asn1StructuralException> { Asn1.Tagged(19u) { +Asn1.Null() }.asSequence() }
shouldThrow<Asn1StructuralException> { Asn1.Tagged(19u) { +Asn1.Null() }.asSet() }
shouldThrow<Asn1StructuralException> { Asn1.Tagged(19u) { +Asn1.Null() }.asPrimitiveOctetString() }
shouldThrow<Asn1StructuralException> { Asn1.Tagged(19u) { +Asn1.Null() }.asEncapsulatingOctetString() }

Asn1.Tagged(19u) { +Asn1.Null() }.let { it.asStructure() shouldBe it }
Asn1.Tagged(19u) { +Asn1.Null() }.let { it.asTagged() shouldBe it }
}


})
Loading