Skip to content
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
@@ -1,9 +1,65 @@
package com.papsign.ktor.openapigen.parameters.parsers.converters

import kotlin.reflect.KClass
import kotlin.reflect.KType

open class ConverterSelectorFactory(vararg val selectors: ConverterSelector): ConverterFactory {
open class ConverterSelectorFactory(vararg selectors: ConverterSelector): ConverterFactory {
private val converterSelectors = selectors.toMutableList()

override fun buildConverter(type: KType): Converter? {
return selectors.find { it.canHandle(type) }?.create(type)
return converterSelectors.find { it.canHandle(type) }?.create(type)
}

fun <T : ConverterSelector> injectConverterBefore(kclass: KClass<T>, converterSelector: ConverterSelector) {
converterSelectors.find { kclass.isInstance(it) }
?.let {
val index = converterSelectors.indexOf(it)
val shiftIndex = if (index <= 0) 0 else index

var previous = converterSelectors.getOrNull(shiftIndex)
converterSelectors[index] = converterSelector

if (shiftIndex == (converterSelectors.size - 1)) {
previous?.let { converterSelectors.add(it) }
} else {
for (i in (index + 1) until converterSelectors.size) {
previous?.let {
val current = converterSelectors[i]
converterSelectors[i] = it
previous = current
}
}
previous?.let { converterSelectors.add(it) }
}
}
?: converterSelectors.add(converterSelector)
}

fun <T : ConverterSelector> injectConverterAfter(kclass: KClass<T>, converterSelector: ConverterSelector) {
converterSelectors.find { kclass.isInstance(it) }
?.let {
val index = converterSelectors.indexOf(it)

if (index == (converterSelectors.size - 1)) {
converterSelectors.add(converterSelector)
} else {
var previous = converterSelectors.getOrNull(index + 1)
converterSelectors[index + 1] = converterSelector

for (i in (index + 2) until converterSelectors.size) {
previous?.let {
val current = converterSelectors[i]
converterSelectors[i] = it
previous = current
}
}
previous?.let { converterSelectors.add(it) }
}
}
?: converterSelectors.add(converterSelector)
}

fun <T : ConverterSelector> removeConverter(kclass: KClass<T>) {
converterSelectors.removeIf { kclass.isInstance(it) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package com.papsign.ktor.openapigen.parameters.parsers.builder.query.form

import com.papsign.ktor.openapigen.parameters.parsers.builders.query.form.FormBuilderFactory
import com.papsign.ktor.openapigen.parameters.parsers.converters.Converter
import com.papsign.ktor.openapigen.parameters.parsers.converters.ConverterSelector
import com.papsign.ktor.openapigen.parameters.parsers.converters.primitive.PrimitiveConverter
import com.papsign.ktor.openapigen.parameters.parsers.converters.primitive.PrimitiveConverterFactory
import com.papsign.ktor.openapigen.parameters.parsers.testSelector
import com.papsign.ktor.openapigen.parameters.parsers.testSelectorFails
import org.junit.After
import org.junit.Before
import org.junit.Test
import java.time.OffsetDateTime
import java.util.UUID
import kotlin.reflect.KType
import kotlin.reflect.full.createType

class InjectBeforeTest {
@Before
fun before() {
PrimitiveConverterFactory.injectConverterBefore(PrimitiveConverter::class, CustomUuidConverter)
}

@After
fun after() {
PrimitiveConverterFactory.removeConverter(CustomUuidConverter::class)
}

@Test
fun testCustomConverter() {
val uuid = "4a5e1ba7-c6fe-49de-abf9-d94614ea3bb8"
val key = "key"
val expected = UUID.fromString(uuid)
val parse = mapOf(
key to listOf(uuid)
)
FormBuilderFactory.testSelector(expected, key, parse, true)
FormBuilderFactory.testSelectorFails<UUID>(key, mapOf(key to listOf("not uuid")), true)
}
}

class InjectAfterAndRemoveTest {
@Before
fun before() {
PrimitiveConverterFactory.injectConverterAfter(PrimitiveConverter::class, AnyToBooleanConverter)
PrimitiveConverterFactory.removeConverter(PrimitiveConverter::class)
}

@After
fun after() {
PrimitiveConverterFactory.injectConverterBefore(AnyToBooleanConverter::class, PrimitiveConverter)
PrimitiveConverterFactory.removeConverter(AnyToBooleanConverter::class)
}

@Test
fun testConverterRemoval() {
val values = listOf("random", 1, UUID.randomUUID(), OffsetDateTime.now())

values.forEach {
val key = "key"
val expected = true
val parse = mapOf(
key to listOf(it.toString())
)

FormBuilderFactory.testSelector(expected, key, parse, true)
}
}
}

private object AnyToBooleanConverter : ConverterSelector, Converter {
override fun convert(value: String): Any = true

override fun canHandle(type: KType): Boolean = true

override fun create(type: KType): Converter = this
}

private object CustomUuidConverter : ConverterSelector, Converter {
override fun convert(value: String): Any = UUID.fromString(value)

override fun canHandle(type: KType): Boolean = type == UUID::class.createType()

override fun create(type: KType): Converter =
if (canHandle(type)) this
else throw RuntimeException("Cannot create converter that can handle $type")
}