NullPropagation.cs 3.6 KB

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