package org.commcare.android.tests.queries; import org.commcare.CommCareApplication; import org.commcare.android.CommCareTestRunner; import org.commcare.android.util.TestUtils; import org.javarosa.core.model.condition.EvaluationContext; import org.javarosa.xpath.XPathParseTool; import org.javarosa.xpath.expr.FunctionUtils; import org.javarosa.xpath.expr.XPathExpression; import org.javarosa.xpath.parser.XPathSyntaxException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.robolectric.annotation.Config; import static junit.framework.Assert.assertEquals; /** * General case query tests * * Note that this should be following the same @Parameterized testing patter we are using in * CommCare core, but can't because the ParameterizedRobolectricTestRunner can't be used with a * custom test runner (we need the custom runer to shadow sqlcipher and the encrpytion libs). * * If/when https://github.com/robolectric/robolectric/issues/2910 ever gets fixed, we should expand * many tests to be run with the parameterized runner. * * @author ctsims */ @Config(application = CommCareApplication.class) @RunWith(CommCareTestRunner.class) public class CaseDbQueryTest { @Before public void setupTests() { TestUtils.initializeStaticTestStorage(); } /** * Tests for basic common case database queries */ @Test public void testBasicCaseQueries() { TestUtils.processResourceTransaction("/inputs/case_create.xml"); EvaluationContext ec = TestUtils.getEvaluationContextWithoutSession(); evaluate("count(instance('casedb')/casedb/case[@case_id = 'test_case_id'])", "1", ec); evaluate("instance('casedb')/casedb/case[@case_id = 'test_case_id']/case_name", "Test Case", ec); evaluate("instance('casedb')/casedb/case[@case_id = 'test_case_id']/case_name", "Test Case", ec); evaluate("instance('casedb')/casedb/case[@case_id = 'test_case_id']/test_value", "initial", ec); evaluate("instance('casedb')/casedb/case[@case_id = 'test_case_id']/missing_value", "", ec); } /** * Tests for basic common case index related queries */ @Test public void testCaseIndexQueries() { TestUtils.processResourceTransaction("/inputs/case_create.xml"); TestUtils.processResourceTransaction("/inputs/case_create_and_index.xml"); EvaluationContext ec = TestUtils.getEvaluationContextWithoutSession(); evaluate("instance('casedb')/casedb/case[@case_id = 'test_case_id_child']/index/parent", "test_case_id", ec); evaluate("instance('casedb')/casedb/case[@case_id = 'test_case_id']/index/missing", "", ec); // TODO PLM: only tests how the case data instance is initialized using // the test framework (TestUtils.getInstanceBackedEvaluationContext). // We need to create robolectric tests that perform this evaluation // during form entry evaluate("instance('casedb')/casedb/case[@case_type = 'unit_test_child'][index/parent = 'test_case_id_2']/@case_id", "test_case_id_child_2", ec); } @Test public void testCaseOptimizationTriggers() { TestUtils.processResourceTransaction("/inputs/case_test_db_optimizations.xml"); EvaluationContext ec = TestUtils.getEvaluationContextWithoutSession(); evaluate("join(',',instance('casedb')/casedb/case[index/parent = 'test_case_parent']/@case_id)", "child_one,child_two,child_three", ec); evaluate("join(',',instance('casedb')/casedb/case[index/parent = 'test_case_parent'][@case_id = 'child_two']/@case_id)", "child_two", ec); evaluate("join(',',instance('casedb')/casedb/case[index/parent = 'test_case_parent'][@case_id != 'child_two']/@case_id)", "child_one,child_three", ec); } @Test public void testIndexSetMemberOptimizations() { TestUtils.processResourceTransaction("/inputs/case_test_db_optimizations.xml"); EvaluationContext ec = TestUtils.getEvaluationContextWithoutSession(); evaluate("join(',',instance('casedb')/casedb/case[selected('test_case_parent', index/parent)]/@case_id)", "child_one,child_two,child_three", ec); evaluate("join(',',instance('casedb')/casedb/case[selected('test_case_parent test_case_parent_2', index/parent)]/@case_id)", "child_one,child_two,child_three", ec); evaluate("join(',',instance('casedb')/casedb/case[selected('test_case_parent_2 test_case_parent', index/parent)]/@case_id)", "child_one,child_two,child_three", ec); evaluate("join(',',instance('casedb')/casedb/case[selected('test_case_parent_2 test_case_parent_3', index/parent)]/@case_id)", "", ec); evaluate("join(',',instance('casedb')/casedb/case[selected('', index/parent)]/@case_id)", "", ec); } @Test public void testModelQueryLookupDerivations() { TestUtils.processResourceTransaction("/inputs/case_test_model_query_lookups.xml"); EvaluationContext ec = TestUtils.getEvaluationContextWithoutSession(); evaluate("join(',',instance('casedb')/casedb/case[@case_type='unit_test_child_child'][@status='open'][true() and " + "instance('casedb')/casedb/case[@case_id = instance('casedb')/casedb/case[@case_id=current()/index/parent]/index/parent]/test = 'true']/@case_id)", "child_ptwo_one_one,child_one_one", ec); } @Test public void testModelSelfReference() { TestUtils.processResourceTransaction("/inputs/case_test_model_query_lookups.xml"); EvaluationContext ec = TestUtils.getEvaluationContextWithoutSession(); evaluate("join(',',instance('casedb')/casedb/case[@case_type='unit_test_child'][@status='open'][true() and " + "count(instance('casedb')/casedb/case[index/parent = instance('casedb')/casedb/case[@case_id=current()/@case_id]/index/parent][false = 'true']) > 0]/@case_id)", "", ec); } @Test public void testBulkQueryProcessingOutcomes() { TestUtils.processResourceTransaction("/inputs/case_test_db_optimizations.xml", true); EvaluationContext ec = TestUtils.getEvaluationContextWithoutSession(); evaluate("join(',',instance('casedb')/casedb/case[selected('test_case_parent', index/parent)]/@case_id)", "child_one,child_two,child_three", ec); evaluate("join(',',instance('casedb')/casedb/case[selected('test_case_parent test_case_parent_2', index/parent)]/@case_id)", "child_one,child_two,child_three", ec); evaluate("join(',',instance('casedb')/casedb/case[selected('test_case_parent_2 test_case_parent', index/parent)]/@case_id)", "child_one,child_two,child_three", ec); evaluate("join(',',instance('casedb')/casedb/case[selected('test_case_parent_2 test_case_parent_3', index/parent)]/@case_id)", "", ec); evaluate("join(',',instance('casedb')/casedb/case[selected('', index/parent)]/@case_id)", "", ec); } public static void evaluate(String xpath, String expectedValue, EvaluationContext ec) { XPathExpression expr; try { expr = XPathParseTool.parseXPath(xpath); String result = FunctionUtils.toString(expr.eval(ec)); assertEquals("XPath: " + xpath, expectedValue, result); } catch (XPathSyntaxException e) { TestUtils.wrapError(e, "XPath: " + xpath); } } }