public void Store() { const string DB_TEST_PATH = "sampledb_store"; if (Directory.Exists(DB_TEST_PATH)) { Directory.Delete(DB_TEST_PATH, true); } Directory.CreateDirectory(DB_TEST_PATH); var sut = new FlashcardboxDb(DB_TEST_PATH); var flashcards = new[] { new FlashcardRecord { Question = "q1", Answer = "a1", Tags = "t1", BinIndex = "1", Id = "1" }, new FlashcardRecord { Question = "q2.1\nq2.2", Answer = "a2.1\na2.2", Tags = "t2,t3", BinIndex = "", Id = "" } }; sut.StoreFlashcards(flashcards); var result = sut.LoadFlashcards(); result.Should().BeEquivalentTo(flashcards); }
public MessageHandling(IEventstore es, FlashcardboxDb db) { _mp = new MessagePump(es); _mp.On <SyncCommand>().Load(new SyncContextManagement(es)).Do(new SyncProcessor(db)); _mp.On <SelectDueCardCommand>().Load(new SelectDueCardContextManager(es)).Do(new SelectDueCardProcessor()); _mp.On <RegisterAnswerCommand>().Load(new RegisterAnswerContextManager(es)).Do(new RegisterAnswerProcessor()); _mp.On <DueCardQuery>().Load(new DueCardContextManager(es)).Do(new DueCardProcessor()); _mp.On <ProgressQuery>().Load(new ProgressContextManager(es)).Do(new ProgressProcessor()); }
private void DumpDb(MessageHandling mh, FlashcardboxDb db) { _testOutputHelper.WriteLine("<<<"); mh.Handle(new SyncCommand()); var cards = db.LoadFlashcards(); foreach (var card in cards.OrderBy(c => c.BinIndex)) { _testOutputHelper.WriteLine($"{card.BinIndex}:{card.Question}"); } _testOutputHelper.WriteLine(">>>"); }
static void Main(string[] args) { var cli = new CLI(args); var db = new FlashcardboxDb(cli.DbPath); var es = new FilebasedEventstore(cli.EventstorePath); var mh = new MessageHandling(es, db); var ui = new UI(mh); ui.Show(); }
public void LoadConfig() { var sut = new FlashcardboxDb("../../../sampledb_load"); var result = sut.LoadConfig(); result.Should().BeEquivalentTo(new FlashcardboxConfig { Bins = new[] { new FlashcardboxConfig.Bin { UpperDueThreshold = 20, LowerDueThreshold = 10 }, new FlashcardboxConfig.Bin { UpperDueThreshold = 50, LowerDueThreshold = 30 } } }); }
public void Load() { var sut = new FlashcardboxDb("../../../sampledb_load"); var result = sut.LoadFlashcards().ToArray(); foreach (var r in result) { _testOutputHelper.WriteLine($"{r.Id}={r.Question}/{r.Answer} [{r.Tags}] @{r.BinIndex}"); } Assert.Equal(3, result.Length); Assert.Equal("1", result[0].Id); Assert.Equal("q1", result[0].Question); Assert.Equal("a1", result[0].Answer); Assert.Equal("", result[0].BinIndex); Assert.Equal("2", result[1].Id); Assert.Equal("t1", result[1].Tags); Assert.Equal("1", result[1].BinIndex); Assert.Equal("", result[2].Id); Assert.Equal("2", result[2].BinIndex); }
public SyncProcessor(FlashcardboxDb db) { _db = db; }
public void Some_cards_are_not_memorized_right_away() { const string DBPATH = "sampledb_acceptance"; File.Copy(Path.Combine(DBPATH, "flashcards v1.csv"), Path.Combine(DBPATH, "flashcards.csv"), true); var db = new FlashcardboxDb(DBPATH); var es = new InMemoryEventstore(); var mh = new MessageHandling(es, db); // box initialized var status = mh.Handle(new SyncCommand()); // 0:a12bcde3fg,1:,2:,3: Memorized("a"); //0:cde3fg,1:12b*,2:a,3: Memorized("1"); //0:cde3fg,1:2b*,2:a1,3: Forgotten("2"); //0:cde3fg,1:b2*,2:a1,3: Memorized("b"); //0:cde3fg,1:2*,2:a1b,3: Memorized("2"); //0:cde3fg,1:2*,2:a1b,3: -> 0:3fg,1:2cde*,2:a1b,3: -> 0:3fg,1:cde*,2:a1b2,3: Forgotten("c"); //0:3fg,1:dec*,2:a1b2,3: Memorized("d"); //0:3fg,1:ec*,2:a1b2d,3: Memorized("e"); //0:3fg,1:c*,2:a1b2de,3: Memorized("a"); //0:3fg,1:c*,2:1b2de*,3:a Forgotten("1"); //0:3fg,1:c1,2:b2de*,3:a Forgotten("b"); //0:3fg,1:c1b,2:2de*,3:a Memorized("2"); //0:3fg,1:c1b,2:de*,3:a2 Memorized("c"); //0:3fg,1:c1b,2:de*,3:a2 -> 0:fg,1:c1b3,2:de*,3:a2 -> 0:fg,1:1b3*,2:dec,3:a2 Memorized("1"); //0:fg,1:b3*,2:dec1,3:a2 Memorized("b"); //0:fg,1:3*,2:dec1b,3:a2 Forgotten("d"); //0:fg,1:3d,2:ec1b*,3:a2 Memorized("e"); //0:fg,1:3d,2:c1b*,3:a2e Memorized("c"); //0:fg,1:3d,2:1b*,3:a2ec Memorized("3"); //0:,1:dfg*,2:1b3,3:a2ec Memorized("d"); //0:,1:fg*,2:1b3d,3:a2ec Memorized("f"); //0:,1:g*,2:1b3df,3:a2ec Forgotten("1"); //0:,1:g1,2:b3df*,3:a2ec Memorized("b"); //0:,1:g1,2:3df*,3:a2ecb Memorized("3"); //0:,1:g1,2:df*,3:a2ecb3 Memorized("g"); //0:,1:1*,2:dfg,3:a2ecb3 Memorized("1"); //0:,1:*,2:dfg1,3:a2ecb3 Memorized("d"); //0:,1:,2:fg1*,3:a2ecb3d Forgotten("f"); //0:,1:f,2:g1*,3:a2ecb3d Memorized("f"); //0:,1:*,2:g1f*,3:a2ecb3d Memorized("g"); //0:,1:*,2:1f*,3:a2ecb3dg Memorized("1"); //0:,1:*,2:f*,3:a2ecb3dg1 Memorized("f"); //0:,1:*,2:*,3:a2ecb3dg1f mh.Handle(new SelectDueCardCommand()).Should().BeOfType <Failure>(); void Memorized(string question) { mh.Handle(new SelectDueCardCommand()); var card = mh.Handle(new DueCardQuery()) as DueCardFoundQueryResult; mh.Handle(new RegisterAnswerCommand { CardId = card.CardId, CorrectlyAnswered = true }); card.Question.Should().Be(question); } void Forgotten(string question) { mh.Handle(new SelectDueCardCommand()); var card = mh.Handle(new DueCardQuery()) as DueCardFoundQueryResult; mh.Handle(new RegisterAnswerCommand { CardId = card.CardId, CorrectlyAnswered = false }); card.Question.Should().Be(question); } }
public void Cards_only_move_forward() { const string DBPATH = "sampledb_acceptance"; File.Copy(Path.Combine(DBPATH, "flashcards v1.csv"), Path.Combine(DBPATH, "flashcards.csv"), true); var db = new FlashcardboxDb(DBPATH); var es = new InMemoryEventstore(); var mh = new MessageHandling(es, db); // box not yet initialized var progress = mh.Handle(new ProgressQuery()); progress.Should().BeEquivalentTo(new ProgressQueryResult { Bins = new[] { new ProgressQueryResult.Bin(), new ProgressQueryResult.Bin() } }); // box initialized var status = mh.Handle(new SyncCommand()); status.Should().BeOfType <SyncSuccess>(); progress = mh.Handle(new ProgressQuery()); progress.Should().BeEquivalentTo(new ProgressQueryResult { Bins = new[] { new ProgressQueryResult.Bin { Count = 10 }, new ProgressQueryResult.Bin { LowerDueThreshold = 2, UpperDueThreshold = 4 }, new ProgressQueryResult.Bin { LowerDueThreshold = 3, UpperDueThreshold = 5 }, new ProgressQueryResult.Bin() } }); // learn first card status = mh.Handle(new SelectDueCardCommand()); status.Should().BeOfType <Success>(); progress = mh.Handle(new ProgressQuery()); progress.Should().BeEquivalentTo(new ProgressQueryResult { Bins = new[] { new ProgressQueryResult.Bin { Count = 6 }, new ProgressQueryResult.Bin { Count = 4, LowerDueThreshold = 2, UpperDueThreshold = 4, IsDue = true }, new ProgressQueryResult.Bin { LowerDueThreshold = 3, UpperDueThreshold = 5 }, new ProgressQueryResult.Bin() } }); var card = mh.Handle(new DueCardQuery()) as DueCardFoundQueryResult; card.Question.Should().Be("a"); status = mh.Handle(new RegisterAnswerCommand { CardId = card.CardId, CorrectlyAnswered = true }); status.Should().BeOfType <Success>(); progress = mh.Handle(new ProgressQuery()); progress.Should().BeEquivalentTo(new ProgressQueryResult { Bins = new[] { new ProgressQueryResult.Bin { Count = 6 }, new ProgressQueryResult.Bin { Count = 3, LowerDueThreshold = 2, UpperDueThreshold = 4, IsDue = true }, new ProgressQueryResult.Bin { Count = 1, LowerDueThreshold = 3, UpperDueThreshold = 5 }, new ProgressQueryResult.Bin() } }); // learn second card mh.Handle(new SelectDueCardCommand()); card = mh.Handle(new DueCardQuery()) as DueCardFoundQueryResult; card.Question.Should().Be("1"); mh.Handle(new RegisterAnswerCommand { CardId = card.CardId, CorrectlyAnswered = true }); progress = mh.Handle(new ProgressQuery()); progress.Should().BeEquivalentTo(new ProgressQueryResult { Bins = new[] { new ProgressQueryResult.Bin { Count = 6 }, new ProgressQueryResult.Bin { Count = 2, LowerDueThreshold = 2, UpperDueThreshold = 4, IsDue = true }, new ProgressQueryResult.Bin { Count = 2, LowerDueThreshold = 3, UpperDueThreshold = 5 }, new ProgressQueryResult.Bin() } }); // learn card 3 mh.Handle(new SelectDueCardCommand()); card = mh.Handle(new DueCardQuery()) as DueCardFoundQueryResult; card.Question.Should().Be("2"); mh.Handle(new RegisterAnswerCommand { CardId = card.CardId, CorrectlyAnswered = true }); progress = mh.Handle(new ProgressQuery()); progress.Should().BeEquivalentTo(new ProgressQueryResult { Bins = new[] { new ProgressQueryResult.Bin { Count = 6 }, new ProgressQueryResult.Bin { Count = 1, LowerDueThreshold = 2, UpperDueThreshold = 4, IsDue = true }, new ProgressQueryResult.Bin { Count = 3, LowerDueThreshold = 3, UpperDueThreshold = 5 }, new ProgressQueryResult.Bin() } }); // learning card 4 first leads to a refill of bin 1 mh.Handle(new SelectDueCardCommand()); card = mh.Handle(new DueCardQuery()) as DueCardFoundQueryResult; card.Question.Should().Be("b"); mh.Handle(new RegisterAnswerCommand { CardId = card.CardId, CorrectlyAnswered = true }); progress = mh.Handle(new ProgressQuery()); progress.Should().BeEquivalentTo(new ProgressQueryResult { Bins = new[] { new ProgressQueryResult.Bin { Count = 3 }, new ProgressQueryResult.Bin { Count = 3, LowerDueThreshold = 2, UpperDueThreshold = 4, IsDue = true }, new ProgressQueryResult.Bin { Count = 4, LowerDueThreshold = 3, UpperDueThreshold = 5 }, new ProgressQueryResult.Bin() } }); // learning card 5 fills up bin 2... mh.Handle(new SelectDueCardCommand()); card = mh.Handle(new DueCardQuery()) as DueCardFoundQueryResult; card.Question.Should().Be("c"); mh.Handle(new RegisterAnswerCommand { CardId = card.CardId, CorrectlyAnswered = true }); // ...but bin 1 stays due because its lower threshold hasn't been reached mh.Handle(new SelectDueCardCommand()); card = mh.Handle(new DueCardQuery()) as DueCardFoundQueryResult; card.Question.Should().Be("d"); mh.Handle(new RegisterAnswerCommand { CardId = card.CardId, CorrectlyAnswered = true }); progress = mh.Handle(new ProgressQuery()); progress.Should().BeEquivalentTo(new ProgressQueryResult { Bins = new[] { new ProgressQueryResult.Bin { Count = 3 }, new ProgressQueryResult.Bin { Count = 1, LowerDueThreshold = 2, UpperDueThreshold = 4, IsDue = true }, new ProgressQueryResult.Bin { Count = 6, LowerDueThreshold = 3, UpperDueThreshold = 5 }, new ProgressQueryResult.Bin() } }); // this only changes now! mh.Handle(new SelectDueCardCommand()); card = mh.Handle(new DueCardQuery()) as DueCardFoundQueryResult; card.Question.Should().Be("a"); mh.Handle(new RegisterAnswerCommand { CardId = card.CardId, CorrectlyAnswered = true }); progress = mh.Handle(new ProgressQuery()); progress.Should().BeEquivalentTo(new ProgressQueryResult { Bins = new[] { new ProgressQueryResult.Bin { Count = 3 }, new ProgressQueryResult.Bin { Count = 1, LowerDueThreshold = 2, UpperDueThreshold = 4, }, new ProgressQueryResult.Bin { Count = 5, LowerDueThreshold = 3, UpperDueThreshold = 5, IsDue = true }, new ProgressQueryResult.Bin { Count = 1 } } }); // learn all cards: // 1(3,1,4,2), 2(3,1,3,3), b(3,1,2,4), e(0,3,4,3), 3(0,2,5,3), f(0,1-g,5-cde3f,4-a12b) // c(0,1-g,5-de3f,4-a12bc), d(0,1-g,3-e3f,5-a12bcd), e(0,1-g,2-3f,6-a12bcde) // g(0,0,3-3fg,7-a12bcde), 3(0,0,2-fg,8-a12bcde3), f(0,0,1-g,9-a12bcde3f), g(0,0,0,10-a12bcde3fg) foreach (var q in "12be3fcdeg3fg".ToCharArray()) { mh.Handle(new SelectDueCardCommand()); card = mh.Handle(new DueCardQuery()) as DueCardFoundQueryResult; mh.Handle(new RegisterAnswerCommand { CardId = card.CardId, CorrectlyAnswered = true }); card.Question.Should().Be(q.ToString()); } mh.Handle(new SelectDueCardCommand()).Should().BeOfType <Failure>(); }