Search in sources :

Example 16 with ANSWER

use of com.ichi2.anki.CardBrowser.Column.ANSWER in project Anki-Android by ankidroid.

the class DeckPickerTest method notEnoughSpaceToBackupBeforeDowngradeShowsError.

@Test
public void notEnoughSpaceToBackupBeforeDowngradeShowsError() {
    Class<DeckPickerNoSpaceForBackup> clazz = DeckPickerNoSpaceForBackup.class;
    try (MockedStatic<InitialActivity> initialActivityMock = mockStatic(InitialActivity.class, Mockito.CALLS_REAL_METHODS)) {
        initialActivityMock.when(() -> InitialActivity.getStartupFailureType(any())).thenAnswer((Answer<InitialActivity.StartupFailure>) invocation -> InitialActivity.StartupFailure.DATABASE_DOWNGRADE_REQUIRED);
        InitialActivityWithConflictTest.setupForValid(getTargetContext());
        DeckPickerNoSpaceForBackup deckPicker = super.startActivityNormallyOpenCollectionWithIntent(clazz, new Intent());
        assertThat("A downgrade failed dialog should be shown", deckPicker.mDisplayedDowngradeFailed, is(true));
    } finally {
        InitialActivityWithConflictTest.setupForDefault();
    }
}
Also used : Arrays(java.util.Arrays) PackageManager(android.content.pm.PackageManager) AbstractSched(com.ichi2.libanki.sched.AbstractSched) DeckConfig(com.ichi2.libanki.DeckConfig) Map(java.util.Map) Matchers.nullValue(org.hamcrest.Matchers.nullValue) Mockito.doReturn(org.mockito.Mockito.doReturn) Matchers.notNullValue(org.hamcrest.Matchers.notNullValue) ParameterizedRobolectricTestRunner(org.robolectric.ParameterizedRobolectricTestRunner) RuntimeEnvironment(org.robolectric.RuntimeEnvironment) DatabaseErrorDialog(com.ichi2.anki.dialogs.DatabaseErrorDialog) DB(com.ichi2.libanki.DB) Parameters(org.robolectric.ParameterizedRobolectricTestRunner.Parameters) Matchers.instanceOf(org.hamcrest.Matchers.instanceOf) BackendEmulatingOpenConflict(com.ichi2.testutils.BackendEmulatingOpenConflict) MockedStatic(org.mockito.MockedStatic) Storage(com.ichi2.libanki.Storage) DbUtils(com.ichi2.testutils.DbUtils) Matchers.is(org.hamcrest.Matchers.is) Mockito.any(org.mockito.Mockito.any) DialogFragment(androidx.fragment.app.DialogFragment) Mockito.mock(org.mockito.Mockito.mock) Context(android.content.Context) ResourceLoader(com.ichi2.utils.ResourceLoader) DeckPickerConfirmDeleteDeckDialog(com.ichi2.anki.dialogs.DeckPickerConfirmDeleteDeckDialog) Mockito.mockStatic(org.mockito.Mockito.mockStatic) RunWith(org.junit.runner.RunWith) Intent(android.content.Intent) HashMap(java.util.HashMap) Editor(android.content.SharedPreferences.Editor) Collection(com.ichi2.libanki.Collection) Mockito.spy(org.mockito.Mockito.spy) Parameter(org.robolectric.ParameterizedRobolectricTestRunner.Parameter) Answer(org.mockito.stubbing.Answer) Menu(android.view.Menu) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) Before(org.junit.Before) Assert.assertNotNull(org.junit.Assert.assertNotNull) Robolectric(org.robolectric.Robolectric) Test(org.junit.Test) Mockito.times(org.mockito.Mockito.times) Mockito.when(org.mockito.Mockito.when) File(java.io.File) BackupManagerTestUtilities(com.ichi2.testutils.BackupManagerTestUtilities) Mockito.verify(org.mockito.Mockito.verify) AnkiActivityUtils(com.ichi2.testutils.AnkiActivityUtils) Mockito(org.mockito.Mockito) UPGRADE_VERSION_KEY(com.ichi2.anki.DeckPicker.UPGRADE_VERSION_KEY) Mockito.never(org.mockito.Mockito.never) Assert.assertNull(org.junit.Assert.assertNull) SharedPreferences(android.content.SharedPreferences) FrameworkSQLiteOpenHelperFactory(androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory) ActivityScenario(androidx.test.core.app.ActivityScenario) Assert.assertEquals(org.junit.Assert.assertEquals) Intent(android.content.Intent) Test(org.junit.Test)

Example 17 with ANSWER

use of com.ichi2.anki.CardBrowser.Column.ANSWER in project Anki-Android by ankidroid.

the class CardContentProvider method insert.

@Override
public Uri insert(@NonNull Uri uri, ContentValues values) {
    if (!hasReadWritePermission() && shouldEnforceQueryOrInsertSecurity()) {
        throwSecurityException("insert", uri);
    }
    Collection col = CollectionHelper.getInstance().getCol(mContext);
    if (col == null) {
        throw new IllegalStateException(COL_NULL_ERROR_MSG);
    }
    col.log(getLogMessage("insert", uri));
    // Find out what data the user is requesting
    int match = sUriMatcher.match(uri);
    switch(match) {
        case NOTES:
            {
                /* Insert new note with specified fields and tags
                 */
                Long modelId = values.getAsLong(FlashCardsContract.Note.MID);
                String flds = values.getAsString(FlashCardsContract.Note.FLDS);
                String tags = values.getAsString(FlashCardsContract.Note.TAGS);
                Models.AllowEmpty allowEmpty = Models.AllowEmpty.fromBoolean(values.getAsBoolean(FlashCardsContract.Note.ALLOW_EMPTY));
                // Create empty note
                com.ichi2.libanki.Note newNote = new com.ichi2.libanki.Note(col, col.getModels().get(modelId));
                // Set fields
                String[] fldsArray = Utils.splitFields(flds);
                // Check that correct number of flds specified
                if (fldsArray.length != newNote.getFields().length) {
                    throw new IllegalArgumentException("Incorrect flds argument : " + flds);
                }
                for (int idx = 0; idx < fldsArray.length; idx++) {
                    newNote.setField(idx, fldsArray[idx]);
                }
                // Set tags
                if (tags != null) {
                    newNote.setTagsFromStr(tags);
                }
                // Add to collection
                col.addNote(newNote, allowEmpty);
                col.save();
                return Uri.withAppendedPath(FlashCardsContract.Note.CONTENT_URI, Long.toString(newNote.getId()));
            }
        case NOTES_ID:
            // Note ID is generated automatically by libanki
            throw new IllegalArgumentException("Not possible to insert note with specific ID");
        case NOTES_ID_CARDS:
        case NOTES_ID_CARDS_ORD:
            // Cards are generated automatically by libanki
            throw new IllegalArgumentException("Not possible to insert cards directly (only through NOTES)");
        case MODELS:
            // Get input arguments
            String modelName = values.getAsString(FlashCardsContract.Model.NAME);
            String css = values.getAsString(FlashCardsContract.Model.CSS);
            Long did = values.getAsLong(FlashCardsContract.Model.DECK_ID);
            String fieldNames = values.getAsString(FlashCardsContract.Model.FIELD_NAMES);
            Integer numCards = values.getAsInteger(FlashCardsContract.Model.NUM_CARDS);
            Integer sortf = values.getAsInteger(FlashCardsContract.Model.SORT_FIELD_INDEX);
            Integer type = values.getAsInteger(FlashCardsContract.Model.TYPE);
            String latexPost = values.getAsString(FlashCardsContract.Model.LATEX_POST);
            String latexPre = values.getAsString(FlashCardsContract.Model.LATEX_PRE);
            // Throw exception if required fields empty
            if (modelName == null || fieldNames == null || numCards == null) {
                throw new IllegalArgumentException("Model name, field_names, and num_cards can't be empty");
            }
            if (did != null && col.getDecks().isDyn(did)) {
                throw new IllegalArgumentException("Cannot set a filtered deck as default deck for a model");
            }
            // Create a new model
            ModelManager mm = col.getModels();
            Model newModel = mm.newModel(modelName);
            try {
                // Add the fields
                String[] allFields = Utils.splitFields(fieldNames);
                for (String f : allFields) {
                    mm.addFieldInNewModel(newModel, mm.newField(f));
                }
                // Add some empty card templates
                for (int idx = 0; idx < numCards; idx++) {
                    String card_name = mContext.getResources().getString(R.string.card_n_name, idx + 1);
                    JSONObject t = Models.newTemplate(card_name);
                    t.put("qfmt", String.format("{{%s}}", allFields[0]));
                    String answerField = allFields[0];
                    if (allFields.length > 1) {
                        answerField = allFields[1];
                    }
                    t.put("afmt", String.format("{{FrontSide}}\\n\\n<hr id=answer>\\n\\n{{%s}}", answerField));
                    mm.addTemplateInNewModel(newModel, t);
                }
                // Add the CSS if specified
                if (css != null) {
                    newModel.put("css", css);
                }
                // Add the did if specified
                if (did != null) {
                    newModel.put("did", did);
                }
                if (sortf != null && sortf < allFields.length) {
                    newModel.put("sortf", sortf);
                }
                if (type != null) {
                    newModel.put("type", type);
                }
                if (latexPost != null) {
                    newModel.put("latexPost", latexPost);
                }
                if (latexPre != null) {
                    newModel.put("latexPre", latexPre);
                }
                // Add the model to collection (from this point on edits will require a full-sync)
                mm.add(newModel);
                col.save();
                // Get the mid and return a URI
                String mid = Long.toString(newModel.getLong("id"));
                return Uri.withAppendedPath(FlashCardsContract.Model.CONTENT_URI, mid);
            } catch (JSONException e) {
                Timber.e(e, "Could not set a field of new model %s", modelName);
                return null;
            }
        case MODELS_ID:
            // Model ID is generated automatically by libanki
            throw new IllegalArgumentException("Not possible to insert model with specific ID");
        case MODELS_ID_TEMPLATES:
            {
                ModelManager models = col.getModels();
                Long mid = getModelIdFromUri(uri, col);
                Model existingModel = models.get(mid);
                if (existingModel == null) {
                    throw new IllegalArgumentException("model missing: " + mid);
                }
                String name = values.getAsString(CardTemplate.NAME);
                String qfmt = values.getAsString(CardTemplate.QUESTION_FORMAT);
                String afmt = values.getAsString(CardTemplate.ANSWER_FORMAT);
                String bqfmt = values.getAsString(CardTemplate.BROWSER_QUESTION_FORMAT);
                String bafmt = values.getAsString(CardTemplate.BROWSER_ANSWER_FORMAT);
                try {
                    JSONObject t = Models.newTemplate(name);
                    t.put("qfmt", qfmt);
                    t.put("afmt", afmt);
                    t.put("bqfmt", bqfmt);
                    t.put("bafmt", bafmt);
                    models.addTemplate(existingModel, t);
                    models.save(existingModel);
                    col.save();
                    return ContentUris.withAppendedId(uri, t.getInt("ord"));
                } catch (ConfirmModSchemaException e) {
                    throw new IllegalArgumentException("Unable to add template without user requesting/accepting full-sync", e);
                } catch (JSONException e) {
                    throw new IllegalArgumentException("Unable to get ord from new template", e);
                }
            }
        case MODELS_ID_TEMPLATES_ID:
            throw new IllegalArgumentException("Not possible to insert template with specific ORD");
        case MODELS_ID_FIELDS:
            {
                ModelManager models = col.getModels();
                long mid = getModelIdFromUri(uri, col);
                Model existingModel = models.get(mid);
                if (existingModel == null) {
                    throw new IllegalArgumentException("model missing: " + mid);
                }
                String name = values.getAsString(FlashCardsContract.Model.FIELD_NAME);
                if (name == null) {
                    throw new IllegalArgumentException("field name missing for model: " + mid);
                }
                JSONObject field = models.newField(name);
                try {
                    models.addField(existingModel, field);
                    col.save();
                    JSONArray flds = existingModel.getJSONArray("flds");
                    return ContentUris.withAppendedId(uri, flds.length() - 1);
                } catch (ConfirmModSchemaException e) {
                    throw new IllegalArgumentException("Unable to insert field: " + name, e);
                } catch (JSONException e) {
                    throw new IllegalArgumentException("Unable to get newly created field: " + name, e);
                }
            }
        case SCHEDULE:
            // Doesn't make sense to insert an object into the schedule table
            throw new IllegalArgumentException("Not possible to perform insert operation on schedule");
        case DECKS:
            // Insert new deck with specified name
            String deckName = values.getAsString(FlashCardsContract.Deck.DECK_NAME);
            did = col.getDecks().id_for_name(deckName);
            if (did != null) {
                throw new IllegalArgumentException("Deck name already exists: " + deckName);
            }
            if (!Decks.isValidDeckName(deckName)) {
                throw new IllegalArgumentException("Invalid deck name '" + deckName + "'");
            }
            try {
                did = col.getDecks().id(deckName);
            } catch (DeckRenameException filteredSubdeck) {
                throw new IllegalArgumentException(filteredSubdeck.getMessage());
            }
            Deck deck = col.getDecks().get(did);
            if (deck != null) {
                try {
                    String deckDesc = values.getAsString(FlashCardsContract.Deck.DECK_DESC);
                    if (deckDesc != null) {
                        deck.put("desc", deckDesc);
                    }
                } catch (JSONException e) {
                    Timber.e(e, "Could not set a field of new deck %s", deckName);
                    return null;
                }
            }
            col.getDecks().flush();
            return Uri.withAppendedPath(FlashCardsContract.Deck.CONTENT_ALL_URI, Long.toString(did));
        case DECK_SELECTED:
            // Can't have more than one selected deck
            throw new IllegalArgumentException("Selected deck can only be queried and updated");
        case DECKS_ID:
            // Deck ID is generated automatically by libanki
            throw new IllegalArgumentException("Not possible to insert deck with specific ID");
        case MEDIA:
            // contentvalue should have data and preferredFileName values
            return insertMediaFile(values, col);
        default:
            // Unknown URI type
            throw new IllegalArgumentException("uri " + uri + " is not supported");
    }
}
Also used : Note(com.ichi2.libanki.Note) JSONArray(com.ichi2.utils.JSONArray) JSONException(com.ichi2.utils.JSONException) Deck(com.ichi2.libanki.Deck) ModelManager(com.ichi2.libanki.ModelManager) DeckRenameException(com.ichi2.libanki.backend.exception.DeckRenameException) JSONObject(com.ichi2.utils.JSONObject) Note(com.ichi2.libanki.Note) Model(com.ichi2.libanki.Model) Collection(com.ichi2.libanki.Collection) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException)

Example 18 with ANSWER

use of com.ichi2.anki.CardBrowser.Column.ANSWER in project Anki-Android by ankidroid.

the class ReviewerTest method jsTime4ShouldBeBlankIfButtonUnavailable.

@Test
public void jsTime4ShouldBeBlankIfButtonUnavailable() {
    // #6623 - easy should be blank when displaying a card with 3 buttons (after displaying a review)
    Note firstNote = addNoteUsingBasicModel("Hello", "World");
    moveToReviewQueue(firstNote.firstCard());
    addNoteUsingBasicModel("Hello", "World2");
    Reviewer reviewer = startReviewer();
    AnkiDroidJsAPI javaScriptFunction = reviewer.javaScriptFunction();
    // The answer needs to be displayed to be able to get the time.
    displayAnswer(reviewer);
    assertThat("4 buttons should be displayed", reviewer.getAnswerButtonCount(), is(4));
    String nextTime = javaScriptFunction.ankiGetNextTime4();
    assertThat(nextTime, not(emptyString()));
    // Display the next answer
    reviewer.answerCard(Consts.BUTTON_FOUR);
    displayAnswer(reviewer);
    if (schedVersion == 1) {
        assertThat("The 4th button should not be visible", reviewer.getAnswerButtonCount(), is(3));
        String learnTime = javaScriptFunction.ankiGetNextTime4();
        assertThat("If the 4th button is not visible, there should be no time4 in JS", learnTime, emptyString());
    }
}
Also used : Note(com.ichi2.libanki.Note) Matchers.emptyString(org.hamcrest.Matchers.emptyString) Test(org.junit.Test)

Example 19 with ANSWER

use of com.ichi2.anki.CardBrowser.Column.ANSWER in project Anki-Android by ankidroid.

the class OverviewStatsBuilderTest method testInfoHtmlStringMonth.

@Test
@Config(qualifiers = "en")
public void testInfoHtmlStringMonth() {
    OverviewStatsBuilder statsTester = new OverviewStatsBuilder(new WebView(getTargetContext()), getCol(), 42L, Stats.AxisType.TYPE_MONTH);
    String HTML = statsTester.createInfoHtmlString();
    assertEquals(HTML, "<center><style>\n" + "h1, h3 { margin-bottom: 0; margin-top: 1em; text-transform: capitalize; }\n" + ".pielabel { text-align:center; padding:0px; color:white; }\n" + "body {color:#FFFFFF;}\n" + "</style><h1>Today</h1>Studied <b>0 cards</b> in <b>0 minutes</b> today<br>Again count: <b>0</b><br>Learn: <b>0</b>, review: <b>0</b>, relearn: <b>0</b>, filtered: <b>0</b><br>No mature cards were studied today<h1>1 month</h1><h3>FORECAST</h3>Total: <b>0</b> reviews<br>Average: <b>0.0</b> reviews/day<br>Due tomorrow: <b>0</b><br><h3>REVIEW COUNT</h3>Days studied: <b>0%</b> (0 of 30)<br>Total: <b>0</b> reviews<br>Average for days studied: <b>0.0</b> reviews/day<br>If you studied every day: <b>0.0</b> reviews/day<br><h3>REVIEW TIME</h3>Days studied: <b>0%</b> (0 of 30)<br>Total: <b>0</b> minutes<br>Average for days studied: <b>0.0</b> minutes/day<br>If you studied every day: <b>0.0</b> minutes/day<br>Average answer time: <b>0.0s</b> (<b>0.00</b> cards/minute)<br><h3>ADDED</h3>Total: <b>0</b> cards<br>Average: <b>0.0</b> cards/day<br><h3>INTERVALS</h3>Average interval: <b>0.0</b> hours<br>Longest interval: <b>0.0</b> hours<h3>ANSWER BUTTONS</h3>Learning: <b>0.00%</b> correct (0 of 0)<br>Young: <b>0.00%</b> correct (0 of 0)<br>Mature: <b>0.00%</b> correct (0 of 0)<h3>CARD TYPES</h3>Total cards: <b>0</b><br>Total notes: <b>0</b><br>Lowest ease: <b>0%</b><br>Average ease: <b>0%</b><br>Highest ease: <b>0%</b></center>");
}
Also used : WebView(android.webkit.WebView) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test) Config(org.robolectric.annotation.Config)

Example 20 with ANSWER

use of com.ichi2.anki.CardBrowser.Column.ANSWER in project Anki-Android by ankidroid.

the class ModelTest method test_req.

@Test
public void test_req() {
    Collection col = getCol();
    ModelManager mm = col.getModels();
    Model basic = mm.byName("Basic");
    assertTrue(basic.has("req"));
    reqSize(basic);
    JSONArray r = basic.getJSONArray("req").getJSONArray(0);
    assertEquals(0, r.getInt(0));
    assertTrue(Arrays.asList(new String[] { REQ_ANY, REQ_ALL }).contains(r.getString(1)));
    assertEquals(1, r.getJSONArray(2).length());
    assertEquals(0, r.getJSONArray(2).getInt(0));
    Model opt = mm.byName("Basic (optional reversed card)");
    reqSize(opt);
    r = opt.getJSONArray("req").getJSONArray(0);
    assertTrue(Arrays.asList(new String[] { REQ_ANY, REQ_ALL }).contains(r.getString(1)));
    assertEquals(1, r.getJSONArray(2).length());
    assertEquals(0, r.getJSONArray(2).getInt(0));
    assertEquals(new JSONArray("[1,\"all\",[1,2]]"), opt.getJSONArray("req").getJSONArray(1));
    // testing any
    opt.getJSONArray("tmpls").getJSONObject(1).put("qfmt", "{{Back}}{{Add Reverse}}");
    mm.save(opt, true);
    assertEquals(new JSONArray("[1, \"any\", [1, 2]]"), opt.getJSONArray("req").getJSONArray(1));
    // testing null
    opt.getJSONArray("tmpls").getJSONObject(1).put("qfmt", "{{^Add Reverse}}{{/Add Reverse}}");
    mm.save(opt, true);
    assertEquals(new JSONArray("[1, \"none\", []]"), opt.getJSONArray("req").getJSONArray(1));
    opt = mm.byName("Basic (type in the answer)");
    reqSize(opt);
    r = opt.getJSONArray("req").getJSONArray(0);
    assertTrue(Arrays.asList(new String[] { REQ_ANY, REQ_ALL }).contains(r.getString(1)));
    if (col.getModels() instanceof ModelsV16) {
        assertEquals(new JSONArray("[0, 1]"), r.getJSONArray(2));
    } else {
        // TODO: Port anki@4e33775ed4346ef136ece6ef5efec5ba46057c6b
        assertEquals(new JSONArray("[0]"), r.getJSONArray(2));
    }
}
Also used : JSONArray(com.ichi2.utils.JSONArray) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Aggregations

Test (org.junit.Test)29 Collection (com.ichi2.libanki.Collection)20 Note (com.ichi2.libanki.Note)20 Card (com.ichi2.libanki.Card)17 RobolectricTest (com.ichi2.anki.RobolectricTest)16 View (android.view.View)9 Intent (android.content.Intent)8 JSONArray (com.ichi2.utils.JSONArray)8 JSONObject (com.ichi2.utils.JSONObject)8 Model (com.ichi2.libanki.Model)7 Bundle (android.os.Bundle)6 WebView (android.webkit.WebView)6 SuppressLint (android.annotation.SuppressLint)5 SharedPreferences (android.content.SharedPreferences)5 TextView (android.widget.TextView)5 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)5 Matcher (java.util.regex.Matcher)5 InputMethodManager (android.view.inputmethod.InputMethodManager)4 Context (android.content.Context)3 Uri (android.net.Uri)3