• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import java.io.IOException;
29 import java.util.Arrays;
30 import java.util.Iterator;
31 import java.util.Map;
32 import java.util.Map.Entry;
33 import java.util.Set;
34 import junit.framework.AssertionFailedError;
35 import junit.framework.TestCase;
36 
37 /**
38  * Unit test for {@link Joiner}.
39  *
40  * @author Kevin Bourrillion
41  */
42 @GwtCompatible(emulated = true)
43 public class JoinerTest extends TestCase {
44   private static final Joiner J = Joiner.on("-");
45 
46   // <Integer> needed to prevent warning :(
47   private static final Iterable<Integer> ITERABLE_ = Arrays.<Integer>asList();
48   private static final Iterable<Integer> ITERABLE_1 = Arrays.asList(1);
49   private static final Iterable<Integer> ITERABLE_12 = Arrays.asList(1, 2);
50   private static final Iterable<Integer> ITERABLE_123 = Arrays.asList(1, 2, 3);
51   private static final Iterable<Integer> ITERABLE_NULL = Arrays.asList((Integer) null);
52   private static final Iterable<Integer> ITERABLE_NULL_NULL = Arrays.asList((Integer) null, null);
53   private static final Iterable<Integer> ITERABLE_NULL_1 = Arrays.asList(null, 1);
54   private static final Iterable<Integer> ITERABLE_1_NULL = Arrays.asList(1, null);
55   private static final Iterable<Integer> ITERABLE_1_NULL_2 = Arrays.asList(1, null, 2);
56   private static final Iterable<Integer> ITERABLE_FOUR_NULLS =
57       Arrays.asList((Integer) null, null, null, null);
58 
testNoSpecialNullBehavior()59   public void testNoSpecialNullBehavior() {
60     checkNoOutput(J, ITERABLE_);
61     checkResult(J, ITERABLE_1, "1");
62     checkResult(J, ITERABLE_12, "1-2");
63     checkResult(J, ITERABLE_123, "1-2-3");
64 
65     try {
66       J.join(ITERABLE_NULL);
67       fail();
68     } catch (NullPointerException expected) {
69     }
70     try {
71       J.join(ITERABLE_1_NULL_2);
72       fail();
73     } catch (NullPointerException expected) {
74     }
75 
76     try {
77       J.join(ITERABLE_NULL.iterator());
78       fail();
79     } catch (NullPointerException expected) {
80     }
81     try {
82       J.join(ITERABLE_1_NULL_2.iterator());
83       fail();
84     } catch (NullPointerException expected) {
85     }
86   }
87 
testOnCharOverride()88   public void testOnCharOverride() {
89     Joiner onChar = Joiner.on('-');
90     checkNoOutput(onChar, ITERABLE_);
91     checkResult(onChar, ITERABLE_1, "1");
92     checkResult(onChar, ITERABLE_12, "1-2");
93     checkResult(onChar, ITERABLE_123, "1-2-3");
94   }
95 
testSkipNulls()96   public void testSkipNulls() {
97     Joiner skipNulls = J.skipNulls();
98     checkNoOutput(skipNulls, ITERABLE_);
99     checkNoOutput(skipNulls, ITERABLE_NULL);
100     checkNoOutput(skipNulls, ITERABLE_NULL_NULL);
101     checkNoOutput(skipNulls, ITERABLE_FOUR_NULLS);
102     checkResult(skipNulls, ITERABLE_1, "1");
103     checkResult(skipNulls, ITERABLE_12, "1-2");
104     checkResult(skipNulls, ITERABLE_123, "1-2-3");
105     checkResult(skipNulls, ITERABLE_NULL_1, "1");
106     checkResult(skipNulls, ITERABLE_1_NULL, "1");
107     checkResult(skipNulls, ITERABLE_1_NULL_2, "1-2");
108   }
109 
testUseForNull()110   public void testUseForNull() {
111     Joiner zeroForNull = J.useForNull("0");
112     checkNoOutput(zeroForNull, ITERABLE_);
113     checkResult(zeroForNull, ITERABLE_1, "1");
114     checkResult(zeroForNull, ITERABLE_12, "1-2");
115     checkResult(zeroForNull, ITERABLE_123, "1-2-3");
116     checkResult(zeroForNull, ITERABLE_NULL, "0");
117     checkResult(zeroForNull, ITERABLE_NULL_NULL, "0-0");
118     checkResult(zeroForNull, ITERABLE_NULL_1, "0-1");
119     checkResult(zeroForNull, ITERABLE_1_NULL, "1-0");
120     checkResult(zeroForNull, ITERABLE_1_NULL_2, "1-0-2");
121     checkResult(zeroForNull, ITERABLE_FOUR_NULLS, "0-0-0-0");
122   }
123 
checkNoOutput(Joiner joiner, Iterable<Integer> set)124   private static void checkNoOutput(Joiner joiner, Iterable<Integer> set) {
125     assertEquals("", joiner.join(set));
126     assertEquals("", joiner.join(set.iterator()));
127 
128     Object[] array = Lists.newArrayList(set).toArray(new Integer[0]);
129     assertEquals("", joiner.join(array));
130 
131     StringBuilder sb1FromIterable = new StringBuilder();
132     assertSame(sb1FromIterable, joiner.appendTo(sb1FromIterable, set));
133     assertEquals(0, sb1FromIterable.length());
134 
135     StringBuilder sb1FromIterator = new StringBuilder();
136     assertSame(sb1FromIterator, joiner.appendTo(sb1FromIterator, set));
137     assertEquals(0, sb1FromIterator.length());
138 
139     StringBuilder sb2 = new StringBuilder();
140     assertSame(sb2, joiner.appendTo(sb2, array));
141     assertEquals(0, sb2.length());
142 
143     try {
144       joiner.appendTo(NASTY_APPENDABLE, set);
145     } catch (IOException e) {
146       throw new AssertionError(e);
147     }
148 
149     try {
150       joiner.appendTo(NASTY_APPENDABLE, set.iterator());
151     } catch (IOException e) {
152       throw new AssertionError(e);
153     }
154 
155     try {
156       joiner.appendTo(NASTY_APPENDABLE, array);
157     } catch (IOException e) {
158       throw new AssertionError(e);
159     }
160   }
161 
162   private static final Appendable NASTY_APPENDABLE =
163       new Appendable() {
164         @Override
165         public Appendable append(CharSequence csq) throws IOException {
166           throw new IOException();
167         }
168 
169         @Override
170         public Appendable append(CharSequence csq, int start, int end) throws IOException {
171           throw new IOException();
172         }
173 
174         @Override
175         public Appendable append(char c) throws IOException {
176           throw new IOException();
177         }
178       };
179 
checkResult(Joiner joiner, Iterable<Integer> parts, String expected)180   private static void checkResult(Joiner joiner, Iterable<Integer> parts, String expected) {
181     assertEquals(expected, joiner.join(parts));
182     assertEquals(expected, joiner.join(parts.iterator()));
183 
184     StringBuilder sb1FromIterable = new StringBuilder().append('x');
185     joiner.appendTo(sb1FromIterable, parts);
186     assertEquals("x" + expected, sb1FromIterable.toString());
187 
188     StringBuilder sb1FromIterator = new StringBuilder().append('x');
189     joiner.appendTo(sb1FromIterator, parts.iterator());
190     assertEquals("x" + expected, sb1FromIterator.toString());
191 
192     Integer[] partsArray = Lists.newArrayList(parts).toArray(new Integer[0]);
193     assertEquals(expected, joiner.join(partsArray));
194 
195     StringBuilder sb2 = new StringBuilder().append('x');
196     joiner.appendTo(sb2, partsArray);
197     assertEquals("x" + expected, sb2.toString());
198 
199     int num = partsArray.length - 2;
200     if (num >= 0) {
201       Object[] rest = new Integer[num];
202       for (int i = 0; i < num; i++) {
203         rest[i] = partsArray[i + 2];
204       }
205 
206       assertEquals(expected, joiner.join(partsArray[0], partsArray[1], rest));
207 
208       StringBuilder sb3 = new StringBuilder().append('x');
209       joiner.appendTo(sb3, partsArray[0], partsArray[1], rest);
210       assertEquals("x" + expected, sb3.toString());
211     }
212   }
213 
test_useForNull_skipNulls()214   public void test_useForNull_skipNulls() {
215     Joiner j = Joiner.on("x").useForNull("y");
216     try {
217       j = j.skipNulls();
218       fail();
219     } catch (UnsupportedOperationException expected) {
220     }
221   }
222 
test_skipNulls_useForNull()223   public void test_skipNulls_useForNull() {
224     Joiner j = Joiner.on("x").skipNulls();
225     try {
226       j = j.useForNull("y");
227       fail();
228     } catch (UnsupportedOperationException expected) {
229     }
230   }
231 
test_useForNull_twice()232   public void test_useForNull_twice() {
233     Joiner j = Joiner.on("x").useForNull("y");
234     try {
235       j = j.useForNull("y");
236       fail();
237     } catch (UnsupportedOperationException expected) {
238     }
239   }
240 
testMap()241   public void testMap() {
242     MapJoiner j = Joiner.on(';').withKeyValueSeparator(':');
243     assertEquals("", j.join(ImmutableMap.of()));
244     assertEquals(":", j.join(ImmutableMap.of("", "")));
245 
246     Map<String, String> mapWithNulls = Maps.newLinkedHashMap();
247     mapWithNulls.put("a", null);
248     mapWithNulls.put(null, "b");
249 
250     try {
251       j.join(mapWithNulls);
252       fail();
253     } catch (NullPointerException expected) {
254     }
255 
256     assertEquals("a:00;00:b", j.useForNull("00").join(mapWithNulls));
257 
258     StringBuilder sb = new StringBuilder();
259     j.appendTo(sb, ImmutableMap.of(1, 2, 3, 4, 5, 6));
260     assertEquals("1:2;3:4;5:6", sb.toString());
261   }
262 
testEntries()263   public void testEntries() {
264     MapJoiner j = Joiner.on(";").withKeyValueSeparator(":");
265     assertEquals("", j.join(ImmutableMultimap.of().entries()));
266     assertEquals("", j.join(ImmutableMultimap.of().entries().iterator()));
267     assertEquals(":", j.join(ImmutableMultimap.of("", "").entries()));
268     assertEquals(":", j.join(ImmutableMultimap.of("", "").entries().iterator()));
269     assertEquals("1:a;1:b", j.join(ImmutableMultimap.of("1", "a", "1", "b").entries()));
270     assertEquals("1:a;1:b", j.join(ImmutableMultimap.of("1", "a", "1", "b").entries().iterator()));
271 
272     Map<String, String> mapWithNulls = Maps.newLinkedHashMap();
273     mapWithNulls.put("a", null);
274     mapWithNulls.put(null, "b");
275     Set<Entry<String, String>> entriesWithNulls = mapWithNulls.entrySet();
276 
277     try {
278       j.join(entriesWithNulls);
279       fail();
280     } catch (NullPointerException expected) {
281     }
282 
283     try {
284       j.join(entriesWithNulls.iterator());
285       fail();
286     } catch (NullPointerException expected) {
287     }
288 
289     assertEquals("a:00;00:b", j.useForNull("00").join(entriesWithNulls));
290     assertEquals("a:00;00:b", j.useForNull("00").join(entriesWithNulls.iterator()));
291 
292     StringBuilder sb1 = new StringBuilder();
293     j.appendTo(sb1, ImmutableMultimap.of(1, 2, 3, 4, 5, 6, 1, 3, 5, 10).entries());
294     assertEquals("1:2;1:3;3:4;5:6;5:10", sb1.toString());
295 
296     StringBuilder sb2 = new StringBuilder();
297     j.appendTo(sb2, ImmutableMultimap.of(1, 2, 3, 4, 5, 6, 1, 3, 5, 10).entries().iterator());
298     assertEquals("1:2;1:3;3:4;5:6;5:10", sb2.toString());
299   }
300 
test_skipNulls_onMap()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
length()312     public int length() {
313       return 3;
314     }
315 
316     @Override
charAt(int index)317     public char charAt(int index) {
318       return "foo".charAt(index);
319     }
320 
321     @Override
subSequence(int start, int end)322     public CharSequence subSequence(int start, int end) {
323       return "foo".subSequence(start, end);
324     }
325 
326     @Override
toString()327     public String toString() {
328       throw new AssertionFailedError("shouldn't be invoked");
329     }
330   }
331 
332   // Don't do this.
333   private static class IterableIterator implements Iterable<Integer>, Iterator<Integer> {
334     private static final ImmutableSet<Integer> INTEGERS = ImmutableSet.of(1, 2, 3, 4);
335     private final Iterator<Integer> iterator;
336 
IterableIterator()337     public IterableIterator() {
338       this.iterator = iterator();
339     }
340 
341     @Override
iterator()342     public Iterator<Integer> iterator() {
343       return INTEGERS.iterator();
344     }
345 
346     @Override
hasNext()347     public boolean hasNext() {
348       return iterator.hasNext();
349     }
350 
351     @Override
next()352     public Integer next() {
353       return iterator.next();
354     }
355 
356     @Override
remove()357     public void remove() {
358       iterator.remove();
359     }
360   }
361 
362   @GwtIncompatible // StringBuilder.append in GWT invokes Object.toString(), unlike the JRE version.
testDontConvertCharSequenceToString()363   public void testDontConvertCharSequenceToString() {
364     assertEquals("foo,foo", Joiner.on(",").join(new DontStringMeBro(), new DontStringMeBro()));
365     assertEquals(
366         "foo,bar,foo",
367         Joiner.on(",").useForNull("bar").join(new DontStringMeBro(), null, new DontStringMeBro()));
368   }
369 
370   @GwtIncompatible // NullPointerTester
testNullPointers()371   public void testNullPointers() {
372     NullPointerTester tester = new NullPointerTester();
373     tester.testAllPublicStaticMethods(Joiner.class);
374     tester.testInstanceMethods(Joiner.on(","), NullPointerTester.Visibility.PACKAGE);
375     tester.testInstanceMethods(Joiner.on(",").skipNulls(), NullPointerTester.Visibility.PACKAGE);
376     tester.testInstanceMethods(
377         Joiner.on(",").useForNull("x"), NullPointerTester.Visibility.PACKAGE);
378     tester.testInstanceMethods(
379         Joiner.on(",").withKeyValueSeparator("="), NullPointerTester.Visibility.PACKAGE);
380   }
381 }
382