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 junit.framework.TestCase;
36 
37 import java.util.ArrayList;
38 import java.util.ConcurrentModificationException;
39 import java.util.Iterator;
40 import java.util.List;
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 String STRING_A = "A";
50   private static String STRING_B = "B";
51   private static String STRING_C = "C";
52 
53   private static ByteString BYTE_STRING_A = ByteString.copyFromUtf8("A");
54   private static ByteString BYTE_STRING_B = ByteString.copyFromUtf8("B");
55   private static 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(asList(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 
assertGenericListImmutable(List<T> list, T value)284   private static <T> void assertGenericListImmutable(List<T> list, T value) {
285     try {
286       list.add(value);
287       fail();
288     } catch (UnsupportedOperationException e) {
289       // expected
290     }
291 
292     try {
293       list.add(0, value);
294       fail();
295     } catch (UnsupportedOperationException e) {
296       // expected
297     }
298 
299     try {
300       list.addAll(asList(value));
301       fail();
302     } catch (UnsupportedOperationException e) {
303       // expected
304     }
305 
306     try {
307       list.addAll(0, asList(value));
308       fail();
309     } catch (UnsupportedOperationException e) {
310       // expected
311     }
312 
313     try {
314       list.clear();
315       fail();
316     } catch (UnsupportedOperationException e) {
317       // expected
318     }
319 
320     try {
321       list.remove(0);
322       fail();
323     } catch (UnsupportedOperationException e) {
324       // expected
325     }
326 
327     try {
328       list.remove(value);
329       fail();
330     } catch (UnsupportedOperationException e) {
331       // expected
332     }
333 
334     try {
335       list.removeAll(asList(value));
336       fail();
337     } catch (UnsupportedOperationException e) {
338       // expected
339     }
340 
341     try {
342       list.retainAll(asList());
343       fail();
344     } catch (UnsupportedOperationException e) {
345       // expected
346     }
347 
348     try {
349       list.retainAll(asList());
350       fail();
351     } catch (UnsupportedOperationException e) {
352       // expected
353     }
354 
355     try {
356       list.set(0, value);
357       fail();
358     } catch (UnsupportedOperationException e) {
359       // expected
360     }
361   }
362 }
363