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