Skip to content

Commit 8bd3ef6

Browse files
java-team-github-botGoogle Java Core Libraries
authored and
Google Java Core Libraries
committedOct 27, 2023
Support deep comparison of unpacked Any messages in FieldNumberTree.
RELNOTES=Fixed a bug that caused ProtoTruth to ignore the contents of unpacked `Any` messages. This fix may cause tests to fail, since ProtoTruth will now check whether the message contents match. If so, you may need to change the values that your tests expect, or there may be a bug in the code under test that had been hidden by the Truth bug. Sorry for the trouble. PiperOrigin-RevId: 577171522
1 parent a12d848 commit 8bd3ef6

File tree

10 files changed

+261
-34
lines changed

10 files changed

+261
-34
lines changed
 

‎extensions/proto/src/main/java/com/google/common/truth/extensions/proto/AnyUtils.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,9 @@ static ExtensionRegistry defaultExtensionRegistry() {
6969
return DEFAULT_EXTENSION_REGISTRY;
7070
}
7171

72-
/** Unpack an `Any` proto using the TypeRegistry and ExtensionRegistry on `config`. */
73-
static Optional<Message> unpack(Message any, FluentEqualityConfig config) {
72+
/** Unpack an `Any` proto using the given TypeRegistry and ExtensionRegistry. */
73+
static Optional<Message> unpack(
74+
Message any, TypeRegistry typeRegistry, ExtensionRegistry extensionRegistry) {
7475
Preconditions.checkArgument(
7576
any.getDescriptorForType().equals(Any.getDescriptor()),
7677
"Expected type google.protobuf.Any, but was: %s",
@@ -80,13 +81,12 @@ static Optional<Message> unpack(Message any, FluentEqualityConfig config) {
8081
ByteString value = (ByteString) any.getField(valueFieldDescriptor());
8182

8283
try {
83-
Descriptor descriptor = config.useTypeRegistry().getDescriptorForTypeUrl(typeUrl);
84+
Descriptor descriptor = typeRegistry.getDescriptorForTypeUrl(typeUrl);
8485
if (descriptor == null) {
8586
return Optional.absent();
8687
}
8788

88-
Message defaultMessage =
89-
DynamicMessage.parseFrom(descriptor, value, config.useExtensionRegistry());
89+
Message defaultMessage = DynamicMessage.parseFrom(descriptor, value, extensionRegistry);
9090
return Optional.of(defaultMessage);
9191
} catch (InvalidProtocolBufferException e) {
9292
return Optional.absent();

‎extensions/proto/src/main/java/com/google/common/truth/extensions/proto/DiffResult.java

+3
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,9 @@ default void printFieldValue(SubScopeId subScopeId, Object o, StringBuilder sb)
557557
case UNKNOWN_FIELD_DESCRIPTOR:
558558
printFieldValue(subScopeId.unknownFieldDescriptor(), o, sb);
559559
return;
560+
case UNPACKED_ANY_VALUE_TYPE:
561+
printFieldValue(AnyUtils.valueFieldDescriptor(), o, sb);
562+
return;
560563
}
561564
throw new AssertionError(subScopeId.kind());
562565
}

‎extensions/proto/src/main/java/com/google/common/truth/extensions/proto/FieldNumberTree.java

+28-11
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616

1717
package com.google.common.truth.extensions.proto;
1818

19+
import com.google.common.base.Optional;
1920
import com.google.common.collect.Maps;
2021
import com.google.protobuf.Descriptors.FieldDescriptor;
22+
import com.google.protobuf.ExtensionRegistry;
2123
import com.google.protobuf.Message;
24+
import com.google.protobuf.TypeRegistry;
2225
import com.google.protobuf.UnknownFieldSet;
2326
import java.util.List;
2427
import java.util.Map;
@@ -62,7 +65,8 @@ boolean hasChild(SubScopeId subScopeId) {
6265
return children.containsKey(subScopeId);
6366
}
6467

65-
static FieldNumberTree fromMessage(Message message) {
68+
static FieldNumberTree fromMessage(
69+
Message message, TypeRegistry typeRegistry, ExtensionRegistry extensionRegistry) {
6670
FieldNumberTree tree = new FieldNumberTree();
6771

6872
// Known fields.
@@ -72,15 +76,25 @@ static FieldNumberTree fromMessage(Message message) {
7276
FieldNumberTree childTree = new FieldNumberTree();
7377
tree.children.put(subScopeId, childTree);
7478

75-
Object fieldValue = knownFieldValues.get(field);
76-
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
77-
if (field.isRepeated()) {
78-
List<?> valueList = (List<?>) fieldValue;
79-
for (Object value : valueList) {
80-
childTree.merge(fromMessage((Message) value));
79+
if (field.equals(AnyUtils.valueFieldDescriptor())) {
80+
// Handle Any protos specially.
81+
Optional<Message> unpackedAny = AnyUtils.unpack(message, typeRegistry, extensionRegistry);
82+
if (unpackedAny.isPresent()) {
83+
tree.children.put(
84+
SubScopeId.ofUnpackedAnyValueType(unpackedAny.get().getDescriptorForType()),
85+
fromMessage(unpackedAny.get(), typeRegistry, extensionRegistry));
86+
}
87+
} else {
88+
Object fieldValue = knownFieldValues.get(field);
89+
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
90+
if (field.isRepeated()) {
91+
List<?> valueList = (List<?>) fieldValue;
92+
for (Object value : valueList) {
93+
childTree.merge(fromMessage((Message) value, typeRegistry, extensionRegistry));
94+
}
95+
} else {
96+
childTree.merge(fromMessage((Message) fieldValue, typeRegistry, extensionRegistry));
8197
}
82-
} else {
83-
childTree.merge(fromMessage((Message) fieldValue));
8498
}
8599
}
86100
}
@@ -91,11 +105,14 @@ static FieldNumberTree fromMessage(Message message) {
91105
return tree;
92106
}
93107

94-
static FieldNumberTree fromMessages(Iterable<? extends Message> messages) {
108+
static FieldNumberTree fromMessages(
109+
Iterable<? extends Message> messages,
110+
TypeRegistry typeRegistry,
111+
ExtensionRegistry extensionRegistry) {
95112
FieldNumberTree tree = new FieldNumberTree();
96113
for (Message message : messages) {
97114
if (message != null) {
98-
tree.merge(fromMessage(message));
115+
tree.merge(fromMessage(message, typeRegistry, extensionRegistry));
99116
}
100117
}
101118
return tree;

‎extensions/proto/src/main/java/com/google/common/truth/extensions/proto/FieldScopeImpl.java

+11-4
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
import com.google.common.collect.Lists;
2929
import com.google.protobuf.Descriptors.Descriptor;
3030
import com.google.protobuf.Descriptors.FieldDescriptor;
31+
import com.google.protobuf.ExtensionRegistry;
3132
import com.google.protobuf.Message;
33+
import com.google.protobuf.TypeRegistry;
3234
import java.util.List;
3335

3436
/**
@@ -62,13 +64,17 @@ private static FieldScope create(
6264
// Instantiation methods.
6365
//////////////////////////////////////////////////////////////////////////////////////////////////
6466

65-
static FieldScope createFromSetFields(Message message) {
67+
static FieldScope createFromSetFields(
68+
Message message, TypeRegistry typeRegistry, ExtensionRegistry extensionRegistry) {
6669
return create(
67-
FieldScopeLogic.partialScope(message),
70+
FieldScopeLogic.partialScope(message, typeRegistry, extensionRegistry),
6871
Functions.constant(String.format("FieldScopes.fromSetFields({%s})", message.toString())));
6972
}
7073

71-
static FieldScope createFromSetFields(Iterable<? extends Message> messages) {
74+
static FieldScope createFromSetFields(
75+
Iterable<? extends Message> messages,
76+
TypeRegistry typeRegistry,
77+
ExtensionRegistry extensionRegistry) {
7278
if (emptyOrAllNull(messages)) {
7379
return create(
7480
FieldScopeLogic.none(),
@@ -82,7 +88,8 @@ static FieldScope createFromSetFields(Iterable<? extends Message> messages) {
8288
getDescriptors(messages));
8389

8490
return create(
85-
FieldScopeLogic.partialScope(messages, optDescriptor.get()),
91+
FieldScopeLogic.partialScope(
92+
messages, optDescriptor.get(), typeRegistry, extensionRegistry),
8693
Functions.constant(String.format("FieldScopes.fromSetFields(%s)", formatList(messages))));
8794
}
8895

‎extensions/proto/src/main/java/com/google/common/truth/extensions/proto/FieldScopeLogic.java

+23-7
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
import com.google.errorprone.annotations.ForOverride;
2929
import com.google.protobuf.Descriptors.Descriptor;
3030
import com.google.protobuf.Descriptors.FieldDescriptor;
31+
import com.google.protobuf.ExtensionRegistry;
3132
import com.google.protobuf.Message;
33+
import com.google.protobuf.TypeRegistry;
3234
import java.util.List;
3335

3436
/**
@@ -267,14 +269,21 @@ public String toString() {
267269
}
268270
}
269271

270-
static FieldScopeLogic partialScope(Message message) {
272+
static FieldScopeLogic partialScope(
273+
Message message, TypeRegistry typeRegistry, ExtensionRegistry extensionRegistry) {
271274
return new RootPartialScopeLogic(
272-
FieldNumberTree.fromMessage(message), message.toString(), message.getDescriptorForType());
275+
FieldNumberTree.fromMessage(message, typeRegistry, extensionRegistry),
276+
message.toString(),
277+
message.getDescriptorForType());
273278
}
274279

275-
static FieldScopeLogic partialScope(Iterable<? extends Message> messages, Descriptor descriptor) {
280+
static FieldScopeLogic partialScope(
281+
Iterable<? extends Message> messages,
282+
Descriptor descriptor,
283+
TypeRegistry typeRegistry,
284+
ExtensionRegistry extensionRegistry) {
276285
return new RootPartialScopeLogic(
277-
FieldNumberTree.fromMessages(messages),
286+
FieldNumberTree.fromMessages(messages, typeRegistry, extensionRegistry),
278287
Joiner.on(", ").useForNull("null").join(messages),
279288
descriptor);
280289
}
@@ -304,11 +313,18 @@ protected FieldMatcherLogicBase(boolean isRecursive) {
304313

305314
@Override
306315
final FieldScopeResult policyFor(Descriptor rootDescriptor, SubScopeId subScopeId) {
307-
if (subScopeId.kind() == SubScopeId.Kind.UNKNOWN_FIELD_DESCRIPTOR) {
308-
return FieldScopeResult.EXCLUDED_RECURSIVELY;
316+
FieldDescriptor fieldDescriptor = null;
317+
switch (subScopeId.kind()) {
318+
case FIELD_DESCRIPTOR:
319+
fieldDescriptor = subScopeId.fieldDescriptor();
320+
break;
321+
case UNPACKED_ANY_VALUE_TYPE:
322+
fieldDescriptor = AnyUtils.valueFieldDescriptor();
323+
break;
324+
case UNKNOWN_FIELD_DESCRIPTOR:
325+
return FieldScopeResult.EXCLUDED_RECURSIVELY;
309326
}
310327

311-
FieldDescriptor fieldDescriptor = subScopeId.fieldDescriptor();
312328
if (matchesFieldDescriptor(rootDescriptor, fieldDescriptor)) {
313329
return FieldScopeResult.of(/* included = */ true, isRecursive);
314330
}

‎extensions/proto/src/main/java/com/google/common/truth/extensions/proto/FieldScopes.java

+77-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
import static com.google.common.truth.extensions.proto.FieldScopeUtil.asList;
2020

2121
import com.google.protobuf.Descriptors.FieldDescriptor;
22+
import com.google.protobuf.ExtensionRegistry;
2223
import com.google.protobuf.Message;
24+
import com.google.protobuf.TypeRegistry;
2325

2426
/** Factory class for {@link FieldScope} instances. */
2527
public final class FieldScopes {
@@ -66,7 +68,58 @@ public final class FieldScopes {
6668
// Alternatively II, add Scope.PARTIAL support to ProtoFluentEquals, but with a different name and
6769
// explicit documentation that it may cause issues with Proto 3.
6870
public static FieldScope fromSetFields(Message message) {
69-
return FieldScopeImpl.createFromSetFields(message);
71+
return fromSetFields(
72+
message, AnyUtils.defaultTypeRegistry(), AnyUtils.defaultExtensionRegistry());
73+
}
74+
75+
/**
76+
* Returns a {@link FieldScope} which is constrained to precisely those specific field paths that
77+
* are explicitly set in the message. Note that, for version 3 protobufs, such a {@link
78+
* FieldScope} will omit fields in the provided message which are set to default values.
79+
*
80+
* <p>This can be used limit the scope of a comparison to a complex set of fields in a very brief
81+
* statement. Often, {@code message} is the expected half of a comparison about to be performed.
82+
*
83+
* <p>Example usage:
84+
*
85+
* <pre>{@code
86+
* Foo actual = Foo.newBuilder().setBar(3).setBaz(4).build();
87+
* Foo expected = Foo.newBuilder().setBar(3).setBaz(5).build();
88+
* // Fails, because actual.getBaz() != expected.getBaz().
89+
* assertThat(actual).isEqualTo(expected);
90+
*
91+
* Foo scope = Foo.newBuilder().setBar(2).build();
92+
* // Succeeds, because only the field 'bar' is compared.
93+
* assertThat(actual).withPartialScope(FieldScopes.fromSetFields(scope)).isEqualTo(expected);
94+
*
95+
* }</pre>
96+
*
97+
* <p>The returned {@link FieldScope} does not respect repeated field indices nor map keys. For
98+
* example, if the provided message sets different field values for different elements of a
99+
* repeated field, like so:
100+
*
101+
* <pre>{@code
102+
* sub_message: {
103+
* foo: "foo"
104+
* }
105+
* sub_message: {
106+
* bar: "bar"
107+
* }
108+
* }</pre>
109+
*
110+
* <p>The {@link FieldScope} will contain {@code sub_message.foo} and {@code sub_message.bar} for
111+
* *all* repeated {@code sub_messages}, including those beyond index 1.
112+
*
113+
* <p>If there are {@code google.protobuf.Any} protos anywhere within these messages, they will be
114+
* unpacked using the provided {@link TypeRegistry} and {@link ExtensionRegistry} to determine
115+
* which fields within them should be compared.
116+
*
117+
* @see ProtoFluentAssertion#unpackingAnyUsing
118+
* @since 1.2
119+
*/
120+
public static FieldScope fromSetFields(
121+
Message message, TypeRegistry typeRegistry, ExtensionRegistry extensionRegistry) {
122+
return FieldScopeImpl.createFromSetFields(message, typeRegistry, extensionRegistry);
70123
}
71124

72125
/**
@@ -89,7 +142,29 @@ public static FieldScope fromSetFields(
89142
* or the {@link FieldScope} for the merge of all the messages. These are equivalent.
90143
*/
91144
public static FieldScope fromSetFields(Iterable<? extends Message> messages) {
92-
return FieldScopeImpl.createFromSetFields(messages);
145+
return fromSetFields(
146+
messages, AnyUtils.defaultTypeRegistry(), AnyUtils.defaultExtensionRegistry());
147+
}
148+
149+
/**
150+
* Creates a {@link FieldScope} covering the fields set in every message in the provided list of
151+
* messages, with the same semantics as in {@link #fromSetFields(Message)}.
152+
*
153+
* <p>This can be thought of as the union of the {@link FieldScope}s for each individual message,
154+
* or the {@link FieldScope} for the merge of all the messages. These are equivalent.
155+
*
156+
* <p>If there are {@code google.protobuf.Any} protos anywhere within these messages, they will be
157+
* unpacked using the provided {@link TypeRegistry} and {@link ExtensionRegistry} to determine
158+
* which fields within them should be compared.
159+
*
160+
* @see ProtoFluentAssertion#unpackingAnyUsing
161+
* @since 1.2
162+
*/
163+
public static FieldScope fromSetFields(
164+
Iterable<? extends Message> messages,
165+
TypeRegistry typeRegistry,
166+
ExtensionRegistry extensionRegistry) {
167+
return FieldScopeImpl.createFromSetFields(messages, typeRegistry, extensionRegistry);
93168
}
94169

95170
/**

‎extensions/proto/src/main/java/com/google/common/truth/extensions/proto/FluentEqualityConfig.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,11 @@ final FluentEqualityConfig withExpectedMessages(Iterable<? extends Message> mess
273273
Builder builder = toBuilder().setHasExpectedMessages(true);
274274
if (compareExpectedFieldsOnly()) {
275275
builder.setCompareFieldsScope(
276-
FieldScopeLogic.and(compareFieldsScope(), FieldScopes.fromSetFields(messages).logic()));
276+
FieldScopeLogic.and(
277+
compareFieldsScope(),
278+
FieldScopeImpl.createFromSetFields(
279+
messages, useTypeRegistry(), useExtensionRegistry())
280+
.logic()));
277281
}
278282
return builder.build();
279283
}

‎extensions/proto/src/main/java/com/google/common/truth/extensions/proto/ProtoTruthMessageDifferencer.java

+8-3
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,10 @@ private DiffResult diffAnyMessages(
221221
if (shouldCompareValue == FieldScopeResult.EXCLUDED_RECURSIVELY) {
222222
valueDiffResult = SingularField.ignored(name(AnyUtils.valueFieldDescriptor()));
223223
} else {
224-
Optional<Message> unpackedActual = AnyUtils.unpack(actual, config);
225-
Optional<Message> unpackedExpected = AnyUtils.unpack(expected, config);
224+
Optional<Message> unpackedActual =
225+
AnyUtils.unpack(actual, config.useTypeRegistry(), config.useExtensionRegistry());
226+
Optional<Message> unpackedExpected =
227+
AnyUtils.unpack(expected, config.useTypeRegistry(), config.useExtensionRegistry());
226228
if (unpackedActual.isPresent()
227229
&& unpackedExpected.isPresent()
228230
&& descriptorsMatch(unpackedActual.get(), unpackedExpected.get())) {
@@ -235,7 +237,10 @@ && descriptorsMatch(unpackedActual.get(), unpackedExpected.get())) {
235237
shouldCompareValue == FieldScopeResult.EXCLUDED_NONRECURSIVELY,
236238
AnyUtils.valueFieldDescriptor(),
237239
name(AnyUtils.valueFieldDescriptor()),
238-
config.subScope(rootDescriptor, AnyUtils.valueSubScopeId()));
240+
config.subScope(
241+
rootDescriptor,
242+
SubScopeId.ofUnpackedAnyValueType(
243+
unpackedActual.get().getDescriptorForType())));
239244
} else {
240245
valueDiffResult =
241246
compareSingularValue(

‎extensions/proto/src/main/java/com/google/common/truth/extensions/proto/SubScopeId.java

+11-1
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@
1717
package com.google.common.truth.extensions.proto;
1818

1919
import com.google.auto.value.AutoOneOf;
20+
import com.google.protobuf.Descriptors.Descriptor;
2021
import com.google.protobuf.Descriptors.FieldDescriptor;
2122

2223
@AutoOneOf(SubScopeId.Kind.class)
2324
abstract class SubScopeId {
2425
enum Kind {
2526
FIELD_DESCRIPTOR,
26-
UNKNOWN_FIELD_DESCRIPTOR;
27+
UNKNOWN_FIELD_DESCRIPTOR,
28+
UNPACKED_ANY_VALUE_TYPE;
2729
}
2830

2931
abstract Kind kind();
@@ -32,6 +34,8 @@ enum Kind {
3234

3335
abstract UnknownFieldDescriptor unknownFieldDescriptor();
3436

37+
abstract Descriptor unpackedAnyValueType();
38+
3539
/** Returns a short, human-readable version of this identifier. */
3640
final String shortName() {
3741
switch (kind()) {
@@ -41,6 +45,8 @@ final String shortName() {
4145
: fieldDescriptor().getName();
4246
case UNKNOWN_FIELD_DESCRIPTOR:
4347
return String.valueOf(unknownFieldDescriptor().fieldNumber());
48+
case UNPACKED_ANY_VALUE_TYPE:
49+
return AnyUtils.valueFieldDescriptor().getName();
4450
}
4551
throw new AssertionError(kind());
4652
}
@@ -52,4 +58,8 @@ static SubScopeId of(FieldDescriptor fieldDescriptor) {
5258
static SubScopeId of(UnknownFieldDescriptor unknownFieldDescriptor) {
5359
return AutoOneOf_SubScopeId.unknownFieldDescriptor(unknownFieldDescriptor);
5460
}
61+
62+
static SubScopeId ofUnpackedAnyValueType(Descriptor unpackedAnyValueType) {
63+
return AutoOneOf_SubScopeId.unpackedAnyValueType(unpackedAnyValueType);
64+
}
5565
}

‎extensions/proto/src/test/java/com/google/common/truth/extensions/proto/FieldScopesTest.java

+90
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,96 @@ public void testIgnoringFieldOfAnyMessage() throws Exception {
384384
.contains("modified: o_any_message.value.r_string[0]: \"foo\" -> \"bar\"");
385385
}
386386

387+
@Test
388+
public void testAnyMessageComparingExpectedFieldsOnly() throws Exception {
389+
390+
String typeUrl =
391+
isProto3()
392+
? "type.googleapis.com/com.google.common.truth.extensions.proto.SubTestMessage3"
393+
: "type.googleapis.com/com.google.common.truth.extensions.proto.SubTestMessage2";
394+
395+
Message message = parse("o_any_message { [" + typeUrl + "]: { o_int: 2 } }");
396+
Message eqMessage =
397+
parse("o_any_message { [" + typeUrl + "]: { o_int: 2 r_string: \"foo\" } }");
398+
Message diffMessage =
399+
parse("o_any_message { [" + typeUrl + "]: { o_int: 3 r_string: \"bar\" } }");
400+
401+
expectThat(eqMessage)
402+
.unpackingAnyUsing(getTypeRegistry(), getExtensionRegistry())
403+
.comparingExpectedFieldsOnly()
404+
.isEqualTo(message);
405+
expectThat(diffMessage)
406+
.unpackingAnyUsing(getTypeRegistry(), getExtensionRegistry())
407+
.comparingExpectedFieldsOnly()
408+
.isNotEqualTo(message);
409+
}
410+
411+
@Test
412+
public void testInvalidAnyMessageComparingExpectedFieldsOnly() throws Exception {
413+
414+
Message message = parse("o_any_message { type_url: 'invalid-type' value: 'abc123' }");
415+
Message eqMessage = parse("o_any_message { type_url: 'invalid-type' value: 'abc123' }");
416+
Message diffMessage = parse("o_any_message { type_url: 'invalid-type' value: 'def456' }");
417+
418+
expectThat(eqMessage)
419+
.unpackingAnyUsing(getTypeRegistry(), getExtensionRegistry())
420+
.comparingExpectedFieldsOnly()
421+
.isEqualTo(message);
422+
expectThat(diffMessage)
423+
.unpackingAnyUsing(getTypeRegistry(), getExtensionRegistry())
424+
.comparingExpectedFieldsOnly()
425+
.isNotEqualTo(message);
426+
}
427+
428+
@Test
429+
public void testDifferentAnyMessagesComparingExpectedFieldsOnly() throws Exception {
430+
431+
// 'o_int' and 'o_float' have the same field numbers in both messages. However, to compare
432+
// accurately, we incorporate the unpacked Descriptor type into the FieldNumberTree as well to
433+
// disambiguate.
434+
String typeUrl1 =
435+
isProto3()
436+
? "type.googleapis.com/com.google.common.truth.extensions.proto.SubTestMessage3"
437+
: "type.googleapis.com/com.google.common.truth.extensions.proto.SubTestMessage2";
438+
String typeUrl2 =
439+
isProto3()
440+
? "type.googleapis.com/com.google.common.truth.extensions.proto.SubSubTestMessage3"
441+
: "type.googleapis.com/com.google.common.truth.extensions.proto.SubSubTestMessage2";
442+
443+
Message message =
444+
parse(
445+
"r_any_message { ["
446+
+ typeUrl1
447+
+ "]: { o_int: 2 } } r_any_message { ["
448+
+ typeUrl2
449+
+ "]: { o_float: 3.1 } }");
450+
Message eqMessage =
451+
parse(
452+
"r_any_message { ["
453+
+ typeUrl1
454+
+ "]: { o_int: 2 o_float: 1.9 } } r_any_message { ["
455+
+ typeUrl2
456+
+ "]: { o_int: 5 o_float: 3.1 } }");
457+
Message diffMessage =
458+
parse(
459+
"r_any_message { ["
460+
+ typeUrl1
461+
+ "]: { o_int: 5 o_float: 3.1 } } r_any_message { ["
462+
+ typeUrl2
463+
+ "]: { o_int: 2 o_float: 1.9 } }");
464+
465+
expectThat(eqMessage)
466+
.unpackingAnyUsing(getTypeRegistry(), getExtensionRegistry())
467+
.ignoringRepeatedFieldOrder()
468+
.comparingExpectedFieldsOnly()
469+
.isEqualTo(message);
470+
expectThat(diffMessage)
471+
.unpackingAnyUsing(getTypeRegistry(), getExtensionRegistry())
472+
.ignoringRepeatedFieldOrder()
473+
.comparingExpectedFieldsOnly()
474+
.isNotEqualTo(message);
475+
}
476+
387477
@Test
388478
public void testIgnoringAllButOneFieldOfSubMessage() {
389479
// Consider all of TestMessage, but none of o_sub_test_message, except

0 commit comments

Comments
 (0)
Please sign in to comment.