/* * Copyright 2010-2014 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.jet; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.intellij.openapi.Disposable; import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.ShutDownTracker; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileFactory; import com.intellij.psi.impl.PsiFileFactoryImpl; import com.intellij.rt.execution.junit.FileComparisonFailure; import com.intellij.testFramework.LightVirtualFile; import com.intellij.util.Function; import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; import junit.framework.TestCase; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; import org.jetbrains.jet.analyzer.AnalyzeExhaust; import org.jetbrains.jet.cli.jvm.compiler.CliLightClassGenerationSupport; import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; import org.jetbrains.jet.codegen.forTestCompile.ForTestCompileRuntime; import org.jetbrains.jet.config.CommonConfigurationKeys; import org.jetbrains.jet.config.CompilerConfiguration; import org.jetbrains.jet.lang.PlatformToKotlinClassMap; import org.jetbrains.jet.lang.descriptors.DependencyKind; import org.jetbrains.jet.lang.descriptors.impl.ModuleDescriptorImpl; import org.jetbrains.jet.lang.descriptors.impl.MutablePackageFragmentDescriptor; import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.diagnostics.Severity; import org.jetbrains.jet.lang.diagnostics.rendering.DefaultErrorMessages; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM; import org.jetbrains.jet.lang.resolve.lazy.JvmResolveUtil; import org.jetbrains.jet.lang.resolve.lazy.LazyResolveTestUtil; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.plugin.JetLanguage; import org.jetbrains.jet.test.InnerTestClasses; import org.jetbrains.jet.test.TestMetadata; import org.jetbrains.jet.test.util.UtilPackage; import org.jetbrains.jet.util.slicedmap.ReadOnlySlice; import org.jetbrains.jet.util.slicedmap.SlicedMap; import org.jetbrains.jet.util.slicedmap.WritableSlice; import org.jetbrains.jet.utils.PathUtil; import org.jetbrains.jet.utils.UtilsPackage; import org.junit.Assert; import javax.tools.*; import java.io.File; import java.io.IOException; import java.io.StringWriter; import java.lang.reflect.Method; import java.nio.charset.Charset; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import static org.jetbrains.jet.ConfigurationKind.ALL; import static org.jetbrains.jet.ConfigurationKind.JDK_AND_ANNOTATIONS; import static org.jetbrains.jet.cli.jvm.JVMConfigurationKeys.ANNOTATIONS_PATH_KEY; import static org.jetbrains.jet.cli.jvm.JVMConfigurationKeys.CLASSPATH_KEY; import static org.jetbrains.jet.jvm.compiler.LoadDescriptorUtil.compileKotlinToDirAndGetAnalyzeExhaust; import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory; public class JetTestUtils { private static final Pattern KT_FILES = Pattern.compile(".*?.kt"); private static final List filesToDelete = new ArrayList(); /** * Syntax: * * // MODULE: name(dependency1, dependency2, ...) * * // FILE: name * * Several files may follow one module */ public static final Pattern FILE_OR_MODULE_PATTERN = Pattern.compile("(?://\\s*MODULE:\\s*(\\w+)(\\(\\w+(?:, \\w+)*\\))?\\s*)?" + "//\\s*FILE:\\s*(.*)$", Pattern.MULTILINE); public static final Pattern DIRECTIVE_PATTERN = Pattern.compile("^//\\s*!(\\w+)(:\\s*(.*)$)?", Pattern.MULTILINE); public static final BindingTrace DUMMY_TRACE = new BindingTrace() { @NotNull @Override public BindingContext getBindingContext() { return new BindingContext() { @NotNull @Override public Diagnostics getDiagnostics() { throw new UnsupportedOperationException(); // TODO } @Override public V get(ReadOnlySlice slice, K key) { return DUMMY_TRACE.get(slice, key); } @NotNull @Override public Collection getKeys(WritableSlice slice) { return DUMMY_TRACE.getKeys(slice); } @NotNull @TestOnly @Override public ImmutableMap getSliceContents(@NotNull ReadOnlySlice slice) { return ImmutableMap.of(); } }; } @Override public void record(WritableSlice slice, K key, V value) { } @Override public void record(WritableSlice slice, K key) { } @Override public V get(ReadOnlySlice slice, K key) { if (slice == BindingContext.PROCESSED) return (V)Boolean.FALSE; return SlicedMap.DO_NOTHING.get(slice, key); } @NotNull @Override public Collection getKeys(WritableSlice slice) { assert slice.isCollective(); return Collections.emptySet(); } @Override public void report(@NotNull Diagnostic diagnostic) { if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(diagnostic.getFactory())) { throw new IllegalStateException("Unresolved: " + diagnostic.getPsiElement().getText()); } } }; public static BindingTrace DUMMY_EXCEPTION_ON_ERROR_TRACE = new BindingTrace() { @NotNull @Override public BindingContext getBindingContext() { return new BindingContext() { @NotNull @Override public Diagnostics getDiagnostics() { throw new UnsupportedOperationException(); } @Override public V get(ReadOnlySlice slice, K key) { return DUMMY_EXCEPTION_ON_ERROR_TRACE.get(slice, key); } @NotNull @Override public Collection getKeys(WritableSlice slice) { return DUMMY_EXCEPTION_ON_ERROR_TRACE.getKeys(slice); } @NotNull @TestOnly @Override public ImmutableMap getSliceContents(@NotNull ReadOnlySlice slice) { return ImmutableMap.of(); } }; } @Override public void record(WritableSlice slice, K key, V value) { } @Override public void record(WritableSlice slice, K key) { } @Override public V get(ReadOnlySlice slice, K key) { return null; } @NotNull @Override public Collection getKeys(WritableSlice slice) { assert slice.isCollective(); return Collections.emptySet(); } @Override public void report(@NotNull Diagnostic diagnostic) { if (diagnostic.getSeverity() == Severity.ERROR) { throw new IllegalStateException(DefaultErrorMessages.RENDERER.render(diagnostic)); } } }; @SuppressWarnings("unchecked") private static final Class[] NO_INNER_CLASSES = new Class[0]; private JetTestUtils() { } @NotNull public static AnalyzeExhaust analyzeFile(@NotNull JetFile file) { return JvmResolveUtil.analyzeOneFileWithJavaIntegration(file); } @NotNull public static AnalyzeExhaust analyzeFileWithoutBody(@NotNull JetFile file) { return JvmResolveUtil.analyzeFilesWithJavaIntegration(file.getProject(), Collections.singleton(file), Predicates.alwaysFalse()); } @NotNull public static JetCoreEnvironment createEnvironmentWithFullJdk(Disposable disposable) { return createEnvironmentWithJdkAndNullabilityAnnotationsFromIdea(disposable, ConfigurationKind.ALL, TestJdkKind.FULL_JDK); } @NotNull public static JetCoreEnvironment createEnvironmentWithMockJdkAndIdeaAnnotations(Disposable disposable) { return createEnvironmentWithMockJdkAndIdeaAnnotations(disposable, ConfigurationKind.ALL); } @NotNull public static JetCoreEnvironment createEnvironmentWithMockJdkAndIdeaAnnotations(Disposable disposable, @NotNull ConfigurationKind configurationKind) { return createEnvironmentWithJdkAndNullabilityAnnotationsFromIdea(disposable, configurationKind, TestJdkKind.MOCK_JDK); } @NotNull public static JetCoreEnvironment createEnvironmentWithJdkAndNullabilityAnnotationsFromIdea( @NotNull Disposable disposable, @NotNull ConfigurationKind configurationKind, @NotNull TestJdkKind jdkKind ) { return JetCoreEnvironment.createForTests(disposable, compilerConfigurationForTests( configurationKind, jdkKind, getAnnotationsJar())); } public static File findMockJdkRtJar() { return new File(JetTestCaseBuilder.getHomeDirectory(), "compiler/testData/mockJDK/jre/lib/rt.jar"); } public static File findAndroidApiJar() { return new File(JetTestCaseBuilder.getHomeDirectory(), "dependencies/android.jar"); } public static File getAnnotationsJar() { return new File(JetTestCaseBuilder.getHomeDirectory(), "compiler/testData/mockJDK/jre/lib/annotations.jar"); } @NotNull public static File getJdkAnnotationsJar() { File jdkAnnotations = new File("dependencies/annotations/kotlin-jdk-annotations.jar"); if (!jdkAnnotations.exists()) { throw new RuntimeException("Kotlin JDK annotations jar not found; please run 'ant dist' to build it"); } return jdkAnnotations; } @NotNull public static File getAndroidSdkAnnotationsJar() { File androidSdkAnnotations = new File("dependencies/annotations/kotlin-android-sdk-annotations.jar"); if (!androidSdkAnnotations.exists()) { throw new RuntimeException("Kotlin Android SDK annotations jar not found; please run 'ant dist' to build it"); } return androidSdkAnnotations; } public static void mkdirs(File file) throws IOException { if (file.isDirectory()) { return; } if (!file.mkdirs()) { if (file.exists()) { throw new IOException("failed to create " + file + " file exists and not a directory"); } throw new IOException(); } } @NotNull public static File tmpDirForTest(TestCase test) throws IOException { File answer = FileUtil.createTempDirectory(test.getClass().getSimpleName(), test.getName()); deleteOnShutdown(answer); return answer; } @NotNull public static File tmpDir(String name) throws IOException { // we should use this form. otherwise directory will be deleted on each test File answer = FileUtil.createTempDirectory(new File(System.getProperty("java.io.tmpdir")), name, ""); deleteOnShutdown(answer); return answer; } public static void deleteOnShutdown(File file) { if (filesToDelete.isEmpty()) { ShutDownTracker.getInstance().registerShutdownTask(new Runnable() { @Override public void run() { ShutDownTracker.invokeAndWait(true, true, new Runnable() { @Override public void run() { for (File victim : filesToDelete) { FileUtil.delete(victim); } } }); } }); } filesToDelete.add(file); } public static void rmrf(File file) { if (file == null) { return; } if (!FileUtil.delete(file)) { throw new RuntimeException("failed to delete " + file); } } @NotNull public static JetFile createFile(@NotNull @NonNls String name, @NotNull String text, @NotNull Project project) { LightVirtualFile virtualFile = new LightVirtualFile(name, JetLanguage.INSTANCE, text); virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET); return (JetFile) ((PsiFileFactoryImpl) PsiFileFactory.getInstance(project)).trySetupPsiForFile(virtualFile, JetLanguage.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 { return FileUtil.loadFile(file, CharsetToolkit.UTF8, true).trim(); } public static String getFilePath(File file) { return FileUtil.toSystemIndependentName(file.getPath()); } @NotNull public static CompilerConfiguration compilerConfigurationForTests(@NotNull ConfigurationKind configurationKind, @NotNull TestJdkKind jdkKind, File... extraClasspath) { return compilerConfigurationForTests(configurationKind, jdkKind, Arrays.asList(extraClasspath), Collections.emptyList()); } @NotNull public static CompilerConfiguration compilerConfigurationForTests(@NotNull ConfigurationKind configurationKind, @NotNull TestJdkKind jdkKind, @NotNull Collection extraClasspath, @NotNull Collection priorityClasspath) { CompilerConfiguration configuration = new CompilerConfiguration(); configuration.addAll(CLASSPATH_KEY, priorityClasspath); if (jdkKind == TestJdkKind.MOCK_JDK) { configuration.add(CLASSPATH_KEY, findMockJdkRtJar()); } else if (jdkKind == TestJdkKind.ANDROID_API) { configuration.add(CLASSPATH_KEY, findAndroidApiJar()); } else { configuration.addAll(CLASSPATH_KEY, PathUtil.getJdkClassesRoots()); } if (configurationKind == ALL) { configuration.add(CLASSPATH_KEY, ForTestCompileRuntime.runtimeJarForTests()); } configuration.addAll(CLASSPATH_KEY, extraClasspath); if (configurationKind == ALL || configurationKind == JDK_AND_ANNOTATIONS) { if (jdkKind == TestJdkKind.ANDROID_API) { configuration.add(ANNOTATIONS_PATH_KEY, getAndroidSdkAnnotationsJar()); } else { configuration.add(ANNOTATIONS_PATH_KEY, getJdkAnnotationsJar()); } } return configuration; } public static void newTrace(@NotNull JetCoreEnvironment environment) { // let the next analysis use another trace CliLightClassGenerationSupport.getInstanceForCli(environment.getProject()).newBindingTrace(); } public static void resolveAllKotlinFiles(JetCoreEnvironment environment) throws IOException { List paths = environment.getConfiguration().get(CommonConfigurationKeys.SOURCE_ROOTS_KEY); if (paths == null) return; List jetFiles = Lists.newArrayList(); for (String path : paths) { jetFiles.add(loadJetFile(environment.getProject(), new File(path))); } LazyResolveTestUtil.resolveEagerly(jetFiles, environment); } @NotNull public static List collectKtFiles(@NotNull File root) { List files = Lists.newArrayList(); FileUtil.collectMatchedFiles(root, KT_FILES, files); return files; } public static void assertEqualsToFile(@NotNull File expectedFile, @NotNull String actual) { try { String actualText = UtilPackage.removeTrailingWhitespacesFromEachLine(StringUtil.convertLineSeparators(actual.trim())); if (!expectedFile.exists()) { FileUtil.writeToFile(expectedFile, actualText); Assert.fail("Expected data file did not exist. Generating: " + expectedFile); } String expected = FileUtil.loadFile(expectedFile, CharsetToolkit.UTF8, true); String expectedText = UtilPackage.removeTrailingWhitespacesFromEachLine(StringUtil.convertLineSeparators(expected.trim())); if (!Comparing.equal(expectedText, actualText)) { throw new FileComparisonFailure("Actual data differs from file content: " + expectedFile.getName(), expected, actual, expectedFile.getAbsolutePath()); } } catch (IOException e) { throw UtilsPackage.rethrow(e); } } public static void compileKotlinWithJava( @NotNull List javaFiles, @NotNull List ktFiles, @NotNull File outDir, @NotNull Disposable disposable ) throws IOException { if (!ktFiles.isEmpty()) { compileKotlinToDirAndGetAnalyzeExhaust(ktFiles, outDir, disposable, ALL); } else { boolean mkdirs = outDir.mkdirs(); assert mkdirs : "Not created: " + outDir; } if (!javaFiles.isEmpty()) { compileJavaFiles(javaFiles, Arrays.asList( "-classpath", outDir.getPath() + File.pathSeparator + ForTestCompileRuntime.runtimeJarForTests(), "-d", outDir.getPath() )); } } public interface TestFileFactory { F createFile(@Nullable M module, String fileName, String text, Map directives); M createModule(String name, List dependencies); } public static abstract class TestFileFactoryNoModules implements TestFileFactory { @Override public final F createFile(@Nullable Void module, String fileName, String text, Map directives) { return create(fileName, text, directives); } public abstract F create(String fileName, String text, Map directives); @Override public Void createModule(String name, List dependencies) { return null; } } public static List createTestFiles(String testFileName, String expectedText, TestFileFactory factory) { Map directives = parseDirectives(expectedText); List testFiles = Lists.newArrayList(); Matcher matcher = FILE_OR_MODULE_PATTERN.matcher(expectedText); if (!matcher.find()) { // One file testFiles.add(factory.createFile(null, testFileName, expectedText, directives)); } else { int processedChars = 0; M module = null; // Many files while (true) { String moduleName = matcher.group(1); String moduleDependencies = matcher.group(2); if (moduleName != null) { module = factory.createModule(moduleName, parseDependencies(moduleDependencies)); } String fileName = matcher.group(3); int start = processedChars; boolean nextFileExists = matcher.find(); int end; if (nextFileExists) { end = matcher.start(); } else { end = expectedText.length(); } String fileText = expectedText.substring(start, end); processedChars = end; testFiles.add(factory.createFile(module, fileName, fileText, directives)); if (!nextFileExists) break; } assert processedChars == expectedText.length() : "Characters skipped from " + processedChars + " to " + (expectedText.length() - 1); } return testFiles; } private static List parseDependencies(@Nullable String dependencies) { if (dependencies == null) return Collections.emptyList(); Matcher matcher = Pattern.compile("\\w+").matcher(dependencies); List result = new ArrayList(); while (matcher.find()) { result.add(matcher.group()); } return result; } @NotNull public static Map parseDirectives(String expectedText) { Map directives = Maps.newHashMap(); Matcher directiveMatcher = DIRECTIVE_PATTERN.matcher(expectedText); int start = 0; while (directiveMatcher.find()) { if (directiveMatcher.start() != start) { Assert.fail("Directives should only occur at the beginning of a file: " + directiveMatcher.group()); } String name = directiveMatcher.group(1); String value = directiveMatcher.group(3); String oldValue = directives.put(name, value); Assert.assertNull("Directive overwritten: " + name + " old value: " + oldValue + " new value: " + value, oldValue); start = directiveMatcher.end() + 1; } return directives; } public static List loadBeforeAfterText(String filePath) { String content; try { content = FileUtil.loadFile(new File(filePath), true); } catch (IOException e) { throw new RuntimeException(e); } List files = createTestFiles("", content, new TestFileFactoryNoModules() { @Override public String create(String fileName, String text, Map directives) { int firstLineEnd = text.indexOf('\n'); return StringUtil.trimTrailing(text.substring(firstLineEnd + 1)); } }); Assert.assertTrue("Exactly two files expected: ", files.size() == 2); return files; } public static String getLastCommentedLines(@NotNull Document document) { List resultLines = new ArrayList(); for (int i = document.getLineCount() - 1; i >= 0; i--) { int lineStart = document.getLineStartOffset(i); int lineEnd = document.getLineEndOffset(i); if (document.getCharsSequence().subSequence(lineStart, lineEnd).toString().trim().isEmpty()) { continue; } if ("//".equals(document.getCharsSequence().subSequence(lineStart, lineStart + 2).toString())) { resultLines.add(document.getCharsSequence().subSequence(lineStart + 2, lineEnd)); } else { break; } } Collections.reverse(resultLines); StringBuilder result = new StringBuilder(); for (CharSequence line : resultLines) { result.append(line).append("\n"); } result.delete(result.length() - 1, result.length()); return result.toString(); } public static String getLastCommentInFile(JetFile file) { PsiElement lastChild = file.getLastChild(); if (lastChild != null && lastChild.getNode().getElementType().equals(JetTokens.WHITE_SPACE)) { lastChild = lastChild.getPrevSibling(); } assert lastChild != null; if (lastChild.getNode().getElementType().equals(JetTokens.BLOCK_COMMENT)) { String lastChildText = lastChild.getText(); return lastChildText.substring(2, lastChildText.length() - 2).trim(); } else if (lastChild.getNode().getElementType().equals(JetTokens.EOL_COMMENT)) { return lastChild.getText().substring(2).trim(); } else { throw new AssertionError("Test file '" + file.getName() + "' should end in a comment; last node was: " + lastChild); } } public static void compileJavaFiles(@NotNull Collection files, List options) throws IOException { JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); DiagnosticCollector diagnosticCollector = new DiagnosticCollector(); StandardJavaFileManager fileManager = javaCompiler.getStandardFileManager(diagnosticCollector, Locale.ENGLISH, Charset.forName("utf-8")); try { Iterable javaFileObjectsFromFiles = fileManager.getJavaFileObjectsFromFiles(files); JavaCompiler.CompilationTask task = javaCompiler.getTask( new StringWriter(), // do not write to System.err fileManager, diagnosticCollector, options, null, javaFileObjectsFromFiles); Boolean success = task.call(); // do NOT inline this variable, call() should complete before errorsToString() Assert.assertTrue(errorsToString(diagnosticCollector), success); } finally { fileManager.close(); } } private static String errorsToString(DiagnosticCollector diagnosticCollector) { StringBuilder builder = new StringBuilder(); for (javax.tools.Diagnostic diagnostic : diagnosticCollector.getDiagnostics()) { if (diagnostic.getKind() == javax.tools.Diagnostic.Kind.ERROR) { builder.append(diagnostic).append("\n"); } } return builder.toString(); } public static void assertAllTestsPresentByMetadata( @NotNull Class testCaseClass, @NotNull String generatorClassFqName, @NotNull File testDataDir, @NotNull Pattern filenamePattern, boolean recursive ) { TestMetadata testClassMetadata = testCaseClass.getAnnotation(TestMetadata.class); Assert.assertNotNull("No metadata for class: " + testCaseClass, testClassMetadata); String rootPath = testClassMetadata.value(); File rootFile = new File(rootPath); Set filePaths = collectPathsMetadata(testCaseClass); File[] files = testDataDir.listFiles(); if (files != null) { for (File file : files) { if (file.isDirectory()) { if (recursive && containsTestData(file, filenamePattern)) { assertTestClassPresentByMetadata(testCaseClass, generatorClassFqName, file); } } else if (filenamePattern.matcher(file.getName()).matches()) { assertFilePathPresent(file, rootFile, filePaths, generatorClassFqName); } } } } public static void assertAllTestsPresentInSingleGeneratedClass( @NotNull Class testCaseClass, @NotNull final String generatorClassFqName, @NotNull File testDataDir, @NotNull final Pattern filenamePattern) { TestMetadata testClassMetadata = testCaseClass.getAnnotation(TestMetadata.class); Assert.assertNotNull("No metadata for class: " + testCaseClass, testClassMetadata); String rootPath = testClassMetadata.value(); final File rootFile = new File(rootPath); final Set filePaths = collectPathsMetadata(testCaseClass); FileUtil.processFilesRecursively(testDataDir, new Processor() { @Override public boolean process(File file) { if (file.isFile() && filenamePattern.matcher(file.getName()).matches()) { assertFilePathPresent(file, rootFile, filePaths, generatorClassFqName); } return true; } }); } private static void assertFilePathPresent(File file, File rootFile, Set filePaths, String generatorClassFqName) { String path = FileUtil.getRelativePath(rootFile, file); if (path != null) { String relativePath = FileUtil.nameToCompare(path); if (!filePaths.contains(relativePath)) { Assert.fail("Test data file missing from the generated test class: " + file + pleaseReRunGenerator(generatorClassFqName)); } } } private static Set collectPathsMetadata(Class testCaseClass) { return ContainerUtil.newHashSet( ContainerUtil.map(collectMethodsMetadata(testCaseClass), new Function() { @Override public String fun(String pathData) { return FileUtil.nameToCompare(pathData); } })); } private static Set collectMethodsMetadata(Class testCaseClass) { Set filePaths = Sets.newHashSet(); for (Method method : testCaseClass.getDeclaredMethods()) { TestMetadata testMetadata = method.getAnnotation(TestMetadata.class); if (testMetadata != null) { filePaths.add(testMetadata.value()); } } return filePaths; } private static boolean containsTestData(File dir, Pattern filenamePattern) { File[] files = dir.listFiles(); assert files != null; for (File file : files) { if (file.isDirectory()) { if (containsTestData(file, filenamePattern)) { return true; } } else { if (filenamePattern.matcher(file.getName()).matches()) { return true; } } } return false; } private static void assertTestClassPresentByMetadata( @NotNull Class outerClass, @NotNull String generatorClassFqName, @NotNull File testDataDir ) { InnerTestClasses innerClassesAnnotation = outerClass.getAnnotation(InnerTestClasses.class); Class[] innerClasses = innerClassesAnnotation == null ? NO_INNER_CLASSES : innerClassesAnnotation.value(); for (Class innerClass : innerClasses) { TestMetadata testMetadata = innerClass.getAnnotation(TestMetadata.class); if (testMetadata != null && testMetadata.value().equals(getFilePath(testDataDir))) { return; } } Assert.fail("Test data directory missing from the generated test class: " + testDataDir + pleaseReRunGenerator(generatorClassFqName)); } private static String pleaseReRunGenerator(String generatorClassFqName) { return "\nPlease re-run the generator: " + generatorClassFqName + getLocationFormattedForConsole(generatorClassFqName); } private static String getLocationFormattedForConsole(String generatorClassFqName) { return "(" + getSimpleName(generatorClassFqName) + ".java:1)"; } private static String getSimpleName(String generatorClassFqName) { return generatorClassFqName.substring(generatorClassFqName.lastIndexOf(".") + 1); } public static JetFile loadJetFile(@NotNull Project project, @NotNull File ioFile) throws IOException { String text = FileUtil.loadFile(ioFile, true); return JetPsiFactory(project).createPhysicalFile(ioFile.getName(), text); } @NotNull public static List loadToJetFiles( @NotNull JetCoreEnvironment environment, @NotNull List files ) throws IOException { List jetFiles = Lists.newArrayList(); for (File file : files) { jetFiles.add(loadJetFile(environment.getProject(), file)); } return jetFiles; } @NotNull public static ModuleDescriptorImpl createEmptyModule() { return createEmptyModule(""); } public static ModuleDescriptorImpl createEmptyModule(@NotNull String name) { return new ModuleDescriptorImpl(Name.special(name), Collections.emptyList(), PlatformToKotlinClassMap.EMPTY); } @NotNull public static MutablePackageFragmentDescriptor createTestPackageFragment(@NotNull Name testPackageName) { return createTestPackageFragment(testPackageName, ""); } @NotNull public static MutablePackageFragmentDescriptor createTestPackageFragment(@NotNull Name testPackageName, @NotNull String moduleName) { ModuleDescriptorImpl module = AnalyzerFacadeForJVM.createJavaModule(moduleName); MutablePackageFragmentProvider provider = new MutablePackageFragmentProvider(module); module.addFragmentProvider(DependencyKind.SOURCES, provider); return provider.getOrCreateFragment(FqName.topLevel(testPackageName)); } @NotNull public static File replaceExtension(@NotNull File file, @Nullable String newExtension) { return new File(file.getParentFile(), FileUtil.getNameWithoutExtension(file) + (newExtension == null ? "" : "." + newExtension)); } }