Browse Source

add a set of test cases

pull/1/head
Sami Vaarala 12 years ago
parent
commit
837d738bbd
  1. 4
      testcases/rhino-case-conversions.txt
  2. 4
      testcases/smjs-case-conversions.txt
  3. 63
      testcases/test-arguments-throwers.js
  4. 12
      testcases/test-builtin-array.js
  5. 12
      testcases/test-builtin-boolean.js
  6. 12
      testcases/test-builtin-date.js
  7. 12
      testcases/test-builtin-duk.js
  8. 12
      testcases/test-builtin-error.js
  9. 12
      testcases/test-builtin-function.js
  10. 42
      testcases/test-builtin-global.js
  11. 15
      testcases/test-builtin-json.js
  12. 795
      testcases/test-builtin-math.js
  13. 38
      testcases/test-builtin-number.js
  14. 20
      testcases/test-builtin-object.js
  15. 1219
      testcases/test-builtin-properties.js
  16. 12
      testcases/test-builtin-regexp.js
  17. 16
      testcases/test-builtin-string-caseconversion-other.js
  18. 14590
      testcases/test-builtin-string-caseconversion-single.js
  19. 18
      testcases/test-builtin-string.js
  20. 38
      testcases/test-conv-checkobjectcoercible.js
  21. 40
      testcases/test-conv-iscallable.js
  22. 271
      testcases/test-conv-samevalue.js
  23. 51
      testcases/test-conv-toboolean.js
  24. 140
      testcases/test-conv-toint32.js
  25. 12
      testcases/test-conv-tointeger.js
  26. 84
      testcases/test-conv-tonumber.js
  27. 12
      testcases/test-conv-toobject.js
  28. 12
      testcases/test-conv-toprimitive.js
  29. 12
      testcases/test-conv-tostring.js
  30. 141
      testcases/test-conv-touint16.js
  31. 140
      testcases/test-conv-touint32.js
  32. 11
      testcases/test-dev-add-prec.js
  33. 63
      testcases/test-dev-arguments-binding.js
  34. 65
      testcases/test-dev-array-literal.js
  35. 34
      testcases/test-dev-array-property-attrs.js
  36. 17
      testcases/test-dev-assign-lhs.js
  37. 33
      testcases/test-dev-assign-trivial-loop.js
  38. 26
      testcases/test-dev-bitops.js
  39. 34
      testcases/test-dev-bnot.js
  40. 34
      testcases/test-dev-bug-autosemi-1.js
  41. 48
      testcases/test-dev-bug-catch-binding.js
  42. 22
      testcases/test-dev-bug-chain-call.js
  43. 17
      testcases/test-dev-bug-closure-outer.js
  44. 18
      testcases/test-dev-bug-finalizer-rescue.js
  45. 41
      testcases/test-dev-bug-for-in-bound-var.js
  46. 21
      testcases/test-dev-bug-for-var-in.js
  47. 26
      testcases/test-dev-bug-formal-implements.js
  48. 25
      testcases/test-dev-bug-func-closure-fnum.js
  49. 33
      testcases/test-dev-bug-func-redecl.js
  50. 44
      testcases/test-dev-bug-lex-regexp-1.js
  51. 17
      testcases/test-dev-bug-ret-call.js
  52. 12
      testcases/test-dev-bug-str-constructor-noarg.js
  53. 16
      testcases/test-dev-bug-typeof-unref.js
  54. 42
      testcases/test-dev-bug-yield-after-callapply.js
  55. 64
      testcases/test-dev-call-chained.js
  56. 12
      testcases/test-dev-call-expr.js
  57. 24
      testcases/test-dev-call-through-this.js
  58. 21
      testcases/test-dev-catch-binding.js
  59. 42
      testcases/test-dev-chaos.js
  60. 35
      testcases/test-dev-comma.js
  61. 107
      testcases/test-dev-compiler-recursion.js
  62. 100
      testcases/test-dev-conditional.js
  63. 12
      testcases/test-dev-cont-callstack.js
  64. 60
      testcases/test-dev-cont-catchstack.js
  65. 12
      testcases/test-dev-cont-valstack.js
  66. 40
      testcases/test-dev-coroutine-basic.js
  67. 123
      testcases/test-dev-ctrl-breakcont.js
  68. 22
      testcases/test-dev-ctrl-trycatch-binding.js
  69. 11
      testcases/test-dev-ctrl-with-binding.js
  70. 25
      testcases/test-dev-dangling-else.js
  71. 186
      testcases/test-dev-declbinding.js
  72. 149
      testcases/test-dev-delete.js
  73. 250
      testcases/test-dev-direct-eval.js
  74. 110
      testcases/test-dev-directive-prologue.js
  75. 29
      testcases/test-dev-enum-deleted-still-in-ancestor.js
  76. 30
      testcases/test-dev-equality.js
  77. 54
      testcases/test-dev-error-constructor.js
  78. 20
      testcases/test-dev-eval-objlit-confusion.js
  79. 20
      testcases/test-dev-exec-valstack-size.js
  80. 12
      testcases/test-dev-for-in-basic.js
  81. 87
      testcases/test-dev-for-in-lhs.js
  82. 32
      testcases/test-dev-func-apply.js
  83. 39
      testcases/test-dev-func-bind.js
  84. 23
      testcases/test-dev-func-call.js
  85. 17
      testcases/test-dev-func-closure-1.js
  86. 100
      testcases/test-dev-func-cons-args.js
  87. 198
      testcases/test-dev-func-formals.js
  88. 11
      testcases/test-dev-func-length-prop.js
  89. 168
      testcases/test-dev-func-name.js
  90. 29
      testcases/test-dev-func-own-name-ref.js
  91. 98
      testcases/test-dev-func-shadowing.js
  92. 14
      testcases/test-dev-func-without-args.js
  93. 14
      testcases/test-dev-implicit-return-value-1.js
  94. 32
      testcases/test-dev-implicit-return-value-2.js
  95. 24
      testcases/test-dev-invalid-lhs.js
  96. 41
      testcases/test-dev-json-cyclic.js
  97. 267
      testcases/test-dev-json-types.js
  98. 34
      testcases/test-dev-json-wrapper.js
  99. 24
      testcases/test-dev-label-parsing.js
  100. 51
      testcases/test-dev-label-source-elem.js

4
testcases/rhino-case-conversions.txt

File diff suppressed because one or more lines are too long

4
testcases/smjs-case-conversions.txt

File diff suppressed because one or more lines are too long

63
testcases/test-arguments-throwers.js

@ -0,0 +1,63 @@
/*
* E5 Section 10.6, main algorithm step 14 requires that a strict
* arguments object 'callee' and 'caller' throwers must be the specific
* thrower defined in E5 Section 13.2.3.
*/
/*===
test get and set
object
object
object
object
true
true
true
true
true
true
true
TypeError
TypeError
===*/
function f(x,y) { 'use strict'; return arguments; };
function g(x,y) { 'use strict'; return arguments; };
var a = f(1,2,3);
var b = g(3,2,1);
pd1 = Object.getOwnPropertyDescriptor(a, "caller");
pd2 = Object.getOwnPropertyDescriptor(a, "callee");
pd3 = Object.getOwnPropertyDescriptor(b, "caller");
pd4 = Object.getOwnPropertyDescriptor(b, "callee");
print('test get and set')
print(typeof pd1);
print(typeof pd2);
print(typeof pd3);
print(typeof pd4);
// all of these should print true
print(pd1.get === pd1.set);
print(pd2.get === pd2.set);
print(pd3.get === pd3.set);
print(pd4.get === pd4.set);
print(pd1.get === pd2.get);
print(pd2.get === pd3.get);
print(pd3.get === pd4.get);
try {
pd1.get();
} catch (e) {
print(e.name);
}
try {
pd2.get();
} catch (e) {
print(e.name);
}

12
testcases/test-builtin-array.js

@ -0,0 +1,12 @@
/*
* Array objects (E5 Section 15.4).
*/
/*---
{
"skip": true
}
---*/
/* FIXME: */

12
testcases/test-builtin-boolean.js

@ -0,0 +1,12 @@
/*
* Boolean objects (E5 Section 15.6).
*/
/*---
{
"skip": true
}
---*/
/* FIXME */

12
testcases/test-builtin-date.js

@ -0,0 +1,12 @@
/*
* Date objects (E5 Sections 15.9, B.2.4, B.2.5, B.2.6).
*/
/*---
{
"skip": true
}
---*/
/* FIXME */

12
testcases/test-builtin-duk.js

@ -0,0 +1,12 @@
/*
* __duk__ builtin.
*/
/*---
{
"skip": true
}
---*/
/* FIXME */

12
testcases/test-builtin-error.js

@ -0,0 +1,12 @@
/*
* Error objects (E5 Section 15.11).
*/
/*---
{
"skip": true
}
---*/
/* FIXME */

12
testcases/test-builtin-function.js

@ -0,0 +1,12 @@
/*
* Function objects (E5 Section 15.3).
*/
/*---
{
"skip": true
}
---*/
/* FIXME */

42
testcases/test-builtin-global.js

@ -0,0 +1,42 @@
/*
* Builtin global (E5 Sections 15.1, B.2.1, B.2.2)
*/
/*---
{
"skip": true
}
---*/
var indirectEval = eval;
var global = indirectEval('this');
/*===
[object global]
===*/
/* [[Class]] implementation defined, but we expect 'global' */
print(global);
/*===
TypeError
TypeError
===*/
/* Not callable or constructable */
try {
global();
} catch (e) {
print(e.name);
}
try {
new global();
} catch (e) {
print(e.name);
}
/* FIXME */

15
testcases/test-builtin-json.js

@ -0,0 +1,15 @@
/*
* JSON object (E5 Section 15.12).
*
* There are detailed JSON tests elsewhere. Here we test the basic
* functionality.
*/
/*---
{
"skip": true
}
---*/
/* FIXME */

795
testcases/test-builtin-math.js

@ -0,0 +1,795 @@
/*
* Math object (E5 Section 15.8).
*
* Difficulties arise from:
*
* - Trigonometric functions are not required to be bit exact
* - Random number testing
* - Some calls distinguish between +0 and -0 (e.g. asin)
*
* To distinguish zero signs, the idiom '1 / x' is used. If x is +0,
* this will result in Infinity, and if x is -0, it will result in
* -Infinity.
*/
function printRounded6(x) {
print(Math.round(x * 1000000));
}
function printExact(x) {
print(x.toString());
}
function zeroSign(x) {
if (x !== 0) {
return 'zero expected';
}
if (1 / x >= 0) {
return 1;
} else {
return -1;
}
}
var pr6 = printRounded6;
var prE = printExact;
/*===
rounded constant test
2718282
2302585
693147
1442695
434294
3141593
707107
1414214
===*/
/* Rounded constant test. */
print('rounded constant test');
pr6(Math.E);
pr6(Math.LN10);
pr6(Math.LN2);
pr6(Math.LOG2E);
pr6(Math.LOG10E);
pr6(Math.PI);
pr6(Math.SQRT1_2);
pr6(Math.SQRT2);
/*===
exact constant test
2.718281828459045
2.302585092994046
0.6931471805599453
1.4426950408889634
0.4342944819032518
3.141592653589793
0.7071067811865476
1.4142135623730951
===*/
/* Exact constant test. The results were taken from V8 and compared
* against Rhino.
*/
print('exact constant test');
prE(Math.E);
prE(Math.LN10);
prE(Math.LN2);
prE(Math.LOG2E);
prE(Math.LOG10E);
prE(Math.PI);
prE(Math.SQRT1_2);
prE(Math.SQRT2);
/*===
abs
123
123
0
1
0
1
NaN
Infinity
Infinity
===*/
print('abs');
prE(Math.abs(+123));
prE(Math.abs(-123));
prE(Math.abs(+0));
print(zeroSign(Math.abs(+0)));
prE(Math.abs(-0));
print(zeroSign(Math.abs(-0)));
prE(Math.abs(Number.NaN));
prE(Math.abs(Number.POSITIVE_INFINITY));
prE(Math.abs(Number.NEGATIVE_INFINITY));
/*===
acos
1570796
0
1
3141593
NaN
NaN
NaN
===*/
print('acos');
pr6(Math.acos(0));
prE(Math.acos(1));
print(zeroSign(Math.acos(1)));
pr6(Math.acos(-1))
pr6(Math.acos(Number.NaN));
pr6(Math.acos(1.0000001));
pr6(Math.acos(-1.0000001));
/*===
asin
0
1
0
-1
1570796
-1570796
NaN
NaN
NaN
===*/
print('asin');
prE(Math.asin(+0));
print(zeroSign(Math.asin(+0)));
prE(Math.asin(-0));
print(zeroSign(Math.asin(-0)));
pr6(Math.asin(1));
pr6(Math.asin(-1))
pr6(Math.asin(Number.NaN));
pr6(Math.asin(1.0000001));
pr6(Math.asin(-1.0000001));
/*===
atan
NaN
0
1
0
-1
1570796
-1570796
===*/
print('atan');
prE(Math.atan(Number.NaN));
prE(Math.atan(+0));
print(zeroSign(Math.atan(+0)));
prE(Math.atan(-0));
print(zeroSign(Math.atan(-0)));
pr6(Math.atan(Number.POSITIVE_INFINITY));
pr6(Math.atan(Number.NEGATIVE_INFINITY));
/*===
atan2
NaN
NaN
NaN
1570796
1570796
0
1
0
1
3141593
3141593
0
-1
0
-1
-3141593
-3141593
-1570796
-1570796
0
1
3141593
0
-1
-3141593
1570796
1570796
-1570796
-1570796
785398
2356194
-785398
-2356194
===*/
print('atan2');
prE(Math.atan2(NaN, NaN));
prE(Math.atan2(1, NaN));
prE(Math.atan2(NaN, 1));
pr6(Math.atan2(1, +0));
pr6(Math.atan2(1, -0));
prE(Math.atan2(+0, 1)); print(zeroSign(Math.atan2(+0, 1)));
prE(Math.atan2(+0, +0)); print(zeroSign(Math.atan2(+0, +0)));
pr6(Math.atan2(+0, -0));
pr6(Math.atan2(+0, -1));
prE(Math.atan2(-0, 1)); print(zeroSign(Math.atan2(-0, 1)));
prE(Math.atan2(-0, +0)); print(zeroSign(Math.atan2(-0, +0)));
pr6(Math.atan2(-0, -0));
pr6(Math.atan2(-0, -1));
pr6(Math.atan2(-1, +0));
pr6(Math.atan2(-1, -0));
prE(Math.atan2(1, Number.POSITIVE_INFINITY)); print(zeroSign(Math.atan2(1, Number.POSITIVE_INFINITY)));
pr6(Math.atan2(1, Number.NEGATIVE_INFINITY));
prE(Math.atan2(-1, Number.POSITIVE_INFINITY)); print(zeroSign(Math.atan2(-1, Number.POSITIVE_INFINITY)));
pr6(Math.atan2(-1, Number.NEGATIVE_INFINITY));
pr6(Math.atan2(Number.POSITIVE_INFINITY, 1));
pr6(Math.atan2(Number.POSITIVE_INFINITY, -1));
pr6(Math.atan2(Number.NEGATIVE_INFINITY, 1));
pr6(Math.atan2(Number.NEGATIVE_INFINITY, -1));
pr6(Math.atan2(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY));
pr6(Math.atan2(Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY));
pr6(Math.atan2(Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY));
pr6(Math.atan2(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY));
/*===
ceil
123
124
-123
-122
4294967307
NaN
0
1
0
-1
Infinity
-Infinity
0
-1
-1
===*/
print('ceil');
prE(Math.ceil(123));
prE(Math.ceil(123.000001));
prE(Math.ceil(-123));
prE(Math.ceil(-122.999999));
prE(Math.ceil(4294967306.5)); // value higher than 32 bits
prE(Math.ceil(NaN));
prE(Math.ceil(+0)); print(zeroSign(Math.ceil(+0)));
prE(Math.ceil(-0)); print(zeroSign(Math.ceil(-0)));
prE(Number.POSITIVE_INFINITY);
prE(Number.NEGATIVE_INFINITY);
prE(Math.ceil(-0.5)); print(zeroSign(Math.ceil(-0.5)));
prE(Math.ceil(-1.0));
/*===
cos
NaN
1
1
NaN
NaN
540302
===*/
print('cos');
prE(Math.cos(NaN));
prE(Math.cos(+0));
prE(Math.cos(-0));
prE(Math.cos(Number.POSITIVE_INFINITY));
prE(Math.cos(Number.NEGATIVE_INFINITY));
pr6(Math.cos(1));
/*===
exp
NaN
1
1
Infinity
0
1
===*/
print('exp');
prE(Math.exp(NaN));
prE(Math.exp(+0));
prE(Math.exp(-0));
prE(Math.exp(Number.POSITIVE_INFINITY));
prE(Math.exp(Number.NEGATIVE_INFINITY)); print(zeroSign(Math.exp(Number.NEGATIVE_INFINITY)));
/*===
floor
123
122
-123
-124
4294967306
NaN
0
1
0
-1
Infinity
-Infinity
0
1
1
===*/
print('floor');
prE(Math.floor(123));
prE(Math.floor(122.999999));
prE(Math.floor(-123));
prE(Math.floor(-124));
prE(Math.floor(4294967306.5)); // value higher than 32 bits
prE(Math.floor(NaN));
prE(Math.floor(+0)); print(zeroSign(Math.floor(+0)));
prE(Math.floor(-0)); print(zeroSign(Math.floor(-0)));
prE(Math.floor(Number.POSITIVE_INFINITY));
prE(Math.floor(Number.NEGATIVE_INFINITY));
prE(Math.floor(0.5)); print(zeroSign(Math.floor(0.5)));
prE(Math.floor(1));
/*===
log
4812184
NaN
NaN
NaN
-Infinity
-Infinity
0
1
Infinity
===*/
print('log');
pr6(Math.log(123));
prE(Math.log(NaN));
prE(Math.log(-0.000001));
prE(Math.log(Number.NEGATIVE_INFINITY));
prE(Math.log(+0));
prE(Math.log(-0));
prE(Math.log(1)); print(zeroSign(Math.log(1)));
prE(Math.log(Number.POSITIVE_INFINITY));
/*===
max
456
Infinity
123
0
1
0
-1
-Infinity
NaN
0
1
0
1
===*/
print('max');
prE(Math.max(123, -123, 456, 234));
prE(Math.max(123, -123, Number.POSITIVE_INFINITY, 234));
prE(Math.max(123));
prE(Math.max(+0));
print(zeroSign(Math.max(+0)));
prE(Math.max(-0));
print(zeroSign(Math.max(-0)));
prE(Math.max()); // -> -Infinity (!)
prE(Math.max(1,2,NaN,4));
prE(Math.max(+0, -0)); // -> +0
print(zeroSign(Math.max(+0, -0)));
prE(Math.max(-0, +0)); // -> +0
print(zeroSign(Math.max(-0, +0)));
/*===
min
-123
-Infinity
123
0
1
0
-1
Infinity
NaN
0
-1
0
-1
===*/
print('min');
prE(Math.min(123, -123, 456, 234));
prE(Math.min(123, -123, Number.NEGATIVE_INFINITY, 234));
prE(Math.min(123));
prE(Math.min(+0));
print(zeroSign(Math.min(+0)));
prE(Math.min(-0));
print(zeroSign(Math.min(-0)));
prE(Math.min()); // -> Infinity (!)
prE(Math.min(1,2,NaN,4));
prE(Math.min(+0, -0)); // -> -0
print(zeroSign(Math.min(+0, -0)));
prE(Math.min(-0, +0)); // -> -0
print(zeroSign(Math.min(-0, +0)));
/*===
pow 1
NaN
NaN
NaN
NaN
NaN
NaN
1
1
1
1
1
1
1
1
1
1
1
1
1
1
NaN
NaN
NaN
NaN
===*/
print('pow 1');
prE(Math.pow(Number.NEGATIVE_INFINITY, NaN));
prE(Math.pow(-1, NaN));
prE(Math.pow(-0, NaN));
prE(Math.pow(+0, NaN));
prE(Math.pow(1, NaN));
prE(Math.pow(Number.POSITIVE_INFINITY, NaN));
prE(Math.pow(Number.NEGATIVE_INFINITY, +0));
prE(Math.pow(-1, +0));
prE(Math.pow(-0, +0));
prE(Math.pow(+0, +0));
prE(Math.pow(1, +0));
prE(Math.pow(Number.POSITIVE_INFINITY, +0));
prE(Math.pow(NaN, +0));
prE(Math.pow(Number.NEGATIVE_INFINITY, -0));
prE(Math.pow(-1, -0));
prE(Math.pow(-0, -0));
prE(Math.pow(+0, -0));
prE(Math.pow(1, -0));
prE(Math.pow(Number.POSITIVE_INFINITY, -0));
prE(Math.pow(NaN, -0));
prE(Math.pow(NaN, Number.NEGATIVE_INFINITY));
prE(Math.pow(NaN, -1));
prE(Math.pow(NaN, +1));
prE(Math.pow(NaN, Number.POSITIVE_INFINITY));
/*===
pow 2
Infinity
Infinity
0
1
0
1
NaN
NaN
NaN
NaN
0
1
0
1
Infinity
Infinity
Infinity
0
1
-Infinity
Infinity
Infinity
Infinity
0
-1
0
1
0
1
0
1
===*/
print('pow 2');
prE(Math.pow(1.0000001, Number.POSITIVE_INFINITY));
prE(Math.pow(-1.0000001, Number.POSITIVE_INFINITY));
prE(Math.pow(1.0000001, Number.NEGATIVE_INFINITY));
print(zeroSign(Math.pow(1.0000001, Number.NEGATIVE_INFINITY)));
prE(Math.pow(-1.0000001, Number.NEGATIVE_INFINITY));
print(zeroSign(Math.pow(-1.0000001, Number.NEGATIVE_INFINITY)));
prE(Math.pow(1, Number.POSITIVE_INFINITY));
prE(Math.pow(-1, Number.POSITIVE_INFINITY));
prE(Math.pow(1, Number.NEGATIVE_INFINITY));
prE(Math.pow(-1, Number.NEGATIVE_INFINITY));
prE(Math.pow(0.999999, Number.POSITIVE_INFINITY));
print(zeroSign(Math.pow(0.999999, Number.POSITIVE_INFINITY)));
prE(Math.pow(-0.999999, Number.POSITIVE_INFINITY));
print(zeroSign(Math.pow(-0.999999, Number.POSITIVE_INFINITY)));
prE(Math.pow(0.999999, Number.NEGATIVE_INFINITY));
prE(Math.pow(-0.999999, Number.NEGATIVE_INFINITY));
prE(Math.pow(Number.POSITIVE_INFINITY, 0.000001));
prE(Math.pow(Number.POSITIVE_INFINITY, -0.000001));
print(zeroSign(Math.pow(Number.POSITIVE_INFINITY, -0.000001)));
prE(Math.pow(Number.NEGATIVE_INFINITY, 3)); // odd integer
prE(Math.pow(Number.NEGATIVE_INFINITY, 4));
prE(Math.pow(Number.NEGATIVE_INFINITY, 4.5));
prE(Math.pow(Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY));
prE(Math.pow(Number.NEGATIVE_INFINITY, -3));
print(zeroSign(Math.pow(Number.NEGATIVE_INFINITY, -3)));
prE(Math.pow(Number.NEGATIVE_INFINITY, -4));
print(zeroSign(Math.pow(Number.NEGATIVE_INFINITY, -4)));
prE(Math.pow(Number.NEGATIVE_INFINITY, -4.5));
print(zeroSign(Math.pow(Number.NEGATIVE_INFINITY, -4.5)));
prE(Math.pow(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY));
print(zeroSign(Math.pow(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY)));
/*===
pow 3
0
1
0
1
Infinity
Infinity
0
-1
0
1
0
1
0
1
-Infinity
Infinity
Infinity
Infinity
NaN
NaN
15213989025
-123345000
1000000
-8107
66
===*/
print('pow 3');
prE(Math.pow(+0, 0.0000001));
print(zeroSign(Math.pow(+0, 0.0000001)));
prE(Math.pow(+0, Number.POSITIVE_INFINITY));
print(zeroSign(Math.pow(+0, Number.POSITIVE_INFINITY)));
prE(Math.pow(+0, -0.000001));
prE(Math.pow(+0, Number.NEGATIVE_INFINITY));
prE(Math.pow(-0, 3));
print(zeroSign(Math.pow(-0, 3)));
prE(Math.pow(-0, 4));
print(zeroSign(Math.pow(-0, 4)));
prE(Math.pow(-0, 4.5));
print(zeroSign(Math.pow(-0, 4.5)));
prE(Math.pow(-0, Number.POSITIVE_INFINITY));
print(zeroSign(Math.pow(-0, Number.POSITIVE_INFINITY)));
prE(Math.pow(-0, -3));
prE(Math.pow(-0, -4));
prE(Math.pow(-0, -4.5));
prE(Math.pow(-0, Number.NEGATIVE_INFINITY));
// x < 0 and x is finite; y is finite and not an integer
prE(Math.pow(-123.345, -123.1));
prE(Math.pow(-123.345, 123.1));
// x < 0 and x is finite, y is finite and an integer
pr6(Math.pow(-123.345, 2));
pr6(Math.pow(-123.345, 1));
pr6(Math.pow(-123.345, 0));
pr6(Math.pow(-123.345, -1));
pr6(Math.pow(-123.345, -2));
/*===
random
true true
true true
===*/
/* This is a statistical test, but should pass almost always. */
print('random');
var rnd_val;
var rnd_sum = 0;
var rnd_ge0 = true;
var rnd_lt0 = true;
for (i = 0; i < 100000; i++) {
rnd_val = Math.random();
if (!(rnd_val >= 0)) { rnd_ge0 = false; }
if (!(rnd_val < 1)) { rnd_lt0 = false; }
rnd_sum += rnd_val;
}
print(rnd_ge0, rnd_lt0);
print(rnd_sum >= 49700.0, rnd_sum <= 50300.0);
/*===
round
NaN
0
1
0
-1
Infinity
-Infinity
0
1
1
0
-1
-1
4
-3
===*/
print('round');
prE(Math.round(NaN));
prE(Math.round(+0));
print(zeroSign(Math.round(+0)));
prE(Math.round(-0));
print(zeroSign(Math.round(-0)));
prE(Math.round(Number.POSITIVE_INFINITY));
prE(Math.round(Number.NEGATIVE_INFINITY));
prE(Math.round(0.400009));
print(zeroSign(Math.round(0.400009)));
prE(Math.round(0.5));
prE(Math.round(-0.5));
print(zeroSign(Math.round(-0.5)));
print(Math.round(-0.500001));
prE(Math.round(3.5));
prE(Math.round(-3.5)); // tie break towards +Infinity
/*===
sin
NaN
0
1
0
-1
NaN
NaN
841471
===*/
print('sin');
prE(Math.sin(NaN));
prE(Math.sin(+0));
print(zeroSign(Math.sin(+0)));
prE(Math.sin(-0));
print(zeroSign(Math.sin(-0)));
prE(Math.sin(Number.POSITIVE_INFINITY));
prE(Math.sin(Number.NEGATIVE_INFINITY));
pr6(Math.sin(1));
/*===
sqrt
2000000
1414214
NaN
NaN
NaN
0
1
0
-1
Infinity
===*/
print('sqrt');
pr6(Math.sqrt(4));
pr6(Math.sqrt(2));
prE(Math.sqrt(NaN));
prE(Math.sqrt(-0.000001));
prE(Math.sqrt(Number.NEGATIVE_INFINITY));
prE(Math.sqrt(+0));
print(zeroSign(Math.sqrt(+0)));
prE(Math.sqrt(-0));
print(zeroSign(Math.sqrt(-0)));
prE(Math.sqrt(Number.POSITIVE_INFINITY));
/*===
tan
1557408
-2185040
648361
NaN
0
1
0
-1
NaN
NaN
===*/
print('tan');
pr6(Math.tan(1));
pr6(Math.tan(2));
pr6(Math.tan(10));
prE(Math.tan(NaN));
prE(Math.tan(+0));
print(zeroSign(Math.tan(+0)));
prE(Math.tan(-0));
print(zeroSign(Math.tan(-0)));
prE(Math.tan(Number.POSITIVE_INFINITY));
prE(Math.tan(Number.NEGATIVE_INFINITY));

38
testcases/test-builtin-number.js

@ -0,0 +1,38 @@
/*
* Number objects (E5 Section 15.7).
*/
/*---
{
"skip": true
}
---*/
/* FIXME */
/*===
undefined
true
true
false
===*/
/* When called as a constructor, a Number instance will always have the
* original Number.prototype regardless of what Number.prototype is now
* set to. E5 Section 15.7.2.1.
*
* However, Number.prototype is not writable or configurable, so this
* behavior doesn't need to be implemented explicitly; just ensure that
* Number.prototype is not writable.
*/
var orig_prototype = Number.prototype;
var repl_prototype = { "foo": "bar" };
Number.prototype = repl_prototype; /* this write will fail silently */
var num = new Number(123);
print(num.foo);
print(Object.getPrototypeOf(num) === Number.prototype);
print(Object.getPrototypeOf(num) === orig_prototype);
print(Object.getPrototypeOf(num) === repl_prototype);

20
testcases/test-builtin-object.js

@ -0,0 +1,20 @@
/*
* Object objects (E5 Section 15.2).
*/
/*---
{
"skip": true
}
---*/
/*===
function
object
===*/
print(typeof Object);
print(typeof Object.prototype);
/* FIXME */

1219
testcases/test-builtin-properties.js

File diff suppressed because it is too large

12
testcases/test-builtin-regexp.js

@ -0,0 +1,12 @@
/*
* RegExp objects (E5 Section 15.10).
*/
/*---
{
"skip": true
}
---*/
/* FIXME */

16
testcases/test-builtin-string-caseconversion-other.js

@ -0,0 +1,16 @@
/*
* Case conversion tests for cases not covered by
*
* test-builtin-string-caseconversion-single.js
*
* Specifically, context and locale specific conversion rules.
*/
/*---
{
"skip": true
}
---*/
/* FIXME */

14590
testcases/test-builtin-string-caseconversion-single.js

File diff suppressed because it is too large

18
testcases/test-builtin-string.js

@ -0,0 +1,18 @@
/*
* String objects (E5 Sections 15.5, B.2.3).
*/
/*---
{
"skip": true
}
---*/
/* FIXME */
/*
* toUpperCase() behavior.
*
* This behavior is also related to RegExp Canonicalization behavior.
*/

38
testcases/test-conv-checkobjectcoercible.js

@ -0,0 +1,38 @@
/*
* CheckObjectCoercible() (E5 Section 9.10).
*
* This primitive cannot be directly tested. It is referenced in the
* specification almost exclusively for String.prototype functions, like
* charAt().
*
* We use String.prototype.charAt() for indirect testing.
*/
function indirectCheckObjectCoercible(x) {
String.prototype.charAt.call(x, 0);
}
/*===
TypeError
TypeError
no error
no error
no error
no error
no error
no error
no error
===*/
var values = [ undefined, null, true, false, 123.0, "foo", {}, [], function () {} ];
var i;
for (i = 0; i < values.length; i++) {
try {
indirectCheckObjectCoercible(values[i]);
print('no error');
} catch (e) {
print(e.name);
}
}

40
testcases/test-conv-iscallable.js

@ -0,0 +1,40 @@
/*
* IsCallable() (E5 Section 9.11).
*
* IsCallable() cannot be directly tested, but Function.prototype.bind()
* provides a very easy primitive for testing it. E5 Section 15.3.4.5, step
* 2 will throw a TypeError if IsCallable(func) is false.
*/
function indirectIsCallable(x) {
Function.prototype.bind.call(x);
}
/*===
TypeError
TypeError
TypeError
TypeError
TypeError
TypeError
TypeError
TypeError
no error
no error
no error
===*/
var values = [ undefined, null, true, false, 123.0, "foo",
{}, [], function () {}, Object.prototype.toLocaleString,
Object.prototype.toLocaleString.bind('foo') ];
var i;
for (i = 0; i < values.length; i++) {
try {
indirectIsCallable(values[i]);
print('no error');
} catch (e) {
print(e.name);
}
}

271
testcases/test-conv-samevalue.js

@ -0,0 +1,271 @@
/*
* SameValue() (E5 Section 9.12).
*
* SameValue() is difficult to test indirectly. It appears in E5 Section
* 8.12.9, [[DefineOwnProperty]] several times.
*
* One relatively simple approach is to create a non-configurable, non-writable
* property, and attempt to use Object.defineProperty() to set a new value for
* the property. If SameValue(oldValue,newValue), no exception is thrown.
* Otherwise, reject (TypeError); see E5 Section 8.12.9, step 10.a.ii.1.
*/
function sameValue(x,y) {
var obj = {};
try {
Object.defineProperty(obj, 'test', {
writable: false,
enumerable: false,
configurable: false,
value: x
});
Object.defineProperty(obj, 'test', {
value: y
});
} catch (e) {
if (e.name === 'TypeError') {
return false;
} else {
throw e;
}
}
return true;
}
function test(x,y) {
print(sameValue(x,y));
}
/*===
test: different types, first undefined
false
false
false
false
false
false
===*/
/* Different types, first is undefined */
print('test: different types, first undefined')
test(undefined, null);
test(undefined, true);
test(undefined, false);
test(undefined, 123.0);
test(undefined, 'foo');
test(undefined, {});
/*===
test: different types, first null
false
false
false
false
false
false
===*/
/* Different types, first is null */
print('test: different types, first null')
test(null, undefined);
test(null, true);
test(null, false);
test(null, 123.0);
test(null, 'foo');
test(null, {});
/*===
test: different types, first boolean
false
false
false
false
false
false
false
false
false
false
===*/
/* Different types, first is boolean */
print('test: different types, first boolean')
test(true, undefined);
test(true, null);
test(true, 123.0);
test(true, 'foo');
test(true, {});
test(false, undefined);
test(false, null);
test(false, 123.0);
test(false, 'foo');
test(false, {});
/*===
test: different types, first number
false
false
false
false
false
false
===*/
/* Different types, first is number */
print('test: different types, first number')
test(123.0, undefined);
test(123.0, null);
test(123.0, true);
test(123.0, false);
test(123.0, 'foo');
test(123.0, {});
/*===
test: different types, first string
false
false
false
false
false
false
===*/
/* Different types, first is string */
print('test: different types, first string')
test('foo', undefined);
test('foo', null);
test('foo', true);
test('foo', false);
test('foo', 123.0);
test('foo', {});
/*===
test: different types, first object
false
false
false
false
false
false
===*/
/* Different types, first is object */
print('test: different types, first object')
test({}, undefined);
test({}, null);
test({}, true);
test({}, false);
test({}, 123.0);
test({}, 'foo');
/*===
test: same types, undefined
true
===*/
/* Same types: undefined */
print('test: same types, undefined')
test(undefined, undefined);
/*===
test: same types, null
true
===*/
/* Same types: null */
print('test: same types, null')
test(null, null);
/*===
test: same types, boolean
true
false
false
true
===*/
/* Same types: boolean */
print('test: same types, boolean')
test(true, true);
test(true, false);
test(false, true);
test(false, false);
/*===
test: same types, number
true
true
false
false
true
true
false
false
true
true
true
===*/
/* Same types: number */
print('test: same types, number')
test(NaN, NaN);
test(-0, -0);
test(-0, +0);
test(+0, -0);
test(+0, +0);
test(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY);
test(Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY);
test(Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY);
test(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY);
test(-123.0, -123.0);
test(123.0, 123.0);
/*===
test: same types, string
true
false
false
true
===*/
/* Same types: string */
print('test: same types, string')
test('', '');
test('foo', '')
test('', 'foo');
test('foo', 'foo');
/*===
test: same types, object
true
false
false
true
===*/
/* Same types: object */
var obj1 = {};
var obj2 = {};
print('test: same types, object')
test(obj1, obj1);
test(obj1, obj2);
test(obj2, obj1);
test(obj2, obj2);

51
testcases/test-conv-toboolean.js

@ -0,0 +1,51 @@
/*
* ToBoolean() (E5 Section 9.2).
*/
function test(values) {
for (var i = 0; i < values.length; i++) {
/* Two logical NOTs is basically ToBoolean() */
print(!!values[i]);
}
}
/*===
false
false
true
false
===*/
test([ undefined, null, true, false ]);
/*===
false
false
false
true
true
true
true
===*/
test([ +0, -0, Number.NaN ]);
test([ 123.0, -123.0, Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY ]);
/*===
false
true
true
===*/
test([ "", "nonempty", "0" ]);
/*===
true
true
true
true
true
===*/
test([ {}, [], function() {}, Number.prototype.toString, Number.prototype.toString.bind('foo') ])

140
testcases/test-conv-toint32.js

@ -0,0 +1,140 @@
/*
* ToInt32() (E5 Section 9.5).
*
* Indirect testing using '<<' (E5 Section 11.7.1): "x << 0" is equivalent
* to ToInt32(). ToInt32() first coerces with ToNumber(), so that is noted
* in the cases.
*/
function toint32(x) {
return x << 0;
}
function zeroSign(x) {
if (x !== 0) {
return 'nz';
}
if (1 / x > 0) {
return 'pos';
} else {
return 'neg';
}
}
function test(x) {
var t = toint32(x);
print(t, zeroSign(t));
}
/*===
0 pos
===*/
// ToNumber(undefined) -> NaN -> +0
test(undefined);
/*===
0 pos
===*/
// ToNumber(null) -> +0 -> +0
test(null);
/*===
1 nz
0 pos
===*/
// ToNumber(true) -> 1 -> 1
test(true);
// Tonumber(false) -> +0 -> +0
test(false);
/*===
0 pos
0 pos
0 pos
0 pos
0 pos
===*/
// ToNumber(NaN) -> NaN -> +0
test(NaN);
// ToNumber(+0) -> +0 -> +0
test(+0);
// ToNumber(-0) -> -0 -> +0
test(-0);
// ToNumber(+Infinity) -> +Infinity -> +0
test(Number.POSITIVE_INFINITY);
// ToNumber(-Infinity) -> -Infinity -> +0
test(Number.NEGATIVE_INFINITY);
/*===
123 nz
-123 nz
0 pos
0 pos
0 pos
0 pos
0 pos
0 pos
0 pos
1410065408 nz
===*/
/* ToNumber() string coercion, E5 Section 9.3.1 */
test("123");
test("-123");
test("+0");
test("-0");
test("Infinity");
test("+Infinity");
test("-Infinity");
test("NaN"); // "NaN" does not parse -> results in NaN number -> +0
test("NaY"); // same case
test("1e10"); // larger than 32-bit, fits in 53 bits of double
/* FIXME: object coercion */
/*===
0 pos
1 nz
-1 nz
2 nz
-1 nz
0 pos
2 nz
===*/
/* A couple of modulo tests */
test(4294967296);
test(4294967297);
test(-1);
test(-4294967294); // +2
test(9007199254740991); // (2^53 - 1) % (2^32) --> 4294967295 --> -1
test(9007199254740992); // (2^53) % (2^32) --> 0
test(9007199254740994); // (2^53 + 2) % (2^32) --> 2 (Note: 2^53+1 not representable)
/*===
3 nz
-3 nz
===*/
/* Rounding
*
* Positive numbers: x -> floor(x) e.g. 3.4 -> 3
* Negative numbers: -x -> -floor(x) e.g. -3.4 -> -3 (not -4)
*/
test(3.4); // -> 3 -> 3
test(-3.4); // -> -3 -> -3

12
testcases/test-conv-tointeger.js

@ -0,0 +1,12 @@
/*
* ToInteger() (E5 Section 9.4).
*/
/*---
{
"skip": true
}
---*/
/* FIXME */

84
testcases/test-conv-tonumber.js

@ -0,0 +1,84 @@
/*
* ToNumber() (E5 Section 9.3).
*
* Postfix increment changes its LHS, put returns ToNumber(oldValue) as the
* expression value. Use this get ToNumber() indirectly.
*/
function tonumber(x) {
var tmp = x;
return tmp++;
}
function zeroSign(x) {
if (x !== 0) {
return 'nz';
}
if (1 / x > 0) {
return 'pos';
} else {
return 'neg';
}
}
function test(x) {
var num = tonumber(x);
print(num, zeroSign(num));
}
/*===
NaN nz
0 pos
1 nz
0 pos
-1 nz
0 neg
0 pos
1 nz
NaN nz
Infinity nz
-Infinity nz
===*/
test(undefined);
test(null);
test(true);
test(false);
test(-1);
test(-0);
test(+0);
test(1);
test(NaN);
test(Number.POSITIVE_INFINITY);
test(Number.NEGATIVE_INFINITY);
/*===
-1 nz
0 neg
0 pos
0 pos
1 nz
-Infinity nz
Infinity nz
Infinity nz
3735928559 nz
===*/
/* String to number */
test("-1");
test("-0");
test("+0");
test("0");
test("1");
test("-Infinity");
test("+Infinity");
test("Infinity");
test("0xdeadbeef");
/* FIXME: octal */
/* FIXME: object coercion */

12
testcases/test-conv-toobject.js

@ -0,0 +1,12 @@
/*
* ToObject() (E5 Section 9.9).
*/
/*---
{
"skip": true
}
---*/
/* FIXME */

12
testcases/test-conv-toprimitive.js

@ -0,0 +1,12 @@
/*
* ToPrimitive() (E5 Section 9.1).
*/
/*---
{
"skip": true
}
---*/
/* FIXME */

12
testcases/test-conv-tostring.js

@ -0,0 +1,12 @@
/*
* ToString() (E5 Section 9.8).
*/
/*---
{
"skip": true
}
---*/
/* FIXME */

141
testcases/test-conv-touint16.js

@ -0,0 +1,141 @@
/*
* ToUint16() (E5 Section 9.7).
*
* Indirect testing using String.fromCharCode() (which seems to be the
* only caller for this internal coercion!). ToUint16() first coerces
* with ToNumber(), so that is noted in the cases.
*/
function touint16(x) {
var str = String.fromCharCode(x); // Coerce with ToUint16 (E5 Section 15.5.3.2)
return str.charCodeAt(0); // Read back
}
function zeroSign(x) {
if (x !== 0) {
return 'nz';
}
if (1 / x > 0) {
return 'pos';
} else {
return 'neg';
}
}
function test(x) {
var t = touint16(x);
print(t, zeroSign(t));
}
/*===
0 pos
===*/
// ToNumber(undefined) -> NaN -> +0
test(undefined);
/*===
0 pos
===*/
// ToNumber(null) -> +0 -> +0
test(null);
/*===
1 nz
0 pos
===*/
// ToNumber(true) -> 1 -> 1
test(true);
// Tonumber(false) -> +0 -> +0
test(false);
/*===
0 pos
0 pos
0 pos
0 pos
0 pos
===*/
// ToNumber(NaN) -> NaN -> +0
test(NaN);
// ToNumber(+0) -> +0 -> +0
test(+0);
// ToNumber(-0) -> -0 -> +0
test(-0);
// ToNumber(+Infinity) -> +Infinity -> +0
test(Number.POSITIVE_INFINITY);
// ToNumber(-Infinity) -> -Infinity -> +0
test(Number.NEGATIVE_INFINITY);
/*===
123 nz
65413 nz
0 pos
0 pos
0 pos
0 pos
0 pos
0 pos
0 pos
58368 nz
===*/
/* ToNumber() string coercion, E5 Section 9.3.1 */
test("123");
test("-123");
test("+0");
test("-0");
test("Infinity");
test("+Infinity");
test("-Infinity");
test("NaN"); // "NaN" does not parse -> results in NaN number -> +0
test("NaY"); // same case
test("1e10"); // larger than 32-bit, fits in 53 bits of double
/* FIXME: object coercion */
/*===
0 pos
1 nz
65535 nz
2 nz
65535 nz
0 pos
2 nz
===*/
/* A couple of modulo tests */
test(4294967296);
test(4294967297);
test(-1); // --> 0xffffU
test(-4294967294); // +2
test(9007199254740991); // (2^53 - 1) % (2^32) --> 4294967295 --> 65535
test(9007199254740992); // (2^53) % (2^32) --> 0
test(9007199254740994); // (2^53 + 2) % (2^32) --> 2 (Note: 2^53+1 not representable)
/*===
3 nz
65533 nz
===*/
/* Rounding
*
* Positive numbers: x -> floor(x) e.g. 3.4 -> 3
* Negative numbers: -x -> -floor(x) e.g. -3.4 -> -3 (not -4)
*/
test(3.4); // -> 3 -> 3
test(-3.4); // -> -3 -> (2^32) - 3

140
testcases/test-conv-touint32.js

@ -0,0 +1,140 @@
/*
* ToUint32() (E5 Section 9.6).
*
* Indirect testing using '>>>' (E5 Section 11.7.3): "x >>> 0" is equivalent
* to ToUint32(x). ToUint32() first coerces with ToNumber(), so that is noted
* in the cases.
*/
function touint32(x) {
return x >>> 0;
}
function zeroSign(x) {
if (x !== 0) {
return 'nz';
}
if (1 / x > 0) {
return 'pos';
} else {
return 'neg';
}
}
function test(x) {
var t = touint32(x);
print(t, zeroSign(t));
}
/*===
0 pos
===*/
// ToNumber(undefined) -> NaN -> +0
test(undefined);
/*===
0 pos
===*/
// ToNumber(null) -> +0 -> +0
test(null);
/*===
1 nz
0 pos
===*/
// ToNumber(true) -> 1 -> 1
test(true);
// Tonumber(false) -> +0 -> +0
test(false);
/*===
0 pos
0 pos
0 pos
0 pos
0 pos
===*/
// ToNumber(NaN) -> NaN -> +0
test(NaN);
// ToNumber(+0) -> +0 -> +0
test(+0);
// ToNumber(-0) -> -0 -> +0
test(-0);
// ToNumber(+Infinity) -> +Infinity -> +0
test(Number.POSITIVE_INFINITY);
// ToNumber(-Infinity) -> -Infinity -> +0
test(Number.NEGATIVE_INFINITY);
/*===
123 nz
4294967173 nz
0 pos
0 pos
0 pos
0 pos
0 pos
0 pos
0 pos
1410065408 nz
===*/
/* ToNumber() string coercion, E5 Section 9.3.1 */
test("123");
test("-123");
test("+0");
test("-0");
test("Infinity");
test("+Infinity");
test("-Infinity");
test("NaN"); // "NaN" does not parse -> results in NaN number -> +0
test("NaY"); // same case
test("1e10"); // larger than 32-bit, fits in 53 bits of double
/* FIXME: object coercion */
/*===
0 pos
1 nz
4294967295 nz
2 nz
4294967295 nz
0 pos
2 nz
===*/
/* A couple of modulo tests */
test(4294967296);
test(4294967297);
test(-1); // --> 0xffffffffU
test(-4294967294); // +2
test(9007199254740991); // (2^53 - 1) % (2^32) --> 4294967295
test(9007199254740992); // (2^53) % (2^32) --> 0
test(9007199254740994); // (2^53 + 2) % (2^32) --> 2 (Note: 2^53+1 not representable)
/*===
3 nz
4294967293 nz
===*/
/* Rounding
*
* Positive numbers: x -> floor(x) e.g. 3.4 -> 3
* Negative numbers: -x -> -floor(x) e.g. -3.4 -> -3 (not -4)
*/
test(3.4); // -> 3 -> 3
test(-3.4); // -> -3 -> (2^32) - 3

11
testcases/test-dev-add-prec.js

@ -0,0 +1,11 @@
/*
* Addition precedence test.
*/
/*===
3foo34
===*/
/* This is equivalent to: (((1 + 2) + 'foo') + 3) + 4 === "3foo34" */
print(1 + 2 + 'foo' + 3 + 4);

63
testcases/test-dev-arguments-binding.js

@ -0,0 +1,63 @@
/*
* Some 'arguments' binding tests
*/
/*===
object
number
object
false
object
===*/
/* A non-strict 'arguments' binding is writable but not deletable. */
function arguments_write() {
print(typeof arguments);
arguments = 1;
print(typeof arguments);
}
function arguments_delete() {
print(typeof arguments);
print(delete arguments);
print(typeof arguments);
}
try {
arguments_write();
} catch (e) {
print(e.name);
}
try {
arguments_delete();
} catch (e) {
print(e.name);
}
/*===
SyntaxError
SyntaxError
===*/
/* A strict 'arguments' binding is immutable. It cannot be deleted nor can
* it be assigned to; doing so would be a SyntaxError.
*
* XXX: how to test that the binding is actually immutable, as it is a
* SyntaxError trying to delete it or assign to it? Even an eval() call
* does not work: the eval will be parsed in strict mode too.
*/
try {
eval("function arguments_strict_delete() { 'use strict'; delete arguments; }");
} catch (e) {
print(e.name);
}
try {
eval("function arguments_strict_delete() { 'use strict'; arguments = 1; }");
} catch (e) {
print(e.name);
}

65
testcases/test-dev-array-literal.js

@ -0,0 +1,65 @@
/*===
0
undefined
1
1
undefined
2
1
2
undefined
===*/
print([].length);
print([][0]);
print([1].length);
print([1][0]);
print([1][1]);
print([1,2].length);
print([1,2][0]);
print([1,2][1]);
print([1,2][2]);
/*===
11
20
===*/
/* two sets of MPUTARR */
print([1,2,3,4,5,6,7,8,9,10,11].length); /* 10 + 1 */
print([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20].length); /* 10 + 10 */
/*===
0
1
1
1
2
2
2
3
===*/
/* elisions */
print([].length);
print([,].length); /* here, even one comma has an effect */
print([1].length);
print([1,].length); /* here, one additional comma has no effect */
print([1,,].length); /* but two do */
print([1,2].length);
print([1,2,].length); /* quite confusingly, one additional comma has no effect */
print([1,2,,].length); /* but two do */
/*===
2
===*/
/* regexp values */
print([/foo/,/bar/].length);

34
testcases/test-dev-array-property-attrs.js

@ -0,0 +1,34 @@
/*
* Property attributes of array entries. Also tests the properties with
* and without an internal "array part".
*/
function printDesc(desc) {
print(desc.writable, desc.enumerable, desc.configurable);
}
/*===
true true true
true true true
true true true
true true true
true true true
true true true
true true true
===*/
/* array is initially dense (array part exists) */
a = [1,2,3];
printDesc(Object.getOwnPropertyDescriptor(a, '0'));
printDesc(Object.getOwnPropertyDescriptor(a, '1'));
printDesc(Object.getOwnPropertyDescriptor(a, '2'));
/* force array to be sparse (array part is abandoned) */
a[10000] = 4;
printDesc(Object.getOwnPropertyDescriptor(a, '0'));
printDesc(Object.getOwnPropertyDescriptor(a, '1'));
printDesc(Object.getOwnPropertyDescriptor(a, '2'));
printDesc(Object.getOwnPropertyDescriptor(a, '10000'));

17
testcases/test-dev-assign-lhs.js

@ -0,0 +1,17 @@
/*===
ReferenceError
===*/
/* Valid LeftHandSideExpression which is invalid for assignment
* is a run-time ReferenceError, not a SyntaxError. E5 allows
* a LHS Reference to be returned from a function, although it
* provides no standard way of doing so.
*/
try {
eval("f() = 1");
} catch (e) {
print(e.name);
}

33
testcases/test-dev-assign-trivial-loop.js

@ -0,0 +1,33 @@
/*===
10
9
8
7
6
5
4
3
2
1
10
9
8
7
6
5
4
3
2
1
===*/
/* Simple tests for assignment */
for (i = 10; i; i -= 1) {
print(i);
}
for (i = 10; i; i = i - 1) {
print(i);
}

26
testcases/test-dev-bitops.js

@ -0,0 +1,26 @@
/*
* Bit op tests.
*/
/* FIXME: incomplete */
/* FIXME: precedence tests, associativity tests */
/* FIXME: ranges, coercion, etc */
/*===
64
===*/
print(255 & 64);
/*===
192
===*/
print(128 | 64);
/*===
191
===*/
print(255 ^ 64);

34
testcases/test-dev-bnot.js

@ -0,0 +1,34 @@
/* FIXME: missing a lot of coercion cases */
/*===
-124
123
-1410065409
1410065408
===*/
print(~123);
print(~~123);
print(~1e10);
print(~~1e10);
/*===
-124
123
-2
1
===*/
/* Ensure that target is not modified (this would happen if expression is
* not allocated a real temporary register but operates directly on a register
* bound value).
*/
var x = 123;
print(~x);
print(x);
var obj = {x:1};
print(~obj.x);
print(obj.x);

34
testcases/test-dev-bug-autosemi-1.js

@ -0,0 +1,34 @@
/*===
10 20
-> 10 21
-> 11 21
===*/
/* Broken at some point. */
var x = 10;
var y = 20;
function f_postinc() {
print(x, y);
// interpreted as "x; ++y;"
x
++y
print('->', x, y);
// interpreted as "x++; y;"
x++
y
print('->', x, y);
}
try {
f_postinc();
} catch (e) {
print(e.name);
}

48
testcases/test-dev-bug-catch-binding.js

@ -0,0 +1,48 @@
/*===
throw
throw
throw
===*/
/* This was broken at an early point: the compiler would use a function-wide
* register binding for 'e' and look up the argument / variable declaration
* instead of the (dynamic) catch binding.
*
* h() would actually work because 'with' turns off fast path identifier
* lookups for its duration.
*/
function f(e) {
try {
throw 'throw';
} catch (e) {
print(e);
}
}
function g() {
var e = 'var';
try {
throw 'throw';
} catch (e) {
print(e);
}
}
function h() {
var e = 'var';
with ({}) {
try {
throw 'throw';
} catch (e) {
print(e);
}
}
}
f('arg');
g();
h();

22
testcases/test-dev-bug-chain-call.js

@ -0,0 +1,22 @@
/*===
3
===*/
var tmp = String.fromCharCode(3.4);
print(tmp.charCodeAt(0));
/*===
3
===*/
print(String.fromCharCode(3.4).charCodeAt(0));
/*===
3
===*/
/* This was broken at some point, and printed "3.4" */
function f(x) { return String.fromCharCode(x).charCodeAt(0); }
print(f(3.4));

17
testcases/test-dev-bug-closure-outer.js

@ -0,0 +1,17 @@
/*===
y 2
x 1
===*/
/* This had a bug at some point. */
function f(x) {
return function(y) {
print('y', y);
print('x', x);
}
}
f(1)(2);

18
testcases/test-dev-bug-finalizer-rescue.js

@ -0,0 +1,18 @@
/*===
finalizer
object
finalizer
object
===*/
a={};
// The finalizer rescues the reference (= makes it reachable again)
__duk__.setFinalizer(a, function(x) { print('finalizer'); a=x });
a = null;
print(typeof a);
a = null;
print(typeof a);

41
testcases/test-dev-bug-for-in-bound-var.js

@ -0,0 +1,41 @@
/*===
0 foo
1 bar
0 foo
1 bar
0 foo
1 bar
===*/
/* g() used to be broken: local_iter would not get assigned to as a
* left-hand side if it was a register-bound variable.
*/
var arr = ['foo', 'bar'];
function f() {
for (global_iter in arr) {
print(global_iter, arr[global_iter]);
}
}
function g() {
var local_iter;
for (local_iter in arr) {
print(local_iter, arr[local_iter]);
}
}
function h() {
for (var local_iter in arr) {
print(local_iter, arr[local_iter]);
}
}
f();
g();
h();

21
testcases/test-dev-bug-for-var-in.js

@ -0,0 +1,21 @@
/*===
0
1
2
0
1
2
===*/
/* Latter variant was broken at some point */
var test = 'Foo';
for (i in test) {
print(i)
}
for (var i in test) {
print(i)
}

26
testcases/test-dev-bug-formal-implements.js

@ -0,0 +1,26 @@
/*===
SyntaxError
===*/
/* This was broken at some point: formal argument list is parsed in
* non-strict mode so 'implements' is allowed. When function is
* detected to be strict, the argument list needs to be rechecked
* to ensure that there are no reserved words which are recognized
* only in strict mode.
*
* This is not actually clear cut in the specification, but this
* behavior follows e.g. V8.
*/
try {
// FutureReservedWord only recognized in strict mode,
// function declared in non-strict mode but function
// itself is strict
eval("function foo(implements) { 'use strict'; };");
print('never here');
} catch (e) {
print(e.name);
}

25
testcases/test-dev-bug-func-closure-fnum.js

@ -0,0 +1,25 @@
/*===
foo,foo
===*/
/* This used to have a bug: closure numbers would get incorrectly used. */
function F() {
this.values = [];
}
F.prototype.f = function() {
this.values[this.values.length] = 'foo';
}
F.prototype.g = function() {
this.values[this.values.length] = 'bar';
}
function test() {
var obj = new F();
obj.f();
obj.f();
print(obj.values);
}
test();

33
testcases/test-dev-bug-func-redecl.js

@ -0,0 +1,33 @@
/*
* Broken at some point; regression test.
*/
/*===
redecl
===*/
function foo(x,y) {
print(x,y);
}
function foo(x,y) {
print('redecl');
}
foo(1,2);
/*===
second 1 2
===*/
/* Shadowing declarations inside a function (register bound) */
function functest() {
function foo(x,y) { print('first',x,y); }
function foo(x,y) { print('second',x,y); }
foo(1,2);
}
functest();

44
testcases/test-dev-bug-lex-regexp-1.js

@ -0,0 +1,44 @@
/*===
62
===*/
/* This parsed incorrectly at one point, the slash was parsed as
* part of a RegExp leading to SyntaxError.
*/
var obj, val;
try {
eval("obj = { foo: 124 };");
eval("val = obj['foo']/2;");
eval("print(val)");
} catch (e) {
print(e.name);
}
/*===
50
===*/
/* Similar test for parens */
try {
print(eval("(50+50)/2"));
} catch (e) {
print(e.name);
}
/*===
NaN
===*/
/* Similar test for braces (this doesn't evaluate to anything useful
* but is not a SyntaxError.
*/
try {
print(eval("({foo:1}/2)"));
} catch (e) {
print(e.name);
}

17
testcases/test-dev-bug-ret-call.js

@ -0,0 +1,17 @@
/*===
A
===*/
/* This was broken at some point, returning 65 (argument) instead of
* desired value, string "A".
*/
function f(x) {
return String.fromCharCode(x);
}
try {
print(f(65));
} catch (e) {
print(e.name);
}

12
testcases/test-dev-bug-str-constructor-noarg.js

@ -0,0 +1,12 @@
/*===
undefined
undefined
===*/
print(String()); // required to result in empty string: ""
print(String(undefined)); // required to result in "undefined"
print(new String().toString()); // required to result in empty string: ""
print(new String(undefined).toString()); // required to result in "undefined"

16
testcases/test-dev-bug-typeof-unref.js

@ -0,0 +1,16 @@
/*===
undefined
===*/
/* 'x' does not resolve, should not cause a ReferenceError but
* an "undefined" typeof. E5 Section 11.4.3, step 2.a.
*
* This was broken at some point.
*/
try {
print(typeof x);
} catch (e) {
print(e.name);
}

42
testcases/test-dev-bug-yield-after-callapply.js

@ -0,0 +1,42 @@
var thread;
var res;
/*===
123
===*/
/* Calling via Function.prototype.call() or Function.prototype.apply() would
* prevent a yield().
*/
function innerfunc() {
__duk__.yield(123);
}
function coroutine1() {
// This is a native call so naive handling would prevent a later yield
innerfunc.call();
}
function coroutine2() {
// Same here
innerfunc.apply();
}
try {
thread = __duk__.spawn(coroutine1);
res = __duk__.resume(thread, 0);
print(res);
} catch (e) {
print(e.name);
}
try {
thread = __duk__.spawn(coroutine2);
res = __duk__.resume(thread, 0);
print(res);
} catch (e) {
print(e.name);
}

64
testcases/test-dev-call-chained.js

@ -0,0 +1,64 @@
/*
* Production for:
*
* f(1).g(2);
*
* comes from:
*
* LeftHandSideExpression -> CallExpression
* -> CallExpression Arguments
* -> (CallExpression . IdentifierName) Arguments
* -> ((MemberExpression Arguments) . IdentifierName) Arguments
* -> ((PrimaryExpression Arguments) . IdentifierName) Arguments
* -> ((Identifer Arguments) . IdentifierName) Arguments
*
* So, the original expression is equivalent to:
*
* (f(1)).g(2);
*
* Note that the first name is an Identifier, i.e. does not allow reserved words.
* However, the latter is not, so this is valid:
*
* foo(1).if(2)
*/
/*===
f 1
g 2
f 1
g 2
f 3
g 4
===*/
function f(x) {
print('f', x);
return {
"g": function(y) {
print('g', y);
}
}
}
function z(x, y) {
f(x).g(y);
}
try {
f(1).g(2);
} catch (e) {
print(e.name);
}
try {
(f(1)).g(2);
} catch (e) {
print(e.name);
}
try {
z(3, 4);
} catch (e) {
print(e.name);
}

12
testcases/test-dev-call-expr.js

@ -0,0 +1,12 @@
/*
* CallExpression tests
*/
/*---
{
"skip": true
}
---*/
/* FIXME: expressions like: foo()() and foo().bar() etc */

24
testcases/test-dev-call-through-this.js

@ -0,0 +1,24 @@
/*===
g this.name: myThis
f this.name: myThis
===*/
/* Ensure that calling through 'this' preserves this binding. */
function f() {
print('f this.name:', this.name);
}
function g() {
print('g this.name:', this.name);
this.f();
}
var myThis = {
name: 'myThis',
f: f
};
g.call(myThis);

21
testcases/test-dev-catch-binding.js

@ -0,0 +1,21 @@
/*===
123
foo
123
===*/
function foo(e) {
print(e);
try {
throw 'foo'
} catch (e) {
print(e);
}
print(e);
}
foo(123);

42
testcases/test-dev-chaos.js

File diff suppressed because one or more lines are too long

35
testcases/test-dev-comma.js

@ -0,0 +1,35 @@
var t;
/*===
1 2 3
3
===*/
print(1,2,3)
print((1,2,3))
/*===
foo
bar
undefined
foo
bar
3
===*/
/* This parses as: (t = print('foo')), (print('bar')), (1+2);
* So 't' gets return value of print('foo') = undefined.
*/
t = print('foo'), print('bar'), 1 + 2;
print(t);
t = (print('foo'), print('bar'), 1 + 2);
print(t);
/*===
3
===*/
t = eval("1, 2, 3");
print(t);

107
testcases/test-dev-compiler-recursion.js

@ -0,0 +1,107 @@
/*
* Tests on compiler recursion limits.
*/
/* FIXME: any other recursion points?
*
* Object and array literals?
*/
var t;
/*===
1
Error
===*/
/* Parenthesis; expression recursion */
function buildParenExpr(count) {
var t = '1';
var i;
for (i = 0; i < count; i++) {
t = '(' + t + ')';
}
return t;
}
try {
/* a reasonable nest count should of course compile */
print(eval(buildParenExpr(50)));
} catch (e) {
print(e.name);
}
try {
/* an internal error without other trouble should happen */
print(eval(buildParenExpr(1000)));
} catch (e) {
print(e.name);
}
/*===
innermost block
Error
===*/
/* Statement recursion */
function buildBlockExpr(count) {
var t = "'innermost block';"; // implicit return value
var i;
for (i = 0; i < count; i++) {
t = "if (true) { " + t + "}";
}
return t;
}
try {
// reasonable count
print(eval(buildBlockExpr(50)));
} catch (e) {
print(e.name);
}
try {
print(eval(buildBlockExpr(1000)));
} catch (e) {
print(e.name);
}
/*===
innermost func
Error
===*/
/* Function recursion */
function buildFuncExpr(count) {
var t = "(function(){ print('innermost func'); })";
var i;
for (i = 0; i < count; i++) {
// t: function expression (not called)
t = "(function(){" + t + "()" + "})";
}
t = t + "()"; // call the outermost
return t;
}
try {
// reasonable
eval(buildFuncExpr(50));
} catch (e) {
print(e.name);
}
try {
eval(buildFuncExpr(1000));
} catch (e) {
print(e.name);
}

100
testcases/test-dev-conditional.js

@ -0,0 +1,100 @@
/*===
1
2
===*/
try {
eval("print(true ? 1 : 2);");
} catch (e) {
print(e.name);
}
try {
eval("print(false ? 1 : 2);");
} catch (e) {
print(e.name);
}
/*===
SyntaxError
1 3
===*/
/* In "A ? B : C" both B and C are AssignmentExpressions, and
* do not allow the comma operator.
*
* In the case of "true ? 1,2 : 3" there is no way to match
* "1,2" against an AssignmentExpression, so a SyntaxError.
*
* In the case of "true ? 1 : 2,3" the ConditionalExpression
* will match "true ? 1 : 2" and there will be a surrounding
* comma expression, i.e.: "(true ? 1 : 2), 3".
*/
try {
eval("print(true ? 1,2 : 3);");
} catch (e) {
print(e.name);
}
try {
eval("print(true ? 1 : 2,3);");
} catch (e) {
print(e.name);
}
/*===
1 4
===*/
/* Here comma works as a normal argument separator. */
try {
eval("print(true ? 1 : 2, false ? 3 : 4);");
} catch (e) {
print(e.name);
}
/*===
C
D
F
G
===*/
/*
* The following:
*
* A ? B ? C : D : E ? F : G
*
* parses as:
*
* A ? (B ? C : D) : (E ? F : G)
*/
try {
eval("print(true ? true ? 'C' : 'D' : true ? 'F' : 'G');");
} catch (e) {
print(e.name);
}
try {
eval("print(true ? false ? 'C' : 'D' : true ? 'F' : 'G');");
} catch (e) {
print(e.name);
}
try {
eval("print(false ? true ? 'C' : 'D' : true ? 'F' : 'G');");
} catch (e) {
print(e.name);
}
try {
eval("print(false ? true ? 'C' : 'D' : false ? 'F' : 'G');");
} catch (e) {
print(e.name);
}

12
testcases/test-dev-cont-callstack.js

@ -0,0 +1,12 @@
/*
* Test that we can continue after a callstack limit error.
*/
/*---
{
"skip": true
}
---*/
/*FIXME*/

60
testcases/test-dev-cont-catchstack.js

@ -0,0 +1,60 @@
/*
* Test that we can continue after a catchstack limit error.
*/
/*===
Error
true
===*/
/* The current limits for callstack and catchstack are the same
* (10000), so a recursive call with more than one catcher should
* ensure that the catchstack is exhausted first.
*
* This only works (= hits catchstack limit) if valstack limit is
* significantly higher (currently 100000).
*/
function f1() {
try {
try {
try {
try {
f1();
} finally {
}
} finally {
}
} finally {
}
} finally {
}
}
try {
f1();
} catch (e) {
print(e.name);
// ensure that it is indeed the catchstack which failed; Rhino and V8
// will fail this test of course
print(/catch/i.test(e.message));
}
/*===
6765
===*
/* Test that we can continue normally. Just a simple recursive call test here. */
function fib(x) {
if (x == 0) { return 0; }
if (x == 1) { return 1; }
return fib(x - 1) + fib(x - 2);
}
try {
print(fib(20));
} catch (e) {
print(e.name);
}

12
testcases/test-dev-cont-valstack.js

@ -0,0 +1,12 @@
/*
* Test that we can continue after a valstack limit error.
*/
/*---
{
"skip": true
}
---*/
/*FIXME*/

40
testcases/test-dev-coroutine-basic.js

@ -0,0 +1,40 @@
/*===
resume tests
yielder starting
yielder arg: foo
yielded with 1
resumed with bar
yielded with 2
resumed with quux
yielded with 3
resumed with baz
yielder ending
yielded with 123
finished
===*/
function yielder(x) {
var yield = __duk__.yield;
print('yielder starting');
print('yielder arg:', x);
print('resumed with', yield(1));
print('resumed with', yield(2));
print('resumed with', yield(3));
print('yielder ending');
return 123;
}
var t = __duk__.spawn(yielder);
print('resume tests');
print('yielded with', __duk__.resume(t, 'foo'));
print('yielded with', __duk__.resume(t, 'bar'));
print('yielded with', __duk__.resume(t, 'quux'));
print('yielded with', __duk__.resume(t, 'baz'));
print('finished');

123
testcases/test-dev-ctrl-breakcont.js

@ -0,0 +1,123 @@
/*
* Some test cases for label matching cases.
*
* Especially, test 'continue' through a switch.
*/
/*===
before break
after do
before continue
after do
===*/
/* fast break (handled with a JUMP) */
try {
do {
print("before break");
break;
print("after break");
} while(0);
print("after do");
} catch (e) {
print(e.name);
}
try {
done = 0;
do {
if (done) {
break;
}
print("before continue");
done = 1;
continue;
print("after continue");
} while(0);
print("after do");
} catch (e) {
print(e.name);
}
/*===
break caught by finally
broke out
continue caught by finally
broke out
===*/
/* slow break across a try-catch boundary, handled with BREAK */
try {
do {
try {
break;
} finally {
print("break caught by finally"); // caught, but rethrown
}
} while(true);
print("broke out");
} catch (e) {
print(e.name);
}
/* slow continue across a try-catch boundary, handled with CONTINUE */
try {
done = 0;
do {
if (done) {
break;
}
try {
done = 1;
continue;
} finally {
print("continue caught by finally"); // caught, but rethrown
}
} while(true);
print("broke out");
} catch (e) {
print(e.name);
}
/*===
===*/
/* FIXME: same tests for 'with' */
/*===
3
2
1
loop done
===*/
/* A continue with an empty label from inside a switch should bypass the
* switch statement (which registers no empty label for 'continue') and
* may match an empty label outside the switch.
*/
try {
count = 3;
do {
print(count);
count -= 1;
if (count == 0) {
break;
}
switch(1) {
case 1:
// this continue should go to top of the do-loop
continue;
}
print("never here");
} while(true);
print("loop done");
} catch (e) {
print(e.name);
}

22
testcases/test-dev-ctrl-trycatch-binding.js

@ -0,0 +1,22 @@
/*===
foo
bar
foo
===*/
try {
throw 'foo';
} catch (e) {
print(e);
try {
throw 'bar';
} catch (e) {
/* new, shadowing lex env here */
print(e);
/* old lex env restored before inner try completes */
}
print(e);
}

11
testcases/test-dev-ctrl-with-binding.js

@ -0,0 +1,11 @@
/*===
Infinity
===*/
with (Number) {
/* binds to Number.POSITIVE_INFINITY */
print(POSITIVE_INFINITY);
}
/* FIXME: more tests */

25
testcases/test-dev-dangling-else.js

@ -0,0 +1,25 @@
/*===
d
c
b
a
===*/
function f(a,b,c) {
if (a) {
print('a');
} else if (b) {
print('b');
} else if (c) {
print('c');
} else {
print('d');
}
}
f(false, false, false);
f(false, false, true);
f(false, true, false);
f(true, false, false);

186
testcases/test-dev-declbinding.js

@ -0,0 +1,186 @@
/*
* Tests for declaration binding instantiation (E5 Section 10.5).
*/
/*===
1
false
1
SyntaxError
1
false
1
SyntaxError
function
false
function
SyntaxError
===*/
/* Argument, function declaration, and variable bindings are
* non-configurable (non-deletable) in function code.
*/
try {
// binding not deletable, 'delete a' returns false (E5 Section 10.2.1.1.5,
// step 3).
eval("function func_arg1(a) { print(a); print(delete a); print(a); }");
func_arg1(1);
} catch (e) {
print(e.name);
}
try {
// in strict mode, SyntaxError
eval("function func_arg2(a) { 'use strict'; print(a); print(delete a); print(a); }");
func_arg2(1);
} catch (e) {
print(e.name);
}
try {
eval("function func_var1() { var a = 1; print(a); print(delete a); print(a); }");
func_var1();
} catch (e) {
print(e.name);
}
try {
eval("function func_var2() { 'use strict'; var a = 1; print(a); print(delete a); print(a); }");
func_var2();
} catch (e) {
print(e.name);
}
try {
eval("function func_fun1() { function a() {}; print(typeof a); print(delete a); print(typeof a); }");
func_fun1();
} catch (e) {
print(e.name);
}
try {
eval("function func_fun2() { 'use strict'; function a() {}; print(typeof a); print(delete a); print(typeof a); }");
func_fun2();
} catch (e) {
print(e.name);
}
/*===
10
true
ReferenceError
function
true
undefined
===*/
/* Variable and function declarations established using a direct eval ARE deletable,
* even in function code.
*/
try {
eval("function func_var_eval1() { eval('var a = 10'); print(a); print(delete(a)); print(a); };");
func_var_eval1();
} catch (e) {
print(e.name);
}
try {
eval("function func_fun_eval1() { eval('function a() {}'); print(typeof a); print(delete(a)); print(typeof a); };");
func_fun_eval1();
} catch (e) {
print(e.name, e.message);
}
/*===
true
SyntaxError
===*/
/* Attempt to delete an unresolvable identifier reference returns true (!) in
* non-strict mode, and is a SyntaxError in strict mode.
*/
try {
eval("function func_unres1(a) { print(delete unresolvable); }");
func_unres1(1);
} catch (e) {
print(e.name);
}
try {
eval("function func_unres2(a) { 'use strict'; print(delete unresolvable); }");
func_unres2(1);
} catch (e) {
print(e.name);
}
/*===
ReferenceError
ReferenceError
object
===*/
/* Arguments binding should exist for functions, not for global/eval code.
*
* Note: 'node' has arguments bound in global code. Rhino also does.
*/
try {
// global
print(typeof arguments);
} catch (e) {
print(e.name);
}
try {
// eval embedded in global
print(eval("typeof arguments"));
} catch (e) {
print(e.name);
}
try {
// function
eval("function foo() { print(typeof arguments); }; foo();");
} catch (e) {
print(e.name);
}
/*===
object
number
SyntaxError
===*/
/* An arguments binding is mutable for non-strict code, immutable for strict code.
*
* Attempt to assign to arguments is a SyntaxError in strict code, so this is
* actually pretty difficult to test :-). Even direct eval in strict code
* creates a separate variable environment.
*/
function arguments_mutability1() {
print(typeof arguments);
arguments = 1;
print(typeof arguments);
}
try {
arguments_mutability1();
} catch (e) {
print(e.name);
}
try {
eval("function arguments_mutability2() {\n" +
" 'use strict';\n" +
" print(typeof arguments);\n" +
" arguments = 1;\n" +
" print(typeof arguments);\n" +
"}");
} catch (e) {
print(e.name);
}

149
testcases/test-dev-delete.js

@ -0,0 +1,149 @@
/* FIXME: deletion tests for unconfigurable bindings etc */
/*===
1 2
undefined 2
undefined undefined
===*/
var obj = {foo:1, bar:2};
print(obj.foo, obj.bar);
delete obj.foo;
print(obj.foo, obj.bar);
delete obj['bar'];
print(obj.foo, obj.bar);
/*===
true
false
false
true
===*/
/* Attempting to delete an unresolvable reference is 'true' in non-strict mode.
* Deleting a resolvable reference returns 'true' or 'false', depending on
* whether the target is deletable.
*/
this.deletable_ref = 1; /* configurable property in global object -> deletable */
try {
/* unresolvable (at run time) */
/* Note: Rhino will throw a TypeError:
* "js: uncaught JavaScript runtime exception: TypeError: Cannot delete property "foo" of null"
*
* V8 works correctly.
*/
print(delete foo);
} catch (e) {
print(e.name);
}
try {
/* resolvable, maps to global object, cannot be deleted */
print(delete NaN); /* this.NaN is a non-configurable property */
} catch (e) {
print(e.name);
}
try {
/* resolvable, a non-deletable variable binding, cannot be deleted */
eval("function f_vardel() { var x; print(delete x); }; f_vardel();");
} catch (e) {
print(e.name);
}
try {
/* resolvable, maps to global object, can be deleted */
print(delete deletable_ref);
} catch (e) {
print(e.name);
}
/*===
SyntaxError
SyntaxError
SyntaxError
SyntaxError
===*/
/* Attempting to delete an unresolvable reference or any identifier
* in strict mode is a compile-time SyntaxError.
*/
try {
eval("function f1(x) { 'use strict'; delete x; }; f1();");
} catch (e) {
print(e.name);
}
try {
eval("function f2() { 'use strict'; var x = 1; delete x; }; f2();");
} catch (e) {
print(e.name);
}
try {
eval("function f3() { 'use strict'; function x() {}; delete x; }; f3();");
} catch (e) {
print(e.name);
}
try {
// parseInt resides in the global object, which is bound to the global
// environment record
eval("function f4() { 'use strict'; delete parseInt; }; f4();");
} catch (e) {
print(e.name);
}
try {
} catch (e) {
print(e.name);
}
/*===
true
test
true
===*/
/* Deleting a non-reference is always 'true', even in strict mode. */
try {
print(delete 1);
} catch (e) {
print(e.name);
}
try {
print(delete print('test'));
} catch (e) {
print(e.name);
}
/*===
1
true
true
undefined
===*/
/* Parenthesis must not affect behavior */
obj = {foo:1};
try {
print(obj.foo);
print(delete ((obj['foo'])));
print(delete ((obj['bar']))); // undefined property -> 'true'
print(obj.foo);
} catch (e) {
print(e.name);
}

250
testcases/test-dev-direct-eval.js

@ -0,0 +1,250 @@
/*
* A bit messy direct eval tests.
*/
var global = this;
var orig_eval = eval;
/*===
false
"this" value
10
20
false
"this" value
20
20
5
===*/
/* Direct eval call needs to (1) be referenced with the name 'eval',
* and (2) bind to the original eval() function.
*
* It does NOT need to be bound through the original environment
* record, i.e. the global object. A local variable with the name
* 'eval' and which points to the built-in eval function is OK.
*/
var x = 5;
function f1() {
var x = 10;
// direct eval, non-strict eval code ->
// * this binding maintained
// * lexical/variable environment maintained
print(eval("this === global"));
print("" + eval("this"));
print(eval("x")); // binds to f1()'s var 'x'
eval("var x = 20"); // modifies f1()'s var 'x'
print(x);
// direct eval, strict eval code ->
// * this binding maintained
// * lexical/variable environment is a fresh one
print(eval("'use strict'; this === global"));
print("" + eval("'use strict'; this"));
print(eval("'use strict'; x")); // "bleeds out", matches f1()'x var 'x'
eval("'use strict'; var x = 30;"); // own env, no change to our 'x'
print(x);
}
try {
f1.call('"this" value');
print(x);
} catch (e) {
print(e.name);
}
/*===
true
Infinity
5
50
20
true
Infinity
15
50
20
15
20
===*/
function f2() {
var x = 50;
var indirect_eval = eval;
// indirect_eval("x") and indirect_eval("var x = 15") fails
// in V8 for some reason
// indirect eval call, non-strict eval code ->
// * this binding is global object
// * lexical/variable environment is the global object
print(indirect_eval("this === global"));
print(indirect_eval("this.Number.POSITIVE_INFINITY"));
print(indirect_eval("x")); // binds to global 'x'
indirect_eval("var x = 15"); // to global object
indirect_eval("var y = 20"); // to global object
print(x); // our 'x'
print(y); // still prints, bleeds to global object
// indirect eval call, strict eval code
// * this binding is global object
// * lexical/variable environment is a fresh one
print(indirect_eval("'use strict'; this === global"));
print(indirect_eval("'use strict'; this.Number.POSITIVE_INFINITY"));
print(indirect_eval("'use strict'; x")); // bleeds out, binds to global 'x'
indirect_eval("'use strict'; var x = 100"); // own copy
indirect_eval("'use strict'; var y = 200"); // own copy
print(x); // our 'x'
print(y); // still prints, bleeds to global object
}
try {
f2.call('"this" value');
print(x);
print(y);
} catch (e) {
print(e.name);
}
/*===
"this" value
===*/
/* Direct eval call through a local variable of name 'eval'.
* Note that we can't simply say 'var eval = eval' because
* that would ALWAYS assign undefined to 'eval' (variable
* declarations happen before any right-hand-sides are
* evaluated).
*/
function f3() {
var eval = orig_eval;
// this is a direct eval -> this binding should remain
print("" + eval('this'));
}
try {
f3.call('"this" value');
} catch (e) {
print(e.name);
}
/*===
false
fake eval
true
false
===*/
/* An illustration that a certain eval() call may change from a direct eval
* to an indirect one dynamically. There are other ways to get the same
* effect.
*
* The impact is that whenever a variable named 'eval' is encountered by
* the compiler, it must always generate slow path code for it. In
* particular, CSVAR must be used for call setup (not CSREG).
*/
var binding_obj = {};
function wrapper() {
var ret;
with (binding_obj) {
ret = function() {
// direct eval --> prints false
// indirect eval --> prints true
print(eval('this === global'));
}
}
return ret;
}
try {
var func = wrapper();
// initially, binding_obj has no 'eval' binding, hence direct eval
func();
// add 'intercepting' eval binding, hence indirect eval
binding_obj.eval = function(x) { print('fake eval'); return orig_eval(x); };
func();
// remove intercepting binding, again a direct eval
delete binding_obj.eval;
func();
} catch (e) {
print(e.name);
}
/*===
forced this
Infinity
Infinity
===*/
/* Is it a direct eval call if an "eval()" target is a bound function
* whose target function is the built-in eval?
*
* The answer in the spec is no: the result of GetValue() for "eval"
* must be the built-in eval function for the call to be considered
* direct.
*
* Check that we follow these semantics.
*/
var bound_eval = eval.bind('bound this'); // bind 'this' to 'bound this'
var indirect_eval = eval;
function bound1() {
// direct eval, this should bound to 'forced this'
print("" + eval("this"));
}
function bound2() {
// indirect eval through a bound function, this should be
// bound to the global object
print(bound_eval("this.Number.POSITIVE_INFINITY"));
}
function bound3() {
// indirect eval through a bound function, but eval code is
// strict; this should still be bound to the global object
print(bound_eval("'use strict'; this.Number.POSITIVE_INFINITY"));
}
try {
/* The 'this' binding for eval() itself (here, the string "bound this")
* should not really matter; the 'this' binding for the evaluated code
* should still be as specified in E5 Section 10.4.2.
*
* The initial [[Call]] would happen using semantics from E5 Section
* 15.3.4.5.1. That algorithm would [[Call]] the built-in eval
* function (E5 Section 10.4.2) which would ignore any 'this' binding.
*/
bound1.call('forced this');
} catch (e) {
print(e.name);
}
try {
bound2.call('forced this');
} catch (e) {
print(e.name);
}
try {
bound3.call('forced this');
} catch (e) {
print(e.name);
}

110
testcases/test-dev-directive-prologue.js

@ -0,0 +1,110 @@
/*
* Various directive prologue tests.
*
* How to detect whether strict mode is enabled? This can be done
* through any strict mode feature. One very simple one is this:
* strict functions don't get a 'this' binding when invoked, whereas
* 'this' binding for non-strict functions is the global object.
*
* Thus, the following prints true when executed inside a strict mode
* function:
*
* print(!this);
*
*/
/*===
false
true
false
true
false
true
===*/
/* Basic test for strict mode directive. */
function f_nostrict() {
print(!this);
}
function f_strict() {
'use strict';
print(!this);
}
function f_nostrict_escape() {
/* escaped characters are significant for directives: the expression
* below is a directive, but not a valid 'use strict' directive.
*/
'use\u0020strict';
print(!this);
}
function f_strict_escape() {
/* the first directive is ignored, the second is still processed (we're
* still in the directive prologue).
*/
'use\u0020strict'; // not a 'use strict' directive, but still a valid directive
'use strict'; // but this is
print(!this);
}
function f_nostrict_plain_string_only() {
/* to be part of the directive prologue, the expression must be a plain
* string with no parens etc.
*/
('use strict'); // not a valid 'use strict' directive, terminates prologue
'use strict'; // no longer a 'use strict' directive, not inside prologue
print(!this);
}
function f_strict_comments_ok() {
/* comments and whitespace don't affect directive prologue parsing */
'use strict' /* comment */;
print(!this);
}
f_nostrict();
f_strict();
f_nostrict_escape();
f_strict_escape();
f_nostrict_plain_string_only();
f_strict_comments_ok();
/*===
false
===*/
/* This was broken at some point: unless the first statement parsing had
* finished, the "in directive prologue" flag would be incorrectly set
* for a nested statement.
*/
function f_nostrict_nested() {
try {
'use strict'; // should have no effect
} catch (e) {
}
print(!this);
}
f_nostrict_nested();
/*===
use strict
use strict
===*/
/* Although directives are special, they are still valid expression statements
* and must generate an implicit return value for e.g. eval().
*/
try {
print(eval("'use strict'"));
print(eval("'use strict'; var x = 10")); // var statement is empty, no effect
} catch (e) {
print(e.name);
}

29
testcases/test-dev-enum-deleted-still-in-ancestor.js

@ -0,0 +1,29 @@
/*
* Property deleted from enumeration target is still found from
* ancestor after deletion. Should it be enumerated or not?
*/
/*---
{
"skip": true
}
---*/
/*===
bar skip
foo inherited
===*/
function F() {};
F.prototype = { "foo": "inherited" };
var a = new F();
a.bar = "skip";
a.foo = "own";
// enumeration order: "bar", "foo"
for (var i in a) {
delete a.foo; // only affects 'a', not F.prototype
print(i, a[i]);
}

30
testcases/test-dev-equality.js

@ -0,0 +1,30 @@
/*
* Basic equality operator tests
*/
/* FIXME: fine grained coercion checks */
/*===
false true false
true false true
false true false
true false true
===*/
print(1 == 2, 2 == 2, 3 == 2);
print(1 != 2, 2 != 2, 3 != 2);
print(1 === 2, 2 === 2, 3 === 2);
print(1 !== 2, 2 !== 2, 3 !== 2);
/*===
true
false
false
true
===*/
print(123 == '123');
print(123 === '123');
print(123 != '123');
print(123 !== '123');

54
testcases/test-dev-error-constructor.js

@ -0,0 +1,54 @@
/*
* Simple cases for Error constructor
*/
var e;
/*===
string
string
===*/
e = new Error(undefined);
print(typeof e.message); /* should be inherited from prototype, empty string */
print(e.message);
// same behavior if called as function
e = Error(undefined);
print(typeof e.message);
print(e.message);
/*===
foo
foo
===*/
e = new Error('foo');
print(e.message);
e = Error('foo');
print(e.message);
/*===
string null
string null
string 123
string 123
===*/
/* ToString() coercion */
e = new Error(null);
print(typeof e.message, e.message);
e = Error(null);
print(typeof e.message, e.message);
e = new Error(123);
print(typeof e.message, e.message);
e = Error(123);
print(typeof e.message, e.message);

20
testcases/test-dev-eval-objlit-confusion.js

@ -0,0 +1,20 @@
/*===
number 1
object
===*/
/* This parses as a block statement with a labeled statement
* ("foo:") and an expression statement ("1").
*/
var t;
t = eval("{foo:1}");
print(typeof t, t);
/* Probable intended object literal. */
t = eval("({foo:1})");
print(typeof t);

20
testcases/test-dev-exec-valstack-size.js

@ -0,0 +1,20 @@
/*
* Just random tests for ensuring valstack does not grow during
* execution.
*/
/*===
try finished
===*/
/* This was broken at one point: executor left temp values on valstack
* which eventually ran out of spare.
*/
try {
eval("for (var i = 0; i < 100000; i++) { 'foo' + i + 'bar' }");
print("try finished");
} catch (e) {
print(e.name);
}

12
testcases/test-dev-for-in-basic.js

@ -0,0 +1,12 @@
/*===
foo -> 1
bar -> 2
===*/
obj = {foo:1,bar:2};
for (i in obj) {
print(i,'->',obj[i]);
}

87
testcases/test-dev-for-in-lhs.js

@ -0,0 +1,87 @@
function lhs() {
print('lhs');
}
function getenum1() {
print('getenum1');
return {};
}
function getenum2() {
print('getenum2');
return { 'foo': 'bar' };
}
function getint() {
print('getint');
return 10;
}
/*===
getenum1
done
getenum2
lhs
ReferenceError
===*/
/* The left-hand-side of a for-in may be a function call (and some other
* expressions allowed by LeftHandSideExpression). This is NOT a SyntaxError
* and will only produce a ReferenceError when the actual assignment is
* attempted.
*
* Note that at least Rhino and V8 won't call the lhs() function before
* throwing a ReferenceError. This seems technically incorrect: E5 Section
* 12.6.4 steps 6.b and 6.c seem to indicate that the LHS should be evaluated
* first, and only the actual attempt to PutValue() to an invalid reference
* should throw a ReferenceError. The specification does allow leeway in
* whether or not the LHS is evaluated repeatedly though.
*
* In any case, the current implementation will evaluate the lhs() before
* throwing a ReferenceError, so the test case now tests for that behavior.
*/
try {
/* Here the enumerator will be empty, so no ReferenceError should happen.
* The lhs() expression is not evaluated at all.
*/
for (lhs() in getenum1()) {
print('loop');
}
print('done');
} catch (e) {
print(e.name);
}
try {
/* Here empty() is called, but ReferenceError occurs on first assignment. */
for (lhs() in getenum2()) {
print('loop');
}
print('done');
} catch (e) {
print(e.name);
}
/*===
getint
getenum2
foo
===*/
/* The variable initializer of a for-in statement may have a value.
* That value is computed before the enumeration target is evaluated.
*/
try {
for (var i = getint() in getenum2()) {
print(i);
}
} catch (e) {
print(e.name);
}

32
testcases/test-dev-func-apply.js

@ -0,0 +1,32 @@
/*===
foo bar
foo bar undefined
foo
foo
foo
foo
===*/
/* The apply 'argArray' does NOT have to be an array; its "length"
* property is coerced with ToUint32() and properties are then
* looped.
*/
/* Note: Rhino will complain the following:
*
* js: uncaught JavaScript runtime exception: TypeError: second argument to Function.prototype.apply must be an array
*
* This seems incorrect (for E5), Section 15.3.4.3 step 3 only checks
* whether the argument is an object.
*/
print.apply(null, { "0": "foo", "1": "bar", "length": 2 });
print.apply(null, { "0": "foo", "1": "bar", "length": 3 });
print.apply(null, { "0": "foo", "1": "bar", "length": 1 });
print.apply(null, { "0": "foo", "1": "bar", "length": 4294967296 }); /* ToUint32(len) -> 0 */
print.apply(null, { "0": "foo", "1": "bar", "length": 4294967297 }); /* ToUint32(len) -> 1 */
print.apply(null, { "0": "foo", "1": "bar", "length": "1" }); /* ToUint32("1") -> 1 */
print.apply(null, { "0": "foo", "1": "bar", "length": true }); /* ToUint32(true) -> 1 */

39
testcases/test-dev-func-bind.js

@ -0,0 +1,39 @@
var func;
/*===
1 2
1 2 3 4
1 2 3
===*/
/* Basic cases */
print.bind(null)();
print.bind(null,1,2)();
print.bind(null,1,2)(3,4);
print.bind(null,1).bind(null,2).bind(null,3)();
/*===
2
2
1
0
0
===*/
/* FIXME: length handling of bound function, improve */
function f1(x,y) {
}
print(f1.length);
func = f1.bind(null);
print(func.length);
func = f1.bind(null, 1);
print(func.length);
func = f1.bind(null, 1, 2);
print(func.length);
func = f1.bind(null, 1, 2, 3);
print(func.length);

23
testcases/test-dev-func-call.js

@ -0,0 +1,23 @@
/*===
1 2
===*/
/* Basic cases */
print.call(null);
print.call(null,1,2);
/*===
TypeError
===*/
/* Contrived case where E5 Section 15.3.4.4 step 1 should cause TypeError */
try {
({ "call": Function.prototype.call }).call();
} catch (e) {
print(e.name);
}
/* FIXME: thisArg handling */

17
testcases/test-dev-func-closure-1.js

@ -0,0 +1,17 @@
/*===
inner 1 2
===*/
function foo(x) {
return function(y) {
print('inner', x, y);
}
}
try {
foo(1)(2);
} catch (e) {
print(e.name);
}

100
testcases/test-dev-func-cons-args.js

@ -0,0 +1,100 @@
/*
* E5 Section 15.3.2: function constructor argument list is not
* necessarily just identifier names, a call argument may contain
* multiple argument declarations.
*
* The arguments joined with "," should parse as a FormalParameterList_opt.
* Apparently this means that the source can contain newlines and comments
* too!
*/
/*===
6
6
6
6
6
6
===*/
var f1, f2, f3, f4, f5, f6;
try {
print(eval('f1 = new Function("a", "b", "c", "return a+b+c"); f1(1,2,3);'));
} catch (e) {
print(e.name);
}
try {
print(eval('f2 = new Function("a, b, c", "return a+b+c"); f2(1,2,3);'));
} catch (e) {
print(e.name);
}
try {
print(eval('f3 = new Function("a, b", "c", "return a+b+c"); f3(1,2,3);'));
} catch (e) {
print(e.name);
}
try {
print(eval('f4 = new Function("a /*first*/", "b /*second*/, c /*third*/", "return a+b+c"); f4(1,2,3);'));
} catch (e) {
print(e.name);
}
try {
/* It's unclear in the specification whether this should be a SyntaxError or not.
* If one naively constructs a parse string as:
*
* function (a, b, c //last) { return a+b+c }
*
* Then this would be a syntax error. On the other hand, the specification does not
* say that this should be done; rather, the argument list, joined by commas, should
* be parsed as a FormalParameterList_opt and the body should be parsed as a
* FunctionBody, separately. So we interpret this to mean that this should actually
* work correctly. The formal argument list to be parsed is:
*
* a,b, c // last
*
* This fails in V8 and Rhino, though. For example, Rhino will complain:
*
* SyntaxError: missing ) after formal parameters
*
* which seems incorrect because FormalParameterList_opt does NOT include parentheses
* at all (just the identifiers and commas).
*
* V8 (Node) will complain:
*
* [SyntaxError: Unexpected token return]
*
*/
print(eval('f5 = new Function("a", "b, c // last", "return a+b+c"); f5(1,2,3);'));
} catch (e) {
print(e.name);
}
try {
/* Here the format argument list to be parsed would be:
*
* a
* ,b
* ,c // last [newline]
*
* Again, this should parse as a FormalParameterList_opt but fails to do so in
* Rhino and V8. Rhino will complain:
*
* SyntaxError: unterminated string literal
*
* whereas V8 will complain:
*
* [SyntaxError: Unexpected token ILLEGAL]
*/
eval('f6 = new Function("a\n", "b\n,c // last\n", "return a+b+c"); f6(1,2,3);');
} catch (e) {
print(e.name);
}

198
testcases/test-dev-func-formals.js

@ -0,0 +1,198 @@
/* Function formal arguments do not accept reserved words.
*
* We interpret this also to mean that a function declaration/expression
* in non-strict code will respect strict mode restricted reserved words
* if the function body is strict. This matches with V8.
*/
var orig_eval = eval;
/*===
SyntaxError
SyntaxError
success
SyntaxError
===*/
try {
// Keyword
eval("function foo(for) {};");
print('never here');
} catch (e) {
print(e.name);
}
try {
// FutureReservedWord
eval("function foo(class) {};");
print('never here');
} catch (e) {
print(e.name);
}
try {
// FutureReservedWord only recognized in strict mode
// -> should work
eval("function foo(implements) { print(implements) }; foo('success');");
} catch (e) {
print(e.name);
}
try {
// FutureReservedWord only recognized in strict mode,
// function declared in non-strict mode but function
// itself is strict
eval("function foo(implements) { 'use strict'; };");
print('never here');
} catch (e) {
print(e.name);
}
/*===
SyntaxError
SyntaxError
success
SyntaxError
===*/
/* Function expressions */
try {
eval("(function foo(for) {})();");
print('never here');
} catch (e) {
print(e.name);
}
try {
eval("(function foo(class) {})();");
print('never here');
} catch (e) {
print(e.name);
}
try {
eval("(function foo(implements) { print(implements) })('success');");
} catch (e) {
print(e.name);
}
try {
eval("(function foo(implements) { 'use strict'; })();");
print('never here');
} catch (e) {
print(e.name);
}
/*===
success
SyntaxError
success
SyntaxError
===*/
/* Eval and arguments */
try {
eval("function foo(eval) { print(eval); }; foo('success');");
} catch (e) {
print(e.name);
}
try {
eval("function foo(eval) { 'use strict'; print(eval); }; foo('success');");
print('never here');
} catch (e) {
print(e.name);
}
try {
eval("function foo(arguments) { print(arguments); }; foo('success');");
} catch (e) {
print(e.name);
}
try {
eval("function foo(arguments) { 'use strict'; print(arguments); }; foo('success');");
print('never here');
} catch (e) {
print(e.name);
}
/*===
success
SyntaxError
success
SyntaxError
===*/
/* Eval and arguments, function expressions */
try {
eval("(function foo(eval) { print(eval); })('success');");
} catch (e) {
print(e.name);
}
try {
eval("(function foo(eval) { 'use strict'; print(eval); })('success');");
print('never here');
} catch (e) {
print(e.name);
}
try {
eval("(function foo(arguments) { print(arguments); })('success');");
} catch (e) {
print(e.name);
}
try {
eval("(function foo(arguments) { 'use strict'; print(arguments); })foo('success');");
print('never here');
} catch (e) {
print(e.name);
}
/*===
2
SyntaxError
===*/
/* Duplicate argument names */
try {
// ok, binds to latter
eval("function foo(a,a) { print(a); }; foo(1,2);");
} catch (e) {
print(e.name);
}
try {
eval("function foo(a,a) { 'use strict'; print(a); }; foo(1,2);");
print('never here');
} catch (e) {
print(e.name);
}
/*===
2
SyntaxError
===*/
/* Duplicate argument names, function expressions */
try {
// ok, binds to latter
eval("(function foo(a,a) { print(a); })(1,2);");
} catch (e) {
print(e.name);
}
try {
eval("(function foo(a,a) { 'use strict'; print(a); })(1,2);");
print('never here');
} catch (e) {
print(e.name);
}

11
testcases/test-dev-func-length-prop.js

@ -0,0 +1,11 @@
/*===
0
2
===*/
function f1() {}
function f2(x,y) {};
print(f1.length);
print(f2.length);

168
testcases/test-dev-func-name.js

@ -0,0 +1,168 @@
/* Function name is an identifier (in both function declaration and
* function expression) and cannot contain reserved words. Also,
* "eval" and "arguments" are prohibited for strict functions (although
* they are not reserved words).
*
* We interpret (like V8) that a strict function contained in non-strict
* code cannot be named with one of the additional strict mode reserved
* words.
*/
var orig_eval = eval;
/*===
SyntaxError
SyntaxError
success
SyntaxError
===*/
try {
// Keyword
eval("function for() {};");
print('never here');
} catch (e) {
print(e.name);
}
try {
// FutureReservedWord
eval("function class() {};");
print('never here');
} catch (e) {
print(e.name);
}
try {
// FutureReservedWord only recognized in strict mode
// -> should work
eval("function implements() { print('success') }; implements();");
} catch (e) {
print(e.name);
}
try {
// FutureReservedWord only recognized in strict mode,
// function declared in non-strict mode but function
// itself is strict
eval("function implements() { 'use strict'; };");
print('never here');
} catch (e) {
print(e.name);
}
/*===
SyntaxError
SyntaxError
success
SyntaxError
===*/
/* Same tests for function declarations */
try {
eval("(function for() {});");
print('never here');
} catch (e) {
print(e.name);
}
try {
eval("(function class() {});");
print('never here');
} catch (e) {
print(e.name);
}
try {
eval("(function implements() { print('success') })();");
} catch (e) {
print(e.name);
}
try {
eval("(function implements() { 'use strict'; });");
print('never here');
} catch (e) {
print(e.name);
}
/*===
SyntaxError
SyntaxError
===*/
try {
eval("function eval() { 'use strict'; };");
} catch (e) {
print(e.name);
}
eval = orig_eval; // just in case
try {
eval("function arguments() { 'use strict'; };");
} catch (e) {
print(e.name);
}
/*===
SyntaxError
SyntaxError
===*/
try {
eval("(function eval() { 'use strict'; })();");
} catch (e) {
print(e.name);
}
eval = orig_eval; // just in case
try {
eval("(function arguments() { 'use strict'; })();");
} catch (e) {
print(e.name);
}
/*===
success
success
===*/
/* Non-strict mode allows eval() and arguments() named functions. */
try {
eval("function eval(a) { print(a); }; eval('success');");
} catch (e) {
print(e.name);
}
eval = orig_eval; // just in case
try {
eval("function arguments(a) { print(a); }; arguments('success');");
} catch (e) {
print(e.name);
}
/*===
success
success
===*/
try {
eval("(function eval(a) { print(a); })('success');");
} catch (e) {
print(e.name);
}
eval = orig_eval; // just in case
try {
eval("(function arguments(a) { print(a); })('success');");
} catch (e) {
print(e.name);
}

29
testcases/test-dev-func-own-name-ref.js

@ -0,0 +1,29 @@
/*===
function
function
===*/
/* Simple test that function declaration name and function expression name
* can be accessed from inside the function.
*/
function foo() {
print(typeof foo);
}
try {
foo();
} catch (e) {
print(e.name);
}
var funcexpr = 'not visible';
var temp = function funcexpr() {
print(typeof funcexpr);
};
try {
temp();
} catch (e) {
print(e.name);
}

98
testcases/test-dev-func-shadowing.js

@ -0,0 +1,98 @@
/*
* Various identifier shadowing cases
*/
/*===
function
undefined
function
inner foo
number
===*/
/* Function expression name is bound outside the function scope;
* a single-identifier scope is created between the surrounding
* scope and the function scope.
*
* Thus you can declare a variable or a function of the same name,
* and it will hide the function name binding.
*/
try {
/* Base case */
eval("(function foo() { print(typeof foo); })();");
} catch (e) {
print(e.name);
}
try {
/* Var declaration shadows and is undefined, since variable
* declaration happens on entry but assignment only when
* statement is reached.
*/
eval("(function foo() { print(typeof foo); var foo = 1; })();");
} catch (e) {
print(e.name);
}
try {
/* Function declaration shadows and is defined as the inner
* function: function declarations happen on entry.
*/
eval("(function foo() { print(typeof foo); foo(); function foo() { print('inner foo'); }; })();");
} catch (e) {
print(e.name);
}
try {
/* Argument shadows the function name binding, again simply
* because the function name binding exists "outside" the
* function scope.
*/
eval("(function foo(foo) { print(typeof foo); })(1);");
} catch (e) {
print(e.name);
}
/*===
123
function
inner func
1
1
10
===*/
/* An argument name shadows automatic 'arguments' binding */
try {
eval("(function foo(arguments) { print(arguments); })(123);");
} catch (e) {
print(e.name);
}
/* A function declaration inside the function shadows automatic 'arguments'
* binding.
*/
try {
eval("(function foo() { function arguments() { print('inner func'); }; print(typeof arguments); arguments(); })();");
} catch (e) {
print(e.name);
}
/* A variable declaration does NOT shadow the automatic 'arguments' binding. */
try {
eval("(function foo() { var arguments; print(arguments[0]); })(1,2)");
} catch (e) {
print(e.name);
}
try {
eval("(function foo() { print(arguments[0]); var arguments = 10; print(arguments); })(1,2)");
} catch (e) {
print(e.name);
}

14
testcases/test-dev-func-without-args.js

@ -0,0 +1,14 @@
/*
* Development time testcase for a function without arguments
*/
/*===
hello world
===*/
try {
eval("(function() { print('hello world'); })();");
} catch (e) {
print(e.name);
}

14
testcases/test-dev-implicit-return-value-1.js

@ -0,0 +1,14 @@
/* FIXME: for eval/global code */
/* FIXME: test for handling of 'valued' and 'non-valued' statements */
/*===
3
3
===*/
/* basic case */
print(eval('1+2;'));
/* an empty statement (like debugger) must not alter non-empty previous result */
print(eval('1+2; debugger;'));

32
testcases/test-dev-implicit-return-value-2.js

@ -0,0 +1,32 @@
/*
* Implicit return value of global code, eval code, and function code.
*
* The return value of a function unless it returns with an explicit
* value is always 'undefined', see E5 Sections 11.2.3 and 13.2.1.
*
* The return value of a program (global code or eval code) is the
* value of its last statement. A 'return' statement outside of a
* function body is, in fact, a SyntaxError (E5 Section 12.9).
* See E5 Sections 14, 15.1.2.1.
*/
/*===
3 number
undefined undefined
3 number
===*/
var t;
t = eval("1+2");
print(t, typeof t);
function f1(a,b) { a+b; }
function f2(a,b) { return a+b; }
t = f1(1,2);
print(t, typeof t);
t = f2(1,2);
print(t, typeof t);

24
testcases/test-dev-invalid-lhs.js

@ -0,0 +1,24 @@
/*
* LeftHandSideExpression allows a much wider syntactical set of
* lvalues than we actually support. Valid LHS values which we
* can't write to must not cause SyntaxError but a ReferenceError.
*
* The side effects of the LHS and the RHS (in that order) must
* happen before the ReferenceError.
*/
/* FIXME: is this correct? Both Rhino and V8 will just throw a
* ReferenceError.
*/
/*===
lhs
rhs
ReferenceError
===*/
try {
eval("print('lhs') = print('rhs');");
} catch(e) {
print(e.name);
}

41
testcases/test-dev-json-cyclic.js

@ -0,0 +1,41 @@
/*===
TypeError
TypeError
TypeError
===*/
/* TypeError is required for cyclic structures. */
obj1 = { 'foo': 1 };
obj1.cycle = obj1;
obj2a = { 'foo': 1 };
obj2b = { 'bar': 2 };
obj2a.cycle = obj2b;
obj2b.cycle = obj2a;
obj3a = { 'foo': 1 };
obj3b = { 'bar': 2 };
obj3c = { 'quux': 3 };
obj3a.cycle = obj3b;
obj3b.cycle = obj3c;
obj3c.cycle = obj3a;
try {
print(JSON.stringify(obj1));
} catch (e) {
print(e.name);
}
try {
print(JSON.stringify(obj2a));
} catch (e) {
print(e.name);
}
try {
print(JSON.stringify(obj3a));
} catch (e) {
print(e.name);
}

267
testcases/test-dev-json-types.js

@ -0,0 +1,267 @@
var t;
var i;
var x;
var numbers;
/*===
undefined undefined
{}
{"foo":1}
[1,2,null,4]
===*/
// result is undefined
t = JSON.stringify(undefined);
print(typeof t, t);
// undefined values are not serialized in objects
print(JSON.stringify({bar:undefined})); // empty case perhaps worth extra test
print(JSON.stringify({foo:1,bar:undefined}));
// undefined values are serialized as 'null' in arrays
print(JSON.stringify([1,2,undefined,4]));
/*===
string null
{"foo":1,"bar":null}
[1,2,null,4]
===*/
t = JSON.stringify(null);
print(typeof t, t);
print(JSON.stringify({foo:1,bar:null}));
print(JSON.stringify([1,2,null,4]));
/*===
string true
{"foo":1,"bar":true}
[1,2,true,4]
===*/
t = JSON.stringify(true);
print(typeof t, t);
print(JSON.stringify({foo:1,bar:true}));
print(JSON.stringify([1,2,true,4]));
/*===
string false
{"foo":1,"bar":false}
[1,2,false,4]
===*/
t = JSON.stringify(false);
print(typeof t, t);
print(JSON.stringify({foo:1,bar:false}));
print(JSON.stringify([1,2,false,4]));
/*===
string -123
{"foo":1,"bar":-123}
[1,2,-123,4]
string 0
{"foo":1,"bar":0}
[1,2,0,4]
string 0
{"foo":1,"bar":0}
[1,2,0,4]
string 123
{"foo":1,"bar":123}
[1,2,123,4]
string null
{"foo":1,"bar":null}
[1,2,null,4]
string null
{"foo":1,"bar":null}
[1,2,null,4]
string null
{"foo":1,"bar":null}
[1,2,null,4]
===*/
/* Basic cases for numbers. Special cases:
*
* +0/-0 serializes as 0 (the sign of zero is always omitted)
* -Infinity serializes a null
* Infinity - "" -
* NaN - "" -
*/
numbers = [ -123, -0, +0, 123,
Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY, Number.NaN ];
for (i = 0; i < numbers.length; i++) {
x = numbers[i];
t = JSON.stringify(x);
print(typeof t, t);
print(JSON.stringify({foo:1,bar:x}));
print(JSON.stringify([1,2,x,4]));
}
/*===
===*/
/* Fraction handling for numbers. */
/* FIXME */
/*===
string "foo"
{"foo":1,"bar":"foo"}
[1,2,"foo",4]
string "foo \n\"bar"
{"foo":1,"bar":"foo \n\"bar"}
[1,2,"foo \n\"bar",4]
===*/
/* Basic cases for strings. */
strings = [ "foo", "foo \n\"bar" ];
for (i = 0; i < strings.length; i++) {
x = strings[i];
t = JSON.stringify(x);
print(typeof t, t);
print(JSON.stringify({foo:1,bar:x}));
print(JSON.stringify([1,2,x,4]));
}
/*===
"\""
"\\"
"/"
"\u0000"
"\u0001"
"\u0002"
"\u0003"
"\u0004"
"\u0005"
"\u0006"
"\u0007"
"\b"
"\t"
"\n"
"\u000b"
"\f"
"\r"
"\u000e"
"\u000f"
"\u0010"
"\u0011"
"\u0012"
"\u0013"
"\u0014"
"\u0015"
"\u0016"
"\u0017"
"\u0018"
"\u0019"
"\u001a"
"\u001b"
"\u001c"
"\u001d"
"\u001e"
"\u001f"
" "
34 128 34
34 129 34
34 130 34
34 131 34
34 132 34
34 133 34
34 134 34
34 135 34
34 136 34
34 137 34
34 138 34
34 139 34
34 140 34
34 141 34
34 142 34
34 143 34
34 144 34
34 145 34
34 146 34
34 147 34
34 148 34
34 149 34
34 150 34
34 151 34
34 152 34
34 153 34
34 154 34
34 155 34
34 156 34
34 157 34
34 158 34
34 159 34
===*/
/* Escape testing.
*
* Note that JSON.stringify() is required to NOT escape any control
* characters which are < U+0020. For instance, U+0080 is encoded
* as the three characters '"', '\u0080' (unescaped), '"'. We test
* for these by looking at the code points.
*
* Also note that although '/' can be escaped in JSON, it MUST NOT
* be escaped by JSON.stringify().
*/
// special chars
strings = [ '"', '\\', '/' ];
for (i = 0; i < strings.length; i++) {
t = JSON.stringify(strings[i]);
print(t);
}
for (i = 0; i <= 32; i++) {
t = JSON.stringify(String.fromCharCode(i));
print(t);
}
for (i = 0x80; i < 0xa0; i++) {
t = JSON.stringify(String.fromCharCode(i));
print(t.charCodeAt(0), t.charCodeAt(1), t.charCodeAt(2));
}
/*===
{"foo":1,"bar":"text","object":{"baz":2},"array":[1,2,3]}
===*/
/* Very basic object/array serialization test. */
t = JSON.stringify({foo:1,bar:'text',object:{baz:2},array:[1,2,3]});
print(t);
/*===
[1,2,null,4]
[1,2,null,4]
[1,2,null,4]
===*/
/* Functions (anything callable) serialize as 'null' */
// anonymous Ecmascript function
t = JSON.stringify([1,2,function(){},4]);
print(t);
// native function
t = JSON.stringify([1,2,Object.prototype.toString,4]);
print(t);
// bound function
t = JSON.stringify([1,2,print.bind('foo'),4]);
print(t);

34
testcases/test-dev-json-wrapper.js

@ -0,0 +1,34 @@
/* When encoding any value (val) using JSON.stringigy(), encoding begins
* with a dummy wrapper object:
*
* { "": val }
*
* This seems to be a purely internal matter but is not: the wrapper
* object is accessible to a replacement function.
*/
var val;
var t;
/*===
replacer
object
foo
foo
===*/
// Here the wrapper object is: { "": "foo" }
val = "foo";
t = JSON.stringify(val, function(k, v) {
// this binding: holder object, i.e. the wrapper
// k: key
// v: value
print("replacer");
print(typeof this);
print(this['']); // access the empty string key of the wrapper!
print(k); // empty string
print(v); // 'foo'
});

24
testcases/test-dev-label-parsing.js

@ -0,0 +1,24 @@
/*
* Simple label parsing test without actual label semantics tests.
*/
/*===
foo
bar
quux
===*/
label1:
print("foo");
label1:
label2:
print("bar");
label1:
label2:
label3:
do {
print("quux");
} while(0);

51
testcases/test-dev-label-source-elem.js

@ -0,0 +1,51 @@
/*
* A labelled statement can only be followed by a statement, not a
* source element, even at the top level. Concretely, a function
* declaration cannot follow a label, nor can an expression statement
* begin with 'function'.
*
* This is the E5 standards compliant behavior, which this test now
* looks for. In practice, it makes sense to parse these as either
* function expressions, or as some form of 'function statements'.
* The test needs to be updated when decision on this is made.
*/
/*===
SyntaxError
SyntaxError
try finished
===*/
try {
/* Function f2 declaration follows label which is not allowed.
* Also, an expression statement cannot begin with 'function',
* so this should result in SyntaxError.
*
* V8 allows this in non-strict mode (as function statement?).
*/
eval("function f1() { mylabel: function f2() {} }");
print("try finished");
} catch (e) {
print(e.name);
}
try {
/* Strict mode should have no effect on this, but this test
* illustrates V8 behavior (i.e. V8 gives a SyntaxError here
* but only in strict mode).
*/
eval("function f1() { 'use strict'; mylabel: function f2() {} }");
print("try finished");
} catch (e) {
print(e.name);
}
try {
/* Here function f2 is a function expression, so it is OK. */
eval("function f1() { mylabel: (function f2() {}) }");
print("try finished");
} catch (e) {
print(e.name);
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save