WeakSetMapTests.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. using Jint.Native;
  2. using Jint.Native.Object;
  3. using Jint.Native.WeakMap;
  4. using Jint.Native.WeakSet;
  5. using Jint.Runtime;
  6. namespace Jint.Tests.Runtime;
  7. public class WeakSetMapTests
  8. {
  9. [Fact]
  10. public void WeakMapShouldThrowWhenCalledWithoutNew()
  11. {
  12. var engine = new Engine();
  13. var e = Assert.Throws<JavaScriptException>(() => engine.Execute("{ const m = new WeakMap(); WeakMap.call(m,[]); }"));
  14. Assert.Equal("Constructor WeakMap requires 'new'", e.Message);
  15. }
  16. [Fact]
  17. public void WeakSetShouldThrowWhenCalledWithoutNew()
  18. {
  19. var engine = new Engine();
  20. var e = Assert.Throws<JavaScriptException>(() => engine.Execute("{ const s = new WeakSet(); WeakSet.call(s,[]); }"));
  21. Assert.Equal("Constructor WeakSet requires 'new'", e.Message);
  22. }
  23. public static IEnumerable<object[]> PrimitiveKeys = new TheoryData<JsValue>
  24. {
  25. JsValue.Null,
  26. JsValue.Undefined,
  27. 0,
  28. 100.04,
  29. double.NaN,
  30. "hello",
  31. true,
  32. new JsSymbol("hello")
  33. };
  34. [Theory]
  35. [MemberData(nameof(PrimitiveKeys))]
  36. public void WeakSetAddShouldThrowForPrimitiveKey(JsValue key)
  37. {
  38. var engine = new Engine();
  39. var weakSet = new WeakSetInstance(engine);
  40. var e = Assert.Throws<JavaScriptException>(() => weakSet.WeakSetAdd(key));
  41. Assert.StartsWith("WeakSet value must be an object, got ", e.Message);
  42. Assert.False(weakSet.WeakSetHas(key));
  43. }
  44. [Theory]
  45. [MemberData(nameof(PrimitiveKeys))]
  46. public void WeakMapSetShouldThrowForPrimitiveKey(JsValue key)
  47. {
  48. var engine = new Engine();
  49. var weakMap = new WeakMapInstance(engine);
  50. var e = Assert.Throws<JavaScriptException>(() => weakMap.WeakMapSet(key, new ObjectInstance(engine)));
  51. Assert.StartsWith("WeakMap key must be an object, got ", e.Message);
  52. Assert.False(weakMap.WeakMapHas(key));
  53. }
  54. [Fact]
  55. public void WeakSetWithInteropObject()
  56. {
  57. var engine = new Engine();
  58. engine.SetValue("context", new { Item = new Item { Value = "Test" } });
  59. Assert.Equal(true, engine.Evaluate(@"
  60. var set1 = new WeakSet();
  61. set1.add(context.Item);
  62. return set1.has(context.Item);
  63. "));
  64. Assert.Equal(true, engine.Evaluate(@"
  65. var item = context.Item;
  66. var set2 = new WeakSet();
  67. set2.add(item);
  68. return set2.has(item);
  69. "));
  70. }
  71. [Fact]
  72. public void StringifyWithoutCircularReferences()
  73. {
  74. var parent = new Parent { Value = "Parent" };
  75. var child = new Child { Value = "Child" };
  76. parent.Child = child;
  77. child.Parent = parent;
  78. var engine = new Engine();
  79. engine.SetValue("context", new { Parent = parent });
  80. engine.Execute(@"
  81. function stringifyWithoutCircularReferences(obj, setConstructor) {
  82. var getCircularReplacer = () => {
  83. var seen = new setConstructor();
  84. return (key, value) => {
  85. if (typeof value === ""object"" && value !== null) {
  86. if (seen.has(value)) {
  87. return undefined;
  88. }
  89. seen.add(value);
  90. }
  91. return value;
  92. };
  93. };
  94. return JSON.stringify(obj, getCircularReplacer());
  95. }
  96. ");
  97. // If I use Set, everything works as expected
  98. const string Expected = "{\"Value\":\"Parent\",\"Child\":{\"Value\":\"Child\"}}";
  99. Assert.Equal(Expected, engine.Evaluate("stringifyWithoutCircularReferences(context.Parent, Set)"));
  100. // With WeakSet I get an error
  101. Assert.Equal(Expected, engine.Evaluate("stringifyWithoutCircularReferences(context.Parent, WeakSet)"));
  102. }
  103. private class Item
  104. {
  105. public string Value { get; set; }
  106. }
  107. private class Parent
  108. {
  109. public string Value { get; set; }
  110. public Child Child { get; set; }
  111. }
  112. private class Child
  113. {
  114. public string Value { get; set; }
  115. public Parent Parent { get; set; }
  116. }
  117. }