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 > 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 @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