NullPropagation.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. using Esprima;
  2. using Jint.Native;
  3. using Jint.Runtime;
  4. using Jint.Runtime.Interop;
  5. using Jint.Runtime.References;
  6. using Xunit;
  7. namespace Jint.Tests.Runtime
  8. {
  9. public class NullPropagation
  10. {
  11. public class NullPropagationReferenceResolver : IReferenceResolver
  12. {
  13. public bool TryUnresolvableReference(Engine engine, Reference reference, out JsValue value)
  14. {
  15. value = reference.GetBase();
  16. return true;
  17. }
  18. public bool TryPropertyReference(Engine engine, Reference reference, ref JsValue value)
  19. {
  20. return value.IsNull() || value.IsUndefined();
  21. }
  22. public bool TryGetCallable(Engine engine, object callee, out JsValue value)
  23. {
  24. if (callee is Reference reference)
  25. {
  26. var name = reference.GetReferencedName().AsString();
  27. if (name == "filter")
  28. {
  29. value = new ClrFunctionInstance(engine, "map", (thisObj, values) => engine.Realm.Intrinsics.Array.ArrayCreate(0));
  30. return true;
  31. }
  32. }
  33. value = new ClrFunctionInstance(engine, "anonymous", (thisObj, values) => thisObj);
  34. return true;
  35. }
  36. public bool CheckCoercible(JsValue value)
  37. {
  38. return true;
  39. }
  40. }
  41. [Fact]
  42. public void CanCallFilterOnNull()
  43. {
  44. var engine = new Engine(cfg => cfg.SetReferencesResolver(new NullPropagationReferenceResolver()));
  45. const string Script = @"
  46. var input = {};
  47. var output = { Tags : input.Tags.filter(x=>x!=null) };
  48. ";
  49. engine.Execute(Script);
  50. var output = engine.GetValue("output").AsObject();
  51. Assert.True(output.Get("Tags").IsArray());
  52. }
  53. [Fact]
  54. public void NullPropagationTest()
  55. {
  56. var engine = new Engine(cfg => cfg.SetReferencesResolver(new NullPropagationReferenceResolver()));
  57. const string Script = @"
  58. var input = {
  59. Address : null
  60. };
  61. var address = input.Address;
  62. var city = input.Address.City;
  63. var length = input.Address.City.length;
  64. var output = {
  65. Count1 : input.Address.City.length,
  66. Count2 : this.XYZ.length
  67. };
  68. ";
  69. engine.Execute(Script);
  70. var address = engine.GetValue("address");
  71. var city = engine.GetValue("city");
  72. var length = engine.GetValue("length");
  73. var output = engine.GetValue("output").AsObject();
  74. Assert.Equal(Null.Instance, address);
  75. Assert.Equal(Null.Instance, city);
  76. Assert.Equal(Null.Instance, length);
  77. Assert.Equal(Null.Instance, output.Get("Count1"));
  78. Assert.Equal(Undefined.Instance, output.Get("Count2"));
  79. }
  80. [Fact]
  81. public void NullPropagationFromArg()
  82. {
  83. var engine = new Engine(cfg => cfg.SetReferencesResolver(new NullPropagationReferenceResolver()));
  84. const string Script = @"
  85. function test(arg) {
  86. return arg.Name;
  87. }
  88. function test2(arg) {
  89. return arg.Name.toUpperCase();
  90. }
  91. ";
  92. engine.Execute(Script);
  93. var result = engine.Invoke("test", Null.Instance);
  94. Assert.Equal(Null.Instance, result);
  95. result = engine.Invoke("test2", Null.Instance);
  96. Assert.Equal(Null.Instance, result);
  97. }
  98. [Fact]
  99. public void NullPropagationShouldNotAffectOperators()
  100. {
  101. var engine = new Engine(cfg => cfg.SetReferencesResolver(new NullPropagationReferenceResolver()));
  102. var jsObject = engine.Realm.Intrinsics.Object.Construct(Arguments.Empty);
  103. jsObject.Set("NullField", JsValue.Null);
  104. var script = @"
  105. this.is_nullfield_not_null = this.NullField !== null;
  106. this.is_notnullfield_not_null = this.NotNullField !== null;
  107. this.has_emptyfield_not_null = this.EmptyField !== null;
  108. ";
  109. var wrapperScript = string.Format(@"function ExecutePatchScript(docInner){{ (function(doc){{ {0} }}).apply(docInner); }};", script);
  110. engine.Execute(wrapperScript, new ParserOptions("main.js"));
  111. engine.Invoke("ExecutePatchScript", jsObject);
  112. Assert.False(jsObject.Get("is_nullfield_not_null").AsBoolean());
  113. Assert.True(jsObject.Get("is_notnullfield_not_null").AsBoolean());
  114. Assert.True(jsObject.Get("has_emptyfield_not_null").AsBoolean());
  115. }
  116. }
  117. }