Browse Source

add ability to validate recursive json datastructures with object references

Kolja Strohm 1 year ago
parent
commit
8f584ac295
7 changed files with 1000 additions and 437 deletions
  1. BIN
      Framework Tests/Framwork.dll
  2. 923 423
      Framework Tests/Json.cpp
  3. 40 13
      JSON.cpp
  4. 8 0
      JSON.h
  5. 1 1
      UIMLView.cpp
  6. 24 0
      XML.cpp
  7. 4 0
      XML.h

BIN
Framework Tests/Framwork.dll


+ 923 - 423
Framework Tests/Json.cpp

@@ -1,431 +1,931 @@
 #include "pch.h"
-#include "CppUnitTest.h"
-#include <Json.h>
+
 #define NO_MAIN
+#include <Json.h>
 #include <main.h>
 
+#include "CppUnitTest.h"
+
 using namespace Microsoft::VisualStudio::CppUnitTestFramework;
 
 namespace FrameworkTests
 {
-	TEST_CLASS(JSONParserTests)
-	{
-	public:
-		TEST_METHOD(NullTest)
-		{
-			Framework::JSON::JSONValue* value = Framework::JSON::Parser::getValue("null");
-			Assert::IsTrue(value != 0, L"Framework::JSON::Parser::getValue('null') should not return 0");
-			Assert::IsTrue(value->getType() == Framework::JSON::JSONType::NULL_, L"Framework::JSON::Parser::getValue('null') should return a json null value");
-			value->release();
-		}
-
-		TEST_METHOD(BooleanTest)
-		{
-			Framework::JSON::JSONValue* value = Framework::JSON::Parser::getValue("false");
-			Assert::IsTrue(value != 0, L"Framework::JSON::Parser::getValue('false') should not return 0");
-			Assert::IsTrue(value->getType() == Framework::JSON::JSONType::BOOLEAN, L"Framework::JSON::Parser::getValue('false') should return a boolean");
-			Assert::IsTrue(((Framework::JSON::JSONBool*)value)->getBool() == false, L"Framework::JSON::Parser::getValue('false') should return a boolean with value false");
-			value->release();
-
-			value = Framework::JSON::Parser::getValue("true");
-			Assert::IsTrue(value != 0, L"Framework::JSON::Parser::getValue('true') should not return 0");
-			Assert::IsTrue(value->getType() == Framework::JSON::JSONType::BOOLEAN, L"Framework::JSON::Parser::getValue('true') should return a boolean");
-			Assert::IsTrue(((Framework::JSON::JSONBool*)value)->getBool() == true, L"Framework::JSON::Parser::getValue('true') should return a boolean with value true");
-			value->release();
-		}
-
-		TEST_METHOD(StringTest)
-		{
-			Framework::JSON::JSONValue* value = Framework::JSON::Parser::getValue("\"test\"");
-			Assert::IsTrue(value != 0, L"Framework::JSON::Parser::getValue('\"test\"') should not return 0");
-			Assert::IsTrue(value->getType() == Framework::JSON::JSONType::STRING, L"Framework::JSON::Parser::getValue('\"test\"') should return a string");
-			Assert::IsTrue(((Framework::JSON::JSONString*)value)->getString().istGleich("test"), L"Framework::JSON::Parser::getValue('\"test\"') should return a string with value 'test'");
-			value->release();
-
-			value = Framework::JSON::Parser::getValue("\"\"");
-			Assert::IsTrue(value != 0, L"Framework::JSON::Parser::getValue('\"\"') should not return 0");
-			Assert::IsTrue(value->getType() == Framework::JSON::JSONType::STRING, L"Framework::JSON::Parser::getValue('\"\"') should return a string");
-			Assert::IsTrue(((Framework::JSON::JSONString*)value)->getString().istGleich(""), L"Framework::JSON::Parser::getValue('\"\"') should return a string with value ''");
-			value->release();
-		}
-
-		TEST_METHOD(NumberTest)
-		{
-			Framework::JSON::JSONValue* value = Framework::JSON::Parser::getValue("0");
-			Assert::IsTrue(value != 0, L"Framework::JSON::Parser::getValue('0') should not return 0");
-			Assert::IsTrue(value->getType() == Framework::JSON::JSONType::NUMBER, L"Framework::JSON::Parser::getValue('0') should return a number");
-			Assert::IsTrue(((Framework::JSON::JSONNumber*)value)->getNumber() == 0.0, L"Framework::JSON::Parser::getValue('0') should return a number with value '0'");
-			value->release();
-
-			value = Framework::JSON::Parser::getValue("1.5");
-			Assert::IsTrue(value != 0, L"Framework::JSON::Parser::getValue('1.5') should not return 0");
-			Assert::IsTrue(value->getType() == Framework::JSON::JSONType::NUMBER, L"Framework::JSON::Parser::getValue('1.5') should return a number");
-			Assert::IsTrue(((Framework::JSON::JSONNumber*)value)->getNumber() == 1.5, L"Framework::JSON::Parser::getValue('1.5') should return a number with value '1.5'");
-			value->release();
-
-			value = Framework::JSON::Parser::getValue("-1.5");
-			Assert::IsTrue(value != 0, L"Framework::JSON::Parser::getValue('-1.5') should not return 0");
-			Assert::IsTrue(value->getType() == Framework::JSON::JSONType::NUMBER, L"Framework::JSON::Parser::getValue('-1.5') should return a number");
-			Assert::IsTrue(((Framework::JSON::JSONNumber*)value)->getNumber() == -1.5, L"Framework::JSON::Parser::getValue('-1.5') should return a number with value '-1.5'");
-			value->release();
-
-			value = Framework::JSON::Parser::getValue("-5.0");
-			Assert::IsTrue(value != 0, L"Framework::JSON::Parser::getValue('-5.0') should not return 0");
-			Assert::IsTrue(value->getType() == Framework::JSON::JSONType::NUMBER, L"Framework::JSON::Parser::getValue('-5.0') should return a number");
-			Assert::IsTrue(((Framework::JSON::JSONNumber*)value)->getNumber() == -5.0, L"Framework::JSON::Parser::getValue('-5.0') should return a number with value '-5.0'");
-			value->release();
-		}
-
-		TEST_METHOD(ArrayTest)
-		{
-			Framework::JSON::JSONValue* value = Framework::JSON::Parser::getValue("[]");
-			Assert::IsTrue(value != 0, L"Framework::JSON::Parser::getValue('[]') should not return 0");
-			Assert::IsTrue(value->getType() == Framework::JSON::JSONType::ARRAY, L"Framework::JSON::Parser::getValue('[]') should return an array");
-			Assert::IsTrue(((Framework::JSON::JSONArray*)value)->getLength() == 0, L"Framework::JSON::Parser::getValue('[]') should return an array with length 0");
-			value->release();
-
-			value = Framework::JSON::Parser::getValue("  \t[ \r\n\tnull   , \r\n\t  1,true , \"\"  ] ");
-			Assert::IsTrue(value != 0, L"Framework::JSON::Parser::getValue('[null, 1, true, \"\"]') should not return 0");
-			Assert::IsTrue(value->getType() == Framework::JSON::JSONType::ARRAY, L"Framework::JSON::Parser::getValue('[null, 1, true, \"\"]') should return an array");
-			Assert::IsTrue(((Framework::JSON::JSONArray*)value)->getLength() == 4, L"Framework::JSON::Parser::getValue('[null, 1, true, \"\"]') should return an array with length 4");
-			Assert::IsTrue(((Framework::JSON::JSONArray*)value)->isValueOfType(0, Framework::JSON::JSONType::NULL_), L"Framework::JSON::Parser::getValue('[null, 1, true, \"\"]') should contain null at index 0");
-			Assert::IsTrue(((Framework::JSON::JSONArray*)value)->isValueOfType(1, Framework::JSON::JSONType::NUMBER), L"Framework::JSON::Parser::getValue('[null, 1, true, \"\"]') should contain a number at index 1");
-			Assert::IsTrue(((Framework::JSON::JSONArray*)value)->isValueOfType(2, Framework::JSON::JSONType::BOOLEAN), L"Framework::JSON::Parser::getValue('[null, 1, true, \"\"]') should contain a boolean at index 2");
-			Assert::IsTrue(((Framework::JSON::JSONArray*)value)->isValueOfType(3, Framework::JSON::JSONType::STRING), L"Framework::JSON::Parser::getValue('[null, 1, true, \"\"]') should contain a boolean at index 3");
-			value->release();
-		}
-
-		TEST_METHOD(MultipleArrayTest)
-		{
-			Framework::JSON::JSONValue* value = Framework::JSON::Parser::getValue("[[1],2,[[]]]");
-			Assert::IsTrue(value != 0, L"Framework::JSON::Parser::getValue('[[1],2,[[]]]') should not return 0");
-			Assert::IsTrue(value->getType() == Framework::JSON::JSONType::ARRAY, L"Framework::JSON::Parser::getValue('[[1],2,[[]]]') should return an array");
-			Assert::IsTrue(((Framework::JSON::JSONArray*)value)->getLength() == 3, L"Framework::JSON::Parser::getValue('[[1],2,[[]]]') should return an array with length 3");
-			Assert::IsTrue(((Framework::JSON::JSONArray*)value)->isValueOfType(0, Framework::JSON::JSONType::ARRAY), L"Framework::JSON::Parser::getValue('[null, 1, true, \"\"]') should contain an array at index 0");
-			Assert::IsTrue(((Framework::JSON::JSONArray*)value)->isValueOfType(1, Framework::JSON::JSONType::NUMBER), L"Framework::JSON::Parser::getValue('[null, 1, true, \"\"]') should contain a number at index 1");
-			Assert::IsTrue(((Framework::JSON::JSONArray*)value)->isValueOfType(2, Framework::JSON::JSONType::ARRAY), L"Framework::JSON::Parser::getValue('[null, 1, true, \"\"]') should contain an array at index 2");
-			value->release();
-		}
-
-		TEST_METHOD(ObjectTest)
-		{
-			Framework::JSON::JSONValue* value = Framework::JSON::Parser::getValue("{\" \": []}");
-			Assert::IsTrue(value != 0, L"Framework::JSON::Parser::getValue('{\"\": []}') should not return 0");
-			Assert::IsTrue(value->getType() == Framework::JSON::JSONType::OBJECT, L"Framework::JSON::Parser::getValue('{\" \": []}') should return an object");
-			Assert::IsTrue(((Framework::JSON::JSONObject*)value)->getFieldCount() == 1, L"Framework::JSON::Parser::getValue('{\" \": []}') should return an object with one attribute");
-			Assert::IsTrue(((Framework::JSON::JSONObject*)value)->isValueOfType(" ", Framework::JSON::JSONType::ARRAY), L"Framework::JSON::Parser::getValue('{\" \": []}') should contain an array at attribute ' '");
-			value->release();
-		}
-
-		TEST_METHOD(ToStringTest)
-		{
-			Framework::JSON::JSONValue* value = Framework::JSON::Parser::getValue("{\" \": [1, true, false, 0.0, {}], \"t\": null}");
-			Framework::JSON::JSONValue* value2 = Framework::JSON::Parser::getValue(value->toString());
-			Assert::IsTrue(isEqual(value, value2), L"Framework::JSON::Parser::getValue(value.toString()) should return a json value eqal to value");
-			value->release();
-			value2->release();
-		}
-
-		static bool isEqual(Framework::JSON::JSONValue* a, Framework::JSON::JSONValue* b)
-		{
-			if (a->getType() != b->getType()) return 0;
-			switch (a->getType())
-			{
-			case Framework::JSON::JSONType::NUMBER:
-				return ((Framework::JSON::JSONNumber*)a)->getNumber() == ((Framework::JSON::JSONNumber*)b)->getNumber();
-			case Framework::JSON::JSONType::BOOLEAN:
-				return ((Framework::JSON::JSONBool*)a)->getBool() == ((Framework::JSON::JSONBool*)b)->getBool();
-			case Framework::JSON::JSONType::STRING:
-				return ((Framework::JSON::JSONString*)a)->getString().istGleich(((Framework::JSON::JSONString*)b)->getString());
-			case Framework::JSON::JSONType::ARRAY:
-			{
-				Framework::JSON::JSONArray* arrayA = (Framework::JSON::JSONArray*)a;
-				Framework::JSON::JSONArray* arrayB = (Framework::JSON::JSONArray*)b;
-				if (arrayA->getLength() != arrayB->getLength()) return 0;
-				for (int i = 0; i < arrayA->getLength(); i++)
-				{
-					Framework::JSON::JSONValue* entryA = arrayA->getValue(i);
-					Framework::JSON::JSONValue* entryB = arrayB->getValue(i);
-					bool eq = isEqual(entryA, entryB);
-					entryA->release();
-					entryB->release();
-					if (!eq) return 0;
-				}
-				return 1;
-			}
-			case Framework::JSON::JSONType::OBJECT:
-			{
-				Framework::JSON::JSONObject* objA = (Framework::JSON::JSONObject*)a;
-				Framework::JSON::JSONObject* objB = (Framework::JSON::JSONObject*)b;
-				if (objA->getFieldCount() != objB->getFieldCount()) return 0;
-				auto oaf = objA->getFields();
-				while (oaf)
-				{
-					if (!objB->hasValue(oaf)) return 0;
-					Framework::JSON::JSONValue* entryA = objA->getValue(oaf);
-					Framework::JSON::JSONValue* entryB = objB->getValue(oaf);
-					bool eq = isEqual(entryA, entryB);
-					entryA->release();
-					entryB->release();
-					if (!eq) return 0;
-					oaf++;
-				}
-				return 1;
-			}
-			}
-			return 1;
-		}
-
-		TEST_METHOD(ToArrayTest)
-		{
-			Framework::JSON::JSONArray* jArray = Framework::JSON::Parser::getValue("[1,2,3,4,5,6,7,8,9,10]")->asArray();
-			Framework::Array<int>* numberArray = jArray->toArray<int>([](Framework::JSON::JSONValue& v)
-				{
-					return (int)v.asNumber()->getNumber();
-				});
-			Assert::IsTrue(numberArray->getEintragAnzahl() == 10, L"Array hat die falsche Anzahl an elementen");
-			Assert::IsTrue(numberArray->get(2) == 3, L"Array hat mindestens ein falsches element");
-			Assert::IsTrue(numberArray->get(7) == 8, L"Array hat mindestens ein falsches element");
-			numberArray->release();
-			numberArray = jArray->toArray<int>([](Framework::JSON::JSONValue& v)
-				{
-					return (int)v.asNumber()->getNumber() % 2 == 0;
-				}, [](Framework::JSON::JSONValue& v)
-				{
-					return (int)v.asNumber()->getNumber();
-				});
-			Assert::IsTrue(numberArray->get(0) == 2, L"Array hat mindestens ein falsches element");
-			Assert::IsTrue(numberArray->get(3) == 8, L"Array hat mindestens ein falsches element");
-			jArray->release();
-		}
-
-		TEST_METHOD(ToRCArrayTest)
-		{
-			Framework::JSON::JSONArray* jArray = Framework::JSON::Parser::getValue("[\"1\",\"2\",\"3\",\"4\",\"5\"]")->asArray();
-			Framework::RCArray<Framework::Text>* numberArray = jArray->toRCArray<Framework::Text>([](Framework::JSON::JSONValue& v)
-				{
-					return new Framework::Text(v.asString()->getString());
-				});
-			Assert::IsTrue(numberArray->getEintragAnzahl() == 5, L"Array hat die falsche Anzahl an elementen");
-			Assert::IsTrue(numberArray->z(1)->istGleich("2"), L"Array hat mindestens ein falsches element");
-			Assert::IsTrue(numberArray->z(4)->istGleich("5"), L"Array hat mindestens ein falsches element");
-			numberArray->release();
-			numberArray = jArray->toRCArray<Framework::Text>([](Framework::JSON::JSONValue& v)
-				{
-					return (int)v.asString()->getString() % 2 == 0;
-				}, [](Framework::JSON::JSONValue& v)
-				{
-					return new Framework::Text(v.asString()->getString());
-				});
-			Assert::IsTrue(numberArray->z(0)->istGleich("2"), L"Array hat mindestens ein falsches element");
-			Assert::IsTrue(numberArray->z(1)->istGleich("4"), L"Array hat mindestens ein falsches element");
-			jArray->release();
-		}
-
-		class TestObject
-		{
-		public:
-			Framework::Text name;
-			Framework::Text value;
-		};
-
-		TEST_METHOD(ParseObjectTest)
-		{
-			Framework::JSON::JSONObject* jObj = Framework::JSON::Parser::getValue("{\"name\": \"test\", \"value\": \"1234\"}")->asObject();
-			TestObject* obj = jObj->parseTo<TestObject>(new TestObject(), [](TestObject* obj, Framework::Text attrName, Framework::JSON::JSONValue& v)
-				{
-					if (attrName.istGleich("name"))
-					{
-						obj->name = v.asString()->getString();
-					}
-					else
-					{
-						obj->value = v.asString()->getString();
-					}
-				});
-			Assert::IsTrue(obj->name.istGleich("test"), L"Feld hat falschen wert");
-			Assert::IsTrue(obj->value.istGleich("1234"), L"Feld hat falschen wert");
-			delete obj;
-			jObj->release();
-		}
-
-		TEST_METHOD(FromArrayTest)
-		{
-			Framework::Array<int> arr;
-			arr.add(1);
-			arr.add(2);
-			arr.add(3);
-			arr.add(4);
-
-			Framework::JSON::JSONArray* jArray = Framework::JSON::JSONArray::fromArray<int>(arr, [](int v)
-				{
-					return new Framework::JSON::JSONNumber(v);
-				});
-			Assert::IsTrue(jArray->getLength() == 4, L"Array hat falsche länge");
-			Framework::JSON::JSONNumber* n = jArray->getValue(1)->asNumber();
-			Assert::IsTrue(n->getNumber() == 2, L"Array hat mindestens einen falschen Wert");
-			n->release();
-			jArray->release();
-
-			Framework::RCArray<Framework::Text> rcArr;
-			rcArr.add(new Framework::Text("1"));
-			rcArr.add(new Framework::Text("2"));
-			rcArr.add(new Framework::Text("3"));
-			rcArr.add(new Framework::Text("4"));
-
-			jArray = Framework::JSON::JSONArray::fromRCArray<Framework::Text>(rcArr, [](Framework::Text& v)
-				{
-					return new Framework::JSON::JSONString(v);
-				});
-			Assert::IsTrue(jArray->getLength() == 4, L"Array hat falsche länge");
-			Framework::JSON::JSONString* s = jArray->getValue(2)->asString();
-			Assert::IsTrue(s->getString().istGleich("3"), L"Array hat mindestens einen falschen Wert");
-			s->release();
-			jArray->release();
-		}
-	};
-
-	TEST_CLASS(JSONValidatorTests)
-	{
-	private:
-		static OutputDebugStringBuf<char, std::char_traits<char>> charDebugOutput;
-		static std::streambuf* buf;
-
-	public:
-		TEST_CLASS_INITIALIZE(Init)
-		{
-			buf = std::cout.rdbuf();
-			std::cout.rdbuf(&charDebugOutput);
-		}
-		TEST_METHOD(ValidTest)
-		{
-			Framework::JSON::Validator::JSONValidator* validator = Framework::JSON::Validator::JSONValidator::buildForArray()->
-				addAcceptedObjectInArray()->
-				withRequiredNumber("x")->
-				whichIsLessThen(5)->
-				finishNumber()->
-				withRequiredBool("bla")->
-				whichIsOptional()->
-				withDefault(true)->
-				finishBool()->
-				finishObject()->finishArray();
-			Framework::JSON::JSONArray* jArray = Framework::JSON::Parser::getValue("[{\"x\": 4, \"bla\": false}]")->asArray();
-			Assert::IsTrue(validator->isValid(jArray), L"A valid json Array was marked as invalid by the validator");
-			validator->release();
-		}
-
-		TEST_METHOD(ComplexTest)
-		{
-			Framework::JSON::Validator::JSONValidator* validator = Framework::JSON::Validator::JSONValidator::buildForArray()->typeSpecifiedByAttribute("type")->addAcceptedObjectInArray()->withRequiredString("type")->withExactMatch("shaped")->finishString()->withRequiredString("group")->finishString()->withRequiredNumber("width")->whichIsGreaterThen(0)->finishNumber()->withRequiredNumber("height")->whichIsGreaterThen(0)->finishNumber()->withRequiredArray("inputs")->addAcceptedObjectInArray()->withRequiredNumber("x")->whichIsGreaterOrEqual(0)->finishNumber()->withRequiredNumber("y")->whichIsGreaterOrEqual(0)->finishNumber()->withRequiredObject("filter")->withRequiredString("itemType")->finishString()->finishObject()->finishObject()->finishArray()->withRequiredObject("output")->withRequiredString("itemType")->finishString()->finishObject()->withRequiredNumber("outputCount")->whichIsGreaterThen(0)->finishNumber()->finishObject()->addAcceptedObjectInArray()->withRequiredString("type")->withExactMatch("unordered")->finishString()->withRequiredString("group")->finishString()->withRequiredArray("inputs")->addAcceptedObjectInArray()->withRequiredNumber("count")->whichIsGreaterThen(0)->finishNumber()->withRequiredObject("filter")->withRequiredString("itemType")->finishString()->finishObject()->finishObject()->finishArray()->withRequiredArray("output")->addAcceptedObjectInArray()->withRequiredObject("filter")->withRequiredString("itemType")->finishString()->finishObject()->withRequiredNumber("count")->whichIsGreaterThen(0)->finishNumber()->finishObject()->finishArray()->finishObject()->finishArray();
-			std::cout << validator->zConstraints()->toString().getText() << "\n";
-			Framework::JSON::JSONValue* value = Framework::JSON::Parser::getValue("[{\"type\": \"shaped\",\"group\": \"inventory\",\"width\": 1,\"height\": 2,\"inputs\": [{\"x\": 0,\"y\": 0,\"filter\": {\"itemType\": \"Cobble\"}},{\"x\": 0,\"y\": -1,\"filter\": {\"itemType\": \"Cobble\"}}],\"output\": {\"itemType\": \"StoneTool\"},\"outputCount\": 1},{\"type\": \"shaped\",\"group\": \"inventory\",\"width\": 1,\"height\": 2,\"inputs\": [{\"x\": 0,\"y\": 0,\"filter\": {\"itemType\": \"Cobble\"}},{\"x\": 0,\"y\": 1,\"filter\": {\"itemType\": \"Cobble\"}}],\"output\": {\"itemType\": \"StoneTool\"},\"outputCount\": 1}]");
-			std::cout << value->toString().getText() << "\n";
-			Framework::JSON::Validator::JSONValidationResult* result = validator->validate(value);
-			result->printInvalidInfo();
-			Assert::IsTrue(!result->isValid(), L"Invalid Json was marked as valid");
-			Framework::JSON::JSONValue* validValue = result->getValidPart();
-			result->release();
-			Assert::IsTrue(validValue == 0, L"getValidPart of invalid validation result without removeInvalidEntries or default values used in validation should return 0");
-			value->release();
-			validator->release();
-		}
-
-		TEST_METHOD(ComplexRemoveInvalidTest)
-		{
-			Framework::JSON::Validator::JSONValidator* validator = Framework::JSON::Validator::JSONValidator::buildForArray()->removeInvalidEntries()->typeSpecifiedByAttribute("type")->addAcceptedObjectInArray()->withRequiredString("type")->withExactMatch("shaped")->finishString()->withRequiredString("group")->finishString()->withRequiredNumber("width")->whichIsGreaterThen(0)->finishNumber()->withRequiredNumber("height")->whichIsGreaterThen(0)->finishNumber()->withRequiredArray("inputs")->addAcceptedObjectInArray()->withRequiredNumber("x")->whichIsGreaterOrEqual(0)->finishNumber()->withRequiredNumber("y")->whichIsGreaterOrEqual(0)->finishNumber()->withRequiredObject("filter")->withRequiredString("itemType")->finishString()->finishObject()->finishObject()->finishArray()->withRequiredObject("output")->withRequiredString("itemType")->finishString()->finishObject()->withRequiredNumber("outputCount")->whichIsGreaterThen(0)->finishNumber()->finishObject()->addAcceptedObjectInArray()->withRequiredString("type")->withExactMatch("unordered")->finishString()->withRequiredString("group")->finishString()->withRequiredArray("inputs")->addAcceptedObjectInArray()->withRequiredNumber("count")->whichIsGreaterThen(0)->finishNumber()->withRequiredObject("filter")->withRequiredString("itemType")->finishString()->finishObject()->finishObject()->finishArray()->withRequiredArray("output")->addAcceptedObjectInArray()->withRequiredObject("filter")->withRequiredString("itemType")->finishString()->finishObject()->withRequiredNumber("count")->whichIsGreaterThen(0)->finishNumber()->finishObject()->finishArray()->finishObject()->finishArray();
-			std::cout << validator->zConstraints()->toString().getText() << "\n";
-			Framework::JSON::JSONValue* value = Framework::JSON::Parser::getValue("[{\"type\": \"shaped\",\"group\": \"inventory\",\"width\": 1,\"height\": 2,\"inputs\": [{\"x\": 0,\"y\": 0,\"filter\": {\"itemType\": \"Cobble\"}},{\"x\": 0,\"y\": -1,\"filter\": {\"itemType\": \"Cobble\"}}],\"output\": {\"itemType\": \"StoneTool\"},\"outputCount\": 1},{\"type\": \"shaped\",\"group\": \"inventory\",\"width\": 1,\"height\": 2,\"inputs\": [{\"x\": 0,\"y\": 0,\"filter\": {\"itemType\": \"Cobble\"}},{\"x\": 0,\"y\": 1,\"filter\": {\"itemType\": \"Cobble\"}}],\"output\": {\"itemType\": \"StoneTool\"},\"outputCount\": 1}]");
-			std::cout << value->toString().getText() << "\n";
-			Framework::JSON::Validator::JSONValidationResult* result = validator->validate(value);
-			result->printInvalidInfo();
-			Assert::IsTrue(!result->isValid(), L"Invalid Json was marked as valid");
-			Framework::JSON::JSONValue* validValue = result->getValidPart();
-			result->release();
-			Framework::JSON::JSONValue* expected = Framework::JSON::Parser::getValue("[{\"type\": \"shaped\",\"group\": \"inventory\",\"width\": 1,\"height\": 2,\"inputs\": [{\"x\": 0,\"y\": 0,\"filter\": {\"itemType\": \"Cobble\"}},{\"x\": 0,\"y\": 1,\"filter\": {\"itemType\": \"Cobble\"}}],\"output\": {\"itemType\": \"StoneTool\"},\"outputCount\": 1}]");
-			Assert::IsTrue(JSONParserTests::isEqual(validValue, expected), L"getValidPart of invalid validation result does not match the expected valid part");
-			result = validator->validate(validValue);
-			Assert::IsTrue(result->isValid(), L"Re validation of a value returned by getValidPart on a validation result should never return an invalid validation result");
-			value->release();
-			value = result->getValidPart();
-			Assert::IsTrue(JSONParserTests::isEqual(validValue, value), L"getValidPart of a valid validation result should return the validated value");
-			value->release();
-			validValue->release();
-			expected->release();
-			validator->release();
-		}
-
-		TEST_METHOD(DefaultValuesTest)
-		{
-			Framework::JSON::Validator::JSONValidator* validator = Framework::JSON::Validator::JSONValidator::buildForArray()
-				->typeSpecifiedByAttribute("type")
-				->removeInvalidEntries()
-				->addAcceptedTypeInArray(
-					Framework::JSON::Validator::JSONValidator::buildForObject()
-					->withRequiredString("type")->withExactMatch("shaped")->finishString()
-					->withRequiredString("group")->withDefault("test")->finishString()
-					->withRequiredNumber("width")->whichIsGreaterThen(0)->finishNumber()
-					->withRequiredNumber("height")->whichIsGreaterThen(0)->finishNumber()
-					->withRequiredAttribute("inputs",
-						Framework::JSON::Validator::JSONValidator::buildForArray()
-						->withDefault(new Framework::JSON::JSONArray())
-						->addAcceptedTypeInArray(Framework::JSON::Validator::JSONValidator::buildForObject()
-							->withRequiredNumber("x")->whichIsGreaterOrEqual(0)->finishNumber()
-							->withRequiredNumber("y")->whichIsGreaterOrEqual(0)->finishNumber()
-							->withRequiredObject("filter")->withRequiredString("itemType")->finishString()->finishObject()
-							->finishObject())
-						->finishArray())
-					->withRequiredObject("output")->withRequiredString("itemType")->finishString()->finishObject()
-					->withRequiredNumber("outputCount")->withDefault(1)->whichIsGreaterThen(0)->finishNumber()
-					->finishObject())
-				->addAcceptedTypeInArray(
-					Framework::JSON::Validator::JSONValidator::buildForObject()
-					->withRequiredString("type")->withExactMatch("unordered")->finishString()
-					->withRequiredString("group")->finishString()
-					->withRequiredAttribute("inputs",
-						Framework::JSON::Validator::JSONValidator::buildForArray()
-						->withDefault(new Framework::JSON::JSONArray())
-						->addAcceptedTypeInArray(
-							Framework::JSON::Validator::JSONValidator::buildForObject()
-							->withRequiredNumber("count")->withDefault(1)->whichIsGreaterThen(0)->finishNumber()
-							->withRequiredObject("filter")->withRequiredString("itemType")->finishString()->finishObject()
-							->finishObject())
-						->finishArray())
-					->withRequiredAttribute("output",
-						Framework::JSON::Validator::JSONValidator::buildForArray()
-						->addAcceptedTypeInArray(Framework::JSON::Validator::JSONValidator::buildForObject()
-							->withRequiredObject("filter")->withRequiredString("itemType")->finishString()->finishObject()
-							->withRequiredNumber("count")->withDefault(1)->whichIsGreaterThen(0)->finishNumber()
-							->finishObject())
-						->finishArray())
-					->finishObject())
-				->finishArray();
-			std::cout << validator->zConstraints()->toString().getText() << "\n";
-			Framework::JSON::JSONValue* value = Framework::JSON::Parser::getValue("[{\"type\": \"shaped\",\"width\": 1,\"height\": 2,\"inputs\": [{\"x\": 0,\"y\": 0,\"filter\": {\"itemType\": \"Cobble\"}},{\"x\": 0,\"y\": 1,\"filter\": {\"itemType\": \"Cobble\"}}],\"output\": {\"itemType\": \"StoneTool\"}},{\"type\": \"shaped\",\"width\": 1,\"height\": 2,\"inputs\": [{\"x\": 0,\"y\": 0,\"filter\": {\"itemType\": \"Cobble\"}},{\"x\": 0,\"y\": -1,\"filter\": {\"itemType\": \"Cobble\"}}],\"output\": {\"itemType\": \"StoneTool\"}},{\"type\": \"unordered\",\"group\": \"bla\", \"inputs\": [{\"filter\": {\"itemType\": \"Cobble\"}},{\"filter\": {\"itemType\": \"Cobble\"}}],\"output\": [{\"filter\": {\"itemType\": \"StoneTool\"}}]}]");
-			std::cout << value->toString().getText() << "\n";
-			Framework::JSON::Validator::JSONValidationResult* result = validator->validate(value);
-			result->printInvalidInfo();
-			Assert::IsTrue(!result->isValid(), L"Invalid Json was marked as valid");
-			Framework::JSON::JSONValue* validValue = result->getValidPart();
-			result->release();
-			Framework::JSON::JSONValue* expected = Framework::JSON::Parser::getValue("[{\"type\": \"shaped\", \"group\": \"test\",\"width\": 1,\"height\": 2,\"inputs\": [{\"x\": 0,\"y\": 0,\"filter\": {\"itemType\": \"Cobble\"}},{\"x\": 0,\"y\": 1,\"filter\": {\"itemType\": \"Cobble\"}}],\"output\": {\"itemType\": \"StoneTool\"}, \"outputCount\": 1},{\"type\": \"unordered\",\"group\": \"bla\", \"inputs\": [{\"count\": 1, \"filter\": {\"itemType\": \"Cobble\"}},{\"count\": 1, \"filter\": {\"itemType\": \"Cobble\"}}],\"output\": [{\"count\": 1, \"filter\": {\"itemType\": \"StoneTool\"}}]}]");
-			Assert::IsTrue(JSONParserTests::isEqual(validValue, expected), L"getValidPart of invalid validation result does not match the expected valid part");
-			result = validator->validate(validValue);
-			Assert::IsTrue(result->isValid(), L"Re validation of a value returned by getValidPart on a validation result should never return an invalid validation result");
-			value->release();
-			value = result->getValidPart();
-			Assert::IsTrue(JSONParserTests::isEqual(validValue, value), L"getValidPart of a valid validation result should return the validated value");
-			value->release();
-			validValue->release();
-			expected->release();
-			validator->release();
-		}
-
-		TEST_CLASS_CLEANUP(Cleanup)
-		{
-			std::cout.rdbuf(buf);
-		}
-	};
-
-	OutputDebugStringBuf<char, std::char_traits<char>> JSONValidatorTests::charDebugOutput;
-	std::streambuf* JSONValidatorTests::buf;
-}
+    TEST_CLASS(JSONParserTests)
+    {
+    public:
+        TEST_METHOD(NullTest)
+        {
+            Framework::JSON::JSONValue* value
+                = Framework::JSON::Parser::getValue("null");
+            Assert::IsTrue(value != 0,
+                L"Framework::JSON::Parser::getValue('null') should not return "
+                L"0");
+            Assert::IsTrue(value->getType() == Framework::JSON::JSONType::NULL_,
+                L"Framework::JSON::Parser::getValue('null') should return a "
+                L"json null value");
+            value->release();
+        }
+
+        TEST_METHOD(BooleanTest)
+        {
+            Framework::JSON::JSONValue* value
+                = Framework::JSON::Parser::getValue("false");
+            Assert::IsTrue(value != 0,
+                L"Framework::JSON::Parser::getValue('false') should not return "
+                L"0");
+            Assert::IsTrue(
+                value->getType() == Framework::JSON::JSONType::BOOLEAN,
+                L"Framework::JSON::Parser::getValue('false') should return a "
+                L"boolean");
+            Assert::IsTrue(
+                ((Framework::JSON::JSONBool*)value)->getBool() == false,
+                L"Framework::JSON::Parser::getValue('false') should return a "
+                L"boolean with value false");
+            value->release();
+
+            value = Framework::JSON::Parser::getValue("true");
+            Assert::IsTrue(value != 0,
+                L"Framework::JSON::Parser::getValue('true') should not return "
+                L"0");
+            Assert::IsTrue(
+                value->getType() == Framework::JSON::JSONType::BOOLEAN,
+                L"Framework::JSON::Parser::getValue('true') should return a "
+                L"boolean");
+            Assert::IsTrue(
+                ((Framework::JSON::JSONBool*)value)->getBool() == true,
+                L"Framework::JSON::Parser::getValue('true') should return a "
+                L"boolean with value true");
+            value->release();
+        }
+
+        TEST_METHOD(StringTest)
+        {
+            Framework::JSON::JSONValue* value
+                = Framework::JSON::Parser::getValue("\"test\"");
+            Assert::IsTrue(value != 0,
+                L"Framework::JSON::Parser::getValue('\"test\"') should not "
+                L"return 0");
+            Assert::IsTrue(
+                value->getType() == Framework::JSON::JSONType::STRING,
+                L"Framework::JSON::Parser::getValue('\"test\"') should return "
+                L"a string");
+            Assert::IsTrue(((Framework::JSON::JSONString*)value)
+                               ->getString()
+                               .istGleich("test"),
+                L"Framework::JSON::Parser::getValue('\"test\"') should return "
+                L"a string with value 'test'");
+            value->release();
+
+            value = Framework::JSON::Parser::getValue("\"\"");
+            Assert::IsTrue(value != 0,
+                L"Framework::JSON::Parser::getValue('\"\"') should not return "
+                L"0");
+            Assert::IsTrue(
+                value->getType() == Framework::JSON::JSONType::STRING,
+                L"Framework::JSON::Parser::getValue('\"\"') should return a "
+                L"string");
+            Assert::IsTrue(((Framework::JSON::JSONString*)value)
+                               ->getString()
+                               .istGleich(""),
+                L"Framework::JSON::Parser::getValue('\"\"') should return a "
+                L"string with value ''");
+            value->release();
+        }
+
+        TEST_METHOD(NumberTest)
+        {
+            Framework::JSON::JSONValue* value
+                = Framework::JSON::Parser::getValue("0");
+            Assert::IsTrue(value != 0,
+                L"Framework::JSON::Parser::getValue('0') should not return 0");
+            Assert::IsTrue(
+                value->getType() == Framework::JSON::JSONType::NUMBER,
+                L"Framework::JSON::Parser::getValue('0') should return a "
+                L"number");
+            Assert::IsTrue(
+                ((Framework::JSON::JSONNumber*)value)->getNumber() == 0.0,
+                L"Framework::JSON::Parser::getValue('0') should return a "
+                L"number with value '0'");
+            value->release();
+
+            value = Framework::JSON::Parser::getValue("1.5");
+            Assert::IsTrue(value != 0,
+                L"Framework::JSON::Parser::getValue('1.5') should not return "
+                L"0");
+            Assert::IsTrue(
+                value->getType() == Framework::JSON::JSONType::NUMBER,
+                L"Framework::JSON::Parser::getValue('1.5') should return a "
+                L"number");
+            Assert::IsTrue(
+                ((Framework::JSON::JSONNumber*)value)->getNumber() == 1.5,
+                L"Framework::JSON::Parser::getValue('1.5') should return a "
+                L"number with value '1.5'");
+            value->release();
+
+            value = Framework::JSON::Parser::getValue("-1.5");
+            Assert::IsTrue(value != 0,
+                L"Framework::JSON::Parser::getValue('-1.5') should not return "
+                L"0");
+            Assert::IsTrue(
+                value->getType() == Framework::JSON::JSONType::NUMBER,
+                L"Framework::JSON::Parser::getValue('-1.5') should return a "
+                L"number");
+            Assert::IsTrue(
+                ((Framework::JSON::JSONNumber*)value)->getNumber() == -1.5,
+                L"Framework::JSON::Parser::getValue('-1.5') should return a "
+                L"number with value '-1.5'");
+            value->release();
+
+            value = Framework::JSON::Parser::getValue("-5.0");
+            Assert::IsTrue(value != 0,
+                L"Framework::JSON::Parser::getValue('-5.0') should not return "
+                L"0");
+            Assert::IsTrue(
+                value->getType() == Framework::JSON::JSONType::NUMBER,
+                L"Framework::JSON::Parser::getValue('-5.0') should return a "
+                L"number");
+            Assert::IsTrue(
+                ((Framework::JSON::JSONNumber*)value)->getNumber() == -5.0,
+                L"Framework::JSON::Parser::getValue('-5.0') should return a "
+                L"number with value '-5.0'");
+            value->release();
+        }
+
+        TEST_METHOD(ArrayTest)
+        {
+            Framework::JSON::JSONValue* value
+                = Framework::JSON::Parser::getValue("[]");
+            Assert::IsTrue(value != 0,
+                L"Framework::JSON::Parser::getValue('[]') should not return 0");
+            Assert::IsTrue(value->getType() == Framework::JSON::JSONType::ARRAY,
+                L"Framework::JSON::Parser::getValue('[]') should return an "
+                L"array");
+            Assert::IsTrue(
+                ((Framework::JSON::JSONArray*)value)->getLength() == 0,
+                L"Framework::JSON::Parser::getValue('[]') should return an "
+                L"array with length 0");
+            value->release();
+
+            value = Framework::JSON::Parser::getValue(
+                "  \t[ \r\n\tnull   , \r\n\t  1,true , \"\"  ] ");
+            Assert::IsTrue(value != 0,
+                L"Framework::JSON::Parser::getValue('[null, 1, true, \"\"]') "
+                L"should not return 0");
+            Assert::IsTrue(value->getType() == Framework::JSON::JSONType::ARRAY,
+                L"Framework::JSON::Parser::getValue('[null, 1, true, \"\"]') "
+                L"should return an array");
+            Assert::IsTrue(
+                ((Framework::JSON::JSONArray*)value)->getLength() == 4,
+                L"Framework::JSON::Parser::getValue('[null, 1, true, \"\"]') "
+                L"should return an array with length 4");
+            Assert::IsTrue(
+                ((Framework::JSON::JSONArray*)value)
+                    ->isValueOfType(0, Framework::JSON::JSONType::NULL_),
+                L"Framework::JSON::Parser::getValue('[null, 1, true, \"\"]') "
+                L"should contain null at index 0");
+            Assert::IsTrue(
+                ((Framework::JSON::JSONArray*)value)
+                    ->isValueOfType(1, Framework::JSON::JSONType::NUMBER),
+                L"Framework::JSON::Parser::getValue('[null, 1, true, \"\"]') "
+                L"should contain a number at index 1");
+            Assert::IsTrue(
+                ((Framework::JSON::JSONArray*)value)
+                    ->isValueOfType(2, Framework::JSON::JSONType::BOOLEAN),
+                L"Framework::JSON::Parser::getValue('[null, 1, true, \"\"]') "
+                L"should contain a boolean at index 2");
+            Assert::IsTrue(
+                ((Framework::JSON::JSONArray*)value)
+                    ->isValueOfType(3, Framework::JSON::JSONType::STRING),
+                L"Framework::JSON::Parser::getValue('[null, 1, true, \"\"]') "
+                L"should contain a boolean at index 3");
+            value->release();
+        }
+
+        TEST_METHOD(MultipleArrayTest)
+        {
+            Framework::JSON::JSONValue* value
+                = Framework::JSON::Parser::getValue("[[1],2,[[]]]");
+            Assert::IsTrue(value != 0,
+                L"Framework::JSON::Parser::getValue('[[1],2,[[]]]') should not "
+                L"return 0");
+            Assert::IsTrue(value->getType() == Framework::JSON::JSONType::ARRAY,
+                L"Framework::JSON::Parser::getValue('[[1],2,[[]]]') should "
+                L"return an array");
+            Assert::IsTrue(
+                ((Framework::JSON::JSONArray*)value)->getLength() == 3,
+                L"Framework::JSON::Parser::getValue('[[1],2,[[]]]') should "
+                L"return an array with length 3");
+            Assert::IsTrue(
+                ((Framework::JSON::JSONArray*)value)
+                    ->isValueOfType(0, Framework::JSON::JSONType::ARRAY),
+                L"Framework::JSON::Parser::getValue('[null, 1, true, \"\"]') "
+                L"should contain an array at index 0");
+            Assert::IsTrue(
+                ((Framework::JSON::JSONArray*)value)
+                    ->isValueOfType(1, Framework::JSON::JSONType::NUMBER),
+                L"Framework::JSON::Parser::getValue('[null, 1, true, \"\"]') "
+                L"should contain a number at index 1");
+            Assert::IsTrue(
+                ((Framework::JSON::JSONArray*)value)
+                    ->isValueOfType(2, Framework::JSON::JSONType::ARRAY),
+                L"Framework::JSON::Parser::getValue('[null, 1, true, \"\"]') "
+                L"should contain an array at index 2");
+            value->release();
+        }
+
+        TEST_METHOD(ObjectTest)
+        {
+            Framework::JSON::JSONValue* value
+                = Framework::JSON::Parser::getValue("{\" \": []}");
+            Assert::IsTrue(value != 0,
+                L"Framework::JSON::Parser::getValue('{\"\": []}') should not "
+                L"return 0");
+            Assert::IsTrue(
+                value->getType() == Framework::JSON::JSONType::OBJECT,
+                L"Framework::JSON::Parser::getValue('{\" \": []}') should "
+                L"return an object");
+            Assert::IsTrue(
+                ((Framework::JSON::JSONObject*)value)->getFieldCount() == 1,
+                L"Framework::JSON::Parser::getValue('{\" \": []}') should "
+                L"return an object with one attribute");
+            Assert::IsTrue(
+                ((Framework::JSON::JSONObject*)value)
+                    ->isValueOfType(" ", Framework::JSON::JSONType::ARRAY),
+                L"Framework::JSON::Parser::getValue('{\" \": []}') should "
+                L"contain an array at attribute ' '");
+            value->release();
+        }
+
+        TEST_METHOD(ToStringTest)
+        {
+            Framework::JSON::JSONValue* value
+                = Framework::JSON::Parser::getValue(
+                    "{\" \": [1, true, false, 0.0, {}], \"t\": null}");
+            Framework::JSON::JSONValue* value2
+                = Framework::JSON::Parser::getValue(value->toString());
+            Assert::IsTrue(isEqual(value, value2),
+                L"Framework::JSON::Parser::getValue(value.toString()) should "
+                L"return a json value eqal to value");
+            value->release();
+            value2->release();
+        }
+
+        static bool isEqual(
+            Framework::JSON::JSONValue * a, Framework::JSON::JSONValue * b)
+        {
+            if (a->getType() != b->getType()) return 0;
+            switch (a->getType())
+            {
+            case Framework::JSON::JSONType::NUMBER:
+                return ((Framework::JSON::JSONNumber*)a)->getNumber()
+                    == ((Framework::JSON::JSONNumber*)b)->getNumber();
+            case Framework::JSON::JSONType::BOOLEAN:
+                return ((Framework::JSON::JSONBool*)a)->getBool()
+                    == ((Framework::JSON::JSONBool*)b)->getBool();
+            case Framework::JSON::JSONType::STRING:
+                return ((Framework::JSON::JSONString*)a)
+                    ->getString()
+                    .istGleich(((Framework::JSON::JSONString*)b)->getString());
+            case Framework::JSON::JSONType::ARRAY:
+                {
+                    Framework::JSON::JSONArray* arrayA
+                        = (Framework::JSON::JSONArray*)a;
+                    Framework::JSON::JSONArray* arrayB
+                        = (Framework::JSON::JSONArray*)b;
+                    if (arrayA->getLength() != arrayB->getLength()) return 0;
+                    for (int i = 0; i < arrayA->getLength(); i++)
+                    {
+                        Framework::JSON::JSONValue* entryA
+                            = arrayA->getValue(i);
+                        Framework::JSON::JSONValue* entryB
+                            = arrayB->getValue(i);
+                        bool eq = isEqual(entryA, entryB);
+                        entryA->release();
+                        entryB->release();
+                        if (!eq) return 0;
+                    }
+                    return 1;
+                }
+            case Framework::JSON::JSONType::OBJECT:
+                {
+                    Framework::JSON::JSONObject* objA
+                        = (Framework::JSON::JSONObject*)a;
+                    Framework::JSON::JSONObject* objB
+                        = (Framework::JSON::JSONObject*)b;
+                    if (objA->getFieldCount() != objB->getFieldCount())
+                        return 0;
+                    auto oaf = objA->getFields();
+                    while (oaf)
+                    {
+                        if (!objB->hasValue(oaf)) return 0;
+                        Framework::JSON::JSONValue* entryA
+                            = objA->getValue(oaf);
+                        Framework::JSON::JSONValue* entryB
+                            = objB->getValue(oaf);
+                        bool eq = isEqual(entryA, entryB);
+                        entryA->release();
+                        entryB->release();
+                        if (!eq) return 0;
+                        oaf++;
+                    }
+                    return 1;
+                }
+            }
+            return 1;
+        }
+
+        TEST_METHOD(ToArrayTest)
+        {
+            Framework::JSON::JSONArray* jArray
+                = Framework::JSON::Parser::getValue("[1,2,3,4,5,6,7,8,9,10]")
+                      ->asArray();
+            Framework::Array<int>* numberArray
+                = jArray->toArray<int>([](Framework::JSON::JSONValue& v) {
+                      return (int)v.asNumber()->getNumber();
+                  });
+            Assert::IsTrue(numberArray->getEintragAnzahl() == 10,
+                L"Array hat die falsche Anzahl an elementen");
+            Assert::IsTrue(numberArray->get(2) == 3,
+                L"Array hat mindestens ein falsches element");
+            Assert::IsTrue(numberArray->get(7) == 8,
+                L"Array hat mindestens ein falsches element");
+            numberArray->release();
+            numberArray = jArray->toArray<int>(
+                [](Framework::JSON::JSONValue& v) {
+                    return (int)v.asNumber()->getNumber() % 2 == 0;
+                },
+                [](Framework::JSON::JSONValue& v) {
+                    return (int)v.asNumber()->getNumber();
+                });
+            Assert::IsTrue(numberArray->get(0) == 2,
+                L"Array hat mindestens ein falsches element");
+            Assert::IsTrue(numberArray->get(3) == 8,
+                L"Array hat mindestens ein falsches element");
+            jArray->release();
+        }
+
+        TEST_METHOD(ToRCArrayTest)
+        {
+            Framework::JSON::JSONArray* jArray
+                = Framework::JSON::Parser::getValue(
+                    "[\"1\",\"2\",\"3\",\"4\",\"5\"]")
+                      ->asArray();
+            Framework::RCArray<Framework::Text>* numberArray
+                = jArray->toRCArray<Framework::Text>(
+                    [](Framework::JSON::JSONValue& v) {
+                        return new Framework::Text(v.asString()->getString());
+                    });
+            Assert::IsTrue(numberArray->getEintragAnzahl() == 5,
+                L"Array hat die falsche Anzahl an elementen");
+            Assert::IsTrue(numberArray->z(1)->istGleich("2"),
+                L"Array hat mindestens ein falsches element");
+            Assert::IsTrue(numberArray->z(4)->istGleich("5"),
+                L"Array hat mindestens ein falsches element");
+            numberArray->release();
+            numberArray = jArray->toRCArray<Framework::Text>(
+                [](Framework::JSON::JSONValue& v) {
+                    return (int)v.asString()->getString() % 2 == 0;
+                },
+                [](Framework::JSON::JSONValue& v) {
+                    return new Framework::Text(v.asString()->getString());
+                });
+            Assert::IsTrue(numberArray->z(0)->istGleich("2"),
+                L"Array hat mindestens ein falsches element");
+            Assert::IsTrue(numberArray->z(1)->istGleich("4"),
+                L"Array hat mindestens ein falsches element");
+            jArray->release();
+        }
+
+        class TestObject
+        {
+        public:
+            Framework::Text name;
+            Framework::Text value;
+        };
+
+        TEST_METHOD(ParseObjectTest)
+        {
+            Framework::JSON::JSONObject* jObj
+                = Framework::JSON::Parser::getValue(
+                    "{\"name\": \"test\", \"value\": \"1234\"}")
+                      ->asObject();
+            TestObject* obj = jObj->parseTo<TestObject>(new TestObject(),
+                [](TestObject* obj,
+                    Framework::Text attrName,
+                    Framework::JSON::JSONValue& v) {
+                    if (attrName.istGleich("name"))
+                    {
+                        obj->name = v.asString()->getString();
+                    }
+                    else
+                    {
+                        obj->value = v.asString()->getString();
+                    }
+                });
+            Assert::IsTrue(
+                obj->name.istGleich("test"), L"Feld hat falschen wert");
+            Assert::IsTrue(
+                obj->value.istGleich("1234"), L"Feld hat falschen wert");
+            delete obj;
+            jObj->release();
+        }
+
+        TEST_METHOD(FromArrayTest)
+        {
+            Framework::Array<int> arr;
+            arr.add(1);
+            arr.add(2);
+            arr.add(3);
+            arr.add(4);
+
+            Framework::JSON::JSONArray* jArray
+                = Framework::JSON::JSONArray::fromArray<int>(arr,
+                    [](int v) { return new Framework::JSON::JSONNumber(v); });
+            Assert::IsTrue(
+                jArray->getLength() == 4, L"Array hat falsche länge");
+            Framework::JSON::JSONNumber* n = jArray->getValue(1)->asNumber();
+            Assert::IsTrue(n->getNumber() == 2,
+                L"Array hat mindestens einen falschen Wert");
+            n->release();
+            jArray->release();
+
+            Framework::RCArray<Framework::Text> rcArr;
+            rcArr.add(new Framework::Text("1"));
+            rcArr.add(new Framework::Text("2"));
+            rcArr.add(new Framework::Text("3"));
+            rcArr.add(new Framework::Text("4"));
+
+            jArray = Framework::JSON::JSONArray::fromRCArray<Framework::Text>(
+                rcArr, [](Framework::Text& v) {
+                    return new Framework::JSON::JSONString(v);
+                });
+            Assert::IsTrue(
+                jArray->getLength() == 4, L"Array hat falsche länge");
+            Framework::JSON::JSONString* s = jArray->getValue(2)->asString();
+            Assert::IsTrue(s->getString().istGleich("3"),
+                L"Array hat mindestens einen falschen Wert");
+            s->release();
+            jArray->release();
+        }
+    };
+
+    TEST_CLASS(JSONValidatorTests)
+    {
+    private:
+        static OutputDebugStringBuf<char, std::char_traits<char>>
+            charDebugOutput;
+        static std::streambuf* buf;
+
+    public:
+        TEST_CLASS_INITIALIZE(Init)
+        {
+            buf = std::cout.rdbuf();
+            std::cout.rdbuf(&charDebugOutput);
+        }
+
+        TEST_METHOD(ValidTest)
+        {
+            Framework::JSON::Validator::JSONValidator* validator
+                = Framework::JSON::Validator::JSONValidator::buildForArray()
+                      ->addAcceptedObjectInArray()
+                      ->withRequiredNumber("x")
+                      ->whichIsLessThen(5)
+                      ->finishNumber()
+                      ->withRequiredBool("bla")
+                      ->whichIsOptional()
+                      ->withDefault(true)
+                      ->finishBool()
+                      ->finishObject()
+                      ->finishArray();
+            Framework::JSON::JSONArray* jArray
+                = Framework::JSON::Parser::getValue(
+                    "[{\"x\": 4, \"bla\": false}]")
+                      ->asArray();
+            Assert::IsTrue(validator->isValid(jArray),
+                L"A valid json Array was marked as invalid by the validator");
+            validator->release();
+        }
+
+        TEST_METHOD(ComplexTest)
+        {
+            Framework::JSON::Validator::JSONValidator* validator
+                = Framework::JSON::Validator::JSONValidator::buildForArray()
+                      ->typeSpecifiedByAttribute("type")
+                      ->addAcceptedObjectInArray()
+                      ->withRequiredString("type")
+                      ->withExactMatch("shaped")
+                      ->finishString()
+                      ->withRequiredString("group")
+                      ->finishString()
+                      ->withRequiredNumber("width")
+                      ->whichIsGreaterThen(0)
+                      ->finishNumber()
+                      ->withRequiredNumber("height")
+                      ->whichIsGreaterThen(0)
+                      ->finishNumber()
+                      ->withRequiredArray("inputs")
+                      ->addAcceptedObjectInArray()
+                      ->withRequiredNumber("x")
+                      ->whichIsGreaterOrEqual(0)
+                      ->finishNumber()
+                      ->withRequiredNumber("y")
+                      ->whichIsGreaterOrEqual(0)
+                      ->finishNumber()
+                      ->withRequiredObject("filter")
+                      ->withRequiredString("itemType")
+                      ->finishString()
+                      ->finishObject()
+                      ->finishObject()
+                      ->finishArray()
+                      ->withRequiredObject("output")
+                      ->withRequiredString("itemType")
+                      ->finishString()
+                      ->finishObject()
+                      ->withRequiredNumber("outputCount")
+                      ->whichIsGreaterThen(0)
+                      ->finishNumber()
+                      ->finishObject()
+                      ->addAcceptedObjectInArray()
+                      ->withRequiredString("type")
+                      ->withExactMatch("unordered")
+                      ->finishString()
+                      ->withRequiredString("group")
+                      ->finishString()
+                      ->withRequiredArray("inputs")
+                      ->addAcceptedObjectInArray()
+                      ->withRequiredNumber("count")
+                      ->whichIsGreaterThen(0)
+                      ->finishNumber()
+                      ->withRequiredObject("filter")
+                      ->withRequiredString("itemType")
+                      ->finishString()
+                      ->finishObject()
+                      ->finishObject()
+                      ->finishArray()
+                      ->withRequiredArray("output")
+                      ->addAcceptedObjectInArray()
+                      ->withRequiredObject("filter")
+                      ->withRequiredString("itemType")
+                      ->finishString()
+                      ->finishObject()
+                      ->withRequiredNumber("count")
+                      ->whichIsGreaterThen(0)
+                      ->finishNumber()
+                      ->finishObject()
+                      ->finishArray()
+                      ->finishObject()
+                      ->finishArray();
+            std::cout << validator->zConstraints()->toString().getText()
+                      << "\n";
+            Framework::JSON::JSONValue* value
+                = Framework::JSON::Parser::getValue(
+                    "[{\"type\": \"shaped\",\"group\": "
+                    "\"inventory\",\"width\": 1,\"height\": 2,\"inputs\": "
+                    "[{\"x\": 0,\"y\": 0,\"filter\": {\"itemType\": "
+                    "\"Cobble\"}},{\"x\": 0,\"y\": -1,\"filter\": "
+                    "{\"itemType\": \"Cobble\"}}],\"output\": {\"itemType\": "
+                    "\"StoneTool\"},\"outputCount\": 1},{\"type\": "
+                    "\"shaped\",\"group\": \"inventory\",\"width\": "
+                    "1,\"height\": 2,\"inputs\": [{\"x\": 0,\"y\": "
+                    "0,\"filter\": {\"itemType\": \"Cobble\"}},{\"x\": "
+                    "0,\"y\": 1,\"filter\": {\"itemType\": "
+                    "\"Cobble\"}}],\"output\": {\"itemType\": "
+                    "\"StoneTool\"},\"outputCount\": 1}]");
+            std::cout << value->toString().getText() << "\n";
+            Framework::JSON::Validator::JSONValidationResult* result
+                = validator->validate(value);
+            result->printInvalidInfo();
+            Assert::IsTrue(
+                !result->isValid(), L"Invalid Json was marked as valid");
+            Framework::JSON::JSONValue* validValue = result->getValidPart();
+            result->release();
+            Assert::IsTrue(validValue == 0,
+                L"getValidPart of invalid validation result without "
+                L"removeInvalidEntries or default values used in validation "
+                L"should return 0");
+            value->release();
+            validator->release();
+        }
+
+        TEST_METHOD(ComplexRemoveInvalidTest)
+        {
+            Framework::JSON::Validator::JSONValidator* validator
+                = Framework::JSON::Validator::JSONValidator::buildForArray()
+                      ->removeInvalidEntries()
+                      ->typeSpecifiedByAttribute("type")
+                      ->addAcceptedObjectInArray()
+                      ->withRequiredString("type")
+                      ->withExactMatch("shaped")
+                      ->finishString()
+                      ->withRequiredString("group")
+                      ->finishString()
+                      ->withRequiredNumber("width")
+                      ->whichIsGreaterThen(0)
+                      ->finishNumber()
+                      ->withRequiredNumber("height")
+                      ->whichIsGreaterThen(0)
+                      ->finishNumber()
+                      ->withRequiredArray("inputs")
+                      ->addAcceptedObjectInArray()
+                      ->withRequiredNumber("x")
+                      ->whichIsGreaterOrEqual(0)
+                      ->finishNumber()
+                      ->withRequiredNumber("y")
+                      ->whichIsGreaterOrEqual(0)
+                      ->finishNumber()
+                      ->withRequiredObject("filter")
+                      ->withRequiredString("itemType")
+                      ->finishString()
+                      ->finishObject()
+                      ->finishObject()
+                      ->finishArray()
+                      ->withRequiredObject("output")
+                      ->withRequiredString("itemType")
+                      ->finishString()
+                      ->finishObject()
+                      ->withRequiredNumber("outputCount")
+                      ->whichIsGreaterThen(0)
+                      ->finishNumber()
+                      ->finishObject()
+                      ->addAcceptedObjectInArray()
+                      ->withRequiredString("type")
+                      ->withExactMatch("unordered")
+                      ->finishString()
+                      ->withRequiredString("group")
+                      ->finishString()
+                      ->withRequiredArray("inputs")
+                      ->addAcceptedObjectInArray()
+                      ->withRequiredNumber("count")
+                      ->whichIsGreaterThen(0)
+                      ->finishNumber()
+                      ->withRequiredObject("filter")
+                      ->withRequiredString("itemType")
+                      ->finishString()
+                      ->finishObject()
+                      ->finishObject()
+                      ->finishArray()
+                      ->withRequiredArray("output")
+                      ->addAcceptedObjectInArray()
+                      ->withRequiredObject("filter")
+                      ->withRequiredString("itemType")
+                      ->finishString()
+                      ->finishObject()
+                      ->withRequiredNumber("count")
+                      ->whichIsGreaterThen(0)
+                      ->finishNumber()
+                      ->finishObject()
+                      ->finishArray()
+                      ->finishObject()
+                      ->finishArray();
+            std::cout << validator->zConstraints()->toString().getText()
+                      << "\n";
+            Framework::JSON::JSONValue* value
+                = Framework::JSON::Parser::getValue(
+                    "[{\"type\": \"shaped\",\"group\": "
+                    "\"inventory\",\"width\": 1,\"height\": 2,\"inputs\": "
+                    "[{\"x\": 0,\"y\": 0,\"filter\": {\"itemType\": "
+                    "\"Cobble\"}},{\"x\": 0,\"y\": -1,\"filter\": "
+                    "{\"itemType\": \"Cobble\"}}],\"output\": {\"itemType\": "
+                    "\"StoneTool\"},\"outputCount\": 1},{\"type\": "
+                    "\"shaped\",\"group\": \"inventory\",\"width\": "
+                    "1,\"height\": 2,\"inputs\": [{\"x\": 0,\"y\": "
+                    "0,\"filter\": {\"itemType\": \"Cobble\"}},{\"x\": "
+                    "0,\"y\": 1,\"filter\": {\"itemType\": "
+                    "\"Cobble\"}}],\"output\": {\"itemType\": "
+                    "\"StoneTool\"},\"outputCount\": 1}]");
+            std::cout << value->toString().getText() << "\n";
+            Framework::JSON::Validator::JSONValidationResult* result
+                = validator->validate(value);
+            result->printInvalidInfo();
+            Assert::IsTrue(
+                !result->isValid(), L"Invalid Json was marked as valid");
+            Framework::JSON::JSONValue* validValue = result->getValidPart();
+            result->release();
+            Framework::JSON::JSONValue* expected
+                = Framework::JSON::Parser::getValue(
+                    "[{\"type\": \"shaped\",\"group\": "
+                    "\"inventory\",\"width\": 1,\"height\": 2,\"inputs\": "
+                    "[{\"x\": 0,\"y\": 0,\"filter\": {\"itemType\": "
+                    "\"Cobble\"}},{\"x\": 0,\"y\": 1,\"filter\": "
+                    "{\"itemType\": \"Cobble\"}}],\"output\": {\"itemType\": "
+                    "\"StoneTool\"},\"outputCount\": 1}]");
+            Assert::IsTrue(JSONParserTests::isEqual(validValue, expected),
+                L"getValidPart of invalid validation result does not match the "
+                L"expected valid part");
+            result = validator->validate(validValue);
+            Assert::IsTrue(result->isValid(),
+                L"Re validation of a value returned by getValidPart on a "
+                L"validation result should never return an invalid validation "
+                L"result");
+            value->release();
+            value = result->getValidPart();
+            Assert::IsTrue(JSONParserTests::isEqual(validValue, value),
+                L"getValidPart of a valid validation result should return the "
+                L"validated value");
+            value->release();
+            validValue->release();
+            expected->release();
+            validator->release();
+        }
+
+        TEST_METHOD(DefaultValuesTest)
+        {
+            Framework::JSON::Validator::JSONValidator* validator
+                = Framework::JSON::Validator::JSONValidator::buildForArray()
+                      ->typeSpecifiedByAttribute("type")
+                      ->removeInvalidEntries()
+                      ->addAcceptedTypeInArray(
+                          Framework::JSON::Validator::JSONValidator::buildForObject()
+                              ->withRequiredString("type")
+                              ->withExactMatch("shaped")
+                              ->finishString()
+                              ->withRequiredString("group")
+                              ->withDefault("test")
+                              ->finishString()
+                              ->withRequiredNumber("width")
+                              ->whichIsGreaterThen(0)
+                              ->finishNumber()
+                              ->withRequiredNumber("height")
+                              ->whichIsGreaterThen(0)
+                              ->finishNumber()
+                              ->withRequiredAttribute("inputs",
+                                  Framework::JSON::Validator::JSONValidator::
+                                      buildForArray()
+                                          ->withDefault(
+                                              new Framework::JSON::JSONArray())
+                                          ->addAcceptedTypeInArray(
+                                              Framework::JSON::Validator::
+                                                  JSONValidator::buildForObject()
+                                                      ->withRequiredNumber("x")
+                                                      ->whichIsGreaterOrEqual(0)
+                                                      ->finishNumber()
+                                                      ->withRequiredNumber("y")
+                                                      ->whichIsGreaterOrEqual(0)
+                                                      ->finishNumber()
+                                                      ->withRequiredObject(
+                                                          "filter")
+                                                      ->withRequiredString(
+                                                          "itemType")
+                                                      ->finishString()
+                                                      ->finishObject()
+                                                      ->finishObject())
+                                          ->finishArray())
+                              ->withRequiredObject("output")
+                              ->withRequiredString("itemType")
+                              ->finishString()
+                              ->finishObject()
+                              ->withRequiredNumber("outputCount")
+                              ->withDefault(1)
+                              ->whichIsGreaterThen(0)
+                              ->finishNumber()
+                              ->finishObject())
+                      ->addAcceptedTypeInArray(
+                          Framework::JSON::Validator::JSONValidator::buildForObject()
+                              ->withRequiredString("type")
+                              ->withExactMatch("unordered")
+                              ->finishString()
+                              ->withRequiredString("group")
+                              ->finishString()
+                              ->withRequiredAttribute("inputs",
+                                  Framework::JSON::Validator::JSONValidator::
+                                      buildForArray()
+                                          ->withDefault(
+                                              new Framework::JSON::JSONArray())
+                                          ->addAcceptedTypeInArray(
+                                              Framework::JSON::Validator::
+                                                  JSONValidator::
+                                                      buildForObject()
+                                                          ->withRequiredNumber(
+                                                              "count")
+                                                          ->withDefault(1)
+                                                          ->whichIsGreaterThen(
+                                                              0)
+                                                          ->finishNumber()
+                                                          ->withRequiredObject(
+                                                              "filter")
+                                                          ->withRequiredString(
+                                                              "itemType")
+                                                          ->finishString()
+                                                          ->finishObject()
+                                                          ->finishObject())
+                                          ->finishArray())
+                              ->withRequiredAttribute("output",
+                                  Framework::JSON::Validator::JSONValidator::
+                                      buildForArray()
+                                          ->addAcceptedTypeInArray(
+                                              Framework::JSON::Validator::
+                                                  JSONValidator::
+                                                      buildForObject()
+                                                          ->withRequiredObject(
+                                                              "filter")
+                                                          ->withRequiredString(
+                                                              "itemType")
+                                                          ->finishString()
+                                                          ->finishObject()
+                                                          ->withRequiredNumber(
+                                                              "count")
+                                                          ->withDefault(1)
+                                                          ->whichIsGreaterThen(
+                                                              0)
+                                                          ->finishNumber()
+                                                          ->finishObject())
+                                          ->finishArray())
+                              ->finishObject())
+                      ->finishArray();
+            std::cout << validator->zConstraints()->toString().getText()
+                      << "\n";
+            Framework::JSON::JSONValue* value
+                = Framework::JSON::Parser::getValue(
+                    "[{\"type\": \"shaped\",\"width\": 1,\"height\": "
+                    "2,\"inputs\": [{\"x\": 0,\"y\": 0,\"filter\": "
+                    "{\"itemType\": \"Cobble\"}},{\"x\": 0,\"y\": "
+                    "1,\"filter\": {\"itemType\": \"Cobble\"}}],\"output\": "
+                    "{\"itemType\": \"StoneTool\"}},{\"type\": "
+                    "\"shaped\",\"width\": 1,\"height\": 2,\"inputs\": "
+                    "[{\"x\": 0,\"y\": 0,\"filter\": {\"itemType\": "
+                    "\"Cobble\"}},{\"x\": 0,\"y\": -1,\"filter\": "
+                    "{\"itemType\": \"Cobble\"}}],\"output\": {\"itemType\": "
+                    "\"StoneTool\"}},{\"type\": \"unordered\",\"group\": "
+                    "\"bla\", \"inputs\": [{\"filter\": {\"itemType\": "
+                    "\"Cobble\"}},{\"filter\": {\"itemType\": "
+                    "\"Cobble\"}}],\"output\": [{\"filter\": {\"itemType\": "
+                    "\"StoneTool\"}}]}]");
+            std::cout << value->toString().getText() << "\n";
+            Framework::JSON::Validator::JSONValidationResult* result
+                = validator->validate(value);
+            result->printInvalidInfo();
+            Assert::IsTrue(
+                !result->isValid(), L"Invalid Json was marked as valid");
+            Framework::JSON::JSONValue* validValue = result->getValidPart();
+            result->release();
+            Framework::JSON::JSONValue* expected
+                = Framework::JSON::Parser::getValue(
+                    "[{\"type\": \"shaped\", \"group\": \"test\",\"width\": "
+                    "1,\"height\": 2,\"inputs\": [{\"x\": 0,\"y\": "
+                    "0,\"filter\": {\"itemType\": \"Cobble\"}},{\"x\": "
+                    "0,\"y\": 1,\"filter\": {\"itemType\": "
+                    "\"Cobble\"}}],\"output\": {\"itemType\": \"StoneTool\"}, "
+                    "\"outputCount\": 1},{\"type\": \"unordered\",\"group\": "
+                    "\"bla\", \"inputs\": [{\"count\": 1, \"filter\": "
+                    "{\"itemType\": \"Cobble\"}},{\"count\": 1, \"filter\": "
+                    "{\"itemType\": \"Cobble\"}}],\"output\": [{\"count\": 1, "
+                    "\"filter\": {\"itemType\": \"StoneTool\"}}]}]");
+            Assert::IsTrue(JSONParserTests::isEqual(validValue, expected),
+                L"getValidPart of invalid validation result does not match the "
+                L"expected valid part");
+            result = validator->validate(validValue);
+            Assert::IsTrue(result->isValid(),
+                L"Re validation of a value returned by getValidPart on a "
+                L"validation result should never return an invalid validation "
+                L"result");
+            value->release();
+            value = result->getValidPart();
+            Assert::IsTrue(JSONParserTests::isEqual(validValue, value),
+                L"getValidPart of a valid validation result should return the "
+                L"validated value");
+            value->release();
+            validValue->release();
+            expected->release();
+            validator->release();
+        }
+
+        TEST_METHOD(RecursiveValidatorTest)
+        {
+            Framework::JSON::Validator::JSONValidator* validator
+                = Framework::JSON::Validator::JSONValidator::buildForObject()
+                      ->setObjectReferenceId("TreeNode")
+                      ->withRequiredAttribute("value",
+                          Framework::JSON::Validator::JSONValidator::
+                              buildForString()
+                                  ->whichCanBeNull()
+                                  ->finishString())
+                      ->withRequiredAttribute("children",
+                          Framework::JSON::Validator::JSONValidator::
+                              buildForArray()
+                                  ->whichIsOptional()
+                                  ->addAcceptedTypeInArray(Framework::JSON::
+                                          Validator::JSONValidator::
+                                              buildForObjectReference(
+                                                  "TreeNode"))
+                                  ->finishArray())
+                      ->finishObject();
+            Framework::JSON::JSONObject* jArray
+                = Framework::JSON::Parser::getValue(
+                    "{\"value\": \"1\", \"children\": [{\"value\": \"2\"}, "
+                    "{\"value\": \"3\", \"children\": [{\"value\": \"4\"}]}]}")
+                      ->asObject();
+            Assert::IsTrue(validator->isValid(jArray),
+                L"A valid json Object was marked as invalid by the validator");
+            validator->release();
+        }
+
+        TEST_CLASS_CLEANUP(Cleanup)
+        {
+            std::cout.rdbuf(buf);
+        }
+    };
+
+    OutputDebugStringBuf<char, std::char_traits<char>>
+        JSONValidatorTests::charDebugOutput;
+    std::streambuf* JSONValidatorTests::buf;
+} // namespace FrameworkTests

+ 40 - 13
JSON.cpp

@@ -1336,6 +1336,18 @@ JSONValidationResult* JSONValidator::validate(
         }
         break;
     case JSONType::OBJECT:
+        if (zConstraints->getName().istGleich("objectRef"))
+        {
+            Text id = zConstraints->getAttributeValue("ref");
+            XML::Editor editor = constraints->select()
+                .selectAllElements()
+                .whereNameEquals("object")
+                .whereAttributeEquals("id", id);
+            if (editor.getSize())
+            {
+                zConstraints = editor.begin().val();
+            }
+        }
         if (!zConstraints->getName().istGleich("object"))
         {
             return new JSONTypeMissmatch(path,
@@ -1385,21 +1397,30 @@ JSONValidationResult* JSONValidator::validate(
                         constraint->getAttributeValue("name")))
                 {
                     XML::Editor tmp = constraint->selectChildren();
-                    Text p = path;
-                    p += ".";
-                    p += constraint->getAttributeValue("name");
-                    if (constraint->getChildCount() != 1)
+                    bool optional = true;
+                    tmp.forEach([&optional](XML::Element* zElement) { 
+                        optional &= zElement->hasAttribute("optional")
+                                 && zElement->getAttributeValue("optional")
+                                        .istGleich("true");
+                        });
+                    if (!optional)
+                    {
+                        Text p = path;
+                        p += ".";
+                        p += constraint->getAttributeValue("name");
+                        if (constraint->getChildCount() != 1)
+                            return new JSONTypeMissmatch(path,
+                                dynamic_cast<JSONValue*>(zValue->getThis()),
+                                dynamic_cast<XML::Element*>(
+                                    zConstraints->getThis()),
+                                new JSONMissingOneOf(p, tmp));
                         return new JSONTypeMissmatch(path,
                             dynamic_cast<JSONValue*>(zValue->getThis()),
-                            dynamic_cast<XML::Element*>(
-                                zConstraints->getThis()),
-                            new JSONMissingOneOf(p, tmp));
-                    return new JSONTypeMissmatch(path,
-                        dynamic_cast<JSONValue*>(zValue->getThis()),
-                        dynamic_cast<XML::Element*>(zConstraints->getThis()),
-                        new JSONMissingValue(p,
-                            dynamic_cast<XML::Element*>(
-                                tmp.begin()->getThis())));
+                            dynamic_cast<XML::Element*>(zConstraints->getThis()),
+                            new JSONMissingValue(p,
+                                dynamic_cast<XML::Element*>(
+                                    tmp.begin()->getThis())));
+                    }
                 }
             }
         }
@@ -1522,4 +1543,10 @@ ArrayValidationBuilder<JSONValidator>* JSONValidator::buildForArray()
         [](XML::Element& e) { return new JSONValidator(e.dublicate()); });
 }
 
+JSONValidator* JSONValidator::buildForObjectReference(Text objectId)
+{
+    return new JSONValidator(
+        new XML::Element(Text("<objectRef ref=\"") + objectId + Text("\"/>")));
+}
+
 #pragma endregion Content

+ 8 - 0
JSON.h

@@ -442,6 +442,7 @@ namespace Framework
                     JSONValidator>* buildForObject();
                 __declspec(dllexport) static ArrayValidationBuilder<
                     JSONValidator>* buildForArray();
+                __declspec(dllexport) static JSONValidator* buildForObjectReference(Text objectId);
             };
 
             template<typename T> class StringValidationBuilder
@@ -665,6 +666,13 @@ namespace Framework
                       builder(builder)
                 {}
 
+                ObjectValidationBuilder<T>* setObjectReferenceId(
+                    Text id)
+                {
+                    element.setAttribute("id", id);
+                    return this;
+                }
+
                 NumberValidationBuilder<ObjectValidationBuilder<T>>*
                 withRequiredNumber(Text name)
                 {

+ 1 - 1
UIMLView.cpp

@@ -207,7 +207,7 @@ void UIMLElement::layout(XML::Element& element,
         if (z)
         {
             generalLayouter.layout(*i.val(),
-                *generalLayouter.zZeichnungById(i->getAttributeValue("id")),
+                *z,
                 pWidth,
                 pHeight,
                 generalLayouter);

+ 24 - 0
XML.cpp

@@ -383,6 +383,14 @@ Iterator<Element*> Element::getChilds() const
     return children->begin();
 }
 
+//! gibt einen Editor für dieses Element zurück
+Editor Element::select()
+{
+    RCArray<Element>* tmp = new RCArray<Element>();
+    tmp->add(dynamic_cast<XML::Element*>(getThis()));
+    return Editor(tmp);
+}
+
 // gibt einen selector zurück der alle childs beinhaltet
 Editor Element::selectChildren() const
 {
@@ -655,6 +663,22 @@ Iterator<Element*> Editor::end()
     return elements->end();
 }
 
+//! Gibt einen selector zurück der alle elemente beinhaltet die in diesem
+//! selector vorkommen und rekursiv alle Kinder der elemente Enthält
+Editor Editor::selectAllElements()
+{
+    RCArray<Element>* list = new RCArray<Element>();
+    for (auto i : *elements)
+    {
+        list->add(dynamic_cast<XML::Element*>(i->getThis()));
+        for (Element* j : i->selectChildren().selectAllElements())
+        {
+            list->add(dynamic_cast<XML::Element*>(j->getThis()));
+        }
+    }
+    return Editor(list);
+}
+
 // gibt einen selector zurück der alle childs beinhaltet
 Editor Editor::selectChildren() const
 {

+ 4 - 0
XML.h

@@ -80,6 +80,8 @@ namespace Framework
             //! gibt einen iterator zurück mit dem durch alle childs iteriert
             //! werden kann
             DLLEXPORT Iterator<Element*> getChilds() const;
+            //! gibt einen Editor für dieses Element zurück
+            DLLEXPORT Editor select();
             //! gibt einen selector zurück der alle childs beinhaltet
             DLLEXPORT Editor selectChildren() const;
             //! gibt eine Liste mit childs zurück, die einen bestimmten Namen
@@ -164,6 +166,8 @@ namespace Framework
             DLLEXPORT Iterator<Element*> begin();
             //! Gibt das ende des iterators zurück
             DLLEXPORT Iterator<Element*> end();
+            //! Gibt einen selector zurück der alle elemente beinhaltet die in diesem selector vorkommen und rekursiv alle Kinder der elemente Enthält
+            DLLEXPORT Editor selectAllElements();
             //! gibt einen selector zurück der alle childs beinhaltet
             DLLEXPORT Editor selectChildren() const;
             //! gibt einen selector zurück der alle parents beinhaltet