com.ichi2.libanki.test.FindTestCase.java Source code

Java tutorial

Introduction

Here is the source code for com.ichi2.libanki.test.FindTestCase.java

Source

/****************************************************************************************
 * Copyright (c) 2012 Kostas Spyropoulos <inigo.aldana@gmail.com>                       *
 *                                                                                      *
 * This program is free software; you can redistribute it and/or modify it under        *
 * the terms of the GNU General Public License as published by the Free Software        *
 * Foundation; either version 3 of the License, or (at your option) any later           *
 * version.                                                                             *
 *                                                                                      *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
 * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
 *                                                                                      *
 * You should have received a copy of the GNU General Public License along with         *
 * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
 ****************************************************************************************/
package com.ichi2.libanki.test;

import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.MediumTest;

import com.ichi2.anki.Pair;
import com.ichi2.libanki.Card;
import com.ichi2.libanki.Collection;
import com.ichi2.libanki.Finder;
import com.ichi2.libanki.Models;
import com.ichi2.libanki.Note;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

public class FindTestCase extends InstrumentationTestCase {
    public FindTestCase(String name) {
        setName(name);
    }

    @MediumTest
    public void test_parse() {
        Finder f = new Finder(null);
        assertTrue(Arrays.equals(f._tokenize("hello world"), new String[] { "hello", "world" }));
        assertTrue(Arrays.equals(f._tokenize("hello  world"), new String[] { "hello", "world" }));
        assertTrue(Arrays.equals(f._tokenize("one -two"), new String[] { "one", "-", "two" }));
        assertTrue(Arrays.equals(f._tokenize("one --two"), new String[] { "one", "-", "two" }));
        assertTrue(Arrays.equals(f._tokenize("one - two"), new String[] { "one", "-", "two" }));
        assertTrue(Arrays.equals(f._tokenize("one or -two"), new String[] { "one", "or", "-", "two" }));
        assertTrue(Arrays.equals(f._tokenize("'hello \"world\"'"), new String[] { "hello \"world\"" }));
        assertTrue(Arrays.equals(f._tokenize("\"hello world\""), new String[] { "hello world" }));
        assertTrue(Arrays.equals(f._tokenize("one (two or ( three or four))"),
                new String[] { "one", "(", "two", "or", "(", "three", "or", "four", ")", ")" }));
        assertTrue(Arrays.equals(f._tokenize("embedded'string"), new String[] { "embedded'string" }));
        assertTrue(Arrays.equals(f._tokenize("deck:'two words'"), new String[] { "deck:two words" }));
    }

    @MediumTest
    public void test_findCards() {
        try {
            Collection deck = Shared.getEmptyDeck(getInstrumentation().getContext());
            Note f = deck.newNote();
            f.setitem("Front", "dog");
            f.setitem("Back", "cat");
            f.addTag("monkey");
            long f1id = f.getId();
            deck.addNote(f);
            long firstCardId = f.cards().get(0).getId();
            f = deck.newNote();
            f.setitem("Front", "goats are fun");
            f.setitem("Back", "sheep");
            f.addTag("sheep goat horse");
            deck.addNote(f);
            long f2id = f.getId();
            f = deck.newNote();
            f.setitem("Front", "cat");
            f.setitem("Back", "sheep");
            deck.addNote(f);
            Card catCard = f.cards().get(0);
            JSONObject m = deck.getModels().current();
            Models mm = deck.getModels();
            JSONObject t = mm.newTemplate("Reverse");
            t.put("qfmt", "{{Back}}");
            t.put("afmt", "{{Front}}");
            mm.addTemplate(m, t);
            mm.save(m);
            f = deck.newNote();
            f.setitem("Front", "test");
            f.setitem("Back", "foo bar");
            deck.addNote(f);
            ArrayList<Card> cards = f.cards();
            ArrayList<Long> latestCardIds = new ArrayList<Long>();
            for (Card c : cards) {
                latestCardIds.add(c.getId());
            }
            // tag searches
            assertTrue(deck.findCards("tag:donkey").size() == 0);
            assertTrue(deck.findCards("tag:sheep").size() == 1);
            assertTrue(deck.findCards("tag:sheep tag:goat").size() == 1);
            assertTrue(deck.findCards("tag:sheep tag:monkey").size() == 0);
            assertTrue(deck.findCards("tag:monkey").size() == 1);
            assertTrue(deck.findCards("tag:sheep -tag:monkey").size() == 1);
            assertTrue(deck.findCards("-tag:sheep").size() == 4);
            deck.getTags().bulkAdd(deck.getDb().queryColumn(Long.class, "select id from notes", 0), "foo bar");
            assertTrue(deck.findCards("tag:bar").size() == 5);
            assertTrue(deck.findCards("tag:foo").size() == 5);
            deck.getTags().bulkRem(deck.getDb().queryColumn(Long.class, "select id from notes", 0), "foo");
            assertTrue(deck.findCards("tag:foo").size() == 0);
            assertTrue(deck.findCards("tag:bar").size() == 5);
            // text searches
            assertTrue(deck.findCards("cat").size() == 2);
            assertTrue(deck.findCards("cat -dog").size() == 1);
            assertTrue(deck.findCards("are goats").size() == 1);
            assertTrue(deck.findCards("\"are goats\"").size() == 0);
            assertTrue(deck.findCards("\"goats are\"").size() == 1);
            // card states
            Card c = f.cards().get(0);
            c.setType(2);
            c.setQueue(2);
            assertTrue(deck.findCards("is:review").size() == 0);
            c.flush();
            assertTrue(Arrays.equals(deck.findCards("is:review").toArray(new Long[] {}), new Long[] { c.getId() }));
            assertTrue(deck.findCards("is:due").size() == 0);
            c.setDue(0);
            c.setQueue(2);
            c.flush();
            assertTrue(Arrays.equals(deck.findCards("is:due").toArray(new Long[] {}), new Long[] { c.getId() }));
            assertTrue(deck.findCards("-is:due").size() == 4);
            c.setQueue(-1);
            // ensure this card gets a later mod time
            c.flush();
            deck.getDb().execute("update cards set mod = mod + 1 where id = " + c.getId());
            assertTrue(
                    Arrays.equals(deck.findCards("is:suspended").toArray(new Long[] {}), new Long[] { c.getId() }));
            // nids
            assertTrue(deck.findCards("nid:54321").size() == 0);
            assertTrue(deck.findCards("nid:" + f.getId()).size() == 2);
            assertTrue(deck.findCards("nid:" + f1id + "," + f2id).size() == 2);
            // templates
            assertTrue(deck.findCards("card:foo").size() == 0);
            assertTrue(deck.findCards("'card:card 1'").size() == 4);
            assertTrue(deck.findCards("card:reverse").size() == 1);
            assertTrue(deck.findCards("card:1").size() == 4);
            assertTrue(deck.findCards("card:2").size() == 1);
            //fields
            assertTrue(deck.findCards("front:dog").size() == 1);
            assertTrue(deck.findCards("-front:dog").size() == 4);
            assertTrue(deck.findCards("front:sheep").size() == 0);
            assertTrue(deck.findCards("back:sheep").size() == 2);
            assertTrue(deck.findCards("-back:sheep").size() == 3);
            assertTrue(deck.findCards("front:do").size() == 0);
            assertTrue(deck.findCards("front:*").size() == 5);
            // ordering
            deck.getConf().put("sortType", "noteCrt");
            List<Long> c2 = deck.findCards("front:*", true);
            assertTrue(latestCardIds.contains(c2.get(c2.size() - 1)));
            c2 = deck.findCards("", true);
            assertTrue(latestCardIds.contains(c2.get(c2.size() - 1)));
            deck.getConf().put("sortType", "noteFld");
            c2 = deck.findCards("", true);
            assertTrue(c2.get(0) == catCard.getId());
            assertTrue(latestCardIds.contains(c2.get(c2.size() - 1)));
            deck.getConf().put("sortType", "cardMod");
            c2 = deck.findCards("", true);
            assertTrue(latestCardIds.contains(c2.get(c2.size() - 1)));
            assertTrue(c2.get(0) == firstCardId);
            deck.getConf().put("sortBackwards", true);
            c2 = deck.findCards("", true);
            assertTrue(latestCardIds.contains(c2.get(0)));
            // model
            assertTrue(deck.findCards("note:basic").size() == 5);
            assertTrue(deck.findCards("-note:basic").size() == 0);
            assertTrue(deck.findCards("-note:foo").size() == 5);
            // deck
            assertTrue(deck.findCards("deck:default").size() == 5);
            assertTrue(deck.findCards("-deck:default").size() == 0);
            assertTrue(deck.findCards("-deck:foo").size() == 5);
            assertTrue(deck.findCards("deck:def*").size() == 5);
            assertTrue(deck.findCards("deck:*EFAULT").size() == 5);
            assertTrue(deck.findCards("deck:*cefault").size() == 0);
            // full search
            f = deck.newNote();
            f.setitem("Front", "hello<b>world</b>");
            f.setitem("Back", "abc");
            deck.addNote(f);
            // as it's the sort field, it matches
            assertTrue(deck.findCards("helloworld").size() == 2);
            //assertTrue(deck.findCards("helloworld", full=true).size() == 2);
            // if we put it on the back, it won't
            String tmpf = f.getitem("Front");
            String tmpb = f.getitem("Back");
            f.setitem("Front", tmpb);
            f.setitem("Back", tmpf);
            f.flush();
            assertTrue(deck.findCards("helloworld").size() == 0);
            //assertTrue(deck.findCards("helloworld", full=true).size() == 2);
            //assertTrue(deck.findCards("back:helloworld", full=true).size() == 2);
            // searching for an invalid special tag should not error
            assertTrue(deck.findCards("is:invalid").size() == 0);
            // should be able to limit to parent deck, no children
            long id = deck.getDb().queryLongScalar("SELECT id FROM cards LIMIT 1");
            deck.getDb().execute(
                    "UPDATE cards SET did = " + deck.getDecks().id("Default::Child") + " WHERE id = " + id);
            assertTrue(deck.findCards("deck:default").size() == 7);
            assertTrue(deck.findCards("deck:default::child").size() == 1);
            assertTrue(deck.findCards("deck:default -deck:default::*").size() == 6);
            // properties
            id = deck.getDb().queryLongScalar("SELECT id FROM cards LIMIT 1");
            deck.getDb().execute("update cards set queue=2, ivl=10, reps=20, due=30, factor=2200 where id = ?",
                    new Object[] { id });
            assertTrue(deck.findCards("prop:ivl>5").size() == 1);
            assertTrue(deck.findCards("prop:ivl<5").size() > 1);
            assertTrue(deck.findCards("prop:ivl>=5").size() == 1);
            assertTrue(deck.findCards("prop:ivl=9").size() == 0);
            assertTrue(deck.findCards("prop:ivl=10").size() == 1);
            assertTrue(deck.findCards("prop:ivl!=10").size() > 1);
            assertTrue(deck.findCards("prop:due>0").size() == 1);
            // due dates should work
            deck.getSched().setToday(15);
            assertTrue(deck.findCards("prop:due=14").size() == 0);
            assertTrue(deck.findCards("prop:due=15").size() == 1);
            assertTrue(deck.findCards("prop:due=16").size() == 0);
            // including negatives
            deck.getSched().setToday(32);
            assertTrue(deck.findCards("prop:due=-1").size() == 0);
            assertTrue(deck.findCards("prop:due=-2").size() == 1);
            // ease factors
            assertTrue(deck.findCards("prop:ease=2.3").size() == 0);
            assertTrue(deck.findCards("prop:ease=2.2").size() == 1);
            assertTrue(deck.findCards("prop:ease>2").size() == 1);
            assertTrue(deck.findCards("-prop:ease>2").size() > 1);
            // recently failed
            assertTrue(deck.findCards("rated:1:1").size() == 0);
            assertTrue(deck.findCards("rated:1:2").size() == 0);
            c = deck.getSched().getCard();
            deck.getSched().answerCard(c, 2);
            assertTrue(deck.findCards("rated:1:1").size() == 0);
            assertTrue(deck.findCards("rated:1:2").size() == 1);
            c = deck.getSched().getCard();
            deck.getSched().answerCard(c, 1);
            assertTrue(deck.findCards("rated:1:1").size() == 1);
            assertTrue(deck.findCards("rated:1:2").size() == 1);
            assertTrue(deck.findCards("rated:1").size() == 2);
            assertTrue(deck.findCards("rated:0:2").size() == 0);
            assertTrue(deck.findCards("rated:2:2").size() == 1);
            // empty field
            assertTrue(deck.findCards("front:").size() == 0);
            f = deck.newNote();
            f.setitem("Front", "");
            f.setitem("Back", "abc2");
            assertTrue(deck.addNote(f) == 1);
            assertTrue(deck.findCards("front:").size() == 1);
            // OR searches and nesting
            assertTrue(deck.findCards("tag:monkey or tag:sheep").size() == 2);
            assertTrue(deck.findCards("(tag:monkey OR tag:sheep)").size() == 2);
            assertTrue(deck.findCards("-(tag:monkey OR tag:sheep)").size() == 6);
            assertTrue(deck.findCards("tag:monkey or (tag:sheep sheep)").size() == 2);
            assertTrue(deck.findCards("tag:monkey or (tag:sheep octopus)").size() == 1);
            // invalid grouping shouldn't error
            assertTrue(deck.findCards(")").size() == 0);
            assertTrue(deck.findCards("(()").size() == 0);
            // added
            assertTrue(deck.findCards("added:0").size() == 0);
            deck.getDb().execute("update cards set id = id - 86400*1000 where id = " + id);
            assertTrue(deck.findCards("added:1").size() == deck.cardCount() - 1);
            assertTrue(deck.findCards("added:2").size() == deck.cardCount());
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
    }

    @MediumTest
    public void test_findReplace() {
        Collection deck = Shared.getEmptyDeck(getInstrumentation().getContext());
        Note f = deck.newNote();
        f.setitem("Front", "foo");
        f.setitem("Back", "bar");
        f.addTag("monkey");
        deck.addNote(f);
        Note f2 = deck.newNote();
        f2.setitem("Front", "baz");
        f2.setitem("Back", "foo");
        f2.addTag("monkey");
        deck.addNote(f2);
        List<Long> nids = new ArrayList<Long>(Arrays.asList(new Long[] { f.getId(), f2.getId() }));
        // should do nothing
        assertTrue(deck.findReplace(nids, "abc", "123") == 0);
        // global replace
        assertTrue(deck.findReplace(nids, "foo", "qux") == 2);
        f.load();
        assertTrue(f.getitem("Front").equals("qux"));
        f2.load();
        assertTrue(f2.getitem("Back").equals("qux"));
        // single field replace
        assertTrue(deck.findReplace(nids, "qux", "foo", "Front") == 1);
        f.load();
        assertTrue(f.getitem("Front").equals("foo"));
        f2.load();
        assertTrue(f2.getitem("Back").equals("qux"));
        // regex replace
        assertTrue(deck.findReplace(nids, "B.r", "reg") == 0);
        f.load();
        assertTrue(!f.getitem("Back").equals("reg"));
        assertTrue(deck.findReplace(nids, "B.r", "reg", true) == 1);
        f.load();
        assertTrue(f.getitem("Back").equals("reg"));
    }

    @MediumTest
    public void test_findDupes() {
        Collection deck = Shared.getEmptyDeck(getInstrumentation().getContext());
        Note f = deck.newNote();
        f.setitem("Front", "foo");
        f.setitem("Back", "bar");
        deck.addNote(f);
        Note f2 = deck.newNote();
        f2.setitem("Front", "baz");
        f2.setitem("Back", "bar");
        deck.addNote(f2);
        Note f3 = deck.newNote();
        f3.setitem("Front", "quux");
        f3.setitem("Back", "bar");
        deck.addNote(f3);
        Note f4 = deck.newNote();
        f4.setitem("Front", "quuux");
        f4.setitem("Back", "nope");
        deck.addNote(f4);
        List<Pair<String, List<Long>>> r = deck.findDupes("Back");
        assertTrue(r.get(0).first.equals("bar"));
        assertTrue(r.get(0).second.size() == 3);
        // valid search
        r = deck.findDupes("Back", "bar");
        assertTrue(r.get(0).first.equals("bar"));
        assertTrue(r.get(0).second.size() == 3);
        // excludes everything
        r = deck.findDupes("Back", "invalid");
        assertTrue(r.size() == 0);
        // front isn't dupe
        assertTrue(deck.findDupes("Front").size() == 0);
    }
}