WeakSetMapTests.cs 3.9 KB

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