Forráskód Böngészése

Fix for CLR exceptions inside TypeReference instances not being caught by JS code (#394)

Fixes #393
Sérgio Fonseca 8 éve
szülő
commit
a216ad328b

+ 27 - 0
Jint.Tests/Runtime/Domain/Thrower.cs

@@ -0,0 +1,27 @@
+using System;
+
+namespace Jint.Tests.Runtime.Domain
+{
+    public class Thrower
+    {
+        public void ThrowArgumentNullException()
+        {
+            throw new ArgumentNullException();
+        }
+
+        public void ThrowExceptionWithMessage(string message)
+        {
+            throw new Exception(message);
+        }
+
+        public void ThrowNotSupportedException()
+        {
+            throw new NotSupportedException();
+        }
+
+        public void ThrowNotSupportedExceptionWithMessage(string message)
+        {
+            throw new NotSupportedException(message);
+        }
+    }
+}

+ 57 - 13
Jint.Tests/Runtime/InteropTests.cs

@@ -1442,10 +1442,11 @@ namespace Jint.Tests.Runtime
         [Fact]
         public void ShouldNotCatchClrExceptions()
         {
-            Assert.ThrowsAny<NotSupportedException>(() => new Engine()
+            var engine = new Engine()
                 .SetValue("throwMyException", new Action(() => { throw new NotSupportedException(); }))
+                .SetValue("Thrower", typeof(Thrower))
                 .Execute(@"
-                    function throwException(){
+                    function throwException1(){
                         try {
                             throwMyException();
                             return;
@@ -1454,9 +1455,20 @@ namespace Jint.Tests.Runtime
                             return;
                         }
                     }
-                ")
-                .Invoke("throwException")
-            );
+
+                    function throwException2(){
+                        try {
+                            new Thrower().ThrowNotSupportedException();
+                            return;
+                        } 
+                        catch(e) {
+                            return;
+                        }
+                    }
+                ");
+
+            Assert.ThrowsAny<NotSupportedException>(() => engine.Invoke("throwException1"));
+            Assert.ThrowsAny<NotSupportedException>(() => engine.Invoke("throwException2"));
         }
 
         [Fact]
@@ -1464,10 +1476,11 @@ namespace Jint.Tests.Runtime
         {
             string exceptionMessage = "myExceptionMessage";
 
-            var result = new Engine(o => o.CatchClrExceptions())
+            var engine = new Engine(o => o.CatchClrExceptions())
                 .SetValue("throwMyException", new Action(() => { throw new Exception(exceptionMessage); }))
+                .SetValue("Thrower", typeof(Thrower))
                 .Execute(@"
-                    function throwException(){
+                    function throwException1(){
                         try {
                             throwMyException();
                             return '';
@@ -1476,10 +1489,20 @@ namespace Jint.Tests.Runtime
                             return e.message;
                         }
                     }
-                ")
-                .Invoke("throwException");
 
-            Assert.Equal(result.AsString(), exceptionMessage);
+                    function throwException2(){
+                        try {
+                            new Thrower().ThrowExceptionWithMessage('myExceptionMessage');
+                            return;
+                        } 
+                        catch(e) {
+                            return e.message;
+                        }
+                    }
+                ");
+
+            Assert.Equal(engine.Invoke("throwException1").AsString(), exceptionMessage);
+            Assert.Equal(engine.Invoke("throwException2").AsString(), exceptionMessage);
         }
 
         [Fact]
@@ -1490,6 +1513,7 @@ namespace Jint.Tests.Runtime
             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(); }))
+                .SetValue("Thrower", typeof(Thrower))
                 .Execute(@"
                     function throwException1(){
                         try {
@@ -1510,12 +1534,32 @@ namespace Jint.Tests.Runtime
                             return e.message;
                         }
                     }
-                ");
 
-            var result = engine.Invoke("throwException1");
+                    function throwException3(){
+                        try {
+                            new Thrower().ThrowNotSupportedExceptionWithMessage('myExceptionMessage');
+                            return '';
+                        } 
+                        catch(e) {
+                            return e.message;
+                        }
+                    }
 
-            Assert.Equal(result.AsString(), exceptionMessage);
+                    function throwException4(){
+                        try {
+                            new Thrower().ThrowArgumentNullException();
+                            return '';
+                        } 
+                        catch(e) {
+                            return e.message;
+                        }
+                    }
+                ");
+            
+            Assert.Equal(engine.Invoke("throwException1").AsString(), exceptionMessage);
             Assert.Throws<ArgumentNullException>(() => engine.Invoke("throwException2"));
+            Assert.Equal(engine.Invoke("throwException3").AsString(), exceptionMessage);
+            Assert.Throws<ArgumentNullException>(() => engine.Invoke("throwException4"));
         }
     }
 }

+ 7 - 0
Jint/Native/JsValue.cs

@@ -328,6 +328,13 @@ namespace Jint.Native
                 return new JsValue(instance);
             }
 
+            var type = value as Type;
+            if(type != null)
+            {
+                var typeReference = TypeReference.CreateTypeReference(engine, type);
+                return new JsValue(typeReference);
+            }
+
             var a = value as System.Array;
             if (a != null)
             {

+ 16 - 1
Jint/Runtime/Interop/MethodInfoFunctionInstance.cs

@@ -84,7 +84,22 @@ namespace Jint.Runtime.Interop
                 }
 
                 // todo: cache method info
-                return JsValue.FromObject(Engine, method.Invoke(thisObject.ToObject(), parameters.ToArray()));
+                try
+                {
+                    return JsValue.FromObject(Engine, method.Invoke(thisObject.ToObject(), parameters.ToArray()));
+                }
+                catch (TargetInvocationException exception)
+                {
+                    var meaningfulException = exception.InnerException ?? exception;
+                    var handler = Engine.Options._ClrExceptionsHandler;
+
+                    if (handler != null && handler(meaningfulException))
+                    {
+                        throw new JavaScriptException(Engine.Error, meaningfulException.Message);
+                    }
+
+                    throw meaningfulException;
+                }
             }
 
             throw new JavaScriptException(Engine.TypeError, "No public methods with the specified arguments were found.");