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 17package com.google.common.base; 18 19import com.google.common.annotations.GwtCompatible; 20import com.google.common.base.Joiner.MapJoiner; 21import com.google.common.collect.ImmutableMap; 22import com.google.common.collect.ImmutableMultimap; 23import com.google.common.collect.ImmutableSet; 24import com.google.common.collect.Lists; 25import com.google.common.collect.Maps; 26 27import junit.framework.AssertionFailedError; 28import junit.framework.TestCase; 29 30import java.io.IOException; 31import java.util.Arrays; 32import java.util.Iterator; 33import java.util.Map; 34import java.util.Set; 35 36/** 37 * Unit test for {@link Joiner}. 38 * 39 * @author Kevin Bourrillion 40 */ 41@GwtCompatible(emulated = true) 42public class JoinerTest extends TestCase { 43 private static final Joiner J = Joiner.on("-"); 44 45 // <Integer> needed to prevent warning :( 46 private static final Iterable<Integer> ITERABLE_ = Arrays.<Integer>asList(); 47 private static final Iterable<Integer> ITERABLE_1 = Arrays.asList(1); 48 private static final Iterable<Integer> ITERABLE_12 = Arrays.asList(1, 2); 49 private static final Iterable<Integer> ITERABLE_123 = Arrays.asList(1, 2, 3); 50 private static final Iterable<Integer> ITERABLE_NULL = Arrays.asList((Integer) null); 51 private static final Iterable<Integer> ITERABLE_NULL_NULL 52 = 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 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 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 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 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 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 = new Appendable() { 163 @Override 164 public Appendable append(CharSequence csq) throws IOException { 165 throw new IOException(); 166 } 167 @Override 168 public Appendable append(CharSequence csq, int start, int end) throws IOException { 169 throw new IOException(); 170 } 171 @Override 172 public Appendable append(char c) throws IOException { 173 throw new IOException(); 174 } 175 }; 176 177 private static void checkResult(Joiner joiner, Iterable<Integer> parts, String expected) { 178 assertEquals(expected, joiner.join(parts)); 179 assertEquals(expected, joiner.join(parts.iterator())); 180 181 StringBuilder sb1FromIterable = new StringBuilder().append('x'); 182 joiner.appendTo(sb1FromIterable, parts); 183 assertEquals("x" + expected, sb1FromIterable.toString()); 184 185 StringBuilder sb1FromIterator = new StringBuilder().append('x'); 186 joiner.appendTo(sb1FromIterator, parts.iterator()); 187 assertEquals("x" + expected, sb1FromIterator.toString()); 188 189 Integer[] partsArray = Lists.newArrayList(parts).toArray(new Integer[0]); 190 assertEquals(expected, joiner.join(partsArray)); 191 192 StringBuilder sb2 = new StringBuilder().append('x'); 193 joiner.appendTo(sb2, partsArray); 194 assertEquals("x" + expected, sb2.toString()); 195 196 int num = partsArray.length - 2; 197 if (num >= 0) { 198 Object[] rest = new Integer[num]; 199 for (int i = 0; i < num; i++) { 200 rest[i] = partsArray[i + 2]; 201 } 202 203 assertEquals(expected, joiner.join(partsArray[0], partsArray[1], rest)); 204 205 StringBuilder sb3 = new StringBuilder().append('x'); 206 joiner.appendTo(sb3, partsArray[0], partsArray[1], rest); 207 assertEquals("x" + expected, sb3.toString()); 208 } 209 } 210 211 public void test_useForNull_skipNulls() { 212 Joiner j = Joiner.on("x").useForNull("y"); 213 try { 214 j = j.skipNulls(); 215 fail(); 216 } catch (UnsupportedOperationException expected) { 217 } 218 } 219 220 public void test_skipNulls_useForNull() { 221 Joiner j = Joiner.on("x").skipNulls(); 222 try { 223 j = j.useForNull("y"); 224 fail(); 225 } catch (UnsupportedOperationException expected) { 226 } 227 } 228 229 public void test_useForNull_twice() { 230 Joiner j = Joiner.on("x").useForNull("y"); 231 try { 232 j = j.useForNull("y"); 233 fail(); 234 } catch (UnsupportedOperationException expected) { 235 } 236 } 237 238 public void testMap() { 239 MapJoiner j = Joiner.on(";").withKeyValueSeparator(":"); 240 assertEquals("", j.join(ImmutableMap.of())); 241 assertEquals(":", j.join(ImmutableMap.of("", ""))); 242 243 Map<String, String> mapWithNulls = Maps.newLinkedHashMap(); 244 mapWithNulls.put("a", null); 245 mapWithNulls.put(null, "b"); 246 247 try { 248 j.join(mapWithNulls); 249 fail(); 250 } catch (NullPointerException expected) { 251 } 252 253 assertEquals("a:00;00:b", j.useForNull("00").join(mapWithNulls)); 254 255 StringBuilder sb = new StringBuilder(); 256 j.appendTo(sb, ImmutableMap.of(1, 2, 3, 4, 5, 6)); 257 assertEquals("1:2;3:4;5:6", sb.toString()); 258 } 259 260 public void testEntries() { 261 MapJoiner j = Joiner.on(";").withKeyValueSeparator(":"); 262 assertEquals("", j.join(ImmutableMultimap.of().entries())); 263 assertEquals("", j.join(ImmutableMultimap.of().entries().iterator())); 264 assertEquals(":", j.join(ImmutableMultimap.of("", "").entries())); 265 assertEquals(":", j.join(ImmutableMultimap.of("", "").entries().iterator())); 266 assertEquals("1:a;1:b", j.join(ImmutableMultimap.of("1", "a", "1", "b").entries())); 267 assertEquals("1:a;1:b", j.join(ImmutableMultimap.of("1", "a", "1", "b").entries().iterator())); 268 269 Map<String, String> mapWithNulls = Maps.newLinkedHashMap(); 270 mapWithNulls.put("a", null); 271 mapWithNulls.put(null, "b"); 272 Set<Map.Entry<String, String>> entriesWithNulls = mapWithNulls.entrySet(); 273 274 try { 275 j.join(entriesWithNulls); 276 fail(); 277 } catch (NullPointerException expected) { 278 } 279 280 try { 281 j.join(entriesWithNulls.iterator()); 282 fail(); 283 } catch (NullPointerException expected) { 284 } 285 286 assertEquals("a:00;00:b", j.useForNull("00").join(entriesWithNulls)); 287 assertEquals("a:00;00:b", j.useForNull("00").join(entriesWithNulls.iterator())); 288 289 StringBuilder sb1 = new StringBuilder(); 290 j.appendTo(sb1, ImmutableMultimap.of(1, 2, 3, 4, 5, 6, 1, 3, 5, 10).entries()); 291 assertEquals("1:2;1:3;3:4;5:6;5:10", sb1.toString()); 292 293 StringBuilder sb2 = new StringBuilder(); 294 j.appendTo(sb2, ImmutableMultimap.of(1, 2, 3, 4, 5, 6, 1, 3, 5, 10).entries().iterator()); 295 assertEquals("1:2;1:3;3:4;5:6;5:10", sb2.toString()); 296 } 297 298 @SuppressWarnings("ReturnValueIgnored") // testing for exception 299 public void test_skipNulls_onMap() { 300 Joiner j = Joiner.on(",").skipNulls(); 301 try { 302 j.withKeyValueSeparator("/"); 303 fail(); 304 } catch (UnsupportedOperationException expected) { 305 } 306 } 307 308 private static class DontStringMeBro implements CharSequence { 309 @Override 310 public int length() { 311 return 3; 312 } 313 @Override 314 public char charAt(int index) { 315 return "foo".charAt(index); 316 } 317 @Override 318 public CharSequence subSequence(int start, int end) { 319 return "foo".subSequence(start, end); 320 } 321 @Override public String toString() { 322 throw new AssertionFailedError("shouldn't be invoked"); 323 } 324 } 325 326 // Don't do this. 327 private static class IterableIterator implements Iterable<Integer>, Iterator<Integer> { 328 private static final ImmutableSet<Integer> INTEGERS = ImmutableSet.of(1, 2, 3, 4); 329 private final Iterator<Integer> iterator; 330 public IterableIterator() { 331 this.iterator = iterator(); 332 } 333 @Override public Iterator<Integer> iterator() { 334 return INTEGERS.iterator(); 335 } 336 @Override public boolean hasNext() { 337 return iterator.hasNext(); 338 } 339 @Override public Integer next() { 340 return iterator.next(); 341 } 342 @Override public void remove() { 343 iterator.remove(); 344 } 345 } 346} 347 348