blob: 385749f53fe3a22824995a432f76a7ae99961591 [file] [log] [blame]
Sergey Mashkov57906eb2017-09-19 14:08:06 +03001package kotlinx.coroutines.experimental.io
2
Sergey Mashkov6d059932017-10-06 18:46:23 +03003import kotlinx.io.pool.*
Sergey Mashkov57906eb2017-09-19 14:08:06 +03004import org.junit.rules.*
5import org.junit.runner.*
6import org.junit.runners.model.*
Sergey Mashkov88951ac2017-10-27 22:36:08 +03007import java.io.*
Sergey Mashkov57906eb2017-09-19 14:08:06 +03008import java.util.concurrent.*
9import kotlin.test.*
10
Sergey Mashkov88951ac2017-10-27 22:36:08 +030011class VerifyingObjectPool<T : Any> internal constructor(private val delegate: ObjectPool<T>, private val log: Boolean = false) : ObjectPool<T> by delegate, TestRule {
Sergey Mashkov57906eb2017-09-19 14:08:06 +030012 private val allocated = ConcurrentHashMap<IdentityWrapper<T>, Boolean>()
13
Sergey Mashkovccf8dde2017-09-29 18:18:00 +030014 val used: Int
15 get() = allocated.size
16
Sergey Mashkov57906eb2017-09-19 14:08:06 +030017 override fun borrow(): T {
Sergey Mashkov88951ac2017-10-27 22:36:08 +030018 if (log) {
19 Trace.Allocate().dump()
20 }
21
Sergey Mashkov57906eb2017-09-19 14:08:06 +030022 val instance = delegate.borrow()
23 if (allocated.put(IdentityWrapper(instance), true) != null) {
24 throw AssertionError("Instance $instance has been provided by the pool twice")
25 }
26 return instance
27 }
28
29 override fun recycle(instance: T) {
Sergey Mashkov88951ac2017-10-27 22:36:08 +030030 if (log) {
31 Trace.Recycle().dump()
32 }
33
Sergey Mashkov57906eb2017-09-19 14:08:06 +030034 if (allocated.remove(IdentityWrapper(instance)) == null) {
35 throw AssertionError("Instance $instance hasn't been borrowed but tried to recycle (possibly double recycle)")
36 }
37 delegate.recycle(instance)
38 }
39
40 override fun apply(base: Statement, description: Description): Statement {
41 return object: Statement() {
42 override fun evaluate() {
Sergey Mashkovccf8dde2017-09-29 18:18:00 +030043 var failed = false
Sergey Mashkov57906eb2017-09-19 14:08:06 +030044 try {
45 base.evaluate()
46 } catch (t: Throwable) {
Sergey Mashkovccf8dde2017-09-29 18:18:00 +030047 failed = true
Sergey Mashkov57906eb2017-09-19 14:08:06 +030048 try {
49 assertEmpty()
50 } catch (emptyFailed: Throwable) {
51 throw MultipleFailureException(listOf(t, emptyFailed))
52 }
53 throw t
54 } finally {
Sergey Mashkovccf8dde2017-09-29 18:18:00 +030055 if (!failed) {
56 assertEmpty()
57 }
Sergey Mashkov57906eb2017-09-19 14:08:06 +030058 }
59 }
60 }
61 }
62
63 private fun assertEmpty() {
64 assertEquals(0, allocated.size)
65 }
66
67 private class IdentityWrapper<T : Any>(private val instance: T) {
68 override fun equals(other: Any?): Boolean {
69 if (other !is IdentityWrapper<*>) return false
70 return other.instance === this.instance
71 }
72
73 override fun hashCode() = System.identityHashCode(instance)
74 }
Sergey Mashkov88951ac2017-10-27 22:36:08 +030075
76 private sealed class Trace : RuntimeException() {
77 class Allocate : Trace()
78 class Recycle() : Trace()
79
80 fun dump() {
81 val sb = StringWriter()
82 val pw = PrintWriter(sb, false)
83 printStackTrace(pw)
84 pw.close()
85
86 println(sb.buffer)
87 }
88 }
89}