1 /* 2 * Copyright (c) 2018, 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 /* 25 * @test 26 * @summary This exercises String#repeat patterns and limits. 27 * @run main/othervm -Xmx4G StringRepeat 28 */ 29 package test.java.lang.String; 30 31 // Android-added: support for wrapper to avoid d8 backporting of String.isBlank (b/191859202). 32 import android.platform.test.annotations.LargeTest; 33 34 import java.lang.invoke.MethodHandle; 35 import java.lang.invoke.MethodHandles; 36 import java.lang.invoke.MethodType; 37 38 import org.testng.Assert; 39 import org.testng.annotations.Test; 40 41 42 public class StringRepeat { 43 /* 44 * Varitions of repeat count. 45 */ 46 static int[] REPEATS = { 47 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 48 32, 64, 128, 256, 512, 1024, 64 * 1024, 1024 * 1024, 49 16 * 1024 * 1024 50 }; 51 52 /* 53 * Varitions of Strings. 54 */ 55 static String[] STRINGS = new String[] { 56 "", "\0", " ", "a", "$", "\u2022", 57 "ab", "abc", "abcd", "abcde", 58 "The quick brown fox jumps over the lazy dog." 59 }; 60 61 /* 62 * Repeat String function tests. 63 */ 64 @LargeTest 65 @Test test1()66 public void test1() { 67 for (int repeat : REPEATS) { 68 for (String string : STRINGS) { 69 long limit = (long)string.length() * (long)repeat; 70 71 // Android-changed: lowered max length limit 72 // if ((long)(Integer.MAX_VALUE >> 1) <= limit) { 73 if ((long)(Integer.MAX_VALUE >> 5) <= limit) { 74 break; 75 } 76 77 // Android-changed: call wrappered repeat() to avoid d8 backport (b/191859202). 78 // verify(string.repeat(repeat), string, repeat); 79 verify(String_repeat(string, repeat), string, repeat); 80 } 81 } 82 } 83 84 /* 85 * Repeat String exception tests. 86 */ 87 @Test test2()88 public void test2() { 89 try { 90 // Android-changed: call wrappered repeat() to avoid d8 backport (b/191859202). 91 // "abc".repeat(-1); 92 String_repeat("abc", -1); 93 throw new RuntimeException("No exception for negative repeat count"); 94 } catch (IllegalArgumentException ex) { 95 // Correct 96 } 97 98 try { 99 // Android-changed: call wrappered repeat() to avoid d8 backport (b/191859202). 100 // "abc".repeat(Integer.MAX_VALUE - 1); 101 String_repeat("abc", Integer.MAX_VALUE - 1); 102 throw new RuntimeException("No exception for large repeat count"); 103 } catch (OutOfMemoryError ex) { 104 // Correct 105 } 106 } 107 108 // Android-added: more tests 109 @Test testEdgeCases()110 public void testEdgeCases() { 111 // Android-changed: call wrappered repeat() to avoid d8 backport (b/191859202). 112 // Assert.assertThrows(IllegalArgumentException.class, () -> "a".repeat(-1)); 113 // Assert.assertThrows(IllegalArgumentException.class, () -> "\u03B1".repeat(-1)); 114 // Assert.assertThrows(OutOfMemoryError.class, () -> "\u03B1\u03B2".repeat(Integer.MAX_VALUE)); 115 Assert.assertThrows(IllegalArgumentException.class, () -> String_repeat("a", -1)); 116 Assert.assertThrows(IllegalArgumentException.class, () -> String_repeat("\u03B1", -1)); 117 Assert.assertThrows(OutOfMemoryError.class, 118 () -> String_repeat("\u03B1\u03B2", Integer.MAX_VALUE)); 119 } 120 121 @Test testCompressed()122 public void testCompressed() { 123 // Android-changed: call wrappered repeat() to avoid d8 backport (b/191859202). 124 // Assert.assertEquals("a".repeat(0), ""); 125 // Assert.assertEquals("a".repeat(1), "a"); 126 // Assert.assertEquals("a".repeat(5), "aaaaa"); 127 Assert.assertEquals(String_repeat("a", 0), ""); 128 Assert.assertEquals(String_repeat("a", 1), "a"); 129 Assert.assertEquals(String_repeat("a", 5), "aaaaa"); 130 131 // Android-changed: call wrappered repeat() to avoid d8 backport (b/191859202). 132 // Assert.assertEquals("abc".repeat(0), ""); 133 // Assert.assertEquals("abc".repeat(1), "abc"); 134 // Assert.assertEquals("abc".repeat(5), "abcabcabcabcabc"); 135 Assert.assertEquals(String_repeat("abc", 0), ""); 136 Assert.assertEquals(String_repeat("abc", 1), "abc"); 137 Assert.assertEquals(String_repeat("abc", 5), "abcabcabcabcabc"); 138 } 139 140 @Test testUncompressed()141 public void testUncompressed() { 142 // Android-changed: call wrappered repeat() to avoid d8 backport (b/191859202). 143 // Assert.assertEquals("\u2022".repeat(0), ""); 144 // Assert.assertEquals("\u2022".repeat(1), "\u2022"); 145 // Assert.assertEquals("\u2022".repeat(5), "\u2022\u2022\u2022\u2022\u2022"); 146 Assert.assertEquals(String_repeat("\u2022", 0), ""); 147 Assert.assertEquals(String_repeat("\u2022", 1), "\u2022"); 148 Assert.assertEquals(String_repeat("\u2022", 5), "\u2022\u2022\u2022\u2022\u2022"); 149 150 // Android-changed: call wrappered repeat() to avoid d8 backport (b/191859202). 151 // Assert.assertEquals("\u03B1\u03B2\u03B3".repeat(0), ""); 152 // Assert.assertEquals("\u03B1\u03B2\u03B3".repeat(1), "αβγ"); 153 // Assert.assertEquals("\u03B1\u03B2\u03B3".repeat(5), "αβγαβγαβγαβγαβγ"); 154 Assert.assertEquals(String_repeat("\u03B1\u03B2\u03B3", 0), ""); 155 Assert.assertEquals(String_repeat("\u03B1\u03B2\u03B3", 1), "αβγ"); 156 Assert.assertEquals(String_repeat("\u03B1\u03B2\u03B3", 5), "αβγαβγαβγαβγαβγ"); 157 } 158 truncate(String string)159 static String truncate(String string) { 160 if (string.length() < 80) { 161 return string; 162 } 163 return string.substring(0, 80) + "..."; 164 } 165 166 /* 167 * Verify string repeat patterns. 168 */ verify(String result, String string, int repeat)169 static void verify(String result, String string, int repeat) { 170 if (string.isEmpty() || repeat == 0) { 171 if (!result.isEmpty()) { 172 String message = String.format("\"%s\".repeat(%d)%n", truncate(string), repeat) + 173 String.format("Result \"%s\"%n", truncate(result)) + 174 String.format("Result expected to be empty, found string of length %d%n", result.length()); 175 Assert.fail(message); 176 } 177 } else { 178 int expected = 0; 179 int count = 0; 180 for (int offset = result.indexOf(string, expected); 181 0 <= offset; 182 offset = result.indexOf(string, expected)) { 183 count++; 184 if (offset != expected) { 185 String message = String.format("\"%s\".repeat(%d)%n", truncate(string), repeat) + 186 String.format("Result \"%s\"%n", truncate(result)) + 187 String.format("Repeat expected at %d, found at = %d%n", expected, offset); 188 Assert.fail(message); 189 } 190 expected += string.length(); 191 } 192 if (count != repeat) { 193 String message = String.format("\"%s\".repeat(%d)%n", truncate(string), repeat) + 194 String.format("Result \"%s\"%n", truncate(result)) + 195 String.format("Repeat count expected to be %d, found %d%n", repeat, count); 196 Assert.fail(message); 197 } 198 } 199 } 200 201 // Android-added: wrapper to avoid d8 backporting of String.isBlank (b/191859202). String_repeat(String input, int count)202 private static String String_repeat(String input, int count) { 203 try { 204 MethodType type = MethodType.methodType(String.class, int.class); 205 MethodHandle repeat = MethodHandles.lookup().findVirtual(String.class, "repeat", type); 206 return (String) repeat.invokeExact(input, count); 207 } catch (IllegalArgumentException | OutOfMemoryError expected) { 208 throw expected; 209 } catch (Throwable t) { 210 throw new RuntimeException(t); 211 } 212 } 213 } 214