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