refactor: rename NovaDbXxx to NovaXxx across entire project
copilot-swe-agent[bot] authored at 2026-02-18 20:12:17
9.91 KiB
NewLife.NovaDb
using System;
using System.IO;
using System.Linq;
using NewLife.NovaDb.Core;
using NewLife.NovaDb.Storage;
using Xunit;

namespace XUnitTest.Storage;

public class TableFileManagerTests : IDisposable
{
    private readonly String _testPath;
    private readonly DbOptions _options;

    public TableFileManagerTests()
    {
        _testPath = Path.Combine(Path.GetTempPath(), $"NovaTest_{Guid.NewGuid()}");
        _options = new DbOptions
        {
            Path = _testPath,
            PageSize = 4096
        };

        Directory.CreateDirectory(_testPath);
    }

    public void Dispose()
    {
        if (Directory.Exists(_testPath))
        {
            Directory.Delete(_testPath, true);
        }
    }

    #region 构造函数
    [Fact]
    public void TestConstructorNullDatabasePath()
    {
        Assert.Throws<ArgumentNullException>(() => new TableFileManager(null!, "Users", _options));
    }

    [Fact]
    public void TestConstructorNullTableName()
    {
        Assert.Throws<ArgumentNullException>(() => new TableFileManager(_testPath, null!, _options));
    }

    [Fact]
    public void TestConstructorEmptyTableName()
    {
        Assert.Throws<ArgumentException>(() => new TableFileManager(_testPath, "", _options));
        Assert.Throws<ArgumentException>(() => new TableFileManager(_testPath, "  ", _options));
    }

    [Fact]
    public void TestConstructorNullOptions()
    {
        Assert.Throws<ArgumentNullException>(() => new TableFileManager(_testPath, "Users", null!));
    }

    [Fact]
    public void TestConstructorProperties()
    {
        var manager = new TableFileManager(_testPath, "Products", _options);
        Assert.Equal(_testPath, manager.DatabasePath);
        Assert.Equal("Products", manager.TableName);
    }
    #endregion

    #region 路径生成
    [Fact]
    public void TestGetDataFilePath()
    {
        var manager = new TableFileManager(_testPath, "Users", _options);

        var path1 = manager.GetDataFilePath();
        Assert.Equal(Path.Combine(_testPath, "Users.data"), path1);

        var path2 = manager.GetDataFilePath(0);
        Assert.Equal(Path.Combine(_testPath, "Users_0.data"), path2);

        var path3 = manager.GetDataFilePath(5);
        Assert.Equal(Path.Combine(_testPath, "Users_5.data"), path3);
    }

    [Fact]
    public void TestGetPrimaryIndexFilePath()
    {
        var manager = new TableFileManager(_testPath, "Orders", _options);

        var path1 = manager.GetPrimaryIndexFilePath();
        Assert.Equal(Path.Combine(_testPath, "Orders.idx"), path1);

        var path2 = manager.GetPrimaryIndexFilePath(0);
        Assert.Equal(Path.Combine(_testPath, "Orders_0.idx"), path2);
    }

    [Fact]
    public void TestGetSecondaryIndexFilePath()
    {
        var manager = new TableFileManager(_testPath, "Products", _options);

        var path1 = manager.GetSecondaryIndexFilePath("idx_name");
        Assert.Equal(Path.Combine(_testPath, "Products_idx_name.idx"), path1);

        var path2 = manager.GetSecondaryIndexFilePath("idx_category", 2);
        Assert.Equal(Path.Combine(_testPath, "Products_2_idx_category.idx"), path2);
    }

    [Fact]
    public void TestGetSecondaryIndexFilePathEmptyName()
    {
        var manager = new TableFileManager(_testPath, "Products", _options);
        Assert.Throws<ArgumentException>(() => manager.GetSecondaryIndexFilePath(""));
        Assert.Throws<ArgumentException>(() => manager.GetSecondaryIndexFilePath("  "));
    }

    [Fact]
    public void TestGetWalFilePath()
    {
        var manager = new TableFileManager(_testPath, "Logs", _options);

        var path1 = manager.GetWalFilePath();
        Assert.Equal(Path.Combine(_testPath, "Logs.wal"), path1);

        var path2 = manager.GetWalFilePath(1);
        Assert.Equal(Path.Combine(_testPath, "Logs_1.wal"), path2);
    }
    #endregion

    #region ListDataShards
    [Fact]
    public void TestListDataShards()
    {
        var manager = new TableFileManager(_testPath, "BigTable", _options);

        File.WriteAllText(manager.GetDataFilePath(0), "");
        File.WriteAllText(manager.GetDataFilePath(2), "");
        File.WriteAllText(manager.GetDataFilePath(5), "");

        var shards = manager.ListDataShards().ToList();

        Assert.Equal(3, shards.Count);
        Assert.Equal(0, shards[0]);
        Assert.Equal(2, shards[1]);
        Assert.Equal(5, shards[2]);
    }

    [Fact]
    public void TestListDataShardsEmpty()
    {
        var manager = new TableFileManager(_testPath, "EmptyTable", _options);
        var shards = manager.ListDataShards().ToList();
        Assert.Empty(shards);
    }

    [Fact]
    public void TestListDataShardsDirectoryNotExists()
    {
        var manager = new TableFileManager("/nonexistent/path", "Users", _options);
        var shards = manager.ListDataShards().ToList();
        Assert.Empty(shards);
    }
    #endregion

    #region ListSecondaryIndexes
    [Fact]
    public void TestListSecondaryIndexes()
    {
        var manager = new TableFileManager(_testPath, "Users", _options);

        // 主键索引(应被忽略,因为不含 _ 分隔的索引名)
        File.WriteAllText(manager.GetPrimaryIndexFilePath(), "");

        File.WriteAllText(manager.GetSecondaryIndexFilePath("idx_email"), "");
        File.WriteAllText(manager.GetSecondaryIndexFilePath("idx_name"), "");
        File.WriteAllText(manager.GetSecondaryIndexFilePath("idx_age", 1), "");

        var indexes = manager.ListSecondaryIndexes().ToList();

        Assert.Equal(3, indexes.Count);
        Assert.Contains("idx_age", indexes);
        Assert.Contains("idx_email", indexes);
        Assert.Contains("idx_name", indexes);
    }

    [Fact]
    public void TestListSecondaryIndexesEmpty()
    {
        var manager = new TableFileManager(_testPath, "NoIndex", _options);
        var indexes = manager.ListSecondaryIndexes().ToList();
        Assert.Empty(indexes);
    }

    [Fact]
    public void TestListSecondaryIndexesDirectoryNotExists()
    {
        var manager = new TableFileManager("/nonexistent/path", "Users", _options);
        var indexes = manager.ListSecondaryIndexes().ToList();
        Assert.Empty(indexes);
    }

    [Fact]
    public void TestListSecondaryIndexesDeduplication()
    {
        var manager = new TableFileManager(_testPath, "Multi", _options);

        // 同一个索引在不同分片存在
        File.WriteAllText(manager.GetSecondaryIndexFilePath("idx_status", 0), "");
        File.WriteAllText(manager.GetSecondaryIndexFilePath("idx_status", 1), "");
        File.WriteAllText(manager.GetSecondaryIndexFilePath("idx_status", 2), "");

        var indexes = manager.ListSecondaryIndexes().ToList();
        Assert.Single(indexes); // 去重后只有一个
        Assert.Contains("idx_status", indexes);
    }
    #endregion

    #region DeleteAllFiles
    [Fact]
    public void TestDeleteAllFiles()
    {
        var manager = new TableFileManager(_testPath, "TempTable", _options);

        File.WriteAllText(manager.GetDataFilePath(), "");
        File.WriteAllText(manager.GetDataFilePath(0), "");
        File.WriteAllText(manager.GetPrimaryIndexFilePath(), "");
        File.WriteAllText(manager.GetSecondaryIndexFilePath("idx_test"), "");
        File.WriteAllText(manager.GetWalFilePath(), "");
        File.WriteAllText(manager.GetWalFilePath(0), "");

        manager.DeleteAllFiles();

        Assert.False(File.Exists(manager.GetDataFilePath()));
        Assert.False(File.Exists(manager.GetDataFilePath(0)));
        Assert.False(File.Exists(manager.GetPrimaryIndexFilePath()));
        Assert.False(File.Exists(manager.GetSecondaryIndexFilePath("idx_test")));
        Assert.False(File.Exists(manager.GetWalFilePath()));
        Assert.False(File.Exists(manager.GetWalFilePath(0)));
    }

    [Fact]
    public void TestDeleteAllFilesNoFiles()
    {
        var manager = new TableFileManager(_testPath, "Empty", _options);
        manager.DeleteAllFiles(); // 不应抛异常
    }

    [Fact]
    public void TestDeleteAllFilesDirectoryNotExists()
    {
        var manager = new TableFileManager("/nonexistent/path", "Users", _options);
        manager.DeleteAllFiles(); // 不应抛异常
    }

    [Fact]
    public void TestDeleteAllFilesDoesNotAffectOtherTables()
    {
        var manager1 = new TableFileManager(_testPath, "TableA", _options);
        var manager2 = new TableFileManager(_testPath, "TableB", _options);

        File.WriteAllText(manager1.GetDataFilePath(), "");
        File.WriteAllText(manager2.GetDataFilePath(), "");

        manager1.DeleteAllFiles();

        Assert.False(File.Exists(manager1.GetDataFilePath()));
        Assert.True(File.Exists(manager2.GetDataFilePath())); // 另一张表不受影响
    }
    #endregion

    #region Exists
    [Fact]
    public void TestExists()
    {
        var manager = new TableFileManager(_testPath, "CheckTable", _options);

        Assert.False(manager.Exists());

        File.WriteAllText(manager.GetDataFilePath(), "");

        Assert.True(manager.Exists());
    }

    [Fact]
    public void TestExistsDirectoryNotExists()
    {
        var manager = new TableFileManager("/nonexistent/path", "Users", _options);
        Assert.False(manager.Exists());
    }
    #endregion

    #region 分片文件综合
    [Fact]
    public void TestShardedFileNaming()
    {
        var manager = new TableFileManager(_testPath, "ShardedTable", _options);

        File.WriteAllText(manager.GetDataFilePath(0), "");
        File.WriteAllText(manager.GetDataFilePath(1), "");
        File.WriteAllText(manager.GetPrimaryIndexFilePath(0), "");
        File.WriteAllText(manager.GetSecondaryIndexFilePath("idx_status", 0), "");
        File.WriteAllText(manager.GetWalFilePath(0), "");

        var shards = manager.ListDataShards().ToList();
        var indexes = manager.ListSecondaryIndexes().ToList();

        Assert.Equal(2, shards.Count);
        Assert.Contains(0, shards);
        Assert.Contains(1, shards);

        Assert.Single(indexes);
        Assert.Contains("idx_status", indexes);
    }
    #endregion
}