• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2016 Google, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.common.truth.extensions.proto;
17 
18 import static com.google.common.base.Preconditions.checkNotNull;
19 import static com.google.common.truth.Truth.assertThat;
20 import static org.junit.Assert.fail;
21 
22 import com.google.common.collect.ImmutableMap;
23 import com.google.protobuf.Any;
24 import com.google.protobuf.Descriptors.Descriptor;
25 import com.google.protobuf.Descriptors.FieldDescriptor;
26 import com.google.protobuf.DynamicMessage;
27 import com.google.protobuf.ExtensionRegistry;
28 import com.google.protobuf.InvalidProtocolBufferException;
29 import com.google.protobuf.Message;
30 import com.google.protobuf.UnknownFieldSet;
31 import java.util.Collection;
32 import java.util.Map;
33 import org.junit.Test;
34 import org.junit.runner.RunWith;
35 import org.junit.runners.Parameterized;
36 import org.junit.runners.Parameterized.Parameters;
37 
38 /** Unit tests for {@link ProtoSubject}. */
39 @RunWith(Parameterized.class)
40 public class ProtoSubjectTest extends ProtoSubjectTestBase {
41 
42   @Parameters(name = "{0}")
parameters()43   public static Collection<Object[]> parameters() {
44     return ProtoSubjectTestBase.parameters();
45   }
46 
ProtoSubjectTest(TestType testType)47   public ProtoSubjectTest(TestType testType) {
48     super(testType);
49   }
50 
51   @Test
testDifferentClasses()52   public void testDifferentClasses() throws InvalidProtocolBufferException {
53     Message message = parse("o_int: 3");
54     DynamicMessage dynamicMessage =
55         DynamicMessage.parseFrom(message.getDescriptorForType(), message.toByteString());
56 
57     expectThat(message).isEqualTo(dynamicMessage);
58     expectThat(dynamicMessage).isEqualTo(message);
59   }
60 
61   @Test
testDifferentDynamicDescriptors()62   public void testDifferentDynamicDescriptors() throws InvalidProtocolBufferException {
63     // Only test once.
64     if (!isProto3()) {
65       return;
66     }
67 
68     DynamicMessage message1 =
69         DynamicMessage.parseFrom(
70             TestMessage2.getDescriptor(),
71             TestMessage2.newBuilder().setOInt(43).build().toByteString());
72     DynamicMessage message2 =
73         DynamicMessage.parseFrom(
74             TestMessage3.getDescriptor(),
75             TestMessage3.newBuilder().setOInt(43).build().toByteString());
76 
77     expectFailureWhenTesting().that(message1).isEqualTo(message2);
78     expectThatFailure().hasMessageThat().contains("different descriptors");
79   }
80 
81   @Test
testFullDiffOnlyWhenRelevant()82   public void testFullDiffOnlyWhenRelevant() {
83     // There are no matches, so 'Full diff' should not be printed.
84     expectFailureWhenTesting().that(parse("o_int: 3")).isEqualTo(parse("o_int: 4"));
85     expectThatFailure().hasMessageThat().doesNotContain("Full diff");
86 
87     // r_string is matched, so the 'Full diff' contains extra information.
88     expectFailureWhenTesting()
89         .that(parse("o_int: 3 r_string: 'abc'"))
90         .isEqualTo(parse("o_int: 4 r_string: 'abc'"));
91     expectThatFailure().hasMessageThat().contains("Full diff");
92   }
93 
94   @Test
testIgnoringFieldAbsence()95   public void testIgnoringFieldAbsence() {
96     Message message = parse("o_int: 3");
97     Message diffMessage = parse("o_int: 3 o_enum: DEFAULT");
98 
99     // Make sure the implementation is reflexive.
100     if (isProto3()) {
101       expectThat(diffMessage).isEqualTo(message);
102       expectThat(message).isEqualTo(diffMessage);
103     } else {
104       expectThat(diffMessage).isNotEqualTo(message);
105       expectThat(message).isNotEqualTo(diffMessage);
106     }
107     expectThat(diffMessage).ignoringFieldAbsence().isEqualTo(message);
108     expectThat(message).ignoringFieldAbsence().isEqualTo(diffMessage);
109 
110     if (!isProto3()) {
111       Message customDefaultMessage = parse("o_int: 3");
112       Message diffCustomDefaultMessage = parse("o_int: 3 o_long_defaults_to_42: 42");
113 
114       expectThat(diffCustomDefaultMessage).isNotEqualTo(customDefaultMessage);
115       expectThat(diffCustomDefaultMessage).ignoringFieldAbsence().isEqualTo(customDefaultMessage);
116       expectThat(customDefaultMessage).isNotEqualTo(diffCustomDefaultMessage);
117       expectThat(customDefaultMessage).ignoringFieldAbsence().isEqualTo(diffCustomDefaultMessage);
118     }
119 
120     if (!isProto3()) {
121       expectFailureWhenTesting().that(diffMessage).isEqualTo(message);
122       expectIsEqualToFailed();
123       expectThatFailure().hasMessageThat().contains("added: o_enum: DEFAULT");
124     }
125 
126     expectFailureWhenTesting().that(diffMessage).ignoringFieldAbsence().isNotEqualTo(message);
127     expectIsNotEqualToFailed();
128     expectThatFailure().hasMessageThat().contains("matched: o_int: 3");
129     if (!isProto3()) {
130       // Proto 3 doesn't cover the field at all when it's not set.
131       expectThatFailure().hasMessageThat().contains("matched: o_enum: DEFAULT");
132     }
133   }
134 
135   @Test
testIgnoringFieldAbsence_anyMessage()136   public void testIgnoringFieldAbsence_anyMessage() {
137     Message message = parse("o_int: 3");
138     Message diffMessage = parse("o_int: 3 o_any_message: {}");
139 
140     expectThat(diffMessage).ignoringFieldAbsence().isEqualTo(message);
141     expectThat(message).ignoringFieldAbsence().isEqualTo(diffMessage);
142 
143     expectFailureWhenTesting().that(diffMessage).isEqualTo(message);
144     expectIsEqualToFailed();
145     expectThatFailure().hasMessageThat().contains("added: o_any_message:");
146 
147     expectFailureWhenTesting().that(diffMessage).ignoringFieldAbsence().isNotEqualTo(message);
148     expectIsNotEqualToFailed();
149     expectThatFailure().hasMessageThat().contains("matched: o_int: 3");
150     expectThatFailure().hasMessageThat().contains("matched: o_any_message");
151   }
152 
153   @Test
testIgnoringFieldAbsence_scoped()154   public void testIgnoringFieldAbsence_scoped() {
155     Message message = parse("o_sub_test_message: { o_test_message: {} }");
156     Message emptyMessage = parse("");
157     Message partialMessage = parse("o_sub_test_message: {}");
158 
159     // All three are equal if we ignore field absence entirely.
160     expectThat(emptyMessage).ignoringFieldAbsence().isEqualTo(message);
161     expectThat(partialMessage).ignoringFieldAbsence().isEqualTo(message);
162 
163     // If we ignore only o_sub_test_message.o_test_message, only the partial message is equal.
164     FieldDescriptor subTestMessageField = getFieldDescriptor("o_sub_test_message");
165     FieldDescriptor subTestMessageTestMessageField =
166         checkNotNull(subTestMessageField.getMessageType().findFieldByName("o_test_message"));
167     expectThat(partialMessage)
168         .ignoringFieldAbsenceOfFieldDescriptors(subTestMessageTestMessageField)
169         .isEqualTo(message);
170     expectFailureWhenTesting()
171         .that(emptyMessage)
172         .ignoringFieldAbsenceOfFieldDescriptors(subTestMessageTestMessageField)
173         .isEqualTo(message);
174     expectIsEqualToFailed();
175     expectThatFailure().hasMessageThat().contains("deleted: o_sub_test_message");
176 
177     // But, we can ignore both.
178     expectThat(partialMessage)
179         .ignoringFieldAbsenceOfFieldDescriptors(subTestMessageField)
180         .ignoringFieldAbsenceOfFieldDescriptors(subTestMessageTestMessageField)
181         .isEqualTo(message);
182     expectThat(partialMessage)
183         .ignoringFieldAbsenceOfFieldDescriptors(subTestMessageField, subTestMessageTestMessageField)
184         .isEqualTo(message);
185     expectThat(emptyMessage)
186         .ignoringFieldAbsenceOfFieldDescriptors(subTestMessageField)
187         .ignoringFieldAbsenceOfFieldDescriptors(subTestMessageTestMessageField)
188         .isEqualTo(message);
189     expectThat(emptyMessage)
190         .ignoringFieldAbsenceOfFieldDescriptors(subTestMessageField, subTestMessageTestMessageField)
191         .isEqualTo(message);
192 
193     try {
194       expectThat(message)
195           .ignoringFieldAbsenceOfFieldDescriptors(getFieldDescriptor("r_string"))
196           .isEqualTo(message);
197       fail("Expected failure.");
198     } catch (Exception e) {
199       assertThat(e).hasMessageThat().contains("r_string");
200       assertThat(e).hasMessageThat().contains("repeated fields cannot be absent");
201     }
202 
203     if (isProto3()) {
204       try {
205         expectThat(message)
206             .ignoringFieldAbsenceOfFieldDescriptors(getFieldDescriptor("o_double"))
207             .isEqualTo(message);
208         fail("Expected failure.");
209       } catch (Exception e) {
210         assertThat(e).hasMessageThat().contains("o_double");
211         assertThat(e).hasMessageThat().contains("is a field without presence");
212       }
213     } else {
214       expectThat(message)
215           .ignoringFieldAbsenceOfFieldDescriptors(getFieldDescriptor("o_double"))
216           .isEqualTo(message);
217     }
218   }
219 
220   @Test
testUnknownFields()221   public void testUnknownFields() throws InvalidProtocolBufferException {
222     Message message =
223         fromUnknownFields(
224             UnknownFieldSet.newBuilder()
225                 .addField(99, UnknownFieldSet.Field.newBuilder().addVarint(42).build())
226                 .build());
227     Message diffMessage =
228         fromUnknownFields(
229             UnknownFieldSet.newBuilder()
230                 .addField(93, UnknownFieldSet.Field.newBuilder().addVarint(42).build())
231                 .build());
232 
233     expectThat(diffMessage).isNotEqualTo(message);
234     expectThat(diffMessage).ignoringFieldAbsence().isEqualTo(message);
235 
236     expectFailureWhenTesting().that(diffMessage).isEqualTo(message);
237     expectIsEqualToFailed();
238     expectThatFailure().hasMessageThat().contains("added: 93[0]: 42");
239     expectThatFailure().hasMessageThat().contains("deleted: 99[0]: 42");
240 
241     expectFailureWhenTesting().that(diffMessage).ignoringFieldAbsence().isNotEqualTo(message);
242     expectIsNotEqualToFailed();
243   }
244 
245   @Test
testRepeatedFieldOrder()246   public void testRepeatedFieldOrder() {
247     Message message = parse("r_string: \"foo\" r_string: \"bar\"");
248     Message eqMessage = parse("r_string: \"bar\" r_string: \"foo\"");
249     Message diffMessage = parse("r_string: \"foo\" r_string: \"foo\" r_string: \"bar\"");
250 
251     expectThat(message).isEqualTo(clone(message));
252     expectThat(message).ignoringRepeatedFieldOrder().isEqualTo(clone(message));
253     expectThat(diffMessage).isNotEqualTo(message);
254     expectThat(diffMessage).ignoringRepeatedFieldOrder().isNotEqualTo(message);
255     expectThat(eqMessage).isNotEqualTo(message);
256     expectThat(eqMessage).ignoringRepeatedFieldOrder().isEqualTo(message);
257 
258     Message nestedMessage =
259         parse(
260             "r_test_message: { o_int: 33 r_string: \"foo\" r_string: \"bar\" } "
261                 + "r_test_message: { o_int: 44 r_string: \"baz\" r_string: \"qux\" } ");
262     Message diffNestedMessage =
263         parse(
264             "r_test_message: { o_int: 33 r_string: \"qux\" r_string: \"baz\" } "
265                 + "r_test_message: { o_int: 44 r_string: \"bar\" r_string: \"foo\" } ");
266     Message eqNestedMessage =
267         parse(
268             "r_test_message: { o_int: 44 r_string: \"qux\" r_string: \"baz\" } "
269                 + "r_test_message: { o_int: 33 r_string: \"bar\" r_string: \"foo\" } ");
270 
271     expectThat(nestedMessage).isEqualTo(clone(nestedMessage));
272     expectThat(nestedMessage).ignoringRepeatedFieldOrder().isEqualTo(clone(nestedMessage));
273     expectThat(diffNestedMessage).isNotEqualTo(nestedMessage);
274     expectThat(diffNestedMessage).ignoringRepeatedFieldOrder().isNotEqualTo(nestedMessage);
275     expectThat(eqNestedMessage).isNotEqualTo(nestedMessage);
276     expectThat(eqNestedMessage).ignoringRepeatedFieldOrder().isEqualTo(nestedMessage);
277 
278     expectFailureWhenTesting().that(eqMessage).isEqualTo(message);
279     expectIsEqualToFailed();
280     expectThatFailure().hasMessageThat().contains("modified: r_string[0]: \"foo\" -> \"bar\"");
281     expectThatFailure().hasMessageThat().contains("modified: r_string[1]: \"bar\" -> \"foo\"");
282 
283     expectFailureWhenTesting().that(eqMessage).ignoringRepeatedFieldOrder().isNotEqualTo(message);
284     expectIsNotEqualToFailed();
285     expectThatFailure().hasMessageThat().contains("moved: r_string[0] -> r_string[1]: \"foo\"");
286     expectThatFailure().hasMessageThat().contains("moved: r_string[1] -> r_string[0]: \"bar\"");
287 
288     expectFailureWhenTesting().that(diffMessage).ignoringRepeatedFieldOrder().isEqualTo(message);
289     expectIsEqualToFailed();
290     expectThatFailure().hasMessageThat().contains("matched: r_string[0]: \"foo\"");
291     expectThatFailure().hasMessageThat().contains("moved: r_string[1] -> r_string[2]: \"bar\"");
292     expectThatFailure().hasMessageThat().contains("added: r_string[1]: \"foo\"");
293   }
294 
295   @Test
testRepeatedFieldOrder_scoped()296   public void testRepeatedFieldOrder_scoped() {
297     Message message =
298         parse("r_string: 'a' r_string: 'b' o_sub_test_message: { r_string: 'c' r_string: 'd' }");
299     Message diffSubMessage =
300         parse("r_string: 'a' r_string: 'b' o_sub_test_message: { r_string: 'd' r_string: 'c' }");
301     Message diffAll =
302         parse("r_string: 'b' r_string: 'a' o_sub_test_message: { r_string: 'd' r_string: 'c' }");
303 
304     FieldDescriptor rootMessageRepeatedfield = getFieldDescriptor("r_string");
305     FieldDescriptor subMessageRepeatedField =
306         checkNotNull(
307             getFieldDescriptor("o_sub_test_message").getMessageType().findFieldByName("r_string"));
308 
309     // Ignoring all repeated field order tests pass.
310     expectThat(diffSubMessage).ignoringRepeatedFieldOrder().isEqualTo(message);
311     expectThat(diffAll).ignoringRepeatedFieldOrder().isEqualTo(message);
312 
313     // Ignoring only some results in failures.
314     //
315     // TODO(user): Whether we check failure message substrings or not is currently ad-hoc on a
316     // per-test basis, and not especially maintainable.  We should make the tests consistent
317     // according to some reasonable rule in this regard.
318     expectFailureWhenTesting()
319         .that(diffSubMessage)
320         .ignoringRepeatedFieldOrderOfFieldDescriptors(rootMessageRepeatedfield)
321         .isEqualTo(message);
322     expectIsEqualToFailed();
323     expectThatFailure()
324         .hasMessageThat()
325         .contains("modified: o_sub_test_message.r_string[0]: \"c\" -> \"d\"");
326     expectThat(diffSubMessage)
327         .ignoringRepeatedFieldOrderOfFieldDescriptors(subMessageRepeatedField)
328         .isEqualTo(message);
329 
330     expectThat(diffAll)
331         .ignoringRepeatedFieldOrderOfFieldDescriptors(rootMessageRepeatedfield)
332         .isNotEqualTo(message);
333     expectThat(diffAll)
334         .ignoringRepeatedFieldOrderOfFieldDescriptors(subMessageRepeatedField)
335         .isNotEqualTo(message);
336     expectThat(diffAll)
337         .ignoringRepeatedFieldOrderOfFieldDescriptors(
338             rootMessageRepeatedfield, subMessageRepeatedField)
339         .isEqualTo(message);
340 
341     try {
342       expectThat(message)
343           .ignoringRepeatedFieldOrderOfFields(getFieldNumber("o_int"))
344           .isEqualTo(message);
345       fail("Expected failure.");
346     } catch (Exception e) {
347       assertThat(e).hasMessageThat().contains("o_int");
348       assertThat(e).hasMessageThat().contains("is not a repeated field");
349     }
350   }
351 
352   @Test
testDoubleTolerance()353   public void testDoubleTolerance() {
354     Message message = parse("o_double: 1.0");
355     Message diffMessage = parse("o_double: 1.1");
356 
357     expectThat(diffMessage).isNotEqualTo(message);
358     expectThat(diffMessage).usingDoubleTolerance(0.2).isEqualTo(message);
359     expectThat(diffMessage).usingDoubleTolerance(0.05).isNotEqualTo(message);
360     expectThat(diffMessage).usingFloatTolerance(0.2f).isNotEqualTo(message);
361   }
362 
363   @Test
testDoubleTolerance_defaultValue()364   public void testDoubleTolerance_defaultValue() {
365     Message message = parse("o_double: 0.0");
366     Message defaultInstance = parse("");
367     Message diffMessage = parse("o_double: 0.01");
368 
369     expectThat(diffMessage).isNotEqualTo(message);
370 
371     if (isProto3()) {
372       // The default value is ignored and treated as unset.
373       // We treat is as equivalent to being set to 0.0 because there is no distinction in Proto 3.
374       expectThat(message).isEqualTo(defaultInstance);
375       expectThat(diffMessage).usingDoubleTolerance(0.1).isEqualTo(message);
376       expectThat(diffMessage).usingDoubleTolerance(0.1).ignoringFieldAbsence().isEqualTo(message);
377     } else {
378       // The default value can be set or unset, so we respect it.
379       expectThat(message).isNotEqualTo(defaultInstance);
380 
381       expectThat(diffMessage).usingDoubleTolerance(0.1).isEqualTo(message);
382       expectThat(diffMessage).usingDoubleTolerance(0.1).isNotEqualTo(defaultInstance);
383       expectThat(diffMessage).usingDoubleTolerance(0.1).ignoringFieldAbsence().isEqualTo(message);
384       expectThat(diffMessage)
385           .usingDoubleTolerance(0.1)
386           .ignoringFieldAbsence()
387           .isEqualTo(defaultInstance);
388 
389       // The same logic applies for a specified default; not available in Proto 3.
390       Message message2 = parse("o_double_defaults_to_42: 42.0");
391       Message diffMessage2 = parse("o_double_defaults_to_42: 42.01");
392 
393       expectThat(diffMessage2).usingDoubleTolerance(0.1).isEqualTo(message2);
394       expectThat(diffMessage2).usingDoubleTolerance(0.1).isNotEqualTo(defaultInstance);
395       expectThat(diffMessage2).usingDoubleTolerance(0.1).ignoringFieldAbsence().isEqualTo(message2);
396       expectThat(diffMessage2)
397           .usingDoubleTolerance(0.1)
398           .ignoringFieldAbsence()
399           .isEqualTo(defaultInstance);
400     }
401   }
402 
403   @Test
testDoubleTolerance_scoped()404   public void testDoubleTolerance_scoped() {
405     Message message = parse("o_double: 1.0 o_double2: 1.0");
406     Message diffMessage = parse("o_double: 1.1 o_double2: 1.5");
407 
408     int doubleFieldNumber = getFieldNumber("o_double");
409     int double2FieldNumber = getFieldNumber("o_double2");
410 
411     expectThat(diffMessage).usingDoubleTolerance(0.6).isEqualTo(message);
412     expectThat(diffMessage).usingDoubleTolerance(0.2).isNotEqualTo(message);
413 
414     // usingDoubleTolerance*() statements override all previous statements.
415     expectThat(diffMessage)
416         .usingDoubleTolerance(0.2)
417         .usingDoubleToleranceForFields(0.6, double2FieldNumber)
418         .isEqualTo(message);
419     expectThat(diffMessage)
420         .usingDoubleToleranceForFields(0.6, doubleFieldNumber, double2FieldNumber)
421         .usingDoubleToleranceForFields(0.2, doubleFieldNumber)
422         .isEqualTo(message);
423 
424     expectThat(diffMessage)
425         .usingDoubleTolerance(0.2)
426         .usingDoubleToleranceForFields(0.6, doubleFieldNumber)
427         .isNotEqualTo(message);
428     expectThat(diffMessage)
429         .usingDoubleToleranceForFields(0.6, double2FieldNumber)
430         .usingDoubleTolerance(0.2)
431         .isNotEqualTo(message);
432     expectThat(diffMessage)
433         .usingDoubleToleranceForFields(0.6, doubleFieldNumber, double2FieldNumber)
434         .usingDoubleToleranceForFields(0.2, double2FieldNumber)
435         .isNotEqualTo(message);
436 
437     try {
438       expectThat(message)
439           .usingDoubleToleranceForFields(3.14159, getFieldNumber("o_int"))
440           .isEqualTo(message);
441       fail("Expected failure.");
442     } catch (Exception e) {
443       assertThat(e).hasMessageThat().contains("o_int");
444       assertThat(e).hasMessageThat().contains("is not a double field");
445     }
446   }
447 
448   @Test
testFloatTolerance()449   public void testFloatTolerance() {
450     Message message = parse("o_float: 1.0");
451     Message diffMessage = parse("o_float: 1.1");
452 
453     expectThat(diffMessage).isNotEqualTo(message);
454     expectThat(diffMessage).usingFloatTolerance(0.2f).isEqualTo(message);
455     expectThat(diffMessage).usingFloatTolerance(0.05f).isNotEqualTo(message);
456     expectThat(diffMessage).usingDoubleTolerance(0.2).isNotEqualTo(message);
457   }
458 
459   @Test
testFloatTolerance_defaultValue()460   public void testFloatTolerance_defaultValue() {
461     Message message = parse("o_float: 0.0");
462     Message defaultInstance = parse("");
463     Message diffMessage = parse("o_float: 0.01");
464 
465     expectThat(diffMessage).isNotEqualTo(message);
466 
467     if (isProto3()) {
468       // The default value is ignored and treated as unset.
469       // We treat is as equivalent to being set to 0.0f because there is no distinction in Proto 3.
470       expectThat(message).isEqualTo(defaultInstance);
471       expectThat(diffMessage).usingFloatTolerance(0.1f).isEqualTo(message);
472       expectThat(diffMessage).usingFloatTolerance(0.1f).ignoringFieldAbsence().isEqualTo(message);
473     } else {
474       // The default value can be set or unset, so we respect it.
475       expectThat(message).isNotEqualTo(defaultInstance);
476 
477       expectThat(diffMessage).usingFloatTolerance(0.1f).isEqualTo(message);
478       expectThat(diffMessage).usingFloatTolerance(0.1f).isNotEqualTo(defaultInstance);
479       expectThat(diffMessage).usingFloatTolerance(0.1f).ignoringFieldAbsence().isEqualTo(message);
480       expectThat(diffMessage)
481           .usingFloatTolerance(0.1f)
482           .ignoringFieldAbsence()
483           .isEqualTo(defaultInstance);
484 
485       // The same logic applies for a specified default; not available in Proto 3.
486       Message message2 = parse("o_float_defaults_to_42: 42.0");
487       Message diffMessage2 = parse("o_float_defaults_to_42: 42.01");
488 
489       expectThat(diffMessage2).usingFloatTolerance(0.1f).isEqualTo(message2);
490       expectThat(diffMessage2).usingFloatTolerance(0.1f).isNotEqualTo(defaultInstance);
491       expectThat(diffMessage2).usingFloatTolerance(0.1f).ignoringFieldAbsence().isEqualTo(message2);
492       expectThat(diffMessage2)
493           .usingFloatTolerance(0.1f)
494           .ignoringFieldAbsence()
495           .isEqualTo(defaultInstance);
496     }
497   }
498 
499   @Test
testFloatTolerance_scoped()500   public void testFloatTolerance_scoped() {
501     Message message = parse("o_float: 1.0 o_float2: 1.0");
502     Message diffMessage = parse("o_float: 1.1 o_float2: 1.5");
503 
504     int floatFieldNumber = getFieldNumber("o_float");
505     int float2FieldNumber = getFieldNumber("o_float2");
506 
507     expectThat(diffMessage).usingFloatTolerance(0.6f).isEqualTo(message);
508     expectThat(diffMessage).usingFloatTolerance(0.2f).isNotEqualTo(message);
509 
510     // usingFloatTolerance*() statements override all previous statements.
511     expectThat(diffMessage)
512         .usingFloatTolerance(0.2f)
513         .usingFloatToleranceForFields(0.6f, float2FieldNumber)
514         .isEqualTo(message);
515     expectThat(diffMessage)
516         .usingFloatTolerance(0.2f)
517         .usingFloatToleranceForFields(0.6f, floatFieldNumber)
518         .isNotEqualTo(message);
519     expectThat(diffMessage)
520         .usingFloatToleranceForFields(0.6f, float2FieldNumber)
521         .usingFloatTolerance(0.2f)
522         .isNotEqualTo(message);
523     expectThat(diffMessage)
524         .usingFloatToleranceForFields(0.6f, floatFieldNumber, float2FieldNumber)
525         .usingFloatToleranceForFields(0.2f, floatFieldNumber)
526         .isEqualTo(message);
527     expectThat(diffMessage)
528         .usingFloatToleranceForFields(0.6f, floatFieldNumber, float2FieldNumber)
529         .usingFloatToleranceForFields(0.2f, float2FieldNumber)
530         .isNotEqualTo(message);
531 
532     try {
533       expectThat(message)
534           .usingFloatToleranceForFields(3.1416f, getFieldNumber("o_int"))
535           .isEqualTo(message);
536       fail("Expected failure.");
537     } catch (Exception e) {
538       assertThat(e).hasMessageThat().contains("o_int");
539       assertThat(e).hasMessageThat().contains("is not a float field");
540     }
541   }
542 
543   @Test
testComparingExpectedFieldsOnly()544   public void testComparingExpectedFieldsOnly() {
545     Message message = parse("o_int: 3 r_string: 'foo'");
546     Message narrowMessage = parse("o_int: 3");
547 
548     expectThat(message).comparingExpectedFieldsOnly().isEqualTo(narrowMessage);
549     expectThat(narrowMessage).comparingExpectedFieldsOnly().isNotEqualTo(message);
550 
551     expectFailureWhenTesting()
552         .that(message)
553         .comparingExpectedFieldsOnly()
554         .isNotEqualTo(narrowMessage);
555     expectThatFailure().hasMessageThat().contains("ignored: r_string");
556   }
557 
558   @Test
testIgnoringExtraRepeatedFieldElements_respectingOrder()559   public void testIgnoringExtraRepeatedFieldElements_respectingOrder() {
560     Message message = parse("r_string: 'foo' r_string: 'bar'");
561     Message eqMessage = parse("r_string: 'foo' r_string: 'foobar' r_string: 'bar'");
562     Message diffMessage = parse("r_string: 'bar' r_string: 'foobar' r_string: 'foo'");
563 
564     expectThat(eqMessage).ignoringExtraRepeatedFieldElements().isEqualTo(message);
565     expectThat(diffMessage).ignoringExtraRepeatedFieldElements().isNotEqualTo(message);
566 
567     expectFailureWhenTesting()
568         .that(eqMessage)
569         .ignoringExtraRepeatedFieldElements()
570         .isNotEqualTo(message);
571     expectThatFailure()
572         .hasMessageThat()
573         .contains("ignored: r_string[?] -> r_string[1]: \"foobar\"");
574 
575     expectFailureWhenTesting()
576         .that(diffMessage)
577         .ignoringExtraRepeatedFieldElements()
578         .isEqualTo(message);
579     expectThatFailure()
580         .hasMessageThat()
581         .contains("out_of_order: r_string[1] -> r_string[0]: \"bar\"");
582     expectThatFailure().hasMessageThat().contains("moved: r_string[0] -> r_string[2]: \"foo\"");
583   }
584 
585   @Test
testIgnoringExtraRepeatedFieldElements_ignoringOrder()586   public void testIgnoringExtraRepeatedFieldElements_ignoringOrder() {
587     Message message = parse("r_string: 'foo' r_string: 'bar'");
588     Message eqMessage = parse("r_string: 'baz' r_string: 'bar' r_string: 'qux' r_string: 'foo'");
589     Message diffMessage = parse("r_string: 'abc' r_string: 'foo' r_string: 'xyz'");
590 
591     expectThat(eqMessage)
592         .ignoringExtraRepeatedFieldElements()
593         .ignoringRepeatedFieldOrder()
594         .isEqualTo(message);
595     expectThat(diffMessage)
596         .ignoringExtraRepeatedFieldElements()
597         .ignoringRepeatedFieldOrder()
598         .isNotEqualTo(message);
599 
600     expectFailureWhenTesting()
601         .that(diffMessage)
602         .ignoringExtraRepeatedFieldElements()
603         .ignoringRepeatedFieldOrder()
604         .isEqualTo(message);
605     expectThatFailure().hasMessageThat().contains("moved: r_string[0] -> r_string[1]: \"foo\"");
606     expectThatFailure().hasMessageThat().contains("deleted: r_string[1]: \"bar\"");
607   }
608 
609   @Test
testIgnoringExtraRepeatedFieldElements_empty()610   public void testIgnoringExtraRepeatedFieldElements_empty() {
611     Message message = parse("o_int: 2");
612     Message diffMessage = parse("o_int: 2 r_string: 'error'");
613 
614     expectThat(diffMessage).ignoringExtraRepeatedFieldElements().isNotEqualTo(message);
615     expectThat(diffMessage)
616         .ignoringExtraRepeatedFieldElements()
617         .ignoringRepeatedFieldOrder()
618         .isNotEqualTo(message);
619 
620     expectThat(diffMessage)
621         .comparingExpectedFieldsOnly()
622         .ignoringExtraRepeatedFieldElements()
623         .isEqualTo(message);
624     expectThat(diffMessage)
625         .comparingExpectedFieldsOnly()
626         .ignoringExtraRepeatedFieldElements()
627         .ignoringRepeatedFieldOrder()
628         .isEqualTo(message);
629   }
630 
631   @Test
testIgnoringExtraRepeatedFieldElements_scoped()632   public void testIgnoringExtraRepeatedFieldElements_scoped() {
633     Message message = parse("r_string: 'a' o_sub_test_message: { r_string: 'c' }");
634     Message diffMessage =
635         parse("r_string: 'a' o_sub_test_message: { r_string: 'b' r_string: 'c' }");
636 
637     FieldDescriptor rootRepeatedField = getFieldDescriptor("r_string");
638     FieldDescriptor subMessageRepeatedField =
639         checkNotNull(
640             getFieldDescriptor("o_sub_test_message").getMessageType().findFieldByName("r_string"));
641 
642     expectThat(diffMessage).ignoringExtraRepeatedFieldElements().isEqualTo(message);
643     expectThat(diffMessage)
644         .ignoringExtraRepeatedFieldElementsOfFieldDescriptors(rootRepeatedField)
645         .isNotEqualTo(message);
646     expectThat(diffMessage)
647         .ignoringExtraRepeatedFieldElementsOfFieldDescriptors(subMessageRepeatedField)
648         .isEqualTo(message);
649     expectThat(diffMessage)
650         .ignoringExtraRepeatedFieldElementsOfFieldDescriptors(
651             rootRepeatedField, subMessageRepeatedField)
652         .isEqualTo(message);
653 
654     try {
655       expectThat(message)
656           .ignoringExtraRepeatedFieldElementsOfFields(getFieldNumber("o_int"))
657           .isEqualTo(message);
658       fail("Expected failure.");
659     } catch (Exception e) {
660       assertThat(e).hasMessageThat().contains("o_int");
661       assertThat(e).hasMessageThat().contains("it cannot contain extra elements");
662     }
663   }
664 
665   // Utility which fills a proto map field, based on the java.util.Map.
makeProtoMap(Map<String, Integer> map)666   private Message makeProtoMap(Map<String, Integer> map) {
667     StringBuilder textProto = new StringBuilder();
668     for (String key : map.keySet()) {
669       int value = map.get(key);
670       textProto
671           .append("test_message_map { key: '")
672           .append(key)
673           .append("' value { o_int: ")
674           .append(value)
675           .append(" } } ");
676     }
677     return parse(textProto.toString());
678   }
679 
680   @Test
testIgnoringExtraRepeatedFieldElements_map()681   public void testIgnoringExtraRepeatedFieldElements_map() {
682     Message message = makeProtoMap(ImmutableMap.of("foo", 2, "bar", 3));
683     Message eqMessage = makeProtoMap(ImmutableMap.of("bar", 3, "qux", 4, "foo", 2));
684     Message diffMessage = makeProtoMap(ImmutableMap.of("quz", 5, "foo", 2));
685     Message emptyMessage = parse("");
686 
687     expectThat(eqMessage).ignoringExtraRepeatedFieldElements().isEqualTo(message);
688     expectThat(eqMessage)
689         .ignoringRepeatedFieldOrder()
690         .ignoringExtraRepeatedFieldElements()
691         .isEqualTo(message);
692     expectThat(diffMessage).ignoringExtraRepeatedFieldElements().isNotEqualTo(message);
693     expectThat(diffMessage)
694         .ignoringExtraRepeatedFieldElements()
695         .ignoringRepeatedFieldOrder()
696         .isNotEqualTo(message);
697 
698     expectThat(message).ignoringExtraRepeatedFieldElements().isNotEqualTo(emptyMessage);
699 
700     expectFailureWhenTesting()
701         .that(diffMessage)
702         .ignoringExtraRepeatedFieldElements()
703         .isEqualTo(message);
704     expectThatFailure().hasMessageThat().contains("matched: test_message_map[\"foo\"].o_int: 2");
705     expectThatFailure().hasMessageThat().contains("ignored: test_message_map[\"quz\"]");
706     expectThatFailure().hasMessageThat().contains("deleted: test_message_map[\"bar\"]");
707   }
708 
709   @Test
testReportingMismatchesOnly_isEqualTo()710   public void testReportingMismatchesOnly_isEqualTo() {
711     Message message = parse("r_string: \"foo\" r_string: \"bar\"");
712     Message diffMessage = parse("r_string: \"foo\" r_string: \"not_bar\"");
713 
714     expectFailureWhenTesting().that(diffMessage).isEqualTo(message);
715     expectIsEqualToFailed();
716     expectThatFailure().hasMessageThat().contains("foo");
717     expectThatFailure().hasMessageThat().contains("bar");
718     expectThatFailure().hasMessageThat().contains("not_bar");
719 
720     expectFailureWhenTesting().that(diffMessage).reportingMismatchesOnly().isEqualTo(message);
721     expectIsEqualToFailed();
722     expectThatFailure().hasMessageThat().doesNotContain("foo");
723     expectThatFailure().hasMessageThat().contains("bar");
724     expectThatFailure().hasMessageThat().contains("not_bar");
725   }
726 
727   @Test
testReportingMismatchesOnly_isNotEqualTo()728   public void testReportingMismatchesOnly_isNotEqualTo() {
729     Message message = parse("o_int: 33 r_string: \"foo\" r_string: \"bar\"");
730     Message diffMessage = parse("o_int: 33 r_string: \"bar\" r_string: \"foo\"");
731 
732     expectFailureWhenTesting().that(diffMessage).ignoringRepeatedFieldOrder().isNotEqualTo(message);
733     expectIsNotEqualToFailed();
734     expectThatFailure().hasMessageThat().contains("33");
735     expectThatFailure().hasMessageThat().contains("foo");
736     expectThatFailure().hasMessageThat().contains("bar");
737 
738     expectFailureWhenTesting()
739         .that(diffMessage)
740         .ignoringRepeatedFieldOrder()
741         .reportingMismatchesOnly()
742         .isNotEqualTo(message);
743     expectIsNotEqualToFailed();
744     expectThatFailure().hasMessageThat().doesNotContain("33");
745     expectThatFailure().hasMessageThat().doesNotContain("foo");
746     expectThatFailure().hasMessageThat().doesNotContain("bar");
747   }
748 
749   @Test
testHasAllRequiredFields()750   public void testHasAllRequiredFields() {
751     // Proto 3 doesn't have required fields.
752     if (isProto3()) {
753       return;
754     }
755 
756     expectThat(parsePartial("")).hasAllRequiredFields();
757     expectThat(parsePartial("o_required_string_message: { required_string: \"foo\" }"))
758         .hasAllRequiredFields();
759 
760     expectFailureWhenTesting()
761         .that(parsePartial("o_required_string_message: {}"))
762         .hasAllRequiredFields();
763     expectThatFailure()
764         .factKeys()
765         .containsExactly(
766             "expected to have all required fields set", "but was missing", "proto was");
767     expectThatFailure()
768         .factValue("but was missing")
769         .isEqualTo("[o_required_string_message.required_string]");
770 
771     expectFailureWhenTesting()
772         .that(parsePartial("r_required_string_message: {} r_required_string_message: {}"))
773         .hasAllRequiredFields();
774     expectThatFailure()
775         .factKeys()
776         .containsExactly(
777             "expected to have all required fields set", "but was missing", "proto was");
778     expectThatFailure()
779         .factValue("but was missing")
780         .contains("r_required_string_message[0].required_string");
781     expectThatFailure()
782         .factValue("but was missing")
783         .contains("r_required_string_message[1].required_string");
784   }
785 
786   @Test
testAnyMessage_notEqual_diffPrintsExpandedAny()787   public void testAnyMessage_notEqual_diffPrintsExpandedAny() {
788     String typeUrl =
789         isProto3()
790             ? "type.googleapis.com/com.google.common.truth.extensions.proto.SubTestMessage3"
791             : "type.googleapis.com/com.google.common.truth.extensions.proto.SubTestMessage2";
792     Message msgWithAny =
793         parse("" + "o_int: 42 " + "o_any_message: { [" + typeUrl + "]: {r_string: \"foo\"} }");
794     Message msgWithoutAny = parse("o_int: 42");
795 
796     expectFailureWhenTesting()
797         .that(msgWithAny)
798         .unpackingAnyUsing(getTypeRegistry(), getExtensionRegistry())
799         .isEqualTo(msgWithoutAny);
800     expectThatFailure()
801         .hasMessageThat()
802         .contains(
803             "added: o_any_message: \n" + "[" + typeUrl + "] {\n" + "  r_string: \"foo\"\n" + "}\n");
804 
805     expectFailureWhenTesting()
806         .that(msgWithoutAny)
807         .unpackingAnyUsing(getTypeRegistry(), getExtensionRegistry())
808         .isEqualTo(msgWithAny);
809     expectThatFailure()
810         .hasMessageThat()
811         .contains(
812             "deleted: o_any_message: \n"
813                 + "["
814                 + typeUrl
815                 + "] {\n"
816                 + "  r_string: \"foo\"\n"
817                 + "}\n");
818   }
819 
820   @Test
testRepeatedAnyMessage_notEqual_diffPrintsExpandedAny()821   public void testRepeatedAnyMessage_notEqual_diffPrintsExpandedAny() {
822     String typeUrl =
823         isProto3()
824             ? "type.googleapis.com/com.google.common.truth.extensions.proto.SubTestMessage3"
825             : "type.googleapis.com/com.google.common.truth.extensions.proto.SubTestMessage2";
826     String fooSubMessage = "{ [" + typeUrl + "]: {r_string: \"foo\"} }";
827     String barSubMessage = "{ [" + typeUrl + "]: {r_string: \"bar\"} }";
828     String bazSubMessage = "{ [" + typeUrl + "]: {r_string: \"baz\"} }";
829     Message msgWithFooBar =
830         parse(
831             ""
832                 + "o_int: 42 "
833                 + "r_any_message: "
834                 + fooSubMessage
835                 + "r_any_message: "
836                 + barSubMessage);
837     Message msgWithBazFoo =
838         parse(
839             ""
840                 + "o_int: 42 "
841                 + "r_any_message: "
842                 + bazSubMessage
843                 + "r_any_message: "
844                 + fooSubMessage);
845 
846     expectFailureWhenTesting()
847         .that(msgWithFooBar)
848         .unpackingAnyUsing(getTypeRegistry(), getExtensionRegistry())
849         .ignoringRepeatedFieldOrder()
850         .isEqualTo(msgWithBazFoo);
851 
852     expectThatFailure()
853         .hasMessageThat()
854         .contains(
855             ""
856                 + "moved: r_any_message[1] -> r_any_message[0]:\n"
857                 + "added: r_any_message[1]: \n"
858                 + "["
859                 + typeUrl
860                 + "] {\n"
861                 + "  r_string: \"bar\"\n"
862                 + "}\n"
863                 + "deleted: r_any_message[0]: \n"
864                 + "["
865                 + typeUrl
866                 + "] {\n"
867                 + "  r_string: \"baz\"\n"
868                 + "}");
869   }
870 
871   @Test
testAnyMessagesWithDifferentTypes()872   public void testAnyMessagesWithDifferentTypes() {
873     String typeUrl =
874         isProto3()
875             ? "type.googleapis.com/com.google.common.truth.extensions.proto.SubTestMessage3"
876             : "type.googleapis.com/com.google.common.truth.extensions.proto.SubTestMessage2";
877     String diffTypeUrl =
878         isProto3()
879             ? "type.googleapis.com/com.google.common.truth.extensions.proto.SubSubTestMessage3"
880             : "type.googleapis.com/com.google.common.truth.extensions.proto.SubSubTestMessage2";
881 
882     Message message = parse("o_any_message: { [" + typeUrl + "]: {r_string: \"foo\"} }");
883     Message diffMessage = parse("o_any_message: { [" + diffTypeUrl + "]: {r_string: \"bar\"} }");
884 
885     expectThat(message)
886         .unpackingAnyUsing(getTypeRegistry(), getExtensionRegistry())
887         .isNotEqualTo(diffMessage);
888 
889     expectFailureWhenTesting()
890         .that(message)
891         .unpackingAnyUsing(getTypeRegistry(), getExtensionRegistry())
892         .isEqualTo(diffMessage);
893     expectThatFailure().hasMessageThat().contains("modified: o_any_message.type_url");
894     expectThatFailure()
895         .hasMessageThat()
896         .containsMatch("modified: o_any_message.value:.*bar.*->.*foo.*");
897   }
898 
899   @Test
testAnyMessageCompareWithEmptyAnyMessage()900   public void testAnyMessageCompareWithEmptyAnyMessage() {
901     String typeUrl =
902         isProto3()
903             ? "type.googleapis.com/com.google.common.truth.extensions.proto.SubTestMessage3"
904             : "type.googleapis.com/com.google.common.truth.extensions.proto.SubTestMessage2";
905 
906     Message messageWithAny = parse("o_any_message: { [" + typeUrl + "]: {o_int: 1} }");
907     Message messageWithEmptyAny = parse("o_any_message: { }");
908 
909     expectThat(messageWithAny)
910         .unpackingAnyUsing(getTypeRegistry(), getExtensionRegistry())
911         .isNotEqualTo(messageWithEmptyAny);
912     expectThat(messageWithEmptyAny)
913         .unpackingAnyUsing(getTypeRegistry(), getExtensionRegistry())
914         .isNotEqualTo(messageWithAny);
915 
916     expectFailureWhenTesting()
917         .that(messageWithAny)
918         .unpackingAnyUsing(getTypeRegistry(), getExtensionRegistry())
919         .isEqualTo(messageWithEmptyAny);
920     expectThatFailure().hasMessageThat().contains("modified: o_any_message.type_url");
921     expectThatFailure().hasMessageThat().contains("modified: o_any_message.value");
922 
923     expectFailureWhenTesting()
924         .that(messageWithEmptyAny)
925         .unpackingAnyUsing(getTypeRegistry(), getExtensionRegistry())
926         .isEqualTo(messageWithAny);
927     expectThatFailure().hasMessageThat().contains("modified: o_any_message.type_url");
928     expectThatFailure().hasMessageThat().contains("modified: o_any_message.value");
929   }
930 
931   @Test
testAnyMessageComparedWithDynamicMessage()932   public void testAnyMessageComparedWithDynamicMessage() throws InvalidProtocolBufferException {
933     String typeUrl =
934         isProto3()
935             ? "type.googleapis.com/com.google.common.truth.extensions.proto.SubTestMessage3"
936             : "type.googleapis.com/com.google.common.truth.extensions.proto.SubTestMessage2";
937 
938     Message messageWithAny = parse("o_any_message: { [" + typeUrl + "]: {o_int: 1} }");
939     FieldDescriptor fieldDescriptor = getFieldDescriptor("o_any_message");
940     Any message = (Any) messageWithAny.getField(fieldDescriptor);
941     DynamicMessage dynamicMessage =
942         DynamicMessage.parseFrom(
943             Any.getDescriptor(), message.toByteString(), ExtensionRegistry.getEmptyRegistry());
944 
945     expectThat(dynamicMessage)
946         .unpackingAnyUsing(getTypeRegistry(), getExtensionRegistry())
947         .isEqualTo(message);
948     expectThat(message)
949         .unpackingAnyUsing(getTypeRegistry(), getExtensionRegistry())
950         .isEqualTo(dynamicMessage);
951   }
952 
953   @Test
testMapWithDefaultKeysAndValues()954   public void testMapWithDefaultKeysAndValues() throws InvalidProtocolBufferException {
955     Descriptor descriptor = getFieldDescriptor("o_int").getContainingType();
956     String defaultString = "";
957     int defaultInt32 = 0;
958     Message message = makeProtoMap(ImmutableMap.of(defaultString, 1, "foo", defaultInt32));
959     Message dynamicMessage =
960         DynamicMessage.parseFrom(
961             descriptor, message.toByteString(), ExtensionRegistry.getEmptyRegistry());
962     expectThat(message).isEqualTo(dynamicMessage);
963   }
964 }
965