WeakSetMapTests.cs 4.0 KB

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