diff --git a/compiler/tests/org/jetbrains/kotlin/util/KotlinVersionsTest.kt b/compiler/tests/org/jetbrains/kotlin/util/KotlinVersionsTest.kt new file mode 100644 index 00000000000..9be580c6538 --- /dev/null +++ b/compiler/tests/org/jetbrains/kotlin/util/KotlinVersionsTest.kt @@ -0,0 +1,139 @@ +/* + * 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.util + +import com.intellij.openapi.util.io.FileUtil +import com.intellij.util.Processor +import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime +import org.jetbrains.kotlin.config.KotlinCompilerVersion +import org.jetbrains.kotlin.config.LanguageVersion +import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase +import org.jetbrains.kotlin.utils.addIfNotNull +import org.junit.Assert +import org.w3c.dom.Element +import java.io.File +import java.util.* +import javax.xml.parsers.DocumentBuilderFactory + +class KotlinVersionsTest : KtUsefulTestCase() { + fun testVersionsAreConsistent() { + val versionPattern = "(\\d+)\\.(\\d+)(\\.(\\d+)|-SNAPSHOT)?".toRegex() + + data class Version(val major: Int, val minor: Int, val patch: Int?, val versionString: String, val source: String) { + fun isConsistentWith(other: Version): Boolean { + return major == other.major && + minor == other.minor && + (patch == null || other.patch == null || patch == other.patch) + } + } + + fun String.toVersionOrNull(source: String): Version? { + val result = versionPattern.matchEntire(this) ?: return null + val (major, minor, _, patch) = result.destructured + return Version(major.toInt(), minor.toInt(), patch.takeUnless(String::isEmpty)?.toInt(), this, source) + } + + fun String.toVersion(source: String): Version = + toVersionOrNull(source) ?: error("Version ($source) is in an unknown format: $this") + + val versions = arrayListOf() + + // This version is null in case of a local build when KotlinCompilerVersion.VERSION = "@snapshot@" + versions.addIfNotNull( + KotlinCompilerVersion.VERSION.substringBefore('-').toVersionOrNull("KotlinCompilerVersion.VERSION") + ) + + versions.add( + ForTestCompileRuntime.runtimeJarClassLoader().loadClass(KotlinVersion::class.qualifiedName!!) + .getDeclaredField((KotlinVersion)::CURRENT.name) + .get(null) + .toString() + .toVersion("KotlinVersion.CURRENT") + ) + + versions.add( + Properties().apply { load(File("resources/kotlinManifest.properties").inputStream()) } + .getProperty("manifest.impl.value.kotlin.version")?.toVersion("kotlinManifest.properties") + ?: error("No Kotlin-Version value in kotlinManifest.properties") + ) + + versions.add( + loadValueFromPomXml("libraries/pom.xml", listOf("properties", "kotlin.language.version")) + ?.toVersion("kotlin.language.version in pom.xml") + ?: error("No kotlin.language.version in libraries/pom.xml") + ) + + versions.add( + loadValueFromPomXml("libraries/pom.xml", listOf("version")) + ?.toVersion("version in pom.xml") + ?: error("No version in libraries/pom.xml") + ) + + versions.add( + LanguageVersion.LATEST.versionString.toVersion("LanguageVersion.LATEST") + ) + + if (versions.any { v1 -> versions.any { v2 -> !v1.isConsistentWith(v2) } }) { + Assert.fail( + "Some versions are inconsistent. Please change the versions so that they are consistent:\n\n" + + versions.joinToString(separator = "\n") { with(it) { "$versionString ($source)" } } + ) + } + } + + fun testMavenProjectVersionsAreEqual() { + data class Pom(val path: String, val version: String) + + val poms = arrayListOf() + + FileUtil.processFilesRecursively(File("libraries"), Processor { file -> + if (file.name == "pom.xml") { + if (loadValueFromPomXml(file.path, listOf("parent", "artifactId")) == "kotlin-project") { + val version = loadValueFromPomXml(file.path, listOf("version")) + ?: error("No version found in pom.xml at $file") + poms.add(Pom(file.path, version)) + } + } + true + }, Processor { file -> file.name != "target" }) + + Assert.assertTrue( + "Too few (<= 10) pom.xml files found. Something must be wrong in the test or in the project structure", + poms.size > 10 + ) + + if (!poms.map(Pom::version).areEqual()) { + Assert.fail( + "Some versions in pom.xml files are different. Please change the versions so that they are equal:\n\n" + + poms.joinToString(separator = "\n") { (path, version) -> "$version $path" } + ) + } + } + + private fun loadValueFromPomXml(filePath: String, query: List): String? { + assert(filePath.endsWith("pom.xml")) { filePath } + + val docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder() + val input = docBuilder.parse(File(filePath).inputStream()) + + return query.fold(input.documentElement) { element, tagName -> + element?.getElementsByTagName(tagName)?.item(0) as? Element + }?.textContent + } + + private fun Collection.areEqual(): Boolean = all(first()::equals) +}