Home | History | Annotate | Download | only in base
      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.forPredicate;
     21 import static com.google.common.base.CharMatcher.inRange;
     22 import static com.google.common.base.CharMatcher.is;
     23 import static com.google.common.base.CharMatcher.isNot;
     24 import static com.google.common.base.CharMatcher.noneOf;
     25 
     26 import com.google.common.annotations.GwtCompatible;
     27 import com.google.common.annotations.GwtIncompatible;
     28 import com.google.common.testing.NullPointerTester;
     29 
     30 import junit.framework.AssertionFailedError;
     31 import junit.framework.TestCase;
     32 
     33 /**
     34  * Unit test for {@link CharMatcher}.
     35  *
     36  * @author Kevin Bourrillion
     37  */
     38 @GwtCompatible(emulated = true)
     39 public class CharMatcherTest extends TestCase {
     40 
     41   @GwtIncompatible("NullPointerTester")
     42   public void testStaticNullPointers() throws Exception {
     43     NullPointerTester tester = new NullPointerTester();
     44     tester.testAllPublicStaticMethods(CharMatcher.class);
     45     tester.testAllPublicInstanceMethods(CharMatcher.ANY);
     46     tester.testAllPublicInstanceMethods(CharMatcher.anyOf("abc"));
     47   }
     48 
     49   private static final CharMatcher WHATEVER = new CharMatcher() {
     50     @Override public boolean matches(char c) {
     51       throw new AssertionFailedError(
     52           "You weren't supposed to actually invoke me!");
     53     }
     54   };
     55 
     56   public void testAnyAndNone_logicalOps() throws Exception {
     57     // These are testing behavior that's never promised by the API, but since
     58     // we're lucky enough that these do pass, it saves us from having to write
     59     // more excruciating tests! Hooray!
     60 
     61     assertSame(CharMatcher.ANY, CharMatcher.NONE.negate());
     62     assertSame(CharMatcher.NONE, CharMatcher.ANY.negate());
     63 
     64     assertSame(WHATEVER, CharMatcher.ANY.and(WHATEVER));
     65     assertSame(CharMatcher.ANY, CharMatcher.ANY.or(WHATEVER));
     66 
     67     assertSame(CharMatcher.NONE, CharMatcher.NONE.and(WHATEVER));
     68     assertSame(WHATEVER, CharMatcher.NONE.or(WHATEVER));
     69   }
     70 
     71   // The rest of the behavior of ANY and NONE will be covered in the tests for
     72   // the text processing methods below.
     73 
     74   // The next tests require ICU4J and have, at least for now, been sliced out
     75   // of the open-source view of the tests.
     76 
     77   @GwtIncompatible("Character.isISOControl")
     78   public void testJavaIsoControl() {
     79     for (int c = 0; c <= Character.MAX_VALUE; c++) {
     80       assertEquals("" + c, Character.isISOControl(c),
     81           CharMatcher.JAVA_ISO_CONTROL.matches((char) c));
     82     }
     83   }
     84 
     85   // There's no way to test LEGACY_WHITESPACE, really; it just is what it is.
     86 
     87   // Omitting tests for the rest of the JAVA_* constants as these are defined
     88   // as extremely straightforward pass-throughs to the JDK methods.
     89 
     90   // We're testing the is(), isNot(), anyOf(), noneOf() and inRange() methods
     91   // below by testing their text-processing methods.
     92 
     93   // The organization of this test class is unusual, as it's not done by
     94   // method, but by overall "scenario". Also, the variety of actual tests we
     95   // do borders on absurd overkill. Better safe than sorry, though?
     96 
     97   public void testEmpty() throws Exception {
     98     doTestEmpty(CharMatcher.ANY);
     99     doTestEmpty(CharMatcher.NONE);
    100     doTestEmpty(is('a'));
    101     doTestEmpty(isNot('a'));
    102     doTestEmpty(anyOf(""));
    103     doTestEmpty(anyOf("x"));
    104     doTestEmpty(anyOf("xy"));
    105     doTestEmpty(anyOf("CharMatcher"));
    106     doTestEmpty(noneOf("CharMatcher"));
    107     doTestEmpty(inRange('n', 'q'));
    108     doTestEmpty(forPredicate(Predicates.equalTo('c')));
    109   }
    110 
    111   @GwtIncompatible("NullPointerTester")
    112   public void testNull() throws Exception {
    113     doTestNull(CharMatcher.ANY);
    114     doTestNull(CharMatcher.NONE);
    115     doTestNull(is('a'));
    116     doTestNull(isNot('a'));
    117     doTestNull(anyOf(""));
    118     doTestNull(anyOf("x"));
    119     doTestNull(anyOf("xy"));
    120     doTestNull(anyOf("CharMatcher"));
    121     doTestNull(noneOf("CharMatcher"));
    122     doTestNull(inRange('n', 'q'));
    123     doTestNull(forPredicate(Predicates.equalTo('c')));
    124   }
    125 
    126   private void doTestEmpty(CharMatcher matcher) throws Exception {
    127     reallyTestEmpty(matcher);
    128     reallyTestEmpty(matcher.negate());
    129     reallyTestEmpty(matcher.precomputed());
    130   }
    131 
    132   private void reallyTestEmpty(CharMatcher matcher) throws Exception {
    133     assertEquals(-1, matcher.indexIn(""));
    134     assertEquals(-1, matcher.indexIn("", 0));
    135     try {
    136       matcher.indexIn("", 1);
    137       fail();
    138     } catch (IndexOutOfBoundsException expected) {
    139     }
    140     try {
    141       matcher.indexIn("", -1);
    142       fail();
    143     } catch (IndexOutOfBoundsException expected) {
    144     }
    145     assertEquals(-1, matcher.lastIndexIn(""));
    146     assertFalse(matcher.matchesAnyOf(""));
    147     assertTrue(matcher.matchesAllOf(""));
    148     assertTrue(matcher.matchesNoneOf(""));
    149     assertEquals("", matcher.removeFrom(""));
    150     assertEquals("", matcher.replaceFrom("", 'z'));
    151     assertEquals("", matcher.replaceFrom("", "ZZ"));
    152     assertEquals("", matcher.trimFrom(""));
    153     assertEquals(0, matcher.countIn(""));
    154   }
    155 
    156   @GwtIncompatible("NullPointerTester")
    157   private void doTestNull(CharMatcher matcher) throws Exception {
    158     NullPointerTester tester = new NullPointerTester();
    159     tester.testAllPublicInstanceMethods(matcher);
    160   }
    161 
    162   public void testNoMatches() {
    163     doTestNoMatches(CharMatcher.NONE, "blah");
    164     doTestNoMatches(is('a'), "bcde");
    165     doTestNoMatches(isNot('a'), "aaaa");
    166     doTestNoMatches(anyOf(""), "abcd");
    167     doTestNoMatches(anyOf("x"), "abcd");
    168     doTestNoMatches(anyOf("xy"), "abcd");
    169     doTestNoMatches(anyOf("CharMatcher"), "zxqy");
    170     doTestNoMatches(noneOf("CharMatcher"), "ChMa");
    171     doTestNoMatches(inRange('p', 'x'), "mom");
    172     doTestNoMatches(forPredicate(Predicates.equalTo('c')), "abe");
    173     doTestNoMatches(inRange('A', 'Z').and(inRange('F', 'K').negate()), "F1a");
    174     doTestNoMatches(CharMatcher.DIGIT, "\tAz()");
    175     doTestNoMatches(CharMatcher.JAVA_DIGIT, "\tAz()");
    176     doTestNoMatches(CharMatcher.DIGIT.and(CharMatcher.ASCII), "\tAz()");
    177     doTestNoMatches(CharMatcher.SINGLE_WIDTH, "\u05bf\u3000");
    178   }
    179 
    180   private void doTestNoMatches(CharMatcher matcher, String s) {
    181     reallyTestNoMatches(matcher, s);
    182     reallyTestAllMatches(matcher.negate(), s);
    183     reallyTestNoMatches(matcher.precomputed(), s);
    184     reallyTestAllMatches(matcher.negate().precomputed(), s);
    185     reallyTestAllMatches(matcher.precomputed().negate(), s);
    186     reallyTestNoMatches(forPredicate(matcher), s);
    187 
    188     reallyTestNoMatches(matcher, new StringBuilder(s));
    189   }
    190 
    191   public void testAllMatches() {
    192     doTestAllMatches(CharMatcher.ANY, "blah");
    193     doTestAllMatches(isNot('a'), "bcde");
    194     doTestAllMatches(is('a'), "aaaa");
    195     doTestAllMatches(noneOf("CharMatcher"), "zxqy");
    196     doTestAllMatches(anyOf("x"), "xxxx");
    197     doTestAllMatches(anyOf("xy"), "xyyx");
    198     doTestAllMatches(anyOf("CharMatcher"), "ChMa");
    199     doTestAllMatches(inRange('m', 'p'), "mom");
    200     doTestAllMatches(forPredicate(Predicates.equalTo('c')), "ccc");
    201     doTestAllMatches(CharMatcher.DIGIT, "0123456789\u0ED0\u1B59");
    202     doTestAllMatches(CharMatcher.JAVA_DIGIT, "0123456789");
    203     doTestAllMatches(CharMatcher.DIGIT.and(CharMatcher.ASCII), "0123456789");
    204     doTestAllMatches(CharMatcher.SINGLE_WIDTH, "\t0123ABCdef~\u00A0\u2111");
    205   }
    206 
    207   private void doTestAllMatches(CharMatcher matcher, String s) {
    208     reallyTestAllMatches(matcher, s);
    209     reallyTestNoMatches(matcher.negate(), s);
    210     reallyTestAllMatches(matcher.precomputed(), s);
    211     reallyTestNoMatches(matcher.negate().precomputed(), s);
    212     reallyTestNoMatches(matcher.precomputed().negate(), s);
    213     reallyTestAllMatches(forPredicate(matcher), s);
    214 
    215     reallyTestAllMatches(matcher, new StringBuilder(s));
    216   }
    217 
    218   private void reallyTestNoMatches(CharMatcher matcher, CharSequence s) {
    219     assertFalse(matcher.matches(s.charAt(0)));
    220     assertEquals(-1, matcher.indexIn(s));
    221     assertEquals(-1, matcher.indexIn(s, 0));
    222     assertEquals(-1, matcher.indexIn(s, 1));
    223     assertEquals(-1, matcher.indexIn(s, s.length()));
    224     try {
    225       matcher.indexIn(s, s.length() + 1);
    226       fail();
    227     } catch (IndexOutOfBoundsException expected) {
    228     }
    229     try {
    230       matcher.indexIn(s, -1);
    231       fail();
    232     } catch (IndexOutOfBoundsException expected) {
    233     }
    234     assertEquals(-1, matcher.lastIndexIn(s));
    235     assertFalse(matcher.matchesAnyOf(s));
    236     assertFalse(matcher.matchesAllOf(s));
    237     assertTrue(matcher.matchesNoneOf(s));
    238 
    239     assertEquals(s.toString(), matcher.removeFrom(s));
    240     assertEquals(s.toString(), matcher.replaceFrom(s, 'z'));
    241     assertEquals(s.toString(), matcher.replaceFrom(s, "ZZ"));
    242     assertEquals(s.toString(), matcher.trimFrom(s));
    243     assertEquals(0, matcher.countIn(s));
    244   }
    245 
    246   private void reallyTestAllMatches(CharMatcher matcher, CharSequence s) {
    247     assertTrue(matcher.matches(s.charAt(0)));
    248     assertEquals(0, matcher.indexIn(s));
    249     assertEquals(0, matcher.indexIn(s, 0));
    250     assertEquals(1, matcher.indexIn(s, 1));
    251     assertEquals(-1, matcher.indexIn(s, s.length()));
    252     assertEquals(s.length() - 1, matcher.lastIndexIn(s));
    253     assertTrue(matcher.matchesAnyOf(s));
    254     assertTrue(matcher.matchesAllOf(s));
    255     assertFalse(matcher.matchesNoneOf(s));
    256     assertEquals("", matcher.removeFrom(s));
    257     assertEquals(Strings.repeat("z", s.length()),
    258         matcher.replaceFrom(s, 'z'));
    259     assertEquals(Strings.repeat("ZZ", s.length()),
    260         matcher.replaceFrom(s, "ZZ"));
    261     assertEquals("", matcher.trimFrom(s));
    262     assertEquals(s.length(), matcher.countIn(s));
    263   }
    264 
    265   public void testGeneral() {
    266     doTestGeneral(is('a'), 'a', 'b');
    267     doTestGeneral(isNot('a'), 'b', 'a');
    268     doTestGeneral(anyOf("x"), 'x', 'z');
    269     doTestGeneral(anyOf("xy"), 'y', 'z');
    270     doTestGeneral(anyOf("CharMatcher"), 'C', 'z');
    271     doTestGeneral(noneOf("CharMatcher"), 'z', 'C');
    272     doTestGeneral(inRange('p', 'x'), 'q', 'z');
    273   }
    274 
    275   private void doTestGeneral(CharMatcher matcher, char match, char noMatch) {
    276     doTestOneCharMatch(matcher, "" + match);
    277     doTestOneCharNoMatch(matcher, "" + noMatch);
    278     doTestMatchThenNoMatch(matcher, "" + match + noMatch);
    279     doTestNoMatchThenMatch(matcher, "" + noMatch + match);
    280   }
    281 
    282   private void doTestOneCharMatch(CharMatcher matcher, String s) {
    283     reallyTestOneCharMatch(matcher, s);
    284     reallyTestOneCharNoMatch(matcher.negate(), s);
    285     reallyTestOneCharMatch(matcher.precomputed(), s);
    286     reallyTestOneCharNoMatch(matcher.negate().precomputed(), s);
    287     reallyTestOneCharNoMatch(matcher.precomputed().negate(), s);
    288   }
    289 
    290   private void doTestOneCharNoMatch(CharMatcher matcher, String s) {
    291     reallyTestOneCharNoMatch(matcher, s);
    292     reallyTestOneCharMatch(matcher.negate(), s);
    293     reallyTestOneCharNoMatch(matcher.precomputed(), s);
    294     reallyTestOneCharMatch(matcher.negate().precomputed(), s);
    295     reallyTestOneCharMatch(matcher.precomputed().negate(), s);
    296   }
    297 
    298   private void doTestMatchThenNoMatch(CharMatcher matcher, String s) {
    299     reallyTestMatchThenNoMatch(matcher, s);
    300     reallyTestNoMatchThenMatch(matcher.negate(), s);
    301     reallyTestMatchThenNoMatch(matcher.precomputed(), s);
    302     reallyTestNoMatchThenMatch(matcher.negate().precomputed(), s);
    303     reallyTestNoMatchThenMatch(matcher.precomputed().negate(), s);
    304   }
    305 
    306   private void doTestNoMatchThenMatch(CharMatcher matcher, String s) {
    307     reallyTestNoMatchThenMatch(matcher, s);
    308     reallyTestMatchThenNoMatch(matcher.negate(), s);
    309     reallyTestNoMatchThenMatch(matcher.precomputed(), s);
    310     reallyTestMatchThenNoMatch(matcher.negate().precomputed(), s);
    311     reallyTestMatchThenNoMatch(matcher.precomputed().negate(), s);
    312   }
    313 
    314   private void reallyTestOneCharMatch(CharMatcher matcher, String s) {
    315     assertTrue(matcher.matches(s.charAt(0)));
    316     assertTrue(matcher.apply(s.charAt(0)));
    317     assertEquals(0, matcher.indexIn(s));
    318     assertEquals(0, matcher.indexIn(s, 0));
    319     assertEquals(-1, matcher.indexIn(s, 1));
    320     assertEquals(0, matcher.lastIndexIn(s));
    321     assertTrue(matcher.matchesAnyOf(s));
    322     assertTrue(matcher.matchesAllOf(s));
    323     assertFalse(matcher.matchesNoneOf(s));
    324     assertEquals("", matcher.removeFrom(s));
    325     assertEquals("z", matcher.replaceFrom(s, 'z'));
    326     assertEquals("ZZ", matcher.replaceFrom(s, "ZZ"));
    327     assertEquals("", matcher.trimFrom(s));
    328     assertEquals(1, matcher.countIn(s));
    329   }
    330 
    331   private void reallyTestOneCharNoMatch(CharMatcher matcher, String s) {
    332     assertFalse(matcher.matches(s.charAt(0)));
    333     assertFalse(matcher.apply(s.charAt(0)));
    334     assertEquals(-1, matcher.indexIn(s));
    335     assertEquals(-1, matcher.indexIn(s, 0));
    336     assertEquals(-1, matcher.indexIn(s, 1));
    337     assertEquals(-1, matcher.lastIndexIn(s));
    338     assertFalse(matcher.matchesAnyOf(s));
    339     assertFalse(matcher.matchesAllOf(s));
    340     assertTrue(matcher.matchesNoneOf(s));
    341 
    342     // Note: only 'assertEquals' is promised by the API.  Although they could
    343     // have been assertSame() on the server side, they have to be assertEquals
    344     // in GWT, because of GWT issue 4491.
    345     assertEquals(s, matcher.removeFrom(s));
    346     assertEquals(s, matcher.replaceFrom(s, 'z'));
    347     assertEquals(s, matcher.replaceFrom(s, "ZZ"));
    348     assertEquals(s, matcher.trimFrom(s));
    349     assertEquals(0, matcher.countIn(s));
    350   }
    351 
    352   private void reallyTestMatchThenNoMatch(CharMatcher matcher, String s) {
    353     assertEquals(0, matcher.indexIn(s));
    354     assertEquals(0, matcher.indexIn(s, 0));
    355     assertEquals(-1, matcher.indexIn(s, 1));
    356     assertEquals(-1, matcher.indexIn(s, 2));
    357     assertEquals(0, matcher.lastIndexIn(s));
    358     assertTrue(matcher.matchesAnyOf(s));
    359     assertFalse(matcher.matchesAllOf(s));
    360     assertFalse(matcher.matchesNoneOf(s));
    361     assertEquals(s.substring(1), matcher.removeFrom(s));
    362     assertEquals("z" + s.substring(1), matcher.replaceFrom(s, 'z'));
    363     assertEquals("ZZ" + s.substring(1), matcher.replaceFrom(s, "ZZ"));
    364     assertEquals(s.substring(1), matcher.trimFrom(s));
    365     assertEquals(1, matcher.countIn(s));
    366   }
    367 
    368   private void reallyTestNoMatchThenMatch(CharMatcher matcher, String s) {
    369     assertEquals(1, matcher.indexIn(s));
    370     assertEquals(1, matcher.indexIn(s, 0));
    371     assertEquals(1, matcher.indexIn(s, 1));
    372     assertEquals(-1, matcher.indexIn(s, 2));
    373     assertEquals(1, matcher.lastIndexIn(s));
    374     assertTrue(matcher.matchesAnyOf(s));
    375     assertFalse(matcher.matchesAllOf(s));
    376     assertFalse(matcher.matchesNoneOf(s));
    377     assertEquals(s.substring(0, 1), matcher.removeFrom(s));
    378     assertEquals(s.substring(0, 1) + "z", matcher.replaceFrom(s, 'z'));
    379     assertEquals(s.substring(0, 1) + "ZZ", matcher.replaceFrom(s, "ZZ"));
    380     assertEquals(s.substring(0, 1), matcher.trimFrom(s));
    381     assertEquals(1, matcher.countIn(s));
    382   }
    383 
    384   // Test collapse() a little differently than the rest, as we really want to
    385   // cover lots of different configurations of input text
    386   public void testCollapse() {
    387     // collapsing groups of - into _
    388     doTestCollapse("-", "_");
    389     doTestCollapse("x-", "x_");
    390     doTestCollapse("-x", "_x");
    391     doTestCollapse("--", "_");
    392     doTestCollapse("x--", "x_");
    393     doTestCollapse("--x", "_x");
    394     doTestCollapse("-x-", "_x_");
    395     doTestCollapse("x-x", "x_x");
    396     doTestCollapse("---", "_");
    397     doTestCollapse("--x-", "_x_");
    398     doTestCollapse("--xx", "_xx");
    399     doTestCollapse("-x--", "_x_");
    400     doTestCollapse("-x-x", "_x_x");
    401     doTestCollapse("-xx-", "_xx_");
    402     doTestCollapse("x--x", "x_x");
    403     doTestCollapse("x-x-", "x_x_");
    404     doTestCollapse("x-xx", "x_xx");
    405     doTestCollapse("x-x--xx---x----x", "x_x_xx_x_x");
    406 
    407     doTestCollapseWithNoChange("");
    408     doTestCollapseWithNoChange("x");
    409     doTestCollapseWithNoChange("xx");
    410   }
    411 
    412   private void doTestCollapse(String in, String out) {
    413     // Try a few different matchers which all match '-' and not 'x'
    414     assertEquals(out, is('-').collapseFrom(in, '_'));
    415     assertEquals(out, is('-').or(is('#')).collapseFrom(in, '_'));
    416     assertEquals(out, isNot('x').collapseFrom(in, '_'));
    417     assertEquals(out, is('x').negate().collapseFrom(in, '_'));
    418     assertEquals(out, anyOf("-").collapseFrom(in, '_'));
    419     assertEquals(out, anyOf("-#").collapseFrom(in, '_'));
    420     assertEquals(out, anyOf("-#123").collapseFrom(in, '_'));
    421   }
    422 
    423   private void doTestCollapseWithNoChange(String inout) {
    424     /*
    425      * Note: assertSame(), not promised by the spec, happens to work with the
    426      * current implementation because String.toString() promises to return
    427      * |this|. However, GWT bug 4491 keeps it from working there, so we stick
    428      * with assertEquals().
    429      */
    430     assertEquals(inout, is('-').collapseFrom(inout, '_'));
    431     assertEquals(inout, is('-').or(is('#')).collapseFrom(inout, '_'));
    432     assertEquals(inout, isNot('x').collapseFrom(inout, '_'));
    433     assertEquals(inout, is('x').negate().collapseFrom(inout, '_'));
    434     assertEquals(inout, anyOf("-").collapseFrom(inout, '_'));
    435     assertEquals(inout, anyOf("-#").collapseFrom(inout, '_'));
    436     assertEquals(inout, anyOf("-#123").collapseFrom(inout, '_'));
    437     assertEquals(inout, CharMatcher.NONE.collapseFrom(inout, '_'));
    438   }
    439 
    440   public void testCollapse_any() {
    441     assertEquals("", CharMatcher.ANY.collapseFrom("", '_'));
    442     assertEquals("_", CharMatcher.ANY.collapseFrom("a", '_'));
    443     assertEquals("_", CharMatcher.ANY.collapseFrom("ab", '_'));
    444     assertEquals("_", CharMatcher.ANY.collapseFrom("abcd", '_'));
    445   }
    446 
    447   public void testTrimFrom() {
    448     // trimming -
    449     doTestTrimFrom("-", "");
    450     doTestTrimFrom("x-", "x");
    451     doTestTrimFrom("-x", "x");
    452     doTestTrimFrom("--", "");
    453     doTestTrimFrom("x--", "x");
    454     doTestTrimFrom("--x", "x");
    455     doTestTrimFrom("-x-", "x");
    456     doTestTrimFrom("x-x", "x-x");
    457     doTestTrimFrom("---", "");
    458     doTestTrimFrom("--x-", "x");
    459     doTestTrimFrom("--xx", "xx");
    460     doTestTrimFrom("-x--", "x");
    461     doTestTrimFrom("-x-x", "x-x");
    462     doTestTrimFrom("-xx-", "xx");
    463     doTestTrimFrom("x--x", "x--x");
    464     doTestTrimFrom("x-x-", "x-x");
    465     doTestTrimFrom("x-xx", "x-xx");
    466     doTestTrimFrom("x-x--xx---x----x", "x-x--xx---x----x");
    467     // additional testing using the doc example
    468     assertEquals("cat", anyOf("ab").trimFrom("abacatbab"));
    469   }
    470 
    471   private void doTestTrimFrom(String in, String out) {
    472     // Try a few different matchers which all match '-' and not 'x'
    473     assertEquals(out, is('-').trimFrom(in));
    474     assertEquals(out, is('-').or(is('#')).trimFrom(in));
    475     assertEquals(out, isNot('x').trimFrom(in));
    476     assertEquals(out, is('x').negate().trimFrom(in));
    477     assertEquals(out, anyOf("-").trimFrom(in));
    478     assertEquals(out, anyOf("-#").trimFrom(in));
    479     assertEquals(out, anyOf("-#123").trimFrom(in));
    480   }
    481 
    482   public void testTrimLeadingFrom() {
    483     // trimming -
    484     doTestTrimLeadingFrom("-", "");
    485     doTestTrimLeadingFrom("x-", "x-");
    486     doTestTrimLeadingFrom("-x", "x");
    487     doTestTrimLeadingFrom("--", "");
    488     doTestTrimLeadingFrom("x--", "x--");
    489     doTestTrimLeadingFrom("--x", "x");
    490     doTestTrimLeadingFrom("-x-", "x-");
    491     doTestTrimLeadingFrom("x-x", "x-x");
    492     doTestTrimLeadingFrom("---", "");
    493     doTestTrimLeadingFrom("--x-", "x-");
    494     doTestTrimLeadingFrom("--xx", "xx");
    495     doTestTrimLeadingFrom("-x--", "x--");
    496     doTestTrimLeadingFrom("-x-x", "x-x");
    497     doTestTrimLeadingFrom("-xx-", "xx-");
    498     doTestTrimLeadingFrom("x--x", "x--x");
    499     doTestTrimLeadingFrom("x-x-", "x-x-");
    500     doTestTrimLeadingFrom("x-xx", "x-xx");
    501     doTestTrimLeadingFrom("x-x--xx---x----x", "x-x--xx---x----x");
    502     // additional testing using the doc example
    503     assertEquals("catbab", anyOf("ab").trimLeadingFrom("abacatbab"));
    504   }
    505 
    506   private void doTestTrimLeadingFrom(String in, String out) {
    507     // Try a few different matchers which all match '-' and not 'x'
    508     assertEquals(out, is('-').trimLeadingFrom(in));
    509     assertEquals(out, is('-').or(is('#')).trimLeadingFrom(in));
    510     assertEquals(out, isNot('x').trimLeadingFrom(in));
    511     assertEquals(out, is('x').negate().trimLeadingFrom(in));
    512     assertEquals(out, anyOf("-#").trimLeadingFrom(in));
    513     assertEquals(out, anyOf("-#123").trimLeadingFrom(in));
    514   }
    515 
    516   public void testTrimTrailingFrom() {
    517     // trimming -
    518     doTestTrimTrailingFrom("-", "");
    519     doTestTrimTrailingFrom("x-", "x");
    520     doTestTrimTrailingFrom("-x", "-x");
    521     doTestTrimTrailingFrom("--", "");
    522     doTestTrimTrailingFrom("x--", "x");
    523     doTestTrimTrailingFrom("--x", "--x");
    524     doTestTrimTrailingFrom("-x-", "-x");
    525     doTestTrimTrailingFrom("x-x", "x-x");
    526     doTestTrimTrailingFrom("---", "");
    527     doTestTrimTrailingFrom("--x-", "--x");
    528     doTestTrimTrailingFrom("--xx", "--xx");
    529     doTestTrimTrailingFrom("-x--", "-x");
    530     doTestTrimTrailingFrom("-x-x", "-x-x");
    531     doTestTrimTrailingFrom("-xx-", "-xx");
    532     doTestTrimTrailingFrom("x--x", "x--x");
    533     doTestTrimTrailingFrom("x-x-", "x-x");
    534     doTestTrimTrailingFrom("x-xx", "x-xx");
    535     doTestTrimTrailingFrom("x-x--xx---x----x", "x-x--xx---x----x");
    536     // additional testing using the doc example
    537     assertEquals("abacat", anyOf("ab").trimTrailingFrom("abacatbab"));
    538   }
    539 
    540   private void doTestTrimTrailingFrom(String in, String out) {
    541     // Try a few different matchers which all match '-' and not 'x'
    542     assertEquals(out, is('-').trimTrailingFrom(in));
    543     assertEquals(out, is('-').or(is('#')).trimTrailingFrom(in));
    544     assertEquals(out, isNot('x').trimTrailingFrom(in));
    545     assertEquals(out, is('x').negate().trimTrailingFrom(in));
    546     assertEquals(out, anyOf("-#").trimTrailingFrom(in));
    547     assertEquals(out, anyOf("-#123").trimTrailingFrom(in));
    548   }
    549 
    550   public void testTrimAndCollapse() {
    551     // collapsing groups of - into _
    552     doTestTrimAndCollapse("-", "");
    553     doTestTrimAndCollapse("x-", "x");
    554     doTestTrimAndCollapse("-x", "x");
    555     doTestTrimAndCollapse("--", "");
    556     doTestTrimAndCollapse("x--", "x");
    557     doTestTrimAndCollapse("--x", "x");
    558     doTestTrimAndCollapse("-x-", "x");
    559     doTestTrimAndCollapse("x-x", "x_x");
    560     doTestTrimAndCollapse("---", "");
    561     doTestTrimAndCollapse("--x-", "x");
    562     doTestTrimAndCollapse("--xx", "xx");
    563     doTestTrimAndCollapse("-x--", "x");
    564     doTestTrimAndCollapse("-x-x", "x_x");
    565     doTestTrimAndCollapse("-xx-", "xx");
    566     doTestTrimAndCollapse("x--x", "x_x");
    567     doTestTrimAndCollapse("x-x-", "x_x");
    568     doTestTrimAndCollapse("x-xx", "x_xx");
    569     doTestTrimAndCollapse("x-x--xx---x----x", "x_x_xx_x_x");
    570   }
    571 
    572   private void doTestTrimAndCollapse(String in, String out) {
    573     // Try a few different matchers which all match '-' and not 'x'
    574     assertEquals(out, is('-').trimAndCollapseFrom(in, '_'));
    575     assertEquals(out, is('-').or(is('#')).trimAndCollapseFrom(in, '_'));
    576     assertEquals(out, isNot('x').trimAndCollapseFrom(in, '_'));
    577     assertEquals(out, is('x').negate().trimAndCollapseFrom(in, '_'));
    578     assertEquals(out, anyOf("-").trimAndCollapseFrom(in, '_'));
    579     assertEquals(out, anyOf("-#").trimAndCollapseFrom(in, '_'));
    580     assertEquals(out, anyOf("-#123").trimAndCollapseFrom(in, '_'));
    581   }
    582 
    583   public void testReplaceFrom() {
    584     assertEquals("yoho", is('a').replaceFrom("yaha", 'o'));
    585     assertEquals("yh", is('a').replaceFrom("yaha", ""));
    586     assertEquals("yoho", is('a').replaceFrom("yaha", "o"));
    587     assertEquals("yoohoo", is('a').replaceFrom("yaha", "oo"));
    588     assertEquals("12 &gt; 5", is('>').replaceFrom("12 > 5", "&gt;"));
    589   }
    590 
    591   public void testPrecomputedOptimizations() {
    592     // These are testing behavior that's never promised by the API.
    593     // Some matchers are so efficient that it is a waste of effort to
    594     // build a precomputed version.
    595     CharMatcher m1 = is('x');
    596     assertSame(m1, m1.precomputed());
    597 
    598     CharMatcher m2 = anyOf("Az");
    599     assertSame(m2, m2.precomputed());
    600 
    601     CharMatcher m3 = inRange('A', 'Z');
    602     assertSame(m3, m3.precomputed());
    603 
    604     assertSame(CharMatcher.NONE, CharMatcher.NONE.precomputed());
    605     assertSame(CharMatcher.ANY, CharMatcher.ANY.precomputed());
    606   }
    607 }
    608