2
0
Эх сурвалжийг харах

allow nullable delegate parameters to be excluded from the JS function call

Brian Beard 10 жил өмнө
parent
commit
9fda44a443

+ 51 - 0
Jint.Tests/Runtime/InteropTests.cs

@@ -74,6 +74,56 @@ namespace Jint.Tests.Runtime
             ");
         }
 
+        [Fact]
+        public void DelegateWithNullableParameterCanBePassedAnUndefined()
+        {
+            _engine.SetValue("isnull", new Func<double?, bool>(x => x == null));
+
+            RunTest(@"
+                assert(isnull(undefined) === true);
+            ");
+        }
+
+        [Fact]
+        public void DelegateWithObjectParameterCanBePassedAnUndefined()
+        {
+            _engine.SetValue("isnull", new Func<object, bool>(x => x == null));
+
+            RunTest(@"
+                assert(isnull(undefined) === true);
+            ");
+        }
+
+        [Fact]
+        public void DelegateWithNullableParameterCanBeExcluded()
+        {
+            _engine.SetValue("isnull", new Func<double?, bool>(x => x == null));
+
+            RunTest(@"
+                assert(isnull() === true);
+            ");
+        }
+
+        [Fact]
+        public void DelegateWithObjectParameterCanBeExcluded()
+        {
+            _engine.SetValue("isnull", new Func<object, bool>(x => x == null));
+
+            RunTest(@"
+                assert(isnull() === true);
+            ");
+        }
+
+        [Fact]
+        public void ExtraParametersAreIgnored()
+        {
+            _engine.SetValue("passNumber", new Func<int, int>(x => x));
+
+            RunTest(@"
+                assert(passNumber(123,'test',{},[],null) === 123);
+            ");
+        }
+
         private delegate string callParams(params object[] values);
         private delegate string callArgumentAndParams(string firstParam, params object[] values);
 
@@ -92,6 +142,7 @@ namespace Jint.Tests.Runtime
                 assert(callArgumentAndParams('a','1','2','3') === 'a:1,2,3');
                 assert(callArgumentAndParams('a','1') === 'a:1');
                 assert(callArgumentAndParams('a') === 'a:');
+                assert(callArgumentAndParams() === ':');
             ");
         }
 

+ 16 - 9
Jint/Runtime/Interop/DelegateWrapper.cs

@@ -27,11 +27,13 @@ namespace Jint.Runtime.Interop
             int delegateArgumentsCount = parameterInfos.Length;
             int delegateNonParamsArgumentsCount = delegateContainsParamsArgument ? delegateArgumentsCount - 1 : delegateArgumentsCount;
 
-            var parameters = new object[delegateArgumentsCount];
+            int jsArgumentsCount = jsArguments.Length;
+            int jsArgumentsWithoutParamsCount = Math.Min(jsArgumentsCount, delegateNonParamsArgumentsCount);
 
+            var parameters = new object[delegateArgumentsCount];
 
             // convert non params parameter to expected types
-            for (var i = 0; i < delegateNonParamsArgumentsCount; i++)
+            for (var i = 0; i < jsArgumentsWithoutParamsCount; i++)
             {
                 var parameterType = parameterInfos[i].ParameterType;
 
@@ -49,7 +51,7 @@ namespace Jint.Runtime.Interop
             }
 
             // assign null to parameters not provided
-            for (var i = jsArguments.Length; i < delegateNonParamsArgumentsCount; i++)
+            for (var i = jsArgumentsWithoutParamsCount; i < delegateNonParamsArgumentsCount; i++)
             {
                 if (parameterInfos[i].ParameterType.IsValueType)
                 {
@@ -64,24 +66,29 @@ namespace Jint.Runtime.Interop
             // assign params to array and converts each objet to expected type
             if(delegateContainsParamsArgument)
             {
-                object[] paramsParameter = new object[jsArguments.Length - delegateNonParamsArgumentsCount];
-                var paramsParameterType = parameterInfos[delegateArgumentsCount -1].ParameterType.GetElementType();
+                int paramsArgumentIndex = delegateArgumentsCount - 1;
+                int paramsCount = Math.Max(0, jsArgumentsCount - delegateNonParamsArgumentsCount);
 
-                for (var i = delegateNonParamsArgumentsCount; i < jsArguments.Length; i++)
+                object[] paramsParameter = new object[paramsCount];
+                var paramsParameterType = parameterInfos[paramsArgumentIndex].ParameterType.GetElementType();
+
+                for (var i = paramsArgumentIndex; i < jsArgumentsCount; i++)
                 {
+                    var paramsIndex = i - paramsArgumentIndex;
+
                     if (paramsParameterType == typeof(JsValue))
                     {
-                        paramsParameter[i - delegateNonParamsArgumentsCount] = jsArguments[i];
+                        paramsParameter[paramsIndex] = jsArguments[i];
                     }
                     else
                     {
-                        paramsParameter[i - delegateNonParamsArgumentsCount] = Engine.ClrTypeConverter.Convert(
+                        paramsParameter[paramsIndex] = Engine.ClrTypeConverter.Convert(
                             jsArguments[i].ToObject(),
                             paramsParameterType,
                             CultureInfo.InvariantCulture);
                     }                    
                 }
-                parameters[delegateNonParamsArgumentsCount] = paramsParameter;
+                parameters[paramsArgumentIndex] = paramsParameter;
             }
 
             return JsValue.FromObject(Engine, _d.DynamicInvoke(parameters));