v8/test/mjsunit/harmony/string-replaceAll.js
Joshua Litt 94890a0d46 [replaceAll] Implement String.prototype.replaceAll.
Implements TC39 String.prototype.replaceAll as a torque
builtin per the https://github.com/tc39/proposal-string-replaceall
proposal.

Note: matchAll changes were already added to V8 in https://chromium-review.googlesource.com/c/v8/v8/+/1846067

Bug: v8:9801
Change-Id: Ib8158eb39c854202d04710d6f9c33dcdd93fad93
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1877054
Commit-Queue: Joshua Litt <joshualitt@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64785}
2019-11-05 19:00:29 +00:00

101 lines
2.6 KiB
JavaScript

// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --harmony-string-replaceall
assertEquals('a-b-c-d', 'a+b+c+d'.replaceAll('+', '-'));
assertEquals('aaaa', 'abcd'.replaceAll(/./g, 'a'));
assertEquals('', ''.replaceAll('a', 'b'));
assertEquals('b', ''.replaceAll('', 'b'));
assertEquals('_x_x_x_', 'xxx'.replaceAll('', '_'));
assertEquals('yx', 'xxx'.replaceAll('xx', 'y'));
assertEquals('xxxx', 'xx'.replaceAll('xx', '$&$&'));
assertEquals('ii', '.+*$.+*$'.replaceAll('.+*$', 'i'));
{
// Non regexp search value with replace method.
const nonRegExpSearchValue = {
[Symbol.replace]: (string, replacer) => {
assertEquals(string, 'barbar');
assertEquals(replacer, 'moo');
return 'foo'
},
toString: () => {
// Verify toString is not called.
unreachable();
}
};
assertEquals('foo', 'barbar'.replaceAll(nonRegExpSearchValue, 'moo'));
}
{
// A custom regexp with non coercible flags.
class RegExpNonCoercibleFlags extends RegExp {
constructor() {
super();
}
static get [Symbol.species]() {
return RegExp;
}
get flags() { return null; }
};
assertThrows(
() => { assertEquals(
'foo',
'barbar'.replaceAll(new RegExpNonCoercibleFlags, 'moo')); },
TypeError);
}
{
// Non regexp search value with replace property
const nonRegExpSearchValue = {
[Symbol.replace]: "doh",
toString: () => {
// Verify toString is not called.
unreachable();
}
};
assertThrows(
() => { 'barbar'.replaceAll(nonRegExpSearchValue, 'moo'); },
TypeError);
}
{
// Non callable, non string replace value.
const nonCallableNonStringReplace = {
toString: () => {
return 'boo';
},
};
assertEquals('booboo', 'moomoo'.replaceAll('moo', nonCallableNonStringReplace));
}
{
const positions = [];
assertEquals('bcb', 'aca'.replaceAll('a',
(searchString, position, string) => {
assertEquals('a', searchString);
assertEquals('aca', string);
positions.push(position);
return 'b';
}));
assertEquals(positions, [0,2]);
}
(function NonGlobalRegex() {
assertThrows(
() => { 'ab'.replaceAll(/./, '.'); },
TypeError);
assertThrows(
() => { 'ab'.replaceAll(/./y, '.'); },
TypeError);
})();
// Tests for stickiness gotcha.
assertEquals('o ppercase!', 'No Uppercase!'.replaceAll(/[A-Z]/g, ''));
assertEquals('o Uppercase?', 'No Uppercase?'.replaceAll(/[A-Z]/gy, ''));
assertEquals(' UPPERCASE!', 'NO UPPERCASE!'.replaceAll(/[A-Z]/gy, ''));