NullPropagation.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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 reference, out JsValue value)
  23. {
  24. value = new JsValue(
  25. new ClrFunctionInstance(engine, (thisObj, values) => thisObj)
  26. );
  27. return true;
  28. }
  29. public bool CheckCoercible(JsValue value)
  30. {
  31. return true;
  32. }
  33. }
  34. [Fact]
  35. public void NullPropagationTest()
  36. {
  37. var engine = new Engine(cfg => cfg.SetReferencesResolver(new NullPropagationReferenceResolver()));
  38. const string Script = @"
  39. var input = {
  40. Address : null
  41. };
  42. var address = input.Address;
  43. var city = input.Address.City;
  44. var length = input.Address.City.length;
  45. var output = {
  46. Count1 : input.Address.City.length,
  47. Count2 : this.XYZ.length
  48. };
  49. ";
  50. engine.Execute(Script);
  51. var address = engine.GetValue("address");
  52. var city = engine.GetValue("city");
  53. var length = engine.GetValue("length");
  54. var output = engine.GetValue("output").AsObject();
  55. Assert.Equal(Null.Instance, address);
  56. Assert.Equal(Null.Instance, city);
  57. Assert.Equal(Null.Instance, length);
  58. Assert.Equal(Null.Instance, output.Get("Count1"));
  59. Assert.Equal(Undefined.Instance, output.Get("Count2"));
  60. }
  61. [Fact]
  62. public void NullPropagationFromArg()
  63. {
  64. var engine = new Engine(cfg => cfg.SetReferencesResolver(new NullPropagationReferenceResolver()));
  65. const string Script = @"
  66. function test(arg) {
  67. return arg.Name;
  68. }
  69. function test2(arg) {
  70. return arg.Name.toUpperCase();
  71. }
  72. ";
  73. engine.Execute(Script);
  74. var result = engine.Invoke("test", Null.Instance);
  75. Assert.Equal(Null.Instance, result);
  76. result = engine.Invoke("test2", Null.Instance);
  77. Assert.Equal(Null.Instance, result);
  78. }
  79. [Fact]
  80. public void NullPropagationShouldNotAffectOperators()
  81. {
  82. var engine = new Engine(cfg => cfg.SetReferencesResolver(new NullPropagationReferenceResolver()));
  83. var jsObject = engine.Object.Construct(Arguments.Empty);
  84. jsObject.Put("NullField", JsValue.Null, true);
  85. var script = @"
  86. this.is_nullfield_not_null = this.NullField !== null;
  87. this.is_notnullfield_not_null = this.NotNullField !== null;
  88. this.has_emptyfield_not_null = this.EmptyField !== null;
  89. ";
  90. var wrapperScript = string.Format(@"function ExecutePatchScript(docInner){{ (function(doc){{ {0} }}).apply(docInner); }};", script);
  91. engine.Execute(wrapperScript, new ParserOptions("main.js"));
  92. engine.Invoke("ExecutePatchScript", jsObject);
  93. Assert.False(jsObject.Get("is_nullfield_not_null").AsBoolean());
  94. Assert.True(jsObject.Get("is_notnullfield_not_null").AsBoolean());
  95. Assert.True(jsObject.Get("has_emptyfield_not_null").AsBoolean());
  96. }
  97. }
  98. }