Files
Resonance/src/Core.Tests/DatabaseTests.cs
T
2026-05-22 20:41:43 +08:00

307 lines
9.0 KiB
C#

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<int>(
"SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='audio_files';");
Assert.Equal(1, tableCount);
// 2. 核心列存在(抽查)
var columns = conn.Query<string>(
"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<string>(
"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<int>(
"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
}