Rename ol.expression to ol.expr
This commit is contained in:
679
test/spec/ol/expr/expression.test.js
Normal file
679
test/spec/ol/expr/expression.test.js
Normal file
@@ -0,0 +1,679 @@
|
||||
goog.provide('ol.test.expression');
|
||||
|
||||
|
||||
describe('ol.expr.parse()', function() {
|
||||
|
||||
it('parses a subset of ECMAScript 5.1 expressions', function() {
|
||||
var expr = ol.expr.parse('foo');
|
||||
expect(expr).to.be.a(ol.expr.Expression);
|
||||
});
|
||||
|
||||
describe('11.1 - primary expressions', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.1
|
||||
|
||||
it('parses identifier expressions', function() {
|
||||
var expr = ol.expr.parse('foo');
|
||||
expect(expr).to.be.a(ol.expr.Identifier);
|
||||
expect(expr.evaluate({foo: 'bar'})).to.be('bar');
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected', function() {
|
||||
var expr = ol.expr.parse(' foo ');
|
||||
expect(expr).to.be.a(ol.expr.Identifier);
|
||||
expect(expr.evaluate({foo: 'bar'})).to.be('bar');
|
||||
});
|
||||
|
||||
it('throws on invalid identifier expressions', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse('3foo');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('f');
|
||||
expect(token.index).to.be(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('parses string literal expressions', function() {
|
||||
var expr = ol.expr.parse('"foo"');
|
||||
expect(expr).to.be.a(ol.expr.Literal);
|
||||
expect(expr.evaluate()).to.be('foo');
|
||||
});
|
||||
|
||||
it('throws on unterminated string', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse('"foo');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.type).to.be(ol.expr.TokenType.EOF);
|
||||
expect(token.index).to.be(4);
|
||||
});
|
||||
});
|
||||
|
||||
it('parses numeric literal expressions', function() {
|
||||
var expr = ol.expr.parse('.42e+2');
|
||||
expect(expr).to.be.a(ol.expr.Literal);
|
||||
expect(expr.evaluate()).to.be(42);
|
||||
});
|
||||
|
||||
it('throws on invalid number', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse('.42eX');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('X');
|
||||
expect(token.index).to.be(4);
|
||||
});
|
||||
});
|
||||
|
||||
it('parses boolean literal expressions', function() {
|
||||
var expr = ol.expr.parse('false');
|
||||
expect(expr).to.be.a(ol.expr.Literal);
|
||||
expect(expr.evaluate()).to.be(false);
|
||||
});
|
||||
|
||||
it('parses null literal expressions', function() {
|
||||
var expr = ol.expr.parse('null');
|
||||
expect(expr).to.be.a(ol.expr.Literal);
|
||||
expect(expr.evaluate()).to.be(null);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('11.2 - left-hand-side expressions', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.2
|
||||
|
||||
it('parses member expressions with dot notation', function() {
|
||||
var expr = ol.expr.parse('foo.bar.baz');
|
||||
expect(expr).to.be.a(ol.expr.Member);
|
||||
var scope = {foo: {bar: {baz: 42}}};
|
||||
expect(expr.evaluate(scope)).to.be(42);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected', function() {
|
||||
var expr = ol.expr.parse(' foo . bar . baz ');
|
||||
expect(expr).to.be.a(ol.expr.Member);
|
||||
var scope = {foo: {bar: {baz: 42}}};
|
||||
expect(expr.evaluate(scope)).to.be(42);
|
||||
});
|
||||
|
||||
it('throws on invalid member expression', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse('foo.4bar');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('b');
|
||||
expect(token.index).to.be(5);
|
||||
});
|
||||
});
|
||||
|
||||
it('parses call expressions with literal arguments', function() {
|
||||
var expr = ol.expr.parse('foo(42, "bar")');
|
||||
expect(expr).to.be.a(ol.expr.Call);
|
||||
var scope = {
|
||||
foo: function(num, str) {
|
||||
expect(num).to.be(42);
|
||||
expect(str).to.be('bar');
|
||||
return str + num;
|
||||
}
|
||||
};
|
||||
expect(expr.evaluate(scope)).to.be('bar42');
|
||||
});
|
||||
|
||||
it('throws on calls with unterminated arguments', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse('foo(42,)');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be(')');
|
||||
expect(token.index).to.be(7);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('11.3 - postfix expressions', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.3
|
||||
it('not supported');
|
||||
});
|
||||
|
||||
|
||||
describe('11.4 - unary operators', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.4
|
||||
|
||||
it('parses logical not operator', function() {
|
||||
var expr = ol.expr.parse('!foo');
|
||||
expect(expr).to.be.a(ol.expr.Not);
|
||||
expect(expr.evaluate({foo: true})).to.be(false);
|
||||
expect(expr.evaluate({foo: false})).to.be(true);
|
||||
expect(expr.evaluate({foo: ''})).to.be(true);
|
||||
expect(expr.evaluate({foo: 'foo'})).to.be(false);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected', function() {
|
||||
var expr = ol.expr.parse(' ! foo');
|
||||
expect(expr).to.be.a(ol.expr.Not);
|
||||
expect(expr.evaluate({foo: true})).to.be(false);
|
||||
expect(expr.evaluate({foo: false})).to.be(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('11.5 - multiplicitave operators', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.5
|
||||
|
||||
it('parses * operator', function() {
|
||||
var expr = ol.expr.parse('foo*bar');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({foo: 10, bar: 20})).to.be(200);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with *', function() {
|
||||
var expr = ol.expr.parse(' foo * bar ');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({foo: 15, bar: 2})).to.be(30);
|
||||
});
|
||||
|
||||
it('parses / operator', function() {
|
||||
var expr = ol.expr.parse('foo/12');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({foo: 10})).to.be(10 / 12);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with /', function() {
|
||||
var expr = ol.expr.parse(' 4 / bar ');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({bar: 3})).to.be(4 / 3);
|
||||
});
|
||||
|
||||
it('parses % operator', function() {
|
||||
var expr = ol.expr.parse('12%foo');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({foo: 10})).to.be(2);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with %', function() {
|
||||
var expr = ol.expr.parse(' 4 %bar ');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({bar: 3})).to.be(1);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('11.6 - additive operators', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.6
|
||||
|
||||
it('parses + operator', function() {
|
||||
var expr = ol.expr.parse('foo+bar');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({foo: 10, bar: 20})).to.be(30);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with +', function() {
|
||||
var expr = ol.expr.parse(' foo +10 ');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({foo: 15})).to.be(25);
|
||||
});
|
||||
|
||||
it('parses - operator', function() {
|
||||
var expr = ol.expr.parse('foo-bar');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({foo: 10, bar: 20})).to.be(-10);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with -', function() {
|
||||
var expr = ol.expr.parse(' foo- 10 ');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({foo: 15})).to.be(5);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('11.7 - bitwise shift operators', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.7
|
||||
it('not supported');
|
||||
});
|
||||
|
||||
describe('11.8 - relational operators', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.8
|
||||
|
||||
it('parses < operator', function() {
|
||||
var expr = ol.expr.parse('foo<bar');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 10, bar: 20})).to.be(true);
|
||||
expect(expr.evaluate({foo: 100, bar: 20})).to.be(false);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with <', function() {
|
||||
var expr = ol.expr.parse(' foo <10 ');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 15})).to.be(false);
|
||||
expect(expr.evaluate({foo: 5})).to.be(true);
|
||||
});
|
||||
|
||||
it('parses > operator', function() {
|
||||
var expr = ol.expr.parse('foo>bar');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 10, bar: 20})).to.be(false);
|
||||
expect(expr.evaluate({foo: 100, bar: 20})).to.be(true);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with >', function() {
|
||||
var expr = ol.expr.parse(' foo> 10 ');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 15})).to.be(true);
|
||||
expect(expr.evaluate({foo: 5})).to.be(false);
|
||||
});
|
||||
|
||||
it('parses <= operator', function() {
|
||||
var expr = ol.expr.parse('foo<=bar');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 10, bar: 20})).to.be(true);
|
||||
expect(expr.evaluate({foo: 100, bar: 20})).to.be(false);
|
||||
expect(expr.evaluate({foo: 20, bar: 20})).to.be(true);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with <=', function() {
|
||||
var expr = ol.expr.parse(' foo<= 10 ');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 15})).to.be(false);
|
||||
expect(expr.evaluate({foo: 5})).to.be(true);
|
||||
expect(expr.evaluate({foo: 10})).to.be(true);
|
||||
});
|
||||
|
||||
it('throws for invalid spacing with <=', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse(' foo< = 10 ');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('=');
|
||||
expect(token.index).to.be(6);
|
||||
});
|
||||
});
|
||||
|
||||
it('parses >= operator', function() {
|
||||
var expr = ol.expr.parse('foo>=bar');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 10, bar: 20})).to.be(false);
|
||||
expect(expr.evaluate({foo: 100, bar: 20})).to.be(true);
|
||||
expect(expr.evaluate({foo: 20, bar: 20})).to.be(true);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with >=', function() {
|
||||
var expr = ol.expr.parse(' foo >=10 ');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 15})).to.be(true);
|
||||
expect(expr.evaluate({foo: 5})).to.be(false);
|
||||
expect(expr.evaluate({foo: 10})).to.be(true);
|
||||
});
|
||||
|
||||
it('throws for invalid spacing with >=', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse(' 10 > =foo ');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('=');
|
||||
expect(token.index).to.be(6);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('11.9 - equality operators', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.9
|
||||
|
||||
it('parses == operator', function() {
|
||||
var expr = ol.expr.parse('foo==42');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 42})).to.be(true);
|
||||
expect(expr.evaluate({foo: 41})).to.be(false);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(true);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with ==', function() {
|
||||
var expr = ol.expr.parse(' 42 ==foo ');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 42})).to.be(true);
|
||||
expect(expr.evaluate({foo: 41})).to.be(false);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(true);
|
||||
});
|
||||
|
||||
it('throws for invalid spacing with ==', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse(' 10 = =foo ');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('=');
|
||||
expect(token.index).to.be(4);
|
||||
});
|
||||
});
|
||||
|
||||
it('parses != operator', function() {
|
||||
var expr = ol.expr.parse('foo!=42');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 42})).to.be(false);
|
||||
expect(expr.evaluate({foo: 41})).to.be(true);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(false);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with !=', function() {
|
||||
var expr = ol.expr.parse(' 42 !=foo ');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 42})).to.be(false);
|
||||
expect(expr.evaluate({foo: 41})).to.be(true);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(false);
|
||||
});
|
||||
|
||||
it('throws for invalid spacing with !=', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse(' 10! =foo ');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('!');
|
||||
expect(token.index).to.be(3);
|
||||
});
|
||||
});
|
||||
|
||||
it('parses === operator', function() {
|
||||
var expr = ol.expr.parse('42===foo');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 42})).to.be(true);
|
||||
expect(expr.evaluate({foo: 41})).to.be(false);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(false);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with ===', function() {
|
||||
var expr = ol.expr.parse(' foo ===42 ');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 42})).to.be(true);
|
||||
expect(expr.evaluate({foo: 41})).to.be(false);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(false);
|
||||
});
|
||||
|
||||
it('throws for invalid spacing with ===', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse(' 10 = == foo ');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('=');
|
||||
expect(token.index).to.be(4);
|
||||
});
|
||||
});
|
||||
|
||||
it('parses !== operator', function() {
|
||||
var expr = ol.expr.parse('foo!==42');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 42})).to.be(false);
|
||||
expect(expr.evaluate({foo: 41})).to.be(true);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(true);
|
||||
});
|
||||
|
||||
it('consumes whitespace as expected with !==', function() {
|
||||
var expr = ol.expr.parse(' 42 !== foo ');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate({foo: 42})).to.be(false);
|
||||
expect(expr.evaluate({foo: 41})).to.be(true);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(true);
|
||||
});
|
||||
|
||||
it('throws for invalid spacing with !==', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse(' 10 != = foo ');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('=');
|
||||
expect(token.index).to.be(7);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('11.10 - binary bitwise operators', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.10
|
||||
it('not supported');
|
||||
});
|
||||
|
||||
describe('11.11 - binary logical operators', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.11
|
||||
|
||||
it('parses && operator', function() {
|
||||
var expr = ol.expr.parse('foo&&bar');
|
||||
expect(expr).to.be.a(ol.expr.Logical);
|
||||
expect(expr.evaluate({foo: true, bar: true})).to.be(true);
|
||||
expect(expr.evaluate({foo: true, bar: false})).to.be(false);
|
||||
expect(expr.evaluate({foo: false, bar: true})).to.be(false);
|
||||
expect(expr.evaluate({foo: false, bar: false})).to.be(false);
|
||||
});
|
||||
|
||||
it('consumes space as expected with &&', function() {
|
||||
var expr = ol.expr.parse(' foo && bar ');
|
||||
expect(expr).to.be.a(ol.expr.Logical);
|
||||
expect(expr.evaluate({foo: true, bar: true})).to.be(true);
|
||||
expect(expr.evaluate({foo: true, bar: false})).to.be(false);
|
||||
expect(expr.evaluate({foo: false, bar: true})).to.be(false);
|
||||
expect(expr.evaluate({foo: false, bar: false})).to.be(false);
|
||||
});
|
||||
|
||||
it('throws for invalid spacing with &&', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse('true & & false');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('&');
|
||||
expect(token.index).to.be(5);
|
||||
});
|
||||
});
|
||||
|
||||
it('parses || operator', function() {
|
||||
var expr = ol.expr.parse('foo||bar');
|
||||
expect(expr).to.be.a(ol.expr.Logical);
|
||||
expect(expr.evaluate({foo: true, bar: true})).to.be(true);
|
||||
expect(expr.evaluate({foo: true, bar: false})).to.be(true);
|
||||
expect(expr.evaluate({foo: false, bar: true})).to.be(true);
|
||||
expect(expr.evaluate({foo: false, bar: false})).to.be(false);
|
||||
});
|
||||
|
||||
it('consumes space as expected with ||', function() {
|
||||
var expr = ol.expr.parse(' foo || bar ');
|
||||
expect(expr).to.be.a(ol.expr.Logical);
|
||||
expect(expr.evaluate({foo: true, bar: true})).to.be(true);
|
||||
expect(expr.evaluate({foo: true, bar: false})).to.be(true);
|
||||
expect(expr.evaluate({foo: false, bar: true})).to.be(true);
|
||||
expect(expr.evaluate({foo: false, bar: false})).to.be(false);
|
||||
});
|
||||
|
||||
it('throws for invalid spacing with ||', function() {
|
||||
expect(function() {
|
||||
ol.expr.parse('true | | false');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('|');
|
||||
expect(token.index).to.be(5);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('11.12 - conditional operator', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.12
|
||||
it('not supported');
|
||||
});
|
||||
|
||||
describe('11.13 - assignment operators', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.13
|
||||
it('not supported');
|
||||
});
|
||||
|
||||
describe('11.14 - comma operator', function() {
|
||||
// http://www.ecma-international.org/ecma-262/5.1/#sec-11.14
|
||||
it('not supported');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('ol.expr.lib', function() {
|
||||
|
||||
var parse = ol.expr.parse;
|
||||
var evaluate = ol.expr.evaluateFeature;
|
||||
|
||||
describe('extent()', function() {
|
||||
|
||||
var nw = new ol.Feature({
|
||||
geom: new ol.geom.Polygon([[
|
||||
[-180, 90], [0, 90], [0, 0], [-180, 0], [-180, 90]
|
||||
]])
|
||||
});
|
||||
|
||||
var se = new ol.Feature({
|
||||
geom: new ol.geom.Polygon([[
|
||||
[180, -90], [0, -90], [0, 0], [180, 0], [180, -90]
|
||||
]])
|
||||
});
|
||||
|
||||
var north = parse('extent(-100, 100, 40, 60)');
|
||||
var south = parse('extent(-100, 100, -60, -40)');
|
||||
var east = parse('extent(80, 100, -50, 50)');
|
||||
var west = parse('extent(-100, -80, -50, 50)');
|
||||
|
||||
it('evaluates to true for features within given extent', function() {
|
||||
|
||||
expect(evaluate(north, nw), true);
|
||||
expect(evaluate(south, nw), false);
|
||||
expect(evaluate(east, nw), false);
|
||||
expect(evaluate(west, nw), true);
|
||||
|
||||
expect(evaluate(north, se), false);
|
||||
expect(evaluate(south, se), true);
|
||||
expect(evaluate(east, se), true);
|
||||
expect(evaluate(west, se), false);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('geometryType()', function() {
|
||||
|
||||
var point = new ol.Feature({
|
||||
geom: new ol.geom.Point([0, 0])
|
||||
});
|
||||
|
||||
var line = new ol.Feature({
|
||||
geom: new ol.geom.LineString([[180, -90], [-180, 90]])
|
||||
});
|
||||
|
||||
var poly = new ol.Feature({
|
||||
geom: new ol.geom.Polygon([[
|
||||
[180, -90], [0, -90], [0, 0], [180, 0], [180, -90]
|
||||
]])
|
||||
});
|
||||
|
||||
var isPoint = parse('geometryType("point")');
|
||||
var isLine = parse('geometryType("linestring")');
|
||||
var isPoly = parse('geometryType("polygon")');
|
||||
var pointOrPoly = parse('geometryType("point") || geometryType("polygon")');
|
||||
|
||||
it('distinguishes point features', function() {
|
||||
expect(evaluate(isPoint, point), true);
|
||||
expect(evaluate(isPoint, line), false);
|
||||
expect(evaluate(isPoint, poly), false);
|
||||
});
|
||||
|
||||
it('distinguishes line features', function() {
|
||||
expect(evaluate(isLine, point), false);
|
||||
expect(evaluate(isLine, line), true);
|
||||
expect(evaluate(isLine, poly), false);
|
||||
});
|
||||
|
||||
it('distinguishes polygon features', function() {
|
||||
expect(evaluate(isPoly, point), false);
|
||||
expect(evaluate(isPoly, line), false);
|
||||
expect(evaluate(isPoly, poly), true);
|
||||
});
|
||||
|
||||
it('can be composed in a logical expression', function() {
|
||||
expect(evaluate(pointOrPoly, point), true);
|
||||
expect(evaluate(pointOrPoly, line), false);
|
||||
expect(evaluate(pointOrPoly, poly), true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('ol.expr.register()', function() {
|
||||
|
||||
var spy;
|
||||
beforeEach(function() {
|
||||
spy = sinon.spy();
|
||||
});
|
||||
|
||||
it('registers custom functions in ol.expr.lib', function() {
|
||||
ol.expr.register('someFunc', spy);
|
||||
expect(ol.expr.lib.someFunc).to.be(spy);
|
||||
});
|
||||
|
||||
it('allows custom functions to be called', function() {
|
||||
ol.expr.register('myFunc', spy);
|
||||
var expr = ol.expr.parse('myFunc(42)');
|
||||
expr.evaluate(null, ol.expr.lib);
|
||||
expect(spy.calledOnce);
|
||||
expect(spy.calledWithExactly(42));
|
||||
});
|
||||
|
||||
it('allows custom functions to be called with identifiers', function() {
|
||||
ol.expr.register('myFunc', spy);
|
||||
var expr = ol.expr.parse('myFunc(foo, 42)');
|
||||
expr.evaluate({foo: 'bar'}, ol.expr.lib);
|
||||
expect(spy.calledOnce);
|
||||
expect(spy.calledWithExactly('bar', 42));
|
||||
});
|
||||
|
||||
it('allows custom functions to be called with custom this obj', function() {
|
||||
ol.expr.register('myFunc', spy);
|
||||
var expr = ol.expr.parse('myFunc(foo, 42)');
|
||||
var that = {};
|
||||
expr.evaluate({foo: 'bar'}, ol.expr.lib, that);
|
||||
expect(spy.calledOnce);
|
||||
expect(spy.calledWithExactly('bar', 42));
|
||||
expect(spy.calledOn(that));
|
||||
});
|
||||
|
||||
it('allows overriding existing ol.expr.lib functions', function() {
|
||||
var orig = ol.expr.lib.extent;
|
||||
expect(orig).not.to.be(spy);
|
||||
ol.expr.register('extent', spy);
|
||||
expect(ol.expr.lib.extent).to.be(spy);
|
||||
ol.expr.lib.extent = orig;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.expr');
|
||||
goog.require('ol.expr.Call');
|
||||
goog.require('ol.expr.Comparison');
|
||||
goog.require('ol.expr.Expression');
|
||||
goog.require('ol.expr.Identifier');
|
||||
goog.require('ol.expr.Literal');
|
||||
goog.require('ol.expr.Logical');
|
||||
goog.require('ol.expr.Math');
|
||||
goog.require('ol.expr.Member');
|
||||
goog.require('ol.expr.Not');
|
||||
goog.require('ol.expr.TokenType');
|
||||
goog.require('ol.expr.UnexpectedToken');
|
||||
goog.require('ol.geom.LineString');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.geom.Polygon');
|
||||
638
test/spec/ol/expr/expressions.test.js
Normal file
638
test/spec/ol/expr/expressions.test.js
Normal file
@@ -0,0 +1,638 @@
|
||||
goog.provide('ol.test.expression.Expression');
|
||||
|
||||
|
||||
describe('ol.expr.Call', function() {
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new expression', function() {
|
||||
var expr = new ol.expr.Call(
|
||||
new ol.expr.Identifier('sqrt'),
|
||||
[new ol.expr.Literal(42)]);
|
||||
expect(expr).to.be.a(ol.expr.Expression);
|
||||
expect(expr).to.be.a(ol.expr.Call);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#evaluate()', function() {
|
||||
var fns = {
|
||||
sqrt: function(value) {
|
||||
return Math.sqrt(value);
|
||||
},
|
||||
strConcat: function() {
|
||||
return Array.prototype.join.call(arguments, '');
|
||||
},
|
||||
discouraged: function() {
|
||||
return this.message;
|
||||
}
|
||||
};
|
||||
|
||||
it('calls method on scope with literal args', function() {
|
||||
var expr = new ol.expr.Call(
|
||||
new ol.expr.Identifier('sqrt'),
|
||||
[new ol.expr.Literal(42)]);
|
||||
expect(expr.evaluate(fns)).to.be(Math.sqrt(42));
|
||||
});
|
||||
|
||||
it('accepts a separate scope for functions', function() {
|
||||
var expr = new ol.expr.Call(
|
||||
new ol.expr.Identifier('sqrt'),
|
||||
[new ol.expr.Identifier('foo')]);
|
||||
expect(expr.evaluate({foo: 42}, fns)).to.be(Math.sqrt(42));
|
||||
});
|
||||
|
||||
it('accepts multiple expression arguments', function() {
|
||||
var expr = new ol.expr.Call(
|
||||
new ol.expr.Identifier('strConcat'),
|
||||
[
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(' comes after '),
|
||||
new ol.expr.Math(
|
||||
ol.expr.MathOp.SUBTRACT,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(1))
|
||||
]);
|
||||
expect(expr.evaluate({foo: 42}, fns)).to.be('42 comes after 41');
|
||||
});
|
||||
|
||||
it('accepts optional this arg', function() {
|
||||
var expr = new ol.expr.Call(
|
||||
new ol.expr.Identifier('discouraged'), []);
|
||||
|
||||
var thisArg = {
|
||||
message: 'avoid this'
|
||||
};
|
||||
|
||||
expect(expr.evaluate(fns, null, thisArg)).to.be('avoid this');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
var callee = new ol.expr.Identifier('sqrt');
|
||||
var args = [new ol.expr.Literal(42)];
|
||||
var expr = new ol.expr.Call(callee, args);
|
||||
|
||||
describe('#getArgs()', function() {
|
||||
it('gets the callee expression', function() {
|
||||
expect(expr.getArgs()).to.be(args);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getCallee()', function() {
|
||||
it('gets the callee expression', function() {
|
||||
expect(expr.getCallee()).to.be(callee);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('ol.expr.Comparison', function() {
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new expression', function() {
|
||||
var expr = new ol.expr.Comparison(
|
||||
ol.expr.ComparisonOp.EQ,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(42));
|
||||
expect(expr).to.be.a(ol.expr.Expression);
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#evaluate()', function() {
|
||||
it('compares with ==', function() {
|
||||
var expr = new ol.expr.Comparison(
|
||||
ol.expr.ComparisonOp.EQ,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(42));
|
||||
|
||||
expect(expr.evaluate({foo: 42})).to.be(true);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(true);
|
||||
expect(expr.evaluate({foo: true})).to.be(false);
|
||||
expect(expr.evaluate({bar: true})).to.be(false);
|
||||
});
|
||||
|
||||
it('compares with !=', function() {
|
||||
var expr = new ol.expr.Comparison(
|
||||
ol.expr.ComparisonOp.NEQ,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(42));
|
||||
|
||||
expect(expr.evaluate({foo: 42})).to.be(false);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(false);
|
||||
expect(expr.evaluate({foo: true})).to.be(true);
|
||||
expect(expr.evaluate({bar: true})).to.be(true);
|
||||
});
|
||||
|
||||
it('compares with ===', function() {
|
||||
var expr = new ol.expr.Comparison(
|
||||
ol.expr.ComparisonOp.STRICT_EQ,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(42));
|
||||
|
||||
expect(expr.evaluate({foo: 42})).to.be(true);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(false);
|
||||
expect(expr.evaluate({foo: true})).to.be(false);
|
||||
expect(expr.evaluate({bar: true})).to.be(false);
|
||||
});
|
||||
|
||||
it('compares with !==', function() {
|
||||
var expr = new ol.expr.Comparison(
|
||||
ol.expr.ComparisonOp.STRICT_NEQ,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(42));
|
||||
|
||||
expect(expr.evaluate({foo: 42})).to.be(false);
|
||||
expect(expr.evaluate({foo: '42'})).to.be(true);
|
||||
expect(expr.evaluate({foo: true})).to.be(true);
|
||||
expect(expr.evaluate({bar: true})).to.be(true);
|
||||
});
|
||||
|
||||
it('compares with >', function() {
|
||||
var expr = new ol.expr.Comparison(
|
||||
ol.expr.ComparisonOp.GT,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(42));
|
||||
|
||||
expect(expr.evaluate({foo: 42})).to.be(false);
|
||||
expect(expr.evaluate({foo: 41})).to.be(false);
|
||||
expect(expr.evaluate({foo: 43})).to.be(true);
|
||||
});
|
||||
|
||||
it('compares with <', function() {
|
||||
var expr = new ol.expr.Comparison(
|
||||
ol.expr.ComparisonOp.LT,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(42));
|
||||
|
||||
expect(expr.evaluate({foo: 42})).to.be(false);
|
||||
expect(expr.evaluate({foo: 41})).to.be(true);
|
||||
expect(expr.evaluate({foo: 43})).to.be(false);
|
||||
});
|
||||
|
||||
it('compares with >=', function() {
|
||||
var expr = new ol.expr.Comparison(
|
||||
ol.expr.ComparisonOp.GTE,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(42));
|
||||
|
||||
expect(expr.evaluate({foo: 42})).to.be(true);
|
||||
expect(expr.evaluate({foo: 41})).to.be(false);
|
||||
expect(expr.evaluate({foo: 43})).to.be(true);
|
||||
});
|
||||
|
||||
it('compares with <=', function() {
|
||||
var expr = new ol.expr.Comparison(
|
||||
ol.expr.ComparisonOp.LTE,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(42));
|
||||
|
||||
expect(expr.evaluate({foo: 42})).to.be(true);
|
||||
expect(expr.evaluate({foo: 41})).to.be(true);
|
||||
expect(expr.evaluate({foo: 43})).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isValidOp()', function() {
|
||||
it('determines if a string is a valid operator', function() {
|
||||
expect(ol.expr.Comparison.isValidOp('<')).to.be(true);
|
||||
expect(ol.expr.Comparison.isValidOp('<')).to.be(true);
|
||||
expect(ol.expr.Comparison.isValidOp('<=')).to.be(true);
|
||||
expect(ol.expr.Comparison.isValidOp('<=')).to.be(true);
|
||||
expect(ol.expr.Comparison.isValidOp('==')).to.be(true);
|
||||
expect(ol.expr.Comparison.isValidOp('!=')).to.be(true);
|
||||
expect(ol.expr.Comparison.isValidOp('===')).to.be(true);
|
||||
expect(ol.expr.Comparison.isValidOp('!==')).to.be(true);
|
||||
|
||||
expect(ol.expr.Comparison.isValidOp('')).to.be(false);
|
||||
expect(ol.expr.Comparison.isValidOp('+')).to.be(false);
|
||||
expect(ol.expr.Comparison.isValidOp('-')).to.be(false);
|
||||
expect(ol.expr.Comparison.isValidOp('&&')).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
var op = ol.expr.ComparisonOp.LTE;
|
||||
var left = new ol.expr.Identifier('foo');
|
||||
var right = new ol.expr.Literal(42);
|
||||
var expr = new ol.expr.Comparison(op, left, right);
|
||||
|
||||
describe('#getOperator()', function() {
|
||||
it('gets the operator', function() {
|
||||
expect(expr.getOperator()).to.be(op);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getLeft()', function() {
|
||||
it('gets the left expression', function() {
|
||||
expect(expr.getLeft()).to.be(left);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getRight()', function() {
|
||||
it('gets the right expression', function() {
|
||||
expect(expr.getRight()).to.be(right);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('ol.expr.Identifier', function() {
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new expression', function() {
|
||||
var expr = new ol.expr.Identifier('foo');
|
||||
expect(expr).to.be.a(ol.expr.Expression);
|
||||
expect(expr).to.be.a(ol.expr.Identifier);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#evaluate()', function() {
|
||||
it('returns a number from the scope', function() {
|
||||
var expr = new ol.expr.Identifier('foo');
|
||||
expect(expr.evaluate({foo: 42})).to.be(42);
|
||||
});
|
||||
|
||||
it('returns a string from the scope', function() {
|
||||
var expr = new ol.expr.Identifier('foo');
|
||||
expect(expr.evaluate({foo: 'chicken'})).to.be('chicken');
|
||||
});
|
||||
|
||||
it('returns a boolean from the scope', function() {
|
||||
var expr = new ol.expr.Identifier('bar');
|
||||
expect(expr.evaluate({bar: false})).to.be(false);
|
||||
expect(expr.evaluate({bar: true})).to.be(true);
|
||||
});
|
||||
|
||||
it('returns a null from the scope', function() {
|
||||
var expr = new ol.expr.Identifier('nada');
|
||||
expect(expr.evaluate({nada: null})).to.be(null);
|
||||
});
|
||||
|
||||
it('works for unicode identifiers', function() {
|
||||
var expr = new ol.expr.Identifier('\u03c0');
|
||||
expect(expr.evaluate({'\u03c0': Math.PI})).to.be(Math.PI);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getName()', function() {
|
||||
var expr = new ol.expr.Identifier('asdf');
|
||||
expect(expr.getName()).to.be('asdf');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('ol.expr.Literal', function() {
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new expression', function() {
|
||||
var expr = new ol.expr.Literal(true);
|
||||
expect(expr).to.be.a(ol.expr.Expression);
|
||||
expect(expr).to.be.a(ol.expr.Literal);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#evaluate()', function() {
|
||||
it('works for numeric literal', function() {
|
||||
var expr = new ol.expr.Literal(42e-11);
|
||||
expect(expr.evaluate()).to.be(4.2e-10);
|
||||
});
|
||||
|
||||
it('works for string literal', function() {
|
||||
var expr = new ol.expr.Literal('asdf');
|
||||
expect(expr.evaluate()).to.be('asdf');
|
||||
});
|
||||
|
||||
it('works for boolean literal', function() {
|
||||
var expr = new ol.expr.Literal(true);
|
||||
expect(expr.evaluate()).to.be(true);
|
||||
});
|
||||
|
||||
it('works for null literal', function() {
|
||||
var expr = new ol.expr.Literal(null);
|
||||
expect(expr.evaluate()).to.be(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getValue()', function() {
|
||||
var expr = new ol.expr.Literal('asdf');
|
||||
expect(expr.getValue()).to.be('asdf');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('ol.expr.Logical', function() {
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new expression', function() {
|
||||
var expr = new ol.expr.Logical(
|
||||
ol.expr.LogicalOp.OR,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Identifier('bar'));
|
||||
expect(expr).to.be.a(ol.expr.Expression);
|
||||
expect(expr).to.be.a(ol.expr.Logical);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#evaluate()', function() {
|
||||
it('applies || to resolved identifiers', function() {
|
||||
var expr = new ol.expr.Logical(
|
||||
ol.expr.LogicalOp.OR,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Identifier('bar'));
|
||||
|
||||
expect(expr.evaluate({foo: true, bar: true})).to.be(true);
|
||||
expect(expr.evaluate({foo: true, bar: false})).to.be(true);
|
||||
expect(expr.evaluate({foo: false, bar: true})).to.be(true);
|
||||
expect(expr.evaluate({foo: false, bar: false})).to.be(false);
|
||||
});
|
||||
|
||||
it('applies && to resolved identifiers', function() {
|
||||
var expr = new ol.expr.Logical(
|
||||
ol.expr.LogicalOp.AND,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Identifier('bar'));
|
||||
|
||||
expect(expr.evaluate({foo: true, bar: true})).to.be(true);
|
||||
expect(expr.evaluate({foo: true, bar: false})).to.be(false);
|
||||
expect(expr.evaluate({foo: false, bar: true})).to.be(false);
|
||||
expect(expr.evaluate({foo: false, bar: false})).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isValidOp()', function() {
|
||||
it('determines if a string is a valid operator', function() {
|
||||
expect(ol.expr.Logical.isValidOp('||')).to.be(true);
|
||||
expect(ol.expr.Logical.isValidOp('&&')).to.be(true);
|
||||
|
||||
expect(ol.expr.Logical.isValidOp('')).to.be(false);
|
||||
expect(ol.expr.Logical.isValidOp('+')).to.be(false);
|
||||
expect(ol.expr.Logical.isValidOp('<')).to.be(false);
|
||||
expect(ol.expr.Logical.isValidOp('|')).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
var op = ol.expr.LogicalOp.AND;
|
||||
var left = new ol.expr.Identifier('foo');
|
||||
var right = new ol.expr.Literal(false);
|
||||
var expr = new ol.expr.Logical(op, left, right);
|
||||
|
||||
describe('#getOperator()', function() {
|
||||
it('gets the operator', function() {
|
||||
expect(expr.getOperator()).to.be(op);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getLeft()', function() {
|
||||
it('gets the left expression', function() {
|
||||
expect(expr.getLeft()).to.be(left);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getRight()', function() {
|
||||
it('gets the right expression', function() {
|
||||
expect(expr.getRight()).to.be(right);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('ol.expr.Math', function() {
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new expression', function() {
|
||||
var expr = new ol.expr.Math(
|
||||
ol.expr.MathOp.ADD,
|
||||
new ol.expr.Literal(40),
|
||||
new ol.expr.Literal(2));
|
||||
expect(expr).to.be.a(ol.expr.Expression);
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#evaluate()', function() {
|
||||
it('does + with numeric literal', function() {
|
||||
var expr = new ol.expr.Math(
|
||||
ol.expr.MathOp.ADD,
|
||||
new ol.expr.Literal(40),
|
||||
new ol.expr.Literal(2));
|
||||
|
||||
expect(expr.evaluate()).to.be(42);
|
||||
});
|
||||
|
||||
it('does + with string literal (note: subject to change)', function() {
|
||||
var expr = new ol.expr.Math(
|
||||
ol.expr.MathOp.ADD,
|
||||
new ol.expr.Literal('foo'),
|
||||
new ol.expr.Literal('bar'));
|
||||
|
||||
expect(expr.evaluate()).to.be('foobar');
|
||||
});
|
||||
|
||||
it('does + with identifiers', function() {
|
||||
var expr = new ol.expr.Math(
|
||||
ol.expr.MathOp.ADD,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Identifier('bar'));
|
||||
|
||||
expect(expr.evaluate({foo: 40, bar: 2})).to.be(42);
|
||||
});
|
||||
|
||||
it('does - with identifiers', function() {
|
||||
var expr = new ol.expr.Math(
|
||||
ol.expr.MathOp.SUBTRACT,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(2));
|
||||
|
||||
expect(expr.evaluate({foo: 40})).to.be(38);
|
||||
});
|
||||
|
||||
it('casts to number with - (note: this may throw later)', function() {
|
||||
var expr = new ol.expr.Math(
|
||||
ol.expr.MathOp.SUBTRACT,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(2));
|
||||
|
||||
expect(expr.evaluate({foo: '40'})).to.be(38);
|
||||
});
|
||||
|
||||
it('does * with identifiers', function() {
|
||||
var expr = new ol.expr.Math(
|
||||
ol.expr.MathOp.MULTIPLY,
|
||||
new ol.expr.Literal(2),
|
||||
new ol.expr.Identifier('foo'));
|
||||
|
||||
expect(expr.evaluate({foo: 21})).to.be(42);
|
||||
});
|
||||
|
||||
it('casts to number with * (note: this may throw later)', function() {
|
||||
var expr = new ol.expr.Math(
|
||||
ol.expr.MathOp.MULTIPLY,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(2));
|
||||
|
||||
expect(expr.evaluate({foo: '21'})).to.be(42);
|
||||
});
|
||||
|
||||
it('does % with identifiers', function() {
|
||||
var expr = new ol.expr.Math(
|
||||
ol.expr.MathOp.MOD,
|
||||
new ol.expr.Literal(97),
|
||||
new ol.expr.Identifier('foo'));
|
||||
|
||||
expect(expr.evaluate({foo: 55})).to.be(42);
|
||||
});
|
||||
|
||||
it('casts to number with % (note: this may throw later)', function() {
|
||||
var expr = new ol.expr.Math(
|
||||
ol.expr.MathOp.MOD,
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Literal(100));
|
||||
|
||||
expect(expr.evaluate({foo: '150'})).to.be(50);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isValidOp()', function() {
|
||||
it('determines if a string is a valid operator', function() {
|
||||
expect(ol.expr.Math.isValidOp('+')).to.be(true);
|
||||
expect(ol.expr.Math.isValidOp('-')).to.be(true);
|
||||
expect(ol.expr.Math.isValidOp('*')).to.be(true);
|
||||
expect(ol.expr.Math.isValidOp('/')).to.be(true);
|
||||
expect(ol.expr.Math.isValidOp('%')).to.be(true);
|
||||
|
||||
expect(ol.expr.Math.isValidOp('')).to.be(false);
|
||||
expect(ol.expr.Math.isValidOp('|')).to.be(false);
|
||||
expect(ol.expr.Math.isValidOp('&')).to.be(false);
|
||||
expect(ol.expr.Math.isValidOp('<')).to.be(false);
|
||||
expect(ol.expr.Math.isValidOp('||')).to.be(false);
|
||||
expect(ol.expr.Math.isValidOp('.')).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
var op = ol.expr.MathOp.MOD;
|
||||
var left = new ol.expr.Identifier('foo');
|
||||
var right = new ol.expr.Literal(20);
|
||||
var expr = new ol.expr.Math(op, left, right);
|
||||
|
||||
describe('#getOperator()', function() {
|
||||
it('gets the operator', function() {
|
||||
expect(expr.getOperator()).to.be(op);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getLeft()', function() {
|
||||
it('gets the left expression', function() {
|
||||
expect(expr.getLeft()).to.be(left);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getRight()', function() {
|
||||
it('gets the right expression', function() {
|
||||
expect(expr.getRight()).to.be(right);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('ol.expr.Member', function() {
|
||||
describe('constructor', function() {
|
||||
it('creates a new expression', function() {
|
||||
var expr = new ol.expr.Member(
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Identifier('bar'));
|
||||
|
||||
expect(expr).to.be.a(ol.expr.Expression);
|
||||
expect(expr).to.be.a(ol.expr.Member);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#evaluate()', function() {
|
||||
it('accesses an object property', function() {
|
||||
|
||||
var expr = new ol.expr.Member(
|
||||
new ol.expr.Identifier('foo'),
|
||||
new ol.expr.Identifier('bar'));
|
||||
|
||||
var scope = {foo: {bar: 42}};
|
||||
expect(expr.evaluate(scope)).to.be(42);
|
||||
});
|
||||
});
|
||||
|
||||
var object = new ol.expr.Identifier('foo');
|
||||
var property = new ol.expr.Identifier('bar');
|
||||
var expr = new ol.expr.Member(object, property);
|
||||
|
||||
describe('#getObject()', function() {
|
||||
expect(expr.getObject()).to.be(object);
|
||||
});
|
||||
|
||||
describe('#getProperty()', function() {
|
||||
expect(expr.getProperty()).to.be(property);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('ol.expr.Not', function() {
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new expression', function() {
|
||||
var expr = new ol.expr.Not(
|
||||
new ol.expr.Literal(true));
|
||||
expect(expr).to.be.a(ol.expr.Expression);
|
||||
expect(expr).to.be.a(ol.expr.Not);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#evaluate()', function() {
|
||||
it('returns the logical complement', function() {
|
||||
var expr = new ol.expr.Not(new ol.expr.Literal(true));
|
||||
expect(expr.evaluate()).to.be(false);
|
||||
|
||||
expr = new ol.expr.Not(new ol.expr.Literal(false));
|
||||
expect(expr.evaluate()).to.be(true);
|
||||
});
|
||||
|
||||
it('negates a truthy string', function() {
|
||||
var expr = new ol.expr.Not(new ol.expr.Literal('asdf'));
|
||||
expect(expr.evaluate()).to.be(false);
|
||||
});
|
||||
|
||||
it('negates a falsy string', function() {
|
||||
var expr = new ol.expr.Not(new ol.expr.Literal(''));
|
||||
expect(expr.evaluate()).to.be(true);
|
||||
});
|
||||
|
||||
it('negates a truthy number', function() {
|
||||
var expr = new ol.expr.Not(new ol.expr.Literal(42));
|
||||
expect(expr.evaluate()).to.be(false);
|
||||
});
|
||||
|
||||
it('negates a falsy number', function() {
|
||||
var expr = new ol.expr.Not(new ol.expr.Literal(NaN));
|
||||
expect(expr.evaluate()).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getArgument()', function() {
|
||||
var argument = new ol.expr.Literal(true);
|
||||
var expr = new ol.expr.Not(argument);
|
||||
expect(expr.getArgument()).to.be(argument);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
goog.require('ol.expr.Call');
|
||||
goog.require('ol.expr.Comparison');
|
||||
goog.require('ol.expr.ComparisonOp');
|
||||
goog.require('ol.expr.Expression');
|
||||
goog.require('ol.expr.Identifier');
|
||||
goog.require('ol.expr.Literal');
|
||||
goog.require('ol.expr.Logical');
|
||||
goog.require('ol.expr.LogicalOp');
|
||||
goog.require('ol.expr.Math');
|
||||
goog.require('ol.expr.MathOp');
|
||||
goog.require('ol.expr.Member');
|
||||
goog.require('ol.expr.Not');
|
||||
509
test/spec/ol/expr/lexer.test.js
Normal file
509
test/spec/ol/expr/lexer.test.js
Normal file
@@ -0,0 +1,509 @@
|
||||
goog.provide('ol.test.expression.Lexer');
|
||||
|
||||
describe('ol.expr.Lexer', function() {
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new lexer', function() {
|
||||
var lexer = new ol.expr.Lexer('foo');
|
||||
expect(lexer).to.be.a(ol.expr.Lexer);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#next()', function() {
|
||||
|
||||
it('returns one token at a time', function() {
|
||||
var source = 'foo === "bar"';
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
|
||||
// scan first token
|
||||
var token = lexer.next();
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
expect(token.value).to.be('foo');
|
||||
|
||||
// scan second token
|
||||
token = lexer.next();
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
expect(token.value).to.be('===');
|
||||
|
||||
// scan third token
|
||||
token = lexer.next();
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
expect(token.value).to.be('bar');
|
||||
|
||||
// scan again
|
||||
token = lexer.next();
|
||||
expect(token.type).to.be(ol.expr.TokenType.EOF);
|
||||
|
||||
// and again
|
||||
token = lexer.next();
|
||||
expect(token.type).to.be(ol.expr.TokenType.EOF);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#peek()', function() {
|
||||
|
||||
var lexer;
|
||||
beforeEach(function() {
|
||||
lexer = new ol.expr.Lexer('foo > 42 && bar == "chicken"');
|
||||
});
|
||||
|
||||
it('looks ahead without consuming token', function() {
|
||||
var token = lexer.peek();
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
expect(token.value).to.be('foo');
|
||||
|
||||
token = lexer.next();
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
expect(token.value).to.be('foo');
|
||||
});
|
||||
|
||||
it('works after a couple scans', function() {
|
||||
var token = lexer.next();
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
expect(token.value).to.be('foo');
|
||||
|
||||
token = lexer.next();
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
expect(token.value).to.be('>');
|
||||
|
||||
token = lexer.peek();
|
||||
expect(token.type).to.be(ol.expr.TokenType.NUMERIC_LITERAL);
|
||||
expect(token.value).to.be(42);
|
||||
|
||||
token = lexer.next();
|
||||
expect(token.type).to.be(ol.expr.TokenType.NUMERIC_LITERAL);
|
||||
expect(token.value).to.be(42);
|
||||
});
|
||||
|
||||
it('returns the same thing when called multiple times', function() {
|
||||
var token = lexer.peek();
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
expect(token.value).to.be('foo');
|
||||
|
||||
for (var i = 0; i < 10; ++i) {
|
||||
token = lexer.peek();
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
expect(token.value).to.be('foo');
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('#scanIdentifier_()', function() {
|
||||
|
||||
function scan(source, part) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var token = lexer.scanIdentifier_(lexer.getCurrentCharCode_());
|
||||
if (!part) {
|
||||
expect(token.index).to.be(0);
|
||||
expect(lexer.peek().type).to.be(ol.expr.TokenType.EOF);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
it('works for short identifiers', function() {
|
||||
var token = scan('a');
|
||||
expect(token.value).to.be('a');
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
});
|
||||
|
||||
it('works for longer identifiers', function() {
|
||||
var token = scan('foo');
|
||||
expect(token.value).to.be('foo');
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
});
|
||||
|
||||
it('works for $ anywhere', function() {
|
||||
var token = scan('$foo$bar$');
|
||||
expect(token.value).to.be('$foo$bar$');
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
});
|
||||
|
||||
it('works for _ anywhere', function() {
|
||||
var token = scan('_foo_bar_');
|
||||
expect(token.value).to.be('_foo_bar_');
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
});
|
||||
|
||||
it('works for keywords', function() {
|
||||
var token = scan('delete');
|
||||
expect(token.value).to.be('delete');
|
||||
expect(token.type).to.be(ol.expr.TokenType.KEYWORD);
|
||||
});
|
||||
|
||||
it('works for null', function() {
|
||||
var token = scan('null');
|
||||
expect(token.value).to.be('null');
|
||||
expect(token.type).to.be(ol.expr.TokenType.NULL_LITERAL);
|
||||
});
|
||||
|
||||
it('works for boolean true', function() {
|
||||
var token = scan('true');
|
||||
expect(token.value).to.be('true');
|
||||
expect(token.type).to.be(ol.expr.TokenType.BOOLEAN_LITERAL);
|
||||
});
|
||||
|
||||
it('works for boolean false', function() {
|
||||
var token = scan('false');
|
||||
expect(token.value).to.be('false');
|
||||
expect(token.type).to.be(ol.expr.TokenType.BOOLEAN_LITERAL);
|
||||
});
|
||||
|
||||
it('works with unicode escape sequences', function() {
|
||||
var token = scan('\u006f\u006c\u0033');
|
||||
expect(token.value).to.be('ol3');
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
});
|
||||
|
||||
it('works with hex escape sequences', function() {
|
||||
var token = scan('\x6f\x6c\x33');
|
||||
expect(token.value).to.be('ol3');
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
});
|
||||
|
||||
it('throws for identifiers starting with a number', function() {
|
||||
expect(function() {
|
||||
scan('4foo');
|
||||
}).throwException();
|
||||
});
|
||||
|
||||
it('throws for identifiers starting with a punctuation char', function() {
|
||||
expect(function() {
|
||||
scan('!foo');
|
||||
}).throwException();
|
||||
});
|
||||
|
||||
it('only scans valid identifier part', function() {
|
||||
var token = scan('foo>bar', true);
|
||||
expect(token.value).to.be('foo');
|
||||
expect(token.type).to.be(ol.expr.TokenType.IDENTIFIER);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#scanNumericLiteral_()', function() {
|
||||
|
||||
function scan(source) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var token = lexer.scanNumericLiteral_(lexer.getCurrentCharCode_());
|
||||
expect(token.index).to.be(0);
|
||||
expect(lexer.peek().type).to.be(ol.expr.TokenType.EOF);
|
||||
return token;
|
||||
}
|
||||
|
||||
it('works for integers', function() {
|
||||
var token = scan('123');
|
||||
expect(token.value).to.be(123);
|
||||
expect(token.type).to.be(ol.expr.TokenType.NUMERIC_LITERAL);
|
||||
});
|
||||
|
||||
it('throws for bogus integer', function() {
|
||||
expect(function() {
|
||||
scan('123z');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('z');
|
||||
expect(token.index).to.be(3);
|
||||
});
|
||||
});
|
||||
|
||||
it('works for float', function() {
|
||||
var token = scan('123.456');
|
||||
expect(token.value).to.be(123.456);
|
||||
expect(token.type).to.be(ol.expr.TokenType.NUMERIC_LITERAL);
|
||||
});
|
||||
|
||||
it('throws for bogus float', function() {
|
||||
expect(function() {
|
||||
scan('123.4x4');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('x');
|
||||
expect(token.index).to.be(5);
|
||||
});
|
||||
});
|
||||
|
||||
it('works with exponent', function() {
|
||||
var token = scan('1.234e5');
|
||||
expect(token.value).to.be(1.234e5);
|
||||
expect(token.type).to.be(ol.expr.TokenType.NUMERIC_LITERAL);
|
||||
});
|
||||
|
||||
it('works with explicit positive exponent', function() {
|
||||
var token = scan('1.234e+5');
|
||||
expect(token.value).to.be(1.234e5);
|
||||
expect(token.type).to.be(ol.expr.TokenType.NUMERIC_LITERAL);
|
||||
});
|
||||
|
||||
it('works with negative exponent', function() {
|
||||
var token = scan('1.234e-5');
|
||||
expect(token.value).to.be(1.234e-5);
|
||||
expect(token.type).to.be(ol.expr.TokenType.NUMERIC_LITERAL);
|
||||
});
|
||||
|
||||
it('throws for bogus float', function() {
|
||||
expect(function() {
|
||||
scan('1.234eo4');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('o');
|
||||
expect(token.index).to.be(6);
|
||||
});
|
||||
});
|
||||
|
||||
it('works with octals', function() {
|
||||
var token = scan('02322');
|
||||
expect(token.value).to.be(1234);
|
||||
expect(token.type).to.be(ol.expr.TokenType.NUMERIC_LITERAL);
|
||||
});
|
||||
|
||||
it('throws for bogus octal', function() {
|
||||
// note that this is more strict than most es5 engines
|
||||
expect(function() {
|
||||
scan('02392');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('9');
|
||||
expect(token.index).to.be(3);
|
||||
});
|
||||
});
|
||||
|
||||
it('works with hex', function() {
|
||||
var token = scan('0x4d2');
|
||||
expect(token.value).to.be(1234);
|
||||
expect(token.type).to.be(ol.expr.TokenType.NUMERIC_LITERAL);
|
||||
});
|
||||
|
||||
it('throws for bogus hex', function() {
|
||||
// note that this is more strict than most es5 engines
|
||||
expect(function() {
|
||||
scan('0x4G');
|
||||
}).throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.value).to.be('G');
|
||||
expect(token.index).to.be(3);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#scanPunctuator_()', function() {
|
||||
|
||||
function scan(source) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var token = lexer.scanPunctuator_(lexer.getCurrentCharCode_());
|
||||
expect(token.index).to.be(0);
|
||||
expect(lexer.peek().type).to.be(ol.expr.TokenType.EOF);
|
||||
return token;
|
||||
}
|
||||
|
||||
it('works for dot', function() {
|
||||
var token = scan('.');
|
||||
expect(token.value).to.be('.');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for bang', function() {
|
||||
var token = scan('!');
|
||||
expect(token.value).to.be('!');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for double equal', function() {
|
||||
var token = scan('==');
|
||||
expect(token.value).to.be('==');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for triple equal', function() {
|
||||
var token = scan('===');
|
||||
expect(token.value).to.be('===');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for not double equal', function() {
|
||||
var token = scan('!=');
|
||||
expect(token.value).to.be('!=');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for not triple equal', function() {
|
||||
var token = scan('!==');
|
||||
expect(token.value).to.be('!==');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for logical or', function() {
|
||||
var token = scan('||');
|
||||
expect(token.value).to.be('||');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for logical and', function() {
|
||||
var token = scan('&&');
|
||||
expect(token.value).to.be('&&');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for plus', function() {
|
||||
var token = scan('+');
|
||||
expect(token.value).to.be('+');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for minus', function() {
|
||||
var token = scan('-');
|
||||
expect(token.value).to.be('-');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for star', function() {
|
||||
var token = scan('*');
|
||||
expect(token.value).to.be('*');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for slash', function() {
|
||||
var token = scan('/');
|
||||
expect(token.value).to.be('/');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
it('works for percent', function() {
|
||||
var token = scan('%');
|
||||
expect(token.value).to.be('%');
|
||||
expect(token.type).to.be(ol.expr.TokenType.PUNCTUATOR);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#scanStringLiteral_()', function() {
|
||||
|
||||
function scan(source) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var token = lexer.scanStringLiteral_(lexer.getCurrentCharCode_());
|
||||
expect(token.index).to.be(0);
|
||||
expect(lexer.peek().type).to.be(ol.expr.TokenType.EOF);
|
||||
return token;
|
||||
}
|
||||
|
||||
it('parses double quoted string', function() {
|
||||
var token = scan('"my string"');
|
||||
expect(token.value).to.be('my string');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses double quoted string with internal single quotes', function() {
|
||||
var token = scan('"my \'quoted\' string"');
|
||||
expect(token.value).to.be('my \'quoted\' string');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses double quoted string with escaped double quotes', function() {
|
||||
var token = scan('"my \\"quoted\\" string"');
|
||||
expect(token.value).to.be('my "quoted" string');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses double quoted string with escaped backslash', function() {
|
||||
var token = scan('"my \\\ string"');
|
||||
expect(token.value).to.be('my \ string');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses double quoted string with unicode escape sequences', function() {
|
||||
var token = scan('"\u006f\u006c\u0033"');
|
||||
expect(token.value).to.be('ol3');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses double quoted string with hex escape sequences', function() {
|
||||
var token = scan('"\x6f\x6c\x33"');
|
||||
expect(token.value).to.be('ol3');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses double quoted string with tab', function() {
|
||||
var token = scan('"a\ttab"');
|
||||
expect(token.value).to.be('a\ttab');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('throws on unterminated double quote', function() {
|
||||
expect(function() {
|
||||
scan('"never \'ending\' string');
|
||||
}).to.throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.type).to.be(ol.expr.TokenType.EOF);
|
||||
expect(token.index).to.be(22);
|
||||
});
|
||||
});
|
||||
|
||||
it('parses single quoted string', function() {
|
||||
var token = scan('\'my string\'');
|
||||
expect(token.value).to.be('my string');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses single quoted string with internal double quotes', function() {
|
||||
var token = scan('\'my "quoted" string\'');
|
||||
expect(token.value).to.be('my "quoted" string');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses single quoted string with escaped single quotes', function() {
|
||||
var token = scan('\'my \\\'quoted\\\' string\'');
|
||||
expect(token.value).to.be('my \'quoted\' string');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses single quoted string with escaped backslash', function() {
|
||||
var token = scan('\'my \\\ string\'');
|
||||
expect(token.value).to.be('my \ string');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses single quoted string with unicode escape sequences', function() {
|
||||
var token = scan('\'\u006f\u006c\u0033\'');
|
||||
expect(token.value).to.be('ol3');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses single quoted string with hex escape sequences', function() {
|
||||
var token = scan('\'\x6f\x6c\x33\'');
|
||||
expect(token.value).to.be('ol3');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('parses single quoted string with tab', function() {
|
||||
var token = scan('\'a\ttab\'');
|
||||
expect(token.value).to.be('a\ttab');
|
||||
expect(token.type).to.be(ol.expr.TokenType.STRING_LITERAL);
|
||||
});
|
||||
|
||||
it('throws on unterminated single quote', function() {
|
||||
expect(function() {
|
||||
scan('\'never "ending" string');
|
||||
}).to.throwException(function(err) {
|
||||
expect(err).to.be.an(ol.expr.UnexpectedToken);
|
||||
var token = err.token;
|
||||
expect(token.type).to.be(ol.expr.TokenType.EOF);
|
||||
expect(token.index).to.be(22);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
goog.require('ol.expr.Lexer');
|
||||
goog.require('ol.expr.TokenType');
|
||||
goog.require('ol.expr.UnexpectedToken');
|
||||
275
test/spec/ol/expr/parser.test.js
Normal file
275
test/spec/ol/expr/parser.test.js
Normal file
@@ -0,0 +1,275 @@
|
||||
goog.provide('ol.test.expression.Parser');
|
||||
|
||||
describe('ol.expr.Parser', function() {
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new expression parser', function() {
|
||||
var parser = new ol.expr.Parser();
|
||||
expect(parser).to.be.a(ol.expr.Parser);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#parseArguments_()', function() {
|
||||
|
||||
function parse(source) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var parser = new ol.expr.Parser();
|
||||
var expr = parser.parseArguments_(lexer);
|
||||
expect(lexer.peek().type).to.be(ol.expr.TokenType.EOF);
|
||||
return expr;
|
||||
}
|
||||
|
||||
it('parses comma separated expressions in parens', function() {
|
||||
var args = parse('(1/3, "foo", true)');
|
||||
expect(args).length(3);
|
||||
|
||||
expect(args[0]).to.be.a(ol.expr.Math);
|
||||
expect(args[0].evaluate()).to.be(1 / 3);
|
||||
|
||||
expect(args[1]).to.be.a(ol.expr.Literal);
|
||||
expect(args[1].evaluate()).to.be('foo');
|
||||
|
||||
expect(args[2]).to.be.a(ol.expr.Literal);
|
||||
expect(args[2].evaluate()).to.be(true);
|
||||
});
|
||||
|
||||
it('throws on invalid arg expression', function() {
|
||||
expect(function() {
|
||||
parse('(6e)');
|
||||
}).throwException();
|
||||
});
|
||||
|
||||
it('throws on unterminated args', function() {
|
||||
expect(function() {
|
||||
parse('("foo", 42, )');
|
||||
}).throwException();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#parseBinaryExpression_()', function() {
|
||||
|
||||
function parse(source) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var parser = new ol.expr.Parser();
|
||||
var expr = parser.parseBinaryExpression_(lexer);
|
||||
expect(lexer.peek().type).to.be(ol.expr.TokenType.EOF);
|
||||
return expr;
|
||||
}
|
||||
|
||||
it('works with multiplicitave operators', function() {
|
||||
var expr = parse('4 * 1e4');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate()).to.be(40000);
|
||||
|
||||
expect(parse('10/3').evaluate()).to.be(10 / 3);
|
||||
});
|
||||
|
||||
it('works with additive operators', function() {
|
||||
var expr = parse('4 +1e4');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate()).to.be(10004);
|
||||
|
||||
expect(parse('10-3').evaluate()).to.be(7);
|
||||
});
|
||||
|
||||
it('works with relational operators', function() {
|
||||
var expr = parse('4 < 1e4');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate()).to.be(true);
|
||||
|
||||
expect(parse('10<3').evaluate()).to.be(false);
|
||||
expect(parse('10 <= "10"').evaluate()).to.be(true);
|
||||
expect(parse('10 > "10"').evaluate()).to.be(false);
|
||||
expect(parse('10 >= 9').evaluate()).to.be(true);
|
||||
});
|
||||
|
||||
it('works with equality operators', function() {
|
||||
var expr = parse('4 == 1e4');
|
||||
expect(expr).to.be.a(ol.expr.Comparison);
|
||||
expect(expr.evaluate()).to.be(false);
|
||||
|
||||
expect(parse('10!=3').evaluate()).to.be(true);
|
||||
expect(parse('10 == "10"').evaluate()).to.be(true);
|
||||
expect(parse('10 === "10"').evaluate()).to.be(false);
|
||||
expect(parse('10 !== "10"').evaluate()).to.be(true);
|
||||
});
|
||||
|
||||
it('works with binary logical operators', function() {
|
||||
var expr = parse('true && false');
|
||||
expect(expr).to.be.a(ol.expr.Logical);
|
||||
expect(expr.evaluate()).to.be(false);
|
||||
|
||||
expect(parse('false||true').evaluate()).to.be(true);
|
||||
expect(parse('false || false').evaluate()).to.be(false);
|
||||
expect(parse('true &&true').evaluate()).to.be(true);
|
||||
});
|
||||
|
||||
it('throws for invalid binary expression', function() {
|
||||
expect(function() {
|
||||
parse('4 * / 2');
|
||||
}).throwException();
|
||||
|
||||
expect(function() {
|
||||
parse('4 < / 2');
|
||||
}).throwException();
|
||||
|
||||
expect(function() {
|
||||
parse('4 * && 2');
|
||||
}).throwException();
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#parseGroupExpression_()', function() {
|
||||
|
||||
function parse(source) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var parser = new ol.expr.Parser();
|
||||
var expr = parser.parseGroupExpression_(lexer);
|
||||
expect(lexer.peek().type).to.be(ol.expr.TokenType.EOF);
|
||||
return expr;
|
||||
}
|
||||
|
||||
it('parses grouped expressions', function() {
|
||||
var expr = parse('(3 * (foo + 2))');
|
||||
expect(expr).to.be.a(ol.expr.Math);
|
||||
expect(expr.evaluate({foo: 3})).to.be(15);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#parseLeftHandSideExpression_()', function() {
|
||||
|
||||
function parse(source) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var parser = new ol.expr.Parser();
|
||||
var expr = parser.parseLeftHandSideExpression_(lexer);
|
||||
expect(lexer.peek().type).to.be(ol.expr.TokenType.EOF);
|
||||
return expr;
|
||||
}
|
||||
|
||||
it('parses member expressions', function() {
|
||||
var expr = parse('foo.bar.bam');
|
||||
expect(expr).to.be.a(ol.expr.Member);
|
||||
});
|
||||
|
||||
it('throws on invalid member expression', function() {
|
||||
expect(function() {
|
||||
parse('foo.4');
|
||||
}).throwException();
|
||||
});
|
||||
|
||||
it('parses call expressions', function() {
|
||||
var expr = parse('foo(bar)');
|
||||
expect(expr).to.be.a(ol.expr.Call);
|
||||
var fns = {
|
||||
foo: function(arg) {
|
||||
expect(arguments).length(1);
|
||||
expect(arg).to.be('chicken');
|
||||
return 'got ' + arg;
|
||||
}
|
||||
};
|
||||
var scope = {
|
||||
bar: 'chicken'
|
||||
};
|
||||
expect(expr.evaluate(scope, fns)).to.be('got chicken');
|
||||
});
|
||||
|
||||
it('throws on invalid call expression', function() {
|
||||
expect(function() {
|
||||
parse('foo(*)');
|
||||
}).throwException();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('#parsePrimaryExpression_()', function() {
|
||||
|
||||
function parse(source) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var parser = new ol.expr.Parser();
|
||||
var expr = parser.parsePrimaryExpression_(lexer);
|
||||
expect(lexer.peek().type).to.be(ol.expr.TokenType.EOF);
|
||||
return expr;
|
||||
}
|
||||
|
||||
it('parses string literal', function() {
|
||||
var expr = parse('"foo"');
|
||||
expect(expr).to.be.a(ol.expr.Literal);
|
||||
expect(expr.evaluate()).to.be('foo');
|
||||
});
|
||||
|
||||
it('parses numeric literal', function() {
|
||||
var expr = parse('.42e2');
|
||||
expect(expr).to.be.a(ol.expr.Literal);
|
||||
expect(expr.evaluate()).to.be(42);
|
||||
});
|
||||
|
||||
it('parses boolean literal', function() {
|
||||
var expr = parse('.42e2');
|
||||
expect(expr).to.be.a(ol.expr.Literal);
|
||||
expect(expr.evaluate()).to.be(42);
|
||||
});
|
||||
|
||||
it('parses null literal', function() {
|
||||
var expr = parse('null');
|
||||
expect(expr).to.be.a(ol.expr.Literal);
|
||||
expect(expr.evaluate()).to.be(null);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#parseUnaryExpression_()', function() {
|
||||
|
||||
function parse(source) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var parser = new ol.expr.Parser();
|
||||
var expr = parser.parseUnaryExpression_(lexer);
|
||||
expect(lexer.peek().type).to.be(ol.expr.TokenType.EOF);
|
||||
return expr;
|
||||
}
|
||||
|
||||
it('parses logical not', function() {
|
||||
var expr = parse('!foo');
|
||||
expect(expr).to.be.a(ol.expr.Not);
|
||||
expect(expr.evaluate({foo: true})).to.be(false);
|
||||
});
|
||||
|
||||
it('works with string literal', function() {
|
||||
var expr = parse('!"foo"');
|
||||
expect(expr).to.be.a(ol.expr.Not);
|
||||
expect(expr.evaluate()).to.be(false);
|
||||
});
|
||||
|
||||
it('works with empty string', function() {
|
||||
var expr = parse('!""');
|
||||
expect(expr).to.be.a(ol.expr.Not);
|
||||
expect(expr.evaluate()).to.be(true);
|
||||
});
|
||||
|
||||
it('works with null', function() {
|
||||
var expr = parse('!null');
|
||||
expect(expr).to.be.a(ol.expr.Not);
|
||||
expect(expr.evaluate()).to.be(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
goog.require('ol.expr.Expression');
|
||||
goog.require('ol.expr.Call');
|
||||
goog.require('ol.expr.Comparison');
|
||||
goog.require('ol.expr.Lexer');
|
||||
goog.require('ol.expr.Literal');
|
||||
goog.require('ol.expr.Logical');
|
||||
goog.require('ol.expr.Math');
|
||||
goog.require('ol.expr.Member');
|
||||
goog.require('ol.expr.Not');
|
||||
goog.require('ol.expr.Parser');
|
||||
goog.require('ol.expr.TokenType');
|
||||
Reference in New Issue
Block a user