use of com.ichi2.libanki.sched.Sched in project Anki-Android by ankidroid.
the class AbstractSchedTest method regression_7984.
@Test
public void regression_7984() {
Collection col = getCol();
SchedV2 sched = (SchedV2) col.getSched();
Time time = getCol().getTime();
Card[] cards = new Card[2];
for (int i = 0; i < 2; i++) {
cards[i] = addNoteUsingBasicModel(Integer.toString(i), "").cards().get(0);
cards[i].setQueue(Consts.QUEUE_TYPE_LRN);
cards[i].setType(Consts.CARD_TYPE_LRN);
cards[i].setDue(time.intTime() - 20 * 60 + i);
cards[i].flush();
}
col.reset();
// Regression test success non deterministically without the sleep
Card gotten = sched.getCard();
advanceRobolectricLooperWithSleep();
assertThat(gotten, is(cards[0]));
sched.answerCard(gotten, Consts.BUTTON_ONE);
gotten = sched.getCard();
assertThat(gotten, is(cards[1]));
sched.answerCard(gotten, Consts.BUTTON_ONE);
gotten = sched.getCard();
assertThat(gotten, is(cards[0]));
}
use of com.ichi2.libanki.sched.Sched in project Anki-Android by ankidroid.
the class AbstractSchedTest method testCardQueue.
@Test
public void testCardQueue() {
Collection col = getCol();
SchedV2 sched = (SchedV2) col.getSched();
SimpleCardQueue queue = new SimpleCardQueue(sched);
assertThat(queue.size(), is(0));
final int nbCard = 6;
long[] cids = new long[nbCard];
for (int i = 0; i < nbCard; i++) {
Note note = addNoteUsingBasicModel("foo", "bar");
Card card = note.firstCard();
long cid = card.getId();
cids[i] = cid;
queue.add(cid);
}
assertThat(queue.size(), is(nbCard));
assertEquals(cids[0], queue.removeFirstCard().getId());
assertThat(queue.size(), is(nbCard - 1));
queue.remove(cids[1]);
assertThat(queue.size(), is(nbCard - 2));
queue.remove(cids[3]);
assertThat(queue.size(), is(nbCard - 3));
assertEquals(cids[2], queue.removeFirstCard().getId());
assertThat(queue.size(), is(nbCard - 4));
assertEquals(cids[4], queue.removeFirstCard().getId());
assertThat(queue.size(), is(nbCard - 5));
}
use of com.ichi2.libanki.sched.Sched in project Anki-Android by ankidroid.
the class AbstractSchedTest method testUndoResetsCardCountsToCorrectValue.
@Test
public void testUndoResetsCardCountsToCorrectValue() throws InterruptedException {
// #6587
addNoteUsingBasicModel("Hello", "World");
Collection col = getCol();
AbstractSched sched = col.getSched();
col.reset();
Card cardBeforeUndo = sched.getCard();
Counts countsBeforeUndo = sched.counts();
// Not shown in the UI, but there is a state where the card has been removed from the queue, but not answered
// where the counts are decremented.
assertThat(countsBeforeUndo, is(new Counts(0, 0, 0)));
sched.answerCard(cardBeforeUndo, Consts.BUTTON_THREE);
waitFortask(new UndoService.Undo().toDelegate(), 5000);
Counts countsAfterUndo = sched.counts();
assertThat("Counts after an undo should be the same as before an undo", countsAfterUndo, is(countsBeforeUndo));
}
use of com.ichi2.libanki.sched.Sched in project Anki-Android by ankidroid.
the class AbstractSchedTest method regression_7066.
@Test
public void regression_7066() {
Collection col = getCol();
DeckConfig dconf = col.getDecks().getConf(1);
dconf.getJSONObject("new").put("bury", true);
AbstractSched sched = col.getSched();
addNoteUsingBasicAndReversedModel("foo", "bar");
addNoteUsingBasicModel("plop", "foo");
col.reset();
Card card = sched.getCard();
sched.setCurrentCard(card);
sched.preloadNextCard();
sched.answerCard(card, Consts.BUTTON_THREE);
card = sched.getCard();
sched.setCurrentCard(card);
AnkiAssert.assertDoesNotThrow(sched::preloadNextCard);
}
use of com.ichi2.libanki.sched.Sched in project Anki-Android by ankidroid.
the class Collection method fixIntegrity.
/**
* Fix possible problems and rebuild caches.
*/
public CheckDatabaseResult fixIntegrity(TaskManager.ProgressCallback<String> progressCallback) {
File file = new File(mPath);
CheckDatabaseResult result = new CheckDatabaseResult(file.length());
final int[] currentTask = { 1 };
// a few fixes are in all-models loops, the rest are one-offs
int totalTasks = (getModels().all().size() * 4) + 27;
Runnable notifyProgress = () -> fixIntegrityProgress(progressCallback, currentTask[0]++, totalTasks);
Consumer<FunctionalInterfaces.FunctionThrowable<Runnable, List<String>, JSONException>> executeIntegrityTask = function -> {
// DEFECT: notifyProgress will lag if an exception is thrown.
try {
mDb.getDatabase().beginTransaction();
result.addAll(function.apply(notifyProgress));
mDb.getDatabase().setTransactionSuccessful();
} catch (Exception e) {
Timber.e(e, "Failed to execute integrity check");
AnkiDroidApp.sendExceptionReport(e, "fixIntegrity");
} finally {
try {
mDb.getDatabase().endTransaction();
} catch (Exception e) {
Timber.e(e, "Failed to end integrity check transaction");
AnkiDroidApp.sendExceptionReport(e, "fixIntegrity - endTransaction");
}
}
};
try {
mDb.getDatabase().beginTransaction();
save();
notifyProgress.run();
if (!mDb.getDatabase().isDatabaseIntegrityOk()) {
return result.markAsFailed();
}
mDb.getDatabase().setTransactionSuccessful();
} catch (SQLiteDatabaseLockedException ex) {
Timber.w(ex, "doInBackgroundCheckDatabase - Database locked");
return result.markAsLocked();
} catch (RuntimeException e) {
Timber.e(e, "doInBackgroundCheckDatabase - RuntimeException on marking card");
AnkiDroidApp.sendExceptionReport(e, "doInBackgroundCheckDatabase");
return result.markAsFailed();
} finally {
// if the database was locked, we never got the transaction.
if (mDb.getDatabase().inTransaction()) {
mDb.getDatabase().endTransaction();
}
}
executeIntegrityTask.accept(this::deleteNotesWithMissingModel);
// for each model
for (Model m : getModels().all()) {
executeIntegrityTask.accept((callback) -> deleteCardsWithInvalidModelOrdinals(callback, m));
executeIntegrityTask.accept((callback) -> deleteNotesWithWrongFieldCounts(callback, m));
}
executeIntegrityTask.accept(this::deleteNotesWithMissingCards);
executeIntegrityTask.accept(this::deleteCardsWithMissingNotes);
executeIntegrityTask.accept(this::removeOriginalDuePropertyWhereInvalid);
executeIntegrityTask.accept(this::removeDynamicPropertyFromNonDynamicDecks);
executeIntegrityTask.accept(this::removeDeckOptionsFromDynamicDecks);
executeIntegrityTask.accept(this::resetInvalidDeckOptions);
executeIntegrityTask.accept(this::rebuildTags);
executeIntegrityTask.accept(this::updateFieldCache);
executeIntegrityTask.accept(this::fixNewCardDuePositionOverflow);
executeIntegrityTask.accept(this::resetNewCardInsertionPosition);
executeIntegrityTask.accept(this::fixExcessiveReviewDueDates);
// v2 sched had a bug that could create decimal intervals
executeIntegrityTask.accept(this::fixDecimalCardsData);
executeIntegrityTask.accept(this::fixDecimalRevLogData);
executeIntegrityTask.accept(this::restoreMissingDatabaseIndices);
executeIntegrityTask.accept(this::ensureModelsAreNotEmpty);
executeIntegrityTask.accept((progressNotifier) -> this.ensureCardsHaveHomeDeck(progressNotifier, result));
// and finally, optimize (unable to be done inside transaction).
try {
optimize(notifyProgress);
} catch (Exception e) {
Timber.e(e, "optimize");
AnkiDroidApp.sendExceptionReport(e, "fixIntegrity - optimize");
}
file = new File(mPath);
long newSize = file.length();
result.setNewSize(newSize);
// if any problems were found, force a full sync
if (result.hasProblems()) {
modSchemaNoCheck();
}
logProblems(result.getProblems());
return result;
}
Aggregations