#!perl -T # WARNING: This is a brilliant example of how not to write code. (Though # I must admit that the sextuple backslash was fun.) BEGIN { require './t/test.pl' } use Test::More tests => 30; use Scalar::Util 'refaddr'; use strict; use utf8; # Test 1: See if the module loads BEGIN { use_ok('JE') }; my $j = new JE; # Tests 2-3: Bind the ok and diag functions isa_ok( $j->new_function( ok => \&ok ), 'JE::Object::Function' ); isa_ok( $j->new_function( diag => \&diag ), 'JE::Object::Function' ); # Test 4: Bind Perl's eval to JS so we can do naughty stuff. isa_ok( $j->new_function( peval => sub { eval shift } ), 'JE::Object::Function' ); # Run JS tests defined $j->eval( <<'--end--' ) or die; // --------------------------------------------------- /* Tests 5-9: global code */ // These line breaks would cause a syntax error according to spec. // JE supports line breaks in string literals. Don't tell anyone. peval(' my @scope = @$JE::Code::scope; # Don\'t do this at # home--I mean in pro- # duction code! These # internal details are sub- # ject to change. ok @scope == 1, "scope chain in global code contains one object"; ok refaddr $scope[0] == refaddr $j, "that object is the global object"; '); var thing; ok(this.hasOwnProperty('thing'), 'global object is the variable object') ok(!delete thing, 'vars declared in global code are undeletable') peval('ok refaddr shift @_ == refaddr $j, "the \'this\' value is the global object"', this) // --------------------------------------------------- /* Tests 10-17: function code */ var obj = Object(); with(obj) { obj.f = function(){ peval(' my @scope = @$JE::Code::scope; my @fscope = @{$${$j->eval("obj.f")->get}{scope}}; ok @scope == 3, q/@scope == 3/; ok @fscope == 2, q/@fscope == 2/; ok refaddr $scope[0] == refaddr $fscope[0] && refaddr $scope[0] == refaddr $j, "first object in function\'s scope chain" . " is the global obj"; ok refaddr $scope[1] == refaddr $fscope[1] && refaddr $scope[1] == refaddr $j->prop("obj"), "\'with\' object in scope chain"; ok ref $scope[2] eq \'JE::Object::Function::Call\', "\\\$scope has a call object"; '); var thing; ok(peval('exists $JE::Code::scope->[-1]{thing} '), "activation object is the variable object") ok(!delete thing, 'vars declared in function code are undeletable') ok(this === obj, '"this" value in function code') } } obj.f() // --------------------------------------------------- /* Tests 18-22: 'global-eval code' (eval code called from global code) */ eval(" peval(' my @scope = @$JE::Code::scope; ok @scope == 1, \"scope chain in global-eval code contains one object\"; ok refaddr $scope[0] == refaddr $j, \"object in global-eval scope chain is the global object\"; '); var thing2; ok(this.hasOwnProperty('thing2'), 'global object is the variable object in global-eval code') ok(delete thing2, 'vars declared in global-eval code are deletable') peval('ok refaddr shift(@_) == refaddr $j, \"the \\'this\\' value in global-eval code is the global object\"', this) ") // --------------------------------------------------- /* Tests 23-30: function-eval code */ var obj2 = Object(); with(obj2) { obj2.f = function(){ eval(" peval(' my @scope = @$JE::Code::scope; my @fscope = @{$${$j->eval(\"obj2.f\")->get}{scope}}; ok @scope == 3, q/@scope == 3 (function-eval)/; ok @fscope == 2, q/@fscope == 2 (function-eval)/; ok refaddr $scope[0] == refaddr $fscope[0] && refaddr $scope[0] == refaddr $j, \"first object in function\\'s scope \" . \" chain is the global obj (in eval code)\"; ok refaddr $scope[1] == refaddr $fscope[1] && refaddr $scope[1] == refaddr $j->prop(\"obj2\"), \"\\'with\\' object in function-eval \" . \"scope chain\"; ok ref $scope[2] eq \\'JE::Object::Function::Call\\', \"\\\\\\$scope has a call object\"; '); var thing; ok(peval('exists $JE::Code::scope->[-1]{thing} '), \"activation object is the variable object \" + \"in function-eval code\") ok(delete thing, 'vars declared in function-eval code are deletable') ok(this === obj2, '\"this\" value in function-eval code') ") // end of eval } } obj2.f() --end--