[Test gen] Consolidate file reads for checking directives

This commit is contained in:
Kirill Rakhman
2024-02-26 18:09:49 +01:00
committed by Space Team
parent 3c23319f70
commit 5bbec23123
3 changed files with 61 additions and 11 deletions
@@ -31,6 +31,9 @@ public final class InTextDirectivesUtils {
public static final String[] IGNORE_BACKEND_DIRECTIVE_PREFIXES = { IGNORE_BACKEND_DIRECTIVE_PREFIX, IGNORE_BACKEND_K1_DIRECTIVE_PREFIX };
public static final String TARGET_BACKEND_DIRECTIVE_PREFIX = "// TARGET_BACKEND: ";
public static final String DORT_TARGET_EXACT_BACKEND_DIRECTIVE_PREFIX = "// DONT_TARGET_EXACT_BACKEND: ";
private InTextDirectivesUtils() {
}
@@ -109,15 +112,20 @@ public final class InTextDirectivesUtils {
@NotNull
public static List<String> findLinesWithPrefixesRemoved(@NotNull String fileText, @NotNull String... prefixes) {
return findLinesWithPrefixesRemoved(fileText, true, true, prefixes);
return findLinesByPrefixRemoved(fileText, true, true, prefixes).values().stream().flatMap(Collection::stream).collect(Collectors.toList());
}
@NotNull
public static List<String> findLinesWithPrefixesRemoved(@NotNull String fileText, boolean trim, boolean strict, @NotNull String... prefixes) {
public static Map<String, List<String>> findLinesByPrefixRemoved(@NotNull String fileText, @NotNull String... prefixes) {
return findLinesByPrefixRemoved(fileText, true, true, prefixes);
}
@NotNull
public static Map<String, List<String>> findLinesByPrefixRemoved(@NotNull String fileText, boolean trim, boolean strict, @NotNull String... prefixes) {
if (prefixes.length == 0) {
throw new IllegalArgumentException("Please specify the prefixes to check");
}
List<String> result = new ArrayList<>();
Map<String, List<String>> result = new HashMap<>();
List<String> cleanedPrefixes = cleanDirectivesFromComments(Arrays.asList(prefixes));
for (String line : fileNonEmptyCommentedLines(fileText)) {
@@ -128,7 +136,7 @@ public final class InTextDirectivesUtils {
if (noPrefixLine.isEmpty() ||
Character.isWhitespace(noPrefixLine.charAt(0)) ||
Character.isWhitespace(prefix.charAt(prefix.length() - 1))) {
result.add(trim ? noPrefixLine.trim() : StringUtil.trimTrailing(StringsKt.drop(noPrefixLine, 1)));
result.computeIfAbsent(prefix, s -> new ArrayList<>()).add(trim ? noPrefixLine.trim() : StringUtil.trimTrailing(StringsKt.drop(noPrefixLine, 1)));
break;
} else if (strict) {
throw new AssertionError(
@@ -209,7 +217,7 @@ public final class InTextDirectivesUtils {
return result;
}
private static String textWithDirectives(@NotNull File file) {
public static String textWithDirectives(@NotNull File file) {
try {
String fileText;
if (file.isDirectory()) {
@@ -229,13 +237,21 @@ public final class InTextDirectivesUtils {
public static boolean isCompatibleTarget(@NotNull TargetBackend targetBackend, @NotNull File file) {
if (targetBackend == TargetBackend.ANY) return true;
String textWithDirectives = textWithDirectives(file);
Map<String, List<String>> byPrefixRemoved =
findLinesByPrefixRemoved(textWithDirectives, DORT_TARGET_EXACT_BACKEND_DIRECTIVE_PREFIX, TARGET_BACKEND_DIRECTIVE_PREFIX);
return isCompatibleTarget(targetBackend, byPrefixRemoved);
}
List<String> doNotTarget = findLinesWithPrefixesRemoved(textWithDirectives(file), "// DONT_TARGET_EXACT_BACKEND: ");
public static boolean isCompatibleTarget(@NotNull TargetBackend targetBackend, Map<String, List<String>> directives) {
if (targetBackend == TargetBackend.ANY) return true;
List<String> doNotTarget = directives.getOrDefault("DONT_TARGET_EXACT_BACKEND: ", Collections.emptyList());
doNotTarget = doNotTarget.stream().flatMap((s) -> Arrays.stream(s.split(" "))).collect(Collectors.toList());
if (doNotTarget.contains(targetBackend.name()))
return false;
List<String> backends = findLinesWithPrefixesRemoved(textWithDirectives(file), "// TARGET_BACKEND: ");
List<String> backends = directives.getOrDefault("TARGET_BACKEND: ", Collections.emptyList());
return isCompatibleTargetExceptAny(targetBackend, backends);
}
@@ -250,6 +266,31 @@ public final class InTextDirectivesUtils {
public static boolean isIgnoredTarget(@NotNull TargetBackend targetBackend, @NotNull File file, boolean includeAny, String... ignoreBackendDirectivePrefixes) {
List<String> ignoredBackends = findListWithPrefixes(textWithDirectives(file), ignoreBackendDirectivePrefixes);
return isIgnoredTarget(targetBackend, includeAny, ignoredBackends);
}
public static boolean isIgnoredTarget(
@NotNull TargetBackend targetBackend,
@NotNull Map<String, List<String>> directives,
boolean includeAny,
String... ignoreBackendDirectivePrefixes
) {
List<String> result = new ArrayList<>();
directives
.entrySet()
.stream()
.filter(entry -> entry.getKey().startsWith("IGNORE_BACKEND"))
.forEach(entry ->
{
for (String s : entry.getValue()) {
splitValues(result, s);
}
}
);
return isIgnoredTarget(targetBackend, includeAny, result);
}
private static boolean isIgnoredTarget(@NotNull TargetBackend targetBackend, boolean includeAny, List<String> ignoredBackends) {
if (ignoredBackends.contains(targetBackend.name())) return true;
if (includeAny && ignoredBackends.contains("ANY")) return true;
return false;
@@ -23,6 +23,16 @@ open class SimpleTestMethodModel(
) : MethodModel {
object Kind : MethodModel.Kind()
val directives: Map<String, List<String>> by lazy(LazyThreadSafetyMode.NONE) {
InTextDirectivesUtils.findLinesByPrefixRemoved(
InTextDirectivesUtils.textWithDirectives(file),
*InTextDirectivesUtils.IGNORE_BACKEND_DIRECTIVE_PREFIXES,
InTextDirectivesUtils.TARGET_BACKEND_DIRECTIVE_PREFIX,
InTextDirectivesUtils.DORT_TARGET_EXACT_BACKEND_DIRECTIVE_PREFIX,
"// WORKS_WHEN_VALUE_CLASS"
)
}
override val kind: MethodModel.Kind
get() = Kind
@@ -33,7 +43,7 @@ open class SimpleTestMethodModel(
}
override fun shouldBeGenerated(): Boolean {
return InTextDirectivesUtils.isCompatibleTarget(targetBackend, file)
return InTextDirectivesUtils.isCompatibleTarget(targetBackend, directives)
}
override val name: String
@@ -53,7 +63,7 @@ open class SimpleTestMethodModel(
val relativePath = FileUtil.getRelativePath(rootDir, file.parentFile)
relativePath + "-" + extractedName.replaceFirstChar(Char::uppercaseChar)
}
val ignored = skipIgnored && InTextDirectivesUtils.isIgnoredTarget(targetBackend, file)
val ignored = skipIgnored && InTextDirectivesUtils.isIgnoredTarget(targetBackend, directives, false)
return (if (ignored) "ignore" else "test") + escapeForJavaIdentifier(unescapedName).replaceFirstChar(Char::uppercaseChar)
}
@@ -10,13 +10,12 @@ import org.jetbrains.kotlin.test.TargetBackend
import java.io.File
import java.util.regex.Pattern
const val WORKS_WHEN_VALUE_CLASS = "WORKS_WHEN_VALUE_CLASS"
// will replace OPTIONAL_JVM_INLINE_ANNOTATION with @JvmInline or remove it depending on compiler backend
// for JVM IR both ones are generated according to value classes feature (https://github.com/Kotlin/KEEP/issues/237)
fun TestEntityModel.containsWithoutJvmInline(): Boolean = when (this) {
is ClassModel -> methods.any { it.containsWithoutJvmInline() } || innerTestClasses.any { it.containsWithoutJvmInline() }
is SimpleTestMethodModel -> file.isFile && file.readLines().any { Regex("^\\s*//\\s*$WORKS_WHEN_VALUE_CLASS\\s*$").matches(it) }
is SimpleTestMethodModel -> file.isFile && "WORKS_WHEN_VALUE_CLASS" in directives
else -> false
}