From bc8179466b8af5f0a446e339abbf5a7d086af4b9 Mon Sep 17 00:00:00 2001 From: Alexey Menshutin Date: Tue, 23 Jul 2024 19:06:20 +0300 Subject: [PATCH] Test framework improvements --- buildSrc/src/main/kotlin/Dependencies.kt | 2 +- usvm-ts/src/main/kotlin/org/usvm/TSTest.kt | 31 ++++++- .../test/kotlin/org/usvm/samples/Arguments.kt | 22 +++++ .../test/kotlin/org/usvm/samples/MinValue.kt | 8 +- .../org/usvm/util/TSMethodTestRunner.kt | 92 ++++++++----------- .../src/test/resources/samples/Arguments.ts | 13 +++ 6 files changed, 109 insertions(+), 59 deletions(-) create mode 100644 usvm-ts/src/test/kotlin/org/usvm/samples/Arguments.kt create mode 100644 usvm-ts/src/test/resources/samples/Arguments.ts diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index 613ed75c4f..61810835b4 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -5,7 +5,7 @@ import org.gradle.plugin.use.PluginDependenciesSpec object Versions { const val detekt = "1.18.1" const val ini4j = "0.5.4" - const val jacodb = "e47c227815" + const val jacodb = "30594f5f7c" const val juliet = "1.3.2" const val junit = "5.9.3" const val kotlin = "1.9.20" diff --git a/usvm-ts/src/main/kotlin/org/usvm/TSTest.kt b/usvm-ts/src/main/kotlin/org/usvm/TSTest.kt index 16a2ac28c1..fa3291eb45 100644 --- a/usvm-ts/src/main/kotlin/org/usvm/TSTest.kt +++ b/usvm-ts/src/main/kotlin/org/usvm/TSTest.kt @@ -8,4 +8,33 @@ class TSTest( val trace: List? = null, ) -class TSMethodCoverage +open class TSMethodCoverage + +object NoCoverage : TSMethodCoverage() + +sealed interface TSObject { + sealed interface TSNumber : TSObject { + data class Integer(val value: Int) : TSNumber + + data class Double(val value: kotlin.Double) : TSNumber + + val number: kotlin.Double + get() = when (this) { + is Integer -> value.toDouble() + is Double -> value + } + } + + data class String(val value: kotlin.String) : TSObject + + data class Boolean(val value: kotlin.Boolean) : TSObject + + + data class Class(val name: String, val properties: Map) : TSObject + + data object AnyObject : TSObject + + data object UndefinedObject : TSObject + + data class Array(val values: List) : TSObject +} diff --git a/usvm-ts/src/test/kotlin/org/usvm/samples/Arguments.kt b/usvm-ts/src/test/kotlin/org/usvm/samples/Arguments.kt new file mode 100644 index 0000000000..a100e9def7 --- /dev/null +++ b/usvm-ts/src/test/kotlin/org/usvm/samples/Arguments.kt @@ -0,0 +1,22 @@ +package org.usvm.samples + +import org.junit.jupiter.api.Disabled +import org.usvm.TSObject +import org.usvm.util.MethodDescriptor +import org.usvm.util.TSMethodTestRunner +import kotlin.test.Test + +class Arguments : TSMethodTestRunner() { + @Test + @Disabled + fun testMinValue() { + discoverProperties( + methodIdentifier = MethodDescriptor( + fileName = "Arguments.ts", + className = "SimpleClass", + methodName = "noArguments", + argumentsNumber = 0 + ) + ) + } +} diff --git a/usvm-ts/src/test/kotlin/org/usvm/samples/MinValue.kt b/usvm-ts/src/test/kotlin/org/usvm/samples/MinValue.kt index 9d82eb926f..d4662c460c 100644 --- a/usvm-ts/src/test/kotlin/org/usvm/samples/MinValue.kt +++ b/usvm-ts/src/test/kotlin/org/usvm/samples/MinValue.kt @@ -1,18 +1,18 @@ package org.usvm.samples import org.junit.jupiter.api.Disabled +import org.usvm.TSObject import org.usvm.util.MethodDescriptor import org.usvm.util.TSMethodTestRunner import kotlin.test.Test -@Disabled("Not yet implemented") class MinValue : TSMethodTestRunner() { - @Test + @Disabled fun testMinValue() { - discoverProperties( + discoverProperties( methodIdentifier = MethodDescriptor( - fileName = "MinValue", + fileName = "MinValue.ts", className = globalClassName, methodName = "findMinValue", argumentsNumber = 1 diff --git a/usvm-ts/src/test/kotlin/org/usvm/util/TSMethodTestRunner.kt b/usvm-ts/src/test/kotlin/org/usvm/util/TSMethodTestRunner.kt index 56944aafcb..f439faeb0e 100644 --- a/usvm-ts/src/test/kotlin/org/usvm/util/TSMethodTestRunner.kt +++ b/usvm-ts/src/test/kotlin/org/usvm/util/TSMethodTestRunner.kt @@ -1,28 +1,41 @@ package org.usvm.util +import org.jacodb.ets.base.EtsAnyType +import org.jacodb.ets.base.EtsBooleanType +import org.jacodb.ets.base.EtsNumberType +import org.jacodb.ets.base.EtsStringType import org.jacodb.ets.base.EtsType +import org.jacodb.ets.base.EtsUndefinedType import org.jacodb.ets.dto.EtsFileDto import org.jacodb.ets.dto.convertToEtsFile import org.jacodb.ets.model.EtsFile import org.jacodb.ets.model.EtsMethod +import org.usvm.NoCoverage import org.usvm.PathSelectionStrategy import org.usvm.TSMachine import org.usvm.TSMethodCoverage +import org.usvm.TSObject import org.usvm.TSTest import org.usvm.UMachineOptions import org.usvm.test.util.TestRunner import org.usvm.test.util.checkers.ignoreNumberOfAnalysisResults +import kotlin.reflect.KClass import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds +typealias CoverageChecker = (TSMethodCoverage) -> Boolean + open class TSMethodTestRunner : TestRunner() { protected val globalClassName = "_DEFAULT_ARK_CLASS" - protected inline fun discoverProperties( + protected val doNotCheckCoverage: CoverageChecker = { _ -> true } + + protected inline fun discoverProperties( methodIdentifier: MethodDescriptor, vararg analysisResultMatchers: (R?) -> Boolean, invariants: Array> = emptyArray(), + noinline coverageChecker: CoverageChecker = doNotCheckCoverage, ) { internalCheck( target = methodIdentifier, @@ -32,14 +45,15 @@ open class TSMethodTestRunner : TestRunner r.parameters + r.resultValue }, expectedTypesForExtractedValues = arrayOf(typeTransformer(R::class)), checkMode = CheckMode.MATCH_PROPERTIES, - coverageChecker = { _ -> true } + coverageChecker = coverageChecker ) } - protected inline fun discoverProperties( + protected inline fun discoverProperties( methodIdentifier: MethodDescriptor, vararg analysisResultMatchers: (T, R?) -> Boolean, invariants: Array> = emptyArray(), + noinline coverageChecker: CoverageChecker = doNotCheckCoverage, ) { internalCheck( target = methodIdentifier, @@ -49,14 +63,15 @@ open class TSMethodTestRunner : TestRunner r.parameters + r.resultValue }, expectedTypesForExtractedValues = arrayOf(typeTransformer(T::class), typeTransformer(R::class)), checkMode = CheckMode.MATCH_PROPERTIES, - coverageChecker = { _ -> true } + coverageChecker = coverageChecker ) } - protected inline fun discoverProperties( + protected inline fun discoverProperties( methodIdentifier: MethodDescriptor, vararg analysisResultMatchers: (T1, T2, R?) -> Boolean, invariants: Array> = emptyArray(), + noinline coverageChecker: CoverageChecker = doNotCheckCoverage, ) { internalCheck( target = methodIdentifier, @@ -70,57 +85,27 @@ open class TSMethodTestRunner : TestRunner true } - ) - } - - protected inline fun discoverProperties( - methodIdentifier: MethodDescriptor, - vararg analysisResultMatchers: (T1, T2, T3, R?) -> Boolean, - invariants: Array> = emptyArray(), - ) { - internalCheck( - target = methodIdentifier, - analysisResultsNumberMatcher = ignoreNumberOfAnalysisResults, - analysisResultsMatchers = analysisResultMatchers, - invariants = invariants, - extractValuesToCheck = { r -> r.parameters + r.resultValue }, - expectedTypesForExtractedValues = arrayOf( - typeTransformer(T1::class), - typeTransformer(T2::class), - typeTransformer(T3::class), - typeTransformer(R::class) - ), - checkMode = CheckMode.MATCH_PROPERTIES, - coverageChecker = { _ -> true } - ) - } - - protected inline fun discoverProperties( - methodIdentifier: MethodDescriptor, - vararg analysisResultMatchers: (T1, T2, T3, T4, R?) -> Boolean, - invariants: Array> = emptyArray(), - ) { - internalCheck( - target = methodIdentifier, - analysisResultsNumberMatcher = ignoreNumberOfAnalysisResults, - analysisResultsMatchers = analysisResultMatchers, - invariants = invariants, - extractValuesToCheck = { r -> r.parameters + r.resultValue }, - expectedTypesForExtractedValues = arrayOf( - typeTransformer(T1::class), - typeTransformer(T2::class), - typeTransformer(T3::class), - typeTransformer(T4::class), - typeTransformer(R::class) - ), - checkMode = CheckMode.MATCH_PROPERTIES, - coverageChecker = { _ -> true } + coverageChecker = coverageChecker ) } override val typeTransformer: (Any?) -> EtsType - get() = TODO("Not yet implemented") + get() = { + require(it is KClass<*>) { "Only TSObjects are allowed" } + + when (it) { + TSObject.AnyObject::class -> EtsAnyType + TSObject.Array::class -> TODO() + TSObject.Boolean::class -> EtsBooleanType + TSObject.Class::class -> TODO() + TSObject.String::class -> EtsStringType + TSObject.TSNumber::class -> EtsNumberType + TSObject.TSNumber.Double::class -> EtsNumberType + TSObject.TSNumber.Integer::class -> EtsNumberType + TSObject.UndefinedObject::class -> EtsUndefinedType + else -> error("Should not be called") + } + } override val checkType: (EtsType?, EtsType?) -> Boolean get() = TODO("Not yet implemented") @@ -157,7 +142,7 @@ open class TSMethodTestRunner : TestRunner) -> TSMethodCoverage = TODO() + override val coverageRunner: (List) -> TSMethodCoverage = { _ -> NoCoverage } override var options: UMachineOptions = UMachineOptions( pathSelectionStrategies = listOf(PathSelectionStrategy.CLOSEST_TO_UNCOVERED_RANDOM), @@ -169,6 +154,7 @@ open class TSMethodTestRunner : TestRunner