• 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.fail;
14 
15 import com.google.protobuf.Descriptors.FieldDescriptor;
16 import map_test.MapForProto2TestProto.BizarroTestMap;
17 import map_test.MapForProto2TestProto.ReservedAsMapField;
18 import map_test.MapForProto2TestProto.ReservedAsMapFieldWithEnumValue;
19 import map_test.MapForProto2TestProto.TestMap;
20 import map_test.MapForProto2TestProto.TestMap.MessageValue;
21 import map_test.MapForProto2TestProto.TestMap.MessageWithRequiredFields;
22 import map_test.MapForProto2TestProto.TestMapOrBuilder;
23 import map_test.MapForProto2TestProto.TestRecursiveMap;
24 import map_test.MapForProto2TestProto.TestUnknownEnumValue;
25 import map_test.Message1;
26 import map_test.RedactAllTypes;
27 import java.io.ByteArrayOutputStream;
28 import java.io.IOException;
29 import java.util.ArrayList;
30 import java.util.HashMap;
31 import java.util.LinkedHashMap;
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 in proto2 protos. */
40 @RunWith(JUnit4.class)
41 public class MapForProto2Test {
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(TestMapOrBuilder message)119   private void assertMapValuesSet(TestMapOrBuilder 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())
334             .isEqualTo(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.getMutableInt32ToStringField().put(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 
newMap(K key1, V value1)411   private static <K, V> Map<K, V> newMap(K key1, V value1) {
412     Map<K, V> map = new HashMap<K, V>();
413     map.put(key1, value1);
414     return map;
415   }
416 
newMap(K key1, V value1, K key2, V value2)417   private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
418     Map<K, V> map = new HashMap<K, V>();
419     map.put(key1, value1);
420     map.put(key2, value2);
421     return map;
422   }
423 
424   @Test
testGettersAndSetters()425   public void testGettersAndSetters() throws Exception {
426     TestMap.Builder builder = TestMap.newBuilder();
427     TestMap message = builder.build();
428     assertMapValuesCleared(message);
429 
430     builder = message.toBuilder();
431     setMapValuesUsingAccessors(builder);
432     message = builder.build();
433     assertMapValuesSet(message);
434 
435     builder = message.toBuilder();
436     updateMapValuesUsingAccessors(builder);
437     message = builder.build();
438     assertMapValuesUpdated(message);
439 
440     builder = message.toBuilder();
441     builder.clear();
442     assertMapValuesCleared(builder);
443     message = builder.build();
444     assertMapValuesCleared(message);
445   }
446 
447   @Test
testPutAll()448   public void testPutAll() throws Exception {
449     TestMap.Builder sourceBuilder = TestMap.newBuilder();
450     setMapValuesUsingAccessors(sourceBuilder);
451     TestMap source = sourceBuilder.build();
452     assertMapValuesSet(source);
453 
454     TestMap.Builder destination = TestMap.newBuilder();
455     copyMapValues(source, destination);
456     assertMapValuesSet(destination.build());
457 
458     assertThat(destination.getInt32ToEnumFieldCount()).isEqualTo(3);
459   }
460 
461   @Test
testPutChecksNullValues()462   public void testPutChecksNullValues() throws Exception {
463     TestMap.Builder builder = TestMap.newBuilder();
464 
465     try {
466       builder.putInt32ToBytesField(1, null);
467       assertWithMessage("expected exception").fail();
468     } catch (NullPointerException e) {
469       // expected.
470     }
471 
472     try {
473       builder.putInt32ToEnumField(1, null);
474       assertWithMessage("expected exception").fail();
475     } catch (NullPointerException e) {
476       // expected.
477     }
478 
479     try {
480       builder.putInt32ToMessageField(1, null);
481       assertWithMessage("expected exception").fail();
482     } catch (NullPointerException e) {
483       // expected.
484     }
485 
486     try {
487       builder.putStringToInt32Field(null, 1);
488       assertWithMessage("expected exception").fail();
489     } catch (NullPointerException e) {
490       // expected.
491     }
492   }
493 
494   @Test
testPutChecksNullKey()495   public void testPutChecksNullKey() throws Exception {
496     TestMap.Builder builder = TestMap.newBuilder();
497 
498     try {
499       builder.putStringToInt32Field(null, 1);
500       assertWithMessage("expected exception").fail();
501     } catch (NullPointerException expected) {
502     }
503   }
504 
505   @Test
testSerializeAndParse()506   public void testSerializeAndParse() throws Exception {
507     TestMap.Builder builder = TestMap.newBuilder();
508     setMapValuesUsingAccessors(builder);
509     TestMap message = builder.build();
510     assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize());
511     message = TestMap.parseFrom(message.toByteString());
512     assertMapValuesSet(message);
513 
514     builder = message.toBuilder();
515     updateMapValuesUsingAccessors(builder);
516     message = builder.build();
517     assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize());
518     message = TestMap.parseFrom(message.toByteString());
519     assertMapValuesUpdated(message);
520 
521     builder = message.toBuilder();
522     builder.clear();
523     message = builder.build();
524     assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize());
525     message = TestMap.parseFrom(message.toByteString());
526     assertMapValuesCleared(message);
527   }
528 
tryParseTestMap(BizarroTestMap bizarroMap)529   private TestMap tryParseTestMap(BizarroTestMap bizarroMap) throws IOException {
530     ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
531     CodedOutputStream output = CodedOutputStream.newInstance(byteArrayOutputStream);
532     bizarroMap.writeTo(output);
533     output.flush();
534     return TestMap.parseFrom(ByteString.copyFrom(byteArrayOutputStream.toByteArray()));
535   }
536 
537   @Test
testParseError()538   public void testParseError() throws Exception {
539     ByteString bytes = TestUtil.toBytes("SOME BYTES");
540     String stringKey = "a string key";
541 
542     TestMap map =
543         tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToInt32Field(5, bytes).build());
544     assertThat(map.getInt32ToInt32FieldOrDefault(5, -1)).isEqualTo(0);
545 
546     map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToStringField(stringKey, 5).build());
547     assertThat(map.getInt32ToStringFieldOrDefault(0, null)).isEmpty();
548 
549     map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToBytesField(stringKey, 5).build());
550     assertThat(ByteString.EMPTY).isEqualTo(map.getInt32ToBytesFieldOrDefault(0, null));
551 
552     map =
553         tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToEnumField(stringKey, bytes).build());
554     assertThat(map.getInt32ToEnumFieldOrDefault(0, null)).isEqualTo(TestMap.EnumValue.FOO);
555 
556     try {
557       tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToMessageField(stringKey, bytes).build());
558       assertWithMessage("expected exception").fail();
559     } catch (InvalidProtocolBufferException expected) {
560       assertThat(expected.getUnfinishedMessage()).isInstanceOf(TestMap.class);
561       map = (TestMap) expected.getUnfinishedMessage();
562       assertThat(map.getInt32ToMessageFieldMap()).isEmpty();
563     }
564 
565     map =
566         tryParseTestMap(
567             BizarroTestMap.newBuilder().putStringToInt32Field(stringKey, bytes).build());
568     assertThat(map.getStringToInt32FieldOrDefault(stringKey, -1)).isEqualTo(0);
569   }
570 
571   @Test
testMergeFrom()572   public void testMergeFrom() throws Exception {
573     TestMap.Builder builder = TestMap.newBuilder();
574     setMapValuesUsingAccessors(builder);
575     TestMap message = builder.build();
576 
577     TestMap.Builder other = TestMap.newBuilder();
578     other.mergeFrom(message);
579     assertMapValuesSet(other.build());
580   }
581 
582   @Test
testEqualsAndHashCode()583   public void testEqualsAndHashCode() throws Exception {
584     // Test that generated equals() and hashCode() will disregard the order
585     // of map entries when comparing/hashing map fields.
586 
587     // We can't control the order of elements in a HashMap. The best we can do
588     // here is to add elements in different order.
589     TestMap.Builder b1 = TestMap.newBuilder();
590     b1.putInt32ToInt32Field(1, 2);
591     b1.putInt32ToInt32Field(3, 4);
592     b1.putInt32ToInt32Field(5, 6);
593     TestMap m1 = b1.build();
594 
595     TestMap.Builder b2 = TestMap.newBuilder();
596     b2.putInt32ToInt32Field(5, 6);
597     b2.putInt32ToInt32Field(1, 2);
598     b2.putInt32ToInt32Field(3, 4);
599     TestMap m2 = b2.build();
600 
601     assertThat(m2).isEqualTo(m1);
602     assertThat(m2.hashCode()).isEqualTo(m1.hashCode());
603 
604     // Make sure we did compare map fields.
605     b2.putInt32ToInt32Field(1, 0);
606     m2 = b2.build();
607     assertThat(m1.equals(m2)).isFalse();
608     // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
609     // to be different.
610   }
611 
612   // The following methods are used to test reflection API.
613 
f(String name)614   private static FieldDescriptor f(String name) {
615     return TestMap.getDescriptor().findFieldByName(name);
616   }
617 
getFieldValue(Message mapEntry, String name)618   private static Object getFieldValue(Message mapEntry, String name) {
619     FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name);
620     return mapEntry.getField(field);
621   }
622 
setFieldValue( Message.Builder mapEntry, String name, Object value)623   private static Message.Builder setFieldValue(
624       Message.Builder mapEntry, String name, Object value) {
625     FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name);
626     mapEntry.setField(field, value);
627     return mapEntry;
628   }
629 
assertHasMapValues(Message message, String name, Map<?, ?> values)630   private static void assertHasMapValues(Message message, String name, Map<?, ?> values) {
631     FieldDescriptor field = f(name);
632     for (Object entry : (List<?>) message.getField(field)) {
633       Message mapEntry = (Message) entry;
634       Object key = getFieldValue(mapEntry, "key");
635       Object value = getFieldValue(mapEntry, "value");
636       assertThat(values.containsKey(key)).isTrue();
637       assertThat(values.get(key)).isEqualTo(value);
638     }
639     assertThat(message.getRepeatedFieldCount(field)).isEqualTo(values.size());
640     for (int i = 0; i < message.getRepeatedFieldCount(field); i++) {
641       Message mapEntry = (Message) message.getRepeatedField(field, i);
642       Object key = getFieldValue(mapEntry, "key");
643       Object value = getFieldValue(mapEntry, "value");
644       assertThat(values.containsKey(key)).isTrue();
645       assertThat(values.get(key)).isEqualTo(value);
646     }
647   }
648 
newMapEntry(Message.Builder builder, String name, K key, V value)649   private static <K, V> Message newMapEntry(Message.Builder builder, String name, K key, V value) {
650     FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name);
651     Message.Builder entryBuilder = builder.newBuilderForField(field);
652     FieldDescriptor keyField = entryBuilder.getDescriptorForType().findFieldByName("key");
653     FieldDescriptor valueField = entryBuilder.getDescriptorForType().findFieldByName("value");
654     entryBuilder.setField(keyField, key);
655     entryBuilder.setField(valueField, value);
656     return entryBuilder.build();
657   }
658 
setMapValues(Message.Builder builder, String name, Map<?, ?> values)659   private static void setMapValues(Message.Builder builder, String name, Map<?, ?> values) {
660     List<Message> entryList = new ArrayList<>();
661     for (Map.Entry<?, ?> entry : values.entrySet()) {
662       entryList.add(newMapEntry(builder, name, entry.getKey(), entry.getValue()));
663     }
664     FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name);
665     builder.setField(field, entryList);
666   }
667 
mapForValues(K key1, V value1, K key2, V value2)668   private static <K, V> Map<K, V> mapForValues(K key1, V value1, K key2, V value2) {
669     Map<K, V> map = new HashMap<>();
670     map.put(key1, value1);
671     map.put(key2, value2);
672     return map;
673   }
674 
675   @Test
testReflectionApi()676   public void testReflectionApi() throws Exception {
677     // In reflection API, map fields are just repeated message fields.
678     TestMap.Builder builder =
679         TestMap.newBuilder()
680             .putInt32ToInt32Field(1, 2)
681             .putInt32ToInt32Field(3, 4)
682             .putInt32ToMessageField(11, MessageValue.newBuilder().setValue(22).build())
683             .putInt32ToMessageField(33, MessageValue.newBuilder().setValue(44).build());
684     TestMap message = builder.build();
685 
686     // Test getField(), getRepeatedFieldCount(), getRepeatedField().
687     assertHasMapValues(message, "int32_to_int32_field", mapForValues(1, 2, 3, 4));
688     assertHasMapValues(
689         message,
690         "int32_to_message_field",
691         mapForValues(
692             11, MessageValue.newBuilder().setValue(22).build(),
693             33, MessageValue.newBuilder().setValue(44).build()));
694 
695     // Test clearField()
696     builder.clearField(f("int32_to_int32_field"));
697     builder.clearField(f("int32_to_message_field"));
698     message = builder.build();
699     assertThat(message.getInt32ToInt32FieldMap()).isEmpty();
700     assertThat(message.getInt32ToMessageFieldMap()).isEmpty();
701 
702     // Test setField()
703     setMapValues(builder, "int32_to_int32_field", mapForValues(11, 22, 33, 44));
704     setMapValues(
705         builder,
706         "int32_to_message_field",
707         mapForValues(
708             111, MessageValue.newBuilder().setValue(222).build(),
709             333, MessageValue.newBuilder().setValue(444).build()));
710     message = builder.build();
711     assertThat(message.getInt32ToInt32FieldMap().get(11).intValue()).isEqualTo(22);
712     assertThat(message.getInt32ToInt32FieldMap().get(33).intValue()).isEqualTo(44);
713     assertThat(message.getInt32ToMessageFieldMap().get(111).getValue()).isEqualTo(222);
714     assertThat(message.getInt32ToMessageFieldMap().get(333).getValue()).isEqualTo(444);
715 
716     // Test addRepeatedField
717     builder.addRepeatedField(
718         f("int32_to_int32_field"), newMapEntry(builder, "int32_to_int32_field", 55, 66));
719     builder.addRepeatedField(
720         f("int32_to_message_field"),
721         newMapEntry(
722             builder,
723             "int32_to_message_field",
724             555,
725             MessageValue.newBuilder().setValue(666).build()));
726     message = builder.build();
727     assertThat(message.getInt32ToInt32FieldMap().get(55).intValue()).isEqualTo(66);
728     assertThat(message.getInt32ToMessageFieldMap().get(555).getValue()).isEqualTo(666);
729 
730     // Test addRepeatedField (overriding existing values)
731     builder.addRepeatedField(
732         f("int32_to_int32_field"), newMapEntry(builder, "int32_to_int32_field", 55, 55));
733     builder.addRepeatedField(
734         f("int32_to_message_field"),
735         newMapEntry(
736             builder,
737             "int32_to_message_field",
738             555,
739             MessageValue.newBuilder().setValue(555).build()));
740     message = builder.build();
741     assertThat(message.getInt32ToInt32FieldMap().get(55).intValue()).isEqualTo(55);
742     assertThat(message.getInt32ToMessageFieldMap().get(555).getValue()).isEqualTo(555);
743 
744     // Test setRepeatedField
745     for (int i = 0; i < builder.getRepeatedFieldCount(f("int32_to_int32_field")); i++) {
746       Message mapEntry = (Message) builder.getRepeatedField(f("int32_to_int32_field"), i);
747       int oldKey = ((Integer) getFieldValue(mapEntry, "key")).intValue();
748       int oldValue = ((Integer) getFieldValue(mapEntry, "value")).intValue();
749       // Swap key with value for each entry.
750       Message.Builder mapEntryBuilder = mapEntry.toBuilder();
751       setFieldValue(mapEntryBuilder, "key", oldValue);
752       setFieldValue(mapEntryBuilder, "value", oldKey);
753       builder.setRepeatedField(f("int32_to_int32_field"), i, mapEntryBuilder.build());
754     }
755     message = builder.build();
756     assertThat(message.getInt32ToInt32FieldMap().get(22).intValue()).isEqualTo(11);
757     assertThat(message.getInt32ToInt32FieldMap().get(44).intValue()).isEqualTo(33);
758     assertThat(message.getInt32ToInt32FieldMap().get(55).intValue()).isEqualTo(55);
759   }
760 
761   // See additional coverage in TextFormatTest.java.
762   @Test
testTextFormat()763   public void testTextFormat() throws Exception {
764     TestMap.Builder builder = TestMap.newBuilder();
765     setMapValuesUsingAccessors(builder);
766     TestMap message = builder.build();
767 
768     String textData = TextFormat.printer().printToString(message);
769 
770     builder = TestMap.newBuilder();
771     TextFormat.merge(textData, builder);
772     message = builder.build();
773 
774     assertMapValuesSet(message);
775   }
776 
777   @Test
testDynamicMessage()778   public void testDynamicMessage() throws Exception {
779     TestMap.Builder builder = TestMap.newBuilder();
780     setMapValuesUsingAccessors(builder);
781     TestMap message = builder.build();
782 
783     Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
784     Message dynamicMessage =
785         dynamicDefaultInstance
786             .newBuilderForType()
787             .mergeFrom(message.toByteString(), ExtensionRegistry.getEmptyRegistry())
788             .build();
789 
790     assertThat(dynamicMessage).isEqualTo(message);
791     assertThat(dynamicMessage.hashCode()).isEqualTo(message.hashCode());
792   }
793 
794   // Check that DynamicMessage handles map field serialization the same way as generated code
795   // regarding unset key and value field in a map entry.
796   @Test
testDynamicMessageUnsetKeyAndValue()797   public void testDynamicMessageUnsetKeyAndValue() throws Exception {
798     FieldDescriptor field = f("int32_to_int32_field");
799 
800     Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
801     Message.Builder builder = dynamicDefaultInstance.newBuilderForType();
802     // Add an entry without key and value.
803     builder.addRepeatedField(field, builder.newBuilderForField(field).build());
804     Message message = builder.build();
805     ByteString bytes = message.toByteString();
806     // Parse it back to the same generated type.
807     Message generatedMessage = TestMap.parseFrom(bytes, ExtensionRegistry.getEmptyRegistry());
808     // Assert the serialized bytes are equivalent.
809     assertThat(bytes).isEqualTo(generatedMessage.toByteString());
810   }
811 
812   @Test
testReflectionEqualsAndHashCode()813   public void testReflectionEqualsAndHashCode() throws Exception {
814     // Test that generated equals() and hashCode() will disregard the order
815     // of map entries when comparing/hashing map fields.
816 
817     // We use DynamicMessage to test reflection based equals()/hashCode().
818     Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
819     FieldDescriptor field = f("int32_to_int32_field");
820 
821     Message.Builder b1 = dynamicDefaultInstance.newBuilderForType();
822     b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 1, 2));
823     b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 3, 4));
824     b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 5, 6));
825     Message m1 = b1.build();
826 
827     Message.Builder b2 = dynamicDefaultInstance.newBuilderForType();
828     b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 5, 6));
829     b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 1, 2));
830     b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 3, 4));
831     Message m2 = b2.build();
832 
833     assertThat(m2).isEqualTo(m1);
834     assertThat(m2.hashCode()).isEqualTo(m1.hashCode());
835 
836     // Make sure we did compare map fields.
837     b2.setRepeatedField(field, 0, newMapEntry(b1, "int32_to_int32_field", 0, 0));
838     m2 = b2.build();
839     assertThat(m1.equals(m2)).isFalse();
840     // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
841     // to be different.
842   }
843 
844   @Test
testUnknownEnumValues()845   public void testUnknownEnumValues() throws Exception {
846     TestUnknownEnumValue builder =
847         TestUnknownEnumValue.newBuilder()
848             .putInt32ToInt32Field(1, 1)
849             .putInt32ToInt32Field(2, 54321)
850             .build();
851     ByteString data = builder.toByteString();
852 
853     TestMap message = TestMap.parseFrom(data, ExtensionRegistry.getEmptyRegistry());
854     // Entries with unknown enum values will be stored into UnknownFieldSet so
855     // there is only one entry in the map.
856     assertThat(message.getInt32ToEnumFieldMap()).hasSize(1);
857     assertThat(message.getInt32ToEnumFieldMap()).containsEntry(1, TestMap.EnumValue.BAR);
858     // UnknownFieldSet should not be empty.
859     assertThat(message.getUnknownFields().asMap()).isNotEmpty();
860     // Serializing and parsing should preserve the unknown entry.
861     data = message.toByteString();
862     TestUnknownEnumValue messageWithUnknownEnums =
863         TestUnknownEnumValue.parseFrom(data, ExtensionRegistry.getEmptyRegistry());
864     assertThat(messageWithUnknownEnums.getInt32ToInt32FieldMap()).hasSize(2);
865     assertThat(messageWithUnknownEnums.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(1);
866     assertThat(messageWithUnknownEnums.getInt32ToInt32FieldMap().get(2).intValue())
867         .isEqualTo(54321);
868   }
869 
870   @Test
testRequiredMessage()871   public void testRequiredMessage() throws Exception {
872     TestMap.Builder builder = TestMap.newBuilder();
873     builder.putRequiredMessageMap(0, MessageWithRequiredFields.newBuilder().buildPartial());
874     TestMap message = builder.buildPartial();
875     assertThat(message.isInitialized()).isFalse();
876 
877     builder.putRequiredMessageMap(0, MessageWithRequiredFields.newBuilder().setValue(1).build());
878     message = builder.build();
879     assertThat(message.isInitialized()).isTrue();
880   }
881 
882   @Test
testRecursiveMap()883   public void testRecursiveMap() throws Exception {
884     TestRecursiveMap.Builder builder = TestRecursiveMap.newBuilder();
885     builder.putRecursiveMapField(1, TestRecursiveMap.newBuilder().setValue(2).build());
886     builder.putRecursiveMapField(3, TestRecursiveMap.newBuilder().setValue(4).build());
887     ByteString data = builder.build().toByteString();
888 
889     TestRecursiveMap message =
890         TestRecursiveMap.parseFrom(data, ExtensionRegistry.getEmptyRegistry());
891     assertThat(message.getRecursiveMapFieldMap().get(1).getValue()).isEqualTo(2);
892     assertThat(message.getRecursiveMapFieldMap().get(3).getValue()).isEqualTo(4);
893   }
894 
895   @Test
testIterationOrder()896   public void testIterationOrder() throws Exception {
897     TestMap.Builder builder = TestMap.newBuilder();
898     setMapValuesUsingAccessors(builder);
899     TestMap message = builder.build();
900 
901     assertThat(new ArrayList<String>(message.getStringToInt32FieldMap().keySet()))
902         .containsExactly("1", "2", "3")
903         .inOrder();
904   }
905 
906   @Test
testContains()907   public void testContains() {
908     TestMap.Builder builder = TestMap.newBuilder();
909     setMapValuesUsingAccessors(builder);
910     assertMapContainsSetValues(builder);
911     assertMapContainsSetValues(builder.build());
912   }
913 
assertMapContainsSetValues(TestMapOrBuilder testMapOrBuilder)914   private void assertMapContainsSetValues(TestMapOrBuilder testMapOrBuilder) {
915     assertThat(testMapOrBuilder.containsInt32ToInt32Field(1)).isTrue();
916     assertThat(testMapOrBuilder.containsInt32ToInt32Field(2)).isTrue();
917     assertThat(testMapOrBuilder.containsInt32ToInt32Field(3)).isTrue();
918     assertThat(testMapOrBuilder.containsInt32ToInt32Field(-1)).isFalse();
919 
920     assertThat(testMapOrBuilder.containsInt32ToStringField(1)).isTrue();
921     assertThat(testMapOrBuilder.containsInt32ToStringField(2)).isTrue();
922     assertThat(testMapOrBuilder.containsInt32ToStringField(3)).isTrue();
923     assertThat(testMapOrBuilder.containsInt32ToStringField(-1)).isFalse();
924 
925     assertThat(testMapOrBuilder.containsInt32ToBytesField(1)).isTrue();
926     assertThat(testMapOrBuilder.containsInt32ToBytesField(2)).isTrue();
927     assertThat(testMapOrBuilder.containsInt32ToBytesField(3)).isTrue();
928     assertThat(testMapOrBuilder.containsInt32ToBytesField(-1)).isFalse();
929 
930     assertThat(testMapOrBuilder.containsInt32ToEnumField(1)).isTrue();
931     assertThat(testMapOrBuilder.containsInt32ToEnumField(2)).isTrue();
932     assertThat(testMapOrBuilder.containsInt32ToEnumField(3)).isTrue();
933     assertThat(testMapOrBuilder.containsInt32ToEnumField(-1)).isFalse();
934 
935     assertThat(testMapOrBuilder.containsInt32ToMessageField(1)).isTrue();
936     assertThat(testMapOrBuilder.containsInt32ToMessageField(2)).isTrue();
937     assertThat(testMapOrBuilder.containsInt32ToMessageField(3)).isTrue();
938     assertThat(testMapOrBuilder.containsInt32ToMessageField(-1)).isFalse();
939 
940     assertThat(testMapOrBuilder.containsStringToInt32Field("1")).isTrue();
941     assertThat(testMapOrBuilder.containsStringToInt32Field("2")).isTrue();
942     assertThat(testMapOrBuilder.containsStringToInt32Field("3")).isTrue();
943     assertThat(testMapOrBuilder.containsStringToInt32Field("-1")).isFalse();
944   }
945 
946   @Test
testCount()947   public void testCount() {
948     TestMap.Builder builder = TestMap.newBuilder();
949     assertMapCounts(0, builder);
950 
951     setMapValuesUsingAccessors(builder);
952     assertMapCounts(3, builder);
953 
954     TestMap message = builder.build();
955     assertMapCounts(3, message);
956 
957     builder = message.toBuilder().putInt32ToInt32Field(4, 44);
958     assertThat(builder.getInt32ToInt32FieldCount()).isEqualTo(4);
959     assertThat(builder.build().getInt32ToInt32FieldCount()).isEqualTo(4);
960 
961     // already present - should be unchanged
962     builder.putInt32ToInt32Field(4, 44);
963     assertThat(builder.getInt32ToInt32FieldCount()).isEqualTo(4);
964   }
965 
assertMapCounts(int expectedCount, TestMapOrBuilder testMapOrBuilder)966   private void assertMapCounts(int expectedCount, TestMapOrBuilder testMapOrBuilder) {
967     assertThat(testMapOrBuilder.getInt32ToInt32FieldCount()).isEqualTo(expectedCount);
968     assertThat(testMapOrBuilder.getInt32ToStringFieldCount()).isEqualTo(expectedCount);
969     assertThat(testMapOrBuilder.getInt32ToBytesFieldCount()).isEqualTo(expectedCount);
970     assertThat(testMapOrBuilder.getInt32ToEnumFieldCount()).isEqualTo(expectedCount);
971     assertThat(testMapOrBuilder.getInt32ToMessageFieldCount()).isEqualTo(expectedCount);
972     assertThat(testMapOrBuilder.getStringToInt32FieldCount()).isEqualTo(expectedCount);
973   }
974 
975   @Test
testGetOrDefault()976   public void testGetOrDefault() {
977     TestMap.Builder builder = TestMap.newBuilder();
978     assertMapCounts(0, builder);
979     setMapValuesUsingAccessors(builder);
980     doTestGetOrDefault(builder);
981     doTestGetOrDefault(builder.build());
982   }
983 
doTestGetOrDefault(TestMapOrBuilder testMapOrBuilder)984   public void doTestGetOrDefault(TestMapOrBuilder testMapOrBuilder) {
985     assertThat(testMapOrBuilder.getInt32ToInt32FieldOrDefault(1, -11)).isEqualTo(11);
986     assertThat(testMapOrBuilder.getInt32ToInt32FieldOrDefault(-1, -11)).isEqualTo(-11);
987 
988     assertThat(testMapOrBuilder.getInt32ToStringFieldOrDefault(1, "-11")).isEqualTo("11");
989     assertWithMessage("-11")
990         .that(testMapOrBuilder.getInt32ToStringFieldOrDefault(-1, null))
991         .isNull();
992 
993     assertThat(testMapOrBuilder.getInt32ToBytesFieldOrDefault(1, null))
994         .isEqualTo(TestUtil.toBytes("11"));
995     assertThat(testMapOrBuilder.getInt32ToBytesFieldOrDefault(-1, null)).isNull();
996 
997     assertThat(testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null))
998         .isEqualTo(TestMap.EnumValue.FOO);
999     assertThat(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null)).isNull();
1000 
1001     assertThat(testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null))
1002         .isEqualTo(MessageValue.newBuilder().setValue(11).build());
1003     assertThat(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null)).isNull();
1004 
1005     assertThat(testMapOrBuilder.getStringToInt32FieldOrDefault("1", -11)).isEqualTo(11);
1006     assertThat(testMapOrBuilder.getStringToInt32FieldOrDefault("-1", -11)).isEqualTo(-11);
1007 
1008     try {
1009       testMapOrBuilder.getStringToInt32FieldOrDefault(null, -11);
1010       assertWithMessage("expected exception").fail();
1011     } catch (NullPointerException e) {
1012       // expected
1013     }
1014   }
1015 
1016   @Test
testGetOrThrow()1017   public void testGetOrThrow() {
1018     TestMap.Builder builder = TestMap.newBuilder();
1019     assertMapCounts(0, builder);
1020     setMapValuesUsingAccessors(builder);
1021     doTestGetOrDefault(builder);
1022     doTestGetOrDefault(builder.build());
1023   }
1024 
doTestGetOrThrow(TestMapOrBuilder testMapOrBuilder)1025   public void doTestGetOrThrow(TestMapOrBuilder testMapOrBuilder) {
1026     assertThat(testMapOrBuilder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11);
1027     try {
1028       testMapOrBuilder.getInt32ToInt32FieldOrThrow(-1);
1029       assertWithMessage("expected exception").fail();
1030     } catch (IllegalArgumentException e) {
1031       // expected
1032     }
1033 
1034     assertThat(testMapOrBuilder.getInt32ToStringFieldOrThrow(1)).isEqualTo("11");
1035 
1036     try {
1037       testMapOrBuilder.getInt32ToStringFieldOrThrow(-1);
1038       assertWithMessage("expected exception").fail();
1039     } catch (IllegalArgumentException e) {
1040       // expected
1041     }
1042 
1043     assertThat(testMapOrBuilder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11"));
1044 
1045     try {
1046       testMapOrBuilder.getInt32ToBytesFieldOrThrow(-1);
1047       assertWithMessage("expected exception").fail();
1048     } catch (IllegalArgumentException e) {
1049       // expected
1050     }
1051 
1052     assertThat(testMapOrBuilder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO);
1053     try {
1054       testMapOrBuilder.getInt32ToEnumFieldOrThrow(-1);
1055       assertWithMessage("expected exception").fail();
1056     } catch (IllegalArgumentException e) {
1057       // expected
1058     }
1059 
1060     assertThat(testMapOrBuilder.getInt32ToMessageFieldOrThrow(1))
1061         .isEqualTo(MessageValue.newBuilder().setValue(11).build());
1062     try {
1063       testMapOrBuilder.getInt32ToMessageFieldOrThrow(-1);
1064       assertWithMessage("expected exception").fail();
1065     } catch (IllegalArgumentException e) {
1066       // expected
1067     }
1068 
1069     assertThat(testMapOrBuilder.getStringToInt32FieldOrThrow("1")).isEqualTo(11);
1070     try {
1071       testMapOrBuilder.getStringToInt32FieldOrThrow("-1");
1072       assertWithMessage("expected exception").fail();
1073     } catch (IllegalArgumentException e) {
1074       // expected
1075     }
1076 
1077     try {
1078       testMapOrBuilder.getStringToInt32FieldOrThrow(null);
1079       assertWithMessage("expected exception").fail();
1080     } catch (NullPointerException e) {
1081       // expected
1082     }
1083   }
1084 
1085   @Test
testPut()1086   public void testPut() {
1087     TestMap.Builder builder = TestMap.newBuilder();
1088     builder.putInt32ToInt32Field(1, 11);
1089     assertThat(builder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11);
1090 
1091     builder.putInt32ToStringField(1, "a");
1092     assertThat(builder.getInt32ToStringFieldOrThrow(1)).isEqualTo("a");
1093     try {
1094       builder.putInt32ToStringField(1, null);
1095       assertWithMessage("expected exception").fail();
1096     } catch (NullPointerException e) {
1097       // expected
1098     }
1099 
1100     builder.putInt32ToBytesField(1, TestUtil.toBytes("11"));
1101     assertThat(builder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11"));
1102     try {
1103       builder.putInt32ToBytesField(1, null);
1104       assertWithMessage("expected exception").fail();
1105     } catch (NullPointerException e) {
1106       // expected
1107     }
1108 
1109     builder.putInt32ToEnumField(1, TestMap.EnumValue.FOO);
1110     assertThat(builder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO);
1111     try {
1112       builder.putInt32ToEnumField(1, null);
1113       assertWithMessage("expected exception").fail();
1114     } catch (NullPointerException e) {
1115       // expected
1116     }
1117 
1118     builder.putStringToInt32Field("a", 1);
1119     assertThat(builder.getStringToInt32FieldOrThrow("a")).isEqualTo(1);
1120     try {
1121       builder.putStringToInt32Field(null, -1);
1122     } catch (NullPointerException e) {
1123       // expected
1124     }
1125   }
1126 
1127   @Test
testRemove()1128   public void testRemove() {
1129     TestMap.Builder builder = TestMap.newBuilder();
1130     setMapValuesUsingAccessors(builder);
1131     assertThat(builder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11);
1132     for (int times = 0; times < 2; times++) {
1133       builder.removeInt32ToInt32Field(1);
1134       assertThat(builder.getInt32ToInt32FieldOrDefault(1, -1)).isEqualTo(-1);
1135     }
1136 
1137     assertThat(builder.getInt32ToStringFieldOrThrow(1)).isEqualTo("11");
1138     for (int times = 0; times < 2; times++) {
1139       builder.removeInt32ToStringField(1);
1140       assertThat(builder.getInt32ToStringFieldOrDefault(1, null)).isNull();
1141     }
1142 
1143     assertThat(builder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11"));
1144     for (int times = 0; times < 2; times++) {
1145       builder.removeInt32ToBytesField(1);
1146       assertThat(builder.getInt32ToBytesFieldOrDefault(1, null)).isNull();
1147     }
1148 
1149     assertThat(builder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO);
1150     for (int times = 0; times < 2; times++) {
1151       builder.removeInt32ToEnumField(1);
1152       assertThat(builder.getInt32ToEnumFieldOrDefault(1, null)).isNull();
1153     }
1154 
1155     assertThat(builder.getStringToInt32FieldOrThrow("1")).isEqualTo(11);
1156     for (int times = 0; times < 2; times++) {
1157       builder.removeStringToInt32Field("1");
1158       assertThat(builder.getStringToInt32FieldOrDefault("1", -1)).isEqualTo(-1);
1159     }
1160 
1161     try {
1162       builder.removeStringToInt32Field(null);
1163       assertWithMessage("expected exception").fail();
1164     } catch (NullPointerException e) {
1165       // expected
1166     }
1167   }
1168 
1169   // Regression test for b/20494788
1170   @Test
testMapInitializationOrder()1171   public void testMapInitializationOrder() throws Exception {
1172     assertThat(RedactAllTypes.getDefaultInstance().getDescriptorForType().getName())
1173         .isEqualTo("RedactAllTypes");
1174 
1175     Message1.Builder builder = Message1.newBuilder();
1176     builder.putMapField("key", true);
1177     Message1 message = builder.build();
1178     Message mapEntry =
1179         (Message)
1180             message.getRepeatedField(
1181                 message.getDescriptorForType().findFieldByName("map_field"), 0);
1182     assertThat(mapEntry.getAllFields()).hasSize(2);
1183   }
1184 
1185   @Test
testReservedWordsFieldNames()1186   public void testReservedWordsFieldNames() {
1187     ReservedAsMapField unused1 = ReservedAsMapField.getDefaultInstance();
1188     ReservedAsMapFieldWithEnumValue unused2 = ReservedAsMapFieldWithEnumValue.getDefaultInstance();
1189   }
1190 
1191   @Test
testGetMap()1192   public void testGetMap() {
1193     TestMap.Builder builder = TestMap.newBuilder();
1194     setMapValuesUsingAccessors(builder);
1195     assertMapValuesSet(builder);
1196     TestMap message = builder.build();
1197     assertThat(message.getStringToInt32FieldMap()).isEqualTo(message.getStringToInt32FieldMap());
1198     assertThat(message.getInt32ToBytesFieldMap()).isEqualTo(message.getInt32ToBytesFieldMap());
1199     assertThat(message.getInt32ToEnumFieldMap()).isEqualTo(message.getInt32ToEnumFieldMap());
1200     assertThat(message.getInt32ToMessageFieldMap()).isEqualTo(message.getInt32ToMessageFieldMap());
1201   }
1202 
1203   @Test
testPutAllWithNullStringValue()1204   public void testPutAllWithNullStringValue() throws Exception {
1205     TestMap.Builder sourceBuilder = TestMap.newBuilder();
1206 
1207     // order preserving map used here to help test rollback
1208     Map<Integer, String> data = new TreeMap<>();
1209     data.put(7, "foo");
1210     data.put(8, "bar");
1211     data.put(9, null);
1212     try {
1213       sourceBuilder.putAllInt32ToStringField(data);
1214       fail("allowed null string value");
1215     } catch (NullPointerException expected) {
1216       // Verify rollback of previously added values.
1217       // They all go in or none do.
1218       assertThat(sourceBuilder.getInt32ToStringFieldMap()).isEmpty();
1219     }
1220   }
1221 
1222   @Test
testPutAllWithNullStringKey()1223   public void testPutAllWithNullStringKey() throws Exception {
1224     TestMap.Builder sourceBuilder = TestMap.newBuilder();
1225 
1226     // order preserving map used here to help test rollback
1227     Map<Integer, String> data = new LinkedHashMap<>();
1228     data.put(7, "foo");
1229     data.put(null, "bar");
1230     data.put(9, "baz");
1231     try {
1232       sourceBuilder.putAllInt32ToStringField(data);
1233       fail("allowed null string key");
1234     } catch (NullPointerException expected) {
1235       // Verify rollback of previously added values.
1236       // They all go in or none do.
1237       assertThat(sourceBuilder.getInt32ToStringFieldMap()).isEmpty();
1238     }
1239   }
1240 
1241   @Test
testPutNullStringValue()1242   public void testPutNullStringValue() throws Exception {
1243     TestMap.Builder sourceBuilder = TestMap.newBuilder();
1244 
1245     try {
1246       sourceBuilder.putInt32ToStringField(8, null);
1247       fail("allowed null string value");
1248     } catch (NullPointerException expected) {
1249       assertNotNull(expected.getMessage());
1250     }
1251   }
1252 }
1253