#!perl -T
BEGIN { require './t/test.pl' }
use Test::More tests => 37;
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' );
# ===================================================
# 11.2.1 Property accessors
# ===================================================
## Tests 4-22 ##
my($lv, $base);
$lv = $j->eval('0 .Θοῦ');
$base = $lv->base;
ok $base->isa('JE::Number') && $base eq '0' &&
$lv->property eq 'Θοῦ', 'primaryexpr . ident';
# Note: The base is not converted to an object when the lvalue is created
# (as described in the spec), but JavaScript can't tell, because an object
# is created when the property is accessed or when a function is called
# (the latter is tested below).
$lv = $j->eval('function(){}.Κύριε');
$base = $lv->base;
ok $base->isa('JE::Object::Function') && $lv->property eq 'Κύριε',
'function(){} . ident';
$lv = $j->eval('"φυλακὴν" [ "toString" ] . τῷ');
$base = $lv->base;
ok $base->id eq $j->eval('String.prototype.toString')->id &&
$lv->property eq 'τῷ', 'memberexpr [ expr ] . ident';
$lv = $j->eval('"στόματί" . toString . μου');
$base = $lv->base;
ok $base->id eq $j->eval('String.prototype.toString')->id &&
$lv->property eq 'μου', 'memberexpr . ident . ident';
$lv = $j->eval('new Object ( ) . καὶ');
$base = $lv->base;
ok $base->isa('JE::Object') && $lv->property eq 'καὶ',
'new memberexpr ( ) . ident';
$lv = $j->eval('"θύραν" [ "περιοχῆς" ]');
$base = $lv->base;
ok $base->isa('JE::String') && $base eq 'θύραν' &&
$lv->property eq 'περιοχῆς', 'primaryexpr [ expr ]';
$lv = $j->eval('function(){} [ "περὶ" ]');
$base = $lv->base;
ok $base->isa('JE::Object::Function') && $lv->property eq 'περὶ',
'function(){} [ expr ]';
$lv = $j->eval('"τὰ" [ "toString" ] [ "χείλη" ]');
$base = $lv->base;
ok $base->id eq $j->eval('String.prototype.toString')->id &&
$lv->property eq 'χείλη', 'memberexpr [ expr ] [ expr ]';
$lv = $j->eval('"μου." . toString [ "Μὴ" ]');
$base = $lv->base;
ok $base->id eq $j->eval('String.prototype.toString')->id &&
$lv->property eq 'Μὴ', 'memberexpr . ident [ expr ]';
$lv = $j->eval('new Object ( ) [ "ἐκκλίνῆς" ]');
$base = $lv->base;
ok $base->isa('JE::Object') && $lv->property eq 'ἐκκλίνῆς',
'new memberexpr ( ) [ expr ]';
$lv = $j->eval('Object ( ) . τὴν ');
$base = $lv->base;
ok $base->isa('JE::Object') && $lv->property eq 'τὴν',
'memberexpr ( ) . ident';
$lv = $j->eval('function(){return Object}() ( ) . καρδίαν ');
$base = $lv->base;
ok $base->isa('JE::Object') && $lv->property eq 'καρδίαν',
'callexpr ( ) . ident';
$lv = $j->eval('function(){return "μου"}() [ "toString" ] . εἰς ');
$base = $lv->base;
ok $base->id eq $j->eval('String.prototype.toString')->id &&
$lv->property eq 'εἰς', 'callexpr [ expr ] . ident';
$lv = $j->eval('function(){return "λόγους"}() . toString . πονηρίας ');
$base = $lv->base;
ok $base->id eq $j->eval('String.prototype.toString')->id &&
$lv->property eq 'πονηρίας', 'callexpr . ident . ident';
$lv = $j->eval('Object ( ) [ "τοῦ" ]');
$base = $lv->base;
ok $base->isa('JE::Object') && $lv->property eq 'τοῦ',
'memberexpr ( ) [ expr ]';
$lv = $j->eval('function(){return Object}() ( ) [ "προφασίζεσθαι" ] ');
$base = $lv->base;
ok $base->isa('JE::Object') && $lv->property eq 'προφασίζεσθαι',
'callexpr ( ) [ expr ]';
$lv = $j->eval('function(){return "προφάσεις"}() [ "toString" ] [ "ἐν" ]');
$base = $lv->base;
ok $base->id eq $j->eval('String.prototype.toString')->id &&
$lv->property eq 'ἐν', 'callexpr [ expr ] [ expr ]';
$lv = $j->eval('function(){return "ἁμαρτίαις."}() . toString [ "Σὺν" ] ');
$base = $lv->base;
ok $base->id eq $j->eval('String.prototype.toString')->id &&
$lv->property eq 'Σὺν', 'callexpr . ident [ expr ]';
is eval { $j->eval('[]["\ud800"]') }, 'undefined',
'Arrays don\'t die on access to a property with a surrogate in its name.';
# JS tests
defined $j->eval( <<'--end--' ) or die;
// ===================================================
// 11.2.2 new
// ===================================================
/* Tests 23-8 */
function keys(obj) {
var k = []
for(k[k.length] in obj);
return k
}
o = new Object;
ok(keys(o) == '' && o.constructor === Object,
'"new memberexpr" when memberexpr returns a function');
error = false
try { new {} }
catch(E) { E instanceof TypeError && (error = 1) }
ok(error, '"new memberexpr" when memberexpr returns a non-function object')
error = false
try { new true }
catch(E) { E instanceof TypeError && (error = 1) }
ok(error, '"new memberexpr" when memberexpr does not return an object')
o = new Object();
ok(keys(o) == '' && o.constructor === Object,
'"new memberexpr()" when memberexpr returns a function');
error = false
try { new {}() }
catch(E) { E instanceof TypeError && (error = 1) }
ok(error,
'"new memberexpr()" when memberexpr returns a non-function object')
error = false
try { new true() }
catch(E) { E instanceof TypeError && (error = 1) }
ok(error, '"new memberexpr()" when memberexpr does not return an object')
// ===================================================
// 11.2.3 Function calls
// ===================================================
/* Tests 29-34 */
ok(function(){
function x() { return this }
return x()
}() === this, 'lvalue() when the lvalue\'s base is a call object')
o = { method: function() { return this } }
ok( o.method() === o, 'lvalue()')
ok( (0,o.method)() === this, 'non_lvalue()')
error = false
try { o() }
catch(E) { E instanceof TypeError && (error = 1) }
ok(error, 'object() when object is not a function')
error = false
try { false() }
catch(E) { E instanceof TypeError && (error = 1) }
ok(error, 'thing() when thing is not an object')
Number.prototype.method = o.method
ok(typeof 0 .method() == 'object' && 0 .method().valueOf() === 0,
'foo.bar() when foo is not an object')
// ===================================================
// 11.2.4 Argument lists
// ===================================================
/* Tests 35-7 */
0,function(){
ok(Array.prototype.join.call(arguments, ',') === '',
'empty argument list')
}(),
function(){
ok(Array.prototype. join.call(arguments, ',') === '1',
'argument list without comma')
}(1),
function(){
ok(Array.prototype. join.call(arguments, ',') === '1,2',
'argument list with a comma')
}(1,2)
--end--