Skip to content

Commit

Permalink
KotlinIoOscSource: add readOscTypeTag()
Browse files Browse the repository at this point in the history
  • Loading branch information
morisil committed Sep 11, 2024
1 parent 10c0db7 commit 5fac16e
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 28 deletions.
52 changes: 24 additions & 28 deletions xemantic-osc-api/src/commonMain/kotlin/io/KotlinIoOscSource.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,30 @@ import com.xemantic.osc.type.OscColor
import com.xemantic.osc.type.OscMidiMessage
import kotlinx.io.*

/**
* Removes bytes from this source interpreting them as OSC Type Tag.
* _Note: the initial comma described in the protocol is already stripped in returned string._
*
* See [Osc Type Tag String specification](https://ccrma.stanford.edu/groups/osc/spec-1_0.html#osc-type-tag-string)
*
* @return the OSC Type Tag String without leading comma character.
* @throws OscInputException if type tag doesn't exist or is malformed.
*/
public fun Source.readOscTypeTag(): String {
val head = readOscString()
if (head.isEmpty()) {
throw OscInputException(
"OSC type tag is empty"
)
}
if (head[0] != ',') {
throw OscInputException(
"OSC type tag must start with ,"
)
}
return head.substring(1)
}

/**
* Removes bytes from this source interpreting them as OSC String.
* The OSC String should be `0`-terminated and padded up to 4 bytes.
Expand Down Expand Up @@ -98,31 +122,3 @@ public inline fun Source.readOscColor(): OscColor =
@Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
public inline fun Source.readOscMidiMessage(): OscMidiMessage =
OscMidiMessage(readUInt())

/**
* Creates a [Source] from supplied bytes.
* Useful for testing.
*
* @param bytes the sequence of bytes.
*/
public fun Source(
vararg bytes: Byte,
): Source = Buffer().apply {
write(bytes)
}

/**
* Creates a [Source] from supplied chars.
* Useful for testing.
*
* @param chars the sequence of characters.
*/
public fun Source(
vararg chars: Char
): Source = Buffer().apply {
write(
chars.map {
it.code.toByte()
}.toByteArray()
)
}
25 changes: 25 additions & 0 deletions xemantic-osc-api/src/commonTest/kotlin/io/KotlinIoOscSourceTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ package com.xemantic.osc.io

import com.xemantic.osc.OscInputException
import com.xemantic.osc.type.OscTimeTag
import com.xemantic.osc.util.Source
import com.xemantic.osc.util.ZERO
import com.xemantic.osc.util.emptySource
import io.kotest.assertions.throwables.shouldThrowWithMessage
import io.kotest.matchers.shouldBe
import kotlinx.io.Buffer
Expand All @@ -29,6 +31,29 @@ import kotlin.test.Test

class KotlinIoOscSourceTest {

@Test
fun shouldReadOscTypeTag() {
Source(',', 'i', ZERO, ZERO).readOscTypeTag() shouldBe "i"
}

@Test
fun shouldNotReadEmptyOscTypeTag() {
shouldThrowWithMessage<OscInputException>(
"Cannot read OSC String, because byte sequence is not 0-terminated"
) {
emptySource().readOscTypeTag()
}
}

@Test
fun shouldNotReadOscTypeTagWhichDoesNotStartWithComma() {
shouldThrowWithMessage<OscInputException>(
"OSC type tag must start with ,"
) {
Source('i', ZERO, ZERO, ZERO).readOscTypeTag()
}
}

@Test
fun shouldReadEmptyOscString() {
Source(0, 0, 0, 0).apply {
Expand Down

0 comments on commit 5fac16e

Please sign in to comment.