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 // Author: ksroka@google.com (Krzysztof Sroka)
9
10 #include "google/protobuf/util/field_comparator.h"
11
12 #include <limits>
13
14 #include <gtest/gtest.h>
15 #include "google/protobuf/descriptor.h"
16 #include "google/protobuf/unittest.pb.h"
17
18 namespace google {
19 namespace protobuf {
20 namespace util {
21 namespace {
22
23 using protobuf_unittest::TestAllTypes;
24
25 class DefaultFieldComparatorTest : public ::testing::Test {
26 protected:
SetUp()27 void SetUp() override { descriptor_ = TestAllTypes::descriptor(); }
28
29 const Descriptor* descriptor_;
30 DefaultFieldComparator comparator_;
31 TestAllTypes message_1_;
32 TestAllTypes message_2_;
33 };
34
TEST_F(DefaultFieldComparatorTest,RecursesIntoGroup)35 TEST_F(DefaultFieldComparatorTest, RecursesIntoGroup) {
36 const FieldDescriptor* field = descriptor_->FindFieldByName("optionalgroup");
37 EXPECT_EQ(
38 FieldComparator::RECURSE,
39 comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
40 }
41
TEST_F(DefaultFieldComparatorTest,RecursesIntoNestedMessage)42 TEST_F(DefaultFieldComparatorTest, RecursesIntoNestedMessage) {
43 const FieldDescriptor* field =
44 descriptor_->FindFieldByName("optional_nested_message");
45 EXPECT_EQ(
46 FieldComparator::RECURSE,
47 comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
48 }
49
TEST_F(DefaultFieldComparatorTest,RecursesIntoForeignMessage)50 TEST_F(DefaultFieldComparatorTest, RecursesIntoForeignMessage) {
51 const FieldDescriptor* field =
52 descriptor_->FindFieldByName("optional_foreign_message");
53 EXPECT_EQ(
54 FieldComparator::RECURSE,
55 comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
56 }
57
TEST_F(DefaultFieldComparatorTest,Int32Comparison)58 TEST_F(DefaultFieldComparatorTest, Int32Comparison) {
59 const FieldDescriptor* field = descriptor_->FindFieldByName("optional_int32");
60 message_1_.set_optional_int32(1);
61 message_2_.set_optional_int32(1);
62
63 EXPECT_EQ(FieldComparator::SAME, comparator_.Compare(message_1_, message_2_,
64 field, -1, -1, nullptr));
65
66 message_2_.set_optional_int32(-1);
67 EXPECT_EQ(
68 FieldComparator::DIFFERENT,
69 comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
70 }
71
TEST_F(DefaultFieldComparatorTest,Int64Comparison)72 TEST_F(DefaultFieldComparatorTest, Int64Comparison) {
73 const FieldDescriptor* field = descriptor_->FindFieldByName("optional_int64");
74 message_1_.set_optional_int64(1L);
75 message_2_.set_optional_int64(1L);
76
77 EXPECT_EQ(FieldComparator::SAME, comparator_.Compare(message_1_, message_2_,
78 field, -1, -1, nullptr));
79
80 message_2_.set_optional_int64(-1L);
81 EXPECT_EQ(
82 FieldComparator::DIFFERENT,
83 comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
84 }
85
TEST_F(DefaultFieldComparatorTest,UInt32Comparison)86 TEST_F(DefaultFieldComparatorTest, UInt32Comparison) {
87 const FieldDescriptor* field =
88 descriptor_->FindFieldByName("optional_uint32");
89 message_1_.set_optional_uint32(1);
90 message_2_.set_optional_uint32(1);
91
92 EXPECT_EQ(FieldComparator::SAME, comparator_.Compare(message_1_, message_2_,
93 field, -1, -1, nullptr));
94
95 message_2_.set_optional_uint32(2);
96 EXPECT_EQ(
97 FieldComparator::DIFFERENT,
98 comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
99 }
100
TEST_F(DefaultFieldComparatorTest,UInt64Comparison)101 TEST_F(DefaultFieldComparatorTest, UInt64Comparison) {
102 const FieldDescriptor* field =
103 descriptor_->FindFieldByName("optional_uint64");
104 message_1_.set_optional_uint64(1L);
105 message_2_.set_optional_uint64(1L);
106
107 EXPECT_EQ(FieldComparator::SAME, comparator_.Compare(message_1_, message_2_,
108 field, -1, -1, nullptr));
109
110 message_2_.set_optional_uint64(2L);
111 EXPECT_EQ(
112 FieldComparator::DIFFERENT,
113 comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
114 }
115
TEST_F(DefaultFieldComparatorTest,BooleanComparison)116 TEST_F(DefaultFieldComparatorTest, BooleanComparison) {
117 const FieldDescriptor* field = descriptor_->FindFieldByName("optional_bool");
118 message_1_.set_optional_bool(true);
119 message_2_.set_optional_bool(true);
120
121 EXPECT_EQ(FieldComparator::SAME, comparator_.Compare(message_1_, message_2_,
122 field, -1, -1, nullptr));
123
124 message_2_.set_optional_bool(false);
125 EXPECT_EQ(
126 FieldComparator::DIFFERENT,
127 comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
128 }
129
TEST_F(DefaultFieldComparatorTest,EnumComparison)130 TEST_F(DefaultFieldComparatorTest, EnumComparison) {
131 const FieldDescriptor* field =
132 descriptor_->FindFieldByName("optional_nested_enum");
133 message_1_.set_optional_nested_enum(TestAllTypes::BAR);
134 message_2_.set_optional_nested_enum(TestAllTypes::BAR);
135
136 EXPECT_EQ(FieldComparator::SAME, comparator_.Compare(message_1_, message_2_,
137 field, -1, -1, nullptr));
138
139 message_2_.set_optional_nested_enum(TestAllTypes::BAZ);
140 EXPECT_EQ(
141 FieldComparator::DIFFERENT,
142 comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
143 }
144
TEST_F(DefaultFieldComparatorTest,StringComparison)145 TEST_F(DefaultFieldComparatorTest, StringComparison) {
146 const FieldDescriptor* field =
147 descriptor_->FindFieldByName("optional_string");
148 message_1_.set_optional_string("foo");
149 message_2_.set_optional_string("foo");
150
151 EXPECT_EQ(FieldComparator::SAME, comparator_.Compare(message_1_, message_2_,
152 field, -1, -1, nullptr));
153
154 message_2_.set_optional_string("bar");
155 EXPECT_EQ(
156 FieldComparator::DIFFERENT,
157 comparator_.Compare(message_1_, message_2_, field, -1, -1, nullptr));
158 }
159
TEST_F(DefaultFieldComparatorTest,FloatingPointComparisonExact)160 TEST_F(DefaultFieldComparatorTest, FloatingPointComparisonExact) {
161 const FieldDescriptor* field_float =
162 descriptor_->FindFieldByName("optional_float");
163 const FieldDescriptor* field_double =
164 descriptor_->FindFieldByName("optional_double");
165
166 message_1_.set_optional_float(0.1f);
167 message_2_.set_optional_float(0.1f);
168 message_1_.set_optional_double(0.1);
169 message_2_.set_optional_double(0.1);
170
171 EXPECT_EQ(FieldComparator::SAME,
172 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
173 nullptr));
174 EXPECT_EQ(FieldComparator::SAME,
175 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
176 nullptr));
177
178 message_2_.set_optional_float(0.2f);
179 message_2_.set_optional_double(0.2);
180
181 EXPECT_EQ(FieldComparator::DIFFERENT,
182 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
183 nullptr));
184 EXPECT_EQ(FieldComparator::DIFFERENT,
185 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
186 nullptr));
187 }
188
TEST_F(DefaultFieldComparatorTest,FloatingPointComparisonApproximate)189 TEST_F(DefaultFieldComparatorTest, FloatingPointComparisonApproximate) {
190 const FieldDescriptor* field_float =
191 descriptor_->FindFieldByName("optional_float");
192 const FieldDescriptor* field_double =
193 descriptor_->FindFieldByName("optional_double");
194
195 message_1_.set_optional_float(2.300005f);
196 message_2_.set_optional_float(2.300006f);
197 message_1_.set_optional_double(2.3000000000000003);
198 message_2_.set_optional_double(2.3000000000000007);
199
200 // Approximate comparison depends on MathUtil, so we assert on MathUtil
201 // results first to check if that's where the failure was introduced.
202 ASSERT_NE(message_1_.optional_float(), message_2_.optional_float());
203 ASSERT_NE(message_1_.optional_double(), message_2_.optional_double());
204 ASSERT_FLOAT_EQ(message_1_.optional_float(), message_2_.optional_float());
205 ASSERT_DOUBLE_EQ(message_1_.optional_double(), message_2_.optional_double());
206
207 // DefaultFieldComparator's default float comparison mode is EXACT.
208 ASSERT_EQ(DefaultFieldComparator::EXACT, comparator_.float_comparison());
209 EXPECT_EQ(FieldComparator::DIFFERENT,
210 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
211 nullptr));
212 EXPECT_EQ(FieldComparator::DIFFERENT,
213 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
214 nullptr));
215
216 comparator_.set_float_comparison(DefaultFieldComparator::APPROXIMATE);
217
218 EXPECT_EQ(FieldComparator::SAME,
219 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
220 nullptr));
221 EXPECT_EQ(FieldComparator::SAME,
222 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
223 nullptr));
224 }
225
TEST_F(DefaultFieldComparatorTest,FloatingPointComparisonTreatNaNsAsEqual)226 TEST_F(DefaultFieldComparatorTest, FloatingPointComparisonTreatNaNsAsEqual) {
227 const FieldDescriptor* field_float =
228 descriptor_->FindFieldByName("optional_float");
229 const FieldDescriptor* field_double =
230 descriptor_->FindFieldByName("optional_double");
231
232 message_1_.set_optional_float(std::numeric_limits<float>::quiet_NaN());
233 message_2_.set_optional_float(std::numeric_limits<float>::quiet_NaN());
234 message_1_.set_optional_double(std::numeric_limits<double>::quiet_NaN());
235 message_2_.set_optional_double(std::numeric_limits<double>::quiet_NaN());
236
237 // DefaultFieldComparator's default float comparison mode is EXACT with
238 // treating NaNs as different.
239 ASSERT_EQ(DefaultFieldComparator::EXACT, comparator_.float_comparison());
240 ASSERT_EQ(false, comparator_.treat_nan_as_equal());
241 EXPECT_EQ(FieldComparator::DIFFERENT,
242 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
243 nullptr));
244 EXPECT_EQ(FieldComparator::DIFFERENT,
245 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
246 nullptr));
247 comparator_.set_float_comparison(DefaultFieldComparator::APPROXIMATE);
248 EXPECT_EQ(FieldComparator::DIFFERENT,
249 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
250 nullptr));
251 EXPECT_EQ(FieldComparator::DIFFERENT,
252 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
253 nullptr));
254
255 comparator_.set_treat_nan_as_equal(true);
256 ASSERT_EQ(true, comparator_.treat_nan_as_equal());
257 comparator_.set_float_comparison(DefaultFieldComparator::EXACT);
258 EXPECT_EQ(FieldComparator::SAME,
259 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
260 nullptr));
261 EXPECT_EQ(FieldComparator::SAME,
262 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
263 nullptr));
264 comparator_.set_float_comparison(DefaultFieldComparator::APPROXIMATE);
265 EXPECT_EQ(FieldComparator::SAME,
266 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
267 nullptr));
268 EXPECT_EQ(FieldComparator::SAME,
269 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
270 nullptr));
271 }
272
TEST_F(DefaultFieldComparatorTest,FloatingPointComparisonWithinFractionOrMargin)273 TEST_F(DefaultFieldComparatorTest,
274 FloatingPointComparisonWithinFractionOrMargin) {
275 const FieldDescriptor* field_float =
276 descriptor_->FindFieldByName("optional_float");
277 const FieldDescriptor* field_double =
278 descriptor_->FindFieldByName("optional_double");
279
280 message_1_.set_optional_float(100.0f);
281 message_2_.set_optional_float(109.9f);
282 message_1_.set_optional_double(100.0);
283 message_2_.set_optional_double(109.9);
284
285 comparator_.set_float_comparison(DefaultFieldComparator::APPROXIMATE);
286 EXPECT_EQ(FieldComparator::DIFFERENT,
287 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
288 nullptr));
289 EXPECT_EQ(FieldComparator::DIFFERENT,
290 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
291 nullptr));
292
293 // Should fail since the fraction is too low.
294 comparator_.SetFractionAndMargin(field_float, 0.01, 0.0);
295 comparator_.SetFractionAndMargin(field_double, 0.01, 0.0);
296
297 EXPECT_EQ(FieldComparator::DIFFERENT,
298 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
299 nullptr));
300 EXPECT_EQ(FieldComparator::DIFFERENT,
301 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
302 nullptr));
303
304 // Should fail since the margin is too low.
305 comparator_.SetFractionAndMargin(field_float, 0.0, 9.0);
306 comparator_.SetFractionAndMargin(field_double, 0.0, 9.0);
307 EXPECT_EQ(FieldComparator::DIFFERENT,
308 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
309 nullptr));
310 EXPECT_EQ(FieldComparator::DIFFERENT,
311 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
312 nullptr));
313
314 // Should succeed since the fraction is high enough.
315 comparator_.SetFractionAndMargin(field_float, 0.2, 0.0);
316 comparator_.SetFractionAndMargin(field_double, 0.2, 0.0);
317 EXPECT_EQ(FieldComparator::SAME,
318 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
319 nullptr));
320 EXPECT_EQ(FieldComparator::SAME,
321 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
322 nullptr));
323
324 // Should succeed since the margin is high enough.
325 comparator_.SetFractionAndMargin(field_float, 0.0, 10.0);
326 comparator_.SetFractionAndMargin(field_double, 0.0, 10.0);
327 EXPECT_EQ(FieldComparator::SAME,
328 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
329 nullptr));
330 EXPECT_EQ(FieldComparator::SAME,
331 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
332 nullptr));
333
334 // Setting values for one of the fields should not affect the other.
335 comparator_.SetFractionAndMargin(field_double, 0.0, 0.0);
336 EXPECT_EQ(FieldComparator::SAME,
337 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
338 nullptr));
339 EXPECT_EQ(FieldComparator::DIFFERENT,
340 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
341 nullptr));
342
343 // +inf should be equal even though they are not technically within margin or
344 // fraction.
345 message_1_.set_optional_float(std::numeric_limits<float>::infinity());
346 message_2_.set_optional_float(std::numeric_limits<float>::infinity());
347 message_1_.set_optional_double(std::numeric_limits<double>::infinity());
348 message_2_.set_optional_double(std::numeric_limits<double>::infinity());
349 comparator_.SetFractionAndMargin(field_float, 0.0, 0.0);
350 comparator_.SetFractionAndMargin(field_double, 0.0, 0.0);
351 EXPECT_EQ(FieldComparator::SAME,
352 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
353 nullptr));
354 EXPECT_EQ(FieldComparator::SAME,
355 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
356 nullptr));
357
358 // -inf should be equal even though they are not technically within margin or
359 // fraction.
360 message_1_.set_optional_float(-std::numeric_limits<float>::infinity());
361 message_2_.set_optional_float(-std::numeric_limits<float>::infinity());
362 message_1_.set_optional_double(-std::numeric_limits<double>::infinity());
363 message_2_.set_optional_double(-std::numeric_limits<double>::infinity());
364 comparator_.SetFractionAndMargin(field_float, 0.0, 0.0);
365 comparator_.SetFractionAndMargin(field_double, 0.0, 0.0);
366 EXPECT_EQ(FieldComparator::SAME,
367 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
368 nullptr));
369 EXPECT_EQ(FieldComparator::SAME,
370 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
371 nullptr));
372
373 // Finite values and inf should not be equal, even for a positive fraction.
374 message_1_.set_optional_float(std::numeric_limits<float>::infinity());
375 message_2_.set_optional_float(0.0f);
376 message_1_.set_optional_double(std::numeric_limits<double>::infinity());
377 message_2_.set_optional_double(0.0);
378 comparator_.SetFractionAndMargin(field_float, 0.1, 0.0);
379 comparator_.SetFractionAndMargin(field_double, 0.1, 0.0);
380 EXPECT_EQ(FieldComparator::DIFFERENT,
381 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
382 nullptr));
383 EXPECT_EQ(FieldComparator::DIFFERENT,
384 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
385 nullptr));
386 }
387
TEST_F(DefaultFieldComparatorTest,FloatingPointComparisonWithinDefaultFractionOrMargin)388 TEST_F(DefaultFieldComparatorTest,
389 FloatingPointComparisonWithinDefaultFractionOrMargin) {
390 const FieldDescriptor* field_float =
391 descriptor_->FindFieldByName("optional_float");
392 const FieldDescriptor* field_double =
393 descriptor_->FindFieldByName("optional_double");
394
395 message_1_.set_optional_float(100.0f);
396 message_2_.set_optional_float(109.9f);
397 message_1_.set_optional_double(100.0);
398 message_2_.set_optional_double(109.9);
399
400 comparator_.set_float_comparison(DefaultFieldComparator::APPROXIMATE);
401 EXPECT_EQ(FieldComparator::DIFFERENT,
402 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
403 nullptr));
404 EXPECT_EQ(FieldComparator::DIFFERENT,
405 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
406 nullptr));
407
408 // Set default fraction and margin.
409 comparator_.SetDefaultFractionAndMargin(0.01, 0.0);
410
411 // Float comparisons should fail since the fraction is too low.
412 EXPECT_EQ(FieldComparator::DIFFERENT,
413 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
414 nullptr));
415 EXPECT_EQ(FieldComparator::DIFFERENT,
416 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
417 nullptr));
418
419 // Set field-specific fraction and margin for one field (field_float) but not
420 // the other (field_double)
421 comparator_.SetFractionAndMargin(field_float, 0.2, 0.0);
422
423 // The field with the override should succeed, since its field-specific
424 // fraction is high enough.
425 EXPECT_EQ(FieldComparator::SAME,
426 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
427 nullptr));
428 // The field with no override should fail, since the default fraction is too
429 // low
430 EXPECT_EQ(FieldComparator::DIFFERENT,
431 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
432 nullptr));
433
434 // Set the default fraction and margin high enough so that fields that use
435 // the default should succeed
436 comparator_.SetDefaultFractionAndMargin(0.2, 0.0);
437 EXPECT_EQ(FieldComparator::SAME,
438 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
439 nullptr));
440
441 // The field with an override should still be OK
442 EXPECT_EQ(FieldComparator::SAME,
443 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
444 nullptr));
445
446 // Set fraction and margin for the field with an override to be too low
447 comparator_.SetFractionAndMargin(field_float, 0.01, 0.0);
448
449 // Now our default is high enough but field_float's override is too low.
450 EXPECT_EQ(FieldComparator::DIFFERENT,
451 comparator_.Compare(message_1_, message_2_, field_float, -1, -1,
452 nullptr));
453 EXPECT_EQ(FieldComparator::SAME,
454 comparator_.Compare(message_1_, message_2_, field_double, -1, -1,
455 nullptr));
456 }
457
458 // Simple test checking whether we compare values at correct indices.
TEST_F(DefaultFieldComparatorTest,RepeatedFieldComparison)459 TEST_F(DefaultFieldComparatorTest, RepeatedFieldComparison) {
460 const FieldDescriptor* field =
461 descriptor_->FindFieldByName("repeated_string");
462
463 message_1_.add_repeated_string("foo");
464 message_1_.add_repeated_string("bar");
465 message_2_.add_repeated_string("bar");
466 message_2_.add_repeated_string("baz");
467
468 EXPECT_EQ(FieldComparator::DIFFERENT,
469 comparator_.Compare(message_1_, message_2_, field, 0, 0, nullptr));
470 EXPECT_EQ(FieldComparator::DIFFERENT,
471 comparator_.Compare(message_1_, message_2_, field, 1, 1, nullptr));
472 EXPECT_EQ(FieldComparator::SAME,
473 comparator_.Compare(message_1_, message_2_, field, 1, 0, nullptr));
474 }
475
476 } // namespace
477 } // namespace util
478 } // namespace protobuf
479 } // namespace google
480