[CLI] Implement CommonToolArguments.toStringList (to replace convertArgumentsToStringList`)
KTIJ-24976
This commit is contained in:
committed by
Space Team
parent
2b893365aa
commit
d07b1b6502
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.compilerRunner
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.arguments.*
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Named
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.Arguments
|
||||
import org.junit.jupiter.params.provider.MethodSource
|
||||
import java.util.Base64.getEncoder
|
||||
import kotlin.random.Random
|
||||
import kotlin.reflect.*
|
||||
import kotlin.reflect.full.findAnnotation
|
||||
import kotlin.reflect.full.isSubtypeOf
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.full.withNullability
|
||||
import kotlin.test.assertContentEquals
|
||||
import kotlin.test.fail
|
||||
|
||||
class CompilerArgumentParsingTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("parameters")
|
||||
fun `test - parsing random compiler arguments`(type: KClass<out CommonToolArguments>, seed: Int, useShortNames: Boolean) {
|
||||
val constructor = type.constructors.find { it.parameters.isEmpty() } ?: error("Missing empty constructor on $type")
|
||||
val arguments = constructor.call()
|
||||
arguments.fillRandomValues(Random(seed))
|
||||
val argumentsAsStrings = arguments.toArgumentStrings(useShortNames)
|
||||
val parsedArguments = parseCommandLineArguments(type, argumentsAsStrings)
|
||||
assertEqualArguments(arguments, parsedArguments)
|
||||
assertEquals(argumentsAsStrings, parsedArguments.toArgumentStrings(useShortNames))
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun parameters(): List<Arguments> = getCompilerArgumentImplementations()
|
||||
.flatMap { clazz ->
|
||||
listOf(1002, 2803, 2411).flatMap { seed ->
|
||||
listOf(true, false).map { useShortNames ->
|
||||
Arguments.of(
|
||||
Named.of("${clazz.simpleName}", clazz),
|
||||
Named.of("seed: $seed", seed),
|
||||
Named.of("useShortNames: $useShortNames", useShortNames)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun assertEqualArguments(expected: CommonToolArguments, actual: CommonToolArguments) {
|
||||
if (expected::class != actual::class) fail("Expected class '${expected::class}', found: '${actual::class}'")
|
||||
expected::class.memberProperties
|
||||
.filter { it.findAnnotation<Argument>() != null }
|
||||
.ifEmpty { fail("No members with ${Argument::class} annotation") }
|
||||
.map { property ->
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
property as KProperty1<Any, Any?>
|
||||
val expectedValue = property.get(expected)
|
||||
val actualValue = property.get(actual)
|
||||
|
||||
val message = "Unexpected value in '${property.name}: '${property.returnType}'"
|
||||
if (property.returnType.isSubtypeOf(typeOf<Array<*>?>())) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
assertContentEquals(
|
||||
expectedValue as Array<Any?>?, actualValue as Array<Any?>?,
|
||||
message
|
||||
)
|
||||
} else assertEquals(
|
||||
expectedValue, actualValue,
|
||||
message
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun CommonToolArguments.fillRandomValues(random: Random) {
|
||||
this::class.memberProperties.filterIsInstance<KMutableProperty1<*, *>>().forEach { property ->
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
property as KMutableProperty1<Any, Any>
|
||||
runCatching {
|
||||
property.set(this, random.randomValue(property.returnType) ?: return@forEach)
|
||||
}.getOrElse {
|
||||
throw Throwable("Failed setting random value for: ${property.name}: ${property.returnType}", it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Random.randomString() = nextBytes(nextInt(8, 12)).let { data ->
|
||||
getEncoder().withoutPadding().encodeToString(data)
|
||||
}
|
||||
|
||||
private fun Random.randomBoolean() = nextBoolean()
|
||||
|
||||
private fun Random.randomStringArray(): Array<String> {
|
||||
val size = nextInt(1, 5)
|
||||
return Array(size) {
|
||||
randomString()
|
||||
}
|
||||
}
|
||||
|
||||
private fun Random.randomList(elementType: KType): List<Any>? {
|
||||
val size = nextInt(1, 5)
|
||||
return List(size) {
|
||||
randomValue(elementType) ?: return null
|
||||
}
|
||||
}
|
||||
|
||||
fun Random.randomValue(type: KType): Any? {
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val type = type.withNullability(false)
|
||||
return when {
|
||||
type == typeOf<String>() -> randomString()
|
||||
type == typeOf<Boolean>() -> randomBoolean()
|
||||
type == typeOf<Array<String>>() -> randomStringArray()
|
||||
type.isSubtypeOf(typeOf<List<*>>()) -> randomList(type.arguments.first().type ?: error("Missing elementType on $type"))
|
||||
type == typeOf<InternalArgument>() -> return null
|
||||
(type.classifier as? KClass<*>)?.isData == true -> null
|
||||
else -> error("Unsupported type '$type'")
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.compilerRunner
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments
|
||||
import org.reflections.Reflections
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
private val reflections = Reflections("org.jetbrains.kotlin")
|
||||
|
||||
fun getCompilerArgumentImplementations(): List<KClass<out CommonToolArguments>> {
|
||||
return reflections.getSubTypesOf(CommonToolArguments::class.java)
|
||||
.map { it.kotlin }
|
||||
.filter { !it.isAbstract }
|
||||
.filterNot { it.isInner }
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.compilerRunner
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.arguments.Argument
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.MethodSource
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KVisibility
|
||||
import kotlin.reflect.full.findAnnotation
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.test.fail
|
||||
|
||||
|
||||
class CompilerArgumentsImplementationTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("implementations")
|
||||
fun `test - all properties with Argument annotation - are public`(implementation: KClass<out CommonToolArguments>) {
|
||||
implementation.memberProperties.forEach { property ->
|
||||
if (property.findAnnotation<Argument>() != null) {
|
||||
if (property.visibility != KVisibility.PUBLIC) {
|
||||
fail(
|
||||
"Property '${property.name}: ${property.returnType}' " +
|
||||
"is marked with @${Argument::class.java.simpleName}, but is not public (${property.visibility})"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun implementations() = getCompilerArgumentImplementations()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user