use of com.ichi2.libanki.Model 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());
}
use of com.ichi2.libanki.Model in project AnkiChinaAndroid by ankichinateam.
the class TemporaryModelTest method testTempModelStorage.
@Test
public void testTempModelStorage() throws Exception {
// Start off with clean state in the cache dir
TemporaryModel.clearTempModelFiles();
// Make sure save / retrieve works
String tempModelPath = TemporaryModel.saveTempModel(getTargetContext(), new JSONObject("{foo: bar}"));
Assert.assertNotNull("Saving temp model unsuccessful", tempModelPath);
JSONObject tempModel = TemporaryModel.getTempModel(tempModelPath);
Assert.assertNotNull("Temp model not read successfully", tempModel);
Assert.assertEquals(new JSONObject("{foo: bar}").toString(), tempModel.toString());
// Make sure clearing works
Assert.assertEquals(1, TemporaryModel.clearTempModelFiles());
Timber.i("The following logged NoSuchFileException is an expected part of verifying a file delete.");
try {
TemporaryModel.getTempModel(tempModelPath);
Assert.fail("Should have caught an exception here because the file is missing");
} catch (IOException e) {
// this is expected
}
}
use of com.ichi2.libanki.Model 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());
}
use of com.ichi2.libanki.Model 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 }));
}
use of com.ichi2.libanki.Model 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());
}
Aggregations