Search in sources :

Example 56 with Sched

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]));
}
Also used : Collection(com.ichi2.libanki.Collection) Time(com.ichi2.libanki.utils.Time) Card(com.ichi2.libanki.Card) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Example 57 with Sched

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));
}
Also used : Note(com.ichi2.libanki.Note) Collection(com.ichi2.libanki.Collection) Card(com.ichi2.libanki.Card) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Example 58 with Sched

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));
}
Also used : Collection(com.ichi2.libanki.Collection) CollectionTask.nonTaskUndo(com.ichi2.async.CollectionTask.nonTaskUndo) Card(com.ichi2.libanki.Card) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Example 59 with Sched

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);
}
Also used : Collection(com.ichi2.libanki.Collection) DeckConfig(com.ichi2.libanki.DeckConfig) Card(com.ichi2.libanki.Card) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Example 60 with Sched

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;
}
Also used : TemplateRenderOutput(com.ichi2.libanki.TemplateManager.TemplateRenderContext.TemplateRenderOutput) Arrays(java.util.Arrays) TaskManager(com.ichi2.async.TaskManager) NonNull(androidx.annotation.NonNull) UsageAnalytics(com.ichi2.anki.analytics.UsageAnalytics) AbstractSched(com.ichi2.libanki.sched.AbstractSched) Random(java.util.Random) DroidBackend(com.ichi2.libanki.backend.DroidBackend) Time(com.ichi2.libanki.utils.Time) FunctionalInterfaces(com.ichi2.utils.FunctionalInterfaces) ParsedNode(com.ichi2.libanki.template.ParsedNode) KotlinCleanup(com.ichi2.utils.KotlinCleanup) SupportSQLiteDatabase(androidx.sqlite.db.SupportSQLiteDatabase) Locale(java.util.Locale) UIUtils(com.ichi2.anki.UIUtils) Map(java.util.Map) CancelListener.isCancelled(com.ichi2.async.CancelListener.isCancelled) JSONException(com.ichi2.utils.JSONException) SQLiteDatabaseLockedException(android.database.sqlite.SQLiteDatabaseLockedException) PrintWriter(java.io.PrintWriter) Upgrade(com.ichi2.upgrade.Upgrade) HashUtil(com.ichi2.utils.HashUtil) GregorianCalendar(java.util.GregorianCalendar) Set(java.util.Set) JSONObject(com.ichi2.utils.JSONObject) Timber(timber.log.Timber) CancelListener(com.ichi2.async.CancelListener) Contract(org.jetbrains.annotations.Contract) List(java.util.List) BackendNotSupportedException(com.ichi2.libanki.backend.exception.BackendNotSupportedException) Nullable(androidx.annotation.Nullable) AnkiDroidApp(com.ichi2.anki.AnkiDroidApp) ContentValues(android.content.ContentValues) UnknownDatabaseVersionException(com.ichi2.libanki.exception.UnknownDatabaseVersionException) Pattern(java.util.regex.Pattern) VersionUtils(com.ichi2.utils.VersionUtils) RustCleanup(net.ankiweb.rsdroid.RustCleanup) Context(android.content.Context) Pair(android.util.Pair) R(com.ichi2.anki.R) HashMap(java.util.HashMap) Sched(com.ichi2.libanki.sched.Sched) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) SuppressLint(android.annotation.SuppressLint) JSONArray(com.ichi2.utils.JSONArray) Calendar(java.util.Calendar) ProgressSender(com.ichi2.async.ProgressSender) ChessFilter(com.ichi2.libanki.hooks.ChessFilter) SupportSQLiteStatement(androidx.sqlite.db.SupportSQLiteStatement) Cursor(android.database.Cursor) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) CheckResult(androidx.annotation.CheckResult) BufferedWriter(java.io.BufferedWriter) FileWriter(java.io.FileWriter) SchedV2(com.ichi2.libanki.sched.SchedV2) TextUtils(android.text.TextUtils) CollectionTask(com.ichi2.async.CollectionTask) TemplateError(com.ichi2.libanki.template.TemplateError) IOException(java.io.IOException) File(java.io.File) Consumer(java.util.function.Consumer) NoSuchDeckException(com.ichi2.libanki.exception.NoSuchDeckException) LinkedBlockingDeque(java.util.concurrent.LinkedBlockingDeque) Collections(java.util.Collections) VisibleForTesting(androidx.annotation.VisibleForTesting) Resources(android.content.res.Resources) SQLiteDatabaseLockedException(android.database.sqlite.SQLiteDatabaseLockedException) SuppressLint(android.annotation.SuppressLint) JSONException(com.ichi2.utils.JSONException) SQLiteDatabaseLockedException(android.database.sqlite.SQLiteDatabaseLockedException) BackendNotSupportedException(com.ichi2.libanki.backend.exception.BackendNotSupportedException) UnknownDatabaseVersionException(com.ichi2.libanki.exception.UnknownDatabaseVersionException) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) IOException(java.io.IOException) NoSuchDeckException(com.ichi2.libanki.exception.NoSuchDeckException) File(java.io.File)

Aggregations

Card (com.ichi2.libanki.Card)44 Collection (com.ichi2.libanki.Collection)38 Test (org.junit.Test)35 RobolectricTest (com.ichi2.anki.RobolectricTest)28 Note (com.ichi2.libanki.Note)19 AbstractSched (com.ichi2.libanki.sched.AbstractSched)18 DeckConfig (com.ichi2.libanki.DeckConfig)11 JSONObject (com.ichi2.utils.JSONObject)9 Cursor (android.database.Cursor)7 Sched (com.ichi2.libanki.Sched)6 SchedV2 (com.ichi2.libanki.sched.SchedV2)6 JSONArray (com.ichi2.utils.JSONArray)6 SuppressLint (android.annotation.SuppressLint)4 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)4 DB (com.ichi2.libanki.DB)4 Model (com.ichi2.libanki.Model)4 Sched (com.ichi2.libanki.sched.Sched)4 ArrayList (java.util.ArrayList)4 Matchers.containsString (org.hamcrest.Matchers.containsString)4 ContentValues (android.content.ContentValues)3