[JS TESTS] Rewrite js tests using new test infrastructure

This commit is contained in:
Ivan Kylchik
2021-08-28 15:51:42 +03:00
parent 4deab9693e
commit a2d2ace71a
51 changed files with 17973 additions and 11986 deletions
@@ -17,4 +17,8 @@ abstract class ModuleStructureExtractor @OptIn(TestInfrastructureInternals::clas
testDataFileName: String,
directivesContainer: DirectivesContainer,
): TestModuleStructure
companion object {
const val DEFAULT_MODULE_NAME = "main"
}
}
@@ -100,3 +100,6 @@ val TestFile.isKtsFile: Boolean
val TestFile.isJavaFile: Boolean
get() = name.endsWith(".java")
val TestFile.isJsFile: Boolean
get() = name.endsWith(".js")
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.test.backend.classic
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.psi.KtFile
@@ -16,8 +17,7 @@ import org.jetbrains.kotlin.test.model.ResultingArtifact
// Old backend (JVM and JS)
data class ClassicBackendInput(
val psiFiles: Collection<KtFile>,
val bindingContext: BindingContext,
val moduleDescriptor: ModuleDescriptor,
val analysisResult: AnalysisResult,
val project: Project,
val languageVersionSettings: LanguageVersionSettings
) : ResultingArtifact.BackendInput<ClassicBackendInput>() {
@@ -30,13 +30,13 @@ class ClassicJvmBackendFacade(
inputArtifact: ClassicBackendInput
): BinaryArtifacts.Jvm {
val configuration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
val (psiFiles, bindingContext, moduleDescriptor, project, _) = inputArtifact
val (psiFiles, analysisResult, project, _) = inputArtifact
// TODO: add configuring classBuilderFactory
val generationState = GenerationState.Builder(
project,
ClassBuilderFactories.TEST,
moduleDescriptor,
bindingContext,
analysisResult.moduleDescriptor,
analysisResult.bindingContext,
psiFiles.toList(),
configuration
).codegenFactory(DefaultCodegenFactory).build()
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
import org.jetbrains.kotlin.test.backend.ir.JvmIrBackendFacade
import org.jetbrains.kotlin.test.builders.CompilerStepsNames.CLASSIC_FRONTEND_HANDLERS_STEP_NAME
import org.jetbrains.kotlin.test.builders.CompilerStepsNames.FIR_HANDLERS_STEP_NAME
import org.jetbrains.kotlin.test.builders.CompilerStepsNames.JS_ARTIFACTS_HANDLERS_STEP_NAME
import org.jetbrains.kotlin.test.builders.CompilerStepsNames.JVM_ARTIFACTS_HANDLERS_STEP_NAME
import org.jetbrains.kotlin.test.builders.CompilerStepsNames.RAW_IR_HANDLERS_STEP_NAME
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontend2ClassicBackendConverter
@@ -35,6 +36,7 @@ object CompilerStepsNames {
const val JVM_BACKEND_STEP_NAME = "jvm backend"
const val JVM_ARTIFACTS_HANDLERS_STEP_NAME = "jvm artifacts handlers"
const val JS_ARTIFACTS_HANDLERS_STEP_NAME = "js artifacts handlers"
}
@@ -95,6 +97,12 @@ inline fun TestConfigurationBuilder.jvmArtifactsHandlersStep(
namedHandlersStep(JVM_ARTIFACTS_HANDLERS_STEP_NAME, ArtifactKinds.Jvm, init)
}
inline fun TestConfigurationBuilder.jsArtifactsHandlersStep(
init: HandlersStepBuilder<BinaryArtifacts.Js>.() -> Unit = {}
) {
namedHandlersStep(JS_ARTIFACTS_HANDLERS_STEP_NAME, ArtifactKinds.Js, init)
}
// and those ones to configure already defined step
inline fun TestConfigurationBuilder.configureClassicFrontendHandlersStep(
init: HandlersStepBuilder<ClassicFrontendOutputArtifact>.() -> Unit = {}
@@ -119,3 +127,9 @@ inline fun TestConfigurationBuilder.configureJvmArtifactsHandlersStep(
) {
configureNamedHandlersStep(JVM_ARTIFACTS_HANDLERS_STEP_NAME, ArtifactKinds.Jvm, init)
}
inline fun TestConfigurationBuilder.configureJsArtifactsHandlersStep(
init: HandlersStepBuilder<BinaryArtifacts.Js>.() -> Unit = {}
) {
configureNamedHandlersStep(JS_ARTIFACTS_HANDLERS_STEP_NAME, ArtifactKinds.Js, init)
}
@@ -5,9 +5,185 @@
package org.jetbrains.kotlin.test.directives
import org.jetbrains.kotlin.cli.common.arguments.K2JsArgumentConstants
import org.jetbrains.kotlin.js.config.ErrorTolerancePolicy
import org.jetbrains.kotlin.js.config.RuntimeDiagnostic
import org.jetbrains.kotlin.js.config.SourceMapSourceEmbedding
import org.jetbrains.kotlin.serialization.js.ModuleKind
import org.jetbrains.kotlin.test.directives.model.DirectiveApplicability
import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer
// TODO fill up all descriptions
object JsEnvironmentConfigurationDirectives : SimpleDirectivesContainer() {
val MODULE_KIND by enumDirective<ModuleKind>("Specifies kind of js module")
val MODULE_KIND by enumDirective<ModuleKind>(
description = "Specifies kind of js module",
applicability = DirectiveApplicability.Module
)
val NO_JS_MODULE_SYSTEM by directive(
description = "",
applicability = DirectiveApplicability.Global
)
val INFER_MAIN_MODULE by directive(
description = "Infer main module automatically using dependency graph",
applicability = DirectiveApplicability.Global
)
val RUN_PLAIN_BOX_FUNCTION by directive(
description = "",
applicability = DirectiveApplicability.Global
)
val NO_INLINE by directive(
description = "Disable inline in js module",
applicability = DirectiveApplicability.Module
)
val SKIP_NODE_JS by directive(
description = "",
applicability = DirectiveApplicability.Global
)
val SKIP_MINIFICATION by directive(
description = "",
applicability = DirectiveApplicability.Global
)
val SKIP_SOURCEMAP_REMAPPING by directive(
description = "",
applicability = DirectiveApplicability.Global
)
val EXPECTED_REACHABLE_NODES by valueDirective(
description = "",
applicability = DirectiveApplicability.Global,
parser = { it.toIntOrNull() }
)
val RECOMPILE by directive(
description = "",
applicability = DirectiveApplicability.File
)
val SOURCE_MAP_EMBED_SOURCES by enumDirective<SourceMapSourceEmbedding>(
description = "",
applicability = DirectiveApplicability.Module
)
val CALL_MAIN by directive(
description = "",
applicability = DirectiveApplicability.Global
)
val KJS_WITH_FULL_RUNTIME by directive(
description = "",
applicability = DirectiveApplicability.Global
)
val EXPECT_ACTUAL_LINKER by directive(
description = "",
applicability = DirectiveApplicability.Global
)
val SKIP_DCE_DRIVEN by directive(
description = "",
applicability = DirectiveApplicability.Global
)
val SPLIT_PER_MODULE by directive(
description = "",
applicability = DirectiveApplicability.Global
)
val SKIP_MANGLE_VERIFICATION by directive(
description = "",
applicability = DirectiveApplicability.Global
)
val ERROR_POLICY by enumDirective<ErrorTolerancePolicy>(
description = "",
applicability = DirectiveApplicability.Global,
additionalParser = { ErrorTolerancePolicy.resolvePolicy(it) }
)
val PROPERTY_LAZY_INITIALIZATION by directive(
description = "",
applicability = DirectiveApplicability.Global
)
val SAFE_EXTERNAL_BOOLEAN by directive(
description = "",
applicability = DirectiveApplicability.Global
)
val SAFE_EXTERNAL_BOOLEAN_DIAGNOSTIC by enumDirective<RuntimeDiagnostic>(
description = "",
applicability = DirectiveApplicability.Global,
additionalParser = {
when (it.lowercase()) {
K2JsArgumentConstants.RUNTIME_DIAGNOSTIC_LOG -> RuntimeDiagnostic.LOG
K2JsArgumentConstants.RUNTIME_DIAGNOSTIC_EXCEPTION -> RuntimeDiagnostic.EXCEPTION
else -> null
}
}
)
val DONT_RUN_GENERATED_CODE by stringDirective(
description = "Specify target backend on which generated code will not be run",
applicability = DirectiveApplicability.Global,
)
// Next directives are used only inside test system and must not be present in test file
val PATH_TO_TEST_DIR by stringDirective(
description = "Specify the path to directory with test files. " +
"This path is used to copy hierarchy from test file to test dir and use the same hierarchy in output dir.",
applicability = DirectiveApplicability.Global
)
val PATH_TO_ROOT_OUTPUT_DIR by stringDirective(
description = "Specify the path to output directory, where all artifacts will be stored",
applicability = DirectiveApplicability.Global
)
val TEST_GROUP_OUTPUT_DIR_PREFIX by stringDirective(
description = "Specify the prefix directory for output directory that will contains artifacts",
applicability = DirectiveApplicability.Global
)
val TYPED_ARRAYS by directive(
description = "Enables typed arrays",
applicability = DirectiveApplicability.Global
)
val GENERATE_SOURCE_MAP by directive(
description = "Enables generation of source map",
applicability = DirectiveApplicability.Global
)
val GENERATE_NODE_JS_RUNNER by directive(
description = "Enables generation of `.node.js` file",
applicability = DirectiveApplicability.Global
)
val RUN_MINIFIER_BY_DEFAULT by directive(
description = "Enables minifier even if `EXPECTED_REACHABLE_NODES` directive is not set",
applicability = DirectiveApplicability.Global
)
val SKIP_REGULAR_MODE by directive(
description = "Disable js runner for common js and dce files",
applicability = DirectiveApplicability.Global
)
val RUN_IR_DCE by directive(
description = "Enables dead code elimination on IR",
applicability = DirectiveApplicability.Global
)
val RUN_IR_PIR by directive(
description = "Enables pir on IR", // TODO what `pir` stands for?
applicability = DirectiveApplicability.Global
)
}
@@ -23,8 +23,7 @@ class ClassicFrontend2ClassicBackendConverter(
val (psiFiles, analysisResults, project, languageVersionSettings) = inputArtifact
return ClassicBackendInput(
psiFiles.values,
analysisResults.bindingContext,
analysisResults.moduleDescriptor,
analysisResults,
project,
languageVersionSettings
)
@@ -31,7 +31,6 @@ import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.incremental.components.InlineConstTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS
import org.jetbrains.kotlin.js.config.JsConfig
import org.jetbrains.kotlin.load.java.lazy.SingleModuleClassResolver
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager
import org.jetbrains.kotlin.name.Name
@@ -54,6 +53,7 @@ import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.model.*
import org.jetbrains.kotlin.test.services.*
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import org.jetbrains.kotlin.test.util.KtTestUtil
import org.jetbrains.kotlin.utils.addToStdlib.runIf
import java.io.File
@@ -244,18 +244,16 @@ class ClassicFrontendFacade(
files: List<KtFile>,
dependentDescriptors: List<ModuleDescriptorImpl>
): AnalysisResult {
val jsConfig = JsConfig(project, configuration, CompilerEnvironment)
val dependentDescriptorsIncludingLibraries = buildList {
addAll(dependentDescriptors)
addAll(jsConfig.moduleDescriptors)
}
// `dependentDescriptors` - modules with source dependency kind
// 'jsConfig.moduleDescriptors' - modules with binary dependency kind
val jsConfig = JsEnvironmentConfigurator.createJsConfig(project, configuration)
return TopDownAnalyzerFacadeForJS.analyzeFiles(
files,
project,
configuration,
moduleDescriptors = dependentDescriptorsIncludingLibraries,
friendModuleDescriptors = emptyList(),
CompilerEnvironment,
project = jsConfig.project,
configuration = jsConfig.configuration,
moduleDescriptors = dependentDescriptors + jsConfig.moduleDescriptors,
friendModuleDescriptors = jsConfig.friendModuleDescriptors,
targetEnvironment = jsConfig.targetEnvironment,
)
}
@@ -6,6 +6,10 @@
package org.jetbrains.kotlin.test.model
import org.jetbrains.kotlin.codegen.ClassFileFactory
import org.jetbrains.kotlin.ir.backend.js.CompilerResult
import org.jetbrains.kotlin.js.backend.ast.JsProgram
import org.jetbrains.kotlin.js.facade.TranslationResult
import java.io.File
object BinaryArtifacts {
class Jvm(val classFileFactory: ClassFileFactory) : ResultingArtifact.Binary<Jvm>() {
@@ -13,9 +17,14 @@ object BinaryArtifacts {
get() = ArtifactKinds.Jvm
}
class Js : ResultingArtifact.Binary<Js>() {
sealed class Js : ResultingArtifact.Binary<Js>() {
abstract val outputFile: File
override val kind: BinaryKind<Js>
get() = ArtifactKinds.Js
class OldJsArtifact(override val outputFile: File, val translationResult: TranslationResult) : Js()
class JsIrArtifact(override val outputFile: File, val compilerResult: CompilerResult) : Js()
}
class Native : ResultingArtifact.Binary<Native>() {
@@ -15,7 +15,7 @@ import java.io.IOException
import org.junit.jupiter.api.Assertions as JUnit5PlatformAssertions
object JUnit5Assertions : AssertionsService() {
private val isTeamCityBuild: Boolean = System.getenv("TEAMCITY_VERSION") != null
val isTeamCityBuild: Boolean = System.getenv("TEAMCITY_VERSION") != null
override fun assertEqualsToFile(expectedFile: File, actual: String, sanitizer: (String) -> String, message: () -> String) {
try {
@@ -5,31 +5,168 @@
package org.jetbrains.kotlin.test.services.configuration
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.config.JsConfig
import org.jetbrains.kotlin.js.config.*
import org.jetbrains.kotlin.resolve.CompilerEnvironment
import org.jetbrains.kotlin.serialization.js.JsModuleDescriptor
import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil
import org.jetbrains.kotlin.serialization.js.ModuleKind
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives.MODULE_KIND
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives.NO_INLINE
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives.ERROR_POLICY
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives.SOURCE_MAP_EMBED_SOURCES
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives.EXPECT_ACTUAL_LINKER
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives.TYPED_ARRAYS
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
import org.jetbrains.kotlin.test.model.DependencyDescription
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.EnvironmentConfigurator
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.*
import org.jetbrains.kotlin.test.util.joinToArrayString
import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeAsciiOnly
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils
import java.io.File
class JsEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigurator(testServices) {
override val directiveContainers: List<DirectivesContainer>
get() = listOf(JsEnvironmentConfigurationDirectives)
companion object {
const val TEST_DATA_DIR_PATH = "js/js.translator/testData"
const val OLD_MODULE_SUFFIX = "_old"
private const val OUTPUT_DIR_NAME = "outputDir"
private const val DCE_OUTPUT_DIR_NAME = "dceOutputDir"
private const val PIR_OUTPUT_DIR_NAME = "pirOutputDir"
private const val MINIFICATION_OUTPUT_DIR_NAME = "minOutputDir"
object ExceptionThrowingReporter : JsConfig.Reporter() {
override fun error(message: String) {
throw AssertionError("Error message reported: $message")
}
}
private val METADATA_CACHE = (JsConfig.JS_STDLIB + JsConfig.JS_KOTLIN_TEST).flatMap { path ->
KotlinJavascriptMetadataUtils.loadMetadata(path).map { metadata ->
val parts = KotlinJavascriptSerializationUtil.readModuleAsProto(metadata.body, metadata.version)
JsModuleDescriptor(metadata.moduleName, parts.kind, parts.importedModules, parts)
}
}
fun getJsArtifactSimpleName(testServices: TestServices, moduleName: String): String {
val testName = testServices.testInfo.methodName.removePrefix("test").decapitalizeAsciiOnly()
val outputFileSuffix = if (moduleName == ModuleStructureExtractor.DEFAULT_MODULE_NAME) "" else "-$moduleName"
return testName + outputFileSuffix
}
fun getJsModuleArtifactPath(testServices: TestServices, moduleName: String): String {
return getJsArtifactsOutputDir(testServices).absolutePath + "/" + getJsArtifactSimpleName(testServices, moduleName) + "_v5"
}
fun getJsArtifactsOutputDir(testServices: TestServices): File {
return testServices.temporaryDirectoryManager.getOrCreateTempDirectory(OUTPUT_DIR_NAME)
}
fun getDceJsArtifactsOutputDir(testServices: TestServices): File {
return testServices.temporaryDirectoryManager.getOrCreateTempDirectory(DCE_OUTPUT_DIR_NAME)
}
fun getPirJsArtifactsOutputDir(testServices: TestServices): File {
return testServices.temporaryDirectoryManager.getOrCreateTempDirectory(PIR_OUTPUT_DIR_NAME)
}
fun getMinificationJsArtifactsOutputDir(testServices: TestServices): File {
return testServices.temporaryDirectoryManager.getOrCreateTempDirectory(MINIFICATION_OUTPUT_DIR_NAME)
}
private fun getPrefixPostfixFile(module: TestModule, prefix: Boolean): File? {
val suffix = if (prefix) ".prefix" else ".postfix"
val originalFile = module.files.first().originalFile
return originalFile.parentFile.resolve(originalFile.name + suffix).takeIf { it.exists() }
}
fun getPrefixFile(module: TestModule): File? = getPrefixPostfixFile(module, prefix = true)
fun getPostfixFile(module: TestModule): File? = getPrefixPostfixFile(module, prefix = false)
fun createJsConfig(project: Project, configuration: CompilerConfiguration): JsConfig {
return JsConfig(
project, configuration, CompilerEnvironment, METADATA_CACHE, (JsConfig.JS_STDLIB + JsConfig.JS_KOTLIN_TEST).toSet()
)
}
}
private fun TestModule.allTransitiveDependencies(): Set<DependencyDescription> {
val modules = testServices.moduleStructure.modules
return regularDependencies.toSet() +
regularDependencies.flatMap { modules.single { module -> module.name == it.moduleName }.allTransitiveDependencies() }
}
override fun configureCompilerConfiguration(configuration: CompilerConfiguration, module: TestModule) {
val moduleKinds = module.directives[JsEnvironmentConfigurationDirectives.MODULE_KIND]
val registeredDirectives = module.directives
val moduleKinds = registeredDirectives[MODULE_KIND]
val moduleKind = when (moduleKinds.size) {
0 -> ModuleKind.PLAIN
0 -> testServices.moduleStructure.allDirectives[MODULE_KIND].singleOrNull() ?: ModuleKind.PLAIN
1 -> moduleKinds.single()
else -> error("Too many module kinds passed ${moduleKinds.joinToArrayString()}")
}
configuration.put(JSConfigurationKeys.MODULE_KIND, moduleKind)
configuration.put(JSConfigurationKeys.LIBRARIES, JsConfig.JS_STDLIB)
val noInline = registeredDirectives.contains(NO_INLINE)
configuration.put(CommonConfigurationKeys.DISABLE_INLINE, noInline)
val dependencies = module.regularDependencies.map { getJsModuleArtifactPath(testServices, it.moduleName) + ".meta.js" }
val allDependencies = module.allTransitiveDependencies().map { getJsModuleArtifactPath(testServices, it.moduleName) + ".meta.js" }
val friends = module.friendDependencies.map { getJsModuleArtifactPath(testServices, it.moduleName) + ".meta.js" }
val libraries = when (module.targetBackend) {
null -> JsConfig.JS_STDLIB + JsConfig.JS_KOTLIN_TEST
TargetBackend.JS_IR_ES6 -> dependencies
TargetBackend.JS_IR -> dependencies
TargetBackend.JS -> JsConfig.JS_STDLIB + JsConfig.JS_KOTLIN_TEST + dependencies
else -> error("Unsupported target backend: ${module.targetBackend}")
}
configuration.put(JSConfigurationKeys.LIBRARIES, libraries)
configuration.put(JSConfigurationKeys.TRANSITIVE_LIBRARIES, allDependencies)
configuration.put(JSConfigurationKeys.FRIEND_PATHS, friends)
configuration.put(CommonConfigurationKeys.MODULE_NAME, module.name.removeSuffix(OLD_MODULE_SUFFIX))
configuration.put(JSConfigurationKeys.TARGET, EcmaVersion.v5)
val errorIgnorancePolicy = registeredDirectives[ERROR_POLICY].singleOrNull() ?: ErrorTolerancePolicy.DEFAULT
configuration.put(JSConfigurationKeys.ERROR_TOLERANCE_POLICY, errorIgnorancePolicy)
if (errorIgnorancePolicy.allowErrors) {
configuration.put(JSConfigurationKeys.DEVELOPER_MODE, true)
}
val multiModule = testServices.moduleStructure.modules.size > 1
configuration.put(JSConfigurationKeys.META_INFO, multiModule)
val sourceDirs = module.files.map { it.originalFile.parent }.distinct()
configuration.put(JSConfigurationKeys.SOURCE_MAP_SOURCE_ROOTS, sourceDirs)
configuration.put(JSConfigurationKeys.SOURCE_MAP, true)
val sourceMapSourceEmbedding = registeredDirectives[SOURCE_MAP_EMBED_SOURCES].singleOrNull() ?: SourceMapSourceEmbedding.NEVER
configuration.put(JSConfigurationKeys.SOURCE_MAP_EMBED_SOURCES, sourceMapSourceEmbedding)
configuration.put(JSConfigurationKeys.TYPED_ARRAYS_ENABLED, TYPED_ARRAYS in registeredDirectives)
configuration.put(JSConfigurationKeys.GENERATE_REGION_COMMENTS, true)
configuration.put(
JSConfigurationKeys.FILE_PATHS_PREFIX_MAP,
mapOf(
// tmpDir.absolutePath to "<TMP>", // TODO check do we need this on js ir tests
File(".").absolutePath.removeSuffix(".") to ""
)
)
configuration.put(CommonConfigurationKeys.EXPECT_ACTUAL_LINKER, EXPECT_ACTUAL_LINKER in registeredDirectives)
}
}
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.platform.CommonPlatforms
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.js.JsPlatforms
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.platform.konan.NativePlatforms
import org.jetbrains.kotlin.test.Assertions
import org.jetbrains.kotlin.test.TargetBackend
@@ -44,7 +45,7 @@ class ModuleStructureExtractorImpl(
private val environmentConfigurators: List<EnvironmentConfigurator>
) : ModuleStructureExtractor(testServices, additionalSourceProviders, moduleStructureTransformers) {
companion object {
private val allowedExtensionsForFiles = listOf(".kt", ".kts", ".java")
private val allowedExtensionsForFiles = listOf(".kt", ".kts", ".java", ".js", ".mjs")
/*
* ([^()\n]+) module name
@@ -86,9 +87,6 @@ class ModuleStructureExtractorImpl(
private val defaultFileName: String
get() = currentTestDataFile.name
private val defaultModuleName: String
get() = "main"
private var currentModuleName: String? = null
private var currentModuleTargetPlatform: TargetPlatform? = null
private var currentModuleFrontendKind: FrontendKind<*>? = null
@@ -237,6 +235,7 @@ class ModuleStructureExtractorImpl(
}
}
ModuleStructureDirectives.JVM_TARGET -> {
if (!defaultsProvider.defaultPlatform.isJvm()) return false
if (currentModuleTargetPlatform != null) {
assertions.fail { "Target platform already specified twice for module $currentModuleName" }
}
@@ -317,7 +316,7 @@ class ModuleStructureExtractorImpl(
val targetBackend = currentModuleTargetBackend ?: defaultsProvider.defaultTargetBackend
currentModuleLanguageVersionSettingsBuilder.configureUsingDirectives(moduleDirectives, environmentConfigurators, targetBackend)
val moduleName = currentModuleName ?: defaultModuleName
val moduleName = currentModuleName ?: DEFAULT_MODULE_NAME
val targetPlatform = currentModuleTargetPlatform ?: parseModulePlatformByName(moduleName) ?: defaultsProvider.defaultPlatform
val testModule = TestModule(
name = moduleName,
@@ -11,12 +11,22 @@ import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.testInfo
import org.jetbrains.kotlin.test.util.KtTestUtil
import java.io.File
import java.util.*
class TemporaryDirectoryManagerImpl(testServices: TestServices) : TemporaryDirectoryManager(testServices) {
private val cache = mutableMapOf<String, File>()
private val rootTempDir: File = run {
val testInfo = testServices.testInfo
KtTestUtil.tmpDirForTest(testInfo.className, testInfo.methodName)
val className = testInfo.className
val methodName = testInfo.methodName
if (!onWindows) return@run KtTestUtil.tmpDirForTest(className, methodName)
// This code will simplify directory name for windows. This is needed because there can occur errors due to long name
val lastDot = className.lastIndexOf('.')
val packageName = className.substring(0, lastDot + 1)
val simplifiedClassName = className.substring(lastDot + 1).getOnlyUpperCaseSymbols()
val simplifiedMethodName = methodName.getOnlyUpperCaseSymbols()
KtTestUtil.tmpDirForTest(packageName + simplifiedClassName, "test$simplifiedMethodName")
}
override fun getOrCreateTempDirectory(name: String): File {
@@ -27,4 +37,12 @@ class TemporaryDirectoryManagerImpl(testServices: TestServices) : TemporaryDirec
cache.clear()
FileUtil.delete(rootTempDir)
}
companion object {
private val onWindows: Boolean = System.getProperty("os.name").lowercase(Locale.getDefault()).contains("windows")
private fun String.getOnlyUpperCaseSymbols(): String {
return this.filter { it.isUpperCase() || it == '$' }.toList().joinToString(separator = "")
}
}
}
@@ -16,6 +16,7 @@ dependencies {
testImplementation(projectTests(":compiler:fir:fir2ir"))
testImplementation(projectTests(":compiler:fir:analysis-tests:legacy-fir-tests"))
testImplementation(projectTests(":compiler:visualizer"))
testImplementation(projectTests(":js:js.tests"))
testImplementation(projectTests(":generators:test-generator"))
testCompileOnly(project(":kotlin-reflect-api"))
testRuntimeOnly(project(":kotlin-reflect"))
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.test.generators
import org.jetbrains.kotlin.generators.generateTestGroupSuiteWithJUnit5
import org.jetbrains.kotlin.generators.util.TestGeneratorUtil
import org.jetbrains.kotlin.js.testNew.*
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.runners.*
import org.jetbrains.kotlin.test.runners.codegen.*
@@ -162,6 +163,46 @@ fun generateJUnit5CompilerTests(args: Array<String>) {
}
}
// ---------------------------------------------- JS tests ----------------------------------------------
testGroup(testsRoot = "js/js.tests/tests-gen", testDataRoot = "js/js.translator/testData") {
testClass<AbstractBoxJsTest> {
model("box/", pattern = "^([^_](.+))\\.kt$", excludeDirs = listOf("incremental"))
}
testClass<AbstractSourceMapGenerationSmokeTest> {
model("sourcemap/")
}
testClass<AbstractOutputPrefixPostfixTest> {
model("outputPrefixPostfix/")
}
testClass<AbstractMultiModuleOrderTest> {
model("multiModuleOrder/")
}
}
testGroup(testsRoot = "js/js.tests/tests-gen", testDataRoot = "compiler/testData") {
val jvmOnlyBoxTests = listOf(
"testsWithJava9",
"testsWithJava15",
"testsWithJava17",
)
testClass<AbstractJsCodegenBoxTest> {
model("codegen/box", excludeDirs = jvmOnlyBoxTests + "compileKotlinAgainstKotlin")
}
testClass<AbstractJsCodegenInlineTest> {
model("codegen/boxInline")
}
testClass<AbstractJsLegacyPrimitiveArraysBoxTest> {
model("codegen/box/arrays")
}
}
// ---------------------------------------------- FIR tests ----------------------------------------------
testGroup(testsRoot = "compiler/fir/analysis-tests/tests-gen", testDataRoot = "compiler/testData") {
+13 -2
View File
@@ -27,10 +27,16 @@ val testJsRuntime by configurations.creating {
}
dependencies {
testApiJUnit5(vintageEngine = true)
testRuntimeOnly(intellijDep())
testApi(protobufFull())
testApi(projectTests(":compiler:tests-common"))
testApi(projectTests(":compiler:test-infrastructure"))
testApi(projectTests(":compiler:test-infrastructure-utils"))
testApi(projectTests(":compiler:tests-compiler-utils"))
testApi(projectTests(":compiler:tests-common-new"))
testCompileOnly(project(":compiler:frontend"))
testCompileOnly(project(":compiler:cli"))
testCompileOnly(project(":compiler:cli-js"))
@@ -240,6 +246,7 @@ val testDataDir = project(":js:js.translator").projectDir.resolve("testData")
projectTest(parallel = true) {
setUpJsBoxTests(jsEnabled = true, jsIrEnabled = true)
systemProperty("kotlin.js.ir.pir", "false")
maxHeapSize = "3g"
inputs.dir(rootDir.resolve("compiler/cli/cli-common/resources")) // compiler.xml
@@ -256,10 +263,12 @@ projectTest(parallel = true) {
configureTestDistribution()
}
projectTest("jsTest", true) {
projectTest("jsTest", parallel = true, jUnit5Enabled = true) {
// PIR temporary disabled
systemProperty("kotlin.js.ir.pir", "false")
setUpJsBoxTests(jsEnabled = true, jsIrEnabled = false)
maxHeapSize = "3g"
useJUnitPlatform()
}
projectTest("jsIrTest", true) {
@@ -294,9 +303,11 @@ projectTest("jsPirTest", true) {
setUpJsBoxTests(jsEnabled = false, jsIrEnabled = true)
}
projectTest("quickTest", true) {
projectTest("quickTest", parallel = true, jUnit5Enabled = true) {
setUpJsBoxTests(jsEnabled = true, jsIrEnabled = false)
maxHeapSize = "3g"
systemProperty("kotlin.js.skipMinificationTest", "true")
useJUnitPlatform()
}
testsJar {}
@@ -29,7 +29,7 @@ fun main(args: Array<String>) {
generateTestGroupSuite(args) {
testGroup("js/js.tests/tests-gen", "js/js.translator/testData", testRunnerMethodName = "runTest0") {
testClass<AbstractBoxJsTest> {
model("box/", pattern = "^([^_](.+))\\.kt$", targetBackend = TargetBackend.JS)
model("box/incremental/", pattern = "^([^_](.+))\\.kt$", targetBackend = TargetBackend.JS)
}
testClass<AbstractIrBoxJsTest> {
@@ -53,14 +53,6 @@ fun main(args: Array<String>) {
model("typescript-export/", pattern = "^([^_](.+))\\.kt$", targetBackend = TargetBackend.JS_IR_ES6)
}
testClass<AbstractSourceMapGenerationSmokeTest> {
model("sourcemap/", pattern = "^([^_](.+))\\.kt$", targetBackend = TargetBackend.JS)
}
testClass<AbstractOutputPrefixPostfixTest> {
model("outputPrefixPostfix/", pattern = "^([^_](.+))\\.kt$", targetBackend = TargetBackend.JS)
}
testClass<AbstractDceTest> {
model("dce/", pattern = "(.+)\\.js", targetBackend = TargetBackend.JS)
}
@@ -77,10 +69,6 @@ fun main(args: Array<String>) {
"testsWithJava17",
)
testClass<AbstractJsCodegenBoxTest> {
model("codegen/box", targetBackend = TargetBackend.JS, excludeDirs = jvmOnlyBoxTests + "compileKotlinAgainstKotlin")
}
testClass<AbstractIrJsCodegenBoxTest> {
model("codegen/box", targetBackend = TargetBackend.JS_IR, excludeDirs = jvmOnlyBoxTests + "compileKotlinAgainstKotlin")
}
@@ -114,18 +102,10 @@ fun main(args: Array<String>) {
model("codegen/boxWasmJsInterop", targetBackend = TargetBackend.WASM)
}
testClass<AbstractIrCodegenWasmJsInteropJsTest> {
model("codegen/boxWasmJsInterop", targetBackend = TargetBackend.JS_IR)
}
testClass<AbstractIrJsCodegenBoxES6Test> {
model("codegen/box", targetBackend = TargetBackend.JS_IR_ES6, excludeDirs = jvmOnlyBoxTests)
}
testClass<AbstractJsCodegenInlineTest> {
model("codegen/boxInline/", targetBackend = TargetBackend.JS)
}
testClass<AbstractIrJsCodegenInlineTest> {
model("codegen/boxInline/", targetBackend = TargetBackend.JS_IR)
}
@@ -133,10 +113,6 @@ fun main(args: Array<String>) {
testClass<AbstractIrJsCodegenInlineES6Test> {
model("codegen/boxInline/", targetBackend = TargetBackend.JS_IR_ES6)
}
testClass<AbstractJsLegacyPrimitiveArraysBoxTest> {
model("codegen/box/arrays", targetBackend = TargetBackend.JS)
}
}
testGroup("js/js.tests/tests-gen", "compiler/testData/binaryCompatibility", testRunnerMethodName = "runTest0") {
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.js.test
import com.google.gwt.dev.js.ThrowExceptionOnErrorReporter
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.vfs.StandardFileSystems
@@ -29,22 +28,19 @@ import org.jetbrains.kotlin.incremental.js.TranslationResultValue
import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationGranularity
import org.jetbrains.kotlin.ir.backend.js.ic.ICCache
import org.jetbrains.kotlin.js.JavaScript
import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.config.*
import org.jetbrains.kotlin.js.dce.DeadCodeElimination
import org.jetbrains.kotlin.js.dce.InputFile
import org.jetbrains.kotlin.js.dce.InputResource
import org.jetbrains.kotlin.js.engine.loadFiles
import org.jetbrains.kotlin.js.facade.K2JSTranslator
import org.jetbrains.kotlin.js.facade.MainCallParameters
import org.jetbrains.kotlin.js.facade.TranslationResult
import org.jetbrains.kotlin.js.facade.TranslationUnit
import org.jetbrains.kotlin.js.parser.parse
import org.jetbrains.kotlin.js.parser.sourcemaps.SourceMapError
import org.jetbrains.kotlin.js.parser.sourcemaps.SourceMapLocationRemapper
import org.jetbrains.kotlin.js.parser.sourcemaps.SourceMapParser
import org.jetbrains.kotlin.js.parser.sourcemaps.SourceMapSuccess
import org.jetbrains.kotlin.js.test.utils.ExceptionThrowingReporter
import org.jetbrains.kotlin.js.testNew.*
import org.jetbrains.kotlin.js.testNew.handlers.JsAstHandler
import org.jetbrains.kotlin.js.testNew.handlers.JsMinifierRunner
import org.jetbrains.kotlin.js.testNew.handlers.JsSourceMapHandler
import org.jetbrains.kotlin.js.testNew.handlers.NodeJsGeneratorHandler
import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver
import org.jetbrains.kotlin.js.sourceMap.SourceMap3Builder
import org.jetbrains.kotlin.js.test.engines.ExternalTool
@@ -67,13 +63,13 @@ import org.jetbrains.kotlin.utils.DFS
import org.jetbrains.kotlin.utils.JsMetadataVersion
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadata
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils
import org.junit.Assert
import java.io.ByteArrayOutputStream
import java.io.Closeable
import java.io.File
import java.io.PrintStream
import java.lang.Boolean.getBoolean
import java.nio.charset.Charset
import java.util.regex.Matcher
import java.util.regex.Pattern
abstract class BasicBoxTest(
@@ -84,7 +80,7 @@ abstract class BasicBoxTest(
private val generateNodeJsRunner: Boolean = true,
private val targetBackend: TargetBackend = TargetBackend.JS
) : KotlinTestWithEnvironment() {
val pathToRootOutputDir = System.getProperty("kotlin.js.test.root.out.dir") ?: error("'kotlin.js.test.root.out.dir' is not set")
private val pathToRootOutputDir = System.getProperty("kotlin.js.test.root.out.dir") ?: error("'kotlin.js.test.root.out.dir' is not set")
private val testGroupOutputDirForCompilation = File(pathToRootOutputDir + "out/" + testGroupOutputDirPrefix)
private val testGroupOutputDirForMinification = File(pathToRootOutputDir + "out-min/" + testGroupOutputDirPrefix)
private val testGroupOutputDirForPir = File(pathToRootOutputDir + "out-pir/" + testGroupOutputDirPrefix)
@@ -94,7 +90,6 @@ abstract class BasicBoxTest(
protected open val runMinifierByDefault: Boolean = false
protected open val skipMinification = getBoolean("kotlin.js.skipMinificationTest")
protected open val overwriteReachableNodes = getBoolean(overwriteReachableNodesProperty)
protected open val skipRegularMode: Boolean = false
protected open val runIrDce: Boolean = false
@@ -127,12 +122,15 @@ abstract class BasicBoxTest(
open fun doTest(filePath: String, expectedResult: String, mainCallParameters: MainCallParameters) {
val file = File(filePath)
@Suppress("NAME_SHADOWING")
val filePath = file.absolutePath
logger.logFile("Test file", file)
val outputDir = getOutputDir(file)
val dceOutputDir = getOutputDir(file, testGroupOutputDirForMinification)
val pirOutputDir = getOutputDir(file, testGroupOutputDirForPir)
var fileContent = KtTestUtil.doLoadFile(file)
val fileContent = KtTestUtil.doLoadFile(file)
val needsFullIrRuntime = KJS_WITH_FULL_RUNTIME.matcher(fileContent).find() || WITH_RUNTIME.matcher(fileContent).find() || WITH_STDLIB.matcher(fileContent).find()
@@ -269,10 +267,7 @@ abstract class BasicBoxTest(
}
}
val globalCommonFiles = JsTestUtils.getFilesInDirectoryByExtension(COMMON_FILES_DIR_PATH, JavaScript.EXTENSION)
val localCommonFile = file.parent + "/" + COMMON_FILES_NAME + JavaScript.DOT_EXTENSION
val localCommonFiles = if (File(localCommonFile).exists()) listOf(localCommonFile) else emptyList()
val commonFiles = JsAdditionalSourceProvider.getAdditionalJsFiles(file.parent).map { it.absolutePath }
val inputJsFilesBefore = mutableListOf<String>()
val inputJsFilesAfter = mutableListOf<String>()
@@ -303,7 +298,7 @@ abstract class BasicBoxTest(
val withModuleSystem = moduleKind != ModuleKind.PLAIN && !NO_MODULE_SYSTEM_PATTERN.matcher(fileContent).find()
if (withModuleSystem) {
moduleEmulationFiles += MODULE_EMULATION_FILE
moduleEmulationFiles += File(MODULE_EMULATION_FILE).absolutePath
}
val additionalJsFile = filePath.removeSuffix("." + KotlinFileType.EXTENSION) + JavaScript.DOT_EXTENSION
@@ -323,7 +318,7 @@ abstract class BasicBoxTest(
inputFiles.filter { it.fileName.endsWith(".mjs") }.map { it.fileName } + listOfNotNull(maybeAdditionalMjsFile)
val allNonEsModuleFiles: List<String> =
additionalFiles + inputJsFilesBefore + globalCommonFiles + localCommonFiles + additionalCommonFiles
additionalFiles + inputJsFilesBefore + commonFiles
fun runIrEsmTests(testOutputDir: File) {
val esmOutputDir = testOutputDir.esModulesSubDir
@@ -374,7 +369,7 @@ abstract class BasicBoxTest(
additionalMainFiles += additionalMainJsFile
}
val allJsFiles = additionalFiles + inputJsFilesBefore + generatedJsFiles.map { it.first } + globalCommonFiles + localCommonFiles +
val allJsFiles = additionalFiles + inputJsFilesBefore + generatedJsFiles.map { it.first } + commonFiles +
additionalMainFiles + inputJsFilesAfter
val dceAllJsFiles = additionalFiles + inputJsFilesBefore + generatedJsFiles.map {
@@ -382,23 +377,21 @@ abstract class BasicBoxTest(
outputDir.absolutePath,
dceOutputDir.absolutePath
)
} + globalCommonFiles + localCommonFiles + additionalMainFiles + inputJsFilesAfter
} + commonFiles + additionalMainFiles + inputJsFilesAfter
val pirAllJsFiles = additionalFiles + inputJsFilesBefore + generatedJsFiles.map {
it.first.replace(
outputDir.absolutePath,
pirOutputDir.absolutePath
)
} +
globalCommonFiles + localCommonFiles + additionalMainFiles + inputJsFilesAfter
} + commonFiles + additionalMainFiles + inputJsFilesAfter
val dontRunGeneratedCode =
InTextDirectivesUtils.dontRunGeneratedCode(targetBackend, file)
val dontRunGeneratedCode = InTextDirectivesUtils.dontRunGeneratedCode(targetBackend, file)
if (!dontRunGeneratedCode && generateNodeJsRunner && !SKIP_NODE_JS.matcher(fileContent).find()) {
val nodeRunnerName = mainModule.outputFileName(outputDir) + ".node.js"
val ignored = InTextDirectivesUtils.isIgnoredTarget(TargetBackend.JS, file)
val nodeRunnerText = generateNodeRunner(allJsFiles, outputDir, mainModuleName, ignored, testPackage)
val nodeRunnerText = NodeJsGeneratorHandler.generateNodeRunner(allJsFiles, outputDir, mainModuleName, ignored, testPackage)
FileUtil.writeToFile(File(nodeRunnerName), nodeRunnerText)
}
@@ -421,74 +414,24 @@ abstract class BasicBoxTest(
val expectedReachableNodesMatcher = EXPECTED_REACHABLE_NODES.matcher(fileContent)
val expectedReachableNodesFound = expectedReachableNodesMatcher.find()
if (!skipMinification &&
if (!dontRunGeneratedCode && !skipMinification &&
(runMinifierByDefault || expectedReachableNodesFound) &&
!SKIP_MINIFICATION.matcher(fileContent).find()
) {
val thresholdChecker: (Int) -> Unit = reachableNodesThresholdChecker(
expectedReachableNodesFound,
expectedReachableNodesMatcher,
fileContent,
file
)
val outputDirForMinification = getOutputDir(file, testGroupOutputDirForMinification)
if (!dontRunGeneratedCode) {
minifyAndRun(
workDir = File(outputDirForMinification, file.nameWithoutExtension),
allJsFiles = allJsFiles,
generatedJsFiles = generatedJsFiles,
expectedResult = expectedResult,
testModuleName = testModuleName,
testPackage = testPackage,
testFunction = testFunction,
withModuleSystem = withModuleSystem,
minificationThresholdChecker = thresholdChecker
)
}
}
}
}
private fun reachableNodesThresholdChecker(
expectedReachableNodesFound: Boolean,
expectedReachableNodesMatcher: Matcher,
fileContent: String,
file: File
) = { reachableNodesCount: Int ->
val replacement = "// $EXPECTED_REACHABLE_NODES_DIRECTIVE: $reachableNodesCount"
val enablingMessage = "To set expected reachable nodes use '$replacement'\n" +
"To enable automatic overwriting reachable nodes use property '-Pfd.$overwriteReachableNodesProperty=true'"
if (expectedReachableNodesFound) {
val expectedReachableNodes = expectedReachableNodesMatcher.group(1).toInt()
val minThreshold = expectedReachableNodes * 9 / 10
val maxThreshold = expectedReachableNodes * 11 / 10
if (reachableNodesCount < minThreshold || reachableNodesCount > maxThreshold) {
val message = "Number of reachable nodes ($reachableNodesCount) does not fit into expected range " +
"[$minThreshold; $maxThreshold]"
val additionalMessage: String =
if (overwriteReachableNodes) {
val newText = fileContent.substring(0, expectedReachableNodesMatcher.start()) +
replacement +
fileContent.substring(expectedReachableNodesMatcher.end())
file.writeText(newText)
""
} else {
"\n$enablingMessage"
}
fail("$message$additionalMessage")
}
} else {
val baseMessage = "The number of expected reachable nodes was not set. Actual reachable nodes: $reachableNodesCount."
if (overwriteReachableNodes) {
file.writeText("$replacement\n$fileContent")
fail(baseMessage)
} else {
println("$baseMessage\n$enablingMessage")
JsMinifierRunner.minifyAndRun(
file = file,
expectedReachableNodes = expectedReachableNodesMatcher.group(1).toInt(),
workDir = File(outputDirForMinification, file.nameWithoutExtension),
allJsFiles = allJsFiles,
generatedJsFiles = generatedJsFiles.map { it.first to it.second.name },
expectedResult = expectedResult,
testModuleName = testModuleName,
testPackage = testPackage,
testFunction = testFunction,
withModuleSystem = withModuleSystem,
) { expect, actual -> TestCase.assertEquals(expect, actual) }
}
}
}
@@ -507,36 +450,6 @@ abstract class BasicBoxTest(
protected open fun performAdditionalChecks(generatedJsFiles: List<String>, outputPrefixFile: File?, outputPostfixFile: File?) {}
protected open fun performAdditionalChecks(inputFile: File, outputFile: File) {}
private fun generateNodeRunner(
files: Collection<String>,
dir: File,
moduleName: String,
ignored: Boolean,
testPackage: String?
): String {
val filesToLoad = files.map { FileUtil.getRelativePath(dir, File(it))!!.replace(File.separatorChar, '/') }.map { "\"$it\"" }
val fqn = testPackage?.let { ".$it" } ?: ""
val loadAndRun = "load([${filesToLoad.joinToString(",")}], '$moduleName')$fqn.box()"
val sb = StringBuilder()
sb.append("module.exports = function(load) {\n")
if (ignored) {
sb.append(" try {\n")
sb.append(" var result = $loadAndRun;\n")
sb.append(" if (result != 'OK') return 'OK';")
sb.append(" return 'fail: expected test failure';\n")
sb.append(" }\n")
sb.append(" catch (e) {\n")
sb.append(" return 'OK';\n")
sb.append("}\n")
} else {
sb.append(" return $loadAndRun;\n")
}
sb.append("};\n")
return sb.toString()
}
protected fun getOutputDir(file: File, testGroupOutputDir: File = testGroupOutputDirForCompilation): File {
val stopFile = File(pathToTestDir)
return generateSequence(file.parentFile) { it.parentFile }
@@ -588,11 +501,7 @@ abstract class BasicBoxTest(
) {
val kotlinFiles = module.files.filter { it.fileName.endsWith(".kt") }
val testFiles = kotlinFiles.map { it.fileName }
val globalCommonFiles = JsTestUtils.getFilesInDirectoryByExtension(COMMON_FILES_DIR_PATH, KotlinFileType.EXTENSION)
val localCommonFile = directory + "/" + COMMON_FILES_NAME + "." + KotlinFileType.EXTENSION
val localCommonFiles = if (File(localCommonFile).exists()) listOf(localCommonFile) else emptyList()
val additionalFiles = globalCommonFiles + localCommonFiles
val additionalFiles = JsAdditionalSourceProvider.getAdditionalKotlinFiles(directory).map { it.absolutePath }
val allSourceFiles = (testFiles + additionalFiles).map(::File)
val psiFiles = createPsiFiles(allSourceFiles.sortedBy { it.canonicalPath }.map { it.canonicalPath })
@@ -868,8 +777,10 @@ abstract class BasicBoxTest(
incrementalData.header = incrementalService.headerMetadata
}
processJsProgram(translationResult.program, units)
checkSourceMap(outputFile, translationResult.program, remap)
JsAstHandler.processUnitsOfJsProgram(translationResult.program, units, targetBackend) { Assert.fail(it) }
JsSourceMapHandler.checkSourceMap(outputFile, translationResult.program, remap) { expected, actual ->
TestCase.assertEquals(expected, actual)
}
}
protected fun wrapWithModuleEmulationMarkers(
@@ -896,75 +807,6 @@ abstract class BasicBoxTest(
}
}
protected fun processJsProgram(program: JsProgram, units: List<TranslationUnit>) {
units.filterIsInstance<TranslationUnit.SourceFile>()
.forEach { DirectiveTestUtils.processDirectives(program, it.file.text, targetBackend) }
// TODO: For now the IR backend generates JS code that doesn't pass verification,
// TODO: so we temporarily disabled AST verification.
if (targetBackend == TargetBackend.JS) {
program.verifyAst()
}
}
private fun checkSourceMap(outputFile: File, program: JsProgram, remap: Boolean) {
val generatedProgram = JsProgram()
generatedProgram.globalBlock.statements += program.globalBlock.statements.map { it.deepCopy() }
generatedProgram.accept(object : RecursiveJsVisitor() {
override fun visitObjectLiteral(x: JsObjectLiteral) {
super.visitObjectLiteral(x)
x.isMultiline = false
}
override fun visitVars(x: JsVars) {
x.isMultiline = false
super.visitVars(x)
}
})
removeLocationFromBlocks(generatedProgram)
generatedProgram.accept(AmbiguousAstSourcePropagation())
val output = TextOutputImpl()
val pathResolver = SourceFilePathResolver(mutableListOf(File(".")), null)
val sourceMapBuilder = SourceMap3Builder(outputFile, output, "")
generatedProgram.accept(
JsToStringGenerationVisitor(
output, SourceMapBuilderConsumer(File("."), sourceMapBuilder, pathResolver, false, false)
)
)
val code = output.toString()
val generatedSourceMap = sourceMapBuilder.build()
val codeWithLines = generatedProgram.toStringWithLineNumbers()
val parsedProgram = JsProgram()
parsedProgram.globalBlock.statements += parse(code, ThrowExceptionOnErrorReporter, parsedProgram.scope, outputFile.path).orEmpty()
removeLocationFromBlocks(parsedProgram)
val sourceMapParseResult = SourceMapParser.parse(generatedSourceMap)
val sourceMap = when (sourceMapParseResult) {
is SourceMapSuccess -> sourceMapParseResult.value
is SourceMapError -> error("Could not parse source map: ${sourceMapParseResult.message}")
}
if (remap) {
val remapper = SourceMapLocationRemapper(sourceMap)
remapper.remap(parsedProgram)
val codeWithRemappedLines = parsedProgram.toStringWithLineNumbers()
TestCase.assertEquals(codeWithLines, codeWithRemappedLines)
}
}
private fun removeLocationFromBlocks(program: JsProgram) {
program.globalBlock.accept(object : RecursiveJsVisitor() {
override fun visitBlock(x: JsBlock) {
super.visitBlock(x)
x.source = null
}
})
}
private fun createPsiFile(fileName: String): KtFile {
val psiManager = PsiManager.getInstance(project)
val fileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL)
@@ -1055,51 +897,6 @@ abstract class BasicBoxTest(
return JsConfig(project, configuration, CompilerEnvironment, METADATA_CACHE, (JsConfig.JS_STDLIB + JsConfig.JS_KOTLIN_TEST).toSet())
}
private fun minifyAndRun(
workDir: File, allJsFiles: List<String>, generatedJsFiles: List<Pair<String, TestModule>>,
expectedResult: String, testModuleName: String?, testPackage: String?, testFunction: String, withModuleSystem: Boolean,
minificationThresholdChecker: (Int) -> Unit
) {
val kotlinJsLib = DIST_DIR_JS_PATH + "kotlin.js"
val kotlinTestJsLib = DIST_DIR_JS_PATH + "kotlin-test.js"
val kotlinJsLibOutput = File(workDir, "kotlin.min.js").path
val kotlinTestJsLibOutput = File(workDir, "kotlin-test.min.js").path
val kotlinJsInputFile = InputFile(InputResource.file(kotlinJsLib), null, kotlinJsLibOutput, "kotlin")
val kotlinTestJsInputFile = InputFile(InputResource.file(kotlinTestJsLib), null, kotlinTestJsLibOutput, "kotlin-test")
val filesToMinify = generatedJsFiles.associate { (fileName, module) ->
val inputFileName = File(fileName).nameWithoutExtension
fileName to InputFile(InputResource.file(fileName), null, File(workDir, inputFileName + ".min.js").absolutePath, module.name)
}
val testFunctionFqn = testModuleName + (if (testPackage.isNullOrEmpty()) "" else ".$testPackage") + ".$testFunction"
val additionalReachableNodes = setOf(
testFunctionFqn, "kotlin.kotlin.io.BufferedOutput", "kotlin.kotlin.io.output.flush",
"kotlin.kotlin.io.output.buffer", "kotlin-test.kotlin.test.overrideAsserter_wbnzx$",
"kotlin-test.kotlin.test.DefaultAsserter"
)
val allFilesToMinify = filesToMinify.values + kotlinJsInputFile + kotlinTestJsInputFile
val dceResult = DeadCodeElimination.run(allFilesToMinify, additionalReachableNodes, true) { _, _ -> }
val reachableNodes = dceResult.reachableNodes
minificationThresholdChecker(reachableNodes.count { it.reachable })
val runList = mutableListOf<String>()
runList += kotlinJsLibOutput
runList += kotlinTestJsLibOutput
runList += TEST_DATA_DIR_PATH + "nashorn-polyfills.js"
runList += allJsFiles.map { filesToMinify[it]?.outputPath ?: it }
val result = engineForMinifier.runAndRestoreContext {
loadFiles(runList)
overrideAsserter()
eval(SETUP_KOTLIN_OUTPUT)
runTestFunction(testModuleName, testPackage, testFunction, withModuleSystem)
}
TestCase.assertEquals(expectedResult, result)
}
private inner class TestFileFactoryImpl() : TestFiles.TestFileFactory<TestModule, TestFile>, Closeable {
var testPackage: String? = null
val tmpDir = KtTestUtil.tmpDir("js-tests")
@@ -1215,10 +1012,6 @@ abstract class BasicBoxTest(
const val TEST_DATA_DIR_PATH = "js/js.translator/testData/"
const val DIST_DIR_JS_PATH = "dist/js/"
private const val COMMON_FILES_NAME = "_common"
private const val COMMON_FILES_DIR = "_commonFiles/"
const val COMMON_FILES_DIR_PATH = TEST_DATA_DIR_PATH + COMMON_FILES_DIR
private const val MODULE_EMULATION_FILE = TEST_DATA_DIR_PATH + "/moduleEmulation.js"
private val MODULE_KIND_PATTERN = Pattern.compile("^// *MODULE_KIND: *(.+)$", Pattern.MULTILINE)
@@ -1262,15 +1055,12 @@ abstract class BasicBoxTest(
@JvmStatic
protected val runTestInNashorn = getBoolean("kotlin.js.useNashorn")
const val TEST_MODULE = "JS_TESTS"
const val TEST_MODULE = "main"
const val DEFAULT_MODULE = "main"
private const val TEST_FUNCTION = "box"
private const val OLD_MODULE_SUFFIX = "_old"
const val KOTLIN_TEST_INTERNAL = "\$kotlin_test_internal\$"
private val engineForMinifier = createScriptEngine()
const val overwriteReachableNodesProperty = "kotlin.js.overwriteReachableNodes"
}
}
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.js.config.JsConfig
import org.jetbrains.kotlin.js.config.RuntimeDiagnostic
import org.jetbrains.kotlin.js.facade.MainCallParameters
import org.jetbrains.kotlin.js.facade.TranslationUnit
import org.jetbrains.kotlin.js.testNew.handlers.JsAstHandler
import org.jetbrains.kotlin.konan.properties.propertyList
import org.jetbrains.kotlin.library.KLIB_PROPERTY_DEPENDS
import org.jetbrains.kotlin.library.KotlinAbiVersion
@@ -37,6 +38,7 @@ import org.jetbrains.kotlin.parsing.parseBoolean
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.util.DummyLogger
import org.jetbrains.kotlin.utils.fileUtils.withReplacedExtensionOrNull
import org.junit.Assert
import java.io.File
import java.lang.Boolean.getBoolean
@@ -194,7 +196,7 @@ abstract class BasicIrBoxTest(
super.doTest(filePath, expectedResult, mainCallParameters)
}
override val testChecker get() = if (runTestInNashorn) NashornIrJsTestChecker() else V8IrJsTestChecker
override val testChecker get() = if (runTestInNashorn) NashornIrJsTestChecker else V8IrJsTestChecker
override fun translateFiles(
units: List<TranslationUnit>,
@@ -460,7 +462,9 @@ abstract class BasicIrBoxTest(
dtsFile.write(compiledModule.tsDefinitions ?: error("No ts definitions"))
}
compiledOutput.jsProgram?.let { processJsProgram(it, units) }
compiledOutput.jsProgram?.let {
JsAstHandler.processUnitsOfJsProgram(it, units, targetBackend = TargetBackend.JS_IR) { Assert.fail(it) }
}
}
private fun generateTestFile(outputDir: File, config: JsConfig, customTestModule: String?) {
@@ -154,7 +154,7 @@ object NashornJsTestChecker : AbstractNashornJsTestChecker() {
}
}
class NashornIrJsTestChecker : AbstractNashornJsTestChecker() {
object NashornIrJsTestChecker : AbstractNashornJsTestChecker() {
override val preloadedScripts = listOf(
BasicBoxTest.TEST_DATA_DIR_PATH + "nashorn-polyfills.js",
"libraries/stdlib/js-v1/src/js/polyfills.js"
@@ -1,53 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.js.test.semantics
import org.jetbrains.kotlin.js.test.BasicBoxTest
import java.io.File
abstract class AbstractOutputPrefixPostfixTest : BasicBoxTest(
BasicBoxTest.TEST_DATA_DIR_PATH + "outputPrefixPostfix/",
"outputPrefixPostfix/",
generateNodeJsRunner = false
) {
override fun getOutputPrefixFile(testFilePath: String): File? {
return newFileIfExists(testFilePath + ".prefix")
}
override fun getOutputPostfixFile(testFilePath: String): File? {
return newFileIfExists(testFilePath + ".postfix")
}
override fun performAdditionalChecks(generatedJsFiles: List<String>, outputPrefixFile: File?, outputPostfixFile: File?) {
super.performAdditionalChecks(generatedJsFiles, outputPrefixFile, outputPostfixFile)
val output = File(generatedJsFiles.first()).readText()
outputPrefixFile?.let {
assertTrue(output.startsWith(it.readText()))
}
outputPostfixFile?.let {
assertTrue(output.endsWith(it.readText()))
}
}
private fun newFileIfExists(path: String): File? {
val file = File(path)
if (!file.exists()) return null
return file
}
}
@@ -1,44 +0,0 @@
/*
* Copyright 2010-2020 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.js.test.semantics
import org.jetbrains.kotlin.js.test.BasicBoxTest
import java.io.File
private val testGroupDir = "multiModuleOrder/"
private val pathToTestGroupDir = BasicBoxTest.TEST_DATA_DIR_PATH + testGroupDir
class MultiModuleOrderTest : BasicBoxTest(pathToTestGroupDir, testGroupDir) {
fun testPlain() {
runTest("plain")
}
fun testUmd() {
runTest("umd")
}
fun runTest(name: String) {
val fullPath = pathToTestGroupDir + "$name.kt"
doTest(fullPath)
checkWrongOrderReported(fullPath, name)
}
private fun checkWrongOrderReported(path: String, name: String) {
val parentDir = getOutputDir(File(path))
val mainJsFile = File(parentDir, "$name-main_v5.js").path
val libJsFile = File(parentDir, "$name-lib_v5.js").path
try {
testChecker.run(listOf(mainJsFile, libJsFile))
} catch (e: RuntimeException) {
assertTrue(e is IllegalStateException)
val message = e.message!!
assertTrue("Exception message should contain reference to dependency (lib)", "'lib'" in message)
assertTrue("Exception message should contain reference to module that failed to load (main)", "'main'" in message)
return
}
fail("Exception should have been thrown due to wrong order of modules")
}
}
@@ -1,80 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.js.test.semantics;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public abstract class TranslatorTestCaseBuilder {
private static final FilenameFilter EMPTY_FILTER = (file, name) -> true;
public interface NamedTestFactory {
@NotNull
Test createTest(@NotNull String filename);
}
@NotNull
public static TestSuite suiteForDirectory(@NotNull String dataPath,
@NotNull NamedTestFactory factory) {
return suiteForDirectory(dataPath, true, EMPTY_FILTER, factory);
}
@NotNull
public static TestSuite suiteForDirectory(@NotNull String dataPath, boolean recursive,
FilenameFilter filter, @NotNull NamedTestFactory factory) {
TestSuite suite = new TestSuite(dataPath);
suite.setName(dataPath);
appendTestsInDirectory(dataPath, recursive, filter, factory, suite);
return suite;
}
public static void appendTestsInDirectory(String dataPath, boolean recursive,
FilenameFilter filter, NamedTestFactory factory, TestSuite suite) {
String extensionKt = ".kt";
FilenameFilter extensionFilter = (dir, name) -> name.endsWith(extensionKt);
FilenameFilter resultFilter;
if (filter != EMPTY_FILTER) {
resultFilter = (file, s) -> extensionFilter.accept(file, s) && filter.accept(file, s);
}
else {
resultFilter = extensionFilter;
}
File dir = new File(dataPath);
if (recursive) {
File[] files = dir.listFiles(File::isDirectory);
assert files != null : dir;
List<File> subdirs = Arrays.asList(files);
Collections.sort(subdirs);
for (File subdir : subdirs) {
suite.addTest(suiteForDirectory(dataPath + "/" + subdir.getName(), true, filter, factory));
}
}
List<File> files = Arrays.asList(dir.listFiles(resultFilter));
Collections.sort(files);
for (File file : files) {
suite.addTest(factory.createTest(file.getName()));
}
}
}
@@ -14,26 +14,3 @@ abstract class AbstractBoxJsTest : BasicBoxTest(
override val runMinifierByDefault: Boolean = true
}
abstract class AbstractJsCodegenBoxTest : BasicBoxTest(
"compiler/testData/codegen/box/",
"codegen/box/"
)
abstract class AbstractJsCodegenInlineTest : BasicBoxTest(
"compiler/testData/codegen/boxInline",
"codegen/boxInline"
)
abstract class AbstractJsLegacyPrimitiveArraysBoxTest : BasicBoxTest(
"compiler/testData/codegen/box/arrays/",
"codegen/box/arrays-legacy-primitivearrays/",
typedArraysEnabled = false
)
abstract class AbstractSourceMapGenerationSmokeTest : BasicBoxTest(
TEST_DATA_DIR_PATH + "sourcemap/",
"sourcemap/",
generateSourceMap = true,
generateNodeJsRunner = false
)
@@ -1,37 +0,0 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.js.test.utils
import org.jetbrains.kotlin.js.backend.ast.JsExpressionStatement
import org.jetbrains.kotlin.js.backend.ast.JsNullLiteral
import org.jetbrains.kotlin.js.backend.ast.JsProgram
import org.jetbrains.kotlin.js.backend.ast.RecursiveJsVisitor
import org.junit.Assert
fun JsProgram.verifyAst() {
accept(object : RecursiveJsVisitor() {
override fun visitExpressionStatement(x: JsExpressionStatement) {
val expression = x.expression
if (expression is JsNullLiteral) {
Assert.fail("Expression statement contains `null` literal")
}
else {
super.visitExpressionStatement(x)
}
}
})
}
@@ -0,0 +1,92 @@
/*
* Copyright 2010-2021 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.js.testNew
import org.jetbrains.kotlin.js.testNew.handlers.JsArtifactsDumpHandler
import org.jetbrains.kotlin.js.testNew.handlers.JsBoxRunner
import org.jetbrains.kotlin.js.testNew.handlers.JsMinifierRunner
import org.jetbrains.kotlin.js.testNew.handlers.NodeJsGeneratorHandler
import org.jetbrains.kotlin.platform.js.JsPlatforms
import org.jetbrains.kotlin.test.Constructor
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.backend.BlackBoxCodegenSuppressor
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.builders.classicFrontendHandlersStep
import org.jetbrains.kotlin.test.builders.irHandlersStep
import org.jetbrains.kotlin.test.builders.jsArtifactsHandlersStep
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.frontend.classic.handlers.ClassicDiagnosticsHandler
import org.jetbrains.kotlin.test.model.*
import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerWithTargetBackendTest
import org.jetbrains.kotlin.test.runners.codegen.commonClassicFrontendHandlersForCodegenTest
import org.jetbrains.kotlin.test.services.configuration.CommonEnvironmentConfigurator
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import org.jetbrains.kotlin.test.services.sourceProviders.CoroutineHelpersSourceFilesProvider
import java.lang.Boolean.getBoolean
abstract class AbstractJsBlackBoxCodegenTestBase<R : ResultingArtifact.FrontendOutput<R>, I : ResultingArtifact.BackendInput<I>>(
val targetFrontend: FrontendKind<R>,
targetBackend: TargetBackend,
private val pathToTestDir: String,
private val testGroupOutputDirPrefix: String,
private val skipMinification: Boolean = getBoolean("kotlin.js.skipMinificationTest"),
) : AbstractKotlinCompilerWithTargetBackendTest(targetBackend) {
abstract val frontendFacade: Constructor<FrontendFacade<R>>
abstract val frontendToBackendConverter: Constructor<Frontend2BackendConverter<R, I>>
abstract val backendFacade: Constructor<BackendFacade<I, BinaryArtifacts.Js>>
override fun TestConfigurationBuilder.configuration() {
globalDefaults {
frontend = targetFrontend
targetPlatform = JsPlatforms.defaultJsPlatform
dependencyKind = DependencyKind.Binary
}
val pathToRootOutputDir = System.getProperty("kotlin.js.test.root.out.dir") ?: error("'kotlin.js.test.root.out.dir' is not set")
defaultDirectives {
JsEnvironmentConfigurationDirectives.PATH_TO_ROOT_OUTPUT_DIR with pathToRootOutputDir
JsEnvironmentConfigurationDirectives.PATH_TO_TEST_DIR with pathToTestDir
JsEnvironmentConfigurationDirectives.TEST_GROUP_OUTPUT_DIR_PREFIX with testGroupOutputDirPrefix
+JsEnvironmentConfigurationDirectives.TYPED_ARRAYS
+JsEnvironmentConfigurationDirectives.GENERATE_NODE_JS_RUNNER
if (skipMinification) +JsEnvironmentConfigurationDirectives.SKIP_MINIFICATION
}
useConfigurators(
::CommonEnvironmentConfigurator,
::JsEnvironmentConfigurator,
)
useAdditionalSourceProviders(
::JsAdditionalSourceProvider,
::CoroutineHelpersSourceFilesProvider,
)
useAfterAnalysisCheckers(
::JsFailingTestSuppressor,
::BlackBoxCodegenSuppressor,
)
facadeStep(frontendFacade)
classicFrontendHandlersStep {
commonClassicFrontendHandlersForCodegenTest()
useHandlers(::ClassicDiagnosticsHandler)
}
facadeStep(frontendToBackendConverter)
irHandlersStep()
facadeStep(backendFacade)
jsArtifactsHandlersStep {
useHandlers(
::JsBoxRunner,
::NodeJsGeneratorHandler,
::JsMinifierRunner,
::JsArtifactsDumpHandler,
)
}
}
}
@@ -0,0 +1,134 @@
/*
* Copyright 2010-2021 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.js.testNew
import org.jetbrains.kotlin.js.testNew.converters.ClassicJsBackendFacade
import org.jetbrains.kotlin.js.testNew.handlers.*
import org.jetbrains.kotlin.test.Constructor
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.backend.classic.ClassicBackendInput
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.builders.configureJsArtifactsHandlersStep
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontend2ClassicBackendConverter
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendFacade
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendOutputArtifact
import org.jetbrains.kotlin.test.model.*
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
abstract class AbstractJsTest(
pathToTestDir: String,
testGroupOutputDirPrefix: String,
) : AbstractJsBlackBoxCodegenTestBase<ClassicFrontendOutputArtifact, ClassicBackendInput>(
FrontendKinds.ClassicFrontend, TargetBackend.JS, pathToTestDir, testGroupOutputDirPrefix
) {
override val frontendFacade: Constructor<FrontendFacade<ClassicFrontendOutputArtifact>>
get() = ::ClassicFrontendFacade
override val frontendToBackendConverter: Constructor<Frontend2BackendConverter<ClassicFrontendOutputArtifact, ClassicBackendInput>>
get() = ::ClassicFrontend2ClassicBackendConverter
override val backendFacade: Constructor<BackendFacade<ClassicBackendInput, BinaryArtifacts.Js>>
get() = ::ClassicJsBackendFacade
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
with(builder) {
configureJsArtifactsHandlersStep {
useHandlers(
::JsTranslationResultHandler,
::JsAstHandler,
::JsSourceMapHandler,
)
}
}
}
}
open class AbstractBoxJsTest : AbstractJsTest(pathToTestDir = "${JsEnvironmentConfigurator.TEST_DATA_DIR_PATH}/box/", testGroupOutputDirPrefix = "box/") {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
with(builder) {
defaultDirectives {
+JsEnvironmentConfigurationDirectives.RUN_MINIFIER_BY_DEFAULT
}
}
}
}
open class AbstractJsCodegenBoxTest : AbstractJsTest(
pathToTestDir = "compiler/testData/codegen/box/",
testGroupOutputDirPrefix = "codegen/box/"
)
open class AbstractJsCodegenInlineTest : AbstractJsTest(
pathToTestDir = "compiler/testData/codegen/boxInline",
testGroupOutputDirPrefix = "codegen/boxInline"
)
open class AbstractJsLegacyPrimitiveArraysBoxTest : AbstractJsTest(
pathToTestDir = "compiler/testData/codegen/box/arrays/",
testGroupOutputDirPrefix = "codegen/box/arrays-legacy-primitivearrays/"
) {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
with(builder) {
defaultDirectives {
-JsEnvironmentConfigurationDirectives.TYPED_ARRAYS
}
}
}
}
open class AbstractSourceMapGenerationSmokeTest : AbstractJsTest(
pathToTestDir = "${JsEnvironmentConfigurator.TEST_DATA_DIR_PATH}/sourcemap/",
testGroupOutputDirPrefix = "sourcemap/"
) {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
with(builder) {
defaultDirectives {
+JsEnvironmentConfigurationDirectives.GENERATE_SOURCE_MAP
-JsEnvironmentConfigurationDirectives.GENERATE_NODE_JS_RUNNER
}
}
}
}
open class AbstractOutputPrefixPostfixTest : AbstractJsTest(
pathToTestDir = "${JsEnvironmentConfigurator.TEST_DATA_DIR_PATH}/outputPrefixPostfix/",
testGroupOutputDirPrefix = "outputPrefixPostfix/"
) {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
with(builder) {
defaultDirectives {
-JsEnvironmentConfigurationDirectives.GENERATE_NODE_JS_RUNNER
}
configureJsArtifactsHandlersStep {
useHandlers(
::JsPrefixPostfixHandler
)
}
}
}
}
open class AbstractMultiModuleOrderTest : AbstractJsTest(
pathToTestDir = "${JsEnvironmentConfigurator.TEST_DATA_DIR_PATH}/multiModuleOrder/",
testGroupOutputDirPrefix = "multiModuleOrder/"
) {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
with(builder) {
configureJsArtifactsHandlersStep {
useHandlers(
::JsWrongModuleHandler
)
}
}
}
}
@@ -0,0 +1,51 @@
/*
* Copyright 2010-2021 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.js.testNew
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.js.JavaScript
import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives
import org.jetbrains.kotlin.test.model.TestFile
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.AdditionalSourceProvider
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import java.io.File
import java.io.FileFilter
class JsAdditionalSourceProvider(testServices: TestServices) : AdditionalSourceProvider(testServices) {
override fun produceAdditionalFiles(globalDirectives: RegisteredDirectives, module: TestModule): List<TestFile> {
return getAdditionalKotlinFiles(module.files.first().originalFile.parent).map { it.toTestFile() }
}
companion object {
private const val COMMON_FILES_NAME = "_common"
private const val COMMON_FILES_DIR = "_commonFiles/"
private const val COMMON_FILES_DIR_PATH = JsEnvironmentConfigurator.TEST_DATA_DIR_PATH + "/" + COMMON_FILES_DIR
private fun getFilesInDirectoryByExtension(directory: String, extension: String): List<String> {
val dir = File(directory)
if (!dir.isDirectory) return emptyList()
return dir.listFiles(FileFilter { it.extension == extension })?.map { it.absolutePath } ?: emptyList()
}
private fun getAdditionalFiles(directory: String, extension: String): List<File> {
val globalCommonFiles = getFilesInDirectoryByExtension(COMMON_FILES_DIR_PATH, extension).map { File(it) }
val localCommonFilePath = "$directory/$COMMON_FILES_NAME.$extension"
val localCommonFile = File(localCommonFilePath).takeIf { it.exists() } ?: return globalCommonFiles
return globalCommonFiles + localCommonFile
}
fun getAdditionalKotlinFiles(directory: String): List<File> {
return getAdditionalFiles(directory, KotlinFileType.EXTENSION)
}
fun getAdditionalJsFiles(directory: String): List<File> {
return getAdditionalFiles(directory, JavaScript.EXTENSION)
}
}
}
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2020 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.js.testNew
import org.jetbrains.kotlin.test.WrappedException
import org.jetbrains.kotlin.test.backend.classic.ClassicBackendFacade
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendFacade
import org.jetbrains.kotlin.test.model.AfterAnalysisChecker
import org.jetbrains.kotlin.test.model.FrontendKinds
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.moduleStructure
import org.jetbrains.kotlin.test.utils.firTestDataFile
class JsFailingTestSuppressor(testServices: TestServices) : AfterAnalysisChecker(testServices) {
override fun suppressIfNeeded(failedAssertions: List<WrappedException>): List<WrappedException> {
val testFile = testServices.moduleStructure.originalTestDataFiles.first()
val failFile = testFile.parentFile.resolve("${testFile.name}.fail").takeIf { it.exists() }
?: return failedAssertions
if (failedAssertions.any { it is WrappedException.FromFacade }) return emptyList()
return failedAssertions + AssertionError("Fail file exists but no exception was thrown. Please remove ${failFile.name}").wrap()
}
}
@@ -0,0 +1,95 @@
/*
* Copyright 2010-2021 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.js.testNew.converters
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.text.StringUtil
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import org.jetbrains.kotlin.cli.common.output.writeAllTo
import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult
import org.jetbrains.kotlin.js.facade.K2JSTranslator
import org.jetbrains.kotlin.js.facade.MainCallParameters
import org.jetbrains.kotlin.js.facade.TranslationResult
import org.jetbrains.kotlin.js.facade.TranslationUnit
import org.jetbrains.kotlin.serialization.js.ModuleKind
import org.jetbrains.kotlin.test.backend.classic.ClassicBackendFacade
import org.jetbrains.kotlin.test.backend.classic.ClassicBackendInput
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.model.ArtifactKinds
import org.jetbrains.kotlin.test.model.BinaryArtifacts
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.PrintStream
import java.nio.charset.Charset
class ClassicJsBackendFacade(
testServices: TestServices
) : ClassicBackendFacade<BinaryArtifacts.Js>(testServices, ArtifactKinds.Js) {
companion object {
const val KOTLIN_TEST_INTERNAL = "\$kotlin_test_internal\$"
}
private fun wrapWithModuleEmulationMarkers(content: String, moduleKind: ModuleKind, moduleId: String): String {
val escapedModuleId = StringUtil.escapeStringCharacters(moduleId)
return when (moduleKind) {
ModuleKind.COMMON_JS -> "$KOTLIN_TEST_INTERNAL.beginModule();\n" +
"$content\n" +
"$KOTLIN_TEST_INTERNAL.endModule(\"$escapedModuleId\");"
ModuleKind.AMD, ModuleKind.UMD ->
"if (typeof $KOTLIN_TEST_INTERNAL !== \"undefined\") { " +
"$KOTLIN_TEST_INTERNAL.setModuleId(\"$escapedModuleId\"); }\n" +
"$content\n"
ModuleKind.PLAIN -> content
ModuleKind.ES -> error("Module emulation markers are not supported for ES modules")
}
}
override fun transform(module: TestModule, inputArtifact: ClassicBackendInput): BinaryArtifacts.Js? {
val configuration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
val (psiFiles, analysisResult, project, _) = inputArtifact
// TODO how to reuse this config from frontend
val jsConfig = JsEnvironmentConfigurator.createJsConfig(project, configuration)
val units = psiFiles.map(TranslationUnit::SourceFile)
val mainCallParameters = when (JsEnvironmentConfigurationDirectives.CALL_MAIN) {
in module.directives -> MainCallParameters.mainWithArguments(listOf())
else -> MainCallParameters.noCall()
}
val translator = K2JSTranslator(jsConfig, false)
val translationResult = translator.translateUnits(
JsEnvironmentConfigurator.Companion.ExceptionThrowingReporter, units, mainCallParameters, analysisResult as? JsAnalysisResult
)
val outputFile = File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name) + ".js")
if (translationResult !is TranslationResult.Success) {
return BinaryArtifacts.Js.OldJsArtifact(outputFile, translationResult)
}
val outputPrefixFile = JsEnvironmentConfigurator.getPrefixFile(module)
val outputPostfixFile = JsEnvironmentConfigurator.getPostfixFile(module)
val outputFiles = translationResult.getOutputFiles(outputFile, outputPrefixFile, outputPostfixFile)
outputFiles.writeAllTo(JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices))
if (jsConfig.moduleKind != ModuleKind.PLAIN) {
val content = FileUtil.loadFile(outputFile, true)
val wrappedContent = wrapWithModuleEmulationMarkers(content, moduleId = jsConfig.moduleId, moduleKind = jsConfig.moduleKind)
FileUtil.writeToFile(outputFile, wrappedContent)
}
return BinaryArtifacts.Js.OldJsArtifact(outputFile, translationResult)
}
}
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2021 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.js.testNew.handlers
import org.jetbrains.kotlin.test.backend.handlers.JsBinaryArtifactHandler
import org.jetbrains.kotlin.test.model.BinaryArtifacts
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
abstract class AbstractJsArtifactsCollector(testServices: TestServices) : JsBinaryArtifactHandler(testServices) {
val modulesToArtifact = mutableMapOf<TestModule, BinaryArtifacts.Js>()
override fun processModule(module: TestModule, info: BinaryArtifacts.Js) {
if (module.name.endsWith(JsEnvironmentConfigurator.OLD_MODULE_SUFFIX)) return
modulesToArtifact[module] = info
}
}
@@ -0,0 +1,57 @@
/*
* Copyright 2010-2021 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.js.testNew.handlers
import org.jetbrains.kotlin.test.backend.handlers.JsBinaryArtifactHandler
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.model.BinaryArtifacts
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.JUnit5Assertions
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import org.jetbrains.kotlin.test.services.moduleStructure
import java.io.File
class JsArtifactsDumpHandler(testServices: TestServices) : JsBinaryArtifactHandler(testServices) {
override fun processModule(module: TestModule, info: BinaryArtifacts.Js) {}
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {
if (JUnit5Assertions.isTeamCityBuild) return
val originalFile = testServices.moduleStructure.originalTestDataFiles.first()
val allDirectives = testServices.moduleStructure.allDirectives
val stopFile = File(allDirectives[JsEnvironmentConfigurationDirectives.PATH_TO_TEST_DIR].first())
val pathToRootOutputDir = allDirectives[JsEnvironmentConfigurationDirectives.PATH_TO_ROOT_OUTPUT_DIR].first()
val testGroupOutputDirPrefix = allDirectives[JsEnvironmentConfigurationDirectives.TEST_GROUP_OUTPUT_DIR_PREFIX].first()
val testGroupOutputDirForCompilation = File(pathToRootOutputDir + "out/" + testGroupOutputDirPrefix)
val testGroupOutputDirForMinification = File(pathToRootOutputDir + "out-min/" + testGroupOutputDirPrefix)
val testGroupOutputDirForPir = File(pathToRootOutputDir + "out-pir/" + testGroupOutputDirPrefix)
val outputDir = getOutputDir(originalFile, testGroupOutputDirForCompilation, stopFile)
val dceOutputDir = getOutputDir(originalFile, testGroupOutputDirForMinification, stopFile)
val pirOutputDir = getOutputDir(originalFile, testGroupOutputDirForPir, stopFile)
val minOutputDir = File(dceOutputDir, originalFile.nameWithoutExtension)
copy(JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices), outputDir)
copy(JsEnvironmentConfigurator.getDceJsArtifactsOutputDir(testServices), dceOutputDir)
copy(JsEnvironmentConfigurator.getPirJsArtifactsOutputDir(testServices), pirOutputDir)
copy(JsEnvironmentConfigurator.getMinificationJsArtifactsOutputDir(testServices), minOutputDir)
}
private fun getOutputDir(file: File, testGroupOutputDir: File, stopFile: File): File {
return generateSequence(file.parentFile) { it.parentFile }
.takeWhile { it != stopFile }
.map { it.name }
.toList().asReversed()
.fold(testGroupOutputDir, ::File)
}
private fun copy(from: File, into: File) {
if (from.listFiles()?.size == 0) return
from.copyRecursively(into, overwrite = true)
}
}
@@ -0,0 +1,62 @@
/*
* Copyright 2010-2021 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.js.testNew.handlers
import org.jetbrains.kotlin.js.backend.ast.JsExpressionStatement
import org.jetbrains.kotlin.js.backend.ast.JsNullLiteral
import org.jetbrains.kotlin.js.backend.ast.JsProgram
import org.jetbrains.kotlin.js.backend.ast.RecursiveJsVisitor
import org.jetbrains.kotlin.js.facade.TranslationResult
import org.jetbrains.kotlin.js.facade.TranslationUnit
import org.jetbrains.kotlin.js.test.utils.DirectiveTestUtils
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.backend.handlers.JsBinaryArtifactHandler
import org.jetbrains.kotlin.test.model.BinaryArtifacts
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.assertions
import org.jetbrains.kotlin.test.services.isKtFile
class JsAstHandler(testServices: TestServices) : JsBinaryArtifactHandler(testServices) {
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {}
override fun processModule(module: TestModule, info: BinaryArtifacts.Js) {
val ktFiles = module.files.filter { it.isKtFile }.map { it.originalContent }
val result = (info as? BinaryArtifacts.Js.OldJsArtifact)?.translationResult
?: throw IllegalArgumentException("JsBoxRunner suppose to work only with old js backend")
processJsProgram((result as TranslationResult.Success).program, ktFiles, module.targetBackend!!) {
testServices.assertions.fail { it }
}
}
companion object {
fun processUnitsOfJsProgram(
program: JsProgram, units: List<TranslationUnit>, targetBackend: TargetBackend, onFail: (String) -> Unit
) {
processJsProgram(program, units.filterIsInstance<TranslationUnit.SourceFile>().map { it.file.text }, targetBackend, onFail)
}
fun processJsProgram(program: JsProgram, psiFiles: List<String>, targetBackend: TargetBackend, onFail: (String) -> Unit) {
// TODO: For now the IR backend generates JS code that doesn't pass verification,
// TODO: so we temporarily disabled AST verification.
if (targetBackend == TargetBackend.JS) {
psiFiles.forEach { DirectiveTestUtils.processDirectives(program, it, targetBackend) }
program.verifyAst(onFail)
}
}
private fun JsProgram.verifyAst(onFail: (String) -> Unit) {
accept(object : RecursiveJsVisitor() {
override fun visitExpressionStatement(x: JsExpressionStatement) {
when (x.expression) {
is JsNullLiteral -> onFail("Expression statement contains `null` literal")
else -> super.visitExpressionStatement(x)
}
}
})
}
}
}
@@ -0,0 +1,57 @@
/*
* Copyright 2010-2021 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.js.testNew.handlers
import org.jetbrains.kotlin.js.testNew.utils.*
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import org.jetbrains.kotlin.test.services.defaultsProvider
import org.jetbrains.kotlin.test.services.moduleStructure
class JsBoxRunner(testServices: TestServices) : AbstractJsArtifactsCollector(testServices) {
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {
if (someAssertionWasFailed) return
val globalDirectives = testServices.moduleStructure.allDirectives
val dontRunGeneratedCode = globalDirectives[JsEnvironmentConfigurationDirectives.DONT_RUN_GENERATED_CODE]
.contains(testServices.defaultsProvider.defaultTargetBackend?.name)
if (dontRunGeneratedCode) return
val (allJsFiles, dceAllJsFiles, pirAllJsFiles) = getAllFilesForRunner(testServices, modulesToArtifact)
val withModuleSystem = testWithModuleSystem(testServices)
val testModuleName = getTestModuleName(testServices)
val testPackage = extractTestPackage(testServices)
val dontSkipRegularMode = JsEnvironmentConfigurationDirectives.SKIP_REGULAR_MODE !in globalDirectives
val dontSkipDceDriven = JsEnvironmentConfigurationDirectives.SKIP_DCE_DRIVEN !in globalDirectives
val runIrDce = JsEnvironmentConfigurationDirectives.RUN_IR_DCE in globalDirectives
val runIrPir = JsEnvironmentConfigurationDirectives.RUN_IR_PIR in globalDirectives
if (dontSkipRegularMode) {
runGeneratedCode(allJsFiles, testModuleName, testPackage, withModuleSystem)
if (runIrDce) {
runGeneratedCode(dceAllJsFiles, testModuleName, testPackage, withModuleSystem)
}
}
if (runIrPir && dontSkipDceDriven) {
runGeneratedCode(pirAllJsFiles, testModuleName, testPackage, withModuleSystem)
}
}
private fun runGeneratedCode(jsFiles: List<String>, testModuleName: String?, testPackage: String?, withModuleSystem: Boolean) {
getTestChecker(testServices)
.check(jsFiles, testModuleName, testPackage, TEST_FUNCTION, DEFAULT_EXPECTED_RESULT, withModuleSystem)
}
companion object {
const val DEFAULT_EXPECTED_RESULT = "OK"
const val TEST_FUNCTION = "box"
}
}
@@ -0,0 +1,158 @@
/*
* Copyright 2010-2021 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.js.testNew.handlers
import org.jetbrains.kotlin.js.dce.DeadCodeElimination
import org.jetbrains.kotlin.js.dce.InputFile
import org.jetbrains.kotlin.js.dce.InputResource
import org.jetbrains.kotlin.js.engine.loadFiles
import org.jetbrains.kotlin.js.test.*
import org.jetbrains.kotlin.js.testNew.utils.extractTestPackage
import org.jetbrains.kotlin.js.testNew.utils.getOnlyJsFilesForRunner
import org.jetbrains.kotlin.js.testNew.utils.getTestModuleName
import org.jetbrains.kotlin.js.testNew.utils.testWithModuleSystem
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import org.jetbrains.kotlin.test.services.defaultsProvider
import org.jetbrains.kotlin.test.services.moduleStructure
import java.io.File
class JsMinifierRunner(testServices: TestServices) : AbstractJsArtifactsCollector(testServices) {
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {
if (someAssertionWasFailed) return
val globalDirectives = testServices.moduleStructure.allDirectives
val dontRunGeneratedCode = globalDirectives[JsEnvironmentConfigurationDirectives.DONT_RUN_GENERATED_CODE]
.contains(testServices.defaultsProvider.defaultTargetBackend?.name)
if (dontRunGeneratedCode) return
val allJsFiles = getOnlyJsFilesForRunner(testServices, modulesToArtifact)
val withModuleSystem = testWithModuleSystem(testServices)
val testModuleName = getTestModuleName(testServices)
val testPackage = extractTestPackage(testServices)
val testFunction = JsBoxRunner.TEST_FUNCTION
val dontSkipMinification = JsEnvironmentConfigurationDirectives.SKIP_MINIFICATION !in globalDirectives
val runMinifierByDefault = JsEnvironmentConfigurationDirectives.RUN_MINIFIER_BY_DEFAULT in globalDirectives
val expectedReachableNodes = globalDirectives[JsEnvironmentConfigurationDirectives.EXPECTED_REACHABLE_NODES].firstOrNull()
if (dontSkipMinification && (runMinifierByDefault || expectedReachableNodes != null)) {
val originalFile = testServices.moduleStructure.originalTestDataFiles.first()
minifyAndRun(
originalFile,
expectedReachableNodes,
workDir = JsEnvironmentConfigurator.getMinificationJsArtifactsOutputDir(testServices),
allJsFiles = allJsFiles,
generatedJsFiles = modulesToArtifact.map { it.value.outputFile.absolutePath to it.key.name },
expectedResult = JsBoxRunner.DEFAULT_EXPECTED_RESULT,
testModuleName = testModuleName,
testPackage = testPackage,
testFunction = testFunction,
withModuleSystem = withModuleSystem
) { expect, actual -> assertions.assertEquals(expect, actual) }
}
}
companion object {
private const val DIST_DIR_JS_PATH = "dist/js/"
private const val overwriteReachableNodesProperty = "kotlin.js.overwriteReachableNodes"
private val overwriteReachableNodes = java.lang.Boolean.getBoolean(overwriteReachableNodesProperty)
private fun minificationThresholdChecker(expectedReachableNodes: Int?, actualReachableNodes: Int, file: File) {
val fileContent = file.readText()
val replacement = "// ${JsEnvironmentConfigurationDirectives.EXPECTED_REACHABLE_NODES.name}: $actualReachableNodes"
val enablingMessage = "To set expected reachable nodes use '$replacement'\n" +
"To enable automatic overwriting reachable nodes use property '-Pfd.${overwriteReachableNodesProperty}=true'"
if (expectedReachableNodes == null) {
val baseMessage = "The number of expected reachable nodes was not set. Actual reachable nodes: $actualReachableNodes."
return when {
overwriteReachableNodes -> {
file.writeText("$replacement\n$fileContent")
throw AssertionError(baseMessage)
}
else -> println("$baseMessage\n$enablingMessage")
}
}
val minThreshold = expectedReachableNodes * 9 / 10
val maxThreshold = expectedReachableNodes * 11 / 10
if (actualReachableNodes < minThreshold || actualReachableNodes > maxThreshold) {
val message = "Number of reachable nodes ($actualReachableNodes) does not fit into expected range " +
"[$minThreshold; $maxThreshold]"
val additionalMessage: String =
if (overwriteReachableNodes) {
val oldValue = "// ${JsEnvironmentConfigurationDirectives.EXPECTED_REACHABLE_NODES.name}: $expectedReachableNodes"
val newText = fileContent.replaceFirst(oldValue, replacement)
file.writeText(newText)
""
} else {
"\n$enablingMessage"
}
throw AssertionError("$message$additionalMessage")
}
}
fun minifyAndRun(
file: File,
expectedReachableNodes: Int?,
workDir: File,
allJsFiles: List<String>,
generatedJsFiles: List<Pair<String, String>>,
expectedResult: String,
testModuleName: String?,
testPackage: String?,
testFunction: String,
withModuleSystem: Boolean,
assertEquals: (String, String) -> Unit
) {
val kotlinJsLib = DIST_DIR_JS_PATH + "kotlin.js"
val kotlinTestJsLib = DIST_DIR_JS_PATH + "kotlin-test.js"
val kotlinJsLibOutput = File(workDir, "kotlin.min.js").path
val kotlinTestJsLibOutput = File(workDir, "kotlin-test.min.js").path
val kotlinJsInputFile = InputFile(InputResource.file(kotlinJsLib), null, kotlinJsLibOutput, "kotlin")
val kotlinTestJsInputFile = InputFile(InputResource.file(kotlinTestJsLib), null, kotlinTestJsLibOutput, "kotlin-test")
val filesToMinify = generatedJsFiles.associate { (fileName, moduleName) ->
val inputFileName = File(fileName).nameWithoutExtension
fileName to InputFile(InputResource.file(fileName), null, File(workDir, inputFileName + ".min.js").absolutePath, moduleName)
}
val testFunctionFqn = testModuleName + (if (testPackage.isNullOrEmpty()) "" else ".$testPackage") + ".$testFunction"
val additionalReachableNodes = setOf(
testFunctionFqn, "kotlin.kotlin.io.BufferedOutput", "kotlin.kotlin.io.output.flush",
"kotlin.kotlin.io.output.buffer", "kotlin-test.kotlin.test.overrideAsserter_wbnzx$",
"kotlin-test.kotlin.test.DefaultAsserter"
)
val allFilesToMinify = filesToMinify.values + kotlinJsInputFile + kotlinTestJsInputFile
val dceResult = DeadCodeElimination.run(allFilesToMinify, additionalReachableNodes, true) { _, _ -> }
val reachableNodes = dceResult.reachableNodes
minificationThresholdChecker(expectedReachableNodes, reachableNodes.count { it.reachable }, file)
val runList = mutableListOf<String>()
runList += kotlinJsLibOutput
runList += kotlinTestJsLibOutput
runList += "${JsEnvironmentConfigurator.TEST_DATA_DIR_PATH}/nashorn-polyfills.js"
runList += allJsFiles.map { filesToMinify[it]?.outputPath ?: it }
val engineForMinifier = createScriptEngine()
val result = engineForMinifier.runAndRestoreContext {
loadFiles(runList)
overrideAsserter()
eval(SETUP_KOTLIN_OUTPUT)
runTestFunction(testModuleName, testPackage, testFunction, withModuleSystem)
}
engineForMinifier.release()
assertEquals(expectedResult, result)
}
}
}
@@ -0,0 +1,26 @@
/*
* Copyright 2010-2021 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.js.testNew.handlers
import org.jetbrains.kotlin.test.backend.handlers.JsBinaryArtifactHandler
import org.jetbrains.kotlin.test.model.BinaryArtifacts
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.assertions
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
class JsPrefixPostfixHandler(testServices: TestServices) : JsBinaryArtifactHandler(testServices) {
override fun processModule(module: TestModule, info: BinaryArtifacts.Js) {
val outputPrefixFile = JsEnvironmentConfigurator.getPrefixFile(module)
val outputPostfixFile = JsEnvironmentConfigurator.getPostfixFile(module)
val outputText = info.outputFile.readText()
outputPrefixFile?.let { testServices.assertions.assertTrue(outputText.startsWith(it.readText())) }
outputPostfixFile?.let { testServices.assertions.assertTrue(outputText.endsWith(it.readText())) }
}
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {}
}
@@ -0,0 +1,101 @@
/*
* Copyright 2010-2021 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.js.testNew.handlers
import com.google.gwt.dev.js.ThrowExceptionOnErrorReporter
import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.facade.TranslationResult
import org.jetbrains.kotlin.js.parser.parse
import org.jetbrains.kotlin.js.parser.sourcemaps.SourceMapError
import org.jetbrains.kotlin.js.parser.sourcemaps.SourceMapLocationRemapper
import org.jetbrains.kotlin.js.parser.sourcemaps.SourceMapParser
import org.jetbrains.kotlin.js.parser.sourcemaps.SourceMapSuccess
import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver
import org.jetbrains.kotlin.js.sourceMap.SourceMap3Builder
import org.jetbrains.kotlin.js.sourceMap.SourceMapBuilderConsumer
import org.jetbrains.kotlin.js.test.utils.AmbiguousAstSourcePropagation
import org.jetbrains.kotlin.js.test.utils.toStringWithLineNumbers
import org.jetbrains.kotlin.js.util.TextOutputImpl
import org.jetbrains.kotlin.test.backend.handlers.JsBinaryArtifactHandler
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.model.BinaryArtifacts
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.assertions
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import java.io.File
class JsSourceMapHandler(testServices: TestServices) : JsBinaryArtifactHandler(testServices) {
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {}
override fun processModule(module: TestModule, info: BinaryArtifacts.Js) {
val outputFile = File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name))
val result = (info as? BinaryArtifacts.Js.OldJsArtifact)?.translationResult
?: throw IllegalArgumentException("JsBoxRunner suppose to work only with old js backend")
val remap = JsEnvironmentConfigurationDirectives.SKIP_SOURCEMAP_REMAPPING !in module.directives
checkSourceMap(outputFile, (result as TranslationResult.Success).program, remap) { expected, actual ->
testServices.assertions.assertEquals(expected, actual)
}
}
companion object {
fun checkSourceMap(outputFile: File, program: JsProgram, remap: Boolean, assertEquals: (String, String) -> Unit) {
val generatedProgram = JsProgram()
generatedProgram.globalBlock.statements += program.globalBlock.statements.map { it.deepCopy() }
generatedProgram.accept(object : RecursiveJsVisitor() {
override fun visitObjectLiteral(x: JsObjectLiteral) {
super.visitObjectLiteral(x)
x.isMultiline = false
}
override fun visitVars(x: JsVars) {
x.isMultiline = false
super.visitVars(x)
}
})
removeLocationFromBlocks(generatedProgram)
generatedProgram.accept(AmbiguousAstSourcePropagation())
val output = TextOutputImpl()
val pathResolver = SourceFilePathResolver(mutableListOf(File(".")), null)
val sourceMapBuilder = SourceMap3Builder(outputFile, output, "")
generatedProgram.accept(
JsToStringGenerationVisitor(
output, SourceMapBuilderConsumer(File("."), sourceMapBuilder, pathResolver, false, false)
)
)
val code = output.toString()
val generatedSourceMap = sourceMapBuilder.build()
val codeWithLines = generatedProgram.toStringWithLineNumbers()
val parsedProgram = JsProgram()
parsedProgram.globalBlock.statements += parse(code, ThrowExceptionOnErrorReporter, parsedProgram.scope, outputFile.path).orEmpty()
removeLocationFromBlocks(parsedProgram)
val sourceMapParseResult = SourceMapParser.parse(generatedSourceMap)
val sourceMap = when (sourceMapParseResult) {
is SourceMapSuccess -> sourceMapParseResult.value
is SourceMapError -> error("Could not parse source map: ${sourceMapParseResult.message}")
}
if (remap) {
SourceMapLocationRemapper(sourceMap).remap(parsedProgram)
val codeWithRemappedLines = parsedProgram.toStringWithLineNumbers()
assertEquals(codeWithLines, codeWithRemappedLines)
}
}
private fun removeLocationFromBlocks(program: JsProgram) {
program.globalBlock.accept(object : RecursiveJsVisitor() {
override fun visitBlock(x: JsBlock) {
super.visitBlock(x)
x.source = null
}
})
}
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2010-2021 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.js.testNew.handlers
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import org.jetbrains.kotlin.js.facade.TranslationResult
import org.jetbrains.kotlin.test.backend.handlers.JsBinaryArtifactHandler
import org.jetbrains.kotlin.test.model.BinaryArtifacts
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import java.io.ByteArrayOutputStream
import java.io.PrintStream
import java.nio.charset.Charset
class JsTranslationResultHandler(testServices: TestServices) : JsBinaryArtifactHandler(testServices) {
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {}
override fun processModule(module: TestModule, info: BinaryArtifacts.Js) {
val result = (info as? BinaryArtifacts.Js.OldJsArtifact)?.translationResult
?: throw IllegalArgumentException("JsTranslationResultHandler suppose to work only with old js backend")
if (result !is TranslationResult.Success) {
val outputStream = ByteArrayOutputStream()
val collector = PrintingMessageCollector(PrintStream(outputStream), MessageRenderer.PLAIN_FULL_PATHS, true)
AnalyzerWithCompilerReport.reportDiagnostics(result.diagnostics, collector)
val messages = outputStream.toByteArray().toString(Charset.forName("UTF-8"))
throw AssertionError("The following errors occurred compiling test:\n$messages")
}
}
}
@@ -0,0 +1,42 @@
/*
* Copyright 2010-2021 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.js.testNew.handlers
import org.jetbrains.kotlin.js.testNew.utils.getTestChecker
import org.jetbrains.kotlin.test.backend.handlers.JsBinaryArtifactHandler
import org.jetbrains.kotlin.test.model.BinaryArtifacts
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.assertions
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import org.jetbrains.kotlin.test.services.moduleStructure
import java.io.File
class JsWrongModuleHandler(testServices: TestServices) : JsBinaryArtifactHandler(testServices) {
override fun processModule(module: TestModule, info: BinaryArtifacts.Js) {}
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {
val originalFileName = testServices.moduleStructure.originalTestDataFiles.first().nameWithoutExtension
val parentDir = JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices)
val mainJsFile = File(parentDir, "${originalFileName}_v5.js").path
val libJsFile = File(parentDir, "$originalFileName-lib_v5.js").path
try {
getTestChecker(testServices).run(listOf(mainJsFile, libJsFile))
} catch (e: RuntimeException) {
testServices.assertions.assertTrue(e is IllegalStateException)
val message = e.message!!
testServices.assertions.assertTrue("'lib'" in message) {
"Exception message should contain reference to dependency (lib)"
}
testServices.assertions.assertTrue("'main'" in message) {
"Exception message should contain reference to module that failed to load (main)"
}
return
}
testServices.assertions.fail { "Exception should have been thrown due to wrong order of modules" }
}
}
@@ -0,0 +1,77 @@
/*
* Copyright 2010-2021 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.js.testNew.handlers
import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.js.testNew.utils.extractTestPackage
import org.jetbrains.kotlin.js.testNew.utils.getMainModuleName
import org.jetbrains.kotlin.js.testNew.utils.getOnlyJsFilesForRunner
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import org.jetbrains.kotlin.test.services.defaultsProvider
import org.jetbrains.kotlin.test.services.moduleStructure
import java.io.File
// Only generate "node.js" file, execution is handled by 'runMocha' task
class NodeJsGeneratorHandler(testServices: TestServices) : AbstractJsArtifactsCollector(testServices) {
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {
if (someAssertionWasFailed) return
val allJsFiles = getOnlyJsFilesForRunner(testServices, modulesToArtifact)
val globalDirectives = testServices.moduleStructure.allDirectives
val dontRunGeneratedCode = globalDirectives[JsEnvironmentConfigurationDirectives.DONT_RUN_GENERATED_CODE]
.contains(testServices.defaultsProvider.defaultTargetBackend?.name)
val generateNodeJsRunner = JsEnvironmentConfigurationDirectives.GENERATE_NODE_JS_RUNNER in globalDirectives
val skipNodeJs = JsEnvironmentConfigurationDirectives.SKIP_NODE_JS in globalDirectives
if (dontRunGeneratedCode || !generateNodeJsRunner || skipNodeJs) return
val mainModuleName = getMainModuleName(testServices)
val outputDir = File(JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices).absolutePath)
val ignored = globalDirectives[CodegenTestDirectives.IGNORE_BACKEND].contains(TargetBackend.JS)
val testPackage = extractTestPackage(testServices)
val nodeRunnerText = generateNodeRunner(allJsFiles, outputDir, mainModuleName, ignored, testPackage)
val nodeRunnerName = JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, mainModuleName) + ".node.js"
FileUtil.writeToFile(File(nodeRunnerName), nodeRunnerText)
}
companion object {
fun generateNodeRunner(files: Collection<String>, dir: File, moduleName: String, ignored: Boolean, testPackage: String?): String {
val filesToLoad = files.map {
val relativePath = when {
it.startsWith(dir.absolutePath) -> FileUtil.getRelativePath(dir, File(it))!!
else -> it
}
"\"${relativePath.replace(File.separatorChar, '/')}\""
}
val fqn = testPackage?.let { ".$it" } ?: ""
val loadAndRun = "load([${filesToLoad.joinToString(",")}], '$moduleName')$fqn.box()"
val sb = StringBuilder()
sb.append("module.exports = function(load) {\n")
if (ignored) {
sb.append(" try {\n")
sb.append(" var result = $loadAndRun;\n")
sb.append(" if (result != 'OK') return 'OK';")
sb.append(" return 'fail: expected test failure';\n")
sb.append(" }\n")
sb.append(" catch (e) {\n")
sb.append(" return 'OK';\n")
sb.append("}\n")
} else {
sb.append(" return $loadAndRun;\n")
}
sb.append("};\n")
return sb.toString()
}
}
}
@@ -0,0 +1,161 @@
/*
* Copyright 2010-2021 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.js.testNew.utils
import org.jetbrains.kotlin.js.JavaScript
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.test.*
import org.jetbrains.kotlin.js.testNew.JsAdditionalSourceProvider
import org.jetbrains.kotlin.js.testNew.handlers.JsBoxRunner.Companion.TEST_FUNCTION
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.serialization.js.ModuleKind
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives.INFER_MAIN_MODULE
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives.NO_JS_MODULE_SYSTEM
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives.RUN_PLAIN_BOX_FUNCTION
import org.jetbrains.kotlin.test.model.BinaryArtifacts
import org.jetbrains.kotlin.test.model.TestFile
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.*
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import java.io.File
private const val MODULE_EMULATION_FILE = "${JsEnvironmentConfigurator.TEST_DATA_DIR_PATH}/moduleEmulation.js"
private fun extractJsFiles(
testServices: TestServices, modulesToArtifact: Map<TestModule, BinaryArtifacts.Js>
): Pair<List<String>, List<String>> {
val outputDir = JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices)
fun copyInputJsFile(module: TestModule, inputJsFile: TestFile): String {
val newName = JsEnvironmentConfigurator.getJsArtifactSimpleName(testServices, module.name) + "-js-" + inputJsFile.name
val targetFile = File(outputDir, newName)
targetFile.writeText(inputJsFile.originalContent)
return targetFile.absolutePath
}
val inputJsFiles = modulesToArtifact
.flatMap { moduleToArtifact -> moduleToArtifact.key.files.map { moduleToArtifact.key to it } }
.filter { it.second.isJsFile }
val after = inputJsFiles
.filter { (_, inputJsFile) -> inputJsFile.name.endsWith("__after.js") }
.map { (module, inputJsFile) -> copyInputJsFile(module, inputJsFile) }
val before = inputJsFiles
.filterNot { (_, inputJsFile) -> inputJsFile.name.endsWith("__after.js") }
.map { (module, inputJsFile) -> copyInputJsFile(module, inputJsFile) }
return before to after
}
private fun getAdditionalFiles(testServices: TestServices): List<String> {
val originalFile = testServices.moduleStructure.originalTestDataFiles.first()
val withModuleSystem = testWithModuleSystem(testServices)
val additionalFiles = mutableListOf<String>()
if (withModuleSystem) additionalFiles += File(MODULE_EMULATION_FILE).absolutePath
originalFile.parentFile.resolve(originalFile.nameWithoutExtension + JavaScript.DOT_EXTENSION)
.takeIf { it.exists() }
?.let { additionalFiles += it.absolutePath }
return additionalFiles
}
private fun getAdditionalMainFiles(testServices: TestServices): List<String> {
val originalFile = testServices.moduleStructure.originalTestDataFiles.first()
val additionalFiles = mutableListOf<String>()
originalFile.parentFile.resolve(originalFile.nameWithoutExtension + "__main.js")
.takeIf { it.exists() }
?.let { additionalFiles += it.absolutePath }
return additionalFiles
}
fun testWithModuleSystem(testServices: TestServices): Boolean {
val globalDirectives = testServices.moduleStructure.allDirectives
val configuration = testServices.compilerConfigurationProvider.getCompilerConfiguration(getMainModule(testServices))
val mainModuleKind = configuration[JSConfigurationKeys.MODULE_KIND]
return mainModuleKind != ModuleKind.PLAIN && NO_JS_MODULE_SYSTEM !in globalDirectives
}
fun getAllFilesForRunner(
testServices: TestServices, modulesToArtifact: Map<TestModule, BinaryArtifacts.Js>
): Triple<List<String>, List<String>, List<String>> {
val originalFile = testServices.moduleStructure.originalTestDataFiles.first()
val outputDir = JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices)
val dceOutputDir = JsEnvironmentConfigurator.getDceJsArtifactsOutputDir(testServices)
val pirOutputDir = JsEnvironmentConfigurator.getPirJsArtifactsOutputDir(testServices)
val commonFiles = JsAdditionalSourceProvider.getAdditionalJsFiles(originalFile.parent).map { it.absolutePath }
val (inputJsFilesBefore, inputJsFilesAfter) = extractJsFiles(testServices, modulesToArtifact)
val additionalFiles = getAdditionalFiles(testServices)
val additionalMainFiles = getAdditionalMainFiles(testServices)
val artifactsPaths = modulesToArtifact.values.map { it.outputFile.absolutePath }
val dceJsFiles = artifactsPaths.map { it.replace(outputDir.absolutePath, dceOutputDir.absolutePath) }
val pirJsFiles = artifactsPaths.map { it.replace(outputDir.absolutePath, pirOutputDir.absolutePath) }
val allJsFiles = additionalFiles + inputJsFilesBefore + artifactsPaths + commonFiles + additionalMainFiles + inputJsFilesAfter
val dceAllJsFiles = additionalFiles + inputJsFilesBefore + dceJsFiles + commonFiles + additionalMainFiles + inputJsFilesAfter
val pirAllJsFiles = additionalFiles + inputJsFilesBefore + pirJsFiles + commonFiles + additionalMainFiles + inputJsFilesAfter
return Triple(allJsFiles, dceAllJsFiles, pirAllJsFiles)
}
fun getOnlyJsFilesForRunner(testServices: TestServices, modulesToArtifact: Map<TestModule, BinaryArtifacts.Js>): List<String> {
return getAllFilesForRunner(testServices, modulesToArtifact).first
}
private fun getMainModule(testServices: TestServices): TestModule {
val modules = testServices.moduleStructure.modules
val inferMainModule = INFER_MAIN_MODULE in testServices.moduleStructure.allDirectives
return when {
inferMainModule -> modules.last()
else -> modules.singleOrNull { it.name == ModuleStructureExtractor.DEFAULT_MODULE_NAME } ?: modules.single()
}
}
fun getMainModuleName(testServices: TestServices): String {
return getMainModule(testServices).name
}
fun getTestModuleName(testServices: TestServices): String? {
val runPlainBoxFunction = RUN_PLAIN_BOX_FUNCTION in testServices.moduleStructure.allDirectives
if (runPlainBoxFunction) return null
return getMainModule(testServices).name
}
fun extractTestPackage(testServices: TestServices): String? {
val runPlainBoxFunction = RUN_PLAIN_BOX_FUNCTION in testServices.moduleStructure.allDirectives
if (runPlainBoxFunction) return null
val ktFiles = testServices.moduleStructure.modules.flatMap { module ->
module.files
.filter { it.isKtFile }
.map {
val project = testServices.compilerConfigurationProvider.getProject(module)
testServices.sourceFileProvider.getKtFileForSourceFile(it, project)
}
}
return ktFiles.single { ktFile ->
val boxFunction = ktFile.declarations.find { it is KtNamedFunction && it.name == TEST_FUNCTION }
boxFunction != null
}.packageFqName.asString().takeIf { it.isNotEmpty() }
}
fun getTestChecker(testServices: TestServices): AbstractJsTestChecker {
val runTestInNashorn = java.lang.Boolean.getBoolean("kotlin.js.useNashorn")
val targetBackend = testServices.defaultsProvider.defaultTargetBackend ?: TargetBackend.JS
return if (targetBackend.isIR) {
if (runTestInNashorn) NashornIrJsTestChecker else V8IrJsTestChecker
} else {
if (runTestInNashorn) NashornJsTestChecker else V8JsTestChecker
}
}
@@ -1,52 +0,0 @@
/*
* Copyright 2010-2021 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.js.test.ir.semantics;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("compiler/testData/codegen/boxWasmJsInterop")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class IrCodegenWasmJsInteropJsTestGenerated extends AbstractIrCodegenWasmJsInteropJsTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
}
public void testAllFilesPresentInBoxWasmJsInterop() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxWasmJsInterop"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
@TestMetadata("externalTypeOperators.kt")
public void testExternalTypeOperators() throws Exception {
runTest("compiler/testData/codegen/boxWasmJsInterop/externalTypeOperators.kt");
}
@TestMetadata("externals.kt")
public void testExternals() throws Exception {
runTest("compiler/testData/codegen/boxWasmJsInterop/externals.kt");
}
@TestMetadata("jsExport.kt")
public void testJsExport() throws Exception {
runTest("compiler/testData/codegen/boxWasmJsInterop/jsExport.kt");
}
@TestMetadata("types.kt")
public void testTypes() throws Exception {
runTest("compiler/testData/codegen/boxWasmJsInterop/types.kt");
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -3,574 +3,645 @@
* 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.js.test.semantics;
package org.jetbrains.kotlin.js.testNew;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
/** This class is generated by {@link GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("compiler/testData/codegen/box/arrays")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class JsLegacyPrimitiveArraysBoxTestGenerated extends AbstractJsLegacyPrimitiveArraysBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
}
@Test
public void testAllFilesPresentInArrays() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/arrays"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
@Test
@TestMetadata("arrayConstructorWithNonInlineLambda.kt")
public void testArrayConstructorWithNonInlineLambda() throws Exception {
runTest("compiler/testData/codegen/box/arrays/arrayConstructorWithNonInlineLambda.kt");
}
@Test
@TestMetadata("arrayConstructorsSimple.kt")
public void testArrayConstructorsSimple() throws Exception {
runTest("compiler/testData/codegen/box/arrays/arrayConstructorsSimple.kt");
}
@Test
@TestMetadata("arrayGetAssignMultiIndex.kt")
public void testArrayGetAssignMultiIndex() throws Exception {
runTest("compiler/testData/codegen/box/arrays/arrayGetAssignMultiIndex.kt");
}
@Test
@TestMetadata("arrayGetMultiIndex.kt")
public void testArrayGetMultiIndex() throws Exception {
runTest("compiler/testData/codegen/box/arrays/arrayGetMultiIndex.kt");
}
@Test
@TestMetadata("arrayInstanceOf.kt")
public void testArrayInstanceOf() throws Exception {
runTest("compiler/testData/codegen/box/arrays/arrayInstanceOf.kt");
}
@Test
@TestMetadata("arrayPlusAssign.kt")
public void testArrayPlusAssign() throws Exception {
runTest("compiler/testData/codegen/box/arrays/arrayPlusAssign.kt");
}
@Test
@TestMetadata("arraysAreCloneable.kt")
public void testArraysAreCloneable() throws Exception {
runTest("compiler/testData/codegen/box/arrays/arraysAreCloneable.kt");
}
@Test
@TestMetadata("cloneArray.kt")
public void testCloneArray() throws Exception {
runTest("compiler/testData/codegen/box/arrays/cloneArray.kt");
}
@Test
@TestMetadata("clonePrimitiveArrays.kt")
public void testClonePrimitiveArrays() throws Exception {
runTest("compiler/testData/codegen/box/arrays/clonePrimitiveArrays.kt");
}
@Test
@TestMetadata("collectionAssignGetMultiIndex.kt")
public void testCollectionAssignGetMultiIndex() throws Exception {
runTest("compiler/testData/codegen/box/arrays/collectionAssignGetMultiIndex.kt");
}
@Test
@TestMetadata("collectionGetMultiIndex.kt")
public void testCollectionGetMultiIndex() throws Exception {
runTest("compiler/testData/codegen/box/arrays/collectionGetMultiIndex.kt");
}
@Test
@TestMetadata("constantArrayOfAny.kt")
public void testConstantArrayOfAny() throws Exception {
runTest("compiler/testData/codegen/box/arrays/constantArrayOfAny.kt");
}
@Test
@TestMetadata("forEachBooleanArray.kt")
public void testForEachBooleanArray() throws Exception {
runTest("compiler/testData/codegen/box/arrays/forEachBooleanArray.kt");
}
@Test
@TestMetadata("forEachByteArray.kt")
public void testForEachByteArray() throws Exception {
runTest("compiler/testData/codegen/box/arrays/forEachByteArray.kt");
}
@Test
@TestMetadata("forEachCharArray.kt")
public void testForEachCharArray() throws Exception {
runTest("compiler/testData/codegen/box/arrays/forEachCharArray.kt");
}
@Test
@TestMetadata("forEachDoubleArray.kt")
public void testForEachDoubleArray() throws Exception {
runTest("compiler/testData/codegen/box/arrays/forEachDoubleArray.kt");
}
@Test
@TestMetadata("forEachFloatArray.kt")
public void testForEachFloatArray() throws Exception {
runTest("compiler/testData/codegen/box/arrays/forEachFloatArray.kt");
}
@Test
@TestMetadata("forEachIntArray.kt")
public void testForEachIntArray() throws Exception {
runTest("compiler/testData/codegen/box/arrays/forEachIntArray.kt");
}
@Test
@TestMetadata("forEachLongArray.kt")
public void testForEachLongArray() throws Exception {
runTest("compiler/testData/codegen/box/arrays/forEachLongArray.kt");
}
@Test
@TestMetadata("forEachShortArray.kt")
public void testForEachShortArray() throws Exception {
runTest("compiler/testData/codegen/box/arrays/forEachShortArray.kt");
}
@Test
@TestMetadata("genericArrayInObjectLiteralConstructor.kt")
public void testGenericArrayInObjectLiteralConstructor() throws Exception {
runTest("compiler/testData/codegen/box/arrays/genericArrayInObjectLiteralConstructor.kt");
}
@Test
@TestMetadata("hashMap.kt")
public void testHashMap() throws Exception {
runTest("compiler/testData/codegen/box/arrays/hashMap.kt");
}
@Test
@TestMetadata("inProjectionAsParameter.kt")
public void testInProjectionAsParameter() throws Exception {
runTest("compiler/testData/codegen/box/arrays/inProjectionAsParameter.kt");
}
@Test
@TestMetadata("inProjectionOfArray.kt")
public void testInProjectionOfArray() throws Exception {
runTest("compiler/testData/codegen/box/arrays/inProjectionOfArray.kt");
}
@Test
@TestMetadata("inProjectionOfList.kt")
public void testInProjectionOfList() throws Exception {
runTest("compiler/testData/codegen/box/arrays/inProjectionOfList.kt");
}
@Test
@TestMetadata("indices.kt")
public void testIndices() throws Exception {
runTest("compiler/testData/codegen/box/arrays/indices.kt");
}
@Test
@TestMetadata("indicesChar.kt")
public void testIndicesChar() throws Exception {
runTest("compiler/testData/codegen/box/arrays/indicesChar.kt");
}
@Test
@TestMetadata("inlineInitializer.kt")
public void testInlineInitializer() throws Exception {
runTest("compiler/testData/codegen/box/arrays/inlineInitializer.kt");
}
@Test
@TestMetadata("iterator.kt")
public void testIterator() throws Exception {
runTest("compiler/testData/codegen/box/arrays/iterator.kt");
}
@Test
@TestMetadata("iteratorBooleanArray.kt")
public void testIteratorBooleanArray() throws Exception {
runTest("compiler/testData/codegen/box/arrays/iteratorBooleanArray.kt");
}
@Test
@TestMetadata("iteratorByteArray.kt")
public void testIteratorByteArray() throws Exception {
runTest("compiler/testData/codegen/box/arrays/iteratorByteArray.kt");
}
@Test
@TestMetadata("iteratorByteArrayNextByte.kt")
public void testIteratorByteArrayNextByte() throws Exception {
runTest("compiler/testData/codegen/box/arrays/iteratorByteArrayNextByte.kt");
}
@Test
@TestMetadata("iteratorCharArray.kt")
public void testIteratorCharArray() throws Exception {
runTest("compiler/testData/codegen/box/arrays/iteratorCharArray.kt");
}
@Test
@TestMetadata("iteratorDoubleArray.kt")
public void testIteratorDoubleArray() throws Exception {
runTest("compiler/testData/codegen/box/arrays/iteratorDoubleArray.kt");
}
@Test
@TestMetadata("iteratorFloatArray.kt")
public void testIteratorFloatArray() throws Exception {
runTest("compiler/testData/codegen/box/arrays/iteratorFloatArray.kt");
}
@Test
@TestMetadata("iteratorIntArray.kt")
public void testIteratorIntArray() throws Exception {
runTest("compiler/testData/codegen/box/arrays/iteratorIntArray.kt");
}
@Test
@TestMetadata("iteratorLongArray.kt")
public void testIteratorLongArray() throws Exception {
runTest("compiler/testData/codegen/box/arrays/iteratorLongArray.kt");
}
@Test
@TestMetadata("iteratorLongArrayNextLong.kt")
public void testIteratorLongArrayNextLong() throws Exception {
runTest("compiler/testData/codegen/box/arrays/iteratorLongArrayNextLong.kt");
}
@Test
@TestMetadata("iteratorShortArray.kt")
public void testIteratorShortArray() throws Exception {
runTest("compiler/testData/codegen/box/arrays/iteratorShortArray.kt");
}
@Test
@TestMetadata("kt1291.kt")
public void testKt1291() throws Exception {
runTest("compiler/testData/codegen/box/arrays/kt1291.kt");
}
@Test
@TestMetadata("kt238.kt")
public void testKt238() throws Exception {
runTest("compiler/testData/codegen/box/arrays/kt238.kt");
}
@Test
@TestMetadata("kt2997.kt")
public void testKt2997() throws Exception {
runTest("compiler/testData/codegen/box/arrays/kt2997.kt");
}
@Test
@TestMetadata("kt33.kt")
public void testKt33() throws Exception {
runTest("compiler/testData/codegen/box/arrays/kt33.kt");
}
@Test
@TestMetadata("kt34291_16dimensions.kt")
public void testKt34291_16dimensions() throws Exception {
runTest("compiler/testData/codegen/box/arrays/kt34291_16dimensions.kt");
}
@Test
@TestMetadata("kt3771.kt")
public void testKt3771() throws Exception {
runTest("compiler/testData/codegen/box/arrays/kt3771.kt");
}
@Test
@TestMetadata("kt4118.kt")
public void testKt4118() throws Exception {
runTest("compiler/testData/codegen/box/arrays/kt4118.kt");
}
@Test
@TestMetadata("kt42932.kt")
public void testKt42932() throws Exception {
runTest("compiler/testData/codegen/box/arrays/kt42932.kt");
}
@Test
@TestMetadata("kt4348.kt")
public void testKt4348() throws Exception {
runTest("compiler/testData/codegen/box/arrays/kt4348.kt");
}
@Test
@TestMetadata("kt4357.kt")
public void testKt4357() throws Exception {
runTest("compiler/testData/codegen/box/arrays/kt4357.kt");
}
@Test
@TestMetadata("kt503.kt")
public void testKt503() throws Exception {
runTest("compiler/testData/codegen/box/arrays/kt503.kt");
}
@Test
@TestMetadata("kt594.kt")
public void testKt594() throws Exception {
runTest("compiler/testData/codegen/box/arrays/kt594.kt");
}
@Test
@TestMetadata("kt7009.kt")
public void testKt7009() throws Exception {
runTest("compiler/testData/codegen/box/arrays/kt7009.kt");
}
@Test
@TestMetadata("kt7288.kt")
public void testKt7288() throws Exception {
runTest("compiler/testData/codegen/box/arrays/kt7288.kt");
}
@Test
@TestMetadata("kt7338.kt")
public void testKt7338() throws Exception {
runTest("compiler/testData/codegen/box/arrays/kt7338.kt");
}
@Test
@TestMetadata("kt779.kt")
public void testKt779() throws Exception {
runTest("compiler/testData/codegen/box/arrays/kt779.kt");
}
@Test
@TestMetadata("kt945.kt")
public void testKt945() throws Exception {
runTest("compiler/testData/codegen/box/arrays/kt945.kt");
}
@Test
@TestMetadata("kt950.kt")
public void testKt950() throws Exception {
runTest("compiler/testData/codegen/box/arrays/kt950.kt");
}
@Test
@TestMetadata("longAsIndex.kt")
public void testLongAsIndex() throws Exception {
runTest("compiler/testData/codegen/box/arrays/longAsIndex.kt");
}
@Test
@TestMetadata("multiArrayConstructors.kt")
public void testMultiArrayConstructors() throws Exception {
runTest("compiler/testData/codegen/box/arrays/multiArrayConstructors.kt");
}
@Test
@TestMetadata("nonLocalReturnArrayConstructor.kt")
public void testNonLocalReturnArrayConstructor() throws Exception {
runTest("compiler/testData/codegen/box/arrays/nonLocalReturnArrayConstructor.kt");
}
@Test
@TestMetadata("nonNullArray.kt")
public void testNonNullArray() throws Exception {
runTest("compiler/testData/codegen/box/arrays/nonNullArray.kt");
}
@Test
@TestMetadata("primitiveArrays.kt")
public void testPrimitiveArrays() throws Exception {
runTest("compiler/testData/codegen/box/arrays/primitiveArrays.kt");
}
@Test
@TestMetadata("stdlib.kt")
public void testStdlib() throws Exception {
runTest("compiler/testData/codegen/box/arrays/stdlib.kt");
}
@Nested
@TestMetadata("compiler/testData/codegen/box/arrays/arraysOfInlineClass")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ArraysOfInlineClass extends AbstractJsLegacyPrimitiveArraysBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
}
public class ArraysOfInlineClass {
@Test
@TestMetadata("accessArrayOfInlineClass.kt")
public void testAccessArrayOfInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/arrays/arraysOfInlineClass/accessArrayOfInlineClass.kt");
}
@Test
@TestMetadata("accessArrayOfUnsigned.kt")
public void testAccessArrayOfUnsigned() throws Exception {
runTest("compiler/testData/codegen/box/arrays/arraysOfInlineClass/accessArrayOfUnsigned.kt");
}
@Test
public void testAllFilesPresentInArraysOfInlineClass() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/arrays/arraysOfInlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
@Test
@TestMetadata("arrayOfInlineClassOfArrayOfInlineClass.kt")
public void testArrayOfInlineClassOfArrayOfInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/arrays/arraysOfInlineClass/arrayOfInlineClassOfArrayOfInlineClass.kt");
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/arrays/forInReversed")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ForInReversed extends AbstractJsLegacyPrimitiveArraysBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
}
public class ForInReversed {
@Test
public void testAllFilesPresentInForInReversed() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/arrays/forInReversed"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
@Test
@TestMetadata("reversedArrayOriginalUpdatedInLoopBody.kt")
public void testReversedArrayOriginalUpdatedInLoopBody() throws Exception {
runTest("compiler/testData/codegen/box/arrays/forInReversed/reversedArrayOriginalUpdatedInLoopBody.kt");
}
@Test
@TestMetadata("reversedArrayReversedArrayOriginalUpdatedInLoopBody.kt")
public void testReversedArrayReversedArrayOriginalUpdatedInLoopBody() throws Exception {
runTest("compiler/testData/codegen/box/arrays/forInReversed/reversedArrayReversedArrayOriginalUpdatedInLoopBody.kt");
}
@Test
@TestMetadata("reversedOriginalUpdatedInLoopBody.kt")
public void testReversedOriginalUpdatedInLoopBody() throws Exception {
runTest("compiler/testData/codegen/box/arrays/forInReversed/reversedOriginalUpdatedInLoopBody.kt");
}
@Test
@TestMetadata("reversedReversedOriginalUpdatedInLoopBody.kt")
public void testReversedReversedOriginalUpdatedInLoopBody() throws Exception {
runTest("compiler/testData/codegen/box/arrays/forInReversed/reversedReversedOriginalUpdatedInLoopBody.kt");
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/arrays/forInUnsignedArray")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ForInUnsignedArray extends AbstractJsLegacyPrimitiveArraysBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
}
public class ForInUnsignedArray {
@Test
public void testAllFilesPresentInForInUnsignedArray() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/arrays/forInUnsignedArray"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
@Test
@TestMetadata("forInUnsignedArray.kt")
public void testForInUnsignedArray() throws Exception {
runTest("compiler/testData/codegen/box/arrays/forInUnsignedArray/forInUnsignedArray.kt");
}
@Test
@TestMetadata("forInUnsignedArrayIndices.kt")
public void testForInUnsignedArrayIndices() throws Exception {
runTest("compiler/testData/codegen/box/arrays/forInUnsignedArray/forInUnsignedArrayIndices.kt");
}
@Test
@TestMetadata("forInUnsignedArrayIndicesReversed.kt")
public void testForInUnsignedArrayIndicesReversed() throws Exception {
runTest("compiler/testData/codegen/box/arrays/forInUnsignedArray/forInUnsignedArrayIndicesReversed.kt");
}
@Test
@TestMetadata("forInUnsignedArrayReversed.kt")
public void testForInUnsignedArrayReversed() throws Exception {
runTest("compiler/testData/codegen/box/arrays/forInUnsignedArray/forInUnsignedArrayReversed.kt");
}
@Test
@TestMetadata("forInUnsignedArrayWithIndex.kt")
public void testForInUnsignedArrayWithIndex() throws Exception {
runTest("compiler/testData/codegen/box/arrays/forInUnsignedArray/forInUnsignedArrayWithIndex.kt");
}
@Test
@TestMetadata("forInUnsignedArrayWithIndexNoElementVar.kt")
public void testForInUnsignedArrayWithIndexNoElementVar() throws Exception {
runTest("compiler/testData/codegen/box/arrays/forInUnsignedArray/forInUnsignedArrayWithIndexNoElementVar.kt");
}
@Test
@TestMetadata("forInUnsignedArrayWithIndexNoIndexVar.kt")
public void testForInUnsignedArrayWithIndexNoIndexVar() throws Exception {
runTest("compiler/testData/codegen/box/arrays/forInUnsignedArray/forInUnsignedArrayWithIndexNoIndexVar.kt");
}
@Test
@TestMetadata("forInUnsignedArrayWithIndexReversed.kt")
public void testForInUnsignedArrayWithIndexReversed() throws Exception {
runTest("compiler/testData/codegen/box/arrays/forInUnsignedArray/forInUnsignedArrayWithIndexReversed.kt");
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/arrays/multiDecl")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class MultiDecl extends AbstractJsLegacyPrimitiveArraysBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
}
public class MultiDecl {
@Test
public void testAllFilesPresentInMultiDecl() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/arrays/multiDecl"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
@Test
@TestMetadata("kt15560.kt")
public void testKt15560() throws Exception {
runTest("compiler/testData/codegen/box/arrays/multiDecl/kt15560.kt");
}
@Test
@TestMetadata("kt15568.kt")
public void testKt15568() throws Exception {
runTest("compiler/testData/codegen/box/arrays/multiDecl/kt15568.kt");
}
@Test
@TestMetadata("kt15575.kt")
public void testKt15575() throws Exception {
runTest("compiler/testData/codegen/box/arrays/multiDecl/kt15575.kt");
}
@Test
@TestMetadata("MultiDeclFor.kt")
public void testMultiDeclFor() throws Exception {
runTest("compiler/testData/codegen/box/arrays/multiDecl/MultiDeclFor.kt");
}
@Test
@TestMetadata("MultiDeclForComponentExtensions.kt")
public void testMultiDeclForComponentExtensions() throws Exception {
runTest("compiler/testData/codegen/box/arrays/multiDecl/MultiDeclForComponentExtensions.kt");
}
@Test
@TestMetadata("MultiDeclForComponentMemberExtensions.kt")
public void testMultiDeclForComponentMemberExtensions() throws Exception {
runTest("compiler/testData/codegen/box/arrays/multiDecl/MultiDeclForComponentMemberExtensions.kt");
}
@Test
@TestMetadata("MultiDeclForComponentMemberExtensionsInExtensionFunction.kt")
public void testMultiDeclForComponentMemberExtensionsInExtensionFunction() throws Exception {
runTest("compiler/testData/codegen/box/arrays/multiDecl/MultiDeclForComponentMemberExtensionsInExtensionFunction.kt");
}
@Test
@TestMetadata("MultiDeclForValCaptured.kt")
public void testMultiDeclForValCaptured() throws Exception {
runTest("compiler/testData/codegen/box/arrays/multiDecl/MultiDeclForValCaptured.kt");
}
@Nested
@TestMetadata("compiler/testData/codegen/box/arrays/multiDecl/int")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Int extends AbstractJsLegacyPrimitiveArraysBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
}
public class Int {
@Test
public void testAllFilesPresentInInt() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/arrays/multiDecl/int"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
@Test
@TestMetadata("MultiDeclForComponentExtensions.kt")
public void testMultiDeclForComponentExtensions() throws Exception {
runTest("compiler/testData/codegen/box/arrays/multiDecl/int/MultiDeclForComponentExtensions.kt");
}
@Test
@TestMetadata("MultiDeclForComponentExtensionsValCaptured.kt")
public void testMultiDeclForComponentExtensionsValCaptured() throws Exception {
runTest("compiler/testData/codegen/box/arrays/multiDecl/int/MultiDeclForComponentExtensionsValCaptured.kt");
}
@Test
@TestMetadata("MultiDeclForComponentMemberExtensions.kt")
public void testMultiDeclForComponentMemberExtensions() throws Exception {
runTest("compiler/testData/codegen/box/arrays/multiDecl/int/MultiDeclForComponentMemberExtensions.kt");
}
@Test
@TestMetadata("MultiDeclForComponentMemberExtensionsInExtensionFunction.kt")
public void testMultiDeclForComponentMemberExtensionsInExtensionFunction() throws Exception {
runTest("compiler/testData/codegen/box/arrays/multiDecl/int/MultiDeclForComponentMemberExtensionsInExtensionFunction.kt");
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/arrays/multiDecl/long")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Long extends AbstractJsLegacyPrimitiveArraysBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
}
public class Long {
@Test
public void testAllFilesPresentInLong() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/arrays/multiDecl/long"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
@Test
@TestMetadata("MultiDeclForComponentExtensions.kt")
public void testMultiDeclForComponentExtensions() throws Exception {
runTest("compiler/testData/codegen/box/arrays/multiDecl/long/MultiDeclForComponentExtensions.kt");
}
@Test
@TestMetadata("MultiDeclForComponentExtensionsValCaptured.kt")
public void testMultiDeclForComponentExtensionsValCaptured() throws Exception {
runTest("compiler/testData/codegen/box/arrays/multiDecl/long/MultiDeclForComponentExtensionsValCaptured.kt");
}
@Test
@TestMetadata("MultiDeclForComponentMemberExtensions.kt")
public void testMultiDeclForComponentMemberExtensions() throws Exception {
runTest("compiler/testData/codegen/box/arrays/multiDecl/long/MultiDeclForComponentMemberExtensions.kt");
}
@Test
@TestMetadata("MultiDeclForComponentMemberExtensionsInExtensionFunction.kt")
public void testMultiDeclForComponentMemberExtensionsInExtensionFunction() throws Exception {
runTest("compiler/testData/codegen/box/arrays/multiDecl/long/MultiDeclForComponentMemberExtensionsInExtensionFunction.kt");
@@ -0,0 +1,39 @@
/*
* Copyright 2010-2021 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.js.testNew;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("js/js.translator/testData/multiModuleOrder")
@TestDataPath("$PROJECT_ROOT")
public class MultiModuleOrderTestGenerated extends AbstractMultiModuleOrderTest {
@Test
public void testAllFilesPresentInMultiModuleOrder() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/multiModuleOrder"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
@Test
@TestMetadata("plain.kt")
public void testPlain() throws Exception {
runTest("js/js.translator/testData/multiModuleOrder/plain.kt");
}
@Test
@TestMetadata("umd.kt")
public void testUmd() throws Exception {
runTest("js/js.translator/testData/multiModuleOrder/umd.kt");
}
}
@@ -3,48 +3,47 @@
* 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.js.test.semantics;
package org.jetbrains.kotlin.js.testNew;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
/** This class is generated by {@link GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("js/js.translator/testData/outputPrefixPostfix")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class OutputPrefixPostfixTestGenerated extends AbstractOutputPrefixPostfixTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
}
@Test
public void testAllFilesPresentInOutputPrefixPostfix() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/outputPrefixPostfix"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS, true);
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/outputPrefixPostfix"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("js/js.translator/testData/outputPrefixPostfix/simple.kt");
}
@Test
@TestMetadata("simpleWithPostfix.kt")
public void testSimpleWithPostfix() throws Exception {
runTest("js/js.translator/testData/outputPrefixPostfix/simpleWithPostfix.kt");
}
@Test
@TestMetadata("simpleWithPrefix.kt")
public void testSimpleWithPrefix() throws Exception {
runTest("js/js.translator/testData/outputPrefixPostfix/simpleWithPrefix.kt");
}
@Test
@TestMetadata("simpleWithPrefixAndPostfix.kt")
public void testSimpleWithPrefixAndPostfix() throws Exception {
runTest("js/js.translator/testData/outputPrefixPostfix/simpleWithPrefixAndPostfix.kt");
@@ -3,48 +3,47 @@
* 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.js.test.semantics;
package org.jetbrains.kotlin.js.testNew;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
/** This class is generated by {@link GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("js/js.translator/testData/sourcemap")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class SourceMapGenerationSmokeTestGenerated extends AbstractSourceMapGenerationSmokeTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
}
@Test
public void testAllFilesPresentInSourcemap() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/sourcemap"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS, true);
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/sourcemap"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
@Test
@TestMetadata("binaryOperation.kt")
public void testBinaryOperation() throws Exception {
runTest("js/js.translator/testData/sourcemap/binaryOperation.kt");
}
@Test
@TestMetadata("emptyIfInsideInlineLambda.kt")
public void testEmptyIfInsideInlineLambda() throws Exception {
runTest("js/js.translator/testData/sourcemap/emptyIfInsideInlineLambda.kt");
}
@Test
@TestMetadata("expressionBody.kt")
public void testExpressionBody() throws Exception {
runTest("js/js.translator/testData/sourcemap/expressionBody.kt");
}
@Test
@TestMetadata("methodCallInMethod.kt")
public void testMethodCallInMethod() throws Exception {
runTest("js/js.translator/testData/sourcemap/methodCallInMethod.kt");
+1 -1
View File
@@ -60,4 +60,4 @@ allFiles.forEach(function(path) {
});
// TODO: Support multimodule tests
console.log(vm.runInContext("JS_TESTS.box()", sandbox));
console.log(vm.runInContext("main.box()", sandbox));