PropertyScrambler.cs 5.9 KB

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