ShadowRealmTests.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. using Jint.Native.Object;
  2. namespace Jint.Tests.PublicInterface;
  3. public class ShadowRealmTests
  4. {
  5. [Fact]
  6. public void CanUseViaEngineMethods()
  7. {
  8. var engine = new Engine(options => options.EnableModules(GetBasePath()));
  9. var shadowRealm = engine.Intrinsics.ShadowRealm.Construct();
  10. // lexically scoped (let/const) are visible during single call
  11. Assert.Equal(123, shadowRealm.Evaluate("const s = 123; const f = () => s; f();"));
  12. Assert.Equal(true, shadowRealm.Evaluate("typeof f === 'undefined'"));
  13. // vars hold longer
  14. Assert.Equal(456, shadowRealm.Evaluate("function foo() { return 456; }; foo();"));
  15. Assert.Equal(456, shadowRealm.Evaluate("foo();"));
  16. // not visible in global engine though
  17. Assert.Equal(true, engine.Evaluate("typeof foo === 'undefined'"));
  18. // modules
  19. var importValue = shadowRealm.ImportValue("./modules/format-name.js", "formatName");
  20. var formatName = (ObjectInstance) importValue.UnwrapIfPromise();
  21. var result = engine.Invoke(formatName, "John", "Doe").AsString();
  22. Assert.Equal("John Doe", result);
  23. }
  24. [Fact]
  25. public void MultipleShadowRealmsDoNotInterfere()
  26. {
  27. var engine = new Engine(options => options.EnableModules(GetBasePath()));
  28. engine.SetValue("message", "world");
  29. engine.Evaluate("function hello() {return message}");
  30. Assert.Equal("world", engine.Evaluate("hello();"));
  31. var shadowRealm = engine.Intrinsics.ShadowRealm.Construct();
  32. shadowRealm.SetValue("message", "realm 1");
  33. shadowRealm.Evaluate("function hello() {return message}");
  34. var shadowRealm2 = engine.Intrinsics.ShadowRealm.Construct();
  35. shadowRealm2.SetValue("message", "realm 2");
  36. shadowRealm2.Evaluate("function hello() {return message}");
  37. // Act & Assert
  38. Assert.Equal("realm 1", shadowRealm.Evaluate("hello();"));
  39. Assert.Equal("realm 2", shadowRealm2.Evaluate("hello();"));
  40. }
  41. [Fact]
  42. public void MultipleShadowRealm_SettingGlobalVariable_DoNotInterfere()
  43. {
  44. var engine = new Engine(options => options.EnableModules(GetBasePath()));
  45. engine.SetValue("message", "hello ");
  46. engine.Evaluate("(function hello() {message += \"engine\"})();");
  47. var shadowRealm = engine.Intrinsics.ShadowRealm.Construct();
  48. shadowRealm.SetValue("message", "hello ");
  49. shadowRealm.Evaluate("(function hello() {message += \"realm 1\"})();");
  50. var shadowRealm2 = engine.Intrinsics.ShadowRealm.Construct();
  51. shadowRealm2.SetValue("message", "hello ");
  52. shadowRealm2.Evaluate("(function hello() {message += \"realm 2\"})();");
  53. // Act & Assert
  54. Assert.Equal("hello engine", engine.Evaluate("message"));
  55. Assert.Equal("hello realm 1", shadowRealm.Evaluate("message"));
  56. Assert.Equal("hello realm 2", shadowRealm2.Evaluate("message"));
  57. }
  58. [Fact]
  59. public void CanReuseScriptWithShadowRealm()
  60. {
  61. var engine = new Engine(options => options.EnableModules(GetBasePath()));
  62. engine.SetValue("message", "engine");
  63. var shadowRealm = engine.Intrinsics.ShadowRealm.Construct();
  64. shadowRealm.SetValue("message", "realm 1");
  65. var shadowRealm2 = engine.Intrinsics.ShadowRealm.Construct();
  66. shadowRealm2.SetValue("message", "realm 2");
  67. var parser = new Esprima.JavaScriptParser();
  68. var script = parser.ParseScript("(function hello() {return \"hello \" + message})();");
  69. // Act & Assert
  70. Assert.Equal("hello engine", engine.Evaluate(script));
  71. Assert.Equal("hello realm 1", shadowRealm.Evaluate(script));
  72. Assert.Equal("hello realm 2", shadowRealm2.Evaluate(script));
  73. }
  74. private static string GetBasePath()
  75. {
  76. var assemblyDirectory = new DirectoryInfo(AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory);
  77. var current = assemblyDirectory;
  78. var binDirectory = $"{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}";
  79. while (current is not null)
  80. {
  81. if (current.FullName.Contains(binDirectory) || current.Name == "bin")
  82. {
  83. current = current.Parent;
  84. continue;
  85. }
  86. var testDirectory = current.GetDirectories("Jint.Tests").FirstOrDefault();
  87. if (testDirectory == null)
  88. {
  89. current = current.Parent;
  90. continue;
  91. }
  92. // found it
  93. current = testDirectory;
  94. break;
  95. }
  96. if (current is null)
  97. {
  98. throw new NullReferenceException($"Could not find tests base path, assemblyPath: {assemblyDirectory}");
  99. }
  100. return Path.Combine(current.FullName, "Runtime", "Scripts");
  101. }
  102. }