1// Protocol Buffers - Google's data interchange format 2// Copyright 2008 Google Inc. All rights reserved. 3// https://developers.google.com/protocol-buffers/ 4// 5// Redistribution and use in source and binary forms, with or without 6// modification, are permitted provided that the following conditions are 7// met: 8// 9// * Redistributions of source code must retain the above copyright 10// notice, this list of conditions and the following disclaimer. 11// * Redistributions in binary form must reproduce the above 12// copyright notice, this list of conditions and the following disclaimer 13// in the documentation and/or other materials provided with the 14// distribution. 15// * Neither the name of Google Inc. nor the names of its 16// contributors may be used to endorse or promote products derived from 17// this software without specific prior written permission. 18// 19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31#include <google/protobuf/util/field_mask_util.h> 32 33#include <algorithm> 34 35#include <google/protobuf/stubs/logging.h> 36#include <google/protobuf/stubs/common.h> 37#include <google/protobuf/field_mask.pb.h> 38#include <google/protobuf/unittest.pb.h> 39#include <google/protobuf/test_util.h> 40#include <gtest/gtest.h> 41 42namespace google { 43namespace protobuf { 44namespace util { 45 46class SnakeCaseCamelCaseTest : public ::testing::Test { 47 protected: 48 string SnakeCaseToCamelCase(const string& input) { 49 string output; 50 if (FieldMaskUtil::SnakeCaseToCamelCase(input, &output)) { 51 return output; 52 } else { 53 return "#FAIL#"; 54 } 55 } 56 57 string CamelCaseToSnakeCase(const string& input) { 58 string output; 59 if (FieldMaskUtil::CamelCaseToSnakeCase(input, &output)) { 60 return output; 61 } else { 62 return "#FAIL#"; 63 } 64 } 65}; 66 67namespace { 68 69TEST_F(SnakeCaseCamelCaseTest, SnakeToCamel) { 70 EXPECT_EQ("fooBar", SnakeCaseToCamelCase("foo_bar")); 71 EXPECT_EQ("FooBar", SnakeCaseToCamelCase("_foo_bar")); 72 EXPECT_EQ("foo3Bar", SnakeCaseToCamelCase("foo3_bar")); 73 // No uppercase letter is allowed. 74 EXPECT_EQ("#FAIL#", SnakeCaseToCamelCase("Foo")); 75 // Any character after a "_" must be a lowercase letter. 76 // 1. "_" cannot be followed by another "_". 77 // 2. "_" cannot be followed by a digit. 78 // 3. "_" cannot appear as the last character. 79 EXPECT_EQ("#FAIL#", SnakeCaseToCamelCase("foo__bar")); 80 EXPECT_EQ("#FAIL#", SnakeCaseToCamelCase("foo_3bar")); 81 EXPECT_EQ("#FAIL#", SnakeCaseToCamelCase("foo_bar_")); 82} 83 84TEST_F(SnakeCaseCamelCaseTest, CamelToSnake) { 85 EXPECT_EQ("foo_bar", CamelCaseToSnakeCase("fooBar")); 86 EXPECT_EQ("_foo_bar", CamelCaseToSnakeCase("FooBar")); 87 EXPECT_EQ("foo3_bar", CamelCaseToSnakeCase("foo3Bar")); 88 // "_"s are not allowed. 89 EXPECT_EQ("#FAIL#", CamelCaseToSnakeCase("foo_bar")); 90} 91 92TEST_F(SnakeCaseCamelCaseTest, RoundTripTest) { 93 // Enumerates all possible snake_case names and test that converting it to 94 // camelCase and then to snake_case again will yield the original name. 95 string name = "___abc123"; 96 std::sort(name.begin(), name.end()); 97 do { 98 string camelName = SnakeCaseToCamelCase(name); 99 if (camelName != "#FAIL#") { 100 EXPECT_EQ(name, CamelCaseToSnakeCase(camelName)); 101 } 102 } while (std::next_permutation(name.begin(), name.end())); 103 104 // Enumerates all possible camelCase names and test that converting it to 105 // snake_case and then to camelCase again will yield the original name. 106 name = "abcABC123"; 107 std::sort(name.begin(), name.end()); 108 do { 109 string camelName = CamelCaseToSnakeCase(name); 110 if (camelName != "#FAIL#") { 111 EXPECT_EQ(name, SnakeCaseToCamelCase(camelName)); 112 } 113 } while (std::next_permutation(name.begin(), name.end())); 114} 115 116using protobuf_unittest::TestAllTypes; 117using protobuf_unittest::NestedTestAllTypes; 118using google::protobuf::FieldMask; 119 120TEST(FieldMaskUtilTest, StringFormat) { 121 FieldMask mask; 122 EXPECT_EQ("", FieldMaskUtil::ToString(mask)); 123 mask.add_paths("foo_bar"); 124 EXPECT_EQ("foo_bar", FieldMaskUtil::ToString(mask)); 125 mask.add_paths("baz_quz"); 126 EXPECT_EQ("foo_bar,baz_quz", FieldMaskUtil::ToString(mask)); 127 128 FieldMaskUtil::FromString("", &mask); 129 EXPECT_EQ(0, mask.paths_size()); 130 FieldMaskUtil::FromString("fooBar", &mask); 131 EXPECT_EQ(1, mask.paths_size()); 132 EXPECT_EQ("fooBar", mask.paths(0)); 133 FieldMaskUtil::FromString("fooBar,bazQuz", &mask); 134 EXPECT_EQ(2, mask.paths_size()); 135 EXPECT_EQ("fooBar", mask.paths(0)); 136 EXPECT_EQ("bazQuz", mask.paths(1)); 137} 138 139TEST(FieldMaskUtilTest, JsonStringFormat) { 140 FieldMask mask; 141 string value; 142 EXPECT_TRUE(FieldMaskUtil::ToJsonString(mask, &value)); 143 EXPECT_EQ("", value); 144 mask.add_paths("foo_bar"); 145 EXPECT_TRUE(FieldMaskUtil::ToJsonString(mask, &value)); 146 EXPECT_EQ("fooBar", value); 147 mask.add_paths("bar_quz"); 148 EXPECT_TRUE(FieldMaskUtil::ToJsonString(mask, &value)); 149 EXPECT_EQ("fooBar,barQuz", value); 150 151 FieldMaskUtil::FromJsonString("", &mask); 152 EXPECT_EQ(0, mask.paths_size()); 153 FieldMaskUtil::FromJsonString("fooBar", &mask); 154 EXPECT_EQ(1, mask.paths_size()); 155 EXPECT_EQ("foo_bar", mask.paths(0)); 156 FieldMaskUtil::FromJsonString("fooBar,bazQuz", &mask); 157 EXPECT_EQ(2, mask.paths_size()); 158 EXPECT_EQ("foo_bar", mask.paths(0)); 159 EXPECT_EQ("baz_quz", mask.paths(1)); 160} 161 162TEST(FieldMaskUtilTest, TestIsVaildPath) { 163 EXPECT_TRUE(FieldMaskUtil::IsValidPath<TestAllTypes>("optional_int32")); 164 EXPECT_FALSE(FieldMaskUtil::IsValidPath<TestAllTypes>("optional_nonexist")); 165 EXPECT_TRUE( 166 FieldMaskUtil::IsValidPath<TestAllTypes>("optional_nested_message.bb")); 167 EXPECT_FALSE(FieldMaskUtil::IsValidPath<TestAllTypes>( 168 "optional_nested_message.nonexist")); 169 // FieldMask cannot be used to specify sub-fields of a repeated message. 170 EXPECT_FALSE( 171 FieldMaskUtil::IsValidPath<TestAllTypes>("repeated_nested_message.bb")); 172} 173 174TEST(FieldMaskUtilTest, TestIsValidFieldMask) { 175 FieldMask mask; 176 FieldMaskUtil::FromString("optional_int32,optional_nested_message.bb", &mask); 177 EXPECT_TRUE(FieldMaskUtil::IsValidFieldMask<TestAllTypes>(mask)); 178 179 FieldMaskUtil::FromString( 180 "optional_int32,optional_nested_message.bb,optional_nonexist", &mask); 181 EXPECT_FALSE(FieldMaskUtil::IsValidFieldMask<TestAllTypes>(mask)); 182} 183 184TEST(FieldMaskUtilTest, TestGetFieldMaskForAllFields) { 185 FieldMask mask; 186 FieldMaskUtil::GetFieldMaskForAllFields<TestAllTypes::NestedMessage>(&mask); 187 EXPECT_EQ(1, mask.paths_size()); 188 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("bb", mask)); 189 190 FieldMaskUtil::GetFieldMaskForAllFields<TestAllTypes>(&mask); 191 EXPECT_EQ(76, mask.paths_size()); 192 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_int32", mask)); 193 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_int64", mask)); 194 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_uint32", mask)); 195 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_uint64", mask)); 196 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_sint32", mask)); 197 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_sint64", mask)); 198 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_fixed32", mask)); 199 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_fixed64", mask)); 200 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_sfixed32", mask)); 201 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_sfixed64", mask)); 202 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_float", mask)); 203 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_double", mask)); 204 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_bool", mask)); 205 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_string", mask)); 206 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_bytes", mask)); 207 EXPECT_TRUE( 208 FieldMaskUtil::IsPathInFieldMask("optional_nested_message", mask)); 209 EXPECT_TRUE( 210 FieldMaskUtil::IsPathInFieldMask("optional_foreign_message", mask)); 211 EXPECT_TRUE( 212 FieldMaskUtil::IsPathInFieldMask("optional_import_message", mask)); 213 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_nested_enum", mask)); 214 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_foreign_enum", mask)); 215 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_import_enum", mask)); 216 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_int32", mask)); 217 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_int64", mask)); 218 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_uint32", mask)); 219 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_uint64", mask)); 220 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_sint32", mask)); 221 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_sint64", mask)); 222 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_fixed32", mask)); 223 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_fixed64", mask)); 224 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_sfixed32", mask)); 225 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_sfixed64", mask)); 226 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_float", mask)); 227 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_double", mask)); 228 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_bool", mask)); 229 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_string", mask)); 230 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_bytes", mask)); 231 EXPECT_TRUE( 232 FieldMaskUtil::IsPathInFieldMask("repeated_nested_message", mask)); 233 EXPECT_TRUE( 234 FieldMaskUtil::IsPathInFieldMask("repeated_foreign_message", mask)); 235 EXPECT_TRUE( 236 FieldMaskUtil::IsPathInFieldMask("repeated_import_message", mask)); 237 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_nested_enum", mask)); 238 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_foreign_enum", mask)); 239 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_import_enum", mask)); 240} 241 242TEST(FieldMaskUtilTest, TestToCanonicalForm) { 243 FieldMask in, out; 244 // Paths will be sorted. 245 FieldMaskUtil::FromString("baz.quz,bar,foo", &in); 246 FieldMaskUtil::ToCanonicalForm(in, &out); 247 EXPECT_EQ("bar,baz.quz,foo", FieldMaskUtil::ToString(out)); 248 // Duplicated paths will be removed. 249 FieldMaskUtil::FromString("foo,bar,foo", &in); 250 FieldMaskUtil::ToCanonicalForm(in, &out); 251 EXPECT_EQ("bar,foo", FieldMaskUtil::ToString(out)); 252 // Sub-paths of other paths will be removed. 253 FieldMaskUtil::FromString("foo.b1,bar.b1,foo.b2,bar", &in); 254 FieldMaskUtil::ToCanonicalForm(in, &out); 255 EXPECT_EQ("bar,foo.b1,foo.b2", FieldMaskUtil::ToString(out)); 256 257 // Test more deeply nested cases. 258 FieldMaskUtil::FromString( 259 "foo.bar.baz1," 260 "foo.bar.baz2.quz," 261 "foo.bar.baz2", 262 &in); 263 FieldMaskUtil::ToCanonicalForm(in, &out); 264 EXPECT_EQ("foo.bar.baz1,foo.bar.baz2", FieldMaskUtil::ToString(out)); 265 FieldMaskUtil::FromString( 266 "foo.bar.baz1," 267 "foo.bar.baz2," 268 "foo.bar.baz2.quz", 269 &in); 270 FieldMaskUtil::ToCanonicalForm(in, &out); 271 EXPECT_EQ("foo.bar.baz1,foo.bar.baz2", FieldMaskUtil::ToString(out)); 272 FieldMaskUtil::FromString( 273 "foo.bar.baz1," 274 "foo.bar.baz2," 275 "foo.bar.baz2.quz," 276 "foo.bar", 277 &in); 278 FieldMaskUtil::ToCanonicalForm(in, &out); 279 EXPECT_EQ("foo.bar", FieldMaskUtil::ToString(out)); 280 FieldMaskUtil::FromString( 281 "foo.bar.baz1," 282 "foo.bar.baz2," 283 "foo.bar.baz2.quz," 284 "foo", 285 &in); 286 FieldMaskUtil::ToCanonicalForm(in, &out); 287 EXPECT_EQ("foo", FieldMaskUtil::ToString(out)); 288} 289 290TEST(FieldMaskUtilTest, TestUnion) { 291 FieldMask mask1, mask2, out; 292 // Test cases without overlapping. 293 FieldMaskUtil::FromString("foo,baz", &mask1); 294 FieldMaskUtil::FromString("bar,quz", &mask2); 295 FieldMaskUtil::Union(mask1, mask2, &out); 296 EXPECT_EQ("bar,baz,foo,quz", FieldMaskUtil::ToString(out)); 297 // Overlap with duplicated paths. 298 FieldMaskUtil::FromString("foo,baz.bb", &mask1); 299 FieldMaskUtil::FromString("baz.bb,quz", &mask2); 300 FieldMaskUtil::Union(mask1, mask2, &out); 301 EXPECT_EQ("baz.bb,foo,quz", FieldMaskUtil::ToString(out)); 302 // Overlap with paths covering some other paths. 303 FieldMaskUtil::FromString("foo.bar.baz,quz", &mask1); 304 FieldMaskUtil::FromString("foo.bar,bar", &mask2); 305 FieldMaskUtil::Union(mask1, mask2, &out); 306 EXPECT_EQ("bar,foo.bar,quz", FieldMaskUtil::ToString(out)); 307} 308 309TEST(FieldMaskUtilTest, TestIntersect) { 310 FieldMask mask1, mask2, out; 311 // Test cases without overlapping. 312 FieldMaskUtil::FromString("foo,baz", &mask1); 313 FieldMaskUtil::FromString("bar,quz", &mask2); 314 FieldMaskUtil::Intersect(mask1, mask2, &out); 315 EXPECT_EQ("", FieldMaskUtil::ToString(out)); 316 // Overlap with duplicated paths. 317 FieldMaskUtil::FromString("foo,baz.bb", &mask1); 318 FieldMaskUtil::FromString("baz.bb,quz", &mask2); 319 FieldMaskUtil::Intersect(mask1, mask2, &out); 320 EXPECT_EQ("baz.bb", FieldMaskUtil::ToString(out)); 321 // Overlap with paths covering some other paths. 322 FieldMaskUtil::FromString("foo.bar.baz,quz", &mask1); 323 FieldMaskUtil::FromString("foo.bar,bar", &mask2); 324 FieldMaskUtil::Intersect(mask1, mask2, &out); 325 EXPECT_EQ("foo.bar.baz", FieldMaskUtil::ToString(out)); 326} 327 328TEST(FieldMaskUtilTest, TestIspathInFieldMask) { 329 FieldMask mask; 330 FieldMaskUtil::FromString("foo.bar", &mask); 331 EXPECT_FALSE(FieldMaskUtil::IsPathInFieldMask("", mask)); 332 EXPECT_FALSE(FieldMaskUtil::IsPathInFieldMask("foo", mask)); 333 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("foo.bar", mask)); 334 EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("foo.bar.baz", mask)); 335 EXPECT_FALSE(FieldMaskUtil::IsPathInFieldMask("foo.bar0.baz", mask)); 336} 337 338TEST(FieldMaskUtilTest, MergeMessage) { 339 TestAllTypes src, dst; 340 TestUtil::SetAllFields(&src); 341 FieldMaskUtil::MergeOptions options; 342 343#define TEST_MERGE_ONE_PRIMITIVE_FIELD(field_name) \ 344 { \ 345 TestAllTypes tmp; \ 346 tmp.set_##field_name(src.field_name()); \ 347 FieldMask mask; \ 348 mask.add_paths(#field_name); \ 349 dst.Clear(); \ 350 FieldMaskUtil::MergeMessageTo(src, mask, options, &dst); \ 351 EXPECT_EQ(tmp.DebugString(), dst.DebugString()); \ 352 } 353 TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_int32) 354 TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_int64) 355 TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_uint32) 356 TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_uint64) 357 TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_sint32) 358 TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_sint64) 359 TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_fixed32) 360 TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_fixed64) 361 TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_sfixed32) 362 TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_sfixed64) 363 TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_float) 364 TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_double) 365 TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_bool) 366 TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_string) 367 TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_bytes) 368 TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_nested_enum) 369 TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_foreign_enum) 370 TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_import_enum) 371#undef TEST_MERGE_ONE_PRIMITIVE_FIELD 372 373#define TEST_MERGE_ONE_FIELD(field_name) \ 374 { \ 375 TestAllTypes tmp; \ 376 *tmp.mutable_##field_name() = src.field_name(); \ 377 FieldMask mask; \ 378 mask.add_paths(#field_name); \ 379 dst.Clear(); \ 380 FieldMaskUtil::MergeMessageTo(src, mask, options, &dst); \ 381 EXPECT_EQ(tmp.DebugString(), dst.DebugString()); \ 382 } 383 TEST_MERGE_ONE_FIELD(optional_nested_message) 384 TEST_MERGE_ONE_FIELD(optional_foreign_message) 385 TEST_MERGE_ONE_FIELD(optional_import_message) 386 387 TEST_MERGE_ONE_FIELD(repeated_int32) 388 TEST_MERGE_ONE_FIELD(repeated_int64) 389 TEST_MERGE_ONE_FIELD(repeated_uint32) 390 TEST_MERGE_ONE_FIELD(repeated_uint64) 391 TEST_MERGE_ONE_FIELD(repeated_sint32) 392 TEST_MERGE_ONE_FIELD(repeated_sint64) 393 TEST_MERGE_ONE_FIELD(repeated_fixed32) 394 TEST_MERGE_ONE_FIELD(repeated_fixed64) 395 TEST_MERGE_ONE_FIELD(repeated_sfixed32) 396 TEST_MERGE_ONE_FIELD(repeated_sfixed64) 397 TEST_MERGE_ONE_FIELD(repeated_float) 398 TEST_MERGE_ONE_FIELD(repeated_double) 399 TEST_MERGE_ONE_FIELD(repeated_bool) 400 TEST_MERGE_ONE_FIELD(repeated_string) 401 TEST_MERGE_ONE_FIELD(repeated_bytes) 402 TEST_MERGE_ONE_FIELD(repeated_nested_message) 403 TEST_MERGE_ONE_FIELD(repeated_foreign_message) 404 TEST_MERGE_ONE_FIELD(repeated_import_message) 405 TEST_MERGE_ONE_FIELD(repeated_nested_enum) 406 TEST_MERGE_ONE_FIELD(repeated_foreign_enum) 407 TEST_MERGE_ONE_FIELD(repeated_import_enum) 408#undef TEST_MERGE_ONE_FIELD 409 410 // Test merge nested fields. 411 NestedTestAllTypes nested_src, nested_dst; 412 nested_src.mutable_child()->mutable_payload()->set_optional_int32(1234); 413 nested_src.mutable_child() 414 ->mutable_child() 415 ->mutable_payload() 416 ->set_optional_int32(5678); 417 FieldMask mask; 418 FieldMaskUtil::FromString("child.payload", &mask); 419 FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst); 420 EXPECT_EQ(1234, nested_dst.child().payload().optional_int32()); 421 EXPECT_EQ(0, nested_dst.child().child().payload().optional_int32()); 422 423 FieldMaskUtil::FromString("child.child.payload", &mask); 424 FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst); 425 EXPECT_EQ(1234, nested_dst.child().payload().optional_int32()); 426 EXPECT_EQ(5678, nested_dst.child().child().payload().optional_int32()); 427 428 nested_dst.Clear(); 429 FieldMaskUtil::FromString("child.child.payload", &mask); 430 FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst); 431 EXPECT_EQ(0, nested_dst.child().payload().optional_int32()); 432 EXPECT_EQ(5678, nested_dst.child().child().payload().optional_int32()); 433 434 nested_dst.Clear(); 435 FieldMaskUtil::FromString("child", &mask); 436 FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst); 437 EXPECT_EQ(1234, nested_dst.child().payload().optional_int32()); 438 EXPECT_EQ(5678, nested_dst.child().child().payload().optional_int32()); 439 440 // Test MergeOptions. 441 442 nested_dst.Clear(); 443 nested_dst.mutable_child()->mutable_payload()->set_optional_int64(4321); 444 // Message fields will be merged by default. 445 FieldMaskUtil::FromString("child.payload", &mask); 446 FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst); 447 EXPECT_EQ(1234, nested_dst.child().payload().optional_int32()); 448 EXPECT_EQ(4321, nested_dst.child().payload().optional_int64()); 449 // Change the behavior to replace message fields. 450 options.set_replace_message_fields(true); 451 FieldMaskUtil::FromString("child.payload", &mask); 452 FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst); 453 EXPECT_EQ(1234, nested_dst.child().payload().optional_int32()); 454 EXPECT_EQ(0, nested_dst.child().payload().optional_int64()); 455 456 // By default, fields missing in source are not cleared in destination. 457 options.set_replace_message_fields(false); 458 nested_dst.mutable_payload(); 459 EXPECT_TRUE(nested_dst.has_payload()); 460 FieldMaskUtil::FromString("payload", &mask); 461 FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst); 462 EXPECT_TRUE(nested_dst.has_payload()); 463 // But they are cleared when replacing message fields. 464 options.set_replace_message_fields(true); 465 nested_dst.Clear(); 466 nested_dst.mutable_payload(); 467 FieldMaskUtil::FromString("payload", &mask); 468 FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst); 469 EXPECT_FALSE(nested_dst.has_payload()); 470 471 nested_src.mutable_payload()->add_repeated_int32(1234); 472 nested_dst.mutable_payload()->add_repeated_int32(5678); 473 // Repeated fields will be appended by default. 474 FieldMaskUtil::FromString("payload.repeated_int32", &mask); 475 FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst); 476 ASSERT_EQ(2, nested_dst.payload().repeated_int32_size()); 477 EXPECT_EQ(5678, nested_dst.payload().repeated_int32(0)); 478 EXPECT_EQ(1234, nested_dst.payload().repeated_int32(1)); 479 // Change the behavior to replace repeated fields. 480 options.set_replace_repeated_fields(true); 481 FieldMaskUtil::FromString("payload.repeated_int32", &mask); 482 FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst); 483 ASSERT_EQ(1, nested_dst.payload().repeated_int32_size()); 484 EXPECT_EQ(1234, nested_dst.payload().repeated_int32(0)); 485} 486 487 488} // namespace 489} // namespace util 490} // namespace protobuf 491} // namespace google 492