Files
2017-07-23 17:58:21 +12:00

655 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;
using System.Globalization;
using System.IO;
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
#else
using System.Linq;
#endif
using System.Reflection;
using System.Text;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
#if DNXCORE50
using Xunit;
using Test = Xunit.FactAttribute;
using Assert = Newtonsoft.Json.Tests.XUnitAssert;
#else
using NUnit.Framework;
#endif
namespace Newtonsoft.Json.Tests.Serialization
{
[TestFixture]
public class ShouldSerializeTests : TestFixtureBase
{
public class A
{
}
public class B
{
public A A { get; set; }
public virtual bool ShouldSerializeA()
{
return false;
}
}
[Test]
public void VirtualShouldSerializeSimple()
{
string json = JsonConvert.SerializeObject(new B());
Assert.AreEqual("{}", json);
}
[Test]
public void VirtualShouldSerialize()
{
var setFoo = new Foo2()
{
name = Guid.NewGuid().ToString(),
myBar = new Bar2()
{
name = Guid.NewGuid().ToString(),
myBaz = new Baz1[]
{
new Baz1()
{
name = Guid.NewGuid().ToString(),
myFrob = new Frob1[]
{
new Frob1 { name = Guid.NewGuid().ToString() }
}
},
new Baz1()
{
name = Guid.NewGuid().ToString(),
myFrob = new Frob1[]
{
new Frob1 { name = Guid.NewGuid().ToString() }
}
},
new Baz1()
{
name = Guid.NewGuid().ToString(),
myFrob = new Frob1[]
{
new Frob1 { name = Guid.NewGuid().ToString() }
}
},
}
}
};
var setFooJson = Serialize(setFoo);
var deserializedSetFoo = JsonConvert.DeserializeObject<Foo2>(setFooJson);
Assert.AreEqual(setFoo.name, deserializedSetFoo.name);
Assert.IsNotNull(deserializedSetFoo.myBar);
Assert.AreEqual(setFoo.myBar.name, deserializedSetFoo.myBar.name);
Assert.IsNotNull(deserializedSetFoo.myBar.myBaz);
Assert.AreEqual(setFoo.myBar.myBaz.Length, deserializedSetFoo.myBar.myBaz.Length);
Assert.AreEqual(setFoo.myBar.myBaz[0].name, deserializedSetFoo.myBar.myBaz[0].name);
Assert.IsNotNull(deserializedSetFoo.myBar.myBaz[0].myFrob[0]);
Assert.AreEqual(setFoo.myBar.myBaz[0].myFrob[0].name, deserializedSetFoo.myBar.myBaz[0].myFrob[0].name);
Assert.AreEqual(setFoo.myBar.myBaz[1].name, deserializedSetFoo.myBar.myBaz[1].name);
Assert.IsNotNull(deserializedSetFoo.myBar.myBaz[2].myFrob[0]);
Assert.AreEqual(setFoo.myBar.myBaz[1].myFrob[0].name, deserializedSetFoo.myBar.myBaz[1].myFrob[0].name);
Assert.AreEqual(setFoo.myBar.myBaz[2].name, deserializedSetFoo.myBar.myBaz[2].name);
Assert.IsNotNull(deserializedSetFoo.myBar.myBaz[2].myFrob[0]);
Assert.AreEqual(setFoo.myBar.myBaz[2].myFrob[0].name, deserializedSetFoo.myBar.myBaz[2].myFrob[0].name);
Assert.AreEqual(true, setFoo.myBar.ShouldSerializemyBazCalled);
}
private string Serialize(Foo2 f)
{
//Code copied from JsonConvert.SerializeObject(), with addition of trace writing
JsonSerializer jsonSerializer = JsonSerializer.CreateDefault();
var traceWriter = new MemoryTraceWriter();
jsonSerializer.TraceWriter = traceWriter;
StringBuilder sb = new StringBuilder(256);
StringWriter sw = new StringWriter(sb, CultureInfo.InvariantCulture);
using (JsonTextWriter jsonWriter = new JsonTextWriter(sw))
{
jsonWriter.Formatting = Formatting.None;
jsonSerializer.Serialize(jsonWriter, f, typeof(Foo2));
}
return sw.ToString();
}
[Test]
public void ShouldSerializeTest()
{
ShouldSerializeTestClass c = new ShouldSerializeTestClass();
c.Name = "James";
c.Age = 27;
string json = JsonConvert.SerializeObject(c, Formatting.Indented);
StringAssert.AreEqual(@"{
""Age"": 27
}", json);
c._shouldSerializeName = true;
json = JsonConvert.SerializeObject(c, Formatting.Indented);
StringAssert.AreEqual(@"{
""Name"": ""James"",
""Age"": 27
}", json);
ShouldSerializeTestClass deserialized = JsonConvert.DeserializeObject<ShouldSerializeTestClass>(json);
Assert.AreEqual("James", deserialized.Name);
Assert.AreEqual(27, deserialized.Age);
}
[Test]
public void ShouldSerializeExample()
{
Employee joe = new Employee();
joe.Name = "Joe Employee";
Employee mike = new Employee();
mike.Name = "Mike Manager";
joe.Manager = mike;
mike.Manager = mike;
string json = JsonConvert.SerializeObject(new[] { joe, mike }, Formatting.Indented);
// [
// {
// "Name": "Joe Employee",
// "Manager": {
// "Name": "Mike Manager"
// }
// },
// {
// "Name": "Mike Manager"
// }
// ]
StringAssert.AreEqual(@"[
{
""Name"": ""Joe Employee"",
""Manager"": {
""Name"": ""Mike Manager""
}
},
{
""Name"": ""Mike Manager""
}
]", json);
}
[Test]
public void SpecifiedTest()
{
SpecifiedTestClass c = new SpecifiedTestClass();
c.Name = "James";
c.Age = 27;
c.NameSpecified = false;
string json = JsonConvert.SerializeObject(c, Formatting.Indented);
StringAssert.AreEqual(@"{
""Age"": 27
}", json);
SpecifiedTestClass deserialized = JsonConvert.DeserializeObject<SpecifiedTestClass>(json);
Assert.IsNull(deserialized.Name);
Assert.IsFalse(deserialized.NameSpecified);
Assert.IsFalse(deserialized.WeightSpecified);
Assert.IsFalse(deserialized.HeightSpecified);
Assert.IsFalse(deserialized.FavoriteNumberSpecified);
Assert.AreEqual(27, deserialized.Age);
c.NameSpecified = true;
c.WeightSpecified = true;
c.HeightSpecified = true;
c.FavoriteNumber = 23;
json = JsonConvert.SerializeObject(c, Formatting.Indented);
StringAssert.AreEqual(@"{
""Name"": ""James"",
""Age"": 27,
""Weight"": 0,
""Height"": 0,
""FavoriteNumber"": 23
}", json);
deserialized = JsonConvert.DeserializeObject<SpecifiedTestClass>(json);
Assert.AreEqual("James", deserialized.Name);
Assert.IsTrue(deserialized.NameSpecified);
Assert.IsTrue(deserialized.WeightSpecified);
Assert.IsTrue(deserialized.HeightSpecified);
Assert.IsTrue(deserialized.FavoriteNumberSpecified);
Assert.AreEqual(27, deserialized.Age);
Assert.AreEqual(23, deserialized.FavoriteNumber);
}
// [Test]
// public void XmlSerializerSpecifiedTrueTest()
// {
// XmlSerializer s = new XmlSerializer(typeof(OptionalOrder));
// StringWriter sw = new StringWriter();
// s.Serialize(sw, new OptionalOrder() { FirstOrder = "First", FirstOrderSpecified = true });
// Console.WriteLine(sw.ToString());
// string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
//<OptionalOrder xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
// <FirstOrder>First</FirstOrder>
//</OptionalOrder>";
// OptionalOrder o = (OptionalOrder)s.Deserialize(new StringReader(xml));
// Console.WriteLine(o.FirstOrder);
// Console.WriteLine(o.FirstOrderSpecified);
// }
// [Test]
// public void XmlSerializerSpecifiedFalseTest()
// {
// XmlSerializer s = new XmlSerializer(typeof(OptionalOrder));
// StringWriter sw = new StringWriter();
// s.Serialize(sw, new OptionalOrder() { FirstOrder = "First", FirstOrderSpecified = false });
// Console.WriteLine(sw.ToString());
// // string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
// //<OptionalOrder xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
// // <FirstOrder>First</FirstOrder>
// //</OptionalOrder>";
// // OptionalOrder o = (OptionalOrder)s.Deserialize(new StringReader(xml));
// // Console.WriteLine(o.FirstOrder);
// // Console.WriteLine(o.FirstOrderSpecified);
// }
public class OptionalOrder
{
// This field shouldn't be serialized
// if it is uninitialized.
public string FirstOrder;
// Use the XmlIgnoreAttribute to ignore the
// special field named "FirstOrderSpecified".
[System.Xml.Serialization.XmlIgnoreAttribute]
public bool FirstOrderSpecified;
}
public class FamilyDetails
{
public string Name { get; set; }
public int NumberOfChildren { get; set; }
[JsonIgnore]
public bool NumberOfChildrenSpecified { get; set; }
}
[Test]
public void SpecifiedExample()
{
FamilyDetails joe = new FamilyDetails();
joe.Name = "Joe Family Details";
joe.NumberOfChildren = 4;
joe.NumberOfChildrenSpecified = true;
FamilyDetails martha = new FamilyDetails();
martha.Name = "Martha Family Details";
martha.NumberOfChildren = 3;
martha.NumberOfChildrenSpecified = false;
string json = JsonConvert.SerializeObject(new[] { joe, martha }, Formatting.Indented);
//[
// {
// "Name": "Joe Family Details",
// "NumberOfChildren": 4
// },
// {
// "Name": "Martha Family Details"
// }
//]
StringAssert.AreEqual(@"[
{
""Name"": ""Joe Family Details"",
""NumberOfChildren"": 4
},
{
""Name"": ""Martha Family Details""
}
]", json);
string mikeString = "{\"Name\": \"Mike Person\"}";
FamilyDetails mike = JsonConvert.DeserializeObject<FamilyDetails>(mikeString);
Assert.AreEqual(false, mike.NumberOfChildrenSpecified);
string mikeFullDisclosureString = "{\"Name\": \"Mike Person\", \"NumberOfChildren\": \"0\"}";
mike = JsonConvert.DeserializeObject<FamilyDetails>(mikeFullDisclosureString);
Assert.AreEqual(true, mike.NumberOfChildrenSpecified);
}
[Test]
public void ShouldSerializeInheritedClassTest()
{
NewEmployee joe = new NewEmployee();
joe.Name = "Joe Employee";
joe.Age = 100;
Employee mike = new Employee();
mike.Name = "Mike Manager";
mike.Manager = mike;
joe.Manager = mike;
//StringWriter sw = new StringWriter();
//XmlSerializer x = new XmlSerializer(typeof(NewEmployee));
//x.Serialize(sw, joe);
//Console.WriteLine(sw);
//JavaScriptSerializer s = new JavaScriptSerializer();
//Console.WriteLine(s.Serialize(new {html = @"<script>hi</script>; & ! ^ * ( ) ! @ # $ % ^ ' "" - , . / ; : [ { } ] ; ' - _ = + ? ` ~ \ |"}));
string json = JsonConvert.SerializeObject(joe, Formatting.Indented);
StringAssert.AreEqual(@"{
""Age"": 100,
""Name"": ""Joe Employee"",
""Manager"": {
""Name"": ""Mike Manager""
}
}", json);
}
[Test]
public void ShouldDeserialize_True()
{
string json = @"{'HasName':true,'Name':'Name!'}";
MemoryTraceWriter traceWriter = new MemoryTraceWriter();
ShouldDeserializeTestClass c = JsonConvert.DeserializeObject<ShouldDeserializeTestClass>(json, new JsonSerializerSettings
{
ContractResolver = ShouldDeserializeContractResolver.Instance,
TraceWriter = traceWriter
});
Assert.AreEqual(null, c.ExtensionData);
Assert.AreEqual(true, c.HasName);
Assert.AreEqual("Name!", c.Name);
Assert.IsTrue(traceWriter.GetTraceMessages().Any(m => m.EndsWith("Verbose ShouldDeserialize result for property 'Name' on Newtonsoft.Json.Tests.Serialization.ShouldDeserializeTestClass: True. Path 'Name'.")));
}
[Test]
public void ShouldDeserialize_False()
{
string json = @"{'HasName':false,'Name':'Name!'}";
MemoryTraceWriter traceWriter = new MemoryTraceWriter();
ShouldDeserializeTestClass c = JsonConvert.DeserializeObject<ShouldDeserializeTestClass>(json, new JsonSerializerSettings
{
ContractResolver = ShouldDeserializeContractResolver.Instance,
TraceWriter = traceWriter
});
Assert.AreEqual(1, c.ExtensionData.Count);
Assert.AreEqual("Name!", (string)c.ExtensionData["Name"]);
Assert.AreEqual(false, c.HasName);
Assert.AreEqual(null, c.Name);
Assert.IsTrue(traceWriter.GetTraceMessages().Any(m => m.EndsWith("Verbose ShouldDeserialize result for property 'Name' on Newtonsoft.Json.Tests.Serialization.ShouldDeserializeTestClass: False. Path 'Name'.")));
}
public class Employee
{
public string Name { get; set; }
public Employee Manager { get; set; }
public bool ShouldSerializeManager()
{
return (Manager != this);
}
}
public class NewEmployee : Employee
{
public int Age { get; set; }
public bool ShouldSerializeName()
{
return false;
}
}
}
public class ShouldSerializeTestClass
{
internal bool _shouldSerializeName;
public string Name { get; set; }
public int Age { get; set; }
public void ShouldSerializeAge()
{
// dummy. should never be used because it doesn't return bool
}
public bool ShouldSerializeName()
{
return _shouldSerializeName;
}
}
public class SpecifiedTestClass
{
private bool _nameSpecified;
public string Name { get; set; }
public int Age { get; set; }
public int Weight { get; set; }
public int Height { get; set; }
public int FavoriteNumber { get; set; }
// dummy. should never be used because it isn't of type bool
[JsonIgnore]
public long AgeSpecified { get; set; }
[JsonIgnore]
public bool NameSpecified
{
get { return _nameSpecified; }
set { _nameSpecified = value; }
}
[JsonIgnore]
public bool WeightSpecified;
[JsonIgnore]
[System.Xml.Serialization.XmlIgnoreAttribute]
public bool HeightSpecified;
[JsonIgnore]
public bool FavoriteNumberSpecified
{
// get only example
get { return FavoriteNumber != 0; }
}
}
public class Foo2
{
private Bar2 myBarField;
public Bar2 myBar
{
get { return myBarField; }
set { myBarField = value; }
}
private string nameField;
public string name
{
get { return nameField; }
set { nameField = value; }
}
public virtual bool ShouldSerializemyBar()
{
return (myBar != null);
}
public virtual bool ShouldSerializename()
{
return (name != null);
}
}
public class Bar2
{
[JsonIgnore]
public bool ShouldSerializemyBazCalled { get; set; }
private Baz1[] myBazField;
public Baz1[] myBaz
{
get { return myBazField; }
set { myBazField = value; }
}
private string nameField;
public string name
{
get { return nameField; }
set { nameField = value; }
}
public virtual bool ShouldSerializemyBaz()
{
ShouldSerializemyBazCalled = true;
return (myBaz != null);
}
public virtual bool ShouldSerializename()
{
return (name != null);
}
}
public class Baz1
{
private Frob1[] myFrobField;
public Frob1[] myFrob
{
get { return myFrobField; }
set { myFrobField = value; }
}
private string nameField;
public string name
{
get { return nameField; }
set { nameField = value; }
}
public virtual bool ShouldSerializename()
{
return (name != null);
}
public virtual bool ShouldSerializemyFrob()
{
return (myFrob != null);
}
}
public class Frob1
{
private string nameField;
public string name
{
get { return nameField; }
set { nameField = value; }
}
public virtual bool ShouldSerializename()
{
return (name != null);
}
}
public class ShouldDeserializeContractResolver : DefaultContractResolver
{
public static new readonly ShouldDeserializeContractResolver Instance = new ShouldDeserializeContractResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
MethodInfo shouldDeserializeMethodInfo = member.DeclaringType.GetMethod("ShouldDeserialize" + member.Name);
if (shouldDeserializeMethodInfo != null)
{
property.ShouldDeserialize = o => { return (bool)shouldDeserializeMethodInfo.Invoke(o, null); };
}
return property;
}
}
public class ShouldDeserializeTestClass
{
[JsonExtensionData]
public IDictionary<string, JToken> ExtensionData { get; set; }
public bool HasName { get; set; }
public string Name { get; set; }
public bool ShouldDeserializeName()
{
return HasName;
}
}
}