PageRenderTime 37ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/test/System.Net.Http.Formatting.Test.Integration/JsonNetSerializationTest.cs

https://bitbucket.org/mdavid/aspnetwebstack
C# | 516 lines | 419 code | 76 blank | 21 comment | 38 complexity | de91b04fc9295aee41d256899dc3a4f0 MD5 | raw file
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Runtime.Serialization;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using Microsoft.TestCommon;
  8. using Newtonsoft.Json;
  9. using Newtonsoft.Json.Linq;
  10. using Xunit;
  11. using Xunit.Extensions;
  12. namespace System.Net.Http.Formatting
  13. {
  14. public class JsonNetSerializationTest
  15. {
  16. public static IEnumerable<object[]> SerializedJson
  17. {
  18. get
  19. {
  20. return new TheoryDataSet<object, string>()
  21. {
  22. // Primitives
  23. { 'f', "\"f\"" },
  24. { "abc", "\"abc\"" },
  25. { "\"\\", @"""\""\\""" },
  26. { 256, "256" },
  27. { (ulong)long.MaxValue, long.MaxValue.ToString() },
  28. { 45.78m, "45.78" },
  29. { .00000457823432, "4.57823432E-06" },
  30. { (byte)24, "24" },
  31. { false, "false" },
  32. { AttributeTargets.Assembly | AttributeTargets.Constructor, "33" },
  33. { ConsoleColor.DarkCyan, "3" },
  34. { new DateTimeOffset(1999, 5, 27, 4, 34, 45, TimeSpan.Zero), "\"1999-05-27T04:34:45+00:00\"" },
  35. { new TimeSpan(5, 30, 0), "\"05:30:00\"" },
  36. { new Uri("http://www.bing.com"), @"""http://www.bing.com/""" },
  37. { new Guid("4ed1cd44-11d7-4b27-b623-0b8b553c8906"), "\"4ed1cd44-11d7-4b27-b623-0b8b553c8906\"" },
  38. // Structs
  39. { new Point() { x = 45, Y = -5}, "{\"x\":45,\"Y\":-5}" },
  40. // Arrays
  41. { new object[] {}, "[]" },
  42. { new int[] { 1, 2, 3}, "[1,2,3]" },
  43. { new string[] { "a", "b"}, "[\"a\",\"b\"]" },
  44. { new Point[] { new Point() { x = 10, Y = 10}, new Point() { x = 20, Y = 20}}, "[{\"x\":10,\"Y\":10},{\"x\":20,\"Y\":20}]" },
  45. // Collections
  46. { new List<int> { 1, 2, 3}, "[1,2,3]" },
  47. { new List<string> { "a", "b"}, "[\"a\",\"b\"]" },
  48. { new List<Point> { new Point() { x = 10, Y = 10}, new Point() { x = 20, Y = 20}}, "[{\"x\":10,\"Y\":10},{\"x\":20,\"Y\":20}]" },
  49. { new MyList<int> { 1, 2, 3}, "[1,2,3]" },
  50. { new MyList<string> { "a", "b"}, "[\"a\",\"b\"]" },
  51. { new MyList<Point> { new Point() { x = 10, Y = 10}, new Point() { x = 20, Y = 20}}, "[{\"x\":10,\"Y\":10},{\"x\":20,\"Y\":20}]" },
  52. // Dictionaries
  53. { new Dictionary<string, string> { { "k1", "v1" }, { "k2", "v2" } }, "{\"k1\":\"v1\",\"k2\":\"v2\"}" },
  54. { new Dictionary<int, string> { { 1, "v1" }, { 2, "v2" } }, "{\"1\":\"v1\",\"2\":\"v2\"}" },
  55. // Anonymous types
  56. { new { Anon1 = 56, Anon2 = "foo"}, "{\"Anon1\":56,\"Anon2\":\"foo\"}" },
  57. // Classes
  58. { new DataContractType() { s = "foo", i = 49, NotAMember = "Error" }, "{\"s\":\"foo\",\"i\":49}" },
  59. { new POCOType() { s = "foo", t = "Error"}, "{\"s\":\"foo\"}" },
  60. { new SerializableType("protected") { publicField = "public", protectedInternalField = "protected internal", internalField = "internal", PublicProperty = "private", nonSerializedField = "Error" }, "{\"publicField\":\"public\",\"internalField\":\"internal\",\"protectedInternalField\":\"protected internal\",\"protectedField\":\"protected\",\"privateField\":\"private\"}" },
  61. // Generics
  62. { new KeyValuePair<string, bool>("foo", false), "{\"Key\":\"foo\",\"Value\":false}" },
  63. // ISerializable types
  64. { new ArgumentNullException("param"), "{\"ClassName\":\"System.ArgumentNullException\",\"Message\":\"Value cannot be null.\",\"Data\":null,\"InnerException\":null,\"HelpURL\":null,\"StackTraceString\":null,\"RemoteStackTraceString\":null,\"RemoteStackIndex\":0,\"ExceptionMethod\":null,\"HResult\":-2147467261,\"Source\":null,\"WatsonBuckets\":null,\"ParamName\":\"param\"}" },
  65. // JSON Values
  66. { new JValue(false), "false" },
  67. { new JValue(54), "54" },
  68. { new JValue("s"), "\"s\"" },
  69. { new JArray() { new JValue(1), new JValue(2) }, "[1,2]" },
  70. { new JObject() { { "k1", new JValue("v1") }, { "k2", new JValue("v2") } }, "{\"k1\":\"v1\",\"k2\":\"v2\"}" },
  71. { new KeyValuePair<JToken, JToken>(new JValue("k"), new JArray() { new JValue("v1"), new JValue("v2") }), "{\"Key\":\"k\",\"Value\":[\"v1\",\"v2\"]}" },
  72. };
  73. }
  74. }
  75. public static IEnumerable<object[]> TypedSerializedJson
  76. {
  77. get
  78. {
  79. return new TheoryDataSet<object, string, Type>()
  80. {
  81. // Null
  82. { null, "null", typeof(POCOType) },
  83. { null, "null", typeof(JToken) },
  84. // Nullables
  85. { new int?(), "null", typeof(int?) },
  86. { new Point?(), "null", typeof(Point?) },
  87. { new ConsoleColor?(), "null", typeof(ConsoleColor?) },
  88. { new int?(45), "45", typeof(int?) },
  89. { new Point?(new Point() { x = 45, Y = -5 }), "{\"x\":45,\"Y\":-5}", typeof(Point?) },
  90. { new ConsoleColor?(ConsoleColor.DarkMagenta), "5", typeof(ConsoleColor?)},
  91. };
  92. }
  93. }
  94. [Theory]
  95. [PropertyData("SerializedJson")]
  96. public void ObjectsSerializeToExpectedJson(object o, string expectedJson)
  97. {
  98. ObjectsSerializeToExpectedJsonWithProvidedType(o, expectedJson, o.GetType());
  99. }
  100. [Theory]
  101. [PropertyData("SerializedJson")]
  102. public void JsonDeserializesToExpectedObject(object expectedObject, string json)
  103. {
  104. JsonDeserializesToExpectedObjectWithProvidedType(expectedObject, json, expectedObject.GetType());
  105. }
  106. [Theory]
  107. [PropertyData("TypedSerializedJson")]
  108. public void ObjectsSerializeToExpectedJsonWithProvidedType(object o, string expectedJson, Type type)
  109. {
  110. Assert.Equal(expectedJson, Serialize(o, type));
  111. }
  112. [Theory]
  113. [PropertyData("TypedSerializedJson")]
  114. public void JsonDeserializesToExpectedObjectWithProvidedType(object expectedObject, string json, Type type)
  115. {
  116. if (expectedObject == null)
  117. {
  118. Assert.Null(Deserialize(json, type));
  119. }
  120. else
  121. {
  122. Assert.Equal(expectedObject, Deserialize(json, type), new ObjectComparer());
  123. }
  124. }
  125. [Fact]
  126. public void CallbacksGetCalled()
  127. {
  128. TypeWithCallbacks o = new TypeWithCallbacks();
  129. string json = Serialize(o, typeof(TypeWithCallbacks));
  130. Assert.Equal("12", o.callbackOrder);
  131. TypeWithCallbacks deserializedObject = Deserialize(json, typeof(TypeWithCallbacks)) as TypeWithCallbacks;
  132. Assert.Equal("34", deserializedObject.callbackOrder);
  133. }
  134. [Fact]
  135. public void DerivedTypesArePreserved()
  136. {
  137. JsonMediaTypeFormatter formatter = new JsonMediaTypeFormatter();
  138. formatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;
  139. string json = Serialize(new Derived(), typeof(Base), formatter);
  140. object deserializedObject = Deserialize(json, typeof(Base), formatter);
  141. Assert.IsType(typeof(Derived), deserializedObject);
  142. }
  143. [Fact]
  144. public void ArbitraryTypesArentDeserializedByDefault()
  145. {
  146. string json = "{\"$type\":\"" + typeof(DangerousType).AssemblyQualifiedName + "\"}";
  147. object deserializedObject = Deserialize(json, typeof(object));
  148. Assert.IsNotType(typeof(DangerousType), deserializedObject);
  149. }
  150. [Fact]
  151. public void ReferencesArePreserved()
  152. {
  153. Ref ref1 = new Ref();
  154. Ref ref2 = new Ref();
  155. ref1.Reference = ref2;
  156. ref2.Reference = ref1;
  157. string json = Serialize(ref1, typeof(Ref));
  158. Ref deserializedObject = Deserialize(json, typeof(Ref)) as Ref;
  159. Assert.ReferenceEquals(deserializedObject, deserializedObject.Reference.Reference);
  160. }
  161. [Fact]
  162. public void DeserializingDeepArraysThrows()
  163. {
  164. StringBuilder sb = new StringBuilder();
  165. int depth = 1500;
  166. for (int i = 0; i < depth; i++)
  167. {
  168. sb.Append("[");
  169. }
  170. sb.Append("null");
  171. for (int i = 0; i < depth; i++)
  172. {
  173. sb.Append("]");
  174. }
  175. string json = sb.ToString();
  176. Assert.Throws(typeof(JsonReaderQuotaException), () => Deserialize(json, typeof(object)));
  177. }
  178. [Theory]
  179. // existing good surrogate pair
  180. [InlineData("ABC \\ud800\\udc00 DEF", "ABC \ud800\udc00 DEF")]
  181. // invalid surrogates (two high back-to-back)
  182. [InlineData("ABC \\ud800\\ud800 DEF", "ABC \ufffd\ufffd DEF")]
  183. // invalid high surrogate at end of string
  184. [InlineData("ABC \\ud800", "ABC \ufffd")]
  185. // high surrogate not followed by low surrogate
  186. [InlineData("ABC \\ud800 DEF", "ABC \ufffd DEF")]
  187. // low surrogate not preceded by high surrogate
  188. [InlineData("ABC \\udc00\\ud800 DEF", "ABC \ufffd\ufffd DEF")]
  189. // make sure unencoded invalid surrogate characters don't make it through
  190. [InlineData("\udc00\ud800\ud800", "??????")]
  191. public void InvalidUnicodeStringsAreFixedUp(string input, string expectedString)
  192. {
  193. string json = "\"" + input + "\"";
  194. string deserializedString = Deserialize(json, typeof(string)) as string;
  195. Assert.Equal(expectedString, deserializedString);
  196. }
  197. private static string Serialize(object o, Type type, MediaTypeFormatter formatter = null)
  198. {
  199. formatter = formatter ?? new JsonMediaTypeFormatter();
  200. MemoryStream ms = new MemoryStream();
  201. formatter.WriteToStreamAsync(type, o, ms, null, null).Wait();
  202. ms.Flush();
  203. ms.Position = 0;
  204. return new StreamReader(ms).ReadToEnd();
  205. }
  206. internal static object Deserialize(string json, Type type, MediaTypeFormatter formatter = null, IFormatterLogger formatterLogger = null)
  207. {
  208. formatter = formatter ?? new JsonMediaTypeFormatter();
  209. MemoryStream ms = new MemoryStream();
  210. byte[] bytes = Encoding.Default.GetBytes(json);
  211. ms.Write(bytes, 0, bytes.Length);
  212. ms.Flush();
  213. ms.Position = 0;
  214. Task<object> readTask = formatter.ReadFromStreamAsync(type, ms, contentHeaders: null, formatterLogger: formatterLogger);
  215. readTask.WaitUntilCompleted();
  216. if (readTask.IsFaulted)
  217. {
  218. throw readTask.Exception.GetBaseException();
  219. }
  220. return readTask.Result;
  221. }
  222. }
  223. public class ObjectComparer : IEqualityComparer<object>
  224. {
  225. bool IEqualityComparer<object>.Equals(object x, object y)
  226. {
  227. Type xType = x.GetType();
  228. if (xType == y.GetType())
  229. {
  230. if (typeof(JToken).IsAssignableFrom(xType) || xType == typeof(ArgumentNullException) || xType == typeof(KeyValuePair<JToken, JToken>))
  231. {
  232. return x.ToString() == y.ToString();
  233. }
  234. if (xType == typeof(DataContractType))
  235. {
  236. return Equals<DataContractType>(x, y);
  237. }
  238. if (xType == typeof(POCOType))
  239. {
  240. return Equals<POCOType>(x, y);
  241. }
  242. if (xType == typeof(SerializableType))
  243. {
  244. return Equals<SerializableType>(x, y);
  245. }
  246. if (xType == typeof(Point))
  247. {
  248. return Equals<Point>(x, y);
  249. }
  250. if (typeof(IEnumerable).IsAssignableFrom(xType))
  251. {
  252. IEnumerator xEnumerator = ((IEnumerable)x).GetEnumerator();
  253. IEnumerator yEnumerator = ((IEnumerable)y).GetEnumerator();
  254. while (xEnumerator.MoveNext())
  255. {
  256. // if x is longer than y
  257. if (!yEnumerator.MoveNext())
  258. {
  259. return false;
  260. }
  261. else
  262. {
  263. if (!xEnumerator.Current.Equals(yEnumerator.Current))
  264. {
  265. return false;
  266. }
  267. }
  268. }
  269. // if y is longer than x
  270. if (yEnumerator.MoveNext())
  271. {
  272. return false;
  273. }
  274. return true;
  275. }
  276. }
  277. return x.Equals(y);
  278. }
  279. int IEqualityComparer<object>.GetHashCode(object obj)
  280. {
  281. throw new NotImplementedException();
  282. }
  283. bool Equals<T>(object x, object y) where T : IEquatable<T>
  284. {
  285. IEquatable<T> yEquatable = (IEquatable<T>)y;
  286. return yEquatable.Equals((T)x);
  287. }
  288. }
  289. // Marked as [Serializable] to check that [DataContract] takes precedence over [Serializable]
  290. [DataContract]
  291. [Serializable]
  292. public class DataContractType : IEquatable<DataContractType>
  293. {
  294. [DataMember]
  295. public string s;
  296. [DataMember]
  297. internal int i;
  298. public string NotAMember;
  299. public bool Equals(DataContractType other)
  300. {
  301. return this.s == other.s && this.i == other.i;
  302. }
  303. }
  304. public class POCOType : IEquatable<POCOType>
  305. {
  306. public string s;
  307. internal string t;
  308. public bool Equals(POCOType other)
  309. {
  310. return this.s == other.s;
  311. }
  312. }
  313. public class MyList<T> : ICollection<T>
  314. {
  315. List<T> innerList = new List<T>();
  316. public IEnumerator<T> GetEnumerator()
  317. {
  318. return innerList.GetEnumerator();
  319. }
  320. public void Add(T item)
  321. {
  322. innerList.Add(item);
  323. }
  324. public void Clear()
  325. {
  326. innerList.Clear();
  327. }
  328. public bool Contains(T item)
  329. {
  330. return innerList.Contains(item);
  331. }
  332. public void CopyTo(T[] array, int arrayIndex)
  333. {
  334. innerList.CopyTo(array, arrayIndex);
  335. }
  336. public int Count
  337. {
  338. get { return innerList.Count; }
  339. }
  340. public bool IsReadOnly
  341. {
  342. get { return ((ICollection<T>)innerList).IsReadOnly; }
  343. }
  344. public bool Remove(T item)
  345. {
  346. return innerList.Remove(item);
  347. }
  348. IEnumerator IEnumerable.GetEnumerator()
  349. {
  350. return innerList.GetEnumerator();
  351. }
  352. IEnumerator<T> IEnumerable<T>.GetEnumerator()
  353. {
  354. return innerList.GetEnumerator();
  355. }
  356. }
  357. [Serializable]
  358. class SerializableType : IEquatable<SerializableType>
  359. {
  360. public SerializableType(string protectedFieldValue)
  361. {
  362. this.protectedField = protectedFieldValue;
  363. }
  364. public string publicField;
  365. internal string internalField;
  366. protected internal string protectedInternalField;
  367. protected string protectedField;
  368. private string privateField;
  369. public string PublicProperty
  370. {
  371. get
  372. {
  373. return privateField;
  374. }
  375. set
  376. {
  377. this.privateField = value;
  378. }
  379. }
  380. [NonSerialized]
  381. public string nonSerializedField;
  382. public bool Equals(SerializableType other)
  383. {
  384. return this.publicField == other.publicField &&
  385. this.internalField == other.internalField &&
  386. this.protectedInternalField == other.protectedInternalField &&
  387. this.protectedField == other.protectedField &&
  388. this.privateField == other.privateField;
  389. }
  390. }
  391. public struct Point : IEquatable<Point>
  392. {
  393. public int x;
  394. public int Y { get; set; }
  395. public bool Equals(Point other)
  396. {
  397. return this.x == other.x && this.Y == other.Y;
  398. }
  399. }
  400. [DataContract(IsReference = true)]
  401. public class Ref
  402. {
  403. [DataMember]
  404. public Ref Reference;
  405. }
  406. public class Base
  407. {
  408. }
  409. public class Derived : Base
  410. {
  411. }
  412. [DataContract]
  413. public class TypeWithCallbacks
  414. {
  415. public string callbackOrder = "";
  416. [OnSerializing]
  417. public void OnSerializing(StreamingContext c)
  418. {
  419. callbackOrder += "1";
  420. }
  421. [OnSerialized]
  422. public void OnSerialized(StreamingContext c)
  423. {
  424. callbackOrder += "2";
  425. }
  426. [OnDeserializing]
  427. public void OnDeserializing(StreamingContext c)
  428. {
  429. callbackOrder += "3";
  430. }
  431. [OnDeserialized]
  432. public void OnDeserialized(StreamingContext c)
  433. {
  434. callbackOrder += "4";
  435. }
  436. }
  437. public class DangerousType
  438. {
  439. }
  440. }