1/* 2 * Copyright (C) 2009 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.truth.Truth.assertThat; 20 21import com.google.common.annotations.GwtCompatible; 22import com.google.common.collect.ImmutableList; 23import com.google.common.collect.ImmutableMap; 24 25import junit.framework.TestCase; 26 27import java.util.Collection; 28import java.util.Iterator; 29import java.util.List; 30import java.util.Map; 31 32/** 33 * @author Julien Silland 34 */ 35@GwtCompatible(emulated = true) 36public class SplitterTest extends TestCase { 37 38 private static final Splitter COMMA_SPLITTER = Splitter.on(','); 39 40 public void testSplitNullString() { 41 try { 42 COMMA_SPLITTER.split(null); 43 fail(); 44 } catch (NullPointerException expected) { 45 } 46 } 47 48 public void testCharacterSimpleSplit() { 49 String simple = "a,b,c"; 50 Iterable<String> letters = COMMA_SPLITTER.split(simple); 51 assertThat(letters).iteratesAs("a", "b", "c"); 52 } 53 54 /** 55 * All of the infrastructure of split and splitToString is identical, so we 56 * do one test of splitToString. All other cases should be covered by testing 57 * of split. 58 * 59 * <p>TODO(user): It would be good to make all the relevant tests run on 60 * both split and splitToString automatically. 61 */ 62 public void testCharacterSimpleSplitToList() { 63 String simple = "a,b,c"; 64 List<String> letters = COMMA_SPLITTER.splitToList(simple); 65 assertThat(letters).iteratesAs("a", "b", "c"); 66 } 67 68 public void testToString() { 69 assertEquals("[]", Splitter.on(',').split("").toString()); 70 assertEquals("[a, b, c]", Splitter.on(',').split("a,b,c").toString()); 71 assertEquals("[yam, bam, jam, ham]", Splitter.on(", ").split("yam, bam, jam, ham").toString()); 72 } 73 74 public void testCharacterSimpleSplitWithNoDelimiter() { 75 String simple = "a,b,c"; 76 Iterable<String> letters = Splitter.on('.').split(simple); 77 assertThat(letters).iteratesAs("a,b,c"); 78 } 79 80 public void testCharacterSplitWithDoubleDelimiter() { 81 String doubled = "a,,b,c"; 82 Iterable<String> letters = COMMA_SPLITTER.split(doubled); 83 assertThat(letters).iteratesAs("a", "", "b", "c"); 84 } 85 86 public void testCharacterSplitWithDoubleDelimiterAndSpace() { 87 String doubled = "a,, b,c"; 88 Iterable<String> letters = COMMA_SPLITTER.split(doubled); 89 assertThat(letters).iteratesAs("a", "", " b", "c"); 90 } 91 92 public void testCharacterSplitWithTrailingDelimiter() { 93 String trailing = "a,b,c,"; 94 Iterable<String> letters = COMMA_SPLITTER.split(trailing); 95 assertThat(letters).iteratesAs("a", "b", "c", ""); 96 } 97 98 public void testCharacterSplitWithLeadingDelimiter() { 99 String leading = ",a,b,c"; 100 Iterable<String> letters = COMMA_SPLITTER.split(leading); 101 assertThat(letters).iteratesAs("", "a", "b", "c"); 102 } 103 104 public void testCharacterSplitWithMulitpleLetters() { 105 Iterable<String> testCharacteringMotto = Splitter.on('-').split( 106 "Testing-rocks-Debugging-sucks"); 107 assertThat(testCharacteringMotto).iteratesAs( 108 "Testing", "rocks", "Debugging", "sucks"); 109 } 110 111 public void testCharacterSplitWithMatcherDelimiter() { 112 Iterable<String> testCharacteringMotto = Splitter 113 .on(CharMatcher.WHITESPACE) 114 .split("Testing\nrocks\tDebugging sucks"); 115 assertThat(testCharacteringMotto).iteratesAs( 116 "Testing", "rocks", "Debugging", "sucks"); 117 } 118 119 public void testCharacterSplitWithDoubleDelimiterOmitEmptyStrings() { 120 String doubled = "a..b.c"; 121 Iterable<String> letters = Splitter.on('.') 122 .omitEmptyStrings().split(doubled); 123 assertThat(letters).iteratesAs("a", "b", "c"); 124 } 125 126 public void testCharacterSplitEmptyToken() { 127 String emptyToken = "a. .c"; 128 Iterable<String> letters = Splitter.on('.').trimResults() 129 .split(emptyToken); 130 assertThat(letters).iteratesAs("a", "", "c"); 131 } 132 133 public void testCharacterSplitEmptyTokenOmitEmptyStrings() { 134 String emptyToken = "a. .c"; 135 Iterable<String> letters = Splitter.on('.') 136 .omitEmptyStrings().trimResults().split(emptyToken); 137 assertThat(letters).iteratesAs("a", "c"); 138 } 139 140 public void testCharacterSplitOnEmptyString() { 141 Iterable<String> nothing = Splitter.on('.').split(""); 142 assertThat(nothing).iteratesAs(""); 143 } 144 145 public void testCharacterSplitOnEmptyStringOmitEmptyStrings() { 146 assertThat(Splitter.on('.').omitEmptyStrings().split("")).isEmpty(); 147 } 148 149 public void testCharacterSplitOnOnlyDelimiter() { 150 Iterable<String> blankblank = Splitter.on('.').split("."); 151 assertThat(blankblank).iteratesAs("", ""); 152 } 153 154 public void testCharacterSplitOnOnlyDelimitersOmitEmptyStrings() { 155 Iterable<String> empty = Splitter.on('.').omitEmptyStrings().split("..."); 156 assertThat(empty).isEmpty(); 157 } 158 159 public void testCharacterSplitWithTrim() { 160 String jacksons = "arfo(Marlon)aorf, (Michael)orfa, afro(Jackie)orfa, " 161 + "ofar(Jemaine), aff(Tito)"; 162 Iterable<String> family = COMMA_SPLITTER 163 .trimResults(CharMatcher.anyOf("afro").or(CharMatcher.WHITESPACE)) 164 .split(jacksons); 165 assertThat(family).iteratesAs( 166 "(Marlon)", "(Michael)", "(Jackie)", "(Jemaine)", "(Tito)"); 167 } 168 169 public void testStringSimpleSplit() { 170 String simple = "a,b,c"; 171 Iterable<String> letters = Splitter.on(',').split(simple); 172 assertThat(letters).iteratesAs("a", "b", "c"); 173 } 174 175 public void testStringSimpleSplitWithNoDelimiter() { 176 String simple = "a,b,c"; 177 Iterable<String> letters = Splitter.on('.').split(simple); 178 assertThat(letters).iteratesAs("a,b,c"); 179 } 180 181 public void testStringSplitWithDoubleDelimiter() { 182 String doubled = "a,,b,c"; 183 Iterable<String> letters = Splitter.on(',').split(doubled); 184 assertThat(letters).iteratesAs("a", "", "b", "c"); 185 } 186 187 public void testStringSplitWithDoubleDelimiterAndSpace() { 188 String doubled = "a,, b,c"; 189 Iterable<String> letters = Splitter.on(',').split(doubled); 190 assertThat(letters).iteratesAs("a", "", " b", "c"); 191 } 192 193 public void testStringSplitWithTrailingDelimiter() { 194 String trailing = "a,b,c,"; 195 Iterable<String> letters = Splitter.on(',').split(trailing); 196 assertThat(letters).iteratesAs("a", "b", "c", ""); 197 } 198 199 public void testStringSplitWithLeadingDelimiter() { 200 String leading = ",a,b,c"; 201 Iterable<String> letters = Splitter.on(',').split(leading); 202 assertThat(letters).iteratesAs("", "a", "b", "c"); 203 } 204 205 public void testStringSplitWithMultipleLetters() { 206 Iterable<String> testStringingMotto = Splitter.on('-').split( 207 "Testing-rocks-Debugging-sucks"); 208 assertThat(testStringingMotto).iteratesAs( 209 "Testing", "rocks", "Debugging", "sucks"); 210 } 211 212 public void testStringSplitWithDoubleDelimiterOmitEmptyStrings() { 213 String doubled = "a..b.c"; 214 Iterable<String> letters = Splitter.on('.') 215 .omitEmptyStrings().split(doubled); 216 assertThat(letters).iteratesAs("a", "b", "c"); 217 } 218 219 public void testStringSplitEmptyToken() { 220 String emptyToken = "a. .c"; 221 Iterable<String> letters = Splitter.on('.').trimResults() 222 .split(emptyToken); 223 assertThat(letters).iteratesAs("a", "", "c"); 224 } 225 226 public void testStringSplitEmptyTokenOmitEmptyStrings() { 227 String emptyToken = "a. .c"; 228 Iterable<String> letters = Splitter.on('.') 229 .omitEmptyStrings().trimResults().split(emptyToken); 230 assertThat(letters).iteratesAs("a", "c"); 231 } 232 233 public void testStringSplitWithLongDelimiter() { 234 String longDelimiter = "a, b, c"; 235 Iterable<String> letters = Splitter.on(", ").split(longDelimiter); 236 assertThat(letters).iteratesAs("a", "b", "c"); 237 } 238 239 public void testStringSplitWithLongLeadingDelimiter() { 240 String longDelimiter = ", a, b, c"; 241 Iterable<String> letters = Splitter.on(", ").split(longDelimiter); 242 assertThat(letters).iteratesAs("", "a", "b", "c"); 243 } 244 245 public void testStringSplitWithLongTrailingDelimiter() { 246 String longDelimiter = "a, b, c, "; 247 Iterable<String> letters = Splitter.on(", ").split(longDelimiter); 248 assertThat(letters).iteratesAs("a", "b", "c", ""); 249 } 250 251 public void testStringSplitWithDelimiterSubstringInValue() { 252 String fourCommasAndFourSpaces = ",,,, "; 253 Iterable<String> threeCommasThenThreeSpaces = Splitter.on(", ").split( 254 fourCommasAndFourSpaces); 255 assertThat(threeCommasThenThreeSpaces).iteratesAs(",,,", " "); 256 } 257 258 public void testStringSplitWithEmptyString() { 259 try { 260 Splitter.on(""); 261 fail(); 262 } catch (IllegalArgumentException expected) { 263 } 264 } 265 266 public void testStringSplitOnEmptyString() { 267 Iterable<String> notMuch = Splitter.on('.').split(""); 268 assertThat(notMuch).iteratesAs(""); 269 } 270 271 public void testStringSplitOnEmptyStringOmitEmptyString() { 272 assertThat(Splitter.on('.').omitEmptyStrings().split("")).isEmpty(); 273 } 274 275 public void testStringSplitOnOnlyDelimiter() { 276 Iterable<String> blankblank = Splitter.on('.').split("."); 277 assertThat(blankblank).iteratesAs("", ""); 278 } 279 280 public void testStringSplitOnOnlyDelimitersOmitEmptyStrings() { 281 Iterable<String> empty = Splitter.on('.').omitEmptyStrings().split("..."); 282 assertThat(empty).isEmpty(); 283 } 284 285 public void testStringSplitWithTrim() { 286 String jacksons = "arfo(Marlon)aorf, (Michael)orfa, afro(Jackie)orfa, " 287 + "ofar(Jemaine), aff(Tito)"; 288 Iterable<String> family = Splitter.on(',') 289 .trimResults(CharMatcher.anyOf("afro").or(CharMatcher.WHITESPACE)) 290 .split(jacksons); 291 assertThat(family).iteratesAs( 292 "(Marlon)", "(Michael)", "(Jackie)", "(Jemaine)", "(Tito)"); 293 } 294 295 // TODO(kevinb): the name of this method suggests it might not actually be testing what it 296 // intends to be testing? 297 298 public void testSplitterIterableIsUnmodifiable_char() { 299 assertIteratorIsUnmodifiable(COMMA_SPLITTER.split("a,b").iterator()); 300 } 301 302 public void testSplitterIterableIsUnmodifiable_string() { 303 assertIteratorIsUnmodifiable(Splitter.on(',').split("a,b").iterator()); 304 } 305 306 private void assertIteratorIsUnmodifiable(Iterator<?> iterator) { 307 iterator.next(); 308 try { 309 iterator.remove(); 310 fail(); 311 } catch (UnsupportedOperationException expected) { 312 } 313 } 314 315 public void testSplitterIterableIsLazy_char() { 316 assertSplitterIterableIsLazy(COMMA_SPLITTER); 317 } 318 319 public void testSplitterIterableIsLazy_string() { 320 assertSplitterIterableIsLazy(Splitter.on(',')); 321 } 322 323 /** 324 * This test really pushes the boundaries of what we support. In general the 325 * splitter's behaviour is not well defined if the char sequence it's 326 * splitting is mutated during iteration. 327 */ 328 private void assertSplitterIterableIsLazy(Splitter splitter) { 329 StringBuilder builder = new StringBuilder(); 330 Iterator<String> iterator = splitter.split(builder).iterator(); 331 332 builder.append("A,"); 333 assertEquals("A", iterator.next()); 334 builder.append("B,"); 335 assertEquals("B", iterator.next()); 336 builder.append("C"); 337 assertEquals("C", iterator.next()); 338 assertFalse(iterator.hasNext()); 339 } 340 341 public void testFixedLengthSimpleSplit() { 342 String simple = "abcde"; 343 Iterable<String> letters = Splitter.fixedLength(2).split(simple); 344 assertThat(letters).iteratesAs("ab", "cd", "e"); 345 } 346 347 public void testFixedLengthSplitEqualChunkLength() { 348 String simple = "abcdef"; 349 Iterable<String> letters = Splitter.fixedLength(2).split(simple); 350 assertThat(letters).iteratesAs("ab", "cd", "ef"); 351 } 352 353 public void testFixedLengthSplitOnlyOneChunk() { 354 String simple = "abc"; 355 Iterable<String> letters = Splitter.fixedLength(3).split(simple); 356 assertThat(letters).iteratesAs("abc"); 357 } 358 359 public void testFixedLengthSplitSmallerString() { 360 String simple = "ab"; 361 Iterable<String> letters = Splitter.fixedLength(3).split(simple); 362 assertThat(letters).iteratesAs("ab"); 363 } 364 365 public void testFixedLengthSplitEmptyString() { 366 String simple = ""; 367 Iterable<String> letters = Splitter.fixedLength(3).split(simple); 368 assertThat(letters).iteratesAs(""); 369 } 370 371 public void testFixedLengthSplitEmptyStringWithOmitEmptyStrings() { 372 assertThat(Splitter.fixedLength(3).omitEmptyStrings().split("")).isEmpty(); 373 } 374 375 public void testFixedLengthSplitIntoChars() { 376 String simple = "abcd"; 377 Iterable<String> letters = Splitter.fixedLength(1).split(simple); 378 assertThat(letters).iteratesAs("a", "b", "c", "d"); 379 } 380 381 public void testFixedLengthSplitZeroChunkLen() { 382 try { 383 Splitter.fixedLength(0); 384 fail(); 385 } catch (IllegalArgumentException expected) { 386 } 387 } 388 389 public void testFixedLengthSplitNegativeChunkLen() { 390 try { 391 Splitter.fixedLength(-1); 392 fail(); 393 } catch (IllegalArgumentException expected) { 394 } 395 } 396 397 public void testLimitLarge() { 398 String simple = "abcd"; 399 Iterable<String> letters = Splitter.fixedLength(1).limit(100).split(simple); 400 assertThat(letters).iteratesAs("a", "b", "c", "d"); 401 } 402 403 public void testLimitOne() { 404 String simple = "abcd"; 405 Iterable<String> letters = Splitter.fixedLength(1).limit(1).split(simple); 406 assertThat(letters).iteratesAs("abcd"); 407 } 408 409 public void testLimitFixedLength() { 410 String simple = "abcd"; 411 Iterable<String> letters = Splitter.fixedLength(1).limit(2).split(simple); 412 assertThat(letters).iteratesAs("a", "bcd"); 413 } 414 415 public void testLimitSeparator() { 416 String simple = "a,b,c,d"; 417 Iterable<String> items = COMMA_SPLITTER.limit(2).split(simple); 418 assertThat(items).iteratesAs("a", "b,c,d"); 419 } 420 421 public void testLimitExtraSeparators() { 422 String text = "a,,,b,,c,d"; 423 Iterable<String> items = COMMA_SPLITTER.limit(2).split(text); 424 assertThat(items).iteratesAs("a", ",,b,,c,d"); 425 } 426 427 public void testLimitExtraSeparatorsOmitEmpty() { 428 String text = "a,,,b,,c,d"; 429 Iterable<String> items = COMMA_SPLITTER.limit(2).omitEmptyStrings().split(text); 430 assertThat(items).iteratesAs("a", "b,,c,d"); 431 } 432 433 public void testLimitExtraSeparatorsOmitEmpty3() { 434 String text = "a,,,b,,c,d"; 435 Iterable<String> items = COMMA_SPLITTER.limit(3).omitEmptyStrings().split(text); 436 assertThat(items).iteratesAs("a", "b", "c,d"); 437 } 438 439 public void testLimitExtraSeparatorsTrim() { 440 String text = ",,a,, , b ,, c,d "; 441 Iterable<String> items = COMMA_SPLITTER.limit(2).omitEmptyStrings().trimResults().split(text); 442 assertThat(items).iteratesAs("a", "b ,, c,d"); 443 } 444 445 public void testLimitExtraSeparatorsTrim3() { 446 String text = ",,a,, , b ,, c,d "; 447 Iterable<String> items = COMMA_SPLITTER.limit(3).omitEmptyStrings().trimResults().split(text); 448 assertThat(items).iteratesAs("a", "b", "c,d"); 449 } 450 451 public void testLimitExtraSeparatorsTrim1() { 452 String text = ",,a,, , b ,, c,d "; 453 Iterable<String> items = COMMA_SPLITTER.limit(1).omitEmptyStrings().trimResults().split(text); 454 assertThat(items).iteratesAs("a,, , b ,, c,d"); 455 } 456 457 public void testLimitExtraSeparatorsTrim1NoOmit() { 458 String text = ",,a,, , b ,, c,d "; 459 Iterable<String> items = COMMA_SPLITTER.limit(1).trimResults().split(text); 460 assertThat(items).iteratesAs(",,a,, , b ,, c,d"); 461 } 462 463 public void testLimitExtraSeparatorsTrim1Empty() { 464 String text = ""; 465 Iterable<String> items = COMMA_SPLITTER.limit(1).split(text); 466 assertThat(items).iteratesAs(""); 467 } 468 469 public void testLimitExtraSeparatorsTrim1EmptyOmit() { 470 String text = ""; 471 Iterable<String> items = COMMA_SPLITTER.omitEmptyStrings().limit(1).split(text); 472 assertThat(items).isEmpty(); 473 } 474 475 @SuppressWarnings("ReturnValueIgnored") // testing for exception 476 public void testInvalidZeroLimit() { 477 try { 478 COMMA_SPLITTER.limit(0); 479 fail(); 480 } catch (IllegalArgumentException expected) { 481 } 482 } 483 484 private static <E> List<E> asList(Collection<E> collection) { 485 return ImmutableList.copyOf(collection); 486 } 487 488 public void testMapSplitter_trimmedBoth() { 489 Map<String, String> m = COMMA_SPLITTER 490 .trimResults() 491 .withKeyValueSeparator(Splitter.on(':').trimResults()) 492 .split("boy : tom , girl: tina , cat : kitty , dog: tommy "); 493 ImmutableMap<String, String> expected = 494 ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy"); 495 assertThat(m).isEqualTo(expected); 496 assertThat(asList(m.entrySet())).isEqualTo(asList(expected.entrySet())); 497 } 498 499 public void testMapSplitter_trimmedEntries() { 500 Map<String, String> m = COMMA_SPLITTER 501 .trimResults() 502 .withKeyValueSeparator(":") 503 .split("boy : tom , girl: tina , cat : kitty , dog: tommy "); 504 ImmutableMap<String, String> expected = 505 ImmutableMap.of("boy ", " tom", "girl", " tina", "cat ", " kitty", "dog", " tommy"); 506 507 assertThat(m).isEqualTo(expected); 508 assertThat(asList(m.entrySet())).isEqualTo(asList(expected.entrySet())); 509 } 510 511 public void testMapSplitter_trimmedKeyValue() { 512 Map<String, String> m = 513 COMMA_SPLITTER.withKeyValueSeparator(Splitter.on(':').trimResults()).split( 514 "boy : tom , girl: tina , cat : kitty , dog: tommy "); 515 ImmutableMap<String, String> expected = 516 ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy"); 517 assertThat(m).isEqualTo(expected); 518 assertThat(asList(m.entrySet())).isEqualTo(asList(expected.entrySet())); 519 } 520 521 public void testMapSplitter_notTrimmed() { 522 Map<String, String> m = COMMA_SPLITTER.withKeyValueSeparator(":").split( 523 " boy:tom , girl: tina , cat :kitty , dog: tommy "); 524 ImmutableMap<String, String> expected = 525 ImmutableMap.of(" boy", "tom ", " girl", " tina ", " cat ", "kitty ", " dog", " tommy "); 526 assertThat(m).isEqualTo(expected); 527 assertThat(asList(m.entrySet())).isEqualTo(asList(expected.entrySet())); 528 } 529 530 public void testMapSplitter_CharacterSeparator() { 531 // try different delimiters. 532 Map<String, String> m = Splitter 533 .on(",") 534 .withKeyValueSeparator(':') 535 .split("boy:tom,girl:tina,cat:kitty,dog:tommy"); 536 ImmutableMap<String, String> expected = 537 ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy"); 538 539 assertThat(m).isEqualTo(expected); 540 assertThat(asList(m.entrySet())).isEqualTo(asList(expected.entrySet())); 541 } 542 543 public void testMapSplitter_multiCharacterSeparator() { 544 // try different delimiters. 545 Map<String, String> m = Splitter 546 .on(",") 547 .withKeyValueSeparator(":^&") 548 .split("boy:^&tom,girl:^&tina,cat:^&kitty,dog:^&tommy"); 549 ImmutableMap<String, String> expected = 550 ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy"); 551 552 assertThat(m).isEqualTo(expected); 553 assertThat(asList(m.entrySet())).isEqualTo(asList(expected.entrySet())); 554 } 555 556 @SuppressWarnings("ReturnValueIgnored") // testing for exception 557 public void testMapSplitter_emptySeparator() { 558 try { 559 COMMA_SPLITTER.withKeyValueSeparator(""); 560 fail(); 561 } catch (IllegalArgumentException expected) { 562 } 563 } 564 565 public void testMapSplitter_malformedEntry() { 566 try { 567 COMMA_SPLITTER.withKeyValueSeparator("=").split("a=1,b,c=2"); 568 fail(); 569 } catch (IllegalArgumentException expected) { 570 } 571 } 572 573 public void testMapSplitter_orderedResults() { 574 Map<String, String> m = Splitter.on(',') 575 .withKeyValueSeparator(":") 576 .split("boy:tom,girl:tina,cat:kitty,dog:tommy"); 577 578 assertThat(m.keySet()).iteratesAs("boy", "girl", "cat", "dog"); 579 assertThat(m).isEqualTo( 580 ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy")); 581 582 // try in a different order 583 m = Splitter.on(',') 584 .withKeyValueSeparator(":") 585 .split("girl:tina,boy:tom,dog:tommy,cat:kitty"); 586 587 assertThat(m.keySet()).iteratesAs("girl", "boy", "dog", "cat"); 588 assertThat(m).isEqualTo( 589 ImmutableMap.of("boy", "tom", "girl", "tina", "cat", "kitty", "dog", "tommy")); 590 } 591 592 public void testMapSplitter_duplicateKeys() { 593 try { 594 Splitter.on(',').withKeyValueSeparator(":").split("a:1,b:2,a:3"); 595 fail(); 596 } catch (IllegalArgumentException expected) { 597 } 598 } 599} 600