package org.commcare.android.tests.formsave;
import android.content.Intent;
import android.os.Environment;
import android.util.Log;
import android.widget.ImageButton;
import org.commcare.CommCareApplication;
import org.commcare.CommCareTestApplication;
import org.commcare.activities.StandardHomeActivity;
import org.commcare.activities.FormEntryActivity;
import org.commcare.android.CommCareTestRunner;
import org.commcare.android.mocks.FormAndDataSyncerFake;
import org.commcare.android.tests.queries.CaseDbQueryTest;
import org.commcare.android.util.TestAppInstaller;
import org.commcare.android.util.TestUtils;
import org.commcare.dalvik.R;
import org.commcare.models.AndroidSessionWrapper;
import org.commcare.models.database.SqlStorage;
import org.commcare.android.database.user.models.FormRecord;
import org.commcare.session.CommCareSession;
import org.commcare.session.SessionNavigator;
import org.commcare.views.QuestionsView;
import org.commcare.views.widgets.IntegerWidget;
import org.javarosa.core.model.condition.EvaluationContext;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowActivity;
import org.robolectric.shadows.ShadowEnvironment;
import java.util.Date;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
/**
* Form Record processing / form save related tests
*
* @author Phillip Mates (pmates@dimagi.com).
*/
@Config(application = CommCareTestApplication.class)
@RunWith(CommCareTestRunner.class)
public class FormRecordProcessingTest {
private static final String TAG = FormRecordProcessingTest.class.getSimpleName();
@Before
public void setup() {
TestAppInstaller.installAppAndLogin(
"jr://resource/commcare-apps/form_save_regressions/profile.ccpr",
"test", "123");
ShadowEnvironment.setExternalStorageState(Environment.MEDIA_MOUNTED);
}
@Test
public void testCaseIndexUpdateDuringFormSave() {
TestUtils.processResourceTransactionIntoAppDb("/inputs/case_create_for_index_table_test.xml");
EvaluationContext ec = TestUtils.getEvaluationContextWithAndroidIIF();
CaseDbQueryTest.evaluate("instance('casedb')/casedb/case[@case_type = 'followup'][index/parent = 'worker_one']/@case_id",
"constant_id", ec);
fillOutFormWithCaseUpdate();
// TODO PLM: I would expect the following evaluation to not result in 'constant_id'
CaseDbQueryTest.evaluate("instance('casedb')/casedb/case[@case_type = 'followup'][index/parent = 'worker_one']/@case_id",
"constant_id", ec);
// check to see that the case index was actually updated
CaseDbQueryTest.evaluate("instance('casedb')/casedb/case[@case_type = 'followup'][index/parent = 'worker_two']/@case_id",
"constant_id", ec);
}
/**
* Regression test for 2.25.1 hotfix where the form record processor
* parser used during form save was using the wrong parser.
*
* Test steps through form and saves it, passing if upon returning to the
* home screen w/ the form sucessfully saved.
*/
@Test
public void testFormRecordProcessingDuringFormSave() {
fillOutFormWithCaseUpdate();
}
private void fillOutFormWithCaseUpdate() {
StandardHomeActivity homeActivity = buildHomeActivityForFormEntryLaunch();
ShadowActivity shadowActivity = Shadows.shadowOf(homeActivity);
Intent formEntryIntent = shadowActivity.getNextStartedActivity();
// make sure the form entry activity should be launched
String intentActivityName = formEntryIntent.getComponent().getClassName();
assertTrue(intentActivityName.equals(FormEntryActivity.class.getName()));
ShadowActivity shadowFormEntryActivity = navigateFormEntry(formEntryIntent);
// trigger CommCareHomeActivity.onActivityResult for the completion of
// FormEntryActivity
shadowActivity.receiveResult(formEntryIntent,
shadowFormEntryActivity.getResultCode(),
shadowFormEntryActivity.getResultIntent());
assertStoredFroms();
}
private StandardHomeActivity buildHomeActivityForFormEntryLaunch() {
AndroidSessionWrapper sessionWrapper =
CommCareApplication.instance().getCurrentSessionWrapper();
CommCareSession session = sessionWrapper.getSession();
session.setCommand("m0-f0");
StandardHomeActivity homeActivity =
Robolectric.buildActivity(StandardHomeActivity.class).create().get();
// make sure we don't actually submit forms by using a fake form submitter
homeActivity.setFormAndDataSyncer(new FormAndDataSyncerFake());
SessionNavigator sessionNavigator = homeActivity.getSessionNavigator();
sessionNavigator.startNextSessionStep();
return homeActivity;
}
private ShadowActivity navigateFormEntry(Intent formEntryIntent) {
// launch form entry
FormEntryActivity formEntryActivity =
Robolectric.buildActivity(FormEntryActivity.class).withIntent(formEntryIntent)
.create().start().resume().get();
ImageButton nextButton = (ImageButton)formEntryActivity.findViewById(R.id.nav_btn_next);
// enter an answer for the question
QuestionsView questionsView = formEntryActivity.getODKView();
IntegerWidget cohort = (IntegerWidget)questionsView.getWidgets().get(0);
cohort.setAnswer("2");
nextButton.performClick();
nextButton.performClick();
ShadowActivity shadowFormEntryActivity = Shadows.shadowOf(formEntryActivity);
long waitStartTime = new Date().getTime();
while (!shadowFormEntryActivity.isFinishing()) {
Log.d(TAG, "Waiting for the form to save and the form entry activity to finish");
if ((new Date().getTime()) - waitStartTime > 5000) {
Assert.fail("form entry activity took too long to finish");
}
}
return shadowFormEntryActivity;
}
private void assertStoredFroms() {
SqlStorage<FormRecord> formsStorage =
CommCareApplication.instance().getUserStorage(FormRecord.class);
int unsentForms = formsStorage.getIDsForValue(FormRecord.META_STATUS,
FormRecord.STATUS_UNSENT).size();
int incompleteForms = formsStorage.getIDsForValue(FormRecord.META_STATUS,
FormRecord.STATUS_INCOMPLETE).size();
assertEquals("There should be a single form waiting to be sent", 1, unsentForms);
assertEquals("There shouldn't be any forms saved as incomplete", 0, incompleteForms);
}
}