• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.base;
18 
19 import static com.google.common.base.CharMatcher.anyOf;
20 import static com.google.common.base.CharMatcher.breakingWhitespace;
21 import static com.google.common.base.CharMatcher.forPredicate;
22 import static com.google.common.base.CharMatcher.inRange;
23 import static com.google.common.base.CharMatcher.is;
24 import static com.google.common.base.CharMatcher.isNot;
25 import static com.google.common.base.CharMatcher.noneOf;
26 import static com.google.common.base.CharMatcher.whitespace;
27 
28 import com.google.common.annotations.GwtCompatible;
29 import com.google.common.annotations.GwtIncompatible;
30 import com.google.common.annotations.J2ktIncompatible;
31 import com.google.common.collect.Sets;
32 import com.google.common.testing.NullPointerTester;
33 import java.util.Arrays;
34 import java.util.BitSet;
35 import java.util.HashSet;
36 import java.util.Random;
37 import java.util.Set;
38 import junit.framework.AssertionFailedError;
39 import junit.framework.TestCase;
40 
41 /**
42  * Unit test for {@link CharMatcher}.
43  *
44  * @author Kevin Bourrillion
45  */
46 @GwtCompatible(emulated = true)
47 @ElementTypesAreNonnullByDefault
48 public class CharMatcherTest extends TestCase {
49 
50   @J2ktIncompatible
51   @GwtIncompatible // NullPointerTester
testStaticNullPointers()52   public void testStaticNullPointers() throws Exception {
53     NullPointerTester tester = new NullPointerTester();
54     tester.testAllPublicStaticMethods(CharMatcher.class);
55     tester.testAllPublicInstanceMethods(CharMatcher.any());
56     tester.testAllPublicInstanceMethods(CharMatcher.anyOf("abc"));
57   }
58 
59   private static final CharMatcher WHATEVER =
60       new CharMatcher() {
61         @Override
62         public boolean matches(char c) {
63           throw new AssertionFailedError("You weren't supposed to actually invoke me!");
64         }
65       };
66 
testAnyAndNone_logicalOps()67   public void testAnyAndNone_logicalOps() throws Exception {
68     // These are testing behavior that's never promised by the API, but since
69     // we're lucky enough that these do pass, it saves us from having to write
70     // more excruciating tests! Hooray!
71 
72     assertSame(CharMatcher.any(), CharMatcher.none().negate());
73     assertSame(CharMatcher.none(), CharMatcher.any().negate());
74 
75     assertSame(WHATEVER, CharMatcher.any().and(WHATEVER));
76     assertSame(CharMatcher.any(), CharMatcher.any().or(WHATEVER));
77 
78     assertSame(CharMatcher.none(), CharMatcher.none().and(WHATEVER));
79     assertSame(WHATEVER, CharMatcher.none().or(WHATEVER));
80   }
81 
82   // The rest of the behavior of ANY and DEFAULT will be covered in the tests for
83   // the text processing methods below.
84 
testWhitespaceBreakingWhitespaceSubset()85   public void testWhitespaceBreakingWhitespaceSubset() throws Exception {
86     for (int c = 0; c <= Character.MAX_VALUE; c++) {
87       if (breakingWhitespace().matches((char) c)) {
88         assertTrue(Integer.toHexString(c), whitespace().matches((char) c));
89       }
90     }
91   }
92 
93   // The next tests require ICU4J and have, at least for now, been sliced out
94   // of the open-source view of the tests.
95 
96   @J2ktIncompatible
97   @GwtIncompatible // Character.isISOControl
testJavaIsoControl()98   public void testJavaIsoControl() {
99     for (int c = 0; c <= Character.MAX_VALUE; c++) {
100       assertEquals(
101           "" + c, Character.isISOControl(c), CharMatcher.javaIsoControl().matches((char) c));
102     }
103   }
104 
105   // Omitting tests for the rest of the JAVA_* constants as these are defined
106   // as extremely straightforward pass-throughs to the JDK methods.
107 
108   // We're testing the is(), isNot(), anyOf(), noneOf() and inRange() methods
109   // below by testing their text-processing methods.
110 
111   // The organization of this test class is unusual, as it's not done by
112   // method, but by overall "scenario". Also, the variety of actual tests we
113   // do borders on absurd overkill. Better safe than sorry, though?
114 
115   @GwtIncompatible // java.util.BitSet
testSetBits()116   public void testSetBits() {
117     doTestSetBits(CharMatcher.any());
118     doTestSetBits(CharMatcher.none());
119     doTestSetBits(is('a'));
120     doTestSetBits(isNot('a'));
121     doTestSetBits(anyOf(""));
122     doTestSetBits(anyOf("x"));
123     doTestSetBits(anyOf("xy"));
124     doTestSetBits(anyOf("CharMatcher"));
125     doTestSetBits(noneOf("CharMatcher"));
126     doTestSetBits(inRange('n', 'q'));
127     doTestSetBits(forPredicate(Predicates.equalTo('c')));
128     doTestSetBits(CharMatcher.ascii());
129     doTestSetBits(CharMatcher.digit());
130     doTestSetBits(CharMatcher.invisible());
131     doTestSetBits(CharMatcher.whitespace());
132     doTestSetBits(inRange('A', 'Z').and(inRange('F', 'K').negate()));
133   }
134 
135   @GwtIncompatible // java.util.BitSet
doTestSetBits(CharMatcher matcher)136   private void doTestSetBits(CharMatcher matcher) {
137     BitSet bitset = new BitSet();
138     matcher.setBits(bitset);
139     for (int i = Character.MIN_VALUE; i <= Character.MAX_VALUE; i++) {
140       assertEquals(matcher.matches((char) i), bitset.get(i));
141     }
142   }
143 
testEmpty()144   public void testEmpty() throws Exception {
145     doTestEmpty(CharMatcher.any());
146     doTestEmpty(CharMatcher.none());
147     doTestEmpty(is('a'));
148     doTestEmpty(isNot('a'));
149     doTestEmpty(anyOf(""));
150     doTestEmpty(anyOf("x"));
151     doTestEmpty(anyOf("xy"));
152     doTestEmpty(anyOf("CharMatcher"));
153     doTestEmpty(noneOf("CharMatcher"));
154     doTestEmpty(inRange('n', 'q'));
155     doTestEmpty(forPredicate(Predicates.equalTo('c')));
156   }
157 
158   @J2ktIncompatible
159   @GwtIncompatible // NullPointerTester
testNull()160   public void testNull() throws Exception {
161     doTestNull(CharMatcher.any());
162     doTestNull(CharMatcher.none());
163     doTestNull(is('a'));
164     doTestNull(isNot('a'));
165     doTestNull(anyOf(""));
166     doTestNull(anyOf("x"));
167     doTestNull(anyOf("xy"));
168     doTestNull(anyOf("CharMatcher"));
169     doTestNull(noneOf("CharMatcher"));
170     doTestNull(inRange('n', 'q'));
171     doTestNull(forPredicate(Predicates.equalTo('c')));
172   }
173 
doTestEmpty(CharMatcher matcher)174   private void doTestEmpty(CharMatcher matcher) throws Exception {
175     reallyTestEmpty(matcher);
176     reallyTestEmpty(matcher.negate());
177     reallyTestEmpty(matcher.precomputed());
178   }
179 
reallyTestEmpty(CharMatcher matcher)180   private void reallyTestEmpty(CharMatcher matcher) throws Exception {
181     assertEquals(-1, matcher.indexIn(""));
182     assertEquals(-1, matcher.indexIn("", 0));
183     try {
184       matcher.indexIn("", 1);
185       fail();
186     } catch (IndexOutOfBoundsException expected) {
187     }
188     try {
189       matcher.indexIn("", -1);
190       fail();
191     } catch (IndexOutOfBoundsException expected) {
192     }
193     assertEquals(-1, matcher.lastIndexIn(""));
194     assertFalse(matcher.matchesAnyOf(""));
195     assertTrue(matcher.matchesAllOf(""));
196     assertTrue(matcher.matchesNoneOf(""));
197     assertEquals("", matcher.removeFrom(""));
198     assertEquals("", matcher.replaceFrom("", 'z'));
199     assertEquals("", matcher.replaceFrom("", "ZZ"));
200     assertEquals("", matcher.trimFrom(""));
201     assertEquals(0, matcher.countIn(""));
202   }
203 
204   @J2ktIncompatible
205   @GwtIncompatible // NullPointerTester
doTestNull(CharMatcher matcher)206   private static void doTestNull(CharMatcher matcher) throws Exception {
207     NullPointerTester tester = new NullPointerTester();
208     tester.testAllPublicInstanceMethods(matcher);
209   }
210 
testNoMatches()211   public void testNoMatches() {
212     doTestNoMatches(CharMatcher.none(), "blah");
213     doTestNoMatches(is('a'), "bcde");
214     doTestNoMatches(isNot('a'), "aaaa");
215     doTestNoMatches(anyOf(""), "abcd");
216     doTestNoMatches(anyOf("x"), "abcd");
217     doTestNoMatches(anyOf("xy"), "abcd");
218     doTestNoMatches(anyOf("CharMatcher"), "zxqy");
219     doTestNoMatches(noneOf("CharMatcher"), "ChMa");
220     doTestNoMatches(inRange('p', 'x'), "mom");
221     doTestNoMatches(forPredicate(Predicates.equalTo('c')), "abe");
222     doTestNoMatches(inRange('A', 'Z').and(inRange('F', 'K').negate()), "F1a");
223     doTestNoMatches(CharMatcher.digit(), "\tAz()");
224     doTestNoMatches(CharMatcher.javaDigit(), "\tAz()");
225     doTestNoMatches(CharMatcher.digit().and(CharMatcher.ascii()), "\tAz()");
226     doTestNoMatches(CharMatcher.singleWidth(), "\u05bf\u3000");
227   }
228 
doTestNoMatches(CharMatcher matcher, String s)229   private void doTestNoMatches(CharMatcher matcher, String s) {
230     reallyTestNoMatches(matcher, s);
231     reallyTestAllMatches(matcher.negate(), s);
232     reallyTestNoMatches(matcher.precomputed(), s);
233     reallyTestAllMatches(matcher.negate().precomputed(), s);
234     reallyTestAllMatches(matcher.precomputed().negate(), s);
235     reallyTestNoMatches(forPredicate(matcher), s);
236 
237     reallyTestNoMatches(matcher, new StringBuilder(s));
238   }
239 
testAllMatches()240   public void testAllMatches() {
241     doTestAllMatches(CharMatcher.any(), "blah");
242     doTestAllMatches(isNot('a'), "bcde");
243     doTestAllMatches(is('a'), "aaaa");
244     doTestAllMatches(noneOf("CharMatcher"), "zxqy");
245     doTestAllMatches(anyOf("x"), "xxxx");
246     doTestAllMatches(anyOf("xy"), "xyyx");
247     doTestAllMatches(anyOf("CharMatcher"), "ChMa");
248     doTestAllMatches(inRange('m', 'p'), "mom");
249     doTestAllMatches(forPredicate(Predicates.equalTo('c')), "ccc");
250     doTestAllMatches(CharMatcher.digit(), "0123456789\u0ED0\u1B59");
251     doTestAllMatches(CharMatcher.javaDigit(), "0123456789");
252     doTestAllMatches(CharMatcher.digit().and(CharMatcher.ascii()), "0123456789");
253     doTestAllMatches(CharMatcher.singleWidth(), "\t0123ABCdef~\u00A0\u2111");
254   }
255 
doTestAllMatches(CharMatcher matcher, String s)256   private void doTestAllMatches(CharMatcher matcher, String s) {
257     reallyTestAllMatches(matcher, s);
258     reallyTestNoMatches(matcher.negate(), s);
259     reallyTestAllMatches(matcher.precomputed(), s);
260     reallyTestNoMatches(matcher.negate().precomputed(), s);
261     reallyTestNoMatches(matcher.precomputed().negate(), s);
262     reallyTestAllMatches(forPredicate(matcher), s);
263 
264     reallyTestAllMatches(matcher, new StringBuilder(s));
265   }
266 
reallyTestNoMatches(CharMatcher matcher, CharSequence s)267   private void reallyTestNoMatches(CharMatcher matcher, CharSequence s) {
268     assertFalse(matcher.matches(s.charAt(0)));
269     assertEquals(-1, matcher.indexIn(s));
270     assertEquals(-1, matcher.indexIn(s, 0));
271     assertEquals(-1, matcher.indexIn(s, 1));
272     assertEquals(-1, matcher.indexIn(s, s.length()));
273     try {
274       matcher.indexIn(s, s.length() + 1);
275       fail();
276     } catch (IndexOutOfBoundsException expected) {
277     }
278     try {
279       matcher.indexIn(s, -1);
280       fail();
281     } catch (IndexOutOfBoundsException expected) {
282     }
283     assertEquals(-1, matcher.lastIndexIn(s));
284     assertFalse(matcher.matchesAnyOf(s));
285     assertFalse(matcher.matchesAllOf(s));
286     assertTrue(matcher.matchesNoneOf(s));
287 
288     assertEquals(s.toString(), matcher.removeFrom(s));
289     assertEquals(s.toString(), matcher.replaceFrom(s, 'z'));
290     assertEquals(s.toString(), matcher.replaceFrom(s, "ZZ"));
291     assertEquals(s.toString(), matcher.trimFrom(s));
292     assertEquals(0, matcher.countIn(s));
293   }
294 
reallyTestAllMatches(CharMatcher matcher, CharSequence s)295   private void reallyTestAllMatches(CharMatcher matcher, CharSequence s) {
296     assertTrue(matcher.matches(s.charAt(0)));
297     assertEquals(0, matcher.indexIn(s));
298     assertEquals(0, matcher.indexIn(s, 0));
299     assertEquals(1, matcher.indexIn(s, 1));
300     assertEquals(-1, matcher.indexIn(s, s.length()));
301     assertEquals(s.length() - 1, matcher.lastIndexIn(s));
302     assertTrue(matcher.matchesAnyOf(s));
303     assertTrue(matcher.matchesAllOf(s));
304     assertFalse(matcher.matchesNoneOf(s));
305     assertEquals("", matcher.removeFrom(s));
306     assertEquals(Strings.repeat("z", s.length()), matcher.replaceFrom(s, 'z'));
307     assertEquals(Strings.repeat("ZZ", s.length()), matcher.replaceFrom(s, "ZZ"));
308     assertEquals("", matcher.trimFrom(s));
309     assertEquals(s.length(), matcher.countIn(s));
310   }
311 
312   // Kotlin subSequence()/replace() always return new strings, violating expectations of this test
313   @J2ktIncompatible
testGeneral()314   public void testGeneral() {
315     doTestGeneral(is('a'), 'a', 'b');
316     doTestGeneral(isNot('a'), 'b', 'a');
317     doTestGeneral(anyOf("x"), 'x', 'z');
318     doTestGeneral(anyOf("xy"), 'y', 'z');
319     doTestGeneral(anyOf("CharMatcher"), 'C', 'z');
320     doTestGeneral(noneOf("CharMatcher"), 'z', 'C');
321     doTestGeneral(inRange('p', 'x'), 'q', 'z');
322   }
323 
doTestGeneral(CharMatcher matcher, char match, char noMatch)324   private void doTestGeneral(CharMatcher matcher, char match, char noMatch) {
325     doTestOneCharMatch(matcher, "" + match);
326     doTestOneCharNoMatch(matcher, "" + noMatch);
327     doTestMatchThenNoMatch(matcher, "" + match + noMatch);
328     doTestNoMatchThenMatch(matcher, "" + noMatch + match);
329   }
330 
doTestOneCharMatch(CharMatcher matcher, String s)331   private void doTestOneCharMatch(CharMatcher matcher, String s) {
332     reallyTestOneCharMatch(matcher, s);
333     reallyTestOneCharNoMatch(matcher.negate(), s);
334     reallyTestOneCharMatch(matcher.precomputed(), s);
335     reallyTestOneCharNoMatch(matcher.negate().precomputed(), s);
336     reallyTestOneCharNoMatch(matcher.precomputed().negate(), s);
337   }
338 
doTestOneCharNoMatch(CharMatcher matcher, String s)339   private void doTestOneCharNoMatch(CharMatcher matcher, String s) {
340     reallyTestOneCharNoMatch(matcher, s);
341     reallyTestOneCharMatch(matcher.negate(), s);
342     reallyTestOneCharNoMatch(matcher.precomputed(), s);
343     reallyTestOneCharMatch(matcher.negate().precomputed(), s);
344     reallyTestOneCharMatch(matcher.precomputed().negate(), s);
345   }
346 
doTestMatchThenNoMatch(CharMatcher matcher, String s)347   private void doTestMatchThenNoMatch(CharMatcher matcher, String s) {
348     reallyTestMatchThenNoMatch(matcher, s);
349     reallyTestNoMatchThenMatch(matcher.negate(), s);
350     reallyTestMatchThenNoMatch(matcher.precomputed(), s);
351     reallyTestNoMatchThenMatch(matcher.negate().precomputed(), s);
352     reallyTestNoMatchThenMatch(matcher.precomputed().negate(), s);
353   }
354 
doTestNoMatchThenMatch(CharMatcher matcher, String s)355   private void doTestNoMatchThenMatch(CharMatcher matcher, String s) {
356     reallyTestNoMatchThenMatch(matcher, s);
357     reallyTestMatchThenNoMatch(matcher.negate(), s);
358     reallyTestNoMatchThenMatch(matcher.precomputed(), s);
359     reallyTestMatchThenNoMatch(matcher.negate().precomputed(), s);
360     reallyTestMatchThenNoMatch(matcher.precomputed().negate(), s);
361   }
362 
363   @SuppressWarnings("deprecation") // intentionally testing apply() method
reallyTestOneCharMatch(CharMatcher matcher, String s)364   private void reallyTestOneCharMatch(CharMatcher matcher, String s) {
365     assertTrue(matcher.matches(s.charAt(0)));
366     assertTrue(matcher.apply(s.charAt(0)));
367     assertEquals(0, matcher.indexIn(s));
368     assertEquals(0, matcher.indexIn(s, 0));
369     assertEquals(-1, matcher.indexIn(s, 1));
370     assertEquals(0, matcher.lastIndexIn(s));
371     assertTrue(matcher.matchesAnyOf(s));
372     assertTrue(matcher.matchesAllOf(s));
373     assertFalse(matcher.matchesNoneOf(s));
374     assertEquals("", matcher.removeFrom(s));
375     assertEquals("z", matcher.replaceFrom(s, 'z'));
376     assertEquals("ZZ", matcher.replaceFrom(s, "ZZ"));
377     assertEquals("", matcher.trimFrom(s));
378     assertEquals(1, matcher.countIn(s));
379   }
380 
381   @SuppressWarnings("deprecation") // intentionally testing apply() method
reallyTestOneCharNoMatch(CharMatcher matcher, String s)382   private void reallyTestOneCharNoMatch(CharMatcher matcher, String s) {
383     assertFalse(matcher.matches(s.charAt(0)));
384     assertFalse(matcher.apply(s.charAt(0)));
385     assertEquals(-1, matcher.indexIn(s));
386     assertEquals(-1, matcher.indexIn(s, 0));
387     assertEquals(-1, matcher.indexIn(s, 1));
388     assertEquals(-1, matcher.lastIndexIn(s));
389     assertFalse(matcher.matchesAnyOf(s));
390     assertFalse(matcher.matchesAllOf(s));
391     assertTrue(matcher.matchesNoneOf(s));
392 
393     assertSame(s, matcher.removeFrom(s));
394     assertSame(s, matcher.replaceFrom(s, 'z'));
395     assertSame(s, matcher.replaceFrom(s, "ZZ"));
396     assertSame(s, matcher.trimFrom(s));
397     assertEquals(0, matcher.countIn(s));
398   }
399 
reallyTestMatchThenNoMatch(CharMatcher matcher, String s)400   private void reallyTestMatchThenNoMatch(CharMatcher matcher, String s) {
401     assertEquals(0, matcher.indexIn(s));
402     assertEquals(0, matcher.indexIn(s, 0));
403     assertEquals(-1, matcher.indexIn(s, 1));
404     assertEquals(-1, matcher.indexIn(s, 2));
405     assertEquals(0, matcher.lastIndexIn(s));
406     assertTrue(matcher.matchesAnyOf(s));
407     assertFalse(matcher.matchesAllOf(s));
408     assertFalse(matcher.matchesNoneOf(s));
409     assertEquals(s.substring(1), matcher.removeFrom(s));
410     assertEquals("z" + s.substring(1), matcher.replaceFrom(s, 'z'));
411     assertEquals("ZZ" + s.substring(1), matcher.replaceFrom(s, "ZZ"));
412     assertEquals(s.substring(1), matcher.trimFrom(s));
413     assertEquals(1, matcher.countIn(s));
414   }
415 
reallyTestNoMatchThenMatch(CharMatcher matcher, String s)416   private void reallyTestNoMatchThenMatch(CharMatcher matcher, String s) {
417     assertEquals(1, matcher.indexIn(s));
418     assertEquals(1, matcher.indexIn(s, 0));
419     assertEquals(1, matcher.indexIn(s, 1));
420     assertEquals(-1, matcher.indexIn(s, 2));
421     assertEquals(1, matcher.lastIndexIn(s));
422     assertTrue(matcher.matchesAnyOf(s));
423     assertFalse(matcher.matchesAllOf(s));
424     assertFalse(matcher.matchesNoneOf(s));
425     assertEquals(s.substring(0, 1), matcher.removeFrom(s));
426     assertEquals(s.substring(0, 1) + "z", matcher.replaceFrom(s, 'z'));
427     assertEquals(s.substring(0, 1) + "ZZ", matcher.replaceFrom(s, "ZZ"));
428     assertEquals(s.substring(0, 1), matcher.trimFrom(s));
429     assertEquals(1, matcher.countIn(s));
430   }
431 
432   /**
433    * Checks that expected is equals to out, and further, if in is equals to expected, then out is
434    * successfully optimized to be identical to in, i.e. that "in" is simply returned.
435    */
assertEqualsSame(String expected, String in, String out)436   private void assertEqualsSame(String expected, String in, String out) {
437     if (expected.equals(in)) {
438       assertSame(in, out);
439     } else {
440       assertEquals(expected, out);
441     }
442   }
443 
444   // Test collapse() a little differently than the rest, as we really want to
445   // cover lots of different configurations of input text
testCollapse()446   public void testCollapse() {
447     // collapsing groups of '-' into '_' or '-'
448     doTestCollapse("-", "_");
449     doTestCollapse("x-", "x_");
450     doTestCollapse("-x", "_x");
451     doTestCollapse("--", "_");
452     doTestCollapse("x--", "x_");
453     doTestCollapse("--x", "_x");
454     doTestCollapse("-x-", "_x_");
455     doTestCollapse("x-x", "x_x");
456     doTestCollapse("---", "_");
457     doTestCollapse("--x-", "_x_");
458     doTestCollapse("--xx", "_xx");
459     doTestCollapse("-x--", "_x_");
460     doTestCollapse("-x-x", "_x_x");
461     doTestCollapse("-xx-", "_xx_");
462     doTestCollapse("x--x", "x_x");
463     doTestCollapse("x-x-", "x_x_");
464     doTestCollapse("x-xx", "x_xx");
465     doTestCollapse("x-x--xx---x----x", "x_x_xx_x_x");
466 
467     doTestCollapseWithNoChange("");
468     doTestCollapseWithNoChange("x");
469     doTestCollapseWithNoChange("xx");
470   }
471 
doTestCollapse(String in, String out)472   private void doTestCollapse(String in, String out) {
473     // Try a few different matchers which all match '-' and not 'x'
474     // Try replacement chars that both do and do not change the value.
475     for (char replacement : new char[] {'_', '-'}) {
476       String expected = out.replace('_', replacement);
477       assertEqualsSame(expected, in, is('-').collapseFrom(in, replacement));
478       assertEqualsSame(expected, in, is('-').collapseFrom(in, replacement));
479       assertEqualsSame(expected, in, is('-').or(is('#')).collapseFrom(in, replacement));
480       assertEqualsSame(expected, in, isNot('x').collapseFrom(in, replacement));
481       assertEqualsSame(expected, in, is('x').negate().collapseFrom(in, replacement));
482       assertEqualsSame(expected, in, anyOf("-").collapseFrom(in, replacement));
483       assertEqualsSame(expected, in, anyOf("-#").collapseFrom(in, replacement));
484       assertEqualsSame(expected, in, anyOf("-#123").collapseFrom(in, replacement));
485     }
486   }
487 
doTestCollapseWithNoChange(String inout)488   private void doTestCollapseWithNoChange(String inout) {
489     assertSame(inout, is('-').collapseFrom(inout, '_'));
490     assertSame(inout, is('-').or(is('#')).collapseFrom(inout, '_'));
491     assertSame(inout, isNot('x').collapseFrom(inout, '_'));
492     assertSame(inout, is('x').negate().collapseFrom(inout, '_'));
493     assertSame(inout, anyOf("-").collapseFrom(inout, '_'));
494     assertSame(inout, anyOf("-#").collapseFrom(inout, '_'));
495     assertSame(inout, anyOf("-#123").collapseFrom(inout, '_'));
496     assertSame(inout, CharMatcher.none().collapseFrom(inout, '_'));
497   }
498 
testCollapse_any()499   public void testCollapse_any() {
500     assertEquals("", CharMatcher.any().collapseFrom("", '_'));
501     assertEquals("_", CharMatcher.any().collapseFrom("a", '_'));
502     assertEquals("_", CharMatcher.any().collapseFrom("ab", '_'));
503     assertEquals("_", CharMatcher.any().collapseFrom("abcd", '_'));
504   }
505 
testTrimFrom()506   public void testTrimFrom() {
507     // trimming -
508     doTestTrimFrom("-", "");
509     doTestTrimFrom("x-", "x");
510     doTestTrimFrom("-x", "x");
511     doTestTrimFrom("--", "");
512     doTestTrimFrom("x--", "x");
513     doTestTrimFrom("--x", "x");
514     doTestTrimFrom("-x-", "x");
515     doTestTrimFrom("x-x", "x-x");
516     doTestTrimFrom("---", "");
517     doTestTrimFrom("--x-", "x");
518     doTestTrimFrom("--xx", "xx");
519     doTestTrimFrom("-x--", "x");
520     doTestTrimFrom("-x-x", "x-x");
521     doTestTrimFrom("-xx-", "xx");
522     doTestTrimFrom("x--x", "x--x");
523     doTestTrimFrom("x-x-", "x-x");
524     doTestTrimFrom("x-xx", "x-xx");
525     doTestTrimFrom("x-x--xx---x----x", "x-x--xx---x----x");
526     // additional testing using the doc example
527     assertEquals("cat", anyOf("ab").trimFrom("abacatbab"));
528   }
529 
doTestTrimFrom(String in, String out)530   private void doTestTrimFrom(String in, String out) {
531     // Try a few different matchers which all match '-' and not 'x'
532     assertEquals(out, is('-').trimFrom(in));
533     assertEquals(out, is('-').or(is('#')).trimFrom(in));
534     assertEquals(out, isNot('x').trimFrom(in));
535     assertEquals(out, is('x').negate().trimFrom(in));
536     assertEquals(out, anyOf("-").trimFrom(in));
537     assertEquals(out, anyOf("-#").trimFrom(in));
538     assertEquals(out, anyOf("-#123").trimFrom(in));
539   }
540 
testTrimLeadingFrom()541   public void testTrimLeadingFrom() {
542     // trimming -
543     doTestTrimLeadingFrom("-", "");
544     doTestTrimLeadingFrom("x-", "x-");
545     doTestTrimLeadingFrom("-x", "x");
546     doTestTrimLeadingFrom("--", "");
547     doTestTrimLeadingFrom("x--", "x--");
548     doTestTrimLeadingFrom("--x", "x");
549     doTestTrimLeadingFrom("-x-", "x-");
550     doTestTrimLeadingFrom("x-x", "x-x");
551     doTestTrimLeadingFrom("---", "");
552     doTestTrimLeadingFrom("--x-", "x-");
553     doTestTrimLeadingFrom("--xx", "xx");
554     doTestTrimLeadingFrom("-x--", "x--");
555     doTestTrimLeadingFrom("-x-x", "x-x");
556     doTestTrimLeadingFrom("-xx-", "xx-");
557     doTestTrimLeadingFrom("x--x", "x--x");
558     doTestTrimLeadingFrom("x-x-", "x-x-");
559     doTestTrimLeadingFrom("x-xx", "x-xx");
560     doTestTrimLeadingFrom("x-x--xx---x----x", "x-x--xx---x----x");
561     // additional testing using the doc example
562     assertEquals("catbab", anyOf("ab").trimLeadingFrom("abacatbab"));
563   }
564 
doTestTrimLeadingFrom(String in, String out)565   private void doTestTrimLeadingFrom(String in, String out) {
566     // Try a few different matchers which all match '-' and not 'x'
567     assertEquals(out, is('-').trimLeadingFrom(in));
568     assertEquals(out, is('-').or(is('#')).trimLeadingFrom(in));
569     assertEquals(out, isNot('x').trimLeadingFrom(in));
570     assertEquals(out, is('x').negate().trimLeadingFrom(in));
571     assertEquals(out, anyOf("-#").trimLeadingFrom(in));
572     assertEquals(out, anyOf("-#123").trimLeadingFrom(in));
573   }
574 
testTrimTrailingFrom()575   public void testTrimTrailingFrom() {
576     // trimming -
577     doTestTrimTrailingFrom("-", "");
578     doTestTrimTrailingFrom("x-", "x");
579     doTestTrimTrailingFrom("-x", "-x");
580     doTestTrimTrailingFrom("--", "");
581     doTestTrimTrailingFrom("x--", "x");
582     doTestTrimTrailingFrom("--x", "--x");
583     doTestTrimTrailingFrom("-x-", "-x");
584     doTestTrimTrailingFrom("x-x", "x-x");
585     doTestTrimTrailingFrom("---", "");
586     doTestTrimTrailingFrom("--x-", "--x");
587     doTestTrimTrailingFrom("--xx", "--xx");
588     doTestTrimTrailingFrom("-x--", "-x");
589     doTestTrimTrailingFrom("-x-x", "-x-x");
590     doTestTrimTrailingFrom("-xx-", "-xx");
591     doTestTrimTrailingFrom("x--x", "x--x");
592     doTestTrimTrailingFrom("x-x-", "x-x");
593     doTestTrimTrailingFrom("x-xx", "x-xx");
594     doTestTrimTrailingFrom("x-x--xx---x----x", "x-x--xx---x----x");
595     // additional testing using the doc example
596     assertEquals("abacat", anyOf("ab").trimTrailingFrom("abacatbab"));
597   }
598 
doTestTrimTrailingFrom(String in, String out)599   private void doTestTrimTrailingFrom(String in, String out) {
600     // Try a few different matchers which all match '-' and not 'x'
601     assertEquals(out, is('-').trimTrailingFrom(in));
602     assertEquals(out, is('-').or(is('#')).trimTrailingFrom(in));
603     assertEquals(out, isNot('x').trimTrailingFrom(in));
604     assertEquals(out, is('x').negate().trimTrailingFrom(in));
605     assertEquals(out, anyOf("-#").trimTrailingFrom(in));
606     assertEquals(out, anyOf("-#123").trimTrailingFrom(in));
607   }
608 
testTrimAndCollapse()609   public void testTrimAndCollapse() {
610     // collapsing groups of '-' into '_' or '-'
611     doTestTrimAndCollapse("", "");
612     doTestTrimAndCollapse("x", "x");
613     doTestTrimAndCollapse("-", "");
614     doTestTrimAndCollapse("x-", "x");
615     doTestTrimAndCollapse("-x", "x");
616     doTestTrimAndCollapse("--", "");
617     doTestTrimAndCollapse("x--", "x");
618     doTestTrimAndCollapse("--x", "x");
619     doTestTrimAndCollapse("-x-", "x");
620     doTestTrimAndCollapse("x-x", "x_x");
621     doTestTrimAndCollapse("---", "");
622     doTestTrimAndCollapse("--x-", "x");
623     doTestTrimAndCollapse("--xx", "xx");
624     doTestTrimAndCollapse("-x--", "x");
625     doTestTrimAndCollapse("-x-x", "x_x");
626     doTestTrimAndCollapse("-xx-", "xx");
627     doTestTrimAndCollapse("x--x", "x_x");
628     doTestTrimAndCollapse("x-x-", "x_x");
629     doTestTrimAndCollapse("x-xx", "x_xx");
630     doTestTrimAndCollapse("x-x--xx---x----x", "x_x_xx_x_x");
631   }
632 
doTestTrimAndCollapse(String in, String out)633   private void doTestTrimAndCollapse(String in, String out) {
634     // Try a few different matchers which all match '-' and not 'x'
635     for (char replacement : new char[] {'_', '-'}) {
636       String expected = out.replace('_', replacement);
637       assertEqualsSame(expected, in, is('-').trimAndCollapseFrom(in, replacement));
638       assertEqualsSame(expected, in, is('-').or(is('#')).trimAndCollapseFrom(in, replacement));
639       assertEqualsSame(expected, in, isNot('x').trimAndCollapseFrom(in, replacement));
640       assertEqualsSame(expected, in, is('x').negate().trimAndCollapseFrom(in, replacement));
641       assertEqualsSame(expected, in, anyOf("-").trimAndCollapseFrom(in, replacement));
642       assertEqualsSame(expected, in, anyOf("-#").trimAndCollapseFrom(in, replacement));
643       assertEqualsSame(expected, in, anyOf("-#123").trimAndCollapseFrom(in, replacement));
644     }
645   }
646 
testReplaceFrom()647   public void testReplaceFrom() {
648     assertEquals("yoho", is('a').replaceFrom("yaha", 'o'));
649     assertEquals("yh", is('a').replaceFrom("yaha", ""));
650     assertEquals("yoho", is('a').replaceFrom("yaha", "o"));
651     assertEquals("yoohoo", is('a').replaceFrom("yaha", "oo"));
652     assertEquals("12 &gt; 5", is('>').replaceFrom("12 > 5", "&gt;"));
653   }
654 
testRetainFrom()655   public void testRetainFrom() {
656     assertEquals("aaa", is('a').retainFrom("bazaar"));
657     assertEquals("z", is('z').retainFrom("bazaar"));
658     assertEquals("!", is('!').retainFrom("!@#$%^&*()-="));
659     assertEquals("", is('x').retainFrom("bazaar"));
660     assertEquals("", is('a').retainFrom(""));
661   }
662 
testPrecomputedOptimizations()663   public void testPrecomputedOptimizations() {
664     // These are testing behavior that's never promised by the API.
665     // Some matchers are so efficient that it is a waste of effort to
666     // build a precomputed version.
667     CharMatcher m1 = is('x');
668     assertSame(m1, m1.precomputed());
669     assertEquals(m1.toString(), m1.precomputed().toString());
670 
671     CharMatcher m2 = anyOf("Az");
672     assertSame(m2, m2.precomputed());
673     assertEquals(m2.toString(), m2.precomputed().toString());
674 
675     CharMatcher m3 = inRange('A', 'Z');
676     assertSame(m3, m3.precomputed());
677     assertEquals(m3.toString(), m3.precomputed().toString());
678 
679     assertSame(CharMatcher.none(), CharMatcher.none().precomputed());
680     assertSame(CharMatcher.any(), CharMatcher.any().precomputed());
681   }
682 
683   @GwtIncompatible // java.util.BitSet
bitSet(String chars)684   private static BitSet bitSet(String chars) {
685     return bitSet(chars.toCharArray());
686   }
687 
688   @GwtIncompatible // java.util.BitSet
bitSet(char[] chars)689   private static BitSet bitSet(char[] chars) {
690     BitSet tmp = new BitSet();
691     for (char c : chars) {
692       tmp.set(c);
693     }
694     return tmp;
695   }
696 
697   @GwtIncompatible // java.util.Random, java.util.BitSet
testSmallCharMatcher()698   public void testSmallCharMatcher() {
699     CharMatcher len1 = SmallCharMatcher.from(bitSet("#"), "#");
700     CharMatcher len2 = SmallCharMatcher.from(bitSet("ab"), "ab");
701     CharMatcher len3 = SmallCharMatcher.from(bitSet("abc"), "abc");
702     CharMatcher len4 = SmallCharMatcher.from(bitSet("abcd"), "abcd");
703     assertTrue(len1.matches('#'));
704     assertFalse(len1.matches('!'));
705     assertTrue(len2.matches('a'));
706     assertTrue(len2.matches('b'));
707     for (char c = 'c'; c < 'z'; c++) {
708       assertFalse(len2.matches(c));
709     }
710     assertTrue(len3.matches('a'));
711     assertTrue(len3.matches('b'));
712     assertTrue(len3.matches('c'));
713     for (char c = 'd'; c < 'z'; c++) {
714       assertFalse(len3.matches(c));
715     }
716     assertTrue(len4.matches('a'));
717     assertTrue(len4.matches('b'));
718     assertTrue(len4.matches('c'));
719     assertTrue(len4.matches('d'));
720     for (char c = 'e'; c < 'z'; c++) {
721       assertFalse(len4.matches(c));
722     }
723 
724     Random rand = new Random(1234);
725     for (int testCase = 0; testCase < 100; testCase++) {
726       char[] chars = randomChars(rand, rand.nextInt(63) + 1);
727       CharMatcher m = SmallCharMatcher.from(bitSet(chars), new String(chars));
728       checkExactMatches(m, chars);
729     }
730   }
731 
checkExactMatches(CharMatcher m, char[] chars)732   static void checkExactMatches(CharMatcher m, char[] chars) {
733     Set<Character> positive = Sets.newHashSetWithExpectedSize(chars.length);
734     for (char c : chars) {
735       positive.add(c);
736     }
737     for (int c = 0; c <= Character.MAX_VALUE; c++) {
738       assertFalse(positive.contains(Character.valueOf((char) c)) ^ m.matches((char) c));
739     }
740   }
741 
randomChars(Random rand, int size)742   static char[] randomChars(Random rand, int size) {
743     Set<Character> chars = new HashSet<>(size);
744     for (int i = 0; i < size; i++) {
745       char c;
746       do {
747         c = (char) rand.nextInt(Character.MAX_VALUE - Character.MIN_VALUE + 1);
748       } while (chars.contains(c));
749       chars.add(c);
750     }
751     char[] retValue = new char[chars.size()];
752     int i = 0;
753     for (char c : chars) {
754       retValue[i++] = c;
755     }
756     Arrays.sort(retValue);
757     return retValue;
758   }
759 
testToString()760   public void testToString() {
761     assertToStringWorks("CharMatcher.none()", CharMatcher.anyOf(""));
762     assertToStringWorks("CharMatcher.is('\\u0031')", CharMatcher.anyOf("1"));
763     assertToStringWorks("CharMatcher.isNot('\\u0031')", CharMatcher.isNot('1'));
764     assertToStringWorks("CharMatcher.anyOf(\"\\u0031\\u0032\")", CharMatcher.anyOf("12"));
765     assertToStringWorks("CharMatcher.anyOf(\"\\u0031\\u0032\\u0033\")", CharMatcher.anyOf("321"));
766     assertToStringWorks("CharMatcher.inRange('\\u0031', '\\u0033')", CharMatcher.inRange('1', '3'));
767   }
768 
assertToStringWorks(String expected, CharMatcher matcher)769   private static void assertToStringWorks(String expected, CharMatcher matcher) {
770     assertEquals(expected, matcher.toString());
771     assertEquals(expected, matcher.precomputed().toString());
772     assertEquals(expected, matcher.negate().negate().toString());
773     assertEquals(expected, matcher.negate().precomputed().negate().toString());
774     assertEquals(expected, matcher.negate().precomputed().negate().precomputed().toString());
775   }
776 }
777