185 lines
7.5 KiB
C#
185 lines
7.5 KiB
C#
/*
|
|
* 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 OpenSimulator 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;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq.Expressions;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using NUnit.Framework;
|
|
using NUnit.Framework.SyntaxHelpers;
|
|
using OpenMetaverse;
|
|
using OpenSim.Framework;
|
|
|
|
namespace OpenSim.Data.Tests
|
|
{
|
|
|
|
//This is generic so that the lambda expressions will work right in IDEs.
|
|
public class PropertyScrambler<T>
|
|
{
|
|
readonly System.Collections.Generic.List<string> membersToNotScramble = new List<string>();
|
|
|
|
private void AddExpressionToNotScrableList(Expression expression)
|
|
{
|
|
UnaryExpression unaryExpression = expression as UnaryExpression;
|
|
if (unaryExpression != null)
|
|
{
|
|
AddExpressionToNotScrableList(unaryExpression.Operand);
|
|
return;
|
|
}
|
|
|
|
MemberExpression memberExpression = expression as MemberExpression;
|
|
if (memberExpression != null)
|
|
{
|
|
if (!(memberExpression.Member is PropertyInfo))
|
|
{
|
|
throw new NotImplementedException("I don't know how deal with a MemberExpression that is a " + expression.Type);
|
|
}
|
|
membersToNotScramble.Add(memberExpression.Member.Name);
|
|
return;
|
|
}
|
|
|
|
throw new NotImplementedException("I don't know how to parse a " + expression.Type);
|
|
}
|
|
|
|
public PropertyScrambler<T> DontScramble(Expression<Func<T, object>> expression)
|
|
{
|
|
AddExpressionToNotScrableList(expression.Body);
|
|
return this;
|
|
}
|
|
|
|
public void Scramble(T obj)
|
|
{
|
|
internalScramble(obj);
|
|
}
|
|
|
|
private void internalScramble(object obj)
|
|
{
|
|
PropertyInfo[] properties = obj.GetType().GetProperties();
|
|
foreach (var property in properties)
|
|
{
|
|
//Skip indexers of classes. We will assume that everything that has an indexer
|
|
// is also IEnumberable. May not always be true, but should be true normally.
|
|
if (property.GetIndexParameters().Length > 0)
|
|
continue;
|
|
|
|
RandomizeProperty(obj, property, null);
|
|
}
|
|
//Now if it implments IEnumberable, it's probably some kind of list, so we should randomize
|
|
// everything inside of it.
|
|
IEnumerable enumerable = obj as IEnumerable;
|
|
if (enumerable != null)
|
|
{
|
|
foreach (object value in enumerable)
|
|
{
|
|
internalScramble(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
private readonly Random random = new Random();
|
|
private void RandomizeProperty(object obj, PropertyInfo property, object[] index)
|
|
{//I'd like a better way to compare, but I had lots of problems with InventoryFolderBase because the ID is inherited.
|
|
if (membersToNotScramble.Contains(property.Name))
|
|
return;
|
|
Type t = property.PropertyType;
|
|
if (!property.CanWrite)
|
|
return;
|
|
object value = property.GetValue(obj, index);
|
|
if (value == null)
|
|
return;
|
|
|
|
if (t == typeof(string))
|
|
property.SetValue(obj, RandomName(), index);
|
|
else if (t == typeof(UUID))
|
|
property.SetValue(obj, UUID.Random(), index);
|
|
else if (t == typeof(sbyte))
|
|
property.SetValue(obj, (sbyte)random.Next(sbyte.MinValue, sbyte.MaxValue), index);
|
|
else if (t == typeof(short))
|
|
property.SetValue(obj, (short)random.Next(short.MinValue, short.MaxValue), index);
|
|
else if (t == typeof(int))
|
|
property.SetValue(obj, random.Next(), index);
|
|
else if (t == typeof(long))
|
|
property.SetValue(obj, random.Next() * int.MaxValue, index);
|
|
else if (t == typeof(byte))
|
|
property.SetValue(obj, (byte)random.Next(byte.MinValue, byte.MaxValue), index);
|
|
else if (t == typeof(ushort))
|
|
property.SetValue(obj, (ushort)random.Next(ushort.MinValue, ushort.MaxValue), index);
|
|
else if (t == typeof(uint))
|
|
property.SetValue(obj, Convert.ToUInt32(random.Next()), index);
|
|
else if (t == typeof(ulong))
|
|
property.SetValue(obj, Convert.ToUInt64(random.Next()) * Convert.ToUInt64(UInt32.MaxValue), index);
|
|
else if (t == typeof(bool))
|
|
property.SetValue(obj, true, index);
|
|
else if (t == typeof(byte[]))
|
|
{
|
|
byte[] bytes = new byte[30];
|
|
random.NextBytes(bytes);
|
|
property.SetValue(obj, bytes, index);
|
|
}
|
|
else
|
|
internalScramble(value);
|
|
}
|
|
|
|
private string RandomName()
|
|
{
|
|
StringBuilder name = new StringBuilder();
|
|
int size = random.Next(5, 12);
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
char ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
|
|
name.Append(ch);
|
|
}
|
|
return name.ToString();
|
|
}
|
|
}
|
|
|
|
[TestFixture]
|
|
public class PropertyScramblerTests
|
|
{
|
|
[Test]
|
|
public void TestScramble()
|
|
{
|
|
AssetBase actual = new AssetBase(UUID.Random(), "asset one", (sbyte)AssetType.Texture);
|
|
new PropertyScrambler<AssetBase>().Scramble(actual);
|
|
}
|
|
|
|
[Test]
|
|
public void DontScramble()
|
|
{
|
|
UUID uuid = UUID.Random();
|
|
AssetBase asset = new AssetBase(uuid, "asset", (sbyte)AssetType.Texture);
|
|
new PropertyScrambler<AssetBase>()
|
|
.DontScramble(x => x.Metadata)
|
|
.DontScramble(x => x.FullID)
|
|
.DontScramble(x => x.ID)
|
|
.Scramble(asset);
|
|
Assert.That(asset.FullID, Is.EqualTo(uuid));
|
|
}
|
|
}
|
|
} |