using System.Text.Json; using QuestionsApi.Models; using QuestionsApi.Services.Flashcards; using Xunit; namespace QuestionsApi.Tests; public sealed class FlashcardImportExportModelTests { [Fact] public void JsonExport_RoundTrips_NotesCardsAndReviewHistory() { var export = new FlashcardJsonExport { SchemaVersion = 1, Settings = new FlashcardSettings { UserId = "user-1", NewCardsPerDay = 20, ReviewsPerDay = 200 }, Decks = [new FlashcardDeck { Id = "deck-1", UserId = "user-1", Name = "Cardio", IsDefault = true }], Notes = [ new FlashcardJsonExportNote { Note = new FlashcardNote { Id = "note-1", UserId = "user-1", DeckId = "deck-1", StableId = "stable-1", Type = FlashcardTypes.Cloze, Prompt = "{{c1::Paris}} is the capital of France", Tags = ["geography"] }, Cards = [ new FlashcardSchedule { Id = "card-1", UserId = "user-1", NoteId = "note-1", Variant = 1, State = FlashcardScheduleStates.Review, Stability = 12.3, Difficulty = 4.5, DueUtc = new DateTime(2026, 1, 1, 0, 0, 0, DateTimeKind.Utc) } ], ReviewLogs = [ new FlashcardReviewLog { Id = "log-1", UserId = "user-1", CardId = "card-1", Rating = FlashcardRatings.Good, ReviewedUtc = new DateTime(2025, 12, 31, 0, 0, 0, DateTimeKind.Utc) } ], Images = [new FlashcardJsonExportImage { AssetId = "asset-1", FileName = "x.png", ContentType = "image/png", Base64Bytes = Convert.ToBase64String([1, 2, 3]) }] } ] }; var json = JsonSerializer.Serialize(export); var roundTripped = JsonSerializer.Deserialize(json); Assert.NotNull(roundTripped); var note = Assert.Single(roundTripped!.Notes); Assert.Equal("stable-1", note.Note.StableId); Assert.Equal(FlashcardTypes.Cloze, note.Note.Type); var card = Assert.Single(note.Cards); Assert.Equal(1, card.Variant); Assert.Equal(12.3, card.Stability); var log = Assert.Single(note.ReviewLogs); Assert.Equal(FlashcardRatings.Good, log.Rating); var image = Assert.Single(note.Images); Assert.Equal([1, 2, 3], Convert.FromBase64String(image.Base64Bytes)); } [Fact] public void Fingerprint_IsStable_ForSameTypePromptAndAnswer_IgnoringSurroundingWhitespace() { var a = FlashcardNoteStore.Fingerprint(FlashcardTypes.Basic, " What is 2+2? ", "4"); var b = FlashcardNoteStore.Fingerprint(FlashcardTypes.Basic, "What is 2+2?", "4"); Assert.Equal(a, b); } [Fact] public void Fingerprint_DiffersWhenAnswerDiffers() { var a = FlashcardNoteStore.Fingerprint(FlashcardTypes.Basic, "What is 2+2?", "4"); var b = FlashcardNoteStore.Fingerprint(FlashcardTypes.Basic, "What is 2+2?", "five"); Assert.NotEqual(a, b); } [Fact] public void Fingerprint_DiffersByType_ForSamePromptAndAnswer() { var basic = FlashcardNoteStore.Fingerprint(FlashcardTypes.Basic, "text", "text"); var cloze = FlashcardNoteStore.Fingerprint(FlashcardTypes.Cloze, "text", "text"); Assert.NotEqual(basic, cloze); } }