Browse Source

Backport add interop option ThrowOnUnresolvedMember (#1905)

Marko Lahma 1 year ago
parent
commit
a2bd5532fe

+ 23 - 1
Jint.Tests/Runtime/InteropTests.MemberAccess.cs

@@ -237,6 +237,8 @@ namespace Jint.Tests.Runtime
 
 
         public class ClassWithData
         public class ClassWithData
         {
         {
+            public int Age => 42;
+
             public DataType Data { get; set; }
             public DataType Data { get; set; }
 
 
             public class DataType
             public class DataType
@@ -251,10 +253,30 @@ namespace Jint.Tests.Runtime
             var engine = new Engine();
             var engine = new Engine();
 
 
             engine.SetValue("obj", new ClassWithData());
             engine.SetValue("obj", new ClassWithData());
-            engine.Execute(@"obj.Data = { Value: '123' };");
+            engine.Execute("obj.Data = { Value: '123' };");
             var obj = engine.Evaluate("obj").ToObject() as ClassWithData;
             var obj = engine.Evaluate("obj").ToObject() as ClassWithData;
 
 
             Assert.Equal("123", obj?.Data.Value);
             Assert.Equal("123", obj?.Data.Value);
         }
         }
+
+        [Fact]
+        public void CanConfigureStrictAccess()
+        {
+            var engine = new Engine();
+
+            engine.SetValue("obj", new ClassWithData());
+            engine.Evaluate("obj.Age").AsNumber().Should().Be(42);
+            engine.Evaluate("obj.AgeMissing").Should().Be(JsValue.Undefined);
+
+            engine = new Engine(options =>
+            {
+                options.Interop.ThrowOnUnresolvedMember = true;
+            });
+
+            engine.SetValue("obj", new ClassWithData());
+            engine.Evaluate("obj.Age").AsNumber().Should().Be(42);
+
+            engine.Invoking(e => e.Evaluate("obj.AgeMissing")).Should().Throw<MissingMemberException>();
+        }
     }
     }
 }
 }

+ 5 - 0
Jint/Options.cs

@@ -359,6 +359,11 @@ public class Options
         /// Should the Array prototype be attached instead of Object prototype to the wrapped interop objects when type looks suitable. Defaults to true.
         /// Should the Array prototype be attached instead of Object prototype to the wrapped interop objects when type looks suitable. Defaults to true.
         /// </summary>
         /// </summary>
         public bool AttachArrayPrototype { get; set; } = true;
         public bool AttachArrayPrototype { get; set; } = true;
+
+        /// <summary>
+        /// Whether the engine should throw an error when a member is not found on a CLR object. Defaults to false.
+        /// </summary>
+        public bool ThrowOnUnresolvedMember { get; set; }
     }
     }
 
 
     public class ConstraintOptions
     public class ConstraintOptions

+ 5 - 0
Jint/Runtime/Interop/TypeResolver.cs

@@ -262,6 +262,11 @@ namespace Jint.Runtime.Interop
                 }
                 }
             }
             }
 
 
+            if (engine.Options.Interop.ThrowOnUnresolvedMember)
+            {
+                throw new MissingMemberException($"Cannot access property '{memberName}' on type '{type.FullName}");
+            }
+
             return ConstantValueAccessor.NullAccessor;
             return ConstantValueAccessor.NullAccessor;
         }
         }