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