// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.kotlin.arguments import org.jdom.Element import org.jetbrains.kotlin.cli.common.arguments.* import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.junit.Assert import org.junit.Test import kotlin.random.Random import kotlin.reflect.KClass import kotlin.reflect.KMutableProperty1 import kotlin.reflect.KProperty1 import kotlin.reflect.full.memberProperties class CompilerArgumentsSerializationTest { @Test fun testDummyJVM() { doSerializeDeserializeAndCompareTest() } @Test fun testRandomFlagArgumentsJVM() { doRandomFlagArgumentsTest() } @Test fun testRandomStringArgumentsJVM() { doRandomStringArgumentsTest() } @Test fun testLongClasspathArgumentJVM() { doSerializeDeserializeAndCompareTest { classpath = generateSequence { generateRandomString(50) }.take(10).toList().joinToString(File.pathSeparator) } } @Test fun testRandomArrayArgumentsJVM() { doRandomArrayArgumentsTest() } @Test fun testDummyJs() { doSerializeDeserializeAndCompareTest() } @Test fun testRandomFlagArgumentsJS() { doRandomFlagArgumentsTest() } @Test fun testRandomStringArgumentsJS() { doRandomStringArgumentsTest() } @Test fun testRandomArrayArgumentsJS() { doRandomArrayArgumentsTest() } @Test fun testDummyMetadata() { doSerializeDeserializeAndCompareTest() } @Test fun testRandomFlagArgumentsMetadata() { doRandomFlagArgumentsTest() } @Test fun testRandomStringArgumentsMetadata() { doRandomStringArgumentsTest() } @Test fun testLongClasspathArgumentMetadata() { doSerializeDeserializeAndCompareTest { classpath = generateSequence { generateRandomString(50) }.take(10).toList().joinToString(File.pathSeparator) } } @Test fun testRandomArrayArgumentsMetadata() { doRandomArrayArgumentsTest() } @Test fun testDummyJsDce() { doSerializeDeserializeAndCompareTest() } @Test fun testRandomFlagArgumentsJSDce() { doRandomFlagArgumentsTest() } @Test fun testRandomStringArgumentsJSDce() { doRandomStringArgumentsTest() } @Test fun testRandomArrayArgumentsJSDce() { doRandomArrayArgumentsTest() } private inline fun doSerializeDeserializeAndCompareTest(configure: T.() -> Unit = {}) { val oldInstance = T::class.java.getConstructor().newInstance().apply(configure) val serializer = CompilerArgumentsSerializerV5(oldInstance) val mockFacetElement = Element("ROOT") val element = serializer.serializeTo(mockFacetElement) val newInstance = T::class.java.getConstructor().newInstance() val deserializer = CompilerArgumentsDeserializerV5(newInstance) deserializer.deserializeFrom(element) T::class.memberProperties.mapNotNull { it.safeAs>() }.forEach { val oldValue = it.get(oldInstance) val newValue = it.get(newInstance) if (oldValue == null && newValue == null) return@forEach Assert.assertNotNull("Old value of property \"${it.name}\" is null but new is not", oldValue) Assert.assertNotNull("New value of property \"${it.name}\" is null but old is not", newValue) if ((it.returnType.classifier as? KClass<*>)?.java?.isArray == true) Assert.assertArrayEquals( "Property ${it.name} has different values before (${it.get(oldInstance).toString()}) and after (${ it.get(newInstance).toString() }) serialization", oldValue as Array<*>, newValue as Array<*> ) else assert(it.get(oldInstance) == it.get(newInstance)) { "Property ${it.name} has different values before (${it.get(oldInstance).toString()}) and after (${ it.get(newInstance).toString() }) serialization" } } } private inline fun doRandomFlagArgumentsTest() { val flagProperties = CompilerArgumentsContentProspector.getFlagCompilerArgumentProperties(T::class) val randomFlags = generateSequence { Random.nextBoolean() }.take(flagProperties.size).toList() doSerializeDeserializeAndCompareTest { flagProperties.zip(randomFlags).forEach { it.first.cast>().set(this, it.second) } } } private inline fun doRandomStringArgumentsTest() { val stringProperties = CompilerArgumentsContentProspector.getStringCompilerArgumentProperties(T::class) val randomStrings = generateSequence { generateRandomString(Random.nextInt(20)) }.take(stringProperties.size).toList() doSerializeDeserializeAndCompareTest { stringProperties.zip(randomStrings).forEach { it.first.cast>().set(this, it.second) } } } private inline fun doRandomArrayArgumentsTest() { val arrayProperties = CompilerArgumentsContentProspector.getArrayCompilerArgumentProperties(T::class) val randomArrays = generateSequence { generateSequence { generateRandomString(Random.nextInt(20)) }.take(Random.nextInt(10)).toList().toTypedArray() }.take(arrayProperties.size).toList() doSerializeDeserializeAndCompareTest { arrayProperties.zip(randomArrays).forEach { it.first.cast?>>().set(this, it.second) } } } companion object { private val charPool: List = ('a'..'z') + ('A'..'Z') + ('0'..'9') private fun generateRandomString(length: Int) = generateSequence { Random.nextInt(0, charPool.size) } .take(length) .map(charPool::get) .joinToString("") } }