use of com.ichi2.libanki.template.Template in project Anki-Android by ankidroid.
the class Storage method _upgradeClozeModel.
private static void _upgradeClozeModel(Collection col, Model m) throws ConfirmModSchemaException {
m.put("type", Consts.MODEL_CLOZE);
// convert first template
JSONObject t = m.getJSONArray("tmpls").getJSONObject(0);
for (String type : new String[] { "qfmt", "afmt" }) {
// noinspection RegExpRedundantEscape // In Android, } should be escaped
t.put(type, t.getString(type).replaceAll("\\{\\{cloze:1:(.+?)\\}\\}", "{{cloze:$1}}"));
}
t.put("name", "Cloze");
// delete non-cloze cards for the model
JSONArray tmpls = m.getJSONArray("tmpls");
ArrayList<JSONObject> rem = new ArrayList<>();
for (JSONObject ta : tmpls.jsonObjectIterable()) {
if (!ta.getString("afmt").contains("{{cloze:")) {
rem.add(ta);
}
}
for (JSONObject r : rem) {
col.getModels().remTemplate(m, r);
}
JSONArray newTmpls = new JSONArray();
newTmpls.put(tmpls.getJSONObject(0));
m.put("tmpls", newTmpls);
Models._updateTemplOrds(m);
col.getModels().save(m);
}
use of com.ichi2.libanki.template.Template 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);
}
use of com.ichi2.libanki.template.Template 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());
}
use of com.ichi2.libanki.template.Template in project Anki-Android by ankidroid.
the class ModelTest method test_cloze_ordinals.
@Test
public void test_cloze_ordinals() throws ConfirmModSchemaException {
Collection col = getCol();
col.getModels().setCurrent(col.getModels().byName("Cloze"));
Model m = col.getModels().current();
ModelManager mm = col.getModels();
// We replace the default Cloze template
JSONObject t = Models.newTemplate("ChainedCloze");
t.put("qfmt", "{{text:cloze:Text}}");
t.put("afmt", "{{text:cloze:Text}}");
mm.addTemplateModChanged(m, t);
mm.save(m);
col.getModels().remTemplate(m, m.getJSONArray("tmpls").getJSONObject(0));
Note note = col.newNote();
note.setItem("Text", "{{c1::firstQ::firstA}}{{c2::secondQ::secondA}}");
col.addNote(note);
assertEquals(2, col.cardCount());
List<Card> cards = note.cards();
assertEquals(2, cards.size());
Card c = cards.get(0);
Card c2 = cards.get(1);
// first card should have first ord
assertEquals(0, c.getOrd());
assertEquals(1, c2.getOrd());
}
use of com.ichi2.libanki.template.Template in project Anki-Android by ankidroid.
the class ModelTest method test_modelChange.
@Test
public void test_modelChange() throws ConfirmModSchemaException {
Collection col = getCol();
Model cloze = col.getModels().byName("Cloze");
// enable second template and add a note
Model basic = col.getModels().current();
ModelManager mm = col.getModels();
JSONObject t = Models.newTemplate("Reverse");
t.put("qfmt", "{{Back}}");
t.put("afmt", "{{Front}}");
mm.addTemplateModChanged(basic, t);
mm.save(basic);
Note note = col.newNote();
note.setItem("Front", "note");
note.setItem("Back", "b123");
col.addNote(note);
// switch fields
Map<Integer, Integer> map = new HashMap<>();
map.put(0, 1);
map.put(1, 0);
col.getModels().change(basic, note.getId(), basic, map, null);
note.load();
assertEquals("b123", note.getItem("Front"));
assertEquals("note", note.getItem("Back"));
// switch cards
Card c0 = note.cards().get(0);
Card c1 = note.cards().get(1);
assertThat(c0.q(), containsString("b123"));
assertThat(c1.q(), containsString("note"));
assertEquals(0, c0.getOrd());
assertEquals(1, c1.getOrd());
col.getModels().change(basic, note.getId(), basic, null, map);
note.load();
c0.load();
c1.load();
assertThat(c0.q(), containsString("note"));
assertThat(c1.q(), containsString("b123"));
assertEquals(1, c0.getOrd());
assertEquals(0, c1.getOrd());
// .cards() returns cards in order
assertEquals(c1.getId(), note.cards().get(0).getId());
// delete first card
map = new HashMap<>();
map.put(0, null);
map.put(1, 1);
// if (isWin) {
// // The low precision timer on Windows reveals a race condition
// time.sleep(0.05);
// }
col.getModels().change(basic, note.getId(), basic, null, map);
note.load();
c0.load();
// the card was deleted
// but we have two cards, as a new one was generated
assertEquals(2, note.numberOfCards());
// an unmapped field becomes blank
assertEquals("b123", note.getItem("Front"));
assertEquals("note", note.getItem("Back"));
col.getModels().change(basic, note.getId(), basic, map, null);
note.load();
assertEquals("", note.getItem("Front"));
assertEquals("note", note.getItem("Back"));
// another note to try model conversion
note = col.newNote();
note.setItem("Front", "f2");
note.setItem("Back", "b2");
col.addNote(note);
// counts = col.getModels().all_use_counts();
// Using older version of the test
assertEquals(2, col.getModels().useCount(basic));
assertEquals(0, col.getModels().useCount(cloze));
// Identity map
map = new HashMap<>();
map.put(0, 0);
map.put(1, 1);
col.getModels().change(basic, note.getId(), cloze, map, map);
note.load();
assertEquals("f2", note.getItem("Text"));
assertEquals(2, note.numberOfCards());
// back the other way, with deletion of second ord
col.getModels().remTemplate(basic, basic.getJSONArray("tmpls").getJSONObject(1));
assertEquals(2, col.getDb().queryScalar("select count() from cards where nid = ?", note.getId()));
map = new HashMap<>();
map.put(0, 0);
col.getModels().change(cloze, note.getId(), basic, map, map);
assertEquals(1, col.getDb().queryScalar("select count() from cards where nid = ?", note.getId()));
}
Aggregations