1 /*
2  * Copyright (c) 2000, 2013, 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 package test.java.lang.String;
24 
25 /**
26  * @test
27  * @bug 6840246 6559590
28  * @summary test String.split()
29  * @key randomness
30  */
31 import java.util.Arrays;
32 import java.util.Random;
33 import java.util.regex.*;
34 
35 import org.testng.annotations.Test;
36 import org.testng.annotations.BeforeClass;
37 
38 // Android-changed: migrate to testng
39 public class Split {
40 
41     private static final String SOURCE = "0123456789";
42     private static final String FAST_PATH_SOURCE = "0123456789abcdefgABCDEFG";
43     private static Random R;
44 
45     @BeforeClass
setUp()46     public static void setUp() {
47         R = new Random();
48     }
49 
50     @Test
testSplit_byDigit()51     public void testSplit_byDigit() {
52         for (int limit=-2; limit<3; limit++) {
53             for (int x=0; x<10; x++) {
54                 String[] result = SOURCE.split(Integer.toString(x), limit);
55                 int expectedLength = limit < 1 ? 2 : limit;
56 
57                 if ((limit == 0) && (x == 9)) {
58                     // expected dropping of ""
59                     if (result.length != 1)
60                         throw new RuntimeException("String.split failure 1");
61                     if (!result[0].equals("012345678")) {
62                         throw new RuntimeException("String.split failure 2");
63                     }
64                 } else {
65                     if (result.length != expectedLength) {
66                         throw new RuntimeException("String.split failure 3");
67                     }
68                     if (!result[0].equals(SOURCE.substring(0,x))) {
69                         if (limit != 1) {
70                             throw new RuntimeException(
71                                 "String.split failure 4");
72                         } else {
73                             if (!result[0].equals(SOURCE.substring(0,10))) {
74                                 throw new RuntimeException(
75                                     "String.split failure 10");
76                             }
77                         }
78                     }
79                     if (expectedLength > 1) { // Check segment 2
80                         if (!result[1].equals(SOURCE.substring(x+1,10)))
81                             throw new RuntimeException("String.split failure 5");
82                     }
83                 }
84             }
85         }
86     }
87 
88     @Test
89     public void testSplit_noMatch() {
90         for (int limit=-2; limit<3; limit++) {
91             String[] result = SOURCE.split("e", limit);
92             if (result.length != 1)
93                 throw new RuntimeException("String.split failure 6");
94             if (!result[0].equals(SOURCE))
95                 throw new RuntimeException("String.split failure 7");
96         }
97     }
98 
99     // Check the case for limit == 0, source = "";
100     // split() now returns 0-length for empty source "" see #6559590
101     @Test
102     public void testSplit_zeroLimit_emptySource() {
103         String source = "";
104         String[] result = source.split("e", 0);
105         if (result.length != 1)
106             throw new RuntimeException("String.split failure 8");
107         if (!result[0].equals(source))
108             throw new RuntimeException("String.split failure 9");
109     }
110 
111     /**
112      * Tests fastpath of {@link java.lang.String#split(String, int)}.
113      *
114      * This test is disabled and just provides explanation of testSplitFastPath_shard*
115      * test functions family. Originally, this test was running around 50 seconds and
116      * was doing the following:
117      *
118      * <pre>
119      * for (boolean doEscape: new boolean[] {false, true}) {
120      *     for (int cp = 0; cp < 0x11000; cp++) {
121      *         ...
122      *     }
123      * }
124      * </pre>
125      *
126      * To make it faster it was sharded into five shards:
127      *
128      * 1) First shard tests {@code doEscape = false} and {@code cp = [0, 0x11000)}, i.e. full range.
129      *    It was accounted for ~10% of all time (~5s), so the whole range goes in single shard.
130      * 2-5) These four shards test {@code doEscape = true} and {@code cp} split in four equal
131      *      intervals.
132      *
133      * There is also {@link #getShardRange(int)} helper function which returns shard range.
134      */
135     @Test(enabled = false)
136     public void testSplit_fastPath() {
137     }
138 
139     @Test
140     public void testSplit_fastPath_shard1_noEscape() {
141         testSplit_fastPath_(FAST_PATH_SOURCE, R, false, 0, 0x11000);
142     }
143 
144     @Test
145     public void testSplit_fastPath_shard2() {
146         int[] shardRange = getShardRange(0);
147         testSplit_fastPath_(FAST_PATH_SOURCE, R, true, shardRange[0], shardRange[1]);
148     }
149 
150     @Test
151     public void testSplit_fastPath_shard3() {
152         int[] shardRange = getShardRange(1);
153         testSplit_fastPath_(FAST_PATH_SOURCE, R, true, shardRange[0], shardRange[1]);
154     }
155 
156     @Test
157     public void testSplit_fastPath_shard4() {
158         int[] shardRange = getShardRange(2);
159         testSplit_fastPath_(FAST_PATH_SOURCE, R, true, shardRange[0], shardRange[1]);
160     }
161 
162     @Test
163     public void testSplit_fastPath_shard5() {
164         int[] shardRange = getShardRange(3);
165         testSplit_fastPath_(FAST_PATH_SOURCE, R, true, shardRange[0], shardRange[1]);
166     }
167 
168     /**
169      * Calculates shard range, i.e. [start, end) by shard index,
170      * assuming there are 4 shards in total; and the whole range spans from 0 to 0x11000.
171      *
172      * @param shardIndex index of the
173      * @return int[] of size 2: [start, end).
174      */
175     private static int[] getShardRange(int shardIndex) {
176         final int SHARD_LENGTH = 0x11000;
177         final int SHARD_COUNT = 4;
178         int shardLength = SHARD_LENGTH / SHARD_COUNT;
179         int shardStart = shardIndex * shardLength;
180         int shardEnd = (shardIndex + 1) * shardLength - 1;
181         return new int[]{ shardStart, shardEnd };
182     }
183 
184     private void testSplit_fastPath_(String source, Random r, boolean doEscape, int cpFrom, int cpTo) {
185         for (int cp = cpFrom; cp < cpTo; cp++) {
186             Pattern p = null;
187             String regex = new String(Character.toChars(cp));
188             if (doEscape)
189                 regex = "\\" + regex;
190             try {
191                 p = Pattern.compile(regex);
192             } catch (PatternSyntaxException pse) {
193                 // illegal syntax
194                 try {
195                     "abc".split(regex);
196                 } catch (PatternSyntaxException pse0) {
197                     continue;
198                 }
199                 throw new RuntimeException("String.split failure 11");
200             }
201             int off = r.nextInt(source.length());
202             String[] srcStrs = new String[] {
203                 "",
204                 source,
205                 regex + source,
206                 source + regex,
207                 source.substring(0, 3)
208                     + regex + source.substring(3, 9)
209                     + regex + source.substring(9, 15)
210                     + regex + source.substring(15),
211                 source.substring(0, off) + regex + source.substring(off)
212             };
213             for (String src: srcStrs) {
214                 for (int limit=-2; limit<3; limit++) {
215                     if (!Arrays.equals(src.split(regex, limit),
216                         p.split(src, limit)))
217                         throw new RuntimeException("String.split failure 12");
218                 }
219             }
220         }
221     }
222 }
223