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