#include <Platform.h> // Only use angled for Platform, else, xcode project won't compile
#include "../cpp_foundation/XString.h"
#include "../cpp_foundation/XStringArray.h"
//#include "../cpp_foundation/unicode_conversions.h"
//#include "../Platform/plist/plist.h"

#include "../cpp_lib/XmlLiteSimpleTypes.h"
#include "../cpp_lib/XmlLiteCompositeTypes.h"
#include "../cpp_lib/XmlLiteParser.h"


static int breakpoint(int i)
{
  return i;
}


static XmlLiteParser gXmlLiteParser;





int move_tests()
{
  gXmlLiteParser.init("\n\n\n<a>\n  <b></b>\n</a>\n");
  while ( gXmlLiteParser.getLine() < 4 && gXmlLiteParser.moveForward() ) ;
  while ( gXmlLiteParser.moveBackward() );
  if ( gXmlLiteParser.getPosition().getLine() != 1 || gXmlLiteParser.getPosition().getCol() != 1 ) return 1;
  
  return 0;
}

int getNextTag_tests()
{
  const char* tag;
  size_t tagLength;
  bool isOpeningTag, isClosingTag;
  bool b;

  gXmlLiteParser.init("<key>");
  b = gXmlLiteParser.getNextTag(&tag, &tagLength, &isOpeningTag, &isClosingTag, true);
  if ( !b ) return breakpoint(1);
  if ( !isOpeningTag ) return breakpoint(2);
  if ( isClosingTag ) return breakpoint(3);
  if ( gXmlLiteParser.getchar() != 0 ) return breakpoint(4);

  
  gXmlLiteParser.init("</key>");
  b = gXmlLiteParser.getNextTag(&tag, &tagLength, &isOpeningTag, &isClosingTag, true);
  if ( !b ) return breakpoint(5);
  if ( isOpeningTag ) return breakpoint(6);
  if ( !isClosingTag ) return breakpoint(7);
  if ( gXmlLiteParser.getchar() != 0 ) return breakpoint(8);

  
  gXmlLiteParser.init("<key/>");
  b = gXmlLiteParser.getNextTag(&tag, &tagLength, &isOpeningTag, &isClosingTag, true);
  if ( !b ) return breakpoint(10);
  if ( !isOpeningTag ) return breakpoint(11);
  if ( isClosingTag ) return breakpoint(12);
  b = gXmlLiteParser.getNextTag(&tag, &tagLength, &isOpeningTag, &isClosingTag, true);
  if ( !b ) return breakpoint(13);
  if ( isOpeningTag ) return breakpoint(14);
  if ( !isClosingTag ) return breakpoint(15);

  //
  // Test xmlLiteParser.getErrorsAndWarnings()
  //
  gXmlLiteParser.init("foo1\n  foo2");
  gXmlLiteParser.moveForwardUntil(0);
  b = gXmlLiteParser.getNextTag(&tag, &tagLength, &isOpeningTag, &isClosingTag, true);
  if ( b ) return breakpoint(13);
  if ( gXmlLiteParser.getErrorsAndWarnings().size() != 1 ) return breakpoint(13);
  if ( !gXmlLiteParser.getErrorsAndWarnings()[0].msg.contains("line 2 col 7") ) return breakpoint(14);

  gXmlLiteParser.init("foo1\n  bar1");
  gXmlLiteParser.moveForwardUntil('b');
  b = gXmlLiteParser.getNextTag(&tag, &tagLength, &isOpeningTag, &isClosingTag, true);
  if ( b ) return breakpoint(13);
  if ( gXmlLiteParser.getErrorsAndWarnings().size() != 1 ) return breakpoint(13);
  if ( !gXmlLiteParser.getErrorsAndWarnings()[0].msg.contains("line 2 col 3") ) return breakpoint(14);
  
  gXmlLiteParser.init("foo1\n  </foo2/>");
  gXmlLiteParser.moveForwardUntil('<');
  b = gXmlLiteParser.getNextTag(&tag, &tagLength, &isOpeningTag, &isClosingTag, true);
  if ( b ) return breakpoint(13);
  if ( gXmlLiteParser.getErrorsAndWarnings().size() != 1 ) return breakpoint(13);
  if ( !gXmlLiteParser.getErrorsAndWarnings()[0].msg.contains("line 2 col 9") ) return breakpoint(14);
  
  gXmlLiteParser.init("foo1\n    </foo2");
  gXmlLiteParser.moveForwardUntil('<');
  b = gXmlLiteParser.getNextTag(&tag, &tagLength, &isOpeningTag, &isClosingTag, true);
  if ( b ) return breakpoint(13);
  if ( gXmlLiteParser.getErrorsAndWarnings().size() != 1 ) return breakpoint(13);
  if ( !gXmlLiteParser.getErrorsAndWarnings()[0].msg.contains("line 2 col 11") ) return breakpoint(14);
  
  gXmlLiteParser.init("foo1\n      </foo2 >");
  gXmlLiteParser.moveForwardUntil('<');
  b = gXmlLiteParser.getNextTag(&tag, &tagLength, &isOpeningTag, &isClosingTag, true);
  if ( b ) return breakpoint(13);
  if ( gXmlLiteParser.getErrorsAndWarnings().size() != 1 ) return breakpoint(13);
  if ( !gXmlLiteParser.getErrorsAndWarnings()[0].msg.contains("line 2 col 13") ) return breakpoint(14);

  gXmlLiteParser.init("foo1\n\n<foo2/");
  gXmlLiteParser.moveForwardUntil('/');
  gXmlLiteParser.moveForwardUntilSignificant();
  b = gXmlLiteParser.getNextTag(&tag, &tagLength, &isOpeningTag, &isClosingTag, true);
  if ( b ) return breakpoint(13);
  if ( gXmlLiteParser.getErrorsAndWarnings().size() != 1 ) return breakpoint(13);
  if ( !gXmlLiteParser.getErrorsAndWarnings()[0].msg.contains("line 3 col 7") ) return breakpoint(14);

  gXmlLiteParser.init("foo1\n\n  <foo2/a");
  gXmlLiteParser.moveForwardUntil('/');
  gXmlLiteParser.moveForwardUntilSignificant();
  b = gXmlLiteParser.getNextTag(&tag, &tagLength, &isOpeningTag, &isClosingTag, true);
  if ( b ) return breakpoint(13);
  if ( gXmlLiteParser.getErrorsAndWarnings().size() != 1 ) return breakpoint(13);
  if ( !gXmlLiteParser.getErrorsAndWarnings()[0].msg.contains("line 3 col 9") ) return breakpoint(14);


  return 0;
}

int getSimpleTag_tests()
{
  const char* tag;
  size_t tagLength;
  const char* value;
  size_t valueLength;
  bool b;
  
  gXmlLiteParser.init("<key>k</key><string>v</string>");
  b = gXmlLiteParser.getSimpleTag(&tag, &tagLength, &value, &valueLength, "key", true);
  if ( !b ) return breakpoint(1);
  if ( !strnIsEqual(tag, tagLength, "key") ) return breakpoint(2);
  if ( !strnIsEqual(value, valueLength, "k") ) return breakpoint(3);
  
  gXmlLiteParser.init("<key/>");
  b = gXmlLiteParser.getSimpleTag(&tag, &tagLength, &value, &valueLength, "key", true);
  if ( !b ) return breakpoint(1);
  if ( value != NULL ) return breakpoint(3);
  if ( valueLength != 0 ) return breakpoint(3);

  gXmlLiteParser.init("<key></key>");
  b = gXmlLiteParser.getSimpleTag(&tag, &tagLength, &value, &valueLength, "key", true);
  if ( !b ) return breakpoint(1);
  if ( value != NULL ) return breakpoint(3);
  if ( valueLength != 0 ) return breakpoint(3);

  gXmlLiteParser.init("<true/>");
  b = gXmlLiteParser.getSimpleTag(&tag, &tagLength, &value, &valueLength, "true", true);
  if ( !b ) return breakpoint(1);
  if ( !strnIsEqual(tag, tagLength, "true") ) return breakpoint(2);
  if ( value != NULL ) return breakpoint(3);
  if ( valueLength != 0 ) return breakpoint(3);

  gXmlLiteParser.init("<key>k<string>v</string>k</key>");
  b = gXmlLiteParser.getSimpleTag(&tag, &tagLength, &value, &valueLength, "key", true);
  if ( b ) return breakpoint(4);

  //
  // Test xmlLiteParser.getErrorsAndWarnings()
  //
  gXmlLiteParser.init("\n\n  </key>k</key>");
  gXmlLiteParser.moveForwardUntilSignificant();
  b = gXmlLiteParser.getSimpleTag(&tag, &tagLength, &value, &valueLength, "key", true);
  if ( b ) return breakpoint(4);
  if ( gXmlLiteParser.getErrorsAndWarnings().size() != 1 ) return breakpoint(13);
  if ( !gXmlLiteParser.getErrorsAndWarnings()[0].msg.contains("line 3 col 3") ) return breakpoint(14);
  
  gXmlLiteParser.init("\n\n    <foo>k</foo>");
  gXmlLiteParser.moveForwardUntilSignificant();
  b = gXmlLiteParser.getSimpleTag(&tag, &tagLength, &value, &valueLength, "key", true);
  if ( b ) return breakpoint(4);
  if ( gXmlLiteParser.getErrorsAndWarnings().size() != 1 ) return breakpoint(13);
  if ( !gXmlLiteParser.getErrorsAndWarnings()[0].msg.contains("line 3 col 5") ) return breakpoint(14);
  
  gXmlLiteParser.init("\n\n    <key></key>");
  gXmlLiteParser.moveForwardUntilSignificant();
  b = gXmlLiteParser.getSimpleTag(&tag, &tagLength, &value, &valueLength, "key", true);
  if ( !b ) return breakpoint(4);
  if ( value != NULL ) return breakpoint(3);
  if ( valueLength != 0 ) return breakpoint(3);

  gXmlLiteParser.init("\n\n    <key>v<key>");
  gXmlLiteParser.moveForwardUntilSignificant();
  b = gXmlLiteParser.getSimpleTag(&tag, &tagLength, &value, &valueLength, "key", true);
  if ( b ) return breakpoint(4);
  if ( gXmlLiteParser.getErrorsAndWarnings().size() != 1 ) return breakpoint(13);
  if ( !gXmlLiteParser.getErrorsAndWarnings()[0].msg.contains("line 3 col 11") ) return breakpoint(14);

  gXmlLiteParser.init("\n\n    <key>v</foo>");
  gXmlLiteParser.moveForwardUntilSignificant();
  b = gXmlLiteParser.getSimpleTag(&tag, &tagLength, &value, &valueLength, "key", true);
  if ( b ) return breakpoint(4);
  if ( gXmlLiteParser.getErrorsAndWarnings().size() != 1 ) return breakpoint(13);
  if ( !gXmlLiteParser.getErrorsAndWarnings()[0].msg.contains("line 3 col 11") ) return breakpoint(14);

  return 0;
}

int getKey_tests()
{
  const char* tag;
  size_t length;
  bool b;
  XmlParserPosition xmlParserPosition;

  gXmlLiteParser.init("<key></key><string>v</string>");
  b = gXmlLiteParser.getKeyTagValue(&tag, &length, &xmlParserPosition, true);
  if ( !b ) return breakpoint(3);
  if ( length != 0 ) return breakpoint(13);

  gXmlLiteParser.init("<key> </key><string>v</string>");
  b = gXmlLiteParser.getKeyTagValue(&tag, &length, &xmlParserPosition, true);
  if ( !b ) return breakpoint(3);
  if ( length != 0 ) return breakpoint(13);

  gXmlLiteParser.init("<key>a</key><string>v</string>");
  b = gXmlLiteParser.getKeyTagValue(&tag, &length, &xmlParserPosition, true);
  if ( !b ) return breakpoint(5);
  if ( !strnIsEqual(tag, length, "a") ) return breakpoint(6);

  gXmlLiteParser.init("<key> a </key><string>v</string>");
  b = gXmlLiteParser.getKeyTagValue(&tag, &length, &xmlParserPosition, true);
  if ( !b ) return breakpoint(6);
  if ( !strnIsEqual(tag, length, "a") ) return breakpoint(6);

  gXmlLiteParser.init("<key>  a  </key><string>v</string>");
  b = gXmlLiteParser.getKeyTagValue(&tag, &length, &xmlParserPosition, true);
  if ( !b ) return breakpoint(7);
  if ( !strnIsEqual(tag, length, "a") ) return breakpoint(6);

  gXmlLiteParser.init("<key>a  </key><string>v</string>");
  b = gXmlLiteParser.getKeyTagValue(&tag, &length, &xmlParserPosition, true);
  if ( !b ) return breakpoint(8);
  if ( !strnIsEqual(tag, length, "a") ) return breakpoint(6);

  gXmlLiteParser.init("<key>  a</key><string>v</string>");
  b = gXmlLiteParser.getKeyTagValue(&tag, &length, &xmlParserPosition, true);
  if ( !b ) return breakpoint(9);
  if ( !strnIsEqual(tag, length, "a") ) return breakpoint(6);

  return 0;
}

int skip_tests()
{
  bool b;

  gXmlLiteParser.init("k</key><string>v</string>");
  b = gXmlLiteParser.skipUntilClosingTag("key", strlen("key"), true);
  if ( !b ) return breakpoint(1);
  if ( !strnIsEqual(gXmlLiteParser.getcharPtr(), strlen(gXmlLiteParser.getcharPtr()), "<string>v</string>") ) return breakpoint(2);

  gXmlLiteParser.init("<string>v</string></key>foo"); // 'foo' is text after closing tag -> fail
  b = gXmlLiteParser.skipUntilClosingTag("key", strlen("key"), true);
  if ( b ) return breakpoint(1);
  if ( gXmlLiteParser.getErrorsAndWarnings().size() != 1 ) return breakpoint(13);
  if ( !gXmlLiteParser.getErrorsAndWarnings()[0].msg.contains("line 1 col 25") ) return breakpoint(14);

  gXmlLiteParser.init("<string>v</string></key><foo>"); // <foo> is the next tag -> success
  b = gXmlLiteParser.skipUntilClosingTag("key", strlen("key"), true);
  if ( !b ) return breakpoint(1);
  if ( !strnIsEqual(gXmlLiteParser.getcharPtr(), strlen(gXmlLiteParser.getcharPtr()), "<foo>") ) return breakpoint(2);
  
  gXmlLiteParser.init("<string>v</string></key>"); // end of file just after skipped tag -> success
  b = gXmlLiteParser.skipUntilClosingTag("key", strlen("key"), true);
  if ( !b ) return breakpoint(1);
  if ( gXmlLiteParser.getchar() != 0 ) return breakpoint(2);

  gXmlLiteParser.init("<string>v</string><foo1><foo11>bar11</foo11></foo1><foo2>bar2</foo2></key><meow>");
  b = gXmlLiteParser.skipUntilClosingTag("key", strlen("key"), true);
  if ( !b ) return breakpoint(1);
  if ( !strnIsEqual(gXmlLiteParser.getcharPtr(), strlen(gXmlLiteParser.getcharPtr()), "<meow>") ) return breakpoint(2);

  // Cannot have a tag containing chars AND subtag
  gXmlLiteParser.init("\n\n\nk<string>v</string></key>");
  gXmlLiteParser.moveForwardUntil('k');
  b = gXmlLiteParser.skipUntilClosingTag("key", strlen("key"), true);
  if ( b ) return breakpoint(2);
  if ( gXmlLiteParser.getErrorsAndWarnings().size() != 1 ) return breakpoint(13);
  if ( !gXmlLiteParser.getErrorsAndWarnings()[0].msg.contains("line 4 col 2") ) return breakpoint(14);

  // Cannot have a tag containing chars AND subtag
  gXmlLiteParser.init("<string>v</string>k</key>");
  b = gXmlLiteParser.skipUntilClosingTag("key", strlen("key"), true);
  if ( b ) return breakpoint(2);
  if ( gXmlLiteParser.getErrorsAndWarnings().size() != 1 ) return breakpoint(13);
  if ( !gXmlLiteParser.getErrorsAndWarnings()[0].msg.contains("line 1 col 19") ) return breakpoint(14);

  
  // Cannot have a tag containing chars AND subtag
  gXmlLiteParser.init("\n </string>v</string>k</key>");
  gXmlLiteParser.moveForwardUntil('<');
  b = gXmlLiteParser.skipNextTag(true);
  if ( b ) return breakpoint(2);
  if ( gXmlLiteParser.getErrorsAndWarnings().size() != 1 ) return breakpoint(13);
  if ( !gXmlLiteParser.getErrorsAndWarnings()[0].msg.contains("line 2 col 2") ) return breakpoint(14);
  
  return 0;
}

int xml_integer_tests()
{
//  XmlAbstractType xml_int8;
//  bool b;
//  UINTN result;
//  bool negative;
//  XString8 s;
//  
//  xmlLiteParser.init("<integer>10</integer>");
//  b = xml_int8.XmlInteger::parseFromXmlLite(&xmlLiteParser, "xmlpath"_XS8, &result, &negative, 0, 12);
//  if ( !b ) return breakpoint(1);
//  if ( result != 10 ) return breakpoint(2);
//  if ( negative ) return breakpoint(3);
//
//  xmlLiteParser.init("<integer>0</integer>");
//  b = xml_int8.XmlInteger::parseFromXmlLite(&xmlLiteParser, "xmlpath"_XS8, &result, &negative, -2, 12);
//  if ( !b ) return breakpoint(10);
//  if ( result != 0 ) return breakpoint(11);
//  if ( negative ) return breakpoint(12);
//
//  xmlLiteParser.init("<integer>-0</integer>");
//  b = xml_int8.XmlInteger::parseFromXmlLite(&xmlLiteParser, "xmlpath"_XS8, &result, &negative, 0, 0);
//  if ( !b ) return breakpoint(20);
//  if ( result != 0 ) return breakpoint(21);
//  if ( negative ) return breakpoint(22);
//
//  xmlLiteParser.init("<integer>10</integer>");
//  b = xml_int8.XmlInteger::parseFromXmlLite(&xmlLiteParser, "xmlpath"_XS8, &result, &negative, 0, UINT64_MAX);
//  if ( !b ) return breakpoint(30);
//  if ( result != 10 ) return breakpoint(31);
//  if ( negative ) return breakpoint(32);
//
//  xmlLiteParser.init("<integer>10</integer>");
//  b = xml_int8.XmlInteger::parseFromXmlLite(&xmlLiteParser, "xmlpath"_XS8, &result, &negative, 0, 12);
//  if ( !b ) return breakpoint(40);
//  if ( result != 10 ) return breakpoint(41);
//  if ( negative ) return breakpoint(42);
//
//  s = S8Printf("<integer>%llu</integer>", UINT64_MAX);
//  xmlLiteParser.init(s.c_str());
//  b = xml_int8.XmlInteger::parseFromXmlLite(&xmlLiteParser, "xmlpath"_XS8, &result, &negative, 0, UINT64_MAX);
//  if ( !b ) return breakpoint(50);
//  if ( result != UINT64_MAX ) return breakpoint(51);
//  if ( negative ) return breakpoint(52);
//  
//  s = S8Printf("<integer>%lld</integer>", INT64_MIN);
//  xmlLiteParser.init(s.c_str());
//  b = xml_int8.XmlInteger::parseFromXmlLite(&xmlLiteParser, "xmlpath"_XS8, &result, &negative, INT64_MIN, UINT64_MAX);
//  if ( !b ) return breakpoint(60);
//  if ( result != (UINT64)INT64_MIN ) return breakpoint(61);
//  if ( !negative ) return breakpoint(62);
//
//  
//  xmlLiteParser.init("<integer>-1000</integer>");
//  b = xml_int8.XmlInteger::parseFromXmlLite(&xmlLiteParser, "xmlpath"_XS8, &result, &negative, -1000, 0);
//  if ( !b ) return breakpoint(70);
//  if ( result != 1000 ) return breakpoint(71);
//  if ( !negative ) return breakpoint(72);
//
//  
//  xmlLiteParser.init("<integer>-1001</integer>");
//  xmlLiteParser.init(s.c_str());
//  b = xml_int8.XmlInteger::parseFromXmlLite(&xmlLiteParser, "xmlpath"_XS8, &result, &negative, -1000, 0);
//  if ( b ) return breakpoint(80);

  return 0;
}

int validate_dict_tests()
{
  bool b;

  class Dict1_Class : public XmlDict
  {
    public:
      class Test1Bool: public XmlBool
      {
      public:
        virtual bool validate(XmlLiteParser* xmlLiteParser, const XString8& xmlPath, const XmlParserPosition& keyPos, bool generateErrors) override {
          RETURN_IF_FALSE( XmlBool::validate(xmlLiteParser, xmlPath, keyPos, generateErrors) );
          xmlLiteParser->addWarning(generateErrors, S8Printf("Test1Bool tag '%s:%d'.", xmlPath.c_str(), keyPos.getLine()));
          return false; // parsing can continue.
        }
      } test1Bool = Test1Bool();

      XmlDictField m_fields[1] = {
        {"test1Bool", test1Bool},
      };
      virtual void getFields(XmlDictField** fields, size_t* nb) override { *fields = m_fields; *nb = sizeof(m_fields)/sizeof(m_fields[0]); };
  };

  class Main1Dict_Class : public XmlDict
  {
    public:
      Dict1_Class dict1 = Dict1_Class();

      virtual bool validate(XmlLiteParser* xmlLiteParser, const XString8& xmlPath, const XmlParserPosition& keyPos, bool generateErrors) override {
        RETURN_IF_FALSE( XmlDict::validate(xmlLiteParser, xmlPath, keyPos, generateErrors) );
        xmlLiteParser->addWarning(generateErrors, S8Printf("dict1 tag '%s:%d'.", xmlPath.c_str(), keyPos.getLine()));
        return false; // parsing can continue.
      }

      XmlDictField m_fields[1] = {
        {"dict1", dict1},
      };

      Main1Dict_Class() {};
      virtual void getFields(XmlDictField** fields, size_t* nb) override { *fields = m_fields; *nb = sizeof(m_fields)/sizeof(m_fields[0]); };
  } mainDict;


  const char* config_test =
   "<dict>\r\n\
      <key>dict1</key>\r\n\
      <dict>\r\n\
        <key>test1Bool</key>\r\n\
        <true/>\r\n\
      </dict>\r\n\
    </dict>\r\n\
  </plist>";

    gXmlLiteParser.init(config_test);
    b = mainDict.parseFromXmlLite(&gXmlLiteParser, "/"_XS8, true);
//gXmlLiteParser.printfErrorsAndWarnings();
    if ( !b ) return breakpoint(1);
    if ( gXmlLiteParser.getErrorsAndWarnings().size() != 1 ) return breakpoint(1);
    if ( !gXmlLiteParser.getErrorsAndWarnings()[0].msg.contains("Test1Bool tag") ) return breakpoint(14);

    if ( !b ) return breakpoint(1);
    gXmlLiteParser.init(config_test);
    mainDict.validate(&gXmlLiteParser, "/"_XS8, XmlParserPosition(), true);
//gXmlLiteParser.printfErrorsAndWarnings();
    if ( !b ) return breakpoint(1);
    if ( gXmlLiteParser.getErrorsAndWarnings().size() != 1 ) return breakpoint(1);
    if ( !gXmlLiteParser.getErrorsAndWarnings()[0].msg.contains("ict1 tag") ) return breakpoint(14);
    
  return 0;
}

int validate_array_tests()
{
  bool b;

  class Main2Dict_Class : public XmlDict
  {
    public:
      XmlArray<XmlBool> array = XmlArray<XmlBool>();

      virtual bool validate(XmlLiteParser* xmlLiteParser, const XString8& xmlPath, const XmlParserPosition& keyPos, bool generateErrors) override {
        RETURN_IF_FALSE( XmlDict::validate(xmlLiteParser, xmlPath, keyPos, generateErrors) );
        xmlLiteParser->addWarning(generateErrors, S8Printf("dict2 tag '%s:%d'.", xmlPath.c_str(), keyPos.getLine()));
        return false; // parsing can continue.
      }

      XmlDictField m_fields[1] = {
        {"array1", array},
      };

      Main2Dict_Class() {};
      virtual void getFields(XmlDictField** fields, size_t* nb) override { *fields = m_fields; *nb = sizeof(m_fields)/sizeof(m_fields[0]); };
  } mainDict;


  const char* config_test =
   "<dict>\r\n\
      <key>array1</key>\r\n\
      <array>\r\n\
        <true/>\r\n\
        <true/>\r\n\
        <string>a</string>\r\n\
      </array>\r\n\
    </dict>\r\n\
  </plist>";

    gXmlLiteParser.init(config_test);
    b = mainDict.parseFromXmlLite(&gXmlLiteParser, "/"_XS8, true);
//gXmlLiteParser.printfErrorsAndWarnings();
    if ( !b ) return breakpoint(1);
    if ( gXmlLiteParser.getErrorsAndWarnings().size() != 1 ) return breakpoint(1);
    if ( !gXmlLiteParser.getErrorsAndWarnings()[0].msg.contains("Expecting <true/> <false/>") ) return breakpoint(14);

    gXmlLiteParser.init(config_test);
    mainDict.validate(&gXmlLiteParser, "/"_XS8, XmlParserPosition(), true);
//gXmlLiteParser.printfErrorsAndWarnings();
    if ( !b ) return breakpoint(1);
    if ( gXmlLiteParser.getErrorsAndWarnings().size() != 1 ) return breakpoint(1);
    if ( !gXmlLiteParser.getErrorsAndWarnings()[0].msg.contains("dict2 tag") ) return breakpoint(14);
    
    return 0;
}

int xml_lite_tests()
{

  int ret;
  
//  XmlLiteParser xmlLiteParser;

  
  
  ret = validate_array_tests();
  if ( ret ) return ret;


  ret = validate_dict_tests();
  if ( ret ) return ret;

  
  ret = xml_integer_tests();
  if ( ret ) return ret;
  
  
  ret = move_tests();
  if ( ret ) return ret;
  
  ret = getNextTag_tests();
  if ( ret ) return ret;
  
  ret = getSimpleTag_tests();
  if ( ret ) return ret;
  
  ret = getKey_tests();
  if ( ret ) return ret;
  
  ret = skip_tests();
  if ( ret ) return ret;

  return 0;
}