1// Copyright 2013 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 28assertEquals(1, Array.prototype.find.length); 29 30var a = [21, 22, 23, 24]; 31assertEquals(undefined, a.find(function() { return false; })); 32assertEquals(21, a.find(function() { return true; })); 33assertEquals(undefined, a.find(function(val) { return 121 === val; })); 34assertEquals(24, a.find(function(val) { return 24 === val; })); 35assertEquals(23, a.find(function(val) { return 23 === val; }), null); 36assertEquals(22, a.find(function(val) { return 22 === val; }), undefined); 37 38 39// 40// Test predicate is not called when array is empty 41// 42(function() { 43 var a = []; 44 var l = -1; 45 var o = -1; 46 var v = -1; 47 var k = -1; 48 49 a.find(function(val, key, obj) { 50 o = obj; 51 l = obj.length; 52 v = val; 53 k = key; 54 55 return false; 56 }); 57 58 assertEquals(-1, l); 59 assertEquals(-1, o); 60 assertEquals(-1, v); 61 assertEquals(-1, k); 62})(); 63 64 65// 66// Test predicate is called with correct argumetns 67// 68(function() { 69 var a = ["b"]; 70 var l = -1; 71 var o = -1; 72 var v = -1; 73 var k = -1; 74 75 var found = a.find(function(val, key, obj) { 76 o = obj; 77 l = obj.length; 78 v = val; 79 k = key; 80 81 return false; 82 }); 83 84 assertArrayEquals(a, o); 85 assertEquals(a.length, l); 86 assertEquals("b", v); 87 assertEquals(0, k); 88 assertEquals(undefined, found); 89})(); 90 91 92// 93// Test predicate is called array.length times 94// 95(function() { 96 var a = [1, 2, 3, 4, 5]; 97 var l = 0; 98 var found = a.find(function() { 99 l++; 100 return false; 101 }); 102 103 assertEquals(a.length, l); 104 assertEquals(undefined, found); 105})(); 106 107 108// 109// Test Array.prototype.find works with String 110// 111(function() { 112 var a = "abcd"; 113 var l = -1; 114 var o = -1; 115 var v = -1; 116 var k = -1; 117 var found = Array.prototype.find.call(a, function(val, key, obj) { 118 o = obj.toString(); 119 l = obj.length; 120 v = val; 121 k = key; 122 123 return false; 124 }); 125 126 assertEquals(a, o); 127 assertEquals(a.length, l); 128 assertEquals("d", v); 129 assertEquals(3, k); 130 assertEquals(undefined, found); 131 132 found = Array.prototype.find.apply(a, [function(val, key, obj) { 133 o = obj.toString(); 134 l = obj.length; 135 v = val; 136 k = key; 137 138 return true; 139 }]); 140 141 assertEquals(a, o); 142 assertEquals(a.length, l); 143 assertEquals("a", v); 144 assertEquals(0, k); 145 assertEquals("a", found); 146})(); 147 148 149// 150// Test Array.prototype.find works with exotic object 151// 152(function() { 153 var l = -1; 154 var o = -1; 155 var v = -1; 156 var k = -1; 157 var a = { 158 prop1: "val1", 159 prop2: "val2", 160 isValid: function() { 161 return this.prop1 === "val1" && this.prop2 === "val2"; 162 } 163 }; 164 165 Array.prototype.push.apply(a, [30, 31, 32]); 166 var found = Array.prototype.find.call(a, function(val, key, obj) { 167 o = obj; 168 l = obj.length; 169 v = val; 170 k = key; 171 172 return !obj.isValid(); 173 }); 174 175 assertArrayEquals(a, o); 176 assertEquals(3, l); 177 assertEquals(32, v); 178 assertEquals(2, k); 179 assertEquals(undefined, found); 180})(); 181 182 183// 184// Test array modifications 185// 186(function() { 187 var a = [1, 2, 3]; 188 var found = a.find(function(val) { a.push(val); return false; }); 189 assertArrayEquals([1, 2, 3, 1, 2, 3], a); 190 assertEquals(6, a.length); 191 assertEquals(undefined, found); 192 193 a = [1, 2, 3]; 194 found = a.find(function(val, key) { a[key] = ++val; return false; }); 195 assertArrayEquals([2, 3, 4], a); 196 assertEquals(3, a.length); 197 assertEquals(undefined, found); 198})(); 199 200 201// 202// Test predicate is called for holes 203// 204(function() { 205 var a = new Array(30); 206 a[11] = 21; 207 a[7] = 10; 208 a[29] = 31; 209 210 var count = 0; 211 a.find(function() { count++; return false; }); 212 assertEquals(30, count); 213})(); 214 215 216(function() { 217 var a = [0, 1, , 3]; 218 var count = 0; 219 var found = a.find(function(val) { return val === undefined; }); 220 assertEquals(undefined, found); 221})(); 222 223 224(function() { 225 var a = [0, 1, , 3]; 226 a.__proto__ = { 227 __proto__: Array.prototype, 228 2: 42, 229 }; 230 var count = 0; 231 var found = a.find(function(val) { return val === 42; }); 232 assertEquals(42, found); 233})(); 234 235 236// 237// Test thisArg 238// 239(function() { 240 // Test String as a thisArg 241 var found = [1, 2, 3].find(function(val, key) { 242 return this.charAt(Number(key)) === String(val); 243 }, "321"); 244 assertEquals(2, found); 245 246 // Test object as a thisArg 247 var thisArg = { 248 elementAt: function(key) { 249 return this[key]; 250 } 251 }; 252 Array.prototype.push.apply(thisArg, ["c", "b", "a"]); 253 254 found = ["a", "b", "c"].find(function(val, key) { 255 return this.elementAt(key) === val; 256 }, thisArg); 257 assertEquals("b", found); 258 259 // Create a new object in each function call when receiver is a 260 // primitive value. See ECMA-262, Annex C. 261 a = []; 262 [1, 2].find(function() { a.push(this) }, ""); 263 assertTrue(a[0] !== a[1]); 264 265 // Do not create a new object otherwise. 266 a = []; 267 [1, 2].find(function() { a.push(this) }, {}); 268 assertEquals(a[0], a[1]); 269 270 // In strict mode primitive values should not be coerced to an object. 271 a = []; 272 [1, 2].find(function() { 'use strict'; a.push(this); }, ""); 273 assertEquals("", a[0]); 274 assertEquals(a[0], a[1]); 275 276})(); 277 278// Test exceptions 279assertThrows('Array.prototype.find.call(null, function() { })', 280 TypeError); 281assertThrows('Array.prototype.find.call(undefined, function() { })', 282 TypeError); 283assertThrows('Array.prototype.find.apply(null, function() { }, [])', 284 TypeError); 285assertThrows('Array.prototype.find.apply(undefined, function() { }, [])', 286 TypeError); 287 288assertThrows('[].find(null)', TypeError); 289assertThrows('[].find(undefined)', TypeError); 290assertThrows('[].find(0)', TypeError); 291assertThrows('[].find(true)', TypeError); 292assertThrows('[].find(false)', TypeError); 293assertThrows('[].find("")', TypeError); 294assertThrows('[].find({})', TypeError); 295assertThrows('[].find([])', TypeError); 296assertThrows('[].find(/\d+/)', TypeError); 297 298assertThrows('Array.prototype.find.call({}, null)', TypeError); 299assertThrows('Array.prototype.find.call({}, undefined)', TypeError); 300assertThrows('Array.prototype.find.call({}, 0)', TypeError); 301assertThrows('Array.prototype.find.call({}, true)', TypeError); 302assertThrows('Array.prototype.find.call({}, false)', TypeError); 303assertThrows('Array.prototype.find.call({}, "")', TypeError); 304assertThrows('Array.prototype.find.call({}, {})', TypeError); 305assertThrows('Array.prototype.find.call({}, [])', TypeError); 306assertThrows('Array.prototype.find.call({}, /\d+/)', TypeError); 307 308assertThrows('Array.prototype.find.apply({}, null, [])', TypeError); 309assertThrows('Array.prototype.find.apply({}, undefined, [])', TypeError); 310assertThrows('Array.prototype.find.apply({}, 0, [])', TypeError); 311assertThrows('Array.prototype.find.apply({}, true, [])', TypeError); 312assertThrows('Array.prototype.find.apply({}, false, [])', TypeError); 313assertThrows('Array.prototype.find.apply({}, "", [])', TypeError); 314assertThrows('Array.prototype.find.apply({}, {}, [])', TypeError); 315assertThrows('Array.prototype.find.apply({}, [], [])', TypeError); 316assertThrows('Array.prototype.find.apply({}, /\d+/, [])', TypeError); 317