GenericMethodTests.cs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. using System;
  2. using Xunit;
  3. namespace Jint.Tests.Runtime;
  4. public class GenericMethodTests
  5. {
  6. [Fact]
  7. public void TestGeneric()
  8. {
  9. var engine = new Engine();
  10. engine.SetValue("TestGenericBaseClass", typeof(TestGenericBaseClass<>));
  11. engine.SetValue("TestGenericClass", typeof(TestGenericClass));
  12. engine.Execute(@"
  13. var testGeneric = new TestGenericClass();
  14. testGeneric.Bar('testing testing 1 2 3');
  15. testGeneric.Foo('hello world');
  16. testGeneric.Add('blah');
  17. ");
  18. Assert.Equal(true, TestGenericClass.BarInvoked);
  19. Assert.Equal(true, TestGenericClass.FooInvoked);
  20. }
  21. [Fact]
  22. public void TestGeneric2()
  23. {
  24. var engine = new Engine();
  25. var testGenericObj = new TestGenericClass();
  26. engine.SetValue("testGenericObj", testGenericObj);
  27. engine.Execute(@"
  28. testGenericObj.Bar('testing testing 1 2 3');
  29. testGenericObj.Foo('hello world');
  30. testGenericObj.Add('blah');
  31. ");
  32. Assert.Equal(1, testGenericObj.Count);
  33. }
  34. [Fact]
  35. public void TestFancyGenericPass()
  36. {
  37. var engine = new Engine();
  38. var testGenericObj = new TestGenericClass();
  39. engine.SetValue("testGenericObj", testGenericObj);
  40. engine.Execute(@"
  41. testGenericObj.Fancy('test', 42, 'foo');
  42. ");
  43. Assert.Equal(true, testGenericObj.FancyInvoked);
  44. }
  45. [Fact]
  46. public void TestFancyGenericFail()
  47. {
  48. var engine = new Engine();
  49. var testGenericObj = new TestGenericClass();
  50. engine.SetValue("testGenericObj", testGenericObj);
  51. var argException = Assert.Throws<Jint.Runtime.JavaScriptException>(() =>
  52. {
  53. engine.Execute(@"
  54. testGenericObj.Fancy('test', 'foo', 42);
  55. ");
  56. });
  57. Assert.Equal("No public methods with the specified arguments were found.", argException.Message);
  58. }
  59. // TPC: TODO: tldr; typescript transpiled to javascript does not include the types in the constructors - JINT should allow you to use generics without specifying type
  60. // The following doesn't work because JINT currently requires generic classes to be instantiated in a way that doesn't comply with typescript transpile of javascript
  61. // i.e. we shouldn't have to specify the type of the generic class when we instantiate it. Since typescript takes the following:
  62. // const someGeneric = new Foo.Bar.MeGeneric<string>()
  63. // and it becomes the following javascript (thru transpile):
  64. // const someGeneric = new Foo.Bar.MeGeneric();
  65. // we _may_ be able to address this by simply instantiating generic types using System.Object for the generic arguments
  66. // This test currently generates the following error:
  67. // No public methods with the specified arguments were found.
  68. public void TestGenericClassDeriveFromGenericInterface()
  69. {
  70. var engine = new Engine(cfg => cfg.AllowClr(typeof(OpenGenericTest<>).Assembly));
  71. engine.SetValue("ClosedGenericTest", typeof(ClosedGenericTest));
  72. engine.SetValue("OpenGenericTest", typeof(OpenGenericTest<>));
  73. engine.SetValue("log", new System.Action<object>(System.Console.WriteLine));
  74. engine.Execute(@"
  75. const closedGenericTest = new ClosedGenericTest();
  76. closedGenericTest.Foo(42);
  77. const temp = new OpenGenericTest(System.String);
  78. ");
  79. }
  80. [Fact]
  81. public void TestGenericMethodUsingCovarianceOrContraviance()
  82. {
  83. var engine = new Engine(cfg => cfg.AllowClr(typeof(PlayerChoiceManager).Assembly));
  84. engine.SetValue("PlayerChoiceManager", typeof(PlayerChoiceManager));
  85. engine.SetValue("TestSelectorWithoutProps", typeof(TestSelectorWithoutProps));
  86. engine.SetValue("TestGenericClass", typeof(TestGenericClass));
  87. // TPC: the following is the C# equivalent
  88. /*
  89. PlayerChoiceManager playerChoiceManager = new PlayerChoiceManager();
  90. var testSelectorWithoutProps = new TestSelectorWithoutProps();
  91. var result = playerChoiceManager.Store.Select(testSelectorWithoutProps);
  92. */
  93. engine.Execute(@"
  94. const playerChoiceManager = new PlayerChoiceManager();
  95. const testSelectorWithoutProps = new TestSelectorWithoutProps();
  96. const result = playerChoiceManager.Store.Select(testSelectorWithoutProps);
  97. ");
  98. Assert.Equal(true, ReduxStore<PlayerChoiceState>.SelectInvoked);
  99. }
  100. public interface IGenericTest<T>
  101. {
  102. void Foo<U>(U u);
  103. }
  104. public class OpenGenericTest<T> : IGenericTest<T>
  105. {
  106. public void Foo<U>(U u)
  107. {
  108. Console.WriteLine("OpenGenericTest: u: " + u);
  109. }
  110. }
  111. public class ClosedGenericTest : IGenericTest<string>
  112. {
  113. public void Foo<U>(U u)
  114. {
  115. Console.WriteLine("ClosedGenericTest: u: " + u);
  116. }
  117. }
  118. public class TestGenericBaseClass<T>
  119. {
  120. private System.Collections.Generic.List<T> _list = new System.Collections.Generic.List<T>();
  121. public int Count
  122. {
  123. get { return _list.Count; }
  124. }
  125. public void Add(T t)
  126. {
  127. _list.Add(t);
  128. }
  129. }
  130. public class TestGenericClass : TestGenericBaseClass<string>
  131. {
  132. public static bool BarInvoked { get; private set; }
  133. public static bool FooInvoked { get; private set; }
  134. public bool FancyInvoked { get; private set; }
  135. public TestGenericClass()
  136. {
  137. BarInvoked = false;
  138. FooInvoked = false;
  139. FancyInvoked = false;
  140. }
  141. public void Bar(string text)
  142. {
  143. Console.WriteLine("TestGenericClass: Bar: text: " + text);
  144. BarInvoked = true;
  145. }
  146. public void Foo<T>(T t)
  147. {
  148. Console.WriteLine("TestGenericClass: Foo: t: " + t);
  149. FooInvoked = true;
  150. }
  151. public void Fancy<T, U>(T t1, U u, T t2)
  152. {
  153. Console.WriteLine("TestGenericClass: FancyInvoked: t1: " + t1 + "u: " + u + " t2: " + t2);
  154. FancyInvoked = true;
  155. }
  156. }
  157. public interface ISelector<in TInput, out TOutput>
  158. {
  159. }
  160. public interface ISelectorWithoutProps<in TInput, out TOutput> : ISelector<TInput, TOutput>
  161. {
  162. IObservable<TOutput> Apply(TInput input);
  163. }
  164. public sealed partial class ReduxStore<TState> where TState : class, new()
  165. {
  166. public static bool SelectInvoked
  167. {
  168. get;
  169. private set;
  170. }
  171. TState _stateSubject;
  172. public ReduxStore()
  173. {
  174. SelectInvoked = false;
  175. }
  176. public IObservable<TResult> Select<TResult>(ISelectorWithoutProps<TState, TResult> selector, string? optionsStr = null)
  177. {
  178. SelectInvoked = true;
  179. return selector.Apply(_stateSubject);
  180. }
  181. }
  182. public class ManagerWithStore<Klass, TState> where Klass : ManagerWithStore<Klass, TState>, new() where TState : class, new()
  183. {
  184. public ReduxStore<TState> Store { get; private set; } = null;
  185. public ManagerWithStore()
  186. {
  187. Store = new ReduxStore<TState>();
  188. }
  189. }
  190. public class PlayerChoiceState
  191. {
  192. }
  193. public class TestSelectorWithoutProps : ISelectorWithoutProps<PlayerChoiceState, string>
  194. {
  195. public IObservable<string> Apply(PlayerChoiceState input)
  196. {
  197. return null;
  198. }
  199. }
  200. public class PlayerChoiceManager : ManagerWithStore<PlayerChoiceManager, PlayerChoiceState>
  201. {
  202. }
  203. }