/* * Copyright 2010-2015 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.generators.tests.generator; import com.google.common.collect.Lists; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.test.KotlinTestUtils; import org.jetbrains.kotlin.test.TargetBackend; import org.jetbrains.kotlin.utils.Printer; import java.io.File; import java.util.*; import java.util.regex.Pattern; public class SimpleTestClassModel implements TestClassModel { private static final Comparator<TestEntityModel> BY_NAME = Comparator.comparing(TestEntityModel::getName); @NotNull private final File rootFile; private final boolean recursive; private final boolean excludeParentDirs; @NotNull private final Pattern filenamePattern; @Nullable private final Boolean checkFilenameStartsLowerCase; @NotNull private final String doTestMethodName; @NotNull private final String testClassName; @NotNull private final TargetBackend targetBackend; @NotNull private final Set<String> excludeDirs; @Nullable private Collection<TestClassModel> innerTestClasses; @Nullable private Collection<MethodModel> testMethods; public SimpleTestClassModel( @NotNull File rootFile, boolean recursive, boolean excludeParentDirs, @NotNull Pattern filenamePattern, @Nullable Boolean checkFilenameStartsLowerCase, @NotNull String doTestMethodName, @NotNull String testClassName, @NotNull TargetBackend targetBackend, @NotNull Collection<String> excludeDirs ) { this.rootFile = rootFile; this.recursive = recursive; this.excludeParentDirs = excludeParentDirs; this.filenamePattern = filenamePattern; this.doTestMethodName = doTestMethodName; this.testClassName = testClassName; this.targetBackend = targetBackend; this.checkFilenameStartsLowerCase = checkFilenameStartsLowerCase; this.excludeDirs = excludeDirs.isEmpty() ? Collections.emptySet() : new LinkedHashSet<>(excludeDirs); } @NotNull @Override public Collection<TestClassModel> getInnerTestClasses() { if (!rootFile.isDirectory() || !recursive) { return Collections.emptyList(); } if (innerTestClasses == null) { List<TestClassModel> children = Lists.newArrayList(); File[] files = rootFile.listFiles(); if (files != null) { for (File file : files) { if (file.isDirectory() && dirHasFilesInside(file) && !excludeDirs.contains(file.getName())) { String innerTestClassName = TestGeneratorUtil.fileNameToJavaIdentifier(file); children.add(new SimpleTestClassModel( file, true, excludeParentDirs, filenamePattern, checkFilenameStartsLowerCase, doTestMethodName, innerTestClassName, targetBackend, excludesStripOneDirectory(file.getName())) ); } } } children.sort(BY_NAME); innerTestClasses = children; } return innerTestClasses; } @NotNull private Set<String> excludesStripOneDirectory(@NotNull String directoryName) { if (excludeDirs.isEmpty()) return excludeDirs; Set<String> result = new LinkedHashSet<>(); for (String excludeDir : excludeDirs) { int firstSlash = excludeDir.indexOf('/'); if (firstSlash >= 0 && excludeDir.substring(0, firstSlash).equals(directoryName)) { result.add(excludeDir.substring(firstSlash + 1)); } } return result; } private static boolean dirHasFilesInside(@NotNull File dir) { return !FileUtil.processFilesRecursively(dir, File::isDirectory); } private static boolean dirHasSubDirs(@NotNull File dir) { File[] listFiles = dir.listFiles(); if (listFiles == null) { return false; } for (File file : listFiles) { if (file.isDirectory()) { return true; } } return false; } @NotNull @Override public Collection<MethodModel> getMethods() { if (testMethods == null) { if (!rootFile.isDirectory()) { testMethods = Collections.singletonList(new SimpleTestMethodModel( rootFile, rootFile, doTestMethodName, filenamePattern, checkFilenameStartsLowerCase, targetBackend )); } else { List<MethodModel> result = Lists.newArrayList(); result.add(new TestAllFilesPresentMethodModel()); File[] listFiles = rootFile.listFiles(); if (listFiles != null) { for (File file : listFiles) { if (filenamePattern.matcher(file.getName()).matches()) { if (file.isDirectory() && excludeParentDirs && dirHasSubDirs(file)) { continue; } result.add(new SimpleTestMethodModel(rootFile, file, doTestMethodName, filenamePattern, checkFilenameStartsLowerCase, targetBackend)); } } } result.sort(BY_NAME); testMethods = result; } } return testMethods; } @Override public boolean isEmpty() { boolean noTestMethods = getMethods().size() == 1; return noTestMethods && getInnerTestClasses().isEmpty(); } @Override public String getDataString() { return KotlinTestUtils.getFilePath(rootFile); } @Nullable @Override public String getDataPathRoot() { return "$PROJECT_ROOT"; } @NotNull @Override public String getName() { return testClassName; } private class TestAllFilesPresentMethodModel implements TestMethodModel { @NotNull @Override public String getName() { return "testAllFilesPresentIn" + testClassName; } @Override public void generateBody(@NotNull Printer p) { StringBuilder exclude = new StringBuilder(); for (String dir : excludeDirs) { exclude.append(", \""); exclude.append(StringUtil.escapeStringCharacters(dir)); exclude.append("\""); } String assertTestsPresentStr = String.format( "KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File(\"%s\"), Pattern.compile(\"%s\"), %s.%s, %s%s);", KotlinTestUtils.getFilePath(rootFile), StringUtil.escapeStringCharacters(filenamePattern.pattern()), TargetBackend.class.getSimpleName(), targetBackend.toString(), recursive, exclude ); p.println(assertTestsPresentStr); } @Override public String getDataString() { return null; } @Override public void generateSignature(@NotNull Printer p) { TestMethodModel.DefaultImpls.generateSignature(this, p); } @Override public boolean shouldBeGenerated() { return true; } } }