2
0

EcmaTest.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Reflection;
  5. using Esprima;
  6. using Esprima.Ast;
  7. using Jint.Runtime;
  8. using Newtonsoft.Json.Linq;
  9. using Xunit;
  10. using Xunit.Abstractions;
  11. namespace Jint.Tests.Ecma
  12. {
  13. public class Chapter6 : EcmaTest
  14. {
  15. [Theory(DisplayName = "Ecma Chapter 6")]
  16. [MemberData(nameof(SourceFiles), parameters: new object[] {"ch06", false })]
  17. [MemberData(nameof(SourceFiles), parameters: new object[] {"ch06", true }, Skip = "Skipped")]
  18. protected void RunTest(SourceFile sourceFile)
  19. {
  20. RunTestInternal(sourceFile);
  21. }
  22. }
  23. public class Chapter7 : EcmaTest
  24. {
  25. [Theory(DisplayName = "Ecma Chapter 7")]
  26. [MemberData(nameof(SourceFiles), parameters: new object[] {"ch07", false })]
  27. [MemberData(nameof(SourceFiles), parameters: new object[] {"ch07", true }, Skip = "Skipped")]
  28. protected void RunTest(SourceFile sourceFile)
  29. {
  30. RunTestInternal(sourceFile);
  31. }
  32. }
  33. public class Chapter8 : EcmaTest
  34. {
  35. [Theory(DisplayName = "Ecma Chapter 8")]
  36. [MemberData(nameof(SourceFiles), parameters: new object[] {"ch08", false })]
  37. [MemberData(nameof(SourceFiles), parameters: new object[] {"ch08", true }, Skip = "Skipped")]
  38. protected void RunTest(SourceFile sourceFile)
  39. {
  40. RunTestInternal(sourceFile);
  41. }
  42. }
  43. public class Chapter9 : EcmaTest
  44. {
  45. [Theory(DisplayName = "Ecma Chapter 9")]
  46. [MemberData(nameof(SourceFiles), parameters: new object[] {"ch09", false })]
  47. [MemberData(nameof(SourceFiles), parameters: new object[] {"ch09", true }, Skip = "Skipped")]
  48. protected void RunTest(SourceFile sourceFile)
  49. {
  50. RunTestInternal(sourceFile);
  51. }
  52. }
  53. public class Chapter10 : EcmaTest
  54. {
  55. [Theory(DisplayName = "Ecma Chapter 10")]
  56. [MemberData(nameof(SourceFiles), parameters: new object[] {"ch10", false })]
  57. [MemberData(nameof(SourceFiles), parameters: new object[] {"ch10", true }, Skip = "Skipped")]
  58. protected void RunTest(SourceFile sourceFile)
  59. {
  60. RunTestInternal(sourceFile);
  61. }
  62. }
  63. public class Chapter11 : EcmaTest
  64. {
  65. [Theory(DisplayName = "Ecma Chapter 11")]
  66. [MemberData(nameof(SourceFiles), parameters: new object[] {"ch11", false })]
  67. [MemberData(nameof(SourceFiles), parameters: new object[] {"ch11", true }, Skip = "Skipped")]
  68. protected void RunTest(SourceFile sourceFile)
  69. {
  70. RunTestInternal(sourceFile);
  71. }
  72. }
  73. public class Chapter12 : EcmaTest
  74. {
  75. [Theory(DisplayName = "Ecma Chapter 12")]
  76. [MemberData(nameof(SourceFiles), parameters: new object[] {"ch12", false })]
  77. [MemberData(nameof(SourceFiles), parameters: new object[] {"ch12", true }, Skip = "Skipped")]
  78. protected void RunTest(SourceFile sourceFile)
  79. {
  80. RunTestInternal(sourceFile);
  81. }
  82. }
  83. public class Chapter13 : EcmaTest
  84. {
  85. [Theory(DisplayName = "Ecma Chapter 13")]
  86. [MemberData(nameof(SourceFiles), parameters: new object[] {"ch13", false })]
  87. [MemberData(nameof(SourceFiles), parameters: new object[] {"ch13", true }, Skip = "Skipped")]
  88. protected void RunTest(SourceFile sourceFile)
  89. {
  90. RunTestInternal(sourceFile);
  91. }
  92. }
  93. public class Chapter14 : EcmaTest
  94. {
  95. [Theory(DisplayName = "Ecma Chapter 14")]
  96. [MemberData(nameof(SourceFiles), parameters: new object[] {"ch14", false })]
  97. [MemberData(nameof(SourceFiles), parameters: new object[] {"ch14", true }, Skip = "Skipped")]
  98. protected void RunTest(SourceFile sourceFile)
  99. {
  100. RunTestInternal(sourceFile);
  101. }
  102. }
  103. public class Chapter15 : EcmaTest
  104. {
  105. // couple of tests are really slow, run in parallel
  106. internal const string SlowTest1 = "ch15/15.1/15.1.3/15.1.3.1/S15.1.3.1_A2.5_T1.js";
  107. internal const string SlowTest2 = "ch15/15.1/15.1.3/15.1.3.1/S15.1.3.1_A2.5_T1.js";
  108. [Theory(DisplayName = "Ecma Chapter 15")]
  109. [MemberData(nameof(SourceFiles), parameters: new object[] {"ch15", false })]
  110. [MemberData(nameof(SourceFiles), parameters: new object[] {"ch15", true }, Skip = "Skipped")]
  111. protected void RunTest(SourceFile sourceFile)
  112. {
  113. if (sourceFile.Source == SlowTest1 || sourceFile.Source == SlowTest2)
  114. {
  115. return;
  116. }
  117. RunTestInternal(sourceFile);
  118. }
  119. }
  120. public class Chapter15_SlowTest1 : EcmaTest
  121. {
  122. [Theory(DisplayName = "Ecma Chapter 15 Slow Test 1")]
  123. [MemberData(nameof(SourceFiles), parameters: new object[] {Chapter15.SlowTest1, false })]
  124. [MemberData(nameof(SourceFiles), parameters: new object[] {Chapter15.SlowTest1, true }, Skip = "Skipped")]
  125. protected void RunTest(SourceFile sourceFile)
  126. {
  127. RunTestInternal(sourceFile);
  128. }
  129. }
  130. public class Chapter15_SlowTest2 : EcmaTest
  131. {
  132. [Theory(DisplayName = "Ecma Chapter 15 Slow Test 2")]
  133. [MemberData(nameof(SourceFiles), parameters: new object[] {Chapter15.SlowTest2, false })]
  134. [MemberData(nameof(SourceFiles), parameters: new object[] {Chapter15.SlowTest2, true }, Skip = "Skipped")]
  135. protected void RunTest(SourceFile sourceFile)
  136. {
  137. RunTestInternal(sourceFile);
  138. }
  139. }
  140. public abstract class EcmaTest
  141. {
  142. private static string _lastError;
  143. private static Script staSource;
  144. private static readonly string BasePath;
  145. private static readonly List<SourceFile> _sourceFiles = new List<SourceFile>(10_000);
  146. private static readonly TimeZoneInfo _pacificTimeZone;
  147. static EcmaTest()
  148. {
  149. try
  150. {
  151. _pacificTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
  152. }
  153. catch (TimeZoneNotFoundException)
  154. {
  155. // https://stackoverflow.com/questions/47848111/how-should-i-fetch-timezoneinfo-in-a-platform-agnostic-way
  156. // should be natively supported soon https://github.com/dotnet/runtime/issues/18644
  157. _pacificTimeZone = TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles");
  158. }
  159. var assemblyPath = new Uri(typeof(EcmaTest).GetTypeInfo().Assembly.Location).LocalPath;
  160. var assemblyDirectory = new FileInfo(assemblyPath).Directory;
  161. BasePath = assemblyDirectory.Parent.Parent.Parent.FullName;
  162. var localPath = assemblyDirectory.Parent.Parent.Parent.FullName;
  163. var fixturesPath = Path.Combine(localPath, "TestCases/alltests.json");
  164. var content = File.ReadAllText(fixturesPath);
  165. var doc = JArray.Parse(content);
  166. var path = Path.Combine(localPath, "TestCases");
  167. foreach (var jToken in doc)
  168. {
  169. _sourceFiles.Add(new SourceFile((JObject) jToken, path));
  170. }
  171. }
  172. protected void RunTestInternal(SourceFile sourceFile)
  173. {
  174. var fullName = Path.Combine(BasePath, sourceFile.BasePath, sourceFile.Source);
  175. if (!File.Exists(fullName))
  176. {
  177. throw new ArgumentException("Could not find source file: " + fullName);
  178. }
  179. string code = File.ReadAllText(fullName);
  180. var negative = code.Contains("@negative");
  181. RunTestCode(code, negative);
  182. }
  183. protected void RunTestCode(string code, bool negative)
  184. {
  185. _lastError = null;
  186. //NOTE: The Date tests in test262 assume the local timezone is Pacific Standard Time
  187. var engine = new Engine(cfg => cfg
  188. .LocalTimeZone(_pacificTimeZone)
  189. );
  190. // loading driver
  191. if (staSource == null)
  192. {
  193. var driverFilename = Path.Combine(BasePath, "TestCases/sta.js");
  194. var source = File.ReadAllText(driverFilename);
  195. staSource = new JavaScriptParser(source, new ParserOptions("sta.js")).ParseScript();
  196. }
  197. engine.Execute(staSource);
  198. if (negative)
  199. {
  200. try
  201. {
  202. engine.Execute(code);
  203. Assert.True(_lastError != null);
  204. Assert.False(true);
  205. }
  206. catch
  207. {
  208. // exception is expected
  209. }
  210. }
  211. else
  212. {
  213. try
  214. {
  215. engine.Execute(code);
  216. }
  217. catch (JavaScriptException j)
  218. {
  219. _lastError = TypeConverter.ToString(j.Error);
  220. }
  221. catch (Exception e)
  222. {
  223. _lastError = e.ToString();
  224. }
  225. Assert.Null(_lastError);
  226. }
  227. }
  228. public static IEnumerable<object[]> SourceFiles(string prefix, bool skipped)
  229. {
  230. var results = new List<object[]>();
  231. foreach(var sourceFile in _sourceFiles)
  232. {
  233. if (prefix != null && !sourceFile.Source.StartsWith(prefix))
  234. {
  235. continue;
  236. }
  237. if (sourceFile.Skip
  238. && (sourceFile.Reason == "part of new test suite"
  239. || sourceFile.Reason.IndexOf("configurable", StringComparison.OrdinalIgnoreCase) > -1))
  240. {
  241. // we consider this obsolete and we don't need to process at all
  242. continue;
  243. }
  244. if (skipped == sourceFile.Skip)
  245. {
  246. results.Add(new object [] { sourceFile });
  247. }
  248. }
  249. return results;
  250. }
  251. public class SourceFile : IXunitSerializable
  252. {
  253. public SourceFile()
  254. {
  255. }
  256. public SourceFile(JObject node, string basePath)
  257. {
  258. Skip = node["skip"].Value<bool>();
  259. Source = node["source"].ToString();
  260. Reason = node["reason"].ToString();
  261. BasePath = basePath;
  262. }
  263. public string Source { get; set; }
  264. public bool Skip { get; set; }
  265. public string Reason { get; set; }
  266. public string BasePath { get; set; }
  267. public void Deserialize(IXunitSerializationInfo info)
  268. {
  269. Skip = info.GetValue<bool>(nameof(Skip));
  270. Source = info.GetValue<string>(nameof(Source));
  271. Reason = info.GetValue<string>(nameof(Reason));
  272. BasePath = info.GetValue<string>(nameof(BasePath));
  273. }
  274. public void Serialize(IXunitSerializationInfo info)
  275. {
  276. info.AddValue(nameof(Skip), Skip);
  277. info.AddValue(nameof(Source), Source);
  278. info.AddValue(nameof(Reason), Reason);
  279. info.AddValue(nameof(BasePath), BasePath);
  280. }
  281. public override string ToString()
  282. {
  283. return Source;
  284. }
  285. }
  286. }
  287. }