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.Lists;
     26 import com.google.common.collect.Maps;
     27 import com.google.common.testing.NullPointerTester;
     28 
     29 import junit.framework.AssertionFailedError;
     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 test_useForNull_skipNulls() {
    214     Joiner j = Joiner.on("x").useForNull("y");
    215     try {
    216       j = j.skipNulls();
    217       fail();
    218     } catch (UnsupportedOperationException expected) {
    219     }
    220   }
    221 
    222   public void test_skipNulls_useForNull() {
    223     Joiner j = Joiner.on("x").skipNulls();
    224     try {
    225       j = j.useForNull("y");
    226       fail();
    227     } catch (UnsupportedOperationException expected) {
    228     }
    229   }
    230 
    231   public void test_useForNull_twice() {
    232     Joiner j = Joiner.on("x").useForNull("y");
    233     try {
    234       j = j.useForNull("y");
    235       fail();
    236     } catch (UnsupportedOperationException expected) {
    237     }
    238   }
    239 
    240   public void testMap() {
    241     MapJoiner j = Joiner.on(";").withKeyValueSeparator(":");
    242     assertEquals("", j.join(ImmutableMap.of()));
    243     assertEquals(":", j.join(ImmutableMap.of("", "")));
    244 
    245     Map<String, String> mapWithNulls = Maps.newLinkedHashMap();
    246     mapWithNulls.put("a", null);
    247     mapWithNulls.put(null, "b");
    248 
    249     try {
    250       j.join(mapWithNulls);
    251       fail();
    252     } catch (NullPointerException expected) {
    253     }
    254 
    255     assertEquals("a:00;00:b", j.useForNull("00").join(mapWithNulls));
    256 
    257     StringBuilder sb = new StringBuilder();
    258     j.appendTo(sb, ImmutableMap.of(1, 2, 3, 4, 5, 6));
    259     assertEquals("1:2;3:4;5:6", sb.toString());
    260   }
    261 
    262   public void testEntries() {
    263     MapJoiner j = Joiner.on(";").withKeyValueSeparator(":");
    264     assertEquals("", j.join(ImmutableMultimap.of().entries()));
    265     assertEquals("", j.join(ImmutableMultimap.of().entries().iterator()));
    266     assertEquals(":", j.join(ImmutableMultimap.of("", "").entries()));
    267     assertEquals(":", j.join(ImmutableMultimap.of("", "").entries().iterator()));
    268     assertEquals("1:a;1:b", j.join(ImmutableMultimap.of("1", "a", "1", "b").entries()));
    269     assertEquals("1:a;1:b", j.join(ImmutableMultimap.of("1", "a", "1", "b").entries().iterator()));
    270 
    271     Map<String, String> mapWithNulls = Maps.newLinkedHashMap();
    272     mapWithNulls.put("a", null);
    273     mapWithNulls.put(null, "b");
    274     Set<Map.Entry<String, String>> entriesWithNulls = mapWithNulls.entrySet();
    275 
    276     try {
    277       j.join(entriesWithNulls);
    278       fail();
    279     } catch (NullPointerException expected) {
    280     }
    281 
    282     try {
    283       j.join(entriesWithNulls.iterator());
    284       fail();
    285     } catch (NullPointerException expected) {
    286     }
    287 
    288     assertEquals("a:00;00:b", j.useForNull("00").join(entriesWithNulls));
    289     assertEquals("a:00;00:b", j.useForNull("00").join(entriesWithNulls.iterator()));
    290 
    291     StringBuilder sb1 = new StringBuilder();
    292     j.appendTo(sb1, ImmutableMultimap.of(1, 2, 3, 4, 5, 6, 1, 3, 5, 10).entries());
    293     assertEquals("1:2;1:3;3:4;5:6;5:10", sb1.toString());
    294 
    295     StringBuilder sb2 = new StringBuilder();
    296     j.appendTo(sb2, ImmutableMultimap.of(1, 2, 3, 4, 5, 6, 1, 3, 5, 10).entries().iterator());
    297     assertEquals("1:2;1:3;3:4;5:6;5:10", sb2.toString());
    298   }
    299 
    300   @SuppressWarnings("ReturnValueIgnored") // testing for exception
    301   public void test_skipNulls_onMap() {
    302     Joiner j = Joiner.on(",").skipNulls();
    303     try {
    304       j.withKeyValueSeparator("/");
    305       fail();
    306     } catch (UnsupportedOperationException expected) {
    307     }
    308   }
    309 
    310   private static class DontStringMeBro implements CharSequence {
    311     @Override
    312     public int length() {
    313       return 3;
    314     }
    315     @Override
    316     public char charAt(int index) {
    317       return "foo".charAt(index);
    318     }
    319     @Override
    320     public CharSequence subSequence(int start, int end) {
    321       return "foo".subSequence(start, end);
    322     }
    323     @Override public String toString() {
    324       throw new AssertionFailedError("shouldn't be invoked");
    325     }
    326   }
    327 
    328   // Don't do this.
    329   private static class IterableIterator implements Iterable<Integer>, Iterator<Integer> {
    330     private static final ImmutableSet<Integer> INTEGERS = ImmutableSet.of(1, 2, 3, 4);
    331     private final Iterator<Integer> iterator;
    332     public IterableIterator() {
    333       this.iterator = iterator();
    334     }
    335     @Override public Iterator<Integer> iterator() {
    336       return INTEGERS.iterator();
    337     }
    338     @Override public boolean hasNext() {
    339       return iterator.hasNext();
    340     }
    341     @Override public Integer next() {
    342       return iterator.next();
    343     }
    344     @Override public void remove() {
    345       iterator.remove();
    346     }
    347   }
    348 
    349   @GwtIncompatible("StringBuilder.append in GWT invokes Object.toString(), unlike the JRE version.")
    350   public void testDontConvertCharSequenceToString() {
    351     assertEquals("foo,foo", Joiner.on(",").join(
    352         new DontStringMeBro(), new DontStringMeBro()));
    353     assertEquals("foo,bar,foo", Joiner.on(",").useForNull("bar").join(
    354         new DontStringMeBro(), null, new DontStringMeBro()));
    355   }
    356 
    357   @GwtIncompatible("NullPointerTester")
    358   public void testNullPointers() {
    359     NullPointerTester tester = new NullPointerTester();
    360     tester.testAllPublicStaticMethods(Joiner.class);
    361     tester.testInstanceMethods(Joiner.on(","), NullPointerTester.Visibility.PACKAGE);
    362     tester.testInstanceMethods(Joiner.on(",").skipNulls(), NullPointerTester.Visibility.PACKAGE);
    363     tester.testInstanceMethods(
    364         Joiner.on(",").useForNull("x"), NullPointerTester.Visibility.PACKAGE);
    365     tester.testInstanceMethods(
    366         Joiner.on(",").withKeyValueSeparator("="), NullPointerTester.Visibility.PACKAGE);
    367   }
    368 }
    369