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