View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.text;
19  
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertFalse;
22  import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
23  import static org.junit.jupiter.api.Assertions.assertTrue;
24  import static org.junit.jupiter.api.Assertions.fail;
25  
26  import java.util.Arrays;
27  import java.util.function.IntUnaryOperator;
28  
29  import org.apache.commons.lang3.ArraySorter;
30  import org.apache.commons.text.RandomStringGenerator.Builder;
31  import org.junit.jupiter.api.Test;
32  import org.junit.jupiter.params.ParameterizedTest;
33  import org.junit.jupiter.params.provider.ValueSource;
34  
35  /**
36   * Tests for {@link RandomStringGenerator}.
37   */
38  class RandomStringGeneratorTest {
39  
40      private static final CharacterPredicate A_FILTER = codePoint -> codePoint == 'a';
41      private static final CharacterPredicate B_FILTER = codePoint -> codePoint == 'b';
42  
43      private static int codePointLength(final String s) {
44          return s.codePointCount(0, s.length());
45      }
46  
47      @Test
48      void testBadMaximumCodePoint() {
49          assertThrowsExactly(IllegalArgumentException.class, () -> RandomStringGenerator.builder().withinRange(0, Character.MAX_CODE_POINT + 1));
50      }
51  
52      @Test
53      void testBadMinAndMax() {
54          assertThrowsExactly(IllegalArgumentException.class, () -> RandomStringGenerator.builder().withinRange(2, 1));
55      }
56  
57      @Test
58      void testBadMinimumCodePoint() {
59          assertThrowsExactly(IllegalArgumentException.class, () -> RandomStringGenerator.builder().withinRange(-1, 1));
60      }
61  
62      @Test
63      void testBuildDeprecated() {
64          final RandomStringGenerator.Builder builder = RandomStringGenerator.builder().withinRange('a', 'z').filteredBy(A_FILTER);
65          final String str = builder.filteredBy(B_FILTER).build().generate(100);
66          for (final char c : str.toCharArray()) {
67              assertEquals('b', c);
68          }
69      }
70  
71      @Test
72      void testChangeOfFilter() {
73          final RandomStringGenerator.Builder builder = RandomStringGenerator.builder().withinRange('a', 'z').filteredBy(A_FILTER);
74          final String str = builder.filteredBy(B_FILTER).get().generate(100);
75          for (final char c : str.toCharArray()) {
76              assertEquals('b', c);
77          }
78      }
79  
80      @Test
81      void testGenerateMinMaxLength() {
82          final int minLength = 0;
83          final int maxLength = 3;
84          final RandomStringGenerator generator = RandomStringGenerator.builder().get();
85          final String str = generator.generate(minLength, maxLength);
86          final int codePointLength = codePointLength(str);
87          assertTrue(codePointLength >= minLength && codePointLength <= maxLength);
88      }
89  
90      @Test
91      void testGenerateMinMaxLengthInvalidLength() {
92          assertThrowsExactly(IllegalArgumentException.class, () -> {
93              final RandomStringGenerator generator = RandomStringGenerator.builder().get();
94              generator.generate(-1, 0);
95          });
96      }
97  
98      @Test
99      void testGenerateMinMaxLengthMinGreaterThanMax() {
100         assertThrowsExactly(IllegalArgumentException.class, () -> {
101             final RandomStringGenerator generator = RandomStringGenerator.builder().get();
102             generator.generate(1, 0);
103         });
104     }
105 
106     @Test
107     void testGenerateTakingIntThrowsNullPointerException() {
108         assertThrowsExactly(NullPointerException.class, () -> {
109             final RandomStringGenerator.Builder randomStringGeneratorBuilder = RandomStringGenerator.builder();
110             final CharacterPredicate[] characterPredicateArray = new CharacterPredicate[2];
111             randomStringGeneratorBuilder.filteredBy(characterPredicateArray);
112             final RandomStringGenerator randomStringGenerator = randomStringGeneratorBuilder.get();
113             randomStringGenerator.generate(18);
114         });
115     }
116 
117     @Test
118     void testInvalidLength() {
119         assertThrowsExactly(IllegalArgumentException.class, () -> RandomStringGenerator.builder().get().generate(-1));
120     }
121 
122     @Test
123     void testMultipleFilters() {
124         final String str = RandomStringGenerator.builder().withinRange('a', 'd').filteredBy(A_FILTER, B_FILTER).get().generate(5000);
125         boolean aFound = false;
126         boolean bFound = false;
127         for (final char c : str.toCharArray()) {
128             if (c == 'a') {
129                 aFound = true;
130             } else if (c == 'b') {
131                 bFound = true;
132             } else {
133                 fail("Invalid character");
134             }
135         }
136         assertTrue(aFound && bFound);
137     }
138 
139     @Test
140     void testNoLoneSurrogates() {
141         final int length = 5000;
142         final String str = RandomStringGenerator.builder().get().generate(length);
143         char lastChar = str.charAt(0);
144         for (int i = 1; i < str.length(); i++) {
145             final char c = str.charAt(i);
146             if (Character.isLowSurrogate(c)) {
147                 assertTrue(Character.isHighSurrogate(lastChar));
148             }
149             if (Character.isHighSurrogate(lastChar)) {
150                 assertTrue(Character.isLowSurrogate(c));
151             }
152             if (Character.isHighSurrogate(c)) {
153                 // test this isn't the last character in the string
154                 assertTrue(i + 1 < str.length());
155             }
156             lastChar = c;
157         }
158     }
159 
160     @Test
161     void testNoPrivateCharacters() {
162         final int startOfPrivateBMPChars = 0xE000;
163         // Request a string in an area of the Basic Multilingual Plane that is
164         // largely occupied by private characters
165         final String str = RandomStringGenerator.builder().withinRange(startOfPrivateBMPChars, Character.MIN_SUPPLEMENTARY_CODE_POINT - 1).get()
166                 .generate(5000);
167         int i = 0;
168         do {
169             final int codePoint = str.codePointAt(i);
170             assertFalse(Character.getType(codePoint) == Character.PRIVATE_USE);
171             i += Character.charCount(codePoint);
172         } while (i < str.length());
173     }
174 
175     @Test
176     void testPasswordExample() {
177         final char[] punctuation = ArraySorter
178                 .sort(new char[] { '!', '"', '#', '$', '&', '\'', '(', ')', ',', '.', ':', ';', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~' });
179         // @formatter:off
180         final RandomStringGenerator generator = RandomStringGenerator.builder()
181                 .setAccumulate(true)
182                 .withinRange('a', 'z')
183                 .withinRange('A', 'Z')
184                 .withinRange('0', '9')
185                 .selectFrom(punctuation)
186                 .get();
187         // @formatter:on
188         final String randomText = generator.generate(10);
189         for (final char c : randomText.toCharArray()) {
190             assertTrue(Character.isLetter(c) || Character.isDigit(c) || Arrays.binarySearch(punctuation, c) >= 0);
191         }
192     }
193 
194     @Test
195     void testRemoveFilters() {
196         final RandomStringGenerator.Builder builder = RandomStringGenerator.builder().withinRange('a', 'z').filteredBy(A_FILTER);
197         builder.filteredBy();
198         final String str = builder.get().generate(100);
199         for (final char c : str.toCharArray()) {
200             if (c != 'a') {
201                 // filter was successfully removed
202                 return;
203             }
204         }
205         fail("Filter appears to have remained in place");
206     }
207 
208     @Test
209     void testSelectFromCharArray() {
210         final String str = "abc";
211         final char[] charArray = str.toCharArray();
212         final RandomStringGenerator generator = RandomStringGenerator.builder().selectFrom(charArray).get();
213         final String randomText = generator.generate(5);
214         for (final char c : randomText.toCharArray()) {
215             assertTrue(str.indexOf(c) != -1);
216         }
217     }
218 
219     @Test
220     void testSelectFromCharVarargs() {
221         final String str = "abc";
222         final RandomStringGenerator generator = RandomStringGenerator.builder().selectFrom('a', 'b', 'c').get();
223         final String randomText = generator.generate(5);
224         for (final char c : randomText.toCharArray()) {
225             assertTrue(str.indexOf(c) != -1);
226         }
227     }
228 
229     @ParameterizedTest
230     @ValueSource(booleans = {false, true})
231     void testSelectFromCharVarargs2(final boolean accumulate) {
232         final String str = "abcde";
233         // @formatter:off
234         final RandomStringGenerator generator = RandomStringGenerator.builder()
235                 .setAccumulate(accumulate)
236                 .selectFrom()
237                 .selectFrom(null)
238                 .selectFrom('a', 'b')
239                 .selectFrom('a', 'b', 'c')
240                 .selectFrom('a', 'b', 'c', 'd')
241                 .selectFrom('a', 'b', 'c', 'd', 'e') // only this last call matters when accumulate is false
242                 .get();
243         // @formatter:on
244         final String randomText = generator.generate(10);
245         for (final char c : randomText.toCharArray()) {
246             assertTrue(str.indexOf(c) != -1);
247         }
248     }
249 
250     @ParameterizedTest
251     @ValueSource(booleans = {false, true})
252     void testSelectFromCharVarargs3(final boolean accumulate) {
253         final String str = "abcde";
254         // @formatter:off
255         final RandomStringGenerator generator = RandomStringGenerator.builder()
256                 .setAccumulate(accumulate)
257                 .selectFrom('a', 'b', 'c', 'd', 'e')
258                 .selectFrom('a', 'b', 'c', 'd')
259                 .selectFrom('a', 'b', 'c')
260                 .selectFrom('a', 'b')
261                 .selectFrom(null)
262                 .selectFrom()
263                 .get();
264         // @formatter:on
265         final String randomText = generator.generate(10);
266         for (final char c : randomText.toCharArray()) {
267             assertEquals(accumulate, str.indexOf(c) != -1);
268         }
269     }
270 
271     @Test
272     void testSelectFromCharVarargSize1() {
273         final RandomStringGenerator generator = RandomStringGenerator.builder().selectFrom('a').get();
274         final String randomText = generator.generate(5);
275         for (final char c : randomText.toCharArray()) {
276             assertEquals('a', c);
277         }
278     }
279 
280     @Test
281     void testSelectFromEmptyCharVarargs() {
282         final RandomStringGenerator generator = RandomStringGenerator.builder().selectFrom().get();
283         final String randomText = generator.generate(5);
284         for (final char c : randomText.toCharArray()) {
285             assertTrue(c >= Character.MIN_CODE_POINT && c <= Character.MAX_CODE_POINT);
286         }
287     }
288 
289     @Test
290     void testSelectFromNullCharVarargs() {
291         final int length = 5;
292         RandomStringGenerator generator = RandomStringGenerator.builder().selectFrom(null).get();
293         String randomText = generator.generate(length);
294         assertEquals(length, codePointLength(randomText));
295         for (final char c : randomText.toCharArray()) {
296             assertTrue(c >= Character.MIN_CODE_POINT && c <= Character.MAX_CODE_POINT);
297         }
298         //
299         final Builder builder = RandomStringGenerator.builder().selectFrom('a');
300         generator = builder.get();
301         randomText = generator.generate(length);
302         for (final char c : randomText.toCharArray()) {
303             assertEquals('a', c);
304         }
305         // null input resets
306         generator = builder.selectFrom(null).get();
307         randomText = generator.generate(length);
308         assertEquals(length, codePointLength(randomText));
309         for (final char c : randomText.toCharArray()) {
310             assertTrue(c >= Character.MIN_CODE_POINT && c <= Character.MAX_CODE_POINT);
311         }
312     }
313 
314     @Test
315     void testSetLength() {
316         final int length = 99;
317         final RandomStringGenerator generator = RandomStringGenerator.builder().get();
318         final String str = generator.generate(length);
319         assertEquals(length, codePointLength(str));
320     }
321 
322     @Test
323     void testUsingRandomIntUnaryOperator() {
324         final char testChar = 'a';
325         final IntUnaryOperator testRandom = n -> testChar;
326         final String str = RandomStringGenerator.builder().usingRandom(testRandom).get().generate(10);
327         for (final char c : str.toCharArray()) {
328             assertEquals(testChar, c);
329         }
330     }
331 
332     @Test
333     void testUsingRandomTextRandomProvider() {
334         final char testChar = 'a';
335         final TextRandomProvider testRandom = n -> testChar;
336         final String str = RandomStringGenerator.builder().usingRandom(testRandom).get().generate(10);
337         for (final char c : str.toCharArray()) {
338             assertEquals(testChar, c);
339         }
340     }
341 
342     @Test
343     void testWithinMultipleRanges() {
344         final int length = 5000;
345         final char[][] pairs = { { 'a', 'z' }, { '0', '9' } };
346         // @formatter:off
347         final RandomStringGenerator generator = RandomStringGenerator.builder()
348                 .withinRange()
349                 .withinRange((char[][]) null)
350                 .withinRange(pairs)
351                 .get();
352         // @formatter:on
353         final String str = generator.generate(length);
354         int minimumCodePoint = 0, maximumCodePoint = 0;
355         for (final char[] pair : pairs) {
356             minimumCodePoint = Math.min(minimumCodePoint, pair[0]);
357             maximumCodePoint = Math.max(maximumCodePoint, pair[1]);
358         }
359         int i = 0;
360         do {
361             final int codePoint = str.codePointAt(i);
362             assertTrue(codePoint >= minimumCodePoint && codePoint <= maximumCodePoint);
363             i += Character.charCount(codePoint);
364         } while (i < str.length());
365     }
366 
367     @Test
368     void testWithinRange() {
369         final int length = 5000;
370         final int minimumCodePoint = 'a';
371         final int maximumCodePoint = 'z';
372         final RandomStringGenerator generator = RandomStringGenerator.builder().withinRange(minimumCodePoint, maximumCodePoint).get();
373         final String str = generator.generate(length);
374         int i = 0;
375         do {
376             final int codePoint = str.codePointAt(i);
377             assertTrue(codePoint >= minimumCodePoint && codePoint <= maximumCodePoint);
378             i += Character.charCount(codePoint);
379         } while (i < str.length());
380     }
381 
382     @Test
383     void testZeroLength() {
384         final RandomStringGenerator generator = RandomStringGenerator.builder().get();
385         assertEquals("", generator.generate(0));
386     }
387 }