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