File: IntegrationTests\NestedObjectIntegrationTest.cs
Web Access
Project: src\src\Features\JsonPatch\test\Microsoft.AspNetCore.JsonPatch.Tests.csproj (Microsoft.AspNetCore.JsonPatch.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Dynamic;
using Microsoft.AspNetCore.Shared;
using Newtonsoft.Json;
using Xunit;
 
namespace Microsoft.AspNetCore.JsonPatch.IntegrationTests;
 
public class NestedObjectIntegrationTest
{
    [Fact]
    public void Replace_DTOWithNullCheck()
    {
        // Arrange
        var targetObject = new SimpleObjectWithNestedObjectWithNullCheck()
        {
            SimpleObjectWithNullCheck = new SimpleObjectWithNullCheck()
            {
                StringProperty = "A"
            }
        };
 
        var patchDocument = new JsonPatchDocument<SimpleObjectWithNestedObjectWithNullCheck>();
        patchDocument.Replace(o => o.SimpleObjectWithNullCheck.StringProperty, "B");
 
        // Act
        patchDocument.ApplyTo(targetObject);
 
        // Assert
        Assert.Equal("B", targetObject.SimpleObjectWithNullCheck.StringProperty);
    }
 
    [Fact]
    public void ReplaceNestedObject_WithSerialization()
    {
        // Arrange
        var targetObject = new SimpleObjectWithNestedObject()
        {
            IntegerValue = 1
        };
 
        var newNested = new NestedObject() { StringProperty = "B" };
        var patchDocument = new JsonPatchDocument<SimpleObjectWithNestedObject>();
        patchDocument.Replace(o => o.NestedObject, newNested);
 
        var serialized = JsonConvert.SerializeObject(patchDocument);
        var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument<SimpleObjectWithNestedObject>>(serialized);
 
        // Act
        deserialized.ApplyTo(targetObject);
 
        // Assert
        Assert.Equal("B", targetObject.NestedObject.StringProperty);
    }
 
    [Fact]
    public void TestStringProperty_InNestedObject()
    {
        // Arrange
        var targetObject = new SimpleObjectWithNestedObject()
        {
            NestedObject = new NestedObject() { StringProperty = "A" }
        };
 
        var patchDocument = new JsonPatchDocument<NestedObject>();
        patchDocument.Test(o => o.StringProperty, "A");
 
        // Act
        patchDocument.ApplyTo(targetObject.NestedObject);
 
        // Assert
        Assert.Equal("A", targetObject.NestedObject.StringProperty);
    }
 
    [Fact]
    public void TestNestedObject()
    {
        // Arrange
        var targetObject = new SimpleObjectWithNestedObject()
        {
            NestedObject = new NestedObject() { StringProperty = "B" }
        };
 
        var testNested = new NestedObject() { StringProperty = "B" };
        var patchDocument = new JsonPatchDocument<SimpleObjectWithNestedObject>();
        patchDocument.Test(o => o.NestedObject, testNested);
 
        // Act
        patchDocument.ApplyTo(targetObject);
 
        // Assert
        Assert.Equal("B", targetObject.NestedObject.StringProperty);
    }
 
    [Fact]
    public void AddReplaces_ExistingStringProperty()
    {
        // Arrange
        var targetObject = new SimpleObjectWithNestedObject()
        {
            SimpleObject = new SimpleObject()
            {
                StringProperty = "A"
            }
        };
 
        var patchDocument = new JsonPatchDocument<SimpleObjectWithNestedObject>();
        patchDocument.Add(o => o.SimpleObject.StringProperty, "B");
 
        // Act
        patchDocument.ApplyTo(targetObject);
 
        // Assert
        Assert.Equal("B", targetObject.SimpleObject.StringProperty);
    }
 
    [Fact]
    public void AddNewProperty_ToExpandoOject_InTypedObject()
    {
        var targetObject = new NestedObject()
        {
            DynamicProperty = new ExpandoObject()
        };
 
        var patchDocument = new JsonPatchDocument();
        patchDocument.Add("DynamicProperty/NewInt", 1);
 
        patchDocument.ApplyTo(targetObject);
 
        Assert.Equal(1, targetObject.DynamicProperty.NewInt);
    }
 
    [Fact]
    public void RemoveStringProperty()
    {
        // Arrange
        var targetObject = new SimpleObjectWithNestedObject()
        {
            SimpleObject = new SimpleObject()
            {
                StringProperty = "A"
            }
        };
 
        var patchDocument = new JsonPatchDocument<SimpleObjectWithNestedObject>();
        patchDocument.Remove(o => o.SimpleObject.StringProperty);
 
        // Act
        patchDocument.ApplyTo(targetObject);
 
        // Assert
        Assert.Null(targetObject.SimpleObject.StringProperty);
    }
 
    [Fact]
    public void CopyStringProperty_ToAnotherStringProperty()
    {
        // Arrange
        var targetObject = new SimpleObjectWithNestedObject()
        {
            SimpleObject = new SimpleObject()
            {
                StringProperty = "A",
                AnotherStringProperty = "B"
            }
        };
 
        var patchDocument = new JsonPatchDocument<SimpleObjectWithNestedObject>();
        patchDocument.Copy(o => o.SimpleObject.StringProperty, o => o.SimpleObject.AnotherStringProperty);
 
        // Act
        patchDocument.ApplyTo(targetObject);
 
        // Assert
        Assert.Equal("A", targetObject.SimpleObject.AnotherStringProperty);
    }
 
    [Fact]
    public void CopyNullStringProperty_ToAnotherStringProperty()
    {
        // Arrange
        var targetObject = new SimpleObjectWithNestedObject()
        {
            SimpleObject = new SimpleObject()
            {
                StringProperty = null,
                AnotherStringProperty = "B"
            }
        };
 
        var patchDocument = new JsonPatchDocument<SimpleObjectWithNestedObject>();
        patchDocument.Copy(o => o.SimpleObject.StringProperty, o => o.SimpleObject.AnotherStringProperty);
 
        // Act
        patchDocument.ApplyTo(targetObject);
 
        // Assert
        Assert.Null(targetObject.SimpleObject.AnotherStringProperty);
    }
 
    [Fact]
    public void Copy_DeepClonesObject()
    {
        // Arrange
        var targetObject = new SimpleObjectWithNestedObject()
        {
            SimpleObject = new SimpleObject()
            {
                StringProperty = "A",
                AnotherStringProperty = "B"
            },
            InheritedObject = new InheritedObject()
            {
                StringProperty = "C",
                AnotherStringProperty = "D"
            }
        };
 
        var patchDocument = new JsonPatchDocument<SimpleObjectWithNestedObject>();
        patchDocument.Copy(o => o.InheritedObject, o => o.SimpleObject);
 
        // Act
        patchDocument.ApplyTo(targetObject);
 
        // Assert
        Assert.Equal("C", targetObject.SimpleObject.StringProperty);
        Assert.Equal("D", targetObject.SimpleObject.AnotherStringProperty);
        Assert.Equal("C", targetObject.InheritedObject.StringProperty);
        Assert.Equal("D", targetObject.InheritedObject.AnotherStringProperty);
        Assert.NotSame(targetObject.SimpleObject.StringProperty, targetObject.InheritedObject.StringProperty);
    }
 
    [Fact]
    public void Copy_KeepsObjectType()
    {
        // Arrange
        var targetObject = new SimpleObjectWithNestedObject()
        {
            SimpleObject = new SimpleObject(),
            InheritedObject = new InheritedObject()
        };
 
        var patchDocument = new JsonPatchDocument<SimpleObjectWithNestedObject>();
        patchDocument.Copy(o => o.InheritedObject, o => o.SimpleObject);
 
        // Act
        patchDocument.ApplyTo(targetObject);
 
        // Assert
        Assert.Equal(typeof(InheritedObject), targetObject.SimpleObject.GetType());
    }
 
    [Fact]
    public void Copy_BreaksObjectReference()
    {
        // Arrange
        var targetObject = new SimpleObjectWithNestedObject()
        {
            SimpleObject = new SimpleObject(),
            InheritedObject = new InheritedObject()
        };
 
        var patchDocument = new JsonPatchDocument<SimpleObjectWithNestedObject>();
        patchDocument.Copy(o => o.InheritedObject, o => o.SimpleObject);
 
        // Act
        patchDocument.ApplyTo(targetObject);
 
        // Assert
        Assert.NotSame(targetObject.SimpleObject, targetObject.InheritedObject);
    }
 
    [Fact]
    public void MoveIntegerValue_ToAnotherIntegerProperty()
    {
        // Arrange
        var targetObject = new SimpleObjectWithNestedObject()
        {
            SimpleObject = new SimpleObject()
            {
                IntegerValue = 2,
                AnotherIntegerValue = 3
            }
        };
 
        var patchDocument = new JsonPatchDocument<SimpleObjectWithNestedObject>();
        patchDocument.Move(o => o.SimpleObject.IntegerValue, o => o.SimpleObject.AnotherIntegerValue);
 
        // Act
        patchDocument.ApplyTo(targetObject);
 
        // Assert
        Assert.Equal(2, targetObject.SimpleObject.AnotherIntegerValue);
        Assert.Equal(0, targetObject.SimpleObject.IntegerValue);
    }
 
    [Fact]
    public void Move_KeepsObjectReference()
    {
        // Arrange
        var sDto = new SimpleObject()
        {
            StringProperty = "A",
            AnotherStringProperty = "B"
        };
        var iDto = new InheritedObject()
        {
            StringProperty = "C",
            AnotherStringProperty = "D"
        };
        var targetObject = new SimpleObjectWithNestedObject()
        {
            SimpleObject = sDto,
            InheritedObject = iDto
        };
 
        var patchDocument = new JsonPatchDocument<SimpleObjectWithNestedObject>();
        patchDocument.Move(o => o.InheritedObject, o => o.SimpleObject);
 
        // Act
        patchDocument.ApplyTo(targetObject);
 
        // Assert
        Assert.Equal("C", targetObject.SimpleObject.StringProperty);
        Assert.Equal("D", targetObject.SimpleObject.AnotherStringProperty);
        Assert.Same(iDto, targetObject.SimpleObject);
        Assert.Null(targetObject.InheritedObject);
    }
 
    private class SimpleObjectWithNullCheck
    {
        private string stringProperty;
 
        public string StringProperty
        {
            get
            {
                return stringProperty;
            }
 
            set
            {
                ArgumentNullThrowHelper.ThrowIfNull(value);
 
                stringProperty = value;
            }
        }
    }
 
    private class SimpleObjectWithNestedObjectWithNullCheck
    {
        public SimpleObjectWithNullCheck SimpleObjectWithNullCheck { get; set; }
 
        public SimpleObjectWithNestedObjectWithNullCheck()
        {
            SimpleObjectWithNullCheck = new SimpleObjectWithNullCheck();
        }
    }
}