// 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 --allow-natives-syntax 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, '')); // Tests for slow path. assertEquals('a', 'a'.replaceAll(%ConstructConsString('abcdefghijklmn', 'def'), 'b')); assertEquals('b', 'abcdefghijklmndef'.replaceAll( %ConstructConsString('abcdefghijklmn', 'def'), 'b')); assertEquals('aaaaaaaaaaaaaaaaaa', 'aaaaaaaaaaaaaaaaaa'.replaceAll( %ConstructConsString('abcdefghijklmn', 'def'), 'b'));