• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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