Jisi Liu | b0f6611 | 2015-08-21 11:18:45 -0700 | [diff] [blame] | 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 | |
Jisi Liu | 1b0ff34 | 2016-04-19 15:14:31 -0700 | [diff] [blame] | 33 | #include <algorithm> |
| 34 | |
Jisi Liu | 3b3c8ab | 2016-03-30 11:39:59 -0700 | [diff] [blame] | 35 | #include <google/protobuf/stubs/logging.h> |
| 36 | #include <google/protobuf/stubs/common.h> |
Jisi Liu | b0f6611 | 2015-08-21 11:18:45 -0700 | [diff] [blame] | 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 | |
| 42 | namespace google { |
| 43 | namespace protobuf { |
| 44 | namespace util { |
Jisi Liu | 3b3c8ab | 2016-03-30 11:39:59 -0700 | [diff] [blame] | 45 | |
| 46 | class 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 | |
Jisi Liu | b0f6611 | 2015-08-21 11:18:45 -0700 | [diff] [blame] | 67 | namespace { |
| 68 | |
Jisi Liu | 3b3c8ab | 2016-03-30 11:39:59 -0700 | [diff] [blame] | 69 | TEST_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 | |
| 84 | TEST_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 | |
| 92 | TEST_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 | |
Jisi Liu | b0f6611 | 2015-08-21 11:18:45 -0700 | [diff] [blame] | 116 | using protobuf_unittest::TestAllTypes; |
| 117 | using protobuf_unittest::NestedTestAllTypes; |
| 118 | using google::protobuf::FieldMask; |
| 119 | |
| 120 | TEST(FieldMaskUtilTest, StringFormat) { |
| 121 | FieldMask mask; |
| 122 | EXPECT_EQ("", FieldMaskUtil::ToString(mask)); |
Jisi Liu | 3b3c8ab | 2016-03-30 11:39:59 -0700 | [diff] [blame] | 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)); |
Jisi Liu | b0f6611 | 2015-08-21 11:18:45 -0700 | [diff] [blame] | 127 | |
| 128 | FieldMaskUtil::FromString("", &mask); |
| 129 | EXPECT_EQ(0, mask.paths_size()); |
Jisi Liu | 3b3c8ab | 2016-03-30 11:39:59 -0700 | [diff] [blame] | 130 | FieldMaskUtil::FromString("fooBar", &mask); |
Jisi Liu | b0f6611 | 2015-08-21 11:18:45 -0700 | [diff] [blame] | 131 | EXPECT_EQ(1, mask.paths_size()); |
Jisi Liu | 3b3c8ab | 2016-03-30 11:39:59 -0700 | [diff] [blame] | 132 | EXPECT_EQ("fooBar", mask.paths(0)); |
| 133 | FieldMaskUtil::FromString("fooBar,bazQuz", &mask); |
Jisi Liu | b0f6611 | 2015-08-21 11:18:45 -0700 | [diff] [blame] | 134 | EXPECT_EQ(2, mask.paths_size()); |
Jisi Liu | 3b3c8ab | 2016-03-30 11:39:59 -0700 | [diff] [blame] | 135 | EXPECT_EQ("fooBar", mask.paths(0)); |
| 136 | EXPECT_EQ("bazQuz", mask.paths(1)); |
| 137 | } |
| 138 | |
| 139 | TEST(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)); |
Jisi Liu | b0f6611 | 2015-08-21 11:18:45 -0700 | [diff] [blame] | 160 | } |
| 161 | |
| 162 | TEST(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 | |
| 174 | TEST(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 | |
| 184 | TEST(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 | |
| 242 | TEST(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 | |
| 290 | TEST(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 | |
| 309 | TEST(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 | |
| 328 | TEST(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 | |
| 338 | TEST(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 |