ExtensionMethodsTest.cs 11 KB

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