UNPKG

fontoxpath

Version:

A minimalistic XPath 3.1 engine in JavaScript

260 lines (230 loc) 16.2 kB
import * as slimdom from 'slimdom'; import { evaluateXPathToBoolean, evaluateXPathToString, evaluateXPathToNumber } from 'fontoxpath'; import evaluateXPathToAsyncSingleton from 'test-helpers/evaluateXPathToAsyncSingleton'; describe('cast as', () => { it('accepts empty sequences', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := () cast as xs:boolean? return $r => empty()'))); it('does not accept empty sequences', () => chai.assert.throws(() => evaluateXPathToBoolean('() cast as xs:boolean'), 'XPTY0004')); it('does not accept sequences of length > 1', () => chai.assert.throws(() => evaluateXPathToBoolean('("a", "b") cast as xs:boolean'), 'XPTY0004')); describe('to xs:boolean', () => { it('casts "true" to true', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := "true" cast as xs:boolean return $r instance of xs:boolean and $r = true()'))); it('casts true() to true', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := true() cast as xs:boolean return $r instance of xs:boolean and $r = true()'))); it('casts "false" to false', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := "false" cast as xs:boolean return $r instance of xs:boolean and $r = false()'))); it('casts "1" to true', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := "1" cast as xs:boolean return $r instance of xs:boolean and $r = true()'))); it('casts "0" to false', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := "0" cast as xs:boolean return $r instance of xs:boolean and $r = false()'))); it('casts xs:untypedAtomic to false', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := xs:untypedAtomic("0") cast as xs:boolean return $r instance of xs:boolean and $r = false()'))); it('throws when given an invalid value', () => chai.assert.throws(() => evaluateXPathToBoolean('"wat" cast as xs:boolean'), 'FORG0001')); it('can cast integers to booleans: true', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := 25 cast as xs:boolean return $r instance of xs:boolean and $r = true()'))); it('can cast integers to booleans: false', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := 0 cast as xs:boolean return $r instance of xs:boolean and $r = false()'))); it('allows casting async params', async () => { chai.assert.isTrue(await evaluateXPathToAsyncSingleton('let $r := 0 => fontoxpath:sleep() cast as xs:boolean return $r instance of xs:boolean and $r = false()')); }); }); describe('to xs:integer', () => { it('can cast booleans to integers: false', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := false() cast as xs:integer return $r instance of xs:integer and $r = 0'))); it('can cast booleans to integers: true', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := true() cast as xs:integer return $r instance of xs:integer and $r = 1'))); it('can cast strings to integers: "123"', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := "123" cast as xs:integer return $r instance of xs:integer and $r = 123'))); it('can cast decimals to integers: 123.2', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := 123.2 cast as xs:integer return $r instance of xs:integer and $r = 123'))); it('can cast decimals to integers: NaN', () => chai.assert.throws(() => evaluateXPathToBoolean('xs:double("NaN") cast as xs:integer'), 'FOCA0002')); it('can cast decimals to integers: INF', () => chai.assert.throws(() => evaluateXPathToBoolean('xs:double("INF") cast as xs:integer'), 'FOCA0002')); it('can cast decimals to integers: out of range', () => chai.assert.throws(() => evaluateXPathToBoolean('xs:double("1E100") cast as xs:integer'), 'FOAR0002')); it('can cast strings to integers: unparsable', () => chai.assert.throws(() => evaluateXPathToBoolean('"Not a number" cast as xs:integer'), 'FORG0001')); }); describe('to xs:decimal', () => { it('can cast booleans to decimals: false', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := false() cast as xs:decimal return $r instance of xs:decimal and $r = 0'))); it('can cast booleans to decimals: true', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := true() cast as xs:decimal return $r instance of xs:decimal and $r = 1'))); it('can cast strings to decimals: "123"', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := "123" cast as xs:decimal return $r instance of xs:decimal and $r = 123'))); it('can cast untypedAtomic to decimals: "123"', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := xs:untypedAtomic("123") cast as xs:decimal return $r instance of xs:decimal and $r = 123'))); it('fails casting non-numeric untypedAtomic to decimals: "Not a number at ALL"', () => chai.assert.throws(() => evaluateXPathToBoolean('let $r := xs:untypedAtomic("Not a number at all") cast as xs:decimal return $r instance of xs:decimal and $r = 123'), 'FORG0001')); it('can cast floats to decimals: 123.2', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := xs:float("123.2") cast as xs:decimal return $r instance of xs:decimal and $r = 123.2'))); it('can cast integers to decimals: 123.2', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := 123 cast as xs:decimal return $r instance of xs:decimal and $r = 123'))); it('fails casting NaN to decimals', () => chai.assert.throws(() => evaluateXPathToBoolean('let $r := xs:float("NaN") cast as xs:decimal return $r instance of xs:decimal and $r = 123.2'), 'FOCA0002')); }); describe('to xs:float', () => { it('can cast booleans to floats: false', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := false() cast as xs:float return $r instance of xs:float and $r = 0'))); it('can cast booleans to floats: true', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := true() cast as xs:float return $r instance of xs:float and $r = 1'))); it('can cast strings to floats: "123"', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := "123" cast as xs:float return $r instance of xs:float and $r = 123'))); it('can cast strings to floats: "INF"', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := "INF" cast as xs:float return $r instance of xs:float and $r > 1000000'))); it('can cast strings to floats: "-INF"', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := "-INF" cast as xs:float return $r instance of xs:float and $r < -1000000'))); it('can cast strings to floats: "NaN"', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := "NaN" cast as xs:float return $r instance of xs:float and $r != $r'))); it('can cast strings to floats: "1E100"', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := "1E3" cast as xs:float return $r instance of xs:float and $r = 1000'))); }); describe('to xs:double', () => { it('can cast booleans to doubles: false', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := false() cast as xs:double return $r instance of xs:double and $r = 0'))); it('can cast booleans to doubles: true', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := true() cast as xs:double return $r instance of xs:double and $r = 1'))); it('can cast strings to doubles: "123"', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := "123" cast as xs:double return $r instance of xs:double and $r = 123'))); it('can cast strings to doubles: "INF"', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := "INF" cast as xs:double return $r instance of xs:double and $r > 1000000'))); it('can cast strings to doubles: "-INF"', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := "-INF" cast as xs:double return $r instance of xs:double and $r < -1000000'))); it('can cast strings to doubles: "NaN"', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := "NaN" cast as xs:double return $r instance of xs:double and $r != $r'))); it('can cast strings to doubles: "1E100"', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := "1E3" cast as xs:double return $r instance of xs:double and $r = 1000'))); }); describe('to xs:string', () => { describe('from xs:float', () => { it('can cast floats to strings: 1E100', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := xs:float("1E100") cast as xs:string return $r instance of xs:string and $r = "1E100"'))); it('can cast floats to strings: 1E100', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := xs:float("1E100") cast as xs:string return $r instance of xs:string and $r = "1E100"'))); it('can cast floats to strings: 0', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := xs:float("0") cast as xs:string return $r instance of xs:string and $r = "0"'))); it('can cast floats to strings: -0', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := xs:float("-0") cast as xs:string return $r instance of xs:string and $r = "-0"'))); it('can cast floats to strings: NaN', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := xs:float("NaN") cast as xs:string return $r instance of xs:string and $r = "NaN"'))); it('can cast floats to strings: INF', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := xs:float("INF") cast as xs:string return $r instance of xs:string and $r = "INF"'))); it('can cast floats to strings: -INF', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := xs:float("-INF") cast as xs:string return $r instance of xs:string and $r = "-INF"'))); it('can cast floats to strings: +INF', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := xs:float("+INF") cast as xs:string return $r instance of xs:string and $r = "INF"'))); }); describe('from xs:double', () => { it('can cast doubles to strings: 1E100', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := xs:double("1E100") cast as xs:string return $r instance of xs:string and $r = "1E100"'))); it('can cast doubles to strings: 1E100', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := xs:double("1E100") cast as xs:string return $r instance of xs:string and $r = "1E100"'))); it('can cast doubles to strings: 0', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := xs:double("0") cast as xs:string return $r instance of xs:string and $r = "0"'))); it('can cast doubles to strings: -0', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := xs:double("-0") cast as xs:string return $r instance of xs:string and $r = "-0"'))); it('can cast doubles to strings: INF', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := xs:double("INF") cast as xs:string return $r instance of xs:string and $r = "INF"'))); it('can cast doubles to strings: -INF', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := xs:double("-INF") cast as xs:string return $r instance of xs:string and $r = "-INF"'))); it('can cast doubles to strings: +INF', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := xs:double("+INF") cast as xs:string return $r instance of xs:string and $r = "INF"'))); }); it('can cast integers to strings: 100', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := xs:integer("100") cast as xs:string return $r instance of xs:string and $r = "100"'))); it('can cast integers to strings: -100', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := xs:integer("-100") cast as xs:string return $r instance of xs:string and $r = "-100"'))); }); describe('to xs:untypedAtomic', () => { it('can cast strings to untypedAtomics', () => chai.assert.isTrue(evaluateXPathToBoolean('let $r := xs:untypedAtomic("1E100") cast as xs:untypedAtomic return $r instance of xs:untypedAtomic and $r = "1E100"'))); }); describe('to xs:anyURI', () => { it('can cast strings to anyURI', () => chai.assert.equal(evaluateXPathToString('xs:anyURI("a string")'), 'a string')); }); describe('to xs:hexBinary', () => { it('can cast the empty string to hexBinary', () => chai.assert.isTrue(evaluateXPathToBoolean('exists(xs:hexBinary(""))'))); }); describe('to xs:base64Binary', () => { it('can cast the empty string to base64Binary', () => chai.assert.isTrue(evaluateXPathToBoolean('exists(xs:base64Binary(""))'))); }); describe('to xs:date', () => { it.skip('can cast a string to date: upper bounds. This will not work because JavaScript Dates do not allow setting the year that far back', () => chai.assert.isTrue(evaluateXPathToBoolean('exists(xs:date("25252734927766555-06-07+02:00"))'))); it.skip('can cast a string to date: lower bounds. This will not work because JavaScript Dates do not allow setting the year that far back', () => chai.assert.isTrue(evaluateXPathToBoolean('exists(xs:date("-25252734927766555-06-07+02:00"))'))); }); describe('to xs:gMonthDay', () => { it('can cast a string to gMonthDay: lower bounds', () => chai.assert.isTrue(evaluateXPathToBoolean('exists(xs:gMonthDay("--01-01Z"))'))); it('can cast a string to gMonthDay: upper bounds', () => chai.assert.isTrue(evaluateXPathToBoolean('exists(xs:gMonthDay("--12-31Z"))'))); }); describe('to xs:long', () => { it('can cast strings to xs:long: max bounds. This will not work because of JavaScript numbers not having the same ranges', () => chai.assert.throws(() => evaluateXPathToNumber('xs:long("9223372036854775808")'), 'FOCA0003')); it('can cast strings to xs:long: middle bounds', () => chai.assert.equal(evaluateXPathToNumber('xs:long("922337203685458")'), 922337203685458)); }); describe('to xs:int', () => { it('can cast strings to xs:int', () => chai.assert.equal(evaluateXPathToNumber('xs:int("1234")'), 1234)); it('xs:int can not be written in hexadecimal', () => chai.assert.throws(() => evaluateXPathToNumber('xs:int("0x1234")'), 'FORG0001')); it('xs:int can not be written with fractions', () => chai.assert.throws(() => evaluateXPathToNumber('xs:int("1.0")'), 'FORG0001')); }); describe('to xs:negativeInteger', () => { it('can cast strings to xs:negativeInteger', () => chai.assert.equal(evaluateXPathToNumber('xs:negativeInteger("-10")'), -10)); it('disallows positive values', () => chai.assert.throws(() => evaluateXPathToNumber('xs:negativeInteger("1")'), 'FORG0001')); it('disallows positive values 0', () => chai.assert.throws(() => evaluateXPathToNumber('xs:negativeInteger("0")'), 'FORG0001')); }); describe('to xs:nonNegativeInteger', () => { it('can cast strings to xs:nonNegativeInteger', () => chai.assert.equal(evaluateXPathToNumber('xs:nonNegativeInteger("10")'), 10)); it('allows 0', () => chai.assert.equal(evaluateXPathToNumber('xs:nonNegativeInteger("0")'), 0)); it('disallows negative values', () => chai.assert.throws(() => evaluateXPathToNumber('xs:nonNegativeInteger("-2")'), 'FORG0001')); }); describe('to xs:normalizedString', () => { it('can cast integers to xs:normalizedString', () => chai.assert.equal(evaluateXPathToString('xs:normalizedString(1234)'), '1234')); }); describe('to xs:ENTITY', () => { it('can cast strings to xs:ENTITY', () => chai.assert.equal(evaluateXPathToString('xs:ENTITY("someString")'), 'someString')); it('disallows empty strings', () => chai.assert.throws(() => evaluateXPathToString('xs:ENTITY("")'), 'FORG0001')); }); describe('to xs:language', () => { it('can cast strings to xs:language', () => chai.assert.isTrue(evaluateXPathToBoolean('exists(xs:language("qya"))'))); it('disallows integers at the start', () => chai.assert.throws(() => evaluateXPathToNumber('xs:language("1234")'), 'FORG0001')); it('disallows integers as a type', () => chai.assert.throws(() => evaluateXPathToNumber('xs:language(xs:int("1234"))'), 'FORG0001')); }); describe('to xs:error', () => { it('can not cast anything to xs:error', () => chai.assert.throws(() => evaluateXPathToNumber('1 cast as xs:error'), 'FORG0001')); }); describe('to xs:dayTimeDuration', () => { it('from xs:yearMonthDuration', () => chai.assert.isTrue(evaluateXPathToBoolean('xs:string(xs:dayTimeDuration(xs:yearMonthDuration("-P543Y456M"))) eq "PT0S"'))); }); });