|
8 | 8 | import random |
9 | 9 | from copy import deepcopy |
10 | 10 | import sys |
| 11 | +import re |
| 12 | + |
| 13 | +TEST_RATINGS_1 = ( |
| 14 | + Rating.Good, |
| 15 | + Rating.Good, |
| 16 | + Rating.Good, |
| 17 | + Rating.Good, |
| 18 | + Rating.Good, |
| 19 | + Rating.Good, |
| 20 | + Rating.Again, |
| 21 | + Rating.Again, |
| 22 | + Rating.Good, |
| 23 | + Rating.Good, |
| 24 | + Rating.Good, |
| 25 | + Rating.Good, |
| 26 | + Rating.Good, |
| 27 | +) |
11 | 28 |
|
12 | 29 |
|
13 | 30 | class TestPyFSRS: |
14 | 31 | def test_review_card(self): |
15 | 32 | scheduler = Scheduler(enable_fuzzing=False) |
16 | 33 |
|
17 | | - ratings = ( |
18 | | - Rating.Good, |
19 | | - Rating.Good, |
20 | | - Rating.Good, |
21 | | - Rating.Good, |
22 | | - Rating.Good, |
23 | | - Rating.Good, |
24 | | - Rating.Again, |
25 | | - Rating.Again, |
26 | | - Rating.Good, |
27 | | - Rating.Good, |
28 | | - Rating.Good, |
29 | | - Rating.Good, |
30 | | - Rating.Good, |
31 | | - ) |
32 | | - |
33 | 34 | card = Card() |
34 | 35 | review_datetime = datetime(2022, 11, 29, 12, 30, 0, 0, timezone.utc) |
35 | 36 |
|
36 | 37 | ivl_history = [] |
37 | | - for rating in ratings: |
| 38 | + for rating in TEST_RATINGS_1: |
38 | 39 | card, _ = scheduler.review_card( |
39 | 40 | card=card, rating=rating, review_datetime=review_datetime |
40 | 41 | ) |
@@ -222,24 +223,9 @@ def test_custom_scheduler_args(self): |
222 | 223 | card = Card() |
223 | 224 | now = datetime(2022, 11, 29, 12, 30, 0, 0, timezone.utc) |
224 | 225 |
|
225 | | - ratings = ( |
226 | | - Rating.Good, |
227 | | - Rating.Good, |
228 | | - Rating.Good, |
229 | | - Rating.Good, |
230 | | - Rating.Good, |
231 | | - Rating.Good, |
232 | | - Rating.Again, |
233 | | - Rating.Again, |
234 | | - Rating.Good, |
235 | | - Rating.Good, |
236 | | - Rating.Good, |
237 | | - Rating.Good, |
238 | | - Rating.Good, |
239 | | - ) |
240 | 226 | ivl_history = [] |
241 | 227 |
|
242 | | - for rating in ratings: |
| 228 | + for rating in TEST_RATINGS_1: |
243 | 229 | card, _ = scheduler.review_card(card, rating, now) |
244 | 230 | ivl = (card.due - card.last_review).days |
245 | 231 | ivl_history.append(ivl) |
@@ -1011,6 +997,150 @@ def test_relearning_card_rate_hard_two_relearning_steps(self): |
1011 | 997 | assert card.state == State.Review |
1012 | 998 | assert card.step is None |
1013 | 999 |
|
| 1000 | + def test_reschedule_card_same_scheduler(self): |
| 1001 | + scheduler = Scheduler(enable_fuzzing=False) |
| 1002 | + |
| 1003 | + card = Card() |
| 1004 | + |
| 1005 | + review_logs = [] |
| 1006 | + for rating in TEST_RATINGS_1: |
| 1007 | + card, review_log = scheduler.review_card( |
| 1008 | + card=card, rating=rating, review_datetime=card.due |
| 1009 | + ) |
| 1010 | + review_logs.append(review_log) |
| 1011 | + |
| 1012 | + rescheduled_card = scheduler.reschedule_card(card=card, review_logs=review_logs) |
| 1013 | + |
| 1014 | + assert card is not rescheduled_card |
| 1015 | + assert card == rescheduled_card |
| 1016 | + |
| 1017 | + def test_reschedule_card_different_parameters(self): |
| 1018 | + scheduler = Scheduler(enable_fuzzing=False) |
| 1019 | + |
| 1020 | + card = Card() |
| 1021 | + |
| 1022 | + review_logs = [] |
| 1023 | + for rating in TEST_RATINGS_1: |
| 1024 | + card, review_log = scheduler.review_card( |
| 1025 | + card=card, rating=rating, review_datetime=card.due |
| 1026 | + ) |
| 1027 | + review_logs.append(review_log) |
| 1028 | + |
| 1029 | + DIFFERENT_PARAMETERS = [ |
| 1030 | + 0.12340357383516173, |
| 1031 | + 1.2931, |
| 1032 | + 2.397673571899466, |
| 1033 | + 8.2956, |
| 1034 | + 6.686820427099132, |
| 1035 | + 0.45021679958387956, |
| 1036 | + 3.077875127553957, |
| 1037 | + 0.053520395733247045, |
| 1038 | + 1.6539992229052127, |
| 1039 | + 0.1466206769107436, |
| 1040 | + 0.6300772488850335, |
| 1041 | + 1.611965002575047, |
| 1042 | + 0.012840136810798864, |
| 1043 | + 0.34853762746216305, |
| 1044 | + 1.8878958285806287, |
| 1045 | + 0.8546376191171063, |
| 1046 | + 1.8729, |
| 1047 | + 0.6748536823468675, |
| 1048 | + 0.20451266082721842, |
| 1049 | + 0.22622814695113844, |
| 1050 | + 0.46030603398979064, |
| 1051 | + ] |
| 1052 | + assert scheduler.parameters != DIFFERENT_PARAMETERS |
| 1053 | + scheduler_with_different_parameters = Scheduler(parameters=DIFFERENT_PARAMETERS) |
| 1054 | + rescheduled_card = scheduler_with_different_parameters.reschedule_card( |
| 1055 | + card=card, review_logs=review_logs |
| 1056 | + ) |
| 1057 | + |
| 1058 | + assert card.card_id == rescheduled_card.card_id |
| 1059 | + assert card.state == rescheduled_card.state |
| 1060 | + assert card.step == rescheduled_card.step |
| 1061 | + assert card.stability != rescheduled_card.stability |
| 1062 | + assert card.difficulty != rescheduled_card.difficulty |
| 1063 | + assert card.last_review == rescheduled_card.last_review |
| 1064 | + assert card.due != rescheduled_card.due |
| 1065 | + |
| 1066 | + def test_reschedule_card_different_desired_retention(self): |
| 1067 | + scheduler = Scheduler(enable_fuzzing=False) |
| 1068 | + |
| 1069 | + card = Card() |
| 1070 | + |
| 1071 | + review_logs = [] |
| 1072 | + for rating in TEST_RATINGS_1: |
| 1073 | + card, review_log = scheduler.review_card( |
| 1074 | + card=card, rating=rating, review_datetime=card.due |
| 1075 | + ) |
| 1076 | + review_logs.append(review_log) |
| 1077 | + |
| 1078 | + DIFFERENT_DESIRED_RETENTION = 0.8 |
| 1079 | + assert scheduler.desired_retention != DIFFERENT_DESIRED_RETENTION |
| 1080 | + scheduler_with_different_retention = Scheduler( |
| 1081 | + desired_retention=DIFFERENT_DESIRED_RETENTION |
| 1082 | + ) |
| 1083 | + rescheduled_card = scheduler_with_different_retention.reschedule_card( |
| 1084 | + card=card, review_logs=review_logs |
| 1085 | + ) |
| 1086 | + |
| 1087 | + assert card.card_id == rescheduled_card.card_id |
| 1088 | + assert card.state == rescheduled_card.state |
| 1089 | + assert card.step == rescheduled_card.step |
| 1090 | + assert card.stability == rescheduled_card.stability |
| 1091 | + assert card.difficulty == rescheduled_card.difficulty |
| 1092 | + assert card.last_review == rescheduled_card.last_review |
| 1093 | + assert card.due < rescheduled_card.due |
| 1094 | + |
| 1095 | + def test_reschedule_card_different_learning_steps(self): |
| 1096 | + scheduler = Scheduler(enable_fuzzing=False) |
| 1097 | + |
| 1098 | + card = Card() |
| 1099 | + |
| 1100 | + review_logs = [] |
| 1101 | + for rating in TEST_RATINGS_1: |
| 1102 | + card, review_log = scheduler.review_card( |
| 1103 | + card=card, rating=rating, review_datetime=card.due |
| 1104 | + ) |
| 1105 | + review_logs.append(review_log) |
| 1106 | + |
| 1107 | + DIFFERENT_LEARNING_STEPS = [timedelta(minutes=1)] * len(review_logs) |
| 1108 | + assert scheduler.learning_steps != DIFFERENT_LEARNING_STEPS |
| 1109 | + scheduler_with_different_retention = Scheduler( |
| 1110 | + learning_steps=DIFFERENT_LEARNING_STEPS |
| 1111 | + ) |
| 1112 | + rescheduled_card = scheduler_with_different_retention.reschedule_card( |
| 1113 | + card=card, review_logs=review_logs |
| 1114 | + ) |
| 1115 | + |
| 1116 | + assert card.card_id == rescheduled_card.card_id |
| 1117 | + assert card.state != rescheduled_card.state |
| 1118 | + assert card.step != rescheduled_card.step |
| 1119 | + assert card.stability == rescheduled_card.stability |
| 1120 | + assert card.difficulty == rescheduled_card.difficulty |
| 1121 | + assert card.last_review == rescheduled_card.last_review |
| 1122 | + assert card.due > rescheduled_card.due |
| 1123 | + |
| 1124 | + def test_reschedule_card_wrong_review_logs(self): |
| 1125 | + scheduler = Scheduler(enable_fuzzing=False) |
| 1126 | + |
| 1127 | + card = Card() |
| 1128 | + |
| 1129 | + review_logs = [] |
| 1130 | + for rating in TEST_RATINGS_1: |
| 1131 | + card, review_log = scheduler.review_card( |
| 1132 | + card=card, rating=rating, review_datetime=card.due |
| 1133 | + ) |
| 1134 | + review_logs.append(review_log) |
| 1135 | + |
| 1136 | + DIFFERENT_CARD_ID = 123 |
| 1137 | + assert card.card_id != DIFFERENT_CARD_ID |
| 1138 | + review_logs[0].card_id = DIFFERENT_CARD_ID |
| 1139 | + |
| 1140 | + EXPECTED_ERROR_MESSAGE = f"ReviewLog card_id {DIFFERENT_CARD_ID} does not match Card card_id {card.card_id}" |
| 1141 | + with pytest.raises(ValueError, match=re.escape(EXPECTED_ERROR_MESSAGE)): |
| 1142 | + _ = scheduler.reschedule_card(card=card, review_logs=review_logs) |
| 1143 | + |
1014 | 1144 | def test_Optimizer_lazy_loading(self): |
1015 | 1145 | assert "fsrs.scheduler" in sys.modules |
1016 | 1146 | assert "fsrs.card" in sys.modules |
|
0 commit comments