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 34function testEqual(a, b) { 35 assertTrue(a == b); 36 assertTrue(b == a); 37 assertFalse(a != b); 38 assertFalse(b != a); 39} 40 41function 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. 49function 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. 56function 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 68testNotEqual(NaN, NaN); 69testNotEqual(NaN, 0); 70testNotEqual(NaN, Infinity); 71 72testEqual(Number.MAX_VALUE, Number.MAX_VALUE); 73testEqual(Number.MIN_VALUE, Number.MIN_VALUE); 74testEqual(Infinity, Infinity); 75testEqual(-Infinity, -Infinity); 76 77testEqual(0, 0); 78testEqual(0, -0); 79testEqual(-0, -0); 80 81testNotEqual(0.9, 1); 82testNotEqual(0.999999, 1); 83testNotEqual(0.9999999999, 1); 84testNotEqual(0.9999999999999, 1); 85 86// Strings are equal if containing the same code points. 87 88testEqual('hello', 'hello'); 89testEqual('hello', 'hel' + 'lo'); 90testEqual('', ''); 91testEqual('\u0020\x20', ' '); // Escapes are not part of the value. 92 93// Booleans are equal if they are the same. 94 95testEqual(true, true); 96testEqual(false, false); 97testNotEqual(true, false); 98 99// Null and undefined are equal to themselves. 100 101testEqual(null, null); 102testEqual(undefined, undefined); 103 104// Objects are equal if they are the same object only. 105 106testEqual(Math, Math); 107testEqual(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. 131testEqual(null, undefined); 132testEqual(undefined, null); 133 134testNotEqual(null, new Wrapper(null)); 135testNotEqual(null, 0); 136testNotEqual(null, false); 137testNotEqual(null, ""); 138testNotEqual(null, new Object()); 139testNotEqual(undefined, new Wrapper(undefined)); 140testNotEqual(undefined, 0); 141testNotEqual(undefined, false); 142testNotEqual(undefined, ""); 143testNotEqual(undefined, new Object()); 144 145// Numbers compared to Strings will convert the string to a number using 146// the internal ToNumber conversion. 147 148testEqual(1, '1'); 149testEqual(255, '0xff'); 150testEqual(0, '\r'); // ToNumber ignores tailing and trailing whitespace. 151testEqual(1e19, '1e19'); 152testEqual(Infinity, "Infinity"); 153 154// Booleans compared to anything else will be converted to numbers. 155testEqual(false, 0); 156testEqual(true, 1); 157testEqual(false, "0"); // String also converted to number. 158testEqual(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 165testEqual(new Boolean(true), true); 166testEqual(new Boolean(true), 1); // First to primtive boolean, then to number. 167testEqual(new Boolean(false), false); 168testEqual(new Boolean(false), 0); 169 170testEqual(new Wrapper(true), true); 171testEqual(new Wrapper(true), 1); 172testEqual(new Wrapper(false), false); 173testEqual(new Wrapper(false), 0); 174 175testEqual(new Wrapper2(true), true); 176testEqual(new Wrapper2(true), 1); 177testEqual(new Wrapper2(false), false); 178testEqual(new Wrapper2(false), 0); 179 180testEqual(new Number(1), true); 181testEqual(new Number(1), 1); 182testEqual(new Number(0), false); 183testEqual(new Number(0), 0); 184 185// Date objects convert to string, not number (and the string does not 186// convert to the number). 187testEqual(new Date(42), String(new Date(42))); 188testNotEqual(new Date(42), Number(new Date(42))); 189var dnow = new Date(); 190testEqual(dnow, dnow); 191testEqual(dnow, String(dnow)); 192testNotEqual(dnow, Number(dnow)); 193 194// Doesn't just call toString, but uses ToPrimitive which tries toString first 195// and valueOf second. 196dnow.toString = null; 197testEqual(dnow, Number(dnow)); 198dnow.valueOf = function () { return "42"; }; 199testEqual(dnow, 42); 200dnow.toString = function () { return "1"; }; 201testEqual(dnow, true); 202 203 204// Objects compared to other objects, or to null and undefined, are not 205// converted to primitive. 206testNotEqual(new Wrapper(null), new Wrapper(null)); 207testNotEqual(new Boolean(true), new Boolean(true)); 208testNotEqual(new Boolean(false), new Boolean(false)); 209testNotEqual(new String("a"), new String("a")); 210testNotEqual(new Number(42), new Number(42)); 211testNotEqual(new Date(42), new Date(42)); 212testNotEqual(new Array(42), new Array(42)); 213testNotEqual(new Object(), new Object()); 214 215// Object that can't be converted to primitive. 216var badObject = { 217 valueOf: null, 218 toString: function() { 219 return this; // Not primitive. 220 } 221}; 222 223testEqual(badObject, badObject); 224testNotEqual(badObject, {}); 225testNotEqual(badObject, null); 226testNotEqual(badObject, undefined); 227// Forcing conversion will throw. 228function 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} 234testBadConversion(0); 235testBadConversion("string"); 236testBadConversion(true); 237