[TEST] Move utils for checking all files presented to KtTestUtil

This is needed to remove dependency on :tests-common from module
  with abstract test generators
This commit is contained in:
Dmitriy Novozhilov
2020-12-14 13:26:50 +03:00
parent 64ce307f7f
commit 9e2d691425
19 changed files with 266 additions and 214 deletions
@@ -0,0 +1,36 @@
/*
* 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.
*/
@file:JvmName("KtAssert")
package org.jetbrains.kotlin.test
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
/*
* Those functions are needed only in this module because it has no testing framework
* with assertions in it's dependencies
*/
internal fun fail(message: String) {
throw AssertionError(message)
}
@OptIn(ExperimentalContracts::class)
internal fun assertNotNull(message: String, value: Any?) {
contract {
returns() implies (value != null)
}
if (value == null) {
fail(message)
}
}
internal fun assertTrue(message: String, value: Boolean) {
if (!value) {
fail(message)
}
}
@@ -13,7 +13,6 @@ import kotlin.text.StringsKt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
import org.junit.Assert;
import java.io.BufferedReader;
import java.io.File;
@@ -149,7 +148,7 @@ public final class InTextDirectivesUtils {
prefixes.removeAll(cleanDirectivesFromComments(knownPrefixes));
Assert.assertTrue("File contains some unexpected directives" + prefixes, prefixes.isEmpty());
KtAssert.assertTrue("File contains some unexpected directives" + prefixes, prefixes.isEmpty());
}
private static String probableDirective(String line) {
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.test.util;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtilRt;
import com.intellij.openapi.vfs.CharsetToolkit;
@@ -13,15 +14,26 @@ import com.intellij.psi.PsiFileFactory;
import com.intellij.psi.impl.PsiFileFactoryImpl;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.util.PathUtil;
import com.intellij.util.containers.ContainerUtil;
import kotlin.collections.SetsKt;
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 org.jetbrains.kotlin.test.KtAssert;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
import static org.jetbrains.kotlin.test.InTextDirectivesUtils.isCompatibleTarget;
public class KtTestUtil {
private static String homeDir = computeHomeDirectory();
@@ -193,4 +205,196 @@ public class KtTestUtil {
throw new IllegalStateException("Failed to create " + file);
}
}
// ---------------------- assert testdata presented by metadata ----------------------
private static final String PLEASE_REGENERATE_TESTS = "Please regenerate tests (GenerateTests.kt)";
public static void assertAllTestsPresentByMetadataWithExcluded(
@NotNull Class<?> testCaseClass,
@NotNull File testDataDir,
@NotNull Pattern filenamePattern,
@Nullable Pattern excludedPattern,
boolean recursive,
@NotNull String... excludeDirs
) {
assertAllTestsPresentByMetadataWithExcluded(testCaseClass, testDataDir, filenamePattern, excludedPattern, TargetBackend.ANY, recursive, excludeDirs);
}
public static void assertAllTestsPresentByMetadata(
@NotNull Class<?> testCaseClass,
@NotNull File testDataDir,
@NotNull Pattern filenamePattern,
boolean recursive,
@NotNull String... excludeDirs
) {
assertAllTestsPresentByMetadata(
testCaseClass,
testDataDir,
filenamePattern,
TargetBackend.ANY,
recursive,
excludeDirs
);
}
public static void assertAllTestsPresentByMetadataWithExcluded(
@NotNull Class<?> testCaseClass,
@NotNull File testDataDir,
@NotNull Pattern filenamePattern,
@Nullable Pattern excludedPattern,
@NotNull TargetBackend targetBackend,
boolean recursive,
@NotNull String... excludeDirs
) {
File rootFile = new File(getTestsRoot(testCaseClass));
Set<String> filePaths = collectPathsMetadata(testCaseClass);
Set<String> exclude = SetsKt.setOf(excludeDirs);
File[] files = testDataDir.listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
if (recursive && containsTestData(file, filenamePattern, excludedPattern) && !exclude.contains(file.getName())) {
assertTestClassPresentByMetadata(testCaseClass, file);
}
}
else {
boolean excluded = excludedPattern != null && excludedPattern.matcher(file.getName()).matches();
if (!excluded && filenamePattern.matcher(file.getName()).matches() && isCompatibleTarget(targetBackend, file)) {
assertFilePathPresent(file, rootFile, filePaths);
}
}
}
}
}
public static void assertAllTestsPresentByMetadata(
@NotNull Class<?> testCaseClass,
@NotNull File testDataDir,
@NotNull Pattern filenamePattern,
@NotNull TargetBackend targetBackend,
boolean recursive,
@NotNull String... excludeDirs
) {
assertAllTestsPresentByMetadataWithExcluded(testCaseClass, testDataDir, filenamePattern, null, targetBackend, recursive, excludeDirs);
}
public static void assertAllTestsPresentInSingleGeneratedClass(
@NotNull Class<?> testCaseClass,
@NotNull File testDataDir,
@NotNull Pattern filenamePattern
) {
assertAllTestsPresentInSingleGeneratedClass(testCaseClass, testDataDir, filenamePattern, TargetBackend.ANY);
}
public static void assertAllTestsPresentInSingleGeneratedClassWithExcluded(
@NotNull Class<?> testCaseClass,
@NotNull File testDataDir,
@NotNull Pattern filenamePattern,
@Nullable Pattern excludePattern
) {
assertAllTestsPresentInSingleGeneratedClass(testCaseClass, testDataDir, filenamePattern, excludePattern, TargetBackend.ANY);
}
public static void assertAllTestsPresentInSingleGeneratedClass(
@NotNull Class<?> testCaseClass,
@NotNull File testDataDir,
@NotNull Pattern filenamePattern,
@NotNull TargetBackend targetBackend
) {
assertAllTestsPresentInSingleGeneratedClass(testCaseClass, testDataDir, filenamePattern, null, targetBackend);
}
public static void assertAllTestsPresentInSingleGeneratedClass(
@NotNull Class<?> testCaseClass,
@NotNull File testDataDir,
@NotNull Pattern filenamePattern,
@Nullable Pattern excludePattern,
@NotNull TargetBackend targetBackend
) {
File rootFile = new File(getTestsRoot(testCaseClass));
Set<String> filePaths = collectPathsMetadata(testCaseClass);
FileUtil.processFilesRecursively(testDataDir, file -> {
boolean excluded = excludePattern != null && excludePattern.matcher(file.getName()).matches();
if (file.isFile() && !excluded && filenamePattern.matcher(file.getName()).matches() && isCompatibleTarget(targetBackend, file)) {
assertFilePathPresent(file, rootFile, filePaths);
}
return true;
});
}
private static void assertFilePathPresent(File file, File rootFile, Set<String> filePaths) {
String path = FileUtil.getRelativePath(rootFile, file);
if (path != null) {
String relativePath = nameToCompare(path);
if (!filePaths.contains(relativePath)) {
KtAssert.fail("Test data file missing from the generated test class: " + file + "\n" + PLEASE_REGENERATE_TESTS);
}
}
}
private static Set<String> collectPathsMetadata(Class<?> testCaseClass) {
return new HashSet<>(ContainerUtil.map(collectMethodsMetadata(testCaseClass), KtTestUtil::nameToCompare));
}
@Nullable
public static String getMethodMetadata(Method method) {
TestMetadata testMetadata = method.getAnnotation(TestMetadata.class);
return (testMetadata != null) ? testMetadata.value() : null;
}
private static Set<String> collectMethodsMetadata(Class<?> testCaseClass) {
Set<String> filePaths = new HashSet<>();
for (Method method : testCaseClass.getDeclaredMethods()) {
String path = getMethodMetadata(method);
if (path != null) {
filePaths.add(path);
}
}
return filePaths;
}
private static boolean containsTestData(File dir, Pattern filenamePattern, @Nullable Pattern excludedPattern) {
File[] files = dir.listFiles();
assert files != null;
for (File file : files) {
if (file.isDirectory()) {
if (containsTestData(file, filenamePattern, excludedPattern)) {
return true;
}
}
else {
boolean excluded = excludedPattern != null && excludedPattern.matcher(file.getName()).matches();
if (! excluded && filenamePattern.matcher(file.getName()).matches()) {
return true;
}
}
}
return false;
}
private static void assertTestClassPresentByMetadata(@NotNull Class<?> outerClass, @NotNull File testDataDir) {
for (Class<?> nestedClass : outerClass.getDeclaredClasses()) {
TestMetadata testMetadata = nestedClass.getAnnotation(TestMetadata.class);
if (testMetadata != null && testMetadata.value().equals(KtTestUtil.getFilePath(testDataDir))) {
return;
}
}
KtAssert.fail("Test data directory missing from the generated test class: " + testDataDir + "\n" + PLEASE_REGENERATE_TESTS);
}
public static String getTestsRoot(@NotNull Class<?> testCaseClass) {
TestMetadata testClassMetadata = testCaseClass.getAnnotation(TestMetadata.class);
KtAssert.assertNotNull("No metadata for class: " + testCaseClass, testClassMetadata);
return testClassMetadata.value();
}
public static String nameToCompare(@NotNull String name) {
return (SystemInfo.isFileSystemCaseSensitive ? name : name.toLowerCase()).replace('\\', '/');
}
}
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.generators.model.*
import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.TestMetadata
import org.jetbrains.kotlin.test.util.KtTestUtil
import org.jetbrains.kotlin.utils.Printer
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
@@ -130,7 +131,7 @@ object NewTestGeneratorImpl : TestGenerator(METHOD_GENERATORS) {
p.println("package $suiteClassPackage;")
p.println()
p.println("import com.intellij.testFramework.TestDataPath;")
p.println("import ${KotlinTestUtils::class.java.canonicalName};")
p.println("import ${KtTestUtil::class.java.canonicalName};")
for (clazz in testClassModels.flatMapTo(mutableSetOf()) { classModel -> classModel.imports }) {
p.println("import ${clazz.name};")
@@ -19,11 +19,9 @@ import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.psi.PsiElement;
import com.intellij.rt.execution.junit.FileComparisonFailure;
import com.intellij.testFramework.TestDataFile;
import com.intellij.util.containers.ContainerUtil;
import junit.framework.TestCase;
import kotlin.Unit;
import kotlin.collections.CollectionsKt;
import kotlin.collections.SetsKt;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
@@ -74,7 +72,6 @@ public class KotlinTestUtils {
public static String TEST_MODULE_NAME = "test-module";
public static final String TEST_GENERATOR_NAME = "org.jetbrains.kotlin.generators.tests.TestsPackage";
private static final String PLEASE_REGENERATE_TESTS = "Please regenerate tests (GenerateTests.kt)";
private static final boolean RUN_IGNORED_TESTS_AS_REGULAR =
Boolean.getBoolean("org.jetbrains.kotlin.run.ignored.tests.as.regular");
@@ -686,12 +683,6 @@ public class KotlinTestUtils {
};
}
public static String getTestsRoot(@NotNull Class<?> testCaseClass) {
TestMetadata testClassMetadata = testCaseClass.getAnnotation(TestMetadata.class);
Assert.assertNotNull("No metadata for class: " + testCaseClass, testClassMetadata);
return testClassMetadata.value();
}
/**
* @return test data file name specified in the metadata of test method
*/
@@ -699,191 +690,13 @@ public class KotlinTestUtils {
public static String getTestDataFileName(@NotNull Class<?> testCaseClass, @NotNull String testName) {
try {
Method method = testCaseClass.getDeclaredMethod(testName);
return getMethodMetadata(method);
return KtTestUtil.getMethodMetadata(method);
}
catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
public static void assertAllTestsPresentByMetadataWithExcluded(
@NotNull Class<?> testCaseClass,
@NotNull File testDataDir,
@NotNull Pattern filenamePattern,
@Nullable Pattern excludedPattern,
boolean recursive,
@NotNull String... excludeDirs
) {
assertAllTestsPresentByMetadataWithExcluded(testCaseClass, testDataDir, filenamePattern, excludedPattern, TargetBackend.ANY, recursive, excludeDirs);
}
public static void assertAllTestsPresentByMetadata(
@NotNull Class<?> testCaseClass,
@NotNull File testDataDir,
@NotNull Pattern filenamePattern,
boolean recursive,
@NotNull String... excludeDirs
) {
assertAllTestsPresentByMetadata(
testCaseClass,
testDataDir,
filenamePattern,
TargetBackend.ANY,
recursive,
excludeDirs
);
}
public static void assertAllTestsPresentByMetadataWithExcluded(
@NotNull Class<?> testCaseClass,
@NotNull File testDataDir,
@NotNull Pattern filenamePattern,
@Nullable Pattern excludedPattern,
@NotNull TargetBackend targetBackend,
boolean recursive,
@NotNull String... excludeDirs
) {
File rootFile = new File(getTestsRoot(testCaseClass));
Set<String> filePaths = collectPathsMetadata(testCaseClass);
Set<String> exclude = SetsKt.setOf(excludeDirs);
File[] files = testDataDir.listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
if (recursive && containsTestData(file, filenamePattern, excludedPattern) && !exclude.contains(file.getName())) {
assertTestClassPresentByMetadata(testCaseClass, file);
}
}
else {
boolean excluded = excludedPattern != null && excludedPattern.matcher(file.getName()).matches();
if (!excluded && filenamePattern.matcher(file.getName()).matches() && isCompatibleTarget(targetBackend, file)) {
assertFilePathPresent(file, rootFile, filePaths);
}
}
}
}
}
public static void assertAllTestsPresentByMetadata(
@NotNull Class<?> testCaseClass,
@NotNull File testDataDir,
@NotNull Pattern filenamePattern,
@NotNull TargetBackend targetBackend,
boolean recursive,
@NotNull String... excludeDirs
) {
assertAllTestsPresentByMetadataWithExcluded(testCaseClass, testDataDir, filenamePattern, null, targetBackend, recursive, excludeDirs);
}
public static void assertAllTestsPresentInSingleGeneratedClass(
@NotNull Class<?> testCaseClass,
@NotNull File testDataDir,
@NotNull Pattern filenamePattern
) {
assertAllTestsPresentInSingleGeneratedClass(testCaseClass, testDataDir, filenamePattern, TargetBackend.ANY);
}
public static void assertAllTestsPresentInSingleGeneratedClassWithExcluded(
@NotNull Class<?> testCaseClass,
@NotNull File testDataDir,
@NotNull Pattern filenamePattern,
@Nullable Pattern excludePattern
) {
assertAllTestsPresentInSingleGeneratedClass(testCaseClass, testDataDir, filenamePattern, excludePattern, TargetBackend.ANY);
}
public static void assertAllTestsPresentInSingleGeneratedClass(
@NotNull Class<?> testCaseClass,
@NotNull File testDataDir,
@NotNull Pattern filenamePattern,
@NotNull TargetBackend targetBackend
) {
assertAllTestsPresentInSingleGeneratedClass(testCaseClass, testDataDir, filenamePattern, null, targetBackend);
}
public static void assertAllTestsPresentInSingleGeneratedClass(
@NotNull Class<?> testCaseClass,
@NotNull File testDataDir,
@NotNull Pattern filenamePattern,
@Nullable Pattern excludePattern,
@NotNull TargetBackend targetBackend
) {
File rootFile = new File(getTestsRoot(testCaseClass));
Set<String> filePaths = collectPathsMetadata(testCaseClass);
FileUtil.processFilesRecursively(testDataDir, file -> {
boolean excluded = excludePattern != null && excludePattern.matcher(file.getName()).matches();
if (file.isFile() && !excluded && filenamePattern.matcher(file.getName()).matches() && isCompatibleTarget(targetBackend, file)) {
assertFilePathPresent(file, rootFile, filePaths);
}
return true;
});
}
private static void assertFilePathPresent(File file, File rootFile, Set<String> filePaths) {
String path = FileUtil.getRelativePath(rootFile, file);
if (path != null) {
String relativePath = nameToCompare(path);
if (!filePaths.contains(relativePath)) {
Assert.fail("Test data file missing from the generated test class: " + file + "\n" + PLEASE_REGENERATE_TESTS);
}
}
}
private static Set<String> collectPathsMetadata(Class<?> testCaseClass) {
return new HashSet<>(ContainerUtil.map(collectMethodsMetadata(testCaseClass), KotlinTestUtils::nameToCompare));
}
@Nullable
private static String getMethodMetadata(Method method) {
TestMetadata testMetadata = method.getAnnotation(TestMetadata.class);
return (testMetadata != null) ? testMetadata.value() : null;
}
private static Set<String> collectMethodsMetadata(Class<?> testCaseClass) {
Set<String> filePaths = new HashSet<>();
for (Method method : testCaseClass.getDeclaredMethods()) {
String path = getMethodMetadata(method);
if (path != null) {
filePaths.add(path);
}
}
return filePaths;
}
private static boolean containsTestData(File dir, Pattern filenamePattern, @Nullable Pattern excludedPattern) {
File[] files = dir.listFiles();
assert files != null;
for (File file : files) {
if (file.isDirectory()) {
if (containsTestData(file, filenamePattern, excludedPattern)) {
return true;
}
}
else {
boolean excluded = excludedPattern != null && excludedPattern.matcher(file.getName()).matches();
if (! excluded && filenamePattern.matcher(file.getName()).matches()) {
return true;
}
}
}
return false;
}
private static void assertTestClassPresentByMetadata(@NotNull Class<?> outerClass, @NotNull File testDataDir) {
for (Class<?> nestedClass : outerClass.getDeclaredClasses()) {
TestMetadata testMetadata = nestedClass.getAnnotation(TestMetadata.class);
if (testMetadata != null && testMetadata.value().equals(KtTestUtil.getFilePath(testDataDir))) {
return;
}
}
Assert.fail("Test data directory missing from the generated test class: " + testDataDir + "\n" + PLEASE_REGENERATE_TESTS);
}
@NotNull
public static KtFile loadJetFile(@NotNull Project project, @NotNull File ioFile) throws IOException {
String text = FileUtil.loadFile(ioFile, true);
@@ -924,10 +737,6 @@ public class KotlinTestUtils {
return testName.toLowerCase().startsWith("allfilespresentin");
}
public static String nameToCompare(@NotNull String name) {
return (SystemInfo.isFileSystemCaseSensitive ? name : name.toLowerCase()).replace('\\', '/');
}
public static boolean isMultiExtensionName(@NotNull String name) {
int firstDotIndex = name.indexOf('.');
if (firstDotIndex == -1) {