opensim-development – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 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  
28 using System;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Drawing;
32 using System.Linq;
33 using System.Linq.Expressions;
34 using System.Reflection;
35 using NUnit.Framework;
36 using NUnit.Framework.Constraints;
37 using OpenMetaverse;
38 using OpenSim.Framework;
39 using OpenSim.Tests.Common;
40  
41 namespace OpenSim.Data.Tests
42 {
43 public static class Constraints
44 {
45 //This is here because C# has a gap in the language, you can't infer type from a constructor
46 public static PropertyCompareConstraint<T> PropertyCompareConstraint<T>(T expected)
47 {
48 return new PropertyCompareConstraint<T>(expected);
49 }
50 }
51  
52 public class PropertyCompareConstraint<T> : NUnit.Framework.Constraints.Constraint
53 {
54 private readonly object _expected;
55 //the reason everywhere uses propertyNames.Reverse().ToArray() is because the stack is backwards of the order we want to display the properties in.
56 private string failingPropertyName = string.Empty;
57 private object failingExpected;
58 private object failingActual;
59  
60 public PropertyCompareConstraint(T expected)
61 {
62 _expected = expected;
63 }
64  
65 public override bool Matches(object actual)
66 {
67 return ObjectCompare(_expected, actual, new Stack<string>());
68 }
69  
70 private bool ObjectCompare(object expected, object actual, Stack<string> propertyNames)
71 {
72 //If they are both null, they are equal
73 if (actual == null && expected == null)
74 return true;
75  
76 //If only one is null, then they aren't
77 if (actual == null || expected == null)
78 {
79 failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray());
80 failingActual = actual;
81 failingExpected = expected;
82 return false;
83 }
84  
85 //prevent loops...
86 if (propertyNames.Count > 50)
87 {
88 failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray());
89 failingActual = actual;
90 failingExpected = expected;
91 return false;
92 }
93  
94 if (actual.GetType() != expected.GetType())
95 {
96 propertyNames.Push("GetType()");
97 failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray());
98 propertyNames.Pop();
99 failingActual = actual.GetType();
100 failingExpected = expected.GetType();
101 return false;
102 }
103  
104 if (actual.GetType() == typeof(Color))
105 {
106 Color actualColor = (Color) actual;
107 Color expectedColor = (Color) expected;
108 if (actualColor.R != expectedColor.R)
109 {
110 propertyNames.Push("R");
111 failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray());
112 propertyNames.Pop();
113 failingActual = actualColor.R;
114 failingExpected = expectedColor.R;
115 return false;
116 }
117 if (actualColor.G != expectedColor.G)
118 {
119 propertyNames.Push("G");
120 failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray());
121 propertyNames.Pop();
122 failingActual = actualColor.G;
123 failingExpected = expectedColor.G;
124 return false;
125 }
126 if (actualColor.B != expectedColor.B)
127 {
128 propertyNames.Push("B");
129 failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray());
130 propertyNames.Pop();
131 failingActual = actualColor.B;
132 failingExpected = expectedColor.B;
133 return false;
134 }
135 if (actualColor.A != expectedColor.A)
136 {
137 propertyNames.Push("A");
138 failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray());
139 propertyNames.Pop();
140 failingActual = actualColor.A;
141 failingExpected = expectedColor.A;
142 return false;
143 }
144 return true;
145 }
146  
147 IComparable comp = actual as IComparable;
148 if (comp != null)
149 {
150 if (comp.CompareTo(expected) != 0)
151 {
152 failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray());
153 failingActual = actual;
154 failingExpected = expected;
155 return false;
156 }
157 return true;
158 }
159  
160 //Now try the much more annoying IComparable<T>
161 Type icomparableInterface = actual.GetType().GetInterface("IComparable`1");
162 if (icomparableInterface != null)
163 {
164 int result = (int)icomparableInterface.GetMethod("CompareTo").Invoke(actual, new[] { expected });
165 if (result != 0)
166 {
167 failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray());
168 failingActual = actual;
169 failingExpected = expected;
170 return false;
171 }
172 return true;
173 }
174  
175 IEnumerable arr = actual as IEnumerable;
176 if (arr != null)
177 {
178 List<object> actualList = arr.Cast<object>().ToList();
179 List<object> expectedList = ((IEnumerable)expected).Cast<object>().ToList();
180 if (actualList.Count != expectedList.Count)
181 {
182 propertyNames.Push("Count");
183 failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray());
184 failingActual = actualList.Count;
185 failingExpected = expectedList.Count;
186 propertyNames.Pop();
187 return false;
188 }
189 //actualList and expectedList should be the same size.
190 for (int i = 0; i < actualList.Count; i++)
191 {
192 propertyNames.Push("[" + i + "]");
193 if (!ObjectCompare(expectedList[i], actualList[i], propertyNames))
194 return false;
195 propertyNames.Pop();
196 }
197 //Everything seems okay...
198 return true;
199 }
200  
201 //Skip static properties. I had a nasty problem comparing colors because of all of the public static colors.
202 PropertyInfo[] properties = expected.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
203 foreach (var property in properties)
204 {
205 if (ignores.Contains(property.Name))
206 continue;
207  
208 object actualValue = property.GetValue(actual, null);
209 object expectedValue = property.GetValue(expected, null);
210  
211 propertyNames.Push(property.Name);
212 if (!ObjectCompare(expectedValue, actualValue, propertyNames))
213 return false;
214 propertyNames.Pop();
215 }
216  
217 return true;
218 }
219  
220 public override void WriteDescriptionTo(MessageWriter writer)
221 {
222 writer.WriteExpectedValue(failingExpected);
223 }
224  
225 public override void WriteActualValueTo(MessageWriter writer)
226 {
227 writer.WriteActualValue(failingActual);
228 writer.WriteLine();
229 writer.Write(" On Property: " + failingPropertyName);
230 }
231  
232 //These notes assume the lambda: (x=>x.Parent.Value)
233 //ignores should really contain like a fully dotted version of the property name, but I'm starting with small steps
234 readonly List<string> ignores = new List<string>();
235 public PropertyCompareConstraint<T> IgnoreProperty(Expression<Func<T, object>> func)
236 {
237 Expression express = func.Body;
238 PullApartExpression(express);
239  
240 return this;
241 }
242  
243 private void PullApartExpression(Expression express)
244 {
245 //This deals with any casts... like implicit casts to object. Not all UnaryExpression are casts, but this is a first attempt.
246 if (express is UnaryExpression)
247 PullApartExpression(((UnaryExpression)express).Operand);
248 if (express is MemberExpression)
249 {
250 //If the inside of the lambda is the access to x, we've hit the end of the chain.
251 // We should track by the fully scoped parameter name, but this is the first rev of doing this.
252 ignores.Add(((MemberExpression)express).Member.Name);
253 }
254 }
255 }
256  
257 [TestFixture]
258 public class PropertyCompareConstraintTest : OpenSimTestCase
259 {
260 public class HasInt
261 {
262 public int TheValue { get; set; }
263 }
264  
265 [Test]
266 public void IntShouldMatch()
267 {
268 HasInt actual = new HasInt { TheValue = 5 };
269 HasInt expected = new HasInt { TheValue = 5 };
270 var constraint = Constraints.PropertyCompareConstraint(expected);
271  
272 Assert.That(constraint.Matches(actual), Is.True);
273 }
274  
275 [Test]
276 public void IntShouldNotMatch()
277 {
278 HasInt actual = new HasInt { TheValue = 5 };
279 HasInt expected = new HasInt { TheValue = 4 };
280 var constraint = Constraints.PropertyCompareConstraint(expected);
281  
282 Assert.That(constraint.Matches(actual), Is.False);
283 }
284  
285  
286 [Test]
287 public void IntShouldIgnore()
288 {
289 HasInt actual = new HasInt { TheValue = 5 };
290 HasInt expected = new HasInt { TheValue = 4 };
291 var constraint = Constraints.PropertyCompareConstraint(expected).IgnoreProperty(x => x.TheValue);
292  
293 Assert.That(constraint.Matches(actual), Is.True);
294 }
295  
296 [Test]
297 public void AssetShouldMatch()
298 {
299 UUID uuid1 = UUID.Random();
300 AssetBase actual = new AssetBase(uuid1, "asset one", (sbyte)AssetType.Texture, UUID.Zero.ToString());
301 AssetBase expected = new AssetBase(uuid1, "asset one", (sbyte)AssetType.Texture, UUID.Zero.ToString());
302  
303 var constraint = Constraints.PropertyCompareConstraint(expected);
304  
305 Assert.That(constraint.Matches(actual), Is.True);
306 }
307  
308 [Test]
309 public void AssetShouldNotMatch()
310 {
311 UUID uuid1 = UUID.Random();
312 AssetBase actual = new AssetBase(uuid1, "asset one", (sbyte)AssetType.Texture, UUID.Zero.ToString());
313 AssetBase expected = new AssetBase(UUID.Random(), "asset one", (sbyte)AssetType.Texture, UUID.Zero.ToString());
314  
315 var constraint = Constraints.PropertyCompareConstraint(expected);
316  
317 Assert.That(constraint.Matches(actual), Is.False);
318 }
319  
320 [Test]
321 public void AssetShouldNotMatch2()
322 {
323 UUID uuid1 = UUID.Random();
324 AssetBase actual = new AssetBase(uuid1, "asset one", (sbyte)AssetType.Texture, UUID.Zero.ToString());
325 AssetBase expected = new AssetBase(uuid1, "asset two", (sbyte)AssetType.Texture, UUID.Zero.ToString());
326  
327 var constraint = Constraints.PropertyCompareConstraint(expected);
328  
329 Assert.That(constraint.Matches(actual), Is.False);
330 }
331  
332 [Test]
333 public void UUIDShouldMatch()
334 {
335 UUID uuid1 = UUID.Random();
336 UUID uuid2 = UUID.Parse(uuid1.ToString());
337  
338 var constraint = Constraints.PropertyCompareConstraint(uuid1);
339  
340 Assert.That(constraint.Matches(uuid2), Is.True);
341 }
342  
343 [Test]
344 public void UUIDShouldNotMatch()
345 {
346 UUID uuid1 = UUID.Random();
347 UUID uuid2 = UUID.Random();
348  
349 var constraint = Constraints.PropertyCompareConstraint(uuid1);
350  
351 Assert.That(constraint.Matches(uuid2), Is.False);
352 }
353  
354 [Test]
355 public void TestColors()
356 {
357 Color actual = Color.Red;
358 Color expected = Color.FromArgb(actual.A, actual.R, actual.G, actual.B);
359  
360 var constraint = Constraints.PropertyCompareConstraint(expected);
361  
362 Assert.That(constraint.Matches(actual), Is.True);
363 }
364  
365 [Test]
366 public void ShouldCompareLists()
367 {
368 List<int> expected = new List<int> { 1, 2, 3 };
369 List<int> actual = new List<int> { 1, 2, 3 };
370  
371 var constraint = Constraints.PropertyCompareConstraint(expected);
372 Assert.That(constraint.Matches(actual), Is.True);
373 }
374  
375  
376 [Test]
377 public void ShouldFailToCompareListsThatAreDifferent()
378 {
379 List<int> expected = new List<int> { 1, 2, 3 };
380 List<int> actual = new List<int> { 1, 2, 4 };
381  
382 var constraint = Constraints.PropertyCompareConstraint(expected);
383 Assert.That(constraint.Matches(actual), Is.False);
384 }
385  
386 [Test]
387 public void ShouldFailToCompareListsThatAreDifferentLengths()
388 {
389 List<int> expected = new List<int> { 1, 2, 3 };
390 List<int> actual = new List<int> { 1, 2 };
391  
392 var constraint = Constraints.PropertyCompareConstraint(expected);
393 Assert.That(constraint.Matches(actual), Is.False);
394 }
395  
396 public class Recursive
397 {
398 public Recursive Other { get; set; }
399 }
400  
401 [Test]
402 public void ErrorsOutOnRecursive()
403 {
404 Recursive parent = new Recursive();
405 Recursive child = new Recursive();
406 parent.Other = child;
407 child.Other = parent;
408  
409 var constraint = Constraints.PropertyCompareConstraint(child);
410 Assert.That(constraint.Matches(child), Is.False);
411 }
412 }
413 }