Search in sources :

Example 31 with Time

use of com.ichi2.libanki.utils.Time in project Anki-Android by ankidroid.

the class Sched method _getCard.

/*
      Getting the next card ****************************************************
      *******************************************
     */
/**
 * Return the next due card, or null.
 */
@Override
@Nullable
protected Card _getCard() {
    // learning card due?
    @Nullable Card c = _getLrnCard(false);
    if (c != null) {
        return c;
    }
    // new first, or time for one?
    if (_timeForNewCard()) {
        c = _getNewCard();
        if (c != null) {
            return c;
        }
    }
    // Card due for review?
    c = _getRevCard();
    if (c != null) {
        return c;
    }
    // day learning card due?
    c = _getLrnDayCard();
    if (c != null) {
        return c;
    }
    // New cards left?
    c = _getNewCard();
    if (c != null) {
        return c;
    }
    // collapse or finish
    return _getLrnCard(true);
}
Also used : Nullable(androidx.annotation.Nullable) Card(com.ichi2.libanki.Card) Nullable(androidx.annotation.Nullable)

Example 32 with Time

use of com.ichi2.libanki.utils.Time in project Anki-Android by ankidroid.

the class FinderTest method test_findCards.

@Test
public void test_findCards() {
    Collection col = getCol();
    Note note = col.newNote();
    note.setItem("Front", "dog");
    note.setItem("Back", "cat");
    note.addTag("monkey animal_1 * %");
    col.addNote(note);
    long n1id = note.getId();
    long firstCardId = note.cards().get(0).getId();
    note = col.newNote();
    note.setItem("Front", "goats are fun");
    note.setItem("Back", "sheep");
    note.addTag("sheep goat horse animal11");
    col.addNote(note);
    long n2id = note.getId();
    note = col.newNote();
    note.setItem("Front", "cat");
    note.setItem("Back", "sheep");
    col.addNote(note);
    Card catCard = note.cards().get(0);
    Model m = col.getModels().current();
    m = col.getModels().copy(m);
    ModelManager mm = col.getModels();
    JSONObject t = Models.newTemplate("Reverse");
    t.put("qfmt", "{{Back}}");
    t.put("afmt", "{{Front}}");
    mm.addTemplateModChanged(m, t);
    mm.save(m);
    note = col.newNote();
    note.setItem("Front", "test");
    note.setItem("Back", "foo bar");
    col.addNote(note);
    col.save();
    List<Long> latestCardIds = note.cids();
    // tag searches
    assertEquals(5, col.findCards("tag:*").size());
    assertEquals(1, col.findCards("tag:\\*").size());
    assertEquals(5, col.findCards("tag:%").size());
    assertEquals(1, col.findCards("tag:\\%").size());
    assertEquals(2, col.findCards("tag:animal_1").size());
    assertEquals(1, col.findCards("tag:animal\\_1").size());
    assertEquals(0, col.findCards("tag:donkey").size());
    assertEquals(1, col.findCards("tag:sheep").size());
    assertEquals(1, col.findCards("tag:sheep tag:goat").size());
    assertEquals(0, col.findCards("tag:sheep tag:monkey").size());
    assertEquals(1, col.findCards("tag:monkey").size());
    assertEquals(1, col.findCards("tag:sheep -tag:monkey").size());
    assertEquals(4, col.findCards("-tag:sheep").size());
    col.getTags().bulkAdd(col.getDb().queryLongList("select id from notes"), "foo bar");
    assertEquals(5, col.findCards("tag:foo").size());
    assertEquals(5, col.findCards("tag:bar").size());
    col.getTags().bulkRem(col.getDb().queryLongList("select id from notes"), "foo");
    assertEquals(0, col.findCards("tag:foo").size());
    assertEquals(5, col.findCards("tag:bar").size());
    // text searches
    assertEquals(2, col.findCards("cat").size());
    assertEquals(1, col.findCards("cat -dog").size());
    assertEquals(1, col.findCards("cat -dog").size());
    assertEquals(1, col.findCards("are goats").size());
    assertEquals(0, col.findCards("\"are goats\"").size());
    assertEquals(1, col.findCards("\"goats are\"").size());
    // card states
    Card c = note.cards().get(0);
    c.setQueue(QUEUE_TYPE_REV);
    c.setType(CARD_TYPE_REV);
    assertEquals(0, col.findCards("is:review").size());
    c.flush();
    assertEqualsArrayList((new Long[] { c.getId() }), col.findCards("is:review"));
    assertEquals(0, col.findCards("is:due").size());
    c.setDue(0);
    c.setQueue(QUEUE_TYPE_REV);
    c.flush();
    assertEqualsArrayList((new Long[] { c.getId() }), col.findCards("is:due"));
    assertEquals(4, col.findCards("-is:due").size());
    c.setQueue(QUEUE_TYPE_SUSPENDED);
    // ensure this card gets a later mod time
    c.flush();
    col.getDb().execute("update cards set mod = mod + 1 where id = ?", c.getId());
    assertEqualsArrayList((new Long[] { c.getId() }), col.findCards("is:suspended"));
    // nids
    assertEquals(0, col.findCards("nid:54321").size());
    assertEquals(2, col.findCards("nid:" + note.getId()).size());
    assertEquals(2, col.findCards("nid:" + n1id + "," + n2id).size());
    // templates
    assertEquals(0, col.findCards("card:foo").size());
    assertEquals(4, col.findCards("\"card:card 1\"").size());
    assertEquals(1, col.findCards("card:reverse").size());
    assertEquals(4, col.findCards("card:1").size());
    assertEquals(1, col.findCards("card:2").size());
    // fields
    assertEquals(1, col.findCards("front:dog").size());
    assertEquals(4, col.findCards("-front:dog").size());
    assertEquals(0, col.findCards("front:sheep").size());
    assertEquals(2, col.findCards("back:sheep").size());
    assertEquals(3, col.findCards("-back:sheep").size());
    assertEquals(0, col.findCards("front:do").size());
    assertEquals(5, col.findCards("front:*").size());
    // ordering
    col.set_config("sortType", "noteCrt");
    col.flush();
    assertTrue(latestCardIds.contains(getLastListElement(col.findCards("front:*", new SortOrder.UseCollectionOrdering()))));
    assertTrue(latestCardIds.contains(getLastListElement(col.findCards("", new SortOrder.UseCollectionOrdering()))));
    col.set_config("sortType", "noteFld");
    col.flush();
    assertEquals(catCard.getId(), (long) col.findCards("", new SortOrder.UseCollectionOrdering()).get(0));
    assertTrue(latestCardIds.contains(getLastListElement(col.findCards("", new SortOrder.UseCollectionOrdering()))));
    col.set_config("sortType", "cardMod");
    col.flush();
    assertTrue(latestCardIds.contains(getLastListElement(col.findCards("", new SortOrder.UseCollectionOrdering()))));
    assertEquals(firstCardId, (long) col.findCards("", new SortOrder.UseCollectionOrdering()).get(0));
    col.set_config("sortBackwards", true);
    col.flush();
    assertTrue(latestCardIds.contains(col.findCards("", new SortOrder.UseCollectionOrdering()).get(0)));
    /* TODO: Port BuiltinSortKind
           assertEquals(firstCardId,
           col.findCards("", BuiltinSortKind.CARD_DUE, reverse=false).get(0)
           );
           assertNotEquals(firstCardId,
           col.findCards("", BuiltinSortKind.CARD_DUE, reverse=true).get(0));
        */
    // model
    assertEquals(3, col.findCards("note:basic").size());
    assertEquals(2, col.findCards("-note:basic").size());
    assertEquals(5, col.findCards("-note:foo").size());
    // col
    assertEquals(5, col.findCards("deck:default").size());
    assertEquals(0, col.findCards("-deck:default").size());
    assertEquals(5, col.findCards("-deck:foo").size());
    assertEquals(5, col.findCards("deck:def*").size());
    assertEquals(5, col.findCards("deck:*EFAULT").size());
    assertEquals(0, col.findCards("deck:*cefault").size());
    // full search
    note = col.newNote();
    note.setItem("Front", "hello<b>world</b>");
    note.setItem("Back", "abc");
    col.addNote(note);
    // as it's the sort field, it matches
    assertEquals(2, col.findCards("helloworld").size());
    // assertEquals(, col.findCards("helloworld", full=true).size())2 This is commented upstream
    // if we put it on the back, it won't
    String note_front = note.getItem("Front");
    String note_back = note.getItem("Back");
    note.setItem("Front", note_back);
    note.setItem("Back", note_front);
    note.flush();
    assertEquals(0, col.findCards("helloworld").size());
    //  Those lines are commented above
    // assertEquals(, col.findCards("helloworld", full=true).size())2
    // assertEquals(, col.findCards("back:helloworld", full=true).size())2
    // searching for an invalid special tag should not error
    // TODO: ensure the search fail
    // assertThrows(Exception.class, () -> col.findCards("is:invalid").size());
    // should be able to limit to parent col, no children
    long id = col.getDb().queryLongScalar("select id from cards limit 1");
    col.getDb().execute("update cards set did = ? where id = ?", addDeck("Default::Child"), id);
    col.save();
    assertEquals(7, col.findCards("deck:default").size());
    assertEquals(1, col.findCards("deck:default::child").size());
    assertEquals(6, col.findCards("deck:default -deck:default::*").size());
    // properties
    id = col.getDb().queryLongScalar("select id from cards limit 1");
    col.getDb().execute("update cards set queue=2, ivl=10, reps=20, due=30, factor=2200 where id = ?", id);
    assertEquals(1, col.findCards("prop:ivl>5").size());
    assertThat(col.findCards("prop:ivl<5").size(), greaterThan(1));
    assertEquals(1, col.findCards("prop:ivl>=5").size());
    assertEquals(0, col.findCards("prop:ivl=9").size());
    assertEquals(1, col.findCards("prop:ivl=10").size());
    assertThat(col.findCards("prop:ivl!=10").size(), greaterThan(1));
    assertEquals(1, col.findCards("prop:due>0").size());
    // due dates should work
    assertEquals(0, col.findCards("prop:due=29").size());
    assertEquals(1, col.findCards("prop:due=30").size());
    // ease factors
    assertEquals(0, col.findCards("prop:ease=2.3").size());
    assertEquals(1, col.findCards("prop:ease=2.2").size());
    assertEquals(1, col.findCards("prop:ease>2").size());
    assertThat(col.findCards("-prop:ease>2").size(), greaterThan(1));
    // recently failed
    if (!isNearCutoff(col)) {
        assertEquals(0, col.findCards("rated:1:1").size());
        assertEquals(0, col.findCards("rated:1:2").size());
        c = getCard();
        col.getSched().answerCard(c, Consts.BUTTON_TWO);
        assertEquals(0, col.findCards("rated:1:1").size());
        assertEquals(1, col.findCards("rated:1:2").size());
        c = getCard();
        col.getSched().answerCard(c, Consts.BUTTON_ONE);
        assertEquals(1, col.findCards("rated:1:1").size());
        assertEquals(1, col.findCards("rated:1:2").size());
        assertEquals(2, col.findCards("rated:1").size());
        assertEquals(0, col.findCards("rated:0:2").size());
        assertEquals(1, col.findCards("rated:2:2").size());
        // added
        assertEquals(0, col.findCards("added:0").size());
        col.getDb().execute("update cards set id = id - " + SECONDS_PER_DAY * 1000 + " where id = ?", id);
        assertEquals(col.cardCount() - 1, col.findCards("added:1").size());
        assertEquals(col.cardCount(), col.findCards("added:2").size());
    } else {
        Timber.w("some find tests disabled near cutoff");
    }
    // empty field
    assertEquals(0, col.findCards("front:").size());
    note = col.newNote();
    note.setItem("Front", "");
    note.setItem("Back", "abc2");
    assertEquals(1, col.addNote(note));
    assertEquals(1, col.findCards("front:").size());
    // OR searches and nesting
    assertEquals(2, col.findCards("tag:monkey or tag:sheep").size());
    assertEquals(2, col.findCards("(tag:monkey OR tag:sheep)").size());
    assertEquals(6, col.findCards("-(tag:monkey OR tag:sheep)").size());
    assertEquals(2, col.findCards("tag:monkey or (tag:sheep sheep)").size());
    assertEquals(1, col.findCards("tag:monkey or (tag:sheep octopus)").size());
// flag
// Todo: ensure it fails
// assertThrows(Exception.class, () -> col.findCards("flag:12"));
}
Also used : JSONObject(com.ichi2.utils.JSONObject) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Example 33 with Time

use of com.ichi2.libanki.utils.Time in project Anki-Android by ankidroid.

the class ReviewerTest method testMultipleCards.

@Test
public synchronized void testMultipleCards() throws ConfirmModSchemaException {
    addNoteWithThreeCards();
    Collection col = getCol();
    JSONObject nw = col.getDecks().confForDid(1).getJSONObject("new");
    MockTime time = getCollectionTime();
    nw.put("delays", new JSONArray(new int[] { 1, 10, 60, 120 }));
    waitForAsyncTasksToComplete();
    Reviewer reviewer = startReviewer();
    waitForAsyncTasksToComplete();
    assertCounts(reviewer, 3, 0, 0);
    // card 1 is shown
    answerCardOrdinalAsGood(reviewer, 1);
    // card get scheduler in [10, 12.5] minutes
    time.addM(3);
    // We wait 3 minutes to ensure card 2 is scheduled after card 1
    // card 2 is shown
    answerCardOrdinalAsGood(reviewer, 2);
    // Same as above
    time.addM(3);
    // card 3 is shown
    answerCardOrdinalAsGood(reviewer, 3);
    undo(reviewer);
    assertCurrentOrdIs(reviewer, 3);
    // card 3 is shown
    answerCardOrdinalAsGood(reviewer, 3);
    // Anki Desktop shows "1"
    assertCurrentOrdIsNot(reviewer, 3);
}
Also used : JSONObject(com.ichi2.utils.JSONObject) JSONArray(com.ichi2.utils.JSONArray) Collection(com.ichi2.libanki.Collection) MockTime(com.ichi2.testutils.MockTime) Test(org.junit.Test)

Example 34 with Time

use of com.ichi2.libanki.utils.Time in project Anki-Android by ankidroid.

the class ReviewerTest method jsTime4ShouldBeBlankIfButtonUnavailable.

@Test
public void jsTime4ShouldBeBlankIfButtonUnavailable() {
    // #6623 - easy should be blank when displaying a card with 3 buttons (after displaying a review)
    Note firstNote = addNoteUsingBasicModel("Hello", "World");
    moveToReviewQueue(firstNote.firstCard());
    addNoteUsingBasicModel("Hello", "World2");
    Reviewer reviewer = startReviewer();
    AnkiDroidJsAPI javaScriptFunction = reviewer.javaScriptFunction();
    // The answer needs to be displayed to be able to get the time.
    displayAnswer(reviewer);
    assertThat("4 buttons should be displayed", reviewer.getAnswerButtonCount(), is(4));
    String nextTime = javaScriptFunction.ankiGetNextTime4();
    assertThat(nextTime, not(emptyString()));
    // Display the next answer
    reviewer.answerCard(Consts.BUTTON_FOUR);
    displayAnswer(reviewer);
    if (schedVersion == 1) {
        assertThat("The 4th button should not be visible", reviewer.getAnswerButtonCount(), is(3));
        String learnTime = javaScriptFunction.ankiGetNextTime4();
        assertThat("If the 4th button is not visible, there should be no time4 in JS", learnTime, emptyString());
    }
}
Also used : Note(com.ichi2.libanki.Note) Matchers.emptyString(org.hamcrest.Matchers.emptyString) Test(org.junit.Test)

Example 35 with Time

use of com.ichi2.libanki.utils.Time in project Anki-Android by ankidroid.

the class OverviewStatsBuilderTest method testInfoHtmlStringMonth.

@Test
@Config(qualifiers = "en")
public void testInfoHtmlStringMonth() {
    OverviewStatsBuilder statsTester = new OverviewStatsBuilder(new WebView(getTargetContext()), getCol(), 42L, Stats.AxisType.TYPE_MONTH);
    String HTML = statsTester.createInfoHtmlString();
    assertEquals(HTML, "<center><style>\n" + "h1, h3 { margin-bottom: 0; margin-top: 1em; text-transform: capitalize; }\n" + ".pielabel { text-align:center; padding:0px; color:white; }\n" + "body {color:#FFFFFF;}\n" + "</style><h1>Today</h1>Studied <b>0 cards</b> in <b>0 minutes</b> today<br>Again count: <b>0</b><br>Learn: <b>0</b>, review: <b>0</b>, relearn: <b>0</b>, filtered: <b>0</b><br>No mature cards were studied today<h1>1 month</h1><h3>FORECAST</h3>Total: <b>0</b> reviews<br>Average: <b>0.0</b> reviews/day<br>Due tomorrow: <b>0</b><br><h3>REVIEW COUNT</h3>Days studied: <b>0%</b> (0 of 30)<br>Total: <b>0</b> reviews<br>Average for days studied: <b>0.0</b> reviews/day<br>If you studied every day: <b>0.0</b> reviews/day<br><h3>REVIEW TIME</h3>Days studied: <b>0%</b> (0 of 30)<br>Total: <b>0</b> minutes<br>Average for days studied: <b>0.0</b> minutes/day<br>If you studied every day: <b>0.0</b> minutes/day<br>Average answer time: <b>0.0s</b> (<b>0.00</b> cards/minute)<br><h3>ADDED</h3>Total: <b>0</b> cards<br>Average: <b>0.0</b> cards/day<br><h3>INTERVALS</h3>Average interval: <b>0.0</b> hours<br>Longest interval: <b>0.0</b> hours<h3>ANSWER BUTTONS</h3>Learning: <b>0.00%</b> correct (0 of 0)<br>Young: <b>0.00%</b> correct (0 of 0)<br>Mature: <b>0.00%</b> correct (0 of 0)<h3>CARD TYPES</h3>Total cards: <b>0</b><br>Total notes: <b>0</b><br>Lowest ease: <b>0%</b><br>Average ease: <b>0%</b><br>Highest ease: <b>0%</b></center>");
}
Also used : WebView(android.webkit.WebView) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test) Config(org.robolectric.annotation.Config)

Aggregations

Test (org.junit.Test)27 Collection (com.ichi2.libanki.Collection)26 JSONObject (com.ichi2.utils.JSONObject)26 RobolectricTest (com.ichi2.anki.RobolectricTest)19 Card (com.ichi2.libanki.Card)19 Note (com.ichi2.libanki.Note)15 JSONArray (com.ichi2.utils.JSONArray)15 Deck (com.ichi2.libanki.Deck)11 ArrayList (java.util.ArrayList)11 DeckConfig (com.ichi2.libanki.DeckConfig)10 IOException (java.io.IOException)10 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)9 HashMap (java.util.HashMap)9 Cursor (android.database.Cursor)8 Nullable (androidx.annotation.Nullable)8 JSONException (com.ichi2.utils.JSONException)8 SharedPreferences (android.content.SharedPreferences)7 Resources (android.content.res.Resources)7 File (java.io.File)7 View (android.view.View)5