1// Copyright 2014 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// Flags: --harmony-strings
29
30assertEquals(1, String.prototype.startsWith.length);
31
32var testString = "Hello World";
33assertTrue(testString.startsWith(""));
34assertTrue(testString.startsWith("Hello"));
35assertFalse(testString.startsWith("hello"));
36assertFalse(testString.startsWith("Hello World!"));
37assertFalse(testString.startsWith(null));
38assertFalse(testString.startsWith(undefined));
39
40assertTrue("null".startsWith(null));
41assertTrue("undefined".startsWith(undefined));
42
43var georgianUnicodeString = "\u10D0\u10D1\u10D2\u10D3\u10D4\u10D5\u10D6\u10D7";
44assertTrue(georgianUnicodeString.startsWith(georgianUnicodeString));
45assertTrue(georgianUnicodeString.startsWith("\u10D0\u10D1\u10D2"));
46assertFalse(georgianUnicodeString.startsWith("\u10D8"));
47
48assertThrows("String.prototype.startsWith.call(null, 'test')", TypeError);
49assertThrows("String.prototype.startsWith.call(null, null)", TypeError);
50assertThrows("String.prototype.startsWith.call(undefined, undefined)", TypeError);
51
52assertThrows("String.prototype.startsWith.apply(null, ['test'])", TypeError);
53assertThrows("String.prototype.startsWith.apply(null, [null])", TypeError);
54assertThrows("String.prototype.startsWith.apply(undefined, [undefined])", TypeError);
55
56var TEST_INPUT = [{
57  msg: "Empty string", val: ""
58}, {
59  msg: "Number 1234.34", val: 1234.34
60}, {
61  msg: "Integer number 0", val: 0
62}, {
63  msg: "Negative number -1", val: -1
64}, {
65  msg: "Boolean true", val: true
66}, {
67  msg: "Boolean false", val: false
68}, {
69  msg: "Empty array []", val: []
70}, {
71  msg: "Empty object {}", val: {}
72}, {
73  msg: "Array of size 3", val: new Array(3)
74}];
75
76function testNonStringValues() {
77  var i = 0;
78  var l = TEST_INPUT.length;
79
80  for (; i < l; i++) {
81    var e = TEST_INPUT[i];
82    var v = e.val;
83    var s = String(v);
84    assertTrue(s.startsWith(v), e.msg);
85    assertTrue(String.prototype.startsWith.call(v, v), e.msg);
86    assertTrue(String.prototype.startsWith.apply(v, [v]), e.msg);
87  }
88}
89testNonStringValues();
90
91var CustomType = function(value) {
92  this.startsWith = String.prototype.startsWith;
93  this.toString = function() {
94    return String(value);
95  }
96};
97
98function testCutomType() {
99  var i = 0;
100  var l = TEST_INPUT.length;
101
102  for (; i < l; i++) {
103    var e = TEST_INPUT[i];
104    var v = e.val;
105    var o = new CustomType(v);
106    assertTrue(o.startsWith(v), e.msg);
107  }
108}
109testCutomType();
110
111// Test cases found in FF
112assertTrue("abc".startsWith("abc"));
113assertTrue("abcd".startsWith("abc"));
114assertTrue("abc".startsWith("a"));
115assertFalse("abc".startsWith("abcd"));
116assertFalse("abc".startsWith("bcde"));
117assertFalse("abc".startsWith("b"));
118assertTrue("abc".startsWith("abc", 0));
119assertFalse("abc".startsWith("bc", 0));
120assertTrue("abc".startsWith("bc", 1));
121assertFalse("abc".startsWith("c", 1));
122assertFalse("abc".startsWith("abc", 1));
123assertTrue("abc".startsWith("c", 2));
124assertFalse("abc".startsWith("d", 2));
125assertFalse("abc".startsWith("dcd", 2));
126assertFalse("abc".startsWith("a", 42));
127assertFalse("abc".startsWith("a", Infinity));
128assertTrue("abc".startsWith("a", NaN));
129assertFalse("abc".startsWith("b", NaN));
130assertTrue("abc".startsWith("ab", -43));
131assertTrue("abc".startsWith("ab", -Infinity));
132assertFalse("abc".startsWith("bc", -42));
133assertFalse("abc".startsWith("bc", -Infinity));
134
135// Test cases taken from
136// https://github.com/mathiasbynens/String.prototype.startsWith/blob/master/tests/tests.js
137Object.prototype[1] = 2; // try to break `arguments[1]`
138
139assertEquals(String.prototype.startsWith.length, 1);
140assertEquals(String.prototype.propertyIsEnumerable("startsWith"), false);
141
142assertEquals("undefined".startsWith(), true);
143assertEquals("undefined".startsWith(undefined), true);
144assertEquals("undefined".startsWith(null), false);
145assertEquals("null".startsWith(), false);
146assertEquals("null".startsWith(undefined), false);
147assertEquals("null".startsWith(null), true);
148
149assertEquals("abc".startsWith(), false);
150assertEquals("abc".startsWith(""), true);
151assertEquals("abc".startsWith("\0"), false);
152assertEquals("abc".startsWith("a"), true);
153assertEquals("abc".startsWith("b"), false);
154assertEquals("abc".startsWith("ab"), true);
155assertEquals("abc".startsWith("bc"), false);
156assertEquals("abc".startsWith("abc"), true);
157assertEquals("abc".startsWith("bcd"), false);
158assertEquals("abc".startsWith("abcd"), false);
159assertEquals("abc".startsWith("bcde"), false);
160
161assertEquals("abc".startsWith("", NaN), true);
162assertEquals("abc".startsWith("\0", NaN), false);
163assertEquals("abc".startsWith("a", NaN), true);
164assertEquals("abc".startsWith("b", NaN), false);
165assertEquals("abc".startsWith("ab", NaN), true);
166assertEquals("abc".startsWith("bc", NaN), false);
167assertEquals("abc".startsWith("abc", NaN), true);
168assertEquals("abc".startsWith("bcd", NaN), false);
169assertEquals("abc".startsWith("abcd", NaN), false);
170assertEquals("abc".startsWith("bcde", NaN), false);
171
172assertEquals("abc".startsWith("", false), true);
173assertEquals("abc".startsWith("\0", false), false);
174assertEquals("abc".startsWith("a", false), true);
175assertEquals("abc".startsWith("b", false), false);
176assertEquals("abc".startsWith("ab", false), true);
177assertEquals("abc".startsWith("bc", false), false);
178assertEquals("abc".startsWith("abc", false), true);
179assertEquals("abc".startsWith("bcd", false), false);
180assertEquals("abc".startsWith("abcd", false), false);
181assertEquals("abc".startsWith("bcde", false), false);
182
183assertEquals("abc".startsWith("", undefined), true);
184assertEquals("abc".startsWith("\0", undefined), false);
185assertEquals("abc".startsWith("a", undefined), true);
186assertEquals("abc".startsWith("b", undefined), false);
187assertEquals("abc".startsWith("ab", undefined), true);
188assertEquals("abc".startsWith("bc", undefined), false);
189assertEquals("abc".startsWith("abc", undefined), true);
190assertEquals("abc".startsWith("bcd", undefined), false);
191assertEquals("abc".startsWith("abcd", undefined), false);
192assertEquals("abc".startsWith("bcde", undefined), false);
193
194assertEquals("abc".startsWith("", null), true);
195assertEquals("abc".startsWith("\0", null), false);
196assertEquals("abc".startsWith("a", null), true);
197assertEquals("abc".startsWith("b", null), false);
198assertEquals("abc".startsWith("ab", null), true);
199assertEquals("abc".startsWith("bc", null), false);
200assertEquals("abc".startsWith("abc", null), true);
201assertEquals("abc".startsWith("bcd", null), false);
202assertEquals("abc".startsWith("abcd", null), false);
203assertEquals("abc".startsWith("bcde", null), false);
204
205assertEquals("abc".startsWith("", -Infinity), true);
206assertEquals("abc".startsWith("\0", -Infinity), false);
207assertEquals("abc".startsWith("a", -Infinity), true);
208assertEquals("abc".startsWith("b", -Infinity), false);
209assertEquals("abc".startsWith("ab", -Infinity), true);
210assertEquals("abc".startsWith("bc", -Infinity), false);
211assertEquals("abc".startsWith("abc", -Infinity), true);
212assertEquals("abc".startsWith("bcd", -Infinity), false);
213assertEquals("abc".startsWith("abcd", -Infinity), false);
214assertEquals("abc".startsWith("bcde", -Infinity), false);
215
216assertEquals("abc".startsWith("", -1), true);
217assertEquals("abc".startsWith("\0", -1), false);
218assertEquals("abc".startsWith("a", -1), true);
219assertEquals("abc".startsWith("b", -1), false);
220assertEquals("abc".startsWith("ab", -1), true);
221assertEquals("abc".startsWith("bc", -1), false);
222assertEquals("abc".startsWith("abc", -1), true);
223assertEquals("abc".startsWith("bcd", -1), false);
224assertEquals("abc".startsWith("abcd", -1), false);
225assertEquals("abc".startsWith("bcde", -1), false);
226
227assertEquals("abc".startsWith("", -0), true);
228assertEquals("abc".startsWith("\0", -0), false);
229assertEquals("abc".startsWith("a", -0), true);
230assertEquals("abc".startsWith("b", -0), false);
231assertEquals("abc".startsWith("ab", -0), true);
232assertEquals("abc".startsWith("bc", -0), false);
233assertEquals("abc".startsWith("abc", -0), true);
234assertEquals("abc".startsWith("bcd", -0), false);
235assertEquals("abc".startsWith("abcd", -0), false);
236assertEquals("abc".startsWith("bcde", -0), false);
237
238assertEquals("abc".startsWith("", +0), true);
239assertEquals("abc".startsWith("\0", +0), false);
240assertEquals("abc".startsWith("a", +0), true);
241assertEquals("abc".startsWith("b", +0), false);
242assertEquals("abc".startsWith("ab", +0), true);
243assertEquals("abc".startsWith("bc", +0), false);
244assertEquals("abc".startsWith("abc", +0), true);
245assertEquals("abc".startsWith("bcd", +0), false);
246assertEquals("abc".startsWith("abcd", +0), false);
247assertEquals("abc".startsWith("bcde", +0), false);
248
249assertEquals("abc".startsWith("", 1), true);
250assertEquals("abc".startsWith("\0", 1), false);
251assertEquals("abc".startsWith("a", 1), false);
252assertEquals("abc".startsWith("b", 1), true);
253assertEquals("abc".startsWith("ab", 1), false);
254assertEquals("abc".startsWith("bc", 1), true);
255assertEquals("abc".startsWith("abc", 1), false);
256assertEquals("abc".startsWith("bcd", 1), false);
257assertEquals("abc".startsWith("abcd", 1), false);
258assertEquals("abc".startsWith("bcde", 1), false);
259
260assertEquals("abc".startsWith("", +Infinity), true);
261assertEquals("abc".startsWith("\0", +Infinity), false);
262assertEquals("abc".startsWith("a", +Infinity), false);
263assertEquals("abc".startsWith("b", +Infinity), false);
264assertEquals("abc".startsWith("ab", +Infinity), false);
265assertEquals("abc".startsWith("bc", +Infinity), false);
266assertEquals("abc".startsWith("abc", +Infinity), false);
267assertEquals("abc".startsWith("bcd", +Infinity), false);
268assertEquals("abc".startsWith("abcd", +Infinity), false);
269assertEquals("abc".startsWith("bcde", +Infinity), false);
270
271assertEquals("abc".startsWith("", true), true);
272assertEquals("abc".startsWith("\0", true), false);
273assertEquals("abc".startsWith("a", true), false);
274assertEquals("abc".startsWith("b", true), true);
275assertEquals("abc".startsWith("ab", true), false);
276assertEquals("abc".startsWith("bc", true), true);
277assertEquals("abc".startsWith("abc", true), false);
278assertEquals("abc".startsWith("bcd", true), false);
279assertEquals("abc".startsWith("abcd", true), false);
280assertEquals("abc".startsWith("bcde", true), false);
281
282assertEquals("abc".startsWith("", "x"), true);
283assertEquals("abc".startsWith("\0", "x"), false);
284assertEquals("abc".startsWith("a", "x"), true);
285assertEquals("abc".startsWith("b", "x"), false);
286assertEquals("abc".startsWith("ab", "x"), true);
287assertEquals("abc".startsWith("bc", "x"), false);
288assertEquals("abc".startsWith("abc", "x"), true);
289assertEquals("abc".startsWith("bcd", "x"), false);
290assertEquals("abc".startsWith("abcd", "x"), false);
291assertEquals("abc".startsWith("bcde", "x"), false);
292
293assertEquals("[a-z]+(bar)?".startsWith("[a-z]+"), true);
294assertThrows(function() { "[a-z]+(bar)?".startsWith(/[a-z]+/); }, TypeError);
295assertEquals("[a-z]+(bar)?".startsWith("(bar)?", 6), true);
296assertThrows(function() { "[a-z]+(bar)?".startsWith(/(bar)?/); }, TypeError);
297assertThrows(function() { "[a-z]+/(bar)?/".startsWith(/(bar)?/); }, TypeError);
298
299// http://mathiasbynens.be/notes/javascript-unicode#poo-test
300var string = "I\xF1t\xEBrn\xE2ti\xF4n\xE0liz\xE6ti\xF8n\u2603\uD83D\uDCA9";
301assertEquals(string.startsWith(""), true);
302assertEquals(string.startsWith("\xF1t\xEBr"), false);
303assertEquals(string.startsWith("\xF1t\xEBr", 1), true);
304assertEquals(string.startsWith("\xE0liz\xE6"), false);
305assertEquals(string.startsWith("\xE0liz\xE6", 11), true);
306assertEquals(string.startsWith("\xF8n\u2603\uD83D\uDCA9"), false);
307assertEquals(string.startsWith("\xF8n\u2603\uD83D\uDCA9", 18), true);
308assertEquals(string.startsWith("\u2603"), false);
309assertEquals(string.startsWith("\u2603", 20), true);
310assertEquals(string.startsWith("\uD83D\uDCA9"), false);
311assertEquals(string.startsWith("\uD83D\uDCA9", 21), true);
312
313assertThrows(function() {
314  String.prototype.startsWith.call(undefined);
315}, TypeError);
316assertThrows(function() {
317  String.prototype.startsWith.call(undefined, "b");
318}, TypeError);
319assertThrows(function() {
320  String.prototype.startsWith.call(undefined, "b", 4);
321}, TypeError);
322assertThrows(function() {
323  String.prototype.startsWith.call(null);
324}, TypeError);
325assertThrows(function() {
326  String.prototype.startsWith.call(null, "b");
327}, TypeError);
328assertThrows(function() {
329  String.prototype.startsWith.call(null, "b", 4);
330}, TypeError);
331assertEquals(String.prototype.startsWith.call(42, "2"), false);
332assertEquals(String.prototype.startsWith.call(42, "4"), true);
333assertEquals(String.prototype.startsWith.call(42, "b", 4), false);
334assertEquals(String.prototype.startsWith.call(42, "2", 1), true);
335assertEquals(String.prototype.startsWith.call(42, "2", 4), false);
336assertEquals(String.prototype.startsWith.call({
337  "toString": function() { return "abc"; }
338}, "b", 0), false);
339assertEquals(String.prototype.startsWith.call({
340  "toString": function() { return "abc"; }
341}, "b", 1), true);
342assertEquals(String.prototype.startsWith.call({
343  "toString": function() { return "abc"; }
344}, "b", 2), false);
345assertThrows(function() {
346  String.prototype.startsWith.call({
347    "toString": function() { throw RangeError(); }
348  }, /./);
349}, RangeError);
350assertThrows(function() {
351  String.prototype.startsWith.call({
352    "toString": function() { return "abc"; }
353  }, /./);
354}, TypeError);
355
356assertThrows(function() {
357  String.prototype.startsWith.apply(undefined);
358}, TypeError);
359assertThrows(function() {
360  String.prototype.startsWith.apply(undefined, ["b"]);
361}, TypeError);
362assertThrows(function() {
363  String.prototype.startsWith.apply(undefined, ["b", 4]);
364}, TypeError);
365assertThrows(function() {
366  String.prototype.startsWith.apply(null);
367}, TypeError);
368assertThrows(function() {
369  String.prototype.startsWith.apply(null, ["b"]);
370}, TypeError);
371assertThrows(function() {
372  String.prototype.startsWith.apply(null, ["b", 4]);
373}, TypeError);
374assertEquals(String.prototype.startsWith.apply(42, ["2"]), false);
375assertEquals(String.prototype.startsWith.apply(42, ["4"]), true);
376assertEquals(String.prototype.startsWith.apply(42, ["b", 4]), false);
377assertEquals(String.prototype.startsWith.apply(42, ["2", 1]), true);
378assertEquals(String.prototype.startsWith.apply(42, ["2", 4]), false);
379assertEquals(String.prototype.startsWith.apply({
380  "toString": function() {
381    return "abc";
382  }
383}, ["b", 0]), false);
384assertEquals(String.prototype.startsWith.apply({
385  "toString": function() {
386    return "abc";
387  }
388}, ["b", 1]), true);
389assertEquals(String.prototype.startsWith.apply({
390  "toString": function() {
391    return "abc";
392  }
393}, ["b", 2]), false);
394assertThrows(function() {
395  String.prototype.startsWith.apply({
396    "toString": function() { throw RangeError(); }
397  }, [/./]);
398}, RangeError);
399assertThrows(function() {
400  String.prototype.startsWith.apply({
401    "toString": function() { return "abc"; }
402  }, [/./]);
403}, TypeError);
404