PageRenderTime 24ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/test/System.Json.Test.Unit/JsonValueDynamicMetaObjectTest.cs

https://bitbucket.org/mdavid/aspnetwebstack
C# | 534 lines | 383 code | 98 blank | 53 comment | 7 complexity | 76be52cefaf21912d49066984b882fbd MD5 | raw file
  1. using System.Collections.Generic;
  2. using System.Dynamic;
  3. using System.Linq.Expressions;
  4. using Xunit;
  5. namespace System.Json
  6. {
  7. /// <summary>
  8. ///This is a test class for JsonValueDynamicMetaObjectTest and is intended to perform sanity tests on this class.
  9. ///Extended tests are performed by the JsonValue dynamic feature tests.
  10. ///</summary>
  11. public class JsonValueDynamicMetaObjectTest
  12. {
  13. const string NonSingleNonNullIndexNotSupported = "Null index or multidimensional indexing is not supported by this indexer; use 'System.Int32' or 'System.String' for array and object indexing respectively.";
  14. /// <summary>
  15. /// A test for GetMetaObject
  16. ///</summary>
  17. [Fact]
  18. public void GetMetaObjectTest()
  19. {
  20. ExceptionHelper.Throws<ArgumentNullException>(() => { var target = GetJsonValueDynamicMetaObject(AnyInstance.AnyJsonObject, null); });
  21. }
  22. /// <summary>
  23. /// A test for BindInvokeMember
  24. ///</summary>
  25. [Fact]
  26. public void BindInvokeMemberTest()
  27. {
  28. JsonValue value = AnyInstance.AnyJsonValue1;
  29. DynamicMetaObject target = GetJsonValueDynamicMetaObject(value);
  30. TestInvokeMemberBinder.TestBindParams(target);
  31. string methodName;
  32. object[] arguments;
  33. object result = null;
  34. methodName = "ToString";
  35. arguments = new object[] { };
  36. TestInvokeMemberBinder.TestMetaObject(target, methodName, arguments);
  37. methodName = "TryReadAs";
  38. arguments = new object[] { typeof(int), result };
  39. TestInvokeMemberBinder.TestMetaObject(target, methodName, arguments);
  40. methodName = "TryReadAsType";
  41. arguments = new object[] { typeof(Person), result };
  42. TestInvokeMemberBinder.TestMetaObject(target, methodName, arguments, true);
  43. }
  44. /// <summary>
  45. /// A test for BindConvert
  46. ///</summary>
  47. [Fact]
  48. public void BindConvertTest()
  49. {
  50. JsonValue value;
  51. DynamicMetaObject target;
  52. value = (JsonValue)AnyInstance.AnyInt;
  53. target = GetJsonValueDynamicMetaObject(value);
  54. TestConvertBinder.TestBindParams(target);
  55. Type[] intTypes = { typeof(int), typeof(uint), typeof(long), };
  56. foreach (Type type in intTypes)
  57. {
  58. TestConvertBinder.TestMetaObject(target, type);
  59. }
  60. value = (JsonValue)AnyInstance.AnyString;
  61. target = GetJsonValueDynamicMetaObject(value);
  62. TestConvertBinder.TestMetaObject(target, typeof(string));
  63. value = (JsonValue)AnyInstance.AnyJsonValue1;
  64. target = GetJsonValueDynamicMetaObject(value);
  65. TestConvertBinder.TestMetaObject(target, typeof(JsonValue));
  66. TestConvertBinder.TestMetaObject(target, typeof(IEnumerable<KeyValuePair<string, JsonValue>>));
  67. TestConvertBinder.TestMetaObject(target, typeof(IDynamicMetaObjectProvider));
  68. TestConvertBinder.TestMetaObject(target, typeof(object));
  69. TestConvertBinder.TestMetaObject(target, typeof(Person), false);
  70. }
  71. /// <summary>
  72. /// A test for BindGetIndex
  73. ///</summary>
  74. [Fact]
  75. public void BindGetIndexTest()
  76. {
  77. JsonValue value = AnyInstance.AnyJsonArray;
  78. DynamicMetaObject target = GetJsonValueDynamicMetaObject(value);
  79. TestGetIndexBinder.TestBindParams(target);
  80. foreach (KeyValuePair<string, JsonValue> pair in value)
  81. {
  82. TestGetIndexBinder.TestMetaObject(target, Int32.Parse(pair.Key));
  83. }
  84. }
  85. /// <summary>
  86. /// A test for BindSetIndex
  87. ///</summary>
  88. [Fact]
  89. public void BindSetIndexTest()
  90. {
  91. JsonValue jsonValue = AnyInstance.AnyJsonArray;
  92. DynamicMetaObject target = GetJsonValueDynamicMetaObject(jsonValue);
  93. TestSetIndexBinder.TestBindParams(target);
  94. int value = 0;
  95. foreach (KeyValuePair<string, JsonValue> pair in jsonValue)
  96. {
  97. TestSetIndexBinder.TestMetaObject(target, Int32.Parse(pair.Key), value++);
  98. }
  99. }
  100. /// <summary>
  101. /// A test for BindGetMember.
  102. ///</summary>
  103. [Fact]
  104. public void BindGetMemberTest()
  105. {
  106. JsonValue value = AnyInstance.AnyJsonObject;
  107. DynamicMetaObject target = GetJsonValueDynamicMetaObject(value);
  108. TestGetMemberBinder.TestBindParams(target);
  109. foreach (KeyValuePair<string, JsonValue> pair in value)
  110. {
  111. TestGetMemberBinder.TestMetaObject(target, pair.Key);
  112. }
  113. }
  114. /// <summary>
  115. /// A test for BindSetMember.
  116. ///</summary>
  117. [Fact]
  118. public void BindSetMemberTest()
  119. {
  120. JsonValue value = AnyInstance.AnyJsonObject;
  121. string expectedMethodSignature = "System.Json.JsonValue SetValue(System.String, System.Object)";
  122. DynamicMetaObject target = GetJsonValueDynamicMetaObject(value);
  123. DynamicMetaObject arg = new DynamicMetaObject(Expression.Parameter(typeof(int)), BindingRestrictions.Empty, AnyInstance.AnyInt);
  124. TestSetMemberBinder.TestBindParams(target, arg);
  125. foreach (KeyValuePair<string, JsonValue> pair in value)
  126. {
  127. TestSetMemberBinder.TestMetaObject(target, pair.Key, arg, expectedMethodSignature);
  128. }
  129. }
  130. /// <summary>
  131. /// A test for GetDynamicMemberNames
  132. ///</summary>
  133. [Fact]
  134. public void GetDynamicMemberNamesTest()
  135. {
  136. JsonValue[] values = AnyInstance.AnyJsonValueArray;
  137. foreach (JsonValue value in values)
  138. {
  139. DynamicMetaObject target = GetJsonValueDynamicMetaObject(value);
  140. List<string> expected = new List<string>();
  141. foreach (KeyValuePair<string, JsonValue> pair in value)
  142. {
  143. expected.Add(pair.Key);
  144. }
  145. IEnumerable<string> retEnumerable = target.GetDynamicMemberNames();
  146. Assert.NotNull(retEnumerable);
  147. List<string> actual = new List<string>(retEnumerable);
  148. Assert.Equal(expected.Count, actual.Count);
  149. for (int i = 0; i < expected.Count; i++)
  150. {
  151. Assert.Equal<string>(expected[i], actual[i]);
  152. }
  153. }
  154. }
  155. /// <summary>
  156. /// Helper method for getting a <see cref="JsonValueDynamicMetaObject"/>.
  157. /// </summary>
  158. /// <param name="jsonValue">The <see cref="JsonValue"/> instance to get the dynamic meta-object from.</param>
  159. /// <returns></returns>
  160. private static DynamicMetaObject GetJsonValueDynamicMetaObject(JsonValue jsonValue)
  161. {
  162. return GetJsonValueDynamicMetaObject(jsonValue, Expression.Parameter(typeof(object)));
  163. }
  164. private static DynamicMetaObject GetJsonValueDynamicMetaObject(JsonValue jsonValue, Expression expression)
  165. {
  166. return ((IDynamicMetaObjectProvider)jsonValue).GetMetaObject(expression);
  167. }
  168. /// <summary>
  169. /// Test binder for method call operation.
  170. /// </summary>
  171. private class TestInvokeMemberBinder : InvokeMemberBinder
  172. {
  173. public TestInvokeMemberBinder(string name, int argCount)
  174. : base(name, false, new CallInfo(argCount, new string[] { }))
  175. {
  176. }
  177. public static void TestBindParams(DynamicMetaObject target)
  178. {
  179. string methodName = "ToString";
  180. object[] arguments = new object[] { };
  181. InvokeMemberBinder binder = new TestInvokeMemberBinder(methodName, arguments.Length);
  182. DynamicMetaObject[] args = new DynamicMetaObject[arguments.Length];
  183. ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindInvokeMember(null, args); });
  184. ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindInvokeMember(binder, null); });
  185. }
  186. public static void TestMetaObject(DynamicMetaObject target, string methodName, object[] arguments, bool isExtension = false)
  187. {
  188. InvokeMemberBinder binder = new TestInvokeMemberBinder(methodName, arguments.Length);
  189. DynamicMetaObject[] args = new DynamicMetaObject[arguments.Length];
  190. for (int idx = 0; idx < args.Length; idx++)
  191. {
  192. object value = arguments[idx];
  193. Type valueType = value != null ? value.GetType() : typeof(object);
  194. args[idx] = new DynamicMetaObject(Expression.Parameter(valueType), BindingRestrictions.Empty, value);
  195. }
  196. DynamicMetaObject result = target.BindInvokeMember(binder, args);
  197. Assert.NotNull(result);
  198. if (isExtension)
  199. {
  200. UnaryExpression expression = result.Expression as UnaryExpression;
  201. Assert.NotNull(expression);
  202. MethodCallExpression callExpression = expression.Operand as MethodCallExpression;
  203. Assert.NotNull(callExpression);
  204. Assert.True(callExpression.Method.ToString().Contains(methodName));
  205. }
  206. else
  207. {
  208. Assert.Same(target, result.Value);
  209. }
  210. }
  211. public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion)
  212. {
  213. throw new NotImplementedException();
  214. }
  215. public override DynamicMetaObject FallbackInvokeMember(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion)
  216. {
  217. // This is where the C# binder does the actual binding.
  218. return new DynamicMetaObject(Expression.Constant("FallbackInvokeMember called"), BindingRestrictions.Empty, target);
  219. }
  220. }
  221. /// <summary>
  222. /// The binder for the cast operation.
  223. /// </summary>
  224. private class TestConvertBinder : ConvertBinder
  225. {
  226. public TestConvertBinder(Type type)
  227. : base(type, false)
  228. {
  229. }
  230. public static void TestBindParams(DynamicMetaObject target)
  231. {
  232. ConvertBinder binder = new TestConvertBinder(typeof(int));
  233. ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindConvert(null); });
  234. }
  235. public static void TestMetaObject(DynamicMetaObject target, Type type, bool isValid = true)
  236. {
  237. ConvertBinder binder = new TestConvertBinder(type);
  238. DynamicMetaObject result = target.BindConvert(binder);
  239. Assert.NotNull(result);
  240. // Convert expression
  241. UnaryExpression expression = result.Expression as UnaryExpression;
  242. Assert.NotNull(expression);
  243. Assert.Equal<Type>(binder.Type, expression.Type);
  244. if (isValid)
  245. {
  246. MethodCallExpression methodCallExp = expression.Operand as MethodCallExpression;
  247. if (methodCallExp != null)
  248. {
  249. Assert.True(methodCallExp.Method.ToString().Contains("CastValue"));
  250. }
  251. else
  252. {
  253. ParameterExpression paramExpression = expression.Operand as ParameterExpression;
  254. Assert.NotNull(paramExpression);
  255. }
  256. }
  257. else
  258. {
  259. Expression<Action> throwExp = Expression.Lambda<Action>(Expression.Block(expression), new ParameterExpression[] { });
  260. ExceptionHelper.Throws<InvalidCastException>(() => throwExp.Compile().Invoke());
  261. }
  262. }
  263. public override DynamicMetaObject FallbackConvert(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
  264. {
  265. throw new NotImplementedException();
  266. }
  267. }
  268. /// <summary>
  269. /// Test binder for int indexer getter operation.
  270. /// </summary>
  271. private class TestGetIndexBinder : GetIndexBinder
  272. {
  273. public TestGetIndexBinder()
  274. : base(new CallInfo(0, new string[] { }))
  275. {
  276. }
  277. public static void TestBindParams(DynamicMetaObject target)
  278. {
  279. GetIndexBinder binder = new TestGetIndexBinder();
  280. Expression typeExpression = Expression.Parameter(typeof(int));
  281. DynamicMetaObject[] indexes =
  282. {
  283. new DynamicMetaObject(typeExpression, BindingRestrictions.Empty, 0),
  284. new DynamicMetaObject(typeExpression, BindingRestrictions.Empty, 1),
  285. new DynamicMetaObject(typeExpression, BindingRestrictions.Empty, 2)
  286. };
  287. ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindGetIndex(null, indexes); });
  288. ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindGetIndex(binder, null); });
  289. DynamicMetaObject[][] invalidIndexesParam =
  290. {
  291. indexes,
  292. new DynamicMetaObject[] { new DynamicMetaObject(typeExpression, BindingRestrictions.Empty, null) },
  293. new DynamicMetaObject[] { null },
  294. new DynamicMetaObject[] { }
  295. };
  296. foreach (DynamicMetaObject[] indexesParam in invalidIndexesParam)
  297. {
  298. DynamicMetaObject metaObj = target.BindGetIndex(binder, indexesParam);
  299. Expression<Action> expression = Expression.Lambda<Action>(Expression.Block(metaObj.Expression), new ParameterExpression[] { });
  300. ExceptionHelper.Throws<ArgumentException>(() => { expression.Compile().Invoke(); }, NonSingleNonNullIndexNotSupported);
  301. }
  302. }
  303. public static void TestMetaObject(DynamicMetaObject target, int index, bool isValid = true)
  304. {
  305. string expectedMethodSignature = "System.Json.JsonValue GetValue(Int32)";
  306. GetIndexBinder binder = new TestGetIndexBinder();
  307. DynamicMetaObject[] indexes = { new DynamicMetaObject(Expression.Parameter(typeof(int)), BindingRestrictions.Empty, index) };
  308. DynamicMetaObject result = target.BindGetIndex(binder, indexes);
  309. Assert.NotNull(result);
  310. MethodCallExpression expression = result.Expression as MethodCallExpression;
  311. Assert.NotNull(expression);
  312. Assert.Equal<string>(expectedMethodSignature, expression.Method.ToString());
  313. }
  314. public override DynamicMetaObject FallbackGetIndex(DynamicMetaObject target, DynamicMetaObject[] indexes, DynamicMetaObject errorSuggestion)
  315. {
  316. throw new NotImplementedException();
  317. }
  318. }
  319. /// <summary>
  320. /// Test binder for int indexer setter operation.
  321. /// </summary>
  322. private class TestSetIndexBinder : SetIndexBinder
  323. {
  324. public TestSetIndexBinder()
  325. : base(new CallInfo(0, new string[] { }))
  326. {
  327. }
  328. public static void TestBindParams(DynamicMetaObject target)
  329. {
  330. SetIndexBinder binder = new TestSetIndexBinder();
  331. Expression typeExpression = Expression.Parameter(typeof(int));
  332. DynamicMetaObject[] indexes = new DynamicMetaObject[] { new DynamicMetaObject(typeExpression, BindingRestrictions.Empty, 0) };
  333. DynamicMetaObject value = new DynamicMetaObject(typeExpression, BindingRestrictions.Empty, (JsonValue)10);
  334. ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindSetIndex(null, indexes, value); });
  335. ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindSetIndex(binder, null, value); });
  336. ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindSetIndex(binder, indexes, null); });
  337. DynamicMetaObject[][] invalidIndexesParam =
  338. {
  339. new DynamicMetaObject[]
  340. {
  341. new DynamicMetaObject(typeExpression, BindingRestrictions.Empty, 0),
  342. new DynamicMetaObject(typeExpression, BindingRestrictions.Empty, 1),
  343. new DynamicMetaObject(typeExpression, BindingRestrictions.Empty, 2)
  344. },
  345. new DynamicMetaObject[]
  346. {
  347. new DynamicMetaObject(typeExpression, BindingRestrictions.Empty, null)
  348. },
  349. new DynamicMetaObject[]
  350. {
  351. }
  352. };
  353. foreach (DynamicMetaObject[] indexesParam in invalidIndexesParam)
  354. {
  355. DynamicMetaObject metaObj = target.BindSetIndex(binder, indexesParam, value);
  356. Expression<Action> expression = Expression.Lambda<Action>(Expression.Block(metaObj.Expression), new ParameterExpression[] { });
  357. ExceptionHelper.Throws<ArgumentException>(() => { expression.Compile().Invoke(); }, NonSingleNonNullIndexNotSupported);
  358. }
  359. }
  360. public static void TestMetaObject(DynamicMetaObject target, int index, JsonValue jsonValue, bool isValid = true)
  361. {
  362. string expectedMethodSignature = "System.Json.JsonValue SetValue(Int32, System.Object)";
  363. SetIndexBinder binder = new TestSetIndexBinder();
  364. DynamicMetaObject[] indexes = { new DynamicMetaObject(Expression.Parameter(typeof(int)), BindingRestrictions.Empty, index) };
  365. DynamicMetaObject value = new DynamicMetaObject(Expression.Parameter(jsonValue.GetType()), BindingRestrictions.Empty, jsonValue);
  366. DynamicMetaObject result = target.BindSetIndex(binder, indexes, value);
  367. Assert.NotNull(result);
  368. MethodCallExpression expression = result.Expression as MethodCallExpression;
  369. Assert.NotNull(expression);
  370. Assert.Equal<string>(expectedMethodSignature, expression.Method.ToString());
  371. }
  372. public override DynamicMetaObject FallbackSetIndex(DynamicMetaObject target, DynamicMetaObject[] indexes, DynamicMetaObject value, DynamicMetaObject errorSuggestion)
  373. {
  374. throw new NotImplementedException();
  375. }
  376. }
  377. /// <summary>
  378. /// Test binder for key indexer getter.
  379. /// </summary>
  380. private class TestGetMemberBinder : GetMemberBinder
  381. {
  382. public TestGetMemberBinder(string name)
  383. : base(name, false)
  384. {
  385. }
  386. public static void TestBindParams(DynamicMetaObject target)
  387. {
  388. GetMemberBinder binder = new TestGetMemberBinder("AnyProperty");
  389. ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindGetMember(null); });
  390. }
  391. public static void TestMetaObject(DynamicMetaObject target, string name, bool isValid = true)
  392. {
  393. string expectedMethodSignature = "System.Json.JsonValue GetValue(System.String)";
  394. GetMemberBinder binder = new TestGetMemberBinder(name);
  395. DynamicMetaObject result = target.BindGetMember(binder);
  396. Assert.NotNull(result);
  397. MethodCallExpression expression = result.Expression as MethodCallExpression;
  398. Assert.NotNull(expression);
  399. Assert.Equal<string>(expectedMethodSignature, expression.Method.ToString());
  400. }
  401. public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
  402. {
  403. throw new NotImplementedException();
  404. }
  405. }
  406. /// <summary>
  407. /// Test binder for key indexer setter.
  408. /// </summary>
  409. private class TestSetMemberBinder : SetMemberBinder
  410. {
  411. public TestSetMemberBinder(string name)
  412. : base(name, false)
  413. {
  414. }
  415. public static void TestBindParams(DynamicMetaObject target, DynamicMetaObject value)
  416. {
  417. SetMemberBinder binder = new TestSetMemberBinder("AnyProperty");
  418. ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindSetMember(null, value); });
  419. ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindSetMember(binder, null); });
  420. }
  421. public static void TestMetaObject(DynamicMetaObject target, string name, DynamicMetaObject value, string expectedMethodSignature, bool isValid = true)
  422. {
  423. SetMemberBinder binder = new TestSetMemberBinder(name);
  424. DynamicMetaObject result = target.BindSetMember(binder, value);
  425. Assert.NotNull(result);
  426. MethodCallExpression expression = result.Expression as MethodCallExpression;
  427. Assert.NotNull(expression);
  428. Assert.Equal<string>(expectedMethodSignature, expression.Method.ToString());
  429. }
  430. public override DynamicMetaObject FallbackSetMember(DynamicMetaObject target, DynamicMetaObject value, DynamicMetaObject errorSuggestion)
  431. {
  432. throw new NotImplementedException();
  433. }
  434. }
  435. }
  436. }