var test = require('tape');
var evaluate = require('../');
var parse = require('esprima').parse;

test('resolved', function (t) {
    t.plan(1);
    
    var src = '[1,2,3+4*10+(n||6),foo(3+5),obj[""+"x"].y]';
    var ast = parse(src).body[0].expression;
    var res = evaluate(ast, {
        n: false,
        foo: function (x) { return x * 100 },
        obj: { x: { y: 555 } }
    });
    t.deepEqual(res, [ 1, 2, 49, 800, 555 ]);
});

test('unresolved', function (t) {
    t.plan(1);
    
    var src = '[1,2,3+4*10*z+n,foo(3+5),obj[""+"x"].y]';
    var ast = parse(src).body[0].expression;
    var res = evaluate(ast, {
        n: 6,
        foo: function (x) { return x * 100 },
        obj: { x: { y: 555 } }
    });
    t.equal(res, undefined);
});

test('boolean', function (t) {
    t.plan(1);
    
    var src = '[ 1===2+3-16/4, [2]==2, [2]!==2, [2]!==[2] ]';
    var ast = parse(src).body[0].expression;
    t.deepEqual(evaluate(ast), [ true, true, true, true ]);
});

test('array methods', function(t) {
    t.plan(1);

    var src = '[1, 2, 3].map(function(n) { return n * 2 })';
    var ast = parse(src).body[0].expression;
    t.deepEqual(evaluate(ast), [2, 4, 6]);
});

test('array methods invocation count', function(t) {
    t.plan(2);

    var variables = {
        values: [1, 2, 3],
        receiver: []
    };
    var src = 'values.forEach(function(x) { receiver.push(x); })'
    var ast = parse(src).body[0].expression;
    evaluate(ast, variables);
    t.equal(variables.receiver.length, 3);
    t.deepEqual(variables.receiver, [1, 2, 3]);
})

test('array methods invocation count debugging', function(t) {
    t.plan(1);

    var invoked = false;
    var variables = {
        values: [],
        onValue: () => {
            console.log("Invoke happened")
            invoked = true
        }
    };
    var src = 'values.forEach(function(x) { onValue() })'
    var ast = parse(src).body[0].expression;
    evaluate(ast, variables);
    t.equal(invoked, false);
})

test('array methods with vars', function(t) {
    t.plan(1);

    var src = '[1, 2, 3].map(function(n) { return n * x })';
    var ast = parse(src).body[0].expression;
    t.deepEqual(evaluate(ast, {x: 2}), [2, 4, 6]);
});

test('evaluate this', function(t) {
    t.plan(1);

    var src = 'this.x + this.y.z';
    var ast = parse(src).body[0].expression;
    var res = evaluate(ast, {
        'this': { x: 1, y: { z: 100 } }
    });
    t.equal(res, 101);
});

test('FunctionExpression unresolved', function(t) {
    t.plan(1);

    var src = '(function(){console.log("Not Good")})';
    var ast = parse(src).body[0].expression;
    var res = evaluate(ast, {});
    t.equal(res, undefined);
});

test('MemberExpressions from Functions unresolved', function(t) {
    t.plan(1);

    var src = '(function () {}).constructor';
    var ast = parse(src).body[0].expression;
    var res = evaluate(ast, {});
    t.equal(res, undefined);
});

test('disallow accessing constructor or __proto__', function (t) {
    t.plan(4)

    var someValue = {};

    var src = 'object.constructor';
    var ast = parse(src).body[0].expression;
    var res = evaluate(ast, { vars: { object: someValue } });
    t.equal(res, undefined);

    var src = 'object["constructor"]';
    var ast = parse(src).body[0].expression;
    var res = evaluate(ast, { vars: { object: someValue } });
    t.equal(res, undefined);

    var src = 'object.__proto__';
    var ast = parse(src).body[0].expression;
    var res = evaluate(ast, { vars: { object: someValue } });
    t.equal(res, undefined);

    var src = 'object["__pro"+"t\x6f__"]';
    var ast = parse(src).body[0].expression;
    var res = evaluate(ast, { vars: { object: someValue } });
    t.equal(res, undefined);
});


test('constructor at runtime only', function(t) {
    t.plan(2)

    var src = '(function myTag(y){return ""[!y?"__proto__":"constructor"][y]})("constructor")("console.log(process.env)")()'
    var ast = parse(src).body[0].expression;
    var res = evaluate(ast);
    t.equal(res, undefined);

    var src = '(function(prop) { return {}[prop ? "benign" : "constructor"][prop] })("constructor")("alert(1)")()'
    var ast = parse(src).body[0].expression;
    var res = evaluate(ast);
    t.equal(res, undefined);
});

test('function declaration does not invoke CallExpressions', function(t) {
    t.plan(1);

    var invoked = false;
    var variables = {
        noop: function(){},
        onInvoke: function() {invoked = true}
    };
    var src = `noop(function(){ onInvoke(); })`;
    var ast = parse(src).body[0].expression;
    evaluate(ast, variables);
    t.equal(invoked, false);
});
@@ -1566,432 +1566,8 @@
 %7D)%0A%0A
-test('array methods invocation count debugging', function(t) %7B%0A    t.plan(1);%0A%0A    var invoked = false;%0A    var variables = %7B%0A        values: %5B%5D,%0A        onValue: () =%3E %7B%0A            console.log(%22Invoke happened%22)%0A            invoked = true%0A        %7D%0A    %7D;%0A    var src = 'values.forEach(function(x) %7B onValue() %7D)'%0A    var ast = parse(src).body%5B0%5D.expression;%0A    evaluate(ast, variables);%0A    t.equal(invoked, false);%0A%7D)%0A%0A
 test

Remove debug test