PageRenderTime 59ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/IronPython_Main/Runtime/Tests/SiteTest/SiteTestScenarios.Tests.Dynamic.cs

#
C# | 1750 lines | 1223 code | 315 blank | 212 comment | 33 complexity | 3b67d3bda5b9a4bb5bd510a67cdb4813 MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, CPL-1.0, CC-BY-SA-3.0, BSD-3-Clause, ISC, AGPL-3.0, LGPL-2.1, Apache-2.0
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if !CLR2
  16. using System.Linq.Expressions;
  17. #else
  18. using Microsoft.Scripting.Ast;
  19. using Microsoft.Scripting.Utils;
  20. #endif
  21. using System;
  22. using System.Collections.Generic;
  23. using System.ComponentModel;
  24. using System.Dynamic;
  25. using System.Reflection;
  26. using System.Runtime.CompilerServices;
  27. using System.Runtime.Serialization;
  28. using System.Runtime.Serialization.Formatters.Binary;
  29. using System.Threading;
  30. using SiteTest.Actions;
  31. using System.IO;
  32. namespace SiteTest {
  33. partial class SiteTestScenarios {
  34. [Test("Remoted IDO")]
  35. private void Scenario_Remoted() {
  36. #region CallSite for each action
  37. var setMember = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("__code__"));
  38. var getMember = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("__code__"));
  39. #endregion
  40. // run locally
  41. object mbro = new MBRODynamicObject();
  42. Assert.AreEqual("MBRO_GetMember", getMember.Target(getMember, mbro));
  43. // run remotely
  44. var domain = AppDomain.CreateDomain("remote");
  45. mbro = domain.CreateInstanceAndUnwrap(typeof(MBRODynamicObject).Assembly.FullName, typeof(MBRODynamicObject).FullName);
  46. getMember = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("__code__"));
  47. Assert.AreEqual("123", getMember.Target(getMember, mbro));
  48. // run in current domain
  49. domain = AppDomain.CurrentDomain;
  50. mbro = domain.CreateInstanceAndUnwrap(typeof(MBRODynamicObject).Assembly.FullName, typeof(MBRODynamicObject).FullName);
  51. getMember = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("__code__"));
  52. Assert.AreEqual("MBRO_GetMember", getMember.Target(getMember, mbro));
  53. ClearRuleCache(getMember);
  54. // run remotely after clearing cache.
  55. domain = AppDomain.CreateDomain("remote");
  56. mbro = domain.CreateInstanceAndUnwrap(typeof(MBRODynamicObject).Assembly.FullName, typeof(MBRODynamicObject).FullName);
  57. getMember = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("__code__"));
  58. Assert.AreEqual("123", getMember.Target(getMember, mbro));
  59. // run locally again
  60. mbro = new MBRODynamicObject();
  61. Assert.AreEqual("MBRO_GetMember", getMember.Target(getMember, mbro));
  62. }
  63. #if CLR45
  64. [Test("Remoted IDO2")]
  65. private void Scenario_Remoted2() {
  66. #region CallSite for each action
  67. var getMember = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("Name"));
  68. #endregion
  69. object sdo = new SerializableDO();
  70. MemoryStream ms = new MemoryStream();
  71. BinaryFormatter formatter = new BinaryFormatter();
  72. formatter.Serialize(ms, sdo);
  73. ms.Seek(0, SeekOrigin.Begin);
  74. object sdo2 = formatter.Deserialize(ms);
  75. Assert.AreEqual("SerializableDO", getMember.Target(getMember, sdo2));
  76. }
  77. #endif
  78. // Support for remoted COM is NYI
  79. //[Test(TestState.COM, "Remoted COM")]
  80. //private void Scenario_RemotedCom() {
  81. // #region CallSite for each action
  82. // var getMember = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("pLong"));
  83. // #endregion
  84. // // run locally
  85. // MBRODynamicObject mbro = new MBRODynamicObject();
  86. // Assert.AreEqual(0, getMember.Target(getMember, mbro.GetComObj()));
  87. // // run remotely
  88. // var domain = AppDomain.CreateDomain("remote");
  89. // mbro = (MBRODynamicObject)domain.CreateInstanceAndUnwrap(typeof(MBRODynamicObject).Assembly.FullName, typeof(MBRODynamicObject).FullName);
  90. // getMember = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("pLong"));
  91. // Assert.AreEqual("777", getMember.Target(getMember, mbro.GetComObj()));
  92. // // need to clear after TestGetMemberBinder.
  93. // ClearRuleCache(getMember);
  94. // // run in current domain
  95. // domain = AppDomain.CurrentDomain;
  96. // mbro = (MBRODynamicObject)domain.CreateInstanceAndUnwrap(typeof(MBRODynamicObject).Assembly.FullName, typeof(MBRODynamicObject).FullName);
  97. // getMember = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("pLong"));
  98. // Assert.AreEqual(0, getMember.Target(getMember, mbro.GetComObj()));
  99. //}
  100. #region Add new Dynamic (IDO Helper) tests here.
  101. /* Call
  102. * Convert
  103. * Create
  104. * DeleteIndex
  105. * DeleteMember
  106. * GetIndex
  107. * GetMember
  108. * Invoke
  109. * Operation
  110. * SetIndex
  111. * SetMember
  112. */
  113. [Test("Simple cases for a basic derivation Dynamic")]
  114. private void Scenario_DynamicIDO_Simple() {
  115. //Get a simple Dynamic IDO
  116. TestDynamicObject dyn = new TestDynamicObject();
  117. #region CallSite for each MetaAction on this IDO
  118. var call = CallSite<Func<CallSite, object, object>>.Create(new TestInvokeMemberBinder("member"));
  119. var convert = CallSite<Func<CallSite, object, string>>.Create(new TestConvertBinder(typeof(String), true));
  120. var create = CallSite<Func<CallSite, object, object>>.Create(new TestCreateBinder());
  121. var deleteIndex = CallSite<Action<CallSite, object>>.Create(new TestDeleteIndexBinder());
  122. var deleteMember = CallSite<Action<CallSite, object>>.Create(new TestDeleteMemberBinder("member"));
  123. var getIndex = CallSite<Func<CallSite, object, object>>.Create(new TestGetIndexBinder());
  124. var getMember = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("member"));
  125. var invoke = CallSite<Func<CallSite, object, object>>.Create(new TestInvokeBinder());
  126. var binaryOperation = CallSite<Func<CallSite, object, object, object>>.Create(new TestBinaryOperationBinder(ExpressionType.Add));
  127. var unaryOperation = CallSite<Func<CallSite, object, object>>.Create(new TestUnaryOperationBinder(ExpressionType.Increment));
  128. var setIndex = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetIndexBinder());
  129. var setIndex2 = CallSite<Func<CallSite, object, object, object, object>>.Create(new TestSetIndexBinder());
  130. var setMember = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("member"));
  131. #endregion
  132. /* Invoke each CallSite. We're using a basic derivation of Dynamic which applies no binding
  133. * logic of its own. The default binding of Dynamic is to fallback to the supplied CallSiteBinder
  134. * every time.
  135. *
  136. * We're also using fairly basic derivations of the basic StandardActions for our CallSiteBinders
  137. * that return a Rule that throws a special BindingException when invoked. This is enough to
  138. * let us know that the basic binding mechanism worked from end-to-end.
  139. */
  140. AssertExceptionThrown<BindingException>(() => call.Target(call, dyn));
  141. AssertExceptionThrown<BindingException>(() => convert.Target(convert, dyn));
  142. AssertExceptionThrown<BindingException>(() => create.Target(create, dyn));
  143. AssertExceptionThrown<BindingException>(() => deleteIndex.Target(deleteIndex, dyn));
  144. AssertExceptionThrown<BindingException>(() => deleteMember.Target(deleteMember, dyn));
  145. AssertExceptionThrown<BindingException>(() => getIndex.Target(getIndex, dyn));
  146. AssertExceptionThrown<BindingException>(() => getMember.Target(getMember, dyn));
  147. AssertExceptionThrown<BindingException>(() => invoke.Target(invoke, dyn));
  148. AssertExceptionThrown<BindingException>(() => binaryOperation.Target(binaryOperation, dyn, 5));
  149. AssertExceptionThrown<BindingException>(() => unaryOperation.Target(unaryOperation, dyn));
  150. AssertExceptionThrown<ArgumentException>(() => setIndex.Target(setIndex, dyn, 3));
  151. AssertExceptionThrown<BindingException>(() => setIndex2.Target(setIndex2, dyn, 3, 10));
  152. AssertExceptionThrown<BindingException>(() => setMember.Target(setMember, dyn, 5));
  153. }
  154. [Test("Simple cases for a derivation DynamicObject that fails each operation")]
  155. private void Scenario_FailingDynamicObject() {
  156. //Get a simple Dynamic IDO
  157. TestDynamicObject3 dyn = new TestDynamicObject3();
  158. #region CallSite for each MetaAction on this IDO
  159. var call = CallSite<Func<CallSite, object, object>>.Create(new TestInvokeMemberBinder("member"));
  160. var convert = CallSite<Func<CallSite, object, string>>.Create(new TestConvertBinder(typeof(String), true));
  161. var create = CallSite<Func<CallSite, object, object>>.Create(new TestCreateBinder());
  162. var deleteIndex = CallSite<Action<CallSite, object>>.Create(new TestDeleteIndexBinder());
  163. var deleteMember = CallSite<Action<CallSite, object>>.Create(new TestDeleteMemberBinder("member"));
  164. var getIndex = CallSite<Func<CallSite, object, object>>.Create(new TestGetIndexBinder());
  165. var getMember = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("member"));
  166. var invoke = CallSite<Func<CallSite, object, object>>.Create(new TestInvokeBinder());
  167. var binaryOperation = CallSite<Func<CallSite, object, object, object>>.Create(new TestBinaryOperationBinder(ExpressionType.Add));
  168. var unaryOperation = CallSite<Func<CallSite, object, object>>.Create(new TestUnaryOperationBinder(ExpressionType.Increment));
  169. var setIndex = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetIndexBinder());
  170. var setIndex2 = CallSite<Func<CallSite, object, object, object, object>>.Create(new TestSetIndexBinder());
  171. var setMember = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("member"));
  172. #endregion
  173. AssertExceptionThrown<BindingException>(() => call.Target(call, dyn));
  174. AssertExceptionThrown<BindingException>(() => convert.Target(convert, dyn));
  175. AssertExceptionThrown<BindingException>(() => create.Target(create, dyn));
  176. AssertExceptionThrown<BindingException>(() => deleteIndex.Target(deleteIndex, dyn));
  177. AssertExceptionThrown<BindingException>(() => deleteMember.Target(deleteMember, dyn));
  178. AssertExceptionThrown<BindingException>(() => getIndex.Target(getIndex, dyn));
  179. AssertExceptionThrown<BindingException>(() => getMember.Target(getMember, dyn));
  180. AssertExceptionThrown<BindingException>(() => invoke.Target(invoke, dyn));
  181. AssertExceptionThrown<BindingException>(() => binaryOperation.Target(binaryOperation, dyn, 5));
  182. AssertExceptionThrown<BindingException>(() => unaryOperation.Target(unaryOperation, dyn));
  183. AssertExceptionThrown<ArgumentException>(() => setIndex.Target(setIndex, dyn, 3));
  184. AssertExceptionThrown<BindingException>(() => setIndex2.Target(setIndex2, dyn, 3, 10));
  185. AssertExceptionThrown<BindingException>(() => setMember.Target(setMember, dyn, 5));
  186. }
  187. [Test("Simple cases for a basic Expando IDO")]
  188. private void Scenario_ExpandoObject() {
  189. //ExpandoObject is a real IDO implementing several actions
  190. var exp = new ExpandoObject();
  191. #region CallSite for each action
  192. var invokeMember = CallSite<Func<CallSite, object, object, object>>.Create(new TestInvokeMemberBinder("member"));
  193. var deleteIndex = CallSite<Action<CallSite, object>>.Create(new TestDeleteIndexBinder());
  194. var deleteMember = CallSite<Action<CallSite, object>>.Create(new TestDeleteMemberBinder("member"));
  195. var deleteMemberUCase = CallSite<Action<CallSite, object>>.Create(new TestDeleteMemberBinder("MEMBER"));
  196. var setIndex = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetIndexBinder());
  197. var setMember = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("member"));
  198. var setMemberUCase = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("MEMBER"));
  199. var setIndex2 = CallSite<Func<CallSite, object, object, object, object>>.Create(new TestSetIndexBinder());
  200. var convert = CallSite<Func<CallSite, object, string>>.Create(new TestConvertBinder(typeof(String), true));
  201. var create = CallSite<Func<CallSite, object, object>>.Create(new TestCreateBinder());
  202. var getIndex = CallSite<Func<CallSite, object, object>>.Create(new TestGetIndexBinder());
  203. var getMember = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("member"));
  204. var getMemberUCase = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("MEMBER"));
  205. var getMember2 = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("__code__")); //GetMember2 gets a member in the language binder.
  206. var invoke = CallSite<Func<CallSite, object, object>>.Create(new TestInvokeBinder());
  207. var unaryOperationNeg = CallSite<Func<CallSite, object, object>>.Create(new TestUnaryOperationBinder(ExpressionType.Increment));
  208. var binaryOperationNeg = CallSite<Func<CallSite, object, object, object>>.Create(new TestBinaryOperationBinder(ExpressionType.Add));
  209. #endregion
  210. //Those actions implemented by ExpandoObject should succeed (SetMember, GetMember, etc).
  211. //The others should fall back to the CallSiteBinder and trigger a BindingException.
  212. Assert.AreEqual(getMember.Target(getMember2, exp), "123");
  213. //deleting a non-existing member results in falling back to the language's binder
  214. AssertExceptionThrown<BindingException>(() => deleteMember.Target(deleteMember, exp));
  215. //Actions implemented by ExpandoObject (GetMember, SetMember, DeleteMember)
  216. AssertExceptionThrown<BindingException>(() => getMember.Target(getMember, exp));
  217. AssertExceptionThrown<BindingException>(() => getMemberUCase.Target(getMemberUCase, exp));
  218. AssertExceptionThrown<BindingException>(() => deleteMember.Target(deleteMember, exp));
  219. setMember.Target(setMember, exp, 52);
  220. Assert.AreEqual(getMember.Target(getMember, exp), 52);
  221. AssertExceptionThrown<BindingException>(() => getMemberUCase.Target(getMemberUCase, exp));
  222. setMemberUCase.Target(setMemberUCase, exp, 9);
  223. Assert.AreEqual(getMember.Target(getMember, exp), 52);
  224. Assert.AreEqual(getMemberUCase.Target(getMemberUCase, exp), 9);
  225. deleteMember.Target(deleteMember, exp);
  226. AssertExceptionThrown<BindingException>(() => getMember.Target(getMember, exp));
  227. Assert.AreEqual(getMemberUCase.Target(getMemberUCase, exp), 9);
  228. deleteMemberUCase.Target(deleteMemberUCase, exp);
  229. AssertExceptionThrown<BindingException>(() => getMember.Target(getMember, exp));
  230. AssertExceptionThrown<BindingException>(() => getMemberUCase.Target(getMemberUCase, exp));
  231. //assign a delegate value to the member
  232. setMember.Target(setMember, exp, (Func<int, int>)(x => x + 1));
  233. //invokeMember should work since the member value is invokable now.
  234. Assert.AreEqual(invokeMember.Target(invokeMember, exp, 100), 101);
  235. setMember.Target(setMember, exp, 52);
  236. //Actions not implemented by ExpandoObject (which default to our basic MetaActions, which return rules throwing BindingErrors)
  237. //the member value is not invokable so invokeMember will result in exception
  238. AssertExceptionThrown<BindingException>(() => invokeMember.Target(invokeMember, exp, 100));
  239. AssertExceptionThrown<BindingException>(() => convert.Target(convert, exp));
  240. AssertExceptionThrown<BindingException>(() => create.Target(create, exp));
  241. AssertExceptionThrown<BindingException>(() => deleteIndex.Target(deleteIndex, exp));
  242. AssertExceptionThrown<BindingException>(() => getIndex.Target(getIndex, exp));
  243. AssertExceptionThrown<BindingException>(() => invoke.Target(invoke, exp));
  244. AssertExceptionThrown<BindingException>(() => binaryOperationNeg.Target(binaryOperationNeg, exp, 7));
  245. AssertExceptionThrown<BindingException>(() => unaryOperationNeg.Target(unaryOperationNeg, exp));
  246. AssertExceptionThrown<ArgumentException>(() => setIndex.Target(setIndex, exp, 3));
  247. AssertExceptionThrown<BindingException>(() => setIndex2.Target(setIndex2, exp, 3, 10));
  248. }
  249. [Test("Basic tests for INotifyPropertyChanged on ExpandoObject")]
  250. private void Scenario_ExpandoObject_NotifyPropertyChanged() {
  251. var expando = new ExpandoObject();
  252. var inpc = expando as INotifyPropertyChanged;
  253. var dict = expando as IDictionary<string, object>;
  254. string changed = "";
  255. PropertyChangedEventHandler handler = (s, e) => {
  256. Assert.AreEqual(expando, s);
  257. changed += e.PropertyName;
  258. };
  259. inpc.PropertyChanged += handler;
  260. Assert.AreEqual(changed, "");
  261. SetMember(expando, "foo", 123);
  262. Assert.AreEqual(changed, "foo"); changed = "";
  263. SetMemberIgnoreCase(expando, "FOO", 456);
  264. Assert.AreEqual(changed, "foo"); changed = "";
  265. DeleteMember(expando, "foo");
  266. Assert.AreEqual(changed, "foo"); changed = "";
  267. AssertExceptionThrown<BindingException>(() => DeleteMember(expando, "foo"));
  268. Assert.AreEqual(changed, "");
  269. SetMember(expando, "foo", 123);
  270. Assert.AreEqual(changed, "foo"); changed = "";
  271. SetMember(expando, "bar", 456);
  272. Assert.AreEqual(changed, "bar"); changed = "";
  273. SetMember(expando, "zed", 456);
  274. Assert.AreEqual(changed, "zed"); changed = "";
  275. SetMember(expando, "red", 789);
  276. Assert.AreEqual(changed, "red"); changed = "";
  277. DeleteMemberIgnoreCase(expando, "ZeD");
  278. Assert.AreEqual(changed, "zed"); changed = "";
  279. dict.Clear();
  280. Assert.AreEqual(changed, "foobarred"); changed = "";
  281. dict.Add("baz", "555");
  282. Assert.AreEqual(changed, "baz"); changed = "";
  283. dict["baz"] = "555";
  284. // We detect duplicates, so we don't fire it.
  285. // It would be okay to fire here, though.
  286. Assert.AreEqual(changed, "");
  287. dict["baz"] = "abc";
  288. Assert.AreEqual(changed, "baz"); changed = "";
  289. dict.Remove(new KeyValuePair<string, object>("baz", "zzz"));
  290. Assert.AreEqual(changed, "");
  291. dict.Remove(new KeyValuePair<string, object>("baz", "abc"));
  292. Assert.AreEqual(changed, "baz"); changed = "";
  293. dict["baz"] = "abc";
  294. dict.Remove("baz");
  295. Assert.AreEqual(changed, "bazbaz"); changed = "";
  296. // Add and remove handlers
  297. inpc.PropertyChanged += handler;
  298. dict["quux"] = 1;
  299. Assert.AreEqual(changed, "quuxquux"); changed = "";
  300. inpc.PropertyChanged -= handler;
  301. dict["quux"] = 2;
  302. Assert.AreEqual(changed, "quux"); changed = "";
  303. inpc.PropertyChanged -= handler;
  304. dict["quux"] = 3;
  305. Assert.AreEqual(changed, "");
  306. }
  307. private static void SetMember(ExpandoObject expando, string name, object value) {
  308. var site = CallSite<Action<CallSite, ExpandoObject, object>>.Create(new TestSetMemberBinder(name));
  309. site.Target(site, expando, value);
  310. }
  311. private static void SetMemberIgnoreCase(ExpandoObject expando, string name, object value) {
  312. var site = CallSite<Action<CallSite, ExpandoObject, object>>.Create(new TestSetMemberBinder(name, true));
  313. site.Target(site, expando, value);
  314. }
  315. private static void DeleteMember(ExpandoObject expando, string name) {
  316. var site = CallSite<Action<CallSite, ExpandoObject>>.Create(new TestDeleteMemberBinder(name));
  317. site.Target(site, expando);
  318. }
  319. private static void DeleteMemberIgnoreCase(ExpandoObject expando, string name) {
  320. var site = CallSite<Action<CallSite, ExpandoObject>>.Create(new TestDeleteMemberBinder(name, true));
  321. site.Target(site, expando);
  322. }
  323. private static object GetMember(ExpandoObject expando, string name) {
  324. var site = CallSite<Func<CallSite, ExpandoObject, object>>.Create(new TestGetMemberBinder(name));
  325. return site.Target(site, expando);
  326. }
  327. [Test("Test GetDynamicMemberNames for a basic Expando IDO")]
  328. private void Scenario_ExpandoObjectGetDynamicMemberNames() {
  329. var exp = new ExpandoObject();
  330. var setMember = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("member1"));
  331. setMember.Target(setMember, exp, 10);
  332. var mo = ((IDynamicMetaObjectProvider)exp).GetMetaObject(Expression.Parameter(typeof(object), "arg0"));
  333. List<string> memberNames = new List<string>(mo.GetDynamicMemberNames());
  334. Assert.AreEqual(1, memberNames.Count);
  335. Assert.AreEqual("member1", memberNames[0]);
  336. setMember = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("member2"));
  337. setMember.Target(setMember, exp, 20);
  338. setMember = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("member3"));
  339. setMember.Target(setMember, exp, 30);
  340. memberNames = new List<string>(mo.GetDynamicMemberNames());
  341. Assert.AreEqual(3, memberNames.Count);
  342. var deleteMember = CallSite<Action<CallSite, object>>.Create(new TestDeleteMemberBinder("member1"));
  343. deleteMember.Target(deleteMember, exp);
  344. memberNames = new List<string>(mo.GetDynamicMemberNames());
  345. Assert.AreEqual(2, memberNames.Count);
  346. //Add the deleted member back. Since ExpandoObject didn't really deleted the member from the class
  347. //(only the value got deleted), the added member should be at the original index.
  348. setMember = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("member1"));
  349. setMember.Target(setMember, exp, 100);
  350. memberNames = new List<string>(mo.GetDynamicMemberNames());
  351. Assert.AreEqual(3, memberNames.Count);
  352. }
  353. #region Testing case-insensitive behavior of ExpandoObject
  354. [Test("Test ExpandoObject when used with case-insensitive get binders-1")]
  355. private void Senario_ExpandoObjectCaseInsensitiveGet1() {
  356. var exp = new ExpandoObject();
  357. ((IDictionary<string, object>)exp).Add("foo", 1);
  358. ((IDictionary<string, object>)exp).Add("FOO", 2);
  359. var getMemberIgnoreCase = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("FoO", true));
  360. AssertExceptionThrown<AmbiguousMatchException>(() => getMemberIgnoreCase.Target(getMemberIgnoreCase, exp));
  361. ((IDictionary<string, object>)exp).Remove("foo");
  362. Assert.AreEqual(getMemberIgnoreCase.Target(getMemberIgnoreCase, exp), 2);
  363. ((IDictionary<string, object>)exp).Remove("FOO");
  364. AssertExceptionThrown<BindingException>(() => getMemberIgnoreCase.Target(getMemberIgnoreCase, exp));
  365. }
  366. [Test("Test ExpandoObject when used with case-insensitive set binders-1")]
  367. private void Senario_ExpandoObjectCaseInsensitiveSet1() {
  368. var exp = new ExpandoObject();
  369. ((IDictionary<string, object>)exp).Add("foo", 1);
  370. ((IDictionary<string, object>)exp).Add("FOO", 2);
  371. var setMemberIgnoreCase = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("FoO", true));
  372. AssertExceptionThrown<AmbiguousMatchException>(() => setMemberIgnoreCase.Target(setMemberIgnoreCase, exp, 100));
  373. ((IDictionary<string, object>)exp).Remove("foo");
  374. setMemberIgnoreCase.Target(setMemberIgnoreCase, exp, 100);
  375. Assert.AreEqual(((IDictionary<string, object>)exp)["FOO"], 100);
  376. ((IDictionary<string, object>)exp).Remove("FOO");
  377. setMemberIgnoreCase.Target(setMemberIgnoreCase, exp, 101);
  378. Assert.AreEqual(((IDictionary<string, object>)exp)["FoO"], 101);
  379. }
  380. [Test("Test ExpandoObject when used with case-insensitive delete binders-1")]
  381. private void Senario_ExpandoObjectCaseInsensitiveDelete1() {
  382. var exp = new ExpandoObject();
  383. ((IDictionary<string, object>)exp).Add("foo", 1);
  384. ((IDictionary<string, object>)exp).Add("FOO", 2);
  385. var deleteMemberIgnoreCase = CallSite<Action<CallSite, object>>.Create(new TestDeleteMemberBinder("FoO", true));
  386. AssertExceptionThrown<AmbiguousMatchException>(() => deleteMemberIgnoreCase.Target(deleteMemberIgnoreCase, exp));
  387. ((IDictionary<string, object>)exp).Remove("foo");
  388. Assert.IsTrue(((IDictionary<string, object>)exp).ContainsKey("FOO"));
  389. deleteMemberIgnoreCase.Target(deleteMemberIgnoreCase, exp);
  390. Assert.IsFalse(((IDictionary<string, object>)exp).ContainsKey("FOO"));
  391. AssertExceptionThrown<BindingException>(() => deleteMemberIgnoreCase.Target(deleteMemberIgnoreCase, exp));
  392. }
  393. [Test("Test ExpandoObject when used with case-insensitive get binders-2")]
  394. private void Senario_ExpandoObjectCaseInsensitiveGet2() {
  395. var exp = new ExpandoObject();
  396. ((IDictionary<string, object>)exp).Add("foo", 1);
  397. ((IDictionary<string, object>)exp).Add("FOO", 2);
  398. ((IDictionary<string, object>)exp).Remove("foo");
  399. ((IDictionary<string, object>)exp).Remove("FOO");
  400. var getMemberIgnoreCase = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("FoO", true));
  401. AssertExceptionThrown<BindingException>(() => getMemberIgnoreCase.Target(getMemberIgnoreCase, exp));
  402. ((IDictionary<string, object>)exp)["foo"] = 1;
  403. Assert.AreEqual(getMemberIgnoreCase.Target(getMemberIgnoreCase, exp), 1);
  404. ((IDictionary<string, object>)exp)["FOO"] = 2;
  405. AssertExceptionThrown<AmbiguousMatchException>(() => getMemberIgnoreCase.Target(getMemberIgnoreCase, exp));
  406. }
  407. [Test("Test ExpandoObject when used with case-insensitive set binders-2")]
  408. private void Senario_ExpandoObjectCaseInsensitiveSet2() {
  409. var exp = new ExpandoObject();
  410. ((IDictionary<string, object>)exp).Add("foo", 1);
  411. ((IDictionary<string, object>)exp).Add("FOO", 2);
  412. ((IDictionary<string, object>)exp).Remove("foo");
  413. ((IDictionary<string, object>)exp).Remove("FOO");
  414. var setMemberIgnoreCase = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("FoO", true));
  415. Assert.IsFalse(((IDictionary<string, object>)exp).ContainsKey("foO"));
  416. setMemberIgnoreCase.Target(setMemberIgnoreCase, exp, 101);
  417. Assert.AreEqual(((IDictionary<string, object>)exp)["FoO"], 101);
  418. ((IDictionary<string, object>)exp)["foo"] = 1;
  419. AssertExceptionThrown<AmbiguousMatchException>(() => setMemberIgnoreCase.Target(setMemberIgnoreCase, exp, 100));
  420. }
  421. [Test("Test ExpandoObject when used with case-insensitive delete binders-2")]
  422. private void Senario_ExpandoObjectCaseInsensitiveDelete2() {
  423. var exp = new ExpandoObject();
  424. ((IDictionary<string, object>)exp).Add("foo", 1);
  425. ((IDictionary<string, object>)exp).Add("FOO", 2);
  426. ((IDictionary<string, object>)exp).Remove("foo");
  427. ((IDictionary<string, object>)exp).Remove("FOO");
  428. var deleteMemberIgnoreCase = CallSite<Action<CallSite, object>>.Create(new TestDeleteMemberBinder("FoO", true));
  429. AssertExceptionThrown<BindingException>(() => deleteMemberIgnoreCase.Target(deleteMemberIgnoreCase, exp));
  430. ((IDictionary<string, object>)exp)["foo"] = 1;
  431. Assert.IsTrue(((IDictionary<string, object>)exp).ContainsKey("foo"));
  432. deleteMemberIgnoreCase.Target(deleteMemberIgnoreCase, exp);
  433. Assert.IsFalse(((IDictionary<string, object>)exp).ContainsKey("foo"));
  434. ((IDictionary<string, object>)exp)["foo"] = 1;
  435. ((IDictionary<string, object>)exp)["FOO"] = 2;
  436. AssertExceptionThrown<AmbiguousMatchException>(() => deleteMemberIgnoreCase.Target(deleteMemberIgnoreCase, exp));
  437. }
  438. [Test("Test ExpandoObject when used with case-insensitive get binders-3")]
  439. private void Senario_ExpandoObjectCaseInsensitiveGet3() {
  440. var exp = new ExpandoObject();
  441. ((IDictionary<string, object>)exp).Add("foo", 1);
  442. ((IDictionary<string, object>)exp).Add("FOO", 2);
  443. ((IDictionary<string, object>)exp).Remove("FOO");
  444. var getMemberIgnoreCase = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("FoO", true));
  445. Assert.AreEqual(getMemberIgnoreCase.Target(getMemberIgnoreCase, exp), 1);
  446. ((IDictionary<string, object>)exp).Remove("foo");
  447. AssertExceptionThrown<BindingException>(() => getMemberIgnoreCase.Target(getMemberIgnoreCase, exp));
  448. ((IDictionary<string, object>)exp)["foo"] = 1;
  449. ((IDictionary<string, object>)exp)["FOO"] = 2;
  450. AssertExceptionThrown<AmbiguousMatchException>(() => getMemberIgnoreCase.Target(getMemberIgnoreCase, exp));
  451. }
  452. [Test("Test ExpandoObject when used with case-insensitive set binders-3")]
  453. private void Senario_ExpandoObjectCaseInsensitiveSet3() {
  454. var exp = new ExpandoObject();
  455. ((IDictionary<string, object>)exp).Add("foo", 1);
  456. ((IDictionary<string, object>)exp).Add("FOO", 2);
  457. ((IDictionary<string, object>)exp).Remove("foo");
  458. var setMemberIgnoreCase = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("FoO", true));
  459. Assert.AreEqual(((IDictionary<string, object>)exp)["FOO"], 2);
  460. setMemberIgnoreCase.Target(setMemberIgnoreCase, exp, 101);
  461. Assert.AreEqual(((IDictionary<string, object>)exp)["FOO"], 101);
  462. ((IDictionary<string, object>)exp)["foo"] = 1;
  463. AssertExceptionThrown<AmbiguousMatchException>(() => setMemberIgnoreCase.Target(setMemberIgnoreCase, exp, 100));
  464. }
  465. [Test("Test ExpandoObject when used with case-insensitive delete binders-3")]
  466. private void Senario_ExpandoObjectCaseInsensitiveDelete3() {
  467. var exp = new ExpandoObject();
  468. ((IDictionary<string, object>)exp).Add("foo", 1);
  469. ((IDictionary<string, object>)exp).Add("FOO", 2);
  470. ((IDictionary<string, object>)exp).Remove("FOO");
  471. var deleteMemberIgnoreCase = CallSite<Action<CallSite, object>>.Create(new TestDeleteMemberBinder("FoO", true));
  472. Assert.IsTrue(((IDictionary<string, object>)exp).ContainsKey("foo"));
  473. deleteMemberIgnoreCase.Target(deleteMemberIgnoreCase, exp);
  474. Assert.IsFalse(((IDictionary<string, object>)exp).ContainsKey("foo"));
  475. AssertExceptionThrown<BindingException>(() => deleteMemberIgnoreCase.Target(deleteMemberIgnoreCase, exp));
  476. ((IDictionary<string, object>)exp)["foo"] = 1;
  477. ((IDictionary<string, object>)exp)["FOO"] = 2;
  478. AssertExceptionThrown<AmbiguousMatchException>(() => deleteMemberIgnoreCase.Target(deleteMemberIgnoreCase, exp));
  479. }
  480. [Test("Test ExpandoObject when used with binders that mix case sensitivity")]
  481. private void Scenario_ExpandoObjectMixCaseSensitivity() {
  482. var exp = new ExpandoObject();
  483. var setMember1 = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("Member"));
  484. var setMember2 = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("member"));
  485. var setMember3 = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("MEMBER"));
  486. var setMemberIgnoreCase1 = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("member", true));
  487. var setMemberIgnoreCase2 = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("MEMBER", true));
  488. var getMember1 = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("Member"));
  489. var getMember2 = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("member"));
  490. var getMemberIgnoreCase1 = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("member", true));
  491. var getMemberIgnoreCase2 = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("Member", true));
  492. var getMemberIgnoreCase3 = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("MEMBER", true));
  493. var deleteMember = CallSite<Action<CallSite, object>>.Create(new TestDeleteMemberBinder("member"));
  494. var deleteMemberIgnoreCase = CallSite<Action<CallSite, object>>.Create(new TestDeleteMemberBinder("member", true));
  495. //Verify that ignore case get can fall back correctly when no match
  496. var getMemberIgnoreCase = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("__cOdE__", true));
  497. Assert.AreEqual("123", getMemberIgnoreCase.Target(getMemberIgnoreCase, exp));
  498. AssertExceptionThrown<BindingException>(() => getMemberIgnoreCase1.Target(getMemberIgnoreCase1, exp));
  499. //exp.member = 1 (ignore case)
  500. setMemberIgnoreCase1.Target(setMemberIgnoreCase1, exp, 100);
  501. //If case insensitive, get the match if there is only one.
  502. //get exp.Member = 100, found the only match
  503. Assert.AreEqual(getMemberIgnoreCase1.Target(getMemberIgnoreCase1, exp), 100);
  504. Assert.AreEqual(getMemberIgnoreCase2.Target(getMemberIgnoreCase2, exp), 100);
  505. deleteMember.Target(deleteMember, exp);
  506. AssertExceptionThrown<BindingException>(() => getMemberIgnoreCase1.Target(getMemberIgnoreCase1, exp));
  507. ((IDictionary<string, object>)exp).Add("member", 1001);
  508. Assert.AreEqual(getMemberIgnoreCase1.Target(getMemberIgnoreCase1, exp), 1001);
  509. ((IDictionary<string, object>)exp)["member"] = 1;
  510. //exp.Member = 1 (case insensitive) overwrites the matching member
  511. setMemberIgnoreCase2.Target(setMemberIgnoreCase2, exp, 1);
  512. Assert.AreEqual(getMember2.Target(getMember2, exp), 1);
  513. Assert.AreEqual(getMemberIgnoreCase1.Target(getMemberIgnoreCase1, exp), 1);
  514. Assert.AreEqual(getMemberIgnoreCase2.Target(getMemberIgnoreCase2, exp), 1);
  515. //exp.Member = 2 (case sensitive)
  516. setMember1.Target(setMember1, exp, 2);
  517. //get exp.member (ignore case) results in AmbigousMatchException
  518. AssertExceptionThrown<AmbiguousMatchException>(() => getMemberIgnoreCase1.Target(getMemberIgnoreCase1, exp));
  519. AssertExceptionThrown<AmbiguousMatchException>(() => getMemberIgnoreCase2.Target(getMemberIgnoreCase2, exp));
  520. AssertExceptionThrown<AmbiguousMatchException>(() => getMemberIgnoreCase3.Target(getMemberIgnoreCase3, exp));
  521. //Delete exp.member (case sensitive)
  522. deleteMember.Target(deleteMember, exp);
  523. Assert.AreEqual(getMember1.Target(getMember1, exp), 2);
  524. AssertExceptionThrown<BindingException>(() => getMember2.Target(getMember2, exp));
  525. Assert.AreEqual(getMemberIgnoreCase1.Target(getMemberIgnoreCase1, exp), 2);
  526. Assert.AreEqual(getMemberIgnoreCase2.Target(getMemberIgnoreCase1, exp), 2);
  527. //exp.member = 1 (case sensitive)
  528. setMember2.Target(setMember2, exp, 1);
  529. //exp.MEMBER = 3 (ignore case) results in AmbiguousMatchException
  530. AssertExceptionThrown<AmbiguousMatchException>(() => setMemberIgnoreCase2.Target(setMemberIgnoreCase2, exp, 3));
  531. //set exp.MEMBER = 3, case-sensitive
  532. setMember3.Target(setMember3, exp, 3);
  533. //get exp.MEMBER (ignore case) AmbiguousMatchException
  534. AssertExceptionThrown<AmbiguousMatchException>(() => getMemberIgnoreCase3.Target(getMemberIgnoreCase3, exp));
  535. //Get exp.Member case sensitively
  536. Assert.AreEqual(getMember1.Target(getMember1, exp), 2);
  537. //Get exp.member case sensitively
  538. Assert.AreEqual(getMember2.Target(getMember2, exp), 1);
  539. //Delete exp.member (case sensitive)
  540. deleteMember.Target(deleteMember, exp);
  541. //Get exp.member (case sensitive) results in BindingException
  542. AssertExceptionThrown<BindingException>(() => getMember2.Target(getMember2, exp));
  543. //Get exp.Member case sensitively
  544. Assert.AreEqual(getMember1.Target(getMember1, exp), 2);
  545. //Get exp.member (case insensitive) results in AmbiguousMatchException
  546. AssertExceptionThrown<AmbiguousMatchException>(() => getMemberIgnoreCase1.Target(getMemberIgnoreCase1, exp));
  547. AssertExceptionThrown<AmbiguousMatchException>(() => getMemberIgnoreCase2.Target(getMemberIgnoreCase2, exp));
  548. AssertExceptionThrown<AmbiguousMatchException>(() => getMemberIgnoreCase3.Target(getMemberIgnoreCase3, exp));
  549. //add the deleted expt.member back (case sensitive)
  550. setMember2.Target(setMember2, exp, 1);
  551. //get exp.member (case insensitive) results in AmbiguousMatchException
  552. AssertExceptionThrown<AmbiguousMatchException>(() => getMemberIgnoreCase1.Target(getMemberIgnoreCase1, exp));
  553. AssertExceptionThrown<AmbiguousMatchException>(() => getMemberIgnoreCase2.Target(getMemberIgnoreCase2, exp));
  554. //apply a case insensitive delete binder results in AmbigousMatchException
  555. AssertExceptionThrown<AmbiguousMatchException>(() => deleteMemberIgnoreCase.Target(deleteMemberIgnoreCase, exp));
  556. //Delete exp.member (case sensitive)
  557. deleteMember.Target(deleteMember, exp);
  558. //delete exp.member case insensitively results in AmbiguousMatchException
  559. AssertExceptionThrown<AmbiguousMatchException>(() => deleteMemberIgnoreCase.Target(deleteMemberIgnoreCase, exp));
  560. //Get exp.member case sensitively results in exception
  561. AssertExceptionThrown<BindingException>(() => getMember2.Target(getMember2, exp));
  562. //Set exp.member case insensitively results in AmbiguousMatchException
  563. AssertExceptionThrown<AmbiguousMatchException>(() => setMemberIgnoreCase2.Target(setMemberIgnoreCase2, exp, 100));
  564. //Get exp.member case insensitively results in AmbiguousMatchException
  565. AssertExceptionThrown<AmbiguousMatchException>(() => getMemberIgnoreCase1.Target(getMemberIgnoreCase1, exp));
  566. }
  567. #endregion
  568. [Test("Test the IDictionary<string, object> members of ExpandoObject")]
  569. private void Scenario_ExpandoObjectIDictionaryMembers() {
  570. var exp = (IDictionary<string, object>)(new ExpandoObject());
  571. Assert.IsFalse(exp.IsReadOnly);
  572. KeyValuePair<string, object> kv1 = new KeyValuePair<string, object>("a", 1);
  573. KeyValuePair<string, object> kv2 = new KeyValuePair<string, object>("b", 2);
  574. KeyValuePair<string, object> kv3 = new KeyValuePair<string, object>("c", 3);
  575. KeyValuePair<string, object> kv4 = new KeyValuePair<string, object>("c", 4);
  576. KeyValuePair<string, object> kv5 = new KeyValuePair<string, object>("d", 5);
  577. exp.Add("a", 1);
  578. exp.Add("b", 2);
  579. exp.Add(kv3);
  580. Assert.IsTrue(exp.Contains(kv1));
  581. Assert.IsTrue(exp.Contains(kv2));
  582. Assert.IsTrue(exp.Contains(kv3));
  583. Assert.IsFalse(exp.Contains(kv5));
  584. Assert.IsTrue(exp.ContainsKey("a"));
  585. Assert.IsTrue(exp.ContainsKey("b"));
  586. Assert.IsTrue(exp.ContainsKey("c"));
  587. Assert.IsTrue(exp.Remove(kv3));
  588. Assert.IsFalse(exp.ContainsKey("c"));
  589. Assert.IsFalse(exp.Remove(kv3)); //Try to remove non-existant
  590. exp.Add(kv3);
  591. Assert.IsFalse(exp.Remove(kv4)); //Remove KVP with same key, but different value
  592. Assert.AreEqual(3, exp.Count); //Nothing should be removed
  593. //adding the same key causes exception
  594. AssertExceptionThrown<ArgumentException>(() => exp.Add("a", 100));
  595. Assert.AreEqual(3, exp.Count);
  596. List<string> keys = new List<string>(exp.Keys);
  597. Assert.AreEqual(keys[0], "a");
  598. List<object> values = new List<object>(exp.Values);
  599. Assert.AreEqual(values[2], 3);
  600. // Various valid/invalid cases with KeyCollection
  601. AssertExceptionThrown<NotSupportedException>(() => exp.Keys.Add("x"));
  602. AssertExceptionThrown<NotSupportedException>(() => exp.Keys.Clear());
  603. Assert.IsTrue(exp.Keys.Contains("a"));
  604. Assert.IsFalse(exp.Keys.Contains("blah"));
  605. Assert.IsTrue(exp.Keys.IsReadOnly);
  606. AssertExceptionThrown<NotSupportedException>(() => exp.Keys.Remove("HI"));
  607. Assert.IsTrue(exp.Keys.Contains("b"));
  608. Assert.IsFalse(exp.Keys.Contains("foo"));
  609. // Various valid/invalid cases with ValueCollection
  610. AssertExceptionThrown<NotSupportedException>(() => exp.Values.Add(2));
  611. AssertExceptionThrown<NotSupportedException>(() => exp.Values.Clear());
  612. Assert.IsTrue(exp.Values.Contains(2));
  613. Assert.IsFalse(exp.Values.Contains(-2));
  614. Assert.IsFalse(exp.Values.Contains(-2));
  615. Assert.IsTrue(exp.Values.IsReadOnly);
  616. AssertExceptionThrown<NotSupportedException>(() => exp.Values.Remove(1));
  617. Assert.IsFalse(exp.Values.Contains("foo"));
  618. //Iterate the Keys or Values collection and the expando changes will
  619. //cause InvalidOperationException
  620. AssertExceptionThrown<InvalidOperationException>(() => IterateAndModifyKeyCollection(exp));
  621. AssertExceptionThrown<InvalidOperationException>(() => IterateAndModifyValueCollection(exp));
  622. // Additional iterator cases
  623. IterateAndModifyKeyCollection2(exp);
  624. IterateAndModifyValueCollection2(exp);
  625. IterateAndModifyKeyCollection3(exp);
  626. IterateAndModifyValueCollection3(exp);
  627. IterateAndModifyKeyCollection4(exp);
  628. IterateAndModifyValueCollection4(exp);
  629. object value;
  630. Assert.IsTrue(exp.TryGetValue("b", out value));
  631. Assert.AreEqual(2, value);
  632. Assert.IsFalse(exp.TryGetValue("x", out value));
  633. KeyValuePair<string, object>[] arr = new KeyValuePair<string, object>[10];
  634. exp.CopyTo(arr, 0);
  635. Assert.AreEqual(arr[2].Value, 3);
  636. AssertExceptionThrown<ArgumentOutOfRangeException>(() => exp.CopyTo(arr, 8));
  637. foreach (var kv in exp) {
  638. Assert.IsTrue(kv.Value != null);
  639. }
  640. // Use non-generic collection
  641. var exp2 = (System.Collections.IEnumerable)(exp);
  642. int cnt = 0;
  643. foreach (var kv in exp2) {
  644. cnt++;
  645. }
  646. Assert.AreEqual(exp.Count, cnt);
  647. //iterate and modify the expando will cause exception
  648. AssertExceptionThrown<InvalidOperationException>(() => IterateAndModifyExpando(exp));
  649. Assert.IsTrue(exp.Remove("a"));
  650. Assert.IsFalse(exp.Remove("a")); //the 2nd time will fail.
  651. //Assert.AreEqual(2, exp.Count);
  652. //add ["a", 100]
  653. exp.Add("a", 100);
  654. Assert.AreEqual(100, exp["a"]);
  655. exp["a"] = 1;
  656. Assert.AreEqual(1, exp["a"]);
  657. AssertExceptionThrown<KeyNotFoundException>(() => value = exp["e"]);
  658. exp["e"] = 5;
  659. Assert.AreEqual(exp["e"], 5);
  660. exp["e"] = 6;
  661. Assert.AreEqual(exp["e"], 6);
  662. Assert.AreEqual(exp.Remove(new KeyValuePair<string, object>("e", 5)), false);
  663. Assert.AreEqual(exp.Remove(new KeyValuePair<string, object>("e", 6)), true);
  664. AssertExceptionThrown<KeyNotFoundException>(() => value = exp["e"]);
  665. exp.Clear();
  666. Assert.AreEqual(0, exp.Count);
  667. Assert.AreEqual(0, exp.Values.Count);
  668. Assert.AreEqual(0, exp.Keys.Count);
  669. // Some additional cases around null
  670. var expnull = (IDictionary<string, object>)(new ExpandoObject());
  671. expnull.Add("a", null);
  672. AssertExceptionThrown<ArgumentNullException>(() => expnull.Add(null, "SDF"));
  673. KeyValuePair<string, object> kvnull = new KeyValuePair<string, object>();
  674. AssertExceptionThrown<ArgumentNullException>(() => expnull.Add(kvnull));
  675. Assert.IsFalse(expnull.Contains(kvnull));
  676. ExpandoObject expando = new ExpandoObject();
  677. exp = (IDictionary<string, object>)expando;
  678. // thread safety, multiple threads adding to the same object.
  679. // All values should be added
  680. Thread t1 = new Thread(() => ExpandoThreadAdder(expando, "Thread1_"));
  681. Thread t2 = new Thread(() => ExpandoThreadAdder(expando, "Thread2_"));
  682. Thread t3 = new Thread(() => ExpandoThreadAdder(expando, "Thread3_"));
  683. Thread t4 = new Thread(() => ExpandoThreadAdder(expando, "Thread4_"));
  684. t1.Start();
  685. t2.Start();
  686. t3.Start();
  687. t4.Start();
  688. t1.Join();
  689. t2.Join();
  690. t3.Join();
  691. t4.Join();
  692. // all values should be set
  693. for (int i = 0; i < 4; i++) {
  694. for (int j = 0; j < 1000; j++) {
  695. Assert.AreEqual(exp["Thread" + (i + 1) + "_" + j.ToString("0000")], j);
  696. }
  697. }
  698. t1 = new Thread(() => ExpandoThreadAdderRemover(expando, "Thread1_"));
  699. t2 = new Thread(() => ExpandoThreadAdderRemover(expando, "Thread2_"));
  700. t3 = new Thread(() => ExpandoThreadAdderRemover(expando, "Thread3_"));
  701. t4 = new Thread(() => ExpandoThreadAdderRemover(expando, "Thread4_"));
  702. t1.Start();
  703. t2.Start();
  704. t3.Start();
  705. t4.Start();
  706. t1.Join();
  707. t2.Join();
  708. t3.Join();
  709. t4.Join();
  710. // all values should have been set and removed
  711. for (int i = 0; i < 4; i++) {
  712. for (int j = 0; j < 1000; j++) {
  713. Assert.AreEqual(exp.ContainsKey("Thread" + (i + 1) + "_" + j.ToString("0000")), false);
  714. }
  715. }
  716. }
  717. [Test("Test the Contains member of ExpandoObject containing a null value")]
  718. private void Scenario_ExpandoObjectWithNullValue() {
  719. var exp = (IDictionary<string, object>)(new ExpandoObject());
  720. exp.Add("a", null);
  721. Assert.IsTrue(exp.Values.Contains(null));
  722. Assert.IsFalse(exp.Values.Contains(1));
  723. }
  724. private static void IterateAndModifyExpando(IDictionary<string, object> exp) {
  725. foreach (var k in exp) {
  726. exp.Add("d", 4);
  727. exp.Remove("d");
  728. }
  729. }
  730. private static void IterateAndModifyKeyCollection(IDictionary<string, object> exp) {
  731. foreach (var k in exp.Keys) {
  732. exp.Add("d", 4);
  733. exp.Remove("d");
  734. }
  735. }
  736. private static void IterateAndModifyValueCollection(IDictionary<string, object> exp) {
  737. foreach (var k in exp.Values) {
  738. exp.Add("d", 4);
  739. exp.Remove("d");
  740. }
  741. }
  742. private static void IterateAndModifyKeyCollection2(IDictionary<string, object> exp) {
  743. ICollection<string> k = exp.Keys;
  744. foreach (var kv in k) {
  745. exp.Add("blah", 5);
  746. int i = 0;
  747. AssertExceptionThrown<InvalidOperationException>(() => i = k.Count);
  748. return;
  749. }
  750. }
  751. private static void IterateAndModifyValueCollection2(IDictionary<string, object> exp) {
  752. ICollection<object> k = exp.Values;
  753. foreach (var kv in k) {
  754. exp.Add("blah2", 6);
  755. int i = 0;
  756. AssertExceptionThrown<InvalidOperationException>(() => i = k.Count);
  757. return;
  758. }
  759. }
  760. private static void IterateAndModifyKeyCollection3(IDictionary<string, object> exp) {
  761. ICollection<string> k = exp.Keys;
  762. foreach (var kv in k) {
  763. exp.Add("blah3", 5);
  764. AssertExceptionThrown<InvalidOperationException>(() => k.Contains("blah"));
  765. return;
  766. }
  767. }
  768. private static void IterateAndModifyValueCollection3(IDictionary<string, object> exp) {
  769. ICollection<object> k = exp.Values;
  770. foreach (var kv in k) {
  771. exp.Add("blah4", 6);
  772. AssertExceptionThrown<InvalidOperationException>(() => k.Contains("blah"));
  773. return;
  774. }
  775. }
  776. private static void IterateAndModifyKeyCollection4(IDictionary<string, object> exp) {
  777. ICollection<string> k = exp.Keys;
  778. string[] arr = new string[10];
  779. foreach (var kv in k) {
  780. exp.Add("blah5", 5);
  781. AssertExceptionThrown<InvalidOperationException>(() => k.CopyTo(arr, 0));
  782. return;
  783. }
  784. }
  785. private static void IterateAndModifyValueCollection4(IDictionary<string, object> exp) {
  786. ICollection<object> k = exp.Values;
  787. object[] arr = new object[10];
  788. foreach (var kv in k) {
  789. exp.Add("blah6", 6);
  790. AssertExceptionThrown<InvalidOperationException>(() => k.CopyTo(arr, 0));
  791. return;
  792. }
  793. }
  794. private static void ExpandoThreadAdder(ExpandoObject self, string name) {
  795. IDictionary<string, object> exp = (IDictionary<string, object>)self;
  796. for (int i = 0; i < 1000; i++) {
  797. string setname = name + i.ToString("0000");
  798. if (exp.ContainsKey(setname)) {
  799. exp[setname] = i;
  800. } else {
  801. exp.Add(setname, i);
  802. }
  803. }
  804. }
  805. private static void ExpandoThreadAdderRemover(ExpandoObject self, string name) {
  806. IDictionary<string, object> exp = (IDictionary<string, object>)self;
  807. for (int i = 0; i < 1000; i++) {
  808. string setname = name + i.ToString("0000");
  809. if (exp.ContainsKey(setname)) {
  810. exp[setname] = i;
  811. } else {
  812. exp.Add(setname, i);
  813. }
  814. exp.Remove(setname);
  815. }
  816. }
  817. [Test(TestState.COM, "Simple negative cases for the IDispatch COM IDO")]
  818. private void Scenario_IDispatch_Negative() {
  819. //Get a COM object that implements IDispatch
  820. Type comType = Type.GetTypeFromProgID("DlrComLibrary.DlrComServer");
  821. Assert.IsNotNull(comType, "Could not retrieve DlrComLibrary.DlrComServer. Make sure you have registered DlrComLibrary.dll on this machine");
  822. var comObj = Activator.CreateInstance(comType);
  823. //var comMeta = MetaObject.ObjectToMetaObject(comObj, Expression.Constant(comObj));
  824. #region CallSite for each Action
  825. var call = CallSite<Func<CallSite, object, int, int, int, int, int, object>>.Create(new TestInvokeMemberBinder("NotThere"));
  826. var convert = CallSite<Func<CallSite, object, string>>.Create(new TestConvertBinder(typeof(String), true));
  827. var create = CallSite<Func<CallSite, object, object>>.Create(new TestCreateBinder());
  828. var deleteIndex = CallSite<Action<CallSite, object, int>>.Create(new TestDeleteIndexBinder());
  829. var deleteMember = CallSite<Action<CallSite, object>>.Create(new TestDeleteMemberBinder("NotThere"));
  830. var getIndex = CallSite<Func<CallSite, object, object, object>>.Create(new TestGetIndexBinder());
  831. var getMember = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("NotThere"));
  832. var invoke = CallSite<Func<CallSite, object, int, int, int, int, int, object>>.Create(new TestInvokeBinder());
  833. var binaryOperation = CallSite<Func<CallSite, object, object, object>>.Create(new TestBinaryOperationBinder(ExpressionType.Add));
  834. var unaryOperation = CallSite<Func<CallSite, object, object>>.Create(new TestUnaryOperationBinder(ExpressionType.Increment));
  835. var setIndex = CallSite<Func<CallSite, object, object, object, object>>.Create(new TestSetIndexBinder());
  836. var setMember = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("NotThere"));
  837. #endregion
  838. //Perform each action, they should all fail and fall back to the given CallSiteBinder
  839. AssertExceptionThrown<BindingException>(() => call.Target(call, comObj, 1, 2, 3, 4, 5));
  840. AssertExceptionThrown<BindingException>(() => convert.Target(convert, comObj));
  841. AssertExceptionThrown<BindingException>(() => create.Target(create, comObj));
  842. AssertExceptionThrown<BindingException>(() => deleteIndex.Target(deleteIndex, comObj, 3));
  843. AssertExceptionThrown<BindingException>(() => deleteMember.Target(deleteMember, comObj));
  844. AssertExceptionThrown<MissingMemberException>(() => getIndex.Target(getIndex, comObj, 3)); //We always try to dispatch to the default property.
  845. AssertExceptionThrown<BindingException>(() => getMember.Target(getMember, comObj));
  846. AssertExceptionThrown<MissingMemberException>(() => invoke.Target(invoke, comObj, 5, 4, 3, 2, 1));
  847. AssertExceptionThrown<BindingException>(() => binaryOperation.Target(binaryOperation, comObj, 13));
  848. AssertExceptionThrown<BindingException>(() => unaryOperation.Target(unaryOperation, comObj));
  849. AssertExceptionThrown<MissingMemberException>(() => setIndex.Target(setIndex, comObj, 3, 4));
  850. AssertExceptionThrown<BindingException>(() => setMember.Target(setMember, comObj, null));
  851. }
  852. [Test(TestState.COM, "Simple positive cases for the IDispatch COM IDO")]
  853. private void Scenario_IDispatch_Positive() {
  854. /* Note: There are no positive cases for IDispatchComObject against these actions:
  855. *
  856. * Create
  857. * BinaryOperation
  858. * UnaryOperation
  859. * Invoke
  860. * DeleteIndex
  861. * DeleteMember
  862. * BinaryOperationOnIndex
  863. * BinaryOperationOnMember
  864. * UnaryOperationOnIndex
  865. * UnaryOperationOnMember
  866. *
  867. */
  868. //Get a COM object that implements IDispatch
  869. Type comType = Type.GetTypeFromProgID("DlrComLibrary.DlrComServer");
  870. Assert.IsNotNull(comType, "Could not retrieve DlrComLibrary.DlrComServer. Make sure you have registered DlrComLibrary.dll on this machine");
  871. var dlrComServer = Activator.CreateInstance(comType);
  872. var propertyObj = Activator.CreateInstance(Type.GetTypeFromProgID("DlrComLibrary.Properties"));
  873. //var comMeta = MetaObject.ObjectToMetaObject(comObj, Expression.Constant(comObj));
  874. #region CallSite for each supported Action
  875. var call = CallSite<Func<CallSite, object, int, int, int, int, int, object>>.Create(new TestInvokeMemberBinder("SumArgs"));
  876. ClearRuleCache(call);
  877. //Why does this insist on returning object??
  878. var getIndex = CallSite<Func<CallSite, object, short, object>>.Create(new TestGetIndexBinder());
  879. ClearRuleCache(getIndex);
  880. var convert = CallSite<Func<CallSite, object, IDynamicMetaObjectProvider>>.Create(new TestConvertBinder(typeof(IDynamicMetaObjectProvider), true));
  881. ClearRuleCache(convert);
  882. var getMember_Method = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("SumArgs"));
  883. ClearRuleCache(getMember_Method);
  884. var getMember_Event = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("SumArgs"));
  885. ClearRuleCache(getMember_Event);
  886. var getMember_Property = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("pLong"));
  887. ClearRuleCache(getMember_Property);
  888. var setIndex = CallSite<Func<CallSite, object, short, bool, object>>.Create(new TestSetIndexBinder());
  889. ClearRuleCache(setIndex);
  890. var setMember_Property = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("pLong"));
  891. ClearRuleCache(setMember_Property);
  892. var setMember_Event = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("SimpleMethod"));
  893. ClearRuleCache(setMember_Event);
  894. #endregion
  895. //Perform each action
  896. Assert.AreEqual(call.Target(call, dlrComServer, 1, 2, 3, 4, 5), 12345);
  897. Assert.AreEqual(true, getIndex.Target(getIndex, propertyObj, 0));
  898. setIndex.Target(setIndex, propertyObj, 0, false);
  899. Assert.AreEqual(false, getIndex.Target(getIndex, propertyObj, 0));
  900. var sumArgs = getMember_Method.Target(getMember_Method, dlrComServer); //Returns a new DispCallable IDO, which is invokable
  901. Assert.IsNotNull(sumArgs);
  902. Assert.AreEqual(0, getMember_Property.Target(getMember_Property, propertyObj));
  903. setMember_Property.Target(setMember_Property, propertyObj, 42);
  904. Assert.AreEqual(42, getMember_Property.Target(getMember_Property, propertyObj));
  905. //@TODO - getMember_Event, setMember_Event, convert
  906. //Repeat each action for dispcallable, which only supports Invoke
  907. #region Negative CallSites for dispcallable
  908. var create = CallSite<Func<CallSite, object, object>>.Create(new TestCreateBinder());
  909. var invoke = CallSite<Func<CallSite, object, int, int, int, int, int, object>>.Create(new TestInvokeBinder());
  910. ClearRuleCache(invoke);
  911. var deleteIndex = CallSite<Action<CallSite, object, int>>.Create(new TestDeleteIndexBinder());
  912. var deleteMember = CallSite<Action<CallSite, object>>.Create(new TestDeleteMemberBinder("NotThere"));
  913. var getMember = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("NotThere"));
  914. var setMember = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("NotThere"));
  915. var binaryOperation = CallSite<Func<CallSite, object, object, object>>.Create(new TestBinaryOperationBinder(ExpressionType.Add));
  916. var unaryOperation = CallSite<Func<CallSite, object, object>>.Create(new TestUnaryOperationBinder(ExpressionType.Increment));
  917. var getIndex2 = CallSite<Func<CallSite, object, int, int, int, int, int, object>>.Create(new TestGetIndexBinder());
  918. #endregion
  919. Assert.AreEqual(invoke.Target(invoke, sumArgs, 5, 4, 3, 2, 1), 54321);
  920. Assert.AreEqual(getIndex2.Target(getIndex2, sumArgs, 5, 4, 3, 2, 1), 54321);
  921. AssertExceptionThrown<MissingMemberException>(() => setIndex.Target(setIndex, sumArgs, 0, false));
  922. AssertExceptionThrown<BindingException>(() => call.Target(call, sumArgs, 6, 7, 8, 9, 10));
  923. AssertExceptionThrown<BindingException>(() => convert.Target(convert, sumArgs));
  924. AssertExceptionThrown<BindingException>(() => create.Target(create, sumArgs));
  925. AssertExceptionThrown<BindingException>(() => deleteIndex.Target(deleteIndex, sumArgs, 3));
  926. AssertExceptionThrown<BindingException>(() => deleteMember.Target(deleteMember, sumArgs));
  927. AssertExceptionThrown<BindingException>(() => getMember.Target(getMember, sumArgs));
  928. AssertExceptionThrown<BindingException>(() => binaryOperation.Target(binaryOperation, sumArgs, 13));
  929. AssertExceptionThrown<BindingException>(() => unaryOperation.Target(unaryOperation, sumArgs));
  930. AssertExceptionThrown<BindingException>(() => setMember.Target(setMember, sumArgs, null));
  931. }
  932. [Test(TestState.COM, "Simple cases for a basic generic COM IDO")]
  933. private void Scenario_GenericCOM_Simple() {
  934. //Get a COM object that does not implement IDispatch
  935. Type comType = Type.GetTypeFromProgID("DlrComLibrary.NonDispatch");
  936. Assert.IsNotNull(comType, "Could not retrieve DlrComLibrary.NonDispatch. Make sure you have registered DlrComLibrary.dll on this machine");
  937. var comObj = Activator.CreateInstance(comType);
  938. //var comMeta = MetaObject.ObjectToMetaObject(comObj, Expression.Constant(comObj));
  939. #region CallSite for each Action
  940. var call = CallSite<Func<CallSite, object, object>>.Create(new TestInvokeMemberBinder("SimpleMethod"));
  941. var convert = CallSite<Func<CallSite, object, string>>.Create(new TestConvertBinder(typeof(String), true));
  942. var create = CallSite<Func<CallSite, object, object>>.Create(new TestCreateBinder());
  943. var deleteIndex = CallSite<Action<CallSite, object, int>>.Create(new TestDeleteIndexBinder());
  944. var deleteMember = CallSite<Action<CallSite, object>>.Create(new TestDeleteMemberBinder("SimpleMethod"));
  945. var getIndex = CallSite<Func<CallSite, object, object, object>>.Create(new TestGetIndexBinder());
  946. var getMember = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("SimpleMethod"));
  947. var invoke = CallSite<Func<CallSite, object, object>>.Create(new TestInvokeBinder());
  948. var binaryOperation = CallSite<Func<CallSite, object, object, object>>.Create(new TestBinaryOperationBinder(ExpressionType.Add));
  949. var unaryOperation = CallSite<Func<CallSite, object, object>>.Create(new TestUnaryOperationBinder(ExpressionType.Increment));
  950. var setIndex = CallSite<Func<CallSite, object, object, object, object>>.Create(new TestSetIndexBinder());
  951. var setMember = CallSite<Func<CallSite, object, long, object>>.Create(new TestSetMemberBinder("SimpleProperty"));
  952. #endregion
  953. //Perform each action, they should all fail and fall back to the given CallSiteBinder
  954. AssertExceptionThrown<BindingException>(() => call.Target(call, comObj));
  955. AssertExceptionThrown<BindingException>(() => convert.Target(convert, comObj));
  956. AssertExceptionThrown<BindingException>(() => create.Target(create, comObj));
  957. AssertExceptionThrown<BindingException>(() => deleteIndex.Target(deleteIndex, comObj, 3));
  958. AssertExceptionThrown<BindingException>(() => deleteMember.Target(deleteMember, comObj));
  959. AssertExceptionThrown<BindingException>(() => getIndex.Target(getIndex, comObj, 3));
  960. AssertExceptionThrown<BindingException>(() => getMember.Target(getMember, comObj));
  961. AssertExceptionThrown<BindingException>(() => invoke.Target(invoke, comObj));
  962. AssertExceptionThrown<BindingException>(() => binaryOperation.Target(binaryOperation, comObj, 13));
  963. AssertExceptionThrown<BindingException>(() => unaryOperation.Target(unaryOperation, comObj));
  964. AssertExceptionThrown<BindingException>(() => setIndex.Target(setIndex, comObj, 3, 4));
  965. AssertExceptionThrown<BindingException>(() => setMember.Target(setMember, comObj, 5));
  966. }
  967. [Test(TestState.COM, "Tests the COM binder against null arguments")]
  968. private void Scenario_COM_Nulls() {
  969. //Method calls
  970. Type comType = Type.GetTypeFromProgID("DlrComLibrary.ParamsInRetVal");
  971. Assert.IsNotNull(comType, "Could not retrieve DlrComLibrary.NonDispatch. Make sure you have registered DlrComLibrary.dll on this machine");
  972. var comObj = Activator.CreateInstance(comType);
  973. var call_mIDispatch = CallSite<Func<CallSite, object, object, object>>.Create(new TestInvokeMemberBinder("mIDispatch"));
  974. var call_mVariant = CallSite<Func<CallSite, object, object, object>>.Create(new TestInvokeMemberBinder("mVariant"));
  975. var getMember_mIDispatch = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("mIDispatch"));
  976. var invoke = CallSite<Func<CallSite, object, object, object>>.Create(new TestInvokeBinder());
  977. //Assert.IsNull(call_mIDispatch.Target(call_mIDispatch, comObj, null));
  978. Assert.IsNull(call_mVariant.Target(call_mVariant, comObj, null));
  979. var mIDispatch = getMember_mIDispatch.Target(getMember_mIDispatch, comObj);
  980. //Assert.IsNull(invoke.Target(invoke, mIDispatch, null));
  981. //Property sets and gets
  982. comType = Type.GetTypeFromProgID("DlrComLibrary.Properties");
  983. comObj = Activator.CreateInstance(comType);
  984. var setMember_pBstr = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("pBstr"));
  985. var setMember_pVariant = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("pVariant"));
  986. var getMember_pBstr = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("pBstr"));
  987. var getMember_pVariant = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("pVariant"));
  988. setMember_pBstr.Target(setMember_pBstr, comObj, null);
  989. Assert.AreEqual(String.Empty, getMember_pBstr.Target(getMember_pBstr, comObj));
  990. setMember_pVariant.Target(setMember_pVariant, comObj, null);
  991. Assert.IsNull(getMember_pVariant.Target(getMember_pVariant, comObj));
  992. }
  993. [Test("Simple cases for instance restrictions")]
  994. private void Scenario_Restriction_Instance() {
  995. }
  996. [Test("Simple cases for type restrictions")]
  997. private void Scenario_Restriction_Type() {
  998. }
  999. [Test("Simple cases for expression restrictions")]
  1000. private void Scenario_Restriction_Expression() {
  1001. }
  1002. [Test("Confirm that the DynamicObject MetaObject code invokes each overriden action")]
  1003. private void Scenario_Dynamic_Overriden() {
  1004. //Get a simple Dynamic IDO
  1005. TestDynamicObject2 dyn = new TestDynamicObject2();
  1006. #region CallSite for each MetaAction
  1007. var call = CallSite<Func<CallSite, object, object>>.Create(new TestInvokeMemberBinder("member"));
  1008. var convert = CallSite<Func<CallSite, object, string>>.Create(new TestConvertBinder(typeof(String), true));
  1009. var create = CallSite<Func<CallSite, object, object>>.Create(new TestCreateBinder());
  1010. var deleteIndex = CallSite<Action<CallSite, object>>.Create(new TestDeleteIndexBinder());
  1011. var deleteMember = CallSite<Action<CallSite, object>>.Create(new TestDeleteMemberBinder("member"));
  1012. var getIndex = CallSite<Func<CallSite, object, object>>.Create(new TestGetIndexBinder());
  1013. var getMember = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("member"));
  1014. var invoke = CallSite<Func<CallSite, object, object>>.Create(new TestInvokeBinder());
  1015. var unaryOperation = CallSite<Func<CallSite, object, object>>.Create(new TestUnaryOperationBinder(ExpressionType.Increment));
  1016. var binaryOperation = CallSite<Func<CallSite, object, object, object>>.Create(new TestBinaryOperationBinder(ExpressionType.Add));
  1017. var setIndex = CallSite<Func<CallSite, object, object, object, object>>.Create(new TestSetIndexBinder());
  1018. var setMember = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("member"));
  1019. #endregion
  1020. //Invoke each CallSite
  1021. Assert.AreEqual("InvokeMember", call.Target(call, dyn));
  1022. Assert.AreEqual("Convert", convert.Target(convert, dyn));
  1023. Assert.AreEqual("CreateInstance", create.Target(create, dyn));
  1024. AssertExceptionThrown<BindingException>(() => deleteIndex.Target(deleteIndex, dyn));
  1025. AssertExceptionThrown<BindingException>(() => deleteMember.Target(deleteMember, dyn));
  1026. Assert.AreEqual("GetIndex", getIndex.Target(getIndex, dyn));
  1027. Assert.AreEqual("GetMember", getMember.Target(getMember, dyn));
  1028. Assert.AreEqual("Invoke", invoke.Target(invoke, dyn));
  1029. Assert.AreEqual("BinaryOperation", binaryOperation.Target(binaryOperation, dyn, 5));
  1030. Assert.AreEqual("UnaryOperation", unaryOperation.Target(unaryOperation, dyn));
  1031. AssertExceptionThrown<BindingException>(() => setIndex.Target(setIndex, dyn, 3, 4));
  1032. AssertExceptionThrown<BindingException>(() => setMember.Target(setMember, dyn, 5));
  1033. }
  1034. [Test("Simple tests of using standard .NET non-IDO types with the metaobjectbinders")]
  1035. private void Scenario_GenericMO() {
  1036. object[] vars = new object[] { "Hello world", 42 };
  1037. #region CallSite for each MetaAction on this IDO
  1038. var call = CallSite<Func<CallSite, object, object>>.Create(new TestInvokeMemberBinder("member"));
  1039. var convert = CallSite<Func<CallSite, object, string>>.Create(new TestConvertBinder(typeof(String), true));
  1040. var create = CallSite<Func<CallSite, object, object>>.Create(new TestCreateBinder());
  1041. var deleteIndex = CallSite<Action<CallSite, object>>.Create(new TestDeleteIndexBinder());
  1042. var deleteMember = CallSite<Action<CallSite, object>>.Create(new TestDeleteMemberBinder("member"));
  1043. var getIndex = CallSite<Func<CallSite, object, object>>.Create(new TestGetIndexBinder());
  1044. var getMember = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("member"));
  1045. var invoke = CallSite<Func<CallSite, object, object>>.Create(new TestInvokeBinder());
  1046. var binaryOperation = CallSite<Func<CallSite, object, object, object>>.Create(new TestBinaryOperationBinder(ExpressionType.Add));
  1047. var unaryOperation = CallSite<Func<CallSite, object, object>>.Create(new TestUnaryOperationBinder(ExpressionType.Increment));
  1048. var setIndex = CallSite<Func<CallSite, object, object, object, object>>.Create(new TestSetIndexBinder());
  1049. var setMember = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("member"));
  1050. #endregion
  1051. //Should all fallback to the callsitebinder
  1052. foreach (object v in vars) {
  1053. AssertExceptionThrown<BindingException>(() => call.Target(call, v));
  1054. AssertExceptionThrown<BindingException>(() => convert.Target(convert, v));
  1055. AssertExceptionThrown<BindingException>(() => create.Target(create, v));
  1056. AssertExceptionThrown<BindingException>(() => deleteIndex.Target(deleteIndex, v));
  1057. AssertExceptionThrown<BindingException>(() => deleteMember.Target(deleteMember, v));
  1058. AssertExceptionThrown<BindingException>(() => getIndex.Target(getIndex, v));
  1059. AssertExceptionThrown<BindingException>(() => getMember.Target(getMember, v));
  1060. AssertExceptionThrown<BindingException>(() => invoke.Target(invoke, v));
  1061. AssertExceptionThrown<BindingException>(() => binaryOperation.Target(binaryOperation, v, 5));
  1062. AssertExceptionThrown<BindingException>(() => unaryOperation.Target(unaryOperation, v));
  1063. AssertExceptionThrown<BindingException>(() => setIndex.Target(setIndex, v, 3, 4));
  1064. AssertExceptionThrown<BindingException>(() => setMember.Target(setMember, v, 5));
  1065. }
  1066. }
  1067. [Test("Confirm that the base virtual methods on DynamicObject all do not throw, but return false")]
  1068. private void Scenario_Dynamic_Negative() {
  1069. //Get a simple Dynamic IDO
  1070. TestDynamicObject dyn = new TestDynamicObject();
  1071. object result = null;
  1072. Assert.IsFalse(dyn.TryBinaryOperation(new TestBinaryOperationBinder(ExpressionType.Add), null, out result));
  1073. Assert.IsNull(result);
  1074. Assert.IsFalse(dyn.TryConvert(new TestConvertBinder(typeof(String), true), out result));
  1075. Assert.IsNull(result);
  1076. Assert.IsFalse(dyn.TryCreateInstance(new TestCreateBinder(), null, out result));
  1077. Assert.IsNull(result);
  1078. Assert.IsFalse(dyn.TryDeleteIndex(new TestDeleteIndexBinder(), null));
  1079. Assert.IsFalse(dyn.TryDeleteMember(new TestDeleteMemberBinder("member")));
  1080. Assert.IsFalse(dyn.TryGetIndex(new TestGetIndexBinder(), null, out result));
  1081. Assert.IsNull(result);
  1082. Assert.IsFalse(dyn.TryGetMember(new TestGetMemberBinder("member"), out result));
  1083. Assert.IsNull(result);
  1084. Assert.IsFalse(dyn.TryInvoke(new TestInvokeBinder(), null, out result));
  1085. Assert.IsNull(result);
  1086. Assert.IsFalse(dyn.TryInvokeMember(new TestInvokeMemberBinder("member"), null, out result));
  1087. Assert.IsNull(result);
  1088. Assert.IsFalse(dyn.TrySetIndex(new TestSetIndexBinder(), null, null));
  1089. Assert.IsFalse(dyn.TrySetMember(new TestSetMemberBinder("member"), null));
  1090. Assert.IsFalse(dyn.TryUnaryOperation(new TestUnaryOperationBinder(ExpressionType.Increment), out result));
  1091. Assert.IsNull(result);
  1092. }
  1093. #endregion
  1094. [Test("Binder atomization")]
  1095. private void Scenario_ManyBinders1() {
  1096. #region CallSite for each action
  1097. var setMember = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("HaHa"));
  1098. var getMember = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("HaHa"));
  1099. #endregion
  1100. // sanity check with expando
  1101. ExpandoObject exp = new ExpandoObject();
  1102. setMember.Target(setMember, exp, 52);
  1103. Assert.AreEqual(52, getMember.Target(getMember, exp));
  1104. var getMember42 = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("HaHa", false, 42));
  1105. Assert.AreEqual(52, getMember42.Target(getMember42, exp));
  1106. // create many shortlived binders of same identity
  1107. for (int i = 0; i < 10000; i++) {
  1108. var getMemberI = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("HaHa", false, 42));
  1109. Assert.AreEqual(52, getMemberI.Target(getMemberI, exp));
  1110. }
  1111. Assert.AreEqual(52, getMember42.Target(getMember42, exp));
  1112. }
  1113. [Test("Binder life times")]
  1114. private void Scenario_ManyBinders2() {
  1115. #region CallSite for each action
  1116. var setMember = CallSite<Func<CallSite, object, object, object>>.Create(new TestSetMemberBinder("HaHa"));
  1117. var getMember = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("HaHa"));
  1118. #endregion
  1119. // sanity check with expando
  1120. ExpandoObject exp = new ExpandoObject();
  1121. setMember.Target(setMember, exp, 52);
  1122. Assert.AreEqual(52, getMember.Target(getMember, exp));
  1123. // create many shortlived binders of different indentity
  1124. for (int i = 0; i < 10000; i++) {
  1125. var getMemberI = CallSite<Func<CallSite, object, object>>.Create(new TestGetMemberBinder("HaHa", false, i));
  1126. Assert.AreEqual(52, getMemberI.Target(getMemberI, exp));
  1127. }
  1128. }
  1129. [Test("Passing IDMOP without restrictions to a standard binder causes InvalidOperationExceptions")]
  1130. private void Scenario_InsufficientRestrictions() {
  1131. var invoke = CallSite<Func<CallSite, string, string>>.Create(new TestBadGetMemberBinder("Something"));
  1132. AssertExceptionThrown<InvalidOperationException>(() => invoke.Target(invoke, "hello"));
  1133. }
  1134. [Test("Ensure binding against delegates works")]
  1135. private void Scenario_DelegateBindings() {
  1136. //The string argument to this callsite tells DelegateBinder which
  1137. //method to bind to, Bind or Target1. Target1 is a delegate, Bind
  1138. //is the typical expression binding. Further, binder exposes
  1139. //two toggles to control whether the rules returned by each binding
  1140. //pass or fail.
  1141. var binder = new DelegateBinder();
  1142. var site = CallSite<Func<CallSite, string, string>>.Create(binder);
  1143. //Caches are empty, bind against the typical expression and ensure it worked
  1144. binder.BindTest = true;
  1145. binder.Target1Test = true;
  1146. Assert.AreEqual("Bind", site.Target(site, "Bind"));
  1147. //Should find the initial rule in the cache and not re-bind
  1148. Assert.AreEqual("Bind", site.Target(site, "Target1"));
  1149. //Make the expression fail and we re-bind to the delegate
  1150. binder.BindTest = false;
  1151. Assert.AreEqual("Target1", site.Target(site, "Target1"));
  1152. //Create a new callsite to clear l0 and l1
  1153. site = CallSite<Func<CallSite, string, string>>.Create(binder);
  1154. //Set BindTest to pass, and we should find it in l2
  1155. binder.BindTest = true;
  1156. Assert.AreEqual("Bind", site.Target(site, "Target1"));
  1157. //Reset the binder and all caches
  1158. binder.BindTest = true;
  1159. ClearRuleCache(site);
  1160. site = CallSite<Func<CallSite, string, string>>.Create(binder);
  1161. //Now bind to the delegate
  1162. Assert.AreEqual("Target1", site.Target(site, "Target1"));
  1163. //Create a new callsite to clear l0 and l1
  1164. site = CallSite<Func<CallSite, string, string>>.Create(binder);
  1165. //Ensure the delegate did not enter l2
  1166. Assert.AreEqual("Bind", site.Target(site, "Bind"));
  1167. //Reset all caches
  1168. ClearRuleCache(site);
  1169. site = CallSite<Func<CallSite, string, string>>.Create(binder);
  1170. //Now bind to the delegate
  1171. Assert.AreEqual("Target1", site.Target(site, "Target1"));
  1172. //And again, the delegate is cached, we should not re-bind
  1173. Assert.AreEqual("Target1", site.Target(site, "Bind"));
  1174. //Make the delegate fail and we re-bind to the expression
  1175. binder.Target1Test = false;
  1176. Assert.AreEqual("Bind", site.Target(site, "Bind"));
  1177. }
  1178. [Test("Test invalid calls to base binder constructors.")]
  1179. private void Scenario_TestBinderArgumentChecking() {
  1180. // BinaryOperationBinder
  1181. AssertExceptionThrown<ArgumentException>(delegate() { new TestBinaryOperationBinder(ExpressionType.Switch); });
  1182. // ConvertBinder
  1183. AssertExceptionThrown<ArgumentNullException>(delegate() { new TestConvertBinder(null, true); });
  1184. // CreateInstanceBinder
  1185. AssertExceptionThrown<ArgumentNullException>(delegate() { new TestCreateBinder(null); });
  1186. // DeleteIndexBinder
  1187. AssertExceptionThrown<ArgumentNullException>(delegate() { new TestDeleteIndexBinder(null); });
  1188. // DeleteMemberBinder
  1189. AssertExceptionThrown<ArgumentNullException>(delegate() { new TestDeleteMemberBinder(null, true); });
  1190. // GetIndexBinder
  1191. AssertExceptionThrown<ArgumentNullException>(delegate() { new TestGetIndexBinder(null); });
  1192. // GetMemberBinder
  1193. AssertExceptionThrown<ArgumentNullException>(delegate { new TestGetMemberBinder(null, true); });
  1194. // InvokeBinder
  1195. AssertExceptionThrown<ArgumentNullException>(delegate { new TestInvokeBinder(null); });
  1196. // InvokeMemberBinder
  1197. AssertExceptionThrown<ArgumentNullException>(delegate { new TestInvokeMemberBinder(null, true, new CallInfo(0)); });
  1198. AssertExceptionThrown<ArgumentNullException>(delegate { new TestInvokeMemberBinder("Hello", true, null); });
  1199. // SetIndexBinder
  1200. AssertExceptionThrown<ArgumentNullException>(delegate { new TestSetIndexBinder(null); });
  1201. // SetMemberBinder
  1202. AssertExceptionThrown<ArgumentNullException>(delegate { new TestSetMemberBinder(null, true); });
  1203. // UnaryOperationBinder
  1204. AssertExceptionThrown<ArgumentException>(delegate { new TestUnaryOperationBinder(ExpressionType.Switch); });
  1205. }
  1206. private static DynamicMetaObject CreateDMO(string name, object value) {
  1207. return new DynamicMetaObject(Expression.Parameter(typeof(object), name), BindingRestrictions.Empty, value);
  1208. }
  1209. private static DynamicMetaObject[] CreateDMOArray(int length) {
  1210. var array = new DynamicMetaObject[length];
  1211. for (int i = 0; i < length; i++) {
  1212. array[i] = CreateDMO("arg" + i, "value" + i);
  1213. }
  1214. return array;
  1215. }
  1216. [Test("Test invalid calls to binder Bind methods.")]
  1217. private void Scenario_TestBinderBindArgumentChecking() {
  1218. var dmo = CreateDMO("Target", new object());
  1219. var dmo_0 = new DynamicMetaObject[0];
  1220. var dmo_1 = CreateDMOArray(1);
  1221. var dmo_2 = CreateDMOArray(2);
  1222. var dmo_5 = CreateDMOArray(5);
  1223. var null_1 = new DynamicMetaObject[1];
  1224. var null_2 = CreateDMOArray(2); null_2[1] = null;
  1225. var null_5 = CreateDMOArray(5); null_5[4] = null;
  1226. // BinaryOperationBinder
  1227. BinaryOperationBinder binary = new TestBinaryOperationBinder(ExpressionType.Add);
  1228. AssertExceptionThrown<ArgumentNullException>(delegate() { binary.Bind(null, dmo_1); });
  1229. AssertExceptionThrown<ArgumentNullException>(delegate() { binary.Bind(dmo, null); });
  1230. AssertExceptionThrown<ArgumentException>(delegate() { binary.Bind(dmo, dmo_2); });
  1231. AssertExceptionThrown<ArgumentNullException>(delegate() { binary.Bind(dmo, null_1); });
  1232. // ConvertBinder
  1233. ConvertBinder convert = new TestConvertBinder(typeof(string), true);
  1234. AssertExceptionThrown<ArgumentNullException>(delegate() { convert.Bind(null, dmo_0); });
  1235. AssertExceptionThrown<ArgumentException>(delegate() { convert.Bind(dmo, dmo_1); });
  1236. AssertExceptionThrown<ArgumentException>(delegate() { convert.Bind(dmo, null_5); });
  1237. // CreateInstanceBinder
  1238. CreateInstanceBinder create = new TestCreateBinder(new CallInfo(2));
  1239. AssertExceptionThrown<ArgumentNullException>(delegate() { create.Bind(null, dmo_2); });
  1240. AssertExceptionThrown<ArgumentNullException>(delegate() { create.Bind(dmo, null); });
  1241. AssertExceptionThrown<ArgumentNullException>(delegate() { create.Bind(dmo, null_5); });
  1242. // DeleteIndexBinder
  1243. DeleteIndexBinder di = new TestDeleteIndexBinder(new CallInfo(2));
  1244. AssertExceptionThrown<ArgumentNullException>(delegate() { di.Bind(null, dmo_2); });
  1245. AssertExceptionThrown<ArgumentNullException>(delegate() { di.Bind(dmo, null); });
  1246. AssertExceptionThrown<ArgumentNullException>(delegate() { di.Bind(dmo, null_2); });
  1247. AssertExceptionThrown<ArgumentNullException>(delegate() { di.Bind(dmo, null_5); });
  1248. // DeleteMemberBinder
  1249. DeleteMemberBinder dm = new TestDeleteMemberBinder("Member", true);
  1250. AssertExceptionThrown<ArgumentNullException>(delegate() { dm.Bind(null, dmo_0); });
  1251. AssertExceptionThrown<ArgumentException>(delegate() { dm.Bind(dmo, dmo_1); });
  1252. // GetIndexBinder
  1253. GetIndexBinder gi = new TestGetIndexBinder(new CallInfo(2));
  1254. AssertExceptionThrown<ArgumentNullException>(delegate() { gi.Bind(null, dmo_2); });
  1255. AssertExceptionThrown<ArgumentNullException>(delegate() { gi.Bind(dmo, null); });
  1256. AssertExceptionThrown<ArgumentNullException>(delegate() { gi.Bind(dmo, null_2); });
  1257. AssertExceptionThrown<ArgumentNullException>(delegate() { gi.Bind(dmo, null_5); });
  1258. // GetMemberBinder
  1259. GetMemberBinder gm = new TestGetMemberBinder("Member", true);
  1260. AssertExceptionThrown<ArgumentNullException>(delegate { gm.Bind(null, dmo_0); });
  1261. AssertExceptionThrown<ArgumentException>(delegate { gm.Bind(dmo, dmo_1); });
  1262. AssertExceptionThrown<ArgumentException>(delegate { gm.Bind(dmo, dmo_5); });
  1263. // InvokeBinder
  1264. InvokeBinder invoke = new TestInvokeBinder(new CallInfo(2));
  1265. AssertExceptionThrown<ArgumentNullException>(delegate { invoke.Bind(null, dmo_2); });
  1266. AssertExceptionThrown<ArgumentNullException>(delegate { invoke.Bind(dmo, null); });
  1267. AssertExceptionThrown<ArgumentNullException>(delegate { invoke.Bind(dmo, null_2); });
  1268. AssertExceptionThrown<ArgumentNullException>(delegate { invoke.Bind(dmo, null_5); });
  1269. // InvokeMemberBinder
  1270. InvokeMemberBinder im = new TestInvokeMemberBinder("Hello", true, new CallInfo(2));
  1271. AssertExceptionThrown<ArgumentNullException>(delegate { im.Bind(null, dmo_2); });
  1272. AssertExceptionThrown<ArgumentNullException>(delegate { im.Bind(dmo, null); });
  1273. AssertExceptionThrown<ArgumentNullException>(delegate { im.Bind(dmo, null_2); });
  1274. AssertExceptionThrown<ArgumentNullException>(delegate { im.Bind(dmo, null_5); });
  1275. // SetIndexBinder
  1276. SetIndexBinder si = new TestSetIndexBinder(new CallInfo(2));
  1277. var null_54 = CreateDMOArray(5); null_54[3] = null;
  1278. AssertExceptionThrown<ArgumentNullException>(delegate { si.Bind(null, dmo_2); });
  1279. AssertExceptionThrown<ArgumentException>(delegate { si.Bind(dmo, dmo_0); });
  1280. AssertExceptionThrown<ArgumentNullException>(delegate { si.Bind(dmo, null); });
  1281. AssertExceptionThrown<ArgumentNullException>(delegate { si.Bind(dmo, null_5); });
  1282. AssertExceptionThrown<ArgumentNullException>(delegate { si.Bind(dmo, null_54); });
  1283. // SetMemberBinder
  1284. SetMemberBinder sm = new TestSetMemberBinder("Member", true);
  1285. AssertExceptionThrown<ArgumentNullException>(delegate { sm.Bind(null, dmo_1); });
  1286. AssertExceptionThrown<ArgumentException>(delegate { sm.Bind(dmo, dmo_2); });
  1287. AssertExceptionThrown<ArgumentNullException>(delegate { sm.Bind(dmo, null); });
  1288. AssertExceptionThrown<ArgumentNullException>(delegate { sm.Bind(dmo, null_1); });
  1289. AssertExceptionThrown<ArgumentException>(delegate { sm.Bind(dmo, null_5); });
  1290. // UnaryOperationBinder
  1291. UnaryOperationBinder unary = new TestUnaryOperationBinder(ExpressionType.Negate);
  1292. AssertExceptionThrown<ArgumentNullException>(delegate { unary.Bind(null, dmo_0); });
  1293. AssertExceptionThrown<ArgumentException>(delegate { unary.Bind(dmo, dmo_2); });
  1294. // DynamicMetaObjectBinder
  1295. SetIndexBinder dmob = new TestSetIndexBinder(new CallInfo(2));
  1296. AssertExceptionThrown<ArgumentOutOfRangeException>(delegate {
  1297. dmob.Bind(new object[] { }, new System.Collections.ObjectModel.ReadOnlyCollection<ParameterExpression>(new ParameterExpression[] { Expression.Parameter(typeof(Int32)) }), Expression.Label());
  1298. });
  1299. AssertExceptionThrown<ArgumentOutOfRangeException>(delegate
  1300. {
  1301. dmob.Bind(new object[] { new object() }, new System.Collections.ObjectModel.ReadOnlyCollection<ParameterExpression>(new ParameterExpression[] { }), Expression.Label());
  1302. });
  1303. AssertExceptionThrown<ArgumentOutOfRangeException>(delegate
  1304. {
  1305. dmob.Bind(new object[] { new object(), new object() }, new System.Collections.ObjectModel.ReadOnlyCollection<ParameterExpression>(new ParameterExpression[] { Expression.Parameter(typeof(Int32)) }), Expression.Label());
  1306. });
  1307. }
  1308. class Regress754079_DO : DynamicObject {
  1309. public object useResult = null;
  1310. public override bool TryConvert(ConvertBinder binder, out object result) {
  1311. result = useResult;
  1312. return true;
  1313. }
  1314. }
  1315. [Test("Regression test for Dev10 bug 754079")]
  1316. private void Regress754079() {
  1317. //This test is only valid on .NET 4.5, which internally is still
  1318. //versioned 4.0 with just a higher build number. 4.0 RTM was
  1319. //build 30319.
  1320. if (System.Environment.Version >= new Version(4, 0, 30322, 0)) {
  1321. Regress754079_DO dynObj = new Regress754079_DO();
  1322. // Converting null -> bool (negative)
  1323. dynObj.useResult = null;
  1324. var convert1 = CallSite<Func<CallSite, object, bool>>.Create(new TestConvertBinder(typeof(bool), true));
  1325. AssertExceptionThrown<InvalidCastException>(() => convert1.Target(convert1, dynObj),
  1326. "The result type 'null' of the dynamic binding produced by the object with type 'SiteTest.SiteTestScenarios+Regress754079_DO' for the binder 'SiteTest.Actions.TestConvertBinder' is not compatible with the result type 'System.Boolean' expected by the call site.");
  1327. // Converting object -> string (negative)
  1328. dynObj.useResult = new object();
  1329. var convert5 = CallSite<Func<CallSite, object, string>>.Create(new TestConvertBinder(typeof(string), true));
  1330. AssertExceptionThrown<InvalidCastException>(() => convert5.Target(convert5, dynObj),
  1331. "The result type 'System.Object' of the dynamic binding produced by the object with type 'SiteTest.SiteTestScenarios+Regress754079_DO' for the binder 'SiteTest.Actions.TestConvertBinder' is not compatible with the result type 'System.String' expected by the call site.");
  1332. // Converting object -> int (negative)
  1333. dynObj.useResult = new object();
  1334. var convert7 = CallSite<Func<CallSite, object, int>>.Create(new TestConvertBinder(typeof(int), true));
  1335. AssertExceptionThrown<InvalidCastException>(() => convert7.Target(convert7, dynObj),
  1336. "The result type 'System.Object' of the dynamic binding produced by the object with type 'SiteTest.SiteTestScenarios+Regress754079_DO' for the binder 'SiteTest.Actions.TestConvertBinder' is not compatible with the result type 'System.Int32' expected by the call site.");
  1337. // Converting float -> string (negative)
  1338. dynObj.useResult = 3.1415968;
  1339. var convert6 = CallSite<Func<CallSite, object, string>>.Create(new TestConvertBinder(typeof(string), true));
  1340. AssertExceptionThrown<InvalidCastException>(() => convert6.Target(convert6, dynObj),
  1341. "The result type 'System.Double' of the dynamic binding produced by the object with type 'SiteTest.SiteTestScenarios+Regress754079_DO' for the binder 'SiteTest.Actions.TestConvertBinder' is not compatible with the result type 'System.String' expected by the call site.");
  1342. // Converting TestAttribute -> Attribute (positive)
  1343. dynObj.useResult = new TestAttribute();
  1344. var convert2 = CallSite<Func<CallSite, object, Attribute>>.Create(new TestConvertBinder(typeof(Attribute), true));
  1345. convert2.Target(convert2, dynObj);
  1346. // Converting int -> IEquatable<int> (positive)
  1347. dynObj.useResult = 1;
  1348. var convert3 = CallSite<Func<CallSite, object, IEquatable<int>>>.Create(new TestConvertBinder(typeof(IEquatable<int>), true));
  1349. convert3.Target(convert3, dynObj);
  1350. // Converting ExpandoObject -> ExpandoObject (positive)
  1351. dynObj.useResult = new ExpandoObject();
  1352. var convert4 = CallSite<Func<CallSite, object, ExpandoObject>>.Create(new TestConvertBinder(typeof(ExpandoObject), true));
  1353. convert4.Target(convert4, dynObj);
  1354. }
  1355. }
  1356. delegate void RefDel012(CallSite site, object dynObj, ref int i, ref int j, ref int k);
  1357. delegate void RefDel01_(CallSite site, object dynObj, ref int i, ref int j, int k);
  1358. delegate void RefDel_12(CallSite site, object dynObj, int i, ref int j, ref int k);
  1359. delegate void RefDel0_2(CallSite site, object dynObj, ref int i, int j, ref int k);
  1360. delegate void RefDel0__(CallSite site, object dynObj, ref int i, int j, int k);
  1361. delegate void RefDel_1_(CallSite site, object dynObj, int i, ref int j, int k);
  1362. delegate void RefDel__2(CallSite site, object dynObj, int i, int j, ref int k);
  1363. delegate void RefDel___(CallSite site, object dynObj, int i, int j, int k);
  1364. [Test("Test byref arguments to DynamicObject invocation")]
  1365. private void Scenario_ByRef() {
  1366. //This test is only valid on .NET 4.5, which internally is still
  1367. //versioned 4.0 with just a higher build number. 4.0 RTM was
  1368. //build 30319.
  1369. if (System.Environment.Version >= new Version(4, 0, 30322, 0)) {
  1370. int i, j, k;
  1371. ByRefDynamicObject dynObj = new ByRefDynamicObject();
  1372. CallSiteBinder[] binders = { new TestInvokeBinder(),
  1373. new TestInvokeMemberBinder("Method"),
  1374. new TestGetIndexBinder(),
  1375. new TestSetIndexBinder(),
  1376. new TestDeleteIndexBinder()
  1377. };
  1378. foreach (CallSiteBinder b in binders) {
  1379. var site0 = CallSite<RefDel012>.Create(b);
  1380. i = j = k = 2;
  1381. site0.Target(site0, dynObj, ref i, ref j, ref k);
  1382. Assert.AreEqual(42, i);
  1383. Assert.AreEqual(43, j);
  1384. if(!(b is TestSetIndexBinder))
  1385. Assert.AreEqual(44, k);
  1386. var site1 = CallSite<RefDel01_>.Create(b);
  1387. i = j = k = 2;
  1388. site1.Target(site1, dynObj, ref i, ref j, k);
  1389. Assert.AreEqual(42, i);
  1390. Assert.AreEqual(43, j);
  1391. Assert.AreEqual(2, k);
  1392. var site2 = CallSite<RefDel_12>.Create(b);
  1393. i = j = k = 2;
  1394. site2.Target(site2, dynObj, i, ref j, ref k);
  1395. Assert.AreEqual(2, i);
  1396. Assert.AreEqual(43, j);
  1397. if (!(b is TestSetIndexBinder))
  1398. Assert.AreEqual(44, k);
  1399. var site3 = CallSite<RefDel0_2>.Create(b);
  1400. i = j = k = 2;
  1401. site3.Target(site3, dynObj, ref i, j, ref k);
  1402. Assert.AreEqual(42, i);
  1403. Assert.AreEqual(2, j);
  1404. if (!(b is TestSetIndexBinder))
  1405. Assert.AreEqual(44, k);
  1406. var site4 = CallSite<RefDel0__>.Create(b);
  1407. i = j = k = 2;
  1408. site4.Target(site4, dynObj, ref i, j, k);
  1409. Assert.AreEqual(42, i);
  1410. Assert.AreEqual(2, j);
  1411. Assert.AreEqual(2, k);
  1412. var site5 = CallSite<RefDel_1_>.Create(b);
  1413. i = j = k = 2;
  1414. site5.Target(site5, dynObj, i, ref j, k);
  1415. Assert.AreEqual(2, i);
  1416. Assert.AreEqual(43, j);
  1417. Assert.AreEqual(2, k);
  1418. var site6 = CallSite<RefDel__2>.Create(b);
  1419. i = j = k = 2;
  1420. site6.Target(site6, dynObj, i, j, ref k);
  1421. Assert.AreEqual(2, i);
  1422. Assert.AreEqual(2, j);
  1423. if (!(b is TestSetIndexBinder))
  1424. Assert.AreEqual(44, k);
  1425. var site7 = CallSite<RefDel___>.Create(b);
  1426. i = j = k = 2;
  1427. site7.Target(site7, dynObj, i, j, k);
  1428. Assert.AreEqual(2, i);
  1429. Assert.AreEqual(2, j);
  1430. Assert.AreEqual(2, k);
  1431. }
  1432. }
  1433. }
  1434. }
  1435. }