Search in sources :

Example 96 with Model

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

the class CollectionTest method test_noteAddDelete.

/**
 *****************
 ** autogenerated from https://github.com/ankitects/anki/blob/2c73dcb2e547c44d9e02c20a00f3c52419dc277b/pylib/tests/test_cards.py *
 ******************
 */
/*TODO
      @Test
      public void test_create_open(){
      (fd, path) = tempfile.mkstemp(suffix=".anki2", prefix="test_attachNew");
      try {
      os.close(fd);
      os.unlink(path);
      } catch (OSError) {
      }
      Collection col = aopen(path);
      // for open()
      String newPath = col.getPath();
      long newMod = col.getMod();
      col.close();

      // reopen
      col = aopen(newPath);
      assertEquals(newMod, col.getMod());
      col.close();

      // non-writeable dir
      if (isWin) {
      String dir = "c:\root.anki2";
      } else {
      String dir = "/attachroot.anki2";
      }
      assertException(Exception, lambda: aopen(dir));
      // reuse tmp file from before, test non-writeable file
      os.chmod(newPath, 0);
      assertException(Exception, lambda: aopen(newPath));
      os.chmod(newPath, 0o666);
      os.unlink(newPath);
      } */
@Test
public void test_noteAddDelete() {
    Collection col = getCol();
    // add a note
    Note note = col.newNote();
    note.setItem("Front", "one");
    note.setItem("Back", "two");
    int n = col.addNote(note);
    assertEquals(1, n);
    // test multiple cards - add another template
    Model m = col.getModels().current();
    ModelManager mm = col.getModels();
    JSONObject t = Models.newTemplate("Reverse");
    t.put("qfmt", "{{Back}}");
    t.put("afmt", "{{Front}}");
    mm.addTemplateModChanged(m, t);
    // todo: remove true which is not upstream
    mm.save(m, true);
    assertEquals(2, col.cardCount());
    // creating new notes should use both cards
    note = col.newNote();
    note.setItem("Front", "three");
    note.setItem("Back", "four");
    n = col.addNote(note);
    assertEquals(2, n);
    assertEquals(4, col.cardCount());
    // check q/a generation
    Card c0 = note.cards().get(0);
    assertThat(c0.q(), containsString("three"));
    // it should not be a duplicate
    assertEquals(note.dupeOrEmpty(), Note.DupeOrEmpty.CORRECT);
    // now let's make a duplicate
    Note note2 = col.newNote();
    note2.setItem("Front", "one");
    note2.setItem("Back", "");
    assertNotEquals(note2.dupeOrEmpty(), Note.DupeOrEmpty.CORRECT);
    // empty first field should not be permitted either
    note2.setItem("Front", " ");
    assertNotEquals(note2.dupeOrEmpty(), Note.DupeOrEmpty.CORRECT);
}
Also used : JSONObject(com.ichi2.utils.JSONObject) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Example 97 with Model

use of com.ichi2.libanki.Model 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 98 with Model

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

the class ReviewerTest method cloneTemplate.

private void cloneTemplate(ModelManager models, Model m) throws ConfirmModSchemaException {
    JSONArray tmpls = m.getJSONArray("tmpls");
    JSONObject defaultTemplate = tmpls.getJSONObject(0);
    JSONObject newTemplate = defaultTemplate.deepClone();
    newTemplate.put("ord", tmpls.length());
    String card_name = getTargetContext().getString(R.string.card_n_name, tmpls.length() + 1);
    newTemplate.put("name", card_name);
    models.addTemplate(m, newTemplate);
}
Also used : JSONObject(com.ichi2.utils.JSONObject) JSONArray(com.ichi2.utils.JSONArray) Matchers.emptyString(org.hamcrest.Matchers.emptyString)

Example 99 with Model

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

the class ReviewerTest method jsAnkiGetDeckName.

@Test
public void jsAnkiGetDeckName() {
    Collection col = getCol();
    ModelManager models = col.getModels();
    DeckManager decks = col.getDecks();
    Long didAb = addDeck("A::B");
    Model basic = models.byName(AnkiDroidApp.getAppResources().getString(R.string.basic_model_name));
    basic.put("did", didAb);
    addNoteUsingBasicModel("foo", "bar");
    Long didA = addDeck("A");
    decks.select(didA);
    Reviewer reviewer = startReviewer();
    AnkiDroidJsAPI javaScriptFunction = reviewer.javaScriptFunction();
    waitForAsyncTasksToComplete();
    assertThat(javaScriptFunction.ankiGetDeckName(), is("B"));
}
Also used : Model(com.ichi2.libanki.Model) Collection(com.ichi2.libanki.Collection) DeckManager(com.ichi2.libanki.DeckManager) ModelManager(com.ichi2.libanki.ModelManager) Test(org.junit.Test)

Example 100 with Model

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

the class TemporaryModelTest method testAddDeleteTracking.

@Test
public void testAddDeleteTracking() {
    // Assume you start with a 2 template model (like "Basic (and reversed)")
    // Add a 3rd new template, remove the 2nd, remove the 1st, add a new now-2nd, remove 1st again
    // ...and it should reduce to just removing the original 1st/2nd and adding the final as first
    TemporaryModel tempModel = new TemporaryModel(new Model("{ \"foo\": \"bar\" }"));
    tempModel.addTemplateChange(ADD, 3);
    Object[][] expected1 = { { 3, ADD } };
    // 3 templates and one change now
    assertTemplateChangesEqual(expected1, tempModel.getTemplateChanges());
    assertTemplateChangesEqual(expected1, tempModel.getAdjustedTemplateChanges());
    Assert.assertArrayEquals(new int[] { 3 }, tempModel.getDeleteDbOrds(3));
    tempModel.addTemplateChange(DELETE, 2);
    // 2 templates and two changes now
    Object[][] expected2 = { { 3, ADD }, { 2, DELETE } };
    Object[][] adjExpected2 = { { 2, ADD }, { 2, DELETE } };
    assertTemplateChangesEqual(expected2, tempModel.getTemplateChanges());
    assertTemplateChangesEqual(adjExpected2, tempModel.getAdjustedTemplateChanges());
    Assert.assertArrayEquals(new int[] { 2, 4 }, tempModel.getDeleteDbOrds(3));
    tempModel.addTemplateChange(DELETE, 1);
    // 1 template and three changes now
    Assert.assertArrayEquals(new int[] { 2, 1, 5 }, tempModel.getDeleteDbOrds(3));
    Object[][] expected3 = { { 3, ADD }, { 2, DELETE }, { 1, DELETE } };
    Object[][] adjExpected3 = { { 1, ADD }, { 2, DELETE }, { 1, DELETE } };
    assertTemplateChangesEqual(expected3, tempModel.getTemplateChanges());
    assertTemplateChangesEqual(adjExpected3, tempModel.getAdjustedTemplateChanges());
    tempModel.addTemplateChange(ADD, 2);
    // 2 templates and 4 changes now
    Assert.assertArrayEquals(new int[] { 2, 1, 5 }, tempModel.getDeleteDbOrds(3));
    Object[][] expected4 = { { 3, ADD }, { 2, DELETE }, { 1, DELETE }, { 2, ADD } };
    Object[][] adjExpected4 = { { 1, ADD }, { 2, DELETE }, { 1, DELETE }, { 2, ADD } };
    assertTemplateChangesEqual(expected4, tempModel.getTemplateChanges());
    assertTemplateChangesEqual(adjExpected4, tempModel.getAdjustedTemplateChanges());
    // Make sure we can resurrect these changes across lifecycle
    Bundle outBundle = tempModel.toBundle();
    assertTemplateChangesEqual(expected4, outBundle.getSerializable("mTemplateChanges"));
    // This is the hard part. We will delete a template we added so everything shifts.
    // The template currently at ordinal 1 was added as template 3 at the start before it slid down on the deletes
    // So the first template add should be negated by this delete, and the second template add should slide down to 1
    tempModel.addTemplateChange(DELETE, 1);
    // 1 template and 3 changes now (the delete just cancelled out one of the adds)
    Assert.assertArrayEquals(new int[] { 2, 1, 5 }, tempModel.getDeleteDbOrds(3));
    Object[][] expected5 = { { 2, DELETE }, { 1, DELETE }, { 1, ADD } };
    Object[][] adjExpected5 = { { 2, DELETE }, { 1, DELETE }, { 1, ADD } };
    assertTemplateChangesEqual(expected5, tempModel.getTemplateChanges());
    assertTemplateChangesEqual(adjExpected5, tempModel.getAdjustedTemplateChanges());
    tempModel.addTemplateChange(ADD, 2);
    // 2 template and 4 changes now (the delete just cancelled out one of the adds)
    Assert.assertArrayEquals(new int[] { 2, 1, 5 }, tempModel.getDeleteDbOrds(3));
    Object[][] expected6 = { { 2, DELETE }, { 1, DELETE }, { 1, ADD }, { 2, ADD } };
    Object[][] adjExpected6 = { { 2, DELETE }, { 1, DELETE }, { 1, ADD }, { 2, ADD } };
    assertTemplateChangesEqual(expected6, tempModel.getTemplateChanges());
    assertTemplateChangesEqual(adjExpected6, tempModel.getAdjustedTemplateChanges());
    tempModel.addTemplateChange(ADD, 3);
    // 2 template and 4 changes now (the delete just cancelled out one of the adds)
    Assert.assertArrayEquals(new int[] { 2, 1, 5 }, tempModel.getDeleteDbOrds(3));
    Object[][] expected7 = { { 2, DELETE }, { 1, DELETE }, { 1, ADD }, { 2, ADD }, { 3, ADD } };
    Object[][] adjExpected7 = { { 2, DELETE }, { 1, DELETE }, { 1, ADD }, { 2, ADD }, { 3, ADD } };
    assertTemplateChangesEqual(expected7, tempModel.getTemplateChanges());
    assertTemplateChangesEqual(adjExpected7, tempModel.getAdjustedTemplateChanges());
    tempModel.addTemplateChange(DELETE, 3);
    // 1 template and 3 changes now (two deletes cancelled out adds)
    Assert.assertArrayEquals(new int[] { 2, 1, 5 }, tempModel.getDeleteDbOrds(3));
    Object[][] expected8 = { { 2, DELETE }, { 1, DELETE }, { 1, ADD }, { 2, ADD } };
    Object[][] adjExpected8 = { { 2, DELETE }, { 1, DELETE }, { 1, ADD }, { 2, ADD } };
    assertTemplateChangesEqual(expected8, tempModel.getTemplateChanges());
    assertTemplateChangesEqual(adjExpected8, tempModel.getAdjustedTemplateChanges());
}
Also used : Bundle(android.os.Bundle) Model(com.ichi2.libanki.Model) Test(org.junit.Test)

Aggregations

JSONObject (com.ichi2.utils.JSONObject)124 Model (com.ichi2.libanki.Model)95 Test (org.junit.Test)82 JSONArray (com.ichi2.utils.JSONArray)79 Collection (com.ichi2.libanki.Collection)53 ArrayList (java.util.ArrayList)48 Note (com.ichi2.libanki.Note)40 RobolectricTest (com.ichi2.anki.RobolectricTest)38 JSONException (com.ichi2.utils.JSONException)32 Intent (android.content.Intent)30 Card (com.ichi2.libanki.Card)27 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)26 HashMap (java.util.HashMap)22 Bundle (android.os.Bundle)20 NonNull (androidx.annotation.NonNull)20 SuppressLint (android.annotation.SuppressLint)16 View (android.view.View)16 ConfirmationDialog (com.ichi2.anki.dialogs.ConfirmationDialog)15 IOException (java.io.IOException)15 Nullable (androidx.annotation.Nullable)14