/* ......... 2015 Ivan Mahonin This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ using System; using System.Collections.Generic; using System.Drawing; namespace Contours { public class Test { class Exception: System.Exception { } public string name; public readonly Dictionary>>> input = new Dictionary>>>(); public readonly Dictionary>>> output = new Dictionary>>>(); public readonly Dictionary results = new Dictionary(); public bool result = false; public static readonly List tests = new List(); void check(string name, Shape shape) { if (!input.ContainsKey(name)) return; List>> contours = null; try { contours = shape.getContours(); } catch(System.Exception) { } output.Add(name, contours); results.Add(name, compareContours(input[name], output[name])); if (!results[name]) result = false; } Shape tryCreateShape(List>> contours) { try { Shape shape = new Shape(); shape.setContours(contours); return shape; } catch (System.Exception) { return null; } } Shape tryCombineShapes(Shape.CombinationMode mode, List>> a, List>> b) { try { Shape sa = new Shape(); Shape sb = new Shape(); sa.setContours(a); sb.setContours(b); return Shape.combine(mode, sa, sb); } catch (System.Exception) { return null; } } public bool run() { result = true; List>> a = null; List>> b = null; if (input.ContainsKey("badA")) a = input["badA"]; else if (input.ContainsKey("a")) a = input["a"]; if (input.ContainsKey("badB")) b = input["badB"]; else if (input.ContainsKey("b")) b = input["b"]; if (a != null) check("a", tryCreateShape(a)); if (b != null) check("b", tryCreateShape(b)); if (a != null && b != null) { check("add", tryCombineShapes(Shape.CombinationMode.Add, a, b)); check("subtract", tryCombineShapes(Shape.CombinationMode.Subtract, a, b)); check("intersection", tryCombineShapes(Shape.CombinationMode.Intersection, a, b)); check("xor", tryCombineShapes(Shape.CombinationMode.Xor, a, b)); } return result; } public static bool compareContours(List a, List b) { if (a == null || b == null) return false; if (a.Count == b.Count) { for(int offset = 0; offset < a.Count; ++offset) { bool equal = true; for(int i = 0; i < a.Count; ++i) if (a[(i + offset)%a.Count] != b[i]) { equal = false; break; } if (equal) return true; } } return false; } public static bool compareContours(List> a, List> b) { if (a == null || b == null) return false; if (a.Count != b.Count) return false; if (a.Count == 0) return true; if (!compareContours(a[0], b[0])) return false; bool[] compared = new bool[a.Count]; for(int i = 1; i < a.Count; ++i) { bool equal = false; for(int j = 1; j < b.Count; ++j) { if (!compared[j] && compareContours(a[i], b[j])) { equal = true; compared[j] = true; break; } } if (!equal) return false; } return true; } public static bool compareContours(List>> a, List>> b) { if (a == null || b == null) return false; if (a.Count != b.Count) return false; bool[] compared = new bool[a.Count]; for(int i = 0; i < a.Count; ++i) { bool equal = false; for(int j = 0; j < b.Count; ++j) { if (!compared[j] && compareContours(a[i], b[j])) { equal = true; compared[j] = true; break; } } if (!equal) return false; } return true; } class Loader { public string text; public int position = 0; void error() { throw new Exception(); } void assert(bool expr) { if (!expr) error(); } void skipSpaces() { while(position < text.Length && char.IsWhiteSpace(text[position])) ++position; if (position < text.Length && text.Substring(position, 2) == "/*") { while(position < text.Length) if (text.Substring(position, 2) == "*/") { position += 2; break; } else ++position; skipSpaces(); } } int loadInt() { skipSpaces(); int startPosition = position; while(position < text.Length && char.IsDigit(text[position])) ++position; assert(startPosition < position); return int.Parse(text.Substring(startPosition, position-startPosition)); } string tryLoadKey(string key) { return tryLoadKey(new string[] { key }); } string tryLoadKey(string key0, string key1) { return tryLoadKey(new string[] { key0, key1 }); } string tryLoadKey(string[] keys) { skipSpaces(); foreach(string key in keys) if (text.Substring(position, key.Length) == key) { position += key.Length; return key; } return null; } string loadKey(string key) { return loadKey(new string[] { key }); } string loadKey(string key0, string key1) { return loadKey(new string[] { key0, key1 }); } string loadKey(string[] keys) { string result = tryLoadKey(keys); assert(result != null); return result; } Point loadPoint() { loadKey("("); int x = loadInt(); loadKey(","); int y = loadInt(); loadKey(")"); return new Point(x, y); } List loadPointList() { List list = new List(); loadKey("("); if (tryLoadKey(")") == null) do { list.Add(loadPoint()); } while(loadKey(",", ")") == ","); return list; } List> loadPointListList() { List> list = new List>(); loadKey("("); if (tryLoadKey(")") == null) do { list.Add(loadPointList()); } while(loadKey(",", ")") == ","); return list; } List>> loadPointListListList() { List>> list = new List>>(); loadKey("("); if (tryLoadKey(")") == null) do { list.Add(loadPointListList()); } while(loadKey(",", ")") == ","); return list; } string loadFieldName() { skipSpaces(); int startPosition = position; while(position < text.Length && char.IsLetterOrDigit(text[position])) ++position; assert(startPosition < position); return text.Substring(startPosition, position-startPosition); } string loadName() { string name = ""; loadKey("("); while(text[position] != ')') name += text[position++]; ++position; return name.Trim(); } Test loadTest() { Test test = new Test(); loadKey("{"); while(tryLoadKey("}") == null) { string name = loadFieldName(); loadKey(":"); if (name == "name") test.name = loadName(); else test.input.Add(name, loadPointListListList()); } return test; } public List loadTestListToEof() { List list = new List(); while(true) { skipSpaces(); if (position >= text.Length) break; list.Add(loadTest()); } return list; } }; static void loadTests(string text) { Loader loader = new Loader(); loader.text = text; tests.Clear(); tests.AddRange(loader.loadTestListToEof()); } public static void loadTestsFromFile(string filename) { loadTests(System.IO.File.ReadAllText(filename)); } public static bool runAll() { bool result = true; foreach(Test test in tests) if (!test.run()) result = false; return result; } static string resultToString(string name, bool result) { return name + ": " + (result ? "+" : "FAILED") + "\n"; } public static string makeReport() { string report = ""; foreach(Test test in tests) { report += resultToString(test.name, test.result); foreach(KeyValuePair pair in test.results) report += resultToString(" " + pair.Key, pair.Value); } return report; } public static void saveReport(string filename) { System.IO.File.WriteAllText(filename, makeReport()); } } }