diff --git a/src/Core.Tests/DatabaseTests.cs b/src/Core.Tests/DatabaseTests.cs new file mode 100644 index 0000000..30e0f46 --- /dev/null +++ b/src/Core.Tests/DatabaseTests.cs @@ -0,0 +1,86 @@ +using System.Data.SQLite; +using Dapper; +using OCES.Resonance.Core; + +namespace Core.Tests; + +public class DatabaseTests +{ + static string NewDbName() => $"test_{Guid.NewGuid():N}"; + + [Fact] + public void InitializeDatabase_ShouldCreateAudioFilesTable() + { + string dbName = NewDbName(); + string dbPath = $"{dbName}.rdb"; + + try + { + // Act + Database.InitializeDatabase(dbName); + + // Assert — 用自己的 SQLite 连接验证 + using var conn = new SQLiteConnection($"Data Source={dbPath};Version=3;"); + conn.Open(); + + // 1. 表存在 + var tableCount = conn.ExecuteScalar( + "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='audio_files';"); + Assert.Equal(1, tableCount); + + // 2. 核心列存在(抽查) + var columns = conn.Query( + "SELECT name FROM pragma_table_info('audio_files') ORDER BY cid;").ToHashSet(); + Assert.Contains("id", columns); + Assert.Contains("unique_id", columns); + Assert.Contains("md5", columns); + Assert.Contains("path", columns); + Assert.Contains("filename", columns); + Assert.Contains("duration", columns); + Assert.Contains("bpm", columns); + Assert.Contains("description", columns); + + // 3. 索引存在 + var indexes = conn.Query( + "SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='audio_files';") + .ToHashSet(); + Assert.Contains("idx_file_name", indexes); + Assert.Contains("idx_md5", indexes); + Assert.Contains("idx_path", indexes); + Assert.Contains("idx_unique_id", indexes); + Assert.Contains("idx_description", indexes); + } + finally + { + if (File.Exists(dbPath)) File.Delete(dbPath); + } + } + + [Fact] + public void InitializeDatabase_ShouldBeIdempotent() + { + string dbName = NewDbName(); + string dbPath = $"{dbName}.rdb"; + + try + { + // Act — 连续调用两次 + Database.InitializeDatabase(dbName); + var exception = Record.Exception(() => Database.InitializeDatabase(dbName)); + + // Assert — 不应抛出异常 + Assert.Null(exception); + + // 表仍然只有一个 + using var conn = new SQLiteConnection($"Data Source={dbPath};Version=3;"); + conn.Open(); + var tableCount = conn.ExecuteScalar( + "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='audio_files';"); + Assert.Equal(1, tableCount); + } + finally + { + if (File.Exists(dbPath)) File.Delete(dbPath); + } + } +} diff --git a/src/Core/Database.cs b/src/Core/Database.cs index c1dddfa..74e8136 100755 --- a/src/Core/Database.cs +++ b/src/Core/Database.cs @@ -11,7 +11,7 @@ public static class Database /// /// 数据库名称(不含扩展名) /// 数据库连接 - static IDbConnection GetConnection(string dbName = "default") + internal static IDbConnection GetConnection(string dbName = "default") { string connectionString = $"Data Source={dbName}.rdb;Version=3;"; return new SQLiteConnection(connectionString); @@ -20,7 +20,7 @@ public static class Database /// /// 初始化数据库表结构 /// - public static void InitializeDatabase() + public static void InitializeDatabase(string databaseName = "default") { using var connection = GetConnection(); connection.Open(); diff --git a/src/Resonance.sln.DotSettings.user b/src/Resonance.sln.DotSettings.user index 77ecf44..123aa44 100755 --- a/src/Resonance.sln.DotSettings.user +++ b/src/Resonance.sln.DotSettings.user @@ -14,5 +14,6 @@ <TestId>xUnit::24F92458-FB39-44BE-A32F-41275183AF1B::net10.0::Core.Tests.AudioMetadataReaderTest.ReadMetadata_ShoudThrow_FileNotFoundException</TestId> <TestId>xUnit::24F92458-FB39-44BE-A32F-41275183AF1B::net10.0::Core.Tests.AudioMetadataReaderTest.ReadMetadata_ShouldThrow_FileNotFoundException</TestId> <TestId>xUnit::24F92458-FB39-44BE-A32F-41275183AF1B::net10.0::Core.Tests.AudioMetadataReaderTest</TestId> + <TestId>xUnit::24F92458-FB39-44BE-A32F-41275183AF1B::net10.0::Core.Tests.DatabaseTests.InitializeDatabase_ShouldCreateAudioFilesTable</TestId> </TestAncestor> </SessionState> \ No newline at end of file