Home | History | Annotate | Download | only in mjsunit
      1 // Copyright 2008 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 // Test for const semantics.
     29 
     30 
     31 function CheckException(e) {
     32   var string = e.toString();
     33   var index = string.indexOf(':');
     34   assertTrue(index >= 0);
     35   var name = string.slice(0, index);
     36   assertTrue(string.indexOf("has already been declared") >= 0 ||
     37              string.indexOf("redeclaration") >= 0);
     38   if (name == 'SyntaxError') return 'TypeError';
     39   return name;
     40 }
     41 
     42 
     43 function TestLocal(s,e) {
     44   try {
     45     return eval("(function(){" + s + ";return " + e + "})")();
     46   } catch (x) {
     47     return CheckException(x);
     48   }
     49 }
     50 
     51 
     52 // NOTE: TestGlobal usually only tests the given string in the context
     53 // of a global object in dictionary mode. This is because we use
     54 // delete to get rid of any added properties.
     55 function TestGlobal(s,e) {
     56   // Collect the global properties before the call.
     57   var properties = [];
     58   for (var key in this) properties.push(key);
     59   // Compute the result.
     60   var result;
     61   try {
     62     var code = s + (e ? "; $$$result=" + e : "");
     63     if (this.execScript) {
     64       execScript(code);
     65     } else {
     66       this.eval(code);
     67     }
     68     // Avoid issues if $$$result is not defined by
     69     // reading it through this.
     70     result = this.$$$result;
     71   } catch (x) {
     72     result = CheckException(x);
     73   }
     74   // Get rid of any introduced global properties before
     75   // returning the result.
     76   for (var key in this) {
     77     if (properties.indexOf(key) == -1) delete this[key];
     78   }
     79   return result;
     80 }
     81 
     82 
     83 function TestContext(s,e) {
     84   try {
     85     // Use a with-statement to force the system to do dynamic
     86     // declarations of the introduced variables or constants.
     87     with ({}) {
     88       return eval(s + ";" + e);
     89     }
     90   } catch (x) {
     91     return CheckException(x);
     92   }
     93 }
     94 
     95 
     96 function TestAll(expected,s,opt_e) {
     97   var e = "";
     98   var msg = s;
     99   if (opt_e) { e = opt_e; msg += "; " + opt_e; }
    100   assertEquals(expected, TestLocal(s,e), "local:'" + msg + "'");
    101   // Redeclarations of global consts do not throw, they are silently ignored.
    102   assertEquals(42, TestGlobal(s, 42), "global:'" + msg + "'");
    103   assertEquals(expected, TestContext(s,e), "context:'" + msg + "'");
    104 }
    105 
    106 
    107 function TestConflict(def0, def1) {
    108   // No eval.
    109   TestAll("TypeError", def0 +'; ' + def1);
    110   // Eval everything.
    111   TestAll("TypeError", 'eval("' + def0 + '; ' + def1 + '")');
    112   // Eval first definition.
    113   TestAll("TypeError", 'eval("' + def0 +'"); ' + def1);
    114   // Eval second definition.
    115   TestAll("TypeError", def0 + '; eval("' + def1 + '")');
    116   // Eval both definitions separately.
    117   TestAll("TypeError", 'eval("' + def0 +'"); eval("' + def1 + '")');
    118 }
    119 
    120 
    121 // Test conflicting definitions.
    122 TestConflict("const x", "var x");
    123 TestConflict("const x = 0", "var x");
    124 TestConflict("const x", "var x = 0");
    125 TestConflict("const x = 0", "var x = 0");
    126 
    127 TestConflict("var x", "const x");
    128 TestConflict("var x = 0", "const x");
    129 TestConflict("var x", "const x = 0");
    130 TestConflict("var x = 0", "const x = 0");
    131 
    132 TestConflict("const x = undefined", "var x");
    133 TestConflict("const x", "var x = undefined");
    134 TestConflict("const x = undefined", "var x = undefined");
    135 
    136 TestConflict("var x = undefined", "const x");
    137 TestConflict("var x", "const x = undefined");
    138 TestConflict("var x = undefined", "const x = undefined");
    139 
    140 TestConflict("const x = undefined", "var x = 0");
    141 TestConflict("const x = 0", "var x = undefined");
    142 
    143 TestConflict("var x = undefined", "const x = 0");
    144 TestConflict("var x = 0", "const x = undefined");
    145 
    146 TestConflict("const x", "function x() { }");
    147 TestConflict("const x = 0", "function x() { }");
    148 TestConflict("const x = undefined", "function x() { }");
    149 
    150 TestConflict("function x() { }", "const x");
    151 TestConflict("function x() { }", "const x = 0");
    152 TestConflict("function x() { }", "const x = undefined");
    153 
    154 TestConflict("const x, y", "var x");
    155 TestConflict("const x, y", "var y");
    156 TestConflict("const x = 0, y", "var x");
    157 TestConflict("const x = 0, y", "var y");
    158 TestConflict("const x, y = 0", "var x");
    159 TestConflict("const x, y = 0", "var y");
    160 TestConflict("const x = 0, y = 0", "var x");
    161 TestConflict("const x = 0, y = 0", "var y");
    162 
    163 TestConflict("var x", "const x, y");
    164 TestConflict("var y", "const x, y");
    165 TestConflict("var x", "const x = 0, y");
    166 TestConflict("var y", "const x = 0, y");
    167 TestConflict("var x", "const x, y = 0");
    168 TestConflict("var y", "const x, y = 0");
    169 TestConflict("var x", "const x = 0, y = 0");
    170 TestConflict("var y", "const x = 0, y = 0");
    171 
    172 
    173 // Test that multiple conflicts do not cause issues.
    174 TestConflict("var x, y", "const x, y");
    175 
    176 
    177 // Test that repeated const declarations throw redeclaration errors.
    178 TestConflict("const x", "const x");
    179 TestConflict("const x = 0", "const x");
    180 TestConflict("const x", "const x = 0");
    181 TestConflict("const x = 0", "const x = 0");
    182 
    183 TestConflict("const x = undefined", "const x");
    184 TestConflict("const x", "const x = undefined");
    185 TestConflict("const x = undefined", "const x = undefined");
    186 
    187 TestConflict("const x = undefined", "const x = 0");
    188 TestConflict("const x = 0", "const x = undefined");
    189 
    190 TestConflict("const x, y", "const x");
    191 TestConflict("const x, y", "const y");
    192 TestConflict("const x = 0, y", "const x");
    193 TestConflict("const x = 0, y", "const y");
    194 TestConflict("const x, y = 0", "const x");
    195 TestConflict("const x, y = 0", "const y");
    196 TestConflict("const x = 0, y = 0", "const x");
    197 TestConflict("const x = 0, y = 0", "const y");
    198 
    199 TestConflict("const x", "const x, y");
    200 TestConflict("const y", "const x, y");
    201 TestConflict("const x", "const x = 0, y");
    202 TestConflict("const y", "const x = 0, y");
    203 TestConflict("const x", "const x, y = 0");
    204 TestConflict("const y", "const x, y = 0");
    205 TestConflict("const x", "const x = 0, y = 0");
    206 TestConflict("const y", "const x = 0, y = 0");
    207 
    208 
    209 // Test that multiple const conflicts do not cause issues.
    210 TestConflict("const x, y", "const x, y");
    211 
    212 
    213 // Test that const inside loop behaves correctly.
    214 var loop = "for (var i = 0; i < 3; i++) { const x = i; }";
    215 TestAll(0, loop, "x");
    216 TestAll(0, "var a,b,c,d,e,f,g,h; " + loop, "x");
    217 
    218 
    219 // Test that const inside with behaves correctly.
    220 TestAll(87, "with ({x:42}) { const x = 87; }", "x");
    221 TestAll(undefined, "with ({x:42}) { const x; }", "x");
    222 
    223 
    224 // Additional tests for how various combinations of re-declarations affect
    225 // the values of the var/const in question.
    226 try {
    227   eval("var undefined;");
    228 } catch (ex) {
    229   assertUnreachable("undefined (1) has thrown");
    230 }
    231 
    232 var original_undef = undefined;
    233 var undefined = 1;  // Should be silently ignored.
    234 assertEquals(original_undef, undefined, "undefined got overwritten");
    235 undefined = original_undef;
    236 
    237 var a; const a; const a = 1;
    238 assertEquals(1, a, "a has wrong value");
    239 a = 2;
    240 assertEquals(2, a, "a should be writable");
    241 
    242 var b = 1; const b = 2;
    243 assertEquals(2, b, "b has wrong value");
    244 
    245 var c = 1; const c = 2; const c = 3;
    246 assertEquals(3, c, "c has wrong value");
    247 
    248 const d = 1; const d = 2;
    249 assertEquals(1, d, "d has wrong value");
    250 
    251 const e = 1; var e = 2;
    252 assertEquals(1, e, "e has wrong value");
    253 
    254 const f = 1; const f;
    255 assertEquals(1, f, "f has wrong value");
    256 
    257 var g; const g = 1;
    258 assertEquals(1, g, "g has wrong value");
    259 g = 2;
    260 assertEquals(2, g, "g should be writable");
    261 
    262 const h; var h = 1;
    263 assertEquals(undefined,h,  "h has wrong value");
    264 
    265 eval("Object.defineProperty(this, 'i', { writable: true });"
    266    + "const i = 7;"
    267    + "assertEquals(7, i, \"i has wrong value\");");
    268 
    269 var global = this;
    270 assertThrows(function() {
    271   Object.defineProperty(global, 'j', { writable: true })
    272 }, TypeError);
    273 const j = 2;  // This is what makes the function above throw, because the
    274 // const declaration gets hoisted and makes the property non-configurable.
    275 assertEquals(2, j, "j has wrong value");
    276 
    277 var k = 1; const k;
    278 // You could argue about the expected result here. For now, the winning
    279 // argument is that "const k;" is equivalent to "const k = undefined;".
    280 assertEquals(undefined, k, "k has wrong value");
    281