예제 #1
0
        static void TestMethod_RejectBadFilesSettings()
        {
            var dirFirst  = TestUtil.GetTestSubDirectory("first");
            var dirSecond = TestUtil.GetTestSubDirectory("second");

            TestUtil.IsEq(null, FormSortFiles.FillFromUI(SortFilesAction.SearchDuplicates, "", "",
                                                         Path.Combine(dirFirst, "notexist"), dirSecond, true, true, true, true));

            TestUtil.IsEq(null, FormSortFiles.FillFromUI(SortFilesAction.SearchDuplicates, "", "",
                                                         dirFirst, Path.Combine(dirSecond, "notexist"), true, true, true, true));

            TestUtil.IsEq(null, FormSortFiles.FillFromUI(SortFilesAction.SearchDuplicates, "", "",
                                                         dirFirst + Utils.Sep, dirSecond, true, true, true, true));

            TestUtil.IsEq(null, FormSortFiles.FillFromUI(SortFilesAction.SearchDuplicates, "", "",
                                                         dirFirst, dirSecond + Utils.Sep, true, true, true, true));

            TestUtil.IsEq(null, FormSortFiles.FillFromUI(SortFilesAction.SearchDuplicates, "", "",
                                                         dirFirst, dirFirst, true, true, true, true));

            Directory.CreateDirectory(Path.Combine(dirFirst, "sub"));
            TestUtil.IsEq(null, FormSortFiles.FillFromUI(SortFilesAction.SearchDuplicates, "", "",
                                                         dirFirst, Path.Combine(dirFirst, "sub"), true, true, true, true));

            // valid for dest to be empty if action is FindDupeFilesInOneDir
            TestUtil.IsTrue(
                FormSortFiles.FillFromUI(SortFilesAction.SearchDuplicatesInOneDir, "", "",
                                         dirFirst, "", true, false, true, true) != null);
        }
        static void TestMethod_SoftDeleteDefaultDir()
        {
            var fakeFile   = PathSep("C:/dirtest/test.doc");
            var deleteDir  = Utils.GetSoftDeleteDirectory(fakeFile);
            var deleteDest = Utils.GetSoftDeleteDestination(fakeFile);

            TestUtil.IsTrue(deleteDest.StartsWith(deleteDir +
                                                  Utils.Sep + "di_test.doc", StringComparison.Ordinal));
        }
 static void TestMethod_UtilsIsDigits()
 {
     TestUtil.IsTrue(!Utils.IsDigits(null));
     TestUtil.IsTrue(!Utils.IsDigits(""));
     TestUtil.IsTrue(Utils.IsDigits("0"));
     TestUtil.IsTrue(Utils.IsDigits("0123"));
     TestUtil.IsTrue(Utils.IsDigits("456789"));
     TestUtil.IsTrue(!Utils.IsDigits("456789a"));
     TestUtil.IsTrue(!Utils.IsDigits("a456789a"));
 }
 static void TestMethod_LooksLikePath()
 {
     TestUtil.IsTrue(!Utils.LooksLikePath(""));
     TestUtil.IsTrue(!Utils.LooksLikePath("/"));
     TestUtil.IsTrue(!Utils.LooksLikePath("\\"));
     TestUtil.IsTrue(!Utils.LooksLikePath("C:"));
     TestUtil.IsTrue(Utils.LooksLikePath("C:\\"));
     TestUtil.IsTrue(Utils.LooksLikePath("C:\\a\\b\\c"));
     TestUtil.IsTrue(Utils.LooksLikePath("\\test"));
     TestUtil.IsTrue(Utils.LooksLikePath("\\test\\a\\b\\c"));
 }
 static void TestMethod_UtilsArePathsDistinct()
 {
     TestUtil.IsTrue(!Utils.ArePathsDistinct("", ""));
     TestUtil.IsTrue(!Utils.ArePathsDistinct("a", "a"));
     TestUtil.IsTrue(!Utils.ArePathsDistinct(@"C:\A", @"C:\A"));
     TestUtil.IsTrue(!Utils.ArePathsDistinct(@"C:\A", @"C:\a"));
     TestUtil.IsTrue(!Utils.ArePathsDistinct(@"C:\A\subdir", @"C:\A"));
     TestUtil.IsTrue(!Utils.ArePathsDistinct(@"C:\A", @"C:\A\subdir"));
     TestUtil.IsTrue(Utils.ArePathsDistinct(@"C:\A", @"C:\AA"));
     TestUtil.IsTrue(Utils.ArePathsDistinct(@"C:\abc", @"C:\ABCDE"));
 }
예제 #6
0
        // use reflection to call all methods that start with TestMethod_
        public static void CallAllTestMethods(Type type, object[] arParams)
        {
            MethodInfo[] methodInfos = type.GetMethods(
                BindingFlags.Static | BindingFlags.NonPublic);
            var sortedMethods = methodInfos.OrderBy(item => item.Name);

            foreach (MethodInfo methodInfo in sortedMethods)
            {
                if (methodInfo.Name.StartsWith("TestMethod_", StringComparison.InvariantCulture))
                {
                    TestUtil.IsTrue(methodInfo.GetParameters().Length == 0);
                    methodInfo.Invoke(null, arParams);
                }
            }
        }
        static void TestMethod_IsExtensionInList()
        {
            var exts = new string[] { ".jpg", ".png" };

            TestUtil.IsTrue(!FilenameUtils.IsExtensionInList("", exts));
            TestUtil.IsTrue(!FilenameUtils.IsExtensionInList("png", exts));
            TestUtil.IsTrue(!FilenameUtils.IsExtensionInList("a.bmp", exts));
            TestUtil.IsTrue(FilenameUtils.IsExtensionInList("a.png", exts));
            TestUtil.IsTrue(FilenameUtils.IsExtensionInList("a.PNG", exts));
            TestUtil.IsTrue(FilenameUtils.IsExtensionInList("a.jpg", exts));
            TestUtil.IsTrue(FilenameUtils.IsExtensionInList("a.bmp.jpg", exts));
            TestUtil.IsTrue(FilenameUtils.IsExt("a.png", ".png"));
            TestUtil.IsTrue(FilenameUtils.IsExt("a.PNG", ".png"));
            TestUtil.IsTrue(!FilenameUtils.IsExt("apng", ".png"));
            TestUtil.IsTrue(!FilenameUtils.IsExt("a.png", ".jpg"));
        }
예제 #8
0
        static void TestMethod_ValidateGoodFilesSettings()
        {
            var dirFirst  = TestUtil.GetTestSubDirectory("first");
            var dirSecond = TestUtil.GetTestSubDirectory("second");
            var settings  = FormSortFiles.FillFromUI(SortFilesAction.SearchDifferences, "", "",
                                                     dirFirst, dirSecond, true, true, false, false);

            TestUtil.IsEq(true, settings.AllowFiletimesDifferForFAT);
            TestUtil.IsEq(true, settings.AllowFiletimesDifferForDST);
            TestUtil.IsEq(dirSecond, settings.RightDirectory);
            TestUtil.IsTrue(Directory.Exists(Path.GetDirectoryName(settings.LogFile)));
            TestUtil.IsEq(false, settings.Mirror);
            TestUtil.IsEq(false, settings.PreviewOnly);
            TestUtil.IsEq(false, settings.SearchDuplicatesCanUseFiletimes);
            TestUtil.IsStringArrayEq(null, settings.SkipDirectories);
            TestUtil.IsStringArrayEq(null, settings.SkipFiles);
            TestUtil.IsEq(dirFirst, settings.LeftDirectory);

            settings = FormSortFiles.FillFromUI(
                SortFilesAction.SearchDifferences, "a", "a\nb b\n\nc\n\n ",
                dirSecond, dirFirst, false, false, true, true);

            TestUtil.IsEq(false, settings.AllowFiletimesDifferForFAT);
            TestUtil.IsEq(false, settings.AllowFiletimesDifferForDST);
            TestUtil.IsEq(dirFirst, settings.RightDirectory);
            TestUtil.IsTrue(Directory.Exists(Path.GetDirectoryName(settings.LogFile)));
            TestUtil.IsEq(true, settings.Mirror);
            TestUtil.IsEq(true, settings.PreviewOnly);
            TestUtil.IsEq(false, settings.SearchDuplicatesCanUseFiletimes);
            TestUtil.IsStringArrayEq("a", settings.SkipDirectories);
            TestUtil.IsStringArrayEq("a|b b|c", settings.SkipFiles);
            TestUtil.IsEq(dirSecond, settings.LeftDirectory);

            settings = FormSortFiles.FillFromUI(SortFilesAction.SearchDuplicatesInOneDir, "", "",
                                                dirFirst, dirSecond, false, false, true, true);

            TestUtil.IsEq(dirFirst, settings.LeftDirectory);
            TestUtil.IsEq(dirFirst, settings.RightDirectory);
            TestUtil.IsEq(false, settings.SearchDuplicatesCanUseFiletimes);

            settings = FormSortFiles.FillFromUI(SortFilesAction.SearchDuplicates, "", "",
                                                dirFirst, dirSecond, true, true, false, false);
            TestUtil.IsEq(true, settings.AllowFiletimesDifferForFAT);
            TestUtil.IsEq(true, settings.AllowFiletimesDifferForDST);
            TestUtil.IsEq(true, settings.SearchDuplicatesCanUseFiletimes);
        }
예제 #9
0
        static void TestMethod_TestFileOpFileSetWritetime()
        {
            var dir    = TestUtil.GetTestSubDirectory("right_fndmved", true);
            var now    = DateTime.UtcNow;
            var future = now.AddMinutes(25);
            var past   = now.AddMinutes(-25);

            // re-use existing logic for fuzzy time comparison,
            // in case, say, we're running this test on a FAT drive with imprecise times.
            var settingsForTimeComparison = new SortFilesSettings();

            settingsForTimeComparison.AllowFiletimesDifferForDST = false;
            settingsForTimeComparison.AllowFiletimesDifferForFAT = true;

            // set write-time to be the future, and undo.
            var path = dir + Utils.Sep + "testIntoFuture.txt";

            File.WriteAllText(path, "testIntoFuture");
            File.SetLastWriteTimeUtc(path, now);
            var op = new FileOpFileSetWritetime(path, now, future);

            op.Do();
            TestUtil.IsTrue(SortFilesSearchDifferences.AreTimesEqual(future,
                                                                     File.GetLastWriteTimeUtc(path), settingsForTimeComparison));
            op.Undo();
            TestUtil.IsTrue(SortFilesSearchDifferences.AreTimesEqual(now,
                                                                     File.GetLastWriteTimeUtc(path), settingsForTimeComparison));

            path = dir + Utils.Sep + "testIntoPast.txt";
            File.WriteAllText(path, "testIntoPast");
            File.SetLastWriteTimeUtc(path, now);
            op = new FileOpFileSetWritetime(path, now, past);
            op.Do();
            TestUtil.IsTrue(SortFilesSearchDifferences.AreTimesEqual(past,
                                                                     File.GetLastWriteTimeUtc(path), settingsForTimeComparison));
            op.Undo();
            TestUtil.IsTrue(SortFilesSearchDifferences.AreTimesEqual(now,
                                                                     File.GetLastWriteTimeUtc(path), settingsForTimeComparison));
        }
        static void TestMethod_UtilsSameExceptExtension()
        {
            TestUtil.IsTrue(FilenameUtils.SameExceptExtension(
                                "test6.jpg", "test6.jpg"));
            TestUtil.IsTrue(FilenameUtils.SameExceptExtension(
                                "test6.jpg", "test6.png"));
            TestUtil.IsTrue(FilenameUtils.SameExceptExtension(
                                "test6.jpg", "test6.BMP"));
            TestUtil.IsTrue(!FilenameUtils.SameExceptExtension(
                                "test6.jpg", "test6.jpg.jpg"));
            TestUtil.IsTrue(!FilenameUtils.SameExceptExtension(
                                "test6a.jpg", "test6.jpg"));
            TestUtil.IsTrue(FilenameUtils.SameExceptExtension(
                                "aa.jpg.test6.jpg", "aa.jpg.test6.bmp"));
            TestUtil.IsTrue(!FilenameUtils.SameExceptExtension(
                                "aa.jpg.test6.jpg", "aa.bmp.test6.jpg"));

            TestUtil.IsTrue(FilenameUtils.SameExceptExtension(
                                PathSep("a/test6.jpg"), PathSep("a/test6.jpg")));
            TestUtil.IsTrue(!FilenameUtils.SameExceptExtension(
                                PathSep("a/test6.jpg"), PathSep("b/test6.jpg")));
        }
예제 #11
0
        static void WriteFiles(string fileLeft, string fileRight,
                               DateTime baseTime, ModifiedTimes m, Content c)
        {
            var addTime       = (m == ModifiedTimes.MTime) ? 1 : 0;
            var contentsLeft  = fileLeft;
            var contentsRight = contentsLeft;

            if (c == Content.AltText)
            {
                // replace first char with *
                contentsRight = "*" + contentsRight.Substring(1);
            }
            else if (c == Content.AddText)
            {
                contentsRight += "***";
            }

            TestUtil.IsTrue(!File.Exists(fileLeft) && !File.Exists(fileRight));
            File.WriteAllText(fileLeft, contentsLeft);
            File.SetLastWriteTimeUtc(fileLeft, baseTime);
            File.WriteAllText(fileRight, contentsRight);
            File.SetLastWriteTimeUtc(fileRight, baseTime.AddHours(addTime));
        }
예제 #12
0
        static void TestMethod_TestSortFilesListOperations()
        {
            // create settings object
            var settings = new SortFilesSettings();
            var left     = TestUtil.GetTestSubDirectory("left_sortfileslist");
            var right    = TestUtil.GetTestSubDirectory("right_sortfileslist");

            settings.LeftDirectory  = left;
            settings.RightDirectory = right;

            // first, set up test files
            File.WriteAllText(left + Utils.Sep + "onlyleft.txt", "onlyl");
            File.WriteAllText(left + Utils.Sep + "changed1.txt", "a");
            File.WriteAllText(left + Utils.Sep + "changed2.txt", "123");
            File.WriteAllText(left + Utils.Sep + "same.txt", "s");
            File.WriteAllText(right + Utils.Sep + "onlyright.txt", "onlyr");
            File.WriteAllText(right + Utils.Sep + "changed1.txt", "abc");
            File.WriteAllText(right + Utils.Sep + "changed2.txt", "124");
            File.WriteAllText(right + Utils.Sep + "same.txt", "s");
            Action checkFileContents = () =>
            {
                TestUtil.IsEq("onlyl", File.ReadAllText(Path.Combine(left, "onlyleft.txt")));
                TestUtil.IsEq("a", File.ReadAllText(Path.Combine(left, "changed1.txt")));
                TestUtil.IsEq("123", File.ReadAllText(Path.Combine(left, "changed2.txt")));
                TestUtil.IsEq("onlyr", File.ReadAllText(Path.Combine(right, "onlyright.txt")));
                TestUtil.IsEq("abc", File.ReadAllText(Path.Combine(right, "changed1.txt")));
                TestUtil.IsEq("124", File.ReadAllText(Path.Combine(right, "changed2.txt")));
            };

            // tweak last write times to ensure files on right look different
            File.SetLastWriteTime(right + Utils.Sep + "changed1.txt",
                                  File.GetLastWriteTime(right + Utils.Sep + "changed1.txt").AddDays(1));
            File.SetLastWriteTime(right + Utils.Sep + "changed2.txt",
                                  File.GetLastWriteTime(right + Utils.Sep + "changed2.txt").AddDays(1));
            File.SetLastWriteTime(right + Utils.Sep + "same.txt",
                                  File.GetLastWriteTime(left + Utils.Sep + "same.txt"));

            // create form and run searchdifferences
            var form = new FormSortFilesList(
                SortFilesAction.SearchDifferences, settings, "", allActionsSynchronous: true);
            ListView listView;

            form.GetTestHooks(out listView, out List <FileComparisonResult> mockSelection,
                              out UndoStack <List <IUndoableFileOp> > undoStack);
            form.RunSortFilesAction();

            // simulate column-header click to sort by path
            form.listView_ColumnClick(null, new ColumnClickEventArgs(2));

            // verify listview contents
            var items = listView.Items.Cast <FileComparisonResult>().ToArray();

            TestUtil.IsEq(4, items.Length);
            TestUtil.IsEq(Utils.Sep + "changed1.txt", items[0].FileInfoLeft.Filename);
            TestUtil.IsEq(null, items[0].FileInfoLeft.ContentHash);
            TestUtil.IsEq(1L, items[0].FileInfoLeft.FileSize);
            TestUtil.IsEq(Utils.Sep + "changed1.txt", items[0].FileInfoRight.Filename);
            TestUtil.IsEq(null, items[0].FileInfoRight.ContentHash);
            TestUtil.IsEq(3L, items[0].FileInfoRight.FileSize);
            TestUtil.IsEq(Utils.Sep + "changed2.txt", items[1].FileInfoLeft.Filename);
            TestUtil.IsEq(null, items[1].FileInfoLeft.ContentHash);
            TestUtil.IsEq(3L, items[1].FileInfoLeft.FileSize);
            TestUtil.IsEq(Utils.Sep + "changed2.txt", items[1].FileInfoRight.Filename);
            TestUtil.IsEq(null, items[1].FileInfoRight.ContentHash);
            TestUtil.IsEq(3L, items[1].FileInfoRight.FileSize);
            TestUtil.IsEq(Utils.Sep + "onlyleft.txt", items[2].FileInfoLeft.Filename);
            TestUtil.IsEq(null, items[2].FileInfoLeft.ContentHash);
            TestUtil.IsEq(5L, items[2].FileInfoLeft.FileSize);
            TestUtil.IsEq(null, items[2].FileInfoRight);
            TestUtil.IsEq(Utils.Sep + "onlyright.txt", items[3].FileInfoRight.Filename);
            TestUtil.IsEq(null, items[3].FileInfoRight.ContentHash);
            TestUtil.IsEq(5L, items[3].FileInfoRight.FileSize);
            TestUtil.IsEq(null, items[3].FileInfoLeft);

            // test CheckSelectedItemsSameType
            mockSelection.Clear();
            TestUtil.IsEq(false, form.CheckSelectedItemsSameType());
            mockSelection.Add((FileComparisonResult)listView.Items[0]);
            TestUtil.IsEq(true, form.CheckSelectedItemsSameType());
            mockSelection.Add((FileComparisonResult)listView.Items[1]);
            TestUtil.IsEq(true, form.CheckSelectedItemsSameType());
            mockSelection.Add((FileComparisonResult)listView.Items[2]);
            TestUtil.IsEq(false, form.CheckSelectedItemsSameType());
            mockSelection.Clear();
            TestUtil.IsEq(false, form.CheckSelectedItemsSameType());
            mockSelection.Add((FileComparisonResult)listView.Items[1]);
            TestUtil.IsEq(true, form.CheckSelectedItemsSameType());
            mockSelection.Add((FileComparisonResult)listView.Items[2]);
            TestUtil.IsEq(false, form.CheckSelectedItemsSameType());

            // delete all on left
            checkFileContents();
            SelectFirstItems(mockSelection, listView, items.Length);
            form.OnClickDeleteFile(left: true, needConfirm: false);

            // see if undo was set as expected
            var lastUndo = undoStack.PeekUndo();

            TestUtil.IsEq(3, lastUndo.Count);
            TestUtil.IsEq(Path.Combine(left, "changed1.txt"), lastUndo[0].Source);
            TestUtil.IsEq(Path.Combine(left, "changed2.txt"), lastUndo[1].Source);
            TestUtil.IsEq(Path.Combine(left, "onlyleft.txt"), lastUndo[2].Source);

            // test file presence
            TestUtil.IsTrue(!File.Exists(Path.Combine(left, "changed1.txt")));
            TestUtil.IsTrue(!File.Exists(Path.Combine(left, "changed2.txt")));
            TestUtil.IsTrue(!File.Exists(Path.Combine(left, "onlyleft.txt")));
            TestUtil.IsTrue(File.Exists(Path.Combine(right, "changed1.txt")));
            TestUtil.IsTrue(File.Exists(Path.Combine(right, "changed2.txt")));
            TestUtil.IsTrue(File.Exists(Path.Combine(right, "onlyright.txt")));

            // run undo
            form.OnUndoClick(needConfirm: false);
            TestUtil.IsEq(null, undoStack.PeekUndo());
            checkFileContents();

            // delete all on right
            SelectFirstItems(mockSelection, listView, items.Length);
            form.OnClickDeleteFile(left: false, needConfirm: false);

            // see if undo was set as expected
            lastUndo = undoStack.PeekUndo();
            TestUtil.IsEq(3, lastUndo.Count);
            TestUtil.IsEq(Path.Combine(right, "changed1.txt"), lastUndo[0].Source);
            TestUtil.IsEq(Path.Combine(right, "changed2.txt"), lastUndo[1].Source);
            TestUtil.IsEq(Path.Combine(right, "onlyright.txt"), lastUndo[2].Source);

            // test file presence
            TestUtil.IsTrue(File.Exists(Path.Combine(left, "changed1.txt")));
            TestUtil.IsTrue(File.Exists(Path.Combine(left, "changed2.txt")));
            TestUtil.IsTrue(File.Exists(Path.Combine(left, "onlyleft.txt")));
            TestUtil.IsTrue(!File.Exists(Path.Combine(right, "changed1.txt")));
            TestUtil.IsTrue(!File.Exists(Path.Combine(right, "changed2.txt")));
            TestUtil.IsTrue(!File.Exists(Path.Combine(right, "onlyright.txt")));

            // run undo
            form.OnUndoClick(needConfirm: false);
            TestUtil.IsEq(null, undoStack.PeekUndo());
            checkFileContents();

            // copy all left to right
            SelectFirstItems(mockSelection, listView, items.Length);
            form.OnClickCopyFile(left: true, needConfirm: false);

            // see if undo was set as expected
            lastUndo = undoStack.PeekUndo();
            TestUtil.IsEq(5, lastUndo.Count);
            TestUtil.IsTrue(lastUndo[0] is FileOpFileMove);
            TestUtil.IsEq(Path.Combine(right, "changed1.txt"), lastUndo[0].Source);
            TestUtil.IsTrue(lastUndo[1] is FileOpFileCopy);
            TestUtil.IsEq(Path.Combine(left, "changed1.txt"), lastUndo[1].Source);
            TestUtil.IsEq(Path.Combine(right, "changed1.txt"), lastUndo[1].Dest);
            TestUtil.IsTrue(lastUndo[2] is FileOpFileMove);
            TestUtil.IsEq(Path.Combine(right, "changed2.txt"), lastUndo[2].Source);
            TestUtil.IsTrue(lastUndo[3] is FileOpFileCopy);
            TestUtil.IsEq(Path.Combine(left, "changed2.txt"), lastUndo[3].Source);
            TestUtil.IsEq(Path.Combine(right, "changed2.txt"), lastUndo[3].Dest);
            TestUtil.IsTrue(lastUndo[4] is FileOpFileCopy);
            TestUtil.IsEq(Path.Combine(left, "onlyleft.txt"), lastUndo[4].Source);
            TestUtil.IsEq(Path.Combine(right, "onlyleft.txt"), lastUndo[4].Dest);

            // test file contents
            TestUtil.IsEq("onlyl", File.ReadAllText(Path.Combine(left, "onlyleft.txt")));
            TestUtil.IsEq("a", File.ReadAllText(Path.Combine(left, "changed1.txt")));
            TestUtil.IsEq("123", File.ReadAllText(Path.Combine(left, "changed2.txt")));
            TestUtil.IsEq("onlyl", File.ReadAllText(Path.Combine(right, "onlyleft.txt")));
            TestUtil.IsEq("onlyr", File.ReadAllText(Path.Combine(right, "onlyright.txt")));
            TestUtil.IsEq("a", File.ReadAllText(Path.Combine(right, "changed1.txt")));
            TestUtil.IsEq("123", File.ReadAllText(Path.Combine(right, "changed2.txt")));

            // run undo
            form.OnUndoClick(needConfirm: false);
            TestUtil.IsEq(null, undoStack.PeekUndo());
            TestUtil.IsTrue(!File.Exists(Path.Combine(right, "onlyleft.txt")));
            checkFileContents();

            // copy all right to left
            SelectFirstItems(mockSelection, listView, items.Length);
            form.OnClickCopyFile(left: false, needConfirm: false);

            // see if undo was set as expected
            lastUndo = undoStack.PeekUndo();
            TestUtil.IsEq(5, lastUndo.Count);
            TestUtil.IsTrue(lastUndo[0] is FileOpFileMove);
            TestUtil.IsEq(Path.Combine(left, "changed1.txt"), lastUndo[0].Source);
            TestUtil.IsTrue(lastUndo[1] is FileOpFileCopy);
            TestUtil.IsEq(Path.Combine(right, "changed1.txt"), lastUndo[1].Source);
            TestUtil.IsEq(Path.Combine(left, "changed1.txt"), lastUndo[1].Dest);
            TestUtil.IsTrue(lastUndo[2] is FileOpFileMove);
            TestUtil.IsEq(Path.Combine(left, "changed2.txt"), lastUndo[2].Source);
            TestUtil.IsTrue(lastUndo[3] is FileOpFileCopy);
            TestUtil.IsEq(Path.Combine(right, "changed2.txt"), lastUndo[3].Source);
            TestUtil.IsEq(Path.Combine(left, "changed2.txt"), lastUndo[3].Dest);
            TestUtil.IsTrue(lastUndo[4] is FileOpFileCopy);
            TestUtil.IsEq(Path.Combine(right, "onlyright.txt"), lastUndo[4].Source);
            TestUtil.IsEq(Path.Combine(left, "onlyright.txt"), lastUndo[4].Dest);

            // test file contents
            TestUtil.IsEq("onlyl", File.ReadAllText(Path.Combine(left, "onlyleft.txt")));
            TestUtil.IsEq("onlyr", File.ReadAllText(Path.Combine(left, "onlyright.txt")));
            TestUtil.IsEq("abc", File.ReadAllText(Path.Combine(left, "changed1.txt")));
            TestUtil.IsEq("124", File.ReadAllText(Path.Combine(left, "changed2.txt")));
            TestUtil.IsEq("onlyr", File.ReadAllText(Path.Combine(right, "onlyright.txt")));
            TestUtil.IsEq("abc", File.ReadAllText(Path.Combine(right, "changed1.txt")));
            TestUtil.IsEq("124", File.ReadAllText(Path.Combine(right, "changed2.txt")));

            // run undo
            form.OnUndoClick(needConfirm: false);
            TestUtil.IsEq(null, undoStack.PeekUndo());
            TestUtil.IsTrue(!File.Exists(Path.Combine(left, "onlyright.txt")));
            checkFileContents();
            form.Dispose();
        }