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 /** 29 * This test uses assert{True,False}(... == ...) instead of 30 * assertEquals(..., ...) to not rely on the details of the 31 * implementation of assertEquals. 32 */ 33 34 function testEqual(a, b) { 35 assertTrue(a == b); 36 assertTrue(b == a); 37 assertFalse(a != b); 38 assertFalse(b != a); 39 } 40 41 function testNotEqual(a, b) { 42 assertFalse(a == b); 43 assertFalse(b == a); 44 assertTrue(a != b); 45 assertTrue(b != a); 46 } 47 48 // Object where ToPrimitive returns value. 49 function Wrapper(value) { 50 this.value = value; 51 this.valueOf = function () { return this.value; }; 52 } 53 54 // Object where ToPrimitive returns value by failover to toString when 55 // valueOf isn't a function. 56 function Wrapper2(value) { 57 this.value = value; 58 this.valueOf = null; 59 this.toString = function () { return this.value; }; 60 } 61 62 63 // Compare values of same type. 64 65 // Numbers are equal if same, unless NaN, which isn't equal to anything, and 66 // +/-0 being equal. 67 68 testNotEqual(NaN, NaN); 69 testNotEqual(NaN, 0); 70 testNotEqual(NaN, Infinity); 71 72 testEqual(Number.MAX_VALUE, Number.MAX_VALUE); 73 testEqual(Number.MIN_VALUE, Number.MIN_VALUE); 74 testEqual(Infinity, Infinity); 75 testEqual(-Infinity, -Infinity); 76 77 testEqual(0, 0); 78 testEqual(0, -0); 79 testEqual(-0, -0); 80 81 testNotEqual(0.9, 1); 82 testNotEqual(0.999999, 1); 83 testNotEqual(0.9999999999, 1); 84 testNotEqual(0.9999999999999, 1); 85 86 // Strings are equal if containing the same code points. 87 88 testEqual('hello', 'hello'); 89 testEqual('hello', 'hel' + 'lo'); 90 testEqual('', ''); 91 testEqual('\u0020\x20', ' '); // Escapes are not part of the value. 92 93 // Booleans are equal if they are the same. 94 95 testEqual(true, true); 96 testEqual(false, false); 97 testNotEqual(true, false); 98 99 // Null and undefined are equal to themselves. 100 101 testEqual(null, null); 102 testEqual(undefined, undefined); 103 104 // Objects are equal if they are the same object only. 105 106 testEqual(Math, Math); 107 testEqual(Object.prototype, Object.prototype); 108 109 110 (function () { 111 var x = new Wrapper(null); 112 var y = x, z = x; 113 testEqual(y, x); 114 })(); 115 116 (function () { 117 var x = new Boolean(true); 118 var y = x, z = x; 119 testEqual(y, x); 120 })(); 121 122 (function () { 123 var x = new Boolean(false); 124 var y = x, z = x; 125 testEqual(y, x); 126 })(); 127 128 // Test comparing values of different types. 129 130 // Null and undefined are equal to each-other, and to nothing else. 131 testEqual(null, undefined); 132 testEqual(undefined, null); 133 134 testNotEqual(null, new Wrapper(null)); 135 testNotEqual(null, 0); 136 testNotEqual(null, false); 137 testNotEqual(null, ""); 138 testNotEqual(null, new Object()); 139 testNotEqual(undefined, new Wrapper(undefined)); 140 testNotEqual(undefined, 0); 141 testNotEqual(undefined, false); 142 testNotEqual(undefined, ""); 143 testNotEqual(undefined, new Object()); 144 145 // Numbers compared to Strings will convert the string to a number using 146 // the internal ToNumber conversion. 147 148 testEqual(1, '1'); 149 testEqual(255, '0xff'); 150 testEqual(0, '\r'); // ToNumber ignores tailing and trailing whitespace. 151 testEqual(1e19, '1e19'); 152 testEqual(Infinity, "Infinity"); 153 154 // Booleans compared to anything else will be converted to numbers. 155 testEqual(false, 0); 156 testEqual(true, 1); 157 testEqual(false, "0"); // String also converted to number. 158 testEqual(true, "1"); 159 160 // Objects compared to Number or String (or Boolean, since that's converted 161 // to Number too) is converted to primitive using ToPrimitive with NO HINT. 162 // Having no hint means Date gets a string hint, and everything else gets 163 // a number hint. 164 165 testEqual(new Boolean(true), true); 166 testEqual(new Boolean(true), 1); // First to primtive boolean, then to number. 167 testEqual(new Boolean(false), false); 168 testEqual(new Boolean(false), 0); 169 170 testEqual(new Wrapper(true), true); 171 testEqual(new Wrapper(true), 1); 172 testEqual(new Wrapper(false), false); 173 testEqual(new Wrapper(false), 0); 174 175 testEqual(new Wrapper2(true), true); 176 testEqual(new Wrapper2(true), 1); 177 testEqual(new Wrapper2(false), false); 178 testEqual(new Wrapper2(false), 0); 179 180 testEqual(new Number(1), true); 181 testEqual(new Number(1), 1); 182 testEqual(new Number(0), false); 183 testEqual(new Number(0), 0); 184 185 // Date objects convert to string, not number (and the string does not 186 // convert to the number). 187 testEqual(new Date(42), String(new Date(42))); 188 testNotEqual(new Date(42), Number(new Date(42))); 189 var dnow = new Date(); 190 testEqual(dnow, dnow); 191 testEqual(dnow, String(dnow)); 192 testNotEqual(dnow, Number(dnow)); 193 194 // Doesn't just call toString, but uses ToPrimitive which tries toString first 195 // and valueOf second. 196 dnow.toString = null; 197 testEqual(dnow, Number(dnow)); 198 dnow.valueOf = function () { return "42"; }; 199 testEqual(dnow, 42); 200 dnow.toString = function () { return "1"; }; 201 testEqual(dnow, true); 202 203 204 // Objects compared to other objects, or to null and undefined, are not 205 // converted to primitive. 206 testNotEqual(new Wrapper(null), new Wrapper(null)); 207 testNotEqual(new Boolean(true), new Boolean(true)); 208 testNotEqual(new Boolean(false), new Boolean(false)); 209 testNotEqual(new String("a"), new String("a")); 210 testNotEqual(new Number(42), new Number(42)); 211 testNotEqual(new Date(42), new Date(42)); 212 testNotEqual(new Array(42), new Array(42)); 213 testNotEqual(new Object(), new Object()); 214 215 // Object that can't be converted to primitive. 216 var badObject = { 217 valueOf: null, 218 toString: function() { 219 return this; // Not primitive. 220 } 221 }; 222 223 testEqual(badObject, badObject); 224 testNotEqual(badObject, {}); 225 testNotEqual(badObject, null); 226 testNotEqual(badObject, undefined); 227 // Forcing conversion will throw. 228 function testBadConversion(value) { 229 assertThrows(function() { return badObject == value; }); 230 assertThrows(function() { return badObject != value; }); 231 assertThrows(function() { return value == badObject; }); 232 assertThrows(function() { return value != badObject; }); 233 } 234 testBadConversion(0); 235 testBadConversion("string"); 236 testBadConversion(true); 237