1 /* 2 * Copyright (c) 2015, 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 26 * @run testng LiteralReplace 27 * @summary Basic tests of String.replace(CharSequence, CharSequence) 28 * @key randomness 29 */ 30 31 import java.util.ArrayList; 32 import java.util.Arrays; 33 import java.util.Iterator; 34 import java.util.regex.Matcher; 35 import java.util.regex.Pattern; 36 import java.util.Random; 37 import sun.misc.JavaLangAccess; 38 import sun.misc.SharedSecrets; 39 40 import org.testng.annotations.Test; 41 import org.testng.annotations.DataProvider; 42 import static org.testng.Assert.fail; 43 44 public class LiteralReplace { 45 46 @Test(dataProvider="sourceTargetReplacementExpected") 47 public void testExpected(String source, String target, 48 String replacement, String expected) 49 { 50 String canonical = canonicalReplace(source, target, replacement); 51 if (!canonical.equals(expected)) { 52 fail("Canonical: " + canonical + " != " + expected); 53 } 54 test0(source, target, replacement, expected); 55 } 56 57 @Test(dataProvider="sourceTargetReplacement") 58 public void testCanonical(String source, String target, 59 String replacement) 60 { 61 String canonical = canonicalReplace(source, target, replacement); 62 test0(source, target, replacement, canonical); 63 } 64 65 private void test0(String source, String target, String replacement, 66 String expected) 67 { 68 String result = source.replace(target, replacement); 69 if (!result.equals(expected)) { 70 fail(result + " != " + expected); 71 } 72 } 73 74 @Test(dataProvider="sourceTargetReplacementWithNull") 75 public void testNPE(String source, String target, String replacement) { 76 try { 77 source.replace(target, replacement); 78 fail("Expected to throw NPE: " + source + ".replace(" + target + 79 "," + replacement + ")"); 80 } catch (NullPointerException npe) { 81 } 82 } 83 84 85 @DataProvider 86 public static Object[][] sourceTargetReplacementExpected() { 87 return new Object[][] { 88 {"aaa", "aa", "b", "ba"}, 89 {"abcdefgh", "def", "DEF", "abcDEFgh"}, 90 {"abcdefgh", "123", "DEF", "abcdefgh"}, 91 {"abcdefgh", "abcdefghi", "DEF", "abcdefgh"}, 92 {"abcdefghabc", "abc", "DEF", "DEFdefghDEF"}, 93 {"abcdefghdef", "def", "", "abcgh"}, 94 {"abcdefgh", "", "_", "_a_b_c_d_e_f_g_h_"}, 95 {"", "", "", ""}, 96 {"", "a", "b", ""}, 97 {"", "", "abc", "abc"}, 98 {"abcdefgh", "abcdefgh", "abcdefgh", "abcdefgh"}, 99 {"abcdefgh", "abcdefgh", "abcdefghi", "abcdefghi"}, 100 {"abcdefgh", "abcdefgh", "", ""}, 101 {"abcdabcd", "abcd", "", ""}, 102 {"aaaaaaaaa", "aa", "_X_", "_X__X__X__X_a"}, 103 {"aaaaaaaaa", "aa", "aaa", "aaaaaaaaaaaaa"}, 104 {"aaaaaaaaa", "aa", "aa", "aaaaaaaaa"}, 105 {"a.c.e.g.", ".", "-", "a-c-e-g-"}, 106 {"abcdefgh", "[a-h]", "X", "abcdefgh"}, 107 {"aa+", "a+", "", "a"}, 108 {"^abc$", "abc", "x", "^x$"}, 109 }; 110 } 111 112 @DataProvider 113 public static Object[][] sourceTargetReplacementWithNull() { 114 return new Object[][] { 115 {"a", "a", null}, 116 {"a", "b", null}, 117 {"a", null, "a"}, 118 {"a", null, "b"}, 119 {"a", null, null}, 120 {null, "a", "a"}, 121 {null, "a", "b"}, 122 {null, "a", null}, 123 {null, null, "a"}, 124 {null, null, null}, 125 }; 126 } 127 128 @DataProvider 129 public static Iterator<Object[]> sourceTargetReplacement() { 130 ArrayList<Object[]> list = new ArrayList<>(); 131 for (int maxSrcLen = 1; maxSrcLen <= (1 << 10); maxSrcLen <<= 1) { 132 for (int maxTrgLen = 1; maxTrgLen <= (1 << 10); maxTrgLen <<= 1) { 133 for (int maxPrlLen = 1; maxPrlLen <= (1 << 10); maxPrlLen <<= 1) { 134 list.add(makeArray(makeRandomString(maxSrcLen), 135 makeRandomString(maxTrgLen), 136 makeRandomString(maxPrlLen))); 137 138 String source = makeRandomString(maxSrcLen); 139 list.add(makeArray(source, 140 mekeRandomSubstring(source, maxTrgLen), 141 makeRandomString(maxPrlLen))); 142 } 143 } 144 } 145 return list.iterator(); 146 } 147 148 // utilities 149 150 /** 151 * How the String.replace(CharSequence, CharSequence) used to be implemented 152 */ 153 private static String canonicalReplace(String source, String target, String replacement) { 154 return Pattern.compile(target.toString(), Pattern.LITERAL).matcher( 155 source).replaceAll(Matcher.quoteReplacement(replacement.toString())); 156 } 157 158 private static final Random random = new Random(); 159 private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); 160 161 private static final char[] CHARS = ("qwertyuiop[]12345678" + 162 "90-=\\`asdfghjkl;'zxcvbnm,./~!@#$%^&*()_+|QWERTYUIOP{" + 163 "}ASDFGHJKL:\"ZXCVBNM<>?\n\r\t\u0444\u044B\u0432\u0430").toCharArray(); 164 165 private static String makeRandomString(int maxLen) { 166 int len = random.nextInt(maxLen); 167 char[] buf = new char[len]; 168 for (int i = 0; i < len; ++i) { 169 buf[i] = CHARS[random.nextInt(CHARS.length)]; 170 } 171 return jla.newStringUnsafe(buf); 172 } 173 174 private static String mekeRandomSubstring(String source, int maxLen) { 175 if (source.isEmpty()) { 176 return source; 177 } 178 int pos = random.nextInt(source.length()); 179 int len = Integer.min(source.length() - pos, 180 random.nextInt(maxLen)); 181 return source.substring(pos, pos + len); 182 } 183 184 private static Object[] makeArray(Object... array) { 185 return array; 186 } 187 }