| /* |
| * Copyright 2000-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 com.intellij.openapi.vcs; |
| |
| import com.intellij.notification.Notification; |
| import com.intellij.openapi.application.Result; |
| import com.intellij.openapi.command.WriteCommandAction; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.util.io.FileUtil; |
| import com.intellij.openapi.util.text.StringUtil; |
| 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.IOException; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import static junit.framework.Assert.assertTrue; |
| import static org.junit.Assert.*; |
| |
| public class VcsTestUtil { |
| public static VirtualFile createFile(@NotNull Project project, @NotNull final VirtualFile parent, @NotNull final String name, |
| @Nullable final String content) { |
| return new WriteCommandAction<VirtualFile>(project) { |
| @Override |
| protected void run(@NotNull Result<VirtualFile> result) throws Throwable { |
| VirtualFile file = parent.createChildData(this, name); |
| if (content != null) { |
| file.setBinaryContent(CharsetToolkit.getUtf8Bytes(content)); |
| } |
| result.setResult(file); |
| } |
| }.execute().throwException().getResultObject(); |
| } |
| |
| /** |
| * 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 final Project project, @NotNull final VirtualFile parent, @NotNull final String name) { |
| return new WriteCommandAction<VirtualFile>(project) { |
| @Override |
| protected void run(@NotNull Result<VirtualFile> result) throws Throwable { |
| VirtualFile dir = parent.findChild(name); |
| if (dir == null) { |
| dir = parent.createChildDirectory(this, name); |
| } |
| result.setResult(dir); |
| } |
| }.execute().throwException().getResultObject(); |
| } |
| |
| public static void renameFileInCommand(@NotNull Project project, @NotNull final VirtualFile file, @NotNull final String newName) { |
| new WriteCommandAction.Simple(project) { |
| @Override |
| protected void run() throws Throwable { |
| try { |
| file.rename(this, newName); |
| } |
| catch (IOException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| }.execute().throwException(); |
| } |
| |
| public static void deleteFileInCommand(@NotNull Project project, @NotNull final VirtualFile file) { |
| new WriteCommandAction.Simple(project) { |
| @Override |
| protected void run() throws Throwable { |
| try { |
| file.delete(this); |
| } |
| catch(IOException ex) { |
| throw new RuntimeException(ex); |
| } |
| } |
| }.execute(); |
| } |
| |
| public static void editFileInCommand(@NotNull Project project, @NotNull final VirtualFile file, @NotNull final String newContent) { |
| assertTrue(file.isValid()); |
| file.getTimeStamp(); |
| new WriteCommandAction.Simple(project) { |
| @Override |
| protected void run() throws Throwable { |
| try { |
| final long newTs = Math.max(System.currentTimeMillis(), file.getTimeStamp() + 1100); |
| file.setBinaryContent(newContent.getBytes(), -1, newTs); |
| final File file1 = new File(file.getPath()); |
| FileUtil.writeToFile(file1, newContent.getBytes()); |
| file.refresh(false, false); |
| assertTrue(file1 + " / " + newTs, file1.setLastModified(newTs)); |
| } |
| catch(IOException ex) { |
| throw new RuntimeException(ex); |
| } |
| } |
| }.execute(); |
| } |
| |
| public static VirtualFile copyFileInCommand(@NotNull Project project, @NotNull final VirtualFile file, |
| @NotNull final VirtualFile newParent, @NotNull final String newName) { |
| return new WriteCommandAction<VirtualFile>(project) { |
| @Override |
| protected void run(@NotNull Result<VirtualFile> result) throws Throwable { |
| try { |
| result.setResult(file.copy(this, newParent, newName)); |
| } |
| catch (IOException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| }.execute().getResultObject(); |
| } |
| |
| public static void moveFileInCommand(@NotNull Project project, @NotNull final VirtualFile file, @NotNull final VirtualFile newParent) { |
| new WriteCommandAction.Simple(project) { |
| @Override |
| protected void run() throws Throwable { |
| try { |
| file.move(this, newParent); |
| } |
| catch (IOException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| }.execute(); |
| } |
| |
| public static <T> void assertEqualCollections(@NotNull String message, @NotNull Collection<T> actual, @NotNull Collection<T> expected) { |
| if (!StringUtil.isEmptyOrSpaces(message) && !message.endsWith(":") && !message.endsWith(": ")) { |
| message += ": "; |
| } |
| if (actual.size() != expected.size()) { |
| fail(message + "Collections don't have the same size. " + stringifyActualExpected(actual, expected)); |
| } |
| for (T act : actual) { |
| if (!expected.contains(act)) { |
| fail(message + "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(message + "Object " + exp + " not found in actual collection." + stringifyActualExpected(actual, expected)); |
| } |
| } |
| } |
| |
| public static <T> void assertEqualCollections(@NotNull Collection<T> actual, @NotNull Collection<T> expected) { |
| assertEqualCollections("", 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<? extends T> actual, |
| @NotNull Collection<? extends 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<? extends 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<? extends E> collection, |
| @NotNull T object, |
| @NotNull EqualityChecker<T, E> equalityChecker) { |
| for (E e : collection) { |
| if (equalityChecker.areEqual(object, e)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| 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(); |
| } |
| |
| } |