/* * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * @test * @summary This exercises String#repeat patterns and limits. * @run main/othervm -Xmx4G StringRepeat */ package test.java.lang.String; // Android-added: support for wrapper to avoid d8 backporting of String.isBlank (b/191859202). import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import org.testng.Assert; import org.testng.annotations.Test; public class StringRepeat { /* * Varitions of repeat count. */ static int[] REPEATS = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 32, 64, 128, 256, 512, 1024, 64 * 1024, 1024 * 1024, 16 * 1024 * 1024 }; /* * Varitions of Strings. */ static String[] STRINGS = new String[] { "", "\0", " ", "a", "$", "\u2022", "ab", "abc", "abcd", "abcde", "The quick brown fox jumps over the lazy dog." }; /* * Repeat String function tests. */ @Test public void test1() { for (int repeat : REPEATS) { for (String string : STRINGS) { long limit = (long)string.length() * (long)repeat; // Android-changed: lowered max length limit // if ((long)(Integer.MAX_VALUE >> 1) <= limit) { if ((long)(Integer.MAX_VALUE >> 5) <= limit) { break; } // Android-changed: call wrappered repeat() to avoid d8 backport (b/191859202). // verify(string.repeat(repeat), string, repeat); verify(String_repeat(string, repeat), string, repeat); } } } /* * Repeat String exception tests. */ @Test public void test2() { try { // Android-changed: call wrappered repeat() to avoid d8 backport (b/191859202). // "abc".repeat(-1); String_repeat("abc", -1); throw new RuntimeException("No exception for negative repeat count"); } catch (IllegalArgumentException ex) { // Correct } try { // Android-changed: call wrappered repeat() to avoid d8 backport (b/191859202). // "abc".repeat(Integer.MAX_VALUE - 1); String_repeat("abc", Integer.MAX_VALUE - 1); throw new RuntimeException("No exception for large repeat count"); } catch (OutOfMemoryError ex) { // Correct } } // Android-added: more tests @Test public void testEdgeCases() { // Android-changed: call wrappered repeat() to avoid d8 backport (b/191859202). // Assert.assertThrows(IllegalArgumentException.class, () -> "a".repeat(-1)); // Assert.assertThrows(IllegalArgumentException.class, () -> "\u03B1".repeat(-1)); // Assert.assertThrows(OutOfMemoryError.class, () -> "\u03B1\u03B2".repeat(Integer.MAX_VALUE)); Assert.assertThrows(IllegalArgumentException.class, () -> String_repeat("a", -1)); Assert.assertThrows(IllegalArgumentException.class, () -> String_repeat("\u03B1", -1)); Assert.assertThrows(OutOfMemoryError.class, () -> String_repeat("\u03B1\u03B2", Integer.MAX_VALUE)); } @Test public void testCompressed() { // Android-changed: call wrappered repeat() to avoid d8 backport (b/191859202). // Assert.assertEquals("a".repeat(0), ""); // Assert.assertEquals("a".repeat(1), "a"); // Assert.assertEquals("a".repeat(5), "aaaaa"); Assert.assertEquals(String_repeat("a", 0), ""); Assert.assertEquals(String_repeat("a", 1), "a"); Assert.assertEquals(String_repeat("a", 5), "aaaaa"); // Android-changed: call wrappered repeat() to avoid d8 backport (b/191859202). // Assert.assertEquals("abc".repeat(0), ""); // Assert.assertEquals("abc".repeat(1), "abc"); // Assert.assertEquals("abc".repeat(5), "abcabcabcabcabc"); Assert.assertEquals(String_repeat("abc", 0), ""); Assert.assertEquals(String_repeat("abc", 1), "abc"); Assert.assertEquals(String_repeat("abc", 5), "abcabcabcabcabc"); } @Test public void testUncompressed() { // Android-changed: call wrappered repeat() to avoid d8 backport (b/191859202). // Assert.assertEquals("\u2022".repeat(0), ""); // Assert.assertEquals("\u2022".repeat(1), "\u2022"); // Assert.assertEquals("\u2022".repeat(5), "\u2022\u2022\u2022\u2022\u2022"); Assert.assertEquals(String_repeat("\u2022", 0), ""); Assert.assertEquals(String_repeat("\u2022", 1), "\u2022"); Assert.assertEquals(String_repeat("\u2022", 5), "\u2022\u2022\u2022\u2022\u2022"); // Android-changed: call wrappered repeat() to avoid d8 backport (b/191859202). // Assert.assertEquals("\u03B1\u03B2\u03B3".repeat(0), ""); // Assert.assertEquals("\u03B1\u03B2\u03B3".repeat(1), "αβγ"); // Assert.assertEquals("\u03B1\u03B2\u03B3".repeat(5), "αβγαβγαβγαβγαβγ"); Assert.assertEquals(String_repeat("\u03B1\u03B2\u03B3", 0), ""); Assert.assertEquals(String_repeat("\u03B1\u03B2\u03B3", 1), "αβγ"); Assert.assertEquals(String_repeat("\u03B1\u03B2\u03B3", 5), "αβγαβγαβγαβγαβγ"); } static String truncate(String string) { if (string.length() < 80) { return string; } return string.substring(0, 80) + "..."; } /* * Verify string repeat patterns. */ static void verify(String result, String string, int repeat) { if (string.isEmpty() || repeat == 0) { if (!result.isEmpty()) { String message = String.format("\"%s\".repeat(%d)%n", truncate(string), repeat) + String.format("Result \"%s\"%n", truncate(result)) + String.format("Result expected to be empty, found string of length %d%n", result.length()); Assert.fail(message); } } else { int expected = 0; int count = 0; for (int offset = result.indexOf(string, expected); 0 <= offset; offset = result.indexOf(string, expected)) { count++; if (offset != expected) { String message = String.format("\"%s\".repeat(%d)%n", truncate(string), repeat) + String.format("Result \"%s\"%n", truncate(result)) + String.format("Repeat expected at %d, found at = %d%n", expected, offset); Assert.fail(message); } expected += string.length(); } if (count != repeat) { String message = String.format("\"%s\".repeat(%d)%n", truncate(string), repeat) + String.format("Result \"%s\"%n", truncate(result)) + String.format("Repeat count expected to be %d, found %d%n", repeat, count); Assert.fail(message); } } } // Android-added: wrapper to avoid d8 backporting of String.isBlank (b/191859202). private static String String_repeat(String input, int count) { try { MethodType type = MethodType.methodType(String.class, int.class); MethodHandle repeat = MethodHandles.lookup().findVirtual(String.class, "repeat", type); return (String) repeat.invokeExact(input, count); } catch (IllegalArgumentException | OutOfMemoryError expected) { throw expected; } catch (Throwable t) { throw new RuntimeException(t); } } }