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 function MjsUnitAssertionError(message) {
     29   this.message = message;
     30   // This allows fetching the stack trace using TryCatch::StackTrace.
     31   this.stack = new Error("").stack;
     32 }
     33 
     34 MjsUnitAssertionError.prototype.toString = function () {
     35   return this.message;
     36 }
     37 
     38 /*
     39  * This file is included in all mini jsunit test cases.  The test
     40  * framework expects lines that signal failed tests to start with
     41  * the f-word and ignore all other lines.
     42  */
     43 
     44 function MjsUnitToString(value) {
     45   switch (typeof value) {
     46     case "string":
     47       return JSON.stringify(value);
     48     case "number":
     49       if (value === 0 && (1 / value) < 0) return "-0";
     50     case "boolean":
     51     case "null":
     52     case "undefined":
     53     case "function":
     54       return String(value);
     55     case "object":
     56       if (value === null) return "null";
     57       var clazz = Object.prototype.toString.call(value);
     58       clazz = clazz.substring(8, clazz.length - 1);
     59       switch (clazz) {
     60         case "Number":
     61         case "String":
     62         case "Boolean":
     63         case "Date":
     64           return clazz + "(" + MjsUnitToString(value.valueOf()) + ")";
     65         case "RegExp":
     66           return value.toString();
     67         case "Array":
     68           return "[" + value.map(MjsUnitArrayElementToString).join(",") + "]";
     69         case "Object":
     70           break;
     71         default:
     72           return clazz + "()";
     73       }
     74       // [[Class]] is "Object".
     75       var constructor = value.constructor.name;
     76       if (name) return name + "()";
     77       return "Object()";
     78     default:
     79       return "-- unknown value --";
     80   }
     81 }
     82 
     83 
     84 function MjsUnitArrayElementToString(value, index, array) {
     85   if (value === undefined && !(index in array)) return "";
     86   return MjsUnitToString(value);
     87 }
     88 
     89 
     90 function fail(expected, found, name_opt) {
     91   var message = "Fail" + "ure";
     92   if (name_opt) {
     93     // Fix this when we ditch the old test runner.
     94     message += " (" + name_opt + ")";
     95   }
     96 
     97   message += ": expected <" + MjsUnitToString(expected) +
     98       "> found <" + MjsUnitToString(found) + ">";
     99   throw new MjsUnitAssertionError(message);
    100 }
    101 
    102 
    103 function deepObjectEquals(a, b) {
    104   var aProps = [];
    105   for (var key in a)
    106     aProps.push(key);
    107   var bProps = [];
    108   for (var key in b)
    109     bProps.push(key);
    110   aProps.sort();
    111   bProps.sort();
    112   if (!deepEquals(aProps, bProps))
    113     return false;
    114   for (var i = 0; i < aProps.length; i++) {
    115     if (!deepEquals(a[aProps[i]], b[aProps[i]]))
    116       return false;
    117   }
    118   return true;
    119 }
    120 
    121 
    122 function deepEquals(a, b) {
    123   if (a == b) {
    124     // Check for -0.
    125     if (a === 0 && b === 0) return (1 / a) === (1 / b);
    126     return true;
    127   }
    128   if (typeof a == "number" && typeof b == "number" && isNaN(a) && isNaN(b)) {
    129     return true;
    130   }
    131   if (a == null || b == null) return false;
    132   if (a.constructor === RegExp || b.constructor === RegExp) {
    133     return (a.constructor === b.constructor) && (a.toString() === b.toString());
    134   }
    135   if ((typeof a) !== 'object' || (typeof b) !== 'object' ||
    136       (a === null) || (b === null))
    137     return false;
    138   if (a.constructor === Array) {
    139     if (b.constructor !== Array)
    140       return false;
    141     if (a.length != b.length)
    142       return false;
    143     for (var i = 0; i < a.length; i++) {
    144       if (i in a) {
    145         if (!(i in b) || !(deepEquals(a[i], b[i])))
    146           return false;
    147       } else if (i in b) {
    148         return false;
    149       }
    150     }
    151     return true;
    152   } else {
    153     return deepObjectEquals(a, b);
    154   }
    155 }
    156 
    157 
    158 function assertSame(expected, found, name_opt) {
    159   if (found !== expected) {
    160     fail(expected, found, name_opt);
    161   }
    162 }
    163 
    164 
    165 function assertEquals(expected, found, name_opt) {
    166   if (!deepEquals(found, expected)) {
    167     fail(expected, found, name_opt);
    168   }
    169 }
    170 
    171 
    172 function assertArrayEquals(expected, found, name_opt) {
    173   var start = "";
    174   if (name_opt) {
    175     start = name_opt + " - ";
    176   }
    177   assertEquals(expected.length, found.length, start + "array length");
    178   if (expected.length == found.length) {
    179     for (var i = 0; i < expected.length; ++i) {
    180       assertEquals(expected[i], found[i], start + "array element at index " + i);
    181     }
    182   }
    183 }
    184 
    185 
    186 function assertTrue(value, name_opt) {
    187   assertEquals(true, value, name_opt);
    188 }
    189 
    190 
    191 function assertFalse(value, name_opt) {
    192   assertEquals(false, value, name_opt);
    193 }
    194 
    195 
    196 function assertNaN(value, name_opt) {
    197   if (!isNaN(value)) {
    198     fail("NaN", value, name_opt);
    199   }
    200 }
    201 
    202 
    203 function assertNull(value, name_opt) {
    204   if (value !== null) {
    205     fail("null", value, name_opt);
    206   }
    207 }
    208 
    209 
    210 function assertNotNull(value, name_opt) {
    211   if (value === null) {
    212     fail("not null", value, name_opt);
    213   }
    214 }
    215 
    216 
    217 function assertThrows(code, type_opt, cause_opt) {
    218   var threwException = true;
    219   try {
    220     if (typeof code == 'function') {
    221       code();
    222     } else {
    223       eval(code);
    224     }
    225     threwException = false;
    226   } catch (e) {
    227     if (typeof type_opt == 'function')
    228       assertInstanceof(e, type_opt);
    229     if (arguments.length >= 3)
    230       assertEquals(e.type, cause_opt);
    231     // Do nothing.
    232   }
    233   if (!threwException) assertTrue(false, "did not throw exception");
    234 }
    235 
    236 
    237 function assertInstanceof(obj, type) {
    238   if (!(obj instanceof type)) {
    239     assertTrue(false, "Object <" + obj + "> is not an instance of <" + type + ">");
    240   }
    241 }
    242 
    243 
    244 function assertDoesNotThrow(code) {
    245   try {
    246     if (typeof code == 'function') {
    247       code();
    248     } else {
    249       eval(code);
    250     }
    251   } catch (e) {
    252     assertTrue(false, "threw an exception: " + (e.message || e));
    253   }
    254 }
    255 
    256 
    257 function assertUnreachable(name_opt) {
    258   // Fix this when we ditch the old test runner.
    259   var message = "Fail" + "ure: unreachable";
    260   if (name_opt) {
    261     message += " - " + name_opt;
    262   }
    263   throw new MjsUnitAssertionError(message);
    264 }
    265