[browser][wasm][tests] JavaScript Interop Marshal tests (#38917)
authorKenneth Pouncey <kjpou@pt.lu>
Mon, 13 Jul 2020 12:31:39 +0000 (14:31 +0200)
committerGitHub <noreply@github.com>
Mon, 13 Jul 2020 12:31:39 +0000 (14:31 +0200)
* [browser][wasm][tests] JavaScript Interop Marshal tests

* Add primitive and string marshal tests

* Add tests for object identity across marshaling calls for JS object and managed objects.

- Tests to make sure the objects stay the same and are not created new.

* Add tests and code cleanup

* Add marshal of js function tests

* Add delegate marshaling test

* Fix License text

* More tests

* Fix an error where `mono_method_resolve` is called before BINDING object was initialized

* Add more marshal tests

* Add more tests

* Address review comments

src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.Tests.csproj
src/libraries/System.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/HelperMarshal.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/MarshalTests.cs [new file with mode: 0644]
src/mono/wasm/runtime-test.js
src/mono/wasm/runtime/binding_support.js

index 959eefad70b6db15d96557d23307deae1d125b41..0bb06264f93e8356006b4ea12a58325b3697d799 100644 (file)
@@ -13,5 +13,7 @@
     <Compile Include="System\Runtime\InteropServices\JavaScript\TypedArrayTests.cs" />
     <Compile Include="System\Runtime\InteropServices\JavaScript\ArrayTests.cs" />
     <!-- <Compile Include="System\Runtime\InteropServices\JavaScript\MapTests.cs" /> -->
+    <Compile Include="System\Runtime\InteropServices\JavaScript\MarshalTests.cs" />
+    <Compile Include="System\Runtime\InteropServices\JavaScript\HelperMarshal.cs" />
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/HelperMarshal.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/HelperMarshal.cs
new file mode 100644 (file)
index 0000000..15771c3
--- /dev/null
@@ -0,0 +1,336 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Runtime.InteropServices.JavaScript;
+using System.Collections.Generic;
+using System.Linq;
+using Xunit;
+
+namespace System.Runtime.InteropServices.JavaScript.Tests
+{
+    public static class HelperMarshal
+    {
+        internal const string INTEROP_CLASS = "[System.Runtime.InteropServices.JavaScript.Tests]System.Runtime.InteropServices.JavaScript.Tests.HelperMarshal:";
+        internal static int _i32Value;
+        private static void InvokeI32(int a, int b)
+        {
+            _i32Value = a + b;
+        }
+
+        internal static float _f32Value;
+        private static void InvokeFloat(float f)
+        {
+            _f32Value = f;
+        }
+
+        internal static double _f64Value;
+        private static void InvokeDouble(double d)
+        {
+            _f64Value = d;
+        }
+
+        internal static long _i64Value;
+        private static void InvokeLong(long l)
+        {
+            _i64Value = l;
+        }
+
+        internal static byte[] _byteBuffer;
+        private static void MarshalArrayBuffer(ArrayBuffer buffer)
+        {
+            using (var bytes = new Uint8Array(buffer))
+                _byteBuffer = bytes.ToArray();
+        }
+
+        private static void MarshalByteBuffer(Uint8Array buffer)
+        {
+            _byteBuffer = buffer.ToArray();
+        }
+
+        internal static int[] _intBuffer;
+        private static void MarshalArrayBufferToInt32Array(ArrayBuffer buffer)
+        {
+            using (var ints = new Int32Array(buffer))
+                _intBuffer = ints.ToArray();
+        }
+
+        internal static string _stringResource;
+        private static void InvokeString(string s)
+        {
+            _stringResource = s;
+        }
+
+        internal static string _marshalledString;
+        private static string InvokeMarshalString()
+        {
+            _marshalledString = "Hic Sunt Dracones";
+            return _marshalledString;
+        }
+
+        internal static object _object1;
+        private static object InvokeObj1(object obj)
+        {
+            _object1 = obj;
+            return obj;
+        }
+
+        internal static object _object2;
+        private static object InvokeObj2(object obj)
+        {
+            _object2 = obj;
+            return obj;
+        }
+
+        internal static object _marshalledObject;
+        private static object InvokeMarshalObj()
+        {
+            _marshalledObject = new object();
+            return _marshalledObject;
+        }
+
+        internal static int _valOne, _valTwo;
+        private static void ManipulateObject(JSObject obj)
+        {
+            _valOne = (int)obj.Invoke("inc");
+            _valTwo = (int)obj.Invoke("add", 20);
+        }
+
+        internal static object[] _jsObjects;
+        private static void MinipulateObjTypes(JSObject obj)
+        {
+            _jsObjects = new object[4];
+            _jsObjects[0] = obj.Invoke("return_int");
+            _jsObjects[1] = obj.Invoke("return_double");
+            _jsObjects[2] = obj.Invoke("return_string");
+            _jsObjects[3] = obj.Invoke("return_bool");
+        }
+
+        internal static int _jsAddFunctionResult;
+        private static void UseFunction(JSObject obj)
+        {
+            _jsAddFunctionResult = (int)obj.Invoke("call", null, 10, 20);
+        }
+
+        internal static int _jsAddAsFunctionResult;
+        private static void UseAsFunction(Function func)
+        {
+            _jsAddAsFunctionResult = (int)func.Call(null, 20, 30);
+        }
+
+        internal static int _functionResultValue;
+        private static Func<int, int, int> CreateFunctionDelegate()
+        {
+            return (a, b) =>
+            {
+                _functionResultValue = a + b;
+                return _functionResultValue;
+            };
+        }
+
+        internal static int _intValue;
+        private static void InvokeInt(int value)
+        {
+            _intValue = value;
+        }
+
+        internal static IntPtr _intPtrValue;
+        private static void InvokeIntPtr(IntPtr i)
+        {
+            _intPtrValue = i;
+        }
+
+        internal static IntPtr _marshaledIntPtrValue;
+        private static IntPtr InvokeMarshalIntPtr()
+        {
+            _marshaledIntPtrValue = (IntPtr)42;
+            return _marshaledIntPtrValue;
+        }
+
+        internal static object[] _jsProperties;
+        private static void RetrieveObjectProperties(JSObject obj)
+        {
+            _jsProperties = new object[4];
+            _jsProperties[0] = obj.GetObjectProperty("myInt");
+            _jsProperties[1] = obj.GetObjectProperty("myDouble");
+            _jsProperties[2] = obj.GetObjectProperty("myString");
+            _jsProperties[3] = obj.GetObjectProperty("myBoolean");
+        }
+
+        private static void PopulateObjectProperties(JSObject obj, bool createIfNotExist)
+        {
+            _jsProperties = new object[4];
+            obj.SetObjectProperty("myInt", 100, createIfNotExist);
+            obj.SetObjectProperty("myDouble", 4.5, createIfNotExist);
+            obj.SetObjectProperty("myString", "qwerty", createIfNotExist);
+            obj.SetObjectProperty("myBoolean", true, createIfNotExist);
+        }
+
+        private static void MarshalByteBufferToInts(ArrayBuffer buffer)
+        {
+            using (var bytes = new Uint8Array(buffer))
+            {
+                var byteBuffer = bytes.ToArray();
+                _intBuffer = new int[bytes.Length / sizeof(int)];
+                for (int i = 0; i < bytes.Length; i += sizeof(int))
+                    _intBuffer[i / sizeof(int)] = BitConverter.ToInt32(byteBuffer, i);
+            }
+        }
+
+        private static void MarshalInt32Array(Int32Array buffer)
+        {
+            _intBuffer = buffer.ToArray();
+        }
+
+        internal static float[] _floatBuffer;
+        private static void MarshalFloat32Array(Float32Array buffer)
+        {
+            _floatBuffer = buffer.ToArray();
+        }
+        private static void MarshalArrayBufferToFloat32Array(ArrayBuffer buffer)
+        {
+            using (var floats = new Float32Array(buffer))
+                _floatBuffer = floats.ToArray();
+        }
+
+        internal static double[] _doubleBuffer;
+        private static void MarshalFloat64Array(Float64Array buffer)
+        {
+            _doubleBuffer = buffer.ToArray();
+        }
+
+        private static void MarshalArrayBufferToFloat64Array(ArrayBuffer buffer)
+        {
+            using (var doubles = new Float64Array(buffer))
+                _doubleBuffer = doubles.ToArray();
+        }
+
+        private static void MarshalByteBufferToDoubles(ArrayBuffer buffer)
+        {
+            using (var doubles = new Float64Array(buffer))
+                _doubleBuffer = doubles.ToArray();
+        }
+
+        private static void SetTypedArraySByte(JSObject obj)
+        {
+            sbyte[] buffer = Enumerable.Repeat((sbyte)0x20, 11).ToArray();
+            obj.SetObjectProperty("typedArray", Int8Array.From(buffer));
+        }
+
+        internal static sbyte[] _taSByte;
+        private static void GetTypedArraySByte(JSObject obj)
+        {
+            _taSByte = ((Int8Array)obj.GetObjectProperty("typedArray")).ToArray();
+        }
+
+        private static void SetTypedArrayByte(JSObject obj)
+        {
+            var dragons = "hic sunt dracones";
+            byte[] buffer = System.Text.Encoding.ASCII.GetBytes(dragons);
+            obj.SetObjectProperty("dracones", Uint8Array.From(buffer));
+        }
+
+        internal static byte[] _taByte;
+        private static void GetTypedArrayByte(JSObject obj)
+        {
+            _taByte = ((Uint8Array)obj.GetObjectProperty("dracones")).ToArray();
+        }
+
+        private static void SetTypedArrayShort(JSObject obj)
+        {
+            short[] buffer = Enumerable.Repeat((short)0x20, 13).ToArray();
+            obj.SetObjectProperty("typedArray", Int16Array.From(buffer));
+        }
+
+        internal static short[] _taShort;
+        private static void GetTypedArrayShort(JSObject obj)
+        {
+            _taShort = ((Int16Array)obj.GetObjectProperty("typedArray")).ToArray();
+        }
+
+        private static void SetTypedArrayUShort(JSObject obj)
+        {
+            ushort[] buffer = Enumerable.Repeat((ushort)0x20, 14).ToArray();
+            obj.SetObjectProperty("typedArray", Uint16Array.From(buffer));
+        }
+
+        internal static ushort[] _taUShort;
+        private static void GetTypedArrayUShort(JSObject obj)
+        {
+            _taUShort = ((Uint16Array)obj.GetObjectProperty("typedArray")).ToArray();
+        }
+
+        private static void SetTypedArrayInt(JSObject obj)
+        {
+            int[] buffer = Enumerable.Repeat((int)0x20, 15).ToArray();
+            obj.SetObjectProperty("typedArray", Int32Array.From(buffer));
+        }
+
+        internal static int[] _taInt;
+        private static void GetTypedArrayInt(JSObject obj)
+        {
+            _taInt = ((Int32Array)obj.GetObjectProperty("typedArray")).ToArray();
+        }
+
+        public static void SetTypedArrayUInt(JSObject obj)
+        {
+            uint[] buffer = Enumerable.Repeat((uint)0x20, 16).ToArray();
+            obj.SetObjectProperty("typedArray", Uint32Array.From(buffer));
+        }
+
+        internal static uint[] _taUInt;
+        private static void GetTypedArrayUInt(JSObject obj)
+        {
+            _taUInt = ((Uint32Array)obj.GetObjectProperty("typedArray")).ToArray();
+        }
+
+        private static void SetTypedArrayFloat(JSObject obj)
+        {
+            float[] buffer = Enumerable.Repeat(3.14f, 17).ToArray();
+            obj.SetObjectProperty("typedArray", Float32Array.From(buffer));
+        }
+
+        internal static float[] _taFloat;
+        private static void GetTypedArrayFloat(JSObject obj)
+        {
+            _taFloat = ((Float32Array)obj.GetObjectProperty("typedArray")).ToArray();
+        }
+
+        private static void SetTypedArrayDouble(JSObject obj)
+        {
+            double[] buffer = Enumerable.Repeat(3.14d, 18).ToArray();
+            obj.SetObjectProperty("typedArray", Float64Array.From(buffer));
+        }
+
+        internal static double[] _taDouble;
+        private static void GetTypedArrayDouble(JSObject obj)
+        {
+            _taDouble = ((Float64Array)obj.GetObjectProperty("typedArray")).ToArray();
+        }
+
+        private static Function _sumFunction;
+        private static void CreateFunctionSum()
+        {
+            _sumFunction = new Function("a", "b", "return a + b");
+        }
+
+        internal static int _sumValue = 0;
+        private static void CallFunctionSum()
+        {
+            _sumValue = (int)_sumFunction.Call(null, 3, 5);
+        }
+
+        private static Function _mathMinFunction;
+        private static void CreateFunctionApply()
+        {
+            var math = (JSObject)Runtime.GetGlobalObject("Math");
+            _mathMinFunction = (Function)math.GetObjectProperty("min");
+
+        }
+
+        internal static int _minValue = 0;
+        private static void CallFunctionApply()
+        {
+            _minValue = (int)_mathMinFunction.Apply(null, new object[] { 5, 6, 2, 3, 7 });
+        }
+    }
+}
diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/MarshalTests.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/MarshalTests.cs
new file mode 100644 (file)
index 0000000..68f16e6
--- /dev/null
@@ -0,0 +1,569 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Runtime.InteropServices.JavaScript;
+using System.Collections.Generic;
+using Xunit;
+
+namespace System.Runtime.InteropServices.JavaScript.Tests
+{
+    public static class MarshalTests
+    {
+        [Fact]
+        public static void MarshalPrimitivesToCS()
+        {
+            HelperMarshal._i32Value = 0;
+            Runtime.InvokeJS("App.call_test_method (\"InvokeI32\", [10, 20])");
+            Assert.Equal(30, HelperMarshal._i32Value);
+
+            HelperMarshal._f32Value = 0;
+            Runtime.InvokeJS("App.call_test_method (\"InvokeFloat\", [1.5])");
+            Assert.Equal(1.5f, HelperMarshal._f32Value);
+
+            HelperMarshal._f64Value = 0;
+            Runtime.InvokeJS("App.call_test_method (\"InvokeDouble\", [4.5])");
+            Assert.Equal(4.5, HelperMarshal._f64Value);
+
+            HelperMarshal._i64Value = 0;
+            Runtime.InvokeJS("App.call_test_method (\"InvokeLong\", [99])");
+            Assert.Equal(99, HelperMarshal._i64Value);
+        }
+
+        [Fact]
+        public static void MarshalArrayBuffer()
+        {
+            Runtime.InvokeJS(@"
+                var buffer = new ArrayBuffer(16);
+                App.call_test_method (""MarshalArrayBuffer"", [ buffer ]);
+            ");
+            Assert.Equal(16, HelperMarshal._byteBuffer.Length);
+        }
+
+        [Fact]
+        public static void MarshalArrayBuffer2Int()
+        {
+            Runtime.InvokeJS(@"
+                var buffer = new ArrayBuffer(16);
+                var int32View = new Int32Array(buffer);
+                for (var i = 0; i < int32View.length; i++) {
+                    int32View[i] = i * 2;
+                }
+                App.call_test_method (""MarshalArrayBufferToInt32Array"", [ buffer ]);
+            ");
+
+            Assert.Equal(4, HelperMarshal._intBuffer.Length);
+            Assert.Equal(0, HelperMarshal._intBuffer[0]);
+            Assert.Equal(2, HelperMarshal._intBuffer[1]);
+            Assert.Equal(4, HelperMarshal._intBuffer[2]);
+            Assert.Equal(6, HelperMarshal._intBuffer[3]);
+        }
+
+        [Fact]
+        public static void MarshalArrayBuffer2Int2()
+        {
+            Runtime.InvokeJS(@"
+                var buffer = new ArrayBuffer(16);
+                var int32View = new Int32Array(buffer);
+                for (var i = 0; i < int32View.length; i++) {
+                    int32View[i] = i * 2;
+                }
+                App.call_test_method (""MarshalByteBufferToInts"", [ buffer ]);                
+            ");
+
+            Assert.Equal(4, HelperMarshal._intBuffer.Length);
+            Assert.Equal(0, HelperMarshal._intBuffer[0]);
+            Assert.Equal(2, HelperMarshal._intBuffer[1]);
+            Assert.Equal(4, HelperMarshal._intBuffer[2]);
+            Assert.Equal(6, HelperMarshal._intBuffer[3]);
+        }
+
+        [Fact]
+        public static void MarshalStringToCS()
+        {
+            HelperMarshal._stringResource = null;
+            Runtime.InvokeJS("App.call_test_method(\"InvokeString\", [\"hello\"])");
+            Assert.Equal("hello", HelperMarshal._stringResource);
+        }
+
+        [Fact]
+        public static void MarshalStringToJS()
+        {
+            HelperMarshal._marshalledString = HelperMarshal._stringResource = null;
+            Runtime.InvokeJS(@"
+                var str = App.call_test_method (""InvokeMarshalString"");
+                App.call_test_method (""InvokeString"", [ str ]);
+            ");
+            Assert.NotNull(HelperMarshal._marshalledString);
+            Assert.Equal(HelperMarshal._marshalledString, HelperMarshal._stringResource);
+        }
+
+        [Fact]
+        public static void JSObjectKeepIdentityAcrossCalls()
+        {
+            HelperMarshal._object1 = HelperMarshal._object2 = null;
+            Runtime.InvokeJS(@"
+                var obj = { foo: 10 };
+                var res = App.call_test_method (""InvokeObj1"", [ obj ]);
+                App.call_test_method (""InvokeObj2"", [ res ]);
+            ");
+
+            Assert.NotNull(HelperMarshal._object1);
+            Assert.Same(HelperMarshal._object1, HelperMarshal._object2);
+        }
+
+        [Fact]
+        public static void CSObjectKeepIdentityAcrossCalls()
+        {
+            HelperMarshal._marshalledObject = HelperMarshal._object1 = HelperMarshal._object2 = null;
+            Runtime.InvokeJS(@"
+                var obj = App.call_test_method (""InvokeMarshalObj"");
+                var res = App.call_test_method (""InvokeObj1"", [ obj ]);
+                App.call_test_method (""InvokeObj2"", [ res ]);
+            ");
+
+            Assert.NotNull(HelperMarshal._object1);
+            Assert.Same(HelperMarshal._marshalledObject, HelperMarshal._object1);
+            Assert.Same(HelperMarshal._object1, HelperMarshal._object2);
+        }
+
+        [Fact]
+        public static void JSInvokeInt()
+        {
+            Runtime.InvokeJS(@"
+                var obj = {
+                    foo: 10,
+                    inc: function() {
+                        var c = this.foo;
+                        ++this.foo;
+                        return c;
+                    },
+                    add: function(val){
+                        return this.foo + val;
+                    }
+                };
+                App.call_test_method (""ManipulateObject"", [ obj ]);
+            ");
+            Assert.Equal(10, HelperMarshal._valOne);
+            Assert.Equal(31, HelperMarshal._valTwo);
+        }
+
+        [Fact]
+        public static void JSInvokeTypes()
+        {
+            Runtime.InvokeJS(@"
+                var obj = {
+                    return_int: function() { return 100; },
+                    return_double: function() { return 4.5; },
+                    return_string: function() { return 'Hic Sunt Dracones'; },
+                    return_bool: function() { return true; },
+                };
+                App.call_test_method (""MinipulateObjTypes"", [ obj ]);
+            ");
+
+            Assert.Equal(100, HelperMarshal._jsObjects[0]);
+            Assert.Equal(4.5, HelperMarshal._jsObjects[1]);
+            Assert.Equal("Hic Sunt Dracones", HelperMarshal._jsObjects[2]);
+            Assert.NotEqual("HIC SVNT LEONES", HelperMarshal._jsObjects[2]);
+            Assert.Equal(true, HelperMarshal._jsObjects[3]);
+        }
+
+        [Fact]
+        public static void JSObjectApply()
+        {
+            Runtime.InvokeJS(@"
+                var do_add = function(a, b) { return a + b };
+                App.call_test_method (""UseFunction"", [ do_add ]);
+            ");
+            Assert.Equal(30, HelperMarshal._jsAddFunctionResult);
+        }
+
+        [Fact]
+        public static void JSObjectAsFunction()
+        {
+            Runtime.InvokeJS(@"
+                var do_add = function(a, b) { return a + b };
+                App.call_test_method (""UseAsFunction"", [ do_add ]);
+            ");
+            Assert.Equal(50, HelperMarshal._jsAddAsFunctionResult);
+        }
+
+        [Fact]
+        public static void MarshalDelegate()
+        {
+            HelperMarshal._object1 = null;
+            Runtime.InvokeJS(@"
+                var funcDelegate = App.call_test_method (""CreateFunctionDelegate"", [  ]);
+                var res = funcDelegate (10, 20);
+                App.call_test_method (""InvokeI32"", [ res, res ]);
+            ");
+
+            Assert.Equal(30, HelperMarshal._functionResultValue);
+            Assert.Equal(60, HelperMarshal._i32Value);
+        }
+        [Fact]
+        public static void BindStaticMethod()
+        {
+            HelperMarshal._intValue = 0;
+            Runtime.InvokeJS(@$"
+                var invoke_int = Module.mono_bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeInt"");
+                invoke_int (200);
+            ");
+
+            Assert.Equal(200, HelperMarshal._intValue);
+        }
+
+        [Fact]
+        public static void BindIntPtrStaticMethod()
+        {
+            HelperMarshal._intPtrValue = IntPtr.Zero;
+            Runtime.InvokeJS(@$"
+                var invoke_int_ptr = Module.mono_bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeIntPtr"");
+                invoke_int_ptr (42);
+            ");
+            Assert.Equal(42, (int)HelperMarshal._intPtrValue);
+        }
+
+        [Fact]
+        public static void MarshalIntPtrToJS()
+        {
+            HelperMarshal._marshaledIntPtrValue = IntPtr.Zero;
+            Runtime.InvokeJS(@$"
+                var invokeMarshalIntPtr = Module.mono_bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeMarshalIntPtr"");
+                var r = invokeMarshalIntPtr ();
+
+                if (r != 42) throw `Invalid int_ptr value`;
+            ");
+            Assert.Equal(42, (int)HelperMarshal._marshaledIntPtrValue);
+        }
+
+        [Fact]
+        public static void InvokeStaticMethod()
+        {
+            HelperMarshal._intValue = 0;
+            Runtime.InvokeJS(@$"
+                Module.mono_call_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeInt"", [ 300 ]);
+            ");
+
+            Assert.Equal(300, HelperMarshal._intValue);
+        }
+
+        [Fact]
+        public static void ResolveMethod()
+        {
+            HelperMarshal._intValue = 0;
+            Runtime.InvokeJS(@$"
+                var invoke_int = Module.mono_method_resolve (""{HelperMarshal.INTEROP_CLASS}InvokeInt"");
+                App.call_test_method (""InvokeInt"", [ invoke_int ]);
+            ");
+
+            Assert.NotEqual(0, HelperMarshal._intValue);
+        }
+
+        [Fact]
+        public static void GetObjectProperties()
+        {
+            Runtime.InvokeJS(@"
+                var obj = {myInt: 100, myDouble: 4.5, myString: ""Hic Sunt Dracones"", myBoolean: true};
+                App.call_test_method (""RetrieveObjectProperties"", [ obj ]);          
+            ");
+
+            Assert.Equal(100, HelperMarshal._jsProperties[0]);
+            Assert.Equal(4.5, HelperMarshal._jsProperties[1]);
+            Assert.Equal("Hic Sunt Dracones", HelperMarshal._jsProperties[2]);
+            Assert.Equal(true, HelperMarshal._jsProperties[3]);
+        }
+
+        [Fact]
+        public static void SetObjectProperties()
+        {
+            Runtime.InvokeJS(@"
+                var obj = {myInt: 200, myDouble: 0, myString: ""foo"", myBoolean: false};
+                App.call_test_method (""PopulateObjectProperties"", [ obj, false ]);           
+                App.call_test_method (""RetrieveObjectProperties"", [ obj ]);          
+            ");
+
+            Assert.Equal(100, HelperMarshal._jsProperties[0]);
+            Assert.Equal(4.5, HelperMarshal._jsProperties[1]);
+            Assert.Equal("qwerty", HelperMarshal._jsProperties[2]);
+            Assert.Equal(true, HelperMarshal._jsProperties[3]);
+        }
+
+        [Fact]
+        public static void SetObjectPropertiesIfNotExistsFalse()
+        {
+            // This test will not create the properties if they do not already exist
+            Runtime.InvokeJS(@"
+                var obj = {myInt: 200};
+                App.call_test_method (""PopulateObjectProperties"", [ obj, false ]);           
+                App.call_test_method (""RetrieveObjectProperties"", [ obj ]);          
+            ");
+
+            Assert.Equal(100, HelperMarshal._jsProperties[0]);
+            Assert.Null(HelperMarshal._jsProperties[1]);
+            Assert.Null(HelperMarshal._jsProperties[2]);
+            Assert.Null(HelperMarshal._jsProperties[3]);
+        }
+
+        [Fact]
+        public static void SetObjectPropertiesIfNotExistsTrue()
+        {
+            // This test will set the value of the property if it exists and will create and 
+            // set the value if it does not exists
+            Runtime.InvokeJS(@"
+                var obj = {myInt: 200};
+                App.call_test_method (""PopulateObjectProperties"", [ obj, true ]);
+                App.call_test_method (""RetrieveObjectProperties"", [ obj ]);
+            ");
+
+            Assert.Equal(100, HelperMarshal._jsProperties[0]);
+            Assert.Equal(4.5, HelperMarshal._jsProperties[1]);
+            Assert.Equal("qwerty", HelperMarshal._jsProperties[2]);
+            Assert.Equal(true, HelperMarshal._jsProperties[3]);
+        }
+
+        [Fact]
+        public static void MarshalTypedArray()
+        {
+            Runtime.InvokeJS(@"
+                var buffer = new ArrayBuffer(16);
+                var uint8View = new Uint8Array(buffer);
+                App.call_test_method (""MarshalByteBuffer"", [ uint8View ]);           
+            ");
+
+            Assert.Equal(16, HelperMarshal._byteBuffer.Length);
+        }
+
+        [Fact]
+        public static void MarshalTypedArray2Int()
+        {
+            Runtime.InvokeJS(@"
+                var buffer = new ArrayBuffer(16);
+                var int32View = new Int32Array(buffer);
+                for (var i = 0; i < int32View.length; i++) {
+                    int32View[i] = i * 2;
+                }
+                App.call_test_method (""MarshalInt32Array"", [ int32View ]);
+            ");
+
+            Assert.Equal(4, HelperMarshal._intBuffer.Length);
+            Assert.Equal(0, HelperMarshal._intBuffer[0]);
+            Assert.Equal(2, HelperMarshal._intBuffer[1]);
+            Assert.Equal(4, HelperMarshal._intBuffer[2]);
+            Assert.Equal(6, HelperMarshal._intBuffer[3]);
+        }
+
+        [Fact]
+        public static void MarshalTypedArray2Float()
+        {
+            Runtime.InvokeJS(@"
+                var typedArray = new Float32Array([1, 2.1334, 3, 4.2, 5]);
+                App.call_test_method (""MarshalFloat32Array"", [ typedArray ]);                
+            ");
+
+            Assert.Equal(1, HelperMarshal._floatBuffer[0]);
+            Assert.Equal(2.1334f, HelperMarshal._floatBuffer[1]);
+            Assert.Equal(3, HelperMarshal._floatBuffer[2]);
+            Assert.Equal(4.2f, HelperMarshal._floatBuffer[3]);
+            Assert.Equal(5, HelperMarshal._floatBuffer[4]);
+        }
+
+        [Fact]
+        public static void MarshalArrayBuffer2Float2()
+        {
+            Runtime.InvokeJS(@"
+                var buffer = new ArrayBuffer(16);
+                var float32View = new Float32Array(buffer);
+                for (var i = 0; i < float32View.length; i++) {
+                    float32View[i] = i * 2.5;
+                }
+                App.call_test_method (""MarshalArrayBufferToFloat32Array"", [ buffer ]);               
+            ");
+
+            Assert.Equal(4, HelperMarshal._floatBuffer.Length);
+            Assert.Equal(0, HelperMarshal._floatBuffer[0]);
+            Assert.Equal(2.5f, HelperMarshal._floatBuffer[1]);
+            Assert.Equal(5, HelperMarshal._floatBuffer[2]);
+            Assert.Equal(7.5f, HelperMarshal._floatBuffer[3]);
+        }
+
+        [Fact]
+        public static void MarshalTypedArray2Double()
+        {
+            Runtime.InvokeJS(@"
+                       var typedArray = new Float64Array([1, 2.1334, 3, 4.2, 5]);
+                       App.call_test_method (""MarshalFloat64Array"", [ typedArray ]);         
+               ");
+
+            Assert.Equal(1, HelperMarshal._doubleBuffer[0]);
+            Assert.Equal(2.1334d, HelperMarshal._doubleBuffer[1]);
+            Assert.Equal(3, HelperMarshal._doubleBuffer[2]);
+            Assert.Equal(4.2d, HelperMarshal._doubleBuffer[3]);
+            Assert.Equal(5, HelperMarshal._doubleBuffer[4]);
+        }
+
+        [Fact]
+        public static void MarshalArrayBuffer2Double()
+        {
+            Runtime.InvokeJS(@"
+                var buffer = new ArrayBuffer(32);
+                var float64View = new Float64Array(buffer);
+                for (var i = 0; i < float64View.length; i++) {
+                    float64View[i] = i * 2.5;
+                }
+                App.call_test_method (""MarshalByteBufferToDoubles"", [ buffer ]);             
+            ");
+
+            Assert.Equal(4, HelperMarshal._doubleBuffer.Length);
+            Assert.Equal(0, HelperMarshal._doubleBuffer[0]);
+            Assert.Equal(2.5d, HelperMarshal._doubleBuffer[1]);
+            Assert.Equal(5, HelperMarshal._doubleBuffer[2]);
+            Assert.Equal(7.5d, HelperMarshal._doubleBuffer[3]);
+        }
+
+        [Fact]
+        public static void MarshalArrayBuffer2Double2()
+        {
+            Runtime.InvokeJS(@"
+                var buffer = new ArrayBuffer(32);
+                var float64View = new Float64Array(buffer);
+                for (var i = 0; i < float64View.length; i++) {
+                    float64View[i] = i * 2.5;
+                }
+                App.call_test_method (""MarshalArrayBufferToFloat64Array"", [ buffer ]);               
+            ");
+
+            Assert.Equal(4, HelperMarshal._doubleBuffer.Length);
+            Assert.Equal(0, HelperMarshal._doubleBuffer[0]);
+            Assert.Equal(2.5f, HelperMarshal._doubleBuffer[1]);
+            Assert.Equal(5, HelperMarshal._doubleBuffer[2]);
+            Assert.Equal(7.5f, HelperMarshal._doubleBuffer[3]);
+        }
+
+        [Fact]
+        public static void MarshalTypedArraySByte()
+        {
+            Runtime.InvokeJS(@"
+                var obj = { };
+                App.call_test_method (""SetTypedArraySByte"", [ obj ]);
+                App.call_test_method (""GetTypedArraySByte"", [ obj ]);
+            ");
+            Assert.Equal(11, HelperMarshal._taSByte.Length);
+            Assert.Equal(32, HelperMarshal._taSByte[0]);
+            Assert.Equal(32, HelperMarshal._taSByte[HelperMarshal._taSByte.Length - 1]);
+        }
+
+        [Fact]
+        public static void MarshalTypedArrayByte()
+        {
+            Runtime.InvokeJS(@"
+                var obj = { };
+                App.call_test_method (""SetTypedArrayByte"", [ obj ]);
+                App.call_test_method (""GetTypedArrayByte"", [ obj ]);
+            ");
+            Assert.Equal(11, HelperMarshal._taSByte.Length);
+            Assert.Equal(104, HelperMarshal._taByte[0]);
+            Assert.Equal(115, HelperMarshal._taByte[HelperMarshal._taByte.Length - 1]);
+            Assert.Equal("hic sunt dracones", System.Text.Encoding.Default.GetString(HelperMarshal._taByte));
+        }
+
+        [Fact]
+        public static void MarshalTypedArrayShort()
+        {
+            Runtime.InvokeJS(@"
+                var obj = { };
+                App.call_test_method (""SetTypedArrayShort"", [ obj ]);
+                App.call_test_method (""GetTypedArrayShort"", [ obj ]);
+            ");
+            Assert.Equal(13, HelperMarshal._taShort.Length);
+            Assert.Equal(32, HelperMarshal._taShort[0]);
+            Assert.Equal(32, HelperMarshal._taShort[HelperMarshal._taShort.Length - 1]);
+        }
+
+        [Fact]
+        public static void MarshalTypedArrayUShort()
+        {
+            Runtime.InvokeJS(@"
+                var obj = { };
+                App.call_test_method (""SetTypedArrayUShort"", [ obj ]);
+                App.call_test_method (""GetTypedArrayUShort"", [ obj ]);
+            ");
+            Assert.Equal(14, HelperMarshal._taUShort.Length);
+            Assert.Equal(32, HelperMarshal._taUShort[0]);
+            Assert.Equal(32, HelperMarshal._taUShort[HelperMarshal._taUShort.Length - 1]);
+        }
+
+        [Fact]
+        public static void MarshalTypedArrayInt()
+        {
+            Runtime.InvokeJS(@"
+                var obj = { };
+                App.call_test_method (""SetTypedArrayInt"", ""o"", [ obj ]);
+                App.call_test_method (""GetTypedArrayInt"", ""o"", [ obj ]);
+            ");
+            Assert.Equal(15, HelperMarshal._taInt.Length);
+            Assert.Equal(32, HelperMarshal._taInt[0]);
+            Assert.Equal(32, HelperMarshal._taInt[HelperMarshal._taInt.Length - 1]);
+        }
+
+        [Fact]
+        public static void MarshalTypedArrayUInt()
+        {
+            Runtime.InvokeJS(@"
+                var obj = { };
+                App.call_test_method (""SetTypedArrayUInt"", [ obj ]);
+                App.call_test_method (""GetTypedArrayUInt"", [ obj ]);
+            ");
+            Assert.Equal(16, HelperMarshal._taUInt.Length);
+            Assert.Equal(32, (int)HelperMarshal._taUInt[0]);
+            Assert.Equal(32, (int)HelperMarshal._taUInt[HelperMarshal._taUInt.Length - 1]);
+        }
+
+        [Fact]
+        public static void MarshalTypedArrayFloat()
+        {
+            Runtime.InvokeJS(@"
+                var obj = { };
+                App.call_test_method (""SetTypedArrayFloat"", [ obj ]);
+                App.call_test_method (""GetTypedArrayFloat"", [ obj ]);
+            ");
+            Assert.Equal(17, HelperMarshal._taFloat.Length);
+            Assert.Equal(3.14f, HelperMarshal._taFloat[0]);
+            Assert.Equal(3.14f, HelperMarshal._taFloat[HelperMarshal._taFloat.Length - 1]);
+        }
+
+        [Fact]
+        public static void MarshalTypedArrayDouble()
+        {
+            Runtime.InvokeJS(@"
+                var obj = { };
+                App.call_test_method (""SetTypedArrayDouble"", ""o"", [ obj ]);
+                App.call_test_method (""GetTypedArrayDouble"", ""o"", [ obj ]);
+            ");
+            Assert.Equal(18, HelperMarshal._taDouble.Length);
+            Assert.Equal(3.14d, HelperMarshal._taDouble[0]);
+            Assert.Equal(3.14d, HelperMarshal._taDouble[HelperMarshal._taDouble.Length - 1]);
+        }
+
+        [Fact]
+        public static void TestFunctionSum()
+        {
+            HelperMarshal._sumValue = 0;
+            Runtime.InvokeJS(@"
+                App.call_test_method (""CreateFunctionSum"", null, [ ]);
+                App.call_test_method (""CallFunctionSum"", null, [  ]);
+            ");
+            Assert.Equal(8, HelperMarshal._sumValue);
+        }
+
+        [Fact]
+        public static void TestFunctionApply()
+        {
+            HelperMarshal._minValue = 0;
+            Runtime.InvokeJS(@"
+                App.call_test_method (""CreateFunctionApply"", null, [ ]);
+                App.call_test_method (""CallFunctionApply"", null, [  ]);
+            ");
+            Assert.Equal(2, HelperMarshal._minValue);
+        }
+    }
+}
index dfbd2bca32b0dbc89195d1cbb654fd9dd3983491..56d21202b89631d7b0276c6abcb3ad0b6802a55e 100644 (file)
@@ -388,4 +388,7 @@ var App = {
                        fail_exec ("Unhanded argument: " + args [0]);
                }
        },
-};
+       call_test_method: function (method_name, args) {
+               return BINDING.call_static_method("[System.Runtime.InteropServices.JavaScript.Tests]System.Runtime.InteropServices.JavaScript.Tests.HelperMarshal:" + method_name, args);
+       }
+};
\ No newline at end of file
index 184e84d9d206bef3bc4b1008550caa7b384db0d9..bdef5f6ac5dc90fa7b9d0b47a740acb5af697abc 100644 (file)
@@ -761,6 +761,8 @@ var BindingSupportLib = {
                },
                
                resolve_method_fqn: function (fqn) {
+                       this.bindings_lazy_init ();
+                       
                        var assembly = fqn.substring(fqn.indexOf ("[") + 1, fqn.indexOf ("]")).trim();
                        fqn = fqn.substring (fqn.indexOf ("]") + 1).trim();