diff --git a/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/JsTestsModel.kt b/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/JsTestsModel.kt index b2b83da234..fb869d835b 100644 --- a/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/JsTestsModel.kt +++ b/utbot-intellij-js/src/main/kotlin/org/utbot/intellij/plugin/language/js/JsTestsModel.kt @@ -4,7 +4,7 @@ import com.intellij.lang.javascript.psi.JSFile import com.intellij.lang.javascript.refactoring.util.JSMemberInfo import com.intellij.openapi.module.Module import com.intellij.openapi.project.Project -import org.utbot.framework.codegen.TestFramework +import org.utbot.framework.codegen.domain.TestFramework import org.utbot.intellij.plugin.models.BaseTestsModel import service.CoverageMode import settings.JsTestGenerationSettings.defaultTimeout diff --git a/utbot-js/build.gradle.kts b/utbot-js/build.gradle.kts index f868206db9..838924fbeb 100644 --- a/utbot-js/build.gradle.kts +++ b/utbot-js/build.gradle.kts @@ -30,17 +30,8 @@ dependencies { testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.1") api(project(":utbot-framework")) implementation(project(":utbot-fuzzers")) - // https://mvnrepository.com/artifact/org.graalvm.js/js - implementation(group = "org.graalvm.js", name = "js", version = "22.1.0.1") - - // https://mvnrepository.com/artifact/org.graalvm.js/js-scriptengine - implementation(group = "org.graalvm.js", name = "js-scriptengine", version = "22.1.0.1") - - // https://mvnrepository.com/artifact/org.graalvm.truffle/truffle-api - implementation(group = "org.graalvm.truffle", name = "truffle-api", version = "22.1.0.1") - - // https://mvnrepository.com/artifact/org.graalvm.sdk/graal-sdk - implementation(group = "org.graalvm.sdk", name = "graal-sdk", version = "22.1.0.1") + // https://mvnrepository.com/artifact/com.google.javascript/closure-compiler + implementation("com.google.javascript:closure-compiler:v20221102") // https://mvnrepository.com/artifact/org.json/json implementation(group = "org.json", name = "json", version = "20220320") @@ -52,4 +43,4 @@ dependencies { implementation("org.functionaljava:functionaljava-quickcheck:5.0") implementation("org.functionaljava:functionaljava-java-core:5.0") implementation(group = "org.apache.commons", name = "commons-text", version = apacheCommonsTextVersion) -} \ No newline at end of file +} diff --git a/utbot-js/src/main/kotlin/api/JsTestGenerator.kt b/utbot-js/src/main/kotlin/api/JsTestGenerator.kt index a8af69a5cc..f18f61face 100644 --- a/utbot-js/src/main/kotlin/api/JsTestGenerator.kt +++ b/utbot-js/src/main/kotlin/api/JsTestGenerator.kt @@ -1,12 +1,9 @@ package api import codegen.JsCodeGenerator -import com.oracle.js.parser.ErrorManager -import com.oracle.js.parser.Parser -import com.oracle.js.parser.ScriptEnvironment -import com.oracle.js.parser.Source -import com.oracle.js.parser.ir.ClassNode -import com.oracle.js.parser.ir.FunctionNode +import com.google.javascript.jscomp.Compiler +import com.google.javascript.jscomp.SourceFile +import com.google.javascript.rhino.Node import framework.api.js.JsClassId import framework.api.js.JsMethodId import framework.api.js.JsMultipleClassId @@ -14,8 +11,8 @@ import framework.api.js.util.isJsBasic import framework.api.js.util.jsErrorClassId import fuzzer.JsFuzzer import fuzzer.providers.JsObjectModelProvider -import org.graalvm.polyglot.Context -import org.utbot.framework.codegen.model.constructor.CgMethodTestSet +import java.io.File +import org.utbot.framework.codegen.domain.models.CgMethodTestSet import org.utbot.framework.plugin.api.EnvironmentModels import org.utbot.framework.plugin.api.ExecutableId import org.utbot.framework.plugin.api.UtAssembleModel @@ -25,10 +22,8 @@ import org.utbot.framework.plugin.api.UtExecutionResult import org.utbot.framework.plugin.api.UtExecutionSuccess import org.utbot.framework.plugin.api.UtExplicitlyThrownException import org.utbot.framework.plugin.api.UtModel -import org.utbot.framework.plugin.api.util.UtContext import org.utbot.framework.plugin.api.util.isStatic import org.utbot.framework.plugin.api.util.voidClassId -import org.utbot.framework.plugin.api.util.withUtContext import org.utbot.fuzzer.FuzzedConcreteValue import org.utbot.fuzzer.FuzzedMethodDescription import org.utbot.fuzzer.FuzzedValue @@ -37,6 +32,11 @@ import parser.JsClassAstVisitor import parser.JsFunctionAstVisitor import parser.JsFuzzerAstVisitor import parser.JsParserUtils +import parser.JsParserUtils.getAbstractFunctionName +import parser.JsParserUtils.getAbstractFunctionParams +import parser.JsParserUtils.getClassMethods +import parser.JsParserUtils.getClassName +import parser.JsParserUtils.getParamName import parser.JsToplevelFunctionAstVisitor import service.CoverageServiceProvider import service.ServiceContext @@ -46,7 +46,6 @@ import settings.JsTestGenerationSettings.dummyClassName import utils.PathResolver import utils.constructClass import utils.toJsAny -import java.io.File class JsTestGenerator( @@ -62,7 +61,7 @@ class JsTestGenerator( private val exports = mutableSetOf() - private lateinit var parsedFile: FunctionNode + private lateinit var parsedFile: Node private val utbotDir = "utbotJs" @@ -97,7 +96,7 @@ class JsTestGenerator( parsedFile = parsedFile, strict = selectedMethods?.isNotEmpty() ?: false ) - parentClassName = classNode?.ident?.name?.toString() + parentClassName = classNode?.getClassName() val classId = makeJsClassId(classNode, ternService) val methods = makeMethodsToTest() if (methods.isEmpty()) throw IllegalArgumentException("No methods to test were found!") @@ -115,14 +114,14 @@ class JsTestGenerator( private fun makeTestsForMethod( classId: JsClassId, - funcNode: FunctionNode, - classNode: ClassNode?, + funcNode: Node, + classNode: Node?, context: ServiceContext, testSets: MutableList, paramNames: MutableMap> ) { val execId = classId.allMethods.find { - it.name == funcNode.name.toString() + it.name == funcNode.getAbstractFunctionName() } ?: throw IllegalStateException() manageExports(classNode, funcNode, execId) val (concreteValues, fuzzedValues) = runFuzzer(funcNode, execId) @@ -167,7 +166,7 @@ class JsTestGenerator( executions = testsForGenerator, ) testSets += testSet - paramNames[execId] = funcNode.parameters.map { it.name.toString() } + paramNames[execId] = funcNode.getAbstractFunctionParams().map { it.getParamName() } } private fun makeImportPrefix(): String { @@ -231,15 +230,15 @@ class JsTestGenerator( } private fun runFuzzer( - funcNode: FunctionNode, + funcNode: Node, execId: JsMethodId ): Pair, List>> { val fuzzerVisitor = JsFuzzerAstVisitor() - funcNode.body.accept(fuzzerVisitor) + fuzzerVisitor.accept(funcNode) val methodUnderTestDescription = FuzzedMethodDescription(execId, fuzzerVisitor.fuzzedConcreteValues).apply { - compilableName = funcNode.name.toString() - val names = funcNode.parameters.map { it.name.toString() } + compilableName = funcNode.getAbstractFunctionName() + val names = funcNode.getAbstractFunctionParams().map { it.getParamName() } parameterNameMap = { index -> names.getOrNull(index) } } val fuzzedValues = @@ -248,28 +247,27 @@ class JsTestGenerator( } private fun manageExports( - classNode: ClassNode?, - funcNode: FunctionNode, + classNode: Node?, + funcNode: Node, execId: JsMethodId ) { - val obligatoryExport = (classNode?.ident?.name ?: funcNode.ident.name).toString() + val obligatoryExport = (classNode?.getClassName() ?: funcNode.getAbstractFunctionName()).toString() val collectedExports = collectExports(execId) exports += (collectedExports + obligatoryExport) exportsManager(exports.toList()) } - private fun makeMethodsToTest(): List { + private fun makeMethodsToTest(): List { return selectedMethods?.map { getFunctionNode( focusedMethodName = it, parentClassName = parentClassName, - fileText = fileText ) } ?: getMethodsToTest() } private fun makeJsClassId( - classNode: ClassNode?, + classNode: Node?, ternService: TernService ): JsClassId { return classNode?.let { @@ -280,21 +278,12 @@ class JsTestGenerator( ) } - private fun runParser(fileText: String): FunctionNode { - // Fixes problem with Graal.polyglot missing from classpath, resulting in error. - withUtContext(UtContext(Context::class.java.classLoader)) { - val parser = Parser( - ScriptEnvironment.builder().build(), - Source.sourceFor("jsFile", fileText), - ErrorManager.ThrowErrorManager() - ) - return parser.parse() - } - } + private fun runParser(fileText: String): Node = + Compiler().parse(SourceFile.fromCode("jsFile", fileText)) - private fun extractToplevelFunctions(): List { + private fun extractToplevelFunctions(): List { val visitor = JsToplevelFunctionAstVisitor() - parsedFile.body.accept(visitor) + visitor.accept(parsedFile) return visitor.extractedMethods } @@ -321,18 +310,12 @@ class JsTestGenerator( return resultList } - private fun getFunctionNode(focusedMethodName: String, parentClassName: String?, fileText: String): FunctionNode { - val parser = Parser( - ScriptEnvironment.builder().build(), - Source.sourceFor("jsFile", fileText), - ErrorManager.ThrowErrorManager() - ) - val fileNode = parser.parse() + private fun getFunctionNode(focusedMethodName: String, parentClassName: String?): Node { val visitor = JsFunctionAstVisitor( focusedMethodName, if (parentClassName != dummyClassName) parentClassName else null ) - fileNode.accept(visitor) + visitor.accept(parsedFile) return visitor.targetFunctionNode } @@ -343,12 +326,10 @@ class JsTestGenerator( getClassMethods("") } - private fun getClassMethods(className: String): List { + private fun getClassMethods(className: String): List { val visitor = JsClassAstVisitor(className) - parsedFile.body.accept(visitor) + visitor.accept(parsedFile) val classNode = JsParserUtils.searchForClassDecl(className, parsedFile) - return classNode?.classElements?.filter { - it.value is FunctionNode - }?.map { it.value as FunctionNode } ?: throw IllegalStateException("Can't extract methods of class $className") + return classNode?.getClassMethods() ?: throw IllegalStateException("Can't extract methods of class $className") } } diff --git a/utbot-js/src/main/kotlin/codegen/JsCodeGenerator.kt b/utbot-js/src/main/kotlin/codegen/JsCodeGenerator.kt index 1c4b3623e7..05cd26747f 100644 --- a/utbot-js/src/main/kotlin/codegen/JsCodeGenerator.kt +++ b/utbot-js/src/main/kotlin/codegen/JsCodeGenerator.kt @@ -2,23 +2,24 @@ package codegen import framework.codegen.JsCgLanguageAssistant import framework.codegen.Mocha -import org.utbot.framework.codegen.ForceStaticMocking -import org.utbot.framework.codegen.HangingTestsTimeout -import org.utbot.framework.codegen.ParametrizedTestSource -import org.utbot.framework.codegen.RegularImport -import org.utbot.framework.codegen.RuntimeExceptionTestsBehaviour -import org.utbot.framework.codegen.StaticsMocking -import org.utbot.framework.codegen.TestFramework -import org.utbot.framework.codegen.model.CodeGeneratorResult -import org.utbot.framework.codegen.model.constructor.CgMethodTestSet -import org.utbot.framework.codegen.model.constructor.TestClassModel -import org.utbot.framework.codegen.model.constructor.context.CgContext -import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor -import org.utbot.framework.codegen.model.visitor.CgAbstractRenderer import org.utbot.framework.plugin.api.CodegenLanguage import org.utbot.framework.plugin.api.ExecutableId import org.utbot.framework.plugin.api.MockFramework import framework.api.js.JsClassId +import org.utbot.framework.codegen.CodeGeneratorResult +import org.utbot.framework.codegen.domain.ForceStaticMocking +import org.utbot.framework.codegen.domain.HangingTestsTimeout +import org.utbot.framework.codegen.domain.ParametrizedTestSource +import org.utbot.framework.codegen.domain.RegularImport +import org.utbot.framework.codegen.domain.RuntimeExceptionTestsBehaviour +import org.utbot.framework.codegen.domain.StaticsMocking +import org.utbot.framework.codegen.domain.TestFramework +import org.utbot.framework.codegen.domain.context.CgContext +import org.utbot.framework.codegen.domain.models.CgClassFile +import org.utbot.framework.codegen.domain.models.CgMethodTestSet +import org.utbot.framework.codegen.domain.models.TestClassModel +import org.utbot.framework.codegen.renderer.CgAbstractRenderer +import org.utbot.framework.codegen.tree.CgTestClassConstructor import settings.JsTestGenerationSettings.fileUnderTestAliases class JsCodeGenerator( @@ -60,8 +61,9 @@ class JsCodeGenerator( testClassCustomName: String? = null, ): CodeGeneratorResult = withCustomContext(testClassCustomName) { val testClassModel = TestClassModel(classUnderTest, cgTestSets) - val testClassFile = CgTestClassConstructor(context).construct(testClassModel) - CodeGeneratorResult(renderClassFile(testClassFile), testClassFile.testsGenerationReport) + val astConstructor = CgTestClassConstructor(context) + val testClassFile = astConstructor.construct(testClassModel) + CodeGeneratorResult(renderClassFile(testClassFile), astConstructor.testsGenerationReport) } private fun withCustomContext(testClassCustomName: String? = null, block: () -> R): R { diff --git a/utbot-js/src/main/kotlin/framework/codegen/JsCgLanguageAssistant.kt b/utbot-js/src/main/kotlin/framework/codegen/JsCgLanguageAssistant.kt index c89ebfa483..fd8e2a47dc 100644 --- a/utbot-js/src/main/kotlin/framework/codegen/JsCgLanguageAssistant.kt +++ b/utbot-js/src/main/kotlin/framework/codegen/JsCgLanguageAssistant.kt @@ -5,13 +5,13 @@ import framework.codegen.model.constructor.tree.JsCgMethodConstructor import framework.codegen.model.constructor.tree.JsCgStatementConstructor import framework.codegen.model.constructor.tree.JsCgVariableConstructor import framework.codegen.model.constructor.visitor.CgJsRenderer -import org.utbot.framework.codegen.model.constructor.TestClassContext -import org.utbot.framework.codegen.model.constructor.context.CgContext -import org.utbot.framework.codegen.model.util.CgPrinter -import org.utbot.framework.codegen.model.visitor.CgAbstractRenderer -import org.utbot.framework.codegen.model.visitor.CgRendererContext +import org.utbot.framework.codegen.domain.context.CgContext +import org.utbot.framework.codegen.domain.context.TestClassContext +import org.utbot.framework.codegen.renderer.CgAbstractRenderer +import org.utbot.framework.codegen.renderer.CgPrinter +import org.utbot.framework.codegen.renderer.CgRendererContext +import org.utbot.framework.codegen.services.language.CgLanguageAssistant import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.CgLanguageAssistant import org.utbot.framework.plugin.api.utils.testClassNameGenerator object JsCgLanguageAssistant : CgLanguageAssistant() { diff --git a/utbot-js/src/main/kotlin/framework/codegen/JsDomain.kt b/utbot-js/src/main/kotlin/framework/codegen/JsDomain.kt index 08f571f327..e07b86bdbb 100644 --- a/utbot-js/src/main/kotlin/framework/codegen/JsDomain.kt +++ b/utbot-js/src/main/kotlin/framework/codegen/JsDomain.kt @@ -1,12 +1,12 @@ package framework.codegen -import org.utbot.framework.codegen.TestFramework import org.utbot.framework.plugin.api.BuiltinClassId import org.utbot.framework.plugin.api.BuiltinMethodId import org.utbot.framework.plugin.api.ClassId import framework.api.js.JsClassId import framework.api.js.util.jsErrorClassId import framework.api.js.util.jsUndefinedClassId +import org.utbot.framework.codegen.domain.TestFramework object Mocha : TestFramework(id = "Mocha", displayName = "Mocha") { diff --git a/utbot-js/src/main/kotlin/framework/codegen/JsTestFrameworkManager.kt b/utbot-js/src/main/kotlin/framework/codegen/JsTestFrameworkManager.kt index 9523c5e9a5..525a267bd6 100644 --- a/utbot-js/src/main/kotlin/framework/codegen/JsTestFrameworkManager.kt +++ b/utbot-js/src/main/kotlin/framework/codegen/JsTestFrameworkManager.kt @@ -1,8 +1,8 @@ package framework.codegen import framework.codegen.model.constructor.tree.MochaManager -import org.utbot.framework.codegen.model.constructor.context.CgContext -import org.utbot.framework.plugin.api.LanguageTestFrameworkManager +import org.utbot.framework.codegen.domain.context.CgContext +import org.utbot.framework.codegen.services.language.LanguageTestFrameworkManager class JsTestFrameworkManager: LanguageTestFrameworkManager() { diff --git a/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgCallableAccessManager.kt b/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgCallableAccessManager.kt index 1f3595ff16..4c44a4c433 100644 --- a/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgCallableAccessManager.kt +++ b/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgCallableAccessManager.kt @@ -1,11 +1,15 @@ package framework.codegen.model.constructor.tree -import org.utbot.framework.codegen.model.constructor.context.CgContext -import org.utbot.framework.codegen.model.constructor.context.CgContextOwner -import org.utbot.framework.codegen.model.constructor.tree.CgCallableAccessManager -import org.utbot.framework.codegen.model.constructor.tree.CgIncompleteMethodCall -import org.utbot.framework.codegen.model.tree.* -import org.utbot.framework.codegen.model.util.resolve +import org.utbot.framework.codegen.domain.context.CgContext +import org.utbot.framework.codegen.domain.context.CgContextOwner +import org.utbot.framework.codegen.domain.models.CgConstructorCall +import org.utbot.framework.codegen.domain.models.CgExecutableCall +import org.utbot.framework.codegen.domain.models.CgExpression +import org.utbot.framework.codegen.domain.models.CgMethodCall +import org.utbot.framework.codegen.domain.models.CgStaticFieldAccess +import org.utbot.framework.codegen.services.access.CgCallableAccessManager +import org.utbot.framework.codegen.services.access.CgIncompleteMethodCall +import org.utbot.framework.codegen.util.resolve import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.ConstructorId import org.utbot.framework.plugin.api.FieldId diff --git a/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgMethodConstructor.kt b/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgMethodConstructor.kt index 1d49ab0bb0..c713d633c6 100644 --- a/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgMethodConstructor.kt +++ b/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgMethodConstructor.kt @@ -1,11 +1,5 @@ package framework.codegen.model.constructor.tree -import org.utbot.framework.codegen.model.constructor.context.CgContext -import org.utbot.framework.codegen.model.constructor.tree.CgMethodConstructor -import org.utbot.framework.codegen.model.tree.CgTestMethod -import org.utbot.framework.codegen.model.tree.CgTestMethodType -import org.utbot.framework.codegen.model.tree.CgValue -import org.utbot.framework.codegen.model.tree.CgVariable import org.utbot.framework.plugin.api.ConcreteExecutionFailureException import org.utbot.framework.plugin.api.ConstructorId import org.utbot.framework.plugin.api.ExecutableId @@ -17,6 +11,12 @@ import org.utbot.framework.plugin.api.onSuccess import org.utbot.framework.plugin.api.util.voidClassId import org.utbot.framework.util.isUnit import java.security.AccessControlException +import org.utbot.framework.codegen.domain.context.CgContext +import org.utbot.framework.codegen.domain.models.CgTestMethod +import org.utbot.framework.codegen.domain.models.CgTestMethodType +import org.utbot.framework.codegen.domain.models.CgValue +import org.utbot.framework.codegen.domain.models.CgVariable +import org.utbot.framework.codegen.tree.CgMethodConstructor class JsCgMethodConstructor(ctx: CgContext) : CgMethodConstructor(ctx) { diff --git a/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgStatementConstructor.kt b/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgStatementConstructor.kt index 51c20fadea..e132a1bb60 100644 --- a/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgStatementConstructor.kt +++ b/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgStatementConstructor.kt @@ -2,43 +2,43 @@ package framework.codegen.model.constructor.tree import fj.data.Either import framework.codegen.model.constructor.util.plus -import org.utbot.framework.codegen.model.constructor.context.CgContext -import org.utbot.framework.codegen.model.constructor.context.CgContextOwner -import org.utbot.framework.codegen.model.constructor.tree.CgCallableAccessManager -import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor -import org.utbot.framework.codegen.model.constructor.util.CgStatementConstructor -import org.utbot.framework.codegen.model.constructor.util.ExpressionWithType -import org.utbot.framework.codegen.model.tree.CgAnnotation -import org.utbot.framework.codegen.model.tree.CgAnonymousFunction -import org.utbot.framework.codegen.model.tree.CgComment -import org.utbot.framework.codegen.model.tree.CgDeclaration -import org.utbot.framework.codegen.model.tree.CgEmptyLine -import org.utbot.framework.codegen.model.tree.CgExpression -import org.utbot.framework.codegen.model.tree.CgForEachLoopBuilder -import org.utbot.framework.codegen.model.tree.CgForLoopBuilder -import org.utbot.framework.codegen.model.tree.CgIfStatement -import org.utbot.framework.codegen.model.tree.CgInnerBlock -import org.utbot.framework.codegen.model.tree.CgIsInstance -import org.utbot.framework.codegen.model.tree.CgLogicalAnd -import org.utbot.framework.codegen.model.tree.CgLogicalOr -import org.utbot.framework.codegen.model.tree.CgMultilineComment -import org.utbot.framework.codegen.model.tree.CgMultipleArgsAnnotation -import org.utbot.framework.codegen.model.tree.CgNamedAnnotationArgument -import org.utbot.framework.codegen.model.tree.CgParameterDeclaration -import org.utbot.framework.codegen.model.tree.CgReturnStatement -import org.utbot.framework.codegen.model.tree.CgSingleArgAnnotation -import org.utbot.framework.codegen.model.tree.CgSingleLineComment -import org.utbot.framework.codegen.model.tree.CgThrowStatement -import org.utbot.framework.codegen.model.tree.CgTryCatch -import org.utbot.framework.codegen.model.tree.CgVariable -import org.utbot.framework.codegen.model.tree.buildAssignment -import org.utbot.framework.codegen.model.tree.buildDeclaration -import org.utbot.framework.codegen.model.tree.buildDoWhileLoop -import org.utbot.framework.codegen.model.tree.buildForLoop -import org.utbot.framework.codegen.model.tree.buildTryCatch -import org.utbot.framework.codegen.model.tree.buildWhileLoop -import org.utbot.framework.codegen.model.util.buildExceptionHandler -import org.utbot.framework.codegen.model.util.resolve +import org.utbot.framework.codegen.domain.context.CgContext +import org.utbot.framework.codegen.domain.context.CgContextOwner +import org.utbot.framework.codegen.domain.models.CgAnnotation +import org.utbot.framework.codegen.domain.models.CgAnonymousFunction +import org.utbot.framework.codegen.domain.models.CgComment +import org.utbot.framework.codegen.domain.models.CgDeclaration +import org.utbot.framework.codegen.domain.models.CgEmptyLine +import org.utbot.framework.codegen.domain.models.CgExpression +import org.utbot.framework.codegen.domain.models.CgIfStatement +import org.utbot.framework.codegen.domain.models.CgInnerBlock +import org.utbot.framework.codegen.domain.models.CgIsInstance +import org.utbot.framework.codegen.domain.models.CgLogicalAnd +import org.utbot.framework.codegen.domain.models.CgLogicalOr +import org.utbot.framework.codegen.domain.models.CgMultilineComment +import org.utbot.framework.codegen.domain.models.CgMultipleArgsAnnotation +import org.utbot.framework.codegen.domain.models.CgNamedAnnotationArgument +import org.utbot.framework.codegen.domain.models.CgParameterDeclaration +import org.utbot.framework.codegen.domain.models.CgReturnStatement +import org.utbot.framework.codegen.domain.models.CgSingleArgAnnotation +import org.utbot.framework.codegen.domain.models.CgSingleLineComment +import org.utbot.framework.codegen.domain.models.CgThrowStatement +import org.utbot.framework.codegen.domain.models.CgTryCatch +import org.utbot.framework.codegen.domain.models.CgVariable +import org.utbot.framework.codegen.services.access.CgCallableAccessManager +import org.utbot.framework.codegen.tree.CgForEachLoopBuilder +import org.utbot.framework.codegen.tree.CgForLoopBuilder +import org.utbot.framework.codegen.tree.CgStatementConstructor +import org.utbot.framework.codegen.tree.CgTestClassConstructor +import org.utbot.framework.codegen.tree.ExpressionWithType +import org.utbot.framework.codegen.tree.buildAssignment +import org.utbot.framework.codegen.tree.buildDeclaration +import org.utbot.framework.codegen.tree.buildDoWhileLoop +import org.utbot.framework.codegen.tree.buildExceptionHandler +import org.utbot.framework.codegen.tree.buildForLoop +import org.utbot.framework.codegen.tree.buildTryCatch +import org.utbot.framework.codegen.tree.buildWhileLoop +import org.utbot.framework.codegen.util.resolve import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.ExecutableId import org.utbot.framework.plugin.api.FieldId diff --git a/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgVariableConstructor.kt b/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgVariableConstructor.kt index 57c619225d..17e6cec972 100644 --- a/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgVariableConstructor.kt +++ b/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgVariableConstructor.kt @@ -1,17 +1,17 @@ package framework.codegen.model.constructor.tree -import org.utbot.framework.codegen.model.constructor.context.CgContext -import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor -import org.utbot.framework.codegen.model.constructor.tree.CgVariableConstructor -import org.utbot.framework.codegen.model.tree.CgLiteral -import org.utbot.framework.codegen.model.tree.CgValue -import org.utbot.framework.codegen.model.util.nullLiteral import org.utbot.framework.plugin.api.UtArrayModel import org.utbot.framework.plugin.api.UtAssembleModel import org.utbot.framework.plugin.api.UtCompositeModel import org.utbot.framework.plugin.api.UtModel import org.utbot.framework.plugin.api.UtReferenceModel import framework.api.js.JsPrimitiveModel +import org.utbot.framework.codegen.domain.context.CgContext +import org.utbot.framework.codegen.domain.models.CgLiteral +import org.utbot.framework.codegen.domain.models.CgValue +import org.utbot.framework.codegen.tree.CgTestClassConstructor +import org.utbot.framework.codegen.tree.CgVariableConstructor +import org.utbot.framework.codegen.util.nullLiteral class JsCgVariableConstructor(ctx: CgContext) : CgVariableConstructor(ctx) { diff --git a/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsTestFrameworkManager.kt b/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsTestFrameworkManager.kt index b40057d896..a65887abd2 100644 --- a/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsTestFrameworkManager.kt +++ b/utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsTestFrameworkManager.kt @@ -3,12 +3,12 @@ package framework.codegen.model.constructor.tree import framework.codegen.Mocha import framework.codegen.jsAssertEquals import framework.codegen.jsAssertThrows -import org.utbot.framework.codegen.model.constructor.TestClassContext -import org.utbot.framework.codegen.model.constructor.context.CgContext -import org.utbot.framework.codegen.model.constructor.tree.TestFrameworkManager -import org.utbot.framework.codegen.model.tree.CgAnnotation -import org.utbot.framework.codegen.model.tree.CgValue -import org.utbot.framework.codegen.model.tree.CgVariable +import org.utbot.framework.codegen.domain.context.CgContext +import org.utbot.framework.codegen.domain.context.TestClassContext +import org.utbot.framework.codegen.domain.models.CgAnnotation +import org.utbot.framework.codegen.domain.models.CgValue +import org.utbot.framework.codegen.domain.models.CgVariable +import org.utbot.framework.codegen.services.framework.TestFrameworkManager import org.utbot.framework.plugin.api.ClassId class MochaManager(context: CgContext) : TestFrameworkManager(context) { diff --git a/utbot-js/src/main/kotlin/framework/codegen/model/constructor/visitor/CgJsRenderer.kt b/utbot-js/src/main/kotlin/framework/codegen/model/constructor/visitor/CgJsRenderer.kt index 00e8d335a4..f4ae3f0b7c 100644 --- a/utbot-js/src/main/kotlin/framework/codegen/model/constructor/visitor/CgJsRenderer.kt +++ b/utbot-js/src/main/kotlin/framework/codegen/model/constructor/visitor/CgJsRenderer.kt @@ -1,14 +1,51 @@ package framework.codegen.model.constructor.visitor import org.apache.commons.text.StringEscapeUtils -import org.utbot.framework.codegen.RegularImport -import org.utbot.framework.codegen.StaticImport -import org.utbot.framework.codegen.isLanguageKeyword -import org.utbot.framework.codegen.model.tree.* -import org.utbot.framework.codegen.model.util.CgPrinter -import org.utbot.framework.codegen.model.util.CgPrinterImpl -import org.utbot.framework.codegen.model.visitor.CgAbstractRenderer -import org.utbot.framework.codegen.model.visitor.CgRendererContext +import org.utbot.framework.codegen.domain.RegularImport +import org.utbot.framework.codegen.domain.StaticImport +import org.utbot.framework.codegen.domain.models.CgAllocateArray +import org.utbot.framework.codegen.domain.models.CgAllocateInitializedArray +import org.utbot.framework.codegen.domain.models.CgAnonymousFunction +import org.utbot.framework.codegen.domain.models.CgArrayAnnotationArgument +import org.utbot.framework.codegen.domain.models.CgArrayElementAccess +import org.utbot.framework.codegen.domain.models.CgArrayInitializer +import org.utbot.framework.codegen.domain.models.CgClass +import org.utbot.framework.codegen.domain.models.CgClassBody +import org.utbot.framework.codegen.domain.models.CgClassFile +import org.utbot.framework.codegen.domain.models.CgConstructorCall +import org.utbot.framework.codegen.domain.models.CgDeclaration +import org.utbot.framework.codegen.domain.models.CgEqualTo +import org.utbot.framework.codegen.domain.models.CgErrorTestMethod +import org.utbot.framework.codegen.domain.models.CgErrorWrapper +import org.utbot.framework.codegen.domain.models.CgExecutableCall +import org.utbot.framework.codegen.domain.models.CgExpression +import org.utbot.framework.codegen.domain.models.CgFieldAccess +import org.utbot.framework.codegen.domain.models.CgForLoop +import org.utbot.framework.codegen.domain.models.CgGetJavaClass +import org.utbot.framework.codegen.domain.models.CgGetKotlinClass +import org.utbot.framework.codegen.domain.models.CgGetLength +import org.utbot.framework.codegen.domain.models.CgInnerBlock +import org.utbot.framework.codegen.domain.models.CgLiteral +import org.utbot.framework.codegen.domain.models.CgMethod +import org.utbot.framework.codegen.domain.models.CgMethodCall +import org.utbot.framework.codegen.domain.models.CgMultipleArgsAnnotation +import org.utbot.framework.codegen.domain.models.CgNamedAnnotationArgument +import org.utbot.framework.codegen.domain.models.CgNotNullAssertion +import org.utbot.framework.codegen.domain.models.CgParameterDeclaration +import org.utbot.framework.codegen.domain.models.CgParameterizedTestDataProviderMethod +import org.utbot.framework.codegen.domain.models.CgSpread +import org.utbot.framework.codegen.domain.models.CgStaticsRegion +import org.utbot.framework.codegen.domain.models.CgSwitchCase +import org.utbot.framework.codegen.domain.models.CgSwitchCaseLabel +import org.utbot.framework.codegen.domain.models.CgTestMethod +import org.utbot.framework.codegen.domain.models.CgThrowStatement +import org.utbot.framework.codegen.domain.models.CgTypeCast +import org.utbot.framework.codegen.domain.models.CgVariable +import org.utbot.framework.codegen.renderer.CgAbstractRenderer +import org.utbot.framework.codegen.renderer.CgPrinter +import org.utbot.framework.codegen.renderer.CgPrinterImpl +import org.utbot.framework.codegen.renderer.CgRendererContext +import org.utbot.framework.codegen.services.language.isLanguageKeyword import org.utbot.framework.plugin.api.BuiltinMethodId import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.TypeParameters diff --git a/utbot-js/src/main/kotlin/parser/IAstVisitor.kt b/utbot-js/src/main/kotlin/parser/IAstVisitor.kt new file mode 100644 index 0000000000..1d8bcf64a2 --- /dev/null +++ b/utbot-js/src/main/kotlin/parser/IAstVisitor.kt @@ -0,0 +1,8 @@ +package parser + +import com.google.javascript.rhino.Node + +interface IAstVisitor { + + fun accept(rootNode: Node) +} \ No newline at end of file diff --git a/utbot-js/src/main/kotlin/parser/JsClassAstVisitor.kt b/utbot-js/src/main/kotlin/parser/JsClassAstVisitor.kt index b6e385b5d8..925d9a22f1 100644 --- a/utbot-js/src/main/kotlin/parser/JsClassAstVisitor.kt +++ b/utbot-js/src/main/kotlin/parser/JsClassAstVisitor.kt @@ -1,26 +1,26 @@ package parser -import com.oracle.js.parser.ir.ClassNode -import com.oracle.js.parser.ir.LexicalContext -import com.oracle.js.parser.ir.visitor.NodeVisitor +import com.google.javascript.jscomp.NodeUtil +import com.google.javascript.rhino.Node +import parser.JsParserUtils.getClassName class JsClassAstVisitor( private val target: String? -) : NodeVisitor(LexicalContext()) { +): IAstVisitor { - lateinit var targetClassNode: ClassNode - lateinit var atLeastSomeClassNode: ClassNode + lateinit var targetClassNode: Node + lateinit var atLeastSomeClassNode: Node var classNodesCount = 0 - override fun enterClassNode(classNode: ClassNode?): Boolean { - classNode?.let { - classNodesCount++ - atLeastSomeClassNode = it - if (it.ident.name.toString() == target) { - targetClassNode = it - return false + override fun accept(rootNode: Node) = + NodeUtil.visitPreOrder(rootNode) { + if (it.isClass) { + classNodesCount++ + atLeastSomeClassNode = it + if (it.getClassName() == target) { + targetClassNode = it + return@visitPreOrder + } } } - return true - } } \ No newline at end of file diff --git a/utbot-js/src/main/kotlin/parser/JsFunctionAstVisitor.kt b/utbot-js/src/main/kotlin/parser/JsFunctionAstVisitor.kt index a7dc3a7b27..9b50843575 100644 --- a/utbot-js/src/main/kotlin/parser/JsFunctionAstVisitor.kt +++ b/utbot-js/src/main/kotlin/parser/JsFunctionAstVisitor.kt @@ -1,32 +1,41 @@ package parser -import com.oracle.js.parser.ir.ClassNode -import com.oracle.js.parser.ir.FunctionNode -import com.oracle.js.parser.ir.LexicalContext -import com.oracle.js.parser.ir.visitor.NodeVisitor +import com.google.javascript.jscomp.NodeUtil +import com.google.javascript.rhino.Node +import java.lang.IllegalStateException +import parser.JsParserUtils.getAbstractFunctionName +import parser.JsParserUtils.getClassName class JsFunctionAstVisitor( private val target: String, private val className: String? -) : NodeVisitor(LexicalContext()) { +): IAstVisitor { - private var lastVisitedClassName: String = "" - lateinit var targetFunctionNode: FunctionNode + lateinit var targetFunctionNode: Node - override fun enterClassNode(classNode: ClassNode?): Boolean { - classNode?.let { - lastVisitedClassName = it.ident.name.toString() - } - return true - } + override fun accept(rootNode: Node) { + NodeUtil.visitPreOrder(rootNode) { node -> + when { + node.isMemberFunctionDef -> { + val name = node.getAbstractFunctionName() + if ( + name == target && + (node.parent?.parent?.getClassName() + ?: throw IllegalStateException("Method AST node has no parent class node")) == className + ) { + targetFunctionNode = node + return@visitPreOrder + } + } - override fun enterFunctionNode(functionNode: FunctionNode?): Boolean { - functionNode?.let { - if (it.name.toString() == target && (className ?: "") == lastVisitedClassName) { - targetFunctionNode = it - return false + node.isFunction -> { + val name = node.getAbstractFunctionName() + if (name == target && className == null && node.parent?.isMemberFunctionDef != true) { + targetFunctionNode = node + return@visitPreOrder + } + } } } - return true } } \ No newline at end of file diff --git a/utbot-js/src/main/kotlin/parser/JsFuzzerAstVisitor.kt b/utbot-js/src/main/kotlin/parser/JsFuzzerAstVisitor.kt index 320c69407a..87eb146920 100644 --- a/utbot-js/src/main/kotlin/parser/JsFuzzerAstVisitor.kt +++ b/utbot-js/src/main/kotlin/parser/JsFuzzerAstVisitor.kt @@ -1,50 +1,50 @@ package parser -import com.oracle.js.parser.ir.BinaryNode -import com.oracle.js.parser.ir.CaseNode -import com.oracle.js.parser.ir.LexicalContext -import com.oracle.js.parser.ir.LiteralNode -import com.oracle.js.parser.ir.Node -import com.oracle.js.parser.ir.visitor.NodeVisitor -import com.oracle.truffle.api.strings.TruffleString +import com.google.javascript.jscomp.NodeUtil +import com.google.javascript.rhino.Node import framework.api.js.util.jsBooleanClassId import framework.api.js.util.jsNumberClassId import framework.api.js.util.jsStringClassId +import java.lang.IllegalStateException import org.utbot.fuzzer.FuzzedConcreteValue import org.utbot.fuzzer.FuzzedContext +import parser.JsParserUtils.getAnyValue +import parser.JsParserUtils.getBinaryExprLeftOperand +import parser.JsParserUtils.getBinaryExprRightOperand +import parser.JsParserUtils.toFuzzedContextComparisonOrNull -class JsFuzzerAstVisitor : NodeVisitor(LexicalContext()) { - private var lastFuzzedOpGlobal: FuzzedContext = FuzzedContext.Unknown +class JsFuzzerAstVisitor : IAstVisitor { + private var lastFuzzedOpGlobal: FuzzedContext = FuzzedContext.Unknown val fuzzedConcreteValues = mutableSetOf() - override fun enterCaseNode(caseNode: CaseNode?): Boolean { - caseNode?.test?.let { - validateNode(it) - } - return true - } - override fun enterBinaryNode(binaryNode: BinaryNode?): Boolean { - binaryNode?.let { binNode -> - val compOp = """>=|<=|>|<|==|!=""".toRegex() - val curOp = compOp.find(binNode.toString())?.value - val currentFuzzedOp = FuzzedContext.Comparison.values().find { curOp == it.sign } ?: FuzzedContext.Unknown - lastFuzzedOpGlobal = currentFuzzedOp - validateNode(binNode.lhs) - lastFuzzedOpGlobal = if (lastFuzzedOpGlobal is FuzzedContext.Comparison) (lastFuzzedOpGlobal as FuzzedContext.Comparison).reverse() else FuzzedContext.Unknown - validateNode(binNode.rhs) + override fun accept(rootNode: Node) { + NodeUtil.visitPreOrder(rootNode) { node -> + val currentFuzzedOp = node.toFuzzedContextComparisonOrNull() + when { + node.isCase -> validateNode( + node.firstChild?.getAnyValue() ?: + throw IllegalStateException("Case AST node has no children") + ) + currentFuzzedOp != null -> { + lastFuzzedOpGlobal = currentFuzzedOp + validateNode(node.getBinaryExprLeftOperand().getAnyValue()) + lastFuzzedOpGlobal = if (lastFuzzedOpGlobal is FuzzedContext.Comparison) + (lastFuzzedOpGlobal as FuzzedContext.Comparison).reverse() else FuzzedContext.Unknown + validateNode(node.getBinaryExprRightOperand().getAnyValue()) + } + } } - return true + } - private fun validateNode(literalNode: Node) { - if (literalNode !is LiteralNode<*>) return - when (literalNode.value) { - is TruffleString -> { + private fun validateNode(value: Any) { + when (value) { + is String -> { fuzzedConcreteValues.add( FuzzedConcreteValue( jsStringClassId, - literalNode.value.toString(), + value.toString(), lastFuzzedOpGlobal ) ) @@ -54,22 +54,14 @@ class JsFuzzerAstVisitor : NodeVisitor(LexicalContext()) { fuzzedConcreteValues.add( FuzzedConcreteValue( jsBooleanClassId, - literalNode.value, + value, lastFuzzedOpGlobal ) ) } - is Int -> { - fuzzedConcreteValues.add(FuzzedConcreteValue(jsNumberClassId, literalNode.value, lastFuzzedOpGlobal)) - } - - is Long -> { - fuzzedConcreteValues.add(FuzzedConcreteValue(jsNumberClassId, literalNode.value, lastFuzzedOpGlobal)) - } - is Double -> { - fuzzedConcreteValues.add(FuzzedConcreteValue(jsNumberClassId, literalNode.value, lastFuzzedOpGlobal)) + fuzzedConcreteValues.add(FuzzedConcreteValue(jsNumberClassId, value, lastFuzzedOpGlobal)) } } } diff --git a/utbot-js/src/main/kotlin/parser/JsParserUtils.kt b/utbot-js/src/main/kotlin/parser/JsParserUtils.kt index a5e5607ae7..b23f2d3d87 100644 --- a/utbot-js/src/main/kotlin/parser/JsParserUtils.kt +++ b/utbot-js/src/main/kotlin/parser/JsParserUtils.kt @@ -1,14 +1,18 @@ package parser -import com.oracle.js.parser.ir.ClassNode -import com.oracle.js.parser.ir.FunctionNode +import com.google.javascript.rhino.Node +import java.lang.IllegalStateException +import org.utbot.fuzzer.FuzzedContext +import parser.JsParserUtils.getMethodName +// Used for .children() calls. +@Suppress("DEPRECATION") object JsParserUtils { // TODO SEVERE: function only works in the same file scope. Add search in exports. - fun searchForClassDecl(className: String?, parsedFile: FunctionNode, strict: Boolean = false): ClassNode? { + fun searchForClassDecl(className: String?, parsedFile: Node, strict: Boolean = false): Node? { val visitor = JsClassAstVisitor(className) - parsedFile.accept(visitor) + visitor.accept(parsedFile) return try { visitor.targetClassNode } catch (e: Exception) { @@ -17,4 +21,122 @@ object JsParserUtils { } else null } } + + /** + * Called upon node with Class token. + */ + fun Node.getClassName(): String = + this.firstChild?.string ?: throw IllegalStateException("Class AST node has no children") + + /** + * Called upon node with Method token. + */ + private fun Node.getMethodName(): String = this.string + + /** + * Called upon node with Function token. + */ + private fun Node.getFunctionName(): String = + this.firstChild?.string ?: throw IllegalStateException("Function AST node has no children") + + /** + * Called upon node with Parameter token. + */ + fun Node.getParamName(): String = this.string + + /** + * Convenience method. Used as a wrapper for [getFunctionName] and [getMethodName] + * functions when the type of function is unknown. + */ + fun Node.getAbstractFunctionName(): String = when { + this.isMemberFunctionDef -> this.getMethodName() + this.isFunction -> this.getFunctionName() + else -> throw IllegalStateException() + } + + /** + * Called upon node with any kind of literal value token. + */ + fun Node.getAnyValue(): Any = when { + this.isNumber -> this.double + this.isString || this.isName -> this.string + this.isTrue -> true + this.isFalse -> false + else -> throw UnsupportedOperationException("Not yet implemented!") + } + + // For some reason Closure Compiler doesn't contain a built-in method + // to check for some tokens. + /** + * Called upon node with any kind of binary comparison token. + */ + fun Node.toFuzzedContextComparisonOrNull(): FuzzedContext.Comparison? = when { + this.isEQ -> FuzzedContext.Comparison.EQ + this.isNE -> FuzzedContext.Comparison.NE + this.token.name == "LT" -> FuzzedContext.Comparison.LT + this.token.name == "GT" -> FuzzedContext.Comparison.GT + this.token.name == "LE" -> FuzzedContext.Comparison.LE + this.token.name == "GE" -> FuzzedContext.Comparison.GE + this.token.name == "SHEQ" -> FuzzedContext.Comparison.EQ + else -> null + } + + /** + * Called upon node with any kind of binary comparison token. + */ + fun Node.getBinaryExprLeftOperand(): Node = this.getChildAtIndex(0) + + /** + * Called upon node with any kind of binary comparison token. + */ + fun Node.getBinaryExprRightOperand(): Node = this.getChildAtIndex(1) + + /** + * Called upon node with Function token. + */ + private fun Node.getFunctionParams(): List = this.getChildAtIndex(1).children().map { it } + + /** + * Called upon node with Method token. + */ + private fun Node.getMethodParams(): List = + this.firstChild?.getFunctionParams() ?: throw IllegalStateException("Method AST node has no children") + + /** + * Convenience method. Used as a wrapper for [getFunctionParams] and [getMethodParams] + * function when the type of function is unknown. + */ + fun Node.getAbstractFunctionParams(): List = when { + this.isMemberFunctionDef -> getMethodParams() + this.isFunction -> getFunctionParams() + else -> throw IllegalStateException() + } + + /** + * Called upon node with Class token. + */ + fun Node.getClassMethods(): List { + val classMembers = this.children().find { it.isClassMembers } + ?: throw IllegalStateException("Can't extract class members of class ${this.getClassName()}") + return classMembers.children().filter { it.isMemberFunctionDef } + + } + + /** + * Called upon node with Class token. + * + * Returns null if class has no constructor. + */ + fun Node.getConstructor(): Node? { + val classMembers = this.children().find { it.isClassMembers } + ?: throw IllegalStateException("Can't extract methods of class ${this.getClassName()}") + return classMembers.children().find { + it.isMemberFunctionDef && it.getMethodName() == "constructor" + }?.firstChild + } + + /** + * Called upon node with Method token. + */ + fun Node.isStatic(): Boolean = this.isStaticMember } \ No newline at end of file diff --git a/utbot-js/src/main/kotlin/parser/JsToplevelFunctionAstVisitor.kt b/utbot-js/src/main/kotlin/parser/JsToplevelFunctionAstVisitor.kt index e77db964fa..92e32d3b0e 100644 --- a/utbot-js/src/main/kotlin/parser/JsToplevelFunctionAstVisitor.kt +++ b/utbot-js/src/main/kotlin/parser/JsToplevelFunctionAstVisitor.kt @@ -1,22 +1,18 @@ package parser -import com.oracle.js.parser.ir.ClassNode -import com.oracle.js.parser.ir.FunctionNode -import com.oracle.js.parser.ir.LexicalContext -import com.oracle.js.parser.ir.visitor.NodeVisitor +import com.google.javascript.jscomp.NodeUtil +import com.google.javascript.rhino.Node -class JsToplevelFunctionAstVisitor : NodeVisitor(LexicalContext()) { +class JsToplevelFunctionAstVisitor : IAstVisitor { - val extractedMethods = mutableListOf() + val extractedMethods = mutableListOf() - override fun enterClassNode(classNode: ClassNode?): Boolean { - return false - } - override fun enterFunctionNode(functionNode: FunctionNode?): Boolean { - functionNode?.let { - extractedMethods += it + override fun accept(rootNode: Node) { + NodeUtil.visitPreOrder(rootNode) { node -> + when { + node.isFunction && !(node.parent?.isMemberFunctionDef ?: true) -> extractedMethods += node + } } - return false } } \ No newline at end of file diff --git a/utbot-js/src/main/kotlin/service/BasicCoverageService.kt b/utbot-js/src/main/kotlin/service/BasicCoverageService.kt index e7df5631a2..c0b4907364 100644 --- a/utbot-js/src/main/kotlin/service/BasicCoverageService.kt +++ b/utbot-js/src/main/kotlin/service/BasicCoverageService.kt @@ -46,6 +46,8 @@ class BasicCoverageService( } } return res + } catch (e: Exception) { + throw Exception("Could not get coverage of test cases!") } finally { removeTempFiles() } @@ -140,4 +142,4 @@ class BasicCoverageService( file.writeText(scriptText) file.createNewFile() } -} +} \ No newline at end of file diff --git a/utbot-js/src/main/kotlin/service/CoverageServiceProvider.kt b/utbot-js/src/main/kotlin/service/CoverageServiceProvider.kt index 2c632e757e..629b91dfd8 100644 --- a/utbot-js/src/main/kotlin/service/CoverageServiceProvider.kt +++ b/utbot-js/src/main/kotlin/service/CoverageServiceProvider.kt @@ -1,13 +1,13 @@ package service -import com.oracle.js.parser.ir.ClassNode -import com.oracle.truffle.api.strings.TruffleString +import com.google.javascript.rhino.Node import org.utbot.framework.plugin.api.UtAssembleModel import org.utbot.framework.plugin.api.UtModel import framework.api.js.JsMethodId import framework.api.js.JsPrimitiveModel import org.utbot.framework.plugin.api.util.isStatic import org.utbot.fuzzer.FuzzedValue +import parser.JsParserUtils.getClassName import settings.JsTestGenerationSettings import settings.JsTestGenerationSettings.tempFileName import utils.PathResolver @@ -24,7 +24,7 @@ class CoverageServiceProvider(private val context: ServiceContext) { mode: CoverageMode, fuzzedValues: List>, execId: JsMethodId, - classNode: ClassNode? + classNode: Node? ): Pair>, List> { return when (mode) { CoverageMode.FAST -> runFastCoverageAnalysis( @@ -47,13 +47,13 @@ class CoverageServiceProvider(private val context: ServiceContext) { context: ServiceContext, fuzzedValues: List>, execId: JsMethodId, - classNode: ClassNode?, + classNode: Node?, ): Pair>, List> { val tempScriptTexts = fuzzedValues.indices.map { "const ${JsTestGenerationSettings.fileUnderTestAliases} = require(\"./${PathResolver.getRelativePath("${context.projectPath}/${context.utbotDir}", context.filePathToInference)}\")\n" + "const fs = require(\"fs\")\n\n" + makeStringForRunJs( fuzzedValue = fuzzedValues[it], method = execId, - containingClass = classNode?.ident?.name, + containingClass = classNode?.getClassName(), index = it, resFilePath = "${context.projectPath}/${context.utbotDir}/$tempFileName", mode = CoverageMode.BASIC @@ -71,14 +71,14 @@ class CoverageServiceProvider(private val context: ServiceContext) { context: ServiceContext, fuzzedValues: List>, execId: JsMethodId, - classNode: ClassNode?, + classNode: Node?, ): Pair>, List> { val covFunName = FastCoverageService.instrument(context) val tempScriptTexts = fuzzedValues.indices.map { makeStringForRunJs( fuzzedValue = fuzzedValues[it], method = execId, - containingClass = classNode?.ident?.name, + containingClass = classNode?.getClassName(), covFunName = covFunName, index = it, resFilePath = "${context.projectPath}/${context.utbotDir}/$tempFileName", @@ -128,7 +128,7 @@ fs.writeFileSync("$resFilePath", JSON.stringify(json)) private fun makeStringForRunJs( fuzzedValue: List, method: JsMethodId, - containingClass: TruffleString?, + containingClass: String?, covFunName: String = "", index: Int, resFilePath: String, @@ -156,7 +156,7 @@ fs.writeFileSync("$resFilePath$index.json", JSON.stringify(json$index)) private fun makeCallFunctionString( fuzzedValue: List, method: JsMethodId, - containingClass: TruffleString? + containingClass: String? ): String { val initClass = containingClass?.let { if (!method.isStatic) { @@ -196,4 +196,4 @@ fs.writeFileSync("$resFilePath$index.json", JSON.stringify(json$index)) (this as JsPrimitiveModel).value.quoteWrapIfNecessary() } } -} \ No newline at end of file +} diff --git a/utbot-js/src/main/kotlin/service/ServiceContext.kt b/utbot-js/src/main/kotlin/service/ServiceContext.kt index 4264120de2..c85e40388f 100644 --- a/utbot-js/src/main/kotlin/service/ServiceContext.kt +++ b/utbot-js/src/main/kotlin/service/ServiceContext.kt @@ -1,12 +1,12 @@ package service -import com.oracle.js.parser.ir.FunctionNode +import com.google.javascript.rhino.Node import settings.JsDynamicSettings data class ServiceContext( val utbotDir: String, val projectPath: String, val filePathToInference: String, - val parsedFile: FunctionNode, + val parsedFile: Node, val settings: JsDynamicSettings, ) \ No newline at end of file diff --git a/utbot-js/src/main/kotlin/service/TernService.kt b/utbot-js/src/main/kotlin/service/TernService.kt index 2c3c1a9560..fff33af9bb 100644 --- a/utbot-js/src/main/kotlin/service/TernService.kt +++ b/utbot-js/src/main/kotlin/service/TernService.kt @@ -1,7 +1,6 @@ package service -import com.oracle.js.parser.ir.ClassNode -import com.oracle.js.parser.ir.FunctionNode +import com.google.javascript.rhino.Node import framework.api.js.JsClassId import framework.api.js.JsMultipleClassId import framework.api.js.util.jsUndefinedClassId @@ -10,6 +9,10 @@ import java.util.Locale import org.json.JSONException import org.json.JSONObject import parser.JsParserUtils +import parser.JsParserUtils.getAbstractFunctionName +import parser.JsParserUtils.getAbstractFunctionParams +import parser.JsParserUtils.getClassName +import parser.JsParserUtils.getConstructor import utils.JsCmdExec import utils.MethodTypes import utils.constructClass @@ -104,14 +107,14 @@ test("${context.filePathToInference}") } } - fun processConstructor(classNode: ClassNode): List { + fun processConstructor(classNode: Node): List { return try { - val classJson = json.getJSONObject(classNode.ident.name.toString()) + val classJson = json.getJSONObject(classNode.getClassName()) val constructorFunc = classJson.getString("!type") .filterNot { setOf(' ', '+', '!').contains(it) } extractParameters(constructorFunc) } catch (e: JSONException) { - (classNode.constructor.value as FunctionNode).parameters.map { jsUndefinedClassId } + classNode.getConstructor()?.getAbstractFunctionParams()?.map { jsUndefinedClassId } ?: emptyList() } } @@ -146,18 +149,18 @@ test("${context.filePathToInference}") } ?: jsUndefinedClassId } - fun processMethod(className: String?, funcNode: FunctionNode, isToplevel: Boolean = false): MethodTypes { + fun processMethod(className: String?, funcNode: Node, isToplevel: Boolean = false): MethodTypes { // Js doesn't support nested classes, so if the function is not top-level, then we can check for only one parent class. try { var scope = className?.let { if (!isToplevel) json.getJSONObject(it) else json } ?: json try { - scope.getJSONObject(funcNode.name.toString()) + scope.getJSONObject(funcNode.getAbstractFunctionName()) } catch (e: JSONException) { scope = scope.getJSONObject("prototype") } - val methodJson = scope.getJSONObject(funcNode.name.toString()) + val methodJson = scope.getJSONObject(funcNode.getAbstractFunctionName()) val typesString = methodJson.getString("!type") .filterNot { setOf(' ', '+', '!').contains(it) } val parametersList = lazy { extractParameters(typesString) } @@ -166,7 +169,7 @@ test("${context.filePathToInference}") return MethodTypes(parametersList, returnType) } catch (e: Exception) { return MethodTypes( - lazy { funcNode.parameters.map { jsUndefinedClassId } }, + lazy { funcNode.getAbstractFunctionParams().map { jsUndefinedClassId } }, lazy { jsUndefinedClassId } ) } diff --git a/utbot-js/src/main/kotlin/utils/JsClassConstructors.kt b/utbot-js/src/main/kotlin/utils/JsClassConstructors.kt index 7cbfd41add..ae175c4cbd 100644 --- a/utbot-js/src/main/kotlin/utils/JsClassConstructors.kt +++ b/utbot-js/src/main/kotlin/utils/JsClassConstructors.kt @@ -1,19 +1,22 @@ package utils -import com.oracle.js.parser.ir.ClassNode -import com.oracle.js.parser.ir.FunctionNode +import com.google.javascript.rhino.Node import framework.api.js.JsClassId import framework.api.js.JsConstructorId import framework.api.js.JsMethodId import framework.api.js.util.jsUndefinedClassId +import parser.JsParserUtils.getAbstractFunctionName +import parser.JsParserUtils.getClassMethods +import parser.JsParserUtils.getClassName +import parser.JsParserUtils.isStatic import service.TernService fun JsClassId.constructClass( ternService: TernService, - classNode: ClassNode? = null, - functions: List = emptyList() + classNode: Node? = null, + functions: List = emptyList() ): JsClassId { - val className = classNode?.ident?.name?.toString() + val className = classNode?.getClassName() val methods = constructMethods(classNode, ternService, className, functions) val constructor = classNode?.let { @@ -37,21 +40,20 @@ fun JsClassId.constructClass( } private fun JsClassId.constructMethods( - classNode: ClassNode?, + classNode: Node?, ternService: TernService, className: String?, - functions: List + functions: List ): Sequence { with(this) { - val methods = classNode?.classElements?.map { - val funcNode = it.value as FunctionNode - val types = ternService.processMethod(className, funcNode) + val methods = classNode?.getClassMethods()?.map { methodNode -> + val types = ternService.processMethod(className, methodNode) JsMethodId( classId = JsClassId(name), - name = funcNode.name.toString(), + name = methodNode.getAbstractFunctionName(), returnTypeNotLazy = jsUndefinedClassId, parametersNotLazy = emptyList(), - staticModifier = it.isStatic, + staticModifier = methodNode.isStatic(), lazyReturnType = types.returnType, lazyParameters = types.parameters, ) @@ -61,7 +63,7 @@ private fun JsClassId.constructMethods( val types = ternService.processMethod(className, funcNode, true) JsMethodId( classId = JsClassId(name), - name = funcNode.name.toString(), + name = funcNode.getAbstractFunctionName(), returnTypeNotLazy = jsUndefinedClassId, parametersNotLazy = emptyList(), staticModifier = true, diff --git a/utbot-js/src/main/kotlin/utils/ValueUtil.kt b/utbot-js/src/main/kotlin/utils/ValueUtil.kt index 80842e9b04..42ba89d911 100644 --- a/utbot-js/src/main/kotlin/utils/ValueUtil.kt +++ b/utbot-js/src/main/kotlin/utils/ValueUtil.kt @@ -14,7 +14,7 @@ fun String.toJsAny(returnType: JsClassId): Pair { this == "true" || this == "false" -> toBoolean() to jsBooleanClassId this == "null" || this == "undefined" -> null to jsUndefinedClassId Regex("^.*Error:.*").matches(this) -> this.replace("Error:", "") to jsErrorClassId - Regex("\".*\"").matches(this) -> this.replace("\"", "") to jsStringClassId + returnType == jsStringClassId -> this.replace("\"", "") to jsStringClassId else -> { if (contains('.')) { (toDoubleOrNull() ?: toBigDecimal()) to jsNumberClassId