InteropTests.TypeReference.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. using Jint.Native;
  2. using Jint.Runtime.Interop;
  3. using Jint.Tests.Runtime.Domain;
  4. using Microsoft.Extensions.DependencyInjection;
  5. namespace Jint.Tests.Runtime;
  6. public partial class InteropTests
  7. {
  8. [Fact]
  9. public void DelegateWithDefaultValueParametersCanBeInvoked()
  10. {
  11. var instance = new A();
  12. _engine.SetValue("Instance", instance);
  13. _engine.SetValue("Class", TypeReference.CreateTypeReference(_engine, typeof(A)));
  14. RunTest(@"
  15. assert(Instance.Call19() === 0);
  16. assert(Instance.Call19(1) === 1);
  17. assert(Instance.Call20(1) === 4);
  18. assert(Instance.Call20(1, 2) === 5);
  19. assert(Instance.Call20(1 , 2, 3) === 6);
  20. assert(Class.Call19Static() === 0);
  21. assert(Class.Call19Static(1) === 1);
  22. assert(Class.Call20Static(1) === 4);
  23. assert(Class.Call20Static(1, 2) === 5);
  24. assert(Class.Call20Static(1 , 2, 3) === 6);
  25. ");
  26. }
  27. [Fact]
  28. public void JavaScriptClassCanExtendClrType()
  29. {
  30. _engine.SetValue("TestClass", TypeReference.CreateTypeReference<TestClass>(_engine));
  31. _engine.Execute("class ExtendedType extends TestClass { constructor() { super(); this.a = 1; } get aProp() { return 'A'; } }");
  32. _engine.Execute("class MyExtendedType extends ExtendedType { constructor() { super(); this.b = 2; } get bProp() { return 'B'; } }");
  33. _engine.Evaluate("let obj = new MyExtendedType();");
  34. _engine.Evaluate("obj.setString('Hello World!');");
  35. Assert.Equal("Hello World!", _engine.Evaluate("obj.string"));
  36. Assert.Equal(1, _engine.Evaluate("obj.a"));
  37. Assert.Equal(2, _engine.Evaluate("obj.b"));
  38. Assert.Equal("A", _engine.Evaluate("obj.aProp"));
  39. Assert.Equal("B", _engine.Evaluate("obj.bProp"));
  40. // TODO we should have a special prototype based on wrapped type so we could differentiate between own and type properties
  41. // Assert.Equal("[\"a\"]", _engine.Evaluate("JSON.stringify(Object.getOwnPropertyNames(new ExtendedType()))"));
  42. // Assert.Equal("[\"a\",\"b\"]", _engine.Evaluate("JSON.stringify(Object.getOwnPropertyNames(new MyExtendedType()))"));
  43. }
  44. [Fact]
  45. public void ShouldAllowMethodsOnClrExtendedTypes()
  46. {
  47. _engine.SetValue("ClrBaseType", TypeReference.CreateTypeReference<TestClass>(_engine));
  48. _engine.Evaluate(@"
  49. class JsBaseType {}
  50. class ExtendsFromJs extends JsBaseType {
  51. constructor() {
  52. super();
  53. this.a = 1;
  54. }
  55. getA() {
  56. return this.a;
  57. }
  58. }
  59. class ExtendsFromClr extends ClrBaseType {
  60. constructor() {
  61. super();
  62. this.a = 1;
  63. }
  64. getA() {
  65. return this.a;
  66. }
  67. }
  68. ");
  69. var extendsFromJs = _engine.Construct("ExtendsFromJs");
  70. Assert.Equal(1, _engine.Evaluate("new ExtendsFromJs().getA();"));
  71. Assert.NotEqual(JsValue.Undefined, extendsFromJs.Get("getA"));
  72. var extendsFromClr = _engine.Construct("ExtendsFromClr");
  73. Assert.Equal(1, _engine.Evaluate("new ExtendsFromClr().getA();"));
  74. Assert.NotEqual(JsValue.Undefined, extendsFromClr.Get("getA"));
  75. }
  76. [Fact]
  77. public void ShouldBeInstanceOfTypeReferenceType()
  78. {
  79. _engine.SetValue("A", typeof(A));
  80. RunTest(@"
  81. var a = new A();
  82. assert(a instanceof A);
  83. ");
  84. }
  85. [Fact]
  86. public void IntegerEnumResolutionShouldWork()
  87. {
  88. var engine = new Engine(options => options.AllowClr(GetType().Assembly));
  89. engine.SetValue("a", new OverLoading());
  90. engine.SetValue("E", TypeReference.CreateTypeReference(engine, typeof(IntegerEnum)));
  91. Assert.Equal("integer-enum", engine.Evaluate("a.testFunc(E.a);").AsString());
  92. }
  93. [Fact]
  94. public void UnsignedIntegerEnumResolutionShouldWork()
  95. {
  96. var engine = new Engine(options => options.AllowClr(GetType().Assembly));
  97. engine.SetValue("E", TypeReference.CreateTypeReference(engine, typeof(UintEnum)));
  98. Assert.Equal(1, engine.Evaluate("E.b;").AsNumber());
  99. }
  100. [Fact]
  101. public void ExceptionFromConstructorShouldPropagate()
  102. {
  103. _engine.SetValue("Class", TypeReference.CreateTypeReference(_engine, typeof(MemberExceptionTest)));
  104. var ex = Assert.Throws<InvalidOperationException>(() => _engine.Evaluate("new Class(true);"));
  105. Assert.Equal("thrown as requested", ex.Message);
  106. }
  107. [Fact]
  108. public void ShouldScoreDoubleToDoubleParameterMatchHigherThanDoubleToFloat()
  109. {
  110. var engine = new Engine();
  111. var mathTypeReference = TypeReference.CreateTypeReference(engine, typeof(Math));
  112. engine.SetValue("Math2", mathTypeReference);
  113. var result = engine.Evaluate("Math2.Max(5.37, 5.56)").AsNumber();
  114. Assert.Equal(5.56d, result);
  115. }
  116. [Fact]
  117. public void TypeReferenceShouldGetIntermediaryPrototype()
  118. {
  119. var engine = new Engine();
  120. engine.SetValue("Person", TypeReference.CreateTypeReference<Person>(engine));
  121. var calls = new List<string>();
  122. engine.SetValue("log", new Action<string>(calls.Add));
  123. engine.Execute("Person.prototype.__defineGetter__('bar', function() { log('called'); return 5 });");
  124. engine.Execute("var instance = new Person();");
  125. engine.Execute("log(instance.bar)");
  126. engine.Execute("var z = {};");
  127. engine.Execute("z['bar'] = 20;");
  128. engine.Execute("log(z['bar']);");
  129. Assert.Equal("called#5#20", string.Join("#", calls));
  130. }
  131. [Fact]
  132. public void CanConfigureCustomInstanceCreator()
  133. {
  134. var collection = new ServiceCollection();
  135. collection.AddTransient<Injectable>();
  136. collection.AddTransient<Dependency>();
  137. var serviceProvider = collection.BuildServiceProvider();
  138. var engine = new Engine(options =>
  139. {
  140. options.Interop.CreateTypeReferenceObject = (e, type, arguments) =>
  141. {
  142. var instance = serviceProvider.GetRequiredService(type);
  143. return instance;
  144. };
  145. });
  146. engine.SetValue("Injectable", TypeReference.CreateTypeReference<Injectable>(engine));
  147. Assert.Equal("Hello world", engine.Evaluate("new Injectable(123, 'abc').getInjectedValue();"));
  148. }
  149. [Fact]
  150. public void ToStringTagShouldReflectType()
  151. {
  152. var reference = TypeReference.CreateTypeReference<Dependency>(_engine);
  153. _engine.SetValue("MyClass", reference);
  154. _engine.Execute("var c = new MyClass();");
  155. Assert.Equal("[object Dependency]", _engine.Evaluate("Object.prototype.toString.call(c);"));
  156. // engine uses registered type reference
  157. _engine.SetValue("c2", new Dependency());
  158. Assert.Equal("[object Dependency]", _engine.Evaluate("Object.prototype.toString.call(c2);"));
  159. }
  160. private class Injectable
  161. {
  162. private readonly Dependency _dependency;
  163. public Injectable(Dependency dependency)
  164. {
  165. _dependency = dependency;
  166. }
  167. public string GetInjectedValue() => _dependency.Value;
  168. }
  169. private class Dependency
  170. {
  171. public string Value => "Hello world";
  172. }
  173. }