//
// Copyright (c) ZeroC, Inc. All rights reserved.
//

(function(module, require, exports)
{
    const Ice = require("ice").Ice;
    const test = require("TestHelper").TestHelper.test;

    async function run(communicator, prx, Test, M, bidir, helper)
    {
        const literals = await prx.opStringLiterals();

        test(Test.s0 == "\\" &&
             Test.s0 == Test.sw0 &&
             Test.s0 == literals[0] &&
             Test.s0 == literals[11]);

        test(Test.s1 == "A" &&
             Test.s1 == Test.sw1 &&
             Test.s1 == literals[1] &&
             Test.s1 == literals[12]);

        test(Test.s2 == "Ice" &&
             Test.s2 == Test.sw2 &&
             Test.s2 == literals[2] &&
             Test.s2 == literals[13]);

        test(Test.s3 == "A21" &&
             Test.s3 == Test.sw3 &&
             Test.s3 == literals[3] &&
             Test.s3 == literals[14]);

        test(Test.s4 == "\\u0041 \\U00000041" &&
             Test.s4 == Test.sw4 &&
             Test.s4 == literals[4] &&
             Test.s4 == literals[15]);

        test(Test.s5 == "\u00FF" &&
             Test.s5 == Test.sw5 &&
             Test.s5 == literals[5] &&
             Test.s5 == literals[16]);

        test(Test.s6 == "\u03FF" &&
             Test.s6 == Test.sw6 &&
             Test.s6 == literals[6] &&
             Test.s6 == literals[17]);

        test(Test.s7 == "\u05F0" &&
             Test.s7 == Test.sw7 &&
             Test.s7 == literals[7] &&
             Test.s7 == literals[18]);

        test(Test.s8 == "\uD800\uDC00" &&
             Test.s8 == Test.sw8 &&
             Test.s8 == literals[8] &&
             Test.s8 == literals[19]);

        test(Test.s9 == "\uD83C\uDF4C" &&
             Test.s9 == Test.sw9 &&
             Test.s9 == literals[9] &&
             Test.s9 == literals[20]);

        test(Test.s10 == "\u0DA7" &&
             Test.s10 == Test.sw10 &&
             Test.s10 == literals[10] &&
             Test.s10 == literals[21]);

        test(Test.ss0 == "'\"?\\\u0007\b\f\n\r\t\v\u0006" &&
             Test.ss0 == Test.ss1 &&
             Test.ss0 == Test.ss2 &&
             Test.ss0 == literals[22] &&
             Test.ss0 == literals[23] &&
             Test.ss0 == literals[24]);

        test(Test.ss3 == "\\\\U\\u\\" &&
             Test.ss3 == literals[25]);

        test(Test.ss4 == "\\A\\" &&
             Test.ss4 == literals[26]);

        test(Test.ss5 == "\\u0041\\" &&
             Test.ss5 == literals[27]);

        test(Test.su0 == Test.su1 &&
             Test.su0 == Test.su2 &&
             Test.su0 == literals[28] &&
             Test.su0 == literals[29] &&
             Test.su0 == literals[30]);

        await prx.ice_ping();

        test(await prx.ice_isA(Test.MyClass.ice_staticId()));

        test((await prx.ice_id()) === Test.MyDerivedClass.ice_staticId());

        test((await prx.ice_ids()).length === 3);

        await prx.opVoid();

        {
            const [retval, p3] = await prx.opByte(0xff, 0x0f);
            test(p3 === 0xf0);
            test(retval === 0xff);
        }

        {
            const [retval, p3] = await prx.opBool(true, false);
            test(p3);
            test(!retval);
        }

        {
            const lo = new Ice.Long(0, 12);
            const [retval, s, i, l] = await prx.opShortIntLong(10, 11, lo);

            test(s === 10);
            test(i === 11);
            test(l.equals(lo));
            test(retval.equals(lo));
        }

        {
            const [retval, f, d] = await prx.opFloatDouble(3.14, 1.1E10);
            test((f - 3.14) <= 0.01);
            test(d == 1.1E10);
            test(retval == 1.1E10);
        }

        try
        {
            await prx.opByte(0xffff, 0xff0f);
            test(false);
        }
        catch(ex)
        {
            test(ex instanceof Ice.MarshalException, ex);
        }

        try
        {
            await prx.opShortIntLong(-32768 - 1, 0, 0);
            test(false);
        }
        catch(ex)
        {
            test(ex instanceof Ice.MarshalException, ex);
        }

        try
        {
            await prx.opShortIntLong(32767 + 1, 0, 0);
            test(false);
        }
        catch(ex)
        {
            test(ex instanceof Ice.MarshalException, ex);
        }

        try
        {
            await prx.opShortIntLong(0, -2147483648 - 1, 0);
            test(false);
        }
        catch(ex)
        {
            test(ex instanceof Ice.MarshalException, ex);
        }

        try
        {
            await prx.opShortIntLong(0, 2147483647 + 1, 0);
            test(false);
        }
        catch(ex)
        {
            test(ex instanceof Ice.MarshalException, ex);
        }

        try
        {
            await prx.opShortIntLong(0, 0, new Ice.Long(0, 0xFFFFFFFF + 1));
            test(false);
        }
        catch(ex)
        {
            test(ex instanceof RangeError, ex);
        }

        try
        {
            await prx.opShortIntLong(0, 0, new Ice.Long(0xFFFFFFFF + 1, 0));
            test(false);
        }
        catch(ex)
        {
            test(ex instanceof RangeError, ex);
        }

        try
        {
            await prx.opShortIntLong(0, 0, new Ice.Long(0, -1));
            test(false);
        }
        catch(ex)
        {
            test(ex instanceof RangeError, ex);
        }

        try
        {
            await prx.opShortIntLong(Number.NaN, 0, new Ice.Long(0, 0));
            test(false);
        }
        catch(ex)
        {
            test(ex instanceof Ice.MarshalException, ex);
        }

        try
        {
            await prx.opFloatDouble(Number.MAX_VALUE, 0);
            test(false);
        }
        catch(ex)
        {
            test(ex instanceof Ice.MarshalException, ex);
        }

        try
        {
            await prx.opFloatDouble(-Number.MAX_VALUE, 0);
            test(false);
        }
        catch(ex)
        {
            test(ex instanceof Ice.MarshalException, ex);
        }

        await prx.opFloatDouble(Number.NaN, Number.NaN);
        await prx.opFloatDouble(-Number.NaN, -Number.NaN);
        await prx.opFloatDouble(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY);
        await prx.opFloatDouble(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY);

        {
            const [retval, p3] = await prx.opString("hello", "world");
            test(p3 === "world hello");
            test(retval === "hello world");
        }

        {
            const [retval, p2] = await prx.opMyEnum(Test.MyEnum.enum2);
            test(p2 === Test.MyEnum.enum2);
            test(retval === Test.MyEnum.enum3);
        }

        {
            // Test null enum
            const [retval, p2] = await prx.opMyEnum(null);
            test(p2 === Test.MyEnum.enum1);
            test(retval === Test.MyEnum.enum3);
        }

        {
             const [retval, p2, p3] = await prx.opMyClass(prx);

            test(p2.ice_getIdentity().equals(Ice.stringToIdentity("test")));
            test(p3.ice_getIdentity().equals(Ice.stringToIdentity("noSuchIdentity")));
            test(retval.ice_getIdentity().equals(Ice.stringToIdentity("test")));
        }

        {
            const si1 = new Test.Structure();
            si1.p = prx;
            si1.e = Test.MyEnum.enum3;
            si1.s = new Test.AnotherStruct();
            si1.s.s = "abc";
            const si2 = new Test.Structure();
            si2.p = null;
            si2.e = Test.MyEnum.enum2;
            si2.s = new Test.AnotherStruct();
            si2.s.s = "def";

            const [retval, p3] = await prx.opStruct(si1, si2);
            test(retval.p === null);
            test(retval.e === Test.MyEnum.enum2);
            test(retval.s.s === "def");
            test(p3.p !== null);
            test(p3.e === Test.MyEnum.enum3);
            test(p3.s.s === "a new string");
        }

        {
            const si1 = new Test.Structure();
            // Test null struct
            const [retval, p3] = await prx.opStruct(si1, null);

            test(retval.p === null);
            test(retval.e === Test.MyEnum.enum1);
            test(retval.s.s === "");
            test(p3.p === null);
            test(p3.e === Test.MyEnum.enum1);
            test(p3.s.s === "a new string");
        }

        {
            const bsi1 = new Uint8Array([0x01, 0x11, 0x12, 0x22]);
            const bsi2 = new Uint8Array([0xf1, 0xf2, 0xf3, 0xf4]);

            const [retval, p3] = await prx.opByteS(bsi1, bsi2);

            test(p3.length === 4);
            test(p3[0] === 0x22);
            test(p3[1] === 0x12);
            test(p3[2] === 0x11);
            test(p3[3] === 0x01);
            test(retval.length === 8);
            test(retval[0] === 0x01);
            test(retval[1] === 0x11);
            test(retval[2] === 0x12);
            test(retval[3] === 0x22);
            test(retval[4] === 0xf1);
            test(retval[5] === 0xf2);
            test(retval[6] === 0xf3);
            test(retval[7] === 0xf4);
        }

        {
            const bsi1 = [true, true, false];
            const bsi2 = [false];
            const [retval, p3] = await prx.opBoolS(bsi1, bsi2);

            test(p3.length == 4);
            test(p3[0]);
            test(p3[1]);
            test(!p3[2]);
            test(!p3[3]);
            test(retval.length == 3);
            test(!retval[0]);
            test(retval[1]);
            test(retval[2]);
        }

        {
            const ssi = [1, 2, 3];
            const isi = [5, 6, 7, 8];
            const l1 = new Ice.Long(0, 10);
            const l2 = new Ice.Long(0, 30);
            const l3 = new Ice.Long(0, 20);
            const lsi = [l1, l2, l3];
            const [retval, sso, iso, lso] = await prx.opShortIntLongS(ssi, isi, lsi);

            test(sso.length === 3);
            test(sso[0] === 1);
            test(sso[1] === 2);
            test(sso[2] === 3);
            test(iso.length === 4);
            test(iso[0] === 8);
            test(iso[1] === 7);
            test(iso[2] === 6);
            test(iso[3] === 5);
            test(lso.length === 6);
            test(lso[0].equals(l1));
            test(lso[1].equals(l2));
            test(lso[2].equals(l3));
            test(lso[3].equals(l1));
            test(lso[4].equals(l2));
            test(lso[5].equals(l3));
            test(retval.length === 3);
            test(retval[0].equals(l1));
            test(retval[1].equals(l2));
            test(retval[2].equals(l3));
        }

        {
            const fsi = [3.14, 1.11];
            const dsi = [1.1E10, 1.2E10, 1.3E10];
            const [retval, fso, dso] = await prx.opFloatDoubleS(fsi, dsi);

            test(fso.length === 2);
            test((fso[0] - 3.14) <= 0.01);
            test((fso[1] - 1.11) <= 0.01);
            test(dso.length === 3);
            test(dso[0] === 1.3E10);
            test(dso[1] === 1.2E10);
            test(dso[2] === 1.1E10);
            test(retval.length === 5);
            test(retval[0] === 1.1E10);
            test(retval[1] === 1.2E10);
            test(retval[2] === 1.3E10);
            test((retval[3] - 3.14) <= 0.01);
            test((retval[4] - 1.11) <= 0.01);
        }

        {
            const ssi1 = ["abc", "de", "fghi"];
            const ssi2 = ["xyz"];
            const [retval, sso] = await prx.opStringS(ssi1, ssi2);

            test(sso.length === 4);
            test(sso[0] === "abc");
            test(sso[1] === "de");
            test(sso[2] === "fghi");
            test(sso[3] === "xyz");
            test(retval.length === 3);
            test(retval[0] === "fghi");
            test(retval[1] === "de");
            test(retval[2] === "abc");
        }

        {
            const bsi1 =
                [
                    new Uint8Array([0x01, 0x11, 0x12]),
                    new Uint8Array([0xff])
                ];

            const bsi2 =
                [
                    new Uint8Array([0x0e]),
                    new Uint8Array([0xf2, 0xf1])
                ];

            const [retval, bso] = await prx.opByteSS(bsi1, bsi2);

            test(bso.length === 2);
            test(bso[0].length === 1);
            test(bso[0][0] === 0xff);
            test(bso[1].length === 3);
            test(bso[1][0] === 0x01);
            test(bso[1][1] === 0x11);
            test(bso[1][2] === 0x12);
            test(retval.length === 4);
            test(retval[0].length === 3);
            test(retval[0][0] === 0x01);
            test(retval[0][1] === 0x11);
            test(retval[0][2] === 0x12);
            test(retval[1].length === 1);
            test(retval[1][0] === 0xff);
            test(retval[2].length === 1);
            test(retval[2][0] === 0x0e);
            test(retval[3].length === 2);
            test(retval[3][0] === 0xf2);
            test(retval[3][1] === 0xf1);
        }

        {
            const bsi1 =
                [
                    [true],
                    [false],
                    [true, true]
                ];

            const bsi2 =
                [
                    [false, false, true]
                ];

            const [retval, bso] = await prx.opBoolSS(bsi1, bsi2);

            test(bso.length === 4);
            test(bso[0].length === 1);
            test(bso[0][0]);
            test(bso[1].length === 1);
            test(!bso[1][0]);
            test(bso[2].length === 2);
            test(bso[2][0]);
            test(bso[2][1]);
            test(bso[3].length === 3);
            test(!bso[3][0]);
            test(!bso[3][1]);
            test(bso[3][2]);
            test(retval.length === 3);
            test(retval[0].length === 2);
            test(retval[0][0]);
            test(retval[0][1]);
            test(retval[1].length === 1);
            test(!retval[1][0]);
            test(retval[2].length === 1);
            test(retval[2][0]);
        }

        {
            const ssi =
                [
                    [1, 2, 5],
                    [13],
                    []
                ];

            const isi =
                [
                    [24, 98],
                    [42]
                ];

            const l1 = new Ice.Long(0, 496);
            const l2 = new Ice.Long(0, 1729);

            const lsi =
                [
                    [l1, l2]
                ];

            const [retval, sso, iso, lso] = await prx.opShortIntLongSS(ssi, isi, lsi);

            test(retval.length === 1);
            test(retval[0].length === 2);
            test(retval[0][0].equals(l1));
            test(retval[0][1].equals(l2));
            test(sso.length === 3);
            test(sso[0].length === 3);
            test(sso[0][0] === 1);
            test(sso[0][1] === 2);
            test(sso[0][2] === 5);
            test(sso[1].length === 1);
            test(sso[1][0] === 13);
            test(sso[2].length === 0);
            test(iso.length === 2);
            test(iso[0].length === 1);
            test(iso[0][0] === 42);
            test(iso[1].length === 2);
            test(iso[1][0] === 24);
            test(iso[1][1] === 98);
            test(lso.length === 2);
            test(lso[0].length === 2);
            test(lso[0][0].equals(l1));
            test(lso[0][1].equals(l2));
            test(lso[1].length === 2);
            test(lso[1][0].equals(l1));
            test(lso[1][1].equals(l2));
        }

        {
            const fsi =
                [
                    [3.14],
                    [1.11],
                    []
                ];

            const dsi =
                [
                    [1.1E10, 1.2E10, 1.3E10]
                ];

            const [retval, fso, dso] = await prx.opFloatDoubleSS(fsi, dsi);

            test(fso.length === 3);
            test(fso[0].length === 1);
            test((fso[0][0] - 3.14) <= 0.01);
            test(fso[1].length === 1);
            test((fso[1][0] - 1.11) <= 0.01);
            test(fso[2].length === 0);
            test(dso.length === 1);
            test(dso[0].length === 3);
            test(dso[0][0] === 1.1E10);
            test(dso[0][1] === 1.2E10);
            test(dso[0][2] === 1.3E10);
            test(retval.length === 2);
            test(retval[0].length === 3);
            test(retval[0][0] === 1.1E10);
            test(retval[0][1] === 1.2E10);
            test(retval[0][2] === 1.3E10);
            test(retval[1].length === 3);
            test(retval[1][0] === 1.1E10);
            test(retval[1][1] === 1.2E10);
            test(retval[1][2] === 1.3E10);
        }

        {
            const ssi1 =
                [
                    ["abc"],
                    ["de", "fghi"]
                ];

            const ssi2 =
                [
                    [],
                    [],
                    ["xyz"]
                ];

            const [retval, sso] = await prx.opStringSS(ssi1, ssi2);
            test(sso.length === 5);
            test(sso[0].length === 1);
            test(sso[0][0] === "abc");
            test(sso[1].length === 2);
            test(sso[1][0] === "de");
            test(sso[1][1] === "fghi");
            test(sso[2].length === 0);
            test(sso[3].length === 0);
            test(sso[4].length === 1);
            test(sso[4][0] === "xyz");
            test(retval.length === 3);
            test(retval[0].length === 1);
            test(retval[0][0] === "xyz");
            test(retval[1].length === 0);
            test(retval[2].length === 0);
        }

        {
            const sssi1 =
                [
                    [
                        ["abc", "de"],
                        ["xyz"]
                    ],
                    [
                        ["hello"]
                    ]
                ];

            const sssi2 =
                [
                    [
                        ["", ""],
                        ["abcd"]
                    ],
                    [
                        [""]
                    ],
                    []
                ];

            const [retval, ssso] = await prx.opStringSSS(sssi1, sssi2);

            test(ssso.length === 5);
            test(ssso[0].length === 2);
            test(ssso[0][0].length === 2);
            test(ssso[0][1].length === 1);
            test(ssso[1].length === 1);
            test(ssso[1][0].length === 1);
            test(ssso[2].length === 2);
            test(ssso[2][0].length === 2);
            test(ssso[2][1].length === 1);
            test(ssso[3].length === 1);
            test(ssso[3][0].length === 1);
            test(ssso[4].length === 0);
            test(ssso[0][0][0] === "abc");
            test(ssso[0][0][1] === "de");
            test(ssso[0][1][0] === "xyz");
            test(ssso[1][0][0] === "hello");
            test(ssso[2][0][0] === "");
            test(ssso[2][0][1] === "");
            test(ssso[2][1][0] === "abcd");
            test(ssso[3][0][0] === "");

            test(retval.length === 3);
            test(retval[0].length === 0);
            test(retval[1].length === 1);
            test(retval[1][0].length === 1);
            test(retval[2].length === 2);
            test(retval[2][0].length === 2);
            test(retval[2][1].length === 1);
            test(retval[1][0][0] === "");
            test(retval[2][0][0] === "");
            test(retval[2][0][1] === "");
            test(retval[2][1][0] === "abcd");
        }

        {
            const di1 = new Test.ByteBoolD();
            di1.set(10, true);
            di1.set(100, false);

            const di2 = new Test.ByteBoolD();
            di2.set(10, true);
            di2.set(11, false);
            di2.set(101, true);

            const [retval, p3] = await prx.opByteBoolD(di1, di2);
            test(Ice.MapUtil.equals(p3, di1));
            test(retval.size === 4);
            test(retval.get(10) === true);
            test(retval.get(11) === false);
            test(retval.get(100) === false);
            test(retval.get(101) === true);
        }

        {
            const di1 = new Test.ShortIntD();
            di1.set(110, -1);
            di1.set(1100, 123123);

            const di2 = new Test.ShortIntD();
            di2.set(110, -1);
            di2.set(111, -100);
            di2.set(1101, 0);

            const [retval, p3] = await prx.opShortIntD(di1, di2);
            test(Ice.MapUtil.equals(p3, di1));
            test(retval.size === 4);
            test(retval.get(110) === -1);
            test(retval.get(111) === -100);
            test(retval.get(1100) === 123123);
            test(retval.get(1101) === 0);
        }

        {
            const di1 = new Test.LongFloatD();
            di1.set(new Ice.Long(0, 999999110), -1.1);
            di1.set(new Ice.Long(0, 999999111), 123123.2);

            const di2 = new Test.LongFloatD();
            di2.set(new Ice.Long(0, 999999110), -1.1);
            di2.set(new Ice.Long(0, 999999120), -100.4);
            di2.set(new Ice.Long(0, 999999130), 0.5);

            const [retval, p3] = await prx.opLongFloatD(di1, di2);

            test(p3.equals(di1, (v1, v2) => (Math.abs(v1) - Math.abs(v2)) <= 0.01));
            test(retval.size === 4);
            test(Math.abs(retval.get(new Ice.Long(0, 999999110))) - Math.abs(-1.1) <= 0.01);
            test(Math.abs(retval.get(new Ice.Long(0, 999999120))) - Math.abs(-100.4) <= 0.01);
            test(retval.get(new Ice.Long(0, 999999111)) - 123123.2 <= 0.01);
            test(retval.get(new Ice.Long(0, 999999130)) - 0.5 <= 0.01);
        }

        {
            const di1 = new Test.StringStringD();
            di1.set("foo", "abc -1.1");
            di1.set("bar", "abc 123123.2");

            const di2 = new Test.StringStringD();
            di2.set("foo", "abc -1.1");
            di2.set("FOO", "abc -100.4");
            di2.set("BAR", "abc 0.5");

            const [retval, p3] = await prx.opStringStringD(di1, di2);
            test(Ice.MapUtil.equals(p3, di1));
            test(retval.size == 4);
            test(retval.get("foo") === "abc -1.1");
            test(retval.get("FOO") === "abc -100.4");
            test(retval.get("bar") === "abc 123123.2");
            test(retval.get("BAR") === "abc 0.5");
        }

        {
            const di1 = new Test.StringMyEnumD();
            di1.set("abc", Test.MyEnum.enum1);
            di1.set("", Test.MyEnum.enum2);

            const di2 = new Test.StringMyEnumD();
            di2.set("abc", Test.MyEnum.enum1);
            di2.set("qwerty", Test.MyEnum.enum3);
            di2.set("Hello!!", Test.MyEnum.enum2);

            const [retval, p3] = await prx.opStringMyEnumD(di1, di2);

            test(Ice.MapUtil.equals(p3, di1));
            test(retval.size === 4);
            test(retval.get("abc") === Test.MyEnum.enum1);
            test(retval.get("qwerty") === Test.MyEnum.enum3);
            test(retval.get("") === Test.MyEnum.enum2);
            test(retval.get("Hello!!") === Test.MyEnum.enum2);
        }

        {
            const di1 = new Test.MyEnumStringD();
            di1.set(Test.MyEnum.enum1, "abc");

            const di2 = new Test.MyEnumStringD();
            di2.set(Test.MyEnum.enum2, "Hello!!");
            di2.set(Test.MyEnum.enum3, "qwerty");

            const [retval, p3] = await prx.opMyEnumStringD(di1, di2);

            test(Ice.MapUtil.equals(p3, di1));
            test(retval.size === 3);
            test(retval.get(Test.MyEnum.enum1) === "abc");
            test(retval.get(Test.MyEnum.enum2) === "Hello!!");
            test(retval.get(Test.MyEnum.enum3) === "qwerty");
        }

        {
            const s11 = new Test.MyStruct(1, 1);
            const s12 = new Test.MyStruct(1, 2);
            const di1 = new Test.MyStructMyEnumD();
            di1.set(s11, Test.MyEnum.enum1);
            di1.set(s12, Test.MyEnum.enum2);
            const s22 = new Test.MyStruct(2, 2);
            const s23 = new Test.MyStruct(2, 3);
            const di2 = new Test.MyStructMyEnumD();
            di2.set(s11, Test.MyEnum.enum1);
            di2.set(s22, Test.MyEnum.enum3);
            di2.set(s23, Test.MyEnum.enum2);

            const [retval, p3] = await prx.opMyStructMyEnumD(di1, di2);
            test(p3.equals(di1));

            test(retval.size === 4);
            test(retval.get(s11) === Test.MyEnum.enum1);
            test(retval.get(s12) === Test.MyEnum.enum2);
            test(retval.get(s22) === Test.MyEnum.enum3);
            test(retval.get(s23) === Test.MyEnum.enum2);
        }

        {
            const ds1 = new Test.ByteBoolD();
            ds1.set(10, true);
            ds1.set(100, false);
            const ds2 = new Test.ByteBoolD();
            ds2.set(10, true);
            ds2.set(11, false);
            ds2.set(101, true);
            const ds3 = new Test.ByteBoolD();
            ds3.set(100, false);
            ds3.set(101, false);

            const [retval, p3] = await prx.opByteBoolDS([ds1, ds2], [ds3]);
            test(retval.length == 2);
            test(retval[0].size == 3);
            test(retval[0].get(10) === true);
            test(retval[0].get(11) === false);
            test(retval[0].get(101) === true);
            test(retval[1].size === 2);
            test(retval[1].get(10) === true);
            test(retval[1].get(100) === false);
            test(p3.length == 3);
            test(p3[0].size == 2);
            test(p3[0].get(100) === false);
            test(p3[0].get(101) === false);
            test(p3[1].size == 2);
            test(p3[1].get(10) === true);
            test(p3[1].get(100) === false);
            test(p3[2].size == 3);
            test(p3[2].get(10) === true);
            test(p3[2].get(11) === false);
            test(p3[2].get(101) === true);
        }

        {
            const di1 = new Test.ShortIntD();
            di1.set(110, -1);
            di1.set(1100, 123123);
            const di2 = new Test.ShortIntD();
            di2.set(110, -1);
            di2.set(111, -100);
            di2.set(1101, 0);
            const di3 = new Test.ShortIntD();
            di3.set(100, -1001);

            const [retval, p3] = await prx.opShortIntDS([di1, di2], [di3]);
            test(retval.length == 2);
            test(retval[0].size == 3);
            test(retval[0].get(110) === -1);
            test(retval[0].get(111) === -100);
            test(retval[0].get(1101) === 0);
            test(retval[1].size === 2);
            test(retval[1].get(110) === -1);
            test(retval[1].get(1100) === 123123);

            test(p3.length === 3);
            test(p3[0].size === 1);
            test(p3[0].get(100) === -1001);
            test(p3[1].size === 2);
            test(p3[1].get(110) === -1);
            test(p3[1].get(1100) === 123123);
            test(p3[2].size === 3);
            test(p3[2].get(110) === -1);
            test(p3[2].get(111) === -100);
            test(p3[2].get(1101) === 0);
        }

        {
            const di1 = new Test.LongFloatD();
            di1.set(new Ice.Long(0, 999999110), -1.1);
            di1.set(new Ice.Long(0, 999999111), 123123.2);
            const di2 = new Test.LongFloatD();
            di2.set(new Ice.Long(0, 999999110), -1.1);
            di2.set(new Ice.Long(0, 999999120), -100.4);
            di2.set(new Ice.Long(0, 999999130), 0.5);
            const di3 = new Test.LongFloatD();
            di3.set(new Ice.Long(0, 999999140), 3.14);

            const [retval, p3] = await prx.opLongFloatDS([di1, di2], [di3]);
            test(retval.length == 2);
            test(retval[0].size == 3);
            test(retval[0].get(new Ice.Long(0, 999999110)) - Math.abs(-1.1) <= 0.1);
            test(retval[0].get(new Ice.Long(0, 999999120)) - Math.abs(-100.4) <= 0.1);
            test(retval[0].get(new Ice.Long(0, 999999130)) - 0.5 <= 0.1);
            test(retval[1].size == 2);
            test(retval[1].get(new Ice.Long(0, 999999110)) - Math.abs(-1.1) <= 0.1);
            test(retval[1].get(new Ice.Long(0, 999999111)) - 123123.2 <= 0.1);

            test(p3.length == 3);
            test(p3[0].size == 1);
            test(p3[0].get(new Ice.Long(0, 999999140)) - 3.14 <= 0.1);
            test(p3[1].size == 2);
            test(p3[1].get(new Ice.Long(0, 999999110)) - Math.abs(-1.1) <= 0.1);
            test(p3[1].get(new Ice.Long(0, 999999111)) - 123123.2 <= 0.1);
            test(p3[2].size == 3);
            test(p3[2].get(new Ice.Long(0, 999999110)) - Math.abs(-1.1) <= 0.1);
            test(p3[2].get(new Ice.Long(0, 999999120)) - Math.abs(-100.4) <= 0.1);
            test(p3[2].get(new Ice.Long(0, 999999130)) - 0.5 <= 0.1);
        }

        {
            const di1 = new Test.StringStringD();
            di1.set("foo", "abc -1.1");
            di1.set("bar", "abc 123123.2");
            const di2 = new Test.StringStringD();
            di2.set("foo", "abc -1.1");
            di2.set("FOO", "abc -100.4");
            di2.set("BAR", "abc 0.5");
            const di3 = new Test.StringStringD();
            di3.set("f00", "ABC -3.14");

            const [retval, p3] = await prx.opStringStringDS([di1, di2], [di3]);
            test(retval.length === 2);
            test(retval[0].size === 3);
            test(retval[0].get("foo") === "abc -1.1");
            test(retval[0].get("FOO") === "abc -100.4");
            test(retval[0].get("BAR") === "abc 0.5");
            test(retval[1].size === 2);
            test(retval[1].get("foo") === "abc -1.1");
            test(retval[1].get("bar") === "abc 123123.2");

            test(p3.length === 3);
            test(p3[0].size === 1);
            test(p3[0].get("f00") === "ABC -3.14");
            test(p3[1].size === 2);
            test(p3[1].get("foo") === "abc -1.1");
            test(p3[1].get("bar") === "abc 123123.2");
            test(p3[2].size === 3);
            test(p3[2].get("foo") === "abc -1.1");
            test(p3[2].get("FOO") === "abc -100.4");
            test(p3[2].get("BAR") === "abc 0.5");
        }

        {
            const di1 = new Test.StringMyEnumD();
            di1.set("abc", Test.MyEnum.enum1);
            di1.set("", Test.MyEnum.enum2);
            const di2 = new Test.StringMyEnumD();
            di2.set("abc", Test.MyEnum.enum1);
            di2.set("qwerty", Test.MyEnum.enum3);
            di2.set("Hello!!", Test.MyEnum.enum2);
            const di3 = new Test.StringMyEnumD();
            di3.set("Goodbye", Test.MyEnum.enum1);

            const [retval, p3] = await prx.opStringMyEnumDS([di1, di2], [di3]);

            test(retval.length == 2);
            test(retval[0].size == 3);
            test(retval[0].get("abc") == Test.MyEnum.enum1);
            test(retval[0].get("qwerty") == Test.MyEnum.enum3);
            test(retval[0].get("Hello!!") == Test.MyEnum.enum2);
            test(retval[1].size == 2);
            test(retval[1].get("abc") == Test.MyEnum.enum1);
            test(retval[1].get("") == Test.MyEnum.enum2);

            test(p3.length == 3);
            test(p3[0].size == 1);
            test(p3[0].get("Goodbye") == Test.MyEnum.enum1);
            test(p3[1].size == 2);
            test(p3[1].get("abc") == Test.MyEnum.enum1);
            test(p3[1].get("") == Test.MyEnum.enum2);
            test(p3[2].size == 3);
            test(p3[2].get("abc") == Test.MyEnum.enum1);
            test(p3[2].get("qwerty") == Test.MyEnum.enum3);
            test(p3[2].get("Hello!!") == Test.MyEnum.enum2);
        }

        {
            const di1 = new Test.MyEnumStringD();
            di1.set(Test.MyEnum.enum1, "abc");
            const di2 = new Test.MyEnumStringD();
            di2.set(Test.MyEnum.enum2, "Hello!!");
            di2.set(Test.MyEnum.enum3, "qwerty");
            const di3 = new Test.MyEnumStringD();
            di3.set(Test.MyEnum.enum1, "Goodbye");

            const [retval, p3] = await prx.opMyEnumStringDS([di1, di2], [di3]);
            test(retval.length == 2);
            test(retval[0].size == 2);
            test(retval[0].get(Test.MyEnum.enum2) === "Hello!!");
            test(retval[0].get(Test.MyEnum.enum3) === "qwerty");
            test(retval[1].size == 1);
            test(retval[1].get(Test.MyEnum.enum1) === "abc");

            test(p3.length == 3);
            test(p3[0].size == 1);
            test(p3[0].get(Test.MyEnum.enum1) === "Goodbye");
            test(p3[1].size == 1);
            test(p3[1].get(Test.MyEnum.enum1) === "abc");
            test(p3[2].size == 2);
            test(p3[2].get(Test.MyEnum.enum2) === "Hello!!");
            test(p3[2].get(Test.MyEnum.enum3) === "qwerty");
        }

        {
            const s11 = new Test.MyStruct(1, 1);
            const s12 = new Test.MyStruct(1, 2);
            const di1 = new Test.MyStructMyEnumD();
            di1.set(s11, Test.MyEnum.enum1);
            di1.set(s12, Test.MyEnum.enum2);

            const s22 = new Test.MyStruct(2, 2);
            const s23 = new Test.MyStruct(2, 3);
            const di2 = new Test.MyStructMyEnumD();
            di2.set(s11, Test.MyEnum.enum1);
            di2.set(s22, Test.MyEnum.enum3);
            di2.set(s23, Test.MyEnum.enum2);

            const di3 = new Test.MyStructMyEnumD();
            di3.set(s23, Test.MyEnum.enum3);

            const [retval, p3] = await prx.opMyStructMyEnumDS([di1, di2], [di3]);
            test(retval.length == 2);
            test(retval[0].size == 3);
            test(retval[0].get(s11) === Test.MyEnum.enum1);
            test(retval[0].get(s22) === Test.MyEnum.enum3);
            test(retval[0].get(s23) === Test.MyEnum.enum2);
            test(retval[1].size == 2);
            test(retval[1].get(s11) === Test.MyEnum.enum1);
            test(retval[1].get(s12) === Test.MyEnum.enum2);

            test(p3.length == 3);
            test(p3[0].size == 1);
            test(p3[0].get(s23) === Test.MyEnum.enum3);
            test(p3[1].size == 2);
            test(p3[1].get(s11) === Test.MyEnum.enum1);
            test(p3[1].get(s12) === Test.MyEnum.enum2);
            test(p3[2].size == 3);
            test(p3[2].get(s11) === Test.MyEnum.enum1);
            test(p3[2].get(s22) === Test.MyEnum.enum3);
            test(p3[2].get(s23) === Test.MyEnum.enum2);
        }

        {
            const sdi1 = new Test.ByteByteSD();
            sdi1.set(0x01, new Uint8Array([0x01, 0x11]));
            sdi1.set(0x22, new Uint8Array([0x12]));
            const sdi2 = new Test.ByteByteSD();
            sdi2.set(0xf1, new Uint8Array([0xf2, 0xf3]));

            const [retval, p3] = await prx.opByteByteSD(sdi1, sdi2);
            test(p3.size == 1);
            test(p3.get(0xf1).length === 2);
            test(p3.get(0xf1)[0] === 0xf2);
            test(p3.get(0xf1)[1] === 0xf3);
            test(retval.size === 3);
            test(retval.get(0x01).length === 2);
            test(retval.get(0x01)[0] === 0x01);
            test(retval.get(0x01)[1] === 0x11);
            test(retval.get(0x22).length === 1);
            test(retval.get(0x22)[0] === 0x12);
            test(retval.get(0xf1).length === 2);
            test(retval.get(0xf1)[0] === 0xf2);
            test(retval.get(0xf1)[1] === 0xf3);
        }

        {
            const si1 = [true, false];
            const si2 = [false, true, true];
            const sdi1 = new Test.BoolBoolSD();
            sdi1.set(false, si1);
            sdi1.set(true, si2);
            const sdi2 = new Test.BoolBoolSD();
            sdi2.set(false, si1);

            const [retval, p3] = await prx.opBoolBoolSD(sdi1, sdi2);
            test(p3.size === 1);
            test(p3.get(false).length === 2);
            test(p3.get(false)[0] === true);
            test(p3.get(false)[1] === false);
            test(retval.size === 2);
            test(retval.get(false).length === 2);
            test(retval.get(false)[0] === true);
            test(retval.get(false)[1] === false);
            test(retval.get(true).length === 3);
            test(retval.get(true)[0] === false);
            test(retval.get(true)[1] === true);
            test(retval.get(true)[2] === true);
        }

        {
            const sdi1 = new Test.ShortShortSD();
            const sdi2 = new Test.ShortShortSD();

            const si1 = [1, 2, 3];
            const si2 = [4, 5];
            const si3 = [6, 7];

            sdi1.set(1, si1);
            sdi1.set(2, si2);
            sdi2.set(4, si3);

            const [retval, p3] = await prx.opShortShortSD(sdi1, sdi2);
            test(p3.size === 1);
            test(p3.get(4).length === 2);
            test(p3.get(4)[0] === 6);
            test(p3.get(4)[1] === 7);
            test(retval.size === 3);
            test(retval.get(1).length === 3);
            test(retval.get(1)[0] === 1);
            test(retval.get(1)[1] === 2);
            test(retval.get(1)[2] === 3);
            test(retval.get(2).length === 2);
            test(retval.get(2)[0] === 4);
            test(retval.get(2)[1] === 5);
            test(retval.get(4).length === 2);
            test(retval.get(4)[0] === 6);
            test(retval.get(4)[1] === 7);
        }

        {
            const sdi1 = new Test.IntIntSD();
            const sdi2 = new Test.IntIntSD();

            const si1 = [100, 200, 300];
            const si2 = [400, 500];
            const si3 = [600, 700];

            sdi1.set(100, si1);
            sdi1.set(200, si2);
            sdi2.set(400, si3);

            const [retval, p3] = await prx.opIntIntSD(sdi1, sdi2);
            test(p3.size === 1);
            test(p3.get(400).length === 2);
            test(p3.get(400)[0] === 600);
            test(p3.get(400)[1] === 700);
            test(retval.size === 3);
            test(retval.get(100).length === 3);
            test(retval.get(100)[0] === 100);
            test(retval.get(100)[1] === 200);
            test(retval.get(100)[2] === 300);
            test(retval.get(200).length === 2);
            test(retval.get(200)[0] === 400);
            test(retval.get(200)[1] === 500);
            test(retval.get(400).length === 2);
            test(retval.get(400)[0] === 600);
            test(retval.get(400)[1] === 700);
        }

        {
            const sdi1 = new Test.LongLongSD();
            const sdi2 = new Test.LongLongSD();

            const si1 = [new Ice.Long(0, 999999110), new Ice.Long(0, 999999111), new Ice.Long(0, 999999110)];
            const si2 = [new Ice.Long(0, 999999120), new Ice.Long(0, 999999130)];
            const si3 = [new Ice.Long(0, 999999110), new Ice.Long(0, 999999120)];

            sdi1.set(new Ice.Long(0, 999999990), si1);
            sdi1.set(new Ice.Long(0, 999999991), si2);
            sdi2.set(new Ice.Long(0, 999999992), si3);

            const [retval, p3] = await prx.opLongLongSD(sdi1, sdi2);
            test(p3.size == 1);
            test(p3.get(new Ice.Long(0, 999999992)).length === 2);
            test(p3.get(new Ice.Long(0, 999999992))[0].equals(new Ice.Long(0, 999999110)));
            test(p3.get(new Ice.Long(0, 999999992))[1].equals(new Ice.Long(0, 999999120)));
            test(retval.size == 3);
            test(retval.get(new Ice.Long(0, 999999990)).length === 3);
            test(retval.get(new Ice.Long(0, 999999990))[0].equals(new Ice.Long(0, 999999110)));
            test(retval.get(new Ice.Long(0, 999999990))[1].equals(new Ice.Long(0, 999999111)));
            test(retval.get(new Ice.Long(0, 999999990))[2].equals(new Ice.Long(0, 999999110)));
            test(retval.get(new Ice.Long(0, 999999991)).length === 2);
            test(retval.get(new Ice.Long(0, 999999991))[0].equals(new Ice.Long(0, 999999120)));
            test(retval.get(new Ice.Long(0, 999999991))[1].equals(new Ice.Long(0, 999999130)));
            test(retval.get(new Ice.Long(0, 999999992)).length === 2);
            test(retval.get(new Ice.Long(0, 999999992))[0].equals(new Ice.Long(0, 999999110)));
            test(retval.get(new Ice.Long(0, 999999992))[1].equals(new Ice.Long(0, 999999120)));
        }

        {
            const sdi1 = new Test.StringFloatSD();
            const sdi2 = new Test.StringFloatSD();

            const si1 = [-1.1, 123123.2, 100.0];
            const si2 = [42.24, -1.61];
            const si3 = [-3.14, 3.14];

            sdi1.set("abc", si1);
            sdi1.set("ABC", si2);
            sdi2.set("aBc", si3);

            const [retval, p3] = await prx.opStringFloatSD(sdi1, sdi2);

            test(p3.size === 1);
            test(p3.get("aBc").length === 2);
            test(p3.get("aBc")[0] - Math.abs(3.14) <= 0.1);
            test(p3.get("aBc")[1] - 3.14 <= 0.1);
            test(retval.size === 3);
            test(retval.get("abc").length === 3);
            test(retval.get("abc")[0] - Math.abs(1.1) <= 0.1);
            test(retval.get("abc")[1] - 123123.2 <= 0.1);
            test(retval.get("abc")[2] - 100.0 <= 0.1);
            test(retval.get("ABC").length === 2);
            test(retval.get("ABC")[0] - 42.24 <= 0.1);
            test(retval.get("ABC")[1] - Math.abs(1.61) <= 0.1);
            test(retval.get("aBc").length === 2);
            test(retval.get("aBc")[0] - Math.abs(3.14) <= 0.1);
            test(retval.get("aBc")[1] - 3.14 <= 0.1);
        }

        {
            const sdi1 = new Test.StringDoubleSD();
            const sdi2 = new Test.StringDoubleSD();

            const si1 = [1.1E10, 1.2E10, 1.3E10];
            const si2 = [1.4E10, 1.5E10];
            const si3 = [1.6E10, 1.7E10];

            sdi1.set("Hello!!", si1);
            sdi1.set("Goodbye", si2);
            sdi2.set("", si3);

            const [retval, p3] = await prx.opStringDoubleSD(sdi1, sdi2);

            test(p3.size === 1);
            test(p3.get("").length === 2);
            test(p3.get("")[0] === 1.6E10);
            test(p3.get("")[1] === 1.7E10);
            test(retval.size === 3);
            test(retval.get("Hello!!").length === 3);
            test(retval.get("Hello!!")[0] === 1.1E10);
            test(retval.get("Hello!!")[1] === 1.2E10);
            test(retval.get("Hello!!")[2] === 1.3E10);
            test(retval.get("Goodbye").length === 2);
            test(retval.get("Goodbye")[0] === 1.4E10);
            test(retval.get("Goodbye")[1] === 1.5E10);
            test(retval.get("").length === 2);
            test(retval.get("")[0] === 1.6E10);
            test(retval.get("")[1] === 1.7E10);
        }

        {
            const sdi1 = new Test.StringStringSD();
            const sdi2 = new Test.StringStringSD();

            const si1 = ["abc", "de", "fghi"];
            const si2 = ["xyz", "or"];
            const si3 = ["and", "xor"];

            sdi1.set("abc", si1);
            sdi1.set("def", si2);
            sdi2.set("ghi", si3);

            const [retval, p3] = await prx.opStringStringSD(sdi1, sdi2);

            test(p3.size === 1);
            test(p3.get("ghi").length === 2);
            test(p3.get("ghi")[0] === "and");
            test(p3.get("ghi")[1] === "xor");
            test(retval.size === 3);
            test(retval.get("abc").length === 3);
            test(retval.get("abc")[0] === "abc");
            test(retval.get("abc")[1] === "de");
            test(retval.get("abc")[2] === "fghi");
            test(retval.get("def").length === 2);
            test(retval.get("def")[0] === "xyz");
            test(retval.get("def")[1] === "or");
            test(retval.get("ghi").length === 2);
            test(retval.get("ghi")[0] === "and");
            test(retval.get("ghi")[1] === "xor");
        }

        {
            const sdi1 = new Test.MyEnumMyEnumSD();
            const sdi2 = new Test.MyEnumMyEnumSD();

            const si1 = [Test.MyEnum.enum1, Test.MyEnum.enum1, Test.MyEnum.enum2];
            const si2 = [Test.MyEnum.enum1, Test.MyEnum.enum2];
            const si3 = [Test.MyEnum.enum3, Test.MyEnum.enum3];

            sdi1.set(Test.MyEnum.enum3, si1);
            sdi1.set(Test.MyEnum.enum2, si2);
            sdi2.set(Test.MyEnum.enum1, si3);

            const [retval, p3] = await prx.opMyEnumMyEnumSD(sdi1, sdi2);
            test(p3.size == 1);
            test(p3.get(Test.MyEnum.enum1).length == 2);
            test(p3.get(Test.MyEnum.enum1)[0] == Test.MyEnum.enum3);
            test(p3.get(Test.MyEnum.enum1)[1] == Test.MyEnum.enum3);
            test(retval.size === 3);
            test(retval.get(Test.MyEnum.enum3).length == 3);
            test(retval.get(Test.MyEnum.enum3)[0] == Test.MyEnum.enum1);
            test(retval.get(Test.MyEnum.enum3)[1] == Test.MyEnum.enum1);
            test(retval.get(Test.MyEnum.enum3)[2] == Test.MyEnum.enum2);
            test(retval.get(Test.MyEnum.enum2).length == 2);
            test(retval.get(Test.MyEnum.enum2)[0] == Test.MyEnum.enum1);
            test(retval.get(Test.MyEnum.enum2)[1] == Test.MyEnum.enum2);
            test(retval.get(Test.MyEnum.enum1).length == 2);
            test(retval.get(Test.MyEnum.enum1)[0] == Test.MyEnum.enum3);
            test(retval.get(Test.MyEnum.enum1)[1] == Test.MyEnum.enum3);
        }

        {
            const lengths = [0, 1, 2, 126, 127, 128, 129, 253, 254, 255, 256, 257, 1000];

            for(const l of lengths)
            {
                const s = new Array(l);
                for(let i = 0; i < l; ++i)
                {
                    s[i] = i;
                }

                const r = await prx.opIntS(s);
                test(r.length == l);
                for(let j = 0; j < r.length; ++j)
                {
                    test(r[j] == -j);
                }
            }
        }

        {
            const ctx = new Ice.Context();
            ctx.set("one", "ONE");
            ctx.set("two", "TWO");
            ctx.set("three", "THREE");
            {
                test(prx.ice_getContext().size === 0);
                const r = await prx.opContext();
                test(!Ice.MapUtil.equals(r, ctx));
            }

            {
                const r = await prx.opContext(ctx);
                test(prx.ice_getContext().size === 0);
                test(Ice.MapUtil.equals(r, ctx));
            }

            {
                const p2 = await Test.MyClassPrx.checkedCast(prx.ice_context(ctx));
                test(Ice.MapUtil.equals(p2.ice_getContext(), ctx));
                let r = await p2.opContext();
                test(Ice.MapUtil.equals(r, ctx));
                r = await p2.opContext(ctx);
                test(Ice.MapUtil.equals(r, ctx));
            }
        }

        if(!bidir)
        {
            //
            // Test implicit context propagation
            //
            const initData = new Ice.InitializationData();
            initData.properties = communicator.getProperties().clone();
            initData.properties.setProperty("Ice.ImplicitContext", "Shared");

            const ic = Ice.initialize(initData);

            let ctx = new Ice.Context();
            ctx.set("one", "ONE");
            ctx.set("two", "TWO");
            ctx.set("three", "THREE");

            let p3 = Test.MyClassPrx.uncheckedCast(ic.stringToProxy("test:" + helper.getTestEndpoint()));

            ic.getImplicitContext().setContext(ctx);
            test(Ice.MapUtil.equals(ic.getImplicitContext().getContext(), ctx));
            test(Ice.MapUtil.equals(await p3.opContext(), ctx));

            test(ic.getImplicitContext().containsKey("zero") == false);
            const r = ic.getImplicitContext().put("zero", "ZERO");
            test(r === undefined);
            test(ic.getImplicitContext().get("zero") == "ZERO");

            ctx = ic.getImplicitContext().getContext();
            test(Ice.MapUtil.equals(await p3.opContext(), ctx));

            const prxContext = new Ice.Context();
            prxContext.set("one", "UN");
            prxContext.set("four", "QUATRE");

            const combined = new Ice.Context(prxContext);
            for(const [key, value] of ctx)
            {
                if(!combined.has(key))
                {
                    combined.set(key, value);
                }
            }

            test(combined.get("one") == "UN");

            p3 = Test.MyClassPrx.uncheckedCast(p3.ice_context(prxContext));

            ic.getImplicitContext().setContext(null);
            test(Ice.MapUtil.equals(await p3.opContext(), prxContext));

            ic.getImplicitContext().setContext(ctx);
            test(Ice.MapUtil.equals(await p3.opContext(), combined));

            test(ic.getImplicitContext().remove("one") == "ONE");

            await ic.destroy();
        }

        {
            const d = 1278312346.0 / 13.0;
            const ds = [];
            for(let i = 0; i < 5; i++)
            {
                ds[i] = d;
            }

            await prx.opDoubleMarshaling(d, ds);
            await prx.opIdempotent();
            await prx.opNonmutating();
        }

        {

            test(await prx.opByte1(0xFF) == 0xFF);
            test(await prx.opShort1(0x7FFF) == 0x7FFF);
            test(await prx.opInt1(0x7FFFFFFF) == 0x7FFFFFFF);
            test((await prx.opLong1(new Ice.Long(0x7FFFFFFF, 0xFFFFFFFF))).equals(new Ice.Long(0x7FFFFFFF, 0xFFFFFFFF)));
            test(await prx.opFloat1(1.0) == 1.0);
            test(await prx.opDouble1(1.0) == 1.0);
            test(await prx.opString1("opString1") == "opString1");
            test((await prx.opStringS1(null)).length === 0);
            test((await prx.opByteBoolD1(null)).size === 0);
            test((await prx.opStringS2(null)).length === 0);
            test((await prx.opByteBoolD2(null)).size === 0);

            const d = Test.MyDerivedClassPrx.uncheckedCast(prx);
            let s = new Test.MyStruct1();
            s.tesT = "Test.MyStruct1.s";
            s.myClass = null;
            s.myStruct1 = "Test.MyStruct1.myStruct1";
            s = await d.opMyStruct1(s);
            test(s.tesT == "Test.MyStruct1.s");
            test(s.myClass === null);
            test(s.myStruct1 == "Test.MyStruct1.myStruct1");
            let c = new Test.MyClass1();
            c.tesT = "Test.MyClass1.testT";
            c.myClass = null;
            c.myClass1 = "Test.MyClass1.myClass1";
            c = await d.opMyClass1(c);
            test(c.tesT == "Test.MyClass1.testT");
            test(c.myClass === null);
            test(c.myClass1 == "Test.MyClass1.myClass1");
        }

        {
            const p1 = await prx.opMStruct1();
            p1.e = Test.MyEnum.enum3;
            const [p2, p3] = await prx.opMStruct2(p1);
            test(p2.equals(p1) && p3.equals(p1));
        }

        {
            await prx.opMSeq1();
            const p1 = ["test"];
            const [p2, p3] = await prx.opMSeq2(p1);
            test(Ice.ArrayUtil.equals(p2, p1) && Ice.ArrayUtil.equals(p3, p1));
        }

        {
            await prx.opMDict1();
            const p1 = new Map();
            p1.set("test", "test");
            const [p2, p3] = await prx.opMDict2(p1);
            test(Ice.MapUtil.equals(p2, p1) && Ice.MapUtil.equals(p3, p1));
        }

        {
            const ds = [];
            for(let i = 0; i < 5; i++)
            {
                ds[i] = 1278312346.0 / 13.0;
            }
            await prx.opDoubleMarshaling(1278312346.0 / 13.0, ds);
        }

        {
            const b = M.BPrx.uncheckedCast(communicator.stringToProxy("b:" + helper.getTestEndpoint()));
            await b.opB();
            await b.opIntf();
        }
    }

    exports.Twoways = {run: run};
}(typeof global !== "undefined" && typeof global.process !== "undefined" ? module : undefined,
  typeof global !== "undefined" && typeof global.process !== "undefined" ? require :
  (typeof WorkerGlobalScope !== "undefined" && self instanceof WorkerGlobalScope) ? self.Ice._require : window.Ice._require,
  typeof global !== "undefined" && typeof global.process !== "undefined" ? exports :
  (typeof WorkerGlobalScope !== "undefined" && self instanceof WorkerGlobalScope) ? self : window));
