• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 package com.google.protobuf;
9 
10 import static com.google.common.truth.Truth.assertThat;
11 import static com.google.common.truth.Truth.assertWithMessage;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertThrows;
14 import static org.junit.Assert.fail;
15 
16 import com.google.protobuf.Descriptors.Descriptor;
17 import com.google.protobuf.Descriptors.EnumDescriptor;
18 import com.google.protobuf.Descriptors.EnumValueDescriptor;
19 import com.google.protobuf.Descriptors.FieldDescriptor;
20 import map_test.MapTestProto.BizarroTestMap;
21 import map_test.MapTestProto.MapContainer;
22 import map_test.MapTestProto.ReservedAsMapField;
23 import map_test.MapTestProto.ReservedAsMapFieldWithEnumValue;
24 import map_test.MapTestProto.TestMap;
25 import map_test.MapTestProto.TestMap.MessageValue;
26 import map_test.MapTestProto.TestMapOrBuilder;
27 import map_test.MapTestProto.TestOnChangeEventPropagation;
28 import java.io.ByteArrayOutputStream;
29 import java.io.IOException;
30 import java.util.ArrayList;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.TreeMap;
35 import org.junit.Test;
36 import org.junit.runner.RunWith;
37 import org.junit.runners.JUnit4;
38 
39 /** Unit tests for map fields. */
40 @RunWith(JUnit4.class)
41 public class MapTest {
42 
setMapValuesUsingMutableMap(TestMap.Builder builder)43   private void setMapValuesUsingMutableMap(TestMap.Builder builder) {
44     builder.getMutableInt32ToInt32Field().put(1, 11);
45     builder.getMutableInt32ToInt32Field().put(2, 22);
46     builder.getMutableInt32ToInt32Field().put(3, 33);
47 
48     builder.getMutableInt32ToStringField().put(1, "11");
49     builder.getMutableInt32ToStringField().put(2, "22");
50     builder.getMutableInt32ToStringField().put(3, "33");
51 
52     builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("11"));
53     builder.getMutableInt32ToBytesField().put(2, TestUtil.toBytes("22"));
54     builder.getMutableInt32ToBytesField().put(3, TestUtil.toBytes("33"));
55 
56     builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.FOO);
57     builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.BAR);
58     builder.getMutableInt32ToEnumField().put(3, TestMap.EnumValue.BAZ);
59 
60     builder.getMutableInt32ToMessageField().put(
61         1, MessageValue.newBuilder().setValue(11).build());
62     builder.getMutableInt32ToMessageField().put(
63         2, MessageValue.newBuilder().setValue(22).build());
64     builder.getMutableInt32ToMessageField().put(
65         3, MessageValue.newBuilder().setValue(33).build());
66 
67     builder.getMutableStringToInt32Field().put("1", 11);
68     builder.getMutableStringToInt32Field().put("2", 22);
69     builder.getMutableStringToInt32Field().put("3", 33);
70   }
71 
setMapValuesUsingAccessors(TestMap.Builder builder)72   private void setMapValuesUsingAccessors(TestMap.Builder builder) {
73     builder
74         .putInt32ToInt32Field(1, 11)
75         .putInt32ToInt32Field(2, 22)
76         .putInt32ToInt32Field(3, 33)
77         .putInt32ToStringField(1, "11")
78         .putInt32ToStringField(2, "22")
79         .putInt32ToStringField(3, "33")
80         .putInt32ToBytesField(1, TestUtil.toBytes("11"))
81         .putInt32ToBytesField(2, TestUtil.toBytes("22"))
82         .putInt32ToBytesField(3, TestUtil.toBytes("33"))
83         .putInt32ToEnumField(1, TestMap.EnumValue.FOO)
84         .putInt32ToEnumField(2, TestMap.EnumValue.BAR)
85         .putInt32ToEnumField(3, TestMap.EnumValue.BAZ)
86         .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(11).build())
87         .putInt32ToMessageField(2, MessageValue.newBuilder().setValue(22).build())
88         .putInt32ToMessageField(3, MessageValue.newBuilder().setValue(33).build())
89         .putStringToInt32Field("1", 11)
90         .putStringToInt32Field("2", 22)
91         .putStringToInt32Field("3", 33);
92   }
93 
94   @Test
testSetMapValues()95   public void testSetMapValues() {
96     TestMap.Builder usingMutableMapBuilder = TestMap.newBuilder();
97     setMapValuesUsingMutableMap(usingMutableMapBuilder);
98     TestMap usingMutableMap = usingMutableMapBuilder.build();
99     assertMapValuesSet(usingMutableMap);
100 
101     TestMap.Builder usingAccessorsBuilder = TestMap.newBuilder();
102     setMapValuesUsingAccessors(usingAccessorsBuilder);
103     TestMap usingAccessors = usingAccessorsBuilder.build();
104     assertMapValuesSet(usingAccessors);
105 
106     assertThat(usingAccessors).isEqualTo(usingMutableMap);
107   }
108 
copyMapValues(TestMap source, TestMap.Builder destination)109   private void copyMapValues(TestMap source, TestMap.Builder destination) {
110     destination
111         .putAllInt32ToInt32Field(source.getInt32ToInt32FieldMap())
112         .putAllInt32ToStringField(source.getInt32ToStringFieldMap())
113         .putAllInt32ToBytesField(source.getInt32ToBytesFieldMap())
114         .putAllInt32ToEnumField(source.getInt32ToEnumFieldMap())
115         .putAllInt32ToMessageField(source.getInt32ToMessageFieldMap())
116         .putAllStringToInt32Field(source.getStringToInt32FieldMap());
117   }
118 
assertMapValuesSet(TestMap message)119   private void assertMapValuesSet(TestMap message) {
120     assertThat(message.getInt32ToInt32FieldMap()).hasSize(3);
121     assertThat(message.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(11);
122     assertThat(message.getInt32ToInt32FieldMap().get(2).intValue()).isEqualTo(22);
123     assertThat(message.getInt32ToInt32FieldMap().get(3).intValue()).isEqualTo(33);
124 
125     assertThat(message.getInt32ToStringFieldMap()).hasSize(3);
126     assertThat(message.getInt32ToStringFieldMap()).containsEntry(1, "11");
127     assertThat(message.getInt32ToStringFieldMap()).containsEntry(2, "22");
128     assertThat(message.getInt32ToStringFieldMap()).containsEntry(3, "33");
129 
130     assertThat(message.getInt32ToBytesFieldMap()).hasSize(3);
131     assertThat(message.getInt32ToBytesFieldMap()).containsEntry(1, TestUtil.toBytes("11"));
132     assertThat(message.getInt32ToBytesFieldMap()).containsEntry(2, TestUtil.toBytes("22"));
133     assertThat(message.getInt32ToBytesFieldMap()).containsEntry(3, TestUtil.toBytes("33"));
134 
135     assertThat(message.getInt32ToEnumFieldMap()).hasSize(3);
136     assertThat(message.getInt32ToEnumFieldMap()).containsEntry(1, TestMap.EnumValue.FOO);
137     assertThat(message.getInt32ToEnumFieldMap()).containsEntry(2, TestMap.EnumValue.BAR);
138     assertThat(message.getInt32ToEnumFieldMap()).containsEntry(3, TestMap.EnumValue.BAZ);
139 
140     assertThat(message.getInt32ToMessageFieldMap()).hasSize(3);
141     assertThat(message.getInt32ToMessageFieldMap().get(1).getValue()).isEqualTo(11);
142     assertThat(message.getInt32ToMessageFieldMap().get(2).getValue()).isEqualTo(22);
143     assertThat(message.getInt32ToMessageFieldMap().get(3).getValue()).isEqualTo(33);
144 
145     assertThat(message.getStringToInt32FieldMap()).hasSize(3);
146     assertThat(message.getStringToInt32FieldMap().get("1").intValue()).isEqualTo(11);
147     assertThat(message.getStringToInt32FieldMap().get("2").intValue()).isEqualTo(22);
148     assertThat(message.getStringToInt32FieldMap().get("3").intValue()).isEqualTo(33);
149   }
150 
updateMapValuesUsingMutableMap(TestMap.Builder builder)151   private void updateMapValuesUsingMutableMap(TestMap.Builder builder) {
152     builder.getMutableInt32ToInt32Field().put(1, 111);
153     builder.getMutableInt32ToInt32Field().remove(2);
154     builder.getMutableInt32ToInt32Field().put(4, 44);
155 
156     builder.getMutableInt32ToStringField().put(1, "111");
157     builder.getMutableInt32ToStringField().remove(2);
158     builder.getMutableInt32ToStringField().put(4, "44");
159 
160     builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("111"));
161     builder.getMutableInt32ToBytesField().remove(2);
162     builder.getMutableInt32ToBytesField().put(4, TestUtil.toBytes("44"));
163 
164     builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.BAR);
165     builder.getMutableInt32ToEnumField().remove(2);
166     builder.getMutableInt32ToEnumField().put(4, TestMap.EnumValue.QUX);
167 
168     builder.getMutableInt32ToMessageField().put(
169         1, MessageValue.newBuilder().setValue(111).build());
170     builder.getMutableInt32ToMessageField().remove(2);
171     builder.getMutableInt32ToMessageField().put(
172         4, MessageValue.newBuilder().setValue(44).build());
173 
174     builder.getMutableStringToInt32Field().put("1", 111);
175     builder.getMutableStringToInt32Field().remove("2");
176     builder.getMutableStringToInt32Field().put("4", 44);
177   }
178 
updateMapValuesUsingAccessors(TestMap.Builder builder)179   private void updateMapValuesUsingAccessors(TestMap.Builder builder) {
180     builder
181         .putInt32ToInt32Field(1, 111)
182         .removeInt32ToInt32Field(2)
183         .putInt32ToInt32Field(4, 44)
184         .putInt32ToStringField(1, "111")
185         .removeInt32ToStringField(2)
186         .putInt32ToStringField(4, "44")
187         .putInt32ToBytesField(1, TestUtil.toBytes("111"))
188         .removeInt32ToBytesField(2)
189         .putInt32ToBytesField(4, TestUtil.toBytes("44"))
190         .putInt32ToEnumField(1, TestMap.EnumValue.BAR)
191         .removeInt32ToEnumField(2)
192         .putInt32ToEnumField(4, TestMap.EnumValue.QUX)
193         .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(111).build())
194         .removeInt32ToMessageField(2)
195         .putInt32ToMessageField(4, MessageValue.newBuilder().setValue(44).build())
196         .putStringToInt32Field("1", 111)
197         .removeStringToInt32Field("2")
198         .putStringToInt32Field("4", 44);
199   }
200 
201   @Test
testUpdateMapValues()202   public void testUpdateMapValues() {
203     TestMap.Builder usingMutableMapBuilder = TestMap.newBuilder();
204     setMapValuesUsingMutableMap(usingMutableMapBuilder);
205     TestMap usingMutableMap = usingMutableMapBuilder.build();
206     assertMapValuesSet(usingMutableMap);
207 
208     TestMap.Builder usingAccessorsBuilder = TestMap.newBuilder();
209     setMapValuesUsingAccessors(usingAccessorsBuilder);
210     TestMap usingAccessors = usingAccessorsBuilder.build();
211     assertMapValuesSet(usingAccessors);
212 
213     assertThat(usingAccessors).isEqualTo(usingMutableMap);
214 
215     usingMutableMapBuilder = usingMutableMap.toBuilder();
216     updateMapValuesUsingMutableMap(usingMutableMapBuilder);
217     usingMutableMap = usingMutableMapBuilder.build();
218     assertMapValuesUpdated(usingMutableMap);
219 
220     usingAccessorsBuilder = usingAccessors.toBuilder();
221     updateMapValuesUsingAccessors(usingAccessorsBuilder);
222     usingAccessors = usingAccessorsBuilder.build();
223     assertMapValuesUpdated(usingAccessors);
224 
225     assertThat(usingAccessors).isEqualTo(usingMutableMap);
226   }
227 
assertMapValuesUpdated(TestMap message)228   private void assertMapValuesUpdated(TestMap message) {
229     assertThat(message.getInt32ToInt32FieldMap()).hasSize(3);
230     assertThat(message.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(111);
231     assertThat(message.getInt32ToInt32FieldMap().get(3).intValue()).isEqualTo(33);
232     assertThat(message.getInt32ToInt32FieldMap().get(4).intValue()).isEqualTo(44);
233 
234     assertThat(message.getInt32ToStringFieldMap()).hasSize(3);
235     assertThat(message.getInt32ToStringFieldMap()).containsEntry(1, "111");
236     assertThat(message.getInt32ToStringFieldMap()).containsEntry(3, "33");
237     assertThat(message.getInt32ToStringFieldMap()).containsEntry(4, "44");
238 
239     assertThat(message.getInt32ToBytesFieldMap()).hasSize(3);
240     assertThat(message.getInt32ToBytesFieldMap()).containsEntry(1, TestUtil.toBytes("111"));
241     assertThat(message.getInt32ToBytesFieldMap()).containsEntry(3, TestUtil.toBytes("33"));
242     assertThat(message.getInt32ToBytesFieldMap()).containsEntry(4, TestUtil.toBytes("44"));
243 
244     assertThat(message.getInt32ToEnumFieldMap()).hasSize(3);
245     assertThat(message.getInt32ToEnumFieldMap()).containsEntry(1, TestMap.EnumValue.BAR);
246     assertThat(message.getInt32ToEnumFieldMap()).containsEntry(3, TestMap.EnumValue.BAZ);
247     assertThat(message.getInt32ToEnumFieldMap()).containsEntry(4, TestMap.EnumValue.QUX);
248 
249     assertThat(message.getInt32ToMessageFieldMap()).hasSize(3);
250     assertThat(message.getInt32ToMessageFieldMap().get(1).getValue()).isEqualTo(111);
251     assertThat(message.getInt32ToMessageFieldMap().get(3).getValue()).isEqualTo(33);
252     assertThat(message.getInt32ToMessageFieldMap().get(4).getValue()).isEqualTo(44);
253 
254     assertThat(message.getStringToInt32FieldMap()).hasSize(3);
255     assertThat(message.getStringToInt32FieldMap().get("1").intValue()).isEqualTo(111);
256     assertThat(message.getStringToInt32FieldMap().get("3").intValue()).isEqualTo(33);
257     assertThat(message.getStringToInt32FieldMap().get("4").intValue()).isEqualTo(44);
258   }
259 
assertMapValuesCleared(TestMapOrBuilder testMapOrBuilder)260   private void assertMapValuesCleared(TestMapOrBuilder testMapOrBuilder) {
261     assertThat(testMapOrBuilder.getInt32ToInt32FieldMap()).isEmpty();
262     assertThat(testMapOrBuilder.getInt32ToInt32FieldCount()).isEqualTo(0);
263     assertThat(testMapOrBuilder.getInt32ToStringFieldMap()).isEmpty();
264     assertThat(testMapOrBuilder.getInt32ToStringFieldCount()).isEqualTo(0);
265     assertThat(testMapOrBuilder.getInt32ToBytesFieldMap()).isEmpty();
266     assertThat(testMapOrBuilder.getInt32ToBytesFieldCount()).isEqualTo(0);
267     assertThat(testMapOrBuilder.getInt32ToEnumFieldMap()).isEmpty();
268     assertThat(testMapOrBuilder.getInt32ToEnumFieldCount()).isEqualTo(0);
269     assertThat(testMapOrBuilder.getInt32ToMessageFieldMap()).isEmpty();
270     assertThat(testMapOrBuilder.getInt32ToMessageFieldCount()).isEqualTo(0);
271     assertThat(testMapOrBuilder.getStringToInt32FieldMap()).isEmpty();
272     assertThat(testMapOrBuilder.getStringToInt32FieldCount()).isEqualTo(0);
273   }
274 
275   @Test
testGetMapIsImmutable()276   public void testGetMapIsImmutable() {
277     TestMap.Builder builder = TestMap.newBuilder();
278     assertMapsAreImmutable(builder);
279     assertMapsAreImmutable(builder.build());
280 
281     setMapValuesUsingAccessors(builder);
282     assertMapsAreImmutable(builder);
283     assertMapsAreImmutable(builder.build());
284   }
285 
assertMapsAreImmutable(TestMapOrBuilder testMapOrBuilder)286   private void assertMapsAreImmutable(TestMapOrBuilder testMapOrBuilder) {
287     assertImmutable(testMapOrBuilder.getInt32ToInt32FieldMap(), 1, 2);
288     assertImmutable(testMapOrBuilder.getInt32ToStringFieldMap(), 1, "2");
289     assertImmutable(testMapOrBuilder.getInt32ToBytesFieldMap(), 1, TestUtil.toBytes("2"));
290     assertImmutable(testMapOrBuilder.getInt32ToEnumFieldMap(), 1, TestMap.EnumValue.FOO);
291     assertImmutable(
292         testMapOrBuilder.getInt32ToMessageFieldMap(), 1, MessageValue.getDefaultInstance());
293     assertImmutable(testMapOrBuilder.getStringToInt32FieldMap(), "1", 2);
294   }
295 
assertImmutable(Map<K, V> map, K key, V value)296   private <K, V> void assertImmutable(Map<K, V> map, K key, V value) {
297     try {
298       map.put(key, value);
299       assertWithMessage("expected exception").fail();
300     } catch (UnsupportedOperationException e) {
301       // expected
302     }
303   }
304 
305   @Test
testMutableMapLifecycle()306   public void testMutableMapLifecycle() {
307     TestMap.Builder builder = TestMap.newBuilder();
308     Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
309     intMap.put(1, 2);
310     assertThat(builder.build().getInt32ToInt32Field()).isEqualTo(newMap(1, 2));
311     try {
312       intMap.put(2, 3);
313       assertWithMessage("expected exception intMap").fail();
314     } catch (UnsupportedOperationException e) {
315       // expected
316     }
317     assertThat(builder.getInt32ToInt32Field()).isEqualTo(newMap(1, 2));
318     builder.getMutableInt32ToInt32Field().put(2, 3);
319     assertThat(builder.getInt32ToInt32Field()).isEqualTo(newMap(1, 2, 2, 3));
320 
321     Map<Integer, TestMap.EnumValue> enumMap = builder.getMutableInt32ToEnumField();
322     enumMap.put(1, TestMap.EnumValue.BAR);
323     assertThat(builder.build().getInt32ToEnumField())
324         .isEqualTo(newMap(1, TestMap.EnumValue.BAR));
325     try {
326       enumMap.put(2, TestMap.EnumValue.FOO);
327       assertWithMessage("expected exception enumMap").fail();
328     } catch (UnsupportedOperationException e) {
329       // expected
330     }
331     assertThat(builder.getInt32ToEnumField()).isEqualTo(newMap(1, TestMap.EnumValue.BAR));
332     builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.FOO);
333     assertThat(builder.getInt32ToEnumField()).isEqualTo(
334         newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO));
335 
336     Map<Integer, String> stringMap = builder.getMutableInt32ToStringField();
337     stringMap.put(1, "1");
338     assertThat(builder.build().getInt32ToStringField()).isEqualTo(newMap(1, "1"));
339     try {
340       stringMap.put(2, "2");
341       assertWithMessage("expected exception stringMap").fail();
342     } catch (UnsupportedOperationException e) {
343       // expected
344     }
345     assertThat(builder.getInt32ToStringField()).isEqualTo(newMap(1, "1"));
346     builder.putInt32ToStringField(2, "2");
347     assertThat(builder.getInt32ToStringField()).isEqualTo(newMap(1, "1", 2, "2"));
348 
349     // Message maps are handled differently, and don't freeze old mutable collections.
350     Map<Integer, TestMap.MessageValue> messageMap = builder.getMutableInt32ToMessageField();
351     messageMap.put(1, TestMap.MessageValue.getDefaultInstance());
352     assertThat(builder.build().getInt32ToMessageField())
353         .isEqualTo(newMap(1, TestMap.MessageValue.getDefaultInstance()));
354     // Mutations on old mutable maps don't affect the builder state.
355     messageMap.put(2, TestMap.MessageValue.getDefaultInstance());
356     assertThat(builder.getInt32ToMessageField()).isEqualTo(
357         newMap(1, TestMap.MessageValue.getDefaultInstance()));
358     builder.putInt32ToMessageField(2, TestMap.MessageValue.getDefaultInstance());
359     assertThat(builder.getInt32ToMessageField()).isEqualTo(
360         newMap(1, TestMap.MessageValue.getDefaultInstance(),
361             2, TestMap.MessageValue.getDefaultInstance()));
362   }
363 
364   @Test
testMutableMapLifecycle_collections()365   public void testMutableMapLifecycle_collections() {
366     TestMap.Builder builder = TestMap.newBuilder();
367     Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
368     intMap.put(1, 2);
369     assertThat(builder.build().getInt32ToInt32Field()).isEqualTo(newMap(1, 2));
370     try {
371       intMap.remove(2);
372       assertWithMessage("expected exception").fail();
373     } catch (UnsupportedOperationException e) {
374       // expected
375     }
376     try {
377       intMap.entrySet().remove(new Object());
378       assertWithMessage("expected exception").fail();
379     } catch (UnsupportedOperationException e) {
380       // expected
381     }
382     try {
383       intMap.entrySet().iterator().remove();
384       assertWithMessage("expected exception").fail();
385     } catch (UnsupportedOperationException e) {
386       // expected
387     }
388     try {
389       intMap.keySet().remove(new Object());
390       assertWithMessage("expected exception").fail();
391     } catch (UnsupportedOperationException e) {
392       // expected
393     }
394     try {
395       intMap.values().remove(new Object());
396       assertWithMessage("expected exception").fail();
397     } catch (UnsupportedOperationException e) {
398       // expected
399     }
400     try {
401       intMap.values().iterator().remove();
402       assertWithMessage("expected exception").fail();
403     } catch (UnsupportedOperationException e) {
404       // expected
405     }
406     assertThat(intMap).isEqualTo(newMap(1, 2));
407     assertThat(builder.getInt32ToInt32Field()).isEqualTo(newMap(1, 2));
408     assertThat(builder.build().getInt32ToInt32Field()).isEqualTo(newMap(1, 2));
409   }
410 
411   @Test
testGettersAndSetters()412   public void testGettersAndSetters() throws Exception {
413     TestMap.Builder builder = TestMap.newBuilder();
414     TestMap message = builder.build();
415     assertMapValuesCleared(message);
416 
417     builder = message.toBuilder();
418     setMapValuesUsingAccessors(builder);
419     message = builder.build();
420     assertMapValuesSet(message);
421 
422     builder = message.toBuilder();
423     updateMapValuesUsingAccessors(builder);
424     message = builder.build();
425     assertMapValuesUpdated(message);
426 
427     builder = message.toBuilder();
428     builder.clear();
429     assertMapValuesCleared(builder);
430     message = builder.build();
431     assertMapValuesCleared(message);
432   }
433 
434   @Test
testPutAll()435   public void testPutAll() throws Exception {
436     TestMap.Builder sourceBuilder = TestMap.newBuilder();
437     setMapValuesUsingAccessors(sourceBuilder);
438     TestMap source = sourceBuilder.build();
439     assertMapValuesSet(source);
440 
441     TestMap.Builder destination = TestMap.newBuilder();
442     copyMapValues(source, destination);
443     assertMapValuesSet(destination.build());
444   }
445 
446   @Test
testPutAllWithNullStringValue()447   public void testPutAllWithNullStringValue() throws Exception {
448     TestMap.Builder sourceBuilder = TestMap.newBuilder();
449 
450     // order preserving map used here to help test rollback
451     Map<Integer, String> data = new TreeMap<>();
452     data.put(7, "foo");
453     data.put(8, "bar");
454     data.put(9, null);
455     try {
456       sourceBuilder.putAllInt32ToStringField(data);
457       fail("allowed null string value");
458     } catch (NullPointerException expected) {
459       // Verify rollback of previously added values.
460       // They all go in or none do.
461       assertThat(sourceBuilder.getInt32ToStringFieldMap()).isEmpty();
462     }
463   }
464 
465   @Test
testPutNullStringValue()466   public void testPutNullStringValue() throws Exception {
467     TestMap.Builder sourceBuilder = TestMap.newBuilder();
468 
469     try {
470       sourceBuilder.putInt32ToStringField(8, null);
471       fail("allowed null string value");
472     } catch (NullPointerException expected) {
473       assertNotNull(expected.getMessage());
474     }
475   }
476 
477   @Test
testPutAllForUnknownEnumValues()478   public void testPutAllForUnknownEnumValues() throws Exception {
479     TestMap source =
480         TestMap.newBuilder()
481             .putAllInt32ToEnumFieldValue(
482                 newMap(
483                     0, 0,
484                     1, 1,
485                     2, 1000)) // unknown value.
486             .build();
487 
488     TestMap destination =
489         TestMap.newBuilder()
490             .putAllInt32ToEnumFieldValue(source.getInt32ToEnumFieldValueMap())
491             .build();
492 
493     assertThat(destination.getInt32ToEnumFieldValueMap().get(0).intValue()).isEqualTo(0);
494     assertThat(destination.getInt32ToEnumFieldValueMap().get(1).intValue()).isEqualTo(1);
495     assertThat(destination.getInt32ToEnumFieldValueMap().get(2).intValue()).isEqualTo(1000);
496     assertThat(destination.getInt32ToEnumFieldCount()).isEqualTo(3);
497   }
498 
499   @Test
testPutForUnknownEnumValues()500   public void testPutForUnknownEnumValues() throws Exception {
501     TestMap message =
502         TestMap.newBuilder()
503             .putInt32ToEnumFieldValue(0, 0)
504             .putInt32ToEnumFieldValue(1, 1)
505             .putInt32ToEnumFieldValue(2, 1000) // unknown value.
506             .build();
507     assertThat(message.getInt32ToEnumFieldValueOrThrow(0)).isEqualTo(0);
508     assertThat(message.getInt32ToEnumFieldValueOrThrow(1)).isEqualTo(1);
509     assertThat(message.getInt32ToEnumFieldValueOrThrow(2)).isEqualTo(1000);
510     assertThat(message.getInt32ToEnumFieldCount()).isEqualTo(3);
511   }
512 
513   @Test
testPutChecksNullKeysAndValues()514   public void testPutChecksNullKeysAndValues() throws Exception {
515     TestMap.Builder builder = TestMap.newBuilder();
516 
517     try {
518       builder.putInt32ToStringField(1, null);
519       assertWithMessage("expected exception").fail();
520     } catch (NullPointerException e) {
521       // expected.
522     }
523 
524     try {
525       builder.putInt32ToBytesField(1, null);
526       assertWithMessage("expected exception").fail();
527     } catch (NullPointerException e) {
528       // expected.
529     }
530 
531     try {
532       builder.putInt32ToEnumField(1, null);
533       assertWithMessage("expected exception").fail();
534     } catch (NullPointerException e) {
535       // expected.
536     }
537 
538     try {
539       builder.putInt32ToMessageField(1, null);
540       assertWithMessage("expected exception").fail();
541     } catch (NullPointerException e) {
542       // expected.
543     }
544 
545     try {
546       builder.putStringToInt32Field(null, 1);
547       assertWithMessage("expected exception").fail();
548     } catch (NullPointerException e) {
549       // expected.
550     }
551   }
552 
553   @Test
testPutBuilderIfAbsent()554   public void testPutBuilderIfAbsent() {
555     TestMap.Builder builder = TestMap.newBuilder();
556     MessageValue.Builder subBuilder = builder.putInt32ToMessageFieldBuilderIfAbsent(1);
557 
558     assertThat(builder.putInt32ToMessageFieldBuilderIfAbsent(1)).isSameInstanceAs(subBuilder);
559 
560     subBuilder.setValue(11);
561     assertThat(builder.getInt32ToMessageFieldOrThrow(1).getValue()).isEqualTo(11);
562     builder.putInt32ToMessageFieldBuilderIfAbsent(1).setValue(22);
563     assertThat(builder.getInt32ToMessageFieldOrThrow(1).getValue()).isEqualTo(22);
564 
565     builder.putInt32ToMessageField(2, MessageValue.newBuilder().setValue(33).build());
566     assertThat(builder.putInt32ToMessageFieldBuilderIfAbsent(2).getValue()).isEqualTo(33);
567   }
568 
569   @Test
testSerializeAndParse()570   public void testSerializeAndParse() throws Exception {
571     TestMap.Builder builder = TestMap.newBuilder();
572     setMapValuesUsingAccessors(builder);
573     TestMap message = builder.build();
574     assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize());
575     message = TestMap.parseFrom(message.toByteString());
576     assertMapValuesSet(message);
577 
578     builder = message.toBuilder();
579     updateMapValuesUsingAccessors(builder);
580     message = builder.build();
581     assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize());
582     message = TestMap.parseFrom(message.toByteString());
583     assertMapValuesUpdated(message);
584 
585     builder = message.toBuilder();
586     builder.clear();
587     message = builder.build();
588     assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize());
589     message = TestMap.parseFrom(message.toByteString());
590     assertMapValuesCleared(message);
591   }
592 
tryParseTestMap(BizarroTestMap bizarroMap)593   private TestMap tryParseTestMap(BizarroTestMap bizarroMap) throws IOException {
594     ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
595     CodedOutputStream output = CodedOutputStream.newInstance(byteArrayOutputStream);
596     bizarroMap.writeTo(output);
597     output.flush();
598     return TestMap.parseFrom(ByteString.copyFrom(byteArrayOutputStream.toByteArray()));
599   }
600 
601   @Test
testParseError()602   public void testParseError() throws Exception {
603     ByteString bytes = TestUtil.toBytes("SOME BYTES");
604     String stringKey = "a string key";
605 
606     TestMap map =
607         tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToInt32Field(5, bytes).build());
608     assertThat(map.getInt32ToInt32FieldOrDefault(5, -1)).isEqualTo(0);
609 
610     map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToStringField(stringKey, 5).build());
611     assertThat(map.getInt32ToStringFieldOrDefault(0, null)).isEmpty();
612 
613     map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToBytesField(stringKey, 5).build());
614     assertThat(ByteString.EMPTY).isEqualTo(map.getInt32ToBytesFieldOrDefault(0, null));
615 
616     map =
617         tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToEnumField(stringKey, bytes).build());
618     assertThat(map.getInt32ToEnumFieldOrDefault(0, null)).isEqualTo(TestMap.EnumValue.FOO);
619 
620     try {
621       tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToMessageField(stringKey, bytes).build());
622       assertWithMessage("expected exception").fail();
623     } catch (InvalidProtocolBufferException expected) {
624       assertThat(expected.getUnfinishedMessage()).isInstanceOf(TestMap.class);
625       map = (TestMap) expected.getUnfinishedMessage();
626       assertThat(map.getInt32ToMessageFieldMap()).isEmpty();
627     }
628 
629     map =
630         tryParseTestMap(
631             BizarroTestMap.newBuilder().putStringToInt32Field(stringKey, bytes).build());
632     assertThat(map.getStringToInt32FieldOrDefault(stringKey, -1)).isEqualTo(0);
633   }
634 
635   @Test
testMergeFrom()636   public void testMergeFrom() throws Exception {
637     TestMap.Builder builder = TestMap.newBuilder();
638     setMapValuesUsingAccessors(builder);
639     TestMap message = builder.build();
640 
641     TestMap.Builder other = TestMap.newBuilder();
642     other.mergeFrom(message);
643     assertMapValuesSet(other.build());
644   }
645 
646   @Test
testEqualsAndHashCode()647   public void testEqualsAndHashCode() throws Exception {
648     // Test that generated equals() and hashCode() will disregard the order
649     // of map entries when comparing/hashing map fields.
650 
651     // We can't control the order of elements in a HashMap. The best we can do
652     // here is to add elements in different order.
653     TestMap m1 =
654         TestMap.newBuilder()
655             .putInt32ToInt32Field(1, 2)
656             .putInt32ToInt32Field(3, 4)
657             .putInt32ToInt32Field(5, 6)
658             .build();
659 
660     TestMap.Builder b2 =
661         TestMap.newBuilder()
662             .putInt32ToInt32Field(5, 6)
663             .putInt32ToInt32Field(1, 2)
664             .putInt32ToInt32Field(3, 4);
665     TestMap m2 = b2.build();
666 
667     assertThat(m2).isEqualTo(m1);
668     assertThat(m2.hashCode()).isEqualTo(m1.hashCode());
669 
670     // Make sure we did compare map fields.
671     b2.putInt32ToInt32Field(1, 0);
672     m2 = b2.build();
673     assertThat(m1.equals(m2)).isFalse();
674     // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
675     // to be different.
676 
677     // Regression test for b/18549190: if a map is a subset of the other map,
678     // equals() should return false.
679     b2.removeInt32ToInt32Field(1);
680     m2 = b2.build();
681     assertThat(m1.equals(m2)).isFalse();
682     assertThat(m2.equals(m1)).isFalse();
683   }
684 
685   @Test
testNestedBuilderOnChangeEventPropagation()686   public void testNestedBuilderOnChangeEventPropagation() {
687     TestOnChangeEventPropagation.Builder parent = TestOnChangeEventPropagation.newBuilder();
688     parent.getOptionalMessageBuilder().putInt32ToInt32Field(1, 2);
689     TestOnChangeEventPropagation message = parent.build();
690     assertThat(message.getOptionalMessage().getInt32ToInt32FieldMap().get(1).intValue())
691         .isEqualTo(2);
692 
693     // Make a change using nested builder.
694     parent.getOptionalMessageBuilder().putInt32ToInt32Field(1, 3);
695 
696     // Should be able to observe the change.
697     message = parent.build();
698     assertThat(message.getOptionalMessage().getInt32ToInt32FieldMap().get(1).intValue())
699         .isEqualTo(3);
700 
701     // Make another change using mergeFrom()
702     TestMap other = TestMap.newBuilder().putInt32ToInt32Field(1, 4).build();
703     parent.getOptionalMessageBuilder().mergeFrom(other);
704 
705     // Should be able to observe the change.
706     message = parent.build();
707     assertThat(message.getOptionalMessage().getInt32ToInt32FieldMap().get(1).intValue())
708         .isEqualTo(4);
709 
710     // Make yet another change by clearing the nested builder.
711     parent.getOptionalMessageBuilder().clear();
712 
713     // Should be able to observe the change.
714     message = parent.build();
715     assertThat(message.getOptionalMessage().getInt32ToInt32FieldMap()).isEmpty();
716   }
717 
718   @Test
testNestedBuilderOnChangeEventPropagationReflection()719   public void testNestedBuilderOnChangeEventPropagationReflection() {
720     FieldDescriptor intMapField = f("int32_to_int32_field");
721     // Create an outer message builder with nested builder.
722     TestOnChangeEventPropagation.Builder parentBuilder = TestOnChangeEventPropagation.newBuilder();
723     TestMap.Builder testMapBuilder = parentBuilder.getOptionalMessageBuilder();
724 
725     // Create a map entry message.
726     TestMap.Builder entryBuilder = TestMap.newBuilder().putInt32ToInt32Field(1, 1);
727 
728     // Put the entry into the nested builder.
729     testMapBuilder.addRepeatedField(intMapField, entryBuilder.getRepeatedField(intMapField, 0));
730 
731     // Should be able to observe the change.
732     TestOnChangeEventPropagation message = parentBuilder.build();
733     assertThat(message.getOptionalMessage().getInt32ToInt32FieldMap()).hasSize(1);
734 
735     // Change the entry value.
736     entryBuilder.putInt32ToInt32Field(1, 4);
737     testMapBuilder = parentBuilder.getOptionalMessageBuilder();
738     testMapBuilder.setRepeatedField(intMapField, 0, entryBuilder.getRepeatedField(intMapField, 0));
739 
740     // Should be able to observe the change.
741     message = parentBuilder.build();
742     assertThat(message.getOptionalMessage().getInt32ToInt32FieldMap().get(1).intValue())
743         .isEqualTo(4);
744 
745     // Clear the nested builder.
746     testMapBuilder = parentBuilder.getOptionalMessageBuilder();
747     testMapBuilder.clearField(intMapField);
748 
749     // Should be able to observe the change.
750     message = parentBuilder.build();
751     assertThat(message.getOptionalMessage().getInt32ToInt32FieldMap()).isEmpty();
752   }
753 
754   // The following methods are used to test reflection API.
755 
f(String name)756   private static FieldDescriptor f(String name) {
757     return TestMap.getDescriptor().findFieldByName(name);
758   }
759 
getFieldValue(Message mapEntry, String name)760   private static Object getFieldValue(Message mapEntry, String name) {
761     FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name);
762     return mapEntry.getField(field);
763   }
764 
setFieldValue( Message.Builder mapEntry, String name, Object value)765   private static Message.Builder setFieldValue(
766       Message.Builder mapEntry, String name, Object value) {
767     FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name);
768     mapEntry.setField(field, value);
769     return mapEntry;
770   }
771 
assertHasMapValues(Message message, String name, Map<?, ?> values)772   private static void assertHasMapValues(Message message, String name, Map<?, ?> values) {
773     FieldDescriptor field = f(name);
774     for (Object entry : (List<?>) message.getField(field)) {
775       Message mapEntry = (Message) entry;
776       Object key = getFieldValue(mapEntry, "key");
777       Object value = getFieldValue(mapEntry, "value");
778       assertThat(values.containsKey(key)).isTrue();
779       assertThat(values.get(key)).isEqualTo(value);
780     }
781     assertThat(message.getRepeatedFieldCount(field)).isEqualTo(values.size());
782     for (int i = 0; i < message.getRepeatedFieldCount(field); i++) {
783       Message mapEntry = (Message) message.getRepeatedField(field, i);
784       Object key = getFieldValue(mapEntry, "key");
785       Object value = getFieldValue(mapEntry, "value");
786       assertThat(values.containsKey(key)).isTrue();
787       assertThat(values.get(key)).isEqualTo(value);
788     }
789   }
790 
newMapEntry(Message.Builder builder, String name, K key, V value)791   private static <K, V> Message newMapEntry(Message.Builder builder, String name, K key, V value) {
792     FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name);
793     Message.Builder entryBuilder = builder.newBuilderForField(field);
794     FieldDescriptor keyField = entryBuilder.getDescriptorForType().findFieldByName("key");
795     FieldDescriptor valueField = entryBuilder.getDescriptorForType().findFieldByName("value");
796     entryBuilder.setField(keyField, key);
797     entryBuilder.setField(valueField, value);
798     return entryBuilder.build();
799   }
800 
setMapValues(Message.Builder builder, String name, Map<?, ?> values)801   private static void setMapValues(Message.Builder builder, String name, Map<?, ?> values) {
802     List<Message> entryList = new ArrayList<>();
803     for (Map.Entry<?, ?> entry : values.entrySet()) {
804       entryList.add(newMapEntry(builder, name, entry.getKey(), entry.getValue()));
805     }
806     FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name);
807     builder.setField(field, entryList);
808   }
809 
mapForValues(K key1, V value1, K key2, V value2)810   private static <K, V> Map<K, V> mapForValues(K key1, V value1, K key2, V value2) {
811     Map<K, V> map = new HashMap<>();
812     map.put(key1, value1);
813     map.put(key2, value2);
814     return map;
815   }
816 
817   @Test
testReflectionApi()818   public void testReflectionApi() throws Exception {
819     // In reflection API, map fields are just repeated message fields.
820     TestMap.Builder builder =
821         TestMap.newBuilder()
822             .putInt32ToInt32Field(1, 2)
823             .putInt32ToInt32Field(3, 4)
824             .putInt32ToMessageField(11, MessageValue.newBuilder().setValue(22).build())
825             .putInt32ToMessageField(33, MessageValue.newBuilder().setValue(44).build());
826     TestMap message = builder.build();
827 
828     // Test getField(), getRepeatedFieldCount(), getRepeatedField().
829     assertHasMapValues(message, "int32_to_int32_field", mapForValues(1, 2, 3, 4));
830     assertHasMapValues(
831         message,
832         "int32_to_message_field",
833         mapForValues(
834             11, MessageValue.newBuilder().setValue(22).build(),
835             33, MessageValue.newBuilder().setValue(44).build()));
836 
837     // Test clearField()
838     builder.clearField(f("int32_to_int32_field"));
839     builder.clearField(f("int32_to_message_field"));
840     message = builder.build();
841     assertThat(message.getInt32ToInt32FieldMap()).isEmpty();
842     assertThat(message.getInt32ToMessageFieldMap()).isEmpty();
843 
844     // Test setField()
845     setMapValues(builder, "int32_to_int32_field", mapForValues(11, 22, 33, 44));
846     setMapValues(
847         builder,
848         "int32_to_message_field",
849         mapForValues(
850             111, MessageValue.newBuilder().setValue(222).build(),
851             333, MessageValue.newBuilder().setValue(444).build()));
852     message = builder.build();
853     assertThat(message.getInt32ToInt32FieldMap().get(11).intValue()).isEqualTo(22);
854     assertThat(message.getInt32ToInt32FieldMap().get(33).intValue()).isEqualTo(44);
855     assertThat(message.getInt32ToMessageFieldMap().get(111).getValue()).isEqualTo(222);
856     assertThat(message.getInt32ToMessageFieldMap().get(333).getValue()).isEqualTo(444);
857 
858     // Test addRepeatedField
859     builder.addRepeatedField(
860         f("int32_to_int32_field"), newMapEntry(builder, "int32_to_int32_field", 55, 66));
861     builder.addRepeatedField(
862         f("int32_to_message_field"),
863         newMapEntry(
864             builder,
865             "int32_to_message_field",
866             555,
867             MessageValue.newBuilder().setValue(666).build()));
868     message = builder.build();
869     assertThat(message.getInt32ToInt32FieldMap().get(55).intValue()).isEqualTo(66);
870     assertThat(message.getInt32ToMessageFieldMap().get(555).getValue()).isEqualTo(666);
871 
872     // Test addRepeatedField (overriding existing values)
873     builder.addRepeatedField(
874         f("int32_to_int32_field"), newMapEntry(builder, "int32_to_int32_field", 55, 55));
875     builder.addRepeatedField(
876         f("int32_to_message_field"),
877         newMapEntry(
878             builder,
879             "int32_to_message_field",
880             555,
881             MessageValue.newBuilder().setValue(555).build()));
882     message = builder.build();
883     assertThat(message.getInt32ToInt32FieldMap().get(55).intValue()).isEqualTo(55);
884     assertThat(message.getInt32ToMessageFieldMap().get(555).getValue()).isEqualTo(555);
885 
886     // Test setRepeatedField
887     for (int i = 0; i < builder.getRepeatedFieldCount(f("int32_to_int32_field")); i++) {
888       Message mapEntry = (Message) builder.getRepeatedField(f("int32_to_int32_field"), i);
889       int oldKey = ((Integer) getFieldValue(mapEntry, "key")).intValue();
890       int oldValue = ((Integer) getFieldValue(mapEntry, "value")).intValue();
891       // Swap key with value for each entry.
892       Message.Builder mapEntryBuilder = mapEntry.toBuilder();
893       setFieldValue(mapEntryBuilder, "key", oldValue);
894       setFieldValue(mapEntryBuilder, "value", oldKey);
895       builder.setRepeatedField(f("int32_to_int32_field"), i, mapEntryBuilder.build());
896     }
897     message = builder.build();
898     assertThat(message.getInt32ToInt32FieldMap().get(22).intValue()).isEqualTo(11);
899     assertThat(message.getInt32ToInt32FieldMap().get(44).intValue()).isEqualTo(33);
900     assertThat(message.getInt32ToInt32FieldMap().get(55).intValue()).isEqualTo(55);
901   }
902 
903   // See additional coverage in TextFormatTest.java.
904   @Test
testTextFormat()905   public void testTextFormat() throws Exception {
906     TestMap.Builder builder = TestMap.newBuilder();
907     setMapValuesUsingAccessors(builder);
908     TestMap message = builder.build();
909 
910     String textData = TextFormat.printer().printToString(message);
911 
912     builder = TestMap.newBuilder();
913     TextFormat.merge(textData, builder);
914     message = builder.build();
915 
916     assertMapValuesSet(message);
917   }
918 
919   @Test
testDynamicMessage()920   public void testDynamicMessage() throws Exception {
921     TestMap.Builder builder = TestMap.newBuilder();
922     setMapValuesUsingAccessors(builder);
923     TestMap message = builder.build();
924 
925     Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
926     Message dynamicMessage =
927         dynamicDefaultInstance
928             .newBuilderForType()
929             .mergeFrom(message.toByteString(), ExtensionRegistry.getEmptyRegistry())
930             .build();
931 
932     assertThat(dynamicMessage).isEqualTo(message);
933     assertThat(dynamicMessage.hashCode()).isEqualTo(message.hashCode());
934   }
935 
936   // Check that DynamicMessage handles map field serialization the same way as generated code
937   // regarding unset key and value field in a map entry.
938   @Test
testDynamicMessageUnsetKeyAndValue()939   public void testDynamicMessageUnsetKeyAndValue() throws Exception {
940     FieldDescriptor field = f("int32_to_int32_field");
941 
942     Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
943     Message.Builder builder = dynamicDefaultInstance.newBuilderForType();
944     // Add an entry without key and value.
945     builder.addRepeatedField(field, builder.newBuilderForField(field).build());
946     Message message = builder.build();
947     ByteString bytes = message.toByteString();
948     // Parse it back to the same generated type.
949     Message generatedMessage = TestMap.parseFrom(bytes, ExtensionRegistry.getEmptyRegistry());
950     // Assert the serialized bytes are equivalent.
951     assertThat(bytes).isEqualTo(generatedMessage.toByteString());
952   }
953 
954   @Test
testReflectionEqualsAndHashCode()955   public void testReflectionEqualsAndHashCode() throws Exception {
956     // Test that generated equals() and hashCode() will disregard the order
957     // of map entries when comparing/hashing map fields.
958 
959     // We use DynamicMessage to test reflection based equals()/hashCode().
960     Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
961     FieldDescriptor field = f("int32_to_int32_field");
962 
963     Message.Builder b1 = dynamicDefaultInstance.newBuilderForType();
964     b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 1, 2));
965     b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 3, 4));
966     b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 5, 6));
967     Message m1 = b1.build();
968 
969     Message.Builder b2 = dynamicDefaultInstance.newBuilderForType();
970     b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 5, 6));
971     b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 1, 2));
972     b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 3, 4));
973     Message m2 = b2.build();
974 
975     assertThat(m2).isEqualTo(m1);
976     assertThat(m2.hashCode()).isEqualTo(m1.hashCode());
977 
978     // Make sure we did compare map fields.
979     b2.setRepeatedField(field, 0, newMapEntry(b1, "int32_to_int32_field", 0, 0));
980     m2 = b2.build();
981     assertThat(m1).isNotEqualTo(m2);
982     // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
983     // to be different.
984   }
985 
986   @Test
987   @SuppressWarnings("ProtoNewBuilderMergeFrom")
testUnknownEnumValues()988   public void testUnknownEnumValues() throws Exception {
989     TestMap.Builder builder =
990         TestMap.newBuilder()
991             .putAllInt32ToEnumFieldValue(
992                 newMap(
993                     0, 0,
994                     1, 1,
995                     2, 1000)); // unknown value.
996     TestMap message = builder.build();
997 
998     assertThat(message.getInt32ToEnumFieldMap()).containsEntry(0, TestMap.EnumValue.FOO);
999     assertThat(message.getInt32ToEnumFieldMap()).containsEntry(1, TestMap.EnumValue.BAR);
1000     assertThat(message.getInt32ToEnumFieldMap()).containsEntry(2, TestMap.EnumValue.UNRECOGNIZED);
1001     assertThat(message.getInt32ToEnumFieldValueMap().get(2).intValue()).isEqualTo(1000);
1002 
1003     // Unknown enum values should be preserved after:
1004     //   1. Serialization and parsing.
1005     //   2. toBuild().
1006     //   3. mergeFrom().
1007     message = TestMap.parseFrom(message.toByteString(), ExtensionRegistry.getEmptyRegistry());
1008     assertThat(message.getInt32ToEnumFieldValueMap().get(2).intValue()).isEqualTo(1000);
1009     builder = message.toBuilder();
1010     assertThat(builder.getInt32ToEnumFieldValueMap().get(2).intValue()).isEqualTo(1000);
1011     builder = TestMap.newBuilder().mergeFrom(message);
1012     assertThat(builder.getInt32ToEnumFieldValueMap().get(2).intValue()).isEqualTo(1000);
1013 
1014     // hashCode()/equals() should take unknown enum values into account.
1015     builder.putAllInt32ToEnumFieldValue(newMap(2, 1001));
1016     TestMap message2 = builder.build();
1017     assertThat(message.hashCode()).isNotEqualTo(message2.hashCode());
1018     assertThat(message.equals(message2)).isFalse();
1019     // Unknown values will be converted to UNRECOGNIZED so the resulted enum map
1020     // should be the same.
1021     assertThat(message.getInt32ToEnumFieldMap()).isEqualTo(message2.getInt32ToEnumFieldMap());
1022   }
1023 
1024   @Test
testUnknownEnumValuesInReflectionApi()1025   public void testUnknownEnumValuesInReflectionApi() throws Exception {
1026     Descriptor descriptor = TestMap.getDescriptor();
1027     EnumDescriptor enumDescriptor = TestMap.EnumValue.getDescriptor();
1028     FieldDescriptor field = descriptor.findFieldByName("int32_to_enum_field");
1029 
1030     Map<Integer, Integer> data =
1031         newMap(
1032             0, 0,
1033             1, 1,
1034             2, 1000); // unknown value
1035 
1036     TestMap.Builder builder = TestMap.newBuilder().putAllInt32ToEnumFieldValue(data);
1037 
1038     // Try to read unknown enum values using reflection API.
1039     for (int i = 0; i < builder.getRepeatedFieldCount(field); i++) {
1040       Message mapEntry = (Message) builder.getRepeatedField(field, i);
1041       int key = ((Integer) getFieldValue(mapEntry, "key")).intValue();
1042       int value = ((EnumValueDescriptor) getFieldValue(mapEntry, "value")).getNumber();
1043       assertThat(value).isEqualTo(data.get(key).intValue());
1044       Message.Builder mapEntryBuilder = mapEntry.toBuilder();
1045       // Increase the value by 1.
1046       setFieldValue(
1047           mapEntryBuilder, "value", enumDescriptor.findValueByNumberCreatingIfUnknown(value + 1));
1048       builder.setRepeatedField(field, i, mapEntryBuilder.build());
1049     }
1050 
1051     // Verify that enum values have been successfully updated.
1052     TestMap message = builder.build();
1053     for (Map.Entry<Integer, Integer> entry : message.getInt32ToEnumFieldValueMap().entrySet()) {
1054       assertThat(entry.getValue().intValue()).isEqualTo(data.get(entry.getKey()) + 1);
1055     }
1056   }
1057 
1058   @Test
testIterationOrder()1059   public void testIterationOrder() throws Exception {
1060     TestMap.Builder builder = TestMap.newBuilder();
1061     setMapValuesUsingAccessors(builder);
1062     TestMap message = builder.build();
1063 
1064     assertThat(new ArrayList<>(message.getStringToInt32FieldMap().keySet()))
1065         .containsExactly("1", "2", "3")
1066         .inOrder();
1067   }
1068 
1069   @Test
testGetMap()1070   public void testGetMap() {
1071     TestMap.Builder builder = TestMap.newBuilder();
1072     setMapValuesUsingAccessors(builder);
1073     TestMap message = builder.build();
1074     assertThat(message.getStringToInt32FieldMap()).isEqualTo(message.getStringToInt32FieldMap());
1075     assertThat(message.getInt32ToBytesFieldMap()).isEqualTo(message.getInt32ToBytesFieldMap());
1076     assertThat(message.getInt32ToEnumFieldMap()).isEqualTo(message.getInt32ToEnumFieldMap());
1077     assertThat(message.getInt32ToEnumFieldValueMap())
1078         .isEqualTo(message.getInt32ToEnumFieldValueMap());
1079     assertThat(message.getInt32ToMessageFieldMap()).isEqualTo(message.getInt32ToMessageFieldMap());
1080   }
1081 
1082   @Test
testContains()1083   public void testContains() {
1084     TestMap.Builder builder = TestMap.newBuilder();
1085     setMapValuesUsingAccessors(builder);
1086     assertMapContainsSetValues(builder);
1087     assertMapContainsSetValues(builder.build());
1088   }
1089 
assertMapContainsSetValues(TestMapOrBuilder testMapOrBuilder)1090   private void assertMapContainsSetValues(TestMapOrBuilder testMapOrBuilder) {
1091     assertThat(testMapOrBuilder.containsInt32ToInt32Field(1)).isTrue();
1092     assertThat(testMapOrBuilder.containsInt32ToInt32Field(2)).isTrue();
1093     assertThat(testMapOrBuilder.containsInt32ToInt32Field(3)).isTrue();
1094     assertThat(testMapOrBuilder.containsInt32ToInt32Field(-1)).isFalse();
1095 
1096     assertThat(testMapOrBuilder.containsInt32ToStringField(1)).isTrue();
1097     assertThat(testMapOrBuilder.containsInt32ToStringField(2)).isTrue();
1098     assertThat(testMapOrBuilder.containsInt32ToStringField(3)).isTrue();
1099     assertThat(testMapOrBuilder.containsInt32ToStringField(-1)).isFalse();
1100 
1101     assertThat(testMapOrBuilder.containsInt32ToBytesField(1)).isTrue();
1102     assertThat(testMapOrBuilder.containsInt32ToBytesField(2)).isTrue();
1103     assertThat(testMapOrBuilder.containsInt32ToBytesField(3)).isTrue();
1104     assertThat(testMapOrBuilder.containsInt32ToBytesField(-1)).isFalse();
1105 
1106     assertThat(testMapOrBuilder.containsInt32ToEnumField(1)).isTrue();
1107     assertThat(testMapOrBuilder.containsInt32ToEnumField(2)).isTrue();
1108     assertThat(testMapOrBuilder.containsInt32ToEnumField(3)).isTrue();
1109     assertThat(testMapOrBuilder.containsInt32ToEnumField(-1)).isFalse();
1110 
1111     assertThat(testMapOrBuilder.containsInt32ToMessageField(1)).isTrue();
1112     assertThat(testMapOrBuilder.containsInt32ToMessageField(2)).isTrue();
1113     assertThat(testMapOrBuilder.containsInt32ToMessageField(3)).isTrue();
1114     assertThat(testMapOrBuilder.containsInt32ToMessageField(-1)).isFalse();
1115 
1116     assertThat(testMapOrBuilder.containsStringToInt32Field("1")).isTrue();
1117     assertThat(testMapOrBuilder.containsStringToInt32Field("2")).isTrue();
1118     assertThat(testMapOrBuilder.containsStringToInt32Field("3")).isTrue();
1119     assertThat(testMapOrBuilder.containsStringToInt32Field("-1")).isFalse();
1120   }
1121 
1122   @Test
testCount()1123   public void testCount() {
1124     TestMap.Builder builder = TestMap.newBuilder();
1125     assertMapCounts(0, builder);
1126 
1127     setMapValuesUsingAccessors(builder);
1128     assertMapCounts(3, builder);
1129 
1130     TestMap message = builder.build();
1131     assertMapCounts(3, message);
1132 
1133     builder = message.toBuilder().putInt32ToInt32Field(4, 44);
1134     assertThat(builder.getInt32ToInt32FieldCount()).isEqualTo(4);
1135     assertThat(builder.build().getInt32ToInt32FieldCount()).isEqualTo(4);
1136 
1137     // already present - should be unchanged
1138     builder.putInt32ToInt32Field(4, 44);
1139     assertThat(builder.getInt32ToInt32FieldCount()).isEqualTo(4);
1140   }
1141 
assertMapCounts(int expectedCount, TestMapOrBuilder testMapOrBuilder)1142   private void assertMapCounts(int expectedCount, TestMapOrBuilder testMapOrBuilder) {
1143     assertThat(testMapOrBuilder.getInt32ToInt32FieldCount()).isEqualTo(expectedCount);
1144     assertThat(testMapOrBuilder.getInt32ToStringFieldCount()).isEqualTo(expectedCount);
1145     assertThat(testMapOrBuilder.getInt32ToBytesFieldCount()).isEqualTo(expectedCount);
1146     assertThat(testMapOrBuilder.getInt32ToEnumFieldCount()).isEqualTo(expectedCount);
1147     assertThat(testMapOrBuilder.getInt32ToMessageFieldCount()).isEqualTo(expectedCount);
1148     assertThat(testMapOrBuilder.getStringToInt32FieldCount()).isEqualTo(expectedCount);
1149   }
1150 
1151   @Test
testGetOrDefault()1152   public void testGetOrDefault() {
1153     TestMap.Builder builder = TestMap.newBuilder();
1154     assertMapCounts(0, builder);
1155     setMapValuesUsingAccessors(builder);
1156     doTestGetOrDefault(builder);
1157     doTestGetOrDefault(builder.build());
1158   }
1159 
doTestGetOrDefault(TestMapOrBuilder testMapOrBuilder)1160   public void doTestGetOrDefault(TestMapOrBuilder testMapOrBuilder) {
1161     assertThat(testMapOrBuilder.getInt32ToInt32FieldOrDefault(1, -11)).isEqualTo(11);
1162     assertThat(testMapOrBuilder.getInt32ToInt32FieldOrDefault(-1, -11)).isEqualTo(-11);
1163 
1164     assertThat(testMapOrBuilder.getInt32ToStringFieldOrDefault(1, "-11")).isEqualTo("11");
1165     assertWithMessage("-11")
1166         .that(testMapOrBuilder.getInt32ToStringFieldOrDefault(-1, null))
1167         .isNull();
1168 
1169     assertThat(testMapOrBuilder.getInt32ToBytesFieldOrDefault(1, null))
1170         .isEqualTo(TestUtil.toBytes("11"));
1171     assertThat(testMapOrBuilder.getInt32ToBytesFieldOrDefault(-1, null)).isNull();
1172 
1173     assertThat(testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null))
1174         .isEqualTo(TestMap.EnumValue.FOO);
1175     assertThat(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null)).isNull();
1176 
1177     assertThat(testMapOrBuilder.getInt32ToEnumFieldValueOrDefault(2, -1))
1178         .isEqualTo(TestMap.EnumValue.BAR.getNumber());
1179     assertThat(testMapOrBuilder.getInt32ToEnumFieldValueOrDefault(-1000, -1)).isEqualTo(-1);
1180 
1181     assertThat(testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null))
1182         .isEqualTo(MessageValue.newBuilder().setValue(11).build());
1183     assertThat(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null)).isNull();
1184 
1185     assertThat(testMapOrBuilder.getStringToInt32FieldOrDefault("1", -11)).isEqualTo(11);
1186     assertThat(testMapOrBuilder.getStringToInt32FieldOrDefault("-1", -11)).isEqualTo(-11);
1187 
1188     try {
1189       testMapOrBuilder.getStringToInt32FieldOrDefault(null, -11);
1190       assertWithMessage("expected exception").fail();
1191     } catch (NullPointerException e) {
1192       // expected
1193     }
1194   }
1195 
1196   @Test
testGetOrThrow()1197   public void testGetOrThrow() {
1198     TestMap.Builder builder = TestMap.newBuilder();
1199     assertMapCounts(0, builder);
1200     setMapValuesUsingAccessors(builder);
1201     doTestGetOrDefault(builder);
1202     doTestGetOrDefault(builder.build());
1203   }
1204 
doTestGetOrThrow(TestMapOrBuilder testMapOrBuilder)1205   public void doTestGetOrThrow(TestMapOrBuilder testMapOrBuilder) {
1206     assertThat(testMapOrBuilder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11);
1207     try {
1208       testMapOrBuilder.getInt32ToInt32FieldOrThrow(-1);
1209       assertWithMessage("expected exception").fail();
1210     } catch (IllegalArgumentException e) {
1211       // expected
1212     }
1213 
1214     assertThat(testMapOrBuilder.getInt32ToStringFieldOrThrow(1)).isEqualTo("11");
1215 
1216     try {
1217       testMapOrBuilder.getInt32ToStringFieldOrThrow(-1);
1218       assertWithMessage("expected exception").fail();
1219     } catch (IllegalArgumentException e) {
1220       // expected
1221     }
1222 
1223     assertThat(testMapOrBuilder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11"));
1224 
1225     try {
1226       testMapOrBuilder.getInt32ToBytesFieldOrThrow(-1);
1227       assertWithMessage("expected exception").fail();
1228     } catch (IllegalArgumentException e) {
1229       // expected
1230     }
1231 
1232     assertThat(testMapOrBuilder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO);
1233     try {
1234       testMapOrBuilder.getInt32ToEnumFieldOrThrow(-1);
1235       assertWithMessage("expected exception").fail();
1236     } catch (IllegalArgumentException e) {
1237       // expected
1238     }
1239 
1240     assertThat(testMapOrBuilder.getInt32ToEnumFieldValueOrThrow(2))
1241         .isEqualTo(TestMap.EnumValue.BAR.getNumber());
1242     try {
1243       testMapOrBuilder.getInt32ToEnumFieldValueOrThrow(-1);
1244       assertWithMessage("expected exception").fail();
1245     } catch (IllegalArgumentException e) {
1246       // expected
1247     }
1248 
1249     assertThat(testMapOrBuilder.getInt32ToMessageFieldOrThrow(1))
1250         .isEqualTo(MessageValue.newBuilder().setValue(11).build());
1251     try {
1252       testMapOrBuilder.getInt32ToMessageFieldOrThrow(-1);
1253       assertWithMessage("expected exception").fail();
1254     } catch (IllegalArgumentException e) {
1255       // expected
1256     }
1257 
1258     assertThat(testMapOrBuilder.getStringToInt32FieldOrThrow("1")).isEqualTo(11);
1259     try {
1260       testMapOrBuilder.getStringToInt32FieldOrThrow("-1");
1261       assertWithMessage("expected exception").fail();
1262     } catch (IllegalArgumentException e) {
1263       // expected
1264     }
1265 
1266     try {
1267       testMapOrBuilder.getStringToInt32FieldOrThrow(null);
1268       assertWithMessage("expected exception").fail();
1269     } catch (NullPointerException e) {
1270       // expected
1271     }
1272   }
1273 
1274   @Test
testPut()1275   public void testPut() {
1276     TestMap.Builder builder = TestMap.newBuilder();
1277     builder.putInt32ToInt32Field(1, 11);
1278     assertThat(builder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11);
1279 
1280     builder.putInt32ToStringField(1, "a");
1281     assertThat(builder.getInt32ToStringFieldOrThrow(1)).isEqualTo("a");
1282     try {
1283       builder.putInt32ToStringField(1, null);
1284       assertWithMessage("expected exception").fail();
1285     } catch (NullPointerException e) {
1286       // expected
1287     }
1288 
1289     builder.putInt32ToBytesField(1, TestUtil.toBytes("11"));
1290     assertThat(builder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11"));
1291     try {
1292       builder.putInt32ToBytesField(1, null);
1293       assertWithMessage("expected exception").fail();
1294     } catch (NullPointerException e) {
1295       // expected
1296     }
1297 
1298     builder.putInt32ToEnumField(1, TestMap.EnumValue.FOO);
1299     assertThat(builder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO);
1300     try {
1301       builder.putInt32ToEnumField(1, null);
1302       assertWithMessage("expected exception").fail();
1303     } catch (NullPointerException e) {
1304       // expected
1305     }
1306 
1307     builder.putInt32ToEnumFieldValue(1, TestMap.EnumValue.BAR.getNumber());
1308     assertThat(builder.getInt32ToEnumFieldValueOrThrow(1))
1309         .isEqualTo(TestMap.EnumValue.BAR.getNumber());
1310     builder.putInt32ToEnumFieldValue(1, -1);
1311     assertThat(builder.getInt32ToEnumFieldValueOrThrow(1)).isEqualTo(-1);
1312     assertThat(builder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.UNRECOGNIZED);
1313 
1314     builder.putStringToInt32Field("a", 1);
1315     assertThat(builder.getStringToInt32FieldOrThrow("a")).isEqualTo(1);
1316     try {
1317       builder.putStringToInt32Field(null, -1);
1318     } catch (NullPointerException e) {
1319       // expected
1320     }
1321   }
1322 
1323   @Test
testRemove()1324   public void testRemove() {
1325     TestMap.Builder builder = TestMap.newBuilder();
1326     setMapValuesUsingAccessors(builder);
1327     assertThat(builder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11);
1328     for (int times = 0; times < 2; times++) {
1329       builder.removeInt32ToInt32Field(1);
1330       assertThat(builder.getInt32ToInt32FieldOrDefault(1, -1)).isEqualTo(-1);
1331     }
1332 
1333     assertThat(builder.getInt32ToStringFieldOrThrow(1)).isEqualTo("11");
1334     for (int times = 0; times < 2; times++) {
1335       builder.removeInt32ToStringField(1);
1336       assertThat(builder.getInt32ToStringFieldOrDefault(1, null)).isNull();
1337     }
1338 
1339     assertThat(builder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11"));
1340     for (int times = 0; times < 2; times++) {
1341       builder.removeInt32ToBytesField(1);
1342       assertThat(builder.getInt32ToBytesFieldOrDefault(1, null)).isNull();
1343     }
1344 
1345     assertThat(builder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO);
1346     for (int times = 0; times < 2; times++) {
1347       builder.removeInt32ToEnumField(1);
1348       assertThat(builder.getInt32ToEnumFieldOrDefault(1, null)).isNull();
1349     }
1350 
1351     assertThat(builder.getStringToInt32FieldOrThrow("1")).isEqualTo(11);
1352     for (int times = 0; times < 2; times++) {
1353       builder.removeStringToInt32Field("1");
1354       assertThat(builder.getStringToInt32FieldOrDefault("1", -1)).isEqualTo(-1);
1355     }
1356 
1357     try {
1358       builder.removeStringToInt32Field(null);
1359       assertWithMessage("expected exception").fail();
1360     } catch (NullPointerException e) {
1361       // expected
1362     }
1363   }
1364 
1365   @Test
testReservedWordsFieldNames()1366   public void testReservedWordsFieldNames() {
1367     ReservedAsMapField unused1 = ReservedAsMapField.getDefaultInstance();
1368     ReservedAsMapFieldWithEnumValue unused2 = ReservedAsMapFieldWithEnumValue.getDefaultInstance();
1369   }
1370 
1371   @Test
testDeterministicSerialization()1372   public void testDeterministicSerialization() throws Exception {
1373     TestMap.Builder builder = TestMap.newBuilder();
1374     // int32->int32
1375     builder.putInt32ToInt32Field(5, 1);
1376     builder.putInt32ToInt32Field(1, 1);
1377     builder.putInt32ToInt32Field(4, 1);
1378     builder.putInt32ToInt32Field(-2, 1);
1379     builder.putInt32ToInt32Field(0, 1);
1380 
1381     // uint32->int32
1382     builder.putUint32ToInt32Field(5, 1);
1383     builder.putUint32ToInt32Field(1, 1);
1384     builder.putUint32ToInt32Field(4, 1);
1385     builder.putUint32ToInt32Field(-2, 1);
1386     builder.putUint32ToInt32Field(0, 1);
1387 
1388     // int64->int32
1389     builder.putInt64ToInt32Field(5L, 1);
1390     builder.putInt64ToInt32Field(1L, 1);
1391     builder.putInt64ToInt32Field(4L, 1);
1392     builder.putInt64ToInt32Field(-2L, 1);
1393     builder.putInt64ToInt32Field(0L, 1);
1394 
1395     // string->int32
1396     builder.putStringToInt32Field("baz", 1);
1397     builder.putStringToInt32Field("foo", 1);
1398     builder.putStringToInt32Field("bar", 1);
1399     builder.putStringToInt32Field("", 1);
1400     builder.putStringToInt32Field("hello", 1);
1401     builder.putStringToInt32Field("world", 1);
1402 
1403     TestMap message = builder.build();
1404     byte[] serialized = new byte[message.getSerializedSize()];
1405     CodedOutputStream output = CodedOutputStream.newInstance(serialized);
1406     output.useDeterministicSerialization();
1407     message.writeTo(output);
1408     output.flush();
1409 
1410     CodedInputStream input = CodedInputStream.newInstance(serialized);
1411     List<Integer> int32Keys = new ArrayList<>();
1412     List<Integer> uint32Keys = new ArrayList<>();
1413     List<Long> int64Keys = new ArrayList<>();
1414     List<String> stringKeys = new ArrayList<>();
1415     int tag;
1416     while (true) {
1417       tag = input.readTag();
1418       if (tag == 0) {
1419         break;
1420       }
1421       int length = input.readRawVarint32();
1422       int oldLimit = input.pushLimit(length);
1423       switch (WireFormat.getTagFieldNumber(tag)) {
1424         case TestMap.STRING_TO_INT32_FIELD_FIELD_NUMBER:
1425           stringKeys.add(readMapStringKey(input));
1426           break;
1427         case TestMap.INT32_TO_INT32_FIELD_FIELD_NUMBER:
1428           int32Keys.add(readMapIntegerKey(input));
1429           break;
1430         case TestMap.UINT32_TO_INT32_FIELD_FIELD_NUMBER:
1431           uint32Keys.add(readMapIntegerKey(input));
1432           break;
1433         case TestMap.INT64_TO_INT32_FIELD_FIELD_NUMBER:
1434           int64Keys.add(readMapLongKey(input));
1435           break;
1436         default:
1437           assertWithMessage("Unexpected fields.").fail();
1438       }
1439       input.popLimit(oldLimit);
1440     }
1441     assertThat(int32Keys).containsExactly(-2, 0, 1, 4, 5).inOrder();
1442     assertThat(uint32Keys).containsExactly(-2, 0, 1, 4, 5).inOrder();
1443     assertThat(int64Keys).containsExactly(-2L, 0L, 1L, 4L, 5L).inOrder();
1444     assertThat(stringKeys).containsExactly("", "bar", "baz", "foo", "hello", "world").inOrder();
1445   }
1446 
1447   @Test
testInitFromPartialDynamicMessage()1448   public void testInitFromPartialDynamicMessage() {
1449     FieldDescriptor fieldDescriptor =
1450         TestMap.getDescriptor().findFieldByNumber(TestMap.INT32_TO_MESSAGE_FIELD_FIELD_NUMBER);
1451     Descriptor mapEntryType = fieldDescriptor.getMessageType();
1452     FieldDescriptor keyField = mapEntryType.findFieldByNumber(1);
1453     FieldDescriptor valueField = mapEntryType.findFieldByNumber(2);
1454     DynamicMessage dynamicMessage =
1455         DynamicMessage.newBuilder(TestMap.getDescriptor())
1456             .addRepeatedField(
1457                 fieldDescriptor,
1458                 DynamicMessage.newBuilder(mapEntryType)
1459                     .setField(keyField, 10)
1460                     .setField(valueField, TestMap.MessageValue.newBuilder().setValue(10).build())
1461                     .build())
1462             .build();
1463     TestMap message = TestMap.newBuilder().mergeFrom(dynamicMessage).build();
1464     assertThat(message.getInt32ToMessageFieldMap())
1465         .containsEntry(10, TestMap.MessageValue.newBuilder().setValue(10).build());
1466   }
1467 
1468   @Test
testInitFromFullyDynamicMessage()1469   public void testInitFromFullyDynamicMessage() {
1470     FieldDescriptor fieldDescriptor =
1471         TestMap.getDescriptor().findFieldByNumber(TestMap.INT32_TO_MESSAGE_FIELD_FIELD_NUMBER);
1472     Descriptor mapEntryType = fieldDescriptor.getMessageType();
1473     FieldDescriptor keyField = mapEntryType.findFieldByNumber(1);
1474     FieldDescriptor valueField = mapEntryType.findFieldByNumber(2);
1475     DynamicMessage dynamicMessage =
1476         DynamicMessage.newBuilder(TestMap.getDescriptor())
1477             .addRepeatedField(
1478                 fieldDescriptor,
1479                 DynamicMessage.newBuilder(mapEntryType)
1480                     .setField(keyField, 10)
1481                     .setField(
1482                         valueField,
1483                         DynamicMessage.newBuilder(TestMap.MessageValue.getDescriptor())
1484                             .setField(
1485                                 TestMap.MessageValue.getDescriptor().findFieldByName("value"), 10)
1486                             .build())
1487                     .build())
1488             .build();
1489     TestMap message = TestMap.newBuilder().mergeFrom(dynamicMessage).build();
1490     assertThat(message.getInt32ToMessageFieldMap())
1491         .containsEntry(10, TestMap.MessageValue.newBuilder().setValue(10).build());
1492   }
1493 
readMapIntegerKey(CodedInputStream input)1494   private int readMapIntegerKey(CodedInputStream input) throws IOException {
1495     int tag = input.readTag();
1496     assertThat(tag).isEqualTo(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT));
1497     int ret = input.readInt32();
1498     // skip the value field.
1499     input.skipField(input.readTag());
1500     assertThat(input.isAtEnd()).isTrue();
1501     return ret;
1502   }
1503 
readMapLongKey(CodedInputStream input)1504   private long readMapLongKey(CodedInputStream input) throws IOException {
1505     int tag = input.readTag();
1506     assertThat(tag).isEqualTo(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT));
1507     long ret = input.readInt64();
1508     // skip the value field.
1509     input.skipField(input.readTag());
1510     assertThat(input.isAtEnd()).isTrue();
1511     return ret;
1512   }
1513 
readMapStringKey(CodedInputStream input)1514   private String readMapStringKey(CodedInputStream input) throws IOException {
1515     int tag = input.readTag();
1516     assertThat(tag).isEqualTo(WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED));
1517     String ret = input.readString();
1518     // skip the value field.
1519     input.skipField(input.readTag());
1520     assertThat(input.isAtEnd()).isTrue();
1521     return ret;
1522   }
1523 
newMap(K key1, V value1)1524   private static <K, V> Map<K, V> newMap(K key1, V value1) {
1525     Map<K, V> map = new HashMap<>();
1526     map.put(key1, value1);
1527     return map;
1528   }
1529 
newMap(K key1, V value1, K key2, V value2)1530   private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
1531     Map<K, V> map = new HashMap<>();
1532     map.put(key1, value1);
1533     map.put(key2, value2);
1534     return map;
1535   }
1536 
newMap(K key1, V value1, K key2, V value2, K key3, V value3)1537   private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2, K key3, V value3) {
1538     Map<K, V> map = new HashMap<>();
1539     map.put(key1, value1);
1540     map.put(key2, value2);
1541     map.put(key3, value3);
1542     return map;
1543   }
1544 
1545   @Test
testMap_withNulls()1546   public void testMap_withNulls() {
1547     TestMap.Builder builder = TestMap.newBuilder();
1548 
1549     try {
1550       builder.putStringToInt32Field(null, 3);
1551       assertWithMessage("expected exception").fail();
1552     } catch (NullPointerException expected) {
1553     }
1554 
1555     try {
1556       builder.putAllStringToInt32Field(newMap(null, 3, "hi", 4));
1557       assertWithMessage("expected exception").fail();
1558     } catch (NullPointerException expected) {
1559     }
1560 
1561     try {
1562       builder.putInt32ToMessageField(3, null);
1563       assertWithMessage("expected exception").fail();
1564     } catch (NullPointerException expected) {
1565     }
1566 
1567     try {
1568       builder.putAllInt32ToMessageField(MapTest.<Integer, MessageValue>newMap(4, null, 5, null));
1569       assertWithMessage("expected exception").fail();
1570     } catch (NullPointerException expected) {
1571     }
1572 
1573     try {
1574       builder.putAllInt32ToMessageField(null);
1575       assertWithMessage("expected exception").fail();
1576     } catch (NullPointerException expected) {
1577     }
1578 
1579     assertThat(builder.build().toByteArray()).isEqualTo(new byte[0]);
1580   }
1581 
1582   @Test
1583   // https://github.com/protocolbuffers/protobuf/issues/9785
testContainer()1584   public void testContainer() {
1585     FieldDescriptor field = MapContainer.getDescriptor().findFieldByName("my_map");
1586     Descriptor entryDescriptor = field.getMessageType();
1587     FieldDescriptor valueDescriptor = entryDescriptor.findFieldByName("value");
1588     Message.Builder builder = MapContainer.newBuilder().newBuilderForField(field);
1589     try {
1590       builder.setField(valueDescriptor, null);
1591       fail("Allowed null field value");
1592     } catch (NullPointerException expected) {
1593       assertThat(expected).hasMessageThat().isNotNull();
1594     }
1595   }
1596 
1597   @Test
getAllFields_mapEntryListMutability()1598   public void getAllFields_mapEntryListMutability() {
1599     TestMap testMap =
1600         TestMap.newBuilder()
1601             .putInt32ToInt32Field(1, 11)
1602             .putInt32ToInt32Field(2, 22)
1603             .putInt32ToMessageField(1, TestMap.MessageValue.newBuilder().setValue(111).build())
1604             .build();
1605     FieldDescriptor int2IntMapField =
1606         TestMap.getDescriptor().findFieldByNumber(TestMap.INT32_TO_INT32_FIELD_FIELD_NUMBER);
1607     FieldDescriptor int2MessageMapField =
1608         TestMap.getDescriptor().findFieldByNumber(TestMap.INT32_TO_MESSAGE_FIELD_FIELD_NUMBER);
1609     Map<FieldDescriptor, Object> allFields = testMap.getAllFields();
1610     List<?> mapEntries = (List<?>) allFields.get(int2IntMapField);
1611     assertThat(mapEntries).hasSize(2);
1612     assertThrows(UnsupportedOperationException.class, mapEntries::clear);
1613     mapEntries = (List<?>) allFields.get(int2MessageMapField);
1614     assertThat(mapEntries).hasSize(1);
1615     assertThrows(UnsupportedOperationException.class, mapEntries::clear);
1616 
1617     TestMap.Builder builder = testMap.toBuilder();
1618     allFields = builder.getAllFields();
1619     mapEntries = (List<?>) allFields.get(int2IntMapField);
1620     assertThat(mapEntries).hasSize(2);
1621     assertThrows(UnsupportedOperationException.class, mapEntries::clear);
1622     builder.clearField(int2IntMapField);
1623     assertThat(mapEntries).hasSize(2);
1624     mapEntries = (List<?>) allFields.get(int2MessageMapField);
1625     assertThat(mapEntries).hasSize(1);
1626     assertThrows(UnsupportedOperationException.class, mapEntries::clear);
1627     builder.clearField(int2MessageMapField);
1628     assertThat(mapEntries).hasSize(1);
1629   }
1630 }
1631