xref: /aosp_15_r20/external/protobuf/csharp/src/Google.Protobuf.Test/FieldMaskTreeTest.cs (revision 1b3f573f81763fcece89efc2b6a5209149e44ab8)
1*1b3f573fSAndroid Build Coastguard Worker #region Copyright notice and license
2*1b3f573fSAndroid Build Coastguard Worker // Protocol Buffers - Google's data interchange format
3*1b3f573fSAndroid Build Coastguard Worker // Copyright 2015 Google Inc.  All rights reserved.
4*1b3f573fSAndroid Build Coastguard Worker // https://developers.google.com/protocol-buffers/
5*1b3f573fSAndroid Build Coastguard Worker //
6*1b3f573fSAndroid Build Coastguard Worker // Redistribution and use in source and binary forms, with or without
7*1b3f573fSAndroid Build Coastguard Worker // modification, are permitted provided that the following conditions are
8*1b3f573fSAndroid Build Coastguard Worker // met:
9*1b3f573fSAndroid Build Coastguard Worker //
10*1b3f573fSAndroid Build Coastguard Worker //     * Redistributions of source code must retain the above copyright
11*1b3f573fSAndroid Build Coastguard Worker // notice, this list of conditions and the following disclaimer.
12*1b3f573fSAndroid Build Coastguard Worker //     * Redistributions in binary form must reproduce the above
13*1b3f573fSAndroid Build Coastguard Worker // copyright notice, this list of conditions and the following disclaimer
14*1b3f573fSAndroid Build Coastguard Worker // in the documentation and/or other materials provided with the
15*1b3f573fSAndroid Build Coastguard Worker // distribution.
16*1b3f573fSAndroid Build Coastguard Worker //     * Neither the name of Google Inc. nor the names of its
17*1b3f573fSAndroid Build Coastguard Worker // contributors may be used to endorse or promote products derived from
18*1b3f573fSAndroid Build Coastguard Worker // this software without specific prior written permission.
19*1b3f573fSAndroid Build Coastguard Worker //
20*1b3f573fSAndroid Build Coastguard Worker // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*1b3f573fSAndroid Build Coastguard Worker // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*1b3f573fSAndroid Build Coastguard Worker // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23*1b3f573fSAndroid Build Coastguard Worker // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24*1b3f573fSAndroid Build Coastguard Worker // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25*1b3f573fSAndroid Build Coastguard Worker // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26*1b3f573fSAndroid Build Coastguard Worker // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27*1b3f573fSAndroid Build Coastguard Worker // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28*1b3f573fSAndroid Build Coastguard Worker // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29*1b3f573fSAndroid Build Coastguard Worker // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30*1b3f573fSAndroid Build Coastguard Worker // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*1b3f573fSAndroid Build Coastguard Worker #endregion
32*1b3f573fSAndroid Build Coastguard Worker 
33*1b3f573fSAndroid Build Coastguard Worker using System.Collections.Generic;
34*1b3f573fSAndroid Build Coastguard Worker using Google.Protobuf.Collections;
35*1b3f573fSAndroid Build Coastguard Worker using Google.Protobuf.TestProtos;
36*1b3f573fSAndroid Build Coastguard Worker using NUnit.Framework;
37*1b3f573fSAndroid Build Coastguard Worker using Google.Protobuf.WellKnownTypes;
38*1b3f573fSAndroid Build Coastguard Worker 
39*1b3f573fSAndroid Build Coastguard Worker namespace Google.Protobuf
40*1b3f573fSAndroid Build Coastguard Worker {
41*1b3f573fSAndroid Build Coastguard Worker     public class FieldMaskTreeTest
42*1b3f573fSAndroid Build Coastguard Worker     {
43*1b3f573fSAndroid Build Coastguard Worker         [Test]
AddFieldPath()44*1b3f573fSAndroid Build Coastguard Worker         public void AddFieldPath()
45*1b3f573fSAndroid Build Coastguard Worker         {
46*1b3f573fSAndroid Build Coastguard Worker             FieldMaskTree tree = new FieldMaskTree();
47*1b3f573fSAndroid Build Coastguard Worker             RepeatedField<string> paths = tree.ToFieldMask().Paths;
48*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(0, paths.Count);
49*1b3f573fSAndroid Build Coastguard Worker 
50*1b3f573fSAndroid Build Coastguard Worker             tree.AddFieldPath("");
51*1b3f573fSAndroid Build Coastguard Worker             paths = tree.ToFieldMask().Paths;
52*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(1, paths.Count);
53*1b3f573fSAndroid Build Coastguard Worker             Assert.Contains("", paths);
54*1b3f573fSAndroid Build Coastguard Worker 
55*1b3f573fSAndroid Build Coastguard Worker             // New branch.
56*1b3f573fSAndroid Build Coastguard Worker             tree.AddFieldPath("foo");
57*1b3f573fSAndroid Build Coastguard Worker             paths = tree.ToFieldMask().Paths;
58*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(2, paths.Count);
59*1b3f573fSAndroid Build Coastguard Worker             Assert.Contains("foo", paths);
60*1b3f573fSAndroid Build Coastguard Worker 
61*1b3f573fSAndroid Build Coastguard Worker             // Redundant path.
62*1b3f573fSAndroid Build Coastguard Worker             tree.AddFieldPath("foo");
63*1b3f573fSAndroid Build Coastguard Worker             paths = tree.ToFieldMask().Paths;
64*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(2, paths.Count);
65*1b3f573fSAndroid Build Coastguard Worker 
66*1b3f573fSAndroid Build Coastguard Worker             // New branch.
67*1b3f573fSAndroid Build Coastguard Worker             tree.AddFieldPath("bar.baz");
68*1b3f573fSAndroid Build Coastguard Worker             paths = tree.ToFieldMask().Paths;
69*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(3, paths.Count);
70*1b3f573fSAndroid Build Coastguard Worker             Assert.Contains("bar.baz", paths);
71*1b3f573fSAndroid Build Coastguard Worker 
72*1b3f573fSAndroid Build Coastguard Worker             // Redundant sub-path.
73*1b3f573fSAndroid Build Coastguard Worker             tree.AddFieldPath("foo.bar");
74*1b3f573fSAndroid Build Coastguard Worker             paths = tree.ToFieldMask().Paths;
75*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(3, paths.Count);
76*1b3f573fSAndroid Build Coastguard Worker 
77*1b3f573fSAndroid Build Coastguard Worker             // New branch from a non-root node.
78*1b3f573fSAndroid Build Coastguard Worker             tree.AddFieldPath("bar.quz");
79*1b3f573fSAndroid Build Coastguard Worker             paths = tree.ToFieldMask().Paths;
80*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(4, paths.Count);
81*1b3f573fSAndroid Build Coastguard Worker             Assert.Contains("bar.quz", paths);
82*1b3f573fSAndroid Build Coastguard Worker 
83*1b3f573fSAndroid Build Coastguard Worker             // A path that matches several existing sub-paths.
84*1b3f573fSAndroid Build Coastguard Worker             tree.AddFieldPath("bar");
85*1b3f573fSAndroid Build Coastguard Worker             paths = tree.ToFieldMask().Paths;
86*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(3, paths.Count);
87*1b3f573fSAndroid Build Coastguard Worker             Assert.Contains("foo", paths);
88*1b3f573fSAndroid Build Coastguard Worker             Assert.Contains("bar", paths);
89*1b3f573fSAndroid Build Coastguard Worker         }
90*1b3f573fSAndroid Build Coastguard Worker 
91*1b3f573fSAndroid Build Coastguard Worker         [Test]
MergeFromFieldMask()92*1b3f573fSAndroid Build Coastguard Worker         public void MergeFromFieldMask()
93*1b3f573fSAndroid Build Coastguard Worker         {
94*1b3f573fSAndroid Build Coastguard Worker             FieldMaskTree tree = new FieldMaskTree();
95*1b3f573fSAndroid Build Coastguard Worker             tree.MergeFromFieldMask(new FieldMask
96*1b3f573fSAndroid Build Coastguard Worker             {
97*1b3f573fSAndroid Build Coastguard Worker                 Paths = {"foo", "bar.baz", "bar.quz"}
98*1b3f573fSAndroid Build Coastguard Worker             });
99*1b3f573fSAndroid Build Coastguard Worker             RepeatedField<string> paths = tree.ToFieldMask().Paths;
100*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(3, paths.Count);
101*1b3f573fSAndroid Build Coastguard Worker             Assert.Contains("foo", paths);
102*1b3f573fSAndroid Build Coastguard Worker             Assert.Contains("bar.baz", paths);
103*1b3f573fSAndroid Build Coastguard Worker             Assert.Contains("bar.quz", paths);
104*1b3f573fSAndroid Build Coastguard Worker 
105*1b3f573fSAndroid Build Coastguard Worker             tree.MergeFromFieldMask(new FieldMask
106*1b3f573fSAndroid Build Coastguard Worker             {
107*1b3f573fSAndroid Build Coastguard Worker                 Paths = {"foo.bar", "bar"}
108*1b3f573fSAndroid Build Coastguard Worker             });
109*1b3f573fSAndroid Build Coastguard Worker             paths = tree.ToFieldMask().Paths;
110*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(2, paths.Count);
111*1b3f573fSAndroid Build Coastguard Worker             Assert.Contains("foo", paths);
112*1b3f573fSAndroid Build Coastguard Worker             Assert.Contains("bar", paths);
113*1b3f573fSAndroid Build Coastguard Worker         }
114*1b3f573fSAndroid Build Coastguard Worker 
115*1b3f573fSAndroid Build Coastguard Worker         [Test]
IntersectFieldPath()116*1b3f573fSAndroid Build Coastguard Worker         public void IntersectFieldPath()
117*1b3f573fSAndroid Build Coastguard Worker         {
118*1b3f573fSAndroid Build Coastguard Worker             FieldMaskTree tree = new FieldMaskTree();
119*1b3f573fSAndroid Build Coastguard Worker             FieldMaskTree result = new FieldMaskTree();
120*1b3f573fSAndroid Build Coastguard Worker             tree.MergeFromFieldMask(new FieldMask
121*1b3f573fSAndroid Build Coastguard Worker             {
122*1b3f573fSAndroid Build Coastguard Worker                 Paths = {"foo", "bar.baz", "bar.quz"}
123*1b3f573fSAndroid Build Coastguard Worker             });
124*1b3f573fSAndroid Build Coastguard Worker 
125*1b3f573fSAndroid Build Coastguard Worker             // Empty path.
126*1b3f573fSAndroid Build Coastguard Worker             tree.IntersectFieldPath("", result);
127*1b3f573fSAndroid Build Coastguard Worker             RepeatedField<string> paths = result.ToFieldMask().Paths;
128*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(0, paths.Count);
129*1b3f573fSAndroid Build Coastguard Worker 
130*1b3f573fSAndroid Build Coastguard Worker             // Non-exist path.
131*1b3f573fSAndroid Build Coastguard Worker             tree.IntersectFieldPath("quz", result);
132*1b3f573fSAndroid Build Coastguard Worker             paths = result.ToFieldMask().Paths;
133*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(0, paths.Count);
134*1b3f573fSAndroid Build Coastguard Worker 
135*1b3f573fSAndroid Build Coastguard Worker             // Sub-path of an existing leaf.
136*1b3f573fSAndroid Build Coastguard Worker             tree.IntersectFieldPath("foo.bar", result);
137*1b3f573fSAndroid Build Coastguard Worker             paths = result.ToFieldMask().Paths;
138*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(1, paths.Count);
139*1b3f573fSAndroid Build Coastguard Worker             Assert.Contains("foo.bar", paths);
140*1b3f573fSAndroid Build Coastguard Worker 
141*1b3f573fSAndroid Build Coastguard Worker             // Match an existing leaf node.
142*1b3f573fSAndroid Build Coastguard Worker             tree.IntersectFieldPath("foo", result);
143*1b3f573fSAndroid Build Coastguard Worker             paths = result.ToFieldMask().Paths;
144*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(1, paths.Count);
145*1b3f573fSAndroid Build Coastguard Worker             Assert.Contains("foo", paths);
146*1b3f573fSAndroid Build Coastguard Worker 
147*1b3f573fSAndroid Build Coastguard Worker             // Non-exist path.
148*1b3f573fSAndroid Build Coastguard Worker             tree.IntersectFieldPath("bar.foo", result);
149*1b3f573fSAndroid Build Coastguard Worker             paths = result.ToFieldMask().Paths;
150*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(1, paths.Count);
151*1b3f573fSAndroid Build Coastguard Worker             Assert.Contains("foo", paths);
152*1b3f573fSAndroid Build Coastguard Worker 
153*1b3f573fSAndroid Build Coastguard Worker             // Match a non-leaf node.
154*1b3f573fSAndroid Build Coastguard Worker             tree.IntersectFieldPath("bar", result);
155*1b3f573fSAndroid Build Coastguard Worker             paths = result.ToFieldMask().Paths;
156*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(3, paths.Count);
157*1b3f573fSAndroid Build Coastguard Worker             Assert.Contains("foo", paths);
158*1b3f573fSAndroid Build Coastguard Worker             Assert.Contains("bar.baz", paths);
159*1b3f573fSAndroid Build Coastguard Worker             Assert.Contains("bar.quz", paths);
160*1b3f573fSAndroid Build Coastguard Worker         }
161*1b3f573fSAndroid Build Coastguard Worker 
Merge(FieldMaskTree tree, IMessage source, IMessage destination, FieldMask.MergeOptions options, bool useDynamicMessage)162*1b3f573fSAndroid Build Coastguard Worker         private void Merge(FieldMaskTree tree, IMessage source, IMessage destination, FieldMask.MergeOptions options, bool useDynamicMessage)
163*1b3f573fSAndroid Build Coastguard Worker         {
164*1b3f573fSAndroid Build Coastguard Worker             if (useDynamicMessage)
165*1b3f573fSAndroid Build Coastguard Worker             {
166*1b3f573fSAndroid Build Coastguard Worker                 var newSource = source.Descriptor.Parser.CreateTemplate();
167*1b3f573fSAndroid Build Coastguard Worker                 newSource.MergeFrom(source.ToByteString());
168*1b3f573fSAndroid Build Coastguard Worker 
169*1b3f573fSAndroid Build Coastguard Worker                 var newDestination = source.Descriptor.Parser.CreateTemplate();
170*1b3f573fSAndroid Build Coastguard Worker                 newDestination.MergeFrom(destination.ToByteString());
171*1b3f573fSAndroid Build Coastguard Worker 
172*1b3f573fSAndroid Build Coastguard Worker                 tree.Merge(newSource, newDestination, options);
173*1b3f573fSAndroid Build Coastguard Worker 
174*1b3f573fSAndroid Build Coastguard Worker                 // Clear before merging:
175*1b3f573fSAndroid Build Coastguard Worker                 foreach (var fieldDescriptor in destination.Descriptor.Fields.InFieldNumberOrder())
176*1b3f573fSAndroid Build Coastguard Worker                 {
177*1b3f573fSAndroid Build Coastguard Worker                     fieldDescriptor.Accessor.Clear(destination);
178*1b3f573fSAndroid Build Coastguard Worker                 }
179*1b3f573fSAndroid Build Coastguard Worker                 destination.MergeFrom(newDestination.ToByteString());
180*1b3f573fSAndroid Build Coastguard Worker             }
181*1b3f573fSAndroid Build Coastguard Worker             else
182*1b3f573fSAndroid Build Coastguard Worker             {
183*1b3f573fSAndroid Build Coastguard Worker                 tree.Merge(source, destination, options);
184*1b3f573fSAndroid Build Coastguard Worker             }
185*1b3f573fSAndroid Build Coastguard Worker         }
186*1b3f573fSAndroid Build Coastguard Worker 
187*1b3f573fSAndroid Build Coastguard Worker         [Test]
188*1b3f573fSAndroid Build Coastguard Worker         [TestCase(true)]
189*1b3f573fSAndroid Build Coastguard Worker         [TestCase(false)]
Merge(bool useDynamicMessage)190*1b3f573fSAndroid Build Coastguard Worker         public void Merge(bool useDynamicMessage)
191*1b3f573fSAndroid Build Coastguard Worker         {
192*1b3f573fSAndroid Build Coastguard Worker             TestAllTypes value = new TestAllTypes
193*1b3f573fSAndroid Build Coastguard Worker             {
194*1b3f573fSAndroid Build Coastguard Worker                 SingleInt32 = 1234,
195*1b3f573fSAndroid Build Coastguard Worker                 SingleNestedMessage = new TestAllTypes.Types.NestedMessage {Bb = 5678},
196*1b3f573fSAndroid Build Coastguard Worker                 RepeatedInt32 = {4321},
197*1b3f573fSAndroid Build Coastguard Worker                 RepeatedNestedMessage = {new TestAllTypes.Types.NestedMessage {Bb = 8765}}
198*1b3f573fSAndroid Build Coastguard Worker             };
199*1b3f573fSAndroid Build Coastguard Worker 
200*1b3f573fSAndroid Build Coastguard Worker             NestedTestAllTypes source = new NestedTestAllTypes
201*1b3f573fSAndroid Build Coastguard Worker             {
202*1b3f573fSAndroid Build Coastguard Worker                 Payload = value,
203*1b3f573fSAndroid Build Coastguard Worker                 Child = new NestedTestAllTypes {Payload = value}
204*1b3f573fSAndroid Build Coastguard Worker             };
205*1b3f573fSAndroid Build Coastguard Worker             // Now we have a message source with the following structure:
206*1b3f573fSAndroid Build Coastguard Worker             //   [root] -+- payload -+- single_int32
207*1b3f573fSAndroid Build Coastguard Worker             //           |           +- single_nested_message
208*1b3f573fSAndroid Build Coastguard Worker             //           |           +- repeated_int32
209*1b3f573fSAndroid Build Coastguard Worker             //           |           +- repeated_nested_message
210*1b3f573fSAndroid Build Coastguard Worker             //           |
211*1b3f573fSAndroid Build Coastguard Worker             //           +- child --- payload -+- single_int32
212*1b3f573fSAndroid Build Coastguard Worker             //                                 +- single_nested_message
213*1b3f573fSAndroid Build Coastguard Worker             //                                 +- repeated_int32
214*1b3f573fSAndroid Build Coastguard Worker             //                                 +- repeated_nested_message
215*1b3f573fSAndroid Build Coastguard Worker 
216*1b3f573fSAndroid Build Coastguard Worker             FieldMask.MergeOptions options = new FieldMask.MergeOptions();
217*1b3f573fSAndroid Build Coastguard Worker 
218*1b3f573fSAndroid Build Coastguard Worker             // Test merging each individual field.
219*1b3f573fSAndroid Build Coastguard Worker             NestedTestAllTypes destination = new NestedTestAllTypes();
220*1b3f573fSAndroid Build Coastguard Worker             Merge(new FieldMaskTree().AddFieldPath("payload.single_int32"),
221*1b3f573fSAndroid Build Coastguard Worker                 source, destination, options, useDynamicMessage);
222*1b3f573fSAndroid Build Coastguard Worker             NestedTestAllTypes expected = new NestedTestAllTypes
223*1b3f573fSAndroid Build Coastguard Worker             {
224*1b3f573fSAndroid Build Coastguard Worker                 Payload = new TestAllTypes
225*1b3f573fSAndroid Build Coastguard Worker                 {
226*1b3f573fSAndroid Build Coastguard Worker                     SingleInt32 = 1234
227*1b3f573fSAndroid Build Coastguard Worker                 }
228*1b3f573fSAndroid Build Coastguard Worker             };
229*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(expected, destination);
230*1b3f573fSAndroid Build Coastguard Worker 
231*1b3f573fSAndroid Build Coastguard Worker             destination = new NestedTestAllTypes();
232*1b3f573fSAndroid Build Coastguard Worker             Merge(new FieldMaskTree().AddFieldPath("payload.single_nested_message"),
233*1b3f573fSAndroid Build Coastguard Worker                 source, destination, options, useDynamicMessage);
234*1b3f573fSAndroid Build Coastguard Worker             expected = new NestedTestAllTypes
235*1b3f573fSAndroid Build Coastguard Worker             {
236*1b3f573fSAndroid Build Coastguard Worker                 Payload = new TestAllTypes
237*1b3f573fSAndroid Build Coastguard Worker                 {
238*1b3f573fSAndroid Build Coastguard Worker                     SingleNestedMessage = new TestAllTypes.Types.NestedMessage {Bb = 5678}
239*1b3f573fSAndroid Build Coastguard Worker                 }
240*1b3f573fSAndroid Build Coastguard Worker             };
241*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(expected, destination);
242*1b3f573fSAndroid Build Coastguard Worker 
243*1b3f573fSAndroid Build Coastguard Worker             destination = new NestedTestAllTypes();
244*1b3f573fSAndroid Build Coastguard Worker             Merge(new FieldMaskTree().AddFieldPath("payload.repeated_int32"),
245*1b3f573fSAndroid Build Coastguard Worker                 source, destination, options, useDynamicMessage);
246*1b3f573fSAndroid Build Coastguard Worker             expected = new NestedTestAllTypes
247*1b3f573fSAndroid Build Coastguard Worker             {
248*1b3f573fSAndroid Build Coastguard Worker                 Payload = new TestAllTypes
249*1b3f573fSAndroid Build Coastguard Worker                 {
250*1b3f573fSAndroid Build Coastguard Worker                     RepeatedInt32 = {4321}
251*1b3f573fSAndroid Build Coastguard Worker                 }
252*1b3f573fSAndroid Build Coastguard Worker             };
253*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(expected, destination);
254*1b3f573fSAndroid Build Coastguard Worker 
255*1b3f573fSAndroid Build Coastguard Worker             destination = new NestedTestAllTypes();
256*1b3f573fSAndroid Build Coastguard Worker             Merge(new FieldMaskTree().AddFieldPath("payload.repeated_nested_message"),
257*1b3f573fSAndroid Build Coastguard Worker                 source, destination, options, useDynamicMessage);
258*1b3f573fSAndroid Build Coastguard Worker             expected = new NestedTestAllTypes
259*1b3f573fSAndroid Build Coastguard Worker             {
260*1b3f573fSAndroid Build Coastguard Worker                 Payload = new TestAllTypes
261*1b3f573fSAndroid Build Coastguard Worker                 {
262*1b3f573fSAndroid Build Coastguard Worker                     RepeatedNestedMessage = {new TestAllTypes.Types.NestedMessage {Bb = 8765}}
263*1b3f573fSAndroid Build Coastguard Worker                 }
264*1b3f573fSAndroid Build Coastguard Worker             };
265*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(expected, destination);
266*1b3f573fSAndroid Build Coastguard Worker 
267*1b3f573fSAndroid Build Coastguard Worker             destination = new NestedTestAllTypes();
268*1b3f573fSAndroid Build Coastguard Worker             Merge(
269*1b3f573fSAndroid Build Coastguard Worker                 new FieldMaskTree().AddFieldPath("child.payload.single_int32"),
270*1b3f573fSAndroid Build Coastguard Worker                 source,
271*1b3f573fSAndroid Build Coastguard Worker                 destination,
272*1b3f573fSAndroid Build Coastguard Worker                 options,
273*1b3f573fSAndroid Build Coastguard Worker                 useDynamicMessage);
274*1b3f573fSAndroid Build Coastguard Worker             expected = new NestedTestAllTypes
275*1b3f573fSAndroid Build Coastguard Worker             {
276*1b3f573fSAndroid Build Coastguard Worker                 Child = new NestedTestAllTypes
277*1b3f573fSAndroid Build Coastguard Worker                 {
278*1b3f573fSAndroid Build Coastguard Worker                     Payload = new TestAllTypes
279*1b3f573fSAndroid Build Coastguard Worker                     {
280*1b3f573fSAndroid Build Coastguard Worker                         SingleInt32 = 1234
281*1b3f573fSAndroid Build Coastguard Worker                     }
282*1b3f573fSAndroid Build Coastguard Worker                 }
283*1b3f573fSAndroid Build Coastguard Worker             };
284*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(expected, destination);
285*1b3f573fSAndroid Build Coastguard Worker 
286*1b3f573fSAndroid Build Coastguard Worker             destination = new NestedTestAllTypes();
287*1b3f573fSAndroid Build Coastguard Worker             Merge(
288*1b3f573fSAndroid Build Coastguard Worker                 new FieldMaskTree().AddFieldPath("child.payload.single_nested_message"),
289*1b3f573fSAndroid Build Coastguard Worker                 source,
290*1b3f573fSAndroid Build Coastguard Worker                 destination,
291*1b3f573fSAndroid Build Coastguard Worker                 options,
292*1b3f573fSAndroid Build Coastguard Worker                 useDynamicMessage);
293*1b3f573fSAndroid Build Coastguard Worker             expected = new NestedTestAllTypes
294*1b3f573fSAndroid Build Coastguard Worker             {
295*1b3f573fSAndroid Build Coastguard Worker                 Child = new NestedTestAllTypes
296*1b3f573fSAndroid Build Coastguard Worker                 {
297*1b3f573fSAndroid Build Coastguard Worker                     Payload = new TestAllTypes
298*1b3f573fSAndroid Build Coastguard Worker                     {
299*1b3f573fSAndroid Build Coastguard Worker                         SingleNestedMessage = new TestAllTypes.Types.NestedMessage {Bb = 5678}
300*1b3f573fSAndroid Build Coastguard Worker                     }
301*1b3f573fSAndroid Build Coastguard Worker                 }
302*1b3f573fSAndroid Build Coastguard Worker             };
303*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(expected, destination);
304*1b3f573fSAndroid Build Coastguard Worker 
305*1b3f573fSAndroid Build Coastguard Worker             destination = new NestedTestAllTypes();
306*1b3f573fSAndroid Build Coastguard Worker             Merge(new FieldMaskTree().AddFieldPath("child.payload.repeated_int32"),
307*1b3f573fSAndroid Build Coastguard Worker                 source, destination, options, useDynamicMessage);
308*1b3f573fSAndroid Build Coastguard Worker             expected = new NestedTestAllTypes
309*1b3f573fSAndroid Build Coastguard Worker             {
310*1b3f573fSAndroid Build Coastguard Worker                 Child = new NestedTestAllTypes
311*1b3f573fSAndroid Build Coastguard Worker                 {
312*1b3f573fSAndroid Build Coastguard Worker                     Payload = new TestAllTypes
313*1b3f573fSAndroid Build Coastguard Worker                     {
314*1b3f573fSAndroid Build Coastguard Worker                         RepeatedInt32 = {4321}
315*1b3f573fSAndroid Build Coastguard Worker                     }
316*1b3f573fSAndroid Build Coastguard Worker                 }
317*1b3f573fSAndroid Build Coastguard Worker             };
318*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(expected, destination);
319*1b3f573fSAndroid Build Coastguard Worker 
320*1b3f573fSAndroid Build Coastguard Worker             destination = new NestedTestAllTypes();
321*1b3f573fSAndroid Build Coastguard Worker             Merge(new FieldMaskTree().AddFieldPath("child.payload.repeated_nested_message"),
322*1b3f573fSAndroid Build Coastguard Worker                 source, destination, options, useDynamicMessage);
323*1b3f573fSAndroid Build Coastguard Worker             expected = new NestedTestAllTypes
324*1b3f573fSAndroid Build Coastguard Worker             {
325*1b3f573fSAndroid Build Coastguard Worker                 Child = new NestedTestAllTypes
326*1b3f573fSAndroid Build Coastguard Worker                 {
327*1b3f573fSAndroid Build Coastguard Worker                     Payload = new TestAllTypes
328*1b3f573fSAndroid Build Coastguard Worker                     {
329*1b3f573fSAndroid Build Coastguard Worker                         RepeatedNestedMessage = {new TestAllTypes.Types.NestedMessage {Bb = 8765}}
330*1b3f573fSAndroid Build Coastguard Worker                     }
331*1b3f573fSAndroid Build Coastguard Worker                 }
332*1b3f573fSAndroid Build Coastguard Worker             };
333*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(expected, destination);
334*1b3f573fSAndroid Build Coastguard Worker 
335*1b3f573fSAndroid Build Coastguard Worker             destination = new NestedTestAllTypes();
336*1b3f573fSAndroid Build Coastguard Worker             Merge(new FieldMaskTree().AddFieldPath("child").AddFieldPath("payload"),
337*1b3f573fSAndroid Build Coastguard Worker                 source, destination, options, useDynamicMessage);
338*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(source, destination);
339*1b3f573fSAndroid Build Coastguard Worker 
340*1b3f573fSAndroid Build Coastguard Worker             // Test repeated options.
341*1b3f573fSAndroid Build Coastguard Worker             destination = new NestedTestAllTypes
342*1b3f573fSAndroid Build Coastguard Worker             {
343*1b3f573fSAndroid Build Coastguard Worker                 Payload = new TestAllTypes
344*1b3f573fSAndroid Build Coastguard Worker                 {
345*1b3f573fSAndroid Build Coastguard Worker                     RepeatedInt32 = { 1000 }
346*1b3f573fSAndroid Build Coastguard Worker                 }
347*1b3f573fSAndroid Build Coastguard Worker             };
348*1b3f573fSAndroid Build Coastguard Worker             Merge(new FieldMaskTree().AddFieldPath("payload.repeated_int32"),
349*1b3f573fSAndroid Build Coastguard Worker                     source, destination, options, useDynamicMessage);
350*1b3f573fSAndroid Build Coastguard Worker             // Default behavior is to append repeated fields.
351*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(2, destination.Payload.RepeatedInt32.Count);
352*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(1000, destination.Payload.RepeatedInt32[0]);
353*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(4321, destination.Payload.RepeatedInt32[1]);
354*1b3f573fSAndroid Build Coastguard Worker             // Change to replace repeated fields.
355*1b3f573fSAndroid Build Coastguard Worker             options.ReplaceRepeatedFields = true;
356*1b3f573fSAndroid Build Coastguard Worker             Merge(new FieldMaskTree().AddFieldPath("payload.repeated_int32"),
357*1b3f573fSAndroid Build Coastguard Worker                 source, destination, options, useDynamicMessage);
358*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(1, destination.Payload.RepeatedInt32.Count);
359*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(4321, destination.Payload.RepeatedInt32[0]);
360*1b3f573fSAndroid Build Coastguard Worker 
361*1b3f573fSAndroid Build Coastguard Worker             // Test message options.
362*1b3f573fSAndroid Build Coastguard Worker             destination = new NestedTestAllTypes
363*1b3f573fSAndroid Build Coastguard Worker             {
364*1b3f573fSAndroid Build Coastguard Worker                 Payload = new TestAllTypes
365*1b3f573fSAndroid Build Coastguard Worker                 {
366*1b3f573fSAndroid Build Coastguard Worker                     SingleInt32 = 1000,
367*1b3f573fSAndroid Build Coastguard Worker                     SingleUint32 = 2000
368*1b3f573fSAndroid Build Coastguard Worker                 }
369*1b3f573fSAndroid Build Coastguard Worker             };
370*1b3f573fSAndroid Build Coastguard Worker             Merge(new FieldMaskTree().AddFieldPath("payload"),
371*1b3f573fSAndroid Build Coastguard Worker                     source, destination, options, useDynamicMessage);
372*1b3f573fSAndroid Build Coastguard Worker             // Default behavior is to merge message fields.
373*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(1234, destination.Payload.SingleInt32);
374*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(2000, destination.Payload.SingleUint32);
375*1b3f573fSAndroid Build Coastguard Worker 
376*1b3f573fSAndroid Build Coastguard Worker             // Test merging unset message fields.
377*1b3f573fSAndroid Build Coastguard Worker             NestedTestAllTypes clearedSource = source.Clone();
378*1b3f573fSAndroid Build Coastguard Worker             clearedSource.Payload = null;
379*1b3f573fSAndroid Build Coastguard Worker             destination = new NestedTestAllTypes();
380*1b3f573fSAndroid Build Coastguard Worker             Merge(new FieldMaskTree().AddFieldPath("payload"),
381*1b3f573fSAndroid Build Coastguard Worker                 clearedSource, destination, options, useDynamicMessage);
382*1b3f573fSAndroid Build Coastguard Worker             Assert.IsNull(destination.Payload);
383*1b3f573fSAndroid Build Coastguard Worker 
384*1b3f573fSAndroid Build Coastguard Worker             // Skip a message field if they are unset in both source and target.
385*1b3f573fSAndroid Build Coastguard Worker             destination = new NestedTestAllTypes();
386*1b3f573fSAndroid Build Coastguard Worker             Merge(new FieldMaskTree().AddFieldPath("payload.single_int32"),
387*1b3f573fSAndroid Build Coastguard Worker                 clearedSource, destination, options, useDynamicMessage);
388*1b3f573fSAndroid Build Coastguard Worker             Assert.IsNull(destination.Payload);
389*1b3f573fSAndroid Build Coastguard Worker 
390*1b3f573fSAndroid Build Coastguard Worker             // Change to replace message fields.
391*1b3f573fSAndroid Build Coastguard Worker             options.ReplaceMessageFields = true;
392*1b3f573fSAndroid Build Coastguard Worker             destination = new NestedTestAllTypes
393*1b3f573fSAndroid Build Coastguard Worker             {
394*1b3f573fSAndroid Build Coastguard Worker                 Payload = new TestAllTypes
395*1b3f573fSAndroid Build Coastguard Worker                 {
396*1b3f573fSAndroid Build Coastguard Worker                     SingleInt32 = 1000,
397*1b3f573fSAndroid Build Coastguard Worker                     SingleUint32 = 2000
398*1b3f573fSAndroid Build Coastguard Worker                 }
399*1b3f573fSAndroid Build Coastguard Worker             };
400*1b3f573fSAndroid Build Coastguard Worker             Merge(new FieldMaskTree().AddFieldPath("payload"),
401*1b3f573fSAndroid Build Coastguard Worker                     source, destination, options, useDynamicMessage);
402*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(1234, destination.Payload.SingleInt32);
403*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(0, destination.Payload.SingleUint32);
404*1b3f573fSAndroid Build Coastguard Worker 
405*1b3f573fSAndroid Build Coastguard Worker             // Test merging unset message fields.
406*1b3f573fSAndroid Build Coastguard Worker             destination = new NestedTestAllTypes
407*1b3f573fSAndroid Build Coastguard Worker             {
408*1b3f573fSAndroid Build Coastguard Worker                 Payload = new TestAllTypes
409*1b3f573fSAndroid Build Coastguard Worker                 {
410*1b3f573fSAndroid Build Coastguard Worker                     SingleInt32 = 1000,
411*1b3f573fSAndroid Build Coastguard Worker                     SingleUint32 = 2000
412*1b3f573fSAndroid Build Coastguard Worker                 }
413*1b3f573fSAndroid Build Coastguard Worker             };
414*1b3f573fSAndroid Build Coastguard Worker             Merge(new FieldMaskTree().AddFieldPath("payload"),
415*1b3f573fSAndroid Build Coastguard Worker                     clearedSource, destination, options, useDynamicMessage);
416*1b3f573fSAndroid Build Coastguard Worker             Assert.IsNull(destination.Payload);
417*1b3f573fSAndroid Build Coastguard Worker 
418*1b3f573fSAndroid Build Coastguard Worker             // Test merging unset primitive fields.
419*1b3f573fSAndroid Build Coastguard Worker             destination = source.Clone();
420*1b3f573fSAndroid Build Coastguard Worker             destination.Payload.SingleInt32 = 0;
421*1b3f573fSAndroid Build Coastguard Worker             NestedTestAllTypes sourceWithPayloadInt32Unset = destination;
422*1b3f573fSAndroid Build Coastguard Worker             destination = source.Clone();
423*1b3f573fSAndroid Build Coastguard Worker             Merge(new FieldMaskTree().AddFieldPath("payload.single_int32"),
424*1b3f573fSAndroid Build Coastguard Worker                 sourceWithPayloadInt32Unset, destination, options, useDynamicMessage);
425*1b3f573fSAndroid Build Coastguard Worker             Assert.AreEqual(0, destination.Payload.SingleInt32);
426*1b3f573fSAndroid Build Coastguard Worker 
427*1b3f573fSAndroid Build Coastguard Worker             // Change to clear unset primitive fields.
428*1b3f573fSAndroid Build Coastguard Worker             options.ReplacePrimitiveFields = true;
429*1b3f573fSAndroid Build Coastguard Worker             destination = source.Clone();
430*1b3f573fSAndroid Build Coastguard Worker             Merge(new FieldMaskTree().AddFieldPath("payload.single_int32"),
431*1b3f573fSAndroid Build Coastguard Worker                 sourceWithPayloadInt32Unset, destination, options, useDynamicMessage);
432*1b3f573fSAndroid Build Coastguard Worker             Assert.IsNotNull(destination.Payload);
433*1b3f573fSAndroid Build Coastguard Worker         }
434*1b3f573fSAndroid Build Coastguard Worker 
435*1b3f573fSAndroid Build Coastguard Worker     }
436*1b3f573fSAndroid Build Coastguard Worker }
437