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 = $"{Path.Combine(PreferencesManager.GetDefaultDatabasePath(), 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 = $"{Path.Combine(PreferencesManager.GetDefaultDatabasePath(), dbName)}.rdb"; try { // Act — 连续调用两次 Database.InitializeDatabase(dbName); Exception? 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); } } #region 读取方法测试 private static AudioFileMeta CreateSampleMeta(int id = 0) { var guid = Guid.NewGuid().ToString("N"); return new AudioFileMeta { Id = id, UniqueId = guid, ShortId = "TEST", Md5 = guid[..16], Path = $"/test/path/{guid}.wav", Filename = $"{guid}.wav", Folder = "test", Directory = "/test/path", Duration = 2.5, BitDepth = 24, Channels = 2, SampleRate = 48000, Type = "WAV", DateAdded = DateTime.UtcNow, LastWriteTime = DateTime.UtcNow, CreationTime = DateTime.UtcNow, Description = "Test explosion sound", Category = "SFX", Keywords = "test,boom,explosion", FxName = "Test Explosion Boom" }; } private static string GetDefaultDbPath() => Path.Combine(PreferencesManager.GetDefaultDatabasePath(), "default.rdb"); private static void DeleteTestEntries(params string[] uniqueIds) { using var conn = new SQLiteConnection($"Data Source={GetDefaultDbPath()};Version=3;"); conn.Open(); foreach (var uid in uniqueIds) conn.Execute("DELETE FROM audio_files WHERE unique_id = @UniqueId", new { UniqueId = uid }); } [Fact] public void AddEntry_Then_GetEntryById_ShouldReturnRecord() { Database.InitializeDatabase(); var meta = CreateSampleMeta(); Assert.True(Database.AddEntry(meta)); try { var retrieved = Database.GetEntryById(meta.Id); Assert.NotNull(retrieved); Assert.Equal(meta.UniqueId, retrieved!.UniqueId); Assert.Equal(meta.Filename, retrieved.Filename); Assert.Equal(meta.Duration, retrieved.Duration); } finally { DeleteTestEntries(meta.UniqueId); } } [Fact] public void GetEntryById_NotFound_ShouldReturnNull() { Database.InitializeDatabase(); var result = Database.GetEntryById(int.MaxValue); Assert.Null(result); } [Fact] public void AddEntry_Then_GetEntryByUniqueId_ShouldReturnRecord() { Database.InitializeDatabase(); var meta = CreateSampleMeta(); Database.AddEntry(meta); try { var retrieved = Database.GetEntryByUniqueId(meta.UniqueId); Assert.NotNull(retrieved); Assert.Equal(meta.Md5, retrieved!.Md5); } finally { DeleteTestEntries(meta.UniqueId); } } [Fact] public void GetEntryByUniqueId_NotFound_ShouldReturnNull() { Database.InitializeDatabase(); var result = Database.GetEntryByUniqueId("nonexistent-guid"); Assert.Null(result); } [Fact] public void QueryEntries_ShouldFilterBySearchText() { Database.InitializeDatabase(); var meta = CreateSampleMeta(); meta.Description = "Unique underwater ambience loop"; meta.Keywords = "water,ocean,deep"; Database.AddEntry(meta); try { var results = Database.QueryEntries(searchText: "underwater").ToList(); Assert.Single(results); Assert.Equal(meta.UniqueId, results[0].UniqueId); var empty = Database.QueryEntries(searchText: "zzz_nonexistent_zzz").ToList(); Assert.Empty(empty); } finally { DeleteTestEntries(meta.UniqueId); } } [Fact] public void QueryEntries_ShouldFilterByDuration() { Database.InitializeDatabase(); var shortMeta = CreateSampleMeta(); shortMeta.Duration = 1.0; var longMeta = CreateSampleMeta(); longMeta.Duration = 10.0; Database.AddEntries(new[] { shortMeta, longMeta }); try { var results = Database.QueryEntries(minDuration: 5.0).ToList(); Assert.Single(results); Assert.Equal(longMeta.UniqueId, results[0].UniqueId); } finally { DeleteTestEntries(shortMeta.UniqueId, longMeta.UniqueId); } } [Fact] public void QueryEntries_ShouldSupportPagination() { Database.InitializeDatabase(); var entries = Enumerable.Range(0, 5).Select(_ => CreateSampleMeta()).ToList(); Database.AddEntries(entries); try { var page = Database.QueryEntries(limit: 2, offset: 1).ToList(); Assert.Equal(2, page.Count); } finally { DeleteTestEntries(entries.Select(e => e.UniqueId).ToArray()); } } [Fact] public void SearchEntries_ShouldFindByKeyword() { Database.InitializeDatabase(); var meta = CreateSampleMeta(); meta.Keywords = "magic,spell,fireball"; Database.AddEntry(meta); try { var results = Database.SearchEntries("fireball").ToList(); Assert.Single(results); } finally { DeleteTestEntries(meta.UniqueId); } } [Fact] public void GetTotalCount_ShouldRespectSearchFilter() { Database.InitializeDatabase(); var meta = CreateSampleMeta(); var uniqueTag = $"UNIQUE_TAG_{meta.UniqueId[..8]}"; meta.Description = uniqueTag; Database.AddEntry(meta); try { var count = Database.GetTotalCount(searchText: uniqueTag); Assert.Equal(1, count); } finally { DeleteTestEntries(meta.UniqueId); } } [Fact] public void AddEntries_ShouldReturnCorrectCount() { Database.InitializeDatabase(); var entries = Enumerable.Range(0, 3).Select(_ => CreateSampleMeta()).ToList(); try { var count = Database.AddEntries(entries); Assert.Equal(3, count); } finally { DeleteTestEntries(entries.Select(e => e.UniqueId).ToArray()); } } #endregion }