1 /* 2 * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* @test 25 * @bug 8058779 8054307 26 * @library /test/lib 27 * @run testng LiteralReplace 28 * @summary Basic tests of String.replace(CharSequence, CharSequence) 29 * @key randomness 30 */ 31 32 import java.util.ArrayList; 33 import java.util.Arrays; 34 import java.util.Iterator; 35 import java.util.regex.Matcher; 36 import java.util.regex.Pattern; 37 import java.util.Random; 38 39 import jdk.test.lib.RandomFactory; 40 41 import org.testng.annotations.Test; 42 import org.testng.annotations.DataProvider; 43 import static org.testng.Assert.fail; 44 45 public class LiteralReplace { 46 47 @Test(dataProvider="sourceTargetReplacementExpected") 48 public void testExpected(String source, String target, 49 String replacement, String expected) 50 { 51 String canonical = canonicalReplace(source, target, replacement); 52 if (!canonical.equals(expected)) { 53 fail("Canonical: " + canonical + " != " + expected); 54 } 55 test0(source, target, replacement, expected); 56 } 57 58 @Test(dataProvider="sourceTargetReplacement") 59 public void testCanonical(String source, String target, 60 String replacement) 61 { 62 String canonical = canonicalReplace(source, target, replacement); 63 test0(source, target, replacement, canonical); 64 } 65 66 private void test0(String source, String target, String replacement, 67 String expected) 68 { 69 String result = source.replace(target, replacement); 70 if (!result.equals(expected)) { 71 fail(result + " != " + expected); 72 } 73 } 74 75 @Test(dataProvider="sourceTargetReplacementWithNull", 76 expectedExceptions = {NullPointerException.class}) 77 public void testNPE(String source, String target, String replacement) { 78 source.replace(target, replacement); 79 } 80 81 82 @DataProvider 83 public static Object[][] sourceTargetReplacementExpected() { 84 return new Object[][] { 85 {"aaa", "aa", "b", "ba"}, 86 {"abcdefgh", "def", "DEF", "abcDEFgh"}, 87 {"abcdefgh", "123", "DEF", "abcdefgh"}, 88 {"abcdefgh", "abcdefghi", "DEF", "abcdefgh"}, 89 {"abcdefghabc", "abc", "DEF", "DEFdefghDEF"}, 90 {"abcdefghdef", "def", "", "abcgh"}, 91 {"abcdefgh", "", "_", "_a_b_c_d_e_f_g_h_"}, 92 {"", "", "", ""}, 93 {"", "a", "b", ""}, 94 {"", "", "abc", "abc"}, 95 {"abcdefgh", "abcdefgh", "abcdefgh", "abcdefgh"}, 96 {"abcdefgh", "abcdefgh", "abcdefghi", "abcdefghi"}, 97 {"abcdefgh", "abcdefgh", "", ""}, 98 {"abcdabcd", "abcd", "", ""}, 99 {"aaaaaaaaa", "aa", "_X_", "_X__X__X__X_a"}, 100 {"aaaaaaaaa", "aa", "aaa", "aaaaaaaaaaaaa"}, 101 {"aaaaaaaaa", "aa", "aa", "aaaaaaaaa"}, 102 {"a.c.e.g.", ".", "-", "a-c-e-g-"}, 103 {"abcdefgh", "[a-h]", "X", "abcdefgh"}, 104 {"aa+", "a+", "", "a"}, 105 {"^abc$", "abc", "x", "^x$"}, 106 107 // more with non-latin1 characters 108 {"\u4e00\u4e00\u4e00", 109 "\u4e00\u4e00", 110 "\u4e01", 111 "\u4e01\u4e00"}, 112 113 {"\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05\u4e06\u4e07\u4e08", 114 "\u4e03\u4e04\u4e05", 115 "\u4e10\u4e11\u4e12", 116 "\u4e00\u4e01\u4e02\u4e10\u4e11\u4e12\u4e06\u4e07\u4e08"}, 117 118 {"\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05\u4e06\u4e07\u4e08", 119 "ABC", 120 "\u4e10\u4e11\u4e12", 121 "\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05\u4e06\u4e07\u4e08"}, 122 123 {"\u4e00\u4e01\u4e02\u4e03\u4e04\u4e02\u4e03\u4e07\u4e08", 124 "\u4e02\u4e03", 125 "\u4e12\u4e13", 126 "\u4e00\u4e01\u4e12\u4e13\u4e04\u4e12\u4e13\u4e07\u4e08"}, 127 128 {"\u4e00\u4e01\u4e02\u4e03\u4e04\u4e02\u4e03\u4e07\u4e08", 129 "\u4e02\u4e03", 130 "ab", 131 "\u4e00\u4e01ab\u4e04ab\u4e07\u4e08"}, 132 133 {"\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05\u4e06\u4e07", 134 "", 135 "_", 136 "_\u4e00_\u4e01_\u4e02_\u4e03_\u4e04_\u4e05_\u4e06_\u4e07_"}, 137 {"^\u4e00\u4e01\u4e02$", 138 "\u4e00\u4e01\u4e02", 139 "\u4e03", 140 "^\u4e03$"}, 141 142 {"", "\u4e00", "\u4e01", ""}, 143 {"", "", "\u4e00\u4e01\u4e02", "\u4e00\u4e01\u4e02"}, 144 145 {"^\u4e00\u4e01\u4e02$", 146 "\u4e00\u4e01\u4e02", 147 "X", 148 "^X$"}, 149 150 {"abcdefgh", 151 "def", 152 "\u4e01", 153 "abc\u4e01gh"}, 154 155 {"abcdefgh", 156 "def", 157 "\u4e01\u4e02", 158 "abc\u4e01\u4e02gh"}, 159 160 {"abcdefabcgh", 161 "abc", 162 "\u4e01\u4e02", 163 "\u4e01\u4e02def\u4e01\u4e02gh"}, 164 165 {"abcdefabcghabc", 166 "abc", 167 "\u4e01\u4e02", 168 "\u4e01\u4e02def\u4e01\u4e02gh\u4e01\u4e02"}, 169 170 {"\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05", 171 "\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05", 172 "abcd", 173 "abcd"}, 174 175 {"\u4e00\u4e01", 176 "\u4e00\u4e01", 177 "abcdefg", 178 "abcdefg"}, 179 180 {"\u4e00\u4e01xyz", 181 "\u4e00\u4e01", 182 "abcdefg", 183 "abcdefgxyz"}, 184 185 {"\u4e00\u4e00\u4e00\u4e00\u4e00\u4e00", 186 "\u4e00\u4e00", 187 "\u4e00\u4e00\u4e00", 188 "\u4e00\u4e00\u4e00\u4e00\u4e00\u4e00\u4e00\u4e00\u4e00"}, 189 190 {"\u4e00\u4e00\u4e00\u4e00\u4e00\u4e00", 191 "\u4e00\u4e00\u4e00", 192 "\u4e00\u4e00", 193 "\u4e00\u4e00\u4e00\u4e00"}, 194 195 {"\u4e00.\u4e01.\u4e02.\u4e03.\u4e04.", 196 ".", 197 "-", 198 "\u4e00-\u4e01-\u4e02-\u4e03-\u4e04-"}, 199 200 {"\u4e00\u4e00\u4e00\u4e00\u4e00\u4e00", 201 "\u4e00", 202 "", 203 ""}, 204 205 {"\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05", 206 "\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05", 207 "", 208 ""}, 209 }; 210 } 211 212 @DataProvider 213 public static Iterator<Object[]> sourceTargetReplacement() { 214 ArrayList<Object[]> list = new ArrayList<>(); 215 for (int maxSrcLen = 1; maxSrcLen <= (1 << 10); maxSrcLen <<= 1) { 216 for (int maxTrgLen = 1; maxTrgLen <= (1 << 10); maxTrgLen <<= 1) { 217 for (int maxPrlLen = 1; maxPrlLen <= (1 << 10); maxPrlLen <<= 1) { 218 list.add(makeArray(makeRandomString(maxSrcLen), 219 makeRandomString(maxTrgLen), 220 makeRandomString(maxPrlLen))); 221 222 String source = makeRandomString(maxSrcLen); 223 list.add(makeArray(source, 224 mekeRandomSubstring(source, maxTrgLen), 225 makeRandomString(maxPrlLen))); 226 } 227 } 228 } 229 return list.iterator(); 230 } 231 232 @DataProvider 233 public static Iterator<Object[]> sourceTargetReplacementWithNull() { 234 ArrayList<Object[]> list = new ArrayList<>(); 235 Object[] arr = {null, "", "a", "b", "string", "str", "ababstrstr"}; 236 for (int i = 0; i < arr.length; ++i) { 237 for (int j = 0; j < arr.length; ++j) { 238 for (int k = 0; k < arr.length; ++k) { 239 if (arr[i] != null && (arr[j] == null || arr[k] == null)) { 240 list.add(makeArray(arr[i], arr[j], arr[k])); 241 } 242 } 243 } 244 } 245 return list.iterator(); 246 } 247 248 // utilities 249 250 /** 251 * How the String.replace(CharSequence, CharSequence) used to be implemented 252 */ 253 private static String canonicalReplace(String source, String target, String replacement) { 254 return Pattern.compile(target.toString(), Pattern.LITERAL).matcher( 255 source).replaceAll(Matcher.quoteReplacement(replacement.toString())); 256 } 257 258 private static final Random random = RandomFactory.getRandom(); 259 260 private static final char[] CHARS = ("qwertyuiop[]12345678" + 261 "90-=\\`asdfghjkl;'zxcvbnm,./~!@#$%^&*()_+|QWERTYUIOP{" + 262 "}ASDFGHJKL:\"ZXCVBNM<>?\n\r\t\u0444\u044B\u0432\u0430").toCharArray(); 263 264 private static String makeRandomString(int maxLen) { 265 int len = random.nextInt(maxLen); 266 char[] buf = new char[len]; 267 for (int i = 0; i < len; ++i) { 268 buf[i] = CHARS[random.nextInt(CHARS.length)]; 269 } 270 return new String(buf); 271 } 272 273 private static String mekeRandomSubstring(String source, int maxLen) { 274 if (source.isEmpty()) { 275 return source; 276 } 277 int pos = random.nextInt(source.length()); 278 int len = Integer.min(source.length() - pos, 279 random.nextInt(maxLen)); 280 return source.substring(pos, pos + len); 281 } 282 283 private static Object[] makeArray(Object... array) { 284 return array; 285 } 286 }