<commit_before>/*global defineSuite*/
defineSuite([
        'Scene/Expression',
        'Scene/ExpressionNodeType',
        'Core/Color'
    ], function(
        Expression,
        ExpressionNodeType,
        Color) {
    'use strict';

    function MockStyleEngine() {
    }

    MockStyleEngine.prototype.makeDirty = function() {
    };

    function MockFeature() {
        this._properties = {};
    }

    MockFeature.prototype.addProperty = function(name, value) {
        this._properties[name] = value;
    };

    MockFeature.prototype.getProperty = function(name) {
        return this._properties[name];
    };

    it ('parses backslashes', function() {
        var expression = new Expression(new MockStyleEngine(), '"\\he\\\\\\ll\\\\o"');
        expect(expression.evaluate(undefined)).toEqual('\\he\\\\\\ll\\\\o');
    });

    it('evaluates variable', function() {
        var feature = new MockFeature();
        feature.addProperty('height', 10);
        feature.addProperty('width', 5);
        feature.addProperty('string', 'hello');
        feature.addProperty('boolean', true);
        feature.addProperty('color', Color.RED);
        feature.addProperty('null', null);
        feature.addProperty('undefined', undefined);

        var expression = new Expression(new MockStyleEngine(), '${height}');
        expect(expression.evaluate(feature)).toEqual(10);

        expression = new Expression(new MockStyleEngine(), '\'${height}\'');
        expect(expression.evaluate(feature)).toEqual('10');

        expression = new Expression(new MockStyleEngine(), '${height}/${width}');
        expect(expression.evaluate(feature)).toEqual(2);

        expression = new Expression(new MockStyleEngine(), '${string}');
        expect(expression.evaluate(feature)).toEqual('hello');

        expression = new Expression(new MockStyleEngine(), '\'replace ${string}\'');
        expect(expression.evaluate(feature)).toEqual('replace hello');

        expression = new Expression(new MockStyleEngine(), '\'replace ${string} multiple ${height}\'');
        expect(expression.evaluate(feature)).toEqual('replace hello multiple 10');

        expression = new Expression(new MockStyleEngine(), '"replace ${string}"');
        expect(expression.evaluate(feature)).toEqual('replace hello');

        expression = new Expression(new MockStyleEngine(), '\'replace ${string\'');
        expect(expression.evaluate(feature)).toEqual('replace ${string');

        expression = new Expression(new MockStyleEngine(), '${boolean}');
        expect(expression.evaluate(feature)).toEqual(true);

        expression = new Expression(new MockStyleEngine(), '\'${boolean}\'');
        expect(expression.evaluate(feature)).toEqual('true');

        expression = new Expression(new MockStyleEngine(), '${color}');
        expect(expression.evaluate(feature)).toEqual(Color.RED);

        expression = new Expression(new MockStyleEngine(), '\'${color}\'');
        expect(expression.evaluate(feature)).toEqual(Color.RED.toString());

        expression = new Expression(new MockStyleEngine(), '${null}');
        expect(expression.evaluate(feature)).toEqual(null);

        expression = new Expression(new MockStyleEngine(), '\'${null}\'');
        expect(expression.evaluate(feature)).toEqual('');

        expression = new Expression(new MockStyleEngine(), '${undefined}');
        expect(expression.evaluate(feature)).toEqual(undefined);

        expression = new Expression(new MockStyleEngine(), '\'${undefined}\'');
        expect(expression.evaluate(feature)).toEqual('');

        expect(function() {
            return new Expression(new MockStyleEngine(), '${height');
        }).toThrowDeveloperError();
    });

    it('throws on invalid expressions', function() {
        expect(function() {
            return new Expression(new MockStyleEngine(), false);
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), '');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), 'this');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), '2; 3;');
        }).toThrowDeveloperError();
    });

    it('throws on unknown characters', function() {
        expect(function() {
            return new Expression(new MockStyleEngine(), '#');
        }).toThrowDeveloperError();
    });

    it('throws on unmatched parenthesis', function() {
        expect(function() {
            return new Expression(new MockStyleEngine(), '((true)');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), '(true))');
        }).toThrowDeveloperError();
    });

    it('throws on unknown identifiers', function() {
        expect(function() {
            return new Expression(new MockStyleEngine(), 'flse');
        }).toThrowDeveloperError();
    });

    it('throws on unknown function calls', function() {
        expect(function() {
            return new Expression(new MockStyleEngine(), 'unknown()');
        }).toThrowDeveloperError();
    });

    it('throws on unknown member function calls', function() {
        expect(function() {
            return new Expression(new MockStyleEngine(), 'regExp().unknown()');
        }).toThrowDeveloperError();
    });

    it('throws with unsupported operators', function() {
        expect(function() {
            return new Expression(new MockStyleEngine(), '~1');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), '2 | 3');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), '2 & 3');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), '2 == 3');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), '2 != 3');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), '2 << 3');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), '2 >> 3');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), '2 >>> 3');
        }).toThrowDeveloperError();
    });

    it('evaluates literal null', function() {
        var expression = new Expression(new MockStyleEngine(), 'null');
        expect(expression.evaluate(undefined)).toEqual(null);
    });

    it('evaluates literal boolean', function() {
        var expression = new Expression(new MockStyleEngine(), 'true');
        expect(expression.evaluate(undefined)).toEqual(true);

        expression = new Expression(new MockStyleEngine(), 'false');
        expect(expression.evaluate(undefined)).toEqual(false);
    });

    it('converts to literal boolean', function() {
        var expression = new Expression(new MockStyleEngine(), 'Boolean()');
        expect(expression.evaluate(undefined)).toEqual(false);

        expression = new Expression(new MockStyleEngine(), 'Boolean(1)');
        expect(expression.evaluate(undefined)).toEqual(true);

        expression = new Expression(new MockStyleEngine(), 'Boolean("true")');
        expect(expression.evaluate(undefined)).toEqual(true);
    });

    it('evaluates literal number', function() {
        var expression = new Expression(new MockStyleEngine(), '1');
        expect(expression.evaluate(undefined)).toEqual(1);

        expression = new Expression(new MockStyleEngine(), '0');
        expect(expression.evaluate(undefined)).toEqual(0);

        expression = new Expression(new MockStyleEngine(), 'NaN');
        expect(expression.evaluate(undefined)).toEqual(NaN);

        expression = new Expression(new MockStyleEngine(), 'Infinity');
        expect(expression.evaluate(undefined)).toEqual(Infinity);
    });

    it('converts to literal number', function() {
        var expression = new Expression(new MockStyleEngine(), 'Number()');
        expect(expression.evaluate(undefined)).toEqual(0);

        expression = new Expression(new MockStyleEngine(), 'Number("1")');
        expect(expression.evaluate(undefined)).toEqual(1);

        expression = new Expression(new MockStyleEngine(), 'Number(true)');
        expect(expression.evaluate(undefined)).toEqual(1);
    });

    it('evaluates literal string', function() {
        var expression = new Expression(new MockStyleEngine(), '\'hello\'');
        expect(expression.evaluate(undefined)).toEqual('hello');
    });

    it('converts to literal string', function() {
        var expression = new Expression(new MockStyleEngine(), 'String()');
        expect(expression.evaluate(undefined)).toEqual('');

        expression = new Expression(new MockStyleEngine(), 'String(1)');
        expect(expression.evaluate(undefined)).toEqual('1');

        expression = new Expression(new MockStyleEngine(), 'String(true)');
        expect(expression.evaluate(undefined)).toEqual('true');
    });

    it('evaluates literal color', function() {
        var expression = new Expression(new MockStyleEngine(), 'color(\'#ffffff\')');
        expect(expression.evaluate(undefined)).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'color(\'#fff\')');
        expect(expression.evaluate(undefined)).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'color(\'white\')');
        expect(expression.evaluate(undefined)).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'color(\'white\', 0.5)');
        expect(expression.evaluate(undefined)).toEqual(new Color(1.0, 1.0, 1.0, 0.5));

        expression = new Expression(new MockStyleEngine(), 'rgb(255, 255, 255)');
        expect(expression.evaluate(undefined)).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'hsl(0, 0, 1)');
        expect(expression.evaluate(undefined)).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'rgba(255, 255, 255, 0.5)');
        expect(expression.evaluate(undefined)).toEqual(new Color(1.0, 1.0, 1.0, 0.5));

        expression = new Expression(new MockStyleEngine(), 'hsla(0, 0, 1, 0.5)');
        expect(expression.evaluate(undefined)).toEqual(new Color(1.0, 1.0, 1.0, 0.5));

        expression = new Expression(new MockStyleEngine(), 'color()');
        expect(expression.evaluate(undefined)).toEqual(Color.WHITE);
    });

    it('evaluates literal color with result parameter', function() {
        var color = new Color();

        var expression = new Expression(new MockStyleEngine(), 'color(\'#0000ff\')');
        expect(expression.evaluateColor(undefined, color)).toEqual(Color.BLUE);
        expect(color).toEqual(Color.BLUE);

        expression = new Expression(new MockStyleEngine(), 'color(\'#f00\')');
        expect(expression.evaluateColor(undefined, color)).toEqual(Color.RED);
        expect(color).toEqual(Color.RED);

        expression = new Expression(new MockStyleEngine(), 'color(\'cyan\')');
        expect(expression.evaluateColor(undefined, color)).toEqual(Color.CYAN);
        expect(color).toEqual(Color.CYAN);

        expression = new Expression(new MockStyleEngine(), 'color(\'white\', 0.5)');
        expect(expression.evaluateColor(undefined, color)).toEqual(new Color(1.0, 1.0, 1.0, 0.5));
        expect(color).toEqual(new Color(1.0, 1.0, 1.0, 0.5));

        expression = new Expression(new MockStyleEngine(), 'rgb(0, 0, 0)');
        expect(expression.evaluateColor(undefined, color)).toEqual(Color.BLACK);
        expect(color).toEqual(Color.BLACK);

        expression = new Expression(new MockStyleEngine(), 'hsl(0, 0, 1)');
        expect(expression.evaluateColor(undefined, color)).toEqual(Color.WHITE);
        expect(color).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'rgba(255, 0, 255, 0.5)');
        expect(expression.evaluateColor(undefined, color)).toEqual(new Color(1.0, 0, 1.0, 0.5));
        expect(color).toEqual(new Color(1.0, 0, 1.0, 0.5));

        expression = new Expression(new MockStyleEngine(), 'hsla(0, 0, 1, 0.5)');
        expect(expression.evaluateColor(undefined, color)).toEqual(new Color(1.0, 1.0, 1.0, 0.5));
        expect(color).toEqual(new Color(1.0, 1.0, 1.0, 0.5));

        expression = new Expression(new MockStyleEngine(), 'color()');
        expect(expression.evaluateColor(undefined, color)).toEqual(Color.WHITE);
        expect(color).toEqual(Color.WHITE);
    });

    it('evaluates color with expressions as arguments', function() {
        var feature = new MockFeature();
        feature.addProperty('hex6', '#ffffff');
        feature.addProperty('hex3', '#fff');
        feature.addProperty('keyword', 'white');
        feature.addProperty('alpha', 0.2);

        var expression = new Expression(new MockStyleEngine(), 'color(${hex6})');
        expect(expression.evaluate(feature)).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'color(${hex3})');
        expect(expression.evaluate(feature)).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'color(${keyword})');
        expect(expression.evaluate(feature)).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'color(${keyword}, ${alpha} + 0.6)');
        expect(expression.evaluate(feature).red).toEqual(1.0);
        expect(expression.evaluate(feature).green).toEqual(1.0);
        expect(expression.evaluate(feature).blue).toEqual(1.0);
        expect(expression.evaluate(feature).alpha).toEqual(0.8);
    });

    it('evaluates rgb with expressions as arguments', function() {
        var feature = new MockFeature();
        feature.addProperty('red', 100);
        feature.addProperty('green', 200);
        feature.addProperty('blue', 255);

        var expression = new Expression(new MockStyleEngine(), 'rgb(${red}, ${green}, ${blue})');
        expect(expression.evaluate(feature)).toEqual(Color.fromBytes(100, 200, 255));

        expression = new Expression(new MockStyleEngine(), 'rgb(${red}/2, ${green}/2, ${blue})');
        expect(expression.evaluate(feature)).toEqual(Color.fromBytes(50, 100, 255));
    });

    it('evaluates hsl with expressions as arguments', function() {
        var feature = new MockFeature();
        feature.addProperty('h', 0.0);
        feature.addProperty('s', 0.0);
        feature.addProperty('l', 1.0);

        var expression = new Expression(new MockStyleEngine(), 'hsl(${h}, ${s}, ${l})');
        expect(expression.evaluate(feature)).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'hsl(${h} + 0.2, ${s} + 1.0, ${l} - 0.5)');
        expect(expression.evaluate(feature)).toEqual(Color.fromHsl(0.2, 1.0, 0.5));
    });

    it('evaluates rgba with expressions as arguments', function() {
        var feature = new MockFeature();
        feature.addProperty('red', 100);
        feature.addProperty('green', 200);
        feature.addProperty('blue', 255);
        feature.addProperty('a', 0.3);

        var expression = new Expression(new MockStyleEngine(), 'rgba(${red}, ${green}, ${blue}, ${a})');
        expect(expression.evaluate(feature)).toEqual(Color.fromBytes(100, 200, 255, 0.3*255));

        expression = new Expression(new MockStyleEngine(), 'rgba(${red}/2, ${green}/2, ${blue}, ${a} * 2)');
        expect(expression.evaluate(feature)).toEqual(Color.fromBytes(50, 100, 255, 0.6*255));
    });

    it('evaluates hsla with expressions as arguments', function() {
        var feature = new MockFeature();
        feature.addProperty('h', 0.0);
        feature.addProperty('s', 0.0);
        feature.addProperty('l', 1.0);
        feature.addProperty('a', 1.0);

        var expression = new Expression(new MockStyleEngine(), 'hsla(${h}, ${s}, ${l}, ${a})');
        expect(expression.evaluate(feature)).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'hsla(${h} + 0.2, ${s} + 1.0, ${l} - 0.5, ${a} / 4)');
        expect(expression.evaluate(feature)).toEqual(Color.fromHsl(0.2, 1.0, 0.5, 0.25));
    });

    it('evaluates rgba with expressions as arguments', function() {
        var feature = new MockFeature();
        feature.addProperty('red', 100);
        feature.addProperty('green', 200);
        feature.addProperty('blue', 255);
        feature.addProperty('alpha', 0.5);

        var expression = new Expression(new MockStyleEngine(), 'rgba(${red}, ${green}, ${blue}, ${alpha})');
        expect(expression.evaluate(feature)).toEqual(Color.fromBytes(100, 200, 255, 0.5 * 255));

        expression = new Expression(new MockStyleEngine(), 'rgba(${red}/2, ${green}/2, ${blue}, ${alpha} + 0.1)');
        expect(expression.evaluate(feature)).toEqual(Color.fromBytes(50, 100, 255, 0.6 * 255));
    });

    it('color constructors throw with wrong number of arguments', function() {
        expect(function() {
            return new Expression(new MockStyleEngine(), 'rgb(255, 255)');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), 'hsl(1, 1)');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), 'rgba(255, 255, 255)');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), 'hsla(1, 1, 1)');
        }).toThrowDeveloperError();
    });

    it('evaluates color properties', function() {
        var expression = new Expression(new MockStyleEngine(), 'color(\'#ffffff\').red');
        expect(expression.evaluate(undefined)).toEqual(1);

        expression = new Expression(new MockStyleEngine(), 'rgb(255, 255, 0).green');
        expect(expression.evaluate(undefined)).toEqual(1);

        expression = new Expression(new MockStyleEngine(), 'rgb("cyan").blue');
        expect(expression.evaluate(undefined)).toEqual(1);

        expression = new Expression(new MockStyleEngine(), 'rgba(255, 255, 0, 0.5).alpha');
        expect(expression.evaluate(undefined)).toEqual(0.5);
    });

    it('evaluates unary not', function() {
        var expression = new Expression(new MockStyleEngine(), '!true');
        expect(expression.evaluate(undefined)).toEqual(false);

        expression = new Expression(new MockStyleEngine(), '!!true');
        expect(expression.evaluate(undefined)).toEqual(true);
    });

    it('evaluates unary negative', function() {
        var expression = new Expression(new MockStyleEngine(), '-5');
        expect(expression.evaluate(undefined)).toEqual(-5);

        expression = new Expression(new MockStyleEngine(), '-(-5)');
        expect(expression.evaluate(undefined)).toEqual(5);
    });

    it('evaluates unary positive', function() {
        var expression = new Expression(new MockStyleEngine(), '+5');
        expect(expression.evaluate(undefined)).toEqual(5);<commit_msg>Fixed test<commit_after>/*global defineSuite*/
defineSuite([
        'Scene/Expression',
        'Scene/ExpressionNodeType',
        'Core/Color'
    ], function(
        Expression,
        ExpressionNodeType,
        Color) {
    'use strict';

    function MockStyleEngine() {
    }

    MockStyleEngine.prototype.makeDirty = function() {
    };

    function MockFeature() {
        this._properties = {};
    }

    MockFeature.prototype.addProperty = function(name, value) {
        this._properties[name] = value;
    };

    MockFeature.prototype.getProperty = function(name) {
        return this._properties[name];
    };

    it ('parses backslashes', function() {
        var expression = new Expression(new MockStyleEngine(), '"\\he\\\\\\ll\\\\o"');
        expect(expression.evaluate(undefined)).toEqual('\\he\\\\\\ll\\\\o');
    });

    it('evaluates variable', function() {
        var feature = new MockFeature();
        feature.addProperty('height', 10);
        feature.addProperty('width', 5);
        feature.addProperty('string', 'hello');
        feature.addProperty('boolean', true);
        feature.addProperty('color', Color.RED);
        feature.addProperty('null', null);
        feature.addProperty('undefined', undefined);

        var expression = new Expression(new MockStyleEngine(), '${height}');
        expect(expression.evaluate(feature)).toEqual(10);

        expression = new Expression(new MockStyleEngine(), '\'${height}\'');
        expect(expression.evaluate(feature)).toEqual('10');

        expression = new Expression(new MockStyleEngine(), '${height}/${width}');
        expect(expression.evaluate(feature)).toEqual(2);

        expression = new Expression(new MockStyleEngine(), '${string}');
        expect(expression.evaluate(feature)).toEqual('hello');

        expression = new Expression(new MockStyleEngine(), '\'replace ${string}\'');
        expect(expression.evaluate(feature)).toEqual('replace hello');

        expression = new Expression(new MockStyleEngine(), '\'replace ${string} multiple ${height}\'');
        expect(expression.evaluate(feature)).toEqual('replace hello multiple 10');

        expression = new Expression(new MockStyleEngine(), '"replace ${string}"');
        expect(expression.evaluate(feature)).toEqual('replace hello');

        expression = new Expression(new MockStyleEngine(), '\'replace ${string\'');
        expect(expression.evaluate(feature)).toEqual('replace ${string');

        expression = new Expression(new MockStyleEngine(), '${boolean}');
        expect(expression.evaluate(feature)).toEqual(true);

        expression = new Expression(new MockStyleEngine(), '\'${boolean}\'');
        expect(expression.evaluate(feature)).toEqual('true');

        expression = new Expression(new MockStyleEngine(), '${color}');
        expect(expression.evaluate(feature)).toEqual(Color.RED);

        expression = new Expression(new MockStyleEngine(), '\'${color}\'');
        expect(expression.evaluate(feature)).toEqual(Color.RED.toString());

        expression = new Expression(new MockStyleEngine(), '${null}');
        expect(expression.evaluate(feature)).toEqual(null);

        expression = new Expression(new MockStyleEngine(), '\'${null}\'');
        expect(expression.evaluate(feature)).toEqual('');

        expression = new Expression(new MockStyleEngine(), '${undefined}');
        expect(expression.evaluate(feature)).toEqual(undefined);

        expression = new Expression(new MockStyleEngine(), '\'${undefined}\'');
        expect(expression.evaluate(feature)).toEqual('');

        expect(function() {
            return new Expression(new MockStyleEngine(), '${height');
        }).toThrowDeveloperError();
    });

    it('throws on invalid expressions', function() {
        expect(function() {
            return new Expression(new MockStyleEngine(), false);
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), '');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), 'this');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), '2; 3;');
        }).toThrowDeveloperError();
    });

    it('throws on unknown characters', function() {
        expect(function() {
            return new Expression(new MockStyleEngine(), '#');
        }).toThrowDeveloperError();
    });

    it('throws on unmatched parenthesis', function() {
        expect(function() {
            return new Expression(new MockStyleEngine(), '((true)');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), '(true))');
        }).toThrowDeveloperError();
    });

    it('throws on unknown identifiers', function() {
        expect(function() {
            return new Expression(new MockStyleEngine(), 'flse');
        }).toThrowDeveloperError();
    });

    it('throws on unknown function calls', function() {
        expect(function() {
            return new Expression(new MockStyleEngine(), 'unknown()');
        }).toThrowDeveloperError();
    });

    it('throws on unknown member function calls', function() {
        expect(function() {
            return new Expression(new MockStyleEngine(), 'regExp().unknown()');
        }).toThrowDeveloperError();
    });

    it('throws with unsupported operators', function() {
        expect(function() {
            return new Expression(new MockStyleEngine(), '~1');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), '2 | 3');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), '2 & 3');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), '2 == 3');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), '2 != 3');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), '2 << 3');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), '2 >> 3');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), '2 >>> 3');
        }).toThrowDeveloperError();
    });

    it('evaluates literal null', function() {
        var expression = new Expression(new MockStyleEngine(), 'null');
        expect(expression.evaluate(undefined)).toEqual(null);
    });

    it('evaluates literal boolean', function() {
        var expression = new Expression(new MockStyleEngine(), 'true');
        expect(expression.evaluate(undefined)).toEqual(true);

        expression = new Expression(new MockStyleEngine(), 'false');
        expect(expression.evaluate(undefined)).toEqual(false);
    });

    it('converts to literal boolean', function() {
        var expression = new Expression(new MockStyleEngine(), 'Boolean()');
        expect(expression.evaluate(undefined)).toEqual(false);

        expression = new Expression(new MockStyleEngine(), 'Boolean(1)');
        expect(expression.evaluate(undefined)).toEqual(true);

        expression = new Expression(new MockStyleEngine(), 'Boolean("true")');
        expect(expression.evaluate(undefined)).toEqual(true);
    });

    it('evaluates literal number', function() {
        var expression = new Expression(new MockStyleEngine(), '1');
        expect(expression.evaluate(undefined)).toEqual(1);

        expression = new Expression(new MockStyleEngine(), '0');
        expect(expression.evaluate(undefined)).toEqual(0);

        expression = new Expression(new MockStyleEngine(), 'NaN');
        expect(expression.evaluate(undefined)).toEqual(NaN);

        expression = new Expression(new MockStyleEngine(), 'Infinity');
        expect(expression.evaluate(undefined)).toEqual(Infinity);
    });

    it('converts to literal number', function() {
        var expression = new Expression(new MockStyleEngine(), 'Number()');
        expect(expression.evaluate(undefined)).toEqual(0);

        expression = new Expression(new MockStyleEngine(), 'Number("1")');
        expect(expression.evaluate(undefined)).toEqual(1);

        expression = new Expression(new MockStyleEngine(), 'Number(true)');
        expect(expression.evaluate(undefined)).toEqual(1);
    });

    it('evaluates literal string', function() {
        var expression = new Expression(new MockStyleEngine(), '\'hello\'');
        expect(expression.evaluate(undefined)).toEqual('hello');
    });

    it('converts to literal string', function() {
        var expression = new Expression(new MockStyleEngine(), 'String()');
        expect(expression.evaluate(undefined)).toEqual('');

        expression = new Expression(new MockStyleEngine(), 'String(1)');
        expect(expression.evaluate(undefined)).toEqual('1');

        expression = new Expression(new MockStyleEngine(), 'String(true)');
        expect(expression.evaluate(undefined)).toEqual('true');
    });

    it('evaluates literal color', function() {
        var expression = new Expression(new MockStyleEngine(), 'color(\'#ffffff\')');
        expect(expression.evaluate(undefined)).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'color(\'#fff\')');
        expect(expression.evaluate(undefined)).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'color(\'white\')');
        expect(expression.evaluate(undefined)).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'color(\'white\', 0.5)');
        expect(expression.evaluate(undefined)).toEqual(new Color(1.0, 1.0, 1.0, 0.5));

        expression = new Expression(new MockStyleEngine(), 'rgb(255, 255, 255)');
        expect(expression.evaluate(undefined)).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'hsl(0, 0, 1)');
        expect(expression.evaluate(undefined)).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'rgba(255, 255, 255, 0.5)');
        expect(expression.evaluate(undefined)).toEqual(new Color(1.0, 1.0, 1.0, 0.5));

        expression = new Expression(new MockStyleEngine(), 'hsla(0, 0, 1, 0.5)');
        expect(expression.evaluate(undefined)).toEqual(new Color(1.0, 1.0, 1.0, 0.5));

        expression = new Expression(new MockStyleEngine(), 'color()');
        expect(expression.evaluate(undefined)).toEqual(Color.WHITE);
    });

    it('evaluates literal color with result parameter', function() {
        var color = new Color();

        var expression = new Expression(new MockStyleEngine(), 'color(\'#0000ff\')');
        expect(expression.evaluateColor(undefined, color)).toEqual(Color.BLUE);
        expect(color).toEqual(Color.BLUE);

        expression = new Expression(new MockStyleEngine(), 'color(\'#f00\')');
        expect(expression.evaluateColor(undefined, color)).toEqual(Color.RED);
        expect(color).toEqual(Color.RED);

        expression = new Expression(new MockStyleEngine(), 'color(\'cyan\')');
        expect(expression.evaluateColor(undefined, color)).toEqual(Color.CYAN);
        expect(color).toEqual(Color.CYAN);

        expression = new Expression(new MockStyleEngine(), 'color(\'white\', 0.5)');
        expect(expression.evaluateColor(undefined, color)).toEqual(new Color(1.0, 1.0, 1.0, 0.5));
        expect(color).toEqual(new Color(1.0, 1.0, 1.0, 0.5));

        expression = new Expression(new MockStyleEngine(), 'rgb(0, 0, 0)');
        expect(expression.evaluateColor(undefined, color)).toEqual(Color.BLACK);
        expect(color).toEqual(Color.BLACK);

        expression = new Expression(new MockStyleEngine(), 'hsl(0, 0, 1)');
        expect(expression.evaluateColor(undefined, color)).toEqual(Color.WHITE);
        expect(color).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'rgba(255, 0, 255, 0.5)');
        expect(expression.evaluateColor(undefined, color)).toEqual(new Color(1.0, 0, 1.0, 0.5));
        expect(color).toEqual(new Color(1.0, 0, 1.0, 0.5));

        expression = new Expression(new MockStyleEngine(), 'hsla(0, 0, 1, 0.5)');
        expect(expression.evaluateColor(undefined, color)).toEqual(new Color(1.0, 1.0, 1.0, 0.5));
        expect(color).toEqual(new Color(1.0, 1.0, 1.0, 0.5));

        expression = new Expression(new MockStyleEngine(), 'color()');
        expect(expression.evaluateColor(undefined, color)).toEqual(Color.WHITE);
        expect(color).toEqual(Color.WHITE);
    });

    it('evaluates color with expressions as arguments', function() {
        var feature = new MockFeature();
        feature.addProperty('hex6', '#ffffff');
        feature.addProperty('hex3', '#fff');
        feature.addProperty('keyword', 'white');
        feature.addProperty('alpha', 0.2);

        var expression = new Expression(new MockStyleEngine(), 'color(${hex6})');
        expect(expression.evaluate(feature)).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'color(${hex3})');
        expect(expression.evaluate(feature)).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'color(${keyword})');
        expect(expression.evaluate(feature)).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'color(${keyword}, ${alpha} + 0.6)');
        expect(expression.evaluate(feature).red).toEqual(1.0);
        expect(expression.evaluate(feature).green).toEqual(1.0);
        expect(expression.evaluate(feature).blue).toEqual(1.0);
        expect(expression.evaluate(feature).alpha).toEqual(0.8);
    });

    it('evaluates rgb with expressions as arguments', function() {
        var feature = new MockFeature();
        feature.addProperty('red', 100);
        feature.addProperty('green', 200);
        feature.addProperty('blue', 255);

        var expression = new Expression(new MockStyleEngine(), 'rgb(${red}, ${green}, ${blue})');
        expect(expression.evaluate(feature)).toEqual(Color.fromBytes(100, 200, 255));

        expression = new Expression(new MockStyleEngine(), 'rgb(${red}/2, ${green}/2, ${blue})');
        expect(expression.evaluate(feature)).toEqual(Color.fromBytes(50, 100, 255));
    });

    it('evaluates hsl with expressions as arguments', function() {
        var feature = new MockFeature();
        feature.addProperty('h', 0.0);
        feature.addProperty('s', 0.0);
        feature.addProperty('l', 1.0);

        var expression = new Expression(new MockStyleEngine(), 'hsl(${h}, ${s}, ${l})');
        expect(expression.evaluate(feature)).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'hsl(${h} + 0.2, ${s} + 1.0, ${l} - 0.5)');
        expect(expression.evaluate(feature)).toEqual(Color.fromHsl(0.2, 1.0, 0.5));
    });

    it('evaluates rgba with expressions as arguments', function() {
        var feature = new MockFeature();
        feature.addProperty('red', 100);
        feature.addProperty('green', 200);
        feature.addProperty('blue', 255);
        feature.addProperty('a', 0.3);

        var expression = new Expression(new MockStyleEngine(), 'rgba(${red}, ${green}, ${blue}, ${a})');
        expect(expression.evaluate(feature)).toEqual(Color.fromBytes(100, 200, 255, 0.3*255));

        expression = new Expression(new MockStyleEngine(), 'rgba(${red}/2, ${green}/2, ${blue}, ${a} * 2)');
        expect(expression.evaluate(feature)).toEqual(Color.fromBytes(50, 100, 255, 0.6*255));
    });

    it('evaluates hsla with expressions as arguments', function() {
        var feature = new MockFeature();
        feature.addProperty('h', 0.0);
        feature.addProperty('s', 0.0);
        feature.addProperty('l', 1.0);
        feature.addProperty('a', 1.0);

        var expression = new Expression(new MockStyleEngine(), 'hsla(${h}, ${s}, ${l}, ${a})');
        expect(expression.evaluate(feature)).toEqual(Color.WHITE);

        expression = new Expression(new MockStyleEngine(), 'hsla(${h} + 0.2, ${s} + 1.0, ${l} - 0.5, ${a} / 4)');
        expect(expression.evaluate(feature)).toEqual(Color.fromHsl(0.2, 1.0, 0.5, 0.25));
    });

    it('evaluates rgba with expressions as arguments', function() {
        var feature = new MockFeature();
        feature.addProperty('red', 100);
        feature.addProperty('green', 200);
        feature.addProperty('blue', 255);
        feature.addProperty('alpha', 0.5);

        var expression = new Expression(new MockStyleEngine(), 'rgba(${red}, ${green}, ${blue}, ${alpha})');
        expect(expression.evaluate(feature)).toEqual(Color.fromBytes(100, 200, 255, 0.5 * 255));

        expression = new Expression(new MockStyleEngine(), 'rgba(${red}/2, ${green}/2, ${blue}, ${alpha} + 0.1)');
        expect(expression.evaluate(feature)).toEqual(Color.fromBytes(50, 100, 255, 0.6 * 255));
    });

    it('color constructors throw with wrong number of arguments', function() {
        expect(function() {
            return new Expression(new MockStyleEngine(), 'rgb(255, 255)');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), 'hsl(1, 1)');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), 'rgba(255, 255, 255)');
        }).toThrowDeveloperError();

        expect(function() {
            return new Expression(new MockStyleEngine(), 'hsla(1, 1, 1)');
        }).toThrowDeveloperError();
    });

    it('evaluates color properties', function() {
        var expression = new Expression(new MockStyleEngine(), 'color(\'#ffffff\').red');
        expect(expression.evaluate(undefined)).toEqual(1);

        expression = new Expression(new MockStyleEngine(), 'rgb(255, 255, 0).green');
        expect(expression.evaluate(undefined)).toEqual(1);

        expression = new Expression(new MockStyleEngine(), 'color("cyan").blue');
        expect(expression.evaluate(undefined)).toEqual(1);

        expression = new Expression(new MockStyleEngine(), 'rgba(255, 255, 0, 0.5).alpha');
        expect(expression.evaluate(undefined)).toEqual(0.5);
    });

    it('evaluates unary not', function() {
        var expression = new Expression(new MockStyleEngine(), '!true');
        expect(expression.evaluate(undefined)).toEqual(false);

        expression = new Expression(new MockStyleEngine(), '!!true');
        expect(expression.evaluate(undefined)).toEqual(true);
    });

    it('evaluates unary negative', function() {
        var expression = new Expression(new MockStyleEngine(), '-5');
        expect(expression.evaluate(undefined)).toEqual(-5);

        expression = new Expression(new MockStyleEngine(), '-(-5)');
        expect(expression.evaluate(undefined)).toEqual(5);
    });

    it('evaluates unary positive', function() {
        var expression = new Expression(new MockStyleEngine(), '+5');
        expect(expression.evaluate(undefined)).toEqual(5);
{'fraction_non_alphanumeric': 0.16641971457537238, 'fraction_numerical': 0.019860147131456497, 'mean_word_length': 3.378556794900979, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 46, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4095256', 'n_tokens_mistral': 10898, 'n_tokens_neox': 10117, 'n_words': 2144}