ExtensionMethodsTest.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. using Jint.Native;
  2. using Jint.Tests.Runtime.Domain;
  3. namespace Jint.Tests.Runtime.ExtensionMethods
  4. {
  5. public class ExtensionMethodsTest
  6. {
  7. [Fact]
  8. public void ShouldInvokeObjectExtensionMethod()
  9. {
  10. var person = new Person();
  11. person.Name = "Mickey Mouse";
  12. person.Age = 35;
  13. var options = new Options();
  14. options.AddExtensionMethods(typeof(PersonExtensions));
  15. var engine = new Engine(options);
  16. engine.SetValue("person", person);
  17. var age = engine.Evaluate("person.MultiplyAge(2)").AsInteger();
  18. Assert.Equal(70, age);
  19. }
  20. [Fact]
  21. public void ShouldInvokeStringExtensionMethod()
  22. {
  23. var options = new Options();
  24. options.AddExtensionMethods(typeof(CustomStringExtensions));
  25. var engine = new Engine(options);
  26. var result = engine.Evaluate("\"Hello World!\".Backwards()").AsString();
  27. Assert.Equal("!dlroW olleH", result);
  28. }
  29. [Fact]
  30. public void ShouldInvokeNumberExtensionMethod()
  31. {
  32. var options = new Options();
  33. options.AddExtensionMethods(typeof(DoubleExtensions));
  34. var engine = new Engine(options);
  35. var result = engine.Evaluate("let numb = 27; numb.Add(13)").AsInteger();
  36. Assert.Equal(40, result);
  37. }
  38. [Fact]
  39. public void ShouldPrioritizingNonGenericMethod()
  40. {
  41. var options = new Options();
  42. options.AddExtensionMethods(typeof(CustomStringExtensions));
  43. var engine = new Engine(options);
  44. var result = engine.Evaluate("\"{'name':'Mickey'}\".DeserializeObject()").ToObject() as dynamic;
  45. Assert.Equal("Mickey", result.name);
  46. }
  47. [Fact]
  48. public void PrototypeFunctionsShouldNotBeOverridden()
  49. {
  50. var engine = new Engine(opts =>
  51. {
  52. opts.AddExtensionMethods(typeof(CustomStringExtensions));
  53. });
  54. //uses split function from StringPrototype
  55. var arr = engine.Evaluate("'yes,no'.split(',')").AsArray();
  56. Assert.Equal("yes", arr[0]);
  57. Assert.Equal("no", arr[1]);
  58. //uses split function from CustomStringExtensions
  59. var arr2 = engine.Evaluate("'yes,no'.split(2)").AsArray();
  60. Assert.Equal("ye", arr2[0]);
  61. Assert.Equal("s,no", arr2[1]);
  62. }
  63. [Fact]
  64. public void OverridePrototypeFunctions()
  65. {
  66. var engine = new Engine(opts =>
  67. {
  68. opts.AddExtensionMethods(typeof(OverrideStringPrototypeExtensions));
  69. });
  70. //uses the overridden split function from OverrideStringPrototypeExtensions
  71. var arr = engine.Evaluate("'yes,no'.split(',')").AsArray();
  72. Assert.Equal("YES", arr[0]);
  73. Assert.Equal("NO", arr[1]);
  74. }
  75. [Fact]
  76. public void HasOwnPropertyShouldWorkCorrectlyInPresenceOfExtensionMethods()
  77. {
  78. var person = new Person();
  79. var options = new Options();
  80. options.AddExtensionMethods(typeof(PersonExtensions));
  81. var engine = new Engine(options);
  82. engine.SetValue("person", person);
  83. var isBogusInPerson = engine.Evaluate("'bogus' in person").AsBoolean();
  84. Assert.False(isBogusInPerson);
  85. var propertyValue = engine.Evaluate("person.bogus");
  86. Assert.Equal(JsValue.Undefined, propertyValue);
  87. }
  88. private Engine GetLinqEngine()
  89. {
  90. return new Engine(opts =>
  91. {
  92. opts.AddExtensionMethods(typeof(Enumerable));
  93. });
  94. }
  95. [Fact]
  96. public void LinqExtensionMethodWithoutGenericParameter()
  97. {
  98. var engine = GetLinqEngine();
  99. var intList = new List<int>() { 0, 1, 2, 3 };
  100. engine.SetValue("intList", intList);
  101. var intSumRes = engine.Evaluate("intList.Sum()").AsNumber();
  102. Assert.Equal(6, intSumRes);
  103. }
  104. [Fact]
  105. public void LinqExtensionMethodWithSingleGenericParameter()
  106. {
  107. var engine = GetLinqEngine();
  108. var stringList = new List<string>() { "working", "linq" };
  109. engine.SetValue("stringList", stringList);
  110. var stringSumRes = engine.Evaluate("stringList.Sum(x => x.length)").AsNumber();
  111. Assert.Equal(11, stringSumRes);
  112. }
  113. [Fact]
  114. public void LinqExtensionMethodWithMultipleGenericParameters()
  115. {
  116. var engine = GetLinqEngine();
  117. var stringList = new List<string>() { "working", "linq" };
  118. engine.SetValue("stringList", stringList);
  119. var stringRes = engine.Evaluate("stringList.Select((x) => x + 'a').ToArray().join()").AsString();
  120. Assert.Equal("workinga,linqa", stringRes);
  121. // The method ambiguity resolver is not so smart to choose the Select method with the correct number of parameters
  122. // Thus, the following script will not work as expected.
  123. // stringList.Select((x, i) => x + i).ToArray().join()
  124. }
  125. [Fact]
  126. public void GenericTypeExtension()
  127. {
  128. var options = new Options();
  129. options.AddExtensionMethods(typeof(ObservableExtensions));
  130. var engine = new Engine(options);
  131. engine.SetValue("log", new System.Action<object>(System.Console.WriteLine));
  132. NameObservable observable = new NameObservable();
  133. engine.SetValue("observable", observable);
  134. engine.Evaluate(@"
  135. log('before');
  136. observable.Subscribe((name) =>{
  137. log('observable: subscribe: name: ' + name);
  138. });
  139. observable.UpdateName('foobar');
  140. log('after');
  141. ");
  142. Assert.Equal("foobar", observable.Last);
  143. }
  144. [Fact]
  145. public void GenericExtensionMethodOnClosedGenericType()
  146. {
  147. var options = new Options();
  148. options.AddExtensionMethods(typeof(ObservableExtensions));
  149. var engine = new Engine(options);
  150. engine.SetValue("log", new System.Action<object>(System.Console.WriteLine));
  151. NameObservable observable = new NameObservable();
  152. engine.SetValue("observable", observable);
  153. var result = engine.Evaluate(@"
  154. log('before calling Select');
  155. var result = observable.Select('some text');
  156. log('result: ' + result);
  157. return result;
  158. ");
  159. //System.Console.WriteLine("GenericExtensionMethodOnGenericType: result: " + result + " result.ToString(): " + result.ToString());
  160. Assert.Equal("some text", result);
  161. }
  162. [Fact]
  163. public void GenericExtensionMethodOnClosedGenericType2()
  164. {
  165. var options = new Options();
  166. options.AddExtensionMethods(typeof(ObservableExtensions));
  167. var engine = new Engine(options);
  168. NameObservable observable = new NameObservable();
  169. observable.Where((text) =>
  170. {
  171. System.Console.WriteLine("GenericExtensionMethodOnClosedGenericType2: NameObservable: Where: text: " + text);
  172. return true;
  173. });
  174. engine.SetValue("observable", observable);
  175. var result = engine.Evaluate(@"
  176. var result = observable.Where(function(text){
  177. return true;
  178. });
  179. observable.UpdateName('testing yo');
  180. observable.CommitName();
  181. return result;
  182. ");
  183. var nameObservableResult = result.ToObject() as NameObservable;
  184. Assert.NotNull(nameObservableResult);
  185. Assert.Equal("testing yo", nameObservableResult.Last);
  186. }
  187. [Fact]
  188. public void GenericExtensionMethodOnOpenGenericType()
  189. {
  190. var options = new Options();
  191. options.AddExtensionMethods(typeof(ObservableExtensions));
  192. var engine = new Engine(options);
  193. BaseObservable<string> observable = new BaseObservable<string>();
  194. observable.Where((text) =>
  195. {
  196. System.Console.WriteLine("GenericExtensionMethodOnOpenGenericType: BaseObservable: Where: text: " + text);
  197. return true;
  198. });
  199. engine.SetValue("observable", observable);
  200. var result = engine.Evaluate(@"
  201. var result = observable.Where(function(text){
  202. return true;
  203. });
  204. observable.Update('testing yo');
  205. observable.BroadcastCompleted();
  206. return result;
  207. ");
  208. System.Console.WriteLine("GenericExtensionMethodOnOpenGenericType: result: " + result + " result.ToString(): " + result.ToString());
  209. var baseObservableResult = result.ToObject() as BaseObservable<string>;
  210. System.Console.WriteLine("GenericExtensionMethodOnOpenGenericType: baseObservableResult: " + baseObservableResult);
  211. Assert.NotNull(baseObservableResult);
  212. Assert.Equal("testing yo", baseObservableResult.Last);
  213. }
  214. [Fact]
  215. public void GenericExtensionMethodOnGenericTypeInstantiatedInJs()
  216. {
  217. var options = new Options();
  218. options.AddExtensionMethods(typeof(ObservableExtensions));
  219. var engine = new Engine(options);
  220. engine.SetValue("BaseObservable", typeof(BaseObservable<>));
  221. engine.SetValue("ObservableFactory", typeof(ObservableFactory));
  222. var result = engine.Evaluate(@"
  223. // you can't instantiate generic types in JS (without providing the types as arguments to the constructor) - i.e. not compatible with transpiled typescript
  224. //const observable = new BaseObservable();
  225. //const observable = BaseObservable.GetBoolBaseObservable();
  226. const observable = ObservableFactory.GetBoolBaseObservable();
  227. var result = observable.Where(function(someBool){
  228. return true;
  229. });
  230. observable.Update(false);
  231. observable.BroadcastCompleted();
  232. return result;
  233. ");
  234. var baseObservableResult = result.ToObject() as BaseObservable<bool>;
  235. System.Console.WriteLine("GenericExtensionMethodOnOpenGenericType: baseObservableResult: " + baseObservableResult);
  236. Assert.NotNull(baseObservableResult);
  237. Assert.Equal(false, baseObservableResult.Last);
  238. }
  239. }
  240. }