corrade-vassal – Rev 1

Subversion Repositories:
Rev:
/*
 * Copyright (c) 2006-2014, openmetaverse.org
 * All rights reserved.
 *
 * - Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 * - Neither the name of the openmetaverse.org nor the names
 *   of its contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/* 
 * 
 * This tests are based upon the description at
 * 
 * http://wiki.secondlife.com/wiki/LLSD
 * 
 * and (partially) generated by the (supposed) reference implementation at
 * 
 * http://svn.secondlife.com/svn/linden/release/indra/lib/python/indra/base/llsd.py
 * 
 */

using System;
using System.IO;
using System.Text;
using System.Xml;
using NUnit.Framework;
using OpenMetaverse.StructuredData;

namespace OpenMetaverse.Tests
{

    [TestFixture()]
    public class BinarySDTests
    {
        private static readonly byte[] binaryHead = Encoding.ASCII.GetBytes("<?llsd/binary?>\n");

        [Test()]
        public void HelperFunctions()
        {
            string s = "this is a teststring so that we can find something from the beginning";
            byte[] sBinary = Encoding.ASCII.GetBytes(s);
            MemoryStream stream = new MemoryStream(sBinary);

            stream.Position = 0L;
            bool result = OSDParser.FindString(stream, "this");
            Assert.AreEqual(true, result);
            Assert.AreEqual(4L, stream.Position);

            stream.Position = 10L;
            result = OSDParser.FindString(stream, "teststring");
            Assert.AreEqual(true, result);
            Assert.AreEqual(20L, stream.Position);

            stream.Position = 25L;
            result = OSDParser.FindString(stream, "notfound");
            Assert.AreEqual(false, result);
            Assert.AreEqual(25L, stream.Position);

            stream.Position = 60L;
            result = OSDParser.FindString(stream, "beginningAndMore");
            Assert.AreEqual(false, result);
            Assert.AreEqual(60L, stream.Position);

            byte[] sFrontWhiteSpace = Encoding.ASCII.GetBytes("   \t\t\n\rtest");
            MemoryStream streamTwo = new MemoryStream(sFrontWhiteSpace);
            OSDParser.SkipWhiteSpace(streamTwo);
            Assert.AreEqual(7L, streamTwo.Position);

            byte[] sMiddleWhiteSpace = Encoding.ASCII.GetBytes("test \t\t\n\rtest");
            MemoryStream streamThree = new MemoryStream(sMiddleWhiteSpace);
            streamThree.Position = 4L;
            OSDParser.SkipWhiteSpace(streamThree);
            Assert.AreEqual(9L, streamThree.Position);

            byte[] sNoWhiteSpace = Encoding.ASCII.GetBytes("testtesttest");
            MemoryStream streamFour = new MemoryStream(sNoWhiteSpace);
            OSDParser.SkipWhiteSpace(streamFour);
            Assert.AreEqual(0L, streamFour.Position);

        }

        // Testvalues for Undef:
        private static byte[] binaryUndefValue = { 0x21 };
        private static byte[] binaryUndef = (byte[])ConcatenateArrays(binaryHead, binaryUndefValue);

        [Test()]
        public void DeserializeUndef()
        {
            OSD llsdUndef = OSDParser.DeserializeLLSDBinary(binaryUndef);
            Assert.AreEqual(OSDType.Unknown, llsdUndef.Type);
        }

        [Test()]
        public void SerializeUndef()
        {
            OSD llsdUndef = new OSD();
            byte[] binaryUndefSerialized = OSDParser.SerializeLLSDBinary(llsdUndef);
            Assert.AreEqual(binaryUndef, binaryUndefSerialized);
        }

        private static byte[] binaryTrueValue = { 0x31 };
        private static byte[] binaryTrue = (byte[])ConcatenateArrays(binaryHead, binaryTrueValue);


        private static byte[] binaryFalseValue = { 0x30 };
        private static byte[] binaryFalse = (byte[])ConcatenateArrays(binaryHead, binaryFalseValue);

        [Test()]
        public void DeserializeBool()
        {
            OSD llsdTrue = OSDParser.DeserializeLLSDBinary(binaryTrue);
            Assert.AreEqual(OSDType.Boolean, llsdTrue.Type);
            Assert.AreEqual(true, llsdTrue.AsBoolean());

            OSD llsdFalse = OSDParser.DeserializeLLSDBinary(binaryFalse);
            Assert.AreEqual(OSDType.Boolean, llsdFalse.Type);
            Assert.AreEqual(false, llsdFalse.AsBoolean());
        }

        [Test()]
        public void SerializeBool()
        {
            OSD llsdTrue = OSD.FromBoolean(true);
            byte[] binaryTrueSerialized = OSDParser.SerializeLLSDBinary(llsdTrue);
            Assert.AreEqual(binaryTrue, binaryTrueSerialized);

            OSD llsdFalse = OSD.FromBoolean(false);
            byte[] binaryFalseSerialized = OSDParser.SerializeLLSDBinary(llsdFalse);
            Assert.AreEqual(binaryFalse, binaryFalseSerialized);
        }

        private static byte[] binaryZeroIntValue = { 0x69, 0x0, 0x0, 0x0, 0x0 };
        private static byte[] binaryZeroInt = (byte[])ConcatenateArrays(binaryHead, binaryZeroIntValue);

        private static byte[] binaryAnIntValue = { 0x69, 0x0, 0x12, 0xd7, 0x9b };
        private static byte[] binaryAnInt = (byte[])ConcatenateArrays(binaryHead, binaryAnIntValue);

        [Test()]
        public void DeserializeInteger()
        {
            OSD llsdZeroInteger = OSDParser.DeserializeLLSDBinary(binaryZeroInt);
            Assert.AreEqual(OSDType.Integer, llsdZeroInteger.Type);
            Assert.AreEqual(0, llsdZeroInteger.AsInteger());


            OSD llsdAnInteger = OSDParser.DeserializeLLSDBinary(binaryAnInt);
            Assert.AreEqual(OSDType.Integer, llsdAnInteger.Type);
            Assert.AreEqual(1234843, llsdAnInteger.AsInteger());
        }

        [Test()]
        public void SerializeInteger()
        {
            OSD llsdZeroInt = OSD.FromInteger(0);
            byte[] binaryZeroIntSerialized = OSDParser.SerializeLLSDBinary(llsdZeroInt);
            Assert.AreEqual(binaryZeroInt, binaryZeroIntSerialized);

            binaryZeroIntSerialized = OSDParser.SerializeLLSDBinary(llsdZeroInt, false);
            Assert.AreEqual(binaryZeroIntValue, binaryZeroIntSerialized);

            OSD llsdAnInt = OSD.FromInteger(1234843);
            byte[] binaryAnIntSerialized = OSDParser.SerializeLLSDBinary(llsdAnInt);
            Assert.AreEqual(binaryAnInt, binaryAnIntSerialized);

            binaryAnIntSerialized = OSDParser.SerializeLLSDBinary(llsdAnInt, false);
            Assert.AreEqual(binaryAnIntValue, binaryAnIntSerialized);
        }

        private static byte[] binaryRealValue = { 0x72, 0x41, 0x2c, 0xec, 0xf6, 0x77, 0xce, 0xd9, 0x17 };
        private static byte[] binaryReal = (byte[])ConcatenateArrays(binaryHead, binaryRealValue);

        [Test()]
        public void DeserializeReal()
        {
            OSD llsdReal = OSDParser.DeserializeLLSDBinary(binaryReal);
            Assert.AreEqual(OSDType.Real, llsdReal.Type);
            Assert.AreEqual(947835.234d, llsdReal.AsReal());
        }

        [Test()]
        public void SerializeReal()
        {
            OSD llsdReal = OSD.FromReal(947835.234d);
            byte[] binaryRealSerialized = OSDParser.SerializeLLSDBinary(llsdReal);
            Assert.AreEqual(binaryReal, binaryRealSerialized);

            binaryRealSerialized = OSDParser.SerializeLLSDBinary(llsdReal);
            Assert.AreEqual(binaryReal, binaryRealSerialized);
        }

        private static byte[] binaryAUUIDValue = { 0x75, 0x97, 0xf4, 0xae, 0xca, 0x88, 0xa1, 0x42, 0xa1, 
                                        0xb3, 0x85, 0xb9, 0x7b, 0x18, 0xab, 0xb2, 0x55 };
        private static byte[] binaryAUUID = (byte[])ConcatenateArrays(binaryHead, binaryAUUIDValue);

        private static byte[] binaryZeroUUIDValue = { 0x75, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
        private static byte[] binaryZeroUUID = (byte[])ConcatenateArrays(binaryHead, binaryZeroUUIDValue);


        [Test()]
        public void DeserializeUUID()
        {
            OSD llsdAUUID = OSDParser.DeserializeLLSDBinary(binaryAUUID);
            Assert.AreEqual(OSDType.UUID, llsdAUUID.Type);
            Assert.AreEqual("97f4aeca-88a1-42a1-b385-b97b18abb255", llsdAUUID.AsString());

            OSD llsdZeroUUID = OSDParser.DeserializeLLSDBinary(binaryZeroUUID);
            Assert.AreEqual(OSDType.UUID, llsdZeroUUID.Type);
            Assert.AreEqual("00000000-0000-0000-0000-000000000000", llsdZeroUUID.AsString());

        }

        [Test()]
        public void SerializeUUID()
        {
            OSD llsdAUUID = OSD.FromUUID(new UUID("97f4aeca-88a1-42a1-b385-b97b18abb255"));
            byte[] binaryAUUIDSerialized = OSDParser.SerializeLLSDBinary(llsdAUUID);
            Assert.AreEqual(binaryAUUID, binaryAUUIDSerialized);

            binaryAUUIDSerialized = OSDParser.SerializeLLSDBinary(llsdAUUID);
            Assert.AreEqual(binaryAUUID, binaryAUUIDSerialized);

            OSD llsdZeroUUID = OSD.FromUUID(new UUID("00000000-0000-0000-0000-000000000000"));
            byte[] binaryZeroUUIDSerialized = OSDParser.SerializeLLSDBinary(llsdZeroUUID);
            Assert.AreEqual(binaryZeroUUID, binaryZeroUUIDSerialized);

            binaryZeroUUIDSerialized = OSDParser.SerializeLLSDBinary(llsdZeroUUID);
            Assert.AreEqual(binaryZeroUUID, binaryZeroUUIDSerialized);
        }

        private static byte[] binaryBinStringValue = { 0x62, 0x0, 0x0, 0x0, 0x34, // this line is the encoding header
                                        0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x73, 
                                        0x69, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x20, 0x63, 0x6f,
                                        0x6e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68,
                                        0x69, 0x73, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0xa, 0xd };
        private static byte[] binaryBinString = (byte[])ConcatenateArrays(binaryHead, binaryBinStringValue);

        [Test()]
        public void DeserializeLLSDBinary()
        {
            OSD llsdBytes = OSDParser.DeserializeLLSDBinary(binaryBinString);
            Assert.AreEqual(OSDType.Binary, llsdBytes.Type);
            byte[] contentBinString = { 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x73, 
                                        0x69, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x20, 0x63, 0x6f,
                                        0x6e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68,
                                        0x69, 0x73, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0xa, 0xd };
            Assert.AreEqual(contentBinString, llsdBytes.AsBinary());
        }

        [Test()]
        public void SerializeLLSDBinary()
        {
            byte[] contentBinString = { 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x73, 
                                        0x69, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x20, 0x63, 0x6f,
                                        0x6e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68,
                                        0x69, 0x73, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0xa, 0xd };
            OSD llsdBinary = OSD.FromBinary(contentBinString);
            byte[] binaryBinarySerialized = OSDParser.SerializeLLSDBinary(llsdBinary);
            Assert.AreEqual(binaryBinString, binaryBinarySerialized);
        }

        private static byte[] binaryEmptyStringValue = { 0x73, 0x0, 0x0, 0x0, 0x0 };
        private static byte[] binaryEmptyString = (byte[])ConcatenateArrays(binaryHead, binaryEmptyStringValue);
        private static byte[] binaryLongStringValue = { 0x73, 0x0, 0x0, 0x0, 0x25, 
                                                            0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
                                                            0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
                                                            0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
                                                            0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
                                                            0x79, 0x7a, 0x30, 0x31, 0x32, 0x33,
                                                            0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30 };
        private static byte[] binaryLongString = (byte[])ConcatenateArrays(binaryHead, binaryLongStringValue);

        [Test()]
        public void DeserializeString()
        {
            OSD llsdEmptyString = OSDParser.DeserializeLLSDBinary(binaryEmptyString);
            Assert.AreEqual(OSDType.String, llsdEmptyString.Type);
            string contentEmptyString = "";
            Assert.AreEqual(contentEmptyString, llsdEmptyString.AsString());

            OSD llsdLongString = OSDParser.DeserializeLLSDBinary(binaryLongString);
            Assert.AreEqual(OSDType.String, llsdLongString.Type);
            string contentLongString = "abcdefghijklmnopqrstuvwxyz01234567890";
            Assert.AreEqual(contentLongString, llsdLongString.AsString());
        }

        [Test()]
        public void SerializeString()
        {
            OSD llsdString = OSD.FromString("abcdefghijklmnopqrstuvwxyz01234567890");
            byte[] binaryLongStringSerialized = OSDParser.SerializeLLSDBinary(llsdString);
            Assert.AreEqual(binaryLongString, binaryLongStringSerialized);

            // A test with some utf8 characters
            string contentAStringXML = "<x>&#x196;&#x214;&#x220;&#x228;&#x246;&#x252;</x>";
            byte[] bytes = Encoding.UTF8.GetBytes(contentAStringXML);
            XmlTextReader xtr = new XmlTextReader(new MemoryStream(bytes, false));
            xtr.Read();
            xtr.Read();

            string contentAString = xtr.ReadString();
            OSD llsdAString = OSD.FromString(contentAString);
            byte[] binaryAString = OSDParser.SerializeLLSDBinary(llsdAString);
            OSD llsdAStringDS = OSDParser.DeserializeLLSDBinary(binaryAString);
            Assert.AreEqual(OSDType.String, llsdAStringDS.Type);
            Assert.AreEqual(contentAString, llsdAStringDS.AsString());

            // we also test for a 4byte character.
            string xml = "<x>&#x10137;</x>";
            byte[] bytesTwo = Encoding.UTF8.GetBytes(xml);
            XmlTextReader xtrTwo = new XmlTextReader(new MemoryStream(bytesTwo, false));
            xtrTwo.Read();
            xtrTwo.Read();
            string content = xtrTwo.ReadString();

            OSD llsdStringOne = OSD.FromString(content);
            byte[] binaryAStringOneSerialized = OSDParser.SerializeLLSDBinary(llsdStringOne);
            OSD llsdStringOneDS = OSDParser.DeserializeLLSDBinary(binaryAStringOneSerialized);
            Assert.AreEqual(OSDType.String, llsdStringOneDS.Type);
            Assert.AreEqual(content, llsdStringOneDS.AsString());

        }

        // Be careful. The current and above mentioned reference implementation has a bug that
        // doesnt allow proper binary Uri encoding.
        // We compare here to a fixed version of Uri encoding
        private static byte[] binaryURIValue = { 0x6c, 0x0, 0x0, 0x0, 0x18, // this line is the encoding header
                                    0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x74,
                                    0x65, 0x73, 0x74, 0x75, 0x72, 0x6c, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2f };
        private static byte[] binaryURI = (byte[])ConcatenateArrays(binaryHead, binaryURIValue);

        [Test()]
        public void DeserializeURI()
        {
            OSD llsdURI = OSDParser.DeserializeLLSDBinary(binaryURI);
            Assert.AreEqual(OSDType.URI, llsdURI.Type);
            Uri uri = new Uri("http://www.testurl.test/");
            Assert.AreEqual(uri, llsdURI.AsUri());

        }

        [Test()]
        public void SerializeURI()
        {
            OSD llsdUri = OSD.FromUri(new Uri("http://www.testurl.test/"));
            byte[] binaryURISerialized = OSDParser.SerializeLLSDBinary(llsdUri);
            Assert.AreEqual(binaryURI, binaryURISerialized);
        }

        // Here is a problem.
        // The reference implementation does serialize to a local timestamp and not to a universal timestamp,
        // which means, this implementation and the reference implementation only work the same in the universal
        // timezone. Therefore this binaryDateTimeValue is generated in the UTC timezone by the reference
        // implementation.
        private static byte[] binaryDateTimeValue = { 100, 0, 0, 192, 141, 167, 222, 209, 65 };
        private static byte[] binaryDateTime = (byte[])ConcatenateArrays(binaryHead, binaryDateTimeValue);

        [Test()]
        public void DeserializeDateTime()
        {
            OSD llsdDateTime = OSDParser.DeserializeLLSDBinary(binaryDateTime);
            Assert.AreEqual(OSDType.Date, llsdDateTime.Type);
            DateTime dt = new DateTime(2008, 1, 1, 20, 10, 31, 0, DateTimeKind.Utc);
            DateTime dateLocal = llsdDateTime.AsDate();
            Assert.AreEqual(dt, dateLocal.ToUniversalTime());
        }

        [Test()]
        public void SerializeDateTime()
        {
            DateTime dt = new DateTime(2008, 1, 1, 20, 10, 31, 0, DateTimeKind.Utc);
            OSD llsdDate = OSD.FromDate(dt);
            byte[] binaryDateSerialized = OSDParser.SerializeLLSDBinary(llsdDate);
            Assert.AreEqual(binaryDateTime, binaryDateSerialized);

            // check if a *local* time can be serialized and deserialized
            DateTime dtOne = new DateTime(2009, 12, 30, 8, 25, 10, DateTimeKind.Local);
            OSD llsdDateOne = OSD.FromDate(dtOne);
            byte[] binaryDateOneSerialized = OSDParser.SerializeLLSDBinary(llsdDateOne);
            OSD llsdDateOneDS = OSDParser.DeserializeLLSDBinary(binaryDateOneSerialized);
            Assert.AreEqual(OSDType.Date, llsdDateOneDS.Type);
            Assert.AreEqual(dtOne, llsdDateOneDS.AsDate());

            DateTime dtTwo = new DateTime(2010, 11, 11, 10, 8, 20, DateTimeKind.Utc);
            OSD llsdDateTwo = OSD.FromDate(dtTwo);
            byte[] binaryDateTwoSerialized = OSDParser.SerializeLLSDBinary(llsdDateTwo);
            OSD llsdDateTwoDS = OSDParser.DeserializeLLSDBinary(binaryDateTwoSerialized);
            Assert.AreEqual(OSDType.Date, llsdDateOneDS.Type);
            Assert.AreEqual(dtTwo.ToLocalTime(), llsdDateTwoDS.AsDate());
        }

        // Data for empty array { }
        private static byte[] binaryEmptyArrayValue = { 0x5b, 0x0, 0x0, 0x0, 0x0, 0x5d };
        // Encoding header + num of elements + tail
        private static byte[] binaryEmptyArray = (byte[])ConcatenateArrays(binaryHead, binaryEmptyArrayValue);
        // Data for simple array { 0 }
        private static byte[] binarySimpleArrayValue = { 0x5b, 0x0, 0x0, 0x0, 0x1, // Encoding header + num of elements
                                                             0x69, 0x0, 0x0, 0x0, 0x0, 0x5d };
        private static byte[] binarySimpleArray = (byte[])ConcatenateArrays(binaryHead, binarySimpleArrayValue);

        // Data for simple array { 0, 0 }
        private static byte[] binarySimpleArrayTwoValue = { 0x5b, 0x0, 0x0, 0x0, 0x2, // Encoding header + num of elements
                                                             0x69, 0x0, 0x0, 0x0, 0x0, 
                                                             0x69, 0x0, 0x0, 0x0, 0x0, 0x5d };
        private static byte[] binarySimpleArrayTwo = (byte[])ConcatenateArrays(binaryHead, binarySimpleArrayTwoValue);

        [Test()]
        public void DeserializeArray()
        {
            OSD llsdEmptyArray = OSDParser.DeserializeLLSDBinary(binaryEmptyArray);
            Assert.AreEqual(OSDType.Array, llsdEmptyArray.Type);
            OSDArray llsdEmptyArrayArray = (OSDArray)llsdEmptyArray;
            Assert.AreEqual(0, llsdEmptyArrayArray.Count);


            OSD llsdSimpleArray = OSDParser.DeserializeLLSDBinary(binarySimpleArray);
            Assert.AreEqual(OSDType.Array, llsdSimpleArray.Type);
            OSDArray llsdArray = (OSDArray)llsdSimpleArray;
            Assert.AreEqual(OSDType.Integer, llsdArray[0].Type);
            Assert.AreEqual(0, llsdArray[0].AsInteger());


            OSD llsdSimpleArrayTwo = OSDParser.DeserializeLLSDBinary(binarySimpleArrayTwo);
            Assert.AreEqual(OSDType.Array, llsdSimpleArrayTwo.Type);
            OSDArray llsdArrayTwo = (OSDArray)llsdSimpleArrayTwo;
            Assert.AreEqual(2, llsdArrayTwo.Count);

            Assert.AreEqual(OSDType.Integer, llsdArrayTwo[0].Type);
            Assert.AreEqual(0, llsdArrayTwo[0].AsInteger());
            Assert.AreEqual(OSDType.Integer, llsdArrayTwo[1].Type);
            Assert.AreEqual(0, llsdArrayTwo[1].AsInteger());
        }

        [Test()]
        public void SerializeArray()
        {
            OSDArray llsdEmptyArray = new OSDArray();
            byte[] binaryEmptyArraySerialized = OSDParser.SerializeLLSDBinary(llsdEmptyArray);
            Assert.AreEqual(binaryEmptyArray, binaryEmptyArraySerialized);

            binaryEmptyArraySerialized = OSDParser.SerializeLLSDBinary(llsdEmptyArray, false);
            Assert.AreEqual(binaryEmptyArrayValue, binaryEmptyArraySerialized);

            OSDArray llsdSimpleArray = new OSDArray();
            llsdSimpleArray.Add(OSD.FromInteger(0));
            byte[] binarySimpleArraySerialized = OSDParser.SerializeLLSDBinary(llsdSimpleArray);
            Assert.AreEqual(binarySimpleArray, binarySimpleArraySerialized);

            binarySimpleArraySerialized = OSDParser.SerializeLLSDBinary(llsdSimpleArray, false);
            Assert.AreEqual(binarySimpleArrayValue, binarySimpleArraySerialized);

            OSDArray llsdSimpleArrayTwo = new OSDArray();
            llsdSimpleArrayTwo.Add(OSD.FromInteger(0));
            llsdSimpleArrayTwo.Add(OSD.FromInteger(0));
            byte[] binarySimpleArrayTwoSerialized = OSDParser.SerializeLLSDBinary(llsdSimpleArrayTwo);
            Assert.AreEqual(binarySimpleArrayTwo, binarySimpleArrayTwoSerialized);

            binarySimpleArrayTwoSerialized = OSDParser.SerializeLLSDBinary(llsdSimpleArrayTwo, false);
            Assert.AreEqual(binarySimpleArrayTwoValue, binarySimpleArrayTwoSerialized);
        }

        // Data for empty dictionary { }
        private static byte[] binaryEmptyMapValue = { 0x7b, 0x0, 0x0, 0x0, 0x0, 0x7d };
        private static byte[] binaryEmptyMap = (byte[])ConcatenateArrays(binaryHead, binaryEmptyMapValue);

        // Data for simple dictionary { test = 0 }
        private static byte[] binarySimpleMapValue = { 0x7b, 0x0, 0x0, 0x0, 0x1, // Encoding header + num of elements
                                                        0x6b, 0x0, 0x0, 0x0, 0x4, // 'k' + keylength 
                                                        0x74, 0x65, 0x73, 0x74,  // key 'test' 
                                                        0x69, 0x0, 0x0, 0x0, 0x0, // i + '0'
                                                        0x7d };
        private static byte[] binarySimpleMap = (byte[])ConcatenateArrays(binaryHead, binarySimpleMapValue);

        // Data for simple dictionary { t0st = 241, tes1 = "aha", test = undef }
        private static byte[] binarySimpleMapTwoValue = { 0x7b, 0x0, 0x0, 0x0, 0x3, // Encoding header + num of elements
                                 0x6b, 0x0, 0x0, 0x0, 0x4, // 'k' + keylength 
                                 0x74, 0x65, 0x73, 0x74,  // key 'test'
                                 0x21, // undef
                                 0x6b, 0x0, 0x0, 0x0, 0x4, // k + keylength 
                                 0x74, 0x65, 0x73, 0x31, // key 'tes1' 
                                 0x73, 0x0, 0x0, 0x0, 0x3, // string head + length
                                 0x61, 0x68, 0x61, // 'aha' 
                                 0x6b, 0x0, 0x0, 0x0, 0x4, // k + keylength 
                                 0x74, 0x30, 0x73, 0x74,  // key 't0st'
                                 0x69, 0x0, 0x0, 0x0, 0xf1, // integer 241
                                 0x7d };
        private static byte[] binarySimpleMapTwo = (byte[])ConcatenateArrays(binaryHead, binarySimpleMapTwoValue);

        [Test()]
        public void DeserializeDictionary()
        {
            OSDMap llsdEmptyMap = (OSDMap)OSDParser.DeserializeLLSDBinary(binaryEmptyMap);
            Assert.AreEqual(OSDType.Map, llsdEmptyMap.Type);
            Assert.AreEqual(0, llsdEmptyMap.Count);

            OSDMap llsdSimpleMap = (OSDMap)OSDParser.DeserializeLLSDBinary(binarySimpleMap);
            Assert.AreEqual(OSDType.Map, llsdSimpleMap.Type);
            Assert.AreEqual(1, llsdSimpleMap.Count);
            Assert.AreEqual(OSDType.Integer, llsdSimpleMap["test"].Type);
            Assert.AreEqual(0, llsdSimpleMap["test"].AsInteger());

            OSDMap llsdSimpleMapTwo = (OSDMap)OSDParser.DeserializeLLSDBinary(binarySimpleMapTwo);
            Assert.AreEqual(OSDType.Map, llsdSimpleMapTwo.Type);
            Assert.AreEqual(3, llsdSimpleMapTwo.Count);
            Assert.AreEqual(OSDType.Unknown, llsdSimpleMapTwo["test"].Type);
            Assert.AreEqual(OSDType.String, llsdSimpleMapTwo["tes1"].Type);
            Assert.AreEqual("aha", llsdSimpleMapTwo["tes1"].AsString());
            Assert.AreEqual(OSDType.Integer, llsdSimpleMapTwo["t0st"].Type);
            Assert.AreEqual(241, llsdSimpleMapTwo["t0st"].AsInteger());


        }

        [Test()]
        public void SerializeDictionary()
        {
            OSDMap llsdEmptyMap = new OSDMap();
            byte[] binaryEmptyMapSerialized = OSDParser.SerializeLLSDBinary(llsdEmptyMap);
            Assert.AreEqual(binaryEmptyMap, binaryEmptyMapSerialized);

            OSDMap llsdSimpleMap = new OSDMap();
            llsdSimpleMap["test"] = OSD.FromInteger(0);
            byte[] binarySimpleMapSerialized = OSDParser.SerializeLLSDBinary(llsdSimpleMap);
            Assert.AreEqual(binarySimpleMap, binarySimpleMapSerialized);

            OSDMap llsdSimpleMapTwo = new OSDMap();
            llsdSimpleMapTwo["t0st"] = OSD.FromInteger(241);
            llsdSimpleMapTwo["tes1"] = OSD.FromString("aha");
            llsdSimpleMapTwo["test"] = new OSD();
            byte[] binarySimpleMapTwoSerialized = OSDParser.SerializeLLSDBinary(llsdSimpleMapTwo);

            // We dont compare here to the original serialized value, because, as maps dont preserve order,
            // the original serialized value is not *exactly* the same. Instead we compare to a deserialized
            // version created by this deserializer.
            OSDMap llsdSimpleMapDeserialized = (OSDMap)OSDParser.DeserializeLLSDBinary(binarySimpleMapTwoSerialized);
            Assert.AreEqual(OSDType.Map, llsdSimpleMapDeserialized.Type);
            Assert.AreEqual(3, llsdSimpleMapDeserialized.Count);
            Assert.AreEqual(OSDType.Integer, llsdSimpleMapDeserialized["t0st"].Type);
            Assert.AreEqual(241, llsdSimpleMapDeserialized["t0st"].AsInteger());
            Assert.AreEqual(OSDType.String, llsdSimpleMapDeserialized["tes1"].Type);
            Assert.AreEqual("aha", llsdSimpleMapDeserialized["tes1"].AsString());
            Assert.AreEqual(OSDType.Unknown, llsdSimpleMapDeserialized["test"].Type);

            // we also test for a 4byte key character.
            string xml = "<x>&#x10137;</x>";
            byte[] bytes = Encoding.UTF8.GetBytes(xml);
            XmlTextReader xtr = new XmlTextReader(new MemoryStream(bytes, false));
            xtr.Read();
            xtr.Read();
            string content = xtr.ReadString();

            OSDMap llsdSimpleMapThree = new OSDMap();
            OSD llsdSimpleValue = OSD.FromString(content);
            llsdSimpleMapThree[content] = llsdSimpleValue;
            Assert.AreEqual(content, llsdSimpleMapThree[content].AsString());

            byte[] binarySimpleMapThree = OSDParser.SerializeLLSDBinary(llsdSimpleMapThree);
            OSDMap llsdSimpleMapThreeDS = (OSDMap)OSDParser.DeserializeLLSDBinary(binarySimpleMapThree);
            Assert.AreEqual(OSDType.Map, llsdSimpleMapThreeDS.Type);
            Assert.AreEqual(1, llsdSimpleMapThreeDS.Count);
            Assert.AreEqual(content, llsdSimpleMapThreeDS[content].AsString());

        }

        private static byte[] binaryNestedValue = { 0x5b, 0x0, 0x0, 0x0, 0x3, 
                                            0x7b, 0x0, 0x0, 0x0, 0x2, 
                                            0x6b, 0x0, 0x0, 0x0, 0x4, 
                                            0x74, 0x65, 0x73, 0x74, 
                                            0x73, 0x0, 0x0, 0x0, 0x4, 
                                            0x77, 0x68, 0x61, 0x74, 
                                            0x6b, 0x0, 0x0, 0x0, 0x4, 
                                            0x74, 0x30, 0x73, 
                                            0x74, 0x5b, 0x0, 0x0, 0x0, 0x2,
                                            0x69, 0x0, 0x0, 0x0, 0x1,
                                            0x69, 0x0, 0x0, 0x0, 0x2,
                                            0x5d, 0x7d, 0x69, 0x0, 0x0, 0x0, 
                                            0x7c, 0x69, 0x0, 0x0, 0x3, 0xdb, 
                                           0x5d };
        private static byte[] binaryNested = (byte[])ConcatenateArrays(binaryHead, binaryNestedValue);

        [Test()]
        public void DeserializeNestedComposite()
        {
            OSD llsdNested = OSDParser.DeserializeLLSDBinary(binaryNested);
            Assert.AreEqual(OSDType.Array, llsdNested.Type);
            OSDArray llsdArray = (OSDArray)llsdNested;
            Assert.AreEqual(3, llsdArray.Count);

            OSDMap llsdMap = (OSDMap)llsdArray[0];
            Assert.AreEqual(OSDType.Map, llsdMap.Type);
            Assert.AreEqual(2, llsdMap.Count);

            OSDArray llsdNestedArray = (OSDArray)llsdMap["t0st"];
            Assert.AreEqual(OSDType.Array, llsdNestedArray.Type);
            OSDInteger llsdNestedIntOne = (OSDInteger)llsdNestedArray[0];
            Assert.AreEqual(OSDType.Integer, llsdNestedIntOne.Type);
            Assert.AreEqual(1, llsdNestedIntOne.AsInteger());
            OSDInteger llsdNestedIntTwo = (OSDInteger)llsdNestedArray[1];
            Assert.AreEqual(OSDType.Integer, llsdNestedIntTwo.Type);
            Assert.AreEqual(2, llsdNestedIntTwo.AsInteger());

            OSDString llsdString = (OSDString)llsdMap["test"];
            Assert.AreEqual(OSDType.String, llsdString.Type);
            Assert.AreEqual("what", llsdString.AsString());

            OSDInteger llsdIntOne = (OSDInteger)llsdArray[1];
            Assert.AreEqual(OSDType.Integer, llsdIntOne.Type);
            Assert.AreEqual(124, llsdIntOne.AsInteger());
            OSDInteger llsdIntTwo = (OSDInteger)llsdArray[2];
            Assert.AreEqual(OSDType.Integer, llsdIntTwo.Type);
            Assert.AreEqual(987, llsdIntTwo.AsInteger());

        }

        [Test()]
        public void SerializeNestedComposite()
        {
            OSDArray llsdNested = new OSDArray();
            OSDMap llsdMap = new OSDMap();
            OSDArray llsdArray = new OSDArray();
            llsdArray.Add(OSD.FromInteger(1));
            llsdArray.Add(OSD.FromInteger(2));
            llsdMap["t0st"] = llsdArray;
            llsdMap["test"] = OSD.FromString("what");
            llsdNested.Add(llsdMap);
            llsdNested.Add(OSD.FromInteger(124));
            llsdNested.Add(OSD.FromInteger(987));

            byte[] binaryNestedSerialized = OSDParser.SerializeLLSDBinary(llsdNested);
            // Because maps don't preserve order, we compare here to a deserialized value. 
            OSDArray llsdNestedDeserialized = (OSDArray)OSDParser.DeserializeLLSDBinary(binaryNestedSerialized);
            Assert.AreEqual(OSDType.Array, llsdNestedDeserialized.Type);
            Assert.AreEqual(3, llsdNestedDeserialized.Count);

            OSDMap llsdMapDeserialized = (OSDMap)llsdNestedDeserialized[0];
            Assert.AreEqual(OSDType.Map, llsdMapDeserialized.Type);
            Assert.AreEqual(2, llsdMapDeserialized.Count);
            Assert.AreEqual(OSDType.Array, llsdMapDeserialized["t0st"].Type);

            OSDArray llsdNestedArray = (OSDArray)llsdMapDeserialized["t0st"];
            Assert.AreEqual(OSDType.Array, llsdNestedArray.Type);
            Assert.AreEqual(2, llsdNestedArray.Count);
            Assert.AreEqual(OSDType.Integer, llsdNestedArray[0].Type);
            Assert.AreEqual(1, llsdNestedArray[0].AsInteger());
            Assert.AreEqual(OSDType.Integer, llsdNestedArray[1].Type);
            Assert.AreEqual(2, llsdNestedArray[1].AsInteger());

            Assert.AreEqual(OSDType.String, llsdMapDeserialized["test"].Type);
            Assert.AreEqual("what", llsdMapDeserialized["test"].AsString());

            Assert.AreEqual(OSDType.Integer, llsdNestedDeserialized[1].Type);
            Assert.AreEqual(124, llsdNestedDeserialized[1].AsInteger());

            Assert.AreEqual(OSDType.Integer, llsdNestedDeserialized[2].Type);
            Assert.AreEqual(987, llsdNestedDeserialized[2].AsInteger());

        }

        [Test()]
        public void SerializeLongMessage()
        {
            // each 80 chars
            string sOne = "asdklfjasadlfkjaerotiudfgjkhsdklgjhsdklfghasdfklhjasdfkjhasdfkljahsdfjklaasdfkj8";
            string sTwo = "asdfkjlaaweoiugsdfjkhsdfg,.mnasdgfkljhrtuiohfglökajsdfoiwghjkdlaaaaseldkfjgheus9";
            
            OSD stringOne = OSD.FromString( sOne );
            OSD stringTwo = OSD.FromString(sTwo);

            OSDMap llsdMap = new OSDMap();
            llsdMap["testOne"] = stringOne;
            llsdMap["testTwo"] = stringTwo;
            llsdMap["testThree"] = stringOne;
            llsdMap["testFour"] = stringTwo;
            llsdMap["testFive"] = stringOne;
            llsdMap["testSix"] = stringTwo;
            llsdMap["testSeven"] = stringOne;
            llsdMap["testEight"] = stringTwo;
            llsdMap["testNine"] = stringOne;
            llsdMap["testTen"] = stringTwo;
            
            
            byte[] binaryData = OSDParser.SerializeLLSDBinary( llsdMap );

            OSDMap llsdMapDS = (OSDMap)OSDParser.DeserializeLLSDBinary( binaryData );
            Assert.AreEqual( OSDType.Map, llsdMapDS.Type );
            Assert.AreEqual( 10, llsdMapDS.Count );
            Assert.AreEqual( sOne, llsdMapDS["testOne"].AsString());
            Assert.AreEqual( sTwo, llsdMapDS["testTwo"].AsString());
            Assert.AreEqual( sOne, llsdMapDS["testThree"].AsString());
            Assert.AreEqual( sTwo, llsdMapDS["testFour"].AsString());
            Assert.AreEqual( sOne, llsdMapDS["testFive"].AsString());
            Assert.AreEqual( sTwo, llsdMapDS["testSix"].AsString());
            Assert.AreEqual( sOne, llsdMapDS["testSeven"].AsString());
            Assert.AreEqual( sTwo, llsdMapDS["testEight"].AsString());
            Assert.AreEqual( sOne, llsdMapDS["testNine"].AsString());
            Assert.AreEqual( sTwo, llsdMapDS["testTen"].AsString());
        }


        static Array ConcatenateArrays(params Array[] arrays)
        {
            if (arrays == null)
            {
                throw new ArgumentNullException("arrays");
            }
            if (arrays.Length == 0)
            {
                throw new ArgumentException("No arrays specified");
            }

            Type type = arrays[0].GetType().GetElementType();
            int totalLength = arrays[0].Length;
            for (int i = 1; i < arrays.Length; i++)
            {
                if (arrays[i].GetType().GetElementType() != type)
                {
                    throw new ArgumentException("Arrays must all be of the same type");
                }
                totalLength += arrays[i].Length;
            }

            Array ret = Array.CreateInstance(type, totalLength);
            int index = 0;
            foreach (Array array in arrays)
            {
                Array.Copy(array, 0, ret, index, array.Length);
                index += array.Length;
            }
            return ret;
        }
    }
}