[TEST] Introduce test-infrastructure-utils module and extract common test utilities here
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2000-2010 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 com.intellij.testFramework;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks the annotated parameter as referencing a file in the testdata directory.
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target({ElementType.PARAMETER})
|
||||
public @interface TestDataFile {
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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 com.intellij.testFramework;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specifies the path to testdata for the current test case class.
|
||||
* May use the variable $CONTENT_ROOT to specify the module content root or
|
||||
* $PROJECT_ROOT to use the project base directory.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE})
|
||||
public @interface TestDataPath {
|
||||
String value();
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.codeMetaInfo
|
||||
|
||||
import org.jetbrains.kotlin.codeMetaInfo.model.ParsedCodeMetaInfo
|
||||
|
||||
object CodeMetaInfoParser {
|
||||
val openingRegex = """(<!([^"]*?((".*?")(, ".*?")*?)?[^"]*?)!>)""".toRegex()
|
||||
val closingRegex = """(<!>)""".toRegex()
|
||||
|
||||
val openingOrClosingRegex = """(${closingRegex.pattern}|${openingRegex.pattern})""".toRegex()
|
||||
|
||||
/*
|
||||
* ([\S&&[^,(){}]]+) -- tag, allowing all non-space characters except bracers and curly bracers
|
||||
* ([{](.*?)[}])? -- list of platforms
|
||||
* (\("(.*?)"\))? -- arguments of meta info
|
||||
* (, )? -- possible separator between different infos
|
||||
*/
|
||||
private val tagRegex = """([\S&&[^,(){}]]+)([{](.*?)[}])?(\("(.*?)"\))?(, )?""".toRegex()
|
||||
|
||||
fun getCodeMetaInfoFromText(renderedText: String): List<ParsedCodeMetaInfo> {
|
||||
var text = renderedText
|
||||
val openingMatchResults = ArrayDeque<MatchResult>()
|
||||
val stackOfOpeningMatchResults = ArrayDeque<MatchResult>()
|
||||
val closingMatchResults = mutableMapOf<MatchResult, MatchResult>()
|
||||
val result = mutableListOf<ParsedCodeMetaInfo>()
|
||||
|
||||
while (true) {
|
||||
var openingStartOffset = Int.MAX_VALUE
|
||||
var closingStartOffset = Int.MAX_VALUE
|
||||
val opening = openingRegex.find(text)
|
||||
val closing = closingRegex.find(text)
|
||||
if (opening == null && closing == null) break
|
||||
|
||||
if (opening != null)
|
||||
openingStartOffset = opening.range.first
|
||||
if (closing != null)
|
||||
closingStartOffset = closing.range.first
|
||||
|
||||
text = if (openingStartOffset < closingStartOffset) {
|
||||
requireNotNull(opening)
|
||||
openingMatchResults.addLast(opening)
|
||||
stackOfOpeningMatchResults.addLast(opening)
|
||||
text.removeRange(openingStartOffset, opening.range.last + 1)
|
||||
} else {
|
||||
requireNotNull(closing)
|
||||
closingMatchResults[stackOfOpeningMatchResults.removeLast()] = closing
|
||||
text.removeRange(closingStartOffset, closing.range.last + 1)
|
||||
}
|
||||
}
|
||||
if (openingMatchResults.size != closingMatchResults.size) {
|
||||
error("Opening and closing tags counts are not equals")
|
||||
}
|
||||
while (!openingMatchResults.isEmpty()) {
|
||||
val openingMatchResult = openingMatchResults.removeLast()
|
||||
val closingMatchResult = closingMatchResults.getValue(openingMatchResult)
|
||||
val allMetaInfos = openingMatchResult.groups[2]!!.value
|
||||
tagRegex.findAll(allMetaInfos).map { it.groups }.forEach {
|
||||
val tag = it[1]!!.value
|
||||
val platforms = it[3]?.value?.split(";") ?: emptyList()
|
||||
val description = it[5]?.value
|
||||
|
||||
result.add(
|
||||
ParsedCodeMetaInfo(
|
||||
openingMatchResult.range.first,
|
||||
closingMatchResult.range.first,
|
||||
platforms.toMutableList(),
|
||||
tag,
|
||||
description
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.codeMetaInfo
|
||||
|
||||
import com.intellij.util.containers.Stack
|
||||
import org.jetbrains.kotlin.checkers.utils.CheckerTestUtil
|
||||
import org.jetbrains.kotlin.codeMetaInfo.model.CodeMetaInfo
|
||||
import java.io.File
|
||||
|
||||
object CodeMetaInfoRenderer {
|
||||
fun renderTagsToText(
|
||||
codeMetaInfos: List<CodeMetaInfo>,
|
||||
originalText: String
|
||||
): StringBuilder {
|
||||
return StringBuilder().apply {
|
||||
renderTagsToText(this, codeMetaInfos, originalText)
|
||||
}
|
||||
}
|
||||
|
||||
fun renderTagsToText(
|
||||
builder: StringBuilder,
|
||||
codeMetaInfos: List<CodeMetaInfo>,
|
||||
originalText: String
|
||||
) {
|
||||
if (codeMetaInfos.isEmpty()) {
|
||||
builder.append(originalText)
|
||||
return
|
||||
}
|
||||
val sortedMetaInfos = getSortedCodeMetaInfos(codeMetaInfos).groupBy { it.start }
|
||||
val opened = Stack<CodeMetaInfo>()
|
||||
|
||||
for ((i, c) in originalText.withIndex()) {
|
||||
processMetaInfosStartedAtOffset(i, sortedMetaInfos, opened, builder)
|
||||
builder.append(c)
|
||||
}
|
||||
val lastSymbolIsNewLine = builder.last() == '\n'
|
||||
if (lastSymbolIsNewLine) {
|
||||
builder.deleteCharAt(builder.length - 1)
|
||||
}
|
||||
processMetaInfosStartedAtOffset(originalText.length, sortedMetaInfos, opened, builder)
|
||||
if (lastSymbolIsNewLine) {
|
||||
builder.appendLine()
|
||||
}
|
||||
}
|
||||
|
||||
private fun processMetaInfosStartedAtOffset(
|
||||
offset: Int,
|
||||
sortedMetaInfos: Map<Int, List<CodeMetaInfo>>,
|
||||
opened: Stack<CodeMetaInfo>,
|
||||
builder: StringBuilder
|
||||
) {
|
||||
checkOpenedAndCloseStringIfNeeded(opened, offset, builder)
|
||||
val matchedCodeMetaInfos = sortedMetaInfos[offset] ?: emptyList()
|
||||
if (matchedCodeMetaInfos.isNotEmpty()) {
|
||||
openStartTag(builder)
|
||||
val iterator = matchedCodeMetaInfos.listIterator()
|
||||
var current: CodeMetaInfo? = iterator.next()
|
||||
|
||||
while (current != null) {
|
||||
val next: CodeMetaInfo? = if (iterator.hasNext()) iterator.next() else null
|
||||
opened.push(current)
|
||||
builder.append(current.asString())
|
||||
when {
|
||||
next == null ->
|
||||
closeStartTag(builder)
|
||||
next.end == current.end ->
|
||||
builder.append(", ")
|
||||
else ->
|
||||
closeStartAndOpenNewTag(builder)
|
||||
}
|
||||
current = next
|
||||
}
|
||||
}
|
||||
// Here we need to handle meta infos which has start == end and close them immediately
|
||||
checkOpenedAndCloseStringIfNeeded(opened, offset, builder)
|
||||
}
|
||||
|
||||
private val metaInfoComparator = (compareBy<CodeMetaInfo> { it.start } then compareByDescending { it.end }) then compareBy { it.tag }
|
||||
|
||||
private fun getSortedCodeMetaInfos(metaInfos: Collection<CodeMetaInfo>): List<CodeMetaInfo> {
|
||||
return metaInfos.sortedWith(metaInfoComparator)
|
||||
}
|
||||
|
||||
private fun closeString(result: StringBuilder) = result.append("<!>")
|
||||
private fun openStartTag(result: StringBuilder) = result.append("<!")
|
||||
private fun closeStartTag(result: StringBuilder) = result.append("!>")
|
||||
private fun closeStartAndOpenNewTag(result: StringBuilder) = result.append("!><!")
|
||||
|
||||
private fun checkOpenedAndCloseStringIfNeeded(opened: Stack<CodeMetaInfo>, end: Int, result: StringBuilder) {
|
||||
var prev: CodeMetaInfo? = null
|
||||
while (!opened.isEmpty() && end == opened.peek().end) {
|
||||
if (prev == null || prev.start != opened.peek().start)
|
||||
closeString(result)
|
||||
prev = opened.pop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun clearFileFromDiagnosticMarkup(file: File) {
|
||||
val text = file.readText()
|
||||
val cleanText = clearTextFromDiagnosticMarkup(text)
|
||||
file.writeText(cleanText)
|
||||
}
|
||||
|
||||
fun clearTextFromDiagnosticMarkup(text: String): String = text.replace(CodeMetaInfoParser.openingOrClosingRegex, "")
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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.codeMetaInfo.model
|
||||
|
||||
import org.jetbrains.kotlin.codeMetaInfo.renderConfigurations.AbstractCodeMetaInfoRenderConfiguration
|
||||
|
||||
interface CodeMetaInfo {
|
||||
val start: Int
|
||||
val end: Int
|
||||
val tag: String
|
||||
val renderConfiguration: AbstractCodeMetaInfoRenderConfiguration
|
||||
val attributes: MutableList<String>
|
||||
|
||||
fun asString(): String
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.codeMetaInfo.model
|
||||
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import org.jetbrains.kotlin.codeMetaInfo.renderConfigurations.DiagnosticCodeMetaInfoRenderConfiguration
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
|
||||
class DiagnosticCodeMetaInfo(
|
||||
override val start: Int,
|
||||
override val end: Int,
|
||||
renderConfiguration: DiagnosticCodeMetaInfoRenderConfiguration,
|
||||
val diagnostic: Diagnostic
|
||||
) : CodeMetaInfo {
|
||||
constructor(
|
||||
range: TextRange,
|
||||
renderConfiguration: DiagnosticCodeMetaInfoRenderConfiguration,
|
||||
diagnostic: Diagnostic
|
||||
) : this(range.startOffset, range.endOffset, renderConfiguration, diagnostic)
|
||||
|
||||
override var renderConfiguration: DiagnosticCodeMetaInfoRenderConfiguration = renderConfiguration
|
||||
private set
|
||||
|
||||
fun replaceRenderConfiguration(renderConfiguration: DiagnosticCodeMetaInfoRenderConfiguration) {
|
||||
this.renderConfiguration = renderConfiguration
|
||||
}
|
||||
|
||||
override val tag: String
|
||||
get() = renderConfiguration.getTag(this)
|
||||
|
||||
override val attributes: MutableList<String> = mutableListOf()
|
||||
|
||||
override fun asString(): String = renderConfiguration.asString(this)
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.codeMetaInfo.model
|
||||
|
||||
import org.jetbrains.kotlin.codeMetaInfo.renderConfigurations.ParsedCodeMetaInfoRenderConfiguration
|
||||
|
||||
class ParsedCodeMetaInfo(
|
||||
override val start: Int,
|
||||
override val end: Int,
|
||||
override val attributes: MutableList<String>,
|
||||
override val tag: String,
|
||||
val description: String?
|
||||
) : CodeMetaInfo {
|
||||
override val renderConfiguration = ParsedCodeMetaInfoRenderConfiguration
|
||||
|
||||
override fun asString(): String = renderConfiguration.asString(this)
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other == null || other !is CodeMetaInfo) return false
|
||||
return this.tag == other.tag && this.start == other.start && this.end == other.end
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = start
|
||||
result = 31 * result + end
|
||||
result = 31 * result + tag.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
fun copy(): ParsedCodeMetaInfo {
|
||||
return ParsedCodeMetaInfo(start, end, attributes.toMutableList(), tag, description)
|
||||
}
|
||||
}
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.codeMetaInfo.renderConfigurations
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import org.jetbrains.kotlin.codeMetaInfo.model.CodeMetaInfo
|
||||
|
||||
abstract class AbstractCodeMetaInfoRenderConfiguration(var renderParams: Boolean = true) {
|
||||
private val clickOrPressRegex = "Click or press (.*)to navigate".toRegex() // We have different hotkeys on different platforms
|
||||
open fun asString(codeMetaInfo: CodeMetaInfo): String = codeMetaInfo.tag + getPlatformsString(codeMetaInfo)
|
||||
|
||||
open fun getAdditionalParams(codeMetaInfo: CodeMetaInfo) = ""
|
||||
|
||||
protected fun sanitizeLineMarkerTooltip(originalText: String?): String {
|
||||
if (originalText == null) return "null"
|
||||
val noHtmlTags = StringUtil.removeHtmlTags(originalText)
|
||||
.replace(" ", "")
|
||||
.replace(clickOrPressRegex, "")
|
||||
.trim()
|
||||
return sanitizeLineBreaks(noHtmlTags)
|
||||
}
|
||||
|
||||
protected fun sanitizeLineBreaks(originalText: String): String {
|
||||
var sanitizedText = originalText
|
||||
sanitizedText = StringUtil.replace(sanitizedText, "\r\n", " ")
|
||||
sanitizedText = StringUtil.replace(sanitizedText, "\n", " ")
|
||||
sanitizedText = StringUtil.replace(sanitizedText, "\r", " ")
|
||||
return sanitizedText
|
||||
}
|
||||
|
||||
protected fun getPlatformsString(codeMetaInfo: CodeMetaInfo): String {
|
||||
if (codeMetaInfo.attributes.isEmpty()) return ""
|
||||
return "{${codeMetaInfo.attributes.joinToString(";")}}"
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.codeMetaInfo.renderConfigurations
|
||||
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import org.jetbrains.kotlin.checkers.diagnostics.factories.DebugInfoDiagnosticFactory1
|
||||
import org.jetbrains.kotlin.codeMetaInfo.model.CodeMetaInfo
|
||||
import org.jetbrains.kotlin.codeMetaInfo.model.DiagnosticCodeMetaInfo
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.*
|
||||
|
||||
open class DiagnosticCodeMetaInfoRenderConfiguration(
|
||||
val withNewInference: Boolean = true,
|
||||
val renderSeverity: Boolean = false
|
||||
) : AbstractCodeMetaInfoRenderConfiguration() {
|
||||
private val crossPlatformLineBreak = """\r?\n""".toRegex()
|
||||
|
||||
override fun asString(codeMetaInfo: CodeMetaInfo): String {
|
||||
if (codeMetaInfo !is DiagnosticCodeMetaInfo) return ""
|
||||
return (getTag(codeMetaInfo)
|
||||
+ getPlatformsString(codeMetaInfo)
|
||||
+ getParamsString(codeMetaInfo))
|
||||
.replace(crossPlatformLineBreak, "")
|
||||
}
|
||||
|
||||
private fun getParamsString(codeMetaInfo: DiagnosticCodeMetaInfo): String {
|
||||
if (!renderParams) return ""
|
||||
val params = mutableListOf<String>()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val renderer = when (codeMetaInfo.diagnostic.factory) {
|
||||
is DebugInfoDiagnosticFactory1 -> DiagnosticWithParameters1Renderer(
|
||||
"{0}",
|
||||
Renderers.TO_STRING
|
||||
) as DiagnosticRenderer<Diagnostic>
|
||||
else -> DefaultErrorMessages.getRendererForDiagnostic(codeMetaInfo.diagnostic)
|
||||
}
|
||||
if (renderer is AbstractDiagnosticWithParametersRenderer) {
|
||||
val renderParameters = renderer.renderParameters(codeMetaInfo.diagnostic)
|
||||
params.addAll(ContainerUtil.map(renderParameters) { it.toString() })
|
||||
}
|
||||
if (renderSeverity)
|
||||
params.add("severity='${codeMetaInfo.diagnostic.severity}'")
|
||||
|
||||
params.add(getAdditionalParams(codeMetaInfo))
|
||||
|
||||
return "(\"${params.filter { it.isNotEmpty() }.joinToString("; ")}\")"
|
||||
}
|
||||
|
||||
fun getTag(codeMetaInfo: DiagnosticCodeMetaInfo): String {
|
||||
return codeMetaInfo.diagnostic.factory.name
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* 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.codeMetaInfo.renderConfigurations
|
||||
|
||||
import org.jetbrains.kotlin.codeMetaInfo.model.CodeMetaInfo
|
||||
import org.jetbrains.kotlin.codeMetaInfo.model.ParsedCodeMetaInfo
|
||||
|
||||
object ParsedCodeMetaInfoRenderConfiguration : AbstractCodeMetaInfoRenderConfiguration() {
|
||||
override fun asString(codeMetaInfo: CodeMetaInfo): String {
|
||||
require(codeMetaInfo is ParsedCodeMetaInfo)
|
||||
return super.asString(codeMetaInfo) + (codeMetaInfo.description?.let { "(\"$it\")" } ?: "")
|
||||
}
|
||||
}
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.codegen.forTestCompile;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ForTestCompileRuntime {
|
||||
private static volatile SoftReference<ClassLoader> reflectJarClassLoader = new SoftReference<>(null);
|
||||
private static volatile SoftReference<ClassLoader> runtimeJarClassLoader = new SoftReference<>(null);
|
||||
|
||||
@NotNull
|
||||
public static File runtimeJarForTests() {
|
||||
return assertExists(new File("dist/kotlinc/lib/kotlin-stdlib.jar"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File runtimeJarForTestsWithJdk8() {
|
||||
return assertExists(new File("dist/kotlinc/lib/kotlin-stdlib-jdk8.jar"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File minimalRuntimeJarForTests() {
|
||||
return assertExists(new File("dist/kotlin-stdlib-minimal-for-test.jar"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File kotlinTestJarForTests() {
|
||||
return assertExists(new File("dist/kotlinc/lib/kotlin-test.jar"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File kotlinTestJUnitJarForTests() {
|
||||
return assertExists(new File("dist/kotlinc/lib/kotlin-test-junit.jar"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File kotlinTestJsJarForTests() {
|
||||
return assertExists(new File("dist/kotlinc/lib/kotlin-test-js.jar"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File reflectJarForTests() {
|
||||
return assertExists(new File("dist/kotlinc/lib/kotlin-reflect.jar"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File scriptRuntimeJarForTests() {
|
||||
return assertExists(new File("dist/kotlinc/lib/kotlin-script-runtime.jar"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File runtimeSourcesJarForTests() {
|
||||
return assertExists(new File("dist/kotlinc/lib/kotlin-stdlib-sources.jar"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File stdlibMavenSourcesJarForTests() {
|
||||
return assertExists(new File("dist/maven/kotlin-stdlib-sources.jar"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File stdlibCommonForTests() {
|
||||
return assertExists(new File("dist/common/kotlin-stdlib-common.jar"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File stdlibCommonSourcesForTests() {
|
||||
return assertExists(new File("dist/common/kotlin-stdlib-common-sources.jar"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File stdlibJsForTests() {
|
||||
return assertExists(new File("dist/kotlinc/lib/kotlin-stdlib-js.jar"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File jetbrainsAnnotationsForTests() {
|
||||
return assertExists(new File("dist/kotlinc/lib/annotations-13.0.jar"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File jvmAnnotationsForTests() {
|
||||
return assertExists(new File("dist/kotlinc/lib/kotlin-annotations-jvm.jar"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File androidAnnotationsForTests() {
|
||||
return assertExists(new File("dist/kotlinc/lib/kotlin-annotations-android.jar"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File coroutinesCompatForTests() {
|
||||
return assertExists(new File("dist/kotlinc/lib/kotlin-coroutines-experimental-compat.jar"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static File assertExists(@NotNull File file) {
|
||||
if (!file.exists()) {
|
||||
throw new IllegalStateException(file + " does not exist. Run 'gradlew dist'");
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static synchronized ClassLoader runtimeAndReflectJarClassLoader() {
|
||||
ClassLoader loader = reflectJarClassLoader.get();
|
||||
if (loader == null) {
|
||||
loader = createClassLoader(runtimeJarForTests(), reflectJarForTests(), scriptRuntimeJarForTests(), kotlinTestJarForTests());
|
||||
reflectJarClassLoader = new SoftReference<>(loader);
|
||||
}
|
||||
return loader;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static synchronized ClassLoader runtimeJarClassLoader() {
|
||||
ClassLoader loader = runtimeJarClassLoader.get();
|
||||
if (loader == null) {
|
||||
loader = createClassLoader(runtimeJarForTests(), scriptRuntimeJarForTests(), kotlinTestJarForTests());
|
||||
runtimeJarClassLoader = new SoftReference<>(loader);
|
||||
}
|
||||
return loader;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static ClassLoader createClassLoader(@NotNull File... files) {
|
||||
try {
|
||||
List<URL> urls = new ArrayList<>(2);
|
||||
for (File file : files) {
|
||||
urls.add(file.toURI().toURL());
|
||||
}
|
||||
return new URLClassLoader(urls.toArray(new URL[urls.size()]), null);
|
||||
}
|
||||
catch (MalformedURLException e) {
|
||||
throw ExceptionUtilsKt.rethrow(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+196
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* 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.test.util;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtilRt;
|
||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
||||
import com.intellij.psi.PsiFileFactory;
|
||||
import com.intellij.psi.impl.PsiFileFactoryImpl;
|
||||
import com.intellij.testFramework.LightVirtualFile;
|
||||
import com.intellij.util.PathUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage;
|
||||
import org.jetbrains.kotlin.psi.KtFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
||||
public class KtTestUtil {
|
||||
private static String homeDir = computeHomeDirectory();
|
||||
|
||||
@NotNull
|
||||
public static File tmpDirForTest(@NotNull String testClassName, @NotNull String testName) throws IOException {
|
||||
return normalizeFile(FileUtil.createTempDirectory(testClassName, testName, false));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File tmpDir(String name) throws IOException {
|
||||
return normalizeFile(FileUtil.createTempDirectory(name, "", false));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File tmpDirForReusableFolder(String name) throws IOException {
|
||||
return normalizeFile(FileUtil.createTempDirectory(new File(System.getProperty("java.io.tmpdir")), name, "", true));
|
||||
}
|
||||
|
||||
private static File normalizeFile(File file) throws IOException {
|
||||
// Get canonical file to be sure that it's the same as inside the compiler,
|
||||
// for example, on Windows, if a canonical path contains any space from FileUtil.createTempDirectory we will get
|
||||
// a File with short names (8.3) in its path and it will break some normalization passes in tests.
|
||||
return file.getCanonicalFile();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static KtFile createFile(@NotNull @NonNls String name, @NotNull String text, @NotNull Project project) {
|
||||
String shortName = name.substring(name.lastIndexOf('/') + 1);
|
||||
shortName = shortName.substring(shortName.lastIndexOf('\\') + 1);
|
||||
LightVirtualFile virtualFile = new LightVirtualFile(shortName, KotlinLanguage.INSTANCE, StringUtilRt.convertLineSeparators(text));
|
||||
|
||||
virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET);
|
||||
PsiFileFactoryImpl factory = (PsiFileFactoryImpl) PsiFileFactory.getInstance(project);
|
||||
//noinspection ConstantConditions
|
||||
return (KtFile) factory.trySetupPsiForFile(virtualFile, KotlinLanguage.INSTANCE, true, false);
|
||||
}
|
||||
|
||||
public static String doLoadFile(String myFullDataPath, String name) throws IOException {
|
||||
String fullName = myFullDataPath + File.separatorChar + name;
|
||||
return doLoadFile(new File(fullName));
|
||||
}
|
||||
|
||||
public static String doLoadFile(@NotNull File file) throws IOException {
|
||||
try {
|
||||
return FileUtil.loadFile(file, CharsetToolkit.UTF8, true);
|
||||
}
|
||||
catch (FileNotFoundException fileNotFoundException) {
|
||||
/*
|
||||
* Unfortunately, the FileNotFoundException will only show the relative path in it's exception message.
|
||||
* This clarifies the exception by showing the full path.
|
||||
*/
|
||||
String messageWithFullPath = file.getAbsolutePath() + " (No such file or directory)";
|
||||
throw new IOException(
|
||||
"Ensure you have your 'Working Directory' configured correctly as the root " +
|
||||
"Kotlin project directory in your test configuration\n\t" +
|
||||
messageWithFullPath,
|
||||
fileNotFoundException);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getFilePath(File file) {
|
||||
return FileUtil.toSystemIndependentName(file.getPath());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File getJdk9Home() {
|
||||
String jdk9 = System.getenv("JDK_9");
|
||||
if (jdk9 == null) {
|
||||
jdk9 = System.getenv("JDK_19");
|
||||
if (jdk9 == null) {
|
||||
throw new AssertionError("Environment variable JDK_9 is not set!");
|
||||
}
|
||||
}
|
||||
return new File(jdk9);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static File getJdk11Home() {
|
||||
String jdk11 = System.getenv("JDK_11");
|
||||
if (jdk11 == null) {
|
||||
return null;
|
||||
}
|
||||
return new File(jdk11);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File getJdk15Home() {
|
||||
String jdk15 = System.getenv("JDK_15");
|
||||
|
||||
if (jdk15 == null) {
|
||||
jdk15 = System.getenv("JDK_15_0");
|
||||
}
|
||||
|
||||
if (jdk15 == null) {
|
||||
throw new AssertionError("Environment variable JDK_15 is not set!");
|
||||
}
|
||||
return new File(jdk15);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getTestDataPathBase() {
|
||||
return getHomeDirectory() + "/compiler/testData";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getHomeDirectory() {
|
||||
return homeDir;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String computeHomeDirectory() {
|
||||
String userDir = System.getProperty("user.dir");
|
||||
File dir = new File(userDir == null ? "." : userDir);
|
||||
return FileUtil.toCanonicalPath(dir.getAbsolutePath());
|
||||
}
|
||||
|
||||
public static File findMockJdkRtJar() {
|
||||
return new File(getHomeDirectory(), "compiler/testData/mockJDK/jre/lib/rt.jar");
|
||||
}
|
||||
|
||||
// Differs from common mock JDK only by one additional 'nonExistingMethod' in Collection and constructor from Double in Throwable
|
||||
// It's needed to test the way we load additional built-ins members that neither in black nor white lists
|
||||
public static File findMockJdkRtModified() {
|
||||
return new File(getHomeDirectory(), "compiler/testData/mockJDKModified/rt.jar");
|
||||
}
|
||||
|
||||
public static File findAndroidApiJar() {
|
||||
String androidJarProp = System.getProperty("android.jar");
|
||||
File androidJarFile = androidJarProp == null ? null : new File(androidJarProp);
|
||||
if (androidJarFile == null || !androidJarFile.isFile()) {
|
||||
throw new RuntimeException(
|
||||
"Unable to get a valid path from 'android.jar' property (" +
|
||||
androidJarProp +
|
||||
"), please point it to the 'android.jar' file location");
|
||||
}
|
||||
return androidJarFile;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File findAndroidSdk() {
|
||||
String androidSdkProp = System.getProperty("android.sdk");
|
||||
File androidSdkDir = androidSdkProp == null ? null : new File(androidSdkProp);
|
||||
if (androidSdkDir == null || !androidSdkDir.isDirectory()) {
|
||||
throw new RuntimeException(
|
||||
"Unable to get a valid path from 'android.sdk' property (" +
|
||||
androidSdkProp +
|
||||
"), please point it to the android SDK location");
|
||||
}
|
||||
return androidSdkDir;
|
||||
}
|
||||
|
||||
public static String getAndroidSdkSystemIndependentPath() {
|
||||
return PathUtil.toSystemIndependentName(findAndroidSdk().getAbsolutePath());
|
||||
}
|
||||
|
||||
public static File getAnnotationsJar() {
|
||||
return new File(getHomeDirectory(), "compiler/testData/mockJDK/jre/lib/annotations.jar");
|
||||
}
|
||||
|
||||
public static void mkdirs(@NotNull File file) {
|
||||
if (file.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
if (!file.mkdirs()) {
|
||||
if (file.exists()) {
|
||||
throw new IllegalStateException("Failed to create " + file + ": file exists and not a directory");
|
||||
}
|
||||
throw new IllegalStateException("Failed to create " + file);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user