Blame mono/Contours/Test.cs

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