Explorar o código

Catching exceptions optionally (#374)

Sébastien Ros %!s(int64=8) %!d(string=hai) anos
pai
achega
0c0fa95357

+ 72 - 15
Jint.Tests/Runtime/InteropTests.cs

@@ -1440,25 +1440,82 @@ namespace Jint.Tests.Runtime
         }
 
         [Fact]
-        public void ShouldCatchClrExceptions()
+        public void ShouldNotCatchClrExceptions()
+        {
+            Assert.ThrowsAny<NotSupportedException>(() => new Engine()
+                .SetValue("throwMyException", new Action(() => { throw new NotSupportedException(); }))
+                .Execute(@"
+                    function throwException(){
+                        try {
+                            throwMyException();
+                            return;
+                        } 
+                        catch(e) {
+                            return;
+                        }
+                    }
+                ")
+                .Invoke("throwException")
+            );
+        }
+
+        [Fact]
+        public void ShouldCatchAllClrExceptions()
         {
             string exceptionMessage = "myExceptionMessage";
-            _engine.SetValue("throwMyException", new Action(() => { throw new Exception(exceptionMessage); }));
-                        
-            RunTest(@"
-                function throwException(){
-                try {
-                    throwMyException();
-                    return '';
-                } 
-                catch(e) {
-                    return e.message;
-                }
-            }
-            ");
-            var result = _engine.Invoke("throwException");
+
+            var result = new Engine(o => o.CatchClrExceptions())
+                .SetValue("throwMyException", new Action(() => { throw new Exception(exceptionMessage); }))
+                .Execute(@"
+                    function throwException(){
+                        try {
+                            throwMyException();
+                            return '';
+                        } 
+                        catch(e) {
+                            return e.message;
+                        }
+                    }
+                ")
+                .Invoke("throwException");
+
             Assert.Equal(result.AsString(), exceptionMessage);
         }
 
+        [Fact]
+        public void ShouldCatchSomeExceptions()
+        {
+            string exceptionMessage = "myExceptionMessage";
+
+            var engine = new Engine(o => o.CatchClrExceptions(e => e is NotSupportedException))
+                .SetValue("throwMyException1", new Action(() => { throw new NotSupportedException(exceptionMessage); }))
+                .SetValue("throwMyException2", new Action(() => { throw new ArgumentNullException(); }))
+                .Execute(@"
+                    function throwException1(){
+                        try {
+                            throwMyException1();
+                            return '';
+                        } 
+                        catch(e) {
+                            return e.message;
+                        }
+                    }
+
+                    function throwException2(){
+                        try {
+                            throwMyException2();
+                            return '';
+                        } 
+                        catch(e) {
+                            return e.message;
+                        }
+                    }
+                ");
+
+            var result = engine.Invoke("throwException1");
+
+            Assert.Equal(result.AsString(), exceptionMessage);
+            Assert.Throws<ArgumentNullException>(() => engine.Invoke("throwException2"));
+        }
     }
 }

+ 3 - 0
Jint.Tests/xunit.runner.json

@@ -0,0 +1,3 @@
+{
+  "methodDisplay": "method"
+}

+ 27 - 2
Jint/Options.cs

@@ -20,7 +20,8 @@ namespace Jint
         private TimeSpan _timeoutInterval;
         private CultureInfo _culture = CultureInfo.CurrentCulture;
         private TimeZoneInfo _localTimeZone = TimeZoneInfo.Local;
-        private List<Assembly> _lookupAssemblies = new List<Assembly>(); 
+        private List<Assembly> _lookupAssemblies = new List<Assembly>();
+        private Predicate<Exception> _clrExceptionsHandler;
 
         /// <summary>
         /// When called, doesn't initialize the global scope.
@@ -83,6 +84,28 @@ namespace Jint
             return this;
         }
 
+        /// <summary>
+        /// Exceptions thrown from CLR code are converted to JavaScript errors and
+        /// can be used in at try/catch statement. By default these exceptions are bubbled
+        /// to the CLR host and interrupt the script execution.
+        /// </summary>
+        public Options CatchClrExceptions()
+        {
+            CatchClrExceptions(_ => true);
+            return this;
+        }
+
+        /// <summary>
+        /// Exceptions that thrown from CLR code are converted to JavaScript errors and
+        /// can be used in at try/catch statement. By default these exceptions are bubbled
+        /// to the CLR host and interrupt the script execution.
+        /// </summary>
+        public Options CatchClrExceptions(Predicate<Exception> handler)
+        {
+            _clrExceptionsHandler = handler;
+            return this;
+        }
+
         public Options MaxStatements(int maxStatements = 0)
         {
             _maxStatements = maxStatements;
@@ -131,7 +154,9 @@ namespace Jint
         internal bool _IsDebugMode => _debugMode;
 
         internal bool _IsClrAllowed => _allowClr;
-        
+
+        internal Predicate<Exception> _ClrExceptionsHandler => _clrExceptionsHandler;
+
         internal IList<Assembly> _LookupAssemblies => _lookupAssemblies;
 
         internal IEnumerable<IObjectConverter> _ObjectConverters => _objectConverters;

+ 8 - 1
Jint/Runtime/Interop/DelegateWrapper.cs

@@ -100,7 +100,14 @@ namespace Jint.Runtime.Interop
             catch (TargetInvocationException exception)
             {
                 var meaningfulException = exception.InnerException ?? exception;
-                throw new JavaScriptException(Engine.Error, meaningfulException.Message);
+                var handler = Engine.Options._ClrExceptionsHandler;
+
+                if (handler != null && handler(meaningfulException))
+                {
+                    throw new JavaScriptException(Engine.Error, meaningfulException.Message);
+                }
+
+                throw meaningfulException;         
             }
         }
     }