Merge pull request #1304 from slluis/mac-proxy-autoconfig
[mono.git] / mcs / class / System.Drawing / Test / DrawingTest / DrawingTestHelper / DrawingTest.cs
1 using System;\r
2 using System.Drawing;\r
3 using System.Diagnostics;\r
4 using System.IO;\r
5 using System.Text;\r
6 using Exocortex.DSP;\r
7 using System.Reflection;\r
8 using System.Xml.Serialization;\r
9 using System.Collections;\r
10 using System.Security.Cryptography;\r
11 using System.Runtime.InteropServices;\r
12 using System.Drawing.Imaging;\r
13 \r
14 #if MONOTOUCH\r
15 #else\r
16 using System.Windows.Forms;\r
17 #endif\r
18 \r
19 using NUnit.Framework;\r
20 \r
21 namespace DrawingTestHelper\r
22 {\r
23         #region Results serialization classes\r
24         public sealed class ExpectedResult {\r
25                 public ExpectedResult(){}\r
26                 public ExpectedResult(string testName, double norm) {\r
27                         TestName = testName;\r
28                         Norm = norm;\r
29                 }\r
30                 public string TestName;\r
31                 public double Norm;\r
32         }\r
33 \r
34         public sealed class ExpectedResults {\r
35                 [XmlArrayItem(typeof(ExpectedResult))]\r
36                 public ArrayList Tests = new ArrayList();\r
37         }\r
38 \r
39         public sealed class ExpectedResultsHash {\r
40                 Hashtable _hash;\r
41                 ExpectedResults _suite;\r
42 \r
43                 public ExpectedResultsHash () {\r
44                         try {\r
45                                 using (StreamReader s = new StreamReader (FileName)) {\r
46                                         _suite = (ExpectedResults)TestSuiteSerializer.Deserialize(s);\r
47                                 }\r
48                         }\r
49                         catch {\r
50                                 _suite = new ExpectedResults ();\r
51                         }\r
52                         _hash = new Hashtable(_suite.Tests.Count);\r
53                         foreach (ExpectedResult res in _suite.Tests)\r
54                                 _hash[res.TestName] = res.Norm;\r
55                 }\r
56 \r
57                 public const string FileName = "ExpectedResults.xml";\r
58                 public readonly static XmlSerializer TestSuiteSerializer = new XmlSerializer(typeof(ExpectedResults));\r
59 \r
60                 public double GetNorm(string testName) {\r
61                         object res = _hash[testName];\r
62                         if (res != null)\r
63                                 return (double)res;\r
64                         return double.NaN;\r
65                 }\r
66 \r
67                 public void WriteNorm (string testName, double myNorm) {\r
68                         if (_hash.Contains (testName)) {\r
69                                 for (int i = 0; i < _suite.Tests.Count; i++) {\r
70                                         ExpectedResult cur = (ExpectedResult) _suite.Tests[i];\r
71                                         if (cur.TestName == testName) {\r
72                                                 cur.Norm = myNorm;\r
73                                                 break;\r
74                                         }\r
75                                 }\r
76                         }\r
77                         else\r
78                                 _suite.Tests.Add(new ExpectedResult(testName, myNorm));\r
79 \r
80                         _hash[testName] = myNorm;\r
81                         using(StreamWriter w = new StreamWriter(FileName))\r
82                                 TestSuiteSerializer.Serialize(w, _suite);\r
83                 }\r
84         }\r
85 \r
86         public sealed class CachedResult {\r
87                 public CachedResult (){}\r
88                 public CachedResult (string testName, string sha1, double norm) {\r
89                         TestName = testName;\r
90                         SHA1 = sha1;\r
91                         Norm = norm;\r
92                         DateTime = DateTime.Now;\r
93                 }\r
94 \r
95                 public string TestName;\r
96                 public string SHA1;\r
97                 public double Norm;\r
98                 public DateTime DateTime;\r
99         }\r
100 \r
101         public sealed class CachedResults {\r
102                 [XmlArrayItem(typeof(CachedResult))]\r
103                 public ArrayList Tests = new ArrayList();\r
104         }\r
105 \r
106         public class Cache {\r
107                 Hashtable _hash;\r
108                 CachedResults _results;\r
109 \r
110                 public const string FileName = "dotnet.CachedResults.xml";\r
111                 public const string NewFileName = "dotnet.NewCachedResults.xml";\r
112                 public readonly static XmlSerializer TestSuiteSerializer =\r
113                         new XmlSerializer(typeof(CachedResults));\r
114 \r
115                 public Cache () {\r
116                         try {\r
117                                 using (StreamReader r = new StreamReader(FileName))\r
118                                         _results = (CachedResults)TestSuiteSerializer.Deserialize(r);\r
119                         }\r
120                         catch {\r
121                                 _results = new CachedResults ();\r
122                         }\r
123                         \r
124                         _hash = new Hashtable(_results.Tests.Count);\r
125                         foreach (CachedResult res in _results.Tests)\r
126                                 _hash[res.SHA1] = res.Norm;\r
127                 }\r
128 \r
129                 public double GetNorm (string sha1) {\r
130                         if (_hash.ContainsKey (sha1))\r
131                                 return (double)_hash[sha1];\r
132                         else\r
133                                 return double.NaN;\r
134                 }\r
135 \r
136                 public void Add (string testName, string sha1, double norm) {\r
137                         if (_hash.ContainsKey (sha1))\r
138                                 throw new ArgumentException ("This SHA1 is already in the cache", "sha1");\r
139 \r
140                         _results.Tests.Add (new CachedResult(testName, sha1, norm));\r
141                         _hash.Add (sha1, norm);\r
142 \r
143                         using(StreamWriter w = new StreamWriter(NewFileName))\r
144                                 TestSuiteSerializer.Serialize(w, _results);\r
145                 }\r
146         }\r
147         #endregion\r
148 \r
149         /// <summary>\r
150         /// Summary description for DrawingTest.\r
151         /// </summary>\r
152         public abstract class DrawingTest : IDisposable {\r
153 \r
154                 public const float DEFAULT_FLOAT_TOLERANCE = 1e-5f; \r
155                 public const int DEFAULT_IMAGE_TOLERANCE = 2; \r
156 \r
157                 Graphics _graphics;\r
158                 protected Bitmap _bitmap;\r
159                 static string _callingFunction;\r
160                 //static int _counter;\r
161                 static Hashtable _mpFuncCount = new Hashtable();\r
162                 static bool _showForms = false;\r
163                 static bool _createResults = true;\r
164                 protected string _ownerClass = "";\r
165                 protected Hashtable _specialTolerance = null;\r
166 \r
167                 protected readonly static ExpectedResultsHash ExpectedResults = new ExpectedResultsHash ();\r
168                 protected readonly static Cache cache = new Cache ();\r
169 \r
170                 public Graphics Graphics {get {return _graphics;}}\r
171                 public Bitmap Bitmap {get { return _bitmap; }}\r
172 \r
173                 public Hashtable SpecialTolerance \r
174                 {\r
175                         get {return _specialTolerance;}\r
176                         set {_specialTolerance = value;}\r
177                 }\r
178 \r
179                 public string OwnerClass \r
180                 {\r
181                         get {return _ownerClass;}\r
182                         set {_ownerClass = value;}\r
183                 }\r
184 \r
185                 public static bool ShowForms \r
186                 {\r
187                         get {return _showForms;}\r
188                         set {_showForms = value;}\r
189                 }\r
190 \r
191                 public static bool CreateResults {\r
192                         get {return _createResults;}\r
193                         set {_createResults = value;}\r
194                 }\r
195 \r
196                 protected DrawingTest() {}\r
197                 \r
198                 private void Init (int width, int height) {\r
199                         Init (new Bitmap (width, height));\r
200                 }\r
201 \r
202                 private void Init (Bitmap bitmap) {\r
203                         _bitmap = bitmap;\r
204                         _graphics = Graphics.FromImage (_bitmap);\r
205                 }\r
206 \r
207                 protected abstract string DetermineCallingFunction ();\r
208 \r
209                 protected interface IMyForm {\r
210                         void Show ();\r
211                 }\r
212 \r
213                 protected abstract IMyForm CreateForm (string title);\r
214 \r
215                 public void Show () {\r
216                         CheckCounter ();\r
217                         if (!ShowForms)\r
218                                 return;\r
219                         IMyForm form = CreateForm(_callingFunction + _mpFuncCount[_callingFunction]);\r
220                         form.Show ();\r
221                 }\r
222         \r
223                 static protected string TestName {\r
224                         get {\r
225                                 return _callingFunction + ":" + _mpFuncCount[_callingFunction]/* + ".dat"*/;\r
226                         }\r
227                 }\r
228 \r
229                 #region GetImageFFTArray\r
230                 private static ComplexF[] GetImageFFTArray(Bitmap bitmap) {\r
231                         float scale = 1F / (float) System.Math.Sqrt(bitmap.Width * bitmap.Height);\r
232                         ComplexF[] data = new ComplexF [bitmap.Width * bitmap.Height * 4];\r
233 \r
234                         int offset = 0;\r
235                         for( int y = 0; y < bitmap.Height; y ++ )\r
236                                 for( int x = 0; x < bitmap.Width; x ++ ) {\r
237                                         Color c = bitmap.GetPixel (x, y);\r
238                                         float s = 1F;\r
239                                         if( (( x + y ) & 0x1 ) != 0 ) {\r
240                                                 s = -1F;\r
241                                         }\r
242 \r
243                                         data [offset++] = new ComplexF( c.A * s / 256F, 0);\r
244                                         data [offset++] = new ComplexF( c.R * s / -256F, 0);\r
245                                         data [offset++] = new ComplexF( c.G * s / 256F, 0);\r
246                                         data [offset++] = new ComplexF( c.B * s / -256F, 0);\r
247                                 }\r
248                         \r
249 \r
250                         Fourier.FFT3( data, 4, bitmap.Width, bitmap.Height, FourierDirection.Forward );\r
251                         \r
252                         for( int i = 0; i < data.Length; i ++ ) {\r
253                                 data[i] *= scale;\r
254                         }\r
255 \r
256                         return data;\r
257                 }\r
258                 #endregion\r
259 \r
260                 abstract public string CalculateSHA1 ();\r
261                 \r
262                 public static double CalculateNorm (Bitmap bitmap) {\r
263                         ComplexF[] matrix = GetImageFFTArray(bitmap);\r
264 \r
265                         double norm = 0;\r
266                         int size_x = 4; //ARGB values\r
267                         int size_y = bitmap.Width;\r
268                         int size_z = bitmap.Height;\r
269                         for (int x=1; x<=size_x; x++) {\r
270                                 double norm_y = 0;\r
271                                 for (int y=1; y<=size_y; y++) {\r
272                                         double norm_z = 0;\r
273                                         for (int z=1; z<=size_z; z++) {\r
274                                                 ComplexF cur = matrix[(size_x-x)+size_x*(size_y-y)+size_x*size_y*(size_z-z)];\r
275                                                 norm_z += cur.GetModulusSquared ();// * z;\r
276                                         }\r
277                                         norm_y += norm_z;// * y;\r
278                                 }\r
279                                 norm += norm_y;// * x;\r
280                         }\r
281                         return norm;\r
282                 }\r
283 \r
284                 public double GetNorm () {\r
285                         string sha1 = CalculateSHA1 ();\r
286 \r
287                         double norm = cache.GetNorm (sha1);\r
288                         if (double.IsNaN (norm)) {\r
289                                 norm = CalculateNorm (_bitmap);\r
290                                 cache.Add (TestName, sha1, norm);\r
291                                 //_bitmap.Save(TestName.Replace(":", "_"));\r
292                         }\r
293                         return norm;\r
294                 }\r
295 \r
296                 protected abstract double GetExpectedNorm (double myNorm);\r
297 \r
298                 private void CheckCounter () {\r
299                         string callFunc = DetermineCallingFunction ();\r
300                         _callingFunction = callFunc;\r
301                         if (!_mpFuncCount.Contains(_callingFunction)) {\r
302                                 \r
303                                 _mpFuncCount[_callingFunction] = 1;\r
304                         }\r
305                         else {\r
306                                 int counter = (int)_mpFuncCount[_callingFunction];\r
307                                 counter ++;\r
308                                 _mpFuncCount[_callingFunction] = counter;\r
309                         }\r
310                 }\r
311 \r
312                 public static void AssertAlmostEqual (float expected, float actual)\r
313                 {\r
314                         AssertAlmostEqual (expected, actual, DEFAULT_FLOAT_TOLERANCE);\r
315                 }\r
316                 \r
317                 public static void AssertAlmostEqual (float expected, float actual, float tolerance)\r
318                 {\r
319                         string msg = String.Format("\nExpected : {0} \nActual : {1}",expected.ToString(),actual.ToString());\r
320                         AssertAlmostEqual (expected, actual, tolerance, msg);\r
321                 }\r
322 \r
323                 private static void AssertAlmostEqual (float expected, float actual, float tolerance, string message)\r
324                 {\r
325                         float error = System.Math.Abs ((expected - actual) / (expected + actual + float.Epsilon));\r
326                         Assert.That (error < tolerance, Is.True, message);\r
327                 }\r
328 \r
329                 public static void AssertAlmostEqual (PointF expected, PointF actual)\r
330                 {\r
331                         string msg = String.Format("\nExpected : {0} \n  Actual : {1}",expected.ToString(),actual.ToString());\r
332                         AssertAlmostEqual (expected.X, actual.X, DEFAULT_FLOAT_TOLERANCE, msg);\r
333                         AssertAlmostEqual (expected.Y, actual.Y, DEFAULT_FLOAT_TOLERANCE, msg);\r
334                 }\r
335 \r
336                 /// <summary>\r
337                 /// Checks that the given bitmap norm is similar to expected\r
338                 /// </summary>\r
339                 /// <param name="tolerance">tolerance in percents (0..100)</param>\r
340                 /// <returns></returns>\r
341                 /// \r
342                 public bool Compare (double tolerance) {\r
343                         CheckCounter ();\r
344 \r
345                         double error = CompareToExpectedInternal()*100;\r
346 \r
347                         if (SpecialTolerance != null)\r
348                                 return error <= GetSpecialTolerance(TestName);\r
349 \r
350                         return error <= tolerance;\r
351                 }\r
352 \r
353                 public bool PDCompare (double tolerance) {\r
354                         Bitmap ri = GetReferenceImage(TestName);\r
355                         if (ri == null)\r
356                                 return true;\r
357 \r
358                         double error = PDComparer.Compare(ri, _bitmap);\r
359                         return error <= tolerance;\r
360                 }\r
361                 \r
362                 public bool Compare () {\r
363                         CheckCounter ();\r
364 \r
365                         double error = CompareToExpectedInternal()*100;\r
366                         \r
367                         if (SpecialTolerance != null)\r
368                                 return error <= GetSpecialTolerance(TestName);\r
369 \r
370                         return error <= DEFAULT_IMAGE_TOLERANCE;\r
371                 }\r
372 \r
373                 public bool PDCompare () {\r
374                         Bitmap ri = GetReferenceImage(TestName);\r
375                         if (ri == null)\r
376                                 return true;\r
377 \r
378                         double error = PDComparer.Compare(ri, _bitmap);\r
379                         return error <= DEFAULT_IMAGE_TOLERANCE;\r
380                 }\r
381 \r
382                 protected abstract Bitmap GetReferenceImage(string testName);\r
383 \r
384                 protected double GetSpecialTolerance(string testName) {\r
385                         try     {\r
386                                 string shortTestName = testName.Substring( testName.LastIndexOf(".") + 1 );\r
387                                 object o = SpecialTolerance[shortTestName];\r
388                                 if (o == null)\r
389                                         return DEFAULT_IMAGE_TOLERANCE;\r
390 \r
391                                 return Convert.ToDouble(o);\r
392                         }\r
393                         catch (System.Exception) {\r
394                                 return DEFAULT_IMAGE_TOLERANCE;\r
395                         }\r
396                 }\r
397 \r
398                 public void AssertCompare () {\r
399                         CheckCounter ();\r
400                         Assert.That ((CompareToExpectedInternal () * 100) < DEFAULT_IMAGE_TOLERANCE, Is.True);\r
401                 }\r
402 \r
403                 public void AssertCompare (double tolerance) {\r
404                         CheckCounter ();\r
405                         Assert.That ((CompareToExpectedInternal () * 100) < tolerance, Is.True);\r
406                 }\r
407                 \r
408                 public double CompareToExpected () {\r
409                         CheckCounter ();\r
410                         return CompareToExpectedInternal ();\r
411                 }\r
412 \r
413                 double CompareToExpectedInternal () {\r
414                         if (ShowForms)\r
415                                 return 0;\r
416 \r
417                         double norm = GetNorm ();\r
418                         double expNorm = GetExpectedNorm (norm);\r
419                         return System.Math.Abs (norm-expNorm)/(norm+expNorm+double.Epsilon);\r
420                 }\r
421 \r
422                 public static DrawingTest Create (int width, int height) {\r
423                         return Create(width, height, "GraphicsFixture");\r
424                 }\r
425                 public static DrawingTest Create (int width, int height, string ownerClass) {\r
426                         DrawingTest test;\r
427                         test = new NetDrawingTest ();\r
428                         test.Init (width, height);\r
429                         test.OwnerClass = ownerClass;\r
430                         return test;\r
431                 }\r
432                 #region IDisposable Members\r
433 \r
434                 public void Dispose()\r
435                 {\r
436                         // TODO:  Add DrawingTest.Dispose implementation\r
437                         if (_graphics != null) {\r
438                                 _graphics.Dispose();\r
439                                 _graphics = null;\r
440                         }\r
441                 }\r
442 \r
443                 #endregion\r
444         }\r
445 \r
446         internal class NetDrawingTest:DrawingTest {\r
447                 public NetDrawingTest () {}\r
448 \r
449                 protected override double GetExpectedNorm (double myNorm) {\r
450                         if (CreateResults)\r
451                                 ExpectedResults.WriteNorm (TestName, myNorm);\r
452 \r
453                         return myNorm;\r
454                 }\r
455 \r
456                 protected override Bitmap GetReferenceImage(string testName) {\r
457                         string fileName = testName.Replace(":", "_") + ".png";\r
458                         try{\r
459                                 if (true){\r
460                                         return new Bitmap("/Developer/MonoTouch/Source/mono/mcs/class/System.Drawing/Test/DrawingTest/Test/PNGs/" + fileName);\r
461                                 } else {\r
462                                         _bitmap.Save( fileName );\r
463                                         GC.Collect();\r
464                                 }\r
465                                 return null;\r
466                         }\r
467                         catch(System.Exception e) {\r
468                                 throw new System.Exception("Error loading .Net reference image: " + fileName);\r
469                         }\r
470                 }\r
471                 \r
472 #if MONOTOUCH\r
473                 private class NetForm:MonoTouch.UIKit.UIViewController,IMyForm {\r
474                         Image image;\r
475                         public NetForm(string title, Image anImage):base() {\r
476                                 //base.Text = title;            \r
477                                 image = anImage;\r
478                         }\r
479                         void IMyForm.Show () {\r
480                                 this.image.Save("test.net.png");\r
481                         }\r
482                 }\r
483 #else\r
484                 private class NetForm:Form,IMyForm {\r
485                         Image image;\r
486                         public NetForm(string title, Image anImage):base() {\r
487                                 base.Text = title;\r
488                                 image = anImage;\r
489                         }\r
490                         protected override void OnPaint(PaintEventArgs e) {\r
491                                 e.Graphics.DrawImageUnscaled (image, 0, 0);\r
492                         }\r
493                         void IMyForm.Show () {\r
494                                 this.Size = image.Size;\r
495                                 this.ShowDialog ();\r
496                                 this.image.Save("test.net.png");\r
497                         }\r
498                 }\r
499 #endif\r
500                 protected override IMyForm CreateForm(string title) {\r
501                         return new NetForm (title, _bitmap);\r
502                 }\r
503 \r
504                 protected override string DetermineCallingFunction() {\r
505                         StackFrame sf = new StackFrame (3, true);\r
506                         MethodBase mb = sf.GetMethod ();\r
507 \r
508                         string name = mb.DeclaringType.FullName + "." + _ownerClass + "." + mb.Name;\r
509                         return name;\r
510                 }\r
511 \r
512                 public override string CalculateSHA1() {\r
513                         Rectangle r = new Rectangle(0, 0, _bitmap.Width, _bitmap.Height);\r
514                         \r
515                         BitmapData data = _bitmap.LockBits (r, ImageLockMode.ReadOnly,\r
516                                 _bitmap.PixelFormat);\r
517                         int dataSize = data.Stride * data.Height;\r
518                         byte [] bdata = new byte [dataSize];\r
519                         Marshal.Copy (data.Scan0, bdata, 0, dataSize);\r
520                         _bitmap.UnlockBits (data);\r
521 \r
522                         SHA1 sha1 = new SHA1CryptoServiceProvider ();\r
523                         byte [] resdata = sha1.ComputeHash (bdata);\r
524                         return Convert.ToBase64String (resdata);\r
525                 }\r
526 \r
527         }\r
528 \r
529 }\r