blob: 3a9fa5bfe1ddec819b0fb61b3a19a9e38c0b0d33 [file] [log] [blame]
package com.intellij.openapi.vcs;
import com.intellij.notification.Notification;
import com.intellij.openapi.application.PluginPathManager;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.junit.Assert.*;
/**
* @author Nadya Zabrodina
*/
public class VcsTestUtil {
// TODO: option - create via IDEA or via java.io. In latter case no need in Project parameter.
public static VirtualFile createFile(@NotNull Project project,
@NotNull final VirtualFile parent,
@NotNull final String name,
@Nullable final String content) {
final Ref<VirtualFile> result = new Ref<VirtualFile>();
new WriteCommandAction.Simple(project) {
@Override
protected void run() throws Throwable {
try {
VirtualFile file = parent.createChildData(this, name);
if (content != null) {
file.setBinaryContent(CharsetToolkit.getUtf8Bytes(content));
}
result.set(file);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
}.execute();
return result.get();
}
/**
* TODO: option - create via IDEA or via java.io. In latter case no need in Project parameter.
* Creates directory inside a write action and returns the resulting reference to it.
* If the directory already exists, does nothing.
*
* @param parent Parent directory.
* @param name Name of the directory.
* @return reference to the created or already existing directory.
*/
public static VirtualFile createDir(@NotNull Project project, @NotNull final VirtualFile parent, @NotNull final String name) {
final Ref<VirtualFile> result = new Ref<VirtualFile>();
new WriteCommandAction.Simple(project) {
@Override
protected void run() throws Throwable {
try {
VirtualFile dir = parent.findChild(name);
if (dir == null) {
dir = parent.createChildDirectory(this, name);
}
result.set(dir);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
}.execute();
return result.get();
}
/**
* Testng compares by iterating over 2 collections, but it won't work for sets which may have different order.
*/
public static <T> void assertEqualCollections(@NotNull Collection<T> actual, @NotNull Collection<T> expected) {
if (actual.size() != expected.size()) {
fail("Collections don't have the same size. " + stringifyActualExpected(actual, expected));
}
for (T act : actual) {
if (!expected.contains(act)) {
fail("Unexpected object " + act + stringifyActualExpected(actual, expected));
}
}
// backwards is needed for collections which may contain duplicates, e.g. Lists.
for (T exp : expected) {
if (!actual.contains(exp)) {
fail("Object " + exp + " not found in actual collection." + stringifyActualExpected(actual, expected));
}
}
}
/**
* Testng compares by iterating over 2 collections, but it won't work for sets which may have different order.
*/
public static <T, E> void assertEqualCollections(@NotNull Collection<T> actual,
@NotNull Collection<E> expected,
@NotNull EqualityChecker<T, E> equalityChecker) {
if (actual.size() != expected.size()) {
fail("Collections don't have the same size. " + stringifyActualExpected(actual, expected));
}
for (T act : actual) {
if (!contains2(expected, act, equalityChecker)) {
fail("Unexpected object " + act + stringifyActualExpected(actual, expected));
}
}
// backwards is needed for collections which may contain duplicates, e.g. Lists.
for (E exp : expected) {
if (!contains(actual, exp, equalityChecker)) {
fail("Object " + exp + " not found in actual collection." + stringifyActualExpected(actual, expected));
}
}
}
private static <T, E> boolean contains(@NotNull Collection<T> collection,
@NotNull E object,
@NotNull EqualityChecker<T, E> equalityChecker) {
for (T t : collection) {
if (equalityChecker.areEqual(t, object)) {
return true;
}
}
return false;
}
private static <T, E> boolean contains2(@NotNull Collection<E> collection,
@NotNull T object,
@NotNull EqualityChecker<T, E> equalityChecker) {
for (E e : collection) {
if (equalityChecker.areEqual(object, e)) {
return true;
}
}
return false;
}
public static Object[][] loadConfigData(@NotNull File dataFolder) throws IOException {
File[] tests = dataFolder.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return !name.startsWith(".");
}
});
Object[][] data = new Object[tests.length][];
for (int i = 0; i < tests.length; i++) {
File testDir = tests[i];
File descriptionFile = null;
File configFile = null;
File resultFile = null;
for (File file : testDir.listFiles()) {
if (file.getName().endsWith("_desc.txt")) {
descriptionFile = file;
}
else if (file.getName().endsWith("_config.txt")) {
configFile = file;
}
else if (file.getName().endsWith("_result.txt")) {
resultFile = file;
}
}
assertNotNull(String.format("description file not found in %s among %s", testDir, Arrays.toString(testDir.list())), descriptionFile);
assertNotNull(String.format("config file file not found in %s among %s", testDir, Arrays.toString(testDir.list())), configFile);
assertNotNull(String.format("result file file not found in %s among %s", testDir, Arrays.toString(testDir.list())), resultFile);
String testName = FileUtil.loadFile(descriptionFile).split("\n")[0]; // description is in the first line of the desc-file
data[i] = new Object[]{
testName, configFile, resultFile
};
}
return data;
}
@NotNull
public static File getTestDataFolder() {
File pluginRoot = new File(PluginPathManager.getPluginHomePath("git4idea"));
return new File(pluginRoot, "testData");
}
public interface EqualityChecker<T, E> {
boolean areEqual(T actual, E expected);
}
@NotNull
public static String stringifyActualExpected(@NotNull Object actual, @NotNull Object expected) {
return "\nExpected:\n" + expected + "\nActual:\n" + actual;
}
@NotNull
public static String toAbsolute(@NotNull String relPath, @NotNull Project project) {
new File(toAbsolute(Collections.singletonList(relPath), project).get(0)).mkdir();
return toAbsolute(Collections.singletonList(relPath), project).get(0);
}
@NotNull
public static List<String> toAbsolute(@NotNull Collection<String> relPaths, @NotNull final Project project) {
return ContainerUtil.map2List(relPaths, new Function<String, String>() {
@Override
public String fun(String s) {
try {
return FileUtil.toSystemIndependentName((new File(project.getBasePath() + "/" + s).getCanonicalPath()));
}
catch (IOException e) {
e.printStackTrace();
return "";
}
}
});
}
public static void assertNotificationShown(@NotNull Project project, @Nullable Notification expected) {
if (expected != null) {
Notification actualNotification =
((TestVcsNotifier)VcsNotifier.getInstance(project)).getLastNotification();
assertNotNull("No notification was shown", actualNotification);
assertEquals("Notification has wrong title", expected.getTitle(), actualNotification.getTitle());
assertEquals("Notification has wrong type", expected.getType(), actualNotification.getType());
assertEquals("Notification has wrong content", adjustTestContent(expected.getContent()), actualNotification.getContent());
}
}
// we allow more spaces and line breaks in tests to make them more readable.
// After all, notifications display html, so all line breaks and extra spaces are ignored.
private static String adjustTestContent(@NotNull String s) {
StringBuilder res = new StringBuilder();
String[] splits = s.split("\n");
for (String split : splits) {
res.append(split.trim());
}
return res.toString();
}
}