PropertyScrambler.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections;
  29. using System.Collections.Generic;
  30. using System.Linq.Expressions;
  31. using System.Reflection;
  32. using System.Text;
  33. using NUnit.Framework;
  34. using OpenMetaverse;
  35. using OpenSim.Framework;
  36. namespace OpenSim.Data.Tests
  37. {
  38. //This is generic so that the lambda expressions will work right in IDEs.
  39. public class PropertyScrambler<T>
  40. {
  41. readonly System.Collections.Generic.List<string> membersToNotScramble = new List<string>();
  42. private void AddExpressionToNotScrableList(Expression expression)
  43. {
  44. UnaryExpression unaryExpression = expression as UnaryExpression;
  45. if (unaryExpression != null)
  46. {
  47. AddExpressionToNotScrableList(unaryExpression.Operand);
  48. return;
  49. }
  50. MemberExpression memberExpression = expression as MemberExpression;
  51. if (memberExpression != null)
  52. {
  53. if (!(memberExpression.Member is PropertyInfo))
  54. {
  55. throw new NotImplementedException("I don't know how deal with a MemberExpression that is a " + expression.Type);
  56. }
  57. membersToNotScramble.Add(memberExpression.Member.Name);
  58. return;
  59. }
  60. throw new NotImplementedException("I don't know how to parse a " + expression.Type);
  61. }
  62. public PropertyScrambler<T> DontScramble(Expression<Func<T, object>> expression)
  63. {
  64. AddExpressionToNotScrableList(expression.Body);
  65. return this;
  66. }
  67. public void Scramble(T obj)
  68. {
  69. internalScramble(obj);
  70. }
  71. private void internalScramble(object obj)
  72. {
  73. PropertyInfo[] properties = obj.GetType().GetProperties();
  74. foreach (var property in properties)
  75. {
  76. //Skip indexers of classes. We will assume that everything that has an indexer
  77. // is also IEnumberable. May not always be true, but should be true normally.
  78. if (property.GetIndexParameters().Length > 0)
  79. continue;
  80. RandomizeProperty(obj, property, null);
  81. }
  82. //Now if it implments IEnumberable, it's probably some kind of list, so we should randomize
  83. // everything inside of it.
  84. IEnumerable enumerable = obj as IEnumerable;
  85. if (enumerable != null)
  86. {
  87. foreach (object value in enumerable)
  88. {
  89. internalScramble(value);
  90. }
  91. }
  92. }
  93. private readonly Random random = new Random();
  94. private void RandomizeProperty(object obj, PropertyInfo property, object[] index)
  95. {//I'd like a better way to compare, but I had lots of problems with InventoryFolderBase because the ID is inherited.
  96. if (membersToNotScramble.Contains(property.Name))
  97. return;
  98. Type t = property.PropertyType;
  99. if (!property.CanWrite)
  100. return;
  101. object value = property.GetValue(obj, index);
  102. if (value == null)
  103. return;
  104. if (t == typeof(string))
  105. property.SetValue(obj, RandomName(), index);
  106. else if (t == typeof(UUID))
  107. property.SetValue(obj, UUID.Random(), index);
  108. else if (t == typeof(sbyte))
  109. property.SetValue(obj, (sbyte)random.Next(sbyte.MinValue, sbyte.MaxValue), index);
  110. else if (t == typeof(short))
  111. property.SetValue(obj, (short)random.Next(short.MinValue, short.MaxValue), index);
  112. else if (t == typeof(int))
  113. property.SetValue(obj, random.Next(), index);
  114. else if (t == typeof(long))
  115. property.SetValue(obj, random.Next() * int.MaxValue, index);
  116. else if (t == typeof(byte))
  117. property.SetValue(obj, (byte)random.Next(byte.MinValue, byte.MaxValue), index);
  118. else if (t == typeof(ushort))
  119. property.SetValue(obj, (ushort)random.Next(ushort.MinValue, ushort.MaxValue), index);
  120. else if (t == typeof(uint))
  121. property.SetValue(obj, Convert.ToUInt32(random.Next()), index);
  122. else if (t == typeof(ulong))
  123. property.SetValue(obj, Convert.ToUInt64(random.Next()) * Convert.ToUInt64(UInt32.MaxValue), index);
  124. else if (t == typeof(bool))
  125. property.SetValue(obj, true, index);
  126. else if (t == typeof(byte[]))
  127. {
  128. byte[] bytes = new byte[30];
  129. random.NextBytes(bytes);
  130. property.SetValue(obj, bytes, index);
  131. }
  132. else
  133. internalScramble(value);
  134. }
  135. private string RandomName()
  136. {
  137. StringBuilder name = new StringBuilder();
  138. int size = random.Next(5, 12);
  139. for (int i = 0; i < size; i++)
  140. {
  141. char ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
  142. name.Append(ch);
  143. }
  144. return name.ToString();
  145. }
  146. }
  147. [TestFixture]
  148. public class PropertyScramblerTests
  149. {
  150. [Test]
  151. public void TestScramble()
  152. {
  153. AssetBase actual = new AssetBase(UUID.Random(), "asset one", (sbyte)AssetType.Texture, UUID.Zero.ToString());
  154. new PropertyScrambler<AssetBase>().Scramble(actual);
  155. }
  156. [Test]
  157. public void DontScramble()
  158. {
  159. UUID uuid = UUID.Random();
  160. AssetBase asset = new AssetBase(uuid, "asset", (sbyte)AssetType.Texture, UUID.Zero.ToString());
  161. new PropertyScrambler<AssetBase>()
  162. .DontScramble(x => x.Metadata)
  163. .DontScramble(x => x.FullID)
  164. .DontScramble(x => x.ID)
  165. .Scramble(asset);
  166. Assert.That(asset.FullID, Is.EqualTo(uuid));
  167. }
  168. }
  169. }