Advertisement
Guest User

JavaScript Strict Mode - Tests

a guest
May 4th, 2011
1,795
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. (function() {
  2.  
  3.   ////////////////////////////////
  4.   //TEST UTILS...
  5.   ////////////////////////////////
  6.  
  7.   var HTML_MODE = 0;
  8.   var CONSOLE_MODE = 1;
  9.  
  10.   var mode = CONSOLE_MODE;
  11.  
  12.   var banner = document.getElementById('banner');
  13.   var currentTestWidget;
  14.  
  15.   var testsPassed = 0;
  16.   var totalTests = 0;
  17.  
  18.   window.console = window.console || {log:alert};
  19.  
  20.   function testException(testName, code, expectedError) {
  21.       'use strict';
  22.       startTest(testName);
  23.       try {
  24.           expectedError == SyntaxError ? eval(code) : code();
  25.           finishTest(false);
  26.       } catch (e) {
  27.           (e instanceof expectedError) ? finishTest(true) : finishTest(false);
  28.       }
  29.   }
  30.  
  31.   function testValue(testName, fn, expectedValue, options) {
  32.       'use strict';
  33.       options = options || {};
  34.       startTest(testName);
  35.       var result = (fn.apply(options.ctx, options.args || []) === expectedValue);
  36.       finishTest(result);
  37.   }
  38.  
  39.   function startTest(testName) {
  40.     if (mode == CONSOLE_MODE) {
  41.       console.log("testing..." + testName);
  42.     } else {
  43.       this.currentWidget = document.createElement('DIV');
  44.       this.currentWidget.innerHTML = testName;
  45.       document.body.appendChild(this.currentWidget);
  46.     }
  47.   }
  48.  
  49.   function finishTest(passed) {
  50.     totalTests++;
  51.     passed && testsPassed++;
  52.     var result = passed ? "passed" : "failed";
  53.     if (mode == CONSOLE_MODE) {
  54.       console.log(result);
  55.     } else {
  56.       this.currentWidget.className = result;
  57.     }
  58.   }
  59.  
  60.   function startAll() {
  61.     if (mode == HTML_MODE) {
  62.       banner.innerHTML += [":", browser.browserName, browser.fullVersion].join(' ');
  63.     }
  64.   }
  65.  
  66.   function finishAll() {
  67.     var result = ["","(", testsPassed, "out of", totalTests, "tests passed", ")"].join(' ');
  68.     if (mode == HTML_MODE) {
  69.       banner.innerHTML += result;
  70.     } else if (mode == CONSOLE_MODE) {
  71.       console.log(result);
  72.     }
  73.   }
  74.  
  75.   ////////////////////////////////
  76.   //THE TESTS...
  77.   ////////////////////////////////
  78.  
  79.   startAll();
  80.  
  81.   // A conforming implementation, when processing strict mode code, may not extend the
  82.   //syntax of NumericLiteral (7.8.3) to include OctalIntegerLiteral as described in B.1.1.
  83.   testException("no octal literals", '012', SyntaxError);
  84.  
  85.   // A conforming implementation, when processing strict mode code (see 10.1.1), may not
  86.   //extend the syntax of EscapeSequence to include OctalEscapeSequence as described in B.1.2.
  87.   testException("no octal escape sequence", '"\\012"', SyntaxError);
  88.  
  89.   // Assignment to an undeclared identifier or otherwise unresolvable reference does not
  90.   //create a property in the global object. When a simple assignment occurs within strict
  91.   //mode code, its LeftHandSide must not evaluate to an unresolvable Reference. If it does
  92.   //a ReferenceError exception is thrown (8.7.2).
  93.   testException(
  94.     "no implied globals",
  95.     function () {'use strict'; x = 3;},
  96.     ReferenceError
  97.   );
  98.  
  99.   //The LeftHandSide also may not be a reference to a data property with the attribute
  100.   //value {[[Writable]]:false}, to an accessor property with the attribute value
  101.   //{[[Set]]:undefined}, nor to a non-existent property of an object whose [[Extensible]]
  102.   //internal property has the value false. In these cases a TypeError exception is thrown
  103.   //(11.13.1).
  104.   var assignToNonWritable = function () {
  105.       'use strict';
  106.       var obj = {};
  107.       Object.defineProperty(obj, "name", {
  108.           writable: false
  109.       });
  110.       obj.name = "octopus";
  111.   }
  112.  
  113.   testException("can't assign to non-writable properties", assignToNonWritable, TypeError);
  114.  
  115.   var assignWhenSetterUndefined = function () {
  116.       'use strict';
  117.       var obj = {};
  118.       Object.defineProperty(obj, "name", {
  119.           set: undefined
  120.       });
  121.       obj.name = "cuttlefish";
  122.   }
  123.  
  124.   testException("can't assign when setter undefined", assignWhenSetterUndefined, TypeError);
  125.  
  126.   var assignToNonExtensible = function () {
  127.       'use strict';
  128.       var obj = {};
  129.       Object.preventExtensions(obj);
  130.       obj.name = "jellyfish";
  131.   }
  132.  
  133.   testException("can't assign to non extensible", assignToNonExtensible, TypeError);
  134.  
  135.   //The identifier eval or arguments may not appear as the LeftHandSideExpression of an
  136.   //Assignment operator (11.13) or of a PostfixExpression (11.13) or as the UnaryExpression
  137.   //operated upon by a Prefix Increment (11.4.4) or a Prefix Decrement (11.4.5) operator.
  138.   testException("can't assign to eval", "eval=3", SyntaxError);
  139.   testException("can't assign to arguments", "arguments=3", SyntaxError);
  140.   testException("can't postfix eval", "eval++", SyntaxError);
  141.   testException("can't postfix arguments", "arguments++", SyntaxError);
  142.   testException("can't prefix eval", "++eval", SyntaxError);
  143.   testException("can't prefix arguments", "++arguments", SyntaxError);
  144.  
  145.   //Arguments objects for strict mode functions define non-configurable accessor properties
  146.   //named "caller" and "callee" which throw a TypeError exception on access (10.6).
  147.   testException(
  148.     "can't use arguments.caller",
  149.     function () {'use strict'; arguments.caller;},
  150.     TypeError
  151.   );
  152.  
  153.   testException(
  154.     "can't use arguments.callee",
  155.     function () {'use strict'; arguments.callee},
  156.     TypeError
  157.   );
  158.  
  159.   //Arguments objects for strict mode functions do not dynamically share their array indexed
  160.   //property values with the corresponding formal parameter bindings of their functions. (10.6).
  161.   var assignToArguments = function (x) {
  162.     'use strict';
  163.     arguments[0] = 3;
  164.     return x;
  165.   }
  166.  
  167.   testValue(
  168.     "arguments not bound to formal params",
  169.     assignToArguments,
  170.     5,
  171.     {args: [5]}
  172.   );
  173.  
  174.   //For strict mode functions, if an arguments object is created the binding of the local
  175.   //identifier arguments to the arguments object is immutable and hence may not be the
  176.   //target of an assignment expression. (10.5).
  177.   var assignToFormalParams = function (x) {
  178.       'use strict';
  179.       x = 3;
  180.       return arguments[0];
  181.   }
  182.  
  183.   testValue(
  184.     "arguments object is immutable",
  185.     assignToFormalParams,
  186.     5,
  187.     {args: [5]}
  188.   );
  189.  
  190.   //It is a SyntaxError if strict mode code contains an ObjectLiteral with more than one
  191.   //definition of any data property (11.1.5).
  192.   testException("no duplicate properties", "({a:1, a:2})", SyntaxError);
  193.  
  194.   //It is a SyntaxError if the Identifier "eval" or the Identifier "arguments occurs as the
  195.   //Identifier in a PropertySetParameterList of a PropertyAssignment that is contained in
  196.   //strict code or if its FunctionBody is strict code (11.1.5).
  197.   testException(
  198.     "eval not allowed in propertySetParameterList",
  199.     "({set a(eval){ }})",
  200.     SyntaxError
  201.   );
  202.  
  203.   testException(
  204.     "arguments not allowed in propertySetParameterList",
  205.     "({set a(arguments){ }})",
  206.     SyntaxError
  207.   );
  208.  
  209.   //Strict mode eval code cannot instantiate variables or functions in the variable environment
  210.   //of the caller to eval. Instead, a new variable environment is created and that environment
  211.   //is used for declaration binding instantiation for the eval code (10.4.2).
  212.   testException(
  213.     "eval cannot create var in calling context",
  214.     function () {'use strict'; eval('var a = 99'); a},
  215.     ReferenceError
  216.   );
  217.  
  218.   //If this is evaluated within strict mode code, then the this value is not coerced to an object.
  219.   //A this value of null or undefined is not converted to the global object and primitive values
  220.   //are not converted to wrapper objects. The this value passed via a function call (including
  221.   //calls made using Function.prototype.apply and Function.prototype.call) do not coerce the
  222.   //passed this value to an object (10.4.3, 11.1.1, 15.3.4.3, 15.3.4.4).
  223.   var getThis = function () {
  224.       'use strict';
  225.       return this;
  226.   }
  227.  
  228.   testValue(
  229.     "this is not coerced",
  230.     getThis,
  231.     4,
  232.     {ctx: 4}
  233.   );
  234.  
  235.   testValue(
  236.     "no global coercion for null",
  237.     getThis,
  238.     null,
  239.     {ctx: null}
  240.   );
  241.  
  242.   //When a delete operator occurs within strict mode code, a SyntaxError is thrown if its
  243.   //UnaryExpression is a direct reference to a variable, function argument, or function name
  244.   //(11.4.1).
  245.   testException("can't delete variable directly", "var a = 3; delete a", SyntaxError);
  246.   testException("can't delete argument", "function(a) {delete a}", SyntaxError);
  247.   testException("can't delete function by name", "function fn() {}; delete fn", SyntaxError);
  248.  
  249.   //When a delete operator occurs within strict mode code, a TypeError is thrown if the
  250.   //property to be deleted has the attribute { [[Configurable]]:false } (11.4.1).
  251.   var deleteNonConfigurable = function () {
  252.       'use strict';
  253.       var obj = {};
  254.       Object.defineProperty(obj, "name", {
  255.           configurable: false
  256.       });
  257.       delete obj.name;
  258.   }
  259.  
  260.   testException("error when deleting non configurable", deleteNonConfigurable, TypeError);
  261.  
  262.   //It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within
  263.   //strict code and its Identifier is eval or arguments (12.2.1).
  264.   testException("can't use eval as var name", "var eval;", SyntaxError);
  265.   testException("can't use arguments as var name", "var arguments;", SyntaxError);
  266.  
  267.   //Strict mode code may not include a WithStatement. The occurrence of a WithStatement
  268.   //in such a context is an SyntaxError (12.10).
  269.   testException("can't use with", "with (Math) {round(sqrt(56.67))}", SyntaxError);
  270.  
  271.   //It is a SyntaxError if a TryStatement with a Catch occurs within strict code and the
  272.   //Identifier of the Catch production is eval or arguments (12.14.1)
  273.   testException("can't use eval as catch id", "try {'cake'} catch(eval) {}", SyntaxError);
  274.   testException("can't use arguments as catch id", "try {'cake'} catch(arguments) {}", SyntaxError);
  275.  
  276.   //It is a SyntaxError if the identifier eval or arguments appears within a
  277.   //FormalParameterList of a strict mode FunctionDeclaration or FunctionExpression (13.1)
  278.   testException("can't use eval as formal param", "function(eval) {}", SyntaxError);
  279.   testException("can't use arguments as formal param", "function(arguments) {}", SyntaxError);
  280.  
  281.   //A strict mode function may not have two or more formal parameters that have the same
  282.   //name. An attempt to create such a function using a FunctionDeclaration, FunctionExpression,
  283.   //or Function constructor is a SyntaxError (13.1, 15.3.2).
  284.   testException("can't duplicate formal params", "function(me, me, me) {}", SyntaxError);
  285.  
  286.   //An implementation may not associate special meanings within strict mode functions to
  287.   //properties named caller or arguments of function instances. ECMAScript code may not
  288.   //create or modify properties with these names on function objects that correspond to
  289.   //strict mode functions (13.2).
  290.   testException(
  291.     "can't use caller obj of function",
  292.     function () {'use strict'; (function () {}).caller},
  293.     TypeError
  294.   );
  295.  
  296.   //It is a SyntaxError to use within strict mode code the identifiers eval or arguments as
  297.   //the Identifier of a FunctionDeclaration or FunctionExpression or as a formal parameter
  298.   //name (13.1). Attempting to dynamically define such a strict mode function using the
  299.   //Function constructor (15.3.2) will throw a SyntaxError exception.
  300.   testException("can't use eval as function name", "function eval() {}", SyntaxError);
  301.   testException("can't use arguments as function name", "function arguments() {}", SyntaxError);
  302.  
  303.   var functionConstructorStr = "new Function('eval', 'use strict')";
  304.   testException("can't use eval as param name via constructor", functionConstructorStr, SyntaxError);
  305.  
  306.   finishAll();
  307.  
  308. })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement