UNPKG

openrosa-xpath-evaluator

Version:

Wrapper for browsers' XPath evaluator with added support for OpenRosa extensions.

261 lines (239 loc) 11.5 kB
const _ = require('lodash'); const { initDoc, assert } = require('./helpers'); const SIMPLE_DATE_MATCH = /^\d{4}-[0-1]\d-[0-3]\d$/; const SIMPLE_DATE_OR_DATE_TIME_MATCH = /^\d{4}-[0-1]\d-[0-3]\d(T[0-2]\d:[0-5]\d:[0-5]\d\.\d\d\d(Z|[+-][0-1]\d(:[0-5]\d)?))?$/; describe('some complex examples', () => { const doc = initDoc(''); _.forEach( { 'concat("uuid:", uuid())': /uuid:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/, '"2015-07-15" < today()': true, "'2015-07-15' > today()": false, "'raw-string'": 'raw-string', 'format-date-time(date-time(decimal-date-time("2003-03-12") + 280), "%b %e, %Y")': /^Dec 17, 2003$/, 'decimal-date-time(today()- 60 )': /^-?[0-9]+(\.[0-9]+)?$/, 'date-time(decimal-date-time(today()- 60 ))': SIMPLE_DATE_MATCH, "if(selected('date' ,'date'), 'first' ,'second')": /^first$/, "if(selected('approx' ,'date'), 'first' ,'second')": /^second$/, "if(selected(/model/instance[1]/pregnancy/group_lmp/lmp_method, 'date'), /model/instance[1]/pregnancy/group_lmp/lmp_date, 'testing')": /testing/, "if(selected(/model/instance[1]/pregnancy/group_lmp/lmp_method, 'date'), /model/instance[1]/pregnancy/group_lmp/lmp_date, concat('testing', '1', '2', '3', '...'))": /testing/, "if(selected(/model/instance[1]/pregnancy/group_lmp/lmp_method, 'date'), /model/instance[1]/pregnancy/group_lmp/lmp_date, date-time(0))": SIMPLE_DATE_OR_DATE_TIME_MATCH, "if(selected(/model/instance[1]/pregnancy/group_lmp/lmp_method, 'date'), /model/instance[1]/pregnancy/group_lmp/lmp_date, date-time(decimal-date-time(today() - 60)))": SIMPLE_DATE_MATCH, "if(selected(/model/instance[1]/pregnancy/group_lmp/lmp_method ,'date'), /model/instance[1]/pregnancy/group_lmp/lmp_date ,date-time(decimal-date-time(today()- 60 )))": SIMPLE_DATE_MATCH, 'if(true(), today(), today())': SIMPLE_DATE_MATCH, 'if(false(), today(), today())': SIMPLE_DATE_MATCH, 'if(true(), "", today())': /^$/, 'if(false(), "", today())': SIMPLE_DATE_MATCH, 'if(true(), today(), "")': SIMPLE_DATE_MATCH, 'if(false(), today(), "")': /^$/, 'coalesce(today(), "")': SIMPLE_DATE_MATCH, 'coalesce("", today())': SIMPLE_DATE_MATCH, 'true() or true() or true()': true, 'true() or true() or false()': true, 'true() or false() or true()': true, 'false() or true() or true()': true, 'true() or false() or false()': true, 'false() or true() or false()': true, 'false() or false() or true()': true, 'false() or false() or false()': false, '(true() or true()) or true()': true, '(true() or true()) or false()': true, '(true() or false()) or true()': true, '(false() or true()) or true()': true, '(true() or false()) or false()': true, '(false() or true()) or false()': true, '(false() or false()) or true()': true, '(false() or false()) or false()': false, 'true() or (true() or true())': true, 'true() or (true() or false())': true, 'true() or (false() or true())': true, 'false() or (true() or true())': true, 'true() or (false() or false())': true, 'false() or (true() or false())': true, 'false() or (false() or true())': true, 'false() or (false() or false())': false, '(true() and true()) or true()': true, '(true() and true()) or false()': true, '(true() and false()) or true()': true, '(false() and true()) or true()': true, '(true() and false()) or false()': false, '(false() and true()) or false()': false, '(false() and false()) or true()': true, '(false() and false()) or false()': false, 'true() or (true() and true())': true, 'true() or (true() and false())': true, 'true() or (false() and true())': true, 'false() or (true() and true())': true, 'true() or (false() and false())': true, 'false() or (true() and false())': false, 'false() or (false() and true())': false, 'false() or (false() and false())': false, '(true() or true()) and true()': true, '(true() or true()) and false()': false, '(true() or false()) and true()': true, '(false() or true()) and true()': true, '(true() or false()) and false()': false, '(false() or true()) and false()': false, '(false() or false()) and true()': false, '(false() or false()) and false()': false, '(true() and true()) and true()': true, '(true() and true()) and false()': false, '(true() and false()) and true()': false, '(false() and true()) and true()': false, '(true() and false()) and false()': false, '(false() and true()) and false()': false, '(false() and false()) and true()': false, '(false() and false()) and false()': false, 'true() and true() and true()': true, 'true() and true() and false()': false, 'true() and false() and true()': false, 'false() and true() and true()': false, 'true() and false() and false()': false, 'false() and true() and false()': false, 'false() and false() and true()': false, 'false() and false() and false()': false, 'true() and (true() or true())': true, 'true() and (true() or false())': true, 'true() and (false() or true())': true, 'true() and (false() or false())': false, 'false() and (true() or true())': false, 'false() and (true() or false())': false, 'false() and (false() or true())': false, 'false() and (false() or false())': false, '(true() and true()) or (false() and false())': true, '(true() and true()) and (false() and false())': false, '(true() and true()) and (false() or true())': true, '((true() or false()) and (false() or true())) and (false() or true())': true, '((true() or false()) and (false() or false())) and (false() or true())': false, '-1': /^-1$/, '1-1': /^0$/, '1+1': /^2$/, '0 > 0': false, '(0 > 0)': false, 'false() != "true"': true, '(false() != "true")': true, '(0 = 0) and (false() != "true")': true, '0 = 0 and false() != "true"': true, '(0 > 0) and (false() != "true")': false, '0 > 0 and false() != "true"': false, "if(/something, 'A', 'B' )": 'B', "if(/something != '', 'A', 'B' )": 'B', "if('' != '', 'A', 'B' )": 'B', "if(true(), 'A', 'B' )": 'A', "if (/something, 'A', 'B' )": 'B', "if (/something != '', 'A', 'B' )": 'B', "if ('' != '', 'A', 'B' )": 'B', "if (true(), 'A', 'B' )": 'A', "not(selected(../dob_method,'approx'))": true, "not(not(selected(../dob_method,'approx')))": false, "selected(../dob_method,'approx')": false, '(0) - (0)': 0, '2*3': 6, '(2*3)': 6, '2 * 3': 6, '(2 * 3)': 6, '2+3': 5, '(2+3)': 5, '2 + 3': 5, '(2 + 3)': 5, '2 + 4': '6', 'today() < (today() + 1)': true, 'today() > (today() + 1)': false, "today() < '1970-06-03'": false, "today() > '1970-06-03'": true, "today() + 1 < '1970-06-03'": false, "today() + 1 > '1970-06-03'": true, '.': [(node) => assert.equal(node.nodeName, '#document')], // Bracketed expressions inside vs outside function calls: 1: 1, '(1)': 1, '(1 + 1) - 1': 1, '((1 + 1) - 1)': 1, '-1 + (1 + 1)': 1, '(-1 + (1 + 1))': 1, 3: 3, '(3)': 3, '(1 + 1) + 1': 3, '((1 + 1) + 1)': 3, 'cos(3)': Math.cos(3), 'cos((1 + 1) + 1)': Math.cos(3), 'cos(1)': Math.cos(1), 'cos((1 + 1) - 1)': Math.cos(1), 'cos(-1 + (1 + 1))': Math.cos(1), // These tests exposed a weird bug which would return "Too many tokens" if dot was followed by a comparator // In all these tests, the root node is being passed to `number()` to allow its comparison with the number // 1. The text is null, so its numeric value is NaN. This makes all comparisons return false. '.>1': false, '.> 1': false, '. >1': false, '. > 1': false, '.>=1': false, '.>= 1': false, '. >=1': false, '. >= 1': false, '.<1': false, '.< 1': false, '. <1': false, '. < 1': false, '.<=1': false, '.<= 1': false, '. <=1': false, '. <= 1': false, '1=1': true, '1=0': false, '0=1': false, '1 =1': true, '1 =0': false, '0 =1': false, '1= 1': true, '1= 0': false, '0= 1': false, '1 = 1': true, '1 = 0': false, '0 = 1': false, "../some-path='some-value'": false, '../some-path="some-value"': false, "../some-path= 'some-value'": false, "../some-path ='some-value'": false, "../some-path = 'some-value'": false, "'some-value'=../some-path": false, '"some-value"=../some-path': false, "'some-value'= ../some-path": false, "'some-value' =../some-path": false, "'some-value' = ../some-path": false, }, (matcher, expression) => { it(`should convert "${expression}" to match "${matcher}"`, () => { const evaluated = doc.xEval(expression); if (Array.isArray(matcher)) { matcher.forEach((nodeMatcher) => { nodeMatcher(evaluated.iterateNext()); }); assert.isNull(evaluated.iterateNext()); } else { switch (typeof matcher) { case 'boolean': assert.equal(evaluated.booleanValue, matcher); return; case 'number': assert.equal(evaluated.numberValue, matcher); return; case 'string': assert.equal(evaluated.stringValue, matcher); return; default: assert.match(evaluated.stringValue, matcher); } } }); } ); });