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