ソースを参照

部分文件夹相关测试

龙腾猫跃 5 ヶ月 前
親
コミット
5edff6c73f
3 ファイル変更、48 行追加、143 行削除
  1. 18 2
      Tests/TestUtils.cs
  2. 29 140
      Tests/Utils/DirectoryUtilsTest.cs
  3. 1 1
      Tests/Utils/PathUtilsTest.cs

+ 18 - 2
Tests/TestUtils.cs

@@ -1,17 +1,33 @@
 namespace MeloongCore.Tests;
 
+/// <summary>
+/// 所有测试的基类。
+/// 会初始化 MeloongCore 并重定向日志输出。
+/// </summary>
+public abstract class TestBase {
+
+    public TestBase() {
+        MeloongCore.Main.Init(new TestLogger());
+    }
+    private class TestLogger : BaseLogger {
+        public override void HandleBehavior(string? rawMessage, string formattedMessage, LogBehavior behavior, Exception? ex)
+            => TestContext.Current!.OutputWriter.WriteLine(formattedMessage);
+    }
+
+}
+
 /// <summary>
 /// 用于带文件测试的基类。
 /// 会在极端路径下创建测试用的临时文件夹。
 /// </summary>
-public abstract class TestWithFolder {
+public abstract class TestWithFolder : TestBase {
 
     /// <summary>
     /// 测试用的临时文件夹路径。
     /// 这是一个包含特殊字符的长路径,不以 \\?\ 开头,以 \ 结尾。
     /// </summary>
     public readonly string tempFolder;
-    public TestWithFolder() {
+    public TestWithFolder() : base() {
         tempFolder = Path.Combine(
             Path.GetTempPath(), "PCL", "Tests",
             $"{GetType().Name}-{Guid.NewGuid()}",

+ 29 - 140
Tests/Utils/DirectoryUtilsTest.cs

@@ -1,101 +1,52 @@
+using TUnit.Assertions.Extensions;
+
 namespace MeloongCore.Tests;
 public class DirectoryUtilsTest : TestWithFolder {
 
-    #region 复制
-
-    [Test]
-    public async Task 复制_自身到自身() {
-        var src = Path.Combine(tempFolder, "SelfCopy");
-        DirectoryUtils.Create(src);
-        FileUtils.Write(Path.Combine(src, "file.txt"), "content");
-
-        DirectoryUtils.Copy(src, src);
-
-        await Assert.That(DirectoryUtils.Exists(src)).IsTrue();
-        await Assert.That(FileUtils.Exists(Path.Combine(src, "file.txt"))).IsTrue();
-    }
-
-    [Test]
-    public async Task 复制_大小写不同() {
-        // 建立源文件夹(全大写)
-        var src = Path.Combine(tempFolder, "CASECOPY");
-        DirectoryUtils.Create(src);
-        FileUtils.Write(Path.Combine(src, "file.txt"), "content");
-
-        // 目标路径仅大小写不同,Copy 应等效于重命名
-        var dest = Path.Combine(tempFolder, "casecopy");
-        DirectoryUtils.Copy(src, dest);
-
-        await Assert.That(FileUtils.Exists(Path.Combine(dest, "file.txt"))).IsTrue();
-    }
+    #region 剪切、复制
 
     [Test]
-    public async Task 复制_不同路径() {
-        var src = Path.Combine(tempFolder, "CopySource");
+    [Arguments("Source", "目标文件夹")]
+    [Arguments("Source", "Source")]
+    [Arguments("Source", "soURCE")]
+    public async Task 复制(string sourceName, string destName) {
+        var src = Path.Combine(tempFolder, sourceName);
         DirectoryUtils.Create(Path.Combine(src, "sub"));
         FileUtils.Write(Path.Combine(src, "a.txt"), "aaa");
-        FileUtils.Write(Path.Combine(src, "sub", "b.txt"), "bbb");
+        FileUtils.Write(Path.Combine(src, "sub", "b file.txt"), "bbb");
+        var dest = Path.Combine(tempFolder, destName);
 
-        var dest = Path.Combine(tempFolder, "CopyDest");
         DirectoryUtils.Copy(src, dest);
 
-        // 源文件夹和文件仍存在
-        await Assert.That(DirectoryUtils.Exists(src)).IsTrue();
-        await Assert.That(FileUtils.Exists(Path.Combine(src, "a.txt"))).IsTrue();
-        // 目标文件夹的文件已正确复制
-        await Assert.That(FileUtils.Exists(Path.Combine(dest, "a.txt"))).IsTrue();
-        await Assert.That(FileUtils.Exists(Path.Combine(dest, "sub", "b.txt"))).IsTrue();
+        await Assert.That(FileUtils.ReadAsString(Path.Combine(src, "a.txt"))).IsEqualTo("aaa");
         await Assert.That(FileUtils.ReadAsString(Path.Combine(dest, "a.txt"))).IsEqualTo("aaa");
+        await Assert.That(FileUtils.ReadAsString(Path.Combine(src, "sub", "b file.txt"))).IsEqualTo("bbb");
+        await Assert.That(FileUtils.ReadAsString(Path.Combine(dest, "sub", "b file.txt"))).IsEqualTo("bbb");
+        await Assert.That(DirectoryUtils.GetDirectories(Path.Combine(tempFolder))).Contains(dest); // 目标文件夹名
     }
 
-    #endregion
-
-    #region 剪切
-
     [Test]
-    public async Task 剪切_自身到自身() {
-        var src = Path.Combine(tempFolder, "SelfMove");
-        DirectoryUtils.Create(src);
-        FileUtils.Write(Path.Combine(src, "file.txt"), "content");
-
-        DirectoryUtils.Move(src, src);
-
-        await Assert.That(DirectoryUtils.Exists(src)).IsTrue();
-        await Assert.That(FileUtils.Exists(Path.Combine(src, "file.txt"))).IsTrue();
-    }
-
-    [Test]
-    public async Task 剪切_大小写不同() {
-        var src = Path.Combine(tempFolder, "CASEMOVE");
-        DirectoryUtils.Create(src);
-        FileUtils.Write(Path.Combine(src, "file.txt"), "content");
-
-        // 目标路径仅大小写不同,Move 应借助临时目录完成重命名
-        var dest = Path.Combine(tempFolder, "casemove");
-        DirectoryUtils.Move(src, dest);
-
-        await Assert.That(FileUtils.Exists(Path.Combine(dest, "file.txt"))).IsTrue();
-    }
-
-    [Test]
-    public async Task 剪切_同一磁盘() {
-        var src = Path.Combine(tempFolder, "MoveSrc");
+    [Arguments("Source", "目标文件夹")]
+    [Arguments("Source", "Source")]
+    [Arguments("Source", "soURCE")]
+    public async Task 剪切(string sourceName, string destName) {
+        var src = Path.Combine(tempFolder, sourceName);
         DirectoryUtils.Create(Path.Combine(src, "sub"));
         FileUtils.Write(Path.Combine(src, "a.txt"), "aaa");
-        FileUtils.Write(Path.Combine(src, "sub", "b.txt"), "bbb");
+        FileUtils.Write(Path.Combine(src, "sub", "b file.txt"), "bbb");
+        var dest = Path.Combine(tempFolder, destName);
 
-        var dest = Path.Combine(tempFolder, "MoveDest");
         DirectoryUtils.Move(src, dest);
 
-        await Assert.That(DirectoryUtils.Exists(src)).IsFalse();
-        await Assert.That(FileUtils.Exists(Path.Combine(dest, "a.txt"))).IsTrue();
-        await Assert.That(FileUtils.Exists(Path.Combine(dest, "sub", "b.txt"))).IsTrue();
         await Assert.That(FileUtils.ReadAsString(Path.Combine(dest, "a.txt"))).IsEqualTo("aaa");
+        await Assert.That(FileUtils.ReadAsString(Path.Combine(dest, "sub", "b file.txt"))).IsEqualTo("bbb");
+        if (src != dest) await Assert.That(DirectoryUtils.GetDirectories(Path.Combine(tempFolder))).DoesNotContain(src);
+        await Assert.That(DirectoryUtils.GetDirectories(Path.Combine(tempFolder))).Contains(dest); // 目标文件夹名
     }
 
     [Test]
     public async Task 剪切_不同磁盘() {
-        // 找到两个不同的就绪固定磁盘;若只有一个则跳过此分支
+        // 寻找两个磁盘
         var drives = DriveInfo.GetDrives()
             .Where(d => d.IsReady && d.DriveType == DriveType.Fixed)
             .ToArray();
@@ -109,12 +60,13 @@ public class DirectoryUtilsTest : TestWithFolder {
         try {
             DirectoryUtils.Create(src);
             FileUtils.Write(Path.Combine(src, "a.txt"), "aaa");
+            FileUtils.Write(Path.Combine(src, "sub", "b file.txt"), "bbb");
 
             DirectoryUtils.Move(src, dest);
 
             await Assert.That(DirectoryUtils.Exists(src)).IsFalse();
-            await Assert.That(FileUtils.Exists(Path.Combine(dest, "a.txt"))).IsTrue();
             await Assert.That(FileUtils.ReadAsString(Path.Combine(dest, "a.txt"))).IsEqualTo("aaa");
+            await Assert.That(FileUtils.ReadAsString(Path.Combine(dest, "sub", "b file.txt"))).IsEqualTo("bbb");
         } finally {
             DirectoryUtils.Delete(srcRoot);
             DirectoryUtils.Delete(destRoot);
@@ -122,71 +74,8 @@ public class DirectoryUtilsTest : TestWithFolder {
     }
 
     [Test]
-    public void 剪切_CurrentFolder_安全检查() {
-        var dest = Path.Combine(tempFolder, "SafetyCheckDest");
-        Assert.Throws<UnauthorizedAccessException>(() => DirectoryUtils.Move(PathUtils.CurrentFolder, dest));
-    }
-
-    #endregion
-
-    #region 删除
-
-    [Test]
-    public async Task 删除_子文件夹中带孤立符号链接() {
-        // 创建一个目标文件夹,供符号链接指向
-        var target = Path.Combine(tempFolder, "SymlinkTarget");
-        DirectoryUtils.Create(target);
-
-        // 创建父文件夹及其子文件夹
-        var parent = Path.Combine(tempFolder, "SymlinkParent");
-        var child = Path.Combine(parent, "child");
-        DirectoryUtils.Create(child);
-
-        // 在子文件夹中建立指向目标的目录链接;若无权限则跳过
-        var link = Path.Combine(child, "link");
-        if (!TryCreateDirectoryLink(link, target)) return;
-        await Assert.That(DirectoryUtils.Exists(link)).IsTrue();
-
-        // 删除目标,使链接成为孤立链接
-        Directory.Delete(PathUtils.ForApi(target));
-        await Assert.That(DirectoryUtils.Exists(target)).IsFalse();
-
-        // 删除含有孤立链接的父文件夹,不应抛出异常
-        DirectoryUtils.Delete(parent);
-        await Assert.That(DirectoryUtils.Exists(parent)).IsFalse();
-    }
-
-    /// <summary>
-    /// 创建指向目标文件夹的目录链接(通过 P/Invoke,不经过 Shell,避免路径中特殊字符的问题)。
-    /// Windows 下使用目录符号链接(需开发者模式);Linux/macOS 下使用符号链接。
-    /// 若当前环境无权创建符号链接,则跳过测试(返回 <see langword="false"/>)。
-    /// </summary>
-    private static bool TryCreateDirectoryLink(string link, string target) {
-        if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
-            // SYMBOLIC_LINK_FLAG_DIRECTORY (1) | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE (2)
-            bool ok = NativeMethods.CreateSymbolicLink(link, target, 3u);
-            if (!ok) {
-                int err = Marshal.GetLastWin32Error();
-                // ERROR_PRIVILEGE_NOT_HELD (1314) 或 ERROR_ACCESS_DENIED (5):无权限,跳过
-                if (err == 1314 || err == 5) return false;
-                throw new InvalidOperationException($"CreateSymbolicLink 失败,Win32 错误码:{err}");
-            }
-            return true;
-        } else {
-            int ret = NativeMethods.Symlink(target, link);
-            if (ret != 0) throw new InvalidOperationException($"symlink 失败,errno:{Marshal.GetLastWin32Error()}");
-            return true;
-        }
-    }
-
-    private static class NativeMethods {
-        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "CreateSymbolicLinkW")]
-        [return: MarshalAs(UnmanagedType.I1)]
-        internal static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, uint dwFlags);
-
-        [DllImport("libc", SetLastError = true, EntryPoint = "symlink")]
-        internal static extern int Symlink(string target, string linkpath);
-    }
+    public void 剪切_安全检查() 
+        => Assert.Throws<UnauthorizedAccessException>(() => DirectoryUtils.Move(PathUtils.CurrentFolder, Path.Combine(tempFolder, "SafetyCheckDest")));
 
     #endregion
 

+ 1 - 1
Tests/Utils/PathUtilsTest.cs

@@ -1,5 +1,5 @@
 namespace MeloongCore.Tests;
-public class PathUtilsTests {
+public class PathUtilsTests : TestBase {
 
     #region 路径处理