Search in sources :

Example 11 with Template

use of com.ichi2.libanki.template.Template in project AnkiChinaAndroid by ankichinateam.

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)

Example 12 with Template

use of com.ichi2.libanki.template.Template in project AnkiChinaAndroid by ankichinateam.

the class CardTemplateEditorTest method testDeleteTemplate.

@Test
public void testDeleteTemplate() {
    String modelName = "Basic (and reversed card)";
    // Start the CardTemplateEditor with a specific model, and make sure the model starts unchanged
    JSONObject collectionBasicModelOriginal = getCurrentDatabaseModelCopy(modelName);
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.putExtra("modelId", collectionBasicModelOriginal.getLong("id"));
    ActivityController<CardTemplateEditor> templateEditorController = Robolectric.buildActivity(CardTemplateEditor.class, intent).create().start().resume().visible();
    saveControllerForCleanup(templateEditorController);
    CardTemplateEditor testEditor = (CardTemplateEditor) templateEditorController.get();
    Assert.assertFalse("Model should not have changed yet", testEditor.modelHasChanged());
    Assert.assertEquals("Model should have 2 templates now", 2, testEditor.getTempModel().getTemplateCount());
    // Try to delete the template - click delete, click confirm for card delete, click confirm again for full sync
    ShadowActivity shadowTestEditor = shadowOf(testEditor);
    Assert.assertTrue("Unable to click?", shadowTestEditor.clickMenuItem(R.id.action_delete));
    advanceRobolectricLooper();
    Assert.assertEquals("Wrong dialog shown?", "Delete the “Card 1” card type, and its 0 cards?", getDialogText(true));
    clickDialogButton(DialogAction.POSITIVE, true);
    advanceRobolectricLooper();
    Assert.assertTrue("Model should have changed", testEditor.modelHasChanged());
    Assert.assertEquals("Model should have 1 template now", 1, testEditor.getTempModel().getTemplateCount());
    // Try to delete the template again, but there's only one
    Assert.assertTrue("Unable to click?", shadowTestEditor.clickMenuItem(R.id.action_delete));
    advanceRobolectricLooper();
    Assert.assertEquals("Did not show dialog about deleting only card?", getResourceString(R.string.card_template_editor_cant_delete), getDialogText(true));
    Assert.assertEquals("Change already in database?", collectionBasicModelOriginal.toString().trim(), getCurrentDatabaseModelCopy(modelName).toString().trim());
    // Save the change to the database and make sure there's only one template after
    JSONObject testEditorModelEdited = testEditor.getTempModel().getModel();
    Assert.assertTrue("Unable to click?", shadowTestEditor.clickMenuItem(R.id.action_confirm));
    advanceRobolectricLooper();
    JSONObject collectionBasicModelCopyEdited = getCurrentDatabaseModelCopy(modelName);
    Assert.assertNotEquals("model is unchanged?", collectionBasicModelOriginal, collectionBasicModelCopyEdited);
    Assert.assertEquals("model did not save?", testEditorModelEdited.toString().trim(), collectionBasicModelCopyEdited.toString().trim());
}
Also used : JSONObject(com.ichi2.utils.JSONObject) ShadowActivity(org.robolectric.shadows.ShadowActivity) ShadowIntent(org.robolectric.shadows.ShadowIntent) Intent(android.content.Intent) Test(org.junit.Test)

Example 13 with Template

use of com.ichi2.libanki.template.Template in project AnkiChinaAndroid by ankichinateam.

the class CardTemplateEditorTest method testDeleteTemplateWithSelectivelyGeneratedCards.

/**
 * In a model with two card templates using different fields, some notes may only use card 1,
 * and some may only use card 2. If you delete the 2nd template,
 * it will cause the notes that only use card 2 to disappear.
 *
 * So the unit test would then be to make a model like the "basic (optional reverse card)"
 * with two fields Enable1 and Enable2, and two templates "card 1" and "card 2".
 * Both cards use selective generation, so they're empty unless the corresponding field is set.
 *
 * So then in the unit test you make the model, add the two templates, then you add two notes,
 * with Enable1 and Enable2 respectively set to "y".
 * Then you try to delete one of the templates and it should fail
 *
 * (question: but I thought deleting one should work - still one card left to maintain the note,
 * and second template delete should fail since we finally get to a place where no cards are left?
 * I am having trouble creating selectively generated cards though - I can do one optional field but not 2 ugh)
 */
@Test
public void testDeleteTemplateWithSelectivelyGeneratedCards() {
    String modelName = "Basic (optional reversed card)";
    Model collectionBasicModelOriginal = getCurrentDatabaseModelCopy(modelName);
    // Start the CardTemplateEditor with a specific model, and make sure the model starts unchanged
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.putExtra("modelId", collectionBasicModelOriginal.getLong("id"));
    ActivityController<CardTemplateEditor> templateEditorController = Robolectric.buildActivity(CardTemplateEditor.class, intent).create().start().resume().visible();
    saveControllerForCleanup(templateEditorController);
    CardTemplateEditor testEditor = (CardTemplateEditor) templateEditorController.get();
    Assert.assertFalse("Model should not have changed yet", testEditor.modelHasChanged());
    Assert.assertEquals("Model should have 2 templates now", 2, testEditor.getTempModel().getTemplateCount());
    Assert.assertFalse("Ordinal pending add?", TemporaryModel.isOrdinalPendingAdd(testEditor.getTempModel(), 0));
    Assert.assertFalse("Ordinal pending add?", TemporaryModel.isOrdinalPendingAdd(testEditor.getTempModel(), 1));
    // Try to delete Card 1 template - click delete, check confirm for card delete popup indicating it was possible, then dismiss it
    ShadowActivity shadowTestEditor = shadowOf(testEditor);
    Assert.assertTrue("Unable to click?", shadowTestEditor.clickMenuItem(R.id.action_delete));
    advanceRobolectricLooper();
    Assert.assertEquals("Wrong dialog shown?", "Delete the “Card 1” card type, and its 0 cards?", getDialogText(true));
    clickDialogButton(DialogAction.NEGATIVE, true);
    advanceRobolectricLooper();
    Assert.assertFalse("Model should not have changed", testEditor.modelHasChanged());
    // Create note with forward and back info, Add Reverse is empty, so should only be one card
    Note selectiveGeneratedNote = getCol().newNote(collectionBasicModelOriginal);
    selectiveGeneratedNote.setField(0, "TestFront");
    selectiveGeneratedNote.setField(1, "TestBack");
    String[] fields = selectiveGeneratedNote.getFields();
    for (String field : fields) {
        Timber.d("Got a field: %s", field);
    }
    getCol().addNote(selectiveGeneratedNote);
    Assert.assertEquals("selective generation should result in one card", 1, getModelCardCount(collectionBasicModelOriginal));
    // Try to delete the template again, but there's selective generation means it would orphan the note
    Assert.assertTrue("Unable to click?", shadowTestEditor.clickMenuItem(R.id.action_delete));
    advanceRobolectricLooper();
    Assert.assertEquals("Did not show dialog about deleting only card?", getResourceString(R.string.card_template_editor_would_delete_note), getDialogText(true));
    clickDialogButton(DialogAction.POSITIVE, true);
    advanceRobolectricLooper();
    Assert.assertNull("Can delete used template?", getCol().getModels().getCardIdsForModel(collectionBasicModelOriginal.getLong("id"), new int[] { 0 }));
    Assert.assertEquals("Change already in database?", collectionBasicModelOriginal.toString().trim(), getCurrentDatabaseModelCopy(modelName).toString().trim());
    Assert.assertFalse("Ordinal pending add?", TemporaryModel.isOrdinalPendingAdd(testEditor.getTempModel(), 0));
    Assert.assertEquals("Change incorrectly added to list?", 0, testEditor.getTempModel().getTemplateChanges().size());
    // Assert can delete 'Card 2'
    Assert.assertNotNull("Cannot delete unused template?", getCol().getModels().getCardIdsForModel(collectionBasicModelOriginal.getLong("id"), new int[] { 1 }));
    // Edit note to have Add Reverse set to 'y' so we get a second card
    selectiveGeneratedNote.setField(2, "y");
    selectiveGeneratedNote.flush();
    // - assert two cards
    Assert.assertEquals("should be two cards now", 2, getModelCardCount(collectionBasicModelOriginal));
    // - assert can delete either Card template but not both
    Assert.assertNotNull("Cannot delete template?", getCol().getModels().getCardIdsForModel(collectionBasicModelOriginal.getLong("id"), new int[] { 0 }));
    Assert.assertNotNull("Cannot delete template?", getCol().getModels().getCardIdsForModel(collectionBasicModelOriginal.getLong("id"), new int[] { 1 }));
    Assert.assertNull("Can delete both templates?", getCol().getModels().getCardIdsForModel(collectionBasicModelOriginal.getLong("id"), new int[] { 0, 1 }));
    // A couple more notes to make sure things are okay
    Note secondNote = getCol().newNote(collectionBasicModelOriginal);
    secondNote.setField(0, "TestFront2");
    secondNote.setField(1, "TestBack2");
    secondNote.setField(2, "y");
    getCol().addNote(secondNote);
    // - assert can delete either Card template but not both
    Assert.assertNotNull("Cannot delete template?", getCol().getModels().getCardIdsForModel(collectionBasicModelOriginal.getLong("id"), new int[] { 0 }));
    Assert.assertNotNull("Cannot delete template?", getCol().getModels().getCardIdsForModel(collectionBasicModelOriginal.getLong("id"), new int[] { 1 }));
    Assert.assertNull("Can delete both templates?", getCol().getModels().getCardIdsForModel(collectionBasicModelOriginal.getLong("id"), new int[] { 0, 1 }));
}
Also used : Note(com.ichi2.libanki.Note) Model(com.ichi2.libanki.Model) ShadowActivity(org.robolectric.shadows.ShadowActivity) ShadowIntent(org.robolectric.shadows.ShadowIntent) Intent(android.content.Intent) Test(org.junit.Test)

Example 14 with Template

use of com.ichi2.libanki.template.Template in project AnkiChinaAndroid by ankichinateam.

the class CardTemplatePreviewerTest method testPreviewUnsavedTemplate.

@Test
public void testPreviewUnsavedTemplate() throws Exception {
    String modelName = "Basic";
    Model collectionBasicModelOriginal = getCurrentDatabaseModelCopy(modelName);
    JSONObject template = collectionBasicModelOriginal.getJSONArray("tmpls").getJSONObject(0);
    template.put("qfmt", template.getString("qfmt").concat("PREVIEWER_TEST"));
    String tempModelPath = TemporaryModel.saveTempModel(getTargetContext(), collectionBasicModelOriginal);
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.putExtra(TemporaryModel.INTENT_MODEL_FILENAME, tempModelPath);
    intent.putExtra("index", 0);
    ActivityController<TestCardTemplatePreviewer> previewerController = Robolectric.buildActivity(TestCardTemplatePreviewer.class, intent).create().start().resume().visible();
    saveControllerForCleanup((previewerController));
    TestCardTemplatePreviewer testCardTemplatePreviewer = (TestCardTemplatePreviewer) previewerController.get();
    Assert.assertTrue("model change did not show up?", testCardTemplatePreviewer.getDummyCard(collectionBasicModelOriginal, 0).q().contains("PREVIEWER_TEST") && testCardTemplatePreviewer.getDummyCard(collectionBasicModelOriginal, 0).a().contains("PREVIEWER_TEST"));
    // Take it through a destroy/re-create lifecycle in order to test instance state persistence
    Bundle outBundle = new Bundle();
    previewerController.saveInstanceState(outBundle);
    previewerController.pause().stop().destroy();
    previewerController = Robolectric.buildActivity(TestCardTemplatePreviewer.class).create(outBundle).start().resume().visible();
    saveControllerForCleanup(previewerController);
    testCardTemplatePreviewer = (TestCardTemplatePreviewer) previewerController.get();
    Assert.assertTrue("model change not preserved in lifecycle??", testCardTemplatePreviewer.getDummyCard(collectionBasicModelOriginal, 0).q().contains("PREVIEWER_TEST") && testCardTemplatePreviewer.getDummyCard(collectionBasicModelOriginal, 0).a().contains("PREVIEWER_TEST"));
    // Make sure we can click
    Assert.assertFalse("Showing the answer already?", testCardTemplatePreviewer.getShowingAnswer());
    testCardTemplatePreviewer.disableDoubleClickPrevention();
    View showAnswerButton = testCardTemplatePreviewer.findViewById(R.id.preview_buttons_layout);
    showAnswerButton.performClick();
    Assert.assertTrue("Not showing the answer?", testCardTemplatePreviewer.getShowingAnswer());
}
Also used : JSONObject(com.ichi2.utils.JSONObject) Bundle(android.os.Bundle) Model(com.ichi2.libanki.Model) Intent(android.content.Intent) View(android.view.View) Test(org.junit.Test)

Example 15 with Template

use of com.ichi2.libanki.template.Template in project AnkiChinaAndroid by ankichinateam.

the class CardTest method test_genrem.

@Test
public void test_genrem() {
    Collection col = getCol();
    Note note = col.newNote();
    note.setItem("Front", "1");
    note.setItem("Back", "");
    col.addNote(note);
    assertEquals(1, note.numberOfCards());
    Model m = col.getModels().current();
    Models mm = col.getModels();
    // adding a new template should automatically create cards
    JSONObject t = Models.newTemplate("rev");
    t.put("qfmt", "{{Front}}");
    t.put("afmt", "");
    mm.addTemplateModChanged(m, t);
    mm.save(m, true);
    assertEquals(2, note.numberOfCards());
    // if the template is changed to remove cards, they'll be removed
    t = m.getJSONArray("tmpls").getJSONObject(1);
    t.put("qfmt", "{{Back}}");
    mm.save(m, true);
    List<Long> rep = col.emptyCids();
    col.remCards(rep);
    assertEquals(1, note.numberOfCards());
    // if we add to the note, a card should be automatically generated
    note.load();
    note.setItem("Back", "1");
    note.flush();
    assertEquals(2, note.numberOfCards());
}
Also used : JSONObject(com.ichi2.utils.JSONObject) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Aggregations

JSONObject (com.ichi2.utils.JSONObject)53 Test (org.junit.Test)35 JSONArray (com.ichi2.utils.JSONArray)28 Model (com.ichi2.libanki.Model)24 ArrayList (java.util.ArrayList)16 Intent (android.content.Intent)14 RobolectricTest (com.ichi2.anki.RobolectricTest)14 Collection (com.ichi2.libanki.Collection)12 Note (com.ichi2.libanki.Note)12 SuppressLint (android.annotation.SuppressLint)9 HashMap (java.util.HashMap)8 Bundle (android.os.Bundle)7 JSONException (com.ichi2.utils.JSONException)7 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)6 Card (com.ichi2.libanki.Card)6 ShadowActivity (org.robolectric.shadows.ShadowActivity)6 ShadowIntent (org.robolectric.shadows.ShadowIntent)6 View (android.view.View)5 ContentResolver (android.content.ContentResolver)4 ContentValues (android.content.ContentValues)4