Files

773 lines
20 KiB
C#

#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Collections.Generic;
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
#else
using System.Linq;
#endif
using System.Text;
using Newtonsoft.Json.Linq;
#if DNXCORE50
using Xunit;
using Test = Xunit.FactAttribute;
using Assert = Newtonsoft.Json.Tests.XUnitAssert;
#else
using NUnit.Framework;
#endif
namespace Newtonsoft.Json.Tests.Linq
{
[TestFixture]
public class MergeTests : TestFixtureBase
{
[Test]
public void MergeInvalidObject()
{
var a = new JObject();
ExceptionAssert.Throws<ArgumentException>(
() => a.Merge(new Version()),
@"Could not determine JSON object type for type System.Version.
Parameter name: content",
@"Could not determine JSON object type for type System.Version. (Parameter 'content')");
}
[Test]
public void MergeArraySelf()
{
var a = new JArray { "1", "2" };
a.Merge(a, new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Replace });
Assert.AreEqual(new JArray { "1", "2" }, a);
}
[Test]
public void MergeObjectSelf()
{
var a = new JObject
{
["1"] = 1,
["2"] = 2
};
a.Merge(a, new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Replace });
Assert.AreEqual(new JObject
{
["1"] = 1,
["2"] = 2
}, a);
}
[Test]
public void MergeArrayIntoArray_Replace()
{
var a = new JArray { "1", "2" };
a.Merge(new string[] { "3", "4" }, new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Replace });
Assert.AreEqual(new JArray { "3", "4" }, a);
}
[Test]
public void MergeArrayIntoArray_Concat()
{
var a = new JArray { "1", "2" };
a.Merge(new string[] { "3", "4" }, new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Concat });
Assert.AreEqual(new JArray { "1", "2", "3", "4" }, a);
}
[Test]
public void MergeArrayIntoArray_Union()
{
var a = new JArray { "1", "2" };
a.Merge(new string[] { "2", "3", "4" }, new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Union });
Assert.AreEqual(new JArray { "1", "2", "3", "4" }, a);
}
[Test]
public void MergeArrayIntoArray_Merge()
{
var a = new JArray { "1", "2" };
a.Merge(new string[] { "2" }, new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Merge });
Assert.AreEqual(new JArray { "2", "2" }, a);
}
[Test]
public void MergeNullString()
{
var a = new JObject { ["a"] = 1 };
var b = new JObject { ["a"] = false ? "2" : null };
a.Merge(b);
Assert.AreEqual(1, (int)a["a"]);
}
[Test]
public void MergeObjectProperty()
{
var left = (JObject)JToken.FromObject(new
{
Property1 = 1
});
var right = (JObject)JToken.FromObject(new
{
Property2 = 2
});
left.Merge(right);
string json = left.ToString();
StringAssert.AreEqual(@"{
""Property1"": 1,
""Property2"": 2
}", json);
}
[Test]
public void MergeChildObject()
{
var left = (JObject)JToken.FromObject(new
{
Property1 = new { SubProperty1 = 1 }
});
var right = (JObject)JToken.FromObject(new
{
Property1 = new { SubProperty2 = 2 }
});
left.Merge(right);
string json = left.ToString();
StringAssert.AreEqual(@"{
""Property1"": {
""SubProperty1"": 1,
""SubProperty2"": 2
}
}", json);
}
[Test]
public void MergeMismatchedTypesRoot()
{
var left = (JObject)JToken.FromObject(new
{
Property1 = new { SubProperty1 = 1 }
});
var right = (JArray)JToken.FromObject(new object[]
{
new { Property1 = 1 },
new { Property1 = 1 }
});
left.Merge(right);
string json = left.ToString();
StringAssert.AreEqual(@"{
""Property1"": {
""SubProperty1"": 1
}
}", json);
}
[Test]
public void MergeMultipleObjects()
{
var left = (JObject)JToken.FromObject(new
{
Property1 = new { SubProperty1 = 1 }
});
var right = (JObject)JToken.FromObject(new
{
Property1 = new { SubProperty2 = 2 },
Property2 = 2
});
left.Merge(right);
string json = left.ToString();
StringAssert.AreEqual(@"{
""Property1"": {
""SubProperty1"": 1,
""SubProperty2"": 2
},
""Property2"": 2
}", json);
}
[Test]
public void MergeArray()
{
var left = (JObject)JToken.FromObject(new
{
Array1 = new object[]
{
new
{
Property1 = new
{
Property1 = 1,
Property2 = 2,
Property3 = 3,
Property4 = 4,
Property5 = (object)null
}
},
new { },
3,
null,
5,
null
}
});
var right = (JObject)JToken.FromObject(new
{
Array1 = new object[]
{
new
{
Property1 = new
{
Property1 = (object)null,
Property2 = 3,
Property3 = new
{
},
Property5 = (object)null
}
},
null,
null,
4,
5.1,
null,
new
{
Property1 = 1
}
}
});
left.Merge(right, new JsonMergeSettings
{
MergeArrayHandling = MergeArrayHandling.Merge
});
string json = left.ToString();
StringAssert.AreEqual(@"{
""Array1"": [
{
""Property1"": {
""Property1"": 1,
""Property2"": 3,
""Property3"": {},
""Property4"": 4,
""Property5"": null
}
},
{},
3,
4,
5.1,
null,
{
""Property1"": 1
}
]
}", json);
}
[Test]
public void ConcatArray()
{
var left = (JObject)JToken.FromObject(new
{
Array1 = new object[]
{
new { Property1 = 1 },
new { Property1 = 1 }
}
});
var right = (JObject)JToken.FromObject(new
{
Array1 = new object[]
{
new { Property1 = 1 },
new { Property2 = 2 },
new { Property3 = 3 }
}
});
left.Merge(right, new JsonMergeSettings
{
MergeArrayHandling = MergeArrayHandling.Concat
});
string json = left.ToString();
StringAssert.AreEqual(@"{
""Array1"": [
{
""Property1"": 1
},
{
""Property1"": 1
},
{
""Property1"": 1
},
{
""Property2"": 2
},
{
""Property3"": 3
}
]
}", json);
}
[Test]
public void MergeMismatchingTypesInArray()
{
var left = (JArray)JToken.FromObject(new object[]
{
true,
null,
new { Property1 = 1 },
new object[] { 1 },
new { Property1 = 1 },
1,
new object[] { 1 }
});
var right = (JArray)JToken.FromObject(new object[]
{
1,
5,
new object[] { 1 },
new { Property1 = 1 },
true,
new { Property1 = 1 },
null
});
left.Merge(right, new JsonMergeSettings
{
MergeArrayHandling = MergeArrayHandling.Merge
});
string json = left.ToString();
StringAssert.AreEqual(@"[
1,
5,
{
""Property1"": 1
},
[
1
],
{
""Property1"": 1
},
{
""Property1"": 1
},
[
1
]
]", json);
}
[Test]
public void MergeMismatchingTypesInObject()
{
var left = (JObject)JToken.FromObject(new
{
Property1 = new object[]
{
1
},
Property2 = new object[]
{
1
},
Property3 = true,
Property4 = true
});
var right = (JObject)JToken.FromObject(new
{
Property1 = new { Nested = true },
Property2 = true,
Property3 = new object[]
{
1
},
Property4 = (object)null
});
left.Merge(right);
string json = left.ToString();
StringAssert.AreEqual(@"{
""Property1"": {
""Nested"": true
},
""Property2"": true,
""Property3"": [
1
],
""Property4"": true
}", json);
}
[Test]
public void MergeArrayOverwrite_Nested()
{
var left = (JObject)JToken.FromObject(new
{
Array1 = new object[]
{
1,
2,
3
}
});
var right = (JObject)JToken.FromObject(new
{
Array1 = new object[]
{
4,
5
}
});
left.Merge(right, new JsonMergeSettings
{
MergeArrayHandling = MergeArrayHandling.Replace
});
string json = left.ToString();
StringAssert.AreEqual(@"{
""Array1"": [
4,
5
]
}", json);
}
[Test]
public void MergeArrayOverwrite_Root()
{
var left = (JArray)JToken.FromObject(new object[]
{
1,
2,
3
});
var right = (JArray)JToken.FromObject(new object[]
{
4,
5
});
left.Merge(right, new JsonMergeSettings
{
MergeArrayHandling = MergeArrayHandling.Replace
});
string json = left.ToString();
StringAssert.AreEqual(@"[
4,
5
]", json);
}
[Test]
public void UnionArrays()
{
var left = (JObject)JToken.FromObject(new
{
Array1 = new object[]
{
new { Property1 = 1 },
new { Property1 = 1 }
}
});
var right = (JObject)JToken.FromObject(new
{
Array1 = new object[]
{
new { Property1 = 1 },
new { Property2 = 2 },
new { Property3 = 3 }
}
});
left.Merge(right, new JsonMergeSettings
{
MergeArrayHandling = MergeArrayHandling.Union
});
string json = left.ToString();
StringAssert.AreEqual(@"{
""Array1"": [
{
""Property1"": 1
},
{
""Property1"": 1
},
{
""Property2"": 2
},
{
""Property3"": 3
}
]
}", json);
}
[Test]
public void MergeJProperty()
{
JProperty p1 = new JProperty("p1", 1);
JProperty p2 = new JProperty("p2", 2);
p1.Merge(p2);
Assert.AreEqual(2, (int)p1.Value);
JProperty p3 = new JProperty("p3");
p1.Merge(p3);
Assert.AreEqual(2, (int)p1.Value);
JProperty p4 = new JProperty("p4", null);
p1.Merge(p4);
Assert.AreEqual(2, (int)p1.Value);
}
[Test]
public void MergeJConstructor()
{
JConstructor c1 = new JConstructor("c1", new[] { 1, 2 });
JConstructor c2 = new JConstructor("c2", new[] { 3, 4 });
c1.Merge(c2);
Assert.AreEqual("c2", c1.Name);
CollectionAssert.AreEquivalent(new[] { 1, 2, 3, 4 }, c1.Select(i => (int)i));
JConstructor c3 = new JConstructor();
c1.Merge(c3);
Assert.AreEqual("c2", c1.Name);
JConstructor c4 = new JConstructor("c4", new[] { 5, 6 });
c1.Merge(c4, new JsonMergeSettings
{
MergeArrayHandling = MergeArrayHandling.Replace
});
Assert.AreEqual("c4", c1.Name);
CollectionAssert.AreEquivalent(new[] { 5, 6 }, c1.Select(i => (int)i));
}
[Test]
public void MergeDefaultContainers()
{
JConstructor c = new JConstructor();
c.Merge(new JConstructor());
Assert.AreEqual(null, c.Name);
Assert.AreEqual(0, c.Count);
JObject o = new JObject();
o.Merge(new JObject());
Assert.AreEqual(0, o.Count);
JArray a = new JArray();
a.Merge(new JArray());
Assert.AreEqual(0, a.Count);
JProperty p = new JProperty("name1");
p.Merge(new JProperty("name2"));
Assert.AreEqual("name1", p.Name);
Assert.AreEqual(0, p.Count);
}
[Test]
public void MergeNull()
{
JConstructor c = new JConstructor();
c.Merge(null);
Assert.AreEqual(null, c.Name);
Assert.AreEqual(0, c.Count);
JObject o = new JObject();
o.Merge(null);
Assert.AreEqual(0, o.Count);
JArray a = new JArray();
a.Merge(null);
Assert.AreEqual(0, a.Count);
JProperty p = new JProperty("name1");
p.Merge(null);
Assert.AreEqual("name1", p.Name);
Assert.AreEqual(0, p.Count);
}
[Test]
public void MergeNullValue()
{
var source = new JObject
{
{"Property1", "value"},
{"Property2", new JObject()},
{"Property3", JValue.CreateNull()},
{"Property4", JValue.CreateUndefined()},
{"Property5", new JArray()}
};
var patch = JObject.Parse("{Property1: null, Property2: null, Property3: null, Property4: null, Property5: null}");
source.Merge(patch, new JsonMergeSettings
{
MergeNullValueHandling = MergeNullValueHandling.Merge
});
Assert.IsNotNull(source["Property1"]);
Assert.AreEqual(JTokenType.Null, source["Property1"].Type);
Assert.IsNotNull(source["Property2"]);
Assert.AreEqual(JTokenType.Null, source["Property2"].Type);
Assert.IsNotNull(source["Property3"]);
Assert.AreEqual(JTokenType.Null, source["Property3"].Type);
Assert.IsNotNull(source["Property4"]);
Assert.AreEqual(JTokenType.Null, source["Property4"].Type);
Assert.IsNotNull(source["Property5"]);
Assert.AreEqual(JTokenType.Null, source["Property5"].Type);
}
[Test]
public void MergeNullValueHandling_Array()
{
string originalJson = @"{
""Bar"": [
""a"",
""b"",
""c""
]
}";
string newJson = @"{
""Bar"": null
}";
JObject oldFoo = JObject.Parse(originalJson);
JObject newFoo = JObject.Parse(newJson);
oldFoo.Merge(newFoo, new JsonMergeSettings
{
MergeNullValueHandling = MergeNullValueHandling.Ignore
});
StringAssert.AreEqual(originalJson, oldFoo.ToString());
oldFoo.Merge(newFoo, new JsonMergeSettings
{
MergeNullValueHandling = MergeNullValueHandling.Merge
});
StringAssert.AreEqual(newJson, newFoo.ToString());
}
[Test]
public void MergeNullValueHandling_Object()
{
string originalJson = @"{
""Bar"": {}
}";
string newJson = @"{
""Bar"": null
}";
JObject oldFoo = JObject.Parse(originalJson);
JObject newFoo = JObject.Parse(newJson);
oldFoo.Merge(newFoo, new JsonMergeSettings
{
MergeNullValueHandling = MergeNullValueHandling.Ignore
});
StringAssert.AreEqual(originalJson, oldFoo.ToString());
oldFoo.Merge(newFoo, new JsonMergeSettings
{
MergeNullValueHandling = MergeNullValueHandling.Merge
});
StringAssert.AreEqual(newJson, newFoo.ToString());
}
[Test]
public void Merge_IgnorePropertyCase()
{
JObject o1 = JObject.Parse(@"{
'Id': '1',
'Words': [ 'User' ]
}");
JObject o2 = JObject.Parse(@"{
'Id': '1',
'words': [ 'Name' ]
}");
o1.Merge(o2, new JsonMergeSettings
{
MergeArrayHandling = MergeArrayHandling.Concat,
MergeNullValueHandling = MergeNullValueHandling.Merge,
PropertyNameComparison = StringComparison.OrdinalIgnoreCase
});
Assert.IsNull(o1["words"]);
Assert.IsNotNull(o1["Words"]);
JArray words = (JArray)o1["Words"];
Assert.AreEqual("User", (string)words[0]);
Assert.AreEqual("Name", (string)words[1]);
}
[Test]
public void MergeSettingsComparisonDefault()
{
JsonMergeSettings settings = new JsonMergeSettings();
Assert.AreEqual(StringComparison.Ordinal, settings.PropertyNameComparison);
}
}
}