<p>
This page verifies that eval, when called as a function, uses the "this" object
provided by the call as its variable object, scope chain, and "this" object.
However, if the "this" object is not the global object eval was originally
associated with, eval throws an exception.
</p>
<p>If the test passes, you'll see a series of pass messages below.</p>
<pre id="console"></pre>

<hr>
<pre id="console"></pre>
<iframe style="width:0; height:0"></iframe>

<script>
if (window.testRunner)
    testRunner.dumpAsText();
    
var topEval = eval;
var frameEval = frames[0].eval;

function log(s)
{
    document.getElementById("console").appendChild(document.createTextNode(s + "\n"));
}

function shouldBe(aDescription, a, b)
{
    if (a === b) {
        log("PASS: " + aDescription + " should be " + b + " and is.");
    } else {
        log("FAIL: " + aDescription + " should be " + b + " but instead is " + a + ".");
    }
}

function testGetX()
{
    window.x = 0;
    frames[0].x = 1;
    var x = 2;

    shouldBe('window.eval("x")', window.eval("x"), 0);
    shouldBe('frames[0].eval("x")', frames[0].eval("x"), 1);

    window.eval = frameEval;
    shouldBe('window.eval("x")', (function() { try { return window.eval("x") } catch(e) { return e.name; } })(), 1);
    window.eval = topEval;

    frames[0].eval = topEval;
    shouldBe('frames[0].eval("x")', (function() { try { frames[0].eval("x") } catch(e) { return e.name; } })(), undefined);
    frames[0].eval = frameEval;
}

function testGetXX()
{
    var xx = 0;

    shouldBe('window.eval("xx")', (function() { try { return window.eval("xx") } catch(e) { return e.name; } })(), "ReferenceError"); 
    shouldBe('frames[0].eval("xx")', (function() { try { return frames[0].eval("xx") } catch(e) { return e.name; } })(), "ReferenceError");

    window.eval = frameEval;
    shouldBe('window.eval("xx")', (function() { try { return window.eval("xx") } catch(e) { return e.name; } })(), "ReferenceError");
    window.eval = topEval;

    frames[0].eval = topEval;
    shouldBe('frames[0].eval("xx")', (function() { try { return frames[0].eval("xx") } catch(e) { return e.name; } })(), "ReferenceError");
    frames[0].eval = frameEval;
}

function testVarY()
{
    shouldBe('window.eval("var y; \"y\" in top")', window.eval("var y; \"y\" in top"), true);
    delete window.y;
    delete frames[0].y;

    shouldBe('frames[0].eval("var y; \"y\" in top.frames[0]")', frames[0].eval("var y; \"y\" in top.frames[0]"), true);
    delete window.y;
    delete frames[0].y;

    window.eval = frameEval;
    shouldBe('window.eval("var y; \"y\" in top.frames[0]")', (function() { try { window.eval("var y; \"y\" in top.frames[0]") } catch(e) { return e.name; } })(), undefined);
    delete window.y;
    delete frames[0].y;
    window.eval = topEval;

    frames[0].eval = topEval;
    shouldBe('frames[0].eval("var y; \"y\" in top")', (function() { try { frames[0].eval("var y; \"y\" in top") } catch(e) { return e.name; } })(), undefined);
    delete window.y;
    delete frames[0].y;
    frames[0].eval = frameEval;
}

function testSetZ()
{
    window.z = 0;
    frames[0].z = 0;
    var z = 0;

    shouldBe('window.eval("z = 1; top.z")', window.eval("z = 1; top.z"), 1);
    shouldBe('frames[0].eval("z = 2; top.frames[0].z")', frames[0].eval("z = 2; top.frames[0].z"), 2);

    window.eval = frameEval;
    shouldBe('window.eval("z = 3; top.frames[0].z")', (function() { try { window.eval("z = 3; top.frames[0].z") } catch(e) { return e.name; } })(), undefined);
    window.eval = topEval;

    frames[0].eval = topEval;
    shouldBe('frames[0].eval("z = 4; top.z")', (function() { try { frames[0].eval("z = 4; top.z") } catch(e) { return e.name; } })(), undefined);
    frames[0].eval = frameEval;
}

function testThis()
{
    shouldBe('window.eval("this")', window.eval.call("wrong", "this"), window);
    shouldBe('frames[0].eval("this")', frames[0].eval.call("wrong", "this"), frames[0]);

    window.eval = frameEval;
    shouldBe('window.eval("this")', (function() { try { window.eval.call("wrong", "this"), frames[0] } catch(e) { return e.name; } })(), undefined);
    window.eval = topEval;

    frames[0].eval = topEval;
    shouldBe('frames[0].eval("this")', (function() { try { frames[0].eval.call("wrong", "this"), window } catch(e) { return e.name; } })(), undefined);
    frames[0].eval = frameEval;
}

log("\n----- Scope Chain Head for Getters: -----\n");
testGetX();
log("\n----- Scope Chain for Getters: -----\n");
testGetXX();
log("\n----- Variable Object: -----\n");
testVarY();
log("\n----- Scope Chain for Setters: -----\n");
testSetZ();
log("\n----- This Object: -----\n");
testThis.call({});
</script>
