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