// Copyright 2022, FOSS-VG Developers and Contributers
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// version 3 along with this program.
// If not, see https://www.gnu.org/licenses/agpl-3.0.en.html

#include <iostream>
#include <cstdint>
#include <vector>
#include <fstream>

#include "assert.hpp"

#include "../lib/nbt.hpp"
#include "../lib/error.hpp"
#include "../lib/javacompat.hpp"

int main(){
    std::cout << "################################################################################" << std::endl;
    std::cout << "NBT object tests" << std::endl;
    std::cout << "################################################################################" << std::endl;

    std::vector<uint8_t> vector;


    // GENERIC #################################################################
    NBT::Tag::Generic generic = NBT::Tag::Generic();
    ASSERT(generic.getTagType() == NBT::TagType::INVALID);
    ASSERT(generic.serialize(&vector).isError);
    ASSERT(generic.serialize(&vector).errorCode == ErrorCodes::INVALID_TYPE);
    ASSERT(generic.serializeWithoutHeader(&vector).isError);
    ASSERT(generic.serializeWithoutHeader(&vector).errorCode == ErrorCodes::INVALID_TYPE);
    // Normally, at this point, we would discard the vector as garbage.
    // In this case, the assertions below exist to test the common
    // serializer code.
    ASSERT(vector.size() == 6);
    ASSERT(
        vector.at(0) == 255 &&
        vector.at(1) ==   0 &&
        vector.at(2) ==   0 &&
        vector.at(3) == 255 &&
        vector.at(4) ==   0 &&
        vector.at(5) ==   0
    );
    generic.name = tiny_utf8::string(std::string(0x10000, 'E'));
    ASSERT(generic.serialize(&vector).isError && generic.serialize(&vector).errorCode == ErrorCodes::OVERRUN);
    vector.clear();
    std::cout << "Passed Generic (super type) test." << std::endl;


    // END #####################################################################
    NBT::Tag::End end = NBT::Tag::End();
    ASSERT(end.getTagType() == NBT::TagType::END);
    ASSERT(!end.serialize(&vector).isError);
    ASSERT(!end.serializeWithoutHeader(&vector).isError);
    ASSERT(vector.size() == 1);
    ASSERT(vector.at(0) == 0);
    vector.clear();
    std::cout << "Passed End test." << std::endl;


    // INT8 ####################################################################
    NBT::Tag::Int8 int8_0 = NBT::Tag::Int8();
    int8_0.setValue(-128);
    int8_0.name = "int8_0";
    NBT::Tag::Int8 int8_1 = NBT::Tag::Int8("int8_1", 127);
    ASSERT(int8_0.getValue() == -128);
    ASSERT(int8_1.getValue() == 127);
    ASSERT(int8_0.getTagType() == 1 && int8_1.getTagType() == 1);
    ASSERT(!int8_0.serialize(&vector).isError);
    ASSERT(!int8_1.serialize(&vector).isError);
    ASSERT(vector.size() == 20);
    ASSERT(
        vector.at( 0) == 1 &&
        vector.at( 1) == 0 &&
        vector.at( 2) == 6 &&
        vector.at( 3) == 'i' &&
        vector.at( 4) == 'n' &&
        vector.at( 5) == 't' &&
        vector.at( 6) == '8' &&
        vector.at( 7) == '_' &&
        vector.at( 8) == '0' &&
        vector.at( 9) == 128 &&
        vector.at(10) == 1 &&
        vector.at(11) == 0 &&
        vector.at(12) == 6 &&
        vector.at(13) == 'i' &&
        vector.at(14) == 'n' &&
        vector.at(15) == 't' &&
        vector.at(16) == '8' &&
        vector.at(17) == '_' &&
        vector.at(18) == '1' &&
        vector.at(19) == 127
    );
    vector.clear();
    int8_0.name = "";
    ASSERT(!int8_0.serialize(&vector).isError);
    ASSERT(vector.size() == 4);
    ASSERT(
        vector.at(0) == 1 &&
        vector.at(1) == 0 &&
        vector.at(2) == 0 &&
        vector.at(3) == 128
    );
    vector.clear();
    ASSERT(!int8_0.serializeWithoutHeader(&vector).isError);
    ASSERT(!int8_1.serializeWithoutHeader(&vector).isError);
    ASSERT(vector.size() == 2);
    ASSERT(
        vector.at(0) == 128 &&
        vector.at(1) == 127
    );
    vector.clear();
    std::cout << "Passed Int8 test." << std::endl;


    // INT16 ###################################################################
    NBT::Tag::Int16 int16_0 = NBT::Tag::Int16();
    int16_0.name = "int16_0";
    int16_0.setValue(-32768);
    NBT::Tag::Int16 int16_1 = NBT::Tag::Int16("int16_1", 32767);
    ASSERT(int16_0.getValue() == -0x8000);
    ASSERT(int16_1.getValue() == 0x7FFF);
    ASSERT(int16_0.getTagType() == 2 && int16_1.getTagType() == 2);
    ASSERT(!int16_0.serialize(&vector).isError);
    ASSERT(!int16_1.serialize(&vector).isError);
    ASSERT(vector.size() == 24);
    ASSERT(
        vector.at( 0) == 2 &&
        vector.at( 1) == 0 &&
        vector.at( 2) == 7 &&
        vector.at( 3) == 'i' &&
        vector.at( 4) == 'n' &&
        vector.at( 5) == 't' &&
        vector.at( 6) == '1' &&
        vector.at( 7) == '6' &&
        vector.at( 8) == '_' &&
        vector.at( 9) == '0' &&
        vector.at(10) == 0x80 &&
        vector.at(11) == 0x00 &&
        vector.at(12) == 2 &&
        vector.at(13) == 0 &&
        vector.at(14) == 7 &&
        vector.at(15) == 'i' &&
        vector.at(16) == 'n' &&
        vector.at(17) == 't' &&
        vector.at(18) == '1' &&
        vector.at(19) == '6' &&
        vector.at(20) == '_' &&
        vector.at(21) == '1' &&
        vector.at(22) == 0x7F &&
        vector.at(23) == 0xFF
    );
    vector.clear();
    int16_0.name = "";
    ASSERT(!int16_0.serialize(&vector).isError);
    ASSERT(vector.size() == 5);
    ASSERT(
        vector.at(0) == 2 &&
        vector.at(1) == 0 &&
        vector.at(2) == 0 &&
        vector.at(3) == 0x80 &&
        vector.at(4) == 0
    );
    vector.clear();
    ASSERT(!int16_0.serializeWithoutHeader(&vector).isError);
    ASSERT(!int16_1.serializeWithoutHeader(&vector).isError);
    ASSERT(vector.size() == 4);
    ASSERT(
        vector.at(0) == 0x80 &&
        vector.at(1) == 0 &&
        vector.at(2) == 0x7F &&
        vector.at(3) == 0xFF
    );
    vector.clear();
    std::cout << "Passed Int16 test." << std::endl;


    // INT32 ###################################################################
    NBT::Tag::Int32 int32_0 = NBT::Tag::Int32();
    int32_0.name = "int32_0";
    int32_0.setValue(-2147483648);
    NBT::Tag::Int32 int32_1 = NBT::Tag::Int32("int32_1", 2147483647);
    ASSERT(int32_0.getValue() == (int32_t) -0x80000000);
    ASSERT(int32_1.getValue() == 0x7FFFFFFF);
    ASSERT(int32_0.getTagType() == 3 && int32_1.getTagType() == 3);
    ASSERT(!int32_0.serialize(&vector).isError);
    ASSERT(!int32_1.serialize(&vector).isError);
    ASSERT(vector.size() == 28);
    ASSERT(
        vector.at( 0) == 3 &&
        vector.at( 1) == 0 &&
        vector.at( 2) == 7 &&
        vector.at( 3) == 'i' &&
        vector.at( 4) == 'n' &&
        vector.at( 5) == 't' &&
        vector.at( 6) == '3' &&
        vector.at( 7) == '2' &&
        vector.at( 8) == '_' &&
        vector.at( 9) == '0' &&
        vector.at(10) == 0x80 &&
        vector.at(11) == 0x00 &&
        vector.at(12) == 0x00 &&
        vector.at(13) == 0x00 &&
        vector.at(14) == 3 &&
        vector.at(15) == 0 &&
        vector.at(16) == 7 &&
        vector.at(17) == 'i' &&
        vector.at(18) == 'n' &&
        vector.at(19) == 't' &&
        vector.at(20) == '3' &&
        vector.at(21) == '2' &&
        vector.at(22) == '_' &&
        vector.at(23) == '1' &&
        vector.at(24) == 0x7F &&
        vector.at(25) == 0xFF &&
        vector.at(26) == 0xFF &&
        vector.at(27) == 0xFF
    );
    vector.clear();
    int32_0.name = "";
    ASSERT(!int32_0.serialize(&vector).isError);
    ASSERT(vector.size() == 7);
    ASSERT(
        vector.at(0) == 3 &&
        vector.at(1) == 0 &&
        vector.at(2) == 0 &&
        vector.at(3) == 0x80 &&
        vector.at(4) == 0 &&
        vector.at(5) == 0 &&
        vector.at(6) == 0
    );
    vector.clear();
    ASSERT(!int32_0.serializeWithoutHeader(&vector).isError);
    ASSERT(!int32_1.serializeWithoutHeader(&vector).isError);
    ASSERT(vector.size() == 8);
    ASSERT(
        vector.at(0) == 0x80 &&
        vector.at(1) == 0 &&
        vector.at(2) == 0 &&
        vector.at(3) == 0 &&
        vector.at(4) == 0x7F &&
        vector.at(5) == 0xFF &&
        vector.at(6) == 0xFF &&
        vector.at(7) == 0xFF
    );
    vector.clear();
    std::cout << "Passed Int32 test." << std::endl;


    // INT64 ###################################################################
    NBT::Tag::Int64 int64_0 = NBT::Tag::Int64();
    int64_0.name = "int64_0";
    int64_0.setValue(-9223372036854775808);
    NBT::Tag::Int64 int64_1 = NBT::Tag::Int64("int64_1", 9223372036854775807);
    ASSERT(int64_0.getValue() == (int64_t) -0x8000000000000000);
    ASSERT(int64_1.getValue() == 0x7FFFFFFFFFFFFFFF);
    ASSERT(int64_0.getTagType() == 4 && int64_1.getTagType() == 4);
    ASSERT(!int64_0.serialize(&vector).isError);
    ASSERT(!int64_1.serialize(&vector).isError);
    ASSERT(vector.size() == 36);
    ASSERT(
        vector.at( 0) == 4 &&
        vector.at( 1) == 0 &&
        vector.at( 2) == 7 &&
        vector.at( 3) == 'i' &&
        vector.at( 4) == 'n' &&
        vector.at( 5) == 't' &&
        vector.at( 6) == '6' &&
        vector.at( 7) == '4' &&
        vector.at( 8) == '_' &&
        vector.at( 9) == '0' &&
        vector.at(10) == 0x80 &&
        vector.at(11) == 0x00 &&
        vector.at(12) == 0x00 &&
        vector.at(13) == 0x00 &&
        vector.at(14) == 0x00 &&
        vector.at(15) == 0x00 &&
        vector.at(16) == 0x00 &&
        vector.at(17) == 0x00 &&
        vector.at(18) == 4 &&
        vector.at(19) == 0 &&
        vector.at(20) == 7 &&
        vector.at(21) == 'i' &&
        vector.at(22) == 'n' &&
        vector.at(23) == 't' &&
        vector.at(24) == '6' &&
        vector.at(25) == '4' &&
        vector.at(26) == '_' &&
        vector.at(27) == '1' &&
        vector.at(28) == 0x7F &&
        vector.at(29) == 0xFF &&
        vector.at(30) == 0xFF &&
        vector.at(31) == 0xFF &&
        vector.at(32) == 0xFF &&
        vector.at(33) == 0xFF &&
        vector.at(34) == 0xFF &&
        vector.at(35) == 0xFF
    );
    vector.clear();
    int64_0.name = "";
    ASSERT(!int64_0.serialize(&vector).isError);
    ASSERT(vector.size() == 11);
    ASSERT(
        vector.at( 0) == 4 &&
        vector.at( 1) == 0 &&
        vector.at( 2) == 0 &&
        vector.at( 3) == 0x80 &&
        vector.at( 4) == 0 &&
        vector.at( 5) == 0 &&
        vector.at( 6) == 0 &&
        vector.at( 7) == 0 &&
        vector.at( 8) == 0 &&
        vector.at( 9) == 0 &&
        vector.at(10) == 0
    );
    vector.clear();
    ASSERT(!int64_0.serializeWithoutHeader(&vector).isError);
    ASSERT(!int64_1.serializeWithoutHeader(&vector).isError);
    ASSERT(vector.size() == 16);
    ASSERT(
        vector.at( 0) == 0x80 &&
        vector.at( 1) == 0 &&
        vector.at( 2) == 0 &&
        vector.at( 3) == 0 &&
        vector.at( 4) == 0 &&
        vector.at( 5) == 0 &&
        vector.at( 6) == 0 &&
        vector.at( 7) == 0 &&
        vector.at( 8) == 0x7F &&
        vector.at( 9) == 0xFF &&
        vector.at(10) == 0xFF &&
        vector.at(11) == 0xFF &&
        vector.at(12) == 0xFF &&
        vector.at(13) == 0xFF &&
        vector.at(14) == 0xFF &&
        vector.at(15) == 0xFF
    );
    vector.clear();
    std::cout << "Passed Int64 test." << std::endl;


    // FLOAT ###################################################################
    // float data: 0xC7777777 => -63351.46484375f
    NBT::Tag::Float float_0 = NBT::Tag::Float();
    float_0.name = "float_0";
    float_0.setValue(-63351.46484375f);
    NBT::Tag::Float float_1 = NBT::Tag::Float("float_1", -63351.46484375f);
    ASSERT(float_0.getValue() == -63351.46484375f);
    ASSERT(float_1.getValue() == -63351.46484375f);
    ASSERT(float_0.getTagType() == 5 && float_1.getTagType() == 5);
    ASSERT(!float_0.serialize(&vector).isError);
    ASSERT(!float_1.serialize(&vector).isError);
    ASSERT(vector.size() == 28);
    ASSERT(
        vector.at( 0) == 5 &&
        vector.at( 1) == 0 &&
        vector.at( 2) == 7 &&
        vector.at( 3) == 'f' &&
        vector.at( 4) == 'l' &&
        vector.at( 5) == 'o' &&
        vector.at( 6) == 'a' &&
        vector.at( 7) == 't' &&
        vector.at( 8) == '_' &&
        vector.at( 9) == '0' &&
        vector.at(10) == 0xC7 &&
        vector.at(11) == 0x77 &&
        vector.at(12) == 0x77 &&
        vector.at(13) == 0x77 &&
        vector.at(14) == 5 &&
        vector.at(15) == 0 &&
        vector.at(16) == 7 &&
        vector.at(17) == 'f' &&
        vector.at(18) == 'l' &&
        vector.at(19) == 'o' &&
        vector.at(20) == 'a' &&
        vector.at(21) == 't' &&
        vector.at(22) == '_' &&
        vector.at(23) == '1' &&
        vector.at(24) == 0xC7 &&
        vector.at(25) == 0x77 &&
        vector.at(26) == 0x77 &&
        vector.at(27) == 0x77
    );
    vector.clear();
    ASSERT(!float_0.serializeWithoutHeader(&vector).isError);
    ASSERT(!float_1.serializeWithoutHeader(&vector).isError);
    ASSERT(vector.size() == 8);
    ASSERT(
        vector.at(0) == 0xC7 &&
        vector.at(1) == 0x77 &&
        vector.at(2) == 0x77 &&
        vector.at(3) == 0x77 &&
        vector.at(4) == 0xC7 &&
        vector.at(5) == 0x77 &&
        vector.at(6) == 0x77 &&
        vector.at(7) == 0x77
    );
    vector.clear();
    std::cout << "Passed Float test." << std::endl;


    // DOUBLE ##################################################################
    // double data 0xC034040008000000 => -20.015625476837158203125
    NBT::Tag::Double double_0 = NBT::Tag::Double();
    double_0.name = "double_0";
    double_0.setValue(-20.015625476837158203125);
    NBT::Tag::Double double_1 = NBT::Tag::Double("double_1", -20.015625476837158203125);
    ASSERT(double_0.getValue() == -20.015625476837158203125);
    ASSERT(double_1.getValue() == -20.015625476837158203125);
    ASSERT(double_0.getTagType() == 6 && double_1.getTagType() == 6);
    ASSERT(!double_0.serialize(&vector).isError);
    ASSERT(!double_1.serialize(&vector).isError);
    ASSERT(vector.size() == 38);
    ASSERT(
        vector.at( 0) == 6 &&
        vector.at( 1) == 0 &&
        vector.at( 2) == 8 &&
        vector.at( 3) == 'd' &&
        vector.at( 4) == 'o' &&
        vector.at( 5) == 'u' &&
        vector.at( 6) == 'b' &&
        vector.at( 7) == 'l' &&
        vector.at( 8) == 'e' &&
        vector.at( 9) == '_' &&
        vector.at(10) == '0' &&
        vector.at(11) == 0xC0 &&
        vector.at(12) == 0x34 &&
        vector.at(13) == 0x04 &&
        vector.at(14) == 0x00 &&
        vector.at(15) == 0x08 &&
        vector.at(16) == 0x00 &&
        vector.at(17) == 0x00 &&
        vector.at(18) == 0x00 &&
        vector.at(19) == 6 &&
        vector.at(20) == 0 &&
        vector.at(21) == 8 &&
        vector.at(22) == 'd' &&
        vector.at(23) == 'o' &&
        vector.at(24) == 'u' &&
        vector.at(25) == 'b' &&
        vector.at(26) == 'l' &&
        vector.at(27) == 'e' &&
        vector.at(28) == '_' &&
        vector.at(29) == '1' &&
        vector.at(30) == 0xC0 &&
        vector.at(31) == 0x34 &&
        vector.at(32) == 0x04 &&
        vector.at(33) == 0x00 &&
        vector.at(34) == 0x08 &&
        vector.at(35) == 0x00 &&
        vector.at(36) == 0x00 &&
        vector.at(37) == 0x00
    );
    vector.clear();
    ASSERT(!double_0.serializeWithoutHeader(&vector).isError);
    ASSERT(!double_1.serializeWithoutHeader(&vector).isError);
    ASSERT(vector.size() == 16);
    ASSERT(
        vector.at( 0) == 0xC0 &&
        vector.at( 1) == 0x34 &&
        vector.at( 2) == 0x04 &&
        vector.at( 3) == 0x00 &&
        vector.at( 4) == 0x08 &&
        vector.at( 5) == 0x00 &&
        vector.at( 6) == 0x00 &&
        vector.at( 7) == 0x00 &&
        vector.at( 8) == 0xC0 &&
        vector.at( 9) == 0x34 &&
        vector.at(10) == 0x04 &&
        vector.at(11) == 0x00 &&
        vector.at(12) == 0x08 &&
        vector.at(13) == 0x00 &&
        vector.at(14) == 0x00 &&
        vector.at(15) == 0x00
    );
    vector.clear();
    std::cout << "Passed Double test." << std::endl;


    // INT8_ARRAY ##############################################################
    std::vector<int8_t> int8DataVector = std::vector<int8_t>();
    int8DataVector.push_back(-128);
    int8DataVector.push_back(127);
    int8DataVector.push_back(0);

    NBT::Tag::Int8Array int8a_0 = NBT::Tag::Int8Array();
    int8a_0.name = "int8a_0";
    int8a_0.setData(int8DataVector);
    NBT::Tag::Int8Array int8a_1 = NBT::Tag::Int8Array("int8a_1", int8DataVector);
    NBT::Tag::Int8Array int8a_2 = NBT::Tag::Int8Array("int8a_2", int8DataVector.size(), int8DataVector.data());
    ASSERT(int8a_0.getTagType() == 7 && int8a_1.getTagType() == 7 && int8a_2.getTagType() == 7);
    ASSERT(
        int8a_0.getData() == int8a_1.getData() &&
        int8a_1.getData() == int8a_2.getData()
    );
    ASSERT(
        !int8a_0.getValue(0).isError &&
        !int8a_1.getValue(1).isError &&
        !int8a_2.getValue(2).isError
    );
    ASSERT(
        int8a_0.getValue(3).isError &&
        int8a_2.getValue(3).errorCode == ErrorCodes::OUT_OF_RANGE
    );
    int8a_1.addElement(-127);
    ErrorOrVoid resultGood = int8a_2.removeElement(1);
    ErrorOrVoid resultError = int8a_2.removeElement(2);
    ASSERT(!resultGood.isError && resultError.isError && resultError.errorCode==ErrorCodes::OUT_OF_RANGE);
    resultGood = int8a_2.setValue(1, 15);
    resultError = int8a_2.setValue(2, 7);
    ASSERT(!resultGood.isError && resultError.isError && resultError.errorCode==ErrorCodes::OUT_OF_RANGE);
    ASSERT(
        int8a_0.length()==3 &&
        int8a_1.length()==4 &&
        int8a_2.length()==2
    );
    ASSERT(
        !int8a_0.serialize(&vector).isError &&
        !int8a_1.serialize(&vector).isError &&
        !int8a_2.serialize(&vector).isError
    );
    ASSERT(vector.size() == 51);
    ASSERT(
        vector.at( 0) == 7 &&
        vector.at( 1) == 0 &&
        vector.at( 2) == 7 &&
        vector.at( 3) == 'i' &&
        vector.at( 4) == 'n' &&
        vector.at( 5) == 't' &&
        vector.at( 6) == '8' &&
        vector.at( 7) == 'a' &&
        vector.at( 8) == '_' &&
        vector.at( 9) == '0' &&
        vector.at(10) == 0 &&
        vector.at(11) == 0 &&
        vector.at(12) == 0 &&
        vector.at(13) == 3 &&
        vector.at(14) == 0x80 &&
        vector.at(15) == 0x7F &&
        vector.at(16) == 0x0 &&
        vector.at(17) == 7 &&
        vector.at(18) == 0 &&
        vector.at(19) == 7 &&
        vector.at(20) == 'i' &&
        vector.at(21) == 'n' &&
        vector.at(22) == 't' &&
        vector.at(23) == '8' &&
        vector.at(24) == 'a' &&
        vector.at(25) == '_' &&
        vector.at(26) == '1' &&
        vector.at(27) == 0 &&
        vector.at(28) == 0 &&
        vector.at(29) == 0 &&
        vector.at(30) == 4 &&
        vector.at(31) == 0x80 &&
        vector.at(32) == 0x7F &&
        vector.at(33) == 0x0 &&
        vector.at(34) == 0x81 &&
        vector.at(35) == 7 &&
        vector.at(36) == 0 &&
        vector.at(37) == 7 &&
        vector.at(38) == 'i' &&
        vector.at(39) == 'n' &&
        vector.at(40) == 't' &&
        vector.at(41) == '8' &&
        vector.at(42) == 'a' &&
        vector.at(43) == '_' &&
        vector.at(44) == '2' &&
        vector.at(45) == 0 &&
        vector.at(46) == 0 &&
        vector.at(47) == 0 &&
        vector.at(48) == 2 &&
        vector.at(49) == 0x80 &&
        vector.at(50) == 0xF
    );
    vector.clear();
    ASSERT(
        !int8a_0.serializeWithoutHeader(&vector).isError &&
        !int8a_1.serializeWithoutHeader(&vector).isError &&
        !int8a_2.serializeWithoutHeader(&vector).isError
    );
    ASSERT(vector.size() == 21);
    ASSERT(
        vector.at( 0) == 0 &&
        vector.at( 1) == 0 &&
        vector.at( 2) == 0 &&
        vector.at( 3) == 3 &&
        vector.at( 4) == 0x80 &&
        vector.at( 5) == 0x7F &&
        vector.at( 6) == 0x00 &&
        vector.at( 7) == 0 &&
        vector.at( 8) == 0 &&
        vector.at( 9) == 0 &&
        vector.at(10) == 4 &&
        vector.at(11) == 0x80 &&
        vector.at(12) == 0x7F &&
        vector.at(13) == 0x00 &&
        vector.at(14) == 0x81 &&
        vector.at(15) == 0 &&
        vector.at(16) == 0 &&
        vector.at(17) == 0 &&
        vector.at(18) == 2 &&
        vector.at(19) == 0x80 &&
        vector.at(20) == 0xF
    );
    vector.clear();
    std::cout << "Passed Int8Array test." << std::endl;


    // STRING ##################################################################
    NBT::Tag::String string_0 = NBT::Tag::String();
    string_0.name = "string_0";
    string_0.setValue("I'm blue dabadee dabadie");
    NBT::Tag::String string_1 = NBT::Tag::String("string_1", "Never gonna give you up");
    ASSERT(string_0.getValue() == "I'm blue dabadee dabadie");
    ASSERT(string_1.getValue() == "Never gonna give you up");
    ASSERT(!string_0.serialize(&vector).isError);
    ASSERT(!string_1.serialize(&vector).isError);
    ASSERT(vector.size() == 73);
    ASSERT(
        vector.at( 0) == 8 &&
        vector.at( 1) == 0 &&
        vector.at( 2) == 8 &&
        vector.at( 3) == 's' &&
        vector.at( 4) == 't' &&
        vector.at( 5) == 'r' &&
        vector.at( 6) == 'i' &&
        vector.at( 7) == 'n' &&
        vector.at( 8) == 'g' &&
        vector.at( 9) == '_' &&
        vector.at(10) == '0' &&
        vector.at(11) == 0 &&
        vector.at(12) == 24 &&
        vector.at(13) == 'I' &&
        vector.at(14) == '\'' &&
        vector.at(15) == 'm' &&
        vector.at(16) == ' ' &&
        vector.at(17) == 'b' &&
        vector.at(18) == 'l' &&
        vector.at(19) == 'u' &&
        vector.at(20) == 'e' &&
        vector.at(21) == ' ' &&
        vector.at(22) == 'd' &&
        vector.at(23) == 'a' &&
        vector.at(24) == 'b' &&
        vector.at(25) == 'a' &&
        vector.at(26) == 'd' &&
        vector.at(27) == 'e' &&
        vector.at(28) == 'e' &&
        vector.at(29) == ' ' &&
        vector.at(30) == 'd' &&
        vector.at(31) == 'a' &&
        vector.at(32) == 'b' &&
        vector.at(33) == 'a' &&
        vector.at(34) == 'd' &&
        vector.at(35) == 'i' &&
        vector.at(36) == 'e' &&
        vector.at(37) == 8 &&
        vector.at(38) == 0 &&
        vector.at(39) == 8 &&
        vector.at(40) == 's' &&
        vector.at(41) == 't' &&
        vector.at(42) == 'r' &&
        vector.at(43) == 'i' &&
        vector.at(44) == 'n' &&
        vector.at(45) == 'g' &&
        vector.at(46) == '_' &&
        vector.at(47) == '1' &&
        vector.at(48) == 0 &&
        vector.at(49) == 23 &&
        vector.at(50) == 'N' &&
        vector.at(51) == 'e' &&
        vector.at(52) == 'v' &&
        vector.at(53) == 'e' &&
        vector.at(54) == 'r' &&
        vector.at(55) == ' ' &&
        vector.at(56) == 'g' &&
        vector.at(57) == 'o' &&
        vector.at(58) == 'n' &&
        vector.at(59) == 'n' &&
        vector.at(60) == 'a' &&
        vector.at(61) == ' ' &&
        vector.at(62) == 'g' &&
        vector.at(63) == 'i' &&
        vector.at(64) == 'v' &&
        vector.at(65) == 'e' &&
        vector.at(66) == ' ' &&
        vector.at(67) == 'y' &&
        vector.at(68) == 'o' &&
        vector.at(69) == 'u' &&
        vector.at(70) == ' ' &&
        vector.at(71) == 'u' &&
        vector.at(72) == 'p'
    );
    vector.clear();
    ASSERT(!string_0.serializeWithoutHeader(&vector).isError);
    ASSERT(!string_1.serializeWithoutHeader(&vector).isError);
    ASSERT(vector.size() == 51);
    ASSERT(
        vector.at( 0) == 0 &&
        vector.at( 1) == 24 &&
        vector.at( 2) == 'I' &&
        vector.at( 3) == '\'' &&
        vector.at( 4) == 'm' &&
        vector.at( 5) == ' ' &&
        vector.at( 6) == 'b' &&
        vector.at( 7) == 'l' &&
        vector.at( 8) == 'u' &&
        vector.at( 9) == 'e' &&
        vector.at(10) == ' ' &&
        vector.at(11) == 'd' &&
        vector.at(12) == 'a' &&
        vector.at(13) == 'b' &&
        vector.at(14) == 'a' &&
        vector.at(15) == 'd' &&
        vector.at(16) == 'e' &&
        vector.at(17) == 'e' &&
        vector.at(18) == ' ' &&
        vector.at(19) == 'd' &&
        vector.at(20) == 'a' &&
        vector.at(21) == 'b' &&
        vector.at(22) == 'a' &&
        vector.at(23) == 'd' &&
        vector.at(24) == 'i' &&
        vector.at(25) == 'e' &&
        vector.at(26) == 0 &&
        vector.at(27) == 23 &&
        vector.at(28) == 'N' &&
        vector.at(29) == 'e' &&
        vector.at(30) == 'v' &&
        vector.at(31) == 'e' &&
        vector.at(32) == 'r' &&
        vector.at(33) == ' ' &&
        vector.at(34) == 'g' &&
        vector.at(35) == 'o' &&
        vector.at(36) == 'n' &&
        vector.at(37) == 'n' &&
        vector.at(38) == 'a' &&
        vector.at(39) == ' ' &&
        vector.at(40) == 'g' &&
        vector.at(41) == 'i' &&
        vector.at(42) == 'v' &&
        vector.at(43) == 'e' &&
        vector.at(44) == ' ' &&
        vector.at(45) == 'y' &&
        vector.at(46) == 'o' &&
        vector.at(47) == 'u' &&
        vector.at(48) == ' ' &&
        vector.at(49) == 'u' &&
        vector.at(50) == 'p'
    );
    vector.clear();
    std::cout << "Passed String test." << std::endl;


    // LIST ####################################################################
    // Things to put in the list
    NBT::Tag::Int8* pointer_1_0 = new NBT::Tag::Int8("entry_1_0", 6);
    NBT::Tag::Int8* pointer_1_1 = new NBT::Tag::Int8("entry_1_1", 38);
    NBT::Tag::Int8* pointer_1_2 = new NBT::Tag::Int8("entry_1_2", 125);
    NBT::Tag::Int8* pointer_1_3 = new NBT::Tag::Int8("entry_1_3", -64); // 0xC0
    NBT::Tag::Int8* pointer_2_0 = new NBT::Tag::Int8("entry_2_0", 56);
    NBT::Tag::Int8* pointer_2_1 = new NBT::Tag::Int8("entry_2_1", 28);
    NBT::Tag::Int8* pointer_2_2 = new NBT::Tag::Int8("entry_2_2", 45);
    NBT::Tag::Int8* pointer_2_3 = new NBT::Tag::Int8("entry_2_3", 78);
    NBT::Tag::Int8* pointer_invalid_0 = new NBT::Tag::Int8("ayya", 78);
    NBT::Tag::Int16* pointer_invalid_1 = new NBT::Tag::Int16("ellohhh", 78);
    std::vector<NBT::Tag::Generic*> listDataVector;
    listDataVector.push_back(pointer_2_0);
    listDataVector.push_back(pointer_2_1);
    listDataVector.push_back(pointer_2_2);
    listDataVector.push_back(pointer_2_3);
    std::vector<NBT::Tag::Generic*> invalidListDataVector;
    invalidListDataVector.push_back(pointer_invalid_0);
    invalidListDataVector.push_back(pointer_invalid_1);

    NBT::Tag::List list_0 = NBT::Tag::List();
    ASSERT(list_0.serialize(&vector).isError);
    ASSERT(list_0.serialize(&vector).errorCode == ErrorCodes::INVALID_TYPE);
    vector.clear();
    NBT::Tag::List list_1 = NBT::Tag::List("list_1", NBT::TagType::INT8);
    ASSERT(list_1.getContainedType() == NBT::TagType::INT8);
    ASSERT(!list_1.appendPointer(pointer_1_0).isError);
    ASSERT(!list_1.appendPointer(pointer_1_1).isError);
    ASSERT(!list_1.appendPointer(pointer_1_2).isError);
    ASSERT(!list_1.appendPointer(pointer_1_3).isError);
    NBT::Tag::Int16* pointer_invalid = new NBT::Tag::Int16("invalid", 400);
    resultError = list_1.appendPointer(pointer_invalid);
    ASSERT(resultError.isError && resultError.errorCode == ErrorCodes::INVALID_TYPE);
    ErrorOr<NBT::Tag::List*> invalid_list_or_error = NBT::Tag::List::constructWithData("list_invalid", invalidListDataVector);
    ASSERT(invalid_list_or_error.isError);
    ASSERT(invalid_list_or_error.errorCode == ErrorCodes::MIXED_TYPES);
    ErrorOr<NBT::Tag::List*> list_2_or_error = NBT::Tag::List::constructWithData("list_2", listDataVector);
    ASSERT(!list_2_or_error.isError);
    NBT::Tag::List* list_2 = list_2_or_error.value;
    ASSERT(list_2->getContainedType() == NBT::TagType::INT8);
    ASSERT(list_1.length() == 4 && list_2->length() == 4);
    ASSERT(!list_2->deleteElement(1).isError);
    ASSERT(list_2->deleteElement(3).isError && list_2->deleteElement(3).errorCode == ErrorCodes::OUT_OF_RANGE);
    ASSERT(!list_2->getElementPointer(2).isError && dynamic_cast<NBT::Tag::Int8*>(list_2->getElementPointer(2).value)->getValue() == 78);
    ASSERT(list_2->getElementPointer(3).isError && list_2->getElementPointer(3).errorCode == ErrorCodes::OUT_OF_RANGE);
    ASSERT(!list_2->setElementPointerAt(0, new NBT::Tag::Int8("set_entry", 3)).isError);
    ErrorOrVoid resultRange = list_2->setElementPointerAt(3, new NBT::Tag::Int8("out_of_range_entry", 2));
    ASSERT(resultRange.isError);
    ASSERT(resultRange.errorCode == ErrorCodes::OUT_OF_RANGE);
    ErrorOrVoid resultType = list_2->setElementPointerAt(0, new NBT::Tag::Int16());
    ASSERT(resultType.isError);
    ASSERT(resultType.errorCode == ErrorCodes::INVALID_TYPE);
    ASSERT(list_2->length() == 3);

    ASSERT(!list_1.serialize(&vector).isError);
    ASSERT(!list_2->serialize(&vector).isError);
    ASSERT(vector.size() == 35);
    ASSERT(
        vector.at( 0) == 9 &&
        vector.at( 1) == 0 &&
        vector.at( 2) == 6 &&
        vector.at( 3) == 'l' &&
        vector.at( 4) == 'i' &&
        vector.at( 5) == 's' &&
        vector.at( 6) == 't' &&
        vector.at( 7) == '_' &&
        vector.at( 8) == '1' &&
        vector.at( 9) == 1 &&
        vector.at(10) == 0 &&
        vector.at(11) == 0 &&
        vector.at(12) == 0 &&
        vector.at(13) == 4 &&
        vector.at(14) == 6 &&
        vector.at(15) == 38 &&
        vector.at(16) == 125 &&
        vector.at(17) == 0xC0 &&
        vector.at(18) == 9 &&
        vector.at(19) == 0 &&
        vector.at(20) == 6 &&
        vector.at(21) == 'l' &&
        vector.at(22) == 'i' &&
        vector.at(23) == 's' &&
        vector.at(24) == 't' &&
        vector.at(25) == '_' &&
        vector.at(26) == '2' &&
        vector.at(27) == 1 &&
        vector.at(28) == 0 &&
        vector.at(29) == 0 &&
        vector.at(30) == 0 &&
        vector.at(31) == 3 &&
        vector.at(32) == 3 &&
        vector.at(33) == 45 &&
        vector.at(34) == 78
    );
    vector.clear();
    ASSERT(!list_1.serializeWithoutHeader(&vector).isError);
    ASSERT(!list_2->serializeWithoutHeader(&vector).isError);
    ASSERT(vector.size() == 17);
    ASSERT(
        vector.at( 0) == 1 &&
        vector.at( 1) == 0 &&
        vector.at( 2) == 0 &&
        vector.at( 3) == 0 &&
        vector.at( 4) == 4 &&
        vector.at( 5) == 6 &&
        vector.at( 6) == 38 &&
        vector.at( 7) == 125 &&
        vector.at( 8) == 0xC0 &&
        vector.at( 9) == 1 &&
        vector.at(10) == 0 &&
        vector.at(11) == 0 &&
        vector.at(12) == 0 &&
        vector.at(13) == 3 &&
        vector.at(14) == 3 &&
        vector.at(15) == 45 &&
        vector.at(16) == 78
    );
    vector.clear();
    std::cout << "Passed List test." << std::endl;


    // COMPOUND ################################################################
    // Things to put in the compound
    std::vector<NBT::Tag::Generic*> compoundDataVector = std::vector<NBT::Tag::Generic*>();
    compoundDataVector.push_back(new NBT::Tag::Int8("0", 0));
    compoundDataVector.push_back(new NBT::Tag::Int16("will be deleted", 0x1337));
    compoundDataVector.push_back(new NBT::Tag::Int16("1", 0x1337));
    compoundDataVector.push_back(new NBT::Tag::String("2", "Hello World!"));
    std::vector<NBT::Tag::Generic*> invalidCompoundDataVector;
    invalidCompoundDataVector.push_back(new NBT::Tag::End());
    invalidCompoundDataVector.push_back(new NBT::Tag::End());
    std::vector<NBT::Tag::Generic*> compoundDataVectorWithEnd;
    compoundDataVectorWithEnd.push_back(new NBT::Tag::Int8("eeee", 25));
    compoundDataVectorWithEnd.push_back(new NBT::Tag::End());

    NBT::Tag::Compound compound_0 = NBT::Tag::Compound();
    compound_0.name = "compound_0";
    NBT::Tag::Compound compound_1 = NBT::Tag::Compound("compound_1");
    ErrorOr<NBT::Tag::Compound*> invalid_compound_or_error = NBT::Tag::Compound::constructWithData("iiiiii", invalidCompoundDataVector);
    ASSERT(invalid_compound_or_error.isError);
    ASSERT(invalid_compound_or_error.errorCode == ErrorCodes::NOT_ALLOWED);
    ErrorOr<NBT::Tag::Compound*> alternate_compound_or_error = NBT::Tag::Compound::constructWithData("iiiiii", compoundDataVectorWithEnd);
    ASSERT(!alternate_compound_or_error.isError);
    ErrorOr<NBT::Tag::Compound*> compound_2_or_error = NBT::Tag::Compound::constructWithData("compound_2", compoundDataVector);
    ASSERT(!compound_2_or_error.isError);
    NBT::Tag::Compound* compound_2 = compound_2_or_error.value;

    ASSERT(!compound_1.appendPointer(new NBT::Tag::Int32("0", 69420)).isError);
    ASSERT(!compound_1.appendPointer(new NBT::Tag::Int8("1", 1)).isError);
    ASSERT(compound_1.appendPointer(new NBT::Tag::End()).isError && compound_1.appendPointer(new NBT::Tag::End()).errorCode == ErrorCodes::NOT_ALLOWED);
    ASSERT(!compound_0.getElementPointer(0).isError && compound_0.getElementPointer(0).value->getTagType() == NBT::TagType::END);
    ASSERT(compound_0.getElementPointer(1).isError && compound_0.getElementPointer(1).errorCode == ErrorCodes::OUT_OF_RANGE);
    ASSERT(!compound_1.getElementPointer(0).isError && compound_1.getElementPointer(0).value->getTagType() == NBT::TagType::INT32);
    ASSERT(!compound_1.getElementPointer(1).isError && compound_1.getElementPointer(1).value->getTagType() == NBT::TagType::INT8);
    ASSERT(!compound_0.setElementPointerAt(0, new NBT::Tag::End()).isError);
    ASSERT(!compound_1.setElementPointerAt(1, new NBT::Tag::Int16("set_element", 0xFFF)).isError);
    ErrorOrVoid resultNotAllowed = compound_0.setElementPointerAt(0, new NBT::Tag::Int64());
    ASSERT(resultNotAllowed.isError && resultNotAllowed.errorCode==ErrorCodes::NOT_ALLOWED);
    resultNotAllowed = compound_1.setElementPointerAt(0, new NBT::Tag::End());
    ASSERT(resultNotAllowed.isError && resultNotAllowed.errorCode==ErrorCodes::NOT_ALLOWED);
    ASSERT(compound_0.setElementPointerAt(1, new NBT::Tag::Int8()).isError && compound_0.setElementPointerAt(1, new NBT::Tag::Int8()).errorCode == ErrorCodes::OUT_OF_RANGE);
    ASSERT(!compound_2->deleteElement(1).isError);
    ASSERT(compound_0.deleteElement(0).isError && compound_0.deleteElement(0).errorCode == ErrorCodes::NOT_ALLOWED);
    ASSERT(compound_0.deleteElement(1).isError && compound_0.deleteElement(1).errorCode == ErrorCodes::OUT_OF_RANGE);
    ASSERT(compound_0.length() == 1);
    ASSERT(compound_1.length() == 3);
    ASSERT(compound_2->length() == 4);
    compound_0.serialize(&vector);
    compound_1.serialize(&vector);
    compound_2->serialize(&vector);
    ASSERT(vector.size() == 95);
    ASSERT(
        vector.at( 0) == 10 &&
        vector.at( 1) == 0 &&
        vector.at( 2) == 10 &&
        vector.at( 3) == 'c' &&
        vector.at( 4) == 'o' &&
        vector.at( 5) == 'm' &&
        vector.at( 6) == 'p' &&
        vector.at( 7) == 'o' &&
        vector.at( 8) == 'u' &&
        vector.at( 9) == 'n' &&
        vector.at(10) == 'd' &&
        vector.at(11) == '_' &&
        vector.at(12) == '0' &&
        vector.at(13) == 0 &&
        vector.at(14) == 10 &&
        vector.at(15) == 0 &&
        vector.at(16) == 10 &&
        vector.at(17) == 'c' &&
        vector.at(18) == 'o' &&
        vector.at(19) == 'm' &&
        vector.at(20) == 'p' &&
        vector.at(21) == 'o' &&
        vector.at(22) == 'u' &&
        vector.at(23) == 'n' &&
        vector.at(24) == 'd' &&
        vector.at(25) == '_' &&
        vector.at(26) == '1' &&
        vector.at(27) == 3 &&
        vector.at(28) == 0 &&
        vector.at(29) == 1 &&
        vector.at(30) == '0' &&
        vector.at(31) == 0x00 &&
        vector.at(32) == 0x01 &&
        vector.at(33) == 0x0f &&
        vector.at(34) == 0x2c &&
        vector.at(35) == 2 &&
        vector.at(36) == 0 &&
        vector.at(37) == 11 &&
        vector.at(38) == 's' &&
        vector.at(39) == 'e' &&
        vector.at(40) == 't' &&
        vector.at(41) == '_' &&
        vector.at(42) == 'e' &&
        vector.at(43) == 'l' &&
        vector.at(44) == 'e' &&
        vector.at(45) == 'm' &&
        vector.at(46) == 'e' &&
        vector.at(47) == 'n' &&
        vector.at(48) == 't' &&
        vector.at(49) == 0x0F &&
        vector.at(50) == 0xFF &&
        vector.at(51) == 0 &&
        vector.at(52) == 10 &&
        vector.at(53) == 0 &&
        vector.at(54) == 10 &&
        vector.at(55) == 'c' &&
        vector.at(56) == 'o' &&
        vector.at(57) == 'm' &&
        vector.at(58) == 'p' &&
        vector.at(59) == 'o' &&
        vector.at(60) == 'u' &&
        vector.at(61) == 'n' &&
        vector.at(62) == 'd' &&
        vector.at(63) == '_' &&
        vector.at(64) == '2' &&
        vector.at(65) == 1 &&
        vector.at(66) == 0 &&
        vector.at(67) == 1 &&
        vector.at(68) == '0' &&
        vector.at(69) == 0x0 &&
        vector.at(70) == 2 &&
        vector.at(71) == 0 &&
        vector.at(72) == 1 &&
        vector.at(73) == '1' &&
        vector.at(74) == 0x13 &&
        vector.at(75) == 0x37 &&
        vector.at(76) == 8 &&
        vector.at(77) == 0 &&
        vector.at(78) == 1 &&
        vector.at(79) == '2' &&
        vector.at(80) == 0 &&
        vector.at(81) == 12 &&
        vector.at(82) == 'H' &&
        vector.at(83) == 'e' &&
        vector.at(84) == 'l' &&
        vector.at(85) == 'l' &&
        vector.at(86) == 'o' &&
        vector.at(87) == ' ' &&
        vector.at(88) == 'W' &&
        vector.at(89) == 'o' &&
        vector.at(90) == 'r' &&
        vector.at(91) == 'l' &&
        vector.at(92) == 'd' &&
        vector.at(93) == '!' &&
        vector.at(94) == 0
    );
    vector.clear();
    compound_0.serializeWithoutHeader(&vector);
    compound_1.serializeWithoutHeader(&vector);
    compound_2->serializeWithoutHeader(&vector);
    ASSERT(vector.size() == 56);
    ASSERT(
        vector.at( 0) == 0 &&
        vector.at( 1) == 3 &&
        vector.at( 2) == 0 &&
        vector.at( 3) == 1 &&
        vector.at( 4) == '0' &&
        vector.at( 5) == 0x00 &&
        vector.at( 6) == 0x01 &&
        vector.at( 7) == 0x0f &&
        vector.at( 8) == 0x2c &&
        vector.at( 9) == 2 &&
        vector.at(10) == 0 &&
        vector.at(11) == 11 &&
        vector.at(12) == 's' &&
        vector.at(13) == 'e' &&
        vector.at(14) == 't' &&
        vector.at(15) == '_' &&
        vector.at(16) == 'e' &&
        vector.at(17) == 'l' &&
        vector.at(18) == 'e' &&
        vector.at(19) == 'm' &&
        vector.at(20) == 'e' &&
        vector.at(21) == 'n' &&
        vector.at(22) == 't' &&
        vector.at(23) == 0x0F &&
        vector.at(24) == 0xFF &&
        vector.at(25) == 0 &&
        vector.at(26) == 1 &&
        vector.at(27) == 0 &&
        vector.at(28) == 1 &&
        vector.at(29) == '0' &&
        vector.at(30) == 0x0 &&
        vector.at(31) == 2 &&
        vector.at(32) == 0 &&
        vector.at(33) == 1 &&
        vector.at(34) == '1' &&
        vector.at(35) == 0x13 &&
        vector.at(36) == 0x37 &&
        vector.at(37) == 8 &&
        vector.at(38) == 0 &&
        vector.at(39) == 1 &&
        vector.at(40) == '2' &&
        vector.at(41) == 0 &&
        vector.at(42) == 12 &&
        vector.at(43) == 'H' &&
        vector.at(44) == 'e' &&
        vector.at(45) == 'l' &&
        vector.at(46) == 'l' &&
        vector.at(47) == 'o' &&
        vector.at(48) == ' ' &&
        vector.at(49) == 'W' &&
        vector.at(50) == 'o' &&
        vector.at(51) == 'r' &&
        vector.at(52) == 'l' &&
        vector.at(53) == 'd' &&
        vector.at(54) == '!' &&
        vector.at(55) == 0
    );
    vector.clear();
    std::cout << "Passed Compound test." << std::endl;

    // INT32_ARRAY #############################################################
    std::vector<int32_t> int32DataVector = std::vector<int32_t>();
    int32DataVector.push_back(-2147483648);
    int32DataVector.push_back(2147483647);
    int32DataVector.push_back(0);

    NBT::Tag::Int32Array int32a_0 = NBT::Tag::Int32Array();
    int32a_0.name = "int32a_0";
    int32a_0.setData(int32DataVector);
    NBT::Tag::Int32Array int32a_1 = NBT::Tag::Int32Array("int32a_1", int32DataVector);
    NBT::Tag::Int32Array int32a_2 = NBT::Tag::Int32Array("int32a_2", int32DataVector.size(), int32DataVector.data());
    ASSERT(int32a_0.getTagType() == 11 && int32a_1.getTagType() == 11 && int32a_2.getTagType() == 11);
    ASSERT(
        int32a_0.getData() == int32a_1.getData() &&
        int32a_1.getData() == int32a_2.getData()
    );
    ASSERT(
        !int32a_0.getValue(0).isError &&
        !int32a_1.getValue(1).isError &&
        !int32a_2.getValue(2).isError
    );
    ASSERT(int32a_0.getValue(3).isError);
    ASSERT(int32a_2.getValue(3).errorCode == ErrorCodes::OUT_OF_RANGE);
    int32a_1.addElement(-2147483647);
    resultGood = int32a_2.removeElement(1);
    resultError = int32a_2.removeElement(2);
    ASSERT(!resultGood.isError && resultError.isError && resultError.errorCode==ErrorCodes::OUT_OF_RANGE);
    resultGood = int32a_2.setValue(1, 15);
    resultError = int32a_2.setValue(2, 7);
    ASSERT(!resultGood.isError && resultError.isError && resultError.errorCode==ErrorCodes::OUT_OF_RANGE);
    ASSERT(
        int32a_0.length()==3 &&
        int32a_1.length()==4 &&
        int32a_2.length()==2
    );
    ASSERT(
        !int32a_0.serialize(&vector).isError &&
        !int32a_1.serialize(&vector).isError &&
        !int32a_2.serialize(&vector).isError
    );
    ASSERT(vector.size() == 81);
    ASSERT(
        vector.at( 0) == 11 &&
        vector.at( 1) == 0 &&
        vector.at( 2) == 8 &&
        vector.at( 3) == 'i' &&
        vector.at( 4) == 'n' &&
        vector.at( 5) == 't' &&
        vector.at( 6) == '3' &&
        vector.at( 7) == '2' &&
        vector.at( 8) == 'a' &&
        vector.at( 9) == '_' &&
        vector.at(10) == '0' &&
        vector.at(11) == 0 &&
        vector.at(12) == 0 &&
        vector.at(13) == 0 &&
        vector.at(14) == 3 &&
        vector.at(15) == 0x80 &&
        vector.at(16) == 0x00 &&
        vector.at(17) == 0x00 &&
        vector.at(18) == 0x00 &&
        vector.at(19) == 0x7F &&
        vector.at(20) == 0xFF &&
        vector.at(21) == 0xFF &&
        vector.at(22) == 0xFF &&
        vector.at(23) == 0x00 &&
        vector.at(24) == 0x00 &&
        vector.at(25) == 0x00 &&
        vector.at(26) == 0x00 &&
        vector.at(27) == 11 &&
        vector.at(28) == 0 &&
        vector.at(29) == 8 &&
        vector.at(30) == 'i' &&
        vector.at(31) == 'n' &&
        vector.at(32) == 't' &&
        vector.at(33) == '3' &&
        vector.at(34) == '2' &&
        vector.at(35) == 'a' &&
        vector.at(36) == '_' &&
        vector.at(37) == '1' &&
        vector.at(38) == 0 &&
        vector.at(39) == 0 &&
        vector.at(40) == 0 &&
        vector.at(41) == 4 &&
        vector.at(42) == 0x80 &&
        vector.at(43) == 0x00 &&
        vector.at(44) == 0x00 &&
        vector.at(45) == 0x00 &&
        vector.at(46) == 0x7F &&
        vector.at(47) == 0xFF &&
        vector.at(48) == 0xFF &&
        vector.at(49) == 0xFF &&
        vector.at(50) == 0x00 &&
        vector.at(51) == 0x00 &&
        vector.at(52) == 0x00 &&
        vector.at(53) == 0x00 &&
        vector.at(54) == 0x80 &&
        vector.at(55) == 0x00 &&
        vector.at(56) == 0x00 &&
        vector.at(57) == 0x01 &&
        vector.at(58) == 11 &&
        vector.at(59) == 0 &&
        vector.at(60) == 8 &&
        vector.at(61) == 'i' &&
        vector.at(62) == 'n' &&
        vector.at(63) == 't' &&
        vector.at(64) == '3' &&
        vector.at(65) == '2' &&
        vector.at(66) == 'a' &&
        vector.at(67) == '_' &&
        vector.at(68) == '2' &&
        vector.at(69) == 0 &&
        vector.at(70) == 0 &&
        vector.at(71) == 0 &&
        vector.at(72) == 2 &&
        vector.at(73) == 0x80 &&
        vector.at(74) == 0x00 &&
        vector.at(75) == 0x00 &&
        vector.at(76) == 0x00 &&
        vector.at(77) == 0x00 &&
        vector.at(78) == 0x00 &&
        vector.at(70) == 0x00 &&
        vector.at(80) == 0x0F
    );
    vector.clear();
    ASSERT(
        !int32a_0.serializeWithoutHeader(&vector).isError &&
        !int32a_1.serializeWithoutHeader(&vector).isError &&
        !int32a_2.serializeWithoutHeader(&vector).isError
    );
    ASSERT(vector.size() == 48);
    ASSERT(
        vector.at( 0) == 0 &&
        vector.at( 1) == 0 &&
        vector.at( 2) == 0 &&
        vector.at( 3) == 3 &&
        vector.at( 4) == 0x80 &&
        vector.at( 5) == 0x00 &&
        vector.at( 6) == 0x00 &&
        vector.at( 7) == 0x00 &&
        vector.at( 8) == 0x7F &&
        vector.at( 9) == 0xFF &&
        vector.at(10) == 0xFF &&
        vector.at(11) == 0xFF &&
        vector.at(12) == 0x00 &&
        vector.at(13) == 0x00 &&
        vector.at(14) == 0x00 &&
        vector.at(15) == 0x00 &&
        vector.at(16) == 0 &&
        vector.at(17) == 0 &&
        vector.at(18) == 0 &&
        vector.at(19) == 4 &&
        vector.at(20) == 0x80 &&
        vector.at(21) == 0x00 &&
        vector.at(22) == 0x00 &&
        vector.at(23) == 0x00 &&
        vector.at(24) == 0x7F &&
        vector.at(25) == 0xFF &&
        vector.at(26) == 0xFF &&
        vector.at(27) == 0xFF &&
        vector.at(28) == 0x00 &&
        vector.at(29) == 0x00 &&
        vector.at(30) == 0x00 &&
        vector.at(31) == 0x00 &&
        vector.at(32) == 0x80 &&
        vector.at(33) == 0x00 &&
        vector.at(34) == 0x00 &&
        vector.at(35) == 0x01 &&
        vector.at(36) == 0 &&
        vector.at(37) == 0 &&
        vector.at(38) == 0 &&
        vector.at(39) == 2 &&
        vector.at(40) == 0x80 &&
        vector.at(41) == 0x00 &&
        vector.at(42) == 0x00 &&
        vector.at(43) == 0x00 &&
        vector.at(44) == 0x00 &&
        vector.at(45) == 0x00 &&
        vector.at(46) == 0x00 &&
        vector.at(47) == 0x0F
    );
    vector.clear();
    std::cout << "Passed Int32Array test." << std::endl;


    // INT64_ARRAY #############################################################
    std::vector<int64_t> int64DataVector = std::vector<int64_t>();
    int64DataVector.push_back(-9223372036854775808);
    int64DataVector.push_back(9223372036854775807);
    int64DataVector.push_back(0);

    NBT::Tag::Int64Array int64a_0 = NBT::Tag::Int64Array();
    int64a_0.name = "int64a_0";
    int64a_0.setData(int64DataVector);
    NBT::Tag::Int64Array int64a_1 = NBT::Tag::Int64Array("int64a_1", int64DataVector);
    NBT::Tag::Int64Array int64a_2 = NBT::Tag::Int64Array("int64a_2", int64DataVector.size(), int64DataVector.data());
    ASSERT(int64a_0.getTagType() == 12 && int64a_1.getTagType() == 12 && int64a_2.getTagType() == 12);
    ASSERT(
        int64a_0.getData() == int64a_1.getData() &&
        int64a_1.getData() == int64a_2.getData()
    );
    ASSERT(
        !int64a_0.getValue(0).isError &&
        !int64a_1.getValue(1).isError &&
        !int64a_2.getValue(2).isError
    );
    ASSERT(int64a_0.getValue(3).isError);
    ASSERT(int64a_2.getValue(3).errorCode == ErrorCodes::OUT_OF_RANGE);
    int64a_1.addElement(-9223372036854775807);
    resultGood = int64a_2.removeElement(1);
    resultError = int64a_2.removeElement(2);
    ASSERT(!resultGood.isError && resultError.isError && resultError.errorCode==ErrorCodes::OUT_OF_RANGE);
    resultGood = int64a_2.setValue(1, 15);
    resultError = int64a_2.setValue(2, 7);
    ASSERT(!resultGood.isError && resultError.isError && resultError.errorCode==ErrorCodes::OUT_OF_RANGE);
    ASSERT(
        int64a_0.length()==3 &&
        int64a_1.length()==4 &&
        int64a_2.length()==2
    );
    ASSERT(
        !int64a_0.serialize(&vector).isError &&
        !int64a_1.serialize(&vector).isError &&
        !int64a_2.serialize(&vector).isError
    );
    ASSERT(vector.size() == 117);
    ASSERT(
        vector.at(  0) == 12 &&
        vector.at(  1) == 0 &&
        vector.at(  2) == 8 &&
        vector.at(  3) == 'i' &&
        vector.at(  4) == 'n' &&
        vector.at(  5) == 't' &&
        vector.at(  6) == '6' &&
        vector.at(  7) == '4' &&
        vector.at(  8) == 'a' &&
        vector.at(  9) == '_' &&
        vector.at( 10) == '0' &&
        vector.at( 11) == 0 &&
        vector.at( 12) == 0 &&
        vector.at( 13) == 0 &&
        vector.at( 14) == 3 &&
        vector.at( 15) == 0x80 &&
        vector.at( 16) == 0x00 &&
        vector.at( 17) == 0x00 &&
        vector.at( 18) == 0x00 &&
        vector.at( 19) == 0x00 &&
        vector.at( 20) == 0x00 &&
        vector.at( 21) == 0x00 &&
        vector.at( 22) == 0x00 &&
        vector.at( 23) == 0x7F &&
        vector.at( 24) == 0xFF &&
        vector.at( 25) == 0xFF &&
        vector.at( 26) == 0xFF &&
        vector.at( 27) == 0xFF &&
        vector.at( 28) == 0xFF &&
        vector.at( 29) == 0xFF &&
        vector.at( 30) == 0xFF &&
        vector.at( 31) == 0x00 &&
        vector.at( 32) == 0x00 &&
        vector.at( 33) == 0x00 &&
        vector.at( 34) == 0x00 &&
        vector.at( 35) == 0x00 &&
        vector.at( 36) == 0x00 &&
        vector.at( 37) == 0x00 &&
        vector.at( 38) == 0x00 &&
        vector.at( 39) == 12 &&
        vector.at( 40) == 0 &&
        vector.at( 41) == 8 &&
        vector.at( 42) == 'i' &&
        vector.at( 43) == 'n' &&
        vector.at( 44) == 't' &&
        vector.at( 45) == '6' &&
        vector.at( 46) == '4' &&
        vector.at( 47) == 'a' &&
        vector.at( 48) == '_' &&
        vector.at( 49) == '1' &&
        vector.at( 50) == 0 &&
        vector.at( 51) == 0 &&
        vector.at( 52) == 0 &&
        vector.at( 53) == 4 &&
        vector.at( 54) == 0x80 &&
        vector.at( 55) == 0x00 &&
        vector.at( 56) == 0x00 &&
        vector.at( 57) == 0x00 &&
        vector.at( 58) == 0x00 &&
        vector.at( 59) == 0x00 &&
        vector.at( 60) == 0x00 &&
        vector.at( 61) == 0x00 &&
        vector.at( 62) == 0x7F &&
        vector.at( 63) == 0xFF &&
        vector.at( 64) == 0xFF &&
        vector.at( 65) == 0xFF &&
        vector.at( 66) == 0xFF &&
        vector.at( 67) == 0xFF &&
        vector.at( 68) == 0xFF &&
        vector.at( 69) == 0xFF &&
        vector.at( 70) == 0x00 &&
        vector.at( 71) == 0x00 &&
        vector.at( 72) == 0x00 &&
        vector.at( 73) == 0x00 &&
        vector.at( 74) == 0x00 &&
        vector.at( 75) == 0x00 &&
        vector.at( 76) == 0x00 &&
        vector.at( 77) == 0x00 &&
        vector.at( 78) == 0x80 &&
        vector.at( 79) == 0x00 &&
        vector.at( 80) == 0x00 &&
        vector.at( 81) == 0x00 &&
        vector.at( 82) == 0x00 &&
        vector.at( 83) == 0x00 &&
        vector.at( 84) == 0x00 &&
        vector.at( 85) == 0x01 &&
        vector.at( 86) == 12 &&
        vector.at( 87) == 0 &&
        vector.at( 88) == 8 &&
        vector.at( 89) == 'i' &&
        vector.at( 90) == 'n' &&
        vector.at( 91) == 't' &&
        vector.at( 92) == '6' &&
        vector.at( 93) == '4' &&
        vector.at( 94) == 'a' &&
        vector.at( 95) == '_' &&
        vector.at( 96) == '2' &&
        vector.at( 97) == 0 &&
        vector.at( 98) == 0 &&
        vector.at( 99) == 0 &&
        vector.at(100) == 2 &&
        vector.at(101) == 0x80 &&
        vector.at(102) == 0x00 &&
        vector.at(103) == 0x00 &&
        vector.at(104) == 0x00 &&
        vector.at(105) == 0x00 &&
        vector.at(106) == 0x00 &&
        vector.at(107) == 0x00 &&
        vector.at(108) == 0x00 &&
        vector.at(109) == 0x00 &&
        vector.at(110) == 0x00 &&
        vector.at(111) == 0x00 &&
        vector.at(112) == 0x00 &&
        vector.at(113) == 0x00 &&
        vector.at(114) == 0x00 &&
        vector.at(115) == 0x00 &&
        vector.at(116) == 0x0F
    );
    vector.clear();
    ASSERT(
        !int64a_0.serializeWithoutHeader(&vector).isError &&
        !int64a_1.serializeWithoutHeader(&vector).isError &&
        !int64a_2.serializeWithoutHeader(&vector).isError
    );
    ASSERT(vector.size() == 84);
    ASSERT(
        vector.at( 0) == 0 &&
        vector.at( 1) == 0 &&
        vector.at( 2) == 0 &&
        vector.at( 3) == 3 &&
        vector.at( 4) == 0x80 &&
        vector.at( 5) == 0x00 &&
        vector.at( 6) == 0x00 &&
        vector.at( 7) == 0x00 &&
        vector.at( 8) == 0x00 &&
        vector.at( 9) == 0x00 &&
        vector.at(10) == 0x00 &&
        vector.at(11) == 0x00 &&
        vector.at(12) == 0x7F &&
        vector.at(13) == 0xFF &&
        vector.at(14) == 0xFF &&
        vector.at(15) == 0xFF &&
        vector.at(16) == 0xFF &&
        vector.at(17) == 0xFF &&
        vector.at(18) == 0xFF &&
        vector.at(19) == 0xFF &&
        vector.at(20) == 0x00 &&
        vector.at(21) == 0x00 &&
        vector.at(22) == 0x00 &&
        vector.at(23) == 0x00 &&
        vector.at(24) == 0x00 &&
        vector.at(25) == 0x00 &&
        vector.at(26) == 0x00 &&
        vector.at(27) == 0x00 &&
        vector.at(28) == 0 &&
        vector.at(29) == 0 &&
        vector.at(30) == 0 &&
        vector.at(31) == 4 &&
        vector.at(32) == 0x80 &&
        vector.at(33) == 0x00 &&
        vector.at(34) == 0x00 &&
        vector.at(35) == 0x00 &&
        vector.at(36) == 0x00 &&
        vector.at(37) == 0x00 &&
        vector.at(38) == 0x00 &&
        vector.at(39) == 0x00 &&
        vector.at(40) == 0x7F &&
        vector.at(41) == 0xFF &&
        vector.at(42) == 0xFF &&
        vector.at(43) == 0xFF &&
        vector.at(44) == 0xFF &&
        vector.at(45) == 0xFF &&
        vector.at(46) == 0xFF &&
        vector.at(47) == 0xFF &&
        vector.at(48) == 0x00 &&
        vector.at(49) == 0x00 &&
        vector.at(50) == 0x00 &&
        vector.at(51) == 0x00 &&
        vector.at(52) == 0x00 &&
        vector.at(53) == 0x00 &&
        vector.at(54) == 0x00 &&
        vector.at(55) == 0x00 &&
        vector.at(56) == 0x80 &&
        vector.at(57) == 0x00 &&
        vector.at(58) == 0x00 &&
        vector.at(59) == 0x00 &&
        vector.at(60) == 0x00 &&
        vector.at(61) == 0x00 &&
        vector.at(62) == 0x00 &&
        vector.at(63) == 0x01 &&
        vector.at(64) == 0 &&
        vector.at(65) == 0 &&
        vector.at(66) == 0 &&
        vector.at(67) == 2 &&
        vector.at(68) == 0x80 &&
        vector.at(69) == 0x00 &&
        vector.at(70) == 0x00 &&
        vector.at(71) == 0x00 &&
        vector.at(72) == 0x00 &&
        vector.at(73) == 0x00 &&
        vector.at(74) == 0x00 &&
        vector.at(75) == 0x00 &&
        vector.at(76) == 0x00 &&
        vector.at(77) == 0x00 &&
        vector.at(78) == 0x00 &&
        vector.at(79) == 0x00 &&
        vector.at(80) == 0x00 &&
        vector.at(81) == 0x00 &&
        vector.at(82) == 0x00 &&
        vector.at(83) == 0x0F
    );
    vector.clear();
    std::cout << "Passed Int64Array test." << std::endl;


    return 0;
}
