Adds a full flashcards system: FSRS-based scheduling, cloze/basic card types, CSV import/export, media storage, and study UI, wired into navigation and the dashboard alongside existing question flows.
42 lines
1.3 KiB
C#
42 lines
1.3 KiB
C#
using QuestionsApi.Services.Flashcards;
|
|
using Xunit;
|
|
|
|
namespace QuestionsApi.Tests;
|
|
|
|
public sealed class FlashcardSchedulingTests
|
|
{
|
|
[Fact]
|
|
public void NextStudyDayStart_IsMidnightOfTheFollowingDay()
|
|
{
|
|
var studyDayStart = new DateTime(2026, 3, 5, 0, 0, 0, DateTimeKind.Utc);
|
|
|
|
var next = FlashcardScheduling.NextStudyDayStart(studyDayStart);
|
|
|
|
Assert.Equal(new DateTime(2026, 3, 6, 0, 0, 0, DateTimeKind.Utc), next);
|
|
}
|
|
|
|
[Fact]
|
|
public void NextStudyDayStart_TruncatesTimeOfDayBeforeAdvancing()
|
|
{
|
|
// A session that started mid-day still buries siblings until the *next calendar day*,
|
|
// not exactly 24h later.
|
|
var studyDayStart = new DateTime(2026, 3, 5, 14, 30, 0, DateTimeKind.Utc);
|
|
|
|
var next = FlashcardScheduling.NextStudyDayStart(studyDayStart);
|
|
|
|
Assert.Equal(new DateTime(2026, 3, 6, 0, 0, 0, DateTimeKind.Utc), next);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(20, null, 0, 20)]
|
|
[InlineData(20, null, 15, 5)]
|
|
[InlineData(20, null, 25, 0)]
|
|
[InlineData(20, 5, 0, 5)]
|
|
[InlineData(20, 0, 0, 0)]
|
|
public void ResolveDailyBudget_DeckOverrideWinsOverGlobal_ClampedAtZero(
|
|
int globalLimit, int? deckOverride, int consumedToday, int expected)
|
|
{
|
|
Assert.Equal(expected, FlashcardScheduling.ResolveDailyBudget(globalLimit, deckOverride, consumedToday));
|
|
}
|
|
}
|