summaryrefslogtreecommitdiff
path: root/tests/unit/SpacedRepetitionModel/SRModel_pickCard_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit/SpacedRepetitionModel/SRModel_pickCard_test.cpp')
-rw-r--r--tests/unit/SpacedRepetitionModel/SRModel_pickCard_test.cpp420
1 files changed, 420 insertions, 0 deletions
diff --git a/tests/unit/SpacedRepetitionModel/SRModel_pickCard_test.cpp b/tests/unit/SpacedRepetitionModel/SRModel_pickCard_test.cpp
new file mode 100644
index 0000000..73ab023
--- /dev/null
+++ b/tests/unit/SpacedRepetitionModel/SRModel_pickCard_test.cpp
@@ -0,0 +1,420 @@
+#include "SRModel_pickCard_test.h"
+#include "../../common/printQtTypes.h"
+#include "../../../src/dictionary/Card.h"
+#include "../../mocks/RandomGenerator_mock.h"
+#include "../../../src/utils/TimeProvider.h"
+
+static const StudySettings* ss = StudySettings::inst();
+
+const double SRModel_pickCard_Test::HourAgo = -1. / 24;
+
+void SRModel_pickCard_Test::SetUp()
+{
+ randomGenerator->setRand(1);
+}
+
+// Time interval
+
+TEST_F(SRModel_pickCard_Test, pick_active1)
+{
+ addStudied(-1, 1);
+ testPicked({0});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_active2)
+{
+ addStudied(-8.5, 8.1);
+ testPicked({0});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_active_and_future)
+{
+ addStudied(-1, 1);
+ addStudied(-1, 2);
+ testPicked({0});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_2active1)
+{
+ addStudied(-1, 1);
+ addStudied(-1.1, 1);
+
+ randomGenerator->setRand(0);
+ testPicked({0});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_2active2)
+{
+ addStudied(-1, 1);
+ addStudied(-1.1, 1);
+ testPicked({1, 0});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_3active)
+{
+ addStudied(-1, 1);
+ addStudied(-1.1, 1);
+ addStudied(-1.2, 1);
+ testPicked({1, 2, 0});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_future1)
+{
+ addStudied(-1, 2);
+ testPicked({NoCard});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_future2)
+{
+ addStudied(-1, 2);
+ addStudied(-1.1, 2);
+ testPicked({NoCard});
+}
+
+
+// Priority cards with small intervals
+// Always pick first cards with small interval
+
+TEST_F(SRModel_pickCard_Test, pick_zeroInterval) // Unreal
+{
+ addStudied(HourAgo, 0);
+ testPicked({0});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_unknown)
+{
+ addUnknown(HourAgo);
+ testPicked({0});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_unknown_and_active)
+{
+ addUnknown(HourAgo);
+ addStudied(-1, 1);
+ testPicked({0, 1});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_learning3min_and_active)
+{
+ addLearning(-3./(24*60)); // 3 min back
+ addStudied(-1, 1);
+ testPicked({1, 0});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_learning10min_and_active)
+{
+ addLearning(-10./(24*60));
+ addStudied(-1, 1);
+ testPicked({0, 1});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_learningPrevDay_and_active)
+{
+ addLearning(-1);
+ addStudied(-1, 1);
+ testPicked({0, 1});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_unknown_and_2actives)
+{
+ addUnknown(HourAgo);
+ addStudied(-1, 1);
+ addStudied(-1.1, 1);
+ testPicked({0, 2, 1});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_remembered_and_2actives)
+{
+ addStudied(-1, ss->nextDayInterval);
+ addStudied(-1, 1);
+ addStudied(-1.1, 1);
+ testPicked({0, 2, 1});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_competing_unknown_and_new)
+{
+ addUnknown(HourAgo);
+ addNew();
+ addStudied(-1, 1);
+ testPicked({0, 1, 2});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_competing_remembered_and_new)
+{
+ addStudied(-1, ss->nextDayInterval);
+ addNew();
+ addStudied(-1, 1);
+ testPicked({0, 1, 2});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_2unknowns_and_2actives)
+{
+ addUnknown(HourAgo);
+ addUnknown(2 * HourAgo);
+ addStudied(-1, 1);
+ addStudied(-1.1, 1);
+ testPicked({1, 0, 3, 2});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_unknown_and_3actives)
+{
+ addUnknown(HourAgo);
+ addStudied(-1, 1);
+ addStudied(-1.1, 1);
+ addStudied(-1.2, 1);
+ testPicked({0, 2, 3, 1});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_unknown_and_remembered)
+{
+ addUnknown(HourAgo);
+ addStudied(-1, ss->nextDayInterval);
+ addStudied(-1, 1);
+ testPicked({0, 1, 2});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_incorrect_and_remembered)
+{
+ addIncorrect(HourAgo);
+ addStudied(-1, ss->nextDayInterval);
+ addStudied(-1, 1);
+ testPicked({0, 1, 2});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_unknown_and_incorrect)
+{
+ addUnknown(HourAgo);
+ addIncorrect(HourAgo);
+ addStudied(-1, 1);
+ testPicked({0, 1, 2});
+}
+
+// New cards
+
+TEST_F(SRModel_pickCard_Test, pick_new)
+{
+ addNew();
+ testPicked({0});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_new_and_studied1)
+{
+ addNew();
+ addStudied(-1.1, 1);
+
+ randomGenerator->setDouble(0.3); // Pick studied first
+ testPicked({1, 0});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_new_and_studied2)
+{
+ addNew();
+ addStudied(-1.1, 1);
+
+ // Pick new first
+ testPicked({0, 1});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_2new)
+{
+ addNew();
+ addNew();
+ testPicked({1, 0});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_3new)
+{
+ for(int i = 0; i < 3; i++)
+ addNew();
+ testPicked({1, 2, 0});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_2new_and_2studied1)
+{
+ addNew();
+ addNew();
+ addStudied(-1, 1);
+ addStudied(-1.1, 1);
+
+ randomGenerator->setDouble(0.3); // Pick studied first
+ testPicked({3, 2, 1, 0});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_2new_and_2studied2)
+{
+ addNew();
+ addNew();
+ addStudied(-1, 1);
+ addStudied(-1.1, 1);
+
+ // Pick new first, double random = 0
+ testPicked({1, 0, 3, 2});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_2new_and_2studied3)
+{
+ addNew();
+ addNew();
+ addStudied(-1, 1);
+ addStudied(-1.1, 1);
+
+ randomGenerator->setDouble(0.3); // Pick studied first
+ model.testPickCard();
+ assertCurCard(3);
+ randomGenerator->setDouble(0.1); // Pick new first
+ model.scheduleCard(4);
+ assertCurCard(1);
+ randomGenerator->setDouble(0.3);
+ model.scheduleCard(4);
+ assertCurCard(2);
+ randomGenerator->setDouble(0.1);
+ model.scheduleCard(4);
+ assertCurCard(0);
+}
+
+TEST_F(SRModel_pickCard_Test, pick_incorrect_new_and_studied)
+{
+ addIncorrect(HourAgo);
+ addNew();
+ addStudied(-1, 1);
+
+ randomGenerator->setDouble(0.3); // Pick studied first
+ testPicked({0, 2, 1});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_newAndActive_newLimitReached)
+{
+ for(int i = 0; i < ss->newCardsDayLimit; i++)
+ addStudied(HourAgo, ss->nextDayInterval);
+
+ addNew();
+ addStudied(-1, 1);
+
+ int studiedCard = ss->newCardsDayLimit + 1;
+ testPicked({studiedCard, NoCard});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_2new_newLimitReached)
+{
+ for(int i = 0; i < ss->newCardsDayLimit; i++)
+ addStudied(HourAgo, ss->nextDayInterval);
+
+ addNew();
+ addNew();
+
+ testPicked({NoCard});
+}
+
+// Remaining incorrect cards
+// Must be taken in the end (both active and new cards are finished)
+
+TEST_F(SRModel_pickCard_Test, pick_remaining_unknown)
+{
+ addUnknown(Now);
+ addStudied(-1, 1);
+ testPicked({1, 0});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_remaining_incorrect)
+{
+ addIncorrect(Now);
+ addStudied(-1, 1);
+ testPicked({1, 0});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_remaining_remembered)
+{
+ addStudied(Now, ss->nextDayInterval);
+ addStudied(-1, 1);
+ testPicked({1, NoCard});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_remaining_unknownAndIncorrect)
+{
+ addIncorrect(HourAgo);
+ addUnknown(Now);
+ addStudied(-1, 1);
+ testPicked({0, 2, 1});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_remaining_after_new)
+{
+ addNew();
+ testPicked({0, 0, 0, NoCard});
+}
+
+TEST_F(SRModel_pickCard_Test, pick_remaining_after_2new)
+{
+ addNew();
+ addNew();
+ testPicked({1, 0, 1, 0, 1, 0, NoCard});
+}
+
+
+
+QDateTime SRModel_pickCard_Test::timeFromDelta(double daysDelta)
+{
+ return TimeProvider::get().addSecs((int)(daysDelta * 24 * 60 * 60));
+}
+
+void SRModel_pickCard_Test::addStudied(double daysDelta, double interval,
+ int grade, int level)
+{
+ QString name = addRecord();
+ pack.generateQuestions();
+ StudyRecord study(level, grade, 2.5, interval);
+ study.date = timeFromDelta(daysDelta);
+ pack.addStudyRecord(name, study);
+}
+
+void SRModel_pickCard_Test::addUnknown(double daysDelta)
+{
+ addStudied(daysDelta, ss->unknownInterval, StudyRecord::Unknown,
+ StudyRecord::ShortLearning);
+}
+
+void SRModel_pickCard_Test::addIncorrect(double daysDelta)
+{
+ addStudied(daysDelta, ss->incorrectInterval, StudyRecord::Incorrect,
+ StudyRecord::ShortLearning);
+}
+
+void SRModel_pickCard_Test::addLearning(double daysDelta)
+{
+ addStudied(daysDelta, ss->learningInterval, StudyRecord::Good,
+ StudyRecord::LongLearning);
+}
+
+void SRModel_pickCard_Test::addNew()
+{
+ addRecord();
+ pack.generateQuestions();
+}
+
+void SRModel_pickCard_Test::assertCurCard(int expCard)
+{
+ if(expCard < 0)
+ {
+ ASSERT_FALSE(model.getCurCard());
+ return;
+ }
+ ASSERT_TRUE(model.getCurCard());
+ ASSERT_EQ(expCard, model.getCurCard()->getQuestion().toInt());
+}
+
+void SRModel_pickCard_Test::testPicked(const vector<int>& expCards)
+{
+ vector<int> pickedCards;
+ for(unsigned i = 0; i < expCards.size(); i++)
+ {
+ if(i == 0)
+ model.testPickCard();
+ else
+ model.scheduleCard(StudyRecord::Good);
+ if(model.getCurCard())
+ pickedCards.push_back(model.getCurCard()->getQuestion().toInt());
+ else
+ pickedCards.push_back(-1);
+ }
+ ASSERT_EQ(expCards, pickedCards);
+}