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

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

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading;
using System.Xml.Linq;
using Microsoft.ClearScript.V8;
using Microsoft.ClearScript.Util;
using Microsoft.ClearScript.Windows;
using Microsoft.CSharp.RuntimeBinder;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
using UIAutomationClient;

// ReSharper disable HeuristicUnreachableCode

namespace Microsoft.ClearScript.Test
{
    [TestClass]
    [DeploymentItem("ClearScriptV8-64.dll")]
    [DeploymentItem("ClearScriptV8-32.dll")]
    [DeploymentItem("v8-x64.dll")]
    [DeploymentItem("v8-ia32.dll")]
    [DeploymentItem("v8-base-x64.dll")]
    [DeploymentItem("v8-base-ia32.dll")]
    [DeploymentItem("v8-zlib-x64.dll")]
    [DeploymentItem("v8-zlib-ia32.dll")]
    [DeploymentItem("ClearScriptConsole.exe")]
    [DeploymentItem("Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll")]
    [SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable", Justification = "Test classes use TestCleanupAttribute for deterministic teardown.")]
    [SuppressMessage("ReSharper", "StringLiteralTypo")]
    [SuppressMessage("ReSharper", "IdentifierTypo")]
    public partial class BugFixTest : ClearScriptTest
    {
        #region setup / teardown

        private ScriptEngine engine;

        [TestInitialize]
        public void TestInitialize()
        {
            engine = new V8ScriptEngine(V8ScriptEngineFlags.EnableDebugging);
        }

        [TestCleanup]
        public void TestCleanup()
        {
            engine.Dispose();
            BaseTestCleanup();
        }

        #endregion

        #region test methods

        // ReSharper disable InconsistentNaming

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_NullArgBinding()
        {
            var value = 123.456 as IConvertible;
            engine.AddRestrictedHostObject("value", value);
            Assert.AreEqual(value.ToString(null), engine.Evaluate("value.ToString(null)"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_NullArgBinding_Ambiguous()
        {
            engine.AddHostObject("lib", new HostTypeCollection("mscorlib"));
            TestUtil.AssertException(() => engine.Execute("lib.System.Console.WriteLine(null)"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_DelegateConstructionSyntax()
        {
            engine.AddHostObject("lib", HostItemFlags.GlobalMembers, new HostTypeCollection("mscorlib"));
            var func = (Func)engine.Evaluate("new (System.Func(System.Int32, System.Int32))(function (x) {return x * x; })");
            Assert.AreEqual(25, func(5));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_DelegateConstructionSyntax_DoubleWrap()
        {
            engine.AddHostObject("lib", HostItemFlags.GlobalMembers, new HostTypeCollection("mscorlib"));
            engine.Execute("cb = new (System.Func(System.Int32, System.Int32))(function (x) {return x * x; })");
            var func = (Func)engine.Evaluate("new (System.Func(System.Int32, System.Int32))(cb)");
            Assert.AreEqual(25, func(5));
        }

        [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_V8ScriptInterruptCrash()
        {
            // run the test several times to verify post-interrupt engine functionality

            for (var iteration = 0; iteration < 16; iteration++)
            {
                var context = new PropertyBag();
                engine.AddHostObject("context", context);

                using (var startEvent = new ManualResetEventSlim(false))
                {
                    context["startEvent"] = startEvent;

                    var interrupted = false;
                    var thread = new Thread(() =>
                    {
                        try
                        {
                            engine.Execute("while (true) { context.startEvent.Set(); }");
                        }
                        catch (ScriptInterruptedException)
                        {
                            interrupted = true;
                        }
                    });

                    thread.Start();
                    startEvent.Wait();
                    engine.Interrupt();
                    thread.Join();
                    Assert.IsTrue(interrupted);
                }
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_InheritedInterfaceMethod()
        {
            var list = new List { 123 };
            var enumerator = list.AsEnumerable().GetEnumerator();
            engine.AddRestrictedHostObject("enumerator", enumerator);
            Assert.IsTrue((bool)engine.Evaluate("enumerator.MoveNext()"));
            Assert.AreEqual(123, engine.Evaluate("enumerator.Current"));
            Assert.IsFalse((bool)engine.Evaluate("enumerator.MoveNext()"));
            engine.Execute("enumerator.Dispose()");
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_EnumEquality()
        {
            engine.AddHostObject("host", new HostFunctions());
            engine.AddHostType("DayOfWeek", typeof(DayOfWeek));
            engine.AddHostType("BindingFlags", typeof(BindingFlags));
            Assert.IsTrue((bool)engine.Evaluate("DayOfWeek.Wednesday == DayOfWeek.Wednesday"));
            Assert.IsTrue((bool)engine.Evaluate("host.flags(BindingFlags.Public, BindingFlags.Instance) == host.flags(BindingFlags.Public, BindingFlags.Instance)"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_FloatParameterBinding()
        {
            engine.AddHostType("Convert", typeof(Convert));
            engine.Script.list = new List();
            const float floatPi = (float)Math.PI;
            engine.Execute("list.Add(Convert.ToSingle(Math.PI))");
            Assert.AreEqual(floatPi, engine.Script.list[0]);
        }

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

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_UInt32RoundTrip()
        {
            engine.AddHostType("UInt32", typeof(uint));
            Assert.AreEqual((long)uint.MaxValue, engine.Evaluate("UInt32.MaxValue"));
        }

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

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_AutoInt64FromDouble()
        {
            engine.AddHostType("Int32", typeof(int));
            Assert.AreEqual((long)int.MaxValue * 123 + 1, engine.Evaluate("Int32.MaxValue * 123 + 1"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_CompiledScriptResult()
        {
            engine.Script.host = new HostFunctions();
            using (var script = ((V8ScriptEngine)engine).Compile("host"))
            {
                Assert.IsInstanceOfType(((V8ScriptEngine)engine).Evaluate(script), typeof(HostFunctions));
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_GenericDelegateConstructorWithArgument()
        {
            engine.AddHostType("Func", "System.Func");
            engine.AddHostType("StringT", typeof(string));
            engine.AddHostType("IntT", typeof(int));
            var func = (Func)engine.Evaluate("new Func(StringT, IntT, function (s) { return s.length; })");
            const string testString = "floccinaucinihilipilification";
            Assert.AreEqual(testString.Length, func(testString));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_HostMethodAsArgument()
        {
            var testObject = new TestObject();
            engine.Script.testObject = testObject;
            engine.Script.expando = new ExpandoObject();
            engine.AddHostType("DateTime", typeof(DateTime));
            engine.Execute("expando.method = testObject.Method");
            Assert.AreEqual(testObject.Method("foo", 123), engine.Evaluate("expando.method('foo', 123)"));
            Assert.AreEqual(testObject.Method(456), engine.Evaluate("expando.method(DateTime, 456)"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_HostIndexedPropertyAsArgument()
        {
            var testObject = new TestObject();
            engine.Script.testObject = testObject;
            engine.Script.expando = new ExpandoObject();
            engine.Execute("expando.property = testObject.Item");
            Assert.AreEqual("foo", engine.Evaluate("expando.property.set(123, 'foo')"));
            Assert.AreEqual("foo", engine.Evaluate("expando.property.get(123)"));
            Assert.AreEqual("foo", engine.Evaluate("expando.property(123)"));
            Assert.AreEqual(456, engine.Evaluate("expando.property.set('bar', 456)"));
            Assert.AreEqual(456, engine.Evaluate("expando.property.get('bar')"));
            Assert.AreEqual(456, engine.Evaluate("expando.property('bar')"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_Nullable_Field()
        {
            engine.Script.test = new NullableTest();
            Assert.IsNull(engine.Evaluate("test.Field"));
            Assert.IsTrue((bool)engine.Evaluate("test.Field === null"));
            engine.Execute("test.Field = 123");
            Assert.AreEqual(123, engine.Evaluate("test.Field"));
            Assert.IsTrue((bool)engine.Evaluate("test.Field === 123"));
            engine.Execute("test.Field = null");
            Assert.IsNull(engine.Evaluate("test.Field"));
            Assert.IsTrue((bool)engine.Evaluate("test.Field === null"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_Nullable_Property()
        {
            engine.Script.test = new NullableTest();
            Assert.IsNull(engine.Evaluate("test.Property"));
            Assert.IsTrue((bool)engine.Evaluate("test.Property === null"));
            engine.Execute("test.Property = 123");
            Assert.AreEqual(123, engine.Evaluate("test.Property"));
            Assert.IsTrue((bool)engine.Evaluate("test.Property === 123"));
            engine.Execute("test.Property = null");
            Assert.IsNull(engine.Evaluate("test.Property"));
            Assert.IsTrue((bool)engine.Evaluate("test.Property === null"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_Nullable_ArgBinding()
        {
            var test = new NullableTest();
            engine.Script.test = test;
            Assert.IsNull(engine.Evaluate("test.Method(null)"));
            Assert.AreEqual(test.Method(5), engine.Evaluate("test.Method(5)"));
            Assert.AreEqual(test.Method(5.1), engine.Evaluate("test.Method(5.1)"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_GlobalObjectCrash()
        {
            engine.AddHostObject("random", HostItemFlags.GlobalMembers, new Random());
            Assert.AreEqual("[object Object]", engine.ExecuteCommand("this"));
        }

        [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_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_VBDynamicArgMarshaling_Numeric()
        {
            var result = TestUtil.InvokeVBTestFunction(@"
                Using engine As New V8ScriptEngine
                    engine.Execute(""data = [5, 4, 'qux', 2, 1]; function getElement(i1, i2, i3) { return data[i1 + i2 - i3]; }"")
                    TestFunction = engine.Script.getElement(CShort(1), CLng(99), CStr(98))
                End Using
            ");

            Assert.AreEqual("qux", result);
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_VBDynamicArgMarshaling_String()
        {
            var result = TestUtil.InvokeVBTestFunction(@"
                Using engine As New V8ScriptEngine
                    engine.Execute(""data = { foo26: 123, bar97: 456.789 }; function getElement(i1, i2) { return data[i1 + i2]; }"")
                    TestFunction = engine.Script.getElement(""bar"", CLng(97))
                End Using
            ");

            Assert.AreEqual(456.789, result);
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_AmbiguousAttribute()
        {
            engine.Script.foo = new AmbiguousAttributeTest();
            engine.Execute("foo.Foo()");
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_CoreBindCache()
        {
            HostItem.ResetCoreBindCache();

            engine.Dispose();
            for (var i = 0; i < 10; i++)
            {
                using (engine = new V8ScriptEngine(V8ScriptEngineFlags.EnableDebugging))
                {
                    engine.Script.host = new HostFunctions();
                    Assert.AreEqual(' ', engine.Evaluate("host.toChar(32)"));
                    Assert.AreEqual('A', engine.Evaluate("host.toChar(65)"));
                    Assert.AreEqual(0.0F, engine.Evaluate("host.toSingle(0)"));
                    Assert.AreEqual(1.0F, engine.Evaluate("host.toSingle(1)"));
                }
            }

            Assert.AreEqual(2L, HostItem.GetCoreBindCount());
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_StringWithNullChar()
        {
            const string value = "abc\0def";
            const string value2 = "ghi\0jkl";
            dynamic func = engine.Evaluate("(function (x) { return x.length; }).valueOf()");
            Assert.AreEqual(value.Length, func(value));
            Assert.AreEqual(value, engine.Evaluate(@"'abc\0def'"));
            dynamic obj = engine.Evaluate(@"({ 'abc\0def': 'ghi\0jkl' })");
            Assert.IsTrue(((DynamicObject)obj).GetDynamicMemberNames().Contains(value));
            Assert.AreEqual(value2, obj[value]);
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_V8ScriptItemWeakBinding()
        {
            // This test verifies that V8 script items no longer prevent their isolates from being
            // destroyed. Previously it exhausted address space and crashed in 32-bit mode.

            for (var i = 0; i < 128; i++)
            {
                using (var tempEngine = new V8ScriptEngine(V8ScriptEngineFlags.EnableDebugging))
                {
                    tempEngine.Evaluate("(function () {}).valueOf()");
                }
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_V8ScriptItemDispose()
        {
            dynamic item1;
            using (var tempEngine = new V8ScriptEngine(V8ScriptEngineFlags.EnableDebugging))
            {
                item1 = tempEngine.Evaluate("(function () { return 123; }).valueOf()");
                Assert.AreEqual(123, item1());

                dynamic item2 = tempEngine.Evaluate("(function () { return 456; }).valueOf()");
                using (item2 as IDisposable)
                {
                    Assert.AreEqual(456, item2());
                }
            }

            using (item1 as IDisposable)
            {
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_V8CompiledScriptWeakBinding()
        {
            // This test verifies that V8 compiled scripts no longer prevent their isolates from
            // being destroyed. Previously it exhausted address space and crashed in 32-bit mode.

            for (var i = 0; i < 128; i++)
            {
                using (var tempEngine = new V8ScriptEngine(V8ScriptEngineFlags.EnableDebugging))
                {
                    tempEngine.Compile("(function () {}).valueOf()");
                }
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_V8CompiledScriptDispose()
        {
            V8Script script1;
            using (var tempEngine = new V8ScriptEngine(V8ScriptEngineFlags.EnableDebugging))
            {
                script1 = tempEngine.Compile("(function () { return 123; })()");
                Assert.AreEqual(123, tempEngine.Evaluate(script1));

                V8Script script2 = tempEngine.Compile("(function () { return 456; })()");
                using (script2)
                {
                    Assert.AreEqual(456, tempEngine.Evaluate(script2));

                }
            }

            using (script1)
            {
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_V8ArrayBufferAllocator()
        {
            engine.Execute("buffer = new ArrayBuffer(12345)");
            Assert.AreEqual(12345, engine.Script.buffer.byteLength);
        }

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

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

            WeakReference wr = null;

            new Action(() =>
            {
                // ReSharper disable AccessToModifiedClosure

                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);

                // ReSharper restore AccessToModifiedClosure
            })();

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

            // ReSharper restore RedundantAssignment
        }

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

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

            WeakReference wr = null;

            new Action(() =>
            {
                // ReSharper disable AccessToModifiedClosure

                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);

                // ReSharper restore AccessToModifiedClosure
            })();

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

            // ReSharper restore RedundantAssignment
        }

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

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

            WeakReference wr1 = null;
            WeakReference wr2 = null;

            new Action(() =>
            {
                // ReSharper disable AccessToModifiedClosure

                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
                ");

                object result;
                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 result));
                Assert.AreEqual(x1.ToString() + x2, result);

                // ReSharper restore AccessToModifiedClosure
            })();

            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_IDispatchExArgLeak_InvokeMethod_JScript()
        {
            // ReSharper disable RedundantAssignment

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

            WeakReference wr1 = null;
            WeakReference wr2 = null;

            new Action(() =>
            {
                // ReSharper disable AccessToModifiedClosure

                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);

                // ReSharper restore AccessToModifiedClosure
            })();

            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_IDispatchExArgLeak_InvokeMethod_VBScript()
        {
            // ReSharper disable RedundantAssignment

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

            WeakReference wr1 = null;
            WeakReference wr2 = null;

            new Action(() =>
            {
                // ReSharper disable AccessToModifiedClosure

                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);

                // ReSharper restore AccessToModifiedClosure
            })();

            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_V8CachedObjectLeak()
        {
            WeakReference wr = null;

            new Action(() =>
            {
                // ReSharper disable RedundantAssignment

                object x = null;

                using (var tempEngine = new V8ScriptEngine())
                {
                    tempEngine.AddHostType("Action", typeof(Action));
                    x = tempEngine.Evaluate("action = new Action(function () {})");
                    wr = new WeakReference(tempEngine);
                }

                Assert.IsInstanceOfType(x, typeof(Action));
                TestUtil.AssertException((Action)x);

                x = null;

                // ReSharper restore RedundantAssignment
            })();

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

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_Resurrection_V8ScriptEngine()
        {
            for (var index = 0; index < 256; index++)
            {
                // ReSharper disable UnusedVariable

                var wrapper = new ResurrectionTestWrapper(new V8ScriptEngine());
                GC.Collect();

                // ReSharper restore UnusedVariable
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_Resurrection_V8Runtime()
        {
            for (var index = 0; index < 256; index++)
            {
                // ReSharper disable UnusedVariable

                var wrapper = new ResurrectionTestWrapper(new V8Runtime());
                GC.Collect();

                // ReSharper restore UnusedVariable
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_Resurrection_V8Script()
        {
            for (var index = 0; index < 256; index++)
            {
                // ReSharper disable UnusedVariable

                var tempEngine = new V8ScriptEngine();
                var wrapper = new ResurrectionTestWrapper(tempEngine.Compile("function foo() {}"));
                GC.Collect();

                // ReSharper restore UnusedVariable
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_Resurrection_V8ScriptItem()
        {
            for (var index = 0; index < 256; index++)
            {
                // ReSharper disable UnusedVariable

                var tempEngine = new V8ScriptEngine();
                var wrapper = new ResurrectionTestWrapper(tempEngine.Script.Math);
                GC.Collect();

                // ReSharper restore UnusedVariable
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_V8GlobalMembers_ReadOnlyPropertyCrash()
        {
            // this test is for a crash that occurred only on debug V8 builds
            engine.AddHostObject("bag", HostItemFlags.GlobalMembers, new PropertyBag());
            engine.AddHostObject("test", HostItemFlags.GlobalMembers, new { foo = 123 });
            TestUtil.AssertException(() => engine.Execute("foo = 456"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_V8GlobalMembers_ReadOnlyPropertyCrash_Index()
        {
            // this test is for a crash that occurred only on debug V8 builds
            engine.AddHostObject("bag", HostItemFlags.GlobalMembers, new PropertyBag());
            engine.AddHostObject("test", HostItemFlags.GlobalMembers, new ReadOnlyCollection(new[] { 5, 4, 3, 2, 1 }));
            TestUtil.AssertException(() => engine.Execute("this[2] = 123"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_V8GlobalMembers_NativeFunctionHiding()
        {
            engine.Execute("function toString() { return 'ABC'; }");
            engine.AddHostObject("bag", HostItemFlags.GlobalMembers, new PropertyBag());
            Assert.AreEqual("ABC", engine.Evaluate("toString()"));
        }

        [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_CallHostObjectFunctionAsConstructor()
        {
            engine.Script.random = new Random();
            engine.AddHostType("Random", typeof(Random));
            var result = engine.Evaluate(@"
                (function () {
                    var x = new Random().NextDouble();
                    try {
                        return new random.constructor();
                    }
                    catch (ex) {
                        return new Random().NextDouble() * x;
                    }
                    return false;
                })()
            ");
            Assert.IsInstanceOfType(result, typeof(double));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_HostItemCachingForHostVariables()
        {
            var foo = new HostFunctions().newVar(new object());
            engine.Script.foo1 = foo;
            engine.Script.foo2 = foo;
            Assert.IsTrue(Convert.ToBoolean(engine.Evaluate("foo1 === foo2")));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_MetaScriptItem_GetDynamicMemberNames()
        {
            var dmop = (IDynamicMetaObjectProvider)engine.Evaluate("({ foo: 123, bar: 456, baz: 789 })");
            var dmo = dmop.GetMetaObject(Expression.Constant(dmop));
            var names = dmo.GetDynamicMemberNames().ToArray();
            Assert.IsTrue(names.Contains("foo"));
            Assert.IsTrue(names.Contains("bar"));
            Assert.IsTrue(names.Contains("baz"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_AmbiguousIndexer()
        {
            IAmbiguousIndexer indexer = new AmbiguousIndexer();
            engine.AddRestrictedHostObject("indexer", indexer);
            engine.AddHostType("DayOfWeek", typeof(DayOfWeek));

            engine.Execute("indexer.Item.set(123, 456)");
            Assert.AreEqual(456, engine.Evaluate("indexer.Item(123)"));
            Assert.IsNull(engine.Evaluate("indexer.Item(789)"));

            engine.Execute("indexer.Item.set(DayOfWeek.Thursday, DayOfWeek.Sunday)");
            Assert.AreEqual(DayOfWeek.Sunday, engine.Evaluate("indexer.Item(DayOfWeek.Thursday)"));
            Assert.IsNull(engine.Evaluate("indexer.Item(DayOfWeek.Tuesday)"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_InaccessiblePropertyAccessors()
        {
            engine.Script.foo = new InaccessiblePropertyAccessors();

            TestUtil.AssertException(() => engine.Evaluate("foo.NoGetter"));
            Assert.AreEqual(123, engine.Evaluate("foo.NoGetter = 123"));

            TestUtil.AssertException(() => engine.Evaluate("foo.PrivateGetter"));
            Assert.AreEqual(456, engine.Evaluate("foo.PrivateGetter = 456"));

            Assert.AreEqual(456, engine.Evaluate("foo.NoSetter"));
            TestUtil.AssertException(() => engine.Evaluate("foo.NoSetter = 789"));

            Assert.AreEqual(456, engine.Evaluate("foo.PrivateSetter"));
            TestUtil.AssertException(() => engine.Evaluate("foo.PrivateSetter = 789"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_InaccessiblePropertyAccessors_Static()
        {
            engine.AddHostType("foo", typeof(InaccessiblePropertyAccessorsStatic));

            TestUtil.AssertException(() => engine.Evaluate("foo.NoGetter"));
            Assert.AreEqual(123, engine.Evaluate("foo.NoGetter = 123"));

            TestUtil.AssertException(() => engine.Evaluate("foo.PrivateGetter"));
            Assert.AreEqual(456, engine.Evaluate("foo.PrivateGetter = 456"));

            Assert.AreEqual(456, engine.Evaluate("foo.NoSetter"));
            TestUtil.AssertException(() => engine.Evaluate("foo.NoSetter = 789"));

            Assert.AreEqual(456, engine.Evaluate("foo.PrivateSetter"));
            TestUtil.AssertException(() => engine.Evaluate("foo.PrivateSetter = 789"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_V8RuntimeConstraintScale()
        {
            const int maxNewSpaceSize = 16;
            const int maxOldSpaceSize = 512;
            const double tolerance = .05;

            var constraints = new V8RuntimeConstraints
            {
                MaxNewSpaceSize = maxNewSpaceSize,
                MaxOldSpaceSize = maxOldSpaceSize
            };

            using (var tempEngine = new V8ScriptEngine(constraints))
            {
                Assert.AreEqual(Math.PI, tempEngine.Evaluate("Math.PI"));
                var expected = Convert.ToDouble(maxNewSpaceSize * 2 + maxOldSpaceSize);
                var actual = Convert.ToDouble(tempEngine.GetRuntimeHeapInfo().HeapSizeLimit / (1024 * 1024));
                var ratio = actual / expected;
                Assert.IsTrue((ratio >= 1 - tolerance) && (ratio = 1 - tolerance) && (ratio  new JScriptEngine(WindowsScriptEngineFlags.EnableDebugging)).ToArray();
            Array.ForEach(engines, tempEngine => tempEngine.Dispose());
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_AssemblyHelpersClass()
        {
            Assert.IsTrue(typeof(AssemblyHelpers).IsStatic());
            Assert.IsNull(typeof(AssemblyHelpers).TypeInitializer);
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_FinalizerHang_V8ScriptItem()
        {
            engine.Script.foo = new Action(arg => {});
            engine.Script.bar = new Action(() =>
            {
                GC.Collect();
                GC.WaitForPendingFinalizers();
            });

            engine.Execute(@"
                for (var i = 0; i < 100; i++) {
                    foo({ index: i });
                }
                bar();
            ");
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_FinalizerHang_V8Script()
        {
            engine.Script.bar = new Action(() =>
            {
                GC.Collect();
                GC.WaitForPendingFinalizers();
            });

            for (var index = 0; index < 100; index++)
            {
                ((V8ScriptEngine)engine).Compile("function foo() { return " + index + "; }");
            }

            engine.Execute("bar()");
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_FinalizerHang_V8ScriptEngine()
        {
            engine.Dispose();

            using (var runtime = new V8Runtime(V8RuntimeFlags.EnableDebugging))
            {
                engine = runtime.CreateScriptEngine();
                engine.Script.bar = new Action(() =>
                {
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                });

                for (var index = 0; index < 100; index++)
                {
                    runtime.CreateScriptEngine();
                }

                engine.Execute("bar()");
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_DynamicMethodArgs()
        {
            engine.Script.foo = new DynamicMethodArgTest();
            Assert.AreEqual("123 456.789 hello", engine.Evaluate("foo.RunTest(123, 456.789, 'hello')"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_NestedInterrupt()
        {
            var context = new PropertyBag();
            engine.AddHostObject("context", context);

            using (var startEvent = new ManualResetEventSlim(false))
            {
                object result = null;
                var interruptedInner = false;
                var interruptedOuter = false;

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

                var thread = new Thread(() =>
                {
                    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);
            }
        }

        [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();
            x["foo"] = 123;
            x["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_PropertyBag_NativeEnumerator_VBScript()
        {
            engine.Dispose();
            engine = new VBScriptEngine();

            var x = new PropertyBag();
            x["foo"] = 123;
            x["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_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();
            x["foo"] = 123;
            x["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();
            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_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_NumericArgConversion_Delegate()
        {
            engine.Script.host = new HostFunctions();
            engine.Script.sbyteFunc = new Func(arg => arg);
            engine.Script.nullableSByteFunc = new Func(arg => arg);
            engine.Script.floatFunc = new Func(arg => arg);
            engine.Script.nullableFloatFunc = new Func(arg => arg);
            engine.Script.doubleFunc = new Func(arg => arg);
            engine.Script.nullableDoubleFunc = new Func(arg => arg);
            engine.Script.decimalFunc = new Func(arg => arg);
            engine.Script.nullableDecimalFunc = new Func(arg => arg);

            Assert.AreEqual(123, engine.Evaluate("sbyteFunc(123)"));
            TestUtil.AssertException(() => engine.Execute("sbyteFunc(234)"));
            TestUtil.AssertException(() => engine.Execute("sbyteFunc(123.5)"));
            TestUtil.AssertException(() => engine.Execute("sbyteFunc(Math.PI)"));
            TestUtil.AssertException(() => engine.Execute("sbyteFunc(host.toDecimal(Math.PI))"));

            Assert.AreEqual(123, engine.Evaluate("nullableSByteFunc(123)"));
            TestUtil.AssertException(() => engine.Execute("nullableSByteFunc(234)"));
            TestUtil.AssertException(() => engine.Execute("nullableSByteFunc(123.5)"));
            TestUtil.AssertException(() => engine.Execute("nullableSByteFunc(Math.PI)"));
            TestUtil.AssertException(() => engine.Execute("nullableSByteFunc(host.toDecimal(Math.PI))"));
            Assert.IsNull(engine.Evaluate("nullableSByteFunc(null)"));

            Assert.AreEqual(123, engine.Evaluate("floatFunc(123)"));
            Assert.AreEqual(123.5f, engine.Evaluate("floatFunc(123.5)"));
            Assert.AreEqual((float)Math.PI, engine.Evaluate("floatFunc(Math.PI)"));
            Assert.AreEqual((float)Math.PI, engine.Evaluate("floatFunc(host.toDecimal(Math.PI))"));

            Assert.AreEqual(123, engine.Evaluate("nullableFloatFunc(123)"));
            Assert.AreEqual(123.5f, engine.Evaluate("nullableFloatFunc(123.5)"));
            Assert.AreEqual((float)Math.PI, engine.Evaluate("nullableFloatFunc(Math.PI)"));
            Assert.AreEqual((float)Math.PI, engine.Evaluate("nullableFloatFunc(host.toDecimal(Math.PI))"));
            Assert.IsNull(engine.Evaluate("nullableFloatFunc(null)"));

            Assert.AreEqual(123, engine.Evaluate("doubleFunc(123)"));
            Assert.AreEqual(123.5f, engine.Evaluate("doubleFunc(123.5)"));
            Assert.AreEqual(Math.PI, engine.Evaluate("doubleFunc(Math.PI)"));
            Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("doubleFunc(host.toDecimal(Math.PI))"));

            Assert.AreEqual(123, engine.Evaluate("nullableDoubleFunc(123)"));
            Assert.AreEqual(123.5f, engine.Evaluate("nullableDoubleFunc(123.5)"));
            Assert.AreEqual(Math.PI, engine.Evaluate("nullableDoubleFunc(Math.PI)"));
            Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("nullableDoubleFunc(host.toDecimal(Math.PI))"));
            Assert.IsNull(engine.Evaluate("nullableDoubleFunc(null)"));

            Assert.AreEqual(123, engine.Evaluate("decimalFunc(123)"));
            Assert.AreEqual(123.5f, engine.Evaluate("decimalFunc(123.5)"));
            Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("decimalFunc(Math.PI)"));
            Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("decimalFunc(host.toDecimal(Math.PI))"));

            Assert.AreEqual(123, engine.Evaluate("nullableDecimalFunc(123)"));
            Assert.AreEqual(123.5f, engine.Evaluate("nullableDecimalFunc(123.5)"));
            Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("nullableDecimalFunc(Math.PI)"));
            Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("nullableDecimalFunc(host.toDecimal(Math.PI))"));
            Assert.IsNull(engine.Evaluate("nullableDecimalFunc(null)"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_NumericArgConversion_Field()
        {
            engine.Script.host = new HostFunctions();
            engine.Script.test = new NumericArgConversionTest();

            Assert.AreEqual(123, engine.Evaluate("test.SByteField = 123; test.SByteField"));
            TestUtil.AssertException(() => engine.Execute("test.SByteField = 234"));
            TestUtil.AssertException(() => engine.Execute("test.SByteField = 123.5"));
            TestUtil.AssertException(() => engine.Execute("test.SByteField = Math.PI"));
            TestUtil.AssertException(() => engine.Execute("test.SByteField = host.toDecimal(Math.PI)"));

            Assert.AreEqual(123, engine.Evaluate("test.NullableSByteField = 123; test.NullableSByteField"));
            TestUtil.AssertException(() => engine.Execute("test.NullableSByteField = 234"));
            TestUtil.AssertException(() => engine.Execute("test.NullableSByteField = 123.5"));
            TestUtil.AssertException(() => engine.Execute("test.NullableSByteField = Math.PI"));
            TestUtil.AssertException(() => engine.Execute("test.NullableSByteField = host.toDecimal(Math.PI)"));
            Assert.IsNull(engine.Evaluate("test.NullableSByteField = null; test.NullableSByteField"));

            Assert.AreEqual(123, engine.Evaluate("test.FloatField = 123; test.FloatField"));
            Assert.AreEqual(123.5f, engine.Evaluate("test.FloatField = 123.5; test.FloatField"));
            Assert.AreEqual((float)Math.PI, engine.Evaluate("test.FloatField = Math.PI; test.FloatField"));
            Assert.AreEqual((float)Math.PI, engine.Evaluate("test.FloatField = host.toDecimal(Math.PI); test.FloatField"));

            Assert.AreEqual(123, engine.Evaluate("test.NullableFloatField = 123; test.NullableFloatField"));
            Assert.AreEqual(123.5f, engine.Evaluate("test.NullableFloatField = 123.5; test.NullableFloatField"));
            Assert.AreEqual((float)Math.PI, engine.Evaluate("test.NullableFloatField = Math.PI; test.NullableFloatField"));
            Assert.AreEqual((float)Math.PI, engine.Evaluate("test.NullableFloatField = host.toDecimal(Math.PI); test.NullableFloatField"));
            Assert.IsNull(engine.Evaluate("test.NullableFloatField = null; test.NullableFloatField"));

            Assert.AreEqual(123, engine.Evaluate("test.DoubleField = 123; test.DoubleField"));
            Assert.AreEqual(123.5f, engine.Evaluate("test.DoubleField = 123.5; test.DoubleField"));
            Assert.AreEqual(Math.PI, engine.Evaluate("test.DoubleField = Math.PI; test.DoubleField"));
            Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.DoubleField = host.toDecimal(Math.PI); test.DoubleField"));

            Assert.AreEqual(123, engine.Evaluate("test.NullableDoubleField = 123; test.NullableDoubleField"));
            Assert.AreEqual(123.5f, engine.Evaluate("test.NullableDoubleField = 123.5; test.NullableDoubleField"));
            Assert.AreEqual(Math.PI, engine.Evaluate("test.NullableDoubleField = Math.PI; test.NullableDoubleField"));
            Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.NullableDoubleField = host.toDecimal(Math.PI); test.NullableDoubleField"));
            Assert.IsNull(engine.Evaluate("test.NullableDoubleField = null; test.NullableDoubleField"));

            Assert.AreEqual(123, engine.Evaluate("test.DecimalField = 123; test.DecimalField"));
            Assert.AreEqual(123.5f, engine.Evaluate("test.DecimalField = 123.5; test.DecimalField"));
            Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.DecimalField = Math.PI; test.DecimalField"));
            Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.DecimalField = host.toDecimal(Math.PI); test.DecimalField"));

            Assert.AreEqual(123, engine.Evaluate("test.NullableDecimalField = 123; test.NullableDecimalField"));
            Assert.AreEqual(123.5f, engine.Evaluate("test.NullableDecimalField = 123.5; test.NullableDecimalField"));
            Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.NullableDecimalField = Math.PI; test.NullableDecimalField"));
            Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.NullableDecimalField = host.toDecimal(Math.PI); test.NullableDecimalField"));
            Assert.IsNull(engine.Evaluate("test.NullableDecimalField = null; test.NullableDecimalField"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_NumericArgConversion_Method()
        {
            engine.Script.host = new HostFunctions();
            engine.Script.test = new NumericArgConversionTest();

            Assert.AreEqual(123, engine.Evaluate("test.SByteMethod(123)"));
            TestUtil.AssertException(() => engine.Execute("test.SByteMethod(234)"));
            TestUtil.AssertException(() => engine.Execute("test.SByteMethod(123.5)"));
            TestUtil.AssertException(() => engine.Execute("test.SByteMethod(Math.PI)"));
            TestUtil.AssertException(() => engine.Execute("test.SByteMethod(host.toDecimal(Math.PI))"));

            Assert.AreEqual(123, engine.Evaluate("test.NullableSByteMethod(123)"));
            TestUtil.AssertException(() => engine.Execute("test.NullableSByteMethod(234)"));
            TestUtil.AssertException(() => engine.Execute("test.NullableSByteMethod(123.5)"));
            TestUtil.AssertException(() => engine.Execute("test.NullableSByteMethod(Math.PI)"));
            TestUtil.AssertException(() => engine.Execute("test.NullableSByteMethod(host.toDecimal(Math.PI))"));
            Assert.IsNull(engine.Evaluate("test.NullableSByteMethod(null)"));

            Assert.AreEqual(123, engine.Evaluate("test.FloatMethod(123)"));
            Assert.AreEqual(123.5f, engine.Evaluate("test.FloatMethod(123.5)"));
            TestUtil.AssertException(() => engine.Execute("test.FloatMethod(Math.PI)"));
            TestUtil.AssertException(() => engine.Execute("test.FloatMethod(host.toDecimal(Math.PI))"));

            Assert.AreEqual(123, engine.Evaluate("test.NullableFloatMethod(123)"));
            Assert.AreEqual(123.5f, engine.Evaluate("test.NullableFloatMethod(123.5)"));
            TestUtil.AssertException(() => engine.Execute("test.NullableFloatMethod(Math.PI)"));
            TestUtil.AssertException(() => engine.Execute("test.NullableFloatMethod(host.toDecimal(Math.PI))"));
            Assert.IsNull(engine.Evaluate("test.NullableFloatMethod(null)"));

            Assert.AreEqual(123, engine.Evaluate("test.DoubleMethod(123)"));
            Assert.AreEqual(123.5f, engine.Evaluate("test.DoubleMethod(123.5)"));
            Assert.AreEqual(Math.PI, engine.Evaluate("test.DoubleMethod(Math.PI)"));
            TestUtil.AssertException(() => engine.Execute("test.DoubleMethod(host.toDecimal(Math.PI))"));

            Assert.AreEqual(123, engine.Evaluate("test.NullableDoubleMethod(123)"));
            Assert.AreEqual(123.5f, engine.Evaluate("test.NullableDoubleMethod(123.5)"));
            Assert.AreEqual(Math.PI, engine.Evaluate("test.NullableDoubleMethod(Math.PI)"));
            TestUtil.AssertException(() => engine.Execute("test.NullableDoubleMethod(host.toDecimal(Math.PI))"));
            Assert.IsNull(engine.Evaluate("test.NullableDoubleMethod(null)"));

            Assert.AreEqual(123, engine.Evaluate("test.DecimalMethod(123)"));
            TestUtil.AssertException(() => engine.Execute("test.DecimalMethod(123.5)"));
            TestUtil.AssertException(() => engine.Execute("test.DecimalMethod(Math.PI)"));
            Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.DecimalMethod(host.toDecimal(Math.PI))"));

            Assert.AreEqual(123, engine.Evaluate("test.NullableDecimalMethod(123)"));
            TestUtil.AssertException(() => engine.Execute("test.NullableDecimalMethod(123.5)"));
            TestUtil.AssertException(() => engine.Execute("test.NullableDecimalMethod(Math.PI)"));
            Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.NullableDecimalMethod(host.toDecimal(Math.PI))"));
            Assert.IsNull(engine.Evaluate("test.NullableDecimalMethod(null)"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_NumericArgConversion_Property()
        {
            engine.Script.host = new HostFunctions();
            engine.Script.test = new NumericArgConversionTest();

            Assert.AreEqual(123, engine.Evaluate("test.SByteProperty = 123; test.SByteProperty"));
            TestUtil.AssertException(() => engine.Execute("test.SByteProperty = 234"));
            TestUtil.AssertException(() => engine.Execute("test.SByteProperty = 123.5"));
            TestUtil.AssertException(() => engine.Execute("test.SByteProperty = Math.PI"));
            TestUtil.AssertException(() => engine.Execute("test.SByteProperty = host.toDecimal(Math.PI)"));

            Assert.AreEqual(123, engine.Evaluate("test.NullableSByteProperty = 123; test.NullableSByteProperty"));
            TestUtil.AssertException(() => engine.Execute("test.NullableSByteProperty = 234"));
            TestUtil.AssertException(() => engine.Execute("test.NullableSByteProperty = 123.5"));
            TestUtil.AssertException(() => engine.Execute("test.NullableSByteProperty = Math.PI"));
            TestUtil.AssertException(() => engine.Execute("test.NullableSByteProperty = host.toDecimal(Math.PI)"));
            Assert.IsNull(engine.Evaluate("test.NullableSByteProperty = null; test.NullableSByteProperty"));

            Assert.AreEqual(123, engine.Evaluate("test.FloatProperty = 123; test.FloatProperty"));
            Assert.AreEqual(123.5f, engine.Evaluate("test.FloatProperty = 123.5; test.FloatProperty"));
            Assert.AreEqual((float)Math.PI, engine.Evaluate("test.FloatProperty = Math.PI; test.FloatProperty"));
            Assert.AreEqual((float)Math.PI, engine.Evaluate("test.FloatProperty = host.toDecimal(Math.PI); test.FloatProperty"));

            Assert.AreEqual(123, engine.Evaluate("test.NullableFloatProperty = 123; test.NullableFloatProperty"));
            Assert.AreEqual(123.5f, engine.Evaluate("test.NullableFloatProperty = 123.5; test.NullableFloatProperty"));
            Assert.AreEqual((float)Math.PI, engine.Evaluate("test.NullableFloatProperty = Math.PI; test.NullableFloatProperty"));
            Assert.AreEqual((float)Math.PI, engine.Evaluate("test.NullableFloatProperty = host.toDecimal(Math.PI); test.NullableFloatProperty"));
            Assert.IsNull(engine.Evaluate("test.NullableFloatProperty = null; test.NullableFloatProperty"));

            Assert.AreEqual(123, engine.Evaluate("test.DoubleProperty = 123; test.DoubleProperty"));
            Assert.AreEqual(123.5f, engine.Evaluate("test.DoubleProperty = 123.5; test.DoubleProperty"));
            Assert.AreEqual(Math.PI, engine.Evaluate("test.DoubleProperty = Math.PI; test.DoubleProperty"));
            Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.DoubleProperty = host.toDecimal(Math.PI); test.DoubleProperty"));

            Assert.AreEqual(123, engine.Evaluate("test.NullableDoubleProperty = 123; test.NullableDoubleProperty"));
            Assert.AreEqual(123.5f, engine.Evaluate("test.NullableDoubleProperty = 123.5; test.NullableDoubleProperty"));
            Assert.AreEqual(Math.PI, engine.Evaluate("test.NullableDoubleProperty = Math.PI; test.NullableDoubleProperty"));
            Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.NullableDoubleProperty = host.toDecimal(Math.PI); test.NullableDoubleProperty"));
            Assert.IsNull(engine.Evaluate("test.NullableDoubleProperty = null; test.NullableDoubleProperty"));

            Assert.AreEqual(123, engine.Evaluate("test.DecimalProperty = 123; test.DecimalProperty"));
            Assert.AreEqual(123.5f, engine.Evaluate("test.DecimalProperty = 123.5; test.DecimalProperty"));
            Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.DecimalProperty = Math.PI; test.DecimalProperty"));
            Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.DecimalProperty = host.toDecimal(Math.PI); test.DecimalProperty"));

            Assert.AreEqual(123, engine.Evaluate("test.NullableDecimalProperty = 123; test.NullableDecimalProperty"));
            Assert.AreEqual(123.5f, engine.Evaluate("test.NullableDecimalProperty = 123.5; test.NullableDecimalProperty"));
            Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.NullableDecimalProperty = Math.PI; test.NullableDecimalProperty"));
            Assert.AreEqual((double)(decimal)Math.PI, engine.Evaluate("test.NullableDecimalProperty = host.toDecimal(Math.PI); test.NullableDecimalProperty"));
            Assert.IsNull(engine.Evaluate("test.NullableDecimalProperty = null; test.NullableDecimalProperty"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_ScriptObjectInHostVariable()
        {
            engine.Script.host = new HostFunctions();
            var documentInfo = new DocumentInfo("Expression") { Flags = DocumentFlags.IsTransient };
            Assert.IsTrue(engine.Evaluate(documentInfo.MakeUnique(engine), "host.newVar({})", false).ToString().StartsWith("[HostVariable:", StringComparison.Ordinal));
        }

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

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_V8HostMethodClobbering()
        {
            engine.Script.host = new HostFunctions();
            Assert.IsInstanceOfType(engine.Evaluate("host.newObj()"), typeof(PropertyBag));
            TestUtil.AssertException(() => engine.Execute("host.newObj = 123"));
            Assert.IsInstanceOfType(engine.Evaluate("host.newObj()"), typeof(PropertyBag));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_V8NativePropertyHiding()
        {
            var foo = new { toString = new Func(() => "testValue") };
            engine.Script.foo = foo;
            Assert.AreEqual(foo.toString(), engine.Evaluate("foo.toString()"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_V8NativePropertyHiding_Method()
        {
            var foo = new HideNativeJavaScriptMethod();
            engine.Script.foo = foo;
            Assert.AreEqual(foo.toString(), engine.Evaluate("foo.toString()"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_EquatableComparison_DateTime()
        {
            engine.Script.x = new DateTime(2007, 5, 22);
            engine.Script.y = new DateTime(2007, 5, 22);
            engine.Script.z = new DateTime(2008, 5, 22);
            Assert.IsTrue((bool)engine.Evaluate("(x == y) && (x === y)"));
            Assert.IsFalse((bool)engine.Evaluate("(x != y) || (x !== y)"));
            Assert.IsTrue((bool)engine.Evaluate("(x != z) && (x !== z)"));
            Assert.IsFalse((bool)engine.Evaluate("(x == z) || (x === z)"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_EquatableComparison_TimeSpan()
        {
            engine.Script.x = TimeSpan.FromSeconds(3.5);
            engine.Script.y = TimeSpan.FromSeconds(3.5);
            engine.Script.z = TimeSpan.FromSeconds(3.6);
            Assert.IsTrue((bool)engine.Evaluate("(x == y) && (x === y)"));
            Assert.IsFalse((bool)engine.Evaluate("(x != y) || (x !== y)"));
            Assert.IsTrue((bool)engine.Evaluate("(x != z) && (x !== z)"));
            Assert.IsFalse((bool)engine.Evaluate("(x == z) || (x === z)"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_EquatableComparison_WrappedNumeric()
        {
            var host = new HostFunctions();
            engine.Script.x = host.toUInt16(25);
            engine.Script.y = host.toUInt16(25);
            engine.Script.z = host.toUInt16(26);
            Assert.IsTrue((bool)engine.Evaluate("(x == y) && (x === y)"));
            Assert.IsFalse((bool)engine.Evaluate("(x != y) || (x !== y)"));
            Assert.IsTrue((bool)engine.Evaluate("(x != z) && (x !== z)"));
            Assert.IsFalse((bool)engine.Evaluate("(x == z) || (x === z)"));
        }

        [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_AddHostType_AssemblyQualifiedName()
        {
            engine.AddHostType("Random", typeof(Random).AssemblyQualifiedName);
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_DoubleExecution()
        {
            engine.Execute(@"
                var num = 0;
                function foo() {
                    num += 1;
                    throw new Error();
                }
            ");

            try
            {
                engine.Script.foo();
            }
            catch (ScriptEngineException)
            {
            }

            Assert.AreEqual(1, engine.Script.num);

            engine.Script.num = 0;
            dynamic foo = engine.Script.foo;

            try
            {
                foo();
            }
            catch (ScriptEngineException)
            {
            }

            Assert.AreEqual(1, engine.Script.num);
        }

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

        [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_DoubleExecution_Delegate()
        {
            // ReSharper disable EmptyGeneralCatchClause

            var num = 0;
            engine.Script.foo = new Action(() =>
            {
                // ReSharper disable AccessToModifiedClosure

                num += 1;
                throw new Exception();

                // ReSharper restore AccessToModifiedClosure
            });

            try
            {
                engine.Script.foo();
            }
            catch (ScriptEngineException)
            {
            }

            Assert.AreEqual(1, num);

            num = 0;
            dynamic foo = engine.Script.foo;

            try
            {
                foo();
            }
            catch (Exception)
            {
            }

            Assert.AreEqual(1, num);

            // ReSharper restore EmptyGeneralCatchClause
        }

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

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_SharedV8RuntimeLeak()
        {
            using (var runtime = new V8Runtime())
            {
                using (runtime.CreateScriptEngine())
                {
                }

                runtime.CollectGarbage(true);
                var heapSize = runtime.GetHeapInfo().TotalHeapSize;

                for (var i = 0; i < 500; i++)
                {
                    using (runtime.CreateScriptEngine())
                    {
                    }

                    if ((i % 25) == 24)
                    {
                        runtime.CollectGarbage(true);
                    }
                }

                runtime.CollectGarbage(true);
                Assert.IsFalse(runtime.GetHeapInfo().TotalHeapSize > (heapSize * 1.75));
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_V8ExceptionWhileInterrupting()
        {
            var context = new PropertyBag();
            engine.Script.context = context;

            var startEvent = new ManualResetEventSlim();
            var waitEvent = new ManualResetEventSlim();
            var tokenSource = new CancellationTokenSource();

            context["count"] = 0;
            context["startEvent"] = startEvent;
            context["waitForCancel"] = new Action(() => waitEvent.Wait(tokenSource.Token));

            var thread = new Thread(() =>
            {
                try
                {
                    engine.Execute(@"
                        context.count = 1;
                        context.startEvent.Set();
                        context.waitForCancel();
                        context.count = 2;
                    ");
                }
                catch (ScriptEngineException)
                {
                }
                catch (ScriptInterruptedException)
                {
                }
            });

            thread.Start();
            startEvent.Wait(Timeout.Infinite);

            tokenSource.Cancel();
            engine.Interrupt();
            thread.Join();

            Assert.AreEqual(1, context["count"]);
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_NestedType()
        {
            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_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_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_V8_Date_now()
        {
            var value = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
            var scriptValue = Convert.ToDouble(engine.Evaluate("Date.now()"));
            Assert.IsTrue(Math.Abs(scriptValue - value) < 25.0);
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_NonEnumerablePropertyAccess()
        {
            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()
        {
            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_VB()
        {
            TestUtil.InvokeVBTestSub(@"
                Using engine As New V8ScriptEngine
                    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_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_VB()
        {
            TestUtil.InvokeVBTestSub(@"
                Using engine As New V8ScriptEngine
                    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_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_JsonDotNetSerialization()
        {
            var obj = engine.Evaluate("({foo:123,bar:'baz'})");
            Assert.AreEqual("{\"foo\":123,\"bar\":\"baz\"}", JsonConvert.SerializeObject(obj));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_RuntimeCompileException()
        {
            using (var runtime = new V8Runtime())
            {
                // ReSharper disable once AccessToDisposedClosure
                TestUtil.AssertException(() => runtime.Compile("function foo bar () {}"));
            }
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_PropertyAccessorScriptability()
        {
            engine.Script.testObject = new PropertyAccessorScriptability();
            engine.Execute("testObject.Foo = 123");
            Assert.AreEqual(123, engine.Evaluate("testObject.Foo"));

            TestUtil.AssertException(() => engine.Execute("testObject.Bar = 123"));
            TestUtil.AssertException(() => engine.Evaluate("testObject.Bar"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_PropertyAccessorScriptability_Static()
        {
            engine.AddHostType("TestObject", typeof(PropertyAccessorScriptabilityStatic));
            engine.Execute("TestObject.Foo = 123");
            Assert.AreEqual(123, engine.Evaluate("TestObject.Foo"));

            TestUtil.AssertException(() => engine.Execute("TestObject.Bar = 123"));
            TestUtil.AssertException(() => engine.Evaluate("TestObject.Bar"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_PublicOverrideInInternalClass()
        {
            engine.Script.foo = new PublicOverrideTest();
            Assert.AreEqual(789, engine.Evaluate("foo.AbstractMethod()"));
            Assert.AreEqual(456, engine.Evaluate("foo.VirtualMethod()"));
            Assert.AreEqual("baz", engine.Evaluate("foo.AbstractProperty"));
            Assert.AreEqual("bar", engine.Evaluate("foo.VirtualProperty"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_ImplicitConversionOperators()
        {
            engine.Script.doc = XDocument.Parse("barqux");
            engine.AddHostType(typeof(Enumerable));
            engine.AddHostType(typeof(XmlName));
            Assert.AreEqual(1, engine.Evaluate("doc.Root.Elements('foo').Count()"));
            Assert.AreEqual("bar", engine.Evaluate("doc.Root.Elements('foo').First().ToString()"));
            Assert.AreEqual(1, engine.Evaluate("doc.Root.Elements(new XmlName('foo')).Count()"));
            Assert.AreEqual("bar", engine.Evaluate("doc.Root.Elements(new XmlName('foo')).First().ToString()"));
        }

        [TestMethod, TestCategory("BugFix")]
        public void BugFix_TextDigest()
        {
            const string allChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
            var random = new Random();

            var proxy = V8TestProxy.Create();
            for (var i = 0; i < 1024; i++)
            {
                var chars = new char[random.Next(8, 256)];
                for (var j = 0; j < chars.Length; j++)
                {
                    chars[j] = allChars[random.Next(allChars.Length - 1)];
                }

                var value = new string(chars);
                Assert.AreEqual(value.GetDigest(), proxy.GetNativeDigest(value));
            }
        }

        [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_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);
            ");
        }

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

        [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\")"));
        }

        // ReSharper restore InconsistentNaming

        #endregion

        #region miscellaneous

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

        public class NullableTest
        {
            public int? Field;

            public double? Property;

            public object Method(int? value)
            {
                return value + 1;
            }

            public object Method(double? value)
            {
                return value * 2.0;
            }
        }

        public abstract class AmbiguousAttributeTestBase
        {
            public abstract object this[int index] { get; }

            public abstract object this[string key] { get; }
        }

        public class AmbiguousAttributeTest : AmbiguousAttributeTestBase
        {
            public override object this[int index] { get { return null; } }

            public override object this[string key] { get { return null; } }

            public void Foo() {}
        }

        public class ResurrectionTestWrapper
        {
            private readonly IDisposable target;

            public ResurrectionTestWrapper(IDisposable target)
            {
                this.target = target;
            }

            ~ResurrectionTestWrapper()
            {
                target.Dispose();
            }
        }

        public interface IAmbiguousIndexerBase1
        {
            object this[int i] { get; set; }
        }

        public interface IAmbiguousIndexerBase2
        {
            object this[int i] { get; set; }
            object this[DayOfWeek d] { get; set; }
        }

        // ReSharper disable PossibleInterfaceMemberAmbiguity

        public interface IAmbiguousIndexer : IAmbiguousIndexerBase1, IAmbiguousIndexerBase2
        {
            new object this[int i] { get; set; }
        }

        // ReSharper restore PossibleInterfaceMemberAmbiguity

        public class AmbiguousIndexer : IAmbiguousIndexer
        {
            private readonly IDictionary byInteger = new ListDictionary();
            private readonly IDictionary byDayOfWeek = new ListDictionary();

            public object this[int key]
            {
                get { return byInteger[key]; }
                set { byInteger[key] = value; }
            }

            public object this[DayOfWeek key]
            {
                get { return byDayOfWeek[key]; }
                set { byDayOfWeek[key] = value; }
            }
        }

        public class InaccessiblePropertyAccessors
        {
            // ReSharper disable UnusedMember.Local

            private int dummy;

            public int NoGetter
            {
                set { dummy = value; }
            }

            public int PrivateGetter
            {
                private get { return dummy; }
                set { dummy = value; }
            }

            public int NoSetter
            {
                get { return dummy; }
            }

            public int PrivateSetter
            {
                get { return dummy; }
                private set { dummy = value; }
            }

            // ReSharper restore UnusedMember.Local
        }

        public static class InaccessiblePropertyAccessorsStatic
        {
            // ReSharper disable UnusedMember.Local

            private static int dummy = 12345;

            public static int NoGetter
            {
                set { dummy = value; }
            }

            public static int PrivateGetter
            {
                private get { return dummy; }
                set { dummy = value; }
            }

            public static int NoSetter
            {
                get { return dummy; }
            }

            public static int PrivateSetter
            {
                get { return dummy; }
                private set { dummy = value; }
            }

            // ReSharper restore UnusedMember.Local
        }

        [NoDefaultScriptAccess]
        public class PropertyAccessorScriptability
        {
            [ScriptMember]
            public int Foo { get; set; }

            [ScriptMember]
            public int Bar { [NoScriptAccess] get; [NoScriptAccess] set; }
        }

        [NoDefaultScriptAccess]
        public static class PropertyAccessorScriptabilityStatic
        {
            [ScriptMember]
            public static int Foo { get; set; }

            [ScriptMember]
            public static int Bar { [NoScriptAccess] get; [NoScriptAccess] set; }
        }

        public class DynamicMethodArgTest : DynamicObject
        {
            public override IEnumerable GetDynamicMemberNames()
            {
                yield return "RunTest";
            }

            // ReSharper disable RedundantOverridenMember

            public override bool TryGetMember(GetMemberBinder binder, out object result)
            {
                // this override is redundant, but required for the test
                return base.TryGetMember(binder, out result);
            }

            // ReSharper restore RedundantOverridenMember

            public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
            {
                if (binder.Name == "RunTest")
                {
                    result = string.Join(" ", args);
                    return true;
                }

                return base.TryInvokeMember(binder, args, out result);
            }
        }

        public class NumericArgConversionTest
        {
            public sbyte SByteField;
            public sbyte? NullableSByteField;
            public float FloatField;
            public float? NullableFloatField;
            public double DoubleField;
            public double? NullableDoubleField;
            public decimal DecimalField;
            public decimal? NullableDecimalField;

            public sbyte SByteMethod(sbyte arg) { return arg; }
            public sbyte? NullableSByteMethod(sbyte? arg) { return arg; }
            public float FloatMethod(float arg) { return arg; }
            public float? NullableFloatMethod(float? arg) { return arg; }
            public double DoubleMethod(double arg) { return arg; }
            public double? NullableDoubleMethod(double? arg) { return arg; }
            public decimal DecimalMethod(decimal arg) { return arg; }
            public decimal? NullableDecimalMethod(decimal? arg) { return arg; }

            public sbyte SByteProperty { get; set; }
            public sbyte? NullableSByteProperty { get; set; }
            public float FloatProperty { get; set; }
            public float? NullableFloatProperty { get; set; }
            public double DoubleProperty { get; set; }
            public double? NullableDoubleProperty { get; set; }
            public decimal DecimalProperty { get; set; }
            public decimal? NullableDecimalProperty { get; set; }
        }

        public class HideNativeJavaScriptMethod
        {
            // ReSharper disable InconsistentNaming

            public string toString()
            {
                return ToString();
            }

            // ReSharper restore InconsistentNaming
        }

        public class NestedTypeTest
        {
            public enum NestedType
            {
                Foo, Bar, Baz, Qux
            }
        }

        public abstract class PublicOverrideTestBase
        {
            public abstract int AbstractMethod();

            public virtual int VirtualMethod()
            {
                return 123;
            }

            public abstract string AbstractProperty { get; }

            public virtual string VirtualProperty
            {
                get { return "foo"; }
            }
        }

        internal class PublicOverrideTest : PublicOverrideTestBase
        {
            public override int AbstractMethod()
            {
                return 789;
            }

            public override int VirtualMethod()
            {
                return 456;
            }

            public override string AbstractProperty
            {
                get { return "baz"; }
            }

            public override string VirtualProperty
            {
                get { return "bar"; }
            }
        }

        public class XmlName
        {
            private readonly string name;

            public XmlName(string name)
            {
                this.name = name;
            }

            public static implicit operator XName(XmlName xmlName)
            {
                return xmlName.name;
            }
        }

        #endregion
    }
}

Web Proxy Viewer  |  New URL  |  Original Page