/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* 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.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project 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 DEVELOPERS ``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 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.
*/
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using log4net.Config;
using NUnit.Framework;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.Framework.Scenes.Serialization;
using OpenSim.Tests.Common;
using OpenMetaverse.StructuredData;
namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
{
[TestFixture]
public class SerialiserTests : OpenSimTestCase
{
private const string ObjectRootPartStubXml =
@"
false
a6dacf01-4636-4bb9-8a97-30609438af9d
e6a5a05e-e8cc-4816-8701-04165e335790
1
0
e6a5a05e-e8cc-4816-8701-04165e335790
2698615125
PrimMyRide
0
false
1099511628032000
0
147.2392.69822.78084
000
-4.371139E-08-1-4.371139E-080
000
000
000
000
0
0
1
AAAAAAAAERGZmQAAAAAABQCVlZUAAAAAQEAAAABAQAAAAAAAAAAAAAAAAAAAAA==
AA==
0
16
0
0
0
100
100
0
0
0
0
0
0
0
9
0
0
0
10100.5
0
Square
Same
00000000-0000-0000-0000-000000000000
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
1
false
false
false
10100.5
0
0001
000
000
0001
0
1211330445
0
0
0
0
00000000-0000-0000-0000-000000000000
a6dacf01-4636-4bb9-8a97-30609438af9d
a6dacf01-4636-4bb9-8a97-30609438af9d
2147483647
2147483647
0
0
2147483647
None
00000000-0000-0000-0000-000000000000
0
";
private const string ObjectWithNoOtherPartsXml = ObjectRootPartStubXml +
@"
";
private const string ObjectWithOtherPartsXml = ObjectRootPartStubXml +
@"
false
a6dacf01-4636-4bb9-8a97-30609438af9d
9958feb1-02a6-49e4-a4ce-eba6f578ee13
3
9958feb1-02a6-49e4-a4ce-eba6f578ee13
1154704500
Alien Head 1
3
false
false
21990232560640000
0
125.5655127.34622.48036
-0.21719360.10839840.0009994507
-0.51221060.4851225-0.49574540.5064908
000
000
000
(No Description)
000255
253
0
5
Vw3dpvgTRUOiIUOGsnpWlAB/f38AAAAAgL8AAACAPwAAAAAAAAAF4ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AA==
0
32
0
0
0
100
100
0
0
0
0
0
0
0
9
0
0
0
9
0
HalfCircle
Same
00000000-0000-0000-0000-000000000000
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
1
false
false
false
0.11481950.01438910.02768878
0001
000
000
0001
1154704499
1256611042
0
10
0
0
00000000-0000-0000-0000-000000000000
7b2022f0-5f19-488c-b7e5-829d8f96b448
7b2022f0-5f19-488c-b7e5-829d8f96b448
647168
647168
0
0
581632
None
00000000-0000-0000-0000-000000000000
0
000
-2
-2
-2
-2
-2
false
a6dacf01-4636-4bb9-8a97-30609438af9d
674b6b86-f5aa-439a-8e00-0d75bc08c80a
3
674b6b86-f5aa-439a-8e00-0d75bc08c80a
1154704501
Alien Head 2
3
false
false
21990232560640000
0
125.5655127.34622.48036
-0.24909970.085201260.0009002686
-0.47653680.5194498-0.53013720.4712104
000
000
000
(No Description)
000255
252
0
0
Vw3dpvgTRUOiIUOGsnpWlAB/f38AAAAAgL8AAACAPwAAAAAAAAAF4ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AA==
0
32
0
0
0
100
150
0
0
0
0
0
0
0
9
0
0
0
9
0
Circle
Same
00000000-0000-0000-0000-000000000000
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
1
false
false
false
0.035743850.059580320.04764182
0001
000
000
0001
1154704499
1256611042
0
10
0
0
00000000-0000-0000-0000-000000000000
7b2022f0-5f19-488c-b7e5-829d8f96b448
7b2022f0-5f19-488c-b7e5-829d8f96b448
647168
647168
0
0
581632
None
00000000-0000-0000-0000-000000000000
0
000
-2
-2
-2
-2
-2
";
private const string ObjectWithBadFloatsXml = @"
false
a6dacf01-4636-4bb9-8a97-30609438af9d
e6a5a05e-e8cc-4816-8701-04165e335790
1
0
e6a5a05e-e8cc-4816-8701-04165e335790
2698615125
NaughtyPrim
0
false
1099511628032000
0
147.2392.69822.78084
000
-4.371139E-08-1-4.371139E-080
000
000
000
000
0
0
1
AAAAAAAAERGZmQAAAAAABQCVlZUAAAAAQEAAAABAQAAAAAAAAAAAAAAAAAAAAA==
AA==
0
16
0
0
0
100
100
0
0
0
0
0
0
0
9
0
0
0
10100.5
0
Square
Same
00000000-0000-0000-0000-000000000000
0
0
0,5
yo mamma
0
0
0
0
0
0
0
0
1
0
0
0
1
false
false
false
10100.5
0
0001
000
000
0001
0
1211330445
0
0
0
0
00000000-0000-0000-0000-000000000000
a6dacf01-4636-4bb9-8a97-30609438af9d
a6dacf01-4636-4bb9-8a97-30609438af9d
2147483647
2147483647
0
0
2147483647
None
00000000-0000-0000-0000-000000000000
0
";
private const string ObjectWithNoPartsXml2 = @"
b46ef588-411e-4a8b-a284-d7dcfe8e74ef
9be68fdd-f740-4a0f-9675-dfbbb536b946
0
0
9be68fdd-f740-4a0f-9675-dfbbb536b946
720005
PrimFun
0
1099511628032000
0
153.9854121.490862.21781
000
0001
000
000
000
000
0
0
0
16
0
0
0
200
200
0
0
0
0
0
0
0
9
0
0
0
1.2831315.9038584.266288
0
Circle
Same
0
iVVnRyTLQ+2SC0fK7RVGXwJ6yc/SU4RDA5nhJbLUw3R1AAAAAAAAaOw8QQOhPSRAAKE9JEAAAAAAAAAAAAAAAAAAAAA=
AA==
1.2831315.9038584.266288
0
0001
000
000
0010
0
1216066902
0
0
0
0
00000000-0000-0000-0000-000000000000
b46ef588-411e-4a8b-a284-d7dcfe8e74ef
b46ef588-411e-4a8b-a284-d7dcfe8e74ef
2147483647
2147483647
0
0
2147483647
None
MyNamespace
MyStore
last words
Rosebud
00000000-0000-0000-0000-000000000000
";
protected Scene m_scene;
protected SerialiserModule m_serialiserModule;
[TestFixtureSetUp]
public void Init()
{
m_serialiserModule = new SerialiserModule();
m_scene = new SceneHelpers().SetupScene();
SceneHelpers.SetupSceneModules(m_scene, m_serialiserModule);
}
[Test]
public void TestDeserializeXmlObjectWithNoOtherParts()
{
TestHelpers.InMethod();
TestHelpers.EnableLogging();
SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(ObjectWithNoOtherPartsXml);
SceneObjectPart rootPart = so.RootPart;
Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790")));
Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d")));
Assert.That(rootPart.Name, Is.EqualTo("PrimMyRide"));
OSDMap store = rootPart.DynAttrs.GetStore("MyNamespace", "MyStore");
Assert.AreEqual(42, store["the answer"].AsInteger());
// TODO: Check other properties
}
[Test]
public void TestDeserializeXmlObjectWithOtherParts()
{
TestHelpers.InMethod();
TestHelpers.EnableLogging();
// We need to do this to get rid of whitespace between elements.
// TODO: Ultimately OpenSimulator xml parser should be set to ignore this but this means a bit of
// rejigging to replace old new XmlTextReader() with the post .NET 2.0 XmlReader.Create() calls
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(ObjectWithOtherPartsXml);
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
using (XmlTextWriter xtw = new XmlTextWriter(sw))
{
// xtw.Formatting = Formatting.Indented;
xdoc.WriteTo(xtw);
}
}
SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(sb.ToString());
SceneObjectPart[] parts = so.Parts;
Assert.AreEqual(3, so.Parts.Length);
{
SceneObjectPart part = parts[0];
Assert.That(part.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790")));
Assert.That(part.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d")));
Assert.That(part.Name, Is.EqualTo("PrimMyRide"));
OSDMap store = part.DynAttrs.GetStore("MyNamespace", "MyStore");
Assert.AreEqual(42, store["the answer"].AsInteger());
}
{
SceneObjectPart part = parts[1];
Assert.That(part.UUID, Is.EqualTo(new UUID("9958feb1-02a6-49e4-a4ce-eba6f578ee13")));
Assert.That(part.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d")));
Assert.That(part.Name, Is.EqualTo("Alien Head 1"));
}
{
SceneObjectPart part = parts[2];
Assert.That(part.UUID, Is.EqualTo(new UUID("674b6b86-f5aa-439a-8e00-0d75bc08c80a")));
Assert.That(part.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d")));
Assert.That(part.Name, Is.EqualTo("Alien Head 2"));
}
// TODO: Check other properties
}
[Test]
public void TestDeserializeBadFloatsXml()
{
TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure();
SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(ObjectWithBadFloatsXml);
SceneObjectPart rootPart = so.RootPart;
Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790")));
Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d")));
Assert.That(rootPart.Name, Is.EqualTo("NaughtyPrim"));
// This terminates the deserialization earlier if couldn't be parsed.
// TODO: Need to address this
Assert.That(rootPart.GroupPosition.X, Is.EqualTo(147.23f));
Assert.That(rootPart.Shape.PathCurve, Is.EqualTo(16));
// Defaults for bad parses
Assert.That(rootPart.Shape.FlexiTension, Is.EqualTo(0));
Assert.That(rootPart.Shape.FlexiDrag, Is.EqualTo(0));
// TODO: Check other properties
}
[Test]
public void TestSerializeXml()
{
TestHelpers.InMethod();
//log4net.Config.XmlConfigurator.Configure();
string rpName = "My Little Donkey";
UUID rpUuid = UUID.Parse("00000000-0000-0000-0000-000000000964");
UUID rpCreatorId = UUID.Parse("00000000-0000-0000-0000-000000000915");
PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere();
// Vector3 groupPosition = new Vector3(10, 20, 30);
// Quaternion rotationOffset = new Quaternion(20, 30, 40, 50);
// Vector3 offsetPosition = new Vector3(5, 10, 15);
SceneObjectPart rp = new SceneObjectPart();
rp.UUID = rpUuid;
rp.Name = rpName;
rp.CreatorID = rpCreatorId;
rp.Shape = shape;
string daNamespace = "MyNamespace";
string daStoreName = "MyStore";
string daKey = "foo";
string daValue = "bar";
OSDMap myStore = new OSDMap();
myStore.Add(daKey, daValue);
rp.DynAttrs = new DAMap();
rp.DynAttrs.SetStore(daNamespace, daStoreName, myStore);
SceneObjectGroup so = new SceneObjectGroup(rp);
// Need to add the object to the scene so that the request to get script state succeeds
m_scene.AddSceneObject(so);
string xml = SceneObjectSerializer.ToOriginalXmlFormat(so);
XmlTextReader xtr = new XmlTextReader(new StringReader(xml));
xtr.ReadStartElement("SceneObjectGroup");
xtr.ReadStartElement("RootPart");
xtr.ReadStartElement("SceneObjectPart");
UUID uuid = UUID.Zero;
string name = null;
UUID creatorId = UUID.Zero;
DAMap daMap = null;
while (xtr.Read() && xtr.Name != "SceneObjectPart")
{
if (xtr.NodeType != XmlNodeType.Element)
continue;
switch (xtr.Name)
{
case "UUID":
xtr.ReadStartElement("UUID");
try
{
uuid = UUID.Parse(xtr.ReadElementString("UUID"));
xtr.ReadEndElement();
}
catch { } // ignore everything but ...
break;
case "Name":
name = xtr.ReadElementContentAsString();
break;
case "CreatorID":
xtr.ReadStartElement("CreatorID");
creatorId = UUID.Parse(xtr.ReadElementString("UUID"));
xtr.ReadEndElement();
break;
case "DynAttrs":
daMap = new DAMap();
daMap.ReadXml(xtr);
break;
}
}
xtr.ReadEndElement();
xtr.ReadEndElement();
xtr.ReadStartElement("OtherParts");
xtr.ReadEndElement();
xtr.Close();
// TODO: More checks
Assert.That(uuid, Is.EqualTo(rpUuid));
Assert.That(name, Is.EqualTo(rpName));
Assert.That(creatorId, Is.EqualTo(rpCreatorId));
Assert.NotNull(daMap);
Assert.AreEqual(daValue, daMap.GetStore(daNamespace, daStoreName)[daKey].AsString());
}
[Test]
public void TestDeserializeXml2()
{
TestHelpers.InMethod();
//log4net.Config.XmlConfigurator.Configure();
SceneObjectGroup so = m_serialiserModule.DeserializeGroupFromXml2(ObjectWithNoPartsXml2);
SceneObjectPart rootPart = so.RootPart;
Assert.That(rootPart.UUID, Is.EqualTo(new UUID("9be68fdd-f740-4a0f-9675-dfbbb536b946")));
Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("b46ef588-411e-4a8b-a284-d7dcfe8e74ef")));
Assert.That(rootPart.Name, Is.EqualTo("PrimFun"));
OSDMap store = rootPart.DynAttrs.GetStore("MyNamespace", "MyStore");
Assert.AreEqual("Rosebud", store["last words"].AsString());
// TODO: Check other properties
}
[Test]
public void TestSerializeXml2()
{
TestHelpers.InMethod();
//log4net.Config.XmlConfigurator.Configure();
string rpName = "My Little Pony";
UUID rpUuid = UUID.Parse("00000000-0000-0000-0000-000000000064");
UUID rpCreatorId = UUID.Parse("00000000-0000-0000-0000-000000000015");
PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere();
// Vector3 groupPosition = new Vector3(10, 20, 30);
// Quaternion rotationOffset = new Quaternion(20, 30, 40, 50);
// Vector3 offsetPosition = new Vector3(5, 10, 15);
SceneObjectPart rp = new SceneObjectPart();
rp.UUID = rpUuid;
rp.Name = rpName;
rp.CreatorID = rpCreatorId;
rp.Shape = shape;
string daNamespace = "MyNamespace";
string daStoreName = "MyStore";
string daKey = "foo";
string daValue = "bar";
OSDMap myStore = new OSDMap();
myStore.Add(daKey, daValue);
rp.DynAttrs = new DAMap();
rp.DynAttrs.SetStore(daNamespace, daStoreName, myStore);
SceneObjectGroup so = new SceneObjectGroup(rp);
// Need to add the object to the scene so that the request to get script state succeeds
m_scene.AddSceneObject(so);
Dictionary options = new Dictionary();
options["old-guids"] = true;
string xml2 = m_serialiserModule.SerializeGroupToXml2(so, options);
XmlTextReader xtr = new XmlTextReader(new StringReader(xml2));
xtr.ReadStartElement("SceneObjectGroup");
xtr.ReadStartElement("SceneObjectPart");
UUID uuid = UUID.Zero;
string name = null;
UUID creatorId = UUID.Zero;
DAMap daMap = null;
while (xtr.Read() && xtr.Name != "SceneObjectPart")
{
if (xtr.NodeType != XmlNodeType.Element)
continue;
switch (xtr.Name)
{
case "UUID":
xtr.ReadStartElement("UUID");
uuid = UUID.Parse(xtr.ReadElementString("Guid"));
xtr.ReadEndElement();
break;
case "Name":
name = xtr.ReadElementContentAsString();
break;
case "CreatorID":
xtr.ReadStartElement("CreatorID");
creatorId = UUID.Parse(xtr.ReadElementString("Guid"));
xtr.ReadEndElement();
break;
case "DynAttrs":
daMap = new DAMap();
daMap.ReadXml(xtr);
break;
}
}
xtr.ReadEndElement();
xtr.ReadStartElement("OtherParts");
xtr.ReadEndElement();
xtr.Close();
// TODO: More checks
Assert.That(uuid, Is.EqualTo(rpUuid));
Assert.That(name, Is.EqualTo(rpName));
Assert.That(creatorId, Is.EqualTo(rpCreatorId));
Assert.NotNull(daMap);
Assert.AreEqual(daValue, daMap.GetStore(daNamespace, daStoreName)[daKey].AsString());
}
}
}