Skip to content

Commit

Permalink
Adopt Burst for parameterized tests
Browse files Browse the repository at this point in the history
It supports Kotlin/Multiplatform.

https://github.com/cashapp/burst
  • Loading branch information
squarejesse committed Oct 16, 2024
1 parent 9bd8436 commit 0d4b0e4
Show file tree
Hide file tree
Showing 18 changed files with 336 additions and 532 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.classpath
.gradle
.kotlin
.project
.settings
eclipsebin
Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ plugins {
buildscript {
dependencies {
classpath(libs.android.gradle.plugin)
classpath(libs.burst.gradle.plugin)
classpath(libs.dokka)
classpath(libs.jmh.gradle.plugin)
classpath(libs.binaryCompatibilityValidator)
Expand Down
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ android-desugar-jdk-libs = { module = "com.android.tools:desugar_jdk_libs", vers
androidx-test-ext-junit = { module = "androidx.test.ext:junit", version = "1.2.1" }
androidx-test-runner = { module = "androidx.test:runner", version = "1.5.2" }
binaryCompatibilityValidator = { module = "org.jetbrains.kotlinx.binary-compatibility-validator:org.jetbrains.kotlinx.binary-compatibility-validator.gradle.plugin", version = "0.16.3" }
burst-gradle-plugin = { module = "app.cash.burst:burst-gradle-plugin", version = "0.3.0" }
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test" }
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit" }
kotlin-time = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version = "0.6.1" }
Expand Down
1 change: 1 addition & 0 deletions okio/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.TestExecutable

plugins {
kotlin("multiplatform")
id("app.cash.burst")
id("org.jetbrains.dokka")
id("com.vanniktech.maven.publish.base")
id("build-support")
Expand Down
222 changes: 101 additions & 121 deletions okio/src/commonTest/kotlin/okio/BufferedSourceFactory.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,135 +16,115 @@

package okio

interface BufferedSourceFactory {
class Pipe(
var sink: BufferedSink,
var source: BufferedSource,
)

val isOneByteAtATime: Boolean

fun pipe(): Pipe

companion object {
val BUFFER: BufferedSourceFactory = object : BufferedSourceFactory {

override val isOneByteAtATime: Boolean
get() = false

override fun pipe(): Pipe {
val buffer = Buffer()
return Pipe(
buffer,
buffer,
)
}
enum class BufferedSourceFactory {
BUFFER {
override val isOneByteAtATime: Boolean
get() = false

override fun pipe(): Pipe {
val buffer = Buffer()
return Pipe(
buffer,
buffer,
)
}

val REAL_BUFFERED_SOURCE: BufferedSourceFactory = object :
BufferedSourceFactory {

override val isOneByteAtATime: Boolean
get() = false

override fun pipe(): Pipe {
val buffer = Buffer()
return Pipe(
buffer,
(buffer as Source).buffer(),
)
}
},

REAL_BUFFERED_SOURCE {
override val isOneByteAtATime: Boolean
get() = false

override fun pipe(): Pipe {
val buffer = Buffer()
return Pipe(
buffer,
(buffer as Source).buffer(),
)
}

/**
* A factory deliberately written to create buffers whose internal segments are always 1 byte
* long. We like testing with these segments because are likely to trigger bugs!
*/
val ONE_BYTE_AT_A_TIME_BUFFERED_SOURCE: BufferedSourceFactory = object :
BufferedSourceFactory {

override val isOneByteAtATime: Boolean
get() = true

override fun pipe(): Pipe {
val buffer = Buffer()
return Pipe(
buffer,
object : Source by buffer {
override fun read(sink: Buffer, byteCount: Long): Long {
// Read one byte into a new buffer, then clone it so that the segment is shared.
// Shared segments cannot be compacted so we'll get a long chain of short segments.
},

/**
* A factory deliberately written to create buffers whose internal segments are always 1 byte
* long. We like testing with these segments because are likely to trigger bugs!
*/
ONE_BYTE_AT_A_TIME_BUFFERED_SOURCE {
override val isOneByteAtATime: Boolean
get() = true

override fun pipe(): Pipe {
val buffer = Buffer()
return Pipe(
buffer,
object : Source by buffer {
override fun read(sink: Buffer, byteCount: Long): Long {
// Read one byte into a new buffer, then clone it so that the segment is shared.
// Shared segments cannot be compacted so we'll get a long chain of short segments.
val box = Buffer()
val result = buffer.read(box, minOf(byteCount, 1L))
if (result > 0L) sink.write(box.copy(), result)
return result
}
}.buffer(),
)
}
},

ONE_BYTE_AT_A_TIME_BUFFER {
override val isOneByteAtATime: Boolean
get() = true

override fun pipe(): Pipe {
val buffer = Buffer()
return Pipe(
object : Sink by buffer {
override fun write(source: Buffer, byteCount: Long) {
// Write each byte into a new buffer, then clone it so that the segments are shared.
// Shared segments cannot be compacted so we'll get a long chain of short segments.
for (i in 0 until byteCount) {
val box = Buffer()
val result = buffer.read(box, minOf(byteCount, 1L))
if (result > 0L) sink.write(box.copy(), result)
return result
box.write(source, 1)
buffer.write(box.copy(), 1)
}
}.buffer(),
)
}
}
}.buffer(),
buffer,
)
}

val ONE_BYTE_AT_A_TIME_BUFFER: BufferedSourceFactory = object :
BufferedSourceFactory {

override val isOneByteAtATime: Boolean
get() = true

override fun pipe(): Pipe {
val buffer = Buffer()
return Pipe(
object : Sink by buffer {
override fun write(source: Buffer, byteCount: Long) {
// Write each byte into a new buffer, then clone it so that the segments are shared.
// Shared segments cannot be compacted so we'll get a long chain of short segments.
for (i in 0 until byteCount) {
val box = Buffer()
box.write(source, 1)
buffer.write(box.copy(), 1)
}
}
}.buffer(),
buffer,
)
}
},

PEEK_BUFFER {
override val isOneByteAtATime: Boolean
get() = false

override fun pipe(): Pipe {
val buffer = Buffer()
return Pipe(
buffer,
buffer.peek(),
)
}

val PEEK_BUFFER: BufferedSourceFactory = object : BufferedSourceFactory {

override val isOneByteAtATime: Boolean
get() = false

override fun pipe(): Pipe {
val buffer = Buffer()
return Pipe(
buffer,
buffer.peek(),
)
}
},

PEEK_BUFFERED_SOURCE {
override val isOneByteAtATime: Boolean
get() = false

override fun pipe(): Pipe {
val buffer = Buffer()
return Pipe(
buffer,
(buffer as Source).buffer().peek(),
)
}
},
;

val PEEK_BUFFERED_SOURCE: BufferedSourceFactory = object :
BufferedSourceFactory {
abstract val isOneByteAtATime: Boolean

override val isOneByteAtATime: Boolean
get() = false
abstract fun pipe(): Pipe

override fun pipe(): Pipe {
val buffer = Buffer()
return Pipe(
buffer,
(buffer as Source).buffer().peek(),
)
}
}

val PARAMETERIZED_TEST_VALUES = mutableListOf<Array<Any>>(
arrayOf(BUFFER),
arrayOf(REAL_BUFFERED_SOURCE),
arrayOf(ONE_BYTE_AT_A_TIME_BUFFERED_SOURCE),
arrayOf(ONE_BYTE_AT_A_TIME_BUFFER),
arrayOf(PEEK_BUFFER),
arrayOf(PEEK_BUFFERED_SOURCE),
)
}
class Pipe(
var sink: BufferedSink,
var source: BufferedSource,
)
}
12 changes: 2 additions & 10 deletions okio/src/jvmTest/kotlin/okio/AwaitSignalTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package okio

import app.cash.burst.Burst
import java.io.InterruptedIOException
import java.util.concurrent.TimeUnit
import java.util.concurrent.locks.Condition
Expand All @@ -25,11 +26,8 @@ import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Assert.fail
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import org.junit.runners.Parameterized.Parameters

@RunWith(Parameterized::class)
@Burst
class AwaitSignalTest(
factory: TimeoutFactory,
) {
Expand Down Expand Up @@ -215,10 +213,4 @@ class AwaitSignalTest(
TimeUnit.MILLISECONDS,
)
}

companion object {
@Parameters(name = "{0}")
@JvmStatic
fun parameters(): List<Array<out Any?>> = TimeoutFactory.entries.map { arrayOf(it) }
}
}
21 changes: 5 additions & 16 deletions okio/src/jvmTest/kotlin/okio/BufferCursorKotlinTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package okio

import app.cash.burst.Burst
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotSame
Expand All @@ -24,23 +25,11 @@ import okio.Buffer.UnsafeCursor
import okio.TestUtil.deepCopy
import org.junit.Assume.assumeTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import org.junit.runners.Parameterized.Parameter
import org.junit.runners.Parameterized.Parameters

@RunWith(Parameterized::class)
class BufferCursorKotlinTest {
companion object {
@Parameters(name = "{0}")
@JvmStatic
fun parameters(): List<Array<out Any?>> {
return BufferFactory.values().map { arrayOf(it) }
}
}

@Parameter lateinit var bufferFactory: BufferFactory

@Burst
class BufferCursorKotlinTest(
private val bufferFactory: BufferFactory,
) {
@Test fun acquireReadOnlyDoesNotCopySharedDataArray() {
val buffer = deepCopy(bufferFactory.newBuffer())
assumeTrue(buffer.size > 0L)
Expand Down
18 changes: 2 additions & 16 deletions okio/src/jvmTest/kotlin/okio/BufferCursorTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package okio

import app.cash.burst.Burst
import java.util.Arrays
import okio.ByteString.Companion.of
import okio.TestUtil.SEGMENT_SIZE
Expand All @@ -27,11 +28,8 @@ import org.junit.Assert.assertNull
import org.junit.Assert.fail
import org.junit.Assume.assumeTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import org.junit.runners.Parameterized.Parameters

@RunWith(Parameterized::class)
@Burst
class BufferCursorTest(
private var bufferFactory: BufferFactory,
) {
Expand Down Expand Up @@ -444,16 +442,4 @@ class BufferCursorTest(
assertEquals(originalSize, cursor.offset)
}
}

companion object {
@JvmStatic
@Parameters(name = "{0}")
fun parameters(): List<Array<Any>> {
val result = mutableListOf<Array<Any>>()
for (bufferFactory in BufferFactory.values()) {
result += arrayOf(bufferFactory)
}
return result
}
}
}
Loading

0 comments on commit 0d4b0e4

Please sign in to comment.