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 com.google.protobuf.Descriptors.FieldDescriptor;
34 import map_test.MapForProto2TestProto.TestMap;
35 import map_test.MapForProto2TestProto.TestMap.MessageValue;
36 import map_test.MapForProto2TestProto.TestMap.MessageWithRequiredFields;
37 import map_test.MapForProto2TestProto.TestRecursiveMap;
38 import map_test.MapForProto2TestProto.TestUnknownEnumValue;
39 import junit.framework.TestCase;
40 
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.HashMap;
44 import java.util.List;
45 import java.util.Map;
46 
47 /**
48  * Unit tests for map fields in proto2 protos.
49  */
50 public class MapForProto2Test extends TestCase {
setMapValues(TestMap.Builder builder)51   private void setMapValues(TestMap.Builder builder) {
52     builder.getMutableInt32ToInt32Field().put(1, 11);
53     builder.getMutableInt32ToInt32Field().put(2, 22);
54     builder.getMutableInt32ToInt32Field().put(3, 33);
55 
56     builder.getMutableInt32ToStringField().put(1, "11");
57     builder.getMutableInt32ToStringField().put(2, "22");
58     builder.getMutableInt32ToStringField().put(3, "33");
59 
60     builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("11"));
61     builder.getMutableInt32ToBytesField().put(2, TestUtil.toBytes("22"));
62     builder.getMutableInt32ToBytesField().put(3, TestUtil.toBytes("33"));
63 
64     builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.FOO);
65     builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.BAR);
66     builder.getMutableInt32ToEnumField().put(3, TestMap.EnumValue.BAZ);
67 
68     builder.getMutableInt32ToMessageField().put(
69         1, MessageValue.newBuilder().setValue(11).build());
70     builder.getMutableInt32ToMessageField().put(
71         2, MessageValue.newBuilder().setValue(22).build());
72     builder.getMutableInt32ToMessageField().put(
73         3, MessageValue.newBuilder().setValue(33).build());
74 
75     builder.getMutableStringToInt32Field().put("1", 11);
76     builder.getMutableStringToInt32Field().put("2", 22);
77     builder.getMutableStringToInt32Field().put("3", 33);
78   }
79 
copyMapValues(TestMap source, TestMap.Builder destination)80   private void copyMapValues(TestMap source, TestMap.Builder destination) {
81     destination
82         .putAllInt32ToInt32Field(source.getInt32ToInt32Field())
83         .putAllInt32ToStringField(source.getInt32ToStringField())
84         .putAllInt32ToBytesField(source.getInt32ToBytesField())
85         .putAllInt32ToEnumField(source.getInt32ToEnumField())
86         .putAllInt32ToMessageField(source.getInt32ToMessageField())
87         .putAllStringToInt32Field(source.getStringToInt32Field());
88   }
89 
assertMapValuesSet(TestMap message)90   private void assertMapValuesSet(TestMap message) {
91     assertEquals(3, message.getInt32ToInt32Field().size());
92     assertEquals(11, message.getInt32ToInt32Field().get(1).intValue());
93     assertEquals(22, message.getInt32ToInt32Field().get(2).intValue());
94     assertEquals(33, message.getInt32ToInt32Field().get(3).intValue());
95 
96     assertEquals(3, message.getInt32ToStringField().size());
97     assertEquals("11", message.getInt32ToStringField().get(1));
98     assertEquals("22", message.getInt32ToStringField().get(2));
99     assertEquals("33", message.getInt32ToStringField().get(3));
100 
101     assertEquals(3, message.getInt32ToBytesField().size());
102     assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesField().get(1));
103     assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesField().get(2));
104     assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
105 
106     assertEquals(3, message.getInt32ToEnumField().size());
107     assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(1));
108     assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(2));
109     assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
110 
111     assertEquals(3, message.getInt32ToMessageField().size());
112     assertEquals(11, message.getInt32ToMessageField().get(1).getValue());
113     assertEquals(22, message.getInt32ToMessageField().get(2).getValue());
114     assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
115 
116     assertEquals(3, message.getStringToInt32Field().size());
117     assertEquals(11, message.getStringToInt32Field().get("1").intValue());
118     assertEquals(22, message.getStringToInt32Field().get("2").intValue());
119     assertEquals(33, message.getStringToInt32Field().get("3").intValue());
120   }
121 
updateMapValues(TestMap.Builder builder)122   private void updateMapValues(TestMap.Builder builder) {
123     builder.getMutableInt32ToInt32Field().put(1, 111);
124     builder.getMutableInt32ToInt32Field().remove(2);
125     builder.getMutableInt32ToInt32Field().put(4, 44);
126 
127     builder.getMutableInt32ToStringField().put(1, "111");
128     builder.getMutableInt32ToStringField().remove(2);
129     builder.getMutableInt32ToStringField().put(4, "44");
130 
131     builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("111"));
132     builder.getMutableInt32ToBytesField().remove(2);
133     builder.getMutableInt32ToBytesField().put(4, TestUtil.toBytes("44"));
134 
135     builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.BAR);
136     builder.getMutableInt32ToEnumField().remove(2);
137     builder.getMutableInt32ToEnumField().put(4, TestMap.EnumValue.QUX);
138 
139     builder.getMutableInt32ToMessageField().put(
140         1, MessageValue.newBuilder().setValue(111).build());
141     builder.getMutableInt32ToMessageField().remove(2);
142     builder.getMutableInt32ToMessageField().put(
143         4, MessageValue.newBuilder().setValue(44).build());
144 
145     builder.getMutableStringToInt32Field().put("1", 111);
146     builder.getMutableStringToInt32Field().remove("2");
147     builder.getMutableStringToInt32Field().put("4", 44);
148   }
149 
assertMapValuesUpdated(TestMap message)150   private void assertMapValuesUpdated(TestMap message) {
151     assertEquals(3, message.getInt32ToInt32Field().size());
152     assertEquals(111, message.getInt32ToInt32Field().get(1).intValue());
153     assertEquals(33, message.getInt32ToInt32Field().get(3).intValue());
154     assertEquals(44, message.getInt32ToInt32Field().get(4).intValue());
155 
156     assertEquals(3, message.getInt32ToStringField().size());
157     assertEquals("111", message.getInt32ToStringField().get(1));
158     assertEquals("33", message.getInt32ToStringField().get(3));
159     assertEquals("44", message.getInt32ToStringField().get(4));
160 
161     assertEquals(3, message.getInt32ToBytesField().size());
162     assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1));
163     assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
164     assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4));
165 
166     assertEquals(3, message.getInt32ToEnumField().size());
167     assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1));
168     assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
169     assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4));
170 
171     assertEquals(3, message.getInt32ToMessageField().size());
172     assertEquals(111, message.getInt32ToMessageField().get(1).getValue());
173     assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
174     assertEquals(44, message.getInt32ToMessageField().get(4).getValue());
175 
176     assertEquals(3, message.getStringToInt32Field().size());
177     assertEquals(111, message.getStringToInt32Field().get("1").intValue());
178     assertEquals(33, message.getStringToInt32Field().get("3").intValue());
179     assertEquals(44, message.getStringToInt32Field().get("4").intValue());
180   }
181 
assertMapValuesCleared(TestMap message)182   private void assertMapValuesCleared(TestMap message) {
183     assertEquals(0, message.getInt32ToInt32Field().size());
184     assertEquals(0, message.getInt32ToStringField().size());
185     assertEquals(0, message.getInt32ToBytesField().size());
186     assertEquals(0, message.getInt32ToEnumField().size());
187     assertEquals(0, message.getInt32ToMessageField().size());
188     assertEquals(0, message.getStringToInt32Field().size());
189   }
190 
testMutableMapLifecycle()191   public void testMutableMapLifecycle() {
192     TestMap.Builder builder = TestMap.newBuilder();
193     Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
194     intMap.put(1, 2);
195     assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
196     try {
197       intMap.put(2, 3);
198       fail();
199     } catch (UnsupportedOperationException e) {
200       // expected
201     }
202     assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
203     builder.getMutableInt32ToInt32Field().put(2, 3);
204     assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
205 
206     Map<Integer, TestMap.EnumValue> enumMap = builder.getMutableInt32ToEnumField();
207     enumMap.put(1, TestMap.EnumValue.BAR);
208     assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField());
209     try {
210       enumMap.put(2, TestMap.EnumValue.FOO);
211       fail();
212     } catch (UnsupportedOperationException e) {
213       // expected
214     }
215     assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumField());
216     builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.FOO);
217     assertEquals(
218         newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO),
219         builder.getInt32ToEnumField());
220 
221     Map<Integer, String> stringMap = builder.getMutableInt32ToStringField();
222     stringMap.put(1, "1");
223     assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField());
224     try {
225       stringMap.put(2, "2");
226       fail();
227     } catch (UnsupportedOperationException e) {
228       // expected
229     }
230     assertEquals(newMap(1, "1"), builder.getInt32ToStringField());
231     builder.getMutableInt32ToStringField().put(2, "2");
232     assertEquals(
233         newMap(1, "1", 2, "2"),
234         builder.getInt32ToStringField());
235 
236     Map<Integer, TestMap.MessageValue> messageMap = builder.getMutableInt32ToMessageField();
237     messageMap.put(1, TestMap.MessageValue.getDefaultInstance());
238     assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
239         builder.build().getInt32ToMessageField());
240     try {
241       messageMap.put(2, TestMap.MessageValue.getDefaultInstance());
242       fail();
243     } catch (UnsupportedOperationException e) {
244       // expected
245     }
246     assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
247         builder.getInt32ToMessageField());
248     builder.getMutableInt32ToMessageField().put(2, TestMap.MessageValue.getDefaultInstance());
249     assertEquals(
250         newMap(1, TestMap.MessageValue.getDefaultInstance(),
251             2, TestMap.MessageValue.getDefaultInstance()),
252         builder.getInt32ToMessageField());
253   }
254 
testMutableMapLifecycle_collections()255   public void testMutableMapLifecycle_collections() {
256     TestMap.Builder builder = TestMap.newBuilder();
257     Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
258     intMap.put(1, 2);
259     assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
260     try {
261       intMap.remove(2);
262       fail();
263     } catch (UnsupportedOperationException e) {
264       // expected
265     }
266     try {
267       intMap.entrySet().remove(new Object());
268       fail();
269     } catch (UnsupportedOperationException e) {
270       // expected
271     }
272     try {
273       intMap.entrySet().iterator().remove();
274       fail();
275     } catch (UnsupportedOperationException e) {
276       // expected
277     }
278     try {
279       intMap.keySet().remove(new Object());
280       fail();
281     } catch (UnsupportedOperationException e) {
282       // expected
283     }
284     try {
285       intMap.values().remove(new Object());
286       fail();
287     } catch (UnsupportedOperationException e) {
288       // expected
289     }
290     try {
291       intMap.values().iterator().remove();
292       fail();
293     } catch (UnsupportedOperationException e) {
294       // expected
295     }
296     assertEquals(newMap(1, 2), intMap);
297     assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
298     assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
299   }
300 
testGettersAndSetters()301   public void testGettersAndSetters() throws Exception {
302     TestMap.Builder builder = TestMap.newBuilder();
303     TestMap message = builder.build();
304     assertMapValuesCleared(message);
305 
306     builder = message.toBuilder();
307     setMapValues(builder);
308     message = builder.build();
309     assertMapValuesSet(message);
310 
311     builder = message.toBuilder();
312     updateMapValues(builder);
313     message = builder.build();
314     assertMapValuesUpdated(message);
315 
316     builder = message.toBuilder();
317     builder.clear();
318     message = builder.build();
319     assertMapValuesCleared(message);
320   }
321 
testPutAll()322   public void testPutAll() throws Exception {
323     TestMap.Builder sourceBuilder = TestMap.newBuilder();
324     setMapValues(sourceBuilder);
325     TestMap source = sourceBuilder.build();
326 
327     TestMap.Builder destination = TestMap.newBuilder();
328     copyMapValues(source, destination);
329     assertMapValuesSet(destination.build());
330   }
331 
testSerializeAndParse()332   public void testSerializeAndParse() throws Exception {
333     TestMap.Builder builder = TestMap.newBuilder();
334     setMapValues(builder);
335     TestMap message = builder.build();
336     assertEquals(message.getSerializedSize(), message.toByteString().size());
337     message = TestMap.parser().parseFrom(message.toByteString());
338     assertMapValuesSet(message);
339 
340     builder = message.toBuilder();
341     updateMapValues(builder);
342     message = builder.build();
343     assertEquals(message.getSerializedSize(), message.toByteString().size());
344     message = TestMap.parser().parseFrom(message.toByteString());
345     assertMapValuesUpdated(message);
346 
347     builder = message.toBuilder();
348     builder.clear();
349     message = builder.build();
350     assertEquals(message.getSerializedSize(), message.toByteString().size());
351     message = TestMap.parser().parseFrom(message.toByteString());
352     assertMapValuesCleared(message);
353   }
354 
testMergeFrom()355   public void testMergeFrom() throws Exception {
356     TestMap.Builder builder = TestMap.newBuilder();
357     setMapValues(builder);
358     TestMap message = builder.build();
359 
360     TestMap.Builder other = TestMap.newBuilder();
361     other.mergeFrom(message);
362     assertMapValuesSet(other.build());
363   }
364 
testEqualsAndHashCode()365   public void testEqualsAndHashCode() throws Exception {
366     // Test that generated equals() and hashCode() will disregard the order
367     // of map entries when comparing/hashing map fields.
368 
369     // We can't control the order of elements in a HashMap. The best we can do
370     // here is to add elements in different order.
371     TestMap.Builder b1 = TestMap.newBuilder();
372     b1.getMutableInt32ToInt32Field().put(1, 2);
373     b1.getMutableInt32ToInt32Field().put(3, 4);
374     b1.getMutableInt32ToInt32Field().put(5, 6);
375     TestMap m1 = b1.build();
376 
377     TestMap.Builder b2 = TestMap.newBuilder();
378     b2.getMutableInt32ToInt32Field().put(5, 6);
379     b2.getMutableInt32ToInt32Field().put(1, 2);
380     b2.getMutableInt32ToInt32Field().put(3, 4);
381     TestMap m2 = b2.build();
382 
383     assertEquals(m1, m2);
384     assertEquals(m1.hashCode(), m2.hashCode());
385 
386     // Make sure we did compare map fields.
387     b2.getMutableInt32ToInt32Field().put(1, 0);
388     m2 = b2.build();
389     assertFalse(m1.equals(m2));
390     // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
391     // to be different.
392   }
393 
394 
395   // The following methods are used to test reflection API.
396 
f(String name)397   private static FieldDescriptor f(String name) {
398     return TestMap.getDescriptor().findFieldByName(name);
399   }
400 
getFieldValue(Message mapEntry, String name)401   private static Object getFieldValue(Message mapEntry, String name) {
402     FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name);
403     return mapEntry.getField(field);
404   }
405 
setFieldValue( Message.Builder mapEntry, String name, Object value)406   private static Message.Builder setFieldValue(
407       Message.Builder mapEntry, String name, Object value) {
408     FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name);
409     mapEntry.setField(field, value);
410     return mapEntry;
411   }
412 
assertHasMapValues(Message message, String name, Map<?, ?> values)413   private static void assertHasMapValues(Message message, String name, Map<?, ?> values) {
414     FieldDescriptor field = f(name);
415     for (Object entry : (List<?>) message.getField(field)) {
416       Message mapEntry = (Message) entry;
417       Object key = getFieldValue(mapEntry, "key");
418       Object value = getFieldValue(mapEntry, "value");
419       assertTrue(values.containsKey(key));
420       assertEquals(value, values.get(key));
421     }
422     assertEquals(values.size(), message.getRepeatedFieldCount(field));
423     for (int i = 0; i < message.getRepeatedFieldCount(field); i++) {
424       Message mapEntry = (Message) message.getRepeatedField(field, i);
425       Object key = getFieldValue(mapEntry, "key");
426       Object value = getFieldValue(mapEntry, "value");
427       assertTrue(values.containsKey(key));
428       assertEquals(value, values.get(key));
429     }
430   }
431 
432   private static <KeyType, ValueType>
newMapEntry(Message.Builder builder, String name, KeyType key, ValueType value)433   Message newMapEntry(Message.Builder builder, String name, KeyType key, ValueType value) {
434     FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name);
435     Message.Builder entryBuilder = builder.newBuilderForField(field);
436     FieldDescriptor keyField = entryBuilder.getDescriptorForType().findFieldByName("key");
437     FieldDescriptor valueField = entryBuilder.getDescriptorForType().findFieldByName("value");
438     entryBuilder.setField(keyField, key);
439     entryBuilder.setField(valueField, value);
440     return entryBuilder.build();
441   }
442 
setMapValues(Message.Builder builder, String name, Map<?, ?> values)443   private static void setMapValues(Message.Builder builder, String name, Map<?, ?> values) {
444     List<Message> entryList = new ArrayList<Message>();
445     for (Map.Entry<?, ?> entry : values.entrySet()) {
446       entryList.add(newMapEntry(builder, name, entry.getKey(), entry.getValue()));
447     }
448     FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name);
449     builder.setField(field, entryList);
450   }
451 
452   private static <KeyType, ValueType>
mapForValues( KeyType key1, ValueType value1, KeyType key2, ValueType value2)453   Map<KeyType, ValueType> mapForValues(
454       KeyType key1, ValueType value1, KeyType key2, ValueType value2) {
455     Map<KeyType, ValueType> map = new HashMap<KeyType, ValueType>();
456     map.put(key1, value1);
457     map.put(key2, value2);
458     return map;
459   }
460 
testReflectionApi()461   public void testReflectionApi() throws Exception {
462     // In reflection API, map fields are just repeated message fields.
463     TestMap.Builder builder = TestMap.newBuilder();
464     builder.getMutableInt32ToInt32Field().put(1, 2);
465     builder.getMutableInt32ToInt32Field().put(3, 4);
466     builder.getMutableInt32ToMessageField().put(
467         11, MessageValue.newBuilder().setValue(22).build());
468     builder.getMutableInt32ToMessageField().put(
469         33, MessageValue.newBuilder().setValue(44).build());
470     TestMap message = builder.build();
471 
472     // Test getField(), getRepeatedFieldCount(), getRepeatedField().
473     assertHasMapValues(message, "int32_to_int32_field",
474         mapForValues(1, 2, 3, 4));
475     assertHasMapValues(message, "int32_to_message_field",
476         mapForValues(
477             11, MessageValue.newBuilder().setValue(22).build(),
478             33, MessageValue.newBuilder().setValue(44).build()));
479 
480     // Test clearField()
481     builder.clearField(f("int32_to_int32_field"));
482     builder.clearField(f("int32_to_message_field"));
483     message = builder.build();
484     assertEquals(0, message.getInt32ToInt32Field().size());
485     assertEquals(0, message.getInt32ToMessageField().size());
486 
487     // Test setField()
488     setMapValues(builder, "int32_to_int32_field",
489         mapForValues(11, 22, 33, 44));
490     setMapValues(builder, "int32_to_message_field",
491         mapForValues(
492             111, MessageValue.newBuilder().setValue(222).build(),
493             333, MessageValue.newBuilder().setValue(444).build()));
494     message = builder.build();
495     assertEquals(22, message.getInt32ToInt32Field().get(11).intValue());
496     assertEquals(44, message.getInt32ToInt32Field().get(33).intValue());
497     assertEquals(222, message.getInt32ToMessageField().get(111).getValue());
498     assertEquals(444, message.getInt32ToMessageField().get(333).getValue());
499 
500     // Test addRepeatedField
501     builder.addRepeatedField(f("int32_to_int32_field"),
502         newMapEntry(builder, "int32_to_int32_field", 55, 66));
503     builder.addRepeatedField(f("int32_to_message_field"),
504         newMapEntry(builder, "int32_to_message_field", 555,
505             MessageValue.newBuilder().setValue(666).build()));
506     message = builder.build();
507     assertEquals(66, message.getInt32ToInt32Field().get(55).intValue());
508     assertEquals(666, message.getInt32ToMessageField().get(555).getValue());
509 
510     // Test addRepeatedField (overriding existing values)
511     builder.addRepeatedField(f("int32_to_int32_field"),
512         newMapEntry(builder, "int32_to_int32_field", 55, 55));
513     builder.addRepeatedField(f("int32_to_message_field"),
514         newMapEntry(builder, "int32_to_message_field", 555,
515             MessageValue.newBuilder().setValue(555).build()));
516     message = builder.build();
517     assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
518     assertEquals(555, message.getInt32ToMessageField().get(555).getValue());
519 
520     // Test setRepeatedField
521     for (int i = 0; i < builder.getRepeatedFieldCount(f("int32_to_int32_field")); i++) {
522       Message mapEntry = (Message) builder.getRepeatedField(f("int32_to_int32_field"), i);
523       int oldKey = ((Integer) getFieldValue(mapEntry, "key")).intValue();
524       int oldValue = ((Integer) getFieldValue(mapEntry, "value")).intValue();
525       // Swap key with value for each entry.
526       Message.Builder mapEntryBuilder = mapEntry.toBuilder();
527       setFieldValue(mapEntryBuilder, "key", oldValue);
528       setFieldValue(mapEntryBuilder, "value", oldKey);
529       builder.setRepeatedField(f("int32_to_int32_field"), i, mapEntryBuilder.build());
530     }
531     message = builder.build();
532     assertEquals(11, message.getInt32ToInt32Field().get(22).intValue());
533     assertEquals(33, message.getInt32ToInt32Field().get(44).intValue());
534     assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
535   }
536 
testTextFormat()537   public void testTextFormat() throws Exception {
538     TestMap.Builder builder = TestMap.newBuilder();
539     setMapValues(builder);
540     TestMap message = builder.build();
541 
542     String textData = TextFormat.printToString(message);
543 
544     builder = TestMap.newBuilder();
545     TextFormat.merge(textData, builder);
546     message = builder.build();
547 
548     assertMapValuesSet(message);
549   }
550 
testDynamicMessage()551   public void testDynamicMessage() throws Exception {
552     TestMap.Builder builder = TestMap.newBuilder();
553     setMapValues(builder);
554     TestMap message = builder.build();
555 
556     Message dynamicDefaultInstance =
557         DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
558     Message dynamicMessage = dynamicDefaultInstance
559         .newBuilderForType().mergeFrom(message.toByteString()).build();
560 
561     assertEquals(message, dynamicMessage);
562     assertEquals(message.hashCode(), dynamicMessage.hashCode());
563   }
564 
testReflectionEqualsAndHashCode()565   public void testReflectionEqualsAndHashCode() throws Exception {
566     // Test that generated equals() and hashCode() will disregard the order
567     // of map entries when comparing/hashing map fields.
568 
569     // We use DynamicMessage to test reflection based equals()/hashCode().
570     Message dynamicDefaultInstance =
571         DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
572     FieldDescriptor field = f("int32_to_int32_field");
573 
574     Message.Builder b1 = dynamicDefaultInstance.newBuilderForType();
575     b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 1, 2));
576     b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 3, 4));
577     b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 5, 6));
578     Message m1 = b1.build();
579 
580     Message.Builder b2 = dynamicDefaultInstance.newBuilderForType();
581     b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 5, 6));
582     b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 1, 2));
583     b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 3, 4));
584     Message m2 = b2.build();
585 
586     assertEquals(m1, m2);
587     assertEquals(m1.hashCode(), m2.hashCode());
588 
589     // Make sure we did compare map fields.
590     b2.setRepeatedField(field, 0, newMapEntry(b1, "int32_to_int32_field", 0, 0));
591     m2 = b2.build();
592     assertFalse(m1.equals(m2));
593     // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
594     // to be different.
595   }
596 
testUnknownEnumValues()597   public void testUnknownEnumValues() throws Exception {
598     TestUnknownEnumValue.Builder builder =
599         TestUnknownEnumValue.newBuilder();
600     builder.getMutableInt32ToInt32Field().put(1, 1);
601     builder.getMutableInt32ToInt32Field().put(2, 54321);
602     ByteString data = builder.build().toByteString();
603 
604     TestMap message = TestMap.parseFrom(data);
605     // Entries with unknown enum values will be stored into UnknownFieldSet so
606     // there is only one entry in the map.
607     assertEquals(1, message.getInt32ToEnumField().size());
608     assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1));
609     // UnknownFieldSet should not be empty.
610     assertFalse(message.getUnknownFields().asMap().isEmpty());
611     // Serializing and parsing should preserve the unknown entry.
612     data = message.toByteString();
613     TestUnknownEnumValue messageWithUnknownEnums =
614         TestUnknownEnumValue.parseFrom(data);
615     assertEquals(2, messageWithUnknownEnums.getInt32ToInt32Field().size());
616     assertEquals(1, messageWithUnknownEnums.getInt32ToInt32Field().get(1).intValue());
617     assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue());
618   }
619 
620 
testRequiredMessage()621   public void testRequiredMessage() throws Exception {
622     TestMap.Builder builder = TestMap.newBuilder();
623     builder.getMutableRequiredMessageMap().put(0,
624         MessageWithRequiredFields.newBuilder().buildPartial());
625     TestMap message = builder.buildPartial();
626     assertFalse(message.isInitialized());
627 
628     builder.getMutableRequiredMessageMap().put(0,
629         MessageWithRequiredFields.newBuilder().setValue(1).build());
630     message = builder.build();
631     assertTrue(message.isInitialized());
632   }
633 
testRecursiveMap()634   public void testRecursiveMap() throws Exception {
635     TestRecursiveMap.Builder builder = TestRecursiveMap.newBuilder();
636     builder.getMutableRecursiveMapField().put(
637         1, TestRecursiveMap.newBuilder().setValue(2).build());
638     builder.getMutableRecursiveMapField().put(
639         3, TestRecursiveMap.newBuilder().setValue(4).build());
640     ByteString data = builder.build().toByteString();
641 
642     TestRecursiveMap message = TestRecursiveMap.parseFrom(data);
643     assertEquals(2, message.getRecursiveMapField().get(1).getValue());
644     assertEquals(4, message.getRecursiveMapField().get(3).getValue());
645   }
646 
testIterationOrder()647   public void testIterationOrder() throws Exception {
648     TestMap.Builder builder = TestMap.newBuilder();
649     setMapValues(builder);
650     TestMap message = builder.build();
651 
652     assertEquals(Arrays.asList("1", "2", "3"),
653         new ArrayList<String>(message.getStringToInt32Field().keySet()));
654   }
655 
656   // Regression test for b/20494788
testMapInitializationOrder()657   public void testMapInitializationOrder() throws Exception {
658     assertEquals("RedactAllTypes", map_test.RedactAllTypes
659         .getDefaultInstance().getDescriptorForType().getName());
660 
661     map_test.Message1.Builder builder =
662         map_test.Message1.newBuilder();
663     builder.getMutableMapField().put("key", true);
664     map_test.Message1 message = builder.build();
665     Message mapEntry = (Message) message.getRepeatedField(
666         message.getDescriptorForType().findFieldByName("map_field"), 0);
667     assertEquals(2, mapEntry.getAllFields().size());
668   }
669 
newMap(K key1, V value1)670   private static <K, V> Map<K, V> newMap(K key1, V value1) {
671     Map<K, V> map = new HashMap<K, V>();
672     map.put(key1, value1);
673     return map;
674   }
675 
newMap(K key1, V value1, K key2, V value2)676   private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
677     Map<K, V> map = new HashMap<K, V>();
678     map.put(key1, value1);
679     map.put(key2, value2);
680     return map;
681   }
682 }
683 
684