Home | History | Annotate | Download | only in base
      1 /*
      2  * Copyright (C) 2008 The Guava Authors
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.common.base;
     18 
     19 import com.google.common.annotations.GwtCompatible;
     20 import com.google.common.annotations.GwtIncompatible;
     21 import com.google.common.base.Joiner.MapJoiner;
     22 import com.google.common.collect.ImmutableMap;
     23 import com.google.common.collect.ImmutableMultimap;
     24 import com.google.common.collect.ImmutableSet;
     25 import com.google.common.collect.Iterators;
     26 import com.google.common.collect.Lists;
     27 import com.google.common.collect.Maps;
     28 import com.google.common.testing.NullPointerTester;
     29 
     30 import junit.framework.TestCase;
     31 
     32 import java.io.IOException;
     33 import java.util.Arrays;
     34 import java.util.Iterator;
     35 import java.util.Map;
     36 import java.util.Set;
     37 
     38 /**
     39  * Unit test for {@link Joiner}.
     40  *
     41  * @author Kevin Bourrillion
     42  */
     43 @GwtCompatible(emulated = true)
     44 public class JoinerTest extends TestCase {
     45   private static final Joiner J = Joiner.on("-");
     46 
     47   // <Integer> needed to prevent warning :(
     48   private static final Iterable<Integer> ITERABLE_ = Arrays.<Integer>asList();
     49   private static final Iterable<Integer> ITERABLE_1 = Arrays.asList(1);
     50   private static final Iterable<Integer> ITERABLE_12 = Arrays.asList(1, 2);
     51   private static final Iterable<Integer> ITERABLE_123 = Arrays.asList(1, 2, 3);
     52   private static final Iterable<Integer> ITERABLE_NULL = Arrays.asList((Integer) null);
     53   private static final Iterable<Integer> ITERABLE_NULL_NULL
     54       = Arrays.asList((Integer) null, null);
     55   private static final Iterable<Integer> ITERABLE_NULL_1 = Arrays.asList(null, 1);
     56   private static final Iterable<Integer> ITERABLE_1_NULL = Arrays.asList(1, null);
     57   private static final Iterable<Integer> ITERABLE_1_NULL_2 = Arrays.asList(1, null, 2);
     58   private static final Iterable<Integer> ITERABLE_FOUR_NULLS
     59       = Arrays.asList((Integer) null, null, null, null);
     60 
     61   public void testNoSpecialNullBehavior() {
     62     checkNoOutput(J, ITERABLE_);
     63     checkResult(J, ITERABLE_1, "1");
     64     checkResult(J, ITERABLE_12, "1-2");
     65     checkResult(J, ITERABLE_123, "1-2-3");
     66 
     67     try {
     68       J.join(ITERABLE_NULL);
     69       fail();
     70     } catch (NullPointerException expected) {
     71     }
     72     try {
     73       J.join(ITERABLE_1_NULL_2);
     74       fail();
     75     } catch (NullPointerException expected) {
     76     }
     77 
     78     try {
     79       J.join(ITERABLE_NULL.iterator());
     80       fail();
     81     } catch (NullPointerException expected) {
     82     }
     83     try {
     84       J.join(ITERABLE_1_NULL_2.iterator());
     85       fail();
     86     } catch (NullPointerException expected) {
     87     }
     88   }
     89 
     90   public void testOnCharOverride() {
     91     Joiner onChar = Joiner.on('-');
     92     checkNoOutput(onChar, ITERABLE_);
     93     checkResult(onChar, ITERABLE_1, "1");
     94     checkResult(onChar, ITERABLE_12, "1-2");
     95     checkResult(onChar, ITERABLE_123, "1-2-3");
     96   }
     97 
     98   public void testSkipNulls() {
     99     Joiner skipNulls = J.skipNulls();
    100     checkNoOutput(skipNulls, ITERABLE_);
    101     checkNoOutput(skipNulls, ITERABLE_NULL);
    102     checkNoOutput(skipNulls, ITERABLE_NULL_NULL);
    103     checkNoOutput(skipNulls, ITERABLE_FOUR_NULLS);
    104     checkResult(skipNulls, ITERABLE_1, "1");
    105     checkResult(skipNulls, ITERABLE_12, "1-2");
    106     checkResult(skipNulls, ITERABLE_123, "1-2-3");
    107     checkResult(skipNulls, ITERABLE_NULL_1, "1");
    108     checkResult(skipNulls, ITERABLE_1_NULL, "1");
    109     checkResult(skipNulls, ITERABLE_1_NULL_2, "1-2");
    110   }
    111 
    112   public void testUseForNull() {
    113     Joiner zeroForNull = J.useForNull("0");
    114     checkNoOutput(zeroForNull, ITERABLE_);
    115     checkResult(zeroForNull, ITERABLE_1, "1");
    116     checkResult(zeroForNull, ITERABLE_12, "1-2");
    117     checkResult(zeroForNull, ITERABLE_123, "1-2-3");
    118     checkResult(zeroForNull, ITERABLE_NULL, "0");
    119     checkResult(zeroForNull, ITERABLE_NULL_NULL, "0-0");
    120     checkResult(zeroForNull, ITERABLE_NULL_1, "0-1");
    121     checkResult(zeroForNull, ITERABLE_1_NULL, "1-0");
    122     checkResult(zeroForNull, ITERABLE_1_NULL_2, "1-0-2");
    123     checkResult(zeroForNull, ITERABLE_FOUR_NULLS, "0-0-0-0");
    124   }
    125 
    126   private static void checkNoOutput(Joiner joiner, Iterable<Integer> set) {
    127     assertEquals("", joiner.join(set));
    128     assertEquals("", joiner.join(set.iterator()));
    129 
    130     Object[] array = Lists.newArrayList(set).toArray(new Integer[0]);
    131     assertEquals("", joiner.join(array));
    132 
    133     StringBuilder sb1FromIterable = new StringBuilder();
    134     assertSame(sb1FromIterable, joiner.appendTo(sb1FromIterable, set));
    135     assertEquals(0, sb1FromIterable.length());
    136 
    137     StringBuilder sb1FromIterator = new StringBuilder();
    138     assertSame(sb1FromIterator, joiner.appendTo(sb1FromIterator, set));
    139     assertEquals(0, sb1FromIterator.length());
    140 
    141     StringBuilder sb2 = new StringBuilder();
    142     assertSame(sb2, joiner.appendTo(sb2, array));
    143     assertEquals(0, sb2.length());
    144 
    145     try {
    146       joiner.appendTo(NASTY_APPENDABLE, set);
    147     } catch (IOException e) {
    148       throw new AssertionError(e);
    149     }
    150 
    151     try {
    152       joiner.appendTo(NASTY_APPENDABLE, set.iterator());
    153     } catch (IOException e) {
    154       throw new AssertionError(e);
    155     }
    156 
    157     try {
    158       joiner.appendTo(NASTY_APPENDABLE, array);
    159     } catch (IOException e) {
    160       throw new AssertionError(e);
    161     }
    162   }
    163 
    164   private static final Appendable NASTY_APPENDABLE = new Appendable() {
    165     @Override
    166     public Appendable append(CharSequence csq) throws IOException {
    167       throw new IOException();
    168     }
    169     @Override
    170     public Appendable append(CharSequence csq, int start, int end) throws IOException {
    171       throw new IOException();
    172     }
    173     @Override
    174     public Appendable append(char c) throws IOException {
    175       throw new IOException();
    176     }
    177   };
    178 
    179   private static void checkResult(Joiner joiner, Iterable<Integer> parts, String expected) {
    180     assertEquals(expected, joiner.join(parts));
    181     assertEquals(expected, joiner.join(parts.iterator()));
    182 
    183     StringBuilder sb1FromIterable = new StringBuilder().append('x');
    184     joiner.appendTo(sb1FromIterable, parts);
    185     assertEquals("x" + expected, sb1FromIterable.toString());
    186 
    187     StringBuilder sb1FromIterator = new StringBuilder().append('x');
    188     joiner.appendTo(sb1FromIterator, parts.iterator());
    189     assertEquals("x" + expected, sb1FromIterator.toString());
    190 
    191     Integer[] partsArray = Lists.newArrayList(parts).toArray(new Integer[0]);
    192     assertEquals(expected, joiner.join(partsArray));
    193 
    194     StringBuilder sb2 = new StringBuilder().append('x');
    195     joiner.appendTo(sb2, partsArray);
    196     assertEquals("x" + expected, sb2.toString());
    197 
    198     int num = partsArray.length - 2;
    199     if (num >= 0) {
    200       Object[] rest = new Integer[num];
    201       for (int i = 0; i < num; i++) {
    202         rest[i] = partsArray[i + 2];
    203       }
    204 
    205       assertEquals(expected, joiner.join(partsArray[0], partsArray[1], rest));
    206 
    207       StringBuilder sb3 = new StringBuilder().append('x');
    208       joiner.appendTo(sb3, partsArray[0], partsArray[1], rest);
    209       assertEquals("x" + expected, sb3.toString());
    210     }
    211   }
    212 
    213   public void testIterableIterator() {
    214     Joiner onChar = Joiner.on('-');
    215     checkIterableIterator(onChar, "1-2-3-4");
    216 
    217     Joiner skipNulls = J.skipNulls();
    218     checkIterableIterator(skipNulls, "1-2-3-4");
    219 
    220     Joiner zeroForNull = J.useForNull("0");
    221     checkIterableIterator(zeroForNull, "1-2-3-4");
    222   }
    223 
    224   private static void checkIterableIterator(Joiner joiner, String expected) {
    225     assertEquals(expected, joiner.join(new IterableIterator()));
    226 
    227     StringBuilder sb1 = new StringBuilder().append('x');
    228     joiner.appendTo(sb1, new IterableIterator());
    229     assertEquals("x" + expected, sb1.toString());
    230 
    231     Integer[] partsArray =
    232         Lists.newArrayList(new IterableIterator().iterator()).toArray(new Integer[0]);
    233     assertEquals(expected, joiner.join(partsArray));
    234 
    235     StringBuilder sb2 = new StringBuilder().append('x');
    236     joiner.appendTo(sb2, partsArray);
    237     assertEquals("x" + expected, sb2.toString());
    238 
    239     int num = partsArray.length - 2;
    240     if (num >= 0) {
    241       Object[] rest = new Integer[num];
    242       for (int i = 0; i < num; i++) {
    243         rest[i] = partsArray[i + 2];
    244       }
    245 
    246       assertEquals(expected, joiner.join(partsArray[0], partsArray[1], rest));
    247 
    248       StringBuilder sb3 = new StringBuilder().append('x');
    249       joiner.appendTo(sb3, partsArray[0], partsArray[1], rest);
    250       assertEquals("x" + expected, sb3.toString());
    251     }
    252   }
    253 
    254   public void test_useForNull_skipNulls() {
    255     Joiner j = Joiner.on("x").useForNull("y");
    256     try {
    257       j.skipNulls();
    258       fail();
    259     } catch (UnsupportedOperationException expected) {
    260     }
    261   }
    262 
    263   public void test_skipNulls_useForNull() {
    264     Joiner j = Joiner.on("x").skipNulls();
    265     try {
    266       j.useForNull("y");
    267       fail();
    268     } catch (UnsupportedOperationException expected) {
    269     }
    270   }
    271 
    272   public void test_useForNull_twice() {
    273     Joiner j = Joiner.on("x").useForNull("y");
    274     try {
    275       j.useForNull("y");
    276       fail();
    277     } catch (UnsupportedOperationException expected) {
    278     }
    279   }
    280 
    281   public void testMap() {
    282     MapJoiner j = Joiner.on(";").withKeyValueSeparator(":");
    283     assertEquals("", j.join(ImmutableMap.of()));
    284     assertEquals(":", j.join(ImmutableMap.of("", "")));
    285 
    286     Map<String, String> mapWithNulls = Maps.newLinkedHashMap();
    287     mapWithNulls.put("a", null);
    288     mapWithNulls.put(null, "b");
    289 
    290     try {
    291       j.join(mapWithNulls);
    292       fail();
    293     } catch (NullPointerException expected) {
    294     }
    295 
    296     assertEquals("a:00;00:b", j.useForNull("00").join(mapWithNulls));
    297 
    298     StringBuilder sb = new StringBuilder();
    299     j.appendTo(sb, ImmutableMap.of(1, 2, 3, 4, 5, 6));
    300     assertEquals("1:2;3:4;5:6", sb.toString());
    301   }
    302 
    303   public void testEntries() {
    304     MapJoiner j = Joiner.on(";").withKeyValueSeparator(":");
    305     assertEquals("", j.join(ImmutableMultimap.of().entries()));
    306     assertEquals("", j.join(ImmutableMultimap.of().entries().iterator()));
    307     assertEquals(":", j.join(ImmutableMultimap.of("", "").entries()));
    308     assertEquals(":", j.join(ImmutableMultimap.of("", "").entries().iterator()));
    309     assertEquals("1:a;1:b", j.join(ImmutableMultimap.of("1", "a", "1", "b").entries()));
    310     assertEquals("1:a;1:b", j.join(ImmutableMultimap.of("1", "a", "1", "b").entries().iterator()));
    311 
    312     Map<String, String> mapWithNulls = Maps.newLinkedHashMap();
    313     mapWithNulls.put("a", null);
    314     mapWithNulls.put(null, "b");
    315     Set<Map.Entry<String, String>> entriesWithNulls = mapWithNulls.entrySet();
    316 
    317     try {
    318       j.join(entriesWithNulls);
    319       fail();
    320     } catch (NullPointerException expected) {
    321     }
    322 
    323     try {
    324       j.join(entriesWithNulls.iterator());
    325       fail();
    326     } catch (NullPointerException expected) {
    327     }
    328 
    329     assertEquals("a:00;00:b", j.useForNull("00").join(entriesWithNulls));
    330     assertEquals("a:00;00:b", j.useForNull("00").join(entriesWithNulls.iterator()));
    331 
    332     StringBuilder sb1 = new StringBuilder();
    333     j.appendTo(sb1, ImmutableMultimap.of(1, 2, 3, 4, 5, 6, 1, 3, 5, 10).entries());
    334     assertEquals("1:2;1:3;3:4;5:6;5:10", sb1.toString());
    335 
    336     StringBuilder sb2 = new StringBuilder();
    337     j.appendTo(sb2, ImmutableMultimap.of(1, 2, 3, 4, 5, 6, 1, 3, 5, 10).entries().iterator());
    338     assertEquals("1:2;1:3;3:4;5:6;5:10", sb2.toString());
    339   }
    340 
    341   public void test_skipNulls_onMap() {
    342     Joiner j = Joiner.on(",").skipNulls();
    343     try {
    344       j.withKeyValueSeparator("/");
    345       fail();
    346     } catch (UnsupportedOperationException expected) {
    347     }
    348   }
    349 
    350   private static class DontStringMeBro implements CharSequence {
    351     @Override
    352     public int length() {
    353       return 3;
    354     }
    355     @Override
    356     public char charAt(int index) {
    357       return "foo".charAt(index);
    358     }
    359     @Override
    360     public CharSequence subSequence(int start, int end) {
    361       return "foo".subSequence(start, end);
    362     }
    363     @Override public String toString() {
    364       fail("shouldn't be invoked");
    365       return null;
    366     }
    367   }
    368 
    369   // Don't do this.
    370   private static class IterableIterator implements Iterable<Integer>, Iterator<Integer> {
    371     private static final ImmutableSet<Integer> INTEGERS = ImmutableSet.of(1, 2, 3, 4);
    372     private final Iterator<Integer> iterator;
    373     public IterableIterator() {
    374       this.iterator = iterator();
    375     }
    376     @Override public Iterator<Integer> iterator() {
    377       return INTEGERS.iterator();
    378     }
    379     @Override public boolean hasNext() {
    380       return iterator.hasNext();
    381     }
    382     @Override public Integer next() {
    383       return iterator.next();
    384     }
    385     @Override public void remove() {
    386       iterator.remove();
    387     }
    388   }
    389 
    390   @GwtIncompatible("StringBuilder.append in GWT invokes Object.toString(), unlike the JRE version.")
    391   public void testDontConvertCharSequenceToString() {
    392     assertEquals("foo,foo", Joiner.on(",").join(
    393         new DontStringMeBro(), new DontStringMeBro()));
    394     assertEquals("foo,bar,foo", Joiner.on(",").useForNull("bar").join(
    395         new DontStringMeBro(), null, new DontStringMeBro()));
    396   }
    397 
    398   @GwtIncompatible("NullPointerTester")
    399   public void testNullPointers() throws Exception {
    400     NullPointerTester tester = new NullPointerTester();
    401     tester.setDefault(StringBuilder.class, new StringBuilder());
    402     // This is necessary because of the generics hackery we have to temporarily support parameters
    403     // which implement both Iterator and Iterable.
    404     tester.setDefault(Object.class, Iterators.emptyIterator());
    405     tester.testAllPublicStaticMethods(Joiner.class);
    406     tester.testAllPublicInstanceMethods(Joiner.on(","));
    407     tester.testAllPublicInstanceMethods(Joiner.on(",").skipNulls());
    408     tester.testAllPublicInstanceMethods(Joiner.on(",").useForNull("x"));
    409     tester.testAllPublicInstanceMethods(
    410         Joiner.on(",").withKeyValueSeparator("="));
    411   }
    412 }
    413