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 @J2ktIncompatible 116 @GwtIncompatible // java.util.BitSet testSetBits()117 public void testSetBits() { 118 doTestSetBits(CharMatcher.any()); 119 doTestSetBits(CharMatcher.none()); 120 doTestSetBits(is('a')); 121 doTestSetBits(isNot('a')); 122 doTestSetBits(anyOf("")); 123 doTestSetBits(anyOf("x")); 124 doTestSetBits(anyOf("xy")); 125 doTestSetBits(anyOf("CharMatcher")); 126 doTestSetBits(noneOf("CharMatcher")); 127 doTestSetBits(inRange('n', 'q')); 128 doTestSetBits(forPredicate(Predicates.equalTo('c'))); 129 doTestSetBits(CharMatcher.ascii()); 130 doTestSetBits(CharMatcher.digit()); 131 doTestSetBits(CharMatcher.invisible()); 132 doTestSetBits(CharMatcher.whitespace()); 133 doTestSetBits(inRange('A', 'Z').and(inRange('F', 'K').negate())); 134 } 135 136 @J2ktIncompatible 137 @GwtIncompatible // java.util.BitSet doTestSetBits(CharMatcher matcher)138 private void doTestSetBits(CharMatcher matcher) { 139 BitSet bitset = new BitSet(); 140 matcher.setBits(bitset); 141 for (int i = Character.MIN_VALUE; i <= Character.MAX_VALUE; i++) { 142 assertEquals(matcher.matches((char) i), bitset.get(i)); 143 } 144 } 145 testEmpty()146 public void testEmpty() throws Exception { 147 doTestEmpty(CharMatcher.any()); 148 doTestEmpty(CharMatcher.none()); 149 doTestEmpty(is('a')); 150 doTestEmpty(isNot('a')); 151 doTestEmpty(anyOf("")); 152 doTestEmpty(anyOf("x")); 153 doTestEmpty(anyOf("xy")); 154 doTestEmpty(anyOf("CharMatcher")); 155 doTestEmpty(noneOf("CharMatcher")); 156 doTestEmpty(inRange('n', 'q')); 157 doTestEmpty(forPredicate(Predicates.equalTo('c'))); 158 } 159 160 @J2ktIncompatible 161 @GwtIncompatible // NullPointerTester testNull()162 public void testNull() throws Exception { 163 doTestNull(CharMatcher.any()); 164 doTestNull(CharMatcher.none()); 165 doTestNull(is('a')); 166 doTestNull(isNot('a')); 167 doTestNull(anyOf("")); 168 doTestNull(anyOf("x")); 169 doTestNull(anyOf("xy")); 170 doTestNull(anyOf("CharMatcher")); 171 doTestNull(noneOf("CharMatcher")); 172 doTestNull(inRange('n', 'q')); 173 doTestNull(forPredicate(Predicates.equalTo('c'))); 174 } 175 doTestEmpty(CharMatcher matcher)176 private void doTestEmpty(CharMatcher matcher) throws Exception { 177 reallyTestEmpty(matcher); 178 reallyTestEmpty(matcher.negate()); 179 reallyTestEmpty(matcher.precomputed()); 180 } 181 reallyTestEmpty(CharMatcher matcher)182 private void reallyTestEmpty(CharMatcher matcher) throws Exception { 183 assertEquals(-1, matcher.indexIn("")); 184 assertEquals(-1, matcher.indexIn("", 0)); 185 try { 186 matcher.indexIn("", 1); 187 fail(); 188 } catch (IndexOutOfBoundsException expected) { 189 } 190 try { 191 matcher.indexIn("", -1); 192 fail(); 193 } catch (IndexOutOfBoundsException expected) { 194 } 195 assertEquals(-1, matcher.lastIndexIn("")); 196 assertFalse(matcher.matchesAnyOf("")); 197 assertTrue(matcher.matchesAllOf("")); 198 assertTrue(matcher.matchesNoneOf("")); 199 assertEquals("", matcher.removeFrom("")); 200 assertEquals("", matcher.replaceFrom("", 'z')); 201 assertEquals("", matcher.replaceFrom("", "ZZ")); 202 assertEquals("", matcher.trimFrom("")); 203 assertEquals(0, matcher.countIn("")); 204 } 205 206 @J2ktIncompatible 207 @GwtIncompatible // NullPointerTester doTestNull(CharMatcher matcher)208 private static void doTestNull(CharMatcher matcher) throws Exception { 209 NullPointerTester tester = new NullPointerTester(); 210 tester.testAllPublicInstanceMethods(matcher); 211 } 212 testNoMatches()213 public void testNoMatches() { 214 doTestNoMatches(CharMatcher.none(), "blah"); 215 doTestNoMatches(is('a'), "bcde"); 216 doTestNoMatches(isNot('a'), "aaaa"); 217 doTestNoMatches(anyOf(""), "abcd"); 218 doTestNoMatches(anyOf("x"), "abcd"); 219 doTestNoMatches(anyOf("xy"), "abcd"); 220 doTestNoMatches(anyOf("CharMatcher"), "zxqy"); 221 doTestNoMatches(noneOf("CharMatcher"), "ChMa"); 222 doTestNoMatches(inRange('p', 'x'), "mom"); 223 doTestNoMatches(forPredicate(Predicates.equalTo('c')), "abe"); 224 doTestNoMatches(inRange('A', 'Z').and(inRange('F', 'K').negate()), "F1a"); 225 doTestNoMatches(CharMatcher.digit(), "\tAz()"); 226 doTestNoMatches(CharMatcher.javaDigit(), "\tAz()"); 227 doTestNoMatches(CharMatcher.digit().and(CharMatcher.ascii()), "\tAz()"); 228 doTestNoMatches(CharMatcher.singleWidth(), "\u05bf\u3000"); 229 } 230 doTestNoMatches(CharMatcher matcher, String s)231 private void doTestNoMatches(CharMatcher matcher, String s) { 232 reallyTestNoMatches(matcher, s); 233 reallyTestAllMatches(matcher.negate(), s); 234 reallyTestNoMatches(matcher.precomputed(), s); 235 reallyTestAllMatches(matcher.negate().precomputed(), s); 236 reallyTestAllMatches(matcher.precomputed().negate(), s); 237 reallyTestNoMatches(forPredicate(matcher), s); 238 239 reallyTestNoMatches(matcher, new StringBuilder(s)); 240 } 241 testAllMatches()242 public void testAllMatches() { 243 doTestAllMatches(CharMatcher.any(), "blah"); 244 doTestAllMatches(isNot('a'), "bcde"); 245 doTestAllMatches(is('a'), "aaaa"); 246 doTestAllMatches(noneOf("CharMatcher"), "zxqy"); 247 doTestAllMatches(anyOf("x"), "xxxx"); 248 doTestAllMatches(anyOf("xy"), "xyyx"); 249 doTestAllMatches(anyOf("CharMatcher"), "ChMa"); 250 doTestAllMatches(inRange('m', 'p'), "mom"); 251 doTestAllMatches(forPredicate(Predicates.equalTo('c')), "ccc"); 252 doTestAllMatches(CharMatcher.digit(), "0123456789\u0ED0\u1B59"); 253 doTestAllMatches(CharMatcher.javaDigit(), "0123456789"); 254 doTestAllMatches(CharMatcher.digit().and(CharMatcher.ascii()), "0123456789"); 255 doTestAllMatches(CharMatcher.singleWidth(), "\t0123ABCdef~\u00A0\u2111"); 256 } 257 doTestAllMatches(CharMatcher matcher, String s)258 private void doTestAllMatches(CharMatcher matcher, String s) { 259 reallyTestAllMatches(matcher, s); 260 reallyTestNoMatches(matcher.negate(), s); 261 reallyTestAllMatches(matcher.precomputed(), s); 262 reallyTestNoMatches(matcher.negate().precomputed(), s); 263 reallyTestNoMatches(matcher.precomputed().negate(), s); 264 reallyTestAllMatches(forPredicate(matcher), s); 265 266 reallyTestAllMatches(matcher, new StringBuilder(s)); 267 } 268 reallyTestNoMatches(CharMatcher matcher, CharSequence s)269 private void reallyTestNoMatches(CharMatcher matcher, CharSequence s) { 270 assertFalse(matcher.matches(s.charAt(0))); 271 assertEquals(-1, matcher.indexIn(s)); 272 assertEquals(-1, matcher.indexIn(s, 0)); 273 assertEquals(-1, matcher.indexIn(s, 1)); 274 assertEquals(-1, matcher.indexIn(s, s.length())); 275 try { 276 matcher.indexIn(s, s.length() + 1); 277 fail(); 278 } catch (IndexOutOfBoundsException expected) { 279 } 280 try { 281 matcher.indexIn(s, -1); 282 fail(); 283 } catch (IndexOutOfBoundsException expected) { 284 } 285 assertEquals(-1, matcher.lastIndexIn(s)); 286 assertFalse(matcher.matchesAnyOf(s)); 287 assertFalse(matcher.matchesAllOf(s)); 288 assertTrue(matcher.matchesNoneOf(s)); 289 290 assertEquals(s.toString(), matcher.removeFrom(s)); 291 assertEquals(s.toString(), matcher.replaceFrom(s, 'z')); 292 assertEquals(s.toString(), matcher.replaceFrom(s, "ZZ")); 293 assertEquals(s.toString(), matcher.trimFrom(s)); 294 assertEquals(0, matcher.countIn(s)); 295 } 296 reallyTestAllMatches(CharMatcher matcher, CharSequence s)297 private void reallyTestAllMatches(CharMatcher matcher, CharSequence s) { 298 assertTrue(matcher.matches(s.charAt(0))); 299 assertEquals(0, matcher.indexIn(s)); 300 assertEquals(0, matcher.indexIn(s, 0)); 301 assertEquals(1, matcher.indexIn(s, 1)); 302 assertEquals(-1, matcher.indexIn(s, s.length())); 303 assertEquals(s.length() - 1, matcher.lastIndexIn(s)); 304 assertTrue(matcher.matchesAnyOf(s)); 305 assertTrue(matcher.matchesAllOf(s)); 306 assertFalse(matcher.matchesNoneOf(s)); 307 assertEquals("", matcher.removeFrom(s)); 308 assertEquals(Strings.repeat("z", s.length()), matcher.replaceFrom(s, 'z')); 309 assertEquals(Strings.repeat("ZZ", s.length()), matcher.replaceFrom(s, "ZZ")); 310 assertEquals("", matcher.trimFrom(s)); 311 assertEquals(s.length(), matcher.countIn(s)); 312 } 313 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 > 5", is('>').replaceFrom("12 > 5", ">")); 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 @J2ktIncompatible 684 @GwtIncompatible // java.util.BitSet bitSet(String chars)685 private static BitSet bitSet(String chars) { 686 return bitSet(chars.toCharArray()); 687 } 688 689 @J2ktIncompatible 690 @GwtIncompatible // java.util.BitSet bitSet(char[] chars)691 private static BitSet bitSet(char[] chars) { 692 BitSet tmp = new BitSet(); 693 for (char c : chars) { 694 tmp.set(c); 695 } 696 return tmp; 697 } 698 699 @J2ktIncompatible 700 @GwtIncompatible // java.util.Random, java.util.BitSet testSmallCharMatcher()701 public void testSmallCharMatcher() { 702 CharMatcher len1 = SmallCharMatcher.from(bitSet("#"), "#"); 703 CharMatcher len2 = SmallCharMatcher.from(bitSet("ab"), "ab"); 704 CharMatcher len3 = SmallCharMatcher.from(bitSet("abc"), "abc"); 705 CharMatcher len4 = SmallCharMatcher.from(bitSet("abcd"), "abcd"); 706 assertTrue(len1.matches('#')); 707 assertFalse(len1.matches('!')); 708 assertTrue(len2.matches('a')); 709 assertTrue(len2.matches('b')); 710 for (char c = 'c'; c < 'z'; c++) { 711 assertFalse(len2.matches(c)); 712 } 713 assertTrue(len3.matches('a')); 714 assertTrue(len3.matches('b')); 715 assertTrue(len3.matches('c')); 716 for (char c = 'd'; c < 'z'; c++) { 717 assertFalse(len3.matches(c)); 718 } 719 assertTrue(len4.matches('a')); 720 assertTrue(len4.matches('b')); 721 assertTrue(len4.matches('c')); 722 assertTrue(len4.matches('d')); 723 for (char c = 'e'; c < 'z'; c++) { 724 assertFalse(len4.matches(c)); 725 } 726 727 Random rand = new Random(1234); 728 for (int testCase = 0; testCase < 100; testCase++) { 729 char[] chars = randomChars(rand, rand.nextInt(63) + 1); 730 CharMatcher m = SmallCharMatcher.from(bitSet(chars), new String(chars)); 731 checkExactMatches(m, chars); 732 } 733 } 734 checkExactMatches(CharMatcher m, char[] chars)735 static void checkExactMatches(CharMatcher m, char[] chars) { 736 Set<Character> positive = Sets.newHashSetWithExpectedSize(chars.length); 737 for (char c : chars) { 738 positive.add(c); 739 } 740 for (int c = 0; c <= Character.MAX_VALUE; c++) { 741 assertFalse(positive.contains(new Character((char) c)) ^ m.matches((char) c)); 742 } 743 } 744 randomChars(Random rand, int size)745 static char[] randomChars(Random rand, int size) { 746 Set<Character> chars = new HashSet<>(size); 747 for (int i = 0; i < size; i++) { 748 char c; 749 do { 750 c = (char) rand.nextInt(Character.MAX_VALUE - Character.MIN_VALUE + 1); 751 } while (chars.contains(c)); 752 chars.add(c); 753 } 754 char[] retValue = new char[chars.size()]; 755 int i = 0; 756 for (char c : chars) { 757 retValue[i++] = c; 758 } 759 Arrays.sort(retValue); 760 return retValue; 761 } 762 testToString()763 public void testToString() { 764 assertToStringWorks("CharMatcher.none()", CharMatcher.anyOf("")); 765 assertToStringWorks("CharMatcher.is('\\u0031')", CharMatcher.anyOf("1")); 766 assertToStringWorks("CharMatcher.isNot('\\u0031')", CharMatcher.isNot('1')); 767 assertToStringWorks("CharMatcher.anyOf(\"\\u0031\\u0032\")", CharMatcher.anyOf("12")); 768 assertToStringWorks("CharMatcher.anyOf(\"\\u0031\\u0032\\u0033\")", CharMatcher.anyOf("321")); 769 assertToStringWorks("CharMatcher.inRange('\\u0031', '\\u0033')", CharMatcher.inRange('1', '3')); 770 } 771 assertToStringWorks(String expected, CharMatcher matcher)772 private static void assertToStringWorks(String expected, CharMatcher matcher) { 773 assertEquals(expected, matcher.toString()); 774 assertEquals(expected, matcher.precomputed().toString()); 775 assertEquals(expected, matcher.negate().negate().toString()); 776 assertEquals(expected, matcher.negate().precomputed().negate().toString()); 777 assertEquals(expected, matcher.negate().precomputed().negate().precomputed().toString()); 778 } 779 } 780