using Microsoft.Data.Sqlite; using Scry.Core.Data; using Scry.Core.Models; using Xunit; namespace Scry.Tests; public class CardDatabaseTests : IDisposable { private readonly string _dbPath; private readonly CardDatabase _database; public CardDatabaseTests() { _dbPath = Path.Combine(Path.GetTempPath(), $"scry_test_{Guid.NewGuid()}.db"); _database = new CardDatabase(_dbPath); } [Fact] public async Task InsertCard_ThenRetrieve_ReturnsMatch() { // First insert oracle and set (foreign keys) var oracle = new Oracle { Id = "oracle-1", Name = "Test Card", ManaCost = "{1}{U}", TypeLine = "Creature" }; await _database.InsertOracleAsync(oracle); var set = new Set { Id = "set-1", Code = "TST", Name = "Test Set" }; await _database.InsertSetAsync(set); var card = new Card { Id = "test-id", OracleId = "oracle-1", SetId = "set-1", SetCode = "TST", Name = "Test Card", CollectorNumber = "1", Hash = new byte[] { 0x01, 0x02, 0x03 }, ImageUri = "https://example.com/image.jpg" }; await _database.InsertCardAsync(card); var retrieved = await _database.GetCardByIdAsync("test-id"); Assert.NotNull(retrieved); Assert.Equal("Test Card", retrieved.Name); Assert.Equal("TST", retrieved.SetCode); Assert.Equal(card.Hash, retrieved.Hash); } [Fact] public async Task InsertCardBatch_InsertsAllCards() { // Insert oracle first var oracle = new Oracle { Id = "oracle-batch", Name = "Batch Card" }; await _database.InsertOracleAsync(oracle); var set = new Set { Id = "set-batch", Code = "TST", Name = "Test Set" }; await _database.InsertSetAsync(set); var cards = Enumerable.Range(0, 100).Select(i => new Card { Id = $"card-{i}", OracleId = "oracle-batch", SetId = "set-batch", SetCode = "TST", Name = $"Card {i}", Hash = new byte[] { (byte)i } }).ToList(); await _database.InsertCardBatchAsync(cards); var count = await _database.GetCardCountAsync(); Assert.Equal(100, count); } [Fact] public async Task GetAllCards_ReturnsAllCards() { var oracle = new Oracle { Id = "oracle-all", Name = "All Card" }; await _database.InsertOracleAsync(oracle); var set = new Set { Id = "set-all", Code = "TST", Name = "Test Set" }; await _database.InsertSetAsync(set); var cards = Enumerable.Range(0, 10).Select(i => new Card { Id = $"card-{i}", OracleId = "oracle-all", SetId = "set-all", SetCode = "TST", Name = $"Card {i}", Hash = new byte[] { (byte)i } }).ToList(); await _database.InsertCardBatchAsync(cards); var all = await _database.GetAllCardsAsync(); Assert.Equal(10, all.Count); } [Fact] public async Task GetCardsByOracleId_ReturnsAllPrintings() { var oracle = new Oracle { Id = "oracle-multi", Name = "Multi Print Card" }; await _database.InsertOracleAsync(oracle); var set1 = new Set { Id = "set-1", Code = "S1", Name = "Set 1" }; var set2 = new Set { Id = "set-2", Code = "S2", Name = "Set 2" }; await _database.InsertSetAsync(set1); await _database.InsertSetAsync(set2); var cards = new[] { new Card { Id = "print-1", OracleId = "oracle-multi", SetId = "set-1", SetCode = "S1", Name = "Multi Print Card", Hash = new byte[] { 0x01 } }, new Card { Id = "print-2", OracleId = "oracle-multi", SetId = "set-2", SetCode = "S2", Name = "Multi Print Card", Hash = new byte[] { 0x02 } }, }; await _database.InsertCardBatchAsync(cards); var printings = await _database.GetCardsByOracleIdAsync("oracle-multi"); Assert.Equal(2, printings.Count); } [Fact] public async Task Metadata_SetAndGet() { await _database.SetMetadataAsync("test_key", "test_value"); var value = await _database.GetMetadataAsync("test_key"); Assert.Equal("test_value", value); } [Fact] public async Task ClearCards_RemovesAllCards() { var oracle = new Oracle { Id = "oracle-clear", Name = "Clear Card" }; await _database.InsertOracleAsync(oracle); var set = new Set { Id = "set-clear", Code = "TST", Name = "Test Set" }; await _database.InsertSetAsync(set); var cards = Enumerable.Range(0, 10).Select(i => new Card { Id = $"card-{i}", OracleId = "oracle-clear", SetId = "set-clear", SetCode = "TST", Name = $"Card {i}", Hash = new byte[] { (byte)i } }).ToList(); await _database.InsertCardBatchAsync(cards); await _database.ClearCardsAsync(); var count = await _database.GetCardCountAsync(); Assert.Equal(0, count); } [Fact] public async Task InsertCard_DuplicateId_Updates() { var oracle = new Oracle { Id = "oracle-dup", Name = "Dup Card" }; await _database.InsertOracleAsync(oracle); var set = new Set { Id = "set-dup", Code = "TST", Name = "Test Set" }; await _database.InsertSetAsync(set); var card1 = new Card { Id = "duplicate-id", OracleId = "oracle-dup", SetId = "set-dup", SetCode = "TST", Name = "Original Name", Hash = new byte[] { 0x01 } }; var card2 = new Card { Id = "duplicate-id", OracleId = "oracle-dup", SetId = "set-dup", SetCode = "TST", Name = "Updated Name", Hash = new byte[] { 0x02 } }; await _database.InsertCardAsync(card1); await _database.InsertCardAsync(card2); var retrieved = await _database.GetCardByIdAsync("duplicate-id"); Assert.NotNull(retrieved); Assert.Equal("Updated Name", retrieved.Name); Assert.Equal(new byte[] { 0x02 }, retrieved.Hash); } [Fact] public async Task InsertOracle_ThenRetrieveByName() { var oracle = new Oracle { Id = "oracle-name", Name = "Lightning Bolt", ManaCost = "{R}", Cmc = 1, TypeLine = "Instant", OracleText = "Lightning Bolt deals 3 damage to any target." }; await _database.InsertOracleAsync(oracle); var retrieved = await _database.GetOracleByNameAsync("Lightning Bolt"); Assert.NotNull(retrieved); Assert.Equal("{R}", retrieved.ManaCost); Assert.Equal(1, retrieved.Cmc); } [Fact] public async Task InsertSet_ThenRetrieveByCode() { var set = new Set { Id = "set-lea", Code = "lea", Name = "Limited Edition Alpha", SetType = "expansion", ReleasedAt = "1993-08-05", CardCount = 295 }; await _database.InsertSetAsync(set); var retrieved = await _database.GetSetByCodeAsync("lea"); Assert.NotNull(retrieved); Assert.Equal("Limited Edition Alpha", retrieved.Name); Assert.Equal(295, retrieved.CardCount); } [Fact] public async Task GetCardsWithHash_OnlyReturnsCardsWithHash() { var oracle = new Oracle { Id = "oracle-hash", Name = "Hash Card" }; await _database.InsertOracleAsync(oracle); var set = new Set { Id = "set-hash", Code = "TST", Name = "Test Set" }; await _database.InsertSetAsync(set); var cardWithHash = new Card { Id = "card-with-hash", OracleId = "oracle-hash", SetId = "set-hash", SetCode = "TST", Name = "Has Hash", Hash = new byte[] { 0x01 } }; var cardWithoutHash = new Card { Id = "card-no-hash", OracleId = "oracle-hash", SetId = "set-hash", SetCode = "TST", Name = "No Hash", Hash = null }; await _database.InsertCardAsync(cardWithHash); await _database.InsertCardAsync(cardWithoutHash); var cardsWithHash = await _database.GetCardsWithHashAsync(); Assert.Single(cardsWithHash); Assert.Equal("card-with-hash", cardsWithHash[0].Id); } public void Dispose() { _database.Dispose(); SqliteConnection.ClearAllPools(); try { if (File.Exists(_dbPath)) { File.Delete(_dbPath); } } catch (IOException) { } } }