[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/ddunkin/ClearScript/master/ClearScriptTest/BugFixTest.Windows.cs [Back]  [Original]

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

using System;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading;
using Microsoft.ClearScript.V8;
using Microsoft.ClearScript.Util;
using Microsoft.ClearScript.Windows;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using UIAutomationClient;

namespace Microsoft.ClearScript.Test
{
    public partial class BugFixTest
    {
        #region test methods

        // ReSharper disable InconsistentNaming

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_JScript_CaseInsensitivity()
        {
            engine.Dispose();
            engine = new JScriptEngine();
            engine.Execute("abc = 1; ABC = 2; function foo() { return 3; } function FOO() { return 4; }");
            Assert.AreEqual(1, engine.Script.abc);
            Assert.AreEqual(2, engine.Script.ABC);
            Assert.AreEqual(3, engine.Script.foo());
            Assert.AreEqual(4, engine.Script.FOO());
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_FloatParameterBinding_JScript()
        {
            engine.Dispose();
            engine = new JScriptEngine();
            BugFix_FloatParameterBinding();
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_UInt32RoundTrip_JScript()
        {
            engine.Dispose();
            engine = new JScriptEngine();
            BugFix_UInt32RoundTrip();
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_IDispatchExArgLeak_SetProperty_JScript()
        {
            // ReSharper disable RedundantAssignment

            engine.Dispose();
            engine = new JScriptEngine();

            WeakReference wr = null;

            new Action(() =>
            {
                object x = Guid.NewGuid();
                wr = new WeakReference(x);

                var result = x.ToString();
                engine.Script.x = x;

                x = null;
                GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
                GC.WaitForPendingFinalizers();

                Assert.AreEqual(result, engine.Evaluate("x.ToString()"));

                engine.Script.x = null;
                engine.CollectGarbage(true);
            })();

            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
            GC.WaitForPendingFinalizers();
            Assert.IsFalse(wr.IsAlive);

            // ReSharper restore RedundantAssignment
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_IDispatchExArgLeak_InvokeMethod_JScript()
        {
            // ReSharper disable RedundantAssignment

            engine.Dispose();
            engine = new JScriptEngine();

            WeakReference wr1 = null;
            WeakReference wr2 = null;

            new Action(() =>
            {
                object x1 = Guid.NewGuid();
                wr1 = new WeakReference(x1);
                object x2 = Guid.NewGuid();
                wr2 = new WeakReference(x2);

                engine.Execute("function foo(x1, x2) { return x1.ToString() + x2.ToString(); }");
                Assert.AreEqual(x1.ToString() + x2, engine.Script.foo(x1, x2));

                engine.CollectGarbage(true);
            })();

            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
            GC.WaitForPendingFinalizers();
            Assert.IsFalse(wr1.IsAlive);
            Assert.IsFalse(wr2.IsAlive);

            // ReSharper restore RedundantAssignment
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_TooManyDebugApplications()
        {
            var engines = Enumerable.Range(0, 2048).Select(index => new JScriptEngine(WindowsScriptEngineFlags.EnableDebugging)).ToArray();
            Array.ForEach(engines, tempEngine => tempEngine.Dispose());
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_NestedInterrupt_JScript()
        {
            engine.Dispose();
            try
            {
                using (var startEvent = new ManualResetEventSlim(false))
                {
                    object result = null;
                    var interruptedInner = false;
                    var interruptedOuter = false;

                    var thread = new Thread(() =>
                    {
                        using (engine = new JScriptEngine(WindowsScriptEngineFlags.EnableDebugging))
                        {
                            var context = new PropertyBag();
                            engine.AddHostObject("context", context);

                            // ReSharper disable once AccessToDisposedClosure
                            context["startEvent"] = startEvent;

                            context["foo"] = new Action(() =>
                            {
                                try
                                {
                                    engine.Execute("while (true) { context.startEvent.Set(); }");
                                }
                                catch (ScriptInterruptedException)
                                {
                                    interruptedInner = true;
                                }
                            });

                            try
                            {
                                result = engine.Evaluate("context.foo(); 123");
                            }
                            catch (ScriptInterruptedException)
                            {
                                interruptedOuter = true;
                            }
                        }
                    });

                    thread.Start();
                    startEvent.Wait();
                    engine.Interrupt();
                    thread.Join();

                    Assert.IsTrue(interruptedInner);
                    Assert.IsFalse(interruptedOuter);
                    Assert.AreEqual(123, result);
                }
            }
            finally
            {
                engine = new V8ScriptEngine(V8ScriptEngineFlags.EnableDebugging);
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_PropertyBag_NativeEnumerator_JScript()
        {
            engine.Dispose();
            engine = new JScriptEngine();

            var x = new PropertyBag { ["foo"] = 123, ["bar"] = "blah" };
            engine.Script.x = x;

            var result = (string)engine.Evaluate(@"
                var result = '';
                for (var e = new Enumerator(x); !e.atEnd(); e.moveNext()) {
                    result += e.item().Value;
                }
                result
            ");

            Assert.AreEqual(7, result.Length);
            Assert.IsTrue(result.IndexOf("123", StringComparison.Ordinal) >= 0);
            Assert.IsTrue(result.IndexOf("blah", StringComparison.Ordinal) >= 0);
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_JScriptStandardsMode_PropertyAccess()
        {
            engine.Dispose();
            engine = new JScriptEngine(WindowsScriptEngineFlags.EnableStandardsMode);
            engine.Script.x = new { foo = 123 };
            Assert.AreEqual(123, engine.Evaluate("x.foo"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_JScriptStandardsMode_MemberEnumeration()
        {
            engine.Dispose();
            engine = new JScriptEngine(WindowsScriptEngineFlags.EnableStandardsMode);

            engine.Script.x = new { foo = 123, bar = "blah" };
            var result = (string)engine.Evaluate(@"
                var result = '';
                for (var i in x) {
                    if ((i == 'foo') || (i == 'bar')) {
                        result += x[i];
                    }
                }
                result
            ");

            Assert.AreEqual(7, result.Length);
            Assert.IsTrue(result.IndexOf("123", StringComparison.Ordinal) >= 0);
            Assert.IsTrue(result.IndexOf("blah", StringComparison.Ordinal) >= 0);
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_JScriptStandardsMode_MemberEnumeration_PropertyBag()
        {
            engine.Dispose();
            engine = new JScriptEngine(WindowsScriptEngineFlags.EnableStandardsMode);

            var x = new PropertyBag { ["foo"] = 123, ["bar"] = "blah" };
            engine.Script.x = x;

            var result = (string)engine.Evaluate(@"
                var result = '';
                for (var i in x) {
                    result += x[i];
                }
                result
            ");

            Assert.AreEqual(7, result.Length);
            Assert.IsTrue(result.IndexOf("123", StringComparison.Ordinal) >= 0);
            Assert.IsTrue(result.IndexOf("blah", StringComparison.Ordinal) >= 0);
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_JScriptStandardsMode_MemberEnumeration_Dynamic()
        {
            engine.Dispose();
            engine = new JScriptEngine(WindowsScriptEngineFlags.EnableStandardsMode);

            dynamic x = new ExpandoObject();
            x.foo = 123;
            x.bar = "blah";
            engine.Script.x = x;

            var result = (string)engine.Evaluate(@"
                var result = '';
                for (var i in x) {
                    if ((i == 'foo') || (i == 'bar')) {
                        result += x[i];
                    }
                }
                result
            ");

            Assert.AreEqual(7, result.Length);
            Assert.IsTrue(result.IndexOf("123", StringComparison.Ordinal) >= 0);
            Assert.IsTrue(result.IndexOf("blah", StringComparison.Ordinal) >= 0);
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_JScriptStandardsMode_MemberDeletion_PropertyBag()
        {
            engine.Dispose();
            engine = new JScriptEngine(WindowsScriptEngineFlags.EnableStandardsMode);

            var x = new PropertyBag { ["foo"] = 123, ["bar"] = "blah" };
            engine.Script.x = x;

            Assert.AreEqual(123, engine.Evaluate("x.foo"));
            Assert.AreEqual("blah", engine.Evaluate("x.bar"));
            Assert.AreEqual(true, engine.Evaluate("delete x.foo"));
            Assert.IsInstanceOfType(engine.Evaluate("x.foo"), typeof(Undefined));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_JScriptStandardsMode_MemberDeletion_Dynamic()
        {
            engine.Dispose();
            engine = new JScriptEngine(WindowsScriptEngineFlags.EnableStandardsMode);

            dynamic x = new ExpandoObject();
            x.foo = 123;
            x.bar = "blah";
            engine.Script.x = x;

            Assert.AreEqual(123, engine.Evaluate("x.foo"));
            Assert.AreEqual("blah", engine.Evaluate("x.bar"));
            Assert.AreEqual(true, engine.Evaluate("delete x.foo"));
            Assert.IsInstanceOfType(engine.Evaluate("x.foo"), typeof(Undefined));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_ScriptObjectInHostVariable_JScript()
        {
            engine.Dispose();
            engine = new JScriptEngine();
            BugFix_ScriptObjectInHostVariable();
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_DoubleExecution_JScript()
        {
            engine.Dispose();
            engine = new JScriptEngine();
            BugFix_DoubleExecution();
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_DoubleExecution_Delegate_JScript()
        {
            engine.Dispose();
            engine = new JScriptEngine();
            BugFix_DoubleExecution_Delegate();
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_NestedType_JScript()
        {
            engine.Dispose();
            engine = new JScriptEngine();

            engine.AddHostType(typeof(NestedTypeTest));
            Assert.AreEqual(NestedTypeTest.NestedType.Foo, engine.Evaluate("NestedTypeTest.NestedType.Foo"));
            Assert.AreEqual(NestedTypeTest.NestedType.Bar, engine.Evaluate("NestedTypeTest.NestedType.Bar"));
            Assert.AreEqual(NestedTypeTest.NestedType.Baz, engine.Evaluate("NestedTypeTest.NestedType.Baz"));
            Assert.AreEqual(NestedTypeTest.NestedType.Qux, engine.Evaluate("NestedTypeTest.NestedType.Qux"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_NonEnumerablePropertyAccess_JScript()
        {
            engine.Dispose();
            engine = new JScriptEngine();

            engine.Script.dump = new Action((obj, value) =>
            {
                Assert.AreEqual(value, obj.message);
            });

            engine.Execute(@"
                message = 'hello';
                dump({ message: message }, message);
                message = 'world';
                dump(new Error(message), message);
            ");
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_NonEnumerablePropertyAccess_JScript_VB()
        {
            TestUtil.InvokeVBTestSub(@"
                Using engine As New JScriptEngine
                    engine.Script.dump = Sub(obj As Object, value As String)
                        Assert.AreEqual(value, obj.message)
                    End Sub
                    engine.Execute(
                        ""message = 'hello';"" & _
                        ""dump({ message: message }, message);"" & _
                        ""message = 'world';"" & _
                        ""dump(new Error(message), message);""
                    )
                End Using
            ");
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_NonexistentPropertyAccess_JScript_VB()
        {
            TestUtil.InvokeVBTestSub(@"
                Using engine As New JScriptEngine
                    engine.Script.dump = Sub(obj As Object, message As Object, stack As Object)
                        Assert.AreEqual(message, obj.message)
                        Assert.AreEqual(stack, obj.stack)
                    End Sub
                    engine.Execute(
                        ""message = 'hello';"" & _
                        ""stack = 'world';"" & _
                        ""dump({ message: message, stack: stack }, message, stack);"" & _
                        ""dump({ message: message }, message, undefined);""
                    )
                End Using
            ");
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_InteropMethodCallWithInteropArg_JScript()
        {
            engine.Dispose();
            engine = new JScriptEngine();
            BugFix_InteropMethodCallWithInteropArg();
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_JScript_TargetInvocationException()
        {
            engine.Dispose();
            engine = new JScriptEngine(WindowsScriptEngineFlags.EnableDebugging);

            engine.Script.foo = new Action(() => throw new Exception("bar"));
            engine.Execute("function test() { foo(); }");

            try
            {
                engine.Invoke("test");
            }
            catch (ScriptEngineException exception)
            {
                Assert.IsTrue(exception.ErrorDetails.Contains("bar\n    at test (Script:0:18) -> foo"));
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VBCallToParameterlessVBScriptSub()
        {
            TestUtil.InvokeVBTestSub(@"
                Using engine As New VBScriptEngine
                    engine.Execute(""sub main : end sub"")
                    engine.Script.main()
                End Using
            ");
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_IDispatchExArgLeak_SetProperty_VBScript()
        {
            // ReSharper disable RedundantAssignment

            engine.Dispose();
            engine = new VBScriptEngine();

            WeakReference wr = null;

            new Action(() =>
            {
                object x = Guid.NewGuid();
                wr = new WeakReference(x);

                var result = x.ToString();
                engine.Script.x = x;

                x = null;
                GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
                GC.WaitForPendingFinalizers();

                Assert.AreEqual(result, engine.Evaluate("x.ToString()"));

                engine.Script.x = null;
                engine.CollectGarbage(true);
            })();

            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
            GC.WaitForPendingFinalizers();
            Assert.IsFalse(wr.IsAlive);

            // ReSharper restore RedundantAssignment
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_IDispatchExArgLeak_GetProperty_VBScript()
        {
            engine.Dispose();
            engine = new VBScriptEngine();

            WeakReference wr1 = null;
            WeakReference wr2 = null;

            new Action(() =>
            {
                object x1 = Guid.NewGuid();
                wr1 = new WeakReference(x1);
                object x2 = Guid.NewGuid();
                wr2 = new WeakReference(x2);

                engine.Execute(@"
                    class MyClass
                        public property get foo(x1, x2)
                            foo = x1.ToString() & x2.ToString()
                        end property
                    end class
                    set bar = new MyClass
                ");

                var bar = (DynamicObject)engine.Script.bar;
                var args = new[] { "foo", HostItem.Wrap(engine, x1), HostItem.Wrap(engine, x2) };
                Assert.IsTrue(bar.GetMetaObject(Expression.Constant(bar)).TryGetIndex(args, out var result));
                Assert.AreEqual(x1.ToString() + x2, result);
            })();

            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
            GC.WaitForPendingFinalizers();
            Assert.IsFalse(wr1.IsAlive);
            Assert.IsFalse(wr2.IsAlive);
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_IDispatchExArgLeak_InvokeMethod_VBScript()
        {
            engine.Dispose();
            engine = new VBScriptEngine();

            WeakReference wr1 = null;
            WeakReference wr2 = null;

            new Action(() =>
            {
                object x1 = Guid.NewGuid();
                wr1 = new WeakReference(x1);
                object x2 = Guid.NewGuid();
                wr2 = new WeakReference(x2);

                engine.Execute("function foo(x1, x2):foo = x1.ToString() & x2.ToString():end function");
                Assert.AreEqual(x1.ToString() + x2, engine.Script.foo(x1, x2));

                engine.CollectGarbage(true);
            })();

            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
            GC.WaitForPendingFinalizers();
            Assert.IsFalse(wr1.IsAlive);
            Assert.IsFalse(wr2.IsAlive);
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VBScriptItemArgsByRef()
        {
            engine.Dispose();
            engine = new VBScriptEngine();

            var a = new object();
            var b = new object();
            var c = new object();
            var x = new object();
            var y = new object();
            var z = new object();

            engine.Script.a = a;
            engine.Script.b = b;
            engine.Script.c = c;
            engine.Script.x = x;
            engine.Script.y = y;
            engine.Script.z = z;

            engine.Execute("sub test(i, j, k) : i = x : j = y : k = z : end sub");
            engine.Script.test(ref a, out b, ref c);

            Assert.AreSame(x, a);
            Assert.AreSame(y, b);
            Assert.AreSame(z, c);
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VBScriptItemArgsByRef_Scalar()
        {
            engine.Dispose();
            engine = new VBScriptEngine();

            var a = 123;
            var b = 456;
            var c = 789;
            const int x = 987;
            const int y = 654;
            const int z = 321;

            engine.Script.a = a;
            engine.Script.b = b;
            engine.Script.c = c;
            engine.Script.x = x;
            engine.Script.y = y;
            engine.Script.z = z;

            engine.Execute("sub test(i, j, k) : i = x : j = y : k = z : end sub");
            engine.Script.test(ref a, out b, ref c);

            Assert.AreEqual(x, a);
            Assert.AreEqual(y, b);
            Assert.AreEqual(z, c);
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VBScriptItemArgsByRef_Enum()
        {
            engine.Dispose();
            engine = new VBScriptEngine();

            var a = DayOfWeek.Monday;
            var b = DayOfWeek.Tuesday;
            var c = DayOfWeek.Wednesday;
            const DayOfWeek x = DayOfWeek.Sunday;
            const DayOfWeek y = DayOfWeek.Saturday;
            const DayOfWeek z = DayOfWeek.Friday;

            engine.Script.a = a;
            engine.Script.b = b;
            engine.Script.c = c;
            engine.Script.x = x;
            engine.Script.y = y;
            engine.Script.z = z;

            engine.Execute("sub test(i, j, k) : i = x : j = y : k = z : end sub");
            engine.Script.test(ref a, out b, ref c);

            Assert.AreEqual(x, a);
            Assert.AreEqual(y, b);
            Assert.AreEqual(z, c);
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VBScriptItemArgsByRef_Struct()
        {
            engine.Dispose();
            engine = new VBScriptEngine();

            var random = new Random();
            var a = TimeSpan.FromMilliseconds(random.NextDouble() * 1000);
            var b = TimeSpan.FromMilliseconds(random.NextDouble() * 1000);
            var c = TimeSpan.FromMilliseconds(random.NextDouble() * 1000);
            var x = TimeSpan.FromMilliseconds(random.NextDouble() * 1000);
            var y = TimeSpan.FromMilliseconds(random.NextDouble() * 1000);
            var z = TimeSpan.FromMilliseconds(random.NextDouble() * 1000);

            engine.Script.a = a;
            engine.Script.b = b;
            engine.Script.c = c;
            engine.Script.x = x;
            engine.Script.y = y;
            engine.Script.z = z;

            engine.Execute("sub test(i, j, k) : i = x : j = y : k = z : end sub");
            engine.Script.test(ref a, out b, ref c);

            Assert.AreEqual(x, a);
            Assert.AreEqual(y, b);
            Assert.AreEqual(z, c);
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VBScriptItemArgsByRef_VB()
        {
            TestUtil.InvokeVBTestSub(@"
                Using engine As New VBScriptEngine

                    Dim a = New Object
                    Dim b = New Object
                    Dim c = New Object
                    Dim x = New Object
                    Dim y = New Object
                    Dim z = New Object

                    engine.Script.a = a
                    engine.Script.b = b
                    engine.Script.c = c
                    engine.Script.x = x
                    engine.Script.y = y
                    engine.Script.z = z

                    engine.Execute(""sub test(i, j, k) : i = x : j = y : k = z : end sub"")
                    engine.Script.test(a, b, c)

                    Assert.AreSame(x, a)
                    Assert.AreSame(y, b)
                    Assert.AreSame(z, c)

                End Using
            ");
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VBScriptItemArgsByRef_VB_Scalar()
        {
            TestUtil.InvokeVBTestSub(@"
                Using engine As New VBScriptEngine

                    Dim a = 123
                    Dim b = 456
                    Dim c = 789
                    Dim x = 987
                    Dim y = 654
                    Dim z = 321

                    engine.Script.a = a
                    engine.Script.b = b
                    engine.Script.c = c
                    engine.Script.x = x
                    engine.Script.y = y
                    engine.Script.z = z

                    engine.Execute(""sub test(i, j, k) : i = x : j = y : k = z : end sub"")
                    engine.Script.test(a, b, c)

                    Assert.AreEqual(x, a)
                    Assert.AreEqual(y, b)
                    Assert.AreEqual(z, c)

                End Using
            ");
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VBScriptItemArgsByRef_VB_Enum()
        {
            TestUtil.InvokeVBTestSub(@"
                Using engine As New VBScriptEngine

                    Dim a = DayOfWeek.Monday
                    Dim b = DayOfWeek.Tuesday
                    Dim c = DayOfWeek.Wednesday
                    Dim x = DayOfWeek.Sunday
                    Dim y = DayOfWeek.Saturday
                    Dim z = DayOfWeek.Friday

                    engine.Script.a = a
                    engine.Script.b = b
                    engine.Script.c = c
                    engine.Script.x = x
                    engine.Script.y = y
                    engine.Script.z = z

                    engine.Execute(""sub test(i, j, k) : i = x : j = y : k = z : end sub"")
                    engine.Script.test(a, b, c)

                    Assert.AreEqual(x, a)
                    Assert.AreEqual(y, b)
                    Assert.AreEqual(z, c)

                End Using
            ");
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VBScriptItemArgsByRef_VB_Struct()
        {
            TestUtil.InvokeVBTestSub(@"
                Using engine As New VBScriptEngine

                    Dim random = New Random
                    Dim a = TimeSpan.FromMilliseconds(random.NextDouble() * 1000)
                    Dim b = TimeSpan.FromMilliseconds(random.NextDouble() * 1000)
                    Dim c = TimeSpan.FromMilliseconds(random.NextDouble() * 1000)
                    Dim x = TimeSpan.FromMilliseconds(random.NextDouble() * 1000)
                    Dim y = TimeSpan.FromMilliseconds(random.NextDouble() * 1000)
                    Dim z = TimeSpan.FromMilliseconds(random.NextDouble() * 1000)

                    engine.Script.a = a
                    engine.Script.b = b
                    engine.Script.c = c
                    engine.Script.x = x
                    engine.Script.y = y
                    engine.Script.z = z

                    engine.Execute(""sub test(i, j, k) : i = x : j = y : k = z : end sub"")
                    engine.Script.test(a, b, c)

                    Assert.AreEqual(x, a)
                    Assert.AreEqual(y, b)
                    Assert.AreEqual(z, c)

                End Using
            ");
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_PropertyBag_NativeEnumerator_VBScript()
        {
            engine.Dispose();
            engine = new VBScriptEngine();

            var x = new PropertyBag { ["foo"] = 123, ["bar"] = "blah" };
            engine.Script.x = x;

            engine.Execute(@"
                function getResult(arg)
                    dim result
                    result = """"
                    for each item in arg
                        result = result & item.Value
                    next
                    getResult = result
                end function
            ");

            var result = (string)engine.Evaluate("getResult(x)");

            Assert.AreEqual(7, result.Length);
            Assert.IsTrue(result.IndexOf("123", StringComparison.Ordinal) >= 0);
            Assert.IsTrue(result.IndexOf("blah", StringComparison.Ordinal) >= 0);
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VBScript_PropertyPut()
        {
            using (var vbEngine = new VBScriptEngine())
            {
                vbEngine.Execute(@"
                    class Test
                        private myFoo
                        public property get foo
                            foo = myFoo
                        end property
                        public property let foo(value)
                            myFoo = value
                        end property
                    end class 
                    set myTest = new Test
                    myTest.foo = 123
                ");

                Assert.AreEqual(123, Convert.ToInt32(vbEngine.Script.myTest.foo));

                vbEngine.Script.myTest.foo = 456;
                Assert.AreEqual(456, Convert.ToInt32(vbEngine.Script.myTest.foo));

                vbEngine.Script.myTest.foo = "blah";
                Assert.AreEqual("blah", vbEngine.Script.myTest.foo);

                vbEngine.Script.myTest.foo = new DateTime(2007, 5, 22);
                Assert.AreEqual(new DateTime(2007, 5, 22), vbEngine.Script.myTest.foo);
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VBScript_PropertyPut_CrossEngine()
        {
            using (var vbEngine = new VBScriptEngine())
            {
                vbEngine.Execute(@"
                    class Test
                        private myFoo
                        public property get foo
                            foo = myFoo
                        end property
                        public property let foo(value)
                            myFoo = value
                        end property
                    end class 
                    set myTest = new Test
                    myTest.foo = 123
                ");

                engine.Script.test = vbEngine.Script.myTest;
                Assert.AreEqual(123, Convert.ToInt32(engine.Evaluate("test.foo")));

                engine.Execute("test.foo = 456");
                Assert.AreEqual(456, Convert.ToInt32(engine.Evaluate("test.foo")));

                engine.Execute("test.foo = \"blah\"");
                Assert.AreEqual("blah", engine.Evaluate("test.foo"));

                engine.AddHostObject("bar", new DateTime(2007, 5, 22));
                engine.Execute("test.foo = bar");
                Assert.AreEqual(new DateTime(2007, 5, 22), engine.Evaluate("test.foo"));
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VBScript_PropertyPut_CrossEngine_VBScript()
        {
            engine.Dispose();
            engine = new VBScriptEngine();
            BugFix_VBScript_PropertyPut_CrossEngine();
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_DoubleExecution_CrossEngine()
        {
            using (var vbEngine = new VBScriptEngine())
            {
                vbEngine.Execute(@"
                    class Test
                        public sub foo
                            count = count + 1
                            err.raise 1, ""vb"", ""Bogus""
                        end sub
                    end class
                    set myTest = new Test
                    count = 0
                ");

                engine.Execute(@"
                    function foo() {
                        vbTest.foo();
                    }
                ");

                engine.Script.vbTest = vbEngine.Script.myTest;

                var message = string.Empty;
                try
                {
                    engine.Script.foo();
                }
                catch (ScriptEngineException exception)
                {
                    message = exception.Message;
                }

                Assert.AreEqual("Error: Bogus", message);
                Assert.AreEqual(1, vbEngine.Script.count);
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_DoubleExecution_CrossEngine_VBScript()
        {
            engine.Dispose();
            engine = new VBScriptEngine();

            using (var vbEngine = new VBScriptEngine())
            {
                vbEngine.Execute(@"
                    class Test
                        public sub foo
                            count = count + 1
                            err.raise 1, ""vb"", ""Bogus""
                        end sub
                    end class
                    set myTest = new Test
                    count = 0
                ");

                engine.Execute(@"
                    sub foo
                        vbTest.foo
                    end sub
                ");

                engine.Script.vbTest = vbEngine.Script.myTest;

                var message = string.Empty;
                try
                {
                    engine.Script.foo();
                }
                catch (ScriptEngineException exception)
                {
                    message = exception.Message;
                }

                Assert.AreEqual("Bogus", message);
                Assert.AreEqual(1, vbEngine.Script.count);
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_NestedType_VBScript()
        {
            engine.Dispose();
            engine = new VBScriptEngine();

            engine.AddHostType(typeof(NestedTypeTest));
            Assert.AreEqual(NestedTypeTest.NestedType.Foo, engine.Evaluate("NestedTypeTest.NestedType.Foo"));
            Assert.AreEqual(NestedTypeTest.NestedType.Bar, engine.Evaluate("NestedTypeTest.NestedType.Bar"));
            Assert.AreEqual(NestedTypeTest.NestedType.Baz, engine.Evaluate("NestedTypeTest.NestedType.Baz"));
            Assert.AreEqual(NestedTypeTest.NestedType.Qux, engine.Evaluate("NestedTypeTest.NestedType.Qux"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_NestedType_VBScript_VB()
        {
            TestUtil.InvokeVBTestSub(@"
                Using engine As New VBScriptEngine
                    engine.AddHostType(GetType(BugFixTest.NestedTypeTest))
                    Assert.AreEqual(BugFixTest.NestedTypeTest.NestedType.Foo, engine.Evaluate(""NestedTypeTest.NestedType.Foo""))
                    Assert.AreEqual(BugFixTest.NestedTypeTest.NestedType.Bar, engine.Evaluate(""NestedTypeTest.NestedType.Bar""))
                    Assert.AreEqual(BugFixTest.NestedTypeTest.NestedType.Baz, engine.Evaluate(""NestedTypeTest.NestedType.Baz""))
                    Assert.AreEqual(BugFixTest.NestedTypeTest.NestedType.Qux, engine.Evaluate(""NestedTypeTest.NestedType.Qux""))
                End Using
            ");
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_WindowsScriptItem_SetPropertyLeak()
        {
            WeakReference wr = null;

            var proc = new Action(() =>
            {
                using (var vbs = new VBScriptEngine())
                {
                    wr = new WeakReference(vbs);

                    vbs.AddHostType(typeof(Console));
                    vbs.Script["foo"] = "bar";
                }
            });

            proc();

            GC.Collect();
            GC.WaitForPendingFinalizers();

            Assert.IsFalse(wr.IsAlive);
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_AmbiguousIndexer_ADODB()
        {
            engine.Dispose();
            engine = new VBScriptEngine(WindowsScriptEngineFlags.EnableDebugging);

            var recordSet = new ADODB.Recordset();
            recordSet.Fields.Append("foo", ADODB.DataTypeEnum.adVarChar, 20);
            recordSet.Open(Missing.Value, Missing.Value, ADODB.CursorTypeEnum.adOpenStatic, ADODB.LockTypeEnum.adLockOptimistic, 0);
            recordSet.AddNew(Missing.Value, Missing.Value);
            recordSet.Fields["foo"].Value = "bar";

            engine.AddHostObject("recordSet", recordSet);
            Assert.AreEqual("bar", engine.Evaluate("recordSet.Fields.Item(\"foo\").Value"));

            engine.Execute("recordSet.Fields.Item(\"foo\").Value = \"qux\"");
            Assert.AreEqual("qux", engine.Evaluate("recordSet.Fields.Item(\"foo\").Value"));

            TestUtil.AssertException(() => engine.Evaluate("recordSet.Fields.Item(\"baz\")"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VBScript_DefaultPropertyEmulation()
        {
            engine.Dispose();
            engine = new VBScriptEngine(WindowsScriptEngineFlags.EnableDebugging);

            engine.AddHostObject("foo", new Variable { Value = 1, IsValid = true });
            engine.AddHostObject("bar", new Variable { Value = 2, IsValid = false });
            engine.Script.baz = new Variable { Value = 3, IsValid = false };

            engine.Execute(@"
                class CQux
                    private v
                    public sub Class_Initialize
                        v = 123
                    end sub
                    public default property get Value
                        Value = v
                    end property
                end class
                class CQuux
                end class
                set qux = new CQux
                set quux = new CQuux
            ");

            engine.Execute("foo = 456");
            Assert.AreEqual(456, engine.Evaluate("foo.Value"));
            Assert.AreEqual(true, engine.Evaluate("foo.IsValid"));

            engine.Execute("foo = bar");
            Assert.AreEqual(2, engine.Evaluate("foo.Value"));
            Assert.AreEqual(true, engine.Evaluate("foo.IsValid"));

            engine.Execute("foo = foo + 789");
            Assert.AreEqual(791, engine.Evaluate("foo.Value"));
            Assert.AreEqual(true, engine.Evaluate("foo.IsValid"));

            engine.Execute("foo = bar + baz");
            Assert.AreEqual(5, engine.Evaluate("foo.Value"));
            Assert.AreEqual(true, engine.Evaluate("foo.IsValid"));

            engine.Execute("foo = qux");
            Assert.AreEqual(123, engine.Evaluate("foo.Value"));
            Assert.AreEqual(true, engine.Evaluate("foo.IsValid"));

            engine.Execute("foo = bar + qux");
            Assert.AreEqual(125, engine.Evaluate("foo.Value"));
            Assert.AreEqual(true, engine.Evaluate("foo.IsValid"));

            engine.Execute("foo = bar + baz + qux");
            Assert.AreEqual(128, engine.Evaluate("foo.Value"));
            Assert.AreEqual(true, engine.Evaluate("foo.IsValid"));

            TestUtil.AssertException(() => engine.Execute("foo = quux"));
            Assert.AreEqual(128, engine.Evaluate("foo.Value"));
            Assert.AreEqual(true, engine.Evaluate("foo.IsValid"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VBScript_ErrorDetails()
        {
            engine.Dispose();
            engine = new VBScriptEngine(WindowsScriptEngineFlags.EnableDebugging);

            engine.AddHostObject("foo", new Variable());
            engine.Execute("sub test\nfoo = \"xyz\"\nend sub");

            try
            {
                engine.Invoke("test");
                Assert.Fail();
            }
            catch (ScriptEngineException exception)
            {
                Assert.IsTrue(exception.ErrorDetails.Contains("at test (Script:1:0) -> foo = \"xyz\""));
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VBScript_ErrorDetails_NoDebugger()
        {
            engine.Dispose();
            engine = new VBScriptEngine();

            engine.AddHostObject("foo", new Variable());
            engine.Execute("sub test\nfoo = \"xyz\"\nend sub");

            try
            {
                engine.Invoke("test");
                Assert.Fail();
            }
            catch (ScriptEngineException exception)
            {
                Assert.IsTrue(exception.ErrorDetails.Contains("at ([unknown]:1:0)"));
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VBScript_ErrorDetails_DirectAccess()
        {
            engine.Dispose();
            engine = new VBScriptEngine(WindowsScriptEngineFlags.EnableDebugging);

            engine.AddHostObject("foo", HostItemFlags.DirectAccess, new Variable());
            engine.Execute("sub test\nfoo = \"xyz\"\nend sub");

            try
            {
                engine.Invoke("test");
                Assert.Fail();
            }
            catch (ScriptEngineException exception)
            {
                Assert.IsTrue(exception.ErrorDetails.Contains("at test (Script:1:0) -> foo = \"xyz\""));
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VBScript_ErrorDetails_DirectAccess_NoDebugger()
        {
            engine.Dispose();
            engine = new VBScriptEngine();

            engine.AddHostObject("foo", HostItemFlags.DirectAccess, new Variable());
            engine.Execute("sub test\nfoo = \"xyz\"\nend sub");

            try
            {
                engine.Invoke("test");
                Assert.Fail();
            }
            catch (ScriptEngineException exception)
            {
                Assert.IsTrue(exception.ErrorDetails.Contains("at ([unknown]:1:0)"));
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VBScript_ErrorDetails_DirectAccess_ReadOnlyProperty()
        {
            engine.Dispose();
            engine = new VBScriptEngine(WindowsScriptEngineFlags.EnableDebugging);

            engine.AddHostObject("foo", HostItemFlags.DirectAccess, new Variable());
            engine.Execute("sub test\nfoo.Description = \"bogus\"\nend sub");

            try
            {
                engine.Invoke("test");
                Assert.Fail();
            }
            catch (ScriptEngineException exception)
            {
                Assert.IsTrue(exception.ErrorDetails.Contains("at test (Script:1:0) -> foo.Description = \"bogus\""));
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VBScript_ErrorDetails_DirectAccess_ReadOnlyProperty_NoDebugger()
        {
            engine.Dispose();
            engine = new VBScriptEngine();

            engine.AddHostObject("foo", HostItemFlags.DirectAccess, new Variable());
            engine.Execute("sub test\nfoo.Description = \"bogus\"\nend sub");

            try
            {
                engine.Invoke("test");
                Assert.Fail();
            }
            catch (ScriptEngineException exception)
            {
                Assert.IsTrue(exception.ErrorDetails.Contains("at ([unknown]:1:0)"));
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VBScript_TargetInvocationException()
        {
            engine.Dispose();
            engine = new VBScriptEngine(WindowsScriptEngineFlags.EnableDebugging);

            engine.Script.foo = new Action(() => throw new Exception("bar"));
            engine.Execute("sub test\nfoo\nend sub");

            try
            {
                engine.Invoke("test");
            }
            catch (ScriptEngineException exception)
            {
                Assert.IsTrue(exception.ErrorDetails.Contains("bar\n    at test (Script:1:0) -> foo"));
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VariantClear()
        {
            // ReSharper disable RedundantAssignment

            WeakReference wr = null;

            new Action(() =>
            {
                var x = new object();
                wr = new WeakReference(x);

                VariantClearTestHelper(x);
                x = null;
            })();

            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
            GC.WaitForPendingFinalizers();

            Assert.IsFalse(wr.IsAlive);

            // ReSharper restore RedundantAssignment
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_InteropMethodCallWithInteropArg()
        {
            engine.AddHostObject("host", new HostFunctions());
            engine.AddHostType("Automation", typeof(CUIAutomationClass));
            engine.AddHostType(typeof(UIA_PropertyIds));
            engine.AddHostType(typeof(UIA_ControlTypeIds));
            engine.AddHostType(typeof(IUIAutomationCondition));
            engine.Execute(@"
                automation = new Automation();
                condition1 = automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_CustomControlTypeId);
                condition2 = automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_CustomControlTypeId);
                condition3 = automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_CustomControlTypeId);
                conditions = host.newArr(IUIAutomationCondition, 3);
                conditions[0] = condition1;
                conditions[1] = condition2;
                conditions[2] = condition3;
                andCondition = automation.CreateAndCondition(condition1, condition2);
                andAndCondition = automation.CreateAndConditionFromArray(conditions);
            ");
        }

        // ReSharper restore InconsistentNaming

        #endregion

        #region miscellaneous

        private static void VariantClearTestHelper(object x)
        {
            using (var engine = new JScriptEngine())
            {
                engine.AddHostObject("x", x);
                engine.Evaluate("x");
            }
        }

        #endregion
    }
}

Web Proxy Viewer  |  New URL  |  Original Page