PropertyScrambler.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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 NUnit.Framework.SyntaxHelpers;
  35. using OpenMetaverse;
  36. using OpenSim.Framework;
  37. namespace OpenSim.Data.Tests
  38. {
  39. //This is generic so that the lambda expressions will work right in IDEs.
  40. public class PropertyScrambler<T>
  41. {
  42. readonly System.Collections.Generic.List<string> membersToNotScramble = new List<string>();
  43. private void AddExpressionToNotScrableList(Expression expression)
  44. {
  45. UnaryExpression unaryExpression = expression as UnaryExpression;
  46. if (unaryExpression != null)
  47. {
  48. AddExpressionToNotScrableList(unaryExpression.Operand);
  49. return;
  50. }
  51. MemberExpression memberExpression = expression as MemberExpression;
  52. if (memberExpression != null)
  53. {
  54. if (!(memberExpression.Member is PropertyInfo))
  55. {
  56. throw new NotImplementedException("I don't know how deal with a MemberExpression that is a " + expression.Type);
  57. }
  58. membersToNotScramble.Add(memberExpression.Member.Name);
  59. return;
  60. }
  61. throw new NotImplementedException("I don't know how to parse a " + expression.Type);
  62. }
  63. public PropertyScrambler<T> DontScramble(Expression<Func<T, object>> expression)
  64. {
  65. AddExpressionToNotScrableList(expression.Body);
  66. return this;
  67. }
  68. public void Scramble(T obj)
  69. {
  70. internalScramble(obj);
  71. }
  72. private void internalScramble(object obj)
  73. {
  74. PropertyInfo[] properties = obj.GetType().GetProperties();
  75. foreach (var property in properties)
  76. {
  77. //Skip indexers of classes. We will assume that everything that has an indexer
  78. // is also IEnumberable. May not always be true, but should be true normally.
  79. if (property.GetIndexParameters().Length > 0)
  80. continue;
  81. RandomizeProperty(obj, property, null);
  82. }
  83. //Now if it implments IEnumberable, it's probably some kind of list, so we should randomize
  84. // everything inside of it.
  85. IEnumerable enumerable = obj as IEnumerable;
  86. if (enumerable != null)
  87. {
  88. foreach (object value in enumerable)
  89. {
  90. internalScramble(value);
  91. }
  92. }
  93. }
  94. private readonly Random random = new Random();
  95. private void RandomizeProperty(object obj, PropertyInfo property, object[] index)
  96. {//I'd like a better way to compare, but I had lots of problems with InventoryFolderBase because the ID is inherited.
  97. if (membersToNotScramble.Contains(property.Name))
  98. return;
  99. Type t = property.PropertyType;
  100. if (!property.CanWrite)
  101. return;
  102. object value = property.GetValue(obj, index);
  103. if (value == null)
  104. return;
  105. if (t == typeof(string))
  106. property.SetValue(obj, RandomName(), index);
  107. else if (t == typeof(UUID))
  108. property.SetValue(obj, UUID.Random(), index);
  109. else if (t == typeof(sbyte))
  110. property.SetValue(obj, (sbyte)random.Next(sbyte.MinValue, sbyte.MaxValue), index);
  111. else if (t == typeof(short))
  112. property.SetValue(obj, (short)random.Next(short.MinValue, short.MaxValue), index);
  113. else if (t == typeof(int))
  114. property.SetValue(obj, random.Next(), index);
  115. else if (t == typeof(long))
  116. property.SetValue(obj, random.Next() * int.MaxValue, index);
  117. else if (t == typeof(byte))
  118. property.SetValue(obj, (byte)random.Next(byte.MinValue, byte.MaxValue), index);
  119. else if (t == typeof(ushort))
  120. property.SetValue(obj, (ushort)random.Next(ushort.MinValue, ushort.MaxValue), index);
  121. else if (t == typeof(uint))
  122. property.SetValue(obj, Convert.ToUInt32(random.Next()), index);
  123. else if (t == typeof(ulong))
  124. property.SetValue(obj, Convert.ToUInt64(random.Next()) * Convert.ToUInt64(UInt32.MaxValue), index);
  125. else if (t == typeof(bool))
  126. property.SetValue(obj, true, index);
  127. else if (t == typeof(byte[]))
  128. {
  129. byte[] bytes = new byte[30];
  130. random.NextBytes(bytes);
  131. property.SetValue(obj, bytes, index);
  132. }
  133. else
  134. internalScramble(value);
  135. }
  136. private string RandomName()
  137. {
  138. StringBuilder name = new StringBuilder();
  139. int size = random.Next(5, 12);
  140. for (int i = 0; i < size; i++)
  141. {
  142. char ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
  143. name.Append(ch);
  144. }
  145. return name.ToString();
  146. }
  147. }
  148. [TestFixture]
  149. public class PropertyScramblerTests
  150. {
  151. [Test]
  152. public void TestScramble()
  153. {
  154. AssetBase actual = new AssetBase(UUID.Random(), "asset one", (sbyte)AssetType.Texture, UUID.Zero.ToString());
  155. new PropertyScrambler<AssetBase>().Scramble(actual);
  156. }
  157. [Test]
  158. public void DontScramble()
  159. {
  160. UUID uuid = UUID.Random();
  161. AssetBase asset = new AssetBase(uuid, "asset", (sbyte)AssetType.Texture, UUID.Zero.ToString());
  162. new PropertyScrambler<AssetBase>()
  163. .DontScramble(x => x.Metadata)
  164. .DontScramble(x => x.FullID)
  165. .DontScramble(x => x.ID)
  166. .Scramble(asset);
  167. Assert.That(asset.FullID, Is.EqualTo(uuid));
  168. }
  169. }
  170. }