use of org.javarosa.core.model.condition.EvaluationContext in project collect by opendatakit.
the class ItemsetWidget method getSelectionArgs.
private String[] getSelectionArgs(List<String> arguments, String nodesetStr, FormController formController) {
// +1 is for the list_name
String[] selectionArgs = new String[arguments.size() + 1];
// parse out the list name, between the ''
String listName = nodesetStr.substring(nodesetStr.indexOf('\'') + 1, nodesetStr.lastIndexOf('\''));
// first argument is always listname
selectionArgs[0] = listName;
if (formController == null) {
Timber.w("Can't instantiate ItemsetWidget with a null FormController.");
return null;
}
// loop through the arguments, evaluate any expressions and build the query string for the DB
for (int i = 0; i < arguments.size(); i++) {
XPathExpression xpr;
try {
xpr = parseTool.parseXPath(arguments.get(i));
} catch (XPathSyntaxException e) {
Timber.e(e);
TextView error = new TextView(getContext());
error.setText(String.format(getContext().getString(R.string.parser_exception), arguments.get(i)));
addAnswerView(error);
break;
}
if (xpr != null) {
FormDef form = formController.getFormDef();
TreeElement treeElement = form.getMainInstance().resolveReference(formEntryPrompt.getIndex().getReference());
EvaluationContext ec = new EvaluationContext(form.getEvaluationContext(), treeElement.getRef());
Object value = xpr.eval(form.getMainInstance(), ec);
if (value == null) {
return null;
} else {
if (value instanceof XPathNodeset) {
value = ((XPathNodeset) value).getValAt(0);
}
selectionArgs[i + 1] = value.toString();
}
}
}
return selectionArgs;
}
use of org.javarosa.core.model.condition.EvaluationContext in project collect by opendatakit.
the class FormController method getQuestionPromptRequiredText.
public String getQuestionPromptRequiredText(FormIndex index) {
// look for the text under the requiredMsg bind attribute
String constraintText = getBindAttribute(index, XFormParser.NAMESPACE_JAVAROSA, "requiredMsg");
if (constraintText != null) {
XPathExpression xpathRequiredMsg;
try {
xpathRequiredMsg = XPathParseTool.parseXPath("string(" + constraintText + ")");
} catch (Exception e) {
// This is a string literal, so no need to evaluate anything.
return constraintText;
}
if (xpathRequiredMsg != null) {
try {
FormDef form = formEntryController.getModel().getForm();
TreeElement treeElement = form.getMainInstance().resolveReference(index.getReference());
EvaluationContext ec = new EvaluationContext(form.getEvaluationContext(), treeElement.getRef());
Object value = xpathRequiredMsg.eval(form.getMainInstance(), ec);
if (!value.equals("")) {
return (String) value;
}
return null;
} catch (Exception e) {
Timber.e(e, "Error evaluating a valid-looking required xpath ");
return constraintText;
}
} else {
return constraintText;
}
}
return null;
}
use of org.javarosa.core.model.condition.EvaluationContext in project javarosa by opendatakit.
the class RestoreUtils method applyDataType.
public static void applyDataType(FormInstance dm, String path, TreeReference parent, int dataType) {
TreeReference ref = childRef(path, parent);
List<TreeReference> v = new EvaluationContext(dm).expandReference(ref);
for (int i = 0; i < v.size(); i++) {
TreeElement e = dm.resolveReference(v.get(i));
e.setDataType(dataType);
}
}
use of org.javarosa.core.model.condition.EvaluationContext in project javarosa by opendatakit.
the class XPathEvalTest method getVariableContext.
private EvaluationContext getVariableContext() {
EvaluationContext ec = new EvaluationContext(null);
ec.setVariable("var_float_five", 5.0f);
ec.setVariable("var_string_five", "five");
ec.setVariable("var_int_five", 5);
ec.setVariable("var_double_five", 5.0);
return ec;
}
use of org.javarosa.core.model.condition.EvaluationContext in project javarosa by opendatakit.
the class XPathEvalTest method doTests.
public void doTests() {
EvaluationContext ec = getFunctionHandlers();
FormInstance instance = createTestInstance();
FormInstance countNonEmptyInstance = createCountNonEmptyTestInstance();
logTestCategory("counting");
testEval("count(/data/path)", countNonEmptyInstance, null, 5.0);
testEval("count-non-empty(/data/path)", countNonEmptyInstance, null, 3);
logTestCategory("unsupporteds");
testEval("/union | /expr", new XPathUnsupportedException());
testEval("/descendant::blah", new XPathUnsupportedException());
testEval("/cant//support", new XPathUnsupportedException());
testEval("/text()", new XPathUnsupportedException());
testEval("/namespace:*", new XPathUnsupportedException());
testEval("(filter-expr)[5]", instance, null, new XPathUnsupportedException());
testEval("(filter-expr)/data", instance, null, new XPathUnsupportedException());
logTestCategory("numeric literals");
testEval("5", 5.0);
testEval("555555.555", 555555.555);
testEval(".000555", 0.000555);
testEval("0", 0.0);
testEval("-5", -5.0);
testEval("-0", -0.0);
testEval("1230000000000000000000", 1.23e21);
testEval("0.00000000000000000123", 1.23e-18);
logTestCategory("string literals");
testEval("''", "");
testEval("'\"'", "\"");
testEval("\"test string\"", "test string");
testEval("' '", " ");
logTestCategory("type conversions");
testEval("true()", TRUE);
testEval("false()", FALSE);
testEval("boolean(true())", TRUE);
testEval("boolean(false())", FALSE);
testEval("boolean(1)", TRUE);
testEval("boolean(-1)", TRUE);
testEval("boolean(0.0001)", TRUE);
testEval("boolean(0)", FALSE);
testEval("boolean(-0)", FALSE);
testEval("boolean(number('NaN'))", FALSE);
testEval("boolean(1 div 0)", TRUE);
testEval("boolean(-1 div 0)", TRUE);
testEval("boolean('')", FALSE);
testEval("boolean('asdf')", TRUE);
testEval("boolean(' ')", TRUE);
testEval("boolean('false')", TRUE);
testEval("boolean(date('2000-01-01'))", TRUE);
testEval("boolean(convertible())", null, ec, TRUE);
testEval("boolean(inconvertible())", null, ec, new XPathTypeMismatchException());
testEval("number(true())", 1.0);
testEval("number(false())", 0.0);
testEval("number('100')", 100.0);
testEval("number('100.001')", 100.001);
testEval("number('.1001')", 0.1001);
testEval("number('1230000000000000000000')", 1.23e21);
testEval("number('0.00000000000000000123')", 1.23e-18);
testEval("number('0')", 0.0);
testEval("number('-0')", -0.0);
testEval("number(' -12345.6789 ')", -12345.6789);
testEval("number('NaN')", NaN);
testEval("number('not a number')", NaN);
testEval("number('- 17')", NaN);
testEval("number(' ')", NaN);
testEval("number('')", NaN);
testEval("number('Infinity')", NaN);
testEval("number('1.1e6')", NaN);
testEval("number('34.56.7')", NaN);
testEval("number(10)", 10.0);
testEval("number(0)", 0.0);
testEval("number(-0)", -0.0);
testEval("number(-123.5)", -123.5);
testEval("number(number('NaN'))", NaN);
testEval("number(1 div 0)", POSITIVE_INFINITY);
testEval("number(-1 div 0)", NEGATIVE_INFINITY);
testEval("number(date('1970-01-01'))", 0.0);
testEval("number(date('1970-01-02'))", 1.0);
testEval("number(date('1969-12-31'))", -1.0);
testEval("number(date('2008-09-05'))", 14127.0);
testEval("number(date('1941-12-07'))", -10252.0);
testEval("number(convertible())", null, ec, 5.0);
testEval("number(inconvertible())", null, ec, new XPathTypeMismatchException());
testEval("string(true())", "true");
testEval("string(false())", "false");
testEval("string(number('NaN'))", "NaN");
testEval("string(1 div 0)", "Infinity");
testEval("string(-1 div 0)", "-Infinity");
testEval("string(0)", "0");
testEval("string(-0)", "0");
testEval("string(123456.0000)", "123456");
testEval("string(-123456)", "-123456");
testEval("string(1)", "1");
testEval("string(-1)", "-1");
testEval("string(.557586)", "0.557586");
// broken: testEval("string(1230000000000000000000)", "1230000000000000000000");
// broken: testEval("string(0.00000000000000000123)", "0.00000000000000000123");
testEval("string('')", "");
testEval("string(' ')", " ");
testEval("string('a string')", "a string");
testEval("string(date('1989-11-09'))", "1989-11-09");
testEval("string(convertible())", null, ec, "hi");
testEval("string(inconvertible())", null, ec, new XPathTypeMismatchException());
logTestCategory("substring functions");
testEval("substr('hello',0)", "hello");
testEval("substr('hello',0,5)", "hello");
testEval("substr('hello',1)", "ello");
testEval("substr('hello',1,5)", "ello");
testEval("substr('hello',1,4)", "ell");
testEval("substr('hello',-2)", "lo");
testEval("substr('hello',0,-1)", "hell");
testEval("contains('a', 'a')", true);
testEval("contains('a', 'b')", false);
testEval("contains('abc', 'b')", true);
testEval("contains('abc', 'bcd')", false);
testEval("not(contains('a', 'b'))", true);
testEval("starts-with('abc', 'a')", true);
testEval("starts-with('', 'a')", false);
testEval("starts-with('', '')", true);
testEval("ends-with('abc', 'a')", false);
testEval("ends-with('abc', 'c')", true);
testEval("ends-with('', '')", true);
logTestCategory("date functions");
testEval("date('2000-01-01')", DateUtils.getDate(2000, 1, 1));
testEval("date('1945-04-26')", DateUtils.getDate(1945, 4, 26));
testEval("date('1996-02-29')", DateUtils.getDate(1996, 2, 29));
testEval("date('1983-09-31')", new XPathTypeMismatchException());
testEval("date('not a date')", new XPathTypeMismatchException());
testEval("date(0)", DateUtils.getDate(1970, 1, 1));
testEval("date(6.5)", DateUtils.getDate(1970, 1, 7));
testEval("date(1)", DateUtils.getDate(1970, 1, 2));
testEval("date(-1)", DateUtils.getDate(1969, 12, 31));
testEval("date(14127)", DateUtils.getDate(2008, 9, 5));
testEval("date(-10252)", DateUtils.getDate(1941, 12, 7));
testEval("date(date('1989-11-09'))", DateUtils.getDate(1989, 11, 9));
testEval("date(true())", new XPathTypeMismatchException());
testEval("date(convertible())", null, ec, new XPathTypeMismatchException());
// note: there are lots of time and timezone-like issues with dates that should be tested (particularly DST changes),
// but it's just too hard and client-dependent, so not doing it now
// basically:
// dates cannot reliably be compared/used across time zones (an issue with the code)
// any time-of-day or DST should be ignored when comparing/using a date (an issue with testing)
/* other built-in functions */
testEval("format-date('2018-01-02T10:20:30.123', \"%Y-%m-%e %H:%M:%S\")", "2018-01-2 10:20:30");
logTestCategory("boolean functions");
testEval("not(true())", FALSE);
testEval("not(false())", TRUE);
testEval("not('')", TRUE);
testEval("boolean-from-string('true')", TRUE);
testEval("boolean-from-string('false')", FALSE);
testEval("boolean-from-string('whatever')", FALSE);
testEval("boolean-from-string('1')", TRUE);
testEval("boolean-from-string('0')", FALSE);
testEval("boolean-from-string(1)", TRUE);
testEval("boolean-from-string(1.0)", TRUE);
testEval("boolean-from-string(1.0001)", FALSE);
testEval("boolean-from-string(true())", TRUE);
testEval("if(true(), 5, 'abc')", 5.0);
testEval("if(false(), 5, 'abc')", "abc");
testEval("if(6 > 7, 5, 'abc')", "abc");
testEval("if('', 5, 'abc')", "abc");
testEval("selected('apple baby crimson', 'apple')", TRUE);
testEval("selected('apple baby crimson', 'baby')", TRUE);
testEval("selected('apple baby crimson', 'crimson')", TRUE);
testEval("selected('apple baby crimson', ' baby ')", TRUE);
testEval("selected('apple baby crimson', 'babby')", FALSE);
testEval("selected('apple baby crimson', 'bab')", FALSE);
testEval("selected('apple', 'apple')", TRUE);
testEval("selected('apple', 'ovoid')", FALSE);
testEval("selected('', 'apple')", FALSE);
logTestCategory("math operators");
testEval("5.5 + 5.5", 11.0);
testEval("0 + 0", 0.0);
testEval("6.1 - 7.8", -1.7);
testEval("-3 + 4", 1.0);
testEval("3 + -4", -1.0);
testEval("1 - 2 - 3", -4.0);
testEval("1 - (2 - 3)", 2.0);
testEval("-(8*5)", -40.0);
testEval("-'19'", -19.0);
testEval("1.1 * -1.1", -1.21);
testEval("-10 div -4", 2.5);
testEval("2 * 3 div 8 * 2", 1.5);
testEval("3 + 3 * 3", 12.0);
testEval("1 div 0", POSITIVE_INFINITY);
testEval("-1 div 0", NEGATIVE_INFINITY);
testEval("0 div 0", NaN);
testEval("3.1 mod 3.1", 0.0);
testEval("5 mod 3.1", 1.9);
testEval("2 mod 3.1", 2.0);
testEval("0 mod 3.1", 0.0);
testEval("5 mod -3", 2.0);
testEval("-5 mod 3", -2.0);
testEval("-5 mod -3", -2.0);
testEval("5 mod 0", NaN);
testEval("5 * (6 + 7)", 65.0);
testEval("'123' * '456'", 56088.0);
logTestCategory("math functions");
testEval("abs(-3.5)", 3.5);
// round, with a single argument
testEval("round('14.29123456789')", 14.0);
testEval("round('14.6')", 15.0);
// round, with two arguments
testEval("round('14.29123456789', 0)", 14.0);
testEval("round('14.29123456789', 1)", 14.3);
testEval("round('14.29123456789', 1.5)", 14.3);
testEval("round('14.29123456789', 2)", 14.29);
testEval("round('14.29123456789', 3)", 14.291);
testEval("round('14.29123456789', 4)", 14.2912);
testEval("round('12345.14', 1)", 12345.1);
testEval("round('-12345.14', 1)", -12345.1);
testEval("round('12345.12345', 0)", 12345.0);
testEval("round('12345.12345', -1)", 12350.0);
testEval("round('12345.12345', -2)", 12300.0);
testEval("round('12350.12345', -2)", 12400.0);
testEval("round('12345.12345', -3)", 12000.0);
// round, with a comma instead of a decimal point
testEval("round('4,6' )", 5.0);
// XPath specification tests
testEval("round('1 div 0', 0)", NaN);
testEval("round('14.5')", 15.0);
testEval("round('NaN')", NaN);
testEval("round('-NaN')", -NaN);
testEval("round('0')", 0.0);
testEval("round('-0')", -0.0);
testEval("round('-0.5')", -0.0);
// non US format
testEval("round('14,6')", 15.0);
// Java 8 tests deprecated by XPath 3.0 specification
// See discussion at https://github.com/opendatakit/javarosa/pull/42#issuecomment-299527754
testEval("round('12345.15', 1)", 12345.2);
testEval("round('-12345.15', 1)", -12345.1);
logTestCategory("strange operators");
testEval("true() + 8", 9.0);
testEval("date('2008-09-08') - date('1983-10-06')", 9104.0);
testEval("true() and true()", TRUE);
testEval("true() and false()", FALSE);
testEval("false() and false()", FALSE);
testEval("true() or true()", TRUE);
testEval("true() or false()", TRUE);
testEval("false() or false()", FALSE);
testEval("true() or true() and false()", TRUE);
testEval("(true() or true()) and false()", FALSE);
// short-circuiting
testEval("true() or date('')", TRUE);
// short-circuiting
testEval("false() and date('')", FALSE);
testEval("'' or 17", TRUE);
testEval("false() or 0 + 2", TRUE);
testEval("(false() or 0) + 2", 2.0);
testEval("4 < 5", TRUE);
testEval("5 < 5", FALSE);
testEval("6 < 5", FALSE);
testEval("4 <= 5", TRUE);
testEval("5 <= 5", TRUE);
testEval("6 <= 5", FALSE);
testEval("4 > 5", FALSE);
testEval("5 > 5", FALSE);
testEval("6 > 5", TRUE);
testEval("4 >= 5", FALSE);
testEval("5 >= 5", TRUE);
testEval("6 >= 5", TRUE);
testEval("-3 > -6", TRUE);
logTestCategory("odd comparisons");
testEval("true() > 0.9999", TRUE);
// no string comparison: converted to number
testEval("'-17' > '-172'", TRUE);
// no string comparison: converted to NaN
testEval("'abc' < 'abcd'", FALSE);
testEval("date('2001-12-26') > date('2001-12-25')", TRUE);
testEval("date('1969-07-20') < date('1969-07-21')", TRUE);
testEval("false() and false() < true()", FALSE);
testEval("(false() and false()) < true()", TRUE);
testEval("6 < 7 - 4", FALSE);
testEval("(6 < 7) - 4", -3.0);
testEval("3 < 4 < 5", TRUE);
testEval("3 < (4 < 5)", FALSE);
testEval("true() = true()", TRUE);
testEval("true() = false()", FALSE);
testEval("true() != true()", FALSE);
testEval("true() != false()", TRUE);
testEval("3 = 3", TRUE);
testEval("3 = 4", FALSE);
testEval("3 != 3", FALSE);
testEval("3 != 4", TRUE);
// handle floating point rounding
testEval("6.1 - 7.8 = -1.7", TRUE);
testEval("'abc' = 'abc'", TRUE);
testEval("'abc' = 'def'", FALSE);
testEval("'abc' != 'abc'", FALSE);
testEval("'abc' != 'def'", TRUE);
testEval("'' = ''", TRUE);
testEval("true() = 17", TRUE);
testEval("0 = false()", TRUE);
testEval("true() = 'true'", TRUE);
testEval("17 = '17.0000000'", TRUE);
testEval("'0017.' = 17", TRUE);
testEval("'017.' = '17.000'", FALSE);
testEval("date('2004-05-01') = date('2004-05-01')", TRUE);
testEval("true() != date('1999-09-09')", FALSE);
testEval("false() and true() != true()", FALSE);
testEval("(false() and true()) != true()", TRUE);
testEval("-3 < 3 = 6 >= 6", TRUE);
logTestCategory("functions, including custom function handlers");
testEval("true(5)", new XPathUnhandledException());
testEval("number()", new XPathUnhandledException());
testEval("string('too', 'many', 'args')", new XPathUnhandledException());
testEval("not-a-function()", new XPathUnhandledException());
testEval("testfunc()", null, ec, TRUE);
testEval("add(3, 5)", null, ec, 8.0);
testEval("add('17', '-14')", null, ec, 3.0);
logTestCategory("proto");
testEval("proto()", null, ec, new XPathTypeMismatchException());
testEval("proto(5, 5)", null, ec, "[Double:5.0,Double:5.0]");
testEval("proto(6)", null, ec, "[Double:6.0]");
testEval("proto('asdf')", null, ec, "[Double:NaN]");
// note: args treated as doubles because
testEval("proto('7', '7')", null, ec, "[Double:7.0,Double:7.0]");
// (double, double) prototype takes precedence and strings are convertible to doubles
testEval("proto(1.1, 'asdf', true())", null, ec, "[Double:1.1,String:asdf,Boolean:true]");
testEval("proto(false(), false(), false())", null, ec, "[Double:0.0,String:false,Boolean:false]");
testEval("proto(1.1, 'asdf', inconvertible())", null, ec, new XPathTypeMismatchException());
testEval("proto(1.1, 'asdf', true(), 16)", null, ec, new XPathTypeMismatchException());
logTestCategory("raw");
testEval("raw()", null, ec, "[]");
testEval("raw(5, 5)", null, ec, "[Double:5.0,Double:5.0]");
testEval("raw('7', '7')", null, ec, "[String:7,String:7]");
// convertible to prototype
testEval("raw('1.1', 'asdf', 17)", null, ec, "[Double:1.1,String:asdf,Boolean:true]");
testEval("raw(get-custom(false()), get-custom(true()))", null, ec, "[CustomType:,CustomSubType:]");
logTestCategory("concat");
testEval("concat()", null, ec, "");
testEval("concat('a')", null, ec, "a");
testEval("concat('a','b','')", null, ec, "ab");
testEval("concat('ab','cde','','fgh',1,false(),'ijklmnop')", null, ec, "abcdefgh1falseijklmnop");
testEval("check-types(55, '55', false(), '1999-09-09', get-custom(false()))", null, ec, TRUE);
testEval("check-types(55, '55', false(), '1999-09-09', get-custom(true()))", null, ec, TRUE);
logTestCategory("regex");
testEval("regex('12345','[0-9]+')", null, ec, TRUE);
testEval("pow(2, 2)", 4.0);
testEval("pow(2, 0)", 1.0);
testEval("pow(0, 4)", 0.0);
testEval("pow(2.5, 2)", 6.25);
testEval("pow(0.5, 2)", .25);
testEval("pow(-1, 2)", 1.0);
testEval("pow(-1, 3)", -1.0);
// So raising things to decimal powers is.... very hard
// to evaluated exactly due to double floating point
// precision. We'll try for things with clean answers
testEval("pow(4, 0.5)", 2.0);
testEval("pow(16, 0.25)", 2.0);
logTestCategory("variable refs");
EvaluationContext varContext = getVariableContext();
testEval("$var_float_five", null, varContext, 5.0);
testEval("$var_string_five", null, varContext, "five");
testEval("$var_int_five", null, varContext, 5.0);
testEval("$var_double_five", null, varContext, 5.0);
logTestCategory("node referencing");
// happy flow scenario where the index node is not blank
FormInstance testInstance = createTestDataForIndexedRepeatFunction(1);
XPathNodeset expected = createExpectedNodesetFromIndexedRepeatFunction(testInstance, 1, "name");
testEval("indexed-repeat( /data/repeat/name , /data/repeat , /data/index1 )", testInstance, null, expected);
// situation where the referenced index node is blank and the default value (0 which means the first repeat group) is used
testInstance = createTestDataForIndexedRepeatFunction(null);
expected = createExpectedNodesetFromIndexedRepeatFunction(testInstance, 0, "name");
testEval("indexed-repeat( /data/repeat/name , /data/repeat , /data/index1 )", testInstance, null, expected);
logTestCategory("crypto functions");
// Support for all 5 supported digest algorithms (required and optional) and default base64 encoding
testEval("digest('some text', 'MD5', 'base64')", "VS4hzUzZkYZ448Gg30kbww==");
testEval("digest('some text', 'SHA-1', 'base64')", "N6pjx3OY2VRHMmLhoAV8HmMu2nc=");
testEval("digest('some text', 'SHA-256', 'base64')", "uU9vElx546X/qoJvWEwQ1SraZp5nYgUbgmtVd20FrtI=");
testEval("digest('some text', 'SHA-384', 'base64')", "zJTsPphzwLmnJIZEKVj2cQZ833e5QnQW0DFEDMYgQeLuE0RJhEfsDO2fcENGG9Hz");
testEval("digest('some text', 'SHA-512', 'base64')", "4nMrrtyj6sFAeChjfeHbynAsP8ns4Wz1Nt241hOc2F3+dGS4I1spgm9gjM9KxkPimxnGN4WKPYcQpZER30LdtQ==");
// Support for hexadecimal encoding
testEval("digest('some text', 'MD5', 'hex')", "552e21cd4cd9918678e3c1a0df491bc3");
// Support for optional third argument (defaults to 'base64')
testEval("digest('some text', 'MD5')", "VS4hzUzZkYZ448Gg30kbww==");
try {
testEval("null-proto()", null, ec, new XPathUnhandledException());
fail("Did not get expected null pointer");
} catch (NullPointerException npe) {
// expected
}
ec.addFunctionHandler(read);
ec.addFunctionHandler(write);
read.val = "testing-read";
testEval("read()", null, ec, "testing-read");
testEval("write('testing-write')", null, ec, TRUE);
if (!"testing-write".equals(write.val))
fail("Custom function handler did not successfully send data to external source");
}
Aggregations