root/demo/Tests.cpp

/////////////////////////////////////////////////////////////////////////////
// N0Slib Serialization Library
// Copyright (c) 2011 Nehmulos
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
/////////////////////////////////////////////////////////////////////////////
// Run These Tests from the project root using ./demo/example
/*
 * Tests.cpp
 *
 *  Created on: 28.07.2011
 *      Author: Nehmulos
 */
#include "TestObject.h"
#include "../src/JsonDrooler.h"
#include "../src/BinaryWriter.h"
#include "../src/BinaryReader.h"
#include <assert.h>

#define TEST_NAME_PARENT "Parent"
#define TEST_NAME_CHILD  "Child1"

/// Create a new Object by classId
nw::DescribedObject *getNewObjectForClassId(nw::ClassId id)
{
        if(id == "Testobject")
                return new TestObject();
        else if(id == "Lulz")
                return NULL; // Return new Lulz();
        return NULL;
}

void readTextures()
{
        nw::XmlReader xr("demo/in/textures.xml");
        std::vector<nw::String> textures;
        xr.describeArray("textures","texture",0);
        for (int i = 0; xr.enterNextElement(i); ++i)
        {
                nw::String path;
                xr.describe("path",path);
                textures.push_back(path);
        }
        assert(textures.at(0) == "killme.png");
        assert(textures.at(1) == "this/library\\ is/garbage/y.png");
}

/// Executed before testing to init the library
void prepareToTest()
{
        nw::Describer::createObjectForClassId = getNewObjectForClassId;
}

///
/// Created for testing purposes. Creates a inited TestObject.
///
TestObject* newTestObject()
{
        TestObject *parent = new TestObject();
        TestObject *child1 = new TestObject();
        parent->children = new TestObject*[1];
        parent->numberOfChildren = 1;
        parent->name = TEST_NAME_PARENT;
        parent->children[0] = child1;

        delete [] parent->blob;
        parent->blob = new int[10]{0,1,2,3,4,5,6,7,8,9};
        parent->blob[0] = 0;
        parent->blob[1] = 1;
        parent->blob[2] = 2;
        parent->blob[3] = 3;
        parent->blob[4] = 4;
        parent->blob[5] = 5;
        parent->blob[6] = 6;
        parent->blob[7] = 7;
        parent->blob[8] = 8;
        parent->blob[9] = 9;
        parent->iAmFalse = false;
        parent->iAmTrue = true;
        child1->parent = parent;
        child1->name = TEST_NAME_CHILD;
//      delete [] child1->blob;
//    child1->blob = new int[10]{9,8,7,6,5,4,3,2,1,0};
        return parent;
}

bool validateDefaultTestObject(nw::String name, TestObject* testObject)
{
        if (testObject != NULL &&
                testObject->name == TEST_NAME_PARENT &&
                testObject->children[0]->name == TEST_NAME_CHILD &&
                testObject->children[0]->parent == testObject)
        {
                if(testObject->blob[0] != 0 ||
                   testObject->blob[1] != 1 ||
                   testObject->blob[2] != 2 ||
                   testObject->blob[3] != 3 ||
                   testObject->blob[4] != 4 ||
                   testObject->blob[5] != 5 ||
                   testObject->blob[6] != 6 ||
                   testObject->blob[7] != 7 ||
                   testObject->blob[8] != 8 ||
                   testObject->blob[9] != 9)
                {
                        std::cout << "Encoded blobs are wrong!" << std::endl;
                        return false;
                }
                if(testObject->iAmTrue == true && testObject->iAmFalse == false)
                {
                        std::cout << name << '\t' << " read valid values. Everything looks okay." << std::endl;
                        return true;
                }
                else
                {
                        std::cout << "The Booleans are wrong!";
                        return false;
                }
        }
        else
        {
                std::cout << "ERROR the names and pointers are wrong!" << std::endl;
                return false;
        }
}

/// Write an Inited TestObject with pointers to a Xml File.
void writeXml()
{
        TestObject* testObject = newTestObject();
        nw::XmlWriter xw("demo/out/example.xml");
        xw.setPointers(nw::PointerCollector(testObject));
        xw.describe("TestObject",(nw::Pointer)testObject);
        xw.close();
        delete testObject;
}

/// Write an Inited TestObject with pointers to a Json File.
void writeJson()
{
        TestObject* testObject = newTestObject();
        nw::JsonWriter   jw("demo/out/example.json");
        jw.setPointers(nw::PointerCollector(testObject));
        jw.describe("TestObject",(nw::Pointer)testObject);
        jw.close();
        delete testObject;
}

/// Write an Inited TestObject with pointers to a Binary File.
// void writeBinary()
// {
//         TestObject* testObject = newTestObject();
//         nw::BinaryWriter bw("demo/out/example.bin");
//         bw.setPointers(nw::PointerCollector(testObject));
//         bw.describe("TestObject", (nw::Pointer)testObject);
//         bw.close();
//         delete testObject;
// }

/// Write an Inited TestObject with pointers to a Json File.
void droolJson()
{
        TestObject* testObject = newTestObject();
        nw::JsonDrooler jw("demo/out/example.json");
        jw.setPointers(nw::PointerCollector(testObject));
        jw.describe("TestObject",(nw::Pointer)testObject);
        jw.close();
        delete testObject;
}

void readXml()
{
        TestObject* testObject = NULL;
        nw::XmlReader    xr("demo/out/example.xml");
        xr.describe("TestObject",(nw::Pointer) testObject);
        xr.close();
        assert(validateDefaultTestObject("Xml", testObject));
}

void readJson()
{
        TestObject* testObject = NULL;
        nw::JsonReader   jr("demo/out/example.json");
        jr.describe("TestObject",(nw::Pointer)testObject);
        jr.close();
        assert(validateDefaultTestObject("Json", testObject));
}

void readJsonUnicode()
{
        nw::String url;
        nw::String titleJp;
        nw::JsonReader jr("demo/in/unicode.json");
        jr.describe("image_url_med", url);
        jr.describe("title_japanese", titleJp);
        jr.close();
        assert(titleJp == "ひだまりスケッチ×ハニカム");
}

void writeXsd()
{
        TestObject* testObject = newTestObject();
//      nw::PointerCollector::collect(testObject);
        nw::XsdWriter xsw("demo/out/example.xsd");
        testObject->describeObject(&xsw);
//      xsw.describe("TestObject", (nw::Pointer) testObject);
        xsw.close();
        delete testObject;
}

// void readBinary()
// {
//         TestObject* testObject = NULL;
//         nw::BinaryReader br("demo/out/example.bin");
//         br.describe("TestObject", (nw::Pointer) testObject);
//         br.close();
//         assert(validateDefaultTestObject("Binary", testObject));
// }

/// Reads an invalid badly formatted xml, that should be still recoverable.
void readUglyXml()
{
        unsigned int so, mi, ne;
        so = mi = ne = 0;
        nw::XmlReader* xrx= new nw::XmlReader("demo/in/extream.xml");
        xrx->describe("so",so);
        bool somebool = true;
        xrx->describe("so",somebool);

        /// Conditional push that writes & reads only if either the given parameter is true
        /// or the tag does exist
        if( xrx->conditionalPush("so",somebool))
        {
//        somebool = true; // Was set by conditional Push
          xrx->describe("mi",mi);
        }
        xrx->pop();
        xrx->describe("ne",ne);
        xrx->close();

        assert(so == 1);
        assert(mi == 2);
        assert(ne == 3);
}

template <class ReaderType>
void readNonsensStrings() {
        std::stringstream ss;
        ss << "asdf { <yo thet ain'>t \"json!";

        nw::String value = "asdf";

        ReaderType reader(ss);
        reader.push("nope");
        reader.describe("value", value);
        reader.pop();
        reader.close();
        assert(value == "asdf");

        ss.str("");
        ReaderType reader2(ss);

        reader2.push("notag");
        reader2.describe("not here", value);
        assert(value == "asdf");
        assert(true);
}

void readJsonWithoutWrapper() {
        std::stringstream ss;
        std::string testValue;
        ss << "\"test\": \"asdf\"";
        nw::JsonReader jr(ss);
        jr.describe("test", testValue);
        jr.close();
        assert(testValue == "asdf");
}

void encodeHex()
{
        nw::String hex = nw::utils::toHex("Hello World");
        assert(hex == "8456C6C6F60275F627C646"); // Hello World String test

        int bin[7] = {0,1,2,3,4,5,6};
        hex = nw::utils::toHex((const char*)bin, sizeof(bin));

        assert(hex == "00000000100000002000000030000000400000005000000060000000"); // array of 7 binary test
}

void decodeHex()
{
        assert(nw::utils::fromHex("8456C6C6F60275F627C646") == "Hello World");
        std::string binstr = nw::utils::fromHex("00000000100000002000000030000000400000005000000060000000");
        unsigned int* bin = (unsigned int*) binstr.data();
        assert(bin[0] == 0 && bin[1] == 1 && bin[2] == 2 && bin[3] == 3 && bin[4] == 4 && bin[5] == 5 && bin[6] == 6);
}

void encodeBase64()
{
        nw::String b64 = nw::utils::toBase64("Hello World");
        assert(b64 == "SGVsbG8gV29ybGQ=");
}

void decodeBase64()
{
        assert(nw::utils::fromBase64("SGVsbG8gV29ybGQ=") == "Hello World");
}

void testPaths()
{
        nw::utils::createDirectory((nw::utils::getHomeDirectory() + "/.noslib").c_str());
        std::cout << nw::utils::getHomeDirectory() << std::endl;
}

void testJsonReplaceInvalidCharacters() {
        std::stringstream ss;
        nw::JsonWriter jw(ss);
        std::string value = "as\\\\ \\ \" \\/ \b \f \n \r \t df\\";
        jw.describe("test", value);
        jw.close();
        std::string json = ss.str();
        assert(std::string::npos != json.find("as\\\\ \\\\ \\\" \\/ \\b \\f \\n \\r \\t df\\"));
}

void templates() {
        std::stringstream ss;
        nw::JsonWriter jw(ss);

        nw::String value = "Hello world";
        nw::describe(jw, "Key", value);
}

void describerGenByFileExtension() {
    nw::Describer* xml = nw::DescriberGen::readerForExtension("demo/out/example.xml");
    nw::Describer* json = nw::DescriberGen::readerForExtension("demo/out/example.json");
    // nw::Describer* bin = nw::DescriberGen::readerForExtension("demo/out/example.bin");
    nw::Describer* bullshit = nw::DescriberGen::readerForExtension("test.bullshit");

    assert(xml);
    assert(json);
    // assert(bin);
    assert(NULL == bullshit);
    assert(dynamic_cast<nw::XmlReader*>(xml));
    assert(dynamic_cast<nw::JsonReader*>(json));
    // assert(dynamic_cast<nw::BinaryReader*>(bin));
    delete xml;
    delete json;
    // delete bin;
}

// TODO test with headers that start with spaces and tabs
void describerGenByHeader() {
    nw::Describer* xml = nw::DescriberGen::readerForHeader("demo/out/example.xml");
    nw::Describer* json = nw::DescriberGen::readerForHeader("demo/out/example.json");
    //nw::Describer* bin = nw::DescriberGen::readerForHeader("demo/out/example.bin");
    std::cerr << "expecting a missing-file-warning now:\n";
    nw::Describer* bullshit = nw::DescriberGen::readerForHeader("test.bullshit");

    assert(xml);
    assert(json);
    //assert(bin);
    assert(NULL == bullshit);
    assert(dynamic_cast<nw::XmlReader*>(xml));
    assert(dynamic_cast<nw::JsonReader*>(json));
    //assert(dynamic_cast<nw::BinaryReader*>(bin));
    delete xml;
    delete json;
    //delete bin;
}

void testAll()
{
        testPaths();

        // encoding / decoding tests
        encodeBase64();
        decodeBase64();
        encodeHex();
        decodeHex();

        droolJson();
        readJson();

        // automated im- and export files created by the library
        writeXml();
        writeXsd();
        writeJson();
        // writeBinary();
        readXml();
        readJson();
        readJsonUnicode();
        // readBinary();

        // import of handwritten badly formatted data
        readUglyXml();
        readTextures();

        testJsonReplaceInvalidCharacters();
        readNonsensStrings<nw::JsonReader>();
        readNonsensStrings<nw::XmlReader>();
        readJsonWithoutWrapper();
        templates();
        describerGenByFileExtension();
        describerGenByHeader();
}

int main(int argc, char **argv) {

        prepareToTest();
        testAll();
        std::cout << "Finished all tests" << std::endl;
        return 0;
}