1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package com.google.protobuf; 32 33 import static java.util.Arrays.asList; 34 35 import java.util.ArrayList; 36 import java.util.Collections; 37 import java.util.ConcurrentModificationException; 38 import java.util.Iterator; 39 import java.util.List; 40 import junit.framework.TestCase; 41 42 /** 43 * Tests for {@link LazyStringArrayList}. 44 * 45 * @author jonp@google.com (Jon Perlow) 46 */ 47 public class LazyStringArrayListTest extends TestCase { 48 49 private static final String STRING_A = "A"; 50 private static final String STRING_B = "B"; 51 private static final String STRING_C = "C"; 52 53 private static final ByteString BYTE_STRING_A = ByteString.copyFromUtf8("A"); 54 private static final ByteString BYTE_STRING_B = ByteString.copyFromUtf8("B"); 55 private static final ByteString BYTE_STRING_C = ByteString.copyFromUtf8("C"); 56 testJustStrings()57 public void testJustStrings() { 58 LazyStringArrayList list = new LazyStringArrayList(); 59 list.add(STRING_A); 60 list.add(STRING_B); 61 list.add(STRING_C); 62 63 assertEquals(3, list.size()); 64 assertSame(STRING_A, list.get(0)); 65 assertSame(STRING_B, list.get(1)); 66 assertSame(STRING_C, list.get(2)); 67 68 list.set(1, STRING_C); 69 assertSame(STRING_C, list.get(1)); 70 71 list.remove(1); 72 assertSame(STRING_A, list.get(0)); 73 assertSame(STRING_C, list.get(1)); 74 75 List<ByteString> byteStringList = list.asByteStringList(); 76 assertEquals(BYTE_STRING_A, byteStringList.get(0)); 77 assertEquals(BYTE_STRING_C, byteStringList.get(1)); 78 79 // Underlying list should be transformed. 80 assertSame(byteStringList.get(0), list.getByteString(0)); 81 assertSame(byteStringList.get(1), list.getByteString(1)); 82 } 83 testJustByteString()84 public void testJustByteString() { 85 LazyStringArrayList list = new LazyStringArrayList(); 86 list.add(BYTE_STRING_A); 87 list.add(BYTE_STRING_B); 88 list.add(BYTE_STRING_C); 89 90 assertEquals(3, list.size()); 91 assertSame(BYTE_STRING_A, list.getByteString(0)); 92 assertSame(BYTE_STRING_B, list.getByteString(1)); 93 assertSame(BYTE_STRING_C, list.getByteString(2)); 94 95 list.remove(1); 96 assertSame(BYTE_STRING_A, list.getByteString(0)); 97 assertSame(BYTE_STRING_C, list.getByteString(1)); 98 99 List<ByteString> byteStringList = list.asByteStringList(); 100 assertSame(BYTE_STRING_A, byteStringList.get(0)); 101 assertSame(BYTE_STRING_C, byteStringList.get(1)); 102 } 103 testConversionBackAndForth()104 public void testConversionBackAndForth() { 105 LazyStringArrayList list = new LazyStringArrayList(); 106 list.add(STRING_A); 107 list.add(BYTE_STRING_B); 108 list.add(BYTE_STRING_C); 109 110 // String a should be the same because it was originally a string 111 assertSame(STRING_A, list.get(0)); 112 113 // String b and c should be different because the string has to be computed 114 // from the ByteString 115 String bPrime = list.get(1); 116 assertNotSame(STRING_B, bPrime); 117 assertEquals(STRING_B, bPrime); 118 String cPrime = list.get(2); 119 assertNotSame(STRING_C, cPrime); 120 assertEquals(STRING_C, cPrime); 121 122 // String c and c should stay the same once cached. 123 assertSame(bPrime, list.get(1)); 124 assertSame(cPrime, list.get(2)); 125 126 // ByteString needs to be computed from string for both a and b 127 ByteString aPrimeByteString = list.getByteString(0); 128 assertEquals(BYTE_STRING_A, aPrimeByteString); 129 ByteString bPrimeByteString = list.getByteString(1); 130 assertNotSame(BYTE_STRING_B, bPrimeByteString); 131 assertEquals(BYTE_STRING_B, list.getByteString(1)); 132 133 // Once cached, ByteString should stay cached. 134 assertSame(aPrimeByteString, list.getByteString(0)); 135 assertSame(bPrimeByteString, list.getByteString(1)); 136 } 137 testCopyConstructorCopiesByReference()138 public void testCopyConstructorCopiesByReference() { 139 LazyStringArrayList list1 = new LazyStringArrayList(); 140 list1.add(STRING_A); 141 list1.add(BYTE_STRING_B); 142 list1.add(BYTE_STRING_C); 143 144 LazyStringArrayList list2 = new LazyStringArrayList(list1); 145 assertEquals(3, list2.size()); 146 assertSame(STRING_A, list2.get(0)); 147 assertSame(BYTE_STRING_B, list2.getByteString(1)); 148 assertSame(BYTE_STRING_C, list2.getByteString(2)); 149 } 150 testListCopyConstructor()151 public void testListCopyConstructor() { 152 List<String> list1 = new ArrayList<String>(); 153 list1.add(STRING_A); 154 list1.add(STRING_B); 155 list1.add(STRING_C); 156 157 LazyStringArrayList list2 = new LazyStringArrayList(list1); 158 assertEquals(3, list2.size()); 159 assertSame(STRING_A, list2.get(0)); 160 assertSame(STRING_B, list2.get(1)); 161 assertSame(STRING_C, list2.get(2)); 162 } 163 testAddAllCopiesByReferenceIfPossible()164 public void testAddAllCopiesByReferenceIfPossible() { 165 LazyStringArrayList list1 = new LazyStringArrayList(); 166 list1.add(STRING_A); 167 list1.add(BYTE_STRING_B); 168 list1.add(BYTE_STRING_C); 169 170 LazyStringArrayList list2 = new LazyStringArrayList(); 171 list2.addAll(list1); 172 173 assertEquals(3, list2.size()); 174 assertSame(STRING_A, list2.get(0)); 175 assertSame(BYTE_STRING_B, list2.getByteString(1)); 176 assertSame(BYTE_STRING_C, list2.getByteString(2)); 177 } 178 testModificationWithIteration()179 public void testModificationWithIteration() { 180 LazyStringArrayList list = new LazyStringArrayList(); 181 list.addAll(asList(STRING_A, STRING_B, STRING_C)); 182 Iterator<String> iterator = list.iterator(); 183 assertEquals(3, list.size()); 184 assertEquals(STRING_A, list.get(0)); 185 assertEquals(STRING_A, iterator.next()); 186 187 // Does not structurally modify. 188 iterator = list.iterator(); 189 list.set(0, STRING_B); 190 iterator.next(); 191 192 list.remove(0); 193 try { 194 iterator.next(); 195 fail(); 196 } catch (ConcurrentModificationException e) { 197 // expected 198 } 199 200 iterator = list.iterator(); 201 list.add(0, STRING_C); 202 try { 203 iterator.next(); 204 fail(); 205 } catch (ConcurrentModificationException e) { 206 // expected 207 } 208 } 209 testMakeImmutable()210 public void testMakeImmutable() { 211 LazyStringArrayList list = new LazyStringArrayList(); 212 list.add(STRING_A); 213 list.add(STRING_B); 214 list.add(STRING_C); 215 list.makeImmutable(); 216 assertGenericListImmutable(list, STRING_A); 217 218 // LazyStringArrayList has extra methods not covered in the generic 219 // assertion. 220 221 try { 222 list.add(BYTE_STRING_A.toByteArray()); 223 fail(); 224 } catch (UnsupportedOperationException e) { 225 // expected 226 } 227 228 try { 229 list.add(BYTE_STRING_A); 230 fail(); 231 } catch (UnsupportedOperationException e) { 232 // expected 233 } 234 235 try { 236 list.addAllByteArray(Collections.singletonList(BYTE_STRING_A.toByteArray())); 237 fail(); 238 } catch (UnsupportedOperationException e) { 239 // expected 240 } 241 242 try { 243 list.addAllByteString(asList(BYTE_STRING_A)); 244 fail(); 245 } catch (UnsupportedOperationException e) { 246 // expected 247 } 248 249 try { 250 list.mergeFrom(new LazyStringArrayList()); 251 fail(); 252 } catch (UnsupportedOperationException e) { 253 // expected 254 } 255 256 try { 257 list.set(0, BYTE_STRING_A.toByteArray()); 258 fail(); 259 } catch (UnsupportedOperationException e) { 260 // expected 261 } 262 263 try { 264 list.set(0, BYTE_STRING_A); 265 fail(); 266 } catch (UnsupportedOperationException e) { 267 // expected 268 } 269 } 270 testImmutabilityPropagation()271 public void testImmutabilityPropagation() { 272 LazyStringArrayList list = new LazyStringArrayList(); 273 list.add(STRING_A); 274 list.makeImmutable(); 275 276 assertGenericListImmutable(list.asByteStringList(), BYTE_STRING_A); 277 278 // Arrays use reference equality so need to retrieve the underlying value 279 // to properly test deep immutability. 280 List<byte[]> byteArrayList = list.asByteArrayList(); 281 assertGenericListImmutable(byteArrayList, byteArrayList.get(0)); 282 } 283 284 @SuppressWarnings("unchecked") assertGenericListImmutable(List<T> list, T value)285 private static <T> void assertGenericListImmutable(List<T> list, T value) { 286 try { 287 list.add(value); 288 fail(); 289 } catch (UnsupportedOperationException e) { 290 // expected 291 } 292 293 try { 294 list.add(0, value); 295 fail(); 296 } catch (UnsupportedOperationException e) { 297 // expected 298 } 299 300 try { 301 list.addAll(asList(value)); 302 fail(); 303 } catch (UnsupportedOperationException e) { 304 // expected 305 } 306 307 try { 308 list.addAll(0, asList(value)); 309 fail(); 310 } catch (UnsupportedOperationException e) { 311 // expected 312 } 313 314 try { 315 list.clear(); 316 fail(); 317 } catch (UnsupportedOperationException e) { 318 // expected 319 } 320 321 try { 322 list.remove(0); 323 fail(); 324 } catch (UnsupportedOperationException e) { 325 // expected 326 } 327 328 try { 329 list.remove(value); 330 fail(); 331 } catch (UnsupportedOperationException e) { 332 // expected 333 } 334 335 try { 336 list.removeAll(asList(value)); 337 fail(); 338 } catch (UnsupportedOperationException e) { 339 // expected 340 } 341 342 try { 343 list.retainAll(asList()); 344 fail(); 345 } catch (UnsupportedOperationException e) { 346 // expected 347 } 348 349 try { 350 list.retainAll(asList()); 351 fail(); 352 } catch (UnsupportedOperationException e) { 353 // expected 354 } 355 356 try { 357 list.set(0, value); 358 fail(); 359 } catch (UnsupportedOperationException e) { 360 // expected 361 } 362 } 363 } 364