using System; using System.Collections.Generic; using System.Text; using NUnit.Framework; using System.Collections; using libsecondlife.StructuredData; namespace libsecondlife.Tests { /// /// XmlLLSDTests is a suite of tests for libsl implementation of the LLSD XML format. /// /// [TestFixture] public class XmlLLSDTests { /// /// Test that the sample LLSD supplied by Linden Lab is properly deserialized. /// The LLSD string in the test is a pared down version of the sample on the blog. /// http://wiki.secondlife.com/wiki/LLSD /// [Test] public void DeserializeLLSDSample() { LLSD theLLSD = null; LLSDMap map = null; LLSD tempLLSD = null; LLSDUUID tempUUID = null; LLSDString tempStr = null; LLSDReal tempReal = null; String testLLSD = @" region_id 67153d5b-3659-afb4-8510-adda2c034649 scale one minute simulator statistics time dilation 0.9878624 sim fps 44.38898 agent updates per second nan total task count 4 active task count 0 pending uploads 0.0001096525 "; //Deserialize the string byte[] bytes = Encoding.UTF8.GetBytes(testLLSD); theLLSD = LLSDParser.DeserializeXml(bytes); //Confirm the contents Assert.IsNotNull(theLLSD); Assert.IsTrue(theLLSD is LLSDMap); Assert.IsTrue(theLLSD.Type == LLSDType.Map); map = (LLSDMap)theLLSD; tempLLSD = map["region_id"]; Assert.IsNotNull(tempLLSD); Assert.IsTrue(tempLLSD is LLSDUUID); Assert.IsTrue(tempLLSD.Type == LLSDType.UUID); tempUUID = (LLSDUUID)tempLLSD; Assert.AreEqual(new LLUUID("67153d5b-3659-afb4-8510-adda2c034649"), tempUUID.AsUUID()); tempLLSD = map["scale"]; Assert.IsNotNull(tempLLSD); Assert.IsTrue(tempLLSD is LLSDString); Assert.IsTrue(tempLLSD.Type == LLSDType.String); tempStr = (LLSDString)tempLLSD; Assert.AreEqual("one minute", tempStr.AsString()); tempLLSD = map["simulator statistics"]; Assert.IsNotNull(tempLLSD); Assert.IsTrue(tempLLSD is LLSDMap); Assert.IsTrue(tempLLSD.Type == LLSDType.Map); map = (LLSDMap)tempLLSD; tempLLSD = map["time dilation"]; Assert.IsNotNull(tempLLSD); Assert.IsTrue(tempLLSD is LLSDReal); Assert.IsTrue(tempLLSD.Type == LLSDType.Real); tempReal = (LLSDReal)tempLLSD; Assert.AreEqual(0.9878624d, tempReal.AsReal()); //TODO - figure out any relevant rounding variability for 64 bit reals tempLLSD = map["sim fps"]; Assert.IsNotNull(tempLLSD); Assert.IsTrue(tempLLSD is LLSDReal); Assert.IsTrue(tempLLSD.Type == LLSDType.Real); tempReal = (LLSDReal)tempLLSD; Assert.AreEqual(44.38898d, tempReal.AsReal()); tempLLSD = map["agent updates per second"]; Assert.IsNotNull(tempLLSD); Assert.IsTrue(tempLLSD is LLSDReal); Assert.IsTrue(tempLLSD.Type == LLSDType.Real); tempReal = (LLSDReal)tempLLSD; Assert.AreEqual(Double.NaN, tempLLSD.AsReal()); tempLLSD = map["total task count"]; Assert.IsNotNull(tempLLSD); Assert.IsTrue(tempLLSD is LLSDReal); Assert.IsTrue(tempLLSD.Type == LLSDType.Real); tempReal = (LLSDReal)tempLLSD; Assert.AreEqual(4.0d, tempReal.AsReal()); tempLLSD = map["active task count"]; Assert.IsNotNull(tempLLSD); Assert.IsTrue(tempLLSD is LLSDReal); Assert.IsTrue(tempLLSD.Type == LLSDType.Real); tempReal = (LLSDReal)tempLLSD; Assert.AreEqual(0.0d, tempReal.AsReal()); tempLLSD = map["pending uploads"]; Assert.IsNotNull(tempLLSD); Assert.IsTrue(tempLLSD is LLSDReal); Assert.IsTrue(tempLLSD.Type == LLSDType.Real); tempReal = (LLSDReal)tempLLSD; Assert.AreEqual(0.0001096525d, tempReal.AsReal()); } /// /// Test that various Real representations are parsed correctly. /// [Test] public void DeserializeReals() { LLSD theLLSD = null; LLSDArray array = null; LLSDReal tempReal = null; String testLLSD = @" 44.38898 nan 4 -13.333 "; //Deserialize the string byte[] bytes = Encoding.UTF8.GetBytes(testLLSD); theLLSD = LLSDParser.DeserializeXml(bytes); Assert.IsTrue(theLLSD is LLSDArray); array = (LLSDArray)theLLSD; Assert.AreEqual(LLSDType.Real, array[0].Type); tempReal = (LLSDReal)array[0]; Assert.AreEqual(44.38898d, tempReal.AsReal()); Assert.AreEqual(LLSDType.Real, array[1].Type); tempReal = (LLSDReal)array[1]; Assert.AreEqual(Double.NaN, tempReal.AsReal()); Assert.AreEqual(LLSDType.Real, array[2].Type); tempReal = (LLSDReal)array[2]; Assert.AreEqual(4.0d, tempReal.AsReal()); Assert.AreEqual(LLSDType.Real, array[3].Type); tempReal = (LLSDReal)array[3]; Assert.AreEqual(-13.333d, tempReal.AsReal()); Assert.AreEqual(LLSDType.Real, array[4].Type); tempReal = (LLSDReal)array[4]; Assert.AreEqual(0d, tempReal.AsReal()); } /// /// Test that various String representations are parsed correctly. /// [Test] public void DeserializeStrings() { LLSD theLLSD = null; LLSDArray array = null; LLSDString tempStr = null; String testLLSD = @" Kissling Attack ships on fire off the shoulder of Orion < > & ' " "; //Deserialize the string byte[] bytes = Encoding.UTF8.GetBytes(testLLSD); theLLSD = LLSDParser.DeserializeXml(bytes); Assert.IsTrue(theLLSD is LLSDArray); array = (LLSDArray)theLLSD; Assert.AreEqual(LLSDType.String, array[0].Type); tempStr = (LLSDString)array[0]; Assert.AreEqual("Kissling", tempStr.AsString()); Assert.AreEqual(LLSDType.String, array[1].Type); tempStr = (LLSDString)array[1]; Assert.AreEqual("Attack ships on fire off the shoulder of Orion", tempStr.AsString()); Assert.AreEqual(LLSDType.String, array[2].Type); tempStr = (LLSDString)array[2]; Assert.AreEqual("< > & \' \"", tempStr.AsString()); Assert.AreEqual(LLSDType.String, array[3].Type); tempStr = (LLSDString)array[3]; Assert.AreEqual("", tempStr.AsString()); } /// /// Test that various Integer representations are parsed correctly. /// These tests currently only test for values within the range of a /// 32 bit signed integer, even though the LLSD specification says /// the type is a 64 bit signed integer, because LLSInteger is currently /// implemented using int, a.k.a. Int32. Not testing Int64 range until /// it's understood if there was a design reason for the Int32. /// [Test] public void DeserializeIntegers() { LLSD theLLSD = null; LLSDArray array = null; LLSDInteger tempInt = null; String testLLSD = @" 2147483647 -2147483648 0 013 "; //Deserialize the string byte[] bytes = Encoding.UTF8.GetBytes(testLLSD); theLLSD = LLSDParser.DeserializeXml(bytes); Assert.IsTrue(theLLSD is LLSDArray); array = (LLSDArray)theLLSD; Assert.AreEqual(LLSDType.Integer, array[0].Type); tempInt = (LLSDInteger)array[0]; Assert.AreEqual(2147483647, tempInt.AsInteger()); Assert.AreEqual(LLSDType.Integer, array[1].Type); tempInt = (LLSDInteger)array[1]; Assert.AreEqual(-2147483648, tempInt.AsInteger()); Assert.AreEqual(LLSDType.Integer, array[2].Type); tempInt = (LLSDInteger)array[2]; Assert.AreEqual(0, tempInt.AsInteger()); Assert.AreEqual(LLSDType.Integer, array[3].Type); tempInt = (LLSDInteger)array[3]; Assert.AreEqual(13, tempInt.AsInteger()); Assert.AreEqual(LLSDType.Integer, array[4].Type); tempInt = (LLSDInteger)array[4]; Assert.AreEqual(0, tempInt.AsInteger()); } /// /// Test that various UUID representations are parsed correctly. /// [Test] public void DeserializeUUID() { LLSD theLLSD = null; LLSDArray array = null; LLSDUUID tempUUID = null; String testLLSD = @" d7f4aeca-88f1-42a1-b385-b9db18abb255 "; //Deserialize the string byte[] bytes = Encoding.UTF8.GetBytes(testLLSD); theLLSD = LLSDParser.DeserializeXml(bytes); Assert.IsTrue(theLLSD is LLSDArray); array = (LLSDArray)theLLSD; Assert.AreEqual(LLSDType.UUID, array[0].Type); tempUUID = (LLSDUUID)array[0]; Assert.AreEqual(new LLUUID("d7f4aeca-88f1-42a1-b385-b9db18abb255"), tempUUID.AsUUID()); Assert.AreEqual(LLSDType.UUID, array[1].Type); tempUUID = (LLSDUUID)array[1]; Assert.AreEqual(LLUUID.Zero, tempUUID.AsUUID()); } /// /// Test that various date representations are parsed correctly. /// [Test] public void DeserializeDates() { LLSD theLLSD = null; LLSDArray array = null; LLSDDate tempDate = null; DateTime testDate; String testLLSD = @" 2006-02-01T14:29:53Z 1999-01-01T00:00:00Z "; //Deserialize the string byte[] bytes = Encoding.UTF8.GetBytes(testLLSD); theLLSD = LLSDParser.DeserializeXml(bytes); Assert.IsTrue(theLLSD is LLSDArray); array = (LLSDArray)theLLSD; Assert.AreEqual(LLSDType.Date, array[0].Type); tempDate = (LLSDDate)array[0]; DateTime.TryParse("2006-02-01T14:29:53Z", out testDate); Assert.AreEqual(testDate, tempDate.AsDate()); Assert.AreEqual(LLSDType.Date, array[1].Type); tempDate = (LLSDDate)array[1]; DateTime.TryParse("1999-01-01T00:00:00Z", out testDate); Assert.AreEqual(testDate, tempDate.AsDate()); Assert.AreEqual(LLSDType.Date, array[2].Type); tempDate = (LLSDDate)array[2]; Assert.AreEqual(Helpers.Epoch, tempDate.AsDate()); } /// /// Test that various Boolean representations are parsed correctly. /// [Test] public void DeserializeBoolean() { LLSD theLLSD = null; LLSDArray array = null; LLSDBoolean tempBool = null; String testLLSD = @" 1 true 0 false "; //Deserialize the string byte[] bytes = Encoding.UTF8.GetBytes(testLLSD); theLLSD = LLSDParser.DeserializeXml(bytes); Assert.IsTrue(theLLSD is LLSDArray); array = (LLSDArray)theLLSD; Assert.AreEqual(LLSDType.Boolean, array[0].Type); tempBool = (LLSDBoolean)array[0]; Assert.AreEqual(true, tempBool.AsBoolean()); Assert.AreEqual(LLSDType.Boolean, array[1].Type); tempBool = (LLSDBoolean)array[1]; Assert.AreEqual(true, tempBool.AsBoolean()); Assert.AreEqual(LLSDType.Boolean, array[2].Type); tempBool = (LLSDBoolean)array[2]; Assert.AreEqual(false, tempBool.AsBoolean()); Assert.AreEqual(LLSDType.Boolean, array[3].Type); tempBool = (LLSDBoolean)array[3]; Assert.AreEqual(false, tempBool.AsBoolean()); Assert.AreEqual(LLSDType.Boolean, array[4].Type); tempBool = (LLSDBoolean)array[4]; Assert.AreEqual(false, tempBool.AsBoolean()); } /// /// Test that binary elements are parsed correctly. /// [Test] public void DeserializeBinary() { LLSD theLLSD = null; LLSDArray array = null; LLSDBinary tempBinary = null; String testLLSD = @" cmFuZG9t dGhlIHF1aWNrIGJyb3duIGZveA== "; //Deserialize the string byte[] bytes = Encoding.UTF8.GetBytes(testLLSD); theLLSD = LLSDParser.DeserializeXml(bytes); Assert.IsTrue(theLLSD is LLSDArray); array = (LLSDArray)theLLSD; Assert.AreEqual(LLSDType.Binary, array[0].Type); tempBinary = (LLSDBinary)array[0]; byte[] testData1 = {114, 97, 110, 100, 111, 109}; TestBinary(tempBinary, testData1); Assert.AreEqual(LLSDType.Binary, array[1].Type); tempBinary = (LLSDBinary)array[1]; byte[] testData2 = {116, 104, 101, 32, 113, 117, 105, 99, 107, 32, 98, 114, 111, 119, 110, 32, 102, 111, 120}; TestBinary(tempBinary, testData2); Assert.AreEqual(LLSDType.Binary, array[1].Type); tempBinary = (LLSDBinary)array[2]; Assert.AreEqual(0, tempBinary.AsBinary().Length); } /// /// Asserts that the contents of the LLSDBinary match the values and length /// of the supplied byte array /// /// /// private void TestBinary(LLSDBinary inBinary, byte[] inExpected) { byte[] binary = inBinary.AsBinary(); Assert.AreEqual(inExpected.Length, binary.Length); for (int i = 0; i < inExpected.Length; i++) { if (inExpected[i] != binary[i]) { Assert.Fail("Expected " + inExpected[i].ToString() + " at position " + i.ToString() + " but saw " + binary[i].ToString()); } } } /// /// Test that undefened elements are parsed correctly. /// Currently this just checks that there is no error since undefined has no /// value and there is no LLSD child class for Undefined elements - the /// current implementation generates an instance of LLSD /// [Test] public void DeserializeUndef() { LLSD theLLSD = null; String testLLSD = @" "; //Deserialize the string byte[] bytes = Encoding.UTF8.GetBytes(testLLSD); theLLSD = LLSDParser.DeserializeXml(bytes); Assert.IsTrue(theLLSD is LLSD); } /// /// Test that various URI representations are parsed correctly. /// [Test] public void DeserializeURI() { LLSD theLLSD = null; LLSDArray array = null; LLSDURI tempURI = null; String testLLSD = @" http://sim956.agni.lindenlab.com:12035/runtime/agents "; //Deserialize the string byte[] bytes = Encoding.UTF8.GetBytes(testLLSD); theLLSD = LLSDParser.DeserializeXml(bytes); Assert.IsTrue(theLLSD is LLSDArray); array = (LLSDArray)theLLSD; Assert.AreEqual(LLSDType.URI, array[0].Type); tempURI = (LLSDURI)array[0]; Uri testURI = new Uri(@"http://sim956.agni.lindenlab.com:12035/runtime/agents"); Assert.AreEqual(testURI, tempURI.AsUri()); Assert.AreEqual(LLSDType.URI, array[1].Type); tempURI = (LLSDURI)array[1]; Assert.AreEqual("", tempURI.AsUri().ToString()); } /// /// Test some nested containers. This is not a very deep or complicated LLSD graph /// but it should reveal basic nesting issues. /// [Test] public void DeserializeNestedContainers() { LLSD theLLSD = null; LLSDArray array = null; LLSDMap map = null; LLSD tempLLSD = null; String testLLSD = @" Map One Array One 1 2 A B 1 4 9 "; //Deserialize the string byte[] bytes = Encoding.UTF8.GetBytes(testLLSD); theLLSD = LLSDParser.DeserializeXml(bytes); Assert.IsTrue(theLLSD is LLSDArray); array = (LLSDArray)theLLSD; Assert.AreEqual(2, array.Count); //The first element of top level array, a map Assert.AreEqual(LLSDType.Map, array[0].Type); map = (LLSDMap)array[0]; //First nested map tempLLSD = map["Map One"]; Assert.IsNotNull(tempLLSD); Assert.AreEqual(LLSDType.Map, tempLLSD.Type); map = (LLSDMap)tempLLSD; //First nested array tempLLSD = map["Array One"]; Assert.IsNotNull(tempLLSD); Assert.AreEqual(LLSDType.Array, tempLLSD.Type); array = (LLSDArray)tempLLSD; Assert.AreEqual(2, array.Count); array = (LLSDArray)theLLSD; //Second element of top level array, an array tempLLSD = array[1]; Assert.AreEqual(LLSDType.Array, tempLLSD.Type); array = (LLSDArray)tempLLSD; Assert.AreEqual(3, array.Count); //Nested array tempLLSD = array[2]; Assert.AreEqual(LLSDType.Array, tempLLSD.Type); array = (LLSDArray)tempLLSD; Assert.AreEqual(3, array.Count); } } }