InteropTests.Dynamic.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. using System.Dynamic;
  2. using Jint.Native;
  3. using Jint.Native.Symbol;
  4. namespace Jint.Tests.PublicInterface;
  5. public partial class InteropTests
  6. {
  7. [Fact]
  8. public void CanAccessExpandoObject()
  9. {
  10. var engine = new Engine();
  11. dynamic expando = new ExpandoObject();
  12. expando.Name = "test";
  13. engine.SetValue("expando", expando);
  14. Assert.Equal("test", engine.Evaluate("expando.Name").ToString());
  15. }
  16. [Fact]
  17. public void DebugView()
  18. {
  19. // allows displaying different local variables under debugger
  20. var engine = new Engine();
  21. var boolNet = true;
  22. var boolJint = (JsBoolean) boolNet;
  23. var doubleNet = 12.34;
  24. var doubleJint = (JsNumber) doubleNet;
  25. var integerNet = 42;
  26. var integerJint = (JsNumber) integerNet;
  27. var stringNet = "ABC";
  28. var stringJint = (JsString) stringNet;
  29. var arrayNet = new[] { 1, 2, 3 };
  30. var arrayListNet = new List<int> { 1, 2, 3 };
  31. var arrayJint = new JsArray(engine, arrayNet.Select(x => (JsNumber) x).ToArray());
  32. var objectNet = new Person { Name = "name", Age = 12 };
  33. var objectJint = new JsObject(engine);
  34. objectJint["name"] = "name";
  35. objectJint["age"] = 12;
  36. objectJint[GlobalSymbolRegistry.ToStringTag] = "Object";
  37. var dictionaryNet = new Dictionary<JsValue, JsValue>();
  38. dictionaryNet["name"] = "name";
  39. dictionaryNet["age"] = 12;
  40. dictionaryNet[GlobalSymbolRegistry.ToStringTag] = "Object";
  41. }
  42. [Fact]
  43. public void CanAccessMemberNamedItemThroughExpando()
  44. {
  45. var parent = (IDictionary<string, object>) new ExpandoObject();
  46. var child = (IDictionary<string, object>) new ExpandoObject();
  47. var values = (IDictionary<string, object>) new ExpandoObject();
  48. parent["child"] = child;
  49. child["item"] = values;
  50. values["title"] = "abc";
  51. _engine.SetValue("parent", parent);
  52. Assert.Equal("abc", _engine.Evaluate("parent.child.item.title"));
  53. }
  54. [Fact]
  55. public void ShouldForOfOnExpandoObject()
  56. {
  57. dynamic o = new ExpandoObject();
  58. o.a = 1;
  59. o.b = 2;
  60. _engine.SetValue("dynamic", o);
  61. var result = _engine.Evaluate("var l = ''; for (var x of dynamic) l += x; return l;").AsString();
  62. Assert.Equal("a,1b,2", result);
  63. }
  64. [Fact]
  65. public void ShouldConvertObjectInstanceToExpando()
  66. {
  67. _engine.Evaluate("var o = {a: 1, b: 'foo'}");
  68. var result = _engine.GetValue("o");
  69. dynamic value = result.ToObject();
  70. Assert.Equal(1, value.a);
  71. Assert.Equal("foo", value.b);
  72. var dic = (IDictionary<string, object>) result.ToObject();
  73. Assert.Equal(1d, dic["a"]);
  74. Assert.Equal("foo", dic["b"]);
  75. }
  76. [Fact]
  77. public void CanAccessDynamicObject()
  78. {
  79. var test = new DynamicClass();
  80. var engine = new Engine();
  81. engine.SetValue("test", test);
  82. Assert.Equal("a", engine.Evaluate("test.a").AsString());
  83. Assert.Equal("b", engine.Evaluate("test.b").AsString());
  84. engine.Evaluate("test.a = 5; test.b = 10; test.Name = 'Jint'");
  85. Assert.Equal(5, engine.Evaluate("test.a").AsNumber());
  86. Assert.Equal(10, engine.Evaluate("test.b").AsNumber());
  87. Assert.Equal("Jint", engine.Evaluate("test.Name").AsString());
  88. Assert.True(engine.Evaluate("test.ContainsKey('a')").AsBoolean());
  89. Assert.True(engine.Evaluate("test.ContainsKey('b')").AsBoolean());
  90. Assert.False(engine.Evaluate("test.ContainsKey('c')").AsBoolean());
  91. }
  92. [Fact]
  93. public void ShouldAccessCustomDynamicObjectProperties()
  94. {
  95. var t = new DynamicType
  96. {
  97. ["MemberKey"] = new MemberType
  98. {
  99. Field = 4
  100. }
  101. };
  102. var e = new Engine().SetValue("dynamicObj", t);
  103. Assert.Equal(4, ((dynamic) t).MemberKey.Field);
  104. Assert.Equal(4, e.Evaluate("dynamicObj.MemberKey.Field"));
  105. }
  106. private class MemberType
  107. {
  108. public int Field;
  109. }
  110. private class DynamicType : DynamicObject
  111. {
  112. private readonly Dictionary<string, object> _data = new();
  113. public override bool TryGetMember(GetMemberBinder binder, out object result)
  114. {
  115. if (_data.ContainsKey(binder.Name))
  116. {
  117. result = this[binder.Name];
  118. return true;
  119. }
  120. return base.TryGetMember(binder, out result);
  121. }
  122. public object this[string key]
  123. {
  124. get
  125. {
  126. _data.TryGetValue(key, out var value);
  127. return value;
  128. }
  129. set => _data[key] = value;
  130. }
  131. }
  132. private class DynamicClass : DynamicObject
  133. {
  134. private readonly Dictionary<string, object> _properties = new Dictionary<string, object>();
  135. public override bool TryGetMember(GetMemberBinder binder, out object result)
  136. {
  137. result = binder.Name;
  138. if (_properties.TryGetValue(binder.Name, out var value))
  139. {
  140. result = value;
  141. }
  142. return true;
  143. }
  144. public override bool TrySetMember(SetMemberBinder binder, object value)
  145. {
  146. _properties[binder.Name] = value;
  147. return true;
  148. }
  149. public string Name { get; set; }
  150. public bool ContainsKey(string key)
  151. {
  152. return _properties.ContainsKey(key);
  153. }
  154. }
  155. private class Person
  156. {
  157. public string Name { get; set; }
  158. public int Age { get; set; }
  159. }
  160. }