diff options
author | Andrei Karas <akaras@inbox.ru> | 2017-07-07 17:05:13 +0300 |
---|---|---|
committer | Andrei Karas <akaras@inbox.ru> | 2017-07-07 17:53:24 +0300 |
commit | 130f07fd84bfdf781eb42903b3fcbabc26199a3a (patch) | |
tree | e4e560c32177e0a64867c5d1584d9bf64b57bbce /src/unittests | |
parent | 9bbd191307c97c7589f93a64a4eb9abf3f11c46b (diff) | |
download | plus-130f07fd84bfdf781eb42903b3fcbabc26199a3a.tar.gz plus-130f07fd84bfdf781eb42903b3fcbabc26199a3a.tar.bz2 plus-130f07fd84bfdf781eb42903b3fcbabc26199a3a.tar.xz plus-130f07fd84bfdf781eb42903b3fcbabc26199a3a.zip |
Move unit tests into unittests directory.
Diffstat (limited to 'src/unittests')
34 files changed, 19350 insertions, 0 deletions
diff --git a/src/unittests/configuration_unittest.cc b/src/unittests/configuration_unittest.cc new file mode 100644 index 000000000..58073bbdb --- /dev/null +++ b/src/unittests/configuration_unittest.cc @@ -0,0 +1,305 @@ +/* + * The ManaPlus Client + * Copyright (C) 2016-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "configuration.h" +#include "configmanager.h" +#include "dirs.h" +#include "logger.h" + +#include "listeners/configlistener.h" + +#include "utils/delete2.h" + +#include "debug.h" + +namespace +{ + int mCalled = 0; + + class TestConfigListener : public ConfigListener + { + public: + void optionChanged(const std::string &name) override final + { + if (name == "testkey123") + mCalled ++; + } + } testListener; +} // namespace + +TEST_CASE("configuration tests", "configuration") +{ + logger = new Logger(); + + Dirs::initRootDir(); + Dirs::initHomeDir(); + + ConfigManager::initConfiguration(); + + SECTION("configuration undefined") + { + const char *const key = "nonsetvalue"; + REQUIRE(config.getValue(key, "not set") == "not set"); + REQUIRE(config.getValue(key, 12345) == 12345); + REQUIRE(config.getValue(key, 12345U) == 12345U); + REQUIRE(config.getValueInt(key, 12345) == 12345); + REQUIRE(config.getValueBool(key, false) == false); + REQUIRE(config.getValueBool(key, true) == true); + REQUIRE(config.getValue(key, -12345) == -12345); + REQUIRE(config.getValue(key, 12.345) > 12.3); + + REQUIRE(config.getIntValue(key) == 0); + REQUIRE(config.getFloatValue(key) >= 0.0f); + REQUIRE(config.getStringValue(key).empty()); + REQUIRE(config.getBoolValue(key) == false); + } + + SECTION("configuration getint default") + { + const char *const key = "sfxVolume"; + REQUIRE(config.getIntValue(key) == 100); + REQUIRE(config.getFloatValue(key) >= 100.0f); + REQUIRE(config.getStringValue(key) == "100"); + REQUIRE(config.getBoolValue(key) == true); + } + + SECTION("configuration getfloat default") + { + const char *const key = "guialpha"; + REQUIRE(config.getIntValue(key) == 0); + REQUIRE(config.getFloatValue(key) >= 0.8f); + REQUIRE(config.getStringValue(key).substr(0, 3) == "0.8"); + REQUIRE(config.getBoolValue(key) == false); + } + + SECTION("configuration getstring default") + { + const char *const key = "soundwhisper"; + REQUIRE(config.getIntValue(key) == 0); + REQUIRE(config.getFloatValue(key) >= 0.0f); + REQUIRE(config.getStringValue(key) == "newmessage"); + REQUIRE(config.getBoolValue(key) == true); + } + + SECTION("configuration getbool default1") + { + const char *const key = "showgender"; + REQUIRE(config.getIntValue(key) == 1); + REQUIRE(config.getFloatValue(key) >= 1.0f); + REQUIRE(config.getStringValue(key) == "1"); + REQUIRE(config.getBoolValue(key) == true); + } + + SECTION("configuration getbool default2") + { + const char *const key = "showlevel"; + REQUIRE(config.getIntValue(key) == 0); + REQUIRE(config.getFloatValue(key) >= 0.0f); + REQUIRE(config.getStringValue(key) == "0"); + REQUIRE(config.getBoolValue(key) == false); + } + + SECTION("configuration getint set") + { + const char *const key = "sfxVolume"; + config.setValue(key, 50); + REQUIRE(config.getIntValue(key) == 50); + REQUIRE(config.getFloatValue(key) >= 50.0f); + REQUIRE(config.getStringValue(key) == "50"); + REQUIRE(config.getBoolValue(key) == true); + + REQUIRE(config.getValue(key, "not set") == "50"); + REQUIRE(config.getValue(key, 12345) == 50); + REQUIRE(config.getValue(key, 12345U) == 50U); + REQUIRE(config.getValueInt(key, 12345) == 50); + REQUIRE(config.getValueBool(key, false) == true); + REQUIRE(config.getValueBool(key, true) == true); + REQUIRE(config.getValue(key, -12345) == 50); + REQUIRE(config.getValue(key, 12.345) >= 50.0); + } + + SECTION("configuration getfloat set") + { + const char *const key = "guialpha"; + config.setValue(key, 50.5); + REQUIRE(config.getIntValue(key) == 50); + REQUIRE(config.getFloatValue(key) >= 50.4f); + REQUIRE(config.getStringValue(key).substr(0, 2) == "50"); + REQUIRE(config.getBoolValue(key) == true); + + REQUIRE(config.getValue(key, "not set").substr(0, 2) == "50"); + REQUIRE(config.getValue(key, 12345) == 50); + REQUIRE(config.getValue(key, 12345U) == 50U); + REQUIRE(config.getValueInt(key, 12345) == 50); + REQUIRE(config.getValueBool(key, false) == true); + REQUIRE(config.getValueBool(key, true) == true); + REQUIRE(config.getValue(key, -12345) == 50); + REQUIRE(config.getValue(key, 12.345) >= 50.4); + } + + SECTION("configuration getstring set") + { + const char *const key = "soundwhisper"; + config.setValue(key, "test line"); + REQUIRE(config.getIntValue(key) == 0); + REQUIRE(config.getFloatValue(key) >= 0.0f); + REQUIRE(config.getStringValue(key) == "test line"); + REQUIRE(config.getBoolValue(key) == false); + + REQUIRE(config.getValue(key, "not set") == "test line"); + REQUIRE(config.getValue(key, 12345) == 0); + REQUIRE(config.getValue(key, 12345U) == 0U); + REQUIRE(config.getValueInt(key, 12345) == 0); + REQUIRE(config.getValueBool(key, false) == false); + REQUIRE(config.getValueBool(key, true) == false); + REQUIRE(config.getValue(key, -12345) == 0); + REQUIRE(config.getValue(key, 12.345) >= 0.0); + } + + SECTION("configuration getbool set1") + { + const char *const key = "showgender"; + config.setValue(key, true); + REQUIRE(config.getIntValue(key) == 1); + REQUIRE(config.getFloatValue(key) >= 1.0f); + REQUIRE(config.getStringValue(key) == "1"); + REQUIRE(config.getBoolValue(key) == true); + + REQUIRE(config.getValue(key, "not set") == "1"); + REQUIRE(config.getValue(key, 12345) == 1); + REQUIRE(config.getValue(key, 12345U) == 1U); + REQUIRE(config.getValueInt(key, 12345) == 1); + REQUIRE(config.getValueBool(key, false) == true); + REQUIRE(config.getValueBool(key, true) == true); + REQUIRE(config.getValue(key, -12345) == 1); + REQUIRE(config.getValue(key, 12.345) >= 1.0); + } + + SECTION("configuration getbool set2") + { + const char *const key = "showgender"; + config.setValue(key, false); + REQUIRE(config.getIntValue(key) == 0); + REQUIRE(config.getFloatValue(key) >= 0.0f); + REQUIRE(config.getStringValue(key) == "0"); + REQUIRE(config.getBoolValue(key) == false); + + REQUIRE(config.getValue(key, "not set") == "0"); + REQUIRE(config.getValue(key, 12345) == 0); + REQUIRE(config.getValue(key, 12345U) == 0U); + REQUIRE(config.getValueInt(key, 12345) == 0); + REQUIRE(config.getValueBool(key, false) == false); + REQUIRE(config.getValueBool(key, true) == false); + REQUIRE(config.getValue(key, -12345) == 0); + REQUIRE(config.getValue(key, 12.345) >= 0.0); + } + + SECTION("configuration deletekey") + { + const char *const key = "testkey123"; + config.setValue(key, 123); + REQUIRE(config.getValueInt(key, 12345) == 123); + config.deleteKey(key); + REQUIRE(config.getValueInt(key, 12345) == 12345); + } + + SECTION("configuration addlistener") + { + const char *const key = "testkey123"; + REQUIRE(mCalled == 0); + config.addListener(key, &testListener); + REQUIRE(mCalled == 0); + config.setValue(key, 123); + REQUIRE(mCalled == 1); + REQUIRE(config.getValueInt(key, 12345) == 123); + REQUIRE(mCalled == 1); + config.setValue(key, 123); + REQUIRE(mCalled == 2); + config.setSilent(key, true); + REQUIRE(mCalled == 2); + REQUIRE(config.getBoolValue(key) == true); + REQUIRE(mCalled == 2); + config.setSilent(key, false); + REQUIRE(mCalled == 2); + REQUIRE(config.getBoolValue(key) == false); + REQUIRE(mCalled == 2); + config.removeListener(key, &testListener); + } + + SECTION("configuration incvalue") + { + const char *const key = "testkey123"; + config.setValue(key, 10); + REQUIRE(config.getValueInt(key, 12345) == 10); + config.incValue(key); + REQUIRE(config.getValueInt(key, 12345) == 11); + } + + SECTION("configuration resetintvalue") + { + const char *const key = "sfxVolume"; + config.setValue(key, 20); + REQUIRE(config.getIntValue(key) == 20); + REQUIRE(config.getFloatValue(key) >= 20.0f); + REQUIRE(config.getStringValue(key) == "20"); + REQUIRE(config.getBoolValue(key) == true); + config.resetIntValue(key); + REQUIRE(config.getIntValue(key) == 100); + REQUIRE(config.getFloatValue(key) >= 100.0f); + REQUIRE(config.getStringValue(key) == "100"); + REQUIRE(config.getBoolValue(key) == true); + } + + SECTION("configuration resetboolvalue1") + { + const char *const key = "showgender"; + config.setValue(key, false); + REQUIRE(config.getIntValue(key) == 0); + REQUIRE(config.getFloatValue(key) >= 0.0f); + REQUIRE(config.getStringValue(key) == "0"); + REQUIRE(config.getBoolValue(key) == false); + + config.resetBoolValue(key); + REQUIRE(config.getIntValue(key) == 1); + REQUIRE(config.getFloatValue(key) >= 1.0f); + REQUIRE(config.getStringValue(key) == "1"); + REQUIRE(config.getBoolValue(key) == true); + } + + SECTION("configuration resetboolvalue2") + { + const char *const key = "showlevel"; + config.setValue(key, true); + REQUIRE(config.getIntValue(key) == 1); + REQUIRE(config.getFloatValue(key) >= 1.0f); + REQUIRE(config.getStringValue(key) == "1"); + REQUIRE(config.getBoolValue(key) == true); + + config.resetBoolValue(key); + REQUIRE(config.getIntValue(key) == 0); + REQUIRE(config.getFloatValue(key) >= 0.0f); + REQUIRE(config.getStringValue(key) == "0"); + REQUIRE(config.getBoolValue(key) == false); + } + + delete2(logger); +} diff --git a/src/unittests/enums/enums_unittest.cc b/src/unittests/enums/enums_unittest.cc new file mode 100644 index 000000000..ebff849d9 --- /dev/null +++ b/src/unittests/enums/enums_unittest.cc @@ -0,0 +1,35 @@ +/* + * The ManaPlus Client + * Copyright (C) 2015-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "enums/being/gender.h" + +#include "utils/cast.h" + +#include "debug.h" + +TEST_CASE("Gender", "Enums") +{ + REQUIRE(CAST_S32(Gender::FEMALE) == 1); + REQUIRE(Gender::FEMALE == static_cast<GenderT>(1)); + REQUIRE(CAST_S32(Gender::MALE) == 0); + REQUIRE(Gender::MALE == static_cast<GenderT>(0)); +} diff --git a/src/unittests/enums/render/mockdrawtype.h b/src/unittests/enums/render/mockdrawtype.h new file mode 100644 index 000000000..7477684d0 --- /dev/null +++ b/src/unittests/enums/render/mockdrawtype.h @@ -0,0 +1,35 @@ +/* + * The ManaPlus Client + * Copyright (C) 2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef ENUMS_RENDER_MOCKDRAWTYPE_H +#define ENUMS_RENDER_MOCKDRAWTYPE_H +#ifdef UNITTESTS + +#include "enums/simpletypes/enumdefines.h" + +enumStart(MockDrawType) +{ + DrawImage = 0, + DrawPattern = 1 +} +enumEnd(MockDrawType); + +#endif // UNITTESTS +#endif // ENUMS_RENDER_MOCKDRAWTYPE_H diff --git a/src/unittests/fs/files_unittest.cc b/src/unittests/fs/files_unittest.cc new file mode 100644 index 000000000..927891fdd --- /dev/null +++ b/src/unittests/fs/files_unittest.cc @@ -0,0 +1,232 @@ +/* + * The ManaPlus Client + * Copyright (C) 2013-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "logger.h" + +#include "fs/files.h" + +#include "fs/virtfs/fs.h" +#include "fs/virtfs/tools.h" + +#include "utils/delete2.h" +#include "utils/stringutils.h" + +#include "resources/resourcemanager/resourcemanager.h" + +#include "debug.h" + +TEST_CASE("Files renameFile", "") +{ + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + const int sz = 1234567; + char *buf = new char[sz]; + for (int f = 0; f < sz; f ++) + buf[f] = f; + + const std::string name1 = "file1.test"; + const std::string name2 = "file2.test"; + FILE *file = fopen(name1.c_str(), "w+b"); + fwrite(buf, 1, sz, file); + fclose(file); + + REQUIRE(0 == Files::renameFile(name1, name2)); + char *buf2 = new char[sz]; + FILE *file2 = fopen(name2.c_str(), "rb"); + REQUIRE_FALSE(nullptr == file2); + fread(buf2, 1, sz, file2); + fclose(file2); + ::remove(name1.c_str()); + ::remove(name2.c_str()); + + for (int f = 0; f < sz; f ++) + REQUIRE(buf[f] == buf2[f]); + + delete [] buf; + delete [] buf2; + ResourceManager::deleteInstance(); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +// VirtFs::deinit(); +} + +TEST_CASE("Files existsLocal", "") +{ + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + REQUIRE(Files::existsLocal(VirtFs::getPath("help/about.txt")) == true); + REQUIRE_FALSE(Files::existsLocal(VirtFs::getPath("help/about1.txt"))); + REQUIRE_FALSE(Files::existsLocal(VirtFs::getPath("help1/about.txt"))); + ResourceManager::deleteInstance(); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +// VirtFs::deinit(); +} + +TEST_CASE("Files loadTextFileString", "") +{ + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + REQUIRE(VirtFs::loadTextFileString("test/simplefile.txt") == + "this is test \nfile."); + ResourceManager::deleteInstance(); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +// VirtFs::deinit(); +} + +TEST_CASE("Files loadTextFile", "") +{ + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + StringVect lines; + VirtFs::loadTextFile("test/simplefile.txt", lines); + REQUIRE(lines.size() == 2); + REQUIRE(lines[0] == "this is test "); + REQUIRE(lines[1] == "file."); + ResourceManager::deleteInstance(); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +// VirtFs::deinit(); +} + +TEST_CASE("Files saveTextFile", "") +{ + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + const std::string dir = VirtFs::getPath("test"); + REQUIRE(!dir.empty()); + Files::saveTextFile(dir, "tempfile.txt", "test line\ntext line2"); + std::string data = VirtFs::loadTextFileString("test/tempfile.txt"); + ::remove((dir + "/tempfile.txt").c_str()); +#ifdef WIN32 + REQUIRE(data == "test line\r\ntext line2\r\n"); +#else // WIN32 + + REQUIRE(data == "test line\ntext line2\n"); +#endif // WIN32 + + ResourceManager::deleteInstance(); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +// VirtFs::deinit(); +} + +TEST_CASE("Files copyFile1", "") +{ + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + const std::string dir = VirtFs::getPath("test"); + REQUIRE(!dir.empty()); + SECTION("copy") + { + REQUIRE(Files::copyFile(pathJoin(dir, "test.txt"), + pathJoin(dir, "tempfile.txt")) == 0); + std::string data = VirtFs::loadTextFileString("test/tempfile.txt"); + ::remove((dir + "/tempfile.txt").c_str()); + REQUIRE(data == "test line 1\ntest line 2"); + } + + SECTION("errors") + { + REQUIRE(Files::copyFile(pathJoin(dir, "test_not_exists.txt"), + pathJoin(dir, "tempfile.txt")) == -1); + REQUIRE(Files::copyFile(pathJoin(dir, "test.txt"), + "/nonexist/root/dir123") == -1); + } + + ResourceManager::deleteInstance(); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +// VirtFs::deinit(); +} + +TEST_CASE("Files loadTextFileLocal", "") +{ + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + const std::string dir = VirtFs::getPath("test"); + REQUIRE(!dir.empty()); + Files::saveTextFile(dir, "tempfile.txt", "test line\ntext line2"); + StringVect lines; + REQUIRE(Files::loadTextFileLocal(pathJoin(dir, "tempfile.txt"), + lines)); + ::remove((dir + "/tempfile.txt").c_str()); + REQUIRE(lines.size() == 2); + REQUIRE(lines[0] == "test line"); + REQUIRE(lines[1] == "text line2"); + + ResourceManager::deleteInstance(); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +// VirtFs::deinit(); +} + +TEST_CASE("Files getFilesInDir", "") +{ + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + StringVect list; + VirtFs::getFilesInDir("test", + list, + ".gpl"); + REQUIRE(list.size() == 1); + REQUIRE(list[0] == pathJoin("test", "palette.gpl")); + + list.clear(); + VirtFs::getFilesInDir("perserver/default", + list, + ".xml"); + REQUIRE(list.size() == 5); + REQUIRE(list[0] == pathJoin("perserver", "default", "charcreation.xml")); + REQUIRE(list[1] == pathJoin("perserver", "default", "deadmessages.xml")); + REQUIRE(list[2] == + pathJoin("perserver", "default", "defaultcommands.xml")); + REQUIRE(list[3] == pathJoin("perserver", "default", "features.xml")); + REQUIRE(list[4] == pathJoin("perserver", "default", "weapons.xml")); + ResourceManager::deleteInstance(); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +// VirtFs::deinit(); +} diff --git a/src/unittests/fs/virtfs/virtfs1_unittest.cc b/src/unittests/fs/virtfs/virtfs1_unittest.cc new file mode 100644 index 000000000..687316397 --- /dev/null +++ b/src/unittests/fs/virtfs/virtfs1_unittest.cc @@ -0,0 +1,3507 @@ +/* + * The ManaPlus Client + * Copyright (C) 2016-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "fs/files.h" + +#include "fs/virtfs/direntry.h" +#include "fs/virtfs/fs.h" +#include "fs/virtfs/rwops.h" +#include "fs/virtfs/list.h" + +#include "utils/checkutils.h" +#include "utils/delete2.h" +#include "utils/foreach.h" +#include "utils/stringutils.h" + +PRAGMA48(GCC diagnostic push) +PRAGMA48(GCC diagnostic ignored "-Wshadow") +#include <SDL_rwops.h> +PRAGMA48(GCC diagnostic pop) + +#ifndef UNITTESTS_CATCH +#include <algorithm> +#endif // UNITTESTS_CATCH + +#include "debug.h" + +TEST_CASE("VirtFs1 getEntries", "") +{ + VirtFs::init("."); + REQUIRE(VirtFs::getEntries().empty()); + REQUIRE(VirtFs::searchByRootInternal("test", std::string()) == nullptr); + VirtFs::deinit(); +} + +TEST_CASE("VirtFs1 getBaseDir", "") +{ + VirtFs::init("."); + REQUIRE(VirtFs::getBaseDir() != nullptr); + VirtFs::deinit(); +} + +TEST_CASE("VirtFs1 mountDir", "") +{ + VirtFs::init("."); + logger = new Logger(); + const std::string sep = dirSeparator; + SECTION("simple 1") + { + REQUIRE(VirtFs::mountDirSilentTest("dir1", + Append_false)); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, std::string()) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, "dir1") == + nullptr); + REQUIRE(VirtFs::searchByRootInternal("test" + sep, std::string()) == + nullptr); + REQUIRE(VirtFs::getEntries().size() == 1); + REQUIRE(VirtFs::getEntries()[0]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir1"); + } + + SECTION("simple 2") + { + REQUIRE(VirtFs::mountDirSilentTest("dir1/", + Append_true)); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, std::string()) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, "dir1") == + nullptr); + REQUIRE(VirtFs::searchByRootInternal("test" + sep, std::string()) == + nullptr); + REQUIRE(VirtFs::getEntries().size() == 1); + REQUIRE(VirtFs::getEntries()[0]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir1" + sep); + } + + SECTION("simple 3") + { + REQUIRE(VirtFs::mountDirSilentTest("dir1", + Append_false)); + REQUIRE(VirtFs::mountDirSilentTest("dir2", + Append_false)); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, std::string()) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, "dir1") == + nullptr); + REQUIRE(VirtFs::searchByRootInternal("dir2" + sep, std::string()) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal("test" + sep, std::string()) == + nullptr); + REQUIRE(VirtFs::getEntries().size() == 2); + REQUIRE(VirtFs::getEntries()[0]->root == "dir2" + sep); + REQUIRE(VirtFs::getEntries()[1]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[1]->subDir.empty()); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir2"); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[1])->userDir == "dir1"); + } + + SECTION("simple 4") + { + REQUIRE(VirtFs::mountDirSilentTest("dir1\\", + Append_true)); + REQUIRE(VirtFs::mountDirSilentTest("dir2", + Append_true)); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, std::string()) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal("dir2" + sep, std::string()) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal("test" + sep, std::string()) == + nullptr); + REQUIRE(VirtFs::getEntries().size() == 2); + REQUIRE(VirtFs::getEntries()[0]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[1]->root == "dir2" + sep); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[1]->subDir.empty()); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir1" + sep); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[1])->userDir == "dir2"); + } + + SECTION("simple 5") + { + REQUIRE(VirtFs::mountDirSilentTest("dir1", + Append_true)); + REQUIRE(VirtFs::mountDirSilentTest("dir2", + Append_true)); + REQUIRE(VirtFs::mountDirSilentTest("dir3/test", + Append_true)); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, std::string()) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal("dir2" + sep, std::string()) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal( + "dir3" + sep + "test" + sep, std::string()) != nullptr); + REQUIRE(VirtFs::searchByRootInternal("test" + sep, std::string()) == + nullptr); + REQUIRE(VirtFs::getEntries().size() == 3); + REQUIRE(VirtFs::getEntries()[0]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[1]->root == "dir2" + sep); + REQUIRE(VirtFs::getEntries()[2]->root == "dir3" + sep + "test" + sep); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[2]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[1]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[2]->subDir.empty()); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir1"); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[1])->userDir == "dir2"); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[2])->userDir == "dir3" + sep + "test"); + } + + SECTION("simple 6") + { + REQUIRE(VirtFs::mountDirSilentTest("dir1", + Append_true)); + REQUIRE(VirtFs::mountDirSilentTest("dir2", + Append_true)); + REQUIRE(VirtFs::mountDirSilentTest("dir3\\test", + Append_false)); + REQUIRE(VirtFs::searchByRootInternal( + "dir1" + sep + "", std::string()) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + "dir2" + sep + "", std::string()) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + "dir3" + sep + "test" + sep, std::string()) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + "test" + sep + "", std::string()) == nullptr); + REQUIRE(VirtFs::getEntries().size() == 3); + REQUIRE(VirtFs::getEntries()[0]->root == "dir3" + sep + "test" + sep); + REQUIRE(VirtFs::getEntries()[1]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[2]->root == "dir2" + sep); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[2]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[1]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[2]->subDir.empty()); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir3" + sep + "test"); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[1])->userDir == "dir1"); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[2])->userDir == "dir2"); + } + + SECTION("subDir 1") + { + REQUIRE(VirtFs::mountDirSilentTest2("dir1", + dirSeparator, + Append_false)); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, std::string()) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal("test" + sep, std::string()) == + nullptr); + REQUIRE(VirtFs::getEntries().size() == 1); + REQUIRE(VirtFs::getEntries()[0]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir1"); + } + + SECTION("subDir 1.2") + { + REQUIRE(VirtFs::mountDirSilentTest2("dir1", + "dir2", + Append_false)); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, "dir2" + sep) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, "dir1" + sep) == + nullptr); + REQUIRE(VirtFs::searchByRootInternal("test" + sep, "dir2" + sep) == + nullptr); + REQUIRE(VirtFs::getEntries().size() == 1); + REQUIRE(VirtFs::getEntries()[0]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir == "dir2" + sep); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir1"); + } + + SECTION("subDir 2") + { + REQUIRE(VirtFs::mountDirSilentTest2("dir1/", + "dir2", + Append_true)); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, "dir2" + sep) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal("test" + sep, "dir2" + sep) == + nullptr); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, "dir1" + sep) == + nullptr); + REQUIRE(VirtFs::getEntries().size() == 1); + REQUIRE(VirtFs::getEntries()[0]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir == "dir2" + sep); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir1" + sep); + } + + SECTION("subDir 3") + { + REQUIRE(VirtFs::mountDirSilentTest2("dir1", + "dir3", + Append_false)); + REQUIRE(VirtFs::mountDirSilentTest2("dir2", + "dir4", + Append_false)); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, "dir3" + sep) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, "dir1" + sep) == + nullptr); + REQUIRE(VirtFs::searchByRootInternal("dir2" + sep, "dir4" + sep) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal("test" + sep, "dir3" + sep) == + nullptr); + REQUIRE(VirtFs::getEntries().size() == 2); + REQUIRE(VirtFs::getEntries()[0]->root == "dir2" + sep); + REQUIRE(VirtFs::getEntries()[1]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[0]->subDir == "dir4" + sep); + REQUIRE(VirtFs::getEntries()[1]->subDir == "dir3" + sep); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir2"); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[1])->userDir == "dir1"); + } + + SECTION("subDir 4") + { + REQUIRE(VirtFs::mountDirSilentTest2("dir1\\", + "dir3", + Append_true)); + REQUIRE(VirtFs::mountDirSilentTest2("dir2", + "dir4", + Append_true)); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, "dir3" + sep) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, "dir1" + sep) == + nullptr); + REQUIRE(VirtFs::searchByRootInternal("dir2" + sep, "dir4" + sep) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal("test" + sep, "dir3" + sep) == + nullptr); + REQUIRE(VirtFs::getEntries().size() == 2); + REQUIRE(VirtFs::getEntries()[0]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[1]->root == "dir2" + sep); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[0]->subDir == "dir3" + sep); + REQUIRE(VirtFs::getEntries()[1]->subDir == "dir4" + sep); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir1" + sep); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[1])->userDir == "dir2"); + } + + SECTION("subDir 5") + { + REQUIRE(VirtFs::mountDirSilentTest2("dir1", + "dir3", + Append_true)); + REQUIRE(VirtFs::mountDirSilentTest2("dir2", + "dir4", + Append_true)); + REQUIRE(VirtFs::mountDirSilentTest2("dir3/test", + "dir5", + Append_true)); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, "dir3" + sep) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal("dir2" + sep, "dir4" + sep) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal( + "dir3" + sep + "test" + sep, "dir5" + sep) != nullptr); + REQUIRE(VirtFs::searchByRootInternal("test" + sep, "dir3" + sep) == + nullptr); + REQUIRE(VirtFs::getEntries().size() == 3); + REQUIRE(VirtFs::getEntries()[0]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[1]->root == "dir2" + sep); + REQUIRE(VirtFs::getEntries()[2]->root == "dir3" + sep + "test" + sep); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[2]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[0]->subDir == "dir3" + sep); + REQUIRE(VirtFs::getEntries()[1]->subDir == "dir4" + sep); + REQUIRE(VirtFs::getEntries()[2]->subDir == "dir5" + sep); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir1"); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[1])->userDir == "dir2"); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[2])->userDir == "dir3" + sep + "test"); + } + + SECTION("subDir 6") + { + REQUIRE(VirtFs::mountDirSilentTest2("dir1", + "dir1", + Append_true)); + REQUIRE(VirtFs::mountDirSilentTest2("dir2", + "dir2", + Append_true)); + REQUIRE(VirtFs::mountDirSilentTest2("dir3\\test", + "dir3\\test", + Append_false)); + REQUIRE(VirtFs::searchByRootInternal( + "dir1" + sep + "", "dir1" + sep) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + "dir2" + sep + "", "dir2" + sep) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + "dir3" + sep + "test" + sep, + "dir3" + sep + "test" + sep) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + "test" + sep + "", "dir1" + sep) == nullptr); + REQUIRE(VirtFs::getEntries().size() == 3); + REQUIRE(VirtFs::getEntries()[0]->root == "dir3" + sep + "test" + sep); + REQUIRE(VirtFs::getEntries()[1]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[2]->root == "dir2" + sep); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[2]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[0]->subDir == + "dir3" + sep + "test" + sep); + REQUIRE(VirtFs::getEntries()[1]->subDir == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[2]->subDir == "dir2" + sep); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir3" + sep + "test"); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[1])->userDir == "dir1"); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[2])->userDir == "dir2"); + } + + SECTION("subDir 7") + { + REQUIRE(VirtFs::mountDirSilentTest("dir1", + Append_true)); + REQUIRE(VirtFs::mountDirSilentTest2("dir1", + "dir2", + Append_true)); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, std::string()) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, "dir2" + sep) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal("test" + sep, "dir2" + sep) == + nullptr); + REQUIRE(VirtFs::getEntries().size() == 2); + REQUIRE(VirtFs::getEntries()[0]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[1]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[1]->subDir == "dir2" + sep); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir1"); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[1])->userDir == "dir1"); + + REQUIRE(VirtFs::unmountDirSilent("dir1")); + REQUIRE(VirtFs::getEntries().size() == 1); + REQUIRE(VirtFs::getEntries()[0]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir == "dir2" + sep); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir1"); + } + + SECTION("subDir 8") + { + REQUIRE(VirtFs::mountDirSilentTest("dir1", + Append_true)); + REQUIRE(VirtFs::mountDirSilentTest2("dir1", + "dir2", + Append_true)); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, std::string()) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, "dir2" + sep) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal("test" + sep, "dir2" + sep) == + nullptr); + REQUIRE(VirtFs::getEntries().size() == 2); + REQUIRE(VirtFs::getEntries()[0]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[1]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[1]->subDir == "dir2" + sep); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir1"); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[1])->userDir == "dir1"); + + REQUIRE(VirtFs::unmountDirSilent2("dir1", "dir2")); + REQUIRE(VirtFs::getEntries().size() == 1); + REQUIRE(VirtFs::getEntries()[0]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir1"); + } + + SECTION("subDir 9") + { + REQUIRE(VirtFs::mountDirSilentTest2("dir1", + dirSeparator, + Append_false)); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, std::string()) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal("dir1" + sep, "dir1") == + nullptr); + REQUIRE(VirtFs::searchByRootInternal("test" + sep, std::string()) == + nullptr); + REQUIRE(VirtFs::getEntries().size() == 1); + REQUIRE(VirtFs::getEntries()[0]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir1"); + } + + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 mountZip", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + const std::string sep = dirSeparator; + if (Files::existsLocal(name) == false) + prefix = "../"; + + SECTION("simple 1") + { + REQUIRE(VirtFs::mountZip(prefix + "data/test/test.zip", + Append_false)); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test.zip", std::string()) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test2.zip", + std::string()) == nullptr); + REQUIRE(VirtFs::getEntries().size() == 1); + REQUIRE(VirtFs::getEntries()[0]->root == + prefix + "data" + sep + "test" + sep + "test.zip"); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Zip); + } + + SECTION("simple 2") + { + REQUIRE(VirtFs::mountZip(prefix + "data/test/test.zip", + Append_false)); + REQUIRE(VirtFs::mountZip(prefix + "data/test/test2.zip", + Append_false)); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test.zip", + std::string()) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test2.zip", + std::string()) != nullptr); + REQUIRE(VirtFs::getEntries().size() == 2); + REQUIRE(VirtFs::getEntries()[0]->root == + prefix + "data" + sep + "test" + sep + "test2.zip"); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[1]->root == + prefix + "data" + sep + "test" + sep + "test.zip"); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[1]->subDir.empty()); + } + + SECTION("simple 3") + { + REQUIRE(VirtFs::mountZip(prefix + "data/test/test.zip", + Append_true)); + REQUIRE(VirtFs::mountZip(prefix + "data/test/test2.zip", + Append_true)); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test.zip", + std::string()) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test2.zip", + std::string()) != nullptr); + REQUIRE(VirtFs::getEntries().size() == 2); + REQUIRE(VirtFs::getEntries()[0]->root == + prefix + "data" + sep + "test" + sep + "test.zip"); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[1]->root == + prefix + "data" + sep + "test" + sep + "test2.zip"); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[1]->subDir.empty()); + } + + SECTION("simple 4") + { + REQUIRE(VirtFs::mountZip(prefix + "data/test/test.zip", + Append_false)); + REQUIRE(VirtFs::mountDir(prefix + "data/test", + Append_false)); + REQUIRE(VirtFs::mountZip(prefix + "data/test/test2.zip", + Append_false)); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test.zip", + std::string()) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test2.zip", + std::string()) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "", + std::string()) != nullptr); + REQUIRE(VirtFs::getEntries().size() == 3); + REQUIRE(VirtFs::getEntries()[0]->root == + prefix + "data" + sep + "test" + sep + "test2.zip"); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[1]->root == + prefix + "data" + sep + "test" + sep + ""); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[1]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[2]->root == + prefix + "data" + sep + "test" + sep + "test.zip"); + REQUIRE(VirtFs::getEntries()[2]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[2]->subDir.empty()); + } + + SECTION("simple 5") + { + REQUIRE(VirtFs::mountZip(prefix + "data/test/test.zip", + Append_false)); + REQUIRE(VirtFs::mountDir(prefix + "data/test", + Append_false)); + REQUIRE(VirtFs::mountZip(prefix + "data/test/test2.zip", + Append_true)); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test.zip", + std::string()) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test2.zip", + std::string()) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "", + std::string()) != nullptr); + REQUIRE(VirtFs::getEntries().size() == 3); + REQUIRE(VirtFs::getEntries()[0]->root == + prefix + "data" + sep + "test" + sep + ""); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[1]->root == + prefix + "data" + sep + "test" + sep + "test.zip"); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[1]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[2]->root == + prefix + "data" + sep + "test" + sep + "test2.zip"); + REQUIRE(VirtFs::getEntries()[2]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[2]->subDir.empty()); + } + + SECTION("subDir 1") + { + REQUIRE(VirtFs::mountZip2(prefix + "data/test/test.zip", + "dir1", + Append_false)); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test.zip", "dir1" + sep) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test2.zip", + std::string()) == nullptr); + REQUIRE(VirtFs::getEntries().size() == 1); + REQUIRE(VirtFs::getEntries()[0]->root == + prefix + "data" + sep + "test" + sep + "test.zip"); + REQUIRE(VirtFs::getEntries()[0]->subDir == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Zip); + } + + SECTION("subDir 2") + { + REQUIRE(VirtFs::mountZip2(prefix + "data/test/test.zip", + "dir1", + Append_false)); + REQUIRE(VirtFs::mountZip2(prefix + "data/test/test2.zip", + "dir2", + Append_false)); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test.zip", "dir1" + sep) != + nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test2.zip", + "dir2" + sep) != nullptr); + REQUIRE(VirtFs::getEntries().size() == 2); + REQUIRE(VirtFs::getEntries()[0]->root == + prefix + "data" + sep + "test" + sep + "test2.zip"); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[0]->subDir == "dir2" + sep); + REQUIRE(VirtFs::getEntries()[1]->root == + prefix + "data" + sep + "test" + sep + "test.zip"); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[1]->subDir == "dir1" + sep); + } + + SECTION("subDir 3") + { + REQUIRE(VirtFs::mountZip2(prefix + "data/test/test.zip", + "dir1", + Append_true)); + REQUIRE(VirtFs::mountZip2(prefix + "data/test/test2.zip", + "dir2", + Append_true)); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test.zip", + "dir1" + sep) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test2.zip", + "dir2" + sep) != nullptr); + REQUIRE(VirtFs::getEntries().size() == 2); + REQUIRE(VirtFs::getEntries()[0]->root == + prefix + "data" + sep + "test" + sep + "test.zip"); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[0]->subDir == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[1]->root == + prefix + "data" + sep + "test" + sep + "test2.zip"); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[1]->subDir == "dir2" + sep); + } + + SECTION("subDir 4") + { + REQUIRE(VirtFs::mountZip2(prefix + "data/test/test.zip", + "dir1", + Append_false)); + REQUIRE(VirtFs::mountDir2(prefix + "data/test", + "dir2", + Append_false)); + REQUIRE(VirtFs::mountZip2(prefix + "data/test/test2.zip", + "dir3", + Append_false)); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test.zip", + "dir1" + sep) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test2.zip", + "dir3" + sep) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "", + "dir2" + sep) != nullptr); + REQUIRE(VirtFs::getEntries().size() == 3); + REQUIRE(VirtFs::getEntries()[0]->root == + prefix + "data" + sep + "test" + sep + "test2.zip"); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[0]->subDir == "dir3" + sep); + REQUIRE(VirtFs::getEntries()[1]->root == + prefix + "data" + sep + "test" + sep + ""); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[1]->subDir == "dir2" + sep); + REQUIRE(VirtFs::getEntries()[2]->root == + prefix + "data" + sep + "test" + sep + "test.zip"); + REQUIRE(VirtFs::getEntries()[2]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[2]->subDir == "dir1" + sep); + } + + SECTION("subDir 5") + { + REQUIRE(VirtFs::mountZip2(prefix + "data/test/test.zip", + "dir1", + Append_false)); + REQUIRE(VirtFs::mountDir2(prefix + "data/test", + "dir2", + Append_false)); + REQUIRE(VirtFs::mountZip2(prefix + "data/test/test2.zip", + "dir3", + Append_true)); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test.zip", + "dir1" + sep) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test2.zip", + "dir3" + sep) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "", + "dir2" + sep) != nullptr); + REQUIRE(VirtFs::getEntries().size() == 3); + REQUIRE(VirtFs::getEntries()[0]->root == + prefix + "data" + sep + "test" + sep + ""); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[0]->subDir == "dir2" + sep); + REQUIRE(VirtFs::getEntries()[1]->root == + prefix + "data" + sep + "test" + sep + "test.zip"); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[1]->subDir == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[2]->root == + prefix + "data" + sep + "test" + sep + "test2.zip"); + REQUIRE(VirtFs::getEntries()[2]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[2]->subDir == "dir3" + sep); + } + + SECTION("subDir 6") + { + REQUIRE(VirtFs::mountZip2(prefix + "data/test/test.zip", + dirSeparator, + Append_false)); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test.zip", + std::string()) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test2.zip", + std::string()) == nullptr); + REQUIRE(VirtFs::getEntries().size() == 1); + REQUIRE(VirtFs::getEntries()[0]->root == + prefix + "data" + sep + "test" + sep + "test.zip"); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Zip); + } + + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 unmount", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + const std::string sep = dirSeparator; + if (Files::existsLocal(name) == false) + prefix = "../"; + + SECTION("simple 1") + { + REQUIRE_THROWS(VirtFs::unmountDir("dir1")); + REQUIRE_THROWS(VirtFs::unmountDir("dir1/")); + } + + SECTION("simple 2") + { + REQUIRE(VirtFs::mountDirSilentTest("dir1", + Append_true)); + REQUIRE_THROWS(VirtFs::unmountDir("dir2")); + REQUIRE(VirtFs::unmountDir("dir1")); + } + + SECTION("simple 3") + { + REQUIRE(VirtFs::mountDirSilentTest("dir1", + Append_true)); + REQUIRE(VirtFs::mountDirSilentTest("dir2//dir3", + Append_true)); + REQUIRE(VirtFs::mountDirSilentTest("dir3", + Append_false)); + REQUIRE(VirtFs::getEntries().size() == 3); + REQUIRE_THROWS(VirtFs::unmountDir("dir2")); + REQUIRE(VirtFs::unmountDir("dir1")); + REQUIRE(VirtFs::getEntries().size() == 2); + REQUIRE(VirtFs::getEntries()[0]->root == "dir3" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir3"); + REQUIRE(VirtFs::getEntries()[1]->root == "dir2" + sep + "dir3" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[1])->userDir == "dir2" + sep + "dir3"); + REQUIRE_THROWS(VirtFs::unmountDir("dir1")); + REQUIRE(VirtFs::getEntries().size() == 2); + REQUIRE(VirtFs::getEntries()[0]->root == "dir3" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir3"); + REQUIRE(VirtFs::getEntries()[1]->root == "dir2" + sep + "dir3" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[1])->userDir == "dir2" + sep + "dir3"); + REQUIRE(VirtFs::unmountDir("dir2/dir3")); + REQUIRE_THROWS(VirtFs::unmountDir("dir2/dir3" + sep)); + REQUIRE(VirtFs::getEntries().size() == 1); + REQUIRE(VirtFs::getEntries()[0]->root == "dir3" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir3"); + } + + SECTION("simple 4") + { + REQUIRE(VirtFs::mountDirSilentTest("dir1", + Append_true)); + REQUIRE(VirtFs::getEntries().size() == 1); + REQUIRE(VirtFs::getEntries()[0]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir1"); + REQUIRE_THROWS(VirtFs::unmountDir("dir2")); + REQUIRE(VirtFs::unmountDir("dir1")); + REQUIRE(VirtFs::getEntries().empty()); + REQUIRE(VirtFs::mountDirSilentTest("dir1", + Append_true)); + REQUIRE(VirtFs::getEntries().size() == 1); + REQUIRE(VirtFs::getEntries()[0]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir1"); + } + + SECTION("simple 5") + { + REQUIRE(VirtFs::mountZip(prefix + "data/test/test.zip", + Append_true)); + REQUIRE(VirtFs::mountZip(prefix + "data/test/test2.zip", + Append_true)); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test.zip", + std::string()) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test2.zip", + std::string()) != nullptr); + REQUIRE(VirtFs::getEntries().size() == 2); + REQUIRE(VirtFs::getEntries()[0]->root == + prefix + "data" + sep + "test" + sep + "test.zip"); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[1]->root == + prefix + "data" + sep + "test" + sep + "test2.zip"); + REQUIRE(VirtFs::getEntries()[1]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Zip); + + VirtFs::unmountZip(prefix + "data/test/test.zip"); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test.zip", + std::string()) == nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test2.zip", + std::string()) != nullptr); + REQUIRE(VirtFs::getEntries().size() == 1); + REQUIRE(VirtFs::getEntries()[0]->root == + prefix + "data" + sep + "test" + sep + "test2.zip"); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Zip); + } + + SECTION("simple 6") + { + REQUIRE(VirtFs::mountZip(prefix + "data/test/test.zip", + Append_false)); + REQUIRE(VirtFs::mountDir(prefix + "data/test", + Append_false)); + REQUIRE(VirtFs::mountZip(prefix + "data\\test/test2.zip", + Append_false)); + + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test.zip", + std::string()) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test2.zip", + std::string()) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "", + std::string()) != nullptr); + REQUIRE(VirtFs::getEntries().size() == 3); + REQUIRE(VirtFs::getEntries()[0]->root == + prefix + "data" + sep + "test" + sep + "test2.zip"); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[1]->root == + prefix + "data" + sep + "test" + sep); + REQUIRE(VirtFs::getEntries()[1]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[2]->root == + prefix + "data" + sep + "test" + sep + "test.zip"); + REQUIRE(VirtFs::getEntries()[2]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[2]->type == FsEntryType::Zip); + + VirtFs::unmountZip(prefix + "data/test/test.zip"); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test.zip", + std::string()) == nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test2.zip", + std::string()) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "", + std::string()) != nullptr); + REQUIRE(VirtFs::getEntries().size() == 2); + REQUIRE(VirtFs::getEntries()[0]->root == + prefix + "data" + sep + "test" + sep + "test2.zip"); + REQUIRE(VirtFs::getEntries()[0]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[1]->root == + prefix + "data" + sep + "test" + sep); + REQUIRE(VirtFs::getEntries()[1]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Dir); + } + + SECTION("subDir 1") + { + REQUIRE_THROWS(VirtFs::unmountDir2("dir1", "dir1")); + REQUIRE_THROWS(VirtFs::unmountDir2("dir1/", "dir1/")); + } + + SECTION("subDir 2") + { + REQUIRE(VirtFs::mountDirSilentTest2("dir1", + "dir2", + Append_true)); + REQUIRE_THROWS(VirtFs::unmountDir("dir1")); + REQUIRE_THROWS(VirtFs::unmountDir("dir2")); + REQUIRE(VirtFs::unmountDir2("dir1", "dir2")); + } + + SECTION("subDir 3") + { + REQUIRE(VirtFs::mountDirSilentTest2("dir1", + "dir2", + Append_true)); + REQUIRE(VirtFs::mountDirSilentTest("dir2//dir3", + Append_true)); + REQUIRE(VirtFs::mountDirSilentTest2("dir3", + "dir4", + Append_false)); + REQUIRE(VirtFs::getEntries().size() == 3); + REQUIRE_THROWS(VirtFs::unmountDir("dir2")); + REQUIRE_THROWS(VirtFs::unmountDir2("dir1", "dir1")); + REQUIRE(VirtFs::unmountDir2("dir1", "dir2")); + REQUIRE(VirtFs::getEntries().size() == 2); + REQUIRE(VirtFs::getEntries()[0]->root == "dir3" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir == "dir4" + sep); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir3"); + REQUIRE(VirtFs::getEntries()[1]->root == "dir2" + sep + "dir3" + sep); + REQUIRE(VirtFs::getEntries()[1]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[1])->userDir == "dir2" + sep + "dir3"); + REQUIRE_THROWS(VirtFs::unmountDir("dir1")); + REQUIRE(VirtFs::getEntries().size() == 2); + REQUIRE(VirtFs::getEntries()[0]->root == "dir3" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir == "dir4" + sep); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir3"); + REQUIRE(VirtFs::getEntries()[1]->root == "dir2" + sep + "dir3" + sep); + REQUIRE(VirtFs::getEntries()[1]->subDir.empty()); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[1])->userDir == "dir2" + sep + "dir3"); + REQUIRE(VirtFs::unmountDir("dir2/dir3")); + REQUIRE_THROWS(VirtFs::unmountDir("dir2/dir3" + sep)); + REQUIRE(VirtFs::getEntries().size() == 1); + REQUIRE(VirtFs::getEntries()[0]->root == "dir3" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir == "dir4" + sep); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir3"); + } + + SECTION("subDir 4") + { + REQUIRE(VirtFs::mountDirSilentTest2("dir1", + "dir2", + Append_true)); + REQUIRE(VirtFs::getEntries().size() == 1); + REQUIRE(VirtFs::getEntries()[0]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir == "dir2" + sep); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir1"); + REQUIRE_THROWS(VirtFs::unmountDir("dir2")); + REQUIRE_THROWS(VirtFs::unmountDir("dir1")); + REQUIRE(VirtFs::unmountDir2("dir1", "dir2")); + REQUIRE(VirtFs::getEntries().empty()); + REQUIRE(VirtFs::mountDirSilentTest2("dir1", + "dir3", + Append_true)); + REQUIRE(VirtFs::getEntries().size() == 1); + REQUIRE(VirtFs::getEntries()[0]->root == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[0]->subDir == "dir3" + sep); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Dir); + REQUIRE(static_cast<VirtFs::DirEntry*>( + VirtFs::getEntries()[0])->userDir == "dir1"); + } + + SECTION("subDir 5") + { + REQUIRE(VirtFs::mountZip2(prefix + "data/test/test.zip", + "dir1", + Append_true)); + REQUIRE(VirtFs::mountZip2(prefix + "data/test/test2.zip", + "dir2", + Append_true)); + + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test.zip", + "dir1" + sep) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test2.zip", + "dir2" + sep) != nullptr); + REQUIRE(VirtFs::getEntries().size() == 2); + REQUIRE(VirtFs::getEntries()[0]->root == + prefix + "data" + sep + "test" + sep + "test.zip"); + REQUIRE(VirtFs::getEntries()[0]->subDir == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[1]->root == + prefix + "data" + sep + "test" + sep + "test2.zip"); + REQUIRE(VirtFs::getEntries()[1]->subDir == "dir2" + sep); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Zip); + + VirtFs::unmountZip2(prefix + "data/test/test.zip", + "dir1"); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test.zip", + std::string()) == nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test2.zip", + "dir2" + sep) != nullptr); + REQUIRE(VirtFs::getEntries().size() == 1); + REQUIRE(VirtFs::getEntries()[0]->root == + prefix + "data" + sep + "test" + sep + "test2.zip"); + REQUIRE(VirtFs::getEntries()[0]->subDir == "dir2" + sep); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Zip); + } + + SECTION("subDir 6") + { + REQUIRE(VirtFs::mountZip2(prefix + "data/test/test.zip", + "dir1", + Append_false)); + REQUIRE(VirtFs::mountDir2(prefix + "data/test", + "dir2", + Append_false)); + REQUIRE(VirtFs::mountZip2(prefix + "data\\test/test2.zip", + "dir3", + Append_false)); + + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test.zip", + "dir1" + sep) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test2.zip", + "dir3" + sep) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "", + "dir2" + sep) != nullptr); + REQUIRE(VirtFs::getEntries().size() == 3); + REQUIRE(VirtFs::getEntries()[0]->root == + prefix + "data" + sep + "test" + sep + "test2.zip"); + REQUIRE(VirtFs::getEntries()[0]->subDir == "dir3" + sep); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[1]->root == + prefix + "data" + sep + "test" + sep); + REQUIRE(VirtFs::getEntries()[1]->subDir == "dir2" + sep); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Dir); + REQUIRE(VirtFs::getEntries()[2]->root == + prefix + "data" + sep + "test" + sep + "test.zip"); + REQUIRE(VirtFs::getEntries()[2]->subDir == "dir1" + sep); + REQUIRE(VirtFs::getEntries()[2]->type == FsEntryType::Zip); + + VirtFs::unmountZip2(prefix + "data/test/test.zip", + "dir1"); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test.zip", + "dir1" + sep) == nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "test2.zip", + "dir3" + sep) != nullptr); + REQUIRE(VirtFs::searchByRootInternal( + prefix + "data" + sep + "test" + sep + "", + "dir2" + sep) != nullptr); + REQUIRE(VirtFs::getEntries().size() == 2); + REQUIRE(VirtFs::getEntries()[0]->root == + prefix + "data" + sep + "test" + sep + "test2.zip"); + REQUIRE(VirtFs::getEntries()[0]->subDir == "dir3" + sep); + REQUIRE(VirtFs::getEntries()[0]->type == FsEntryType::Zip); + REQUIRE(VirtFs::getEntries()[1]->root == + prefix + "data" + sep + "test" + sep); + REQUIRE(VirtFs::getEntries()[1]->subDir == "dir2" + sep); + REQUIRE(VirtFs::getEntries()[1]->type == FsEntryType::Dir); + } + + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 exists1", "") +{ + VirtFs::init("."); + logger = new Logger(); + const bool dir1 = VirtFs::mountDirSilent("data/", + Append_false); + VirtFs::mountDirSilent("..\\data", + Append_false); + + REQUIRE(VirtFs::exists("test")); + REQUIRE(VirtFs::exists("test/")); + REQUIRE(VirtFs::exists("test/dir1")); + REQUIRE(VirtFs::exists("test/dir1/")); + REQUIRE(VirtFs::exists("test/dir") == false); + REQUIRE(VirtFs::exists("test//units.xml") == true); + REQUIRE(VirtFs::exists("test/\\units123.xml") == false); + REQUIRE(VirtFs::exists("tesQ/units.xml") == false); + REQUIRE(VirtFs::exists("units.xml") == false); + + if (dir1 == true) + { + VirtFs::mountDir("data//test", + Append_false); + } + else + { + VirtFs::mountDirSilent("..//data\\test", + Append_false); + } + + REQUIRE(VirtFs::exists("test") == true); + REQUIRE(VirtFs::exists("test/dir1")); + REQUIRE(VirtFs::exists("test/dir1\\")); + REQUIRE(VirtFs::exists("test/dir") == false); + REQUIRE(VirtFs::exists("test\\units.xml") == true); + REQUIRE(VirtFs::exists("test/units123.xml") == false); + REQUIRE(VirtFs::exists("tesQ/units.xml") == false); + REQUIRE(VirtFs::exists("units.xml") == true); + REQUIRE(VirtFs::exists("units.xml/") == false); + + if (dir1 == true) + VirtFs::unmountDirSilent("data/test"); + else + VirtFs::unmountDirSilent("../data/test"); + + REQUIRE(VirtFs::exists("test") == true); + REQUIRE(VirtFs::exists("test/dir1")); + REQUIRE(VirtFs::exists("test/dir") == false); + REQUIRE(VirtFs::exists("test\\units.xml") == true); + REQUIRE(VirtFs::exists("test/units123.xml") == false); + REQUIRE(VirtFs::exists("tesQ/units.xml") == false); + REQUIRE(VirtFs::exists("units.xml") == false); + REQUIRE(VirtFs::exists("units.xml/") == false); + + REQUIRE_THROWS(VirtFs::exists("test/../units.xml")); + + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 exists2", "") +{ + VirtFs::init("."); + logger = new Logger(); + const bool dir1 = VirtFs::mountDirSilent2("data/", + "test", + Append_false); + VirtFs::mountDirSilent2("..\\data", + "test", + Append_false); + + REQUIRE(VirtFs::exists("test") == false); + REQUIRE(VirtFs::exists("test/") == false); + REQUIRE(VirtFs::exists("dir1")); + REQUIRE(VirtFs::exists("dir1/")); + REQUIRE(VirtFs::exists("dir") == false); + REQUIRE(VirtFs::exists("units.xml") == true); + REQUIRE(VirtFs::exists("units123.xml") == false); + REQUIRE(VirtFs::exists("tesQ/units.xml") == false); + REQUIRE(VirtFs::exists("units.xml")); + REQUIRE(VirtFs::exists("file1.txt") == false); + REQUIRE(VirtFs::exists("file2.txt") == false); + + if (dir1 == true) + { + VirtFs::mountDir2("data//test", + "dir2", + Append_false); + } + else + { + VirtFs::mountDirSilent2("..//data\\test", + "dir2", + Append_false); + } + + REQUIRE(VirtFs::exists("test") == false); + REQUIRE(VirtFs::exists("test/") == false); + REQUIRE(VirtFs::exists("dir1")); + REQUIRE(VirtFs::exists("dir1/")); + REQUIRE(VirtFs::exists("dir") == false); + REQUIRE(VirtFs::exists("units.xml") == true); + REQUIRE(VirtFs::exists("units123.xml") == false); + REQUIRE(VirtFs::exists("tesQ/units.xml") == false); + REQUIRE(VirtFs::exists("units.xml")); + REQUIRE(VirtFs::exists("file1.txt")); + REQUIRE(VirtFs::exists("file2.txt")); + + if (dir1 == true) + VirtFs::unmountDirSilent2("data/test", "dir2"); + else + VirtFs::unmountDirSilent2("../data/test", "dir2"); + + REQUIRE(VirtFs::exists("test") == false); + REQUIRE(VirtFs::exists("test/") == false); + REQUIRE(VirtFs::exists("dir1")); + REQUIRE(VirtFs::exists("dir1/")); + REQUIRE(VirtFs::exists("dir") == false); + REQUIRE(VirtFs::exists("units.xml") == true); + REQUIRE(VirtFs::exists("units123.xml") == false); + REQUIRE(VirtFs::exists("tesQ/units.xml") == false); + REQUIRE(VirtFs::exists("units.xml")); + REQUIRE(VirtFs::exists("file1.txt") == false); + REQUIRE(VirtFs::exists("file2.txt") == false); + + REQUIRE_THROWS(VirtFs::exists("test/../units.xml")); + + VirtFs::deinit(); + delete2(logger); +} + +static void removeTemp(StringVect &restrict list) +{ + int cnt = 0; + std::sort(list.begin(), list.end()); + + FOR_EACH (StringVectIter, it, list) + { + if (*it != "serverlistplus.xml.part") + { + logger->log("file: %d %s", + cnt, + (*it).c_str()); + cnt ++; + } + } + + FOR_EACH (StringVectIter, it, list) + { + if (*it == "serverlistplus.xml.part") + { + list.erase(it); + return; + } + } +} + +TEST_CASE("VirtFs1 getRealDir1", "") +{ + VirtFs::init("."); + logger = new Logger(); + const std::string sep = dirSeparator; + REQUIRE(VirtFs::getRealDir(".").empty()); + REQUIRE(VirtFs::getRealDir("..").empty()); + const bool dir1 = VirtFs::mountDirSilent("data", + Append_false); + REQUIRE((dir1 || VirtFs::mountDirSilent("../data", + Append_false)) == true); + if (dir1 == true) + { + REQUIRE(VirtFs::getRealDir("test") == "data"); + REQUIRE(VirtFs::getRealDir("test/test.txt") == + "data"); + REQUIRE(VirtFs::getRealDir("test\\test.txt") == + "data"); + REQUIRE(VirtFs::getRealDir("test//test.txt") == + "data"); + } + else + { + REQUIRE(VirtFs::getRealDir("test") == "../data"); + REQUIRE(VirtFs::getRealDir("test/test.txt") == + "../data"); + REQUIRE(VirtFs::getRealDir("test\\test.txt") == + "../data"); + REQUIRE(VirtFs::getRealDir("test//test.txt") == + "../data"); + } + REQUIRE(VirtFs::getRealDir("zzz").empty()); + + VirtFs::mountDirSilent("data/test", + Append_false); + VirtFs::mountDirSilent("../data/test", + Append_false); + if (dir1 == true) + { + REQUIRE(VirtFs::getRealDir("test") == "data"); + REQUIRE(VirtFs::getRealDir("test/test.txt") == + "data"); + REQUIRE(VirtFs::getRealDir("test\\test.txt") == + "data"); + REQUIRE(VirtFs::getRealDir("test.txt") == + "data" + sep + "test"); + } + else + { + REQUIRE(VirtFs::getRealDir("test") == ".." + sep + "data"); + REQUIRE(VirtFs::getRealDir("test/test.txt") == + ".." + sep + "data"); + REQUIRE(VirtFs::getRealDir("test\\test.txt") == + ".." + sep + "data"); + REQUIRE(VirtFs::getRealDir("test.txt") == + ".." + sep + "data" + sep + "test"); + } + REQUIRE(VirtFs::getRealDir("zzz").empty()); + + VirtFs::unmountDirSilent("data/test"); + VirtFs::unmountDirSilent("../data/test"); + + if (dir1 == true) + { + REQUIRE(VirtFs::getRealDir("test") == "data"); + REQUIRE(VirtFs::getRealDir("test/test.txt") == + "data"); + } + else + { + REQUIRE(VirtFs::getRealDir("test") == ".." + sep + "data"); + REQUIRE(VirtFs::getRealDir("test/test.txt") == + ".." + sep + "data"); + } + REQUIRE(VirtFs::getRealDir("zzz").empty()); + + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 getRealDir2", "") +{ + VirtFs::init("."); + logger = new Logger(); + const std::string sep = dirSeparator; + std::string name("data/test/test.zip"); + std::string prefix("data" + sep + "test" + sep); + if (Files::existsLocal(name) == false) + prefix = ".." + sep + prefix; + VirtFs::mountZip(prefix + "test2.zip", + Append_false); + + REQUIRE(VirtFs::getRealDir(".").empty()); + REQUIRE(VirtFs::getRealDir("..").empty()); + REQUIRE(VirtFs::getRealDir("test.txt") == prefix + "test2.zip"); + REQUIRE(VirtFs::getRealDir("dir/1") == prefix + "test2.zip"); + REQUIRE(VirtFs::getRealDir("dir\\dye.png") == + prefix + "test2.zip"); + REQUIRE(VirtFs::getRealDir("zzz").empty()); + + VirtFs::mountZip(prefix + "test.zip", + Append_false); + REQUIRE(VirtFs::getRealDir("dir//dye.png") == + prefix + "test2.zip"); + REQUIRE(VirtFs::getRealDir("dir///hide.png") == + prefix + "test.zip"); + REQUIRE(VirtFs::getRealDir("dir\\\\brimmedhat.png") == + prefix + "test.zip"); + REQUIRE(VirtFs::getRealDir("zzz").empty()); + + VirtFs::unmountZip(prefix + "test.zip"); + + REQUIRE(VirtFs::getRealDir("dir/brimmedhat.png").empty()); + REQUIRE(VirtFs::getRealDir("test.txt") == prefix + "test2.zip"); + REQUIRE(VirtFs::getRealDir("dir//dye.png") == + prefix + "test2.zip"); + REQUIRE(VirtFs::getRealDir("zzz").empty()); + + VirtFs::unmountZip(prefix + "test2.zip"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 getRealDir3", "") +{ + VirtFs::init("."); + logger = new Logger(); + const std::string sep = dirSeparator; + REQUIRE(VirtFs::getRealDir(".").empty()); + REQUIRE(VirtFs::getRealDir("..").empty()); + const bool dir1 = VirtFs::mountDirSilent2("data", + "test", + Append_false); + REQUIRE((dir1 || VirtFs::mountDirSilent2("../data", + "test", + Append_false)) == true); + REQUIRE(VirtFs::getRealDir("file1.txt").empty()); + if (dir1 == true) + { + REQUIRE(VirtFs::getRealDir("dir1") == "data"); + REQUIRE(VirtFs::getRealDir("simplefile.txt") == "data"); + } + else + { + REQUIRE(VirtFs::getRealDir("dir1") == ".." + sep + "data"); + REQUIRE(VirtFs::getRealDir("simplefile.txt") == ".." + sep + "data"); + } + REQUIRE(VirtFs::getRealDir("zzz").empty()); + + VirtFs::mountDirSilent2("data/test", + "dir2", + Append_false); + VirtFs::mountDirSilent2("../data/test", + "dir2", + Append_false); + REQUIRE(VirtFs::getRealDir("dir").empty()); + if (dir1 == true) + { + REQUIRE(VirtFs::getRealDir("file1.txt") == "data" + sep + "test"); + REQUIRE(VirtFs::getRealDir("simplefile.txt") == "data"); + } + else + { + REQUIRE(VirtFs::getRealDir("file1.txt") == + ".." + sep + "data" + sep + "test"); + REQUIRE(VirtFs::getRealDir("simplefile.txt") == ".." + sep + "data"); + } + REQUIRE(VirtFs::getRealDir("zzz").empty()); + + VirtFs::deinit(); + delete2(logger); +} + +static bool inList(const VirtFs::List *const list, + const std::string &name) +{ + FOR_EACH (StringVectCIter, it, list->names) + { + if (*it == name) + return true; + } + return false; +} + +static bool inList(StringVect list, + const std::string &name) +{ + FOR_EACH (StringVectCIter, it, list) + { + if (*it == name) + return true; + } + return false; +} + +static bool inList(StringVect list, + const std::string &dir, + const std::string &name) +{ + const std::string path = pathJoin(dir, name); + FOR_EACH (StringVectCIter, it, list) + { + if (*it == path) + return true; + } + return false; +} + +TEST_CASE("VirtFs1 enumerateFiles1", "") +{ + VirtFs::init("."); + logger = new Logger; + + VirtFs::mountDirSilent("data", + Append_false); + VirtFs::mountDirSilent("../data", + Append_false); + + VirtFs::List *list = nullptr; + + const int cnt1 = VirtFs::exists("test/test2.txt") ? 28 : 27; + const int cnt2 = 28; + + VirtFs::permitLinks(false); + list = VirtFs::enumerateFiles("test"); + removeTemp(list->names); + const size_t sz = list->names.size(); + REQUIRE(sz == cnt1); + VirtFs::freeList(list); + + VirtFs::permitLinks(true); + list = VirtFs::enumerateFiles("test/"); + removeTemp(list->names); + REQUIRE(list->names.size() == cnt2); + VirtFs::freeList(list); + + VirtFs::permitLinks(true); + list = VirtFs::enumerateFiles("test/units.xml"); + REQUIRE(list->names.empty()); + VirtFs::freeList(list); + + VirtFs::permitLinks(false); + list = VirtFs::enumerateFiles("test\\"); + removeTemp(list->names); + REQUIRE(list->names.size() == cnt1); + VirtFs::freeList(list); + + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 enumerateFiles2", "") +{ + VirtFs::init("."); + logger = new Logger; + + VirtFs::mountDirSilent("data/test/dir1", + Append_false); + VirtFs::mountDirSilent("../data/test/dir1", + Append_false); + + VirtFs::List *list = nullptr; + + list = VirtFs::enumerateFiles("/"); + REQUIRE(list->names.size() == 5); + REQUIRE(inList(list, "file1.txt")); + REQUIRE_FALSE(inList(list, "file2.txt")); + VirtFs::freeList(list); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 enumerateFiles3", "") +{ + VirtFs::init("."); + logger = new Logger; + + VirtFs::mountDirSilent("data/test/dir1", + Append_false); + VirtFs::mountDirSilent("../data/test/dir1", + Append_false); + VirtFs::mountDirSilent("data/test/dir2", + Append_false); + VirtFs::mountDirSilent("../data/test/dir2", + Append_false); + + VirtFs::List *list = nullptr; + + list = VirtFs::enumerateFiles("/"); + REQUIRE(inList(list, "file1.txt")); + REQUIRE(inList(list, "file2.txt")); + VirtFs::freeList(list); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFsZip enumerateFiles4", "") +{ + VirtFs::init("."); + logger = new Logger; + std::string name("data/test/test.zip"); + std::string prefix("data\\test/"); + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "test.zip", + Append_false); + + VirtFs::List *list = nullptr; + + list = VirtFs::enumerateFiles("dir"); + REQUIRE(list->names.size() == 2); + REQUIRE(inList(list, "brimmedhat.png")); + REQUIRE(inList(list, "hide.png")); + VirtFs::freeList(list); + + VirtFs::unmountZip(prefix + "test.zip"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFsZip enumerateFiles5", "") +{ + VirtFs::init("."); + logger = new Logger; + std::string name("data/test/test.zip"); + std::string prefix("data//test/"); + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "test.zip", + Append_true); + VirtFs::mountZip(prefix + "test2.zip", + Append_true); + + VirtFs::List *list = nullptr; + + list = VirtFs::enumerateFiles("dir"); + FOR_EACH (StringVectCIter, it, list->names) + { + logger->log("filename: " + *it); + } + + REQUIRE(list->names.size() == 5); + REQUIRE(inList(list, "brimmedhat.png")); + REQUIRE(inList(list, "hide.png")); + REQUIRE(inList(list, "1")); + REQUIRE(inList(list, "gpl")); + REQUIRE(inList(list, "dye.png")); + VirtFs::freeList(list); + + VirtFs::unmountZip(prefix + "test.zip"); + VirtFs::unmountZip(prefix + "test2.zip"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFsZip enumerateFiles6", "") +{ + VirtFs::init("."); + logger = new Logger; + std::string name("data/test/test.zip"); + std::string prefix("data\\test/"); + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "test.zip", + Append_false); + + VirtFs::List *list = nullptr; + + list = VirtFs::enumerateFiles("/"); + REQUIRE(list->names.size() == 1); + REQUIRE(inList(list, "dir")); + VirtFs::freeList(list); + + VirtFs::unmountZip(prefix + "test.zip"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFsZip enumerateFiles7", "") +{ + VirtFs::init("."); + logger = new Logger; + std::string name("data/test/test.zip"); + std::string prefix("data\\test/"); + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "test2.zip", + Append_false); + + VirtFs::List *list = nullptr; + + list = VirtFs::enumerateFiles("/"); + REQUIRE(list->names.size() == 4); + REQUIRE(inList(list, "dir")); + REQUIRE(inList(list, "dir2")); + REQUIRE(inList(list, "test.txt")); + REQUIRE(inList(list, "units.xml")); + VirtFs::freeList(list); + + VirtFs::unmountZip(prefix + "test2.zip"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFsZip enumerateFiles8", "") +{ + VirtFs::init("."); + logger = new Logger; + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "data/test/test2.zip", + Append_false); + VirtFs::mountDirSilent(prefix + "data/test", + Append_false); + + VirtFs::List *list = nullptr; + + list = VirtFs::enumerateFiles("dir2"); + REQUIRE(list->names.size() >= 6); + REQUIRE(inList(list, "file1.txt")); + REQUIRE(inList(list, "file2.txt")); + REQUIRE(inList(list, "hide.png")); + REQUIRE(inList(list, "paths.xml")); + REQUIRE(inList(list, "test.txt")); + REQUIRE(inList(list, "units.xml")); + VirtFs::freeList(list); + + VirtFs::unmountZip(prefix + "data/test/test2.zip"); + VirtFs::unmountDir(prefix + "data/test"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFsZip enumerateFiles9", "") +{ + VirtFs::init("."); + logger = new Logger; + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "data/test/test2.zip", + Append_false); + VirtFs::mountDirSilent(prefix + "data/test", + Append_false); + + VirtFs::List *list = nullptr; + + list = VirtFs::enumerateFiles("dir"); + REQUIRE(list->names.size() == 4); + REQUIRE(inList(list, "1")); + REQUIRE(inList(list, "gpl")); + REQUIRE(inList(list, "dye.png")); + REQUIRE(inList(list, "hide.png")); + VirtFs::freeList(list); + + VirtFs::unmountZip(prefix + "data/test/test2.zip"); + VirtFs::unmountDir(prefix + "data/test"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFsZip enumerateFiles10", "") +{ + VirtFs::init("."); + logger = new Logger; + std::string name("data/test/test.zip"); + std::string prefix("data\\test/"); + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip2(prefix + "test.zip", + "dir", + Append_false); + + VirtFs::List *list = nullptr; + + list = VirtFs::enumerateFiles("/"); + REQUIRE(list->names.size() == 2); + REQUIRE(inList(list, "brimmedhat.png")); + REQUIRE(inList(list, "hide.png")); + VirtFs::freeList(list); + + VirtFs::unmountZip2(prefix + "test.zip", + "dir"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFsZip enumerateFiles11", "") +{ + VirtFs::init("."); + logger = new Logger; + std::string name("data/test/test.zip"); + std::string prefix("data\\test/"); + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip2(prefix + "test2.zip", + "dir", + Append_false); + + VirtFs::List *list = nullptr; + + list = VirtFs::enumerateFiles("1"); + REQUIRE(list->names.size() == 2); + REQUIRE(inList(list, "file1.txt")); + REQUIRE(inList(list, "test.txt")); + VirtFs::freeList(list); + + VirtFs::unmountZip2(prefix + "test2.zip", + "dir"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 enumerateFiles12", "") +{ + VirtFs::init("."); + logger = new Logger; + + VirtFs::mountDirSilent2("data/test", + "dir2", + Append_false); + VirtFs::mountDirSilent2("../data/test", + "dir2", + Append_false); + + VirtFs::List *list = nullptr; + + list = VirtFs::enumerateFiles("/"); + REQUIRE(inList(list, "file1.txt")); + REQUIRE(inList(list, "file2.txt")); + VirtFs::freeList(list); + + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 enumerateFiles13", "") +{ + VirtFs::init("."); + logger = new Logger; + + VirtFs::mountDirSilent2("data", + "test", + Append_false); + VirtFs::mountDirSilent2("../data", + "test", + Append_false); + + VirtFs::List *list = nullptr; + + list = VirtFs::enumerateFiles("dir2"); + REQUIRE(inList(list, "file1.txt")); + REQUIRE(inList(list, "file2.txt")); + VirtFs::freeList(list); + + VirtFs::deinit(); + delete2(logger); +} + + +TEST_CASE("VirtFs1 isDirectory1", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountDir(prefix + "data", + Append_false); + + REQUIRE(VirtFs::isDirectory("test/units.xml") == false); + REQUIRE(VirtFs::isDirectory("test/units.xml/") == false); + REQUIRE(VirtFs::isDirectory("test//units.xml") == false); + REQUIRE(VirtFs::isDirectory("test/units123.xml") == false); + REQUIRE(VirtFs::isDirectory("test//units123.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ//units.xml") == false); + REQUIRE(VirtFs::isDirectory("units.xml") == false); + REQUIRE(VirtFs::isDirectory("test") == true); + REQUIRE(VirtFs::isDirectory("test/") == true); + REQUIRE(VirtFs::isDirectory("test//") == true); + REQUIRE(VirtFs::isDirectory("test/dir1") == true); + REQUIRE(VirtFs::isDirectory("test//dir1") == true); + REQUIRE(VirtFs::isDirectory("test//dir1/") == true); + REQUIRE(VirtFs::isDirectory("test//dir1//") == true); + REQUIRE(VirtFs::isDirectory("test\\dir1/") == true); + REQUIRE(VirtFs::isDirectory("test/dir1//") == true); + REQUIRE(VirtFs::isDirectory("testQ") == false); + REQUIRE(VirtFs::isDirectory("testQ/") == false); + REQUIRE(VirtFs::isDirectory("testQ//") == false); + + VirtFs::mountDir(prefix + "data/test", + Append_false); + + REQUIRE(VirtFs::isDirectory("test/units.xml") == false); + REQUIRE(VirtFs::isDirectory("test/units.xml/") == false); + REQUIRE(VirtFs::isDirectory("test//units.xml") == false); + REQUIRE(VirtFs::isDirectory("test/units123.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false); + REQUIRE(VirtFs::isDirectory("units.xml") == false); + REQUIRE(VirtFs::isDirectory("test") == true); + REQUIRE(VirtFs::isDirectory("testQ") == false); + REQUIRE(VirtFs::isDirectory("test/dir1") == true); + REQUIRE(VirtFs::isDirectory("test\\dir1") == true); + + VirtFs::unmountDir(prefix + "data/test"); + + REQUIRE(VirtFs::isDirectory("test/units.xml") == false); + REQUIRE(VirtFs::isDirectory("test/units123.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false); + REQUIRE(VirtFs::isDirectory("units.xml") == false); + REQUIRE(VirtFs::isDirectory("units.xml/") == false); + REQUIRE(VirtFs::isDirectory("test") == true); + REQUIRE(VirtFs::isDirectory("test/") == true); + REQUIRE(VirtFs::isDirectory("testQ") == false); + REQUIRE(VirtFs::isDirectory("test/dir1") == true); + + VirtFs::unmountDirSilent(prefix + "data"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 isDirectory2", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "data/test/test2.zip", + Append_false); + + REQUIRE(VirtFs::isDirectory("dir2/units.xml") == false); + REQUIRE(VirtFs::isDirectory("dir2/units.xml/") == false); + REQUIRE(VirtFs::isDirectory("dir2//units.xml") == false); + REQUIRE(VirtFs::isDirectory("dir2/units123.xml") == false); + REQUIRE(VirtFs::isDirectory("dir2//units123.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ//units.xml") == false); + REQUIRE(VirtFs::isDirectory("units.xml") == false); + REQUIRE(VirtFs::isDirectory("dir") == true); + REQUIRE(VirtFs::isDirectory("dir2/") == true); + REQUIRE(VirtFs::isDirectory("dir2//") == true); + REQUIRE(VirtFs::isDirectory("dir/1") == true); + REQUIRE(VirtFs::isDirectory("dir//1") == true); + REQUIRE(VirtFs::isDirectory("dir\\1/") == true); + REQUIRE(VirtFs::isDirectory("dir/1") == true); + REQUIRE(VirtFs::isDirectory("dir/1/zzz") == false); + REQUIRE(VirtFs::isDirectory("test/dir1\\") == false); + REQUIRE(VirtFs::isDirectory("testQ") == false); + REQUIRE(VirtFs::isDirectory("testQ/") == false); + REQUIRE(VirtFs::isDirectory("testQ//") == false); + + VirtFs::mountZip(prefix + "data/test/test.zip", + Append_false); + + REQUIRE(VirtFs::isDirectory("dir2/units.xml") == false); + REQUIRE(VirtFs::isDirectory("dir2/units.xml/") == false); + REQUIRE(VirtFs::isDirectory("dir2\\units.xml") == false); + REQUIRE(VirtFs::isDirectory("dir2/units123.xml") == false); + REQUIRE(VirtFs::isDirectory("dir2//units123.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ//units.xml") == false); + REQUIRE(VirtFs::isDirectory("units.xml") == false); + REQUIRE(VirtFs::isDirectory("dir") == true); + REQUIRE(VirtFs::isDirectory("dir2/") == true); + REQUIRE(VirtFs::isDirectory("dir2\\") == true); + REQUIRE(VirtFs::isDirectory("dir/1") == true); + REQUIRE(VirtFs::isDirectory("dir//1") == true); + REQUIRE(VirtFs::isDirectory("dir//1/") == true); + REQUIRE(VirtFs::isDirectory("dir/1") == true); + REQUIRE(VirtFs::isDirectory("dir/1/zzz") == false); + REQUIRE(VirtFs::isDirectory("test/dir1//") == false); + REQUIRE(VirtFs::isDirectory("testQ") == false); + REQUIRE(VirtFs::isDirectory("testQ/") == false); + REQUIRE(VirtFs::isDirectory("testQ//") == false); + + VirtFs::unmountZip(prefix + "data/test/test2.zip"); + + REQUIRE(VirtFs::isDirectory("dir2/units.xml") == false); + REQUIRE(VirtFs::isDirectory("dir2/units.xml/") == false); + REQUIRE(VirtFs::isDirectory("dir2//units.xml") == false); + REQUIRE(VirtFs::isDirectory("dir2/units123.xml") == false); + REQUIRE(VirtFs::isDirectory("dir2//units123.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ//units.xml") == false); + REQUIRE(VirtFs::isDirectory("units.xml") == false); + REQUIRE(VirtFs::isDirectory("dir") == true); + REQUIRE(VirtFs::isDirectory("dir2/") == false); + REQUIRE(VirtFs::isDirectory("dir2//") == false); + REQUIRE(VirtFs::isDirectory("dir/1") == false); + REQUIRE(VirtFs::isDirectory("dir\\1") == false); + REQUIRE(VirtFs::isDirectory("dir//1/") == false); + REQUIRE(VirtFs::isDirectory("dir/1") == false); + REQUIRE(VirtFs::isDirectory("dir/1/zzz") == false); + REQUIRE(VirtFs::isDirectory("test/dir1//") == false); + REQUIRE(VirtFs::isDirectory("testQ") == false); + REQUIRE(VirtFs::isDirectory("testQ/") == false); + REQUIRE(VirtFs::isDirectory("testQ//") == false); + + VirtFs::unmountZip(prefix + "data/test/test.zip"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 isDirectory3", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountDir2(prefix + "data", + "test", + Append_false); + + REQUIRE(VirtFs::isDirectory("units.xml") == false); + REQUIRE(VirtFs::isDirectory("units.xml/") == false); + REQUIRE(VirtFs::isDirectory("units123.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ//units.xml") == false); + REQUIRE(VirtFs::isDirectory("test") == false); + REQUIRE(VirtFs::isDirectory("dir1") == true); + REQUIRE(VirtFs::isDirectory("dir2//") == true); + REQUIRE(VirtFs::isDirectory("test/dir1") == false); + REQUIRE(VirtFs::isDirectory("testQ") == false); + REQUIRE(VirtFs::isDirectory("testQ/") == false); + REQUIRE(VirtFs::isDirectory("testQ//") == false); + + VirtFs::unmountDirSilent2(prefix + "data", + "test"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 isDirectory4", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip2(prefix + "data/test/test2.zip", + "dir", + Append_false); + + REQUIRE(VirtFs::isDirectory("dir2/units.xml") == false); + REQUIRE(VirtFs::isDirectory("dir2/units.xml/") == false); + REQUIRE(VirtFs::isDirectory("dir2//units.xml") == false); + REQUIRE(VirtFs::isDirectory("dir2/units123.xml") == false); + REQUIRE(VirtFs::isDirectory("dir2//units123.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ//units.xml") == false); + REQUIRE(VirtFs::isDirectory("units.xml") == false); + REQUIRE(VirtFs::isDirectory("1") == true); + REQUIRE(VirtFs::isDirectory("gpl") == true); + REQUIRE(VirtFs::isDirectory("dir2/") == false); + REQUIRE(VirtFs::isDirectory("dir/1") == false); + REQUIRE(VirtFs::isDirectory("dir/1/zzz") == false); + REQUIRE(VirtFs::isDirectory("test/dir1\\") == false); + REQUIRE(VirtFs::isDirectory("testQ") == false); + REQUIRE(VirtFs::isDirectory("testQ/") == false); + REQUIRE(VirtFs::isDirectory("testQ//") == false); + + VirtFs::unmountZip2(prefix + "data/test/test2.zip", + "dir"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 openRead1", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountDir(prefix + "data", + Append_false); + + VirtFs::File *file = nullptr; + + file = VirtFs::openRead("test/units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("test\\units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("test/units123.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("tesQ/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("testQ"); + REQUIRE(file == nullptr); + + VirtFs::mountDir(prefix + "data/test", + Append_false); + + file = VirtFs::openRead("test/units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("test/units123.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("tesQ/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("testQ"); + REQUIRE(file == nullptr); + + VirtFs::unmountDir(prefix + "data/test"); + + file = VirtFs::openRead("test/units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("test/units123.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("tesQ/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("testQ"); + REQUIRE(file == nullptr); + + VirtFs::unmountDir(prefix + "data"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 openRead2", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix("data/test/"); + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "test2.zip", + Append_false); + + VirtFs::File *file = nullptr; + + file = VirtFs::openRead("dir2/units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("dir2\\units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("dir2/units123.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("tesQ/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("units.xml1"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("testQ"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("dir/brimmedhat.png"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("dir//brimmedhat.png"); + REQUIRE(file == nullptr); + + VirtFs::mountZip(prefix + "test.zip", + Append_false); + + file = VirtFs::openRead("dir2/units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("dir2//units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("dir2/units123.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("tesQ/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("units.xml1"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("testQ"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("dir/brimmedhat.png"); + REQUIRE(file != nullptr); + VirtFs::close(file); + + VirtFs::unmountZip(prefix + "test.zip"); + + file = VirtFs::openRead("dir2/units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("dir2\\/\\units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("dir2/units123.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("tesQ/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("units.xml1"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("testQ"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("dir/brimmedhat.png"); + REQUIRE(file == nullptr); + + VirtFs::unmountZip(prefix + "test2.zip"); + + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 openRead3", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountDir2(prefix + "data", + "test", + Append_false); + + VirtFs::File *file = nullptr; + + file = VirtFs::openRead("units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("test/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("units123.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("tesQ/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("testQ"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("file1.txt"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("file2.txt"); + REQUIRE(file == nullptr); + + VirtFs::mountDir2(prefix + "data/test", + "dir2", + Append_false); + + file = VirtFs::openRead("units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("test/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("units123.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("tesQ/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("testQ"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("file1.txt"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("file2.txt"); + REQUIRE(file != nullptr); + VirtFs::close(file); + + VirtFs::unmountDir2(prefix + "data/test", + "dir2"); + + file = VirtFs::openRead("units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("test/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("units123.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("tesQ/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("testQ"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("file1.txt"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("file2.txt"); + REQUIRE(file == nullptr); + + VirtFs::unmountDir2(prefix + "data", + "test"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 openRead4", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix("data/test/"); + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip2(prefix + "test2.zip", + "dir", + Append_false); + + VirtFs::File *file = nullptr; + + file = VirtFs::openRead("dye.png"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("1\\test.txt"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("dir/dye.png"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("tesQ/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("dye.png1"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("testQ"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("brimmedhat.png"); + REQUIRE(file == nullptr); + + VirtFs::mountZip2(prefix + "test.zip", + "dir", + Append_false); + + file = VirtFs::openRead("dye.png"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("1\\test.txt"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("dir/dye.png"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("tesQ/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("dye.png1"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("testQ"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("brimmedhat.png"); + REQUIRE(file != nullptr); + VirtFs::close(file); + + VirtFs::unmountZip2(prefix + "test.zip", + "dir"); + + file = VirtFs::openRead("dye.png"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("1\\test.txt"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("dir/dye.png"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("tesQ/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("dye.png1"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("testQ"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("brimmedhat.png"); + REQUIRE(file == nullptr); + + VirtFs::unmountZip2(prefix + "test2.zip", + "dir"); + + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 permitLinks", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountDir(prefix + "data", + Append_false); + + const int cnt1 = VirtFs::exists("test/test2.txt") ? 26 : 25; + const int cnt2 = 26; + + StringVect list; + VirtFs::permitLinks(false); + VirtFs::getFiles("test", list); + removeTemp(list); + const size_t sz = list.size(); + REQUIRE(sz == cnt1); + + list.clear(); + VirtFs::permitLinks(true); + VirtFs::getFiles("test", list); + removeTemp(list); + REQUIRE(list.size() == cnt2); + + list.clear(); + VirtFs::permitLinks(false); + VirtFs::getFiles("test", list); + removeTemp(list); + REQUIRE(list.size() == cnt1); + + VirtFs::unmountDirSilent(prefix + "data"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 read1", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountDir(prefix + "data", + Append_false); + + VirtFs::File *file = VirtFs::openRead("test/test.txt"); + REQUIRE(file != nullptr); + REQUIRE(VirtFs::fileLength(file) == 23); + const int fileSize = VirtFs::fileLength(file); + + void *restrict buffer = calloc(fileSize + 1, 1); + REQUIRE(VirtFs::read(file, buffer, 1, fileSize) == fileSize); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 1\ntest line 2") == 0); + REQUIRE(VirtFs::tell(file) == fileSize); + REQUIRE(VirtFs::eof(file) != 0); + + free(buffer); + buffer = calloc(fileSize + 1, 1); + REQUIRE(VirtFs::seek(file, 12) != 0); + REQUIRE(VirtFs::eof(file) == 0); + REQUIRE(VirtFs::tell(file) == 12); + REQUIRE(VirtFs::read(file, buffer, 1, 11) == 11); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 2") == 0); + REQUIRE(VirtFs::eof(file) != 0); + + VirtFs::close(file); + free(buffer); + + VirtFs::unmountDir(prefix + "data"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 read2", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix("data/test/"); + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "test2.zip", + Append_false); + VirtFs::File *file = nullptr; + void *restrict buffer = nullptr; + + SECTION("test 1") + { + file = VirtFs::openRead("dir2//test.txt"); + REQUIRE(file != nullptr); + REQUIRE(VirtFs::fileLength(file) == 23); + const int fileSize = VirtFs::fileLength(file); + + buffer = calloc(fileSize + 1, 1); + REQUIRE(VirtFs::read(file, buffer, 1, fileSize) == fileSize); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 1\ntest line 2") == 0); + REQUIRE(VirtFs::tell(file) == fileSize); + REQUIRE(VirtFs::eof(file) != 0); + } + + SECTION("test 2") + { + file = VirtFs::openRead("dir2\\/test.txt"); + REQUIRE(file != nullptr); + REQUIRE(VirtFs::fileLength(file) == 23); + const int fileSize = VirtFs::fileLength(file); + + buffer = calloc(fileSize + 1, 1); + REQUIRE(VirtFs::seek(file, 12) != 0); + REQUIRE(VirtFs::eof(file) == 0); + REQUIRE(VirtFs::tell(file) == 12); + REQUIRE(VirtFs::read(file, buffer, 1, 11) == 11); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 2") == 0); + REQUIRE(VirtFs::eof(file) != 0); + } + + SECTION("test 3") + { + file = VirtFs::openRead("dir2//test.txt"); + REQUIRE(file != nullptr); + const int fileSize = VirtFs::fileLength(file); + + buffer = calloc(fileSize + 1, 1); + for (int f = 0; f < fileSize; f ++) + { + REQUIRE(VirtFs::seek(file, f) != 0); + REQUIRE(VirtFs::eof(file) == 0); + REQUIRE(VirtFs::tell(file) == f); + } + } + + SECTION("test 4") + { + file = VirtFs::openRead("dir2/test.txt"); + REQUIRE(file != nullptr); + const int fileSize = VirtFs::fileLength(file); + const char *restrict const str = "test line 1\ntest line 2"; + buffer = calloc(fileSize + 1, 1); + for (int f = 0; f < fileSize - 1; f ++) + { + REQUIRE(VirtFs::read(file, buffer, 1, 1) == 1); + REQUIRE(static_cast<char*>(buffer)[0] == str[f]); + REQUIRE(VirtFs::eof(file) == 0); + REQUIRE(VirtFs::tell(file) == f + 1); + } + REQUIRE(VirtFs::read(file, buffer, 1, 1) == 1); + REQUIRE(static_cast<char*>(buffer)[0] == str[22]); + REQUIRE(VirtFs::eof(file) != 0); + REQUIRE(VirtFs::tell(file) == fileSize); + } + + SECTION("test 5") + { + file = VirtFs::openRead("dir2\\\\test.txt"); + REQUIRE(file != nullptr); + const int fileSize = VirtFs::fileLength(file); + const char *restrict const str = "test line 1\ntest line 2"; + buffer = calloc(fileSize + 1, 1); + for (int f = 0; f < fileSize - 1; f += 2) + { + REQUIRE(VirtFs::read(file, buffer, 2, 1) == 1); + REQUIRE(static_cast<char*>(buffer)[0] == str[f]); + REQUIRE(static_cast<char*>(buffer)[1] == str[f + 1]); + REQUIRE(VirtFs::eof(file) == 0); + REQUIRE(VirtFs::tell(file) == f + 2); + } + REQUIRE(VirtFs::eof(file) == 0); + REQUIRE(VirtFs::tell(file) == 22); + REQUIRE(VirtFs::read(file, buffer, 2, 1) == 0); + REQUIRE(VirtFs::eof(file) == 0); + } + + SECTION("test 6") + { + file = VirtFs::openRead("dir2//test.txt"); + REQUIRE(file != nullptr); + const int fileSize = VirtFs::fileLength(file); + const char *restrict const str = "test line 1\ntest line 2"; + buffer = calloc(fileSize + 1, 1); + for (int f = 0; f < fileSize - 1; f += 2) + { + REQUIRE(VirtFs::read(file, buffer, 1, 2) == 2); + REQUIRE(static_cast<char*>(buffer)[0] == str[f]); + REQUIRE(static_cast<char*>(buffer)[1] == str[f + 1]); + REQUIRE(VirtFs::eof(file) == 0); + REQUIRE(VirtFs::tell(file) == f + 2); + } + REQUIRE(VirtFs::eof(file) == 0); + REQUIRE(VirtFs::tell(file) == 22); + REQUIRE(VirtFs::read(file, buffer, 1, 2) == 1); + REQUIRE(static_cast<char*>(buffer)[0] == str[22]); + REQUIRE(VirtFs::eof(file) != 0); + } + + VirtFs::close(file); + free(buffer); + VirtFs::unmountZip(prefix + "test2.zip"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 loadFile1", "") +{ + VirtFs::init("."); + int fileSize = 0; + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountDir(prefix + "data", + Append_false); + + const char *const buffer = VirtFs::loadFile("test/test.txt", fileSize); + REQUIRE(static_cast<const void*>(buffer) != nullptr); + REQUIRE(fileSize == 23); + REQUIRE(strncmp(buffer, "test line 1\ntest line 2", 23) == 0); + delete [] buffer; + + VirtFs::unmountDir(prefix + "data"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 loadFile2", "") +{ + VirtFs::init("."); + int fileSize = 0; + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "data/test/test2.zip", + Append_false); + + SECTION("test 1") + { + const char *restrict buffer = VirtFs::loadFile("dir2//test.txt", + fileSize); + REQUIRE(static_cast<const void*>(buffer) != nullptr); + REQUIRE(fileSize == 23); + REQUIRE(strncmp(buffer, "test line 1\ntest line 2", 23) == 0); + delete [] buffer; + } + + SECTION("test 2") + { + const char *restrict buffer = VirtFs::loadFile("dir2\\/test.txt", + fileSize); + REQUIRE(static_cast<const void*>(buffer) != nullptr); + REQUIRE(fileSize == 23); + REQUIRE(strncmp(buffer, "test line 1\ntest line 2", 23) == 0); + delete [] buffer; + } + + VirtFs::unmountZip(prefix + "data/test/test2.zip"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 loadFile3", "") +{ + VirtFs::init("."); + int fileSize = 0; + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountDir2(prefix + "data", + "test", + Append_false); + + const char *const buffer = VirtFs::loadFile("test.txt", fileSize); + REQUIRE(static_cast<const void*>(buffer) != nullptr); + REQUIRE(fileSize == 23); + REQUIRE(strncmp(buffer, "test line 1\ntest line 2", 23) == 0); + delete [] buffer; + + VirtFs::unmountDir2(prefix + "data", + "test"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 loadFile4", "") +{ + VirtFs::init("."); + int fileSize = 0; + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip2(prefix + "data/test/test2.zip", + "dir2", + Append_false); + + SECTION("test 1") + { + const char *restrict buffer = VirtFs::loadFile("test.txt", + fileSize); + REQUIRE(static_cast<const void*>(buffer) != nullptr); + REQUIRE(fileSize == 23); + REQUIRE(strncmp(buffer, "test line 1\ntest line 2", 23) == 0); + delete [] buffer; + } + + SECTION("test 2") + { + const char *restrict buffer = VirtFs::loadFile("test.txt", + fileSize); + REQUIRE(static_cast<const void*>(buffer) != nullptr); + REQUIRE(fileSize == 23); + REQUIRE(strncmp(buffer, "test line 1\ntest line 2", 23) == 0); + delete [] buffer; + } + + VirtFs::unmountZip2(prefix + "data/test/test2.zip", + "dir2"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 rwops_read1", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountDir(prefix + "data", + Append_false); + + SDL_RWops *file = VirtFs::rwopsOpenRead("test/test.txt"); + REQUIRE(file != nullptr); +#ifdef USE_SDL2 + REQUIRE(file->size(file) == 23); +#endif // USE_SDL2 + + const int fileSize = 23; + + void *restrict buffer = calloc(fileSize + 1, 1); + REQUIRE(file->read(file, buffer, 1, fileSize) == fileSize); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 1\ntest line 2") == 0); + REQUIRE(file->seek(file, 0, SEEK_CUR) == fileSize); + + free(buffer); + buffer = calloc(fileSize + 1, 1); + REQUIRE(file->seek(file, 12, SEEK_SET) != 0); + REQUIRE(file->seek(file, 0, SEEK_CUR) == 12); + REQUIRE(file->read(file, buffer, 1, 11) == 11); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 2") == 0); + + file->close(file); + free(buffer); + + VirtFs::unmountDir(prefix + "data"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 rwops_read2", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix("data/test/"); + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "test2.zip", + Append_false); + SDL_RWops *file = nullptr; + void *restrict buffer = nullptr; + + SECTION("test 1") + { + file = VirtFs::rwopsOpenRead("dir2//test.txt"); + REQUIRE(file != nullptr); +#ifdef USE_SDL2 + REQUIRE(file->size(file) == 23); +#endif // USE_SDL2 + const int fileSize = 23; + + buffer = calloc(fileSize + 1, 1); + REQUIRE(file->read(file, buffer, 1, fileSize) == fileSize); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 1\ntest line 2") == 0); + REQUIRE(file->seek(file, 0, SEEK_CUR) == fileSize); + } + + SECTION("test 2") + { + file = VirtFs::rwopsOpenRead("dir2\\/test.txt"); + REQUIRE(file != nullptr); +#ifdef USE_SDL2 + REQUIRE(file->size(file) == 23); +#endif // USE_SDL2 + const int fileSize = 23; + + buffer = calloc(fileSize + 1, 1); + REQUIRE(file->seek(file, 12, SEEK_SET) != 0); + REQUIRE(file->seek(file, 0, SEEK_CUR) == 12); + REQUIRE(file->read(file, buffer, 1, 11) == 11); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 2") == 0); + } + + SECTION("test 3") + { + file = VirtFs::rwopsOpenRead("dir2//test.txt"); + REQUIRE(file != nullptr); + const int fileSize = 23; + + buffer = calloc(fileSize + 1, 1); + for (int f = 0; f < fileSize; f ++) + { + REQUIRE(file->seek(file, f, SEEK_SET) == f); + REQUIRE(file->seek(file, 0, SEEK_CUR) == f); + } + } + + SECTION("test 4") + { + file = VirtFs::rwopsOpenRead("dir2/test.txt"); + REQUIRE(file != nullptr); + const int fileSize = 23; + const char *restrict const str = "test line 1\ntest line 2"; + buffer = calloc(fileSize + 1, 1); + for (int f = 0; f < fileSize - 1; f ++) + { + REQUIRE(file->read(file, buffer, 1, 1) == 1); + REQUIRE(static_cast<char*>(buffer)[0] == str[f]); + REQUIRE(file->seek(file, 0, SEEK_CUR) == f + 1); + } + REQUIRE(file->read(file, buffer, 1, 1) == 1); + REQUIRE(static_cast<char*>(buffer)[0] == str[22]); + REQUIRE(file->seek(file, 0, SEEK_CUR) == fileSize); + } + + SECTION("test 5") + { + file = VirtFs::rwopsOpenRead("dir2\\\\test.txt"); + REQUIRE(file != nullptr); + const int fileSize = 23; + const char *restrict const str = "test line 1\ntest line 2"; + buffer = calloc(fileSize + 1, 1); + for (int f = 0; f < fileSize - 1; f += 2) + { + REQUIRE(file->read(file, buffer, 2, 1) == 1); + REQUIRE(static_cast<char*>(buffer)[0] == str[f]); + REQUIRE(static_cast<char*>(buffer)[1] == str[f + 1]); + REQUIRE(file->seek(file, 0, SEEK_CUR) == f + 2); + } + REQUIRE(file->seek(file, 0, SEEK_CUR) == 22); + REQUIRE(file->read(file, buffer, 2, 1) == 0); + } + + SECTION("test 6") + { + file = VirtFs::rwopsOpenRead("dir2//test.txt"); + REQUIRE(file != nullptr); + const int fileSize = 23; + const char *restrict const str = "test line 1\ntest line 2"; + buffer = calloc(fileSize + 1, 1); + for (int f = 0; f < fileSize - 1; f += 2) + { + REQUIRE(file->read(file, buffer, 1, 2) == 2); + REQUIRE(static_cast<char*>(buffer)[0] == str[f]); + REQUIRE(static_cast<char*>(buffer)[1] == str[f + 1]); + REQUIRE(file->seek(file, 0, SEEK_CUR) == f + 2); + } + REQUIRE(file->seek(file, 0, SEEK_CUR) == 22); + REQUIRE(file->read(file, buffer, 1, 2) == 1); + REQUIRE(static_cast<char*>(buffer)[0] == str[22]); + } + + SECTION("test 7") + { + file = VirtFs::rwopsOpenRead("dir2//test.txt"); + REQUIRE(file != nullptr); + const int fileSize = 23; + const char *restrict const str = "test line 1\ntest line 2"; + buffer = calloc(fileSize + 1, 1); + for (int f = 0; f < fileSize - 1; f += 2) + { + REQUIRE(file->read(file, buffer, 1, 2) == 2); + REQUIRE(file->seek(file, -2, SEEK_CUR) == f); + REQUIRE(file->seek(file, 0, SEEK_CUR) == f); + REQUIRE(file->seek(file, 2, SEEK_CUR) == f + 2); + REQUIRE(static_cast<char*>(buffer)[0] == str[f]); + REQUIRE(static_cast<char*>(buffer)[1] == str[f + 1]); + REQUIRE(file->seek(file, 0, SEEK_CUR) == f + 2); + } + REQUIRE(file->seek(file, 0, SEEK_CUR) == 22); + REQUIRE(file->read(file, buffer, 1, 2) == 1); + REQUIRE(static_cast<char*>(buffer)[0] == str[22]); + } + + SECTION("test 8") + { + file = VirtFs::rwopsOpenRead("dir2//test.txt"); + REQUIRE(file != nullptr); + const int fileSize = 23; + const char *restrict const str = "test line 1\ntest line 2"; + buffer = calloc(fileSize + 1, 1); + for (int f = 0; f < fileSize - 1; f += 2) + { + REQUIRE(file->seek(file, -f - 2, SEEK_END) == 23 - f - 2); + REQUIRE(file->read(file, buffer, 1, 2) == 2); + REQUIRE(static_cast<char*>(buffer)[0] == str[23 - f - 2]); + REQUIRE(static_cast<char*>(buffer)[1] == str[23 - f - 2 + 1]); + REQUIRE(file->seek(file, 0, SEEK_CUR) == 23 - f); + } + // 3 + REQUIRE(file->seek(file, 1, SEEK_CUR) == 4); + // 4 + REQUIRE(file->read(file, buffer, 1, 2) == 2); + // 6 + REQUIRE(static_cast<char*>(buffer)[0] == str[4]); + REQUIRE(static_cast<char*>(buffer)[1] == str[5]); + REQUIRE(file->seek(file, -7, SEEK_CUR) == -1); + REQUIRE(file->seek(file, 6, SEEK_SET) == 6); + REQUIRE(file->seek(file, -6, SEEK_CUR) == 0); + } + + if (file != nullptr) + file->close(file); + free(buffer); + VirtFs::unmountZip(prefix + "test2.zip"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 rwops_read3", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountDir(prefix + "data", + Append_false); + SDL_RWops *file = nullptr; + void *restrict buffer = nullptr; + + SECTION("test 1") + { + file = VirtFs::rwopsOpenRead("test/test.txt"); + REQUIRE(file != nullptr); +#ifdef USE_SDL2 + REQUIRE(file->size(file) == 23); +#endif // USE_SDL2 + const int fileSize = 23; + + buffer = calloc(fileSize + 1, 1); + REQUIRE(file->read(file, buffer, 1, fileSize) == fileSize); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 1\ntest line 2") == 0); + REQUIRE(file->seek(file, 0, SEEK_CUR) == fileSize); + } + + SECTION("test 2") + { + file = VirtFs::rwopsOpenRead("test\\test.txt"); + REQUIRE(file != nullptr); +#ifdef USE_SDL2 + REQUIRE(file->size(file) == 23); +#endif // USE_SDL2 + const int fileSize = 23; + + buffer = calloc(fileSize + 1, 1); + REQUIRE(file->seek(file, 12, SEEK_SET) != 0); + REQUIRE(file->seek(file, 0, SEEK_CUR) == 12); + REQUIRE(file->read(file, buffer, 1, 11) == 11); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 2") == 0); + } + + SECTION("test 3") + { + file = VirtFs::rwopsOpenRead("test\\/test.txt"); + REQUIRE(file != nullptr); + const int fileSize = 23; + + buffer = calloc(fileSize + 1, 1); + for (int f = 0; f < fileSize; f ++) + { + REQUIRE(file->seek(file, f, SEEK_SET) == f); + REQUIRE(file->seek(file, 0, SEEK_CUR) == f); + } + } + + SECTION("test 4") + { + file = VirtFs::rwopsOpenRead("test/test.txt"); + REQUIRE(file != nullptr); + const int fileSize = 23; + const char *restrict const str = "test line 1\ntest line 2"; + buffer = calloc(fileSize + 1, 1); + for (int f = 0; f < fileSize - 1; f ++) + { + REQUIRE(file->read(file, buffer, 1, 1) == 1); + REQUIRE(static_cast<char*>(buffer)[0] == str[f]); + REQUIRE(file->seek(file, 0, SEEK_CUR) == f + 1); + } + REQUIRE(file->read(file, buffer, 1, 1) == 1); + REQUIRE(static_cast<char*>(buffer)[0] == str[22]); + REQUIRE(file->seek(file, 0, SEEK_CUR) == fileSize); + } + + SECTION("test 5") + { + file = VirtFs::rwopsOpenRead("test///test.txt"); + REQUIRE(file != nullptr); + const int fileSize = 23; + const char *restrict const str = "test line 1\ntest line 2"; + buffer = calloc(fileSize + 1, 1); + for (int f = 0; f < fileSize - 1; f += 2) + { + REQUIRE(file->read(file, buffer, 2, 1) == 1); + REQUIRE(static_cast<char*>(buffer)[0] == str[f]); + REQUIRE(static_cast<char*>(buffer)[1] == str[f + 1]); + REQUIRE(file->seek(file, 0, SEEK_CUR) == f + 2); + } + REQUIRE(file->seek(file, 0, SEEK_CUR) == 22); + REQUIRE(file->read(file, buffer, 2, 1) == 0); + } + + SECTION("test 6") + { + file = VirtFs::rwopsOpenRead("test\\\\test.txt"); + REQUIRE(file != nullptr); + const int fileSize = 23; + const char *restrict const str = "test line 1\ntest line 2"; + buffer = calloc(fileSize + 1, 1); + for (int f = 0; f < fileSize - 1; f += 2) + { + REQUIRE(file->read(file, buffer, 1, 2) == 2); + REQUIRE(static_cast<char*>(buffer)[0] == str[f]); + REQUIRE(static_cast<char*>(buffer)[1] == str[f + 1]); + REQUIRE(file->seek(file, 0, SEEK_CUR) == f + 2); + } + REQUIRE(file->seek(file, 0, SEEK_CUR) == 22); + REQUIRE(file->read(file, buffer, 1, 2) == 1); + REQUIRE(static_cast<char*>(buffer)[0] == str[22]); + } + + SECTION("test 7") + { + file = VirtFs::rwopsOpenRead("test//test.txt"); + REQUIRE(file != nullptr); + const int fileSize = 23; + const char *restrict const str = "test line 1\ntest line 2"; + buffer = calloc(fileSize + 1, 1); + for (int f = 0; f < fileSize - 1; f += 2) + { + REQUIRE(file->read(file, buffer, 1, 2) == 2); + REQUIRE(file->seek(file, -2, SEEK_CUR) == f); + REQUIRE(file->seek(file, 0, SEEK_CUR) == f); + REQUIRE(file->seek(file, 2, SEEK_CUR) == f + 2); + REQUIRE(static_cast<char*>(buffer)[0] == str[f]); + REQUIRE(static_cast<char*>(buffer)[1] == str[f + 1]); + REQUIRE(file->seek(file, 0, SEEK_CUR) == f + 2); + } + REQUIRE(file->seek(file, 0, SEEK_CUR) == 22); + REQUIRE(file->read(file, buffer, 1, 2) == 1); + REQUIRE(static_cast<char*>(buffer)[0] == str[22]); + } + + SECTION("test 8") + { + file = VirtFs::rwopsOpenRead("test/test.txt"); + REQUIRE(file != nullptr); + const int fileSize = 23; + const char *restrict const str = "test line 1\ntest line 2"; + buffer = calloc(fileSize + 1, 1); + for (int f = 0; f < fileSize - 1; f += 2) + { + REQUIRE(file->seek(file, -f - 2, SEEK_END) == 23 - f - 2); + REQUIRE(file->read(file, buffer, 1, 2) == 2); + REQUIRE(static_cast<char*>(buffer)[0] == str[23 - f - 2]); + REQUIRE(static_cast<char*>(buffer)[1] == str[23 - f - 2 + 1]); + REQUIRE(file->seek(file, 0, SEEK_CUR) == 23 - f); + } + // 3 + REQUIRE(file->seek(file, 1, SEEK_CUR) == 4); + // 4 + REQUIRE(file->read(file, buffer, 1, 2) == 2); + // 6 + REQUIRE(static_cast<char*>(buffer)[0] == str[4]); + REQUIRE(static_cast<char*>(buffer)[1] == str[5]); + REQUIRE(file->seek(file, -7, SEEK_CUR) == -1); + REQUIRE(file->seek(file, 6, SEEK_SET) == 6); + REQUIRE(file->seek(file, -6, SEEK_CUR) == 0); + } + + if (file != nullptr) + file->close(file); + free(buffer); + VirtFs::unmountDir(prefix + "data"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 getFiles zip1", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "data/test/test2.zip", + Append_false); + + StringVect list; + VirtFs::getFiles("dir", list); + REQUIRE(list.size() == 2); + REQUIRE(inList(list, "dye.png")); + REQUIRE(inList(list, "hide.png")); + + list.clear(); + VirtFs::getFiles("dir2", list); + REQUIRE(list.size() == 4); + REQUIRE(inList(list, "hide.png")); + REQUIRE(inList(list, "paths.xml")); + REQUIRE(inList(list, "test.txt")); + REQUIRE(inList(list, "units.xml")); + + VirtFs::unmountZip(prefix + "data/test/test2.zip"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 getFiles zip2", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip2(prefix + "data/test/test2.zip", + "dir", + Append_false); + + StringVect list; + VirtFs::getFiles(dirSeparator, list); + REQUIRE(list.size() == 2); + REQUIRE(inList(list, "dye.png")); + REQUIRE(inList(list, "hide.png")); + + list.clear(); + VirtFs::getFiles("1", list); + REQUIRE(list.size() == 2); + REQUIRE(inList(list, "file1.txt")); + REQUIRE(inList(list, "test.txt")); + + VirtFs::unmountZip2(prefix + "data/test/test2.zip", + "dir"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 getDirs1", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "data/test/test2.zip", + Append_false); + + StringVect list; + VirtFs::getDirs("dir", list); + REQUIRE(list.size() == 2); + REQUIRE(inList(list, "1")); + REQUIRE(inList(list, "gpl")); + list.clear(); + + VirtFs::getDirs("dir2", list); + REQUIRE(list.empty()); + + VirtFs::unmountZip(prefix + "data/test/test2.zip"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 getDirs2", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + StringVect list; + + SECTION("dir1") + { + VirtFs::mountDir(prefix + "data/test", + Append_false); + + VirtFs::getDirs("/", list); +// REQUIRE(list.size() == 2); + REQUIRE(inList(list, "dir1")); + REQUIRE(inList(list, "dir2")); + list.clear(); + + VirtFs::getDirs("dir1", list); + REQUIRE(list.empty()); + + VirtFs::unmountDir(prefix + "data/test"); + } + + SECTION("dir2") + { + VirtFs::mountDir(prefix + "data", + Append_false); + + VirtFs::getDirs("sfx", list); + REQUIRE(inList(list, "system")); + list.clear(); + + VirtFs::getDirs("evol", list); + REQUIRE(list.size() == 2); + REQUIRE(inList(list, "icons")); + REQUIRE(inList(list, "images")); + + VirtFs::unmountDir(prefix + "data"); + } + + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 getDirs3", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip2(prefix + "data/test/test2.zip", + "dir", + Append_false); + + StringVect list; + VirtFs::getDirs(dirSeparator, list); + REQUIRE(list.size() == 2); + REQUIRE(inList(list, "1")); + REQUIRE(inList(list, "gpl")); + list.clear(); + + VirtFs::getDirs("1", list); + REQUIRE(list.empty()); + + VirtFs::unmountZip2(prefix + "data/test/test2.zip", + "dir"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 getDirs4", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + StringVect list; + + SECTION("dir1") + { + VirtFs::mountDir2(prefix + "data", + "test", + Append_false); + + VirtFs::getDirs("/", list); + REQUIRE(inList(list, "dir1")); + REQUIRE(inList(list, "dir2")); + list.clear(); + + VirtFs::getDirs("dir1", list); + REQUIRE(list.empty()); + + VirtFs::unmountDir2(prefix + "data", + "test"); + } + + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 getFilesWithDir1", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "data/test/test2.zip", + Append_false); + + StringVect list; + VirtFs::getFilesWithDir("dir", list); + REQUIRE(list.size() == 2); + REQUIRE(inList(list, "dir", "dye.png")); + REQUIRE(inList(list, "dir", "hide.png")); + list.clear(); + + VirtFs::getFilesWithDir("dir2", list); + REQUIRE(list.size() == 4); + REQUIRE(inList(list, "dir2", "hide.png")); + REQUIRE(inList(list, "dir2", "paths.xml")); + REQUIRE(inList(list, "dir2", "test.txt")); + REQUIRE(inList(list, "dir2", "units.xml")); + list.clear(); + + VirtFs::getFilesWithDir(dirSeparator, list); + REQUIRE(list.size() > 2); + REQUIRE(inList(list, dirSeparator, "test.txt")); + REQUIRE(inList(list, dirSeparator, "units.xml")); + list.clear(); + + VirtFs::unmountZip(prefix + "data/test/test2.zip"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 getFilesWithDir2", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + StringVect list; + + SECTION("dir1") + { + VirtFs::mountDir(prefix + "data/graphics", + Append_false); + + VirtFs::getFilesWithDir("/", list); + REQUIRE(list.size() <= 5); + VirtFs::unmountDir(prefix + "data/graphics"); + } + + SECTION("dir2") + { + VirtFs::mountDir(prefix + "data", + Append_false); + + VirtFs::getFilesWithDir("music", list); + REQUIRE(list.size() <= 5); + REQUIRE(!list.empty()); + REQUIRE(inList(list, "music", "keprohm.ogg")); + list.clear(); + + VirtFs::getFilesWithDir(pathJoin("evol", "icons"), list); +#ifdef WIN32 + REQUIRE(list.size() == 1); + REQUIRE(inList(list, pathJoin("evol", "icons"), "evol-client.ico")); +#else // WIN32 + + REQUIRE(list.size() == 3); + REQUIRE(inList(list, pathJoin("evol", "icons"), "evol-client.ico")); + REQUIRE(inList(list, pathJoin("evol", "icons"), "evol-client.png")); + REQUIRE(inList(list, pathJoin("evol", "icons"), "evol-client.xpm")); +#endif // WIN32 + + VirtFs::unmountDir(prefix + "data"); + } + + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 getFilesWithDir3", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip2(prefix + "data/test/test2.zip", + "dir", + Append_false); + + StringVect list; + VirtFs::getFilesWithDir("1", list); + REQUIRE(list.size() == 2); + REQUIRE(inList(list, "1", "file1.txt")); + REQUIRE(inList(list, "1", "test.txt")); + list.clear(); + + VirtFs::getFilesWithDir(dirSeparator, list); + REQUIRE(list.size() == 2); + REQUIRE(inList(list, dirSeparator, "dye.png")); + REQUIRE(inList(list, dirSeparator, "hide.png")); + list.clear(); + + VirtFs::unmountZip2(prefix + "data/test/test2.zip", + "dir"); + VirtFs::deinit(); + delete2(logger); +} + +TEST_CASE("VirtFs1 getFilesWithDir4", "") +{ + VirtFs::init("."); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + StringVect list; + + SECTION("dir1") + { + VirtFs::mountDir2(prefix + "data/graphics", + "sprites", + Append_false); + + VirtFs::getFilesWithDir("/", list); + REQUIRE(list.size() <= 16); + VirtFs::unmountDir2(prefix + "data/graphics", + "sprites"); + } + + SECTION("dir2") + { + VirtFs::mountDir2(prefix + "data", + "test", + Append_false); + + VirtFs::getFilesWithDir("dir1", list); + REQUIRE(list.size() <= 6); + REQUIRE(!list.empty()); + REQUIRE(inList(list, "dir1", "file1.txt")); + list.clear(); + + VirtFs::unmountDir2(prefix + "data", + "test"); + } + + VirtFs::deinit(); + delete2(logger); +} diff --git a/src/unittests/fs/virtfs/virtfs_unittest.cc b/src/unittests/fs/virtfs/virtfs_unittest.cc new file mode 100644 index 000000000..c31f0965e --- /dev/null +++ b/src/unittests/fs/virtfs/virtfs_unittest.cc @@ -0,0 +1,1054 @@ +/* + * The ManaPlus Client + * Copyright (C) 2016-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "fs/files.h" +#include "fs/paths.h" + +#include "fs/virtfs/fs.h" +#include "fs/virtfs/list.h" + +#include "utils/checkutils.h" +#include "utils/delete2.h" +#include "utils/foreach.h" + +#ifndef UNITTESTS_CATCH +#include <algorithm> +#endif // UNITTESTS_CATCH + +#include "debug.h" + +TEST_CASE("VirtFs dirSeparator", "") +{ + REQUIRE(dirSeparator != nullptr); + REQUIRE(VirtFs::getDirSeparator() == std::string(dirSeparator)); + VirtFs::updateDirSeparator(); + REQUIRE(dirSeparator != nullptr); + REQUIRE(VirtFs::getDirSeparator() == std::string(dirSeparator)); +} + +TEST_CASE("VirtFs getBaseDir", "") +{ + REQUIRE(VirtFs::getBaseDir() != nullptr); +} + +TEST_CASE("VirtFs getUserDir", "") +{ + REQUIRE(VirtFs::getUserDir() != nullptr); +} + +TEST_CASE("VirtFs exists1", "") +{ + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + REQUIRE(VirtFs::exists("test") == true); + REQUIRE(VirtFs::exists("test/dir1") == true); + REQUIRE(VirtFs::exists("test/dir") == false); + REQUIRE(VirtFs::exists("test/units.xml") == true); + REQUIRE(VirtFs::exists("test/units123.xml") == false); + REQUIRE(VirtFs::exists("tesQ/units.xml") == false); + REQUIRE(VirtFs::exists("units.xml") == false); + + VirtFs::mountDirSilent("data/test", Append_false); + VirtFs::mountDirSilent("../data/test", Append_false); + + REQUIRE(VirtFs::exists("test") == true); + REQUIRE(VirtFs::exists("test/dir1") == true); + REQUIRE(VirtFs::exists("test/dir") == false); + REQUIRE(VirtFs::exists("test/units.xml") == true); + REQUIRE(VirtFs::exists("test/units123.xml") == false); + REQUIRE(VirtFs::exists("tesQ/units.xml") == false); + REQUIRE(VirtFs::exists("units.xml") == true); + + VirtFs::unmountDirSilent("data/test"); + VirtFs::unmountDirSilent("../data/test"); + + REQUIRE(VirtFs::exists("test") == true); + REQUIRE(VirtFs::exists("test/dir1") == true); + REQUIRE(VirtFs::exists("test/dir") == false); + REQUIRE(VirtFs::exists("test/units.xml") == true); + REQUIRE(VirtFs::exists("test/units123.xml") == false); + REQUIRE(VirtFs::exists("tesQ/units.xml") == false); + REQUIRE(VirtFs::exists("units.xml") == false); + + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +} + +TEST_CASE("VirtFs exists2", "") +{ + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "data/test/test2.zip", Append_false); + + REQUIRE(VirtFs::exists("test") == false); + REQUIRE(VirtFs::exists("test/units.xml") == false); + REQUIRE(VirtFs::exists("test.txt") == true); + REQUIRE(VirtFs::exists("dir/hide.png") == true); + REQUIRE(VirtFs::exists("dir/gpl") == true); + REQUIRE(VirtFs::exists("dir/gpl/zzz") == false); + REQUIRE(VirtFs::exists("units.xml") == true); + REQUIRE(VirtFs::exists("units.xml.") == false); + REQUIRE(VirtFs::exists("units.xml2") == false); + + VirtFs::unmountZip(prefix + "data/test/test2.zip"); + delete2(logger); +} + +TEST_CASE("VirtFs exists3", "") +{ + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "data/test/test.zip", Append_false); + VirtFs::mountZip(prefix + "data/test/test2.zip", Append_false); + + REQUIRE(VirtFs::exists("test") == false); + REQUIRE(VirtFs::exists("test/units.xml") == false); + REQUIRE(VirtFs::exists("dir/brimmedhat.png")); + REQUIRE(VirtFs::exists("dir//brimmedhat.png")); + REQUIRE(VirtFs::exists("dir//hide.png")); + REQUIRE(VirtFs::exists("dir/1")); + REQUIRE(VirtFs::exists("dir/gpl")); + REQUIRE(VirtFs::exists("dir/dye.png")); + REQUIRE(VirtFs::exists("dir/2") == false); + REQUIRE(VirtFs::exists("dir2/2") == false); + REQUIRE(VirtFs::exists("dir2/paths.xml")); + + VirtFs::unmountZip(prefix + "data/test/test.zip"); + VirtFs::unmountZip(prefix + "data/test/test2.zip"); + delete2(logger); +} + +TEST_CASE("VirtFs exists4", "") +{ + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "data/test/test.zip", Append_false); + VirtFs::mountDirSilent(prefix + "data/test", Append_false); + + REQUIRE(VirtFs::exists("test") == false); + REQUIRE(VirtFs::exists("test/units.xml") == false); + REQUIRE(VirtFs::exists("dir/brimmedhat.png")); + REQUIRE(VirtFs::exists("dir//brimmedhat.png")); + REQUIRE(VirtFs::exists("dir//hide.png")); + REQUIRE(VirtFs::exists("dir/1") == false); + REQUIRE(VirtFs::exists("dir/gpl") == false); + REQUIRE(VirtFs::exists("dir/dye.png") == false); + REQUIRE(VirtFs::exists("dir/2") == false); + REQUIRE(VirtFs::exists("dir2/2") == false); + REQUIRE(VirtFs::exists("dir2/paths.xml") == false); + REQUIRE(VirtFs::exists("units.xml")); + REQUIRE(VirtFs::exists("dir1/file1.txt")); + REQUIRE(VirtFs::exists("dir2/file2.txt")); + REQUIRE(VirtFs::exists("dir2/file3.txt") == false); + + VirtFs::unmountZip(prefix + "data/test/test.zip"); + VirtFs::unmountDirSilent(prefix + "data/test"); + delete2(logger); +} + +TEST_CASE("VirtFs exists5", "") +{ + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + const std::string realDir = getRealPath(prefix + "data"); + logger->log("real dir: " + realDir); + REQUIRE_FALSE(VirtFs::exists(realDir)); + + delete2(logger); +} + +TEST_CASE("VirtFs exists6", "") +{ + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip2(prefix + "data/test/test2.zip", + "dir", + Append_false); + + REQUIRE(VirtFs::exists("test") == false); + REQUIRE(VirtFs::exists("test/units.xml") == false); + REQUIRE(VirtFs::exists("test.txt") == false); + REQUIRE(VirtFs::exists("dir/hide.png") == false); + REQUIRE(VirtFs::exists("dir/gpl") == false); + REQUIRE(VirtFs::exists("dir/gpl/zzz") == false); + REQUIRE(VirtFs::exists("units.xml") == false); + REQUIRE(VirtFs::exists("units.xml.") == false); + REQUIRE(VirtFs::exists("units.xml2") == false); + REQUIRE(VirtFs::exists("hide.png")); + REQUIRE(VirtFs::exists("dye.png")); + REQUIRE(VirtFs::exists("gpl")); + REQUIRE(VirtFs::exists("gpl/zzz") == false); + + VirtFs::unmountZip2(prefix + "data/test/test2.zip", + "dir"); + delete2(logger); +} + +static void removeTemp(StringVect &restrict list) +{ + int cnt = 0; + std::sort(list.begin(), list.end()); + + FOR_EACH (StringVectIter, it, list) + { + if (*it != "serverlistplus.xml.part") + { + logger->log("file: %d %s", + cnt, + (*it).c_str()); + cnt ++; + } + } + + FOR_EACH (StringVectIter, it, list) + { + if (*it == "serverlistplus.xml.part") + { + list.erase(it); + return; + } + } +} + +static bool inList(const VirtFs::List *const list, + const std::string &name) +{ + FOR_EACH (StringVectCIter, it, list->names) + { + if (*it == name) + return true; + } + return false; +} + +TEST_CASE("VirtFs enumerateFiles1", "") +{ + logger = new Logger; + + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + VirtFs::List *list = nullptr; + + const int cnt1 = VirtFs::exists("test/test2.txt") ? 28 : 27; + const int cnt2 = 28; + + VirtFs::permitLinks(false); + list = VirtFs::enumerateFiles("test"); + removeTemp(list->names); + const size_t sz = list->names.size(); + REQUIRE(sz == cnt1); + VirtFs::freeList(list); + + VirtFs::permitLinks(true); + list = VirtFs::enumerateFiles("test"); + removeTemp(list->names); + REQUIRE(list->names.size() == cnt2); + VirtFs::freeList(list); + + VirtFs::permitLinks(false); + list = VirtFs::enumerateFiles("test"); + removeTemp(list->names); + REQUIRE(list->names.size() == cnt1); + VirtFs::freeList(list); + + list = VirtFs::enumerateFiles("test/units.xml"); + removeTemp(list->names); + REQUIRE(list->names.empty()); + VirtFs::freeList(list); + + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +} + +TEST_CASE("VirtFs enumerateFiles2", "") +{ + logger = new Logger; + + VirtFs::mountDirSilent("data/test/dir1", + Append_false); + VirtFs::mountDirSilent("../data/test/dir1", + Append_false); + + VirtFs::List *list = nullptr; + + list = VirtFs::enumerateFiles("/"); + REQUIRE(list->names.size() == 5); + VirtFs::freeList(list); + + VirtFs::unmountDirSilent("data/test/dir1"); + VirtFs::unmountDirSilent("../data/test/dir1"); + delete2(logger); +} + +TEST_CASE("VirtFs enumerateFiles3", "") +{ + logger = new Logger; + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "data/test/test.zip", + Append_false); + + VirtFs::List *list = nullptr; + + list = VirtFs::enumerateFiles("/"); + REQUIRE(list->names.size() == 1); + REQUIRE(inList(list, "dir")); + VirtFs::freeList(list); + + VirtFs::unmountZip(prefix + "data/test/test.zip"); + delete2(logger); +} + +TEST_CASE("VirtFs enumerateFiles4", "") +{ + logger = new Logger; + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "data/test/test2.zip", + Append_false); + + VirtFs::List *list = nullptr; + + list = VirtFs::enumerateFiles("/"); + REQUIRE(list->names.size() == 4); + REQUIRE(inList(list, "dir")); + REQUIRE(inList(list, "dir2")); + REQUIRE(inList(list, "test.txt")); + REQUIRE(inList(list, "units.xml")); + VirtFs::freeList(list); + + VirtFs::unmountZip(prefix + "data/test/test2.zip"); + delete2(logger); +} + +TEST_CASE("VirtFs enumerateFiles5", "") +{ + logger = new Logger; + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "data/test/test2.zip", + Append_false); + VirtFs::mountDirSilent(prefix + "data/test", Append_false); + + VirtFs::List *list = nullptr; + + list = VirtFs::enumerateFiles("dir2"); + REQUIRE(inList(list, "file1.txt")); + REQUIRE(inList(list, "file2.txt")); + REQUIRE(inList(list, "hide.png")); + REQUIRE(inList(list, "paths.xml")); + REQUIRE(inList(list, "test.txt")); + REQUIRE(inList(list, "units.xml")); + VirtFs::freeList(list); + + VirtFs::unmountZip(prefix + "data/test/test2.zip"); + VirtFs::unmountDirSilent(prefix + "data/test"); + delete2(logger); +} + +TEST_CASE("VirtFs isDirectory1", "") +{ + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + REQUIRE(VirtFs::isDirectory("test/units.xml") == false); + REQUIRE(VirtFs::isDirectory("test/units.xml/") == false); + REQUIRE(VirtFs::isDirectory("test//units.xml") == false); + REQUIRE(VirtFs::isDirectory("test/units123.xml") == false); + REQUIRE(VirtFs::isDirectory("test//units123.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ//units.xml") == false); + REQUIRE(VirtFs::isDirectory("units.xml") == false); + REQUIRE(VirtFs::isDirectory("test") == true); + REQUIRE(VirtFs::isDirectory("test/") == true); + REQUIRE(VirtFs::isDirectory("test//") == true); + REQUIRE(VirtFs::isDirectory("test/dir1") == true); + REQUIRE(VirtFs::isDirectory("test//dir1") == true); + REQUIRE(VirtFs::isDirectory("test//dir1/") == true); + REQUIRE(VirtFs::isDirectory("test//dir1//") == true); + REQUIRE(VirtFs::isDirectory("test/dir1/") == true); + REQUIRE(VirtFs::isDirectory("test/dir1//") == true); + REQUIRE(VirtFs::isDirectory("testQ") == false); + REQUIRE(VirtFs::isDirectory("testQ/") == false); + REQUIRE(VirtFs::isDirectory("testQ//") == false); + + VirtFs::mountDirSilent("data/test", Append_false); + VirtFs::mountDirSilent("../data/test", Append_false); + + REQUIRE(VirtFs::isDirectory("test/units.xml") == false); + REQUIRE(VirtFs::isDirectory("test/units.xml/") == false); + REQUIRE(VirtFs::isDirectory("test//units.xml") == false); + REQUIRE(VirtFs::isDirectory("test/units123.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false); + REQUIRE(VirtFs::isDirectory("units.xml") == false); + REQUIRE(VirtFs::isDirectory("test") == true); + REQUIRE(VirtFs::isDirectory("testQ") == false); + REQUIRE(VirtFs::isDirectory("test/dir1") == true); + + VirtFs::unmountDirSilent("data/test"); + VirtFs::unmountDirSilent("../data/test"); + + REQUIRE(VirtFs::isDirectory("test/units.xml") == false); + REQUIRE(VirtFs::isDirectory("test/units123.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false); + REQUIRE(VirtFs::isDirectory("units.xml") == false); + REQUIRE(VirtFs::isDirectory("units.xml/") == false); + REQUIRE(VirtFs::isDirectory("test") == true); + REQUIRE(VirtFs::isDirectory("test/") == true); + REQUIRE(VirtFs::isDirectory("testQ") == false); + REQUIRE(VirtFs::isDirectory("test/dir1") == true); + + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +} + +TEST_CASE("VirtFs isDirectory2", "") +{ + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "data/test/test2.zip", Append_false); + + REQUIRE(VirtFs::isDirectory("test/units.xml") == false); + REQUIRE(VirtFs::isDirectory("dir") == true); + REQUIRE(VirtFs::isDirectory("dir/") == true); + REQUIRE(VirtFs::isDirectory("dir//") == true); + REQUIRE(VirtFs::isDirectory("dir2") == true); + REQUIRE(VirtFs::isDirectory("dir3") == false); + REQUIRE(VirtFs::isDirectory("test.txt") == false); + + VirtFs::unmountZip(prefix + "data/test/test2.zip"); + delete2(logger); +} + +TEST_CASE("VirtFs isDirectory3", "") +{ + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountDir(prefix + "data", Append_false); + VirtFs::mountZip(prefix + "data/test/test2.zip", Append_false); + + REQUIRE(VirtFs::isDirectory("test/units.xml") == false); + REQUIRE(VirtFs::isDirectory("test")); + REQUIRE(VirtFs::isDirectory("test//dye.png") == false); + REQUIRE(VirtFs::isDirectory("dir")); + REQUIRE(VirtFs::isDirectory("dir/")); + REQUIRE(VirtFs::isDirectory("dir//")); + REQUIRE(VirtFs::isDirectory("dir2")); + REQUIRE(VirtFs::isDirectory("dir3") == false); + REQUIRE(VirtFs::isDirectory("test.txt") == false); + REQUIRE(VirtFs::isDirectory("dir/hide.png") == false); + + VirtFs::unmountZip(prefix + "data/test/test2.zip"); + VirtFs::unmountDir(prefix + "data"); + delete2(logger); +} + +TEST_CASE("VirtFs openRead1", "") +{ + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + VirtFs::File *file = nullptr; + + file = VirtFs::openRead("test/units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("test/units123.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("tesQ/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("units.xml"); + REQUIRE(file == nullptr); +// file = VirtFs::openRead("test"); +// REQUIRE(file == nullptr); + file = VirtFs::openRead("testQ"); + REQUIRE(file == nullptr); + + VirtFs::mountDirSilent("data/test", Append_false); + VirtFs::mountDirSilent("../data/test", Append_false); + + file = VirtFs::openRead("test/units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("test/units123.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("tesQ/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); +// file = VirtFs::openRead("test"); +// REQUIRE(file == nullptr); + file = VirtFs::openRead("testQ"); + REQUIRE(file == nullptr); + + VirtFs::unmountDirSilent("data/test"); + VirtFs::unmountDirSilent("../data/test"); + + file = VirtFs::openRead("test/units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("test/units123.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("tesQ/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("units.xml"); + REQUIRE(file == nullptr); +// file = VirtFs::openRead("test"); +// REQUIRE(file == nullptr); + file = VirtFs::openRead("testQ"); + REQUIRE(file == nullptr); + + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +} + +TEST_CASE("VirtFs openRead2", "") +{ + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "data/test/test2.zip", Append_false); + + VirtFs::File *file = nullptr; + + file = VirtFs::openRead("test/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("dir/hide.png"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("dir//hide.png"); + REQUIRE(file != nullptr); + VirtFs::close(file); + + VirtFs::unmountZip(prefix + "data/test/test2.zip"); + delete2(logger); +} + +TEST_CASE("VirtFs openRead3", "") +{ + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "data/test/test2.zip", Append_false); + VirtFs::mountDir(prefix + "data/test", Append_false); + + VirtFs::File *file = nullptr; + + file = VirtFs::openRead("test/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("dir/hide.png"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("dir//hide.png"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("dir/dye.png"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("dir/dye.pn_"); + REQUIRE(file == nullptr); + + VirtFs::unmountZip(prefix + "data/test/test2.zip"); + VirtFs::unmountDir(prefix + "data/test"); + delete2(logger); +} + +TEST_CASE("VirtFs getRealDir1", "") +{ + logger = new Logger(); + const std::string sep = dirSeparator; + REQUIRE(VirtFs::getRealDir(".").empty()); + REQUIRE(VirtFs::getRealDir("..").empty()); + const bool dir1 = VirtFs::mountDirSilent("data", Append_false); + REQUIRE((dir1 || VirtFs::mountDirSilent("../data", Append_false)) + == true); + if (dir1 == true) + { + REQUIRE(VirtFs::getRealDir("test") == "data"); + REQUIRE(VirtFs::getRealDir("test/test.txt") == + "data"); + } + else + { + REQUIRE(VirtFs::getRealDir("test") == "../data"); + REQUIRE(VirtFs::getRealDir("test/test.txt") == + "../data"); + } + REQUIRE(VirtFs::getRealDir("zzz").empty()); + + VirtFs::mountDirSilent("data/test", Append_false); + VirtFs::mountDirSilent("../data/test", Append_false); + if (dir1 == true) + { + REQUIRE(VirtFs::getRealDir("test") == "data"); + REQUIRE(VirtFs::getRealDir("test/test.txt") == + "data"); + REQUIRE(VirtFs::getRealDir("test.txt") == + "data" + sep + "test"); + } + else + { + REQUIRE(VirtFs::getRealDir("test") == ".." + sep + "data"); + REQUIRE(VirtFs::getRealDir("test/test.txt") == + ".." + sep + "data"); + REQUIRE(VirtFs::getRealDir("test.txt") == + ".." + sep + "data" + sep + "test"); + } + REQUIRE(VirtFs::getRealDir("zzz").empty()); + + if (dir1 == true) + { + VirtFs::mountZip("data/test/test.zip", Append_false); + REQUIRE(VirtFs::getRealDir("dir/brimmedhat.png") == + "data" + sep + "test" + sep + "test.zip"); + REQUIRE(VirtFs::getRealDir("hide.png") == + "data" + sep + "test"); + } + else + { + VirtFs::mountZip("../data/test/test.zip", Append_false); + REQUIRE(VirtFs::getRealDir("dir/brimmedhat.png") == + ".." + sep + "data" + sep + "test" + sep + "test.zip"); + REQUIRE(VirtFs::getRealDir("hide.png") == + ".." + sep + "data" + sep + "test"); + } + + VirtFs::unmountDirSilent("data/test"); + VirtFs::unmountDirSilent("../data/test"); + + if (dir1 == true) + { + REQUIRE(VirtFs::getRealDir("test") == "data"); + REQUIRE(VirtFs::getRealDir("test/test.txt") == + "data"); + REQUIRE(VirtFs::getRealDir("dir/hide.png") == + "data" + sep + "test" + sep + "test.zip"); + } + else + { + REQUIRE(VirtFs::getRealDir("test") == ".." + sep + "data"); + REQUIRE(VirtFs::getRealDir("test/test.txt") == + ".." + sep + "data"); + REQUIRE(VirtFs::getRealDir("dir/hide.png") == + ".." + sep + "data" + sep + "test" + sep + "test.zip"); + } + REQUIRE(VirtFs::exists("dir/hide.png")); + REQUIRE(VirtFs::getRealDir("zzz").empty()); + + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + if (dir1 == true) + VirtFs::unmountZip("data/test/test.zip"); + else + VirtFs::unmountZip("../data/test/test.zip"); + delete2(logger); +} + +TEST_CASE("VirtFs getrealDir2", "") +{ + logger = new Logger(); + const std::string sep = dirSeparator; + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "data/test/test2.zip", Append_false); + VirtFs::mountDir(prefix + "data/test", Append_false); + VirtFs::mountDir(prefix + "data", Append_false); + + REQUIRE(VirtFs::getRealDir("zzz").empty()); + + REQUIRE(VirtFs::getRealDir("dir1/file1.txt") == + prefix + "data" + sep + "test"); + REQUIRE(VirtFs::getRealDir("hide.png") == + prefix + "data" + sep + "test"); + REQUIRE(VirtFs::getRealDir("dir//hide.png") == + prefix + "data" + sep + "test" + sep + "test2.zip"); + REQUIRE(VirtFs::getRealDir("dir/1//test.txt") == + prefix + "data" + sep + "test" + sep + "test2.zip"); + + VirtFs::unmountZip(prefix + "data/test/test2.zip"); + VirtFs::unmountDir(prefix + "data/test"); + VirtFs::unmountDir(prefix + "data"); + delete2(logger); +} + +TEST_CASE("VirtFs getrealDir3", "") +{ + logger = new Logger(); + const std::string sep = dirSeparator; + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip2(prefix + "data/test/test2.zip", + "dir", + Append_false); + VirtFs::mountDir(prefix + "data/test", Append_false); + + REQUIRE(VirtFs::getRealDir("zzz").empty()); + + REQUIRE(VirtFs::getRealDir("dir1/file1.txt") == + prefix + "data" + sep + "test"); + REQUIRE(VirtFs::getRealDir("hide.png") == + prefix + "data" + sep + "test"); + REQUIRE(VirtFs::getRealDir("hide.png") == + prefix + "data" + sep + "test"); + REQUIRE(VirtFs::getRealDir("1//test.txt") == + prefix + "data" + sep + "test" + sep + "test2.zip"); + + VirtFs::unmountZip2(prefix + "data/test/test2.zip", + "dir"); + VirtFs::unmountDir(prefix + "data/test"); + delete2(logger); +} + +TEST_CASE("VirtFs permitLinks1", "") +{ + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + const int cnt1 = VirtFs::exists("test/test2.txt") ? 26 : 25; + const int cnt2 = 26; + + StringVect list; + VirtFs::permitLinks(false); + VirtFs::getFiles("test", list); + removeTemp(list); + const size_t sz = list.size(); + REQUIRE(sz == cnt1); + + list.clear(); + VirtFs::permitLinks(true); + VirtFs::getFiles("test", list); + removeTemp(list); + REQUIRE(list.size() == cnt2); + + list.clear(); + VirtFs::permitLinks(false); + VirtFs::getFiles("test", list); + removeTemp(list); + REQUIRE(list.size() == cnt1); + + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +} + +TEST_CASE("VirtFs permitLinks2", "") +{ + logger = new Logger(); + VirtFs::mountDirSilent2("data", + "test", + Append_false); + VirtFs::mountDirSilent2("../data", + "test", + Append_false); + + const int cnt1 = VirtFs::exists("test2.txt") ? 26 : 25; + const int cnt2 = 26; + + StringVect list; + VirtFs::permitLinks(false); + VirtFs::getFiles(dirSeparator, list); + removeTemp(list); + const size_t sz = list.size(); + REQUIRE(sz == cnt1); + + list.clear(); + VirtFs::permitLinks(true); + VirtFs::getFiles(dirSeparator, list); + removeTemp(list); + REQUIRE(list.size() == cnt2); + + list.clear(); + VirtFs::permitLinks(false); + VirtFs::getFiles(dirSeparator, list); + removeTemp(list); + REQUIRE(list.size() == cnt1); + + VirtFs::unmountDirSilent2("data", + "test"); + VirtFs::unmountDirSilent2("../data", + "test"); + delete2(logger); +} + +TEST_CASE("VirtFs read1", "") +{ + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + VirtFs::File *file = VirtFs::openRead("test/test.txt"); + REQUIRE(file != nullptr); + REQUIRE(VirtFs::fileLength(file) == 23); + const int fileSize = VirtFs::fileLength(file); + + void *restrict buffer = calloc(fileSize + 1, 1); + REQUIRE(VirtFs::read(file, buffer, 1, fileSize) == fileSize); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 1\ntest line 2") == 0); + REQUIRE(VirtFs::tell(file) == fileSize); + REQUIRE(VirtFs::eof(file) == true); + + free(buffer); + buffer = calloc(fileSize + 1, 1); + REQUIRE(VirtFs::seek(file, 12) != 0); + REQUIRE(VirtFs::eof(file) == false); + REQUIRE(VirtFs::tell(file) == 12); + REQUIRE(VirtFs::read(file, buffer, 1, 11) == 11); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 2") == 0); + REQUIRE(VirtFs::eof(file) == true); + + VirtFs::close(file); + free(buffer); + + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +} + +TEST_CASE("VirtFs read2", "") +{ + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "data/test/test2.zip", Append_false); + + VirtFs::File *file = VirtFs::openRead("dir2/test.txt"); + REQUIRE(file != nullptr); + REQUIRE(VirtFs::fileLength(file) == 23); + const int fileSize = VirtFs::fileLength(file); + + void *restrict buffer = calloc(fileSize + 1, 1); + REQUIRE(VirtFs::read(file, buffer, 1, fileSize) == fileSize); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 1\ntest line 2") == 0); + REQUIRE(VirtFs::tell(file) == fileSize); + REQUIRE(VirtFs::eof(file) == true); + + free(buffer); + buffer = calloc(fileSize + 1, 1); + REQUIRE(VirtFs::seek(file, 12) != 0); + REQUIRE(VirtFs::eof(file) == false); + REQUIRE(VirtFs::tell(file) == 12); + REQUIRE(VirtFs::read(file, buffer, 1, 11) == 11); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 2") == 0); + REQUIRE(VirtFs::eof(file) == true); + + VirtFs::close(file); + free(buffer); + + VirtFs::unmountZip(prefix + "data/test/test2.zip"); + delete2(logger); +} + +TEST_CASE("VirtFs read3", "") +{ + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "data/test/test2.zip", Append_false); + VirtFs::mountDir(prefix + "data", Append_false); + + VirtFs::File *file = VirtFs::openRead("dir2/test.txt"); + REQUIRE(file != nullptr); + REQUIRE(VirtFs::fileLength(file) == 23); + const int fileSize = VirtFs::fileLength(file); + + void *restrict buffer = calloc(fileSize + 1, 1); + REQUIRE(VirtFs::read(file, buffer, 1, fileSize) == fileSize); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 1\ntest line 2") == 0); + REQUIRE(VirtFs::tell(file) == fileSize); + REQUIRE(VirtFs::eof(file) == true); + + free(buffer); + buffer = calloc(fileSize + 1, 1); + REQUIRE(VirtFs::seek(file, 12) != 0); + REQUIRE(VirtFs::eof(file) == false); + REQUIRE(VirtFs::tell(file) == 12); + REQUIRE(VirtFs::read(file, buffer, 1, 11) == 11); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 2") == 0); + REQUIRE(VirtFs::eof(file) == true); + + VirtFs::close(file); + free(buffer); + + VirtFs::unmountZip(prefix + "data/test/test2.zip"); + VirtFs::unmountDir(prefix + "data"); + delete2(logger); +} + +TEST_CASE("VirtFs read4", "") +{ + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountDir(prefix + "data/test", Append_true); + VirtFs::mountZip(prefix + "data/test/test5.zip", Append_true); + + VirtFs::File *file = VirtFs::openRead("dir1/file1.txt"); + REQUIRE(file != nullptr); + REQUIRE(VirtFs::fileLength(file) == 23); + const int fileSize = VirtFs::fileLength(file); + + void *restrict buffer = calloc(fileSize + 1, 1); + REQUIRE(VirtFs::read(file, buffer, 1, fileSize) == fileSize); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 1\ntest line 2") == 0); + REQUIRE(VirtFs::tell(file) == fileSize); + REQUIRE(VirtFs::eof(file) == true); + + free(buffer); + buffer = calloc(fileSize + 1, 1); + REQUIRE(VirtFs::seek(file, 12) != 0); + REQUIRE(VirtFs::eof(file) == false); + REQUIRE(VirtFs::tell(file) == 12); + REQUIRE(VirtFs::read(file, buffer, 1, 11) == 11); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 2") == 0); + REQUIRE(VirtFs::eof(file) == true); + + VirtFs::close(file); + free(buffer); + + VirtFs::unmountZip(prefix + "data/test/test5.zip"); + VirtFs::unmountDir(prefix + "data/test"); + delete2(logger); +} + +TEST_CASE("VirtFs read5", "") +{ + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountZip(prefix + "data/test/test5.zip", Append_true); + VirtFs::mountDir(prefix + "data/test", Append_true); + + VirtFs::File *file = VirtFs::openRead("dir1/file1.txt"); + REQUIRE(file != nullptr); + REQUIRE(VirtFs::fileLength(file) == 23); + const int fileSize = VirtFs::fileLength(file); + + void *restrict buffer = calloc(fileSize + 1, 1); + REQUIRE(VirtFs::read(file, buffer, 1, fileSize) == fileSize); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 3\ntest line 4") == 0); + REQUIRE(VirtFs::tell(file) == fileSize); + REQUIRE(VirtFs::eof(file) == true); + + free(buffer); + buffer = calloc(fileSize + 1, 1); + REQUIRE(VirtFs::seek(file, 12) != 0); + REQUIRE(VirtFs::eof(file) == false); + REQUIRE(VirtFs::tell(file) == 12); + REQUIRE(VirtFs::read(file, buffer, 1, 11) == 11); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 4") == 0); + REQUIRE(VirtFs::eof(file) == true); + + VirtFs::close(file); + free(buffer); + + VirtFs::unmountZip(prefix + "data/test/test5.zip"); + VirtFs::unmountDir(prefix + "data/test"); + delete2(logger); +} diff --git a/src/unittests/fs/virtfs/zip_unittest.cc b/src/unittests/fs/virtfs/zip_unittest.cc new file mode 100644 index 000000000..10b4b52b5 --- /dev/null +++ b/src/unittests/fs/virtfs/zip_unittest.cc @@ -0,0 +1,304 @@ +/* + * The ManaPlus Client + * Copyright (C) 2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "logger.h" + +#include "fs/files.h" + +#include "fs/virtfs/fszip.h" +#include "fs/virtfs/zipentry.h" +#include "fs/virtfs/zipreader.h" +#include "fs/virtfs/ziplocalheader.h" + +#include "utils/delete2.h" + +#include "debug.h" + +extern const char *dirSeparator; + +TEST_CASE("Zip readArchiveInfo", "") +{ + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + const std::string sep = dirSeparator; + if (Files::existsLocal(name) == false) + prefix = "../"; + + SECTION("test.zip") + { + name = prefix + "data/test/test.zip"; + + VirtFs::ZipEntry *const entry = new VirtFs::ZipEntry(name, + dirSeparator, + VirtFs::FsZip::getFuncs()); + std::vector<VirtFs::ZipLocalHeader*> &headers = entry->mHeaders; + + REQUIRE(VirtFs::ZipReader::readArchiveInfo(entry)); + REQUIRE(headers.size() == 2); + REQUIRE(entry->root == name); + REQUIRE(headers[0]->fileName == "dir" + sep + "hide.png"); + REQUIRE(headers[0]->compressSize == 365); + REQUIRE(headers[0]->uncompressSize == 368); + REQUIRE(headers[1]->fileName == "dir" + sep + "brimmedhat.png"); + REQUIRE(headers[1]->compressSize == 1959); + REQUIRE(headers[1]->uncompressSize == 1959); + + delete entry; + } + + SECTION("test2.zip") + { + name = prefix + "data/test/test2.zip"; + + VirtFs::ZipEntry *const entry = new VirtFs::ZipEntry(name, + dirSeparator, + VirtFs::FsZip::getFuncs()); + std::vector<VirtFs::ZipLocalHeader*> &headers = entry->mHeaders; + + REQUIRE(VirtFs::ZipReader::readArchiveInfo(entry)); + REQUIRE(headers.size() == 11); + REQUIRE(entry->root == name); + REQUIRE(headers[0]->fileName == "test.txt"); + REQUIRE(headers[0]->compressSize == 17); + REQUIRE(headers[0]->uncompressSize == 23); + + REQUIRE(headers[1]->fileName == "dir2" + sep + "hide.png"); + REQUIRE(headers[1]->compressSize == 365); + REQUIRE(headers[1]->uncompressSize == 368); + + REQUIRE(headers[2]->fileName == "dir2" + sep + "test.txt"); + REQUIRE(headers[2]->compressSize == 17); + REQUIRE(headers[2]->uncompressSize == 23); + + REQUIRE(headers[3]->fileName == "dir2" + sep + "paths.xml"); + REQUIRE(headers[3]->compressSize == 154); + REQUIRE(headers[3]->uncompressSize == 185); + + REQUIRE(headers[4]->fileName == "dir2" + sep + "units.xml"); + REQUIRE(headers[4]->compressSize == 202); + REQUIRE(headers[4]->uncompressSize == 306); + + REQUIRE(headers[5]->fileName == "dir" + sep + "hide.png"); + REQUIRE(headers[5]->compressSize == 365); + REQUIRE(headers[5]->uncompressSize == 368); + + REQUIRE(headers[6]->fileName == + "dir" + sep + "1" + sep + "test.txt"); + REQUIRE(headers[6]->compressSize == 17); + REQUIRE(headers[6]->uncompressSize == 23); + + REQUIRE(headers[7]->fileName == + "dir" + sep + "1" + sep + "file1.txt"); + REQUIRE(headers[7]->compressSize == 17); + REQUIRE(headers[7]->uncompressSize == 23); + + REQUIRE(headers[8]->fileName == + "dir" + sep + "gpl" + sep + "palette.gpl"); + REQUIRE(headers[8]->compressSize == 128); + REQUIRE(headers[8]->uncompressSize == 213); + + REQUIRE(headers[9]->fileName == + "dir" + sep + "dye.png"); + REQUIRE(headers[9]->compressSize == 794); + REQUIRE(headers[9]->uncompressSize == 794); + + REQUIRE(headers[10]->fileName == "units.xml"); + REQUIRE(headers[10]->compressSize == 202); + REQUIRE(headers[10]->uncompressSize == 306); + + delete entry; + } + + SECTION("test3.zip") + { + name = prefix + "data/test/test3.zip"; + + VirtFs::ZipEntry *const entry = new VirtFs::ZipEntry(name, + dirSeparator, + VirtFs::FsZip::getFuncs()); + std::vector<VirtFs::ZipLocalHeader*> &headers = entry->mHeaders; + + REQUIRE(VirtFs::ZipReader::readArchiveInfo(entry)); + REQUIRE(headers.size() == 2); + REQUIRE(entry->root == name); + REQUIRE(headers[0]->fileName == "test.txt"); + REQUIRE(headers[0]->compressSize == 17); + REQUIRE(headers[0]->uncompressSize == 23); + REQUIRE(headers[1]->fileName == "units.xml"); + REQUIRE(headers[1]->compressSize == 202); + REQUIRE(headers[1]->uncompressSize == 306); + + delete entry; + } + + SECTION("test4.zip") + { + name = prefix + "data/test/test4.zip"; + + VirtFs::ZipEntry *const entry = new VirtFs::ZipEntry(name, + dirSeparator, + VirtFs::FsZip::getFuncs()); + std::vector<VirtFs::ZipLocalHeader*> &headers = entry->mHeaders; + + REQUIRE(VirtFs::ZipReader::readArchiveInfo(entry)); + REQUIRE(entry->root == name); + REQUIRE(headers.empty()); + + delete entry; + } + + delete2(logger); +} + +TEST_CASE("Zip readCompressedFile", "") +{ + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../"; + + SECTION("empty") + { + REQUIRE_THROWS(VirtFs::ZipReader::readCompressedFile(nullptr)); + } + + SECTION("test2.zip") + { + name = prefix + "data/test/test2.zip"; + + VirtFs::ZipEntry *const entry = new VirtFs::ZipEntry(name, + dirSeparator, + VirtFs::FsZip::getFuncs()); + std::vector<VirtFs::ZipLocalHeader*> &headers = entry->mHeaders; + + REQUIRE(VirtFs::ZipReader::readArchiveInfo(entry)); + REQUIRE(headers.size() == 11); + REQUIRE(entry->root == name); + // test.txt + uint8_t *const buf = VirtFs::ZipReader::readCompressedFile(headers[0]); + REQUIRE(buf != nullptr); + delete [] buf; + delete entry; + } + + delete2(logger); +} + +TEST_CASE("Zip readFile", "") +{ + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../"; + + SECTION("empty") + { + REQUIRE_THROWS(VirtFs::ZipReader::readFile(nullptr)); + } + + SECTION("test.zip") + { + name = prefix + "data/test/test.zip"; + + VirtFs::ZipEntry *const entry = new VirtFs::ZipEntry(name, + dirSeparator, + VirtFs::FsZip::getFuncs()); + std::vector<VirtFs::ZipLocalHeader*> &headers = entry->mHeaders; + + REQUIRE(VirtFs::ZipReader::readArchiveInfo(entry)); + REQUIRE(headers.size() == 2); + REQUIRE(entry->root == name); + for (int f = 0; f < 2; f ++) + { + logger->log("test header: %s, %u, %u", + headers[f]->fileName.c_str(), + headers[f]->compressSize, + headers[f]->uncompressSize); + const uint8_t *const buf = VirtFs::ZipReader::readFile(headers[f]); + REQUIRE(buf != nullptr); + delete [] buf; + } + delete entry; + } + + SECTION("test2.zip") + { + name = prefix + "data/test/test2.zip"; + + VirtFs::ZipEntry *const entry = new VirtFs::ZipEntry(name, + dirSeparator, + VirtFs::FsZip::getFuncs()); + std::vector<VirtFs::ZipLocalHeader*> &headers = entry->mHeaders; + + REQUIRE(VirtFs::ZipReader::readArchiveInfo(entry)); + REQUIRE(headers.size() == 11); + REQUIRE(entry->root == name); + // test.txt + const uint8_t *buf = VirtFs::ZipReader::readFile(headers[0]); + REQUIRE(buf != nullptr); + const std::string str = std::string(reinterpret_cast<const char*>(buf), + headers[0]->uncompressSize); + REQUIRE(str == "test line 1\ntest line 2"); + delete [] buf; + for (int f = 0; f < 11; f ++) + { + logger->log("test header: %s, %u, %u", + headers[f]->fileName.c_str(), + headers[f]->compressSize, + headers[f]->uncompressSize); + buf = VirtFs::ZipReader::readFile(headers[f]); + REQUIRE(buf != nullptr); + delete [] buf; + } + delete entry; + } + + SECTION("test3.zip") + { + name = prefix + "data/test/test3.zip"; + + VirtFs::ZipEntry *const entry = new VirtFs::ZipEntry(name, + dirSeparator, + VirtFs::FsZip::getFuncs()); + std::vector<VirtFs::ZipLocalHeader*> &headers = entry->mHeaders; + + REQUIRE(VirtFs::ZipReader::readArchiveInfo(entry)); + REQUIRE(headers.size() == 2); + REQUIRE(entry->root == name); + for (int f = 0; f < 2; f ++) + { + logger->log("test header: %s, %u, %u", + headers[f]->fileName.c_str(), + headers[f]->compressSize, + headers[f]->uncompressSize); + const uint8_t *const buf = VirtFs::ZipReader::readFile(headers[f]); + REQUIRE(buf != nullptr); + delete [] buf; + } + delete entry; + } + + delete2(logger); +} diff --git a/src/unittests/gui/fonts/textchunklist_unittest.cc b/src/unittests/gui/fonts/textchunklist_unittest.cc new file mode 100644 index 000000000..c8df87455 --- /dev/null +++ b/src/unittests/gui/fonts/textchunklist_unittest.cc @@ -0,0 +1,548 @@ +/* + * The ManaPlus Client + * Copyright (C) 2013-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "gui/fonts/font.h" +#include "gui/fonts/textchunk.h" + +#include "debug.h" + +TEST_CASE("TextChunkList empty", "TextChunkList") +{ + TextChunkList list; + + REQUIRE(0 == list.size); + REQUIRE(nullptr == list.start); + REQUIRE(nullptr == list.end); + REQUIRE(list.search.empty()); + REQUIRE(list.searchWidth.empty()); +} + +TEST_CASE("TextChunkList add 1", "TextChunkList") +{ + TextChunkList list; + + TextChunk *const chunk = new TextChunk("test", + Color(1, 2, 3), Color(2, 3, 4), nullptr); + + list.insertFirst(chunk); + + REQUIRE(1 == list.size); + REQUIRE(chunk == list.start); + REQUIRE(chunk == list.end); + REQUIRE(nullptr == chunk->prev); + REQUIRE(nullptr == chunk->next); + + REQUIRE(1 == list.search.size()); + REQUIRE(chunk == (*list.search.find(TextChunkSmall( + chunk->text, chunk->color, chunk->color2))).second); + + REQUIRE(1 == list.searchWidth.size()); + REQUIRE(chunk == (*list.searchWidth.find(chunk->text)).second); + delete chunk; +} + +TEST_CASE("TextChunkList add 2", "TextChunkList") +{ + TextChunkList list; + + TextChunk *const chunk1 = new TextChunk("test", + Color(1, 2, 3), Color(3, 4, 5), nullptr); + TextChunk *const chunk2 = new TextChunk("test", + Color(2, 3, 4), Color(4, 5, 6), nullptr); + + list.insertFirst(chunk2); + list.insertFirst(chunk1); + + REQUIRE(2 == list.size); + REQUIRE(chunk1 == list.start); + REQUIRE(chunk2 == list.end); + REQUIRE(nullptr == chunk1->prev); + REQUIRE(chunk2 == chunk1->next); + REQUIRE(chunk1 == chunk2->prev); + REQUIRE(nullptr == chunk2->next); + + REQUIRE(2 == list.search.size()); + REQUIRE(chunk1 == (*list.search.find(TextChunkSmall( + chunk1->text, chunk1->color, chunk1->color2))).second); + REQUIRE(chunk2 == (*list.search.find(TextChunkSmall( + chunk2->text, chunk2->color, chunk2->color2))).second); + + REQUIRE(1 == list.searchWidth.size()); + REQUIRE(chunk1 == (*list.searchWidth.find(chunk1->text)).second); + delete chunk1; + delete chunk2; +} + +TEST_CASE("TextChunkList addRemoveBack 1", "TextChunkList") +{ + TextChunkList list; + + TextChunk *const chunk = new TextChunk("test", + Color(1, 2, 3), Color(1, 2, 3), nullptr); + + list.insertFirst(chunk); + list.removeBack(); + + REQUIRE(0 == list.size); + REQUIRE(nullptr == list.start); + REQUIRE(nullptr == list.end); + REQUIRE(list.search.empty()); + REQUIRE(list.searchWidth.empty()); +} + +TEST_CASE("TextChunkList addRemoveBack 2", "TextChunkList") +{ + TextChunkList list; + + TextChunk *const chunk1 = new TextChunk("test", + Color(1, 2, 3), Color(1, 2, 3), nullptr); + TextChunk *const chunk2 = new TextChunk("test2", + Color(1, 2, 4), Color(1, 2, 5), nullptr); + + list.insertFirst(chunk2); + list.insertFirst(chunk1); + list.removeBack(); + + REQUIRE(1 == list.size); + REQUIRE(chunk1 == list.start); + REQUIRE(chunk1 == list.end); + REQUIRE(nullptr == chunk1->prev); + REQUIRE(nullptr == chunk1->next); + + REQUIRE(1 == list.search.size()); + REQUIRE(chunk1 == (*list.search.find(TextChunkSmall( + chunk1->text, chunk1->color, chunk1->color2))).second); + + REQUIRE(1 == list.searchWidth.size()); + REQUIRE(chunk1 == (*list.searchWidth.find(chunk1->text)).second); + delete chunk1; +} + +TEST_CASE("TextChunkList addRemoveBack 3", "TextChunkList") +{ + TextChunkList list; + + TextChunk *const chunk1 = new TextChunk("test", + Color(1, 2, 3), Color(1, 2, 3), nullptr); + TextChunk *const chunk2 = new TextChunk("test2", + Color(2, 3, 4), Color(2, 3, 4), nullptr); + + list.insertFirst(chunk2); + list.insertFirst(chunk1); + list.removeBack(2); + + REQUIRE(0 == list.size); + REQUIRE(nullptr == list.start); + REQUIRE(nullptr == list.end); + + REQUIRE(list.search.empty()); + REQUIRE(list.searchWidth.empty()); +} + +TEST_CASE("TextChunkList addRemoveBack 4", "TextChunkList") +{ + TextChunkList list; + + TextChunk *const chunk1 = new TextChunk("test", + Color(1, 2, 3), Color(1, 2, 3), nullptr); + TextChunk *const chunk2 = new TextChunk("test2", + Color(2, 3, 4), Color(2, 3, 4), nullptr); + TextChunk *const chunk3 = new TextChunk("test", + Color(3, 4, 5), Color(3, 4, 5), nullptr); + + list.insertFirst(chunk3); + list.insertFirst(chunk2); + list.insertFirst(chunk1); + list.removeBack(); + list.removeBack(); + + REQUIRE(1 == list.size); + REQUIRE(chunk1 == list.start); + REQUIRE(chunk1 == list.end); + REQUIRE(nullptr == chunk1->prev); + REQUIRE(nullptr == chunk1->next); + + REQUIRE(1 == list.search.size()); + REQUIRE(chunk1 == (*list.search.find(TextChunkSmall( + chunk1->text, chunk1->color, chunk1->color2))).second); + + REQUIRE(list.searchWidth.empty()); + delete chunk1; +} + +TEST_CASE("TextChunkList moveToFirst 1", "TextChunkList") +{ + TextChunkList list; + + TextChunk *const chunk = new TextChunk("test", + Color(1, 2, 3), Color(2, 3, 4), nullptr); + + list.insertFirst(chunk); + list.moveToFirst(chunk); + + REQUIRE(1 == list.size); + REQUIRE(chunk == list.start); + REQUIRE(chunk == list.end); + REQUIRE(nullptr == chunk->prev); + REQUIRE(nullptr == chunk->next); + delete chunk; +} + +TEST_CASE("TextChunkList moveToFirst 2", "TextChunkList") +{ + TextChunkList list; + + TextChunk *const chunk1 = new TextChunk("test", + Color(1, 2, 3), Color(1, 2, 3), nullptr); + TextChunk *const chunk2 = new TextChunk("test", + Color(2, 3, 4), Color(1, 2, 3), nullptr); + + list.insertFirst(chunk1); + list.insertFirst(chunk2); + list.moveToFirst(chunk1); + + REQUIRE(2 == list.size); + REQUIRE(chunk1 == list.start); + REQUIRE(chunk2 == list.end); + REQUIRE(nullptr == chunk1->prev); + REQUIRE(chunk2 == chunk1->next); + REQUIRE(chunk1 == chunk2->prev); + REQUIRE(nullptr == chunk2->next); + delete chunk1; + delete chunk2; +} + +TEST_CASE("TextChunkList moveToFirst 3", "TextChunkList") +{ + TextChunkList list; + + TextChunk *const chunk1 = new TextChunk("test", + Color(1, 2, 3), Color(1, 2, 3), nullptr); + TextChunk *const chunk2 = new TextChunk("test", + Color(1, 2, 4), Color(1, 2, 3), nullptr); + TextChunk *const chunk3 = new TextChunk("test", + Color(1, 2, 5), Color(1, 2, 3), nullptr); + + list.insertFirst(chunk3); + list.insertFirst(chunk1); + list.insertFirst(chunk2); + list.moveToFirst(chunk1); + + REQUIRE(3 == list.size); + REQUIRE(chunk1 == list.start); + REQUIRE(chunk3 == list.end); + REQUIRE(nullptr == chunk1->prev); + REQUIRE(chunk2 == chunk1->next); + REQUIRE(chunk1 == chunk2->prev); + REQUIRE(chunk3 == chunk2->next); + REQUIRE(chunk2 == chunk3->prev); + REQUIRE(nullptr == chunk3->next); + delete chunk1; + delete chunk2; + delete chunk3; +} + +TEST_CASE("TextChunkList moveToFirst 4", "TextChunkList") +{ + TextChunkList list; + + TextChunk *const chunk1 = new TextChunk("test", + Color(), Color(), nullptr); + TextChunk *const chunk2 = new TextChunk("test2", + Color(), Color(), nullptr); + TextChunk *const chunk3 = new TextChunk("test3", + Color(), Color(), nullptr); + + list.insertFirst(chunk1); + list.insertFirst(chunk3); + list.insertFirst(chunk2); + list.moveToFirst(chunk1); + + REQUIRE(3 == list.size); + REQUIRE(chunk1 == list.start); + REQUIRE(chunk3 == list.end); + REQUIRE(nullptr == chunk1->prev); + REQUIRE(chunk2 == chunk1->next); + REQUIRE(chunk1 == chunk2->prev); + REQUIRE(chunk3 == chunk2->next); + REQUIRE(chunk2 == chunk3->prev); + REQUIRE(nullptr == chunk3->next); + delete chunk1; + delete chunk2; + delete chunk3; +} + +TEST_CASE("TextChunkList clear 1", "TextChunkList") +{ + TextChunkList list; + const int chunksLeft = textChunkCnt; + + TextChunk *const chunk = new TextChunk("test", + Color(), Color(), nullptr); + + list.insertFirst(chunk); + list.clear(); + + REQUIRE(0 == list.size); + REQUIRE(nullptr == list.start); + REQUIRE(nullptr == list.end); + REQUIRE(chunksLeft == textChunkCnt); + REQUIRE(list.search.empty()); + REQUIRE(list.searchWidth.empty()); +} + +TEST_CASE("TextChunkList clear 2", "TextChunkList") +{ + TextChunkList list; + const int chunksLeft = textChunkCnt; + + TextChunk *const chunk1 = new TextChunk("test", + Color(1, 2, 3), Color(2, 0, 0), nullptr); + TextChunk *const chunk2 = new TextChunk("test", + Color(1, 2, 3), Color(2, 0, 1), nullptr); + TextChunk *const chunk3 = new TextChunk("test", + Color(1, 2, 3), Color(2, 0, 2), nullptr); + + list.insertFirst(chunk1); + list.insertFirst(chunk2); + list.insertFirst(chunk3); + list.clear(); + + REQUIRE(0 == list.size); + REQUIRE(nullptr == list.start); + REQUIRE(nullptr == list.end); + REQUIRE(chunksLeft == textChunkCnt); + REQUIRE(list.search.empty()); + REQUIRE(list.searchWidth.empty()); +} + +TEST_CASE("TextChunkList clear 3", "TextChunkList") +{ + TextChunkList list; + const int chunksLeft = textChunkCnt; + + TextChunk *const chunk1 = new TextChunk("test", + Color(1, 2, 3), Color(2, 0, 0), nullptr); + TextChunk *const chunk2 = new TextChunk("test", + Color(1, 2, 3), Color(2, 0, 1), nullptr); + TextChunk *const chunk3 = new TextChunk("test", + Color(1, 2, 3), Color(2, 0, 2), nullptr); + + list.insertFirst(chunk1); + list.insertFirst(chunk2); + list.insertFirst(chunk3); + list.moveToFirst(chunk1); + REQUIRE((chunksLeft + 3) == textChunkCnt); + REQUIRE(3 == list.search.size()); + REQUIRE(1 == list.searchWidth.size()); + + list.removeBack(); + REQUIRE((chunksLeft + 2) == textChunkCnt); + REQUIRE(2 == list.search.size()); + REQUIRE(list.searchWidth.empty()); + + list.clear(); + REQUIRE(chunksLeft == textChunkCnt); + REQUIRE(list.search.empty()); + REQUIRE(list.searchWidth.empty()); +} + +TEST_CASE("TextChunkList clear 4", "TextChunkList") +{ + TextChunkList list; + const int chunksLeft = textChunkCnt; + + TextChunk *const chunk1 = new TextChunk("test", + Color(1, 2, 3), Color(2, 0, 0), nullptr); + TextChunk *const chunk2 = new TextChunk("test", + Color(1, 2, 3), Color(2, 0, 1), nullptr); + TextChunk *const chunk3 = new TextChunk("test3", + Color(1, 2, 3), Color(2, 0, 2), nullptr); + + list.insertFirst(chunk1); + list.insertFirst(chunk2); + list.insertFirst(chunk3); + list.moveToFirst(chunk2); + REQUIRE((chunksLeft + 3) == textChunkCnt); + REQUIRE(3 == list.search.size()); + REQUIRE(2 == list.searchWidth.size()); + + list.removeBack(2); + REQUIRE((chunksLeft + 1) == textChunkCnt); + REQUIRE(1 == list.search.size()); + REQUIRE(list.searchWidth.empty()); + + list.clear(); + REQUIRE(chunksLeft == textChunkCnt); + REQUIRE(list.search.empty()); + REQUIRE(list.searchWidth.empty()); +} + +TEST_CASE("TextChunkList remove 1", "TextChunkList") +{ + TextChunkList list; + const int chunksLeft = textChunkCnt; + + TextChunk *const chunk = new TextChunk("test", + Color(), Color(), nullptr); + + list.insertFirst(chunk); + list.remove(chunk); + delete chunk; + + REQUIRE(0 == list.size); + REQUIRE(nullptr == list.start); + REQUIRE(nullptr == list.end); + REQUIRE(chunksLeft == textChunkCnt); + REQUIRE(list.search.empty()); + REQUIRE(list.searchWidth.empty()); +} + +TEST_CASE("TextChunkList remove 2", "TextChunkList") +{ + TextChunkList list; + const int chunksLeft = textChunkCnt; + + TextChunk *const chunk1 = new TextChunk("test1", + Color(1, 2, 3), Color(2, 0, 0), nullptr); + TextChunk *const chunk2 = new TextChunk("test2", + Color(1, 2, 3), Color(2, 0, 1), nullptr); + TextChunk *const chunk3 = new TextChunk("test3", + Color(1, 2, 3), Color(2, 0, 2), nullptr); + + list.insertFirst(chunk1); + list.insertFirst(chunk2); + list.insertFirst(chunk3); + list.remove(chunk1); + delete chunk1; + + REQUIRE(2 == list.size); + REQUIRE(chunk3 == list.start); + REQUIRE(chunk2 == list.end); + REQUIRE((chunksLeft + 2) == textChunkCnt); + REQUIRE(2 == list.search.size()); + REQUIRE(2 == list.searchWidth.size()); + delete chunk2; + delete chunk3; +} + +TEST_CASE("TextChunkList remove 3", "TextChunkList") +{ + TextChunkList list; + const int chunksLeft = textChunkCnt; + + TextChunk *const chunk1 = new TextChunk("test1", + Color(1, 2, 3), Color(2, 0, 0), nullptr); + TextChunk *const chunk2 = new TextChunk("test2", + Color(1, 2, 3), Color(2, 0, 1), nullptr); + TextChunk *const chunk3 = new TextChunk("test3", + Color(1, 2, 3), Color(2, 0, 2), nullptr); + + list.insertFirst(chunk1); + list.insertFirst(chunk2); + list.insertFirst(chunk3); + list.remove(chunk2); + delete chunk2; + + REQUIRE(2 == list.size); + REQUIRE(chunk3 == list.start); + REQUIRE(chunk1 == list.end); + REQUIRE((chunksLeft + 2) == textChunkCnt); + REQUIRE(2 == list.search.size()); + REQUIRE(2 == list.searchWidth.size()); + delete chunk1; + delete chunk3; +} + +TEST_CASE("TextChunkList sort 1", "TextChunkList") +{ + TextChunkSmall item1("test line1", + Color(1, 2, 3), Color(1, 2, 3)); + TextChunkSmall item2("test line1", + Color(1, 2, 3), Color(1, 2, 3)); + TextChunkSmall item3("test line2", + Color(1, 2, 3), Color(1, 2, 3)); + REQUIRE(false == (item1 < item2)); + REQUIRE(false == (item2 < item1)); + REQUIRE(item1 < item3); + REQUIRE(false == (item3 < item1)); +} + +TEST_CASE("TextChunkList sort 2", "TextChunkList") +{ + TextChunkSmall item1("test line1", + Color(1, 2, 3), Color(1, 2, 3)); + TextChunkSmall item2("test line1", + Color(2, 3, 4), Color(1, 2, 3)); + REQUIRE(item1 < item2); + REQUIRE(false == (item2 < item1)); +} + +TEST_CASE("TextChunkList sort 3", "TextChunkList") +{ + TextChunkSmall item1("test line1", + Color(1, 2, 3), Color(1, 2, 3)); + TextChunkSmall item2("test line1", + Color(1, 3, 4), Color(1, 2, 3)); + REQUIRE(item1 < item2); + REQUIRE(false == (item2 < item1)); +} + +TEST_CASE("TextChunkList sort 4", "TextChunkList") +{ + TextChunkSmall item1("test line1", + Color(1, 2, 3), Color(1, 2, 3)); + TextChunkSmall item2("test line1", + Color(1, 2, 4), Color(1, 2, 3)); + REQUIRE(item1 < item2); + REQUIRE(false == (item2 < item1)); +} + +TEST_CASE("TextChunkList sort 5", "TextChunkList") +{ + TextChunkSmall item1("test line1", + Color(1, 2, 3), Color(1, 2, 3)); + TextChunkSmall item2("test line1", + Color(1, 2, 3), Color(2, 2, 3)); + REQUIRE(item1 < item2); + REQUIRE(false == (item2 < item1)); +} + +TEST_CASE("TextChunkList sort 6", "TextChunkList") +{ + TextChunkSmall item1("test line1", + Color(1, 2, 3), Color(1, 2, 3)); + TextChunkSmall item2("test line1", + Color(1, 2, 3), Color(1, 3, 3)); + REQUIRE(item1 < item2); + REQUIRE(false == (item2 < item1)); +} + +TEST_CASE("TextChunkList sort 7", "TextChunkList") +{ + TextChunkSmall item1("test line1", + Color(1, 2, 3), Color(1, 2, 3)); + TextChunkSmall item2("test line1", + Color(1, 2, 3), Color(1, 2, 4)); + REQUIRE(item1 < item2); + REQUIRE(false == (item2 < item1)); +} diff --git a/src/unittests/gui/widgets/browserbox_unittest.cc b/src/unittests/gui/widgets/browserbox_unittest.cc new file mode 100644 index 000000000..128c7a52c --- /dev/null +++ b/src/unittests/gui/widgets/browserbox_unittest.cc @@ -0,0 +1,211 @@ +/* + * The ManaPlus Client + * Copyright (C) 2012-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "client.h" +#include "configuration.h" +#include "configmanager.h" +#include "dirs.h" +#include "graphicsmanager.h" + +#include "being/actorsprite.h" + +#include "fs/virtfs/fs.h" + +#include "gui/gui.h" + +#include "gui/fonts/font.h" + +#include "gui/widgets/browserbox.h" + +#include "utils/delete2.h" +#include "utils/env.h" + +#include "render/sdlgraphics.h" + +#include "resources/resourcemanager/resourcemanager.h" + +#include "resources/sdlimagehelper.h" + +#include "debug.h" + +TEST_CASE("BrowserBox leak test1", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} + +TEST_CASE("BrowserBox tests", "browserbox") +{ + setEnv("SDL_VIDEODRIVER", "dummy"); + + client = new Client; + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + mainGraphics = new SDLGraphics; + imageHelper = new SDLImageHelper; +#ifdef USE_SDL2 + SDLImageHelper::setRenderer(graphicsManager.createRenderer( + graphicsManager.createWindow(640, 480, 0, + SDL_WINDOW_SHOWN | SDL_SWSURFACE), SDL_RENDERER_SOFTWARE)); +#else // USE_SDL2 + + graphicsManager.createWindow(640, 480, 0, SDL_ANYFORMAT | SDL_SWSURFACE); +#endif // USE_SDL2 + + theme = new Theme; + Theme::selectSkin(); + + Dirs::initRootDir(); + Dirs::initHomeDir(); + + ConfigManager::initConfiguration(); + getConfigDefaults2(config.getDefaultValues()); + branding.setDefaultValues(getBrandingDefaults()); + + ActorSprite::load(); + gui = new Gui(); + gui->postInit(mainGraphics); + + Widget::setGlobalFont(new Font("/usr/share/fonts/truetype/" + "ttf-dejavu/DejaVuSans-Oblique.ttf", 18)); + BrowserBox *const box = new BrowserBox(nullptr, + Opaque_true, + ""); + box->setWidth(100); + std::string row = "test"; + box->addRow(row); + REQUIRE(box->hasRows() == true); + box->clearRows(); + row = "@@"; + box->addRow(row); + row = "@@|"; + box->addRow(row); + row = "|@@"; + box->addRow(row); + row = "@@|@@"; + box->addRow(row); + row = "|@@@@"; + box->addRow(row); + row = "@@11|22@@"; + box->addRow(row); + row = "##@@11|22@@"; + box->addRow(row); + row = "@@##|22@@"; + box->addRow(row); + row = "@@11|##22@@"; + box->addRow(row); + row = "@@11|22##@@"; + box->addRow(row); + row = "@@11|22@@##"; + box->addRow(row); + row = "<##@@11|22@@"; + box->addRow(row); + row = "@@<##|22@@"; + box->addRow(row); + row = "@@11|<##22@@"; + box->addRow(row); + row = "@@11|22<##@@"; + box->addRow(row); + row = "@@11|22@@<##"; + box->addRow(row); + row = "<##11|22@@"; + box->addRow(row); + row = "<##|22@@"; + box->addRow(row); + row = "11|<##22@@"; + box->addRow(row); + row = "11|22<##@@"; + box->addRow(row); + row = "11|22@@<##"; + box->addRow(row); + row = "##>@@11|22@@"; + box->addRow(row); + row = "@@##>|22@@"; + box->addRow(row); + row = "@@11|##>22@@"; + box->addRow(row); + row = "@@11|22##>@@"; + box->addRow(row); + row = "@@11|22@@##>"; + box->addRow(row); + row = "<##11|22##>"; + box->addRow(row); + row = "<##|22##>"; + box->addRow(row); + row = "11|<##22##>"; + box->addRow(row); + row = "11|22<####>"; + box->addRow(row); + row = "11|22##><##"; + box->addRow(row); + row = "%%@@11|22@@"; + box->addRow(row); + row = "%%2@@11|22@@"; + box->addRow(row); + row = "<%%11|22@@"; + box->addRow(row); + row = "@@%%>|22@@"; + box->addRow(row); + row = "<%%|22%%>"; + box->addRow(row); + row = "11|22<%%%%>"; + box->addRow(row); + row = "%%"; + box->addRow(row); + row = "%%1"; + box->addRow(row); + row = "%%##"; + box->addRow(row); + row = "%%###"; + box->addRow(row); + row = "##%%"; + box->addRow(row); + row = "##1%%"; + box->addRow(row); + row = "##%%2"; + box->addRow(row); + row = "##1%%2"; + box->addRow(row); + + delete Widget::getGloablFont(); + Widget::setGlobalFont(nullptr); + delete box; + delete2(client); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +// VirtFs::deinit(); +} + +TEST_CASE("BrowserBox leak test2", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} diff --git a/src/unittests/gui/windowmanager_unittest.cc b/src/unittests/gui/windowmanager_unittest.cc new file mode 100644 index 000000000..75949fc44 --- /dev/null +++ b/src/unittests/gui/windowmanager_unittest.cc @@ -0,0 +1,984 @@ +/* + * The ManaPlus Client + * Copyright (C) 2013-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "client.h" +#include "configmanager.h" +#include "configuration.h" +#include "dirs.h" +#include "graphicsmanager.h" +#include "main.h" +#include "settings.h" +#include "textcommand.h" + +#include "being/localplayer.h" + +#include "const/resources/currency.h" + +#include "fs/virtfs/fs.h" + +#include "gui/gui.h" +#include "gui/mailmessage.h" +#include "gui/userpalette.h" +#include "gui/windowmanager.h" + +#include "gui/popups/beingpopup.h" +#include "gui/popups/itempopup.h" +#include "gui/popups/popupmenu.h" +#include "gui/popups/skillpopup.h" +#include "gui/popups/spellpopup.h" +#include "gui/popups/speechbubble.h" +#include "gui/popups/statuspopup.h" +#include "gui/popups/textboxpopup.h" +#include "gui/popups/textpopup.h" + +#include "gui/widgets/desktop.h" +#include "gui/widgets/emoteshortcutcontainer.h" +#include "gui/widgets/createwidget.h" + +#include "gui/windows/bankwindow.h" +#include "gui/windows/buydialog.h" +#include "gui/windows/buyingstoreselldialog.h" +#include "gui/windows/buyselldialog.h" +#include "gui/windows/charselectdialog.h" +#include "gui/windows/changeemaildialog.h" +#include "gui/windows/changepassworddialog.h" +#include "gui/windows/chatwindow.h" +#include "gui/windows/connectiondialog.h" +#include "gui/windows/confirmdialog.h" +#include "gui/windows/cutinwindow.h" +#include "gui/windows/debugwindow.h" +#include "gui/windows/didyouknowwindow.h" +#include "gui/windows/editdialog.h" +#include "gui/windows/editserverdialog.h" +#include "gui/windows/eggselectiondialog.h" +#include "gui/windows/emotewindow.h" +#include "gui/windows/equipmentwindow.h" +#include "gui/windows/helpwindow.h" +#include "gui/windows/insertcarddialog.h" +#include "gui/windows/inventorywindow.h" +#include "gui/windows/itemamountwindow.h" +#include "gui/windows/killstats.h" +#include "gui/windows/logindialog.h" +#include "gui/windows/maileditwindow.h" +#include "gui/windows/mailviewwindow.h" +#include "gui/windows/mailwindow.h" +#include "gui/windows/minimap.h" +#include "gui/windows/ministatuswindow.h" +#include "gui/windows/npcdialog.h" +#include "gui/windows/npcselldialog.h" +#include "gui/windows/okdialog.h" +#include "gui/windows/outfitwindow.h" +#include "gui/windows/questswindow.h" +#include "gui/windows/quitdialog.h" +#include "gui/windows/registerdialog.h" +#include "gui/windows/serverdialog.h" +#include "gui/windows/serverinfowindow.h" +#include "gui/windows/setupwindow.h" +#include "gui/windows/shopwindow.h" +#include "gui/windows/shortcutwindow.h" +#include "gui/windows/skilldialog.h" +#include "gui/windows/socialwindow.h" +#include "gui/windows/statuswindow.h" +#include "gui/windows/textcommandeditor.h" +#include "gui/windows/textdialog.h" +#include "gui/windows/textselectdialog.h" +#include "gui/windows/tradewindow.h" +#include "gui/windows/updaterwindow.h" +#include "gui/windows/whoisonline.h" +#include "gui/windows/worldselectdialog.h" + +#include "input/touch/touchmanager.h" + +#include "net/logindata.h" + +#include "net/eathena/charserverhandler.h" +#include "net/eathena/inventoryhandler.h" +#include "net/eathena/serverfeatures.h" +#include "net/eathena/playerhandler.h" + +#include "render/sdlgraphics.h" + +#include "resources/sdlimagehelper.h" + +#include "resources/db/unitsdb.h" + +#include "resources/item/item.h" + +#include "resources/map/map.h" + +#include "resources/resourcemanager/resourcemanager.h" + +#include "utils/delete2.h" +#include "utils/env.h" +#include "utils/gettext.h" + +#include "utils/translation/translationmanager.h" + +#include "debug.h" + +extern QuitDialog *quitDialog; + +TEST_CASE("windows leak test1", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} + +TEST_CASE("Windows tests", "windowmanager") +{ + setEnv("SDL_VIDEODRIVER", "dummy"); + + client = new Client; + XML::initXML(); + SDL_Init(SDL_INIT_VIDEO); + logger = new Logger(); + ResourceManager::deleteInstance(); + ResourceManager::cleanOrphans(true); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + VirtFs::mountDirSilent("data/test", Append_false); + VirtFs::mountDirSilent("../data/test", Append_false); + paths.setDefaultValues(getPathsDefaults()); + branding.setValue("onlineServerFile", "test/serverlistplus.xml"); + mainGraphics = new SDLGraphics; + imageHelper = new SDLImageHelper; +#ifdef USE_SDL2 + SDLImageHelper::setRenderer(graphicsManager.createRenderer( + graphicsManager.createWindow(640, 480, 0, + SDL_WINDOW_SHOWN | SDL_SWSURFACE), SDL_RENDERER_SOFTWARE)); +#else // USE_SDL2 + + graphicsManager.createWindow(640, 480, 0, SDL_ANYFORMAT | SDL_SWSURFACE); +#endif // USE_SDL2 + + userPalette = new UserPalette; + config.setValue("fontSize", 16); + theme = new Theme; + Theme::selectSkin(); + + Dirs::initRootDir(); + Dirs::initHomeDir(); + + const std::string cfgName = settings.configDir + + "/nonexistserver/config.xml"; + ::remove(cfgName.c_str()); + + ConfigManager::initConfiguration(); + getConfigDefaults2(config.getDefaultValues()); + branding.setDefaultValues(getBrandingDefaults()); + ConfigManager::initServerConfig("nonexistserver"); + + localPlayer = new LocalPlayer(static_cast<BeingId>(1), + BeingTypeId_zero); + + ActorSprite::load(); + gui = new Gui(); + gui->postInit(mainGraphics); + touchManager.init(); + UnitsDb::loadUnits(); + charServerHandler = new EAthena::CharServerHandler; + serverFeatures = new EAthena::ServerFeatures; + inventoryHandler = new EAthena::InventoryHandler; + playerHandler = new EAthena::PlayerHandler; + paths.setValue("itemIcons", ""); + + TranslationManager::init(); + + mainGraphics->setVideoMode(640, 480, 1, 8, false, false, false, false); + + SECTION("bankWindow") + { + CREATEWIDGETV0(bankWindow, BankWindow); + gui->draw(); + mainGraphics->updateScreen(); + delete2(bankWindow); + } + SECTION("buyDialog1") + { + BuyDialog *dialog; + CREATEWIDGETV0(dialog, BuyDialog); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + } + SECTION("buyDialog2") + { + BuyDialog *dialog; + CREATEWIDGETV(dialog, BuyDialog, + BeingId_zero, + DEFAULT_CURRENCY); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + } +#ifdef TMWA_SUPPORT + SECTION("buyDialog3") + { + BuyDialog *dialog; + CREATEWIDGETV(dialog, BuyDialog, + "user", + DEFAULT_CURRENCY); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + } +#endif // TMWA_SUPPORT + SECTION("buyDialog4") + { + BuyDialog *dialog; + BeingTypeId id = static_cast<BeingTypeId>(1); + Map *map = new Map("test map", + 10, 10, + 32, 32); + Being *being = Being::createBeing(BeingId_zero, + ActorType::Avatar, + id, + map); + CREATEWIDGETV(dialog, BuyDialog, + being, + DEFAULT_CURRENCY); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + delete2(being); + } + SECTION("BuyingStoreSellDialog") + { + BuyingStoreSellDialog *dialog; + CREATEWIDGETV(dialog, BuyingStoreSellDialog, + BeingId_zero, 0); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + } + SECTION("BuySellDialog1") + { + BuySellDialog *dialog; + CREATEWIDGETV(dialog, BuySellDialog, BeingId_zero); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + } + SECTION("BuySellDialog2") + { + BuySellDialog *dialog; + CREATEWIDGETV(dialog, BuySellDialog, "user"); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + } + SECTION("ChangeEmailDialog") + { + LoginData data; + ChangeEmailDialog *dialog; + CREATEWIDGETV(dialog, ChangeEmailDialog, data); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + } + SECTION("ChangePasswordDialog") + { + LoginData data; + ChangePasswordDialog *dialog; + CREATEWIDGETV(dialog, ChangePasswordDialog, data); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + } + SECTION("CharSelectDialog") + { + LoginData data; + CharSelectDialog *dialog; + CREATEWIDGETV(dialog, CharSelectDialog, data); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + } + SECTION("CharCreateDialog") + { +// LoginData data; +// CharSelectDialog *dialog2; +// CREATEWIDGETV(dialog2, CharSelectDialog, data); +// CharCreateDialog *dialog; +// CREATEWIDGETV(dialog, CharCreateDialog, dialog2, 0); +// gui->draw(); +// mainGraphics->updateScreen(); +// delete2(dialog); +// delete2(dialog2); + } + SECTION("ChatWindow") + { + CREATEWIDGETV(chatWindow, ChatWindow, + "Chat"); + gui->draw(); + mainGraphics->updateScreen(); + delete2(chatWindow); + } + SECTION("ConfirmDialog") + { + ConfirmDialog *dialog; + CREATEWIDGETV(dialog, ConfirmDialog, + "", "", "", false, Modal_false, nullptr); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + } + SECTION("CutinWindow") + { + CREATEWIDGETV0(cutInWindow, CutInWindow); + gui->draw(); + mainGraphics->updateScreen(); + delete2(cutInWindow); + } + SECTION("DebugWindow") + { + CREATEWIDGETV0(debugWindow, DebugWindow); + gui->draw(); + mainGraphics->updateScreen(); + delete2(debugWindow); + } + SECTION("didYouKnowWindow") + { + CREATEWIDGETV0(didYouKnowWindow, DidYouKnowWindow); + gui->draw(); + mainGraphics->updateScreen(); + delete2(didYouKnowWindow); + } + SECTION("EditDialog") + { + EditDialog *dialog; + CREATEWIDGETV(dialog, EditDialog, + "", "", "", 100, nullptr, Modal_false); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + } + SECTION("EditServerDialog") + { + ServerInfo mCurrentServer; + settings.configDir = VirtFs::getRealDir("test/serverlistplus.xml"); + ServerDialog *serverDialog = CREATEWIDGETR(ServerDialog, + &mCurrentServer, + settings.configDir); + EditServerDialog *editServerDialog = CREATEWIDGETR(EditServerDialog, + serverDialog, mCurrentServer, 0); + gui->draw(); + mainGraphics->updateScreen(); + delete2(editServerDialog); + delete2(serverDialog); + } + SECTION("EggSelectionDialog") + { + EggSelectionDialog *dialog = CREATEWIDGETR0(EggSelectionDialog); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + } + SECTION("EmoteWindow") + { + EmoteWindow *dialog = CREATEWIDGETR0(EmoteWindow); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + } + SECTION("EquipmentWindow") + { + Equipment *equipment = new Equipment; + Map *map = new Map("test", 100, 100, 32, 32); + Being *being = Being::createBeing(BeingId_zero, + ActorType::Player, + BeingTypeId_zero, + map); + EquipmentWindow *dialog = CREATEWIDGETR(EquipmentWindow, + equipment, being, false); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + delete2(being); + delete2(map); + delete2(equipment); + } + SECTION("helpWindow") + { + CREATEWIDGETV0(helpWindow, HelpWindow); + gui->draw(); + mainGraphics->updateScreen(); + delete2(helpWindow); + } + SECTION("InsertCardDialog") + { + Item *item = new Item(5000, + ItemType::Card, + 1, + 0, + ItemColor_one, + Identified_true, + Damaged_false, + Favorite_false, + Equipm_true, + Equipped_false); + InsertCardDialog *dialog = CREATEWIDGETR(InsertCardDialog, + 0, item); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + delete2(item); + } + SECTION("InventoryWindow") + { + Inventory *inventory = new Inventory(InventoryType::Inventory); + InventoryWindow *dialog = CREATEWIDGETR(InventoryWindow, + inventory); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + delete2(inventory); + } + SECTION("ItemAmountWindow") + { + Item *item = new Item(5000, + ItemType::Card, + 1, + 0, + ItemColor_one, + Identified_true, + Damaged_false, + Favorite_false, + Equipm_true, + Equipped_false); + ItemAmountWindow *dialog = CREATEWIDGETR(ItemAmountWindow, + ItemAmountWindowUsage::ItemDrop, nullptr, item); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + delete2(item); + } + SECTION("KillStats") + { + CREATEWIDGETV0(killStats, KillStats); + gui->draw(); + mainGraphics->updateScreen(); + delete2(killStats); + } + SECTION("loginDialog") + { + ServerInfo mCurrentServer; + LoginDialog *loginDialog = CREATEWIDGETR(LoginDialog, + loginData, + &mCurrentServer, + &settings.options.updateHost); + gui->draw(); + mainGraphics->updateScreen(); + delete2(loginDialog); + } + SECTION("MailEditWindow") + { + CREATEWIDGETV0(mailEditWindow, MailEditWindow); + gui->draw(); + mainGraphics->updateScreen(); + delete2(mailEditWindow); + } + SECTION("MailViewWindow") + { + MailMessage *message = new MailMessage; + CREATEWIDGETV(mailViewWindow, MailViewWindow, + message); + gui->draw(); + mainGraphics->updateScreen(); + delete2(mailViewWindow); + } + SECTION("MailWindow") + { + CREATEWIDGETV0(mailWindow, MailWindow); + gui->draw(); + mainGraphics->updateScreen(); + delete2(mailWindow); + } + SECTION("Minimap") + { + CREATEWIDGETV0(minimap, Minimap); + gui->draw(); + mainGraphics->updateScreen(); + delete2(minimap); + } + SECTION("MiniStatusWindow") + { + CREATEWIDGETV0(miniStatusWindow, MiniStatusWindow); + gui->draw(); + mainGraphics->updateScreen(); + delete2(miniStatusWindow); + } + SECTION("NpcDialog") + { + NpcDialog *dialog = CREATEWIDGETR(NpcDialog, BeingId_zero); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + } + SECTION("NpcSellDialog") + { + NpcSellDialog *dialog = CREATEWIDGETR(NpcSellDialog, BeingId_zero); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + } + SECTION("OkDialog") + { + OkDialog *dialog = CREATEWIDGETR(OkDialog, + "", "", "", DialogType::SILENCE, Modal_false, + ShowCenter_true, nullptr, 100); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + } + SECTION("OutfitWindow") + { + CREATEWIDGETV0(outfitWindow, OutfitWindow); + gui->draw(); + mainGraphics->updateScreen(); + delete2(outfitWindow); + } + SECTION("QuestsWindow") + { + CREATEWIDGETV0(questsWindow, QuestsWindow); + gui->draw(); + mainGraphics->updateScreen(); + delete2(questsWindow); + } + SECTION("QuitDialog") + { + CREATEWIDGETV(quitDialog, QuitDialog, + &quitDialog); + gui->draw(); + mainGraphics->updateScreen(); + delete2(quitDialog); + } + SECTION("RegisterDialog") + { + RegisterDialog *dialog = CREATEWIDGETR(RegisterDialog, + loginData); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + } + SECTION("serversDialog") + { + ServerInfo mCurrentServer; + settings.configDir = VirtFs::getRealDir("test/serverlistplus.xml"); + ServerDialog *serverDialog = CREATEWIDGETR(ServerDialog, + &mCurrentServer, + settings.configDir); + gui->draw(); + mainGraphics->updateScreen(); + delete2(serverDialog); + } + SECTION("serversInfoWindow") + { + ServerInfo mCurrentServer; + CREATEWIDGETV(serverInfoWindow, ServerInfoWindow, + mCurrentServer); + gui->draw(); + mainGraphics->updateScreen(); + delete2(serverInfoWindow); + } + SECTION("setupWindow") + { + CREATEWIDGETV0(setupWindow, SetupWindow); + gui->draw(); + mainGraphics->updateScreen(); + delete2(setupWindow); + } + SECTION("ShopSellDialog") + { + // only tmwa skipping + } + SECTION("ShopWindow") + { + CREATEWIDGETV0(shopWindow, ShopWindow); + gui->draw(); + mainGraphics->updateScreen(); + delete2(shopWindow); + } + SECTION("ShortcutWindow1") + { + EmoteShortcutContainer *container = + new EmoteShortcutContainer(nullptr); + CREATEWIDGETV(itemShortcutWindow, ShortcutWindow, + "name", + container); + gui->draw(); + mainGraphics->updateScreen(); + delete2(itemShortcutWindow); + } + SECTION("ShortcutWindow2") + { + CREATEWIDGETV(itemShortcutWindow, ShortcutWindow, ""); + gui->draw(); + mainGraphics->updateScreen(); + delete2(itemShortcutWindow); + } + SECTION("SkillDialog") + { + CREATEWIDGETV0(skillDialog, SkillDialog); + gui->draw(); + mainGraphics->updateScreen(); + delete2(skillDialog); + } + SECTION("SocialWindow") + { + CREATEWIDGETV0(socialWindow, SocialWindow); + gui->draw(); + mainGraphics->updateScreen(); + delete2(socialWindow); + } + SECTION("StatusWindow") + { + CREATEWIDGETV0(statusWindow, StatusWindow); + gui->draw(); + mainGraphics->updateScreen(); + delete2(statusWindow); + } + SECTION("TextCommandEditor") + { + TextCommand *textCommand = new TextCommand(1, "", "", "", + CommandTarget::NoTarget, ""); + TextCommandEditor *dialog = CREATEWIDGETR(TextCommandEditor, + textCommand); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + delete2(textCommand); + } + + SECTION("TextDialog") + { + TextDialog *dialog = CREATEWIDGETR(TextDialog, + "", "", nullptr, false); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + } + SECTION("TextSelectDialog") + { + TextSelectDialog *dialog = CREATEWIDGETR(TextSelectDialog, + "", "", AllowQuit_false); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + } + SECTION("TradeWindow") + { + CREATEWIDGETV0(tradeWindow, TradeWindow); + gui->draw(); + mainGraphics->updateScreen(); + delete2(tradeWindow); + } + SECTION("UpdaterWindow") + { + CREATEWIDGETV(updaterWindow, UpdaterWindow, + "", "", false, UpdateType::Skip); + gui->draw(); + mainGraphics->updateScreen(); + delete2(updaterWindow); + } + SECTION("WhoIsOnline") + { + CREATEWIDGETV0(whoIsOnline, WhoIsOnline); + gui->draw(); + mainGraphics->updateScreen(); + delete2(whoIsOnline); + } + SECTION("WorldSelectDialog") + { + Worlds worlds; + WorldSelectDialog *dialog = CREATEWIDGETR(WorldSelectDialog, + worlds); + gui->draw(); + mainGraphics->updateScreen(); + delete2(dialog); + } + SECTION("popupMenu") + { + CREATEWIDGETV0(popupMenu, PopupMenu); + gui->draw(); + mainGraphics->updateScreen(); + delete2(popupMenu); + } + SECTION("skillPopup") + { + CREATEWIDGETV0(skillPopup, SkillPopup); + gui->draw(); + mainGraphics->updateScreen(); + delete2(skillPopup); + } + SECTION("SpeechBubble") + { + SpeechBubble *bubble = CREATEWIDGETR0(SpeechBubble); + gui->draw(); + mainGraphics->updateScreen(); + delete2(bubble); + } + SECTION("beingPopup") + { + CREATEWIDGETV0(beingPopup, BeingPopup); + gui->draw(); + mainGraphics->updateScreen(); + delete2(beingPopup); + } + SECTION("textPopup") + { + CREATEWIDGETV0(textPopup, TextPopup); + gui->draw(); + mainGraphics->updateScreen(); + delete2(textPopup); + } + SECTION("textBoxPopup") + { + CREATEWIDGETV0(textBoxPopup, TextBoxPopup); + gui->draw(); + mainGraphics->updateScreen(); + delete2(textBoxPopup); + } + SECTION("itemPopup") + { + CREATEWIDGETV0(itemPopup, ItemPopup); + gui->draw(); + mainGraphics->updateScreen(); + delete2(itemPopup); + } + SECTION("spellPopup") + { + CREATEWIDGETV0(spellPopup, SpellPopup); + gui->draw(); + mainGraphics->updateScreen(); + delete2(spellPopup); + } + SECTION("StatusPopup") + { + StatusPopup *status = CREATEWIDGETR0(StatusPopup); + gui->draw(); + mainGraphics->updateScreen(); + delete2(status); + } + SECTION("desktop") + { + CREATEWIDGETV(desktop, Desktop, nullptr); + gui->draw(); + mainGraphics->updateScreen(); + delete2(desktop); + } + SECTION("connectionDialog") + { + ConnectionDialog *connectionDialog = CREATEWIDGETR(ConnectionDialog, + // TRANSLATORS: connection dialog header + _("Logging in"), + State::SWITCH_SERVER); + gui->draw(); + mainGraphics->updateScreen(); + delete2(connectionDialog); + } + + delete2(localPlayer); + delete2(userPalette); + delete2(client); + delete2(serverFeatures); + delete2(inventoryHandler); + delete2(charServerHandler); + delete2(playerHandler); + delete2(gui); + ResourceManager::deleteInstance(); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + VirtFs::unmountDirSilent("data/test"); + VirtFs::unmountDirSilent("../data/test"); + delete2(logger); + +// VirtFs::deinit(); +} + +TEST_CASE("WindowManager", "create windows") +{ + setEnv("SDL_VIDEODRIVER", "dummy"); + + client = new Client; + XML::initXML(); + SDL_Init(SDL_INIT_VIDEO); + logger = new Logger(); + ResourceManager::deleteInstance(); + ResourceManager::cleanOrphans(true); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + VirtFs::mountDirSilent("data/test", Append_false); + VirtFs::mountDirSilent("../data/test", Append_false); + paths.setDefaultValues(getPathsDefaults()); + branding.setValue("onlineServerFile", "test/serverlistplus.xml"); + mainGraphics = new SDLGraphics; + imageHelper = new SDLImageHelper; +#ifdef USE_SDL2 + SDLImageHelper::setRenderer(graphicsManager.createRenderer( + graphicsManager.createWindow(640, 480, 0, + SDL_WINDOW_SHOWN | SDL_SWSURFACE), SDL_RENDERER_SOFTWARE)); +#else // USE_SDL2 + + graphicsManager.createWindow(640, 480, 0, SDL_ANYFORMAT | SDL_SWSURFACE); +#endif // USE_SDL2 + + config.setValue("fontSize", 16); + theme = new Theme; + Theme::selectSkin(); + + Dirs::initRootDir(); + Dirs::initHomeDir(); + + const std::string cfgName = settings.configDir + + "/nonexistserver/config.xml"; + ::remove(cfgName.c_str()); + + ConfigManager::initConfiguration(); + getConfigDefaults2(config.getDefaultValues()); + branding.setDefaultValues(getBrandingDefaults()); + ConfigManager::initServerConfig("nonexistserver"); + + localPlayer = new LocalPlayer(static_cast<BeingId>(1), + BeingTypeId_zero); + + ActorSprite::load(); + gui = new Gui(); + gui->postInit(mainGraphics); + touchManager.init(); + UnitsDb::loadUnits(); + charServerHandler = new EAthena::CharServerHandler; + serverFeatures = new EAthena::ServerFeatures; + inventoryHandler = new EAthena::InventoryHandler; + playerHandler = new EAthena::PlayerHandler; + paths.setValue("itemIcons", ""); + + TranslationManager::init(); + + mainGraphics->setVideoMode(640, 480, 1, 8, false, false, false, false); + + SECTION("create windows") + { + WindowManager::createWindows(); + WindowManager::deleteWindows(); + } + + SECTION("init") + { + WindowManager::init(); + } + + SECTION("initTitle") + { + WindowManager::initTitle(); + REQUIRE(settings.windowCaption == strprintf("%s %s", + branding.getStringValue("appName").c_str(), + SMALL_VERSION)); + } + + SECTION("updateTitle1") + { + settings.serverName = std::string(); + settings.login = std::string(); + WindowManager::updateTitle(); + REQUIRE(settings.windowCaption == strprintf("%s %s", + branding.getStringValue("appName").c_str(), + SMALL_VERSION)); + } + + SECTION("updateTitle2") + { + settings.serverName = "server"; + settings.login = std::string(); + WindowManager::updateTitle(); + REQUIRE(settings.windowCaption == strprintf("%s %s - %s", + branding.getStringValue("appName").c_str(), + SMALL_VERSION, + settings.serverName.c_str())); + } + + SECTION("updateTitle3") + { + settings.serverName = "server"; + settings.login = "login"; + WindowManager::updateTitle(); + REQUIRE(settings.windowCaption == strprintf("%s %s - %s %s", + branding.getStringValue("appName").c_str(), + SMALL_VERSION, + settings.login.c_str(), + settings.serverName.c_str())); + } + + SECTION("setFramerate1") + { + settings.limitFps = true; + WindowManager::setFramerate(60); + REQUIRE(WindowManager::getFramerate() == 60); + WindowManager::setFramerate(10); + REQUIRE(WindowManager::getFramerate() == 10); + WindowManager::setFramerate(0); + REQUIRE(WindowManager::getFramerate() == 10); + } + + SECTION("setFramerate2") + { + settings.limitFps = false; + WindowManager::setFramerate(60); + REQUIRE(WindowManager::getFramerate() == 0); + WindowManager::setFramerate(10); + REQUIRE(WindowManager::getFramerate() == 0); + WindowManager::setFramerate(0); + REQUIRE(WindowManager::getFramerate() == 0); + } + + settings.serverName = std::string(); + settings.login = std::string(); + settings.limitFps = true; + + delete2(localPlayer); + delete2(client); + delete2(serverFeatures); + delete2(inventoryHandler); + delete2(charServerHandler); + delete2(playerHandler); + delete2(gui); + ResourceManager::deleteInstance(); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + VirtFs::unmountDirSilent("data/test"); + VirtFs::unmountDirSilent("../data/test"); + delete2(logger); + +// VirtFs::deinit(); +} + +TEST_CASE("windows leak test2", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} diff --git a/src/unittests/integrity_unittest.cc b/src/unittests/integrity_unittest.cc new file mode 100644 index 000000000..b2c234109 --- /dev/null +++ b/src/unittests/integrity_unittest.cc @@ -0,0 +1,366 @@ +/* + * The ManaPlus Client + * Copyright (C) 2013-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "client.h" +#include "logger.h" +#include "graphicsmanager.h" + +#include "being/actorsprite.h" + +#include "fs/files.h" + +#include "fs/virtfs/fs.h" +#include "fs/virtfs/rwops.h" + +#include "gui/gui.h" + +#include "input/inputactionmap.h" + +#include "resources/image/image.h" + +#include "resources/loaders/imageloader.h" + +#include "resources/sdlimagehelper.h" +#ifdef USE_SDL2 +#include "resources/surfaceimagehelper.h" +#endif // USE_SDL2 + +#include "resources/resourcemanager/resourcemanager.h" + +#include "utils/env.h" +#include "utils/delete2.h" +#include "utils/foreach.h" + +PRAGMA48(GCC diagnostic push) +PRAGMA48(GCC diagnostic ignored "-Wshadow") +#include <SDL_image.h> +PRAGMA48(GCC diagnostic pop) + +#ifndef UNITTESTS_CATCH +#include <algorithm> +#endif // UNITTESTS_CATCH + +#include "debug.h" + +namespace +{ + class InputActionSortFunctorTest final + { + public: + bool operator() (const InputActionT key1, + const InputActionT key2) const + { + REQUIRE(CAST_SIZE(key1) < CAST_SIZE(InputAction::TOTAL)); + REQUIRE(CAST_SIZE(key2) < CAST_SIZE(InputAction::TOTAL)); + REQUIRE(key1 < InputAction::TOTAL); + REQUIRE(key2 < InputAction::TOTAL); + return keys[CAST_SIZE(key1)].priority + >= keys[CAST_SIZE(key2)].priority; + } + + const InputActionData *keys A_NONNULLPOINTER; + }; + InputActionSortFunctorTest inputActionDataSorterTest; +} // namespace + +static bool compareBuffers(const unsigned char *const buf2) +{ + bool isCorrect(true); + int sz = 0; + const unsigned char *buf1 = reinterpret_cast<const unsigned char*>( + VirtFs::loadFile("hide.png", sz)); + REQUIRE(buf1 != nullptr); + REQUIRE(sz == 368); + for (int f = 0; f < sz; f ++) + { + if (buf1[f] != buf2[f]) + { + isCorrect = false; + logger->log("Wrong buffer chars: 0x%x vs 0x%x", + buf1[f], + buf2[f]); + } + } + delete [] buf1; + return isCorrect; +} + +TEST_CASE("integrity leak test1", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} + +TEST_CASE("integrity tests", "integrity") +{ + setEnv("SDL_VIDEODRIVER", "dummy"); + + client = new Client; + XML::initXML(); + SDL_Init(SDL_INIT_VIDEO); + logger = new Logger(); + std::string name("data/test/test.zip"); + std::string prefix; + if (Files::existsLocal(name) == false) + prefix = "../" + prefix; + + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + +#ifdef USE_SDL2 + imageHelper = new SurfaceImageHelper; + + SDLImageHelper::setRenderer(graphicsManager.createRenderer( + graphicsManager.createWindow(640, 480, 0, + SDL_WINDOW_SHOWN | SDL_SWSURFACE), SDL_RENDERER_SOFTWARE)); +#else // USE_SDL2 + + imageHelper = new SDLImageHelper(); + + graphicsManager.createWindow(640, 480, 0, SDL_ANYFORMAT | SDL_SWSURFACE); +#endif // USE_SDL2 + + ActorSprite::load(); + const char *const name1 = "dir/hide.png"; + const int size1 = 368; + + SECTION("integrity test 1") + { + REQUIRE(sizeof(inputActionData) / sizeof(InputActionData) == + CAST_SIZE(InputAction::TOTAL)); + } + + SECTION("integrity test 2") + { + KeyToActionMap actionMap; + const size_t sz = CAST_SIZE(InputAction::TOTAL); + for (size_t i = 0; i < sz; i ++) + { + InputActionT val = static_cast<InputActionT>(i); + REQUIRE(val < InputAction::TOTAL); + REQUIRE(val > InputAction::NO_VALUE); + REQUIRE(val > InputAction::UNDEFINED_VALUE); + REQUIRE(CAST_SIZE(val) < CAST_SIZE(InputAction::TOTAL)); + REQUIRE(CAST_SIZE(val) < CAST_SIZE(InputAction::NO_VALUE)); + REQUIRE(CAST_SIZE(val) < CAST_SIZE(InputAction::UNDEFINED_VALUE)); + REQUIRE(CAST_S32(val) < CAST_S32(InputAction::TOTAL)); + REQUIRE(CAST_S32(val) > CAST_S32(InputAction::NO_VALUE)); + REQUIRE(CAST_S32(val) > CAST_S32(InputAction::UNDEFINED_VALUE)); + } + } + + SECTION("integrity test 3") + { + KeyToActionMap actionMap; + int cnt = 0; + const size_t sz = CAST_SIZE(InputAction::TOTAL); + for (size_t i = 0; i < sz; i ++) + { + actionMap[cnt++].push_back(static_cast<InputActionT>(i)); + if (cnt > 3) + cnt = 0; + } + FOR_EACH (KeyToActionMapIter, it, actionMap) + { + KeysVector *const keys = &it->second; + FOR_EACHP (KeysVectorIter, itk, keys) + { + const size_t val = CAST_SIZE(*itk); + REQUIRE(val < sz); + } + } + } + + SECTION("integrity test 4") + { + KeyToActionMap actionMap; + KeyTimeMap keyTimeMap; + actionMap.clear(); + keyTimeMap.clear(); + + for (size_t i = 0; i < CAST_SIZE(InputAction::TOTAL); i ++) + { + actionMap[10].push_back( + static_cast<InputActionT>(i)); + } + + KeysVector *const keys = &actionMap[0]; + inputActionDataSorterTest.keys = &inputActionData[0]; + std::sort(keys->begin(), keys->end(), inputActionDataSorterTest); + } + + SECTION("integrity test 5") + { + KeyToActionMap mKeyToAction; + KeyToIdMap mKeyToId; + KeyTimeMap mKeyTimeMap; + inputManager.updateKeyActionMap(mKeyToAction, mKeyToId, + mKeyTimeMap, InputType::KEYBOARD); + } + + SECTION("integrity Loader::getImage test 1") + { + Image *const image = Loader::getImage( + "graphics/images/login_wallpaper.png"); + REQUIRE(image != nullptr); + REQUIRE(image->getSDLSurface() != nullptr); + image->decRef(); + } + + SECTION("integrity Loader::getImage test 2") + { + VirtFs::mountZip(prefix + "data/test/test.zip", Append_false); + Image *const image = Loader::getImage( + "dir/hide.png"); + VirtFs::unmountZip(prefix + "data/test/test.zip"); + REQUIRE(image != nullptr); + REQUIRE(image->getSDLSurface() != nullptr); + image->decRef(); + } + + SECTION("integrity Loader::getImage test 3") + { + VirtFs::mountZip(prefix + "data/test/test.zip", Append_false); + Image *const image = Loader::getImage( + "dir/brimmedhat.png"); + VirtFs::unmountZip(prefix + "data/test/test.zip"); + REQUIRE(image != nullptr); + REQUIRE(image->getSDLSurface() != nullptr); + image->decRef(); + } + + SECTION("integrity Loader::getImage test 4") + { + VirtFs::mountZip(prefix + "data/test/test.zip", Append_false); + + SDL_RWops *const rw = VirtFs::rwopsOpenRead(name1); + REQUIRE(rw != nullptr); + unsigned char buf[size1]; + const size_t sz = SDL_RWread(rw, buf, 1, size1); + if (sz != size1) + SDL_RWclose(rw); + REQUIRE(sz == size1); + SDL_RWclose(rw); + VirtFs::unmountZip(prefix + "data/test/test.zip"); + VirtFs::mountDirSilent(prefix + "data/test", Append_true); + REQUIRE(compareBuffers(buf)); + VirtFs::unmountDirSilent(prefix + "data/test"); + } + + SECTION("integrity Loader::getImage test 7") + { + VirtFs::mountZip(prefix + "data/test/test.zip", Append_false); + + SDL_RWops *const rw = VirtFs::rwopsOpenRead(name1); + REQUIRE(rw != nullptr); + int64_t seek = SDL_RWseek(rw, 0, RW_SEEK_END); + if (seek == -1) + SDL_RWclose(rw); + REQUIRE(seek != -1); + const int64_t pos = SDL_RWtell(rw); + if (pos != size1) + SDL_RWclose(rw); + REQUIRE(pos == size1); + + seek = SDL_RWseek(rw, 0, RW_SEEK_SET); + if (seek == -1) + SDL_RWclose(rw); + REQUIRE(seek != -1); + + unsigned char buf[size1]; + const size_t sz = SDL_RWread(rw, buf, 1, pos); + if (sz != size1) + SDL_RWclose(rw); + REQUIRE(sz == size1); + + SDL_RWclose(rw); + VirtFs::unmountZip(prefix + "data/test/test.zip"); + VirtFs::mountDirSilent("data/test", Append_true); + VirtFs::mountDirSilent("../data/test", Append_true); + REQUIRE(compareBuffers(buf)); + VirtFs::unmountDirSilent("data/test"); + VirtFs::unmountDirSilent("../data/test"); + } + + SECTION("integrity Loader::getImage test 8") + { + VirtFs::mountZip(prefix + "data/test/test.zip", Append_false); + + SDL_RWops *const rw = VirtFs::rwopsOpenRead(name1); + REQUIRE(rw != nullptr); + if (IMG_isPNG(rw) == 0) + { + SDL_RWclose(rw); + REQUIRE(false); + } + SDL_Surface *const tmpImage = IMG_LoadPNG_RW(rw); + SDL_RWclose(rw); + VirtFs::unmountZip(prefix + "data/test/test.zip"); + REQUIRE(tmpImage != nullptr); + SDL_FreeSurface(tmpImage); + } + + SECTION("integrity Loader::getImage test 9") + { + VirtFs::mountZip(prefix + "data/test/test.zip", Append_false); + + SDL_RWops *const rw = VirtFs::rwopsOpenRead(name1); + REQUIRE(rw != nullptr); + Resource *const res = imageHelper->load(rw); + VirtFs::unmountZip(prefix + "data/test/test.zip"); + REQUIRE(res != nullptr); + delete res; + } + + SECTION("integrity Loader::getImage test 10") + { + VirtFs::mountZip(prefix + "data/test/test.zip", Append_false); + Image *const image = Loader::getImage( + name1); + VirtFs::unmountZip(prefix + "data/test/test.zip"); + REQUIRE(image != nullptr); + REQUIRE(image->getSDLSurface() != nullptr); + image->decRef(); + } + + ResourceManager::cleanOrphans(true); + + delete client; + client = nullptr; + + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +// VirtFs::deinit(); +} + +TEST_CASE("integrity leak test2", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} diff --git a/src/unittests/render/mockdrawitem.h b/src/unittests/render/mockdrawitem.h new file mode 100644 index 000000000..75951123e --- /dev/null +++ b/src/unittests/render/mockdrawitem.h @@ -0,0 +1,60 @@ +/* + * The ManaPlus Client + * Copyright (C) 2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef RENDER_MOCKDRAWITEM_H +#define RENDER_MOCKDRAWITEM_H + +#ifdef UNITTESTS + +#include "unittests/enums/render/mockdrawtype.h" + +#include "localconsts.h" + +class Image; + +struct MockDrawItem final +{ + MockDrawItem(const MockDrawTypeT type, + const Image *const image0, + const int x0, + const int y0, + const int width0, + const int height0) : + image(image0), + drawType(type), + x(x0), + y(y0), + width(width0), + height(height0) + { + } + + A_DEFAULT_COPY(MockDrawItem) + + const Image *image; + MockDrawTypeT drawType; + int x; + int y; + int width; + int height; +}; + +#endif // UNITTESTS +#endif // RENDER_MOCKDRAWITEM_H diff --git a/src/unittests/render/mockgraphics.cc b/src/unittests/render/mockgraphics.cc new file mode 100644 index 000000000..b484ad4d1 --- /dev/null +++ b/src/unittests/render/mockgraphics.cc @@ -0,0 +1,301 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/render/mockgraphics.h" + +#include "graphicsmanager.h" + +#include "utils/sdlcheckutils.h" + +#include "render/vertexes/imagecollection.h" + +#include "debug.h" + +MockGraphics::MockGraphics() : + Graphics() +{ + mOpenGL = RENDER_SOFTWARE; + mName = "Software"; +} + +MockGraphics::~MockGraphics() +{ +} + +void MockGraphics::drawRescaledImage(const Image *restrict const image + A_UNUSED, + int dstX A_UNUSED, + int dstY A_UNUSED, + const int desiredWidth A_UNUSED, + const int desiredHeight A_UNUSED) + restrict2 +{ +} + +void MockGraphics::drawImage(const Image *restrict const image, + int dstX, + int dstY) restrict2 +{ + mDraws.push_back(MockDrawItem(MockDrawType::DrawImage, + image, + dstX, + dstY, + 0, + 0)); +} + +void MockGraphics::drawImageInline(const Image *restrict const image A_UNUSED, + int dstX A_UNUSED, + int dstY A_UNUSED) restrict2 +{ +} + +void MockGraphics::copyImage(const Image *restrict const image A_UNUSED, + int dstX A_UNUSED, + int dstY A_UNUSED) restrict2 +{ +} + +void MockGraphics::drawImageCached(const Image *restrict const image A_UNUSED, + int x A_UNUSED, + int y A_UNUSED) restrict2 +{ +} + +void MockGraphics::drawPatternCached(const Image *restrict const image + A_UNUSED, + const int x A_UNUSED, + const int y A_UNUSED, + const int w A_UNUSED, + const int h A_UNUSED) restrict2 +{ +} + +void MockGraphics::completeCache() restrict2 +{ +} + +void MockGraphics::drawPattern(const Image *restrict const image, + const int x, + const int y, + const int w, + const int h) restrict2 +{ + mDraws.push_back(MockDrawItem(MockDrawType::DrawPattern, + image, + x, + y, + w, + h)); +} + +void MockGraphics::drawPatternInline(const Image *restrict const image + A_UNUSED, + const int x A_UNUSED, + const int y A_UNUSED, + const int w A_UNUSED, + const int h A_UNUSED) restrict2 +{ +} + +void MockGraphics::drawRescaledPattern(const Image *restrict const image + A_UNUSED, + const int x A_UNUSED, + const int y A_UNUSED, + const int w A_UNUSED, + const int h A_UNUSED, + const int scaledWidth A_UNUSED, + const int scaledHeight A_UNUSED) + restrict2 +{ +} + +void MockGraphics::calcPattern(ImageVertexes *restrict const vert A_UNUSED, + const Image *restrict const image A_UNUSED, + const int x A_UNUSED, + const int y A_UNUSED, + const int w A_UNUSED, + const int h A_UNUSED) const restrict2 +{ +} + +void MockGraphics::calcPatternInline(ImageVertexes *restrict const vert + A_UNUSED, + const Image *restrict const image + A_UNUSED, + const int x A_UNUSED, + const int y A_UNUSED, + const int w A_UNUSED, + const int h A_UNUSED) const restrict2 +{ +} + +void MockGraphics::calcPattern(ImageCollection *restrict const vertCol + A_UNUSED, + const Image *restrict const image A_UNUSED, + const int x A_UNUSED, + const int y A_UNUSED, + const int w A_UNUSED, + const int h A_UNUSED) const restrict2 +{ +} + +void MockGraphics::calcTileVertexes(ImageVertexes *restrict const vert, + const Image *restrict const image, + int x, int y) const restrict2 +{ + vert->image = image; + calcTileSDL(vert, x, y); +} + +void MockGraphics::calcTileVertexesInline(ImageVertexes *restrict const vert + A_UNUSED, + const Image *restrict const image + A_UNUSED, + int x A_UNUSED, + int y A_UNUSED) const restrict2 +{ +} + +void MockGraphics::calcTileSDL(ImageVertexes *restrict const vert A_UNUSED, + int x A_UNUSED, + int y A_UNUSED) const restrict2 +{ +} + +void MockGraphics::calcTileCollection(ImageCollection *restrict const vertCol + A_UNUSED, + const Image *restrict const image + A_UNUSED, + int x A_UNUSED, + int y A_UNUSED) restrict2 +{ +} + +void MockGraphics::drawTileCollection(const ImageCollection *restrict const + vertCol A_UNUSED) restrict2 +{ +} + +void MockGraphics::drawTileVertexes(const ImageVertexes *restrict const + vert A_UNUSED) restrict2 +{ +} + +void MockGraphics::updateScreen() restrict2 +{ +} + +void MockGraphics::calcWindow(ImageCollection *restrict const vertCol A_UNUSED, + const int x A_UNUSED, + const int y A_UNUSED, + const int w A_UNUSED, + const int h A_UNUSED, + const ImageRect &restrict imgRect A_UNUSED) + restrict2 +{ +} + +void MockGraphics::fillRectangle(const Rect &restrict rectangle A_UNUSED) + restrict2 +{ +} + +void MockGraphics::beginDraw() restrict2 +{ + pushClipArea(Rect(0, 0, mRect.w, mRect.h)); +} + +void MockGraphics::endDraw() restrict2 +{ + popClipArea(); +} + +void MockGraphics::pushClipArea(const Rect &restrict area) restrict2 +{ + Graphics::pushClipArea(area); +} + +void MockGraphics::popClipArea() restrict2 +{ + Graphics::popClipArea(); +} + +void MockGraphics::drawPoint(int x A_UNUSED, + int y A_UNUSED) restrict2 +{ +} + +void MockGraphics::drawRectangle(const Rect &restrict rectangle A_UNUSED) + restrict2 +{ +} + +void MockGraphics::drawLine(int x1 A_UNUSED, + int y1 A_UNUSED, + int x2 A_UNUSED, + int y2 A_UNUSED) restrict2 +{ +} + +bool MockGraphics::setVideoMode(const int w, const int h, + const int scale, + const int bpp, + const bool fs, + const bool hwaccel, + const bool resize, + const bool noFrame) restrict2 +{ + setMainFlags(w, h, scale, bpp, fs, hwaccel, resize, noFrame); + + if ((mWindow = graphicsManager.createWindow(w, h, bpp, + getSoftwareFlags())) == nullptr) + { + mRect.w = 0; + mRect.h = 0; + return false; + } + + mRect.w = CAST_U16(mRect.w); + mRect.h = CAST_U16(mRect.h); + + return videoInfo(); +} + +void MockGraphics::drawImageRect(const int x A_UNUSED, + const int y A_UNUSED, + const int w A_UNUSED, + const int h A_UNUSED, + const ImageRect &restrict imgRect A_UNUSED) + restrict2 +{ +} + +void MockGraphics::calcImageRect(ImageVertexes *restrict const vert A_UNUSED, + const int x A_UNUSED, + const int y A_UNUSED, + const int w A_UNUSED, + const int h A_UNUSED, + const ImageRect &restrict imgRect A_UNUSED) + restrict2 +{ +} diff --git a/src/unittests/render/mockgraphics.h b/src/unittests/render/mockgraphics.h new file mode 100644 index 000000000..ccc6d75e6 --- /dev/null +++ b/src/unittests/render/mockgraphics.h @@ -0,0 +1,55 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef RENDER_MOCKGRAPHICS_H +#define RENDER_MOCKGRAPHICS_H + +#ifdef UNITTESTS + +#include "render/graphics.h" + +#include "unittests/render/mockdrawitem.h" + +#include "localconsts.h" + +#include <vector> + +class MockGraphics final : public Graphics +{ + public: + MockGraphics(); + + A_DELETE_COPY(MockGraphics) + + ~MockGraphics(); + + #include "render/graphicsdef.hpp" + RENDER_GRAPHICSDEF_HPP + + #include "render/softwaregraphicsdef.hpp" + RENDER_SOFTWAREGRAPHICSDEF_HPP + + std::vector<MockDrawItem> mDraws; +}; + +#endif // UNITTESTS +#endif // RENDER_MOCKGRAPHICS_H diff --git a/src/unittests/resources/dye/dye_unittest.cc b/src/unittests/resources/dye/dye_unittest.cc new file mode 100644 index 000000000..fcdeb7b17 --- /dev/null +++ b/src/unittests/resources/dye/dye_unittest.cc @@ -0,0 +1,2020 @@ +/* + * The ManaPlus Client + * Copyright (C) 2013-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "client.h" +#include "graphicsmanager.h" +#include "logger.h" + +#include "being/actorsprite.h" + +#include "fs/virtfs/fs.h" + +#include "gui/gui.h" + +#include "resources/sdlimagehelper.h" +#ifdef USE_SDL2 +#include "resources/surfaceimagehelper.h" +#endif // USE_SDL2 + +#include "resources/dye/dye.h" +#include "resources/dye/dyepalette.h" + +#include "resources/image/image.h" + +#include "resources/loaders/imageloader.h" + +#include "resources/resourcemanager/resourcemanager.h" + +#include "utils/delete2.h" +#include "utils/env.h" + +PRAGMA48(GCC diagnostic push) +PRAGMA48(GCC diagnostic ignored "-Wshadow") +#ifndef USE_SDL2 +#include <SDL.h> +#endif // USE_SDL2 +PRAGMA48(GCC diagnostic pop) + +#include "debug.h" + +#ifdef USE_OPENGL + +TEST_CASE("Dye leak test1", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} + +TEST_CASE("Dye replaceSOGLColor 1 1", "") +{ + DyePalette palette("#00ff00,000011", 6); + uint32_t data[1]; + data[0] = buildHex(0x01, 0x02, 0x03, 0x10); + DYEPALETTE(palette, SOGLColor)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x01, 0x02, 0x03, 0x10)); +} + +TEST_CASE("Dye replaceSOGLColor 1 2", "") +{ + DyePalette palette("#01ff02,030411", 6); + uint32_t data[1]; + data[0] = buildHex(0x20, 0x02, 0xff, 0x01); + DYEPALETTE(palette, SOGLColor)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x20, 0x11, 0x04, 0x03)); +} + +TEST_CASE("Dye replaceSOGLColor 1 3", "") +{ + DyePalette palette("#404040,200000,0100ee,102030", 6); + uint32_t data[1]; + data[0] = buildHex(0x40, 0xee, 0x00, 0x01); + DYEPALETTE(palette, SOGLColor)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x40, 0x30, 0x20, 0x10)); +} + +TEST_CASE("Dye replaceSOGLColor 2 1", "") +{ + DyePalette palette("#01ff02,030411", 6); + uint32_t data[2]; + data[0] = buildHex(0x20, 0x02, 0xff, 0x01); + data[1] = buildHex(0x30, 0x02, 0xff, 0x01); + DYEPALETTE(palette, SOGLColor)(&data[0], 2); + REQUIRE(data[0] == buildHex(0x20, 0x11, 0x04, 0x03)); + REQUIRE(data[1] == buildHex(0x30, 0x11, 0x04, 0x03)); +} + +TEST_CASE("Dye replaceSOGLColor 4 1", "") +{ + DyePalette palette("#01ff02,030411", 6); + uint32_t data[4]; + data[0] = buildHex(0x20, 0x02, 0xff, 0x01); + data[1] = buildHex(0x30, 0x02, 0xff, 0x01); + data[2] = buildHex(0x40, 0x02, 0xff, 0x01); + data[3] = buildHex(0x50, 0x02, 0xff, 0x02); + DYEPALETTE(palette, SOGLColor)(&data[0], 4); + REQUIRE(data[0] == buildHex(0x20, 0x11, 0x04, 0x03)); + REQUIRE(data[1] == buildHex(0x30, 0x11, 0x04, 0x03)); + REQUIRE(data[2] == buildHex(0x40, 0x11, 0x04, 0x03)); + REQUIRE(data[3] == buildHex(0x50, 0x02, 0xff, 0x02)); +} + +TEST_CASE("Dye replaceSOGLColor 8 1", "") +{ + DyePalette palette("#01ff02,030411,01ee02,010203", 6); + uint32_t data[8]; + data[0] = buildHex(0x20, 0x02, 0xff, 0x01); + data[1] = buildHex(0x30, 0x02, 0xff, 0x01); + data[2] = buildHex(0x40, 0x02, 0xff, 0x01); + data[3] = buildHex(0x50, 0x02, 0xff, 0x02); + data[4] = buildHex(0x20, 0x02, 0xff, 0x01); + data[5] = buildHex(0x30, 0x02, 0xff, 0x01); + data[6] = buildHex(0x40, 0x02, 0xff, 0x01); + data[7] = buildHex(0x60, 0x02, 0xff, 0x02); + DYEPALETTE(palette, SOGLColor)(&data[0], 8); + REQUIRE(data[0] == buildHex(0x20, 0x11, 0x04, 0x03)); + REQUIRE(data[1] == buildHex(0x30, 0x11, 0x04, 0x03)); + REQUIRE(data[2] == buildHex(0x40, 0x11, 0x04, 0x03)); + REQUIRE(data[3] == buildHex(0x50, 0x02, 0xff, 0x02)); + REQUIRE(data[4] == buildHex(0x20, 0x11, 0x04, 0x03)); + REQUIRE(data[5] == buildHex(0x30, 0x11, 0x04, 0x03)); + REQUIRE(data[6] == buildHex(0x40, 0x11, 0x04, 0x03)); + REQUIRE(data[7] == buildHex(0x60, 0x02, 0xff, 0x02)); +} + +TEST_CASE("Dye replaceSOGLColor 1 1 default", "") +{ + DyePalette palette("#00ff00,000011", 6); + uint32_t data[1]; + data[0] = buildHex(0x01, 0x02, 0x03, 0x10); + palette.replaceSOGLColorDefault(&data[0], 1); + REQUIRE(data[0] == buildHex(0x01, 0x02, 0x03, 0x10)); +} + +TEST_CASE("Dye replaceSOGLColor 1 2 default", "") +{ + DyePalette palette("#01ff02,030411", 6); + uint32_t data[1]; + data[0] = buildHex(0x20, 0x02, 0xff, 0x01); + palette.replaceSOGLColorDefault(&data[0], 1); + REQUIRE(data[0] == buildHex(0x20, 0x11, 0x04, 0x03)); +} + +TEST_CASE("Dye replaceSOGLColor 1 3 default", "") +{ + DyePalette palette("#404040,200000,0100ee,102030", 6); + uint32_t data[1]; + data[0] = buildHex(0x40, 0xee, 0x00, 0x01); + palette.replaceSOGLColorDefault(&data[0], 1); + REQUIRE(data[0] == buildHex(0x40, 0x30, 0x20, 0x10)); +} + +TEST_CASE("Dye replaceSOGLColor 2 1 default", "") +{ + DyePalette palette("#01ff02,030411", 6); + uint32_t data[2]; + data[0] = buildHex(0x20, 0x02, 0xff, 0x01); + data[1] = buildHex(0x30, 0x02, 0xff, 0x01); + palette.replaceSOGLColorDefault(&data[0], 2); + REQUIRE(data[0] == buildHex(0x20, 0x11, 0x04, 0x03)); + REQUIRE(data[1] == buildHex(0x30, 0x11, 0x04, 0x03)); +} + +TEST_CASE("Dye replaceSOGLColor 4 1 default", "") +{ + DyePalette palette("#01ff02,030411", 6); + uint32_t data[4]; + data[0] = buildHex(0x20, 0x02, 0xff, 0x01); + data[1] = buildHex(0x30, 0x02, 0xff, 0x01); + data[2] = buildHex(0x40, 0x02, 0xff, 0x01); + data[3] = buildHex(0x50, 0x02, 0xff, 0x02); + palette.replaceSOGLColorDefault(&data[0], 4); + REQUIRE(data[0] == buildHex(0x20, 0x11, 0x04, 0x03)); + REQUIRE(data[1] == buildHex(0x30, 0x11, 0x04, 0x03)); + REQUIRE(data[2] == buildHex(0x40, 0x11, 0x04, 0x03)); + REQUIRE(data[3] == buildHex(0x50, 0x02, 0xff, 0x02)); +} + +TEST_CASE("Dye replaceSOGLColor 8 1 default", "") +{ + DyePalette palette("#01ff02,030411,01ee02,010203", 6); + uint32_t data[8]; + data[0] = buildHex(0x20, 0x02, 0xff, 0x01); + data[1] = buildHex(0x30, 0x02, 0xff, 0x01); + data[2] = buildHex(0x40, 0x02, 0xff, 0x01); + data[3] = buildHex(0x50, 0x02, 0xff, 0x02); + data[4] = buildHex(0x20, 0x02, 0xff, 0x01); + data[5] = buildHex(0x30, 0x02, 0xff, 0x01); + data[6] = buildHex(0x40, 0x02, 0xff, 0x01); + data[7] = buildHex(0x60, 0x02, 0xff, 0x02); + palette.replaceSOGLColorDefault(&data[0], 8); + REQUIRE(data[0] == buildHex(0x20, 0x11, 0x04, 0x03)); + REQUIRE(data[1] == buildHex(0x30, 0x11, 0x04, 0x03)); + REQUIRE(data[2] == buildHex(0x40, 0x11, 0x04, 0x03)); + REQUIRE(data[3] == buildHex(0x50, 0x02, 0xff, 0x02)); + REQUIRE(data[4] == buildHex(0x20, 0x11, 0x04, 0x03)); + REQUIRE(data[5] == buildHex(0x30, 0x11, 0x04, 0x03)); + REQUIRE(data[6] == buildHex(0x40, 0x11, 0x04, 0x03)); + REQUIRE(data[7] == buildHex(0x60, 0x02, 0xff, 0x02)); +} + +TEST_CASE("Dye replaceSOGLColor 8 1 sse2", "") +{ + DyePalette palette("#01ff02,030411,01ee02,010203", 6); + uint32_t data[8]; + data[0] = buildHex(0x20, 0x02, 0xff, 0x01); + data[1] = buildHex(0x30, 0x02, 0xff, 0x01); + data[2] = buildHex(0x40, 0x02, 0xff, 0x01); + data[3] = buildHex(0x50, 0x02, 0xff, 0x02); + data[4] = buildHex(0x20, 0x02, 0xff, 0x01); + data[5] = buildHex(0x30, 0x02, 0xff, 0x01); + data[6] = buildHex(0x40, 0x02, 0xff, 0x01); + data[7] = buildHex(0x60, 0x02, 0xff, 0x02); + DYEPALETTE(palette, SOGLColorSse2)(&data[0], 8); + REQUIRE(data[0] == buildHex(0x20, 0x11, 0x04, 0x03)); + REQUIRE(data[1] == buildHex(0x30, 0x11, 0x04, 0x03)); + REQUIRE(data[2] == buildHex(0x40, 0x11, 0x04, 0x03)); + REQUIRE(data[3] == buildHex(0x50, 0x02, 0xff, 0x02)); + REQUIRE(data[4] == buildHex(0x20, 0x11, 0x04, 0x03)); + REQUIRE(data[5] == buildHex(0x30, 0x11, 0x04, 0x03)); + REQUIRE(data[6] == buildHex(0x40, 0x11, 0x04, 0x03)); + REQUIRE(data[7] == buildHex(0x60, 0x02, 0xff, 0x02)); +} + +TEST_CASE("Dye replaceSOGLColor 8 1 avx2", "") +{ + DyePalette palette("#01ff02,030411,01ee02,010203", 6); + uint32_t data[8]; + data[0] = buildHex(0x20, 0x02, 0xff, 0x01); + data[1] = buildHex(0x30, 0x02, 0xff, 0x01); + data[2] = buildHex(0x40, 0x02, 0xff, 0x01); + data[3] = buildHex(0x50, 0x02, 0xff, 0x02); + data[4] = buildHex(0x20, 0x02, 0xff, 0x01); + data[5] = buildHex(0x30, 0x02, 0xff, 0x01); + data[6] = buildHex(0x40, 0x02, 0xff, 0x01); + data[7] = buildHex(0x60, 0x02, 0xff, 0x02); + DYEPALETTE(palette, SOGLColorAvx2)(&data[0], 8); + REQUIRE(data[0] == buildHex(0x20, 0x11, 0x04, 0x03)); + REQUIRE(data[1] == buildHex(0x30, 0x11, 0x04, 0x03)); + REQUIRE(data[2] == buildHex(0x40, 0x11, 0x04, 0x03)); + REQUIRE(data[3] == buildHex(0x50, 0x02, 0xff, 0x02)); + REQUIRE(data[4] == buildHex(0x20, 0x11, 0x04, 0x03)); + REQUIRE(data[5] == buildHex(0x30, 0x11, 0x04, 0x03)); + REQUIRE(data[6] == buildHex(0x40, 0x11, 0x04, 0x03)); + REQUIRE(data[7] == buildHex(0x60, 0x02, 0xff, 0x02)); +} + + +TEST_CASE("Dye replaceAOGLColor 1 1", "") +{ + DyePalette palette("#00ff0010,00001120", 8); + uint32_t data[1]; + data[0] = buildHex(0x10, 0x03, 0x02, 0x01); + DYEPALETTE(palette, AOGLColor)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x10, 0x03, 0x02, 0x01)); +} + +TEST_CASE("Dye replaceAOGLColor 1 2", "") +{ + DyePalette palette("#00ff0120,020311ff", 8); + uint32_t data[1]; + data[0] = buildHex(0x20, 0x01, 0xff, 0x00); + DYEPALETTE(palette, AOGLColor)(&data[0], 1); + REQUIRE(data[0] == buildHex(0xff, 0x11, 0x03, 0x02)); +} + +TEST_CASE("Dye replaceAOGLColor 1 3", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[1]; + data[0] = buildHex(0x40, 0xee, 0x00, 0x01); + DYEPALETTE(palette, AOGLColor)(&data[0], 1); + REQUIRE(data[0] == buildHex(0xff, 0x30, 0x20, 0x10)); +} + +TEST_CASE("Dye replaceAOGLColor 2 1", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[2]; + data[0] = buildHex(0x40, 0xee, 0x00, 0x01); + data[1] = buildHex(0x40, 0xee, 0x00, 0x01); + DYEPALETTE(palette, AOGLColor)(&data[0], 2); + REQUIRE(data[0] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[1] == buildHex(0xff, 0x30, 0x20, 0x10)); +} + +TEST_CASE("Dye replaceAOGLColor 4 1", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[4]; + data[0] = buildHex(0x40, 0xee, 0x00, 0x01); + data[1] = buildHex(0x40, 0xee, 0x00, 0x01); + data[2] = buildHex(0x41, 0xee, 0x00, 0x01); + data[3] = buildHex(0x40, 0xee, 0x00, 0x01); + DYEPALETTE(palette, AOGLColor)(&data[0], 4); + REQUIRE(data[0] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[1] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[2] == buildHex(0x41, 0xee, 0x00, 0x01)); + REQUIRE(data[3] == buildHex(0xff, 0x30, 0x20, 0x10)); +} + +TEST_CASE("Dye replaceAOGLColor 8 1", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[8]; + data[0] = buildHex(0x40, 0xee, 0x00, 0x01); + data[1] = buildHex(0x40, 0xee, 0x00, 0x01); + data[2] = buildHex(0x41, 0xee, 0x00, 0x01); + data[3] = buildHex(0x40, 0xee, 0x00, 0x01); + data[4] = buildHex(0x40, 0xee, 0x00, 0x01); + data[5] = buildHex(0x40, 0x40, 0x40, 0x40); + data[6] = buildHex(0x41, 0xe0, 0x00, 0x01); + data[7] = buildHex(0x40, 0xee, 0x00, 0x01); + DYEPALETTE(palette, AOGLColor)(&data[0], 8); + REQUIRE(data[0] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[1] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[2] == buildHex(0x41, 0xee, 0x00, 0x01)); + REQUIRE(data[3] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[4] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[5] == buildHex(0x00, 0x00, 0x00, 0x20)); + REQUIRE(data[6] == buildHex(0x41, 0xe0, 0x00, 0x01)); + REQUIRE(data[7] == buildHex(0xff, 0x30, 0x20, 0x10)); +} + +TEST_CASE("Dye replaceAOGLColor 1 1 default", "") +{ + DyePalette palette("#00ff0010,00001120", 8); + uint32_t data[1]; + data[0] = buildHex(0x10, 0x03, 0x02, 0x01); + palette.replaceAOGLColorDefault(&data[0], 1); + REQUIRE(data[0] == buildHex(0x10, 0x03, 0x02, 0x01)); +} + +TEST_CASE("Dye replaceAOGLColor 1 2 default", "") +{ + DyePalette palette("#00ff0120,020311ff", 8); + uint32_t data[1]; + data[0] = buildHex(0x20, 0x01, 0xff, 0x00); + palette.replaceAOGLColorDefault(&data[0], 1); + REQUIRE(data[0] == buildHex(0xff, 0x11, 0x03, 0x02)); +} + +TEST_CASE("Dye replaceAOGLColor 1 3 default", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[1]; + data[0] = buildHex(0x40, 0xee, 0x00, 0x01); + palette.replaceAOGLColorDefault(&data[0], 1); + REQUIRE(data[0] == buildHex(0xff, 0x30, 0x20, 0x10)); +} + +TEST_CASE("Dye replaceAOGLColor 2 1 default", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[2]; + data[0] = buildHex(0x40, 0xee, 0x00, 0x01); + data[1] = buildHex(0x40, 0xee, 0x00, 0x01); + palette.replaceAOGLColorDefault(&data[0], 2); + REQUIRE(data[0] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[1] == buildHex(0xff, 0x30, 0x20, 0x10)); +} + +TEST_CASE("Dye replaceAOGLColor 4 1 default", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[4]; + data[0] = buildHex(0x40, 0xee, 0x00, 0x01); + data[1] = buildHex(0x40, 0xee, 0x00, 0x01); + data[2] = buildHex(0x41, 0xee, 0x00, 0x01); + data[3] = buildHex(0x40, 0xee, 0x00, 0x01); + palette.replaceAOGLColorDefault(&data[0], 4); + REQUIRE(data[0] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[1] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[2] == buildHex(0x41, 0xee, 0x00, 0x01)); + REQUIRE(data[3] == buildHex(0xff, 0x30, 0x20, 0x10)); +} + +TEST_CASE("Dye replaceAOGLColor 8 1 default", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[8]; + data[0] = buildHex(0x40, 0xee, 0x00, 0x01); + data[1] = buildHex(0x40, 0xee, 0x00, 0x01); + data[2] = buildHex(0x41, 0xee, 0x00, 0x01); + data[3] = buildHex(0x40, 0xee, 0x00, 0x01); + data[4] = buildHex(0x40, 0xee, 0x00, 0x01); + data[5] = buildHex(0x40, 0x40, 0x40, 0x40); + data[6] = buildHex(0x41, 0xe0, 0x00, 0x01); + data[7] = buildHex(0x40, 0xee, 0x00, 0x01); + palette.replaceAOGLColorDefault(&data[0], 8); + REQUIRE(data[0] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[1] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[2] == buildHex(0x41, 0xee, 0x00, 0x01)); + REQUIRE(data[3] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[4] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[5] == buildHex(0x00, 0x00, 0x00, 0x20)); + REQUIRE(data[6] == buildHex(0x41, 0xe0, 0x00, 0x01)); + REQUIRE(data[7] == buildHex(0xff, 0x30, 0x20, 0x10)); +} + +TEST_CASE("Dye replaceAOGLColor 8 1 sse2", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[8]; + data[0] = buildHex(0x40, 0xee, 0x00, 0x01); + data[1] = buildHex(0x40, 0xee, 0x00, 0x01); + data[2] = buildHex(0x41, 0xee, 0x00, 0x01); + data[3] = buildHex(0x40, 0xee, 0x00, 0x01); + data[4] = buildHex(0x40, 0xee, 0x00, 0x01); + data[5] = buildHex(0x40, 0x40, 0x40, 0x40); + data[6] = buildHex(0x41, 0xe0, 0x00, 0x01); + data[7] = buildHex(0x40, 0xee, 0x00, 0x01); + DYEPALETTE(palette, AOGLColorSse2)(&data[0], 8); + REQUIRE(data[0] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[1] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[2] == buildHex(0x41, 0xee, 0x00, 0x01)); + REQUIRE(data[3] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[4] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[5] == buildHex(0x00, 0x00, 0x00, 0x20)); + REQUIRE(data[6] == buildHex(0x41, 0xe0, 0x00, 0x01)); + REQUIRE(data[7] == buildHex(0xff, 0x30, 0x20, 0x10)); +} + +TEST_CASE("Dye replaceAOGLColor 8 1 avx2", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[8]; + data[0] = buildHex(0x40, 0xee, 0x00, 0x01); + data[1] = buildHex(0x40, 0xee, 0x00, 0x01); + data[2] = buildHex(0x41, 0xee, 0x00, 0x01); + data[3] = buildHex(0x40, 0xee, 0x00, 0x01); + data[4] = buildHex(0x40, 0xee, 0x00, 0x01); + data[5] = buildHex(0x40, 0x40, 0x40, 0x40); + data[6] = buildHex(0x41, 0xe0, 0x00, 0x01); + data[7] = buildHex(0x40, 0xee, 0x00, 0x01); + DYEPALETTE(palette, AOGLColorAvx2)(&data[0], 8); + REQUIRE(data[0] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[1] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[2] == buildHex(0x41, 0xee, 0x00, 0x01)); + REQUIRE(data[3] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[4] == buildHex(0xff, 0x30, 0x20, 0x10)); + REQUIRE(data[5] == buildHex(0x00, 0x00, 0x00, 0x20)); + REQUIRE(data[6] == buildHex(0x41, 0xe0, 0x00, 0x01)); + REQUIRE(data[7] == buildHex(0xff, 0x30, 0x20, 0x10)); +} +#endif // USE_OPENGL + + +TEST_CASE("Dye replaceSColor 1 1", "") +{ + DyePalette palette("#00ff00,000011", 6); + uint32_t data[1]; + data[0] = buildHex(0x10, 0x03, 0x02, 0x01); + DYEPALETTE(palette, SColor)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x10, 0x03, 0x02, 0x01)); +} + +TEST_CASE("Dye replaceSColor 1 2", "") +{ + DyePalette palette("#403020,706050", 6); + uint32_t data[1]; + data[0] = buildHex(0x40, 0x30, 0x20, 0x10); + DYEPALETTE(palette, SColor)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); +} + +TEST_CASE("Dye replaceSColor 1 3", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[1]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + DYEPALETTE(palette, SColor)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); +} + +TEST_CASE("Dye replaceSColor 2 1", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[2]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + DYEPALETTE(palette, SColor)(&data[0], 2); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); +} + +TEST_CASE("Dye replaceSColor 3 1", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[3]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x30, 0x20, 0x30); + DYEPALETTE(palette, SColor)(&data[0], 3); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0x70, 0x60, 0x50, 0x30)); +} + +TEST_CASE("Dye replaceSColor 4 1", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[4]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x20); + DYEPALETTE(palette, SColor)(&data[0], 4); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x20)); +} + +TEST_CASE("Dye replaceSColor 5 1", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[5]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x30); + data[4] = buildHex(0xff, 0x30, 0x20, 0x20); + DYEPALETTE(palette, SColor)(&data[0], 5); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x30)); + REQUIRE(data[4] == buildHex(0x70, 0x60, 0x50, 0x20)); +} + +TEST_CASE("Dye replaceSColor 7 1", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[7]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x20); + data[4] = buildHex(0xff, 0x30, 0x20, 0x10); + data[5] = buildHex(0xff, 0x30, 0x20, 0x40); + data[6] = buildHex(0xff, 0x40, 0x20, 0x50); + DYEPALETTE(palette, SColor)(&data[0], 7); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[4] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[5] == buildHex(0x70, 0x60, 0x50, 0x40)); + REQUIRE(data[6] == buildHex(0xff, 0x40, 0x20, 0x50)); +} + +TEST_CASE("Dye replaceSColor 8 1", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[8]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x20); + data[4] = buildHex(0xff, 0x30, 0x20, 0x10); + data[5] = buildHex(0xff, 0x30, 0x20, 0x40); + data[6] = buildHex(0xff, 0x40, 0x20, 0x50); + data[7] = buildHex(0xff, 0x30, 0x20, 0x60); + DYEPALETTE(palette, SColor)(&data[0], 8); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[4] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[5] == buildHex(0x70, 0x60, 0x50, 0x40)); + REQUIRE(data[6] == buildHex(0xff, 0x40, 0x20, 0x50)); + REQUIRE(data[7] == buildHex(0x70, 0x60, 0x50, 0x60)); +} + +TEST_CASE("Dye replaceSColor 9 1", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[9]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x20); + data[4] = buildHex(0xff, 0x30, 0x20, 0x10); + data[5] = buildHex(0xff, 0x30, 0x20, 0x40); + data[6] = buildHex(0xff, 0x40, 0x20, 0x50); + data[7] = buildHex(0xff, 0x30, 0x20, 0x60); + data[8] = buildHex(0xff, 0x30, 0x20, 0x70); + DYEPALETTE(palette, SColor)(&data[0], 9); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[4] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[5] == buildHex(0x70, 0x60, 0x50, 0x40)); + REQUIRE(data[6] == buildHex(0xff, 0x40, 0x20, 0x50)); + REQUIRE(data[7] == buildHex(0x70, 0x60, 0x50, 0x60)); + REQUIRE(data[8] == buildHex(0x70, 0x60, 0x50, 0x70)); +} + +TEST_CASE("Dye replaceSColor 10 1", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[10]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x20); + data[4] = buildHex(0xff, 0x30, 0x20, 0x10); + data[5] = buildHex(0xff, 0x30, 0x20, 0x40); + data[6] = buildHex(0xff, 0x40, 0x20, 0x50); + data[7] = buildHex(0xff, 0x30, 0x20, 0x60); + data[8] = buildHex(0x12, 0x34, 0x56, 0x70); + data[9] = buildHex(0xff, 0x30, 0x20, 0x80); + DYEPALETTE(palette, SColor)(&data[0], 10); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[4] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[5] == buildHex(0x70, 0x60, 0x50, 0x40)); + REQUIRE(data[6] == buildHex(0xff, 0x40, 0x20, 0x50)); + REQUIRE(data[7] == buildHex(0x70, 0x60, 0x50, 0x60)); + REQUIRE(data[8] == buildHex(0x00, 0x00, 0x00, 0x70)); + REQUIRE(data[9] == buildHex(0x70, 0x60, 0x50, 0x80)); +} + +TEST_CASE("Dye replaceSColor 1 1 default", "") +{ + DyePalette palette("#00ff00,000011", 6); + uint32_t data[1]; + data[0] = buildHex(0x10, 0x03, 0x02, 0x01); + palette.replaceSColorDefault(&data[0], 1); + REQUIRE(data[0] == buildHex(0x10, 0x03, 0x02, 0x01)); +} + +TEST_CASE("Dye replaceSColor 1 2 default", "") +{ + DyePalette palette("#403020,706050", 6); + uint32_t data[1]; + data[0] = buildHex(0x40, 0x30, 0x20, 0x10); + palette.replaceSColorDefault(&data[0], 1); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); +} + +TEST_CASE("Dye replaceSColor 1 3 default", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[1]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + palette.replaceSColorDefault(&data[0], 1); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); +} + +TEST_CASE("Dye replaceSColor 2 1 default", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[2]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + palette.replaceSColorDefault(&data[0], 2); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); +} + +TEST_CASE("Dye replaceSColor 3 1 default", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[3]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x30, 0x20, 0x30); + palette.replaceSColorDefault(&data[0], 3); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0x70, 0x60, 0x50, 0x30)); +} + +TEST_CASE("Dye replaceSColor 4 1 default", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[4]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x20); + palette.replaceSColorDefault(&data[0], 4); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x20)); +} + +TEST_CASE("Dye replaceSColor 5 1 default", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[5]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x30); + data[4] = buildHex(0xff, 0x30, 0x20, 0x20); + palette.replaceSColorDefault(&data[0], 5); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x30)); + REQUIRE(data[4] == buildHex(0x70, 0x60, 0x50, 0x20)); +} + +TEST_CASE("Dye replaceSColor 7 1 default", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[7]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x20); + data[4] = buildHex(0xff, 0x30, 0x20, 0x10); + data[5] = buildHex(0xff, 0x30, 0x20, 0x40); + data[6] = buildHex(0xff, 0x40, 0x20, 0x50); + palette.replaceSColorDefault(&data[0], 7); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[4] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[5] == buildHex(0x70, 0x60, 0x50, 0x40)); + REQUIRE(data[6] == buildHex(0xff, 0x40, 0x20, 0x50)); +} + +TEST_CASE("Dye replaceSColor 8 1 default", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[8]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x20); + data[4] = buildHex(0xff, 0x30, 0x20, 0x10); + data[5] = buildHex(0xff, 0x30, 0x20, 0x40); + data[6] = buildHex(0xff, 0x40, 0x20, 0x50); + data[7] = buildHex(0xff, 0x30, 0x20, 0x60); + palette.replaceSColorDefault(&data[0], 8); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[4] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[5] == buildHex(0x70, 0x60, 0x50, 0x40)); + REQUIRE(data[6] == buildHex(0xff, 0x40, 0x20, 0x50)); + REQUIRE(data[7] == buildHex(0x70, 0x60, 0x50, 0x60)); +} + +TEST_CASE("Dye replaceSColor 9 1 default", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[9]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x20); + data[4] = buildHex(0xff, 0x30, 0x20, 0x10); + data[5] = buildHex(0xff, 0x30, 0x20, 0x40); + data[6] = buildHex(0xff, 0x40, 0x20, 0x50); + data[7] = buildHex(0xff, 0x30, 0x20, 0x60); + data[8] = buildHex(0xff, 0x30, 0x20, 0x70); + palette.replaceSColorDefault(&data[0], 9); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[4] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[5] == buildHex(0x70, 0x60, 0x50, 0x40)); + REQUIRE(data[6] == buildHex(0xff, 0x40, 0x20, 0x50)); + REQUIRE(data[7] == buildHex(0x70, 0x60, 0x50, 0x60)); + REQUIRE(data[8] == buildHex(0x70, 0x60, 0x50, 0x70)); +} + +TEST_CASE("Dye replaceSColor 10 1 default", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[10]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x20); + data[4] = buildHex(0xff, 0x30, 0x20, 0x10); + data[5] = buildHex(0xff, 0x30, 0x20, 0x40); + data[6] = buildHex(0xff, 0x40, 0x20, 0x50); + data[7] = buildHex(0xff, 0x30, 0x20, 0x60); + data[8] = buildHex(0x12, 0x34, 0x56, 0x70); + data[9] = buildHex(0xff, 0x30, 0x20, 0x80); + palette.replaceSColorDefault(&data[0], 10); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[4] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[5] == buildHex(0x70, 0x60, 0x50, 0x40)); + REQUIRE(data[6] == buildHex(0xff, 0x40, 0x20, 0x50)); + REQUIRE(data[7] == buildHex(0x70, 0x60, 0x50, 0x60)); + REQUIRE(data[8] == buildHex(0x00, 0x00, 0x00, 0x70)); + REQUIRE(data[9] == buildHex(0x70, 0x60, 0x50, 0x80)); +} + +TEST_CASE("Dye replaceSColor 1 1 sse2", "") +{ + DyePalette palette("#00ff00,000011", 6); + uint32_t data[1]; + data[0] = buildHex(0x10, 0x03, 0x02, 0x01); + DYEPALETTE(palette, SColorSse2)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x10, 0x03, 0x02, 0x01)); +} + +TEST_CASE("Dye replaceSColor 1 2 sse2", "") +{ + DyePalette palette("#403020,706050", 6); + uint32_t data[1]; + data[0] = buildHex(0x40, 0x30, 0x20, 0x10); + DYEPALETTE(palette, SColorSse2)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); +} + +TEST_CASE("Dye replaceSColor 1 3 sse2", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[1]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + DYEPALETTE(palette, SColorSse2)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); +} + +TEST_CASE("Dye replaceSColor 2 1 sse2", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[2]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + DYEPALETTE(palette, SColorSse2)(&data[0], 2); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); +} + +TEST_CASE("Dye replaceSColor 3 1 sse2", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[3]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x30, 0x20, 0x30); + DYEPALETTE(palette, SColorSse2)(&data[0], 3); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0x70, 0x60, 0x50, 0x30)); +} + +TEST_CASE("Dye replaceSColor 4 1 sse2", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[4]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x20); + DYEPALETTE(palette, SColorSse2)(&data[0], 4); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x20)); +} + +TEST_CASE("Dye replaceSColor 5 1 sse2", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[5]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x30); + data[4] = buildHex(0xff, 0x30, 0x20, 0x20); + DYEPALETTE(palette, SColorSse2)(&data[0], 5); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x30)); + REQUIRE(data[4] == buildHex(0x70, 0x60, 0x50, 0x20)); +} + +TEST_CASE("Dye replaceSColor 7 1 sse2", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[7]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x20); + data[4] = buildHex(0xff, 0x30, 0x20, 0x10); + data[5] = buildHex(0xff, 0x30, 0x20, 0x40); + data[6] = buildHex(0xff, 0x40, 0x20, 0x50); + DYEPALETTE(palette, SColorSse2)(&data[0], 7); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[4] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[5] == buildHex(0x70, 0x60, 0x50, 0x40)); + REQUIRE(data[6] == buildHex(0xff, 0x40, 0x20, 0x50)); +} + +TEST_CASE("Dye replaceSColor 8 1 sse2", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[8]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x20); + data[4] = buildHex(0xff, 0x30, 0x20, 0x10); + data[5] = buildHex(0xff, 0x30, 0x20, 0x40); + data[6] = buildHex(0xff, 0x40, 0x20, 0x50); + data[7] = buildHex(0xff, 0x30, 0x20, 0x60); + DYEPALETTE(palette, SColorSse2)(&data[0], 8); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[4] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[5] == buildHex(0x70, 0x60, 0x50, 0x40)); + REQUIRE(data[6] == buildHex(0xff, 0x40, 0x20, 0x50)); + REQUIRE(data[7] == buildHex(0x70, 0x60, 0x50, 0x60)); +} + +TEST_CASE("Dye replaceSColor 9 1 sse2", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[9]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x20); + data[4] = buildHex(0xff, 0x30, 0x20, 0x10); + data[5] = buildHex(0xff, 0x30, 0x20, 0x40); + data[6] = buildHex(0xff, 0x40, 0x20, 0x50); + data[7] = buildHex(0xff, 0x30, 0x20, 0x60); + data[8] = buildHex(0xff, 0x30, 0x20, 0x70); + DYEPALETTE(palette, SColorSse2)(&data[0], 9); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[4] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[5] == buildHex(0x70, 0x60, 0x50, 0x40)); + REQUIRE(data[6] == buildHex(0xff, 0x40, 0x20, 0x50)); + REQUIRE(data[7] == buildHex(0x70, 0x60, 0x50, 0x60)); + REQUIRE(data[8] == buildHex(0x70, 0x60, 0x50, 0x70)); +} + +TEST_CASE("Dye replaceSColor 10 1 sse2", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[10]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x20); + data[4] = buildHex(0xff, 0x30, 0x20, 0x10); + data[5] = buildHex(0xff, 0x30, 0x20, 0x40); + data[6] = buildHex(0xff, 0x40, 0x20, 0x50); + data[7] = buildHex(0xff, 0x30, 0x20, 0x60); + data[8] = buildHex(0x12, 0x34, 0x56, 0x70); + data[9] = buildHex(0xff, 0x30, 0x20, 0x80); + DYEPALETTE(palette, SColorSse2)(&data[0], 10); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[4] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[5] == buildHex(0x70, 0x60, 0x50, 0x40)); + REQUIRE(data[6] == buildHex(0xff, 0x40, 0x20, 0x50)); + REQUIRE(data[7] == buildHex(0x70, 0x60, 0x50, 0x60)); + REQUIRE(data[8] == buildHex(0x00, 0x00, 0x00, 0x70)); + REQUIRE(data[9] == buildHex(0x70, 0x60, 0x50, 0x80)); +} + +TEST_CASE("Dye replaceSColor 1 1 avx2", "") +{ + DyePalette palette("#00ff00,000011", 6); + uint32_t data[1]; + data[0] = buildHex(0x10, 0x03, 0x02, 0x01); + DYEPALETTE(palette, SColorAvx2)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x10, 0x03, 0x02, 0x01)); +} + +TEST_CASE("Dye replaceSColor 1 2 avx2", "") +{ + DyePalette palette("#403020,706050", 6); + uint32_t data[1]; + data[0] = buildHex(0x40, 0x30, 0x20, 0x10); + DYEPALETTE(palette, SColorAvx2)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); +} + +TEST_CASE("Dye replaceSColor 1 3 avx2", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[1]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + DYEPALETTE(palette, SColorAvx2)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); +} + +TEST_CASE("Dye replaceSColor 2 1 avx2", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[2]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + DYEPALETTE(palette, SColorAvx2)(&data[0], 2); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); +} + +TEST_CASE("Dye replaceSColor 3 1 avx2", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[3]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x30, 0x20, 0x30); + DYEPALETTE(palette, SColorAvx2)(&data[0], 3); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0x70, 0x60, 0x50, 0x30)); +} + +TEST_CASE("Dye replaceSColor 4 1 avx2", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[4]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x20); + DYEPALETTE(palette, SColorAvx2)(&data[0], 4); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x20)); +} + +TEST_CASE("Dye replaceSColor 5 1 avx2", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[5]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x30); + data[4] = buildHex(0xff, 0x30, 0x20, 0x20); + DYEPALETTE(palette, SColorAvx2)(&data[0], 5); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x30)); + REQUIRE(data[4] == buildHex(0x70, 0x60, 0x50, 0x20)); +} + +TEST_CASE("Dye replaceSColor 7 1 avx2", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[7]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x20); + data[4] = buildHex(0xff, 0x30, 0x20, 0x10); + data[5] = buildHex(0xff, 0x30, 0x20, 0x40); + data[6] = buildHex(0xff, 0x40, 0x20, 0x50); + DYEPALETTE(palette, SColorAvx2)(&data[0], 7); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[4] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[5] == buildHex(0x70, 0x60, 0x50, 0x40)); + REQUIRE(data[6] == buildHex(0xff, 0x40, 0x20, 0x50)); +} + +TEST_CASE("Dye replaceSColor 8 1 avx2", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[8]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x20); + data[4] = buildHex(0xff, 0x30, 0x20, 0x10); + data[5] = buildHex(0xff, 0x30, 0x20, 0x40); + data[6] = buildHex(0xff, 0x40, 0x20, 0x50); + data[7] = buildHex(0xff, 0x30, 0x20, 0x60); + DYEPALETTE(palette, SColorAvx2)(&data[0], 8); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[4] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[5] == buildHex(0x70, 0x60, 0x50, 0x40)); + REQUIRE(data[6] == buildHex(0xff, 0x40, 0x20, 0x50)); + REQUIRE(data[7] == buildHex(0x70, 0x60, 0x50, 0x60)); +} + +TEST_CASE("Dye replaceSColor 9 1 avx2", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[9]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x20); + data[4] = buildHex(0xff, 0x30, 0x20, 0x10); + data[5] = buildHex(0xff, 0x30, 0x20, 0x40); + data[6] = buildHex(0xff, 0x40, 0x20, 0x50); + data[7] = buildHex(0xff, 0x30, 0x20, 0x60); + data[8] = buildHex(0xff, 0x30, 0x20, 0x70); + DYEPALETTE(palette, SColorAvx2)(&data[0], 9); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[4] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[5] == buildHex(0x70, 0x60, 0x50, 0x40)); + REQUIRE(data[6] == buildHex(0xff, 0x40, 0x20, 0x50)); + REQUIRE(data[7] == buildHex(0x70, 0x60, 0x50, 0x60)); + REQUIRE(data[8] == buildHex(0x70, 0x60, 0x50, 0x70)); +} + +TEST_CASE("Dye replaceSColor 10 1 avx2", "") +{ + DyePalette palette("#123456,000000,ff3020,706050", 6); + uint32_t data[10]; + data[0] = buildHex(0xff, 0x30, 0x20, 0x10); + data[1] = buildHex(0xff, 0x30, 0x20, 0x20); + data[2] = buildHex(0xff, 0x40, 0x20, 0x10); + data[3] = buildHex(0xff, 0x30, 0x20, 0x20); + data[4] = buildHex(0xff, 0x30, 0x20, 0x10); + data[5] = buildHex(0xff, 0x30, 0x20, 0x40); + data[6] = buildHex(0xff, 0x40, 0x20, 0x50); + data[7] = buildHex(0xff, 0x30, 0x20, 0x60); + data[8] = buildHex(0x12, 0x34, 0x56, 0x70); + data[9] = buildHex(0xff, 0x30, 0x20, 0x80); + DYEPALETTE(palette, SColorAvx2)(&data[0], 10); + REQUIRE(data[0] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[1] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[2] == buildHex(0xff, 0x40, 0x20, 0x10)); + REQUIRE(data[3] == buildHex(0x70, 0x60, 0x50, 0x20)); + REQUIRE(data[4] == buildHex(0x70, 0x60, 0x50, 0x10)); + REQUIRE(data[5] == buildHex(0x70, 0x60, 0x50, 0x40)); + REQUIRE(data[6] == buildHex(0xff, 0x40, 0x20, 0x50)); + REQUIRE(data[7] == buildHex(0x70, 0x60, 0x50, 0x60)); + REQUIRE(data[8] == buildHex(0x00, 0x00, 0x00, 0x70)); + REQUIRE(data[9] == buildHex(0x70, 0x60, 0x50, 0x80)); +} + + +TEST_CASE("Dye replaceAColor 1 1", "") +{ + DyePalette palette("#00ff0010,00001120", 8); + uint32_t data[1]; + data[0] = buildHex(0x10, 0x03, 0x02, 0x01); + DYEPALETTE(palette, AColor)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x10, 0x03, 0x02, 0x01)); +} + +TEST_CASE("Dye replaceAColor 1 2", "") +{ + DyePalette palette("#02ff0120,040311ff", 8); + uint32_t data[1]; + data[0] = buildHex(0x02, 0xff, 0x01, 0x20); + DYEPALETTE(palette, AColor)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x04, 0x03, 0x11, 0xff)); +} + +TEST_CASE("Dye replaceAColor 1 3", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[1]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + DYEPALETTE(palette, AColor)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); +} + +TEST_CASE("Dye replaceAColor 2 1", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[2]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + DYEPALETTE(palette, AColor)(&data[0], 2); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 3 1", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[3]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x50, 0x40, 0x40, 0x30); + data[2] = buildHex(0x40, 0x40, 0x40, 0x40); + DYEPALETTE(palette, AColor)(&data[0], 3); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x50, 0x40, 0x40, 0x30)); + REQUIRE(data[2] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 4 1", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[4]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x40, 0x40, 0x40, 0x40); + DYEPALETTE(palette, AColor)(&data[0], 4); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 5 1", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[5]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x50, 0x40, 0x40, 0x60); + data[4] = buildHex(0x40, 0x40, 0x40, 0x40); + DYEPALETTE(palette, AColor)(&data[0], 5); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x50, 0x40, 0x40, 0x60)); + REQUIRE(data[4] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 7 1", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[7]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x40, 0x40, 0x40, 0x40); + data[4] = buildHex(0x01, 0x00, 0xee, 0x40); + data[5] = buildHex(0x40, 0x40, 0x41, 0x40); + data[6] = buildHex(0x01, 0x00, 0xee, 0x50); + DYEPALETTE(palette, AColor)(&data[0], 7); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[4] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[5] == buildHex(0x40, 0x40, 0x41, 0x40)); + REQUIRE(data[6] == buildHex(0x01, 0x00, 0xee, 0x50)); +} + +TEST_CASE("Dye replaceAColor 8 1", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[8]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x40, 0x40, 0x40, 0x40); + data[4] = buildHex(0x01, 0x00, 0xee, 0x40); + data[5] = buildHex(0x40, 0x40, 0x41, 0x40); + data[6] = buildHex(0x01, 0x00, 0xee, 0x50); + data[7] = buildHex(0x40, 0x40, 0x40, 0x40); + DYEPALETTE(palette, AColor)(&data[0], 8); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[4] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[5] == buildHex(0x40, 0x40, 0x41, 0x40)); + REQUIRE(data[6] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[7] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 9 1", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[9]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x40, 0x40, 0x40, 0x40); + data[4] = buildHex(0x01, 0x00, 0xee, 0x40); + data[5] = buildHex(0x40, 0x40, 0x41, 0x40); + data[6] = buildHex(0x01, 0x00, 0xee, 0x50); + data[7] = buildHex(0x02, 0x40, 0x40, 0x40); + data[8] = buildHex(0x40, 0x40, 0x40, 0x40); + DYEPALETTE(palette, AColor)(&data[0], 9); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[4] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[5] == buildHex(0x40, 0x40, 0x41, 0x40)); + REQUIRE(data[6] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[7] == buildHex(0x02, 0x40, 0x40, 0x40)); + REQUIRE(data[8] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 10 1", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[10]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x40, 0x40, 0x40, 0x40); + data[4] = buildHex(0x01, 0x00, 0xee, 0x40); + data[5] = buildHex(0x40, 0x40, 0x41, 0x40); + data[6] = buildHex(0x01, 0x00, 0xee, 0x50); + data[7] = buildHex(0x02, 0x40, 0x40, 0x40); + data[8] = buildHex(0x40, 0x40, 0x40, 0x40); + data[9] = buildHex(0x01, 0x00, 0xee, 0x40); + DYEPALETTE(palette, AColor)(&data[0], 10); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[4] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[5] == buildHex(0x40, 0x40, 0x41, 0x40)); + REQUIRE(data[6] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[7] == buildHex(0x02, 0x40, 0x40, 0x40)); + REQUIRE(data[8] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[9] == buildHex(0x10, 0x20, 0x30, 0xff)); +} + +TEST_CASE("Dye replaceAColor 1 1 default", "") +{ + DyePalette palette("#00ff0010,00001120", 8); + uint32_t data[1]; + data[0] = buildHex(0x10, 0x03, 0x02, 0x01); + palette.replaceAColorDefault(&data[0], 1); + REQUIRE(data[0] == buildHex(0x10, 0x03, 0x02, 0x01)); +} + +TEST_CASE("Dye replaceAColor 1 2 default", "") +{ + DyePalette palette("#02ff0120,040311ff", 8); + uint32_t data[1]; + data[0] = buildHex(0x02, 0xff, 0x01, 0x20); + palette.replaceAColorDefault(&data[0], 1); + REQUIRE(data[0] == buildHex(0x04, 0x03, 0x11, 0xff)); +} + +TEST_CASE("Dye replaceAColor 1 3 default", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[1]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + palette.replaceAColorDefault(&data[0], 1); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); +} + +TEST_CASE("Dye replaceAColor 2 1 default", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[2]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + palette.replaceAColorDefault(&data[0], 2); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 3 1 default", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[3]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x50, 0x40, 0x40, 0x30); + data[2] = buildHex(0x40, 0x40, 0x40, 0x40); + palette.replaceAColorDefault(&data[0], 3); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x50, 0x40, 0x40, 0x30)); + REQUIRE(data[2] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 4 1 default", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[4]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x40, 0x40, 0x40, 0x40); + palette.replaceAColorDefault(&data[0], 4); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 5 1 default", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[5]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x50, 0x40, 0x40, 0x60); + data[4] = buildHex(0x40, 0x40, 0x40, 0x40); + palette.replaceAColorDefault(&data[0], 5); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x50, 0x40, 0x40, 0x60)); + REQUIRE(data[4] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 7 1 default", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[7]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x40, 0x40, 0x40, 0x40); + data[4] = buildHex(0x01, 0x00, 0xee, 0x40); + data[5] = buildHex(0x40, 0x40, 0x41, 0x40); + data[6] = buildHex(0x01, 0x00, 0xee, 0x50); + palette.replaceAColorDefault(&data[0], 7); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[4] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[5] == buildHex(0x40, 0x40, 0x41, 0x40)); + REQUIRE(data[6] == buildHex(0x01, 0x00, 0xee, 0x50)); +} + +TEST_CASE("Dye replaceAColor 8 1 default", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[8]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x40, 0x40, 0x40, 0x40); + data[4] = buildHex(0x01, 0x00, 0xee, 0x40); + data[5] = buildHex(0x40, 0x40, 0x41, 0x40); + data[6] = buildHex(0x01, 0x00, 0xee, 0x50); + data[7] = buildHex(0x40, 0x40, 0x40, 0x40); + palette.replaceAColorDefault(&data[0], 8); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[4] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[5] == buildHex(0x40, 0x40, 0x41, 0x40)); + REQUIRE(data[6] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[7] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 9 1 default", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[9]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x40, 0x40, 0x40, 0x40); + data[4] = buildHex(0x01, 0x00, 0xee, 0x40); + data[5] = buildHex(0x40, 0x40, 0x41, 0x40); + data[6] = buildHex(0x01, 0x00, 0xee, 0x50); + data[7] = buildHex(0x02, 0x40, 0x40, 0x40); + data[8] = buildHex(0x40, 0x40, 0x40, 0x40); + palette.replaceAColorDefault(&data[0], 9); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[4] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[5] == buildHex(0x40, 0x40, 0x41, 0x40)); + REQUIRE(data[6] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[7] == buildHex(0x02, 0x40, 0x40, 0x40)); + REQUIRE(data[8] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 10 1 default", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[10]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x40, 0x40, 0x40, 0x40); + data[4] = buildHex(0x01, 0x00, 0xee, 0x40); + data[5] = buildHex(0x40, 0x40, 0x41, 0x40); + data[6] = buildHex(0x01, 0x00, 0xee, 0x50); + data[7] = buildHex(0x02, 0x40, 0x40, 0x40); + data[8] = buildHex(0x40, 0x40, 0x40, 0x40); + data[9] = buildHex(0x01, 0x00, 0xee, 0x40); + palette.replaceAColorDefault(&data[0], 10); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[4] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[5] == buildHex(0x40, 0x40, 0x41, 0x40)); + REQUIRE(data[6] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[7] == buildHex(0x02, 0x40, 0x40, 0x40)); + REQUIRE(data[8] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[9] == buildHex(0x10, 0x20, 0x30, 0xff)); +} + +TEST_CASE("Dye replaceAColor 1 1 sse2", "") +{ + DyePalette palette("#00ff0010,00001120", 8); + uint32_t data[1]; + data[0] = buildHex(0x10, 0x03, 0x02, 0x01); + DYEPALETTE(palette, AColorSse2)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x10, 0x03, 0x02, 0x01)); +} + +TEST_CASE("Dye replaceAColor 1 2 sse2", "") +{ + DyePalette palette("#02ff0120,040311ff", 8); + uint32_t data[1]; + data[0] = buildHex(0x02, 0xff, 0x01, 0x20); + DYEPALETTE(palette, AColorSse2)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x04, 0x03, 0x11, 0xff)); +} + +TEST_CASE("Dye replaceAColor 1 3 sse2", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[1]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + DYEPALETTE(palette, AColorSse2)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); +} + +TEST_CASE("Dye replaceAColor 2 1 sse2", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[2]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + DYEPALETTE(palette, AColorSse2)(&data[0], 2); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 3 1 sse2", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[3]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x50, 0x40, 0x40, 0x30); + data[2] = buildHex(0x40, 0x40, 0x40, 0x40); + DYEPALETTE(palette, AColorSse2)(&data[0], 3); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x50, 0x40, 0x40, 0x30)); + REQUIRE(data[2] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 4 1 sse2", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[4]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x40, 0x40, 0x40, 0x40); + DYEPALETTE(palette, AColorSse2)(&data[0], 4); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 5 1 sse2", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[5]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x50, 0x40, 0x40, 0x60); + data[4] = buildHex(0x40, 0x40, 0x40, 0x40); + DYEPALETTE(palette, AColorSse2)(&data[0], 5); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x50, 0x40, 0x40, 0x60)); + REQUIRE(data[4] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 7 1 sse2", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[7]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x40, 0x40, 0x40, 0x40); + data[4] = buildHex(0x01, 0x00, 0xee, 0x40); + data[5] = buildHex(0x40, 0x40, 0x41, 0x40); + data[6] = buildHex(0x01, 0x00, 0xee, 0x50); + DYEPALETTE(palette, AColorSse2)(&data[0], 7); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[4] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[5] == buildHex(0x40, 0x40, 0x41, 0x40)); + REQUIRE(data[6] == buildHex(0x01, 0x00, 0xee, 0x50)); +} + +TEST_CASE("Dye replaceAColor 8 1 sse2", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[8]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x40, 0x40, 0x40, 0x40); + data[4] = buildHex(0x01, 0x00, 0xee, 0x40); + data[5] = buildHex(0x40, 0x40, 0x41, 0x40); + data[6] = buildHex(0x01, 0x00, 0xee, 0x50); + data[7] = buildHex(0x40, 0x40, 0x40, 0x40); + DYEPALETTE(palette, AColorSse2)(&data[0], 8); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[4] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[5] == buildHex(0x40, 0x40, 0x41, 0x40)); + REQUIRE(data[6] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[7] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 9 1 sse2", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[9]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x40, 0x40, 0x40, 0x40); + data[4] = buildHex(0x01, 0x00, 0xee, 0x40); + data[5] = buildHex(0x40, 0x40, 0x41, 0x40); + data[6] = buildHex(0x01, 0x00, 0xee, 0x50); + data[7] = buildHex(0x02, 0x40, 0x40, 0x40); + data[8] = buildHex(0x40, 0x40, 0x40, 0x40); + DYEPALETTE(palette, AColorSse2)(&data[0], 9); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[4] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[5] == buildHex(0x40, 0x40, 0x41, 0x40)); + REQUIRE(data[6] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[7] == buildHex(0x02, 0x40, 0x40, 0x40)); + REQUIRE(data[8] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 10 1 sse2", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[10]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x40, 0x40, 0x40, 0x40); + data[4] = buildHex(0x01, 0x00, 0xee, 0x40); + data[5] = buildHex(0x40, 0x40, 0x41, 0x40); + data[6] = buildHex(0x01, 0x00, 0xee, 0x50); + data[7] = buildHex(0x02, 0x40, 0x40, 0x40); + data[8] = buildHex(0x40, 0x40, 0x40, 0x40); + data[9] = buildHex(0x01, 0x00, 0xee, 0x40); + DYEPALETTE(palette, AColorSse2)(&data[0], 10); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[4] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[5] == buildHex(0x40, 0x40, 0x41, 0x40)); + REQUIRE(data[6] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[7] == buildHex(0x02, 0x40, 0x40, 0x40)); + REQUIRE(data[8] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[9] == buildHex(0x10, 0x20, 0x30, 0xff)); +} + +TEST_CASE("Dye replaceAColor 1 1 avx2", "") +{ + DyePalette palette("#00ff0010,00001120", 8); + uint32_t data[1]; + data[0] = buildHex(0x10, 0x03, 0x02, 0x01); + DYEPALETTE(palette, AColorAvx2)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x10, 0x03, 0x02, 0x01)); +} + +TEST_CASE("Dye replaceAColor 1 2 avx2", "") +{ + DyePalette palette("#02ff0120,040311ff", 8); + uint32_t data[1]; + data[0] = buildHex(0x02, 0xff, 0x01, 0x20); + DYEPALETTE(palette, AColorAvx2)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x04, 0x03, 0x11, 0xff)); +} + +TEST_CASE("Dye replaceAColor 1 3 avx2", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[1]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + DYEPALETTE(palette, AColorAvx2)(&data[0], 1); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); +} + +TEST_CASE("Dye replaceAColor 2 1 avx2", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[2]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + DYEPALETTE(palette, AColorAvx2)(&data[0], 2); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 3 1 avx2", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[3]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x50, 0x40, 0x40, 0x30); + data[2] = buildHex(0x40, 0x40, 0x40, 0x40); + DYEPALETTE(palette, AColorAvx2)(&data[0], 3); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x50, 0x40, 0x40, 0x30)); + REQUIRE(data[2] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 4 1 avx2", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[4]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x40, 0x40, 0x40, 0x40); + DYEPALETTE(palette, AColorAvx2)(&data[0], 4); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 5 1 avx2", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[5]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x50, 0x40, 0x40, 0x60); + data[4] = buildHex(0x40, 0x40, 0x40, 0x40); + DYEPALETTE(palette, AColorAvx2)(&data[0], 5); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x50, 0x40, 0x40, 0x60)); + REQUIRE(data[4] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 7 1 avx2", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[7]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x40, 0x40, 0x40, 0x40); + data[4] = buildHex(0x01, 0x00, 0xee, 0x40); + data[5] = buildHex(0x40, 0x40, 0x41, 0x40); + data[6] = buildHex(0x01, 0x00, 0xee, 0x50); + DYEPALETTE(palette, AColorAvx2)(&data[0], 7); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[4] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[5] == buildHex(0x40, 0x40, 0x41, 0x40)); + REQUIRE(data[6] == buildHex(0x01, 0x00, 0xee, 0x50)); +} + +TEST_CASE("Dye replaceAColor 8 1 avx2", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[8]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x40, 0x40, 0x40, 0x40); + data[4] = buildHex(0x01, 0x00, 0xee, 0x40); + data[5] = buildHex(0x40, 0x40, 0x41, 0x40); + data[6] = buildHex(0x01, 0x00, 0xee, 0x50); + data[7] = buildHex(0x40, 0x40, 0x40, 0x40); + DYEPALETTE(palette, AColorAvx2)(&data[0], 8); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[4] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[5] == buildHex(0x40, 0x40, 0x41, 0x40)); + REQUIRE(data[6] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[7] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 9 1 avx2", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[9]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x40, 0x40, 0x40, 0x40); + data[4] = buildHex(0x01, 0x00, 0xee, 0x40); + data[5] = buildHex(0x40, 0x40, 0x41, 0x40); + data[6] = buildHex(0x01, 0x00, 0xee, 0x50); + data[7] = buildHex(0x02, 0x40, 0x40, 0x40); + data[8] = buildHex(0x40, 0x40, 0x40, 0x40); + DYEPALETTE(palette, AColorAvx2)(&data[0], 9); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[4] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[5] == buildHex(0x40, 0x40, 0x41, 0x40)); + REQUIRE(data[6] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[7] == buildHex(0x02, 0x40, 0x40, 0x40)); + REQUIRE(data[8] == buildHex(0x20, 0x00, 0x00, 0x00)); +} + +TEST_CASE("Dye replaceAColor 10 1 avx2", "") +{ + DyePalette palette("#40404040,20000000,0100ee40,102030ff", 8); + uint32_t data[10]; + data[0] = buildHex(0x01, 0x00, 0xee, 0x40); + data[1] = buildHex(0x40, 0x40, 0x40, 0x40); + data[2] = buildHex(0x01, 0x00, 0xee, 0x50); + data[3] = buildHex(0x40, 0x40, 0x40, 0x40); + data[4] = buildHex(0x01, 0x00, 0xee, 0x40); + data[5] = buildHex(0x40, 0x40, 0x41, 0x40); + data[6] = buildHex(0x01, 0x00, 0xee, 0x50); + data[7] = buildHex(0x02, 0x40, 0x40, 0x40); + data[8] = buildHex(0x40, 0x40, 0x40, 0x40); + data[9] = buildHex(0x01, 0x00, 0xee, 0x40); + DYEPALETTE(palette, AColorAvx2)(&data[0], 10); + REQUIRE(data[0] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[1] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[2] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[3] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[4] == buildHex(0x10, 0x20, 0x30, 0xff)); + REQUIRE(data[5] == buildHex(0x40, 0x40, 0x41, 0x40)); + REQUIRE(data[6] == buildHex(0x01, 0x00, 0xee, 0x50)); + REQUIRE(data[7] == buildHex(0x02, 0x40, 0x40, 0x40)); + REQUIRE(data[8] == buildHex(0x20, 0x00, 0x00, 0x00)); + REQUIRE(data[9] == buildHex(0x10, 0x20, 0x30, 0xff)); +} + + +TEST_CASE("Dye normalDye 1", "") +{ + Dye dye("R:#203040,506070"); + uint32_t data[1]; + data[0] = buildHex(0x50, 0x00, 0x00, 0x55); + dye.normalDye(&data[0], 1); + REQUIRE(data[0] == buildHex(0x14, 0x1e, 0x28, 0x55)); +} + +TEST_CASE("Dye normalDye 2", "") +{ + Dye dye("G:#203040,506070"); + uint32_t data[1]; + data[0] = buildHex(0x00, 0x50, 0x00, 0x60); + dye.normalDye(&data[0], 1); + REQUIRE(data[0] == buildHex(0x14, 0x1e, 0x28, 0x60)); +} + + +#ifdef USE_OPENGL +TEST_CASE("Dye normalOGLDye 1", "") +{ + Dye dye("R:#203040,506070"); + uint32_t data[1]; + data[0] = buildHex(0x50, 0x00, 0x00, 0x55); + dye.normalOGLDye(&data[0], 1); + REQUIRE(data[0] == buildHex(0x50, 0x2a, 0x20, 0x15)); +} +#endif // USE_OPENGL + +static void dyeCheck(const std::string &dyeString, + const std::string &dstName) +{ + const std::string srcName = "arrow_up.png"; + + Image *const image1 = Loader::getImage(srcName + dyeString); + Image *const image2 = Loader::getImage(dstName); + REQUIRE(image1 != nullptr); + REQUIRE(image2 != nullptr); + SDL_Surface *const surface1 = image1->getSDLSurface(); + SDL_Surface *const surface2 = image2->getSDLSurface(); + REQUIRE(surface1 != nullptr); + REQUIRE(surface2 != nullptr); + REQUIRE(surface1->w == surface2->w); + REQUIRE(surface1->h == surface2->h); + REQUIRE(surface1->pixels != nullptr); + REQUIRE(surface2->pixels != nullptr); + const uint32_t *const ptr1 = static_cast<const uint32_t *>( + surface1->pixels); + const uint32_t *const ptr2 = static_cast<const uint32_t *>( + surface2->pixels); + const size_t sz = surface1->w * surface1->h; + for (size_t idx = 0; idx < sz; idx ++) + { + REQUIRE(ptr1[idx] == ptr2[idx]); + } + image2->decRef(); + image1->decRef(); +} + +TEST_CASE("Dye real dye", "") +{ + setEnv("SDL_VIDEODRIVER", "dummy"); + + client = new Client; + SDL_Init(SDL_INIT_VIDEO); + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + VirtFs::mountDirSilent("data/test", Append_false); + VirtFs::mountDirSilent("../data/test", Append_false); + +#ifdef USE_SDL2 + imageHelper = new SurfaceImageHelper; + + SDLImageHelper::setRenderer(graphicsManager.createRenderer( + graphicsManager.createWindow(640, 480, 0, + SDL_WINDOW_SHOWN | SDL_SWSURFACE), SDL_RENDERER_SOFTWARE)); +#else // USE_SDL2 + + imageHelper = new SDLImageHelper; + + graphicsManager.createWindow(640, 480, 0, SDL_ANYFORMAT | SDL_SWSURFACE); +#endif // USE_SDL2 + + ActorSprite::load(); + + SECTION("B dye") + { + dyeCheck("|B:#FFC88A", "arrow_up_B.png"); + } + + SECTION("S dye") + { + dyeCheck("|S:#0000FF,FF0000", "arrow_up_S.png"); + } + + SECTION("A dye") + { + dyeCheck("|A:#0000FFFF,FF000050", "arrow_up_A.png"); + } + delete2(client); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + VirtFs::unmountDirSilent("data/test"); + VirtFs::unmountDirSilent("../data/test"); + delete2(logger); +// VirtFs::deinit(); +} + +TEST_CASE("Dye leak test2", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} diff --git a/src/unittests/resources/dye/dyepalette_unittest.cc b/src/unittests/resources/dye/dyepalette_unittest.cc new file mode 100644 index 000000000..0e99e9871 --- /dev/null +++ b/src/unittests/resources/dye/dyepalette_unittest.cc @@ -0,0 +1,422 @@ +/* + * The ManaPlus Client + * Copyright (C) 2013-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "client.h" +#include "configuration.h" +#include "configmanager.h" +#include "dirs.h" +#include "graphicsmanager.h" + +#include "being/actorsprite.h" + +#include "fs/virtfs/fs.h" + +#include "gui/gui.h" +#include "gui/theme.h" + +#include "render/sdlgraphics.h" + +#include "resources/sdlimagehelper.h" + +#include "resources/db/palettedb.h" + +#include "resources/dye/dyepalette.h" + +#include "resources/resourcemanager/resourcemanager.h" + +#include "utils/delete2.h" +#include "utils/env.h" + +PRAGMA48(GCC diagnostic push) +PRAGMA48(GCC diagnostic ignored "-Wshadow") +#ifndef USE_SDL2 +#include <SDL.h> +#endif // USE_SDL2 +PRAGMA48(GCC diagnostic pop) + +#include "debug.h" + +TEST_CASE("DyePalette leak test1", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} + +TEST_CASE("DyePalette tests", "") +{ + setEnv("SDL_VIDEODRIVER", "dummy"); + + client = new Client; + XML::initXML(); + SDL_Init(SDL_INIT_VIDEO); + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + VirtFs::mountDirSilent("data/test", Append_false); + VirtFs::mountDirSilent("../data/test", Append_false); + + mainGraphics = new SDLGraphics; + imageHelper = new SDLImageHelper(); +#ifdef USE_SDL2 + SDLImageHelper::setRenderer(graphicsManager.createRenderer( + graphicsManager.createWindow(640, 480, 0, + SDL_WINDOW_SHOWN | SDL_SWSURFACE), SDL_RENDERER_SOFTWARE)); +#else // USE_SDL2 + + graphicsManager.createWindow(640, 480, 0, SDL_ANYFORMAT | SDL_SWSURFACE); +#endif // USE_SDL2 + + theme = new Theme; + Theme::selectSkin(); + + Dirs::initRootDir(); + Dirs::initHomeDir(); + + ConfigManager::initConfiguration(); + getConfigDefaults2(config.getDefaultValues()); + branding.setDefaultValues(getBrandingDefaults()); + + ActorSprite::load(); + gui = new Gui(); + gui->postInit(mainGraphics); + paths.setDefaultValues(getPathsDefaults()); + PaletteDB::load(); + + SECTION("simple test 1") + { + DyePalette palette("#12ff34", 6); + REQUIRE(palette.mColors.size() == 1); + REQUIRE(palette.mColors[0].value[0] == 0x12); + REQUIRE(palette.mColors[0].value[1] == 0xff); + REQUIRE(palette.mColors[0].value[2] == 0x34); + REQUIRE(palette.mColors[0].value[3] == 0x00); + } + + SECTION("simple test 2") + { + DyePalette palette("#12ff3456", 8); + REQUIRE(palette.mColors.size() == 1); + REQUIRE(palette.mColors[0].value[0] == 0x12); + REQUIRE(palette.mColors[0].value[1] == 0xff); + REQUIRE(palette.mColors[0].value[2] == 0x34); + REQUIRE(palette.mColors[0].value[3] == 0x56); + } + + SECTION("simple test 3") + { + DyePalette palette("#12ff34,002211", 6); + REQUIRE(palette.mColors.size() == 2); + REQUIRE(palette.mColors[0].value[0] == 0x12); + REQUIRE(palette.mColors[0].value[1] == 0xff); + REQUIRE(palette.mColors[0].value[2] == 0x34); + REQUIRE(palette.mColors[0].value[3] == 0x00); + + REQUIRE(palette.mColors[1].value[0] == 0x00); + REQUIRE(palette.mColors[1].value[1] == 0x22); + REQUIRE(palette.mColors[1].value[2] == 0x11); + REQUIRE(palette.mColors[1].value[3] == 0x00); + } + + SECTION("simple test 4") + { + DyePalette palette("#12ff3412,00221133", 8); + REQUIRE(palette.mColors.size() == 2); + REQUIRE(palette.mColors[0].value[0] == 0x12); + REQUIRE(palette.mColors[0].value[1] == 0xff); + REQUIRE(palette.mColors[0].value[2] == 0x34); + REQUIRE(palette.mColors[0].value[3] == 0x12); + + REQUIRE(palette.mColors[1].value[0] == 0x00); + REQUIRE(palette.mColors[1].value[1] == 0x22); + REQUIRE(palette.mColors[1].value[2] == 0x11); + REQUIRE(palette.mColors[1].value[3] == 0x33); + } + + SECTION("simple test 5") + { + DyePalette palette("#12ff34,", 6); + REQUIRE(palette.mColors.size() == 1); + REQUIRE(palette.mColors[0].value[0] == 0x12); + REQUIRE(palette.mColors[0].value[1] == 0xff); + REQUIRE(palette.mColors[0].value[2] == 0x34); + REQUIRE(palette.mColors[0].value[3] == 0x00); + } + + SECTION("simple test 6") + { + DyePalette palette("#12ff3456,", 8); + REQUIRE(palette.mColors.size() == 1); + REQUIRE(palette.mColors[0].value[0] == 0x12); + REQUIRE(palette.mColors[0].value[1] == 0xff); + REQUIRE(palette.mColors[0].value[2] == 0x34); + REQUIRE(palette.mColors[0].value[3] == 0x56); + } + + SECTION("simple test 7") + { + DyePalette palette("#,,,12ff3412,,00221133", 8); + REQUIRE(palette.mColors.size() == 2); + REQUIRE(palette.mColors[0].value[0] == 0x12); + REQUIRE(palette.mColors[0].value[1] == 0xff); + REQUIRE(palette.mColors[0].value[2] == 0x34); + REQUIRE(palette.mColors[0].value[3] == 0x12); + + REQUIRE(palette.mColors[1].value[0] == 0x00); + REQUIRE(palette.mColors[1].value[1] == 0x22); + REQUIRE(palette.mColors[1].value[2] == 0x11); + REQUIRE(palette.mColors[1].value[3] == 0x33); + } + + SECTION("palette test 1") + { + DyePalette palette("@Untitled1", 6); + REQUIRE(palette.mColors.size() == 1); + REQUIRE(palette.mColors[0].value[0] == 47); + REQUIRE(palette.mColors[0].value[1] == 56); + REQUIRE(palette.mColors[0].value[2] == 46); + REQUIRE(palette.mColors[0].value[3] == 255); + } + + SECTION("palette test 2") + { + DyePalette palette("@Untitled1,Untitled8", 6); + REQUIRE(palette.mColors.size() == 2); + REQUIRE(palette.mColors[0].value[0] == 47); + REQUIRE(palette.mColors[0].value[1] == 56); + REQUIRE(palette.mColors[0].value[2] == 46); + REQUIRE(palette.mColors[0].value[3] == 255); + + REQUIRE(palette.mColors[1].value[0] == 0); + REQUIRE(palette.mColors[1].value[1] == 0); + REQUIRE(palette.mColors[1].value[2] == 255); + REQUIRE(palette.mColors[1].value[3] == 255); + } + + SECTION("palette test 3") + { + DyePalette palette("@Untitled1,", 6); + REQUIRE(palette.mColors.size() == 1); + REQUIRE(palette.mColors[0].value[0] == 47); + REQUIRE(palette.mColors[0].value[1] == 56); + REQUIRE(palette.mColors[0].value[2] == 46); + REQUIRE(palette.mColors[0].value[3] == 255); + } + + SECTION("palette test 4") + { + DyePalette palette("@,,,Untitled1,,Untitled8", 6); + REQUIRE(palette.mColors.size() == 2); + REQUIRE(palette.mColors[0].value[0] == 47); + REQUIRE(palette.mColors[0].value[1] == 56); + REQUIRE(palette.mColors[0].value[2] == 46); + REQUIRE(palette.mColors[0].value[3] == 255); + + REQUIRE(palette.mColors[1].value[0] == 0); + REQUIRE(palette.mColors[1].value[1] == 0); + REQUIRE(palette.mColors[1].value[2] == 255); + REQUIRE(palette.mColors[1].value[3] == 255); + } + + SECTION("palette test 5") + { + DyePalette palette("@12ff34", 6); + REQUIRE(palette.mColors.size() == 1); + REQUIRE(palette.mColors[0].value[0] == 0x12); + REQUIRE(palette.mColors[0].value[1] == 0xff); + REQUIRE(palette.mColors[0].value[2] == 0x34); + REQUIRE(palette.mColors[0].value[3] == 0x00); + } + + SECTION("palette test 6") + { + DyePalette palette("@12ff3456", 8); + REQUIRE(palette.mColors.size() == 1); + REQUIRE(palette.mColors[0].value[0] == 0x12); + REQUIRE(palette.mColors[0].value[1] == 0xff); + REQUIRE(palette.mColors[0].value[2] == 0x34); + REQUIRE(palette.mColors[0].value[3] == 0x56); + } + + SECTION("palette test 7") + { + DyePalette palette("@12ff34,002211", 6); + REQUIRE(palette.mColors.size() == 2); + REQUIRE(palette.mColors[0].value[0] == 0x12); + REQUIRE(palette.mColors[0].value[1] == 0xff); + REQUIRE(palette.mColors[0].value[2] == 0x34); + REQUIRE(palette.mColors[0].value[3] == 0x00); + + REQUIRE(palette.mColors[1].value[0] == 0x00); + REQUIRE(palette.mColors[1].value[1] == 0x22); + REQUIRE(palette.mColors[1].value[2] == 0x11); + REQUIRE(palette.mColors[1].value[3] == 0x00); + } + + SECTION("palette test 8") + { + DyePalette palette("@12ff3412,00221133", 8); + REQUIRE(palette.mColors.size() == 2); + REQUIRE(palette.mColors[0].value[0] == 0x12); + REQUIRE(palette.mColors[0].value[1] == 0xff); + REQUIRE(palette.mColors[0].value[2] == 0x34); + REQUIRE(palette.mColors[0].value[3] == 0x12); + + REQUIRE(palette.mColors[1].value[0] == 0x00); + REQUIRE(palette.mColors[1].value[1] == 0x22); + REQUIRE(palette.mColors[1].value[2] == 0x11); + REQUIRE(palette.mColors[1].value[3] == 0x33); + } + + SECTION("palette test 9") + { + DyePalette palette("@12ff34,", 6); + REQUIRE(palette.mColors.size() == 1); + REQUIRE(palette.mColors[0].value[0] == 0x12); + REQUIRE(palette.mColors[0].value[1] == 0xff); + REQUIRE(palette.mColors[0].value[2] == 0x34); + REQUIRE(palette.mColors[0].value[3] == 0x00); + } + + SECTION("palette test 10") + { + DyePalette palette("@12ff3456,", 8); + REQUIRE(palette.mColors.size() == 1); + REQUIRE(palette.mColors[0].value[0] == 0x12); + REQUIRE(palette.mColors[0].value[1] == 0xff); + REQUIRE(palette.mColors[0].value[2] == 0x34); + REQUIRE(palette.mColors[0].value[3] == 0x56); + } + + SECTION("palette test 11") + { + DyePalette palette("@,,,12ff3412,,00221133", 8); + REQUIRE(palette.mColors.size() == 2); + REQUIRE(palette.mColors[0].value[0] == 0x12); + REQUIRE(palette.mColors[0].value[1] == 0xff); + REQUIRE(palette.mColors[0].value[2] == 0x34); + REQUIRE(palette.mColors[0].value[3] == 0x12); + + REQUIRE(palette.mColors[1].value[0] == 0x00); + REQUIRE(palette.mColors[1].value[1] == 0x22); + REQUIRE(palette.mColors[1].value[2] == 0x11); + REQUIRE(palette.mColors[1].value[3] == 0x33); + } + + SECTION("palette test 12") + { + DyePalette palette("@Untitled1,334455", 6); + REQUIRE(palette.mColors.size() == 2); + REQUIRE(palette.mColors[0].value[0] == 47); + REQUIRE(palette.mColors[0].value[1] == 56); + REQUIRE(palette.mColors[0].value[2] == 46); + REQUIRE(palette.mColors[0].value[3] == 255); + + REQUIRE(palette.mColors[1].value[0] == 0x33); + REQUIRE(palette.mColors[1].value[1] == 0x44); + REQUIRE(palette.mColors[1].value[2] == 0x55); + REQUIRE(palette.mColors[1].value[3] == 0x00); + } + + SECTION("palette test 13") + { + DyePalette palette("@Untitled1,33445566", 8); + REQUIRE(palette.mColors.size() == 2); + REQUIRE(palette.mColors[0].value[0] == 47); + REQUIRE(palette.mColors[0].value[1] == 56); + REQUIRE(palette.mColors[0].value[2] == 46); + REQUIRE(palette.mColors[0].value[3] == 255); + + REQUIRE(palette.mColors[1].value[0] == 0x33); + REQUIRE(palette.mColors[1].value[1] == 0x44); + REQUIRE(palette.mColors[1].value[2] == 0x55); + REQUIRE(palette.mColors[1].value[3] == 0x66); + } + + SECTION("palette test 14") + { + DyePalette palette("@+77,Untitled1", 8); + REQUIRE(palette.mColors.size() == 1); + REQUIRE(palette.mColors[0].value[0] == 47); + REQUIRE(palette.mColors[0].value[1] == 56); + REQUIRE(palette.mColors[0].value[2] == 46); + REQUIRE(palette.mColors[0].value[3] == 0x77); + } + + SECTION("palette test 15") + { + DyePalette palette("@+87,Untitled1,Untitled8", 8); + REQUIRE(palette.mColors.size() == 2); + REQUIRE(palette.mColors[0].value[0] == 47); + REQUIRE(palette.mColors[0].value[1] == 56); + REQUIRE(palette.mColors[0].value[2] == 46); + REQUIRE(palette.mColors[0].value[3] == 0x87); + + REQUIRE(palette.mColors[1].value[0] == 0); + REQUIRE(palette.mColors[1].value[1] == 0); + REQUIRE(palette.mColors[1].value[2] == 255); + REQUIRE(palette.mColors[1].value[3] == 0x87); + } + + SECTION("palette test 16") + { + DyePalette palette("@+87,Untitled1,+34,Untitled8", 8); + REQUIRE(palette.mColors.size() == 2); + REQUIRE(palette.mColors[0].value[0] == 47); + REQUIRE(palette.mColors[0].value[1] == 56); + REQUIRE(palette.mColors[0].value[2] == 46); + REQUIRE(palette.mColors[0].value[3] == 0x87); + + REQUIRE(palette.mColors[1].value[0] == 0); + REQUIRE(palette.mColors[1].value[1] == 0); + REQUIRE(palette.mColors[1].value[2] == 255); + REQUIRE(palette.mColors[1].value[3] == 0x34); + } + + SECTION("palette test 17") + { + DyePalette palette("@+12,+23,+77,Untitled1", 8); + REQUIRE(palette.mColors.size() == 1); + REQUIRE(palette.mColors[0].value[0] == 47); + REQUIRE(palette.mColors[0].value[1] == 56); + REQUIRE(palette.mColors[0].value[2] == 46); + REQUIRE(palette.mColors[0].value[3] == 0x77); + } + delete2(client); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + VirtFs::unmountDirSilent("data/test"); + VirtFs::unmountDirSilent("../data/test"); + delete2(logger); +// VirtFs::deinit(); +} + +TEST_CASE("DyePalette leak test2", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} diff --git a/src/unittests/resources/map/maplayer_unittest.cc b/src/unittests/resources/map/maplayer_unittest.cc new file mode 100644 index 000000000..85d8c4f09 --- /dev/null +++ b/src/unittests/resources/map/maplayer_unittest.cc @@ -0,0 +1,3213 @@ +/* + * The ManaPlus Client + * Copyright (C) 2016-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "graphicsmanager.h" + +#include "being/localplayer.h" + +#include "enums/resources/map/blockmask.h" +#include "enums/resources/map/mapitemtype.h" + +#include "fs/virtfs/fs.h" + +#include "gui/theme.h" + +#include "unittests/render/mockgraphics.h" + +#include "utils/delete2.h" +#include "utils/env.h" + +#include "resources/sdlimagehelper.h" + +#include "resources/image/image.h" + +#include "resources/map/map.h" +#include "resources/map/maplayer.h" +#include "resources/map/speciallayer.h" + +#include "debug.h" + +TEST_CASE("MapLayer getTileDrawWidth", "") +{ + Image *const img1 = new Image(32, 32); + Image *const img2 = new Image(32, 32); + Image *const img3 = new Image(32, 32); + MapLayer *layer = nullptr; + int width; + int nextTile; + + SECTION("simple 1") + { + layer = new MapLayer("test", + 0, 0, + 1, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + TileInfo *const tiles = layer->getTiles(); + REQUIRE(layer->getTileDrawWidth(tiles, + 1, + width, + nextTile) == 0); + REQUIRE(width == 32); + REQUIRE(nextTile == 0); + } + + SECTION("simple 2") + { + layer = new MapLayer("test", + 0, 0, + 2, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + TileInfo *const tiles = layer->getTiles(); + REQUIRE(layer->getTileDrawWidth(tiles, + 2, + width, + nextTile) == 0); + REQUIRE(width == 32); + REQUIRE(nextTile == 1); + } + + SECTION("simple 3") + { + layer = new MapLayer("test", + 0, 0, + 2, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img2); + TileInfo *const tiles = layer->getTiles(); + REQUIRE(layer->getTileDrawWidth(tiles, + 1, + width, + nextTile) == 0); + REQUIRE(width == 32); + REQUIRE(nextTile == 0); + + REQUIRE(layer->getTileDrawWidth(tiles + 1, + 1, + width, + nextTile) == 0); + REQUIRE(width == 32); + REQUIRE(nextTile == 0); + } + + SECTION("simple 4") + { + layer = new MapLayer("test", + 0, 0, + 2, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img1); + TileInfo *const tiles = layer->getTiles(); + REQUIRE(layer->getTileDrawWidth(tiles, + 2, + width, + nextTile) == 1); + REQUIRE(width == 64); + REQUIRE(nextTile == 1); + + REQUIRE(layer->getTileDrawWidth(tiles + 1, + 1, + width, + nextTile) == 0); + REQUIRE(width == 32); + REQUIRE(nextTile == 0); + } + + SECTION("simple 4.2") + { + layer = new MapLayer("test", + 0, 0, + 3, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(2, 0, img1); + TileInfo *const tiles = layer->getTiles(); + REQUIRE(layer->getTileDrawWidth(tiles, + 3, + width, + nextTile) == 0); + REQUIRE(width == 32); + REQUIRE(nextTile == 1); + + REQUIRE(layer->getTileDrawWidth(tiles + 2, + 1, + width, + nextTile) == 0); + REQUIRE(width == 32); + REQUIRE(nextTile == 0); + } + + SECTION("simple 5") + { + layer = new MapLayer("test", + 0, 0, + 3, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img1); + TileInfo *const tiles = layer->getTiles(); + REQUIRE(layer->getTileDrawWidth(tiles, + 3, + width, + nextTile) == 1); + REQUIRE(width == 64); + REQUIRE(nextTile == 2); + + REQUIRE(layer->getTileDrawWidth(tiles + 1, + 2, + width, + nextTile) == 0); + REQUIRE(width == 32); + REQUIRE(nextTile == 1); + } + + SECTION("simple 6") + { + layer = new MapLayer("test", + 0, 0, + 3, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img1); + layer->setTile(2, 0, img2); + TileInfo *const tiles = layer->getTiles(); + REQUIRE(layer->getTileDrawWidth(tiles, + 3, + width, + nextTile) == 1); + REQUIRE(width == 64); + REQUIRE(nextTile == 1); + + REQUIRE(layer->getTileDrawWidth(tiles + 1, + 2, + width, + nextTile) == 0); + REQUIRE(width == 32); + REQUIRE(nextTile == 0); + + REQUIRE(layer->getTileDrawWidth(tiles + 2, + 1, + width, + nextTile) == 0); + REQUIRE(width == 32); + REQUIRE(nextTile == 0); + } + + SECTION("simple 7") + { + layer = new MapLayer("test", + 0, 0, + 3, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img1); + layer->setTile(2, 0, img2); + TileInfo *const tiles = layer->getTiles(); + tiles[1].isEnabled = false; + REQUIRE(layer->getTileDrawWidth(tiles, + 3, + width, + nextTile) == 0); + REQUIRE(width == 32); + REQUIRE(nextTile == 1); + +// REQUIRE(layer->getTileDrawWidth(tiles + 1, +// 2, +// width, +// nextTile) == 0); +// REQUIRE(width == 32); +// REQUIRE(nextTile == 0); + + REQUIRE(layer->getTileDrawWidth(tiles + 2, + 1, + width, + nextTile) == 0); + REQUIRE(width == 32); + REQUIRE(nextTile == 0); + } + + SECTION("simple 8") + { + layer = new MapLayer("test", + 0, 0, + 3, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img1); + layer->setTile(2, 0, img2); + TileInfo *const tiles = layer->getTiles(); + tiles[0].isEnabled = false; +// REQUIRE(layer->getTileDrawWidth(tiles, +// 3, +// width, +// nextTile) == 1); +// REQUIRE(width == 0); +// REQUIRE(nextTile == 1); + + REQUIRE(layer->getTileDrawWidth(tiles + 1, + 2, + width, + nextTile) == 0); + REQUIRE(width == 32); + REQUIRE(nextTile == 0); + + REQUIRE(layer->getTileDrawWidth(tiles + 2, + 1, + width, + nextTile) == 0); + REQUIRE(width == 32); + REQUIRE(nextTile == 0); + } + + SECTION("normal 1") + { + layer = new MapLayer("test", + 0, 0, + 100, 100, + false, + 0, + 0); + layer->setTile(1, 10, img1); + layer->setTile(2, 10, img1); + layer->setTile(3, 10, img1); + layer->setTile(4, 10, img2); + layer->setTile(5, 10, nullptr); + layer->setTile(6, 10, img2); + layer->setTile(7, 10, nullptr); + layer->setTile(8, 10, nullptr); + layer->setTile(9, 10, img2); + layer->setTile(10, 10, img2); + layer->setTile(11, 10, img3); + layer->setTile(12, 10, nullptr); + layer->setTile(13, 10, nullptr); + layer->setTile(14, 10, nullptr); + layer->setTile(15, 10, img1); + layer->setTile(16, 10, img1); + layer->setTile(17, 10, img1); + TileInfo *const tiles = layer->getTiles(); + + REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 1, + 100 - 1, + width, + nextTile) == 2); + REQUIRE(width == 96); + REQUIRE(nextTile == 2); + + REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 2, + 100 - 2, + width, + nextTile) == 1); + REQUIRE(width == 64); + REQUIRE(nextTile == 1); + + REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 3, + 100 - 3, + width, + nextTile) == 0); + REQUIRE(width == 32); + REQUIRE(nextTile == 0); + + REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 4, + 100 - 4, + width, + nextTile) == 0); + REQUIRE(width == 32); + REQUIRE(nextTile == 1); + + REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 6, + 100 - 6, + width, + nextTile) == 0); + REQUIRE(width == 32); + REQUIRE(nextTile == 2); + + REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 9, + 100 - 9, + width, + nextTile) == 1); + REQUIRE(width == 64); + REQUIRE(nextTile == 1); + + REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 10, + 100 - 10, + width, + nextTile) == 0); + REQUIRE(width == 32); + REQUIRE(nextTile == 0); + + REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 11, + 100 - 11, + width, + nextTile) == 0); + REQUIRE(width == 32); + REQUIRE(nextTile == 3); + + REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 15, + 100 - 15, + width, + nextTile) == 2); + REQUIRE(width == 96); + REQUIRE(nextTile == 84); + + REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 16, + 100 - 16, + width, + nextTile) == 1); + REQUIRE(width == 64); + REQUIRE(nextTile == 83); + + REQUIRE(layer->getTileDrawWidth(tiles + 10 * 100 + 17, + 100 - 17, + width, + nextTile) == 0); + REQUIRE(width == 32); + REQUIRE(nextTile == 82); + } + + delete layer; + delete img1; + delete img2; + delete img3; +} + + +TEST_CASE("MapLayer getEmptyTileDrawWidth", "") +{ + Image *const img1 = new Image(32, 32); + Image *const img2 = new Image(32, 32); + Image *const img3 = new Image(32, 32); + MapLayer *layer = nullptr; + int nextTile; + + SECTION("simple 2") + { + layer = new MapLayer("test", + 0, 0, + 2, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + TileInfo *const tiles = layer->getTiles(); + REQUIRE(layer->getEmptyTileDrawWidth(tiles + 1, + 1, + nextTile) == 0); + REQUIRE(nextTile == 0); + } + + SECTION("simple 4") + { + layer = new MapLayer("test", + 0, 0, + 3, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(2, 0, img1); + TileInfo *const tiles = layer->getTiles(); + REQUIRE(layer->getEmptyTileDrawWidth(tiles + 1, + 2, + nextTile) == 0); + REQUIRE(nextTile == 0); + } + + SECTION("simple 5") + { + layer = new MapLayer("test", + 0, 0, + 3, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img1); + TileInfo *const tiles = layer->getTiles(); + REQUIRE(layer->getEmptyTileDrawWidth(tiles + 2, + 1, + nextTile) == 0); + REQUIRE(nextTile == 0); + } + + SECTION("normal 1") + { + layer = new MapLayer("test", + 0, 0, + 100, 100, + false, + 0, + 0); + layer->setTile(1, 10, img1); + layer->setTile(2, 10, img1); + layer->setTile(3, 10, img1); + layer->setTile(4, 10, img2); + layer->setTile(5, 10, nullptr); + layer->setTile(6, 10, img2); + layer->setTile(7, 10, nullptr); + layer->setTile(8, 10, nullptr); + layer->setTile(9, 10, img2); + layer->setTile(10, 10, img2); + layer->setTile(11, 10, img3); + layer->setTile(12, 10, nullptr); + layer->setTile(13, 10, nullptr); + layer->setTile(14, 10, nullptr); + layer->setTile(15, 10, img1); + layer->setTile(16, 10, img1); + layer->setTile(17, 10, img1); + TileInfo *const tiles = layer->getTiles(); + + REQUIRE(layer->getEmptyTileDrawWidth(tiles + 10 * 100 + 0, + 100 - 0, + nextTile) == 0); + REQUIRE(nextTile == 0); + + REQUIRE(layer->getEmptyTileDrawWidth(tiles + 10 * 100 + 5, + 100 - 5, + nextTile) == 0); + REQUIRE(nextTile == 0); + + REQUIRE(layer->getEmptyTileDrawWidth(tiles + 10 * 100 + 7, + 100 - 7, + nextTile) == 1); + REQUIRE(nextTile == 1); + + REQUIRE(layer->getEmptyTileDrawWidth(tiles + 10 * 100 + 8, + 100 - 8, + nextTile) == 0); + REQUIRE(nextTile == 0); + + REQUIRE(layer->getEmptyTileDrawWidth(tiles + 10 * 100 + 12, + 100 - 12, + nextTile) == 2); + REQUIRE(nextTile == 2); + + REQUIRE(layer->getEmptyTileDrawWidth(tiles + 10 * 100 + 13, + 100 - 13, + nextTile) == 1); + REQUIRE(nextTile == 1); + + REQUIRE(layer->getEmptyTileDrawWidth(tiles + 10 * 100 + 14, + 100 - 14, + nextTile) == 0); + REQUIRE(nextTile == 0); + } + + delete layer; + delete img1; + delete img2; + delete img3; +} + + +TEST_CASE("MapLayer updateCache", "") +{ + Image *const img1 = new Image(32, 32); + Image *const img2 = new Image(32, 32); + Image *const img3 = new Image(32, 32); + MapLayer *layer = nullptr; + + SECTION("simple 1") + { + layer = new MapLayer("test", + 0, 0, + 1, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + TileInfo *const tiles = layer->getTiles(); + layer->updateCache(1, 1); + REQUIRE(tiles[0].isEnabled == true); + REQUIRE(tiles[0].width == 32); + REQUIRE(tiles[0].count == 0); + REQUIRE(tiles[0].nextTile == 0); + } + + SECTION("simple 2") + { + layer = new MapLayer("test", + 0, 0, + 2, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + TileInfo *const tiles = layer->getTiles(); + layer->updateCache(2, 1); + REQUIRE(tiles[0].isEnabled == true); + REQUIRE(tiles[0].width == 32); + REQUIRE(tiles[0].count == 0); + REQUIRE(tiles[0].nextTile == 1); + REQUIRE(tiles[1].isEnabled == false); + REQUIRE(tiles[1].width == 0); + REQUIRE(tiles[1].count == 0); + REQUIRE(tiles[1].nextTile == 0); + } + + SECTION("simple 3") + { + layer = new MapLayer("test", + 0, 0, + 2, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img2); + TileInfo *const tiles = layer->getTiles(); + layer->updateCache(2, 1); + REQUIRE(tiles[0].isEnabled == true); + REQUIRE(tiles[0].width == 32); + REQUIRE(tiles[0].count == 0); + REQUIRE(tiles[0].nextTile == 0); + REQUIRE(tiles[1].isEnabled == true); + REQUIRE(tiles[1].width == 32); + REQUIRE(tiles[1].count == 0); + REQUIRE(tiles[1].nextTile == 0); + } + + SECTION("simple 4") + { + layer = new MapLayer("test", + 0, 0, + 2, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img1); + TileInfo *const tiles = layer->getTiles(); + layer->updateCache(2, 1); + REQUIRE(tiles[0].isEnabled == true); + REQUIRE(tiles[0].width == 64); + REQUIRE(tiles[0].count == 1); + REQUIRE(tiles[0].nextTile == 1); + REQUIRE(tiles[1].isEnabled == true); + REQUIRE(tiles[1].width == 32); + REQUIRE(tiles[1].count == 0); + REQUIRE(tiles[1].nextTile == 0); + } + + SECTION("simple 4.2") + { + layer = new MapLayer("test", + 0, 0, + 3, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(2, 0, img1); + TileInfo *const tiles = layer->getTiles(); + layer->updateCache(3, 1); + REQUIRE(tiles[0].isEnabled == true); + REQUIRE(tiles[0].width == 32); + REQUIRE(tiles[0].count == 0); + REQUIRE(tiles[0].nextTile == 1); + REQUIRE(tiles[1].isEnabled == false); + REQUIRE(tiles[1].width == 0); + REQUIRE(tiles[1].count == 0); + REQUIRE(tiles[1].nextTile == 0); + REQUIRE(tiles[2].isEnabled == true); + REQUIRE(tiles[2].width == 32); + REQUIRE(tiles[2].count == 0); + REQUIRE(tiles[2].nextTile == 0); + } + + SECTION("simple 5") + { + layer = new MapLayer("test", + 0, 0, + 3, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img1); + TileInfo *const tiles = layer->getTiles(); + layer->updateCache(3, 1); + REQUIRE(tiles[0].isEnabled == true); + REQUIRE(tiles[0].width == 64); + REQUIRE(tiles[0].count == 1); + REQUIRE(tiles[0].nextTile == 2); + REQUIRE(tiles[1].isEnabled == true); + REQUIRE(tiles[1].width == 32); + REQUIRE(tiles[1].count == 0); + REQUIRE(tiles[1].nextTile == 1); + REQUIRE(tiles[2].isEnabled == false); + REQUIRE(tiles[2].width == 0); + REQUIRE(tiles[2].count == 0); + REQUIRE(tiles[2].nextTile == 0); + } + + SECTION("simple 6") + { + layer = new MapLayer("test", + 0, 0, + 3, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img1); + layer->setTile(2, 0, img2); + TileInfo *const tiles = layer->getTiles(); + layer->updateCache(3, 1); + REQUIRE(tiles[0].isEnabled == true); + REQUIRE(tiles[0].width == 64); + REQUIRE(tiles[0].count == 1); + REQUIRE(tiles[0].nextTile == 1); + REQUIRE(tiles[1].isEnabled == true); + REQUIRE(tiles[1].width == 32); + REQUIRE(tiles[1].count == 0); + REQUIRE(tiles[1].nextTile == 0); + REQUIRE(tiles[2].isEnabled == true); + REQUIRE(tiles[2].width == 32); + REQUIRE(tiles[2].count == 0); + REQUIRE(tiles[2].nextTile == 0); + } + + SECTION("simple 7") + { + layer = new MapLayer("test", + 0, 0, + 3, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img1); + layer->setTile(2, 0, img2); + TileInfo *const tiles = layer->getTiles(); + tiles[0].isEnabled = false; + layer->updateCache(3, 1); + REQUIRE(tiles[0].isEnabled == false); + REQUIRE(tiles[0].width == 0); + REQUIRE(tiles[0].count == 0); + REQUIRE(tiles[0].nextTile == 0); + REQUIRE(tiles[1].isEnabled == true); + REQUIRE(tiles[1].width == 32); + REQUIRE(tiles[1].count == 0); + REQUIRE(tiles[1].nextTile == 0); + REQUIRE(tiles[2].isEnabled == true); + REQUIRE(tiles[2].width == 32); + REQUIRE(tiles[2].count == 0); + REQUIRE(tiles[2].nextTile == 0); + } + + SECTION("normal 1") + { + layer = new MapLayer("test", + 0, 0, + 100, 100, + false, + 0, + 0); + layer->setTile(1, 10, img1); + layer->setTile(2, 10, img1); + layer->setTile(3, 10, img1); + layer->setTile(4, 10, img2); + layer->setTile(5, 10, nullptr); + layer->setTile(6, 10, img2); + layer->setTile(7, 10, nullptr); + layer->setTile(8, 10, nullptr); + layer->setTile(9, 10, img2); + layer->setTile(10, 10, img2); + layer->setTile(11, 10, img3); + layer->setTile(12, 10, nullptr); + layer->setTile(13, 10, nullptr); + layer->setTile(14, 10, nullptr); + layer->setTile(15, 10, img1); + layer->setTile(16, 10, img1); + layer->setTile(17, 10, img1); + TileInfo *const tiles = layer->getTiles(); + layer->updateCache(100, 100); + + REQUIRE(tiles[0 * 100 + 0].isEnabled == false); + REQUIRE(tiles[0 * 100 + 0].width == 0); + REQUIRE(tiles[0 * 100 + 0].count == 99); + REQUIRE(tiles[0 * 100 + 0].nextTile == 99); + + REQUIRE(tiles[0 * 100 + 1].isEnabled == false); + REQUIRE(tiles[0 * 100 + 1].width == 0); + REQUIRE(tiles[0 * 100 + 1].count == 98); + REQUIRE(tiles[0 * 100 + 1].nextTile == 98); + + REQUIRE(tiles[10 * 100 + 0].isEnabled == false); + REQUIRE(tiles[10 * 100 + 0].width == 0); + REQUIRE(tiles[10 * 100 + 0].count == 0); + REQUIRE(tiles[10 * 100 + 0].nextTile == 0); + + REQUIRE(tiles[10 * 100 + 1].isEnabled == true); + REQUIRE(tiles[10 * 100 + 1].width == 96); + REQUIRE(tiles[10 * 100 + 1].count == 2); + REQUIRE(tiles[10 * 100 + 1].nextTile == 2); + + REQUIRE(tiles[10 * 100 + 2].isEnabled == true); + REQUIRE(tiles[10 * 100 + 2].width == 64); + REQUIRE(tiles[10 * 100 + 2].count == 1); + REQUIRE(tiles[10 * 100 + 2].nextTile == 1); + + REQUIRE(tiles[10 * 100 + 3].isEnabled == true); + REQUIRE(tiles[10 * 100 + 3].width == 32); + REQUIRE(tiles[10 * 100 + 3].count == 0); + REQUIRE(tiles[10 * 100 + 3].nextTile == 0); + + REQUIRE(tiles[10 * 100 + 4].isEnabled == true); + REQUIRE(tiles[10 * 100 + 4].width == 32); + REQUIRE(tiles[10 * 100 + 4].count == 0); + REQUIRE(tiles[10 * 100 + 4].nextTile == 1); + + REQUIRE(tiles[10 * 100 + 5].isEnabled == false); + REQUIRE(tiles[10 * 100 + 5].width == 0); + REQUIRE(tiles[10 * 100 + 5].count == 0); + REQUIRE(tiles[10 * 100 + 5].nextTile == 0); + + REQUIRE(tiles[10 * 100 + 6].isEnabled == true); + REQUIRE(tiles[10 * 100 + 6].width == 32); + REQUIRE(tiles[10 * 100 + 6].count == 0); + REQUIRE(tiles[10 * 100 + 6].nextTile == 2); + + REQUIRE(tiles[10 * 100 + 7].isEnabled == false); + REQUIRE(tiles[10 * 100 + 7].width == 0); + REQUIRE(tiles[10 * 100 + 7].count == 1); + REQUIRE(tiles[10 * 100 + 7].nextTile == 1); + + REQUIRE(tiles[10 * 100 + 8].isEnabled == false); + REQUIRE(tiles[10 * 100 + 8].width == 0); + REQUIRE(tiles[10 * 100 + 8].count == 0); + REQUIRE(tiles[10 * 100 + 8].nextTile == 0); + + REQUIRE(tiles[10 * 100 + 9].isEnabled == true); + REQUIRE(tiles[10 * 100 + 9].width == 64); + REQUIRE(tiles[10 * 100 + 9].count == 1); + REQUIRE(tiles[10 * 100 + 9].nextTile == 1); + + REQUIRE(tiles[10 * 100 + 10].isEnabled == true); + REQUIRE(tiles[10 * 100 + 10].width == 32); + REQUIRE(tiles[10 * 100 + 10].count == 0); + REQUIRE(tiles[10 * 100 + 10].nextTile == 0); + + REQUIRE(tiles[10 * 100 + 11].isEnabled == true); + REQUIRE(tiles[10 * 100 + 11].width == 32); + REQUIRE(tiles[10 * 100 + 11].count == 0); + REQUIRE(tiles[10 * 100 + 11].nextTile == 3); + + REQUIRE(tiles[10 * 100 + 12].isEnabled == false); + REQUIRE(tiles[10 * 100 + 12].width == 0); + REQUIRE(tiles[10 * 100 + 12].count == 2); + REQUIRE(tiles[10 * 100 + 12].nextTile == 2); + + REQUIRE(tiles[10 * 100 + 13].isEnabled == false); + REQUIRE(tiles[10 * 100 + 13].width == 0); + REQUIRE(tiles[10 * 100 + 13].count == 1); + REQUIRE(tiles[10 * 100 + 13].nextTile == 1); + + REQUIRE(tiles[10 * 100 + 14].isEnabled == false); + REQUIRE(tiles[10 * 100 + 14].width == 0); + REQUIRE(tiles[10 * 100 + 14].count == 0); + REQUIRE(tiles[10 * 100 + 14].nextTile == 0); + + REQUIRE(tiles[10 * 100 + 15].isEnabled == true); + REQUIRE(tiles[10 * 100 + 15].width == 96); + REQUIRE(tiles[10 * 100 + 15].count == 2); + REQUIRE(tiles[10 * 100 + 15].nextTile == 84); + + REQUIRE(tiles[10 * 100 + 16].isEnabled == true); + REQUIRE(tiles[10 * 100 + 16].width == 64); + REQUIRE(tiles[10 * 100 + 16].count == 1); + REQUIRE(tiles[10 * 100 + 16].nextTile == 83); + + REQUIRE(tiles[10 * 100 + 17].isEnabled == true); + REQUIRE(tiles[10 * 100 + 17].width == 32); + REQUIRE(tiles[10 * 100 + 17].count == 0); + REQUIRE(tiles[10 * 100 + 17].nextTile == 82); + } + + SECTION("normal2") + { + const int maxX = 100; + const int maxY = 100; + layer = new MapLayer("test", + 0, 0, + maxX, maxY, + false, + 0, + 0); + TileInfo *const tiles = layer->getTiles(); + for (int x = 0; x < maxX; x ++) + { + for (int y = 0; y < maxY; y ++) + { + layer->setTile(x, y, img1); + tiles[y * maxX + x].isEnabled = false; + } + } + tiles[10 * maxX + 41].isEnabled = true; + layer->updateCache(maxX, maxY); + + REQUIRE(tiles[10 * maxX + 0].isEnabled == false); + REQUIRE(tiles[10 * maxX + 0].width == 0); + REQUIRE(tiles[10 * maxX + 0].count == 40); + REQUIRE(tiles[10 * maxX + 0].nextTile == 40); + + REQUIRE(tiles[10 * maxX + 1].isEnabled == false); + REQUIRE(tiles[10 * maxX + 1].width == 0); + REQUIRE(tiles[10 * maxX + 1].count == 39); + REQUIRE(tiles[10 * maxX + 1].nextTile == 39); + } + + delete layer; + delete img1; + delete img2; + delete img3; +} + +TEST_CASE("MapLayer updateConditionTiles", "") +{ + Image *const img1 = new Image(32, 32); + Map *map = nullptr; + MapLayer *layer = nullptr; + + SECTION("simple 1") + { + map = new Map("map", + 1, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 1, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + map->addLayer(layer); + layer->setTileCondition(BlockMask::WATER); + TileInfo *const tiles = layer->getTiles(); + + map->addBlockMask(0, 0, BlockType::NONE); + layer->updateConditionTiles(map->getMetaTiles(), + 1, 1); + REQUIRE(tiles[0].isEnabled == false); + + map->addBlockMask(0, 0, BlockType::WATER); + layer->updateConditionTiles(map->getMetaTiles(), + 1, 1); + REQUIRE(tiles[0].isEnabled == true); + } + + SECTION("normal 1") + { + map = new Map("map", + 100, 200, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 100, 200, + false, + 0, + 0); + layer->setTile(10, 10, img1); + layer->setTile(10, 20, img1); + layer->setTile(10, 30, img1); + map->addLayer(layer); + layer->setTileCondition(BlockMask::WATER); + TileInfo *const tiles = layer->getTiles(); + + map->addBlockMask(10, 10, BlockType::NONE); + map->addBlockMask(10, 20, BlockType::NONE); + map->addBlockMask(20, 20, BlockType::NONE); + layer->updateConditionTiles(map->getMetaTiles(), + 100, 200); + for (int x = 0; x < 100; x ++) + { + for (int y = 0; y < 200; y ++) + { + REQUIRE(tiles[y * 100 + x].isEnabled == false); + } + } + } + + SECTION("normal 2") + { + map = new Map("map", + 100, 200, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 100, 200, + false, + 0, + 0); + layer->setTile(10, 10, img1); + layer->setTile(10, 20, img1); + layer->setTile(10, 30, img1); + map->addLayer(layer); + layer->setTileCondition(BlockMask::WATER); + TileInfo *const tiles = layer->getTiles(); + + map->addBlockMask(10, 10, BlockType::WATER); + map->addBlockMask(10, 20, BlockType::WATER); + map->addBlockMask(20, 20, BlockType::WATER); + layer->updateConditionTiles(map->getMetaTiles(), + 100, 200); + for (int x = 0; x < 100; x ++) + { + for (int y = 0; y < 200; y ++) + { + if ((x == 10 && y == 10) || (x == 10 && y == 20)) + { + REQUIRE(tiles[y * 100 + x].isEnabled == true); + } + else + { + REQUIRE(tiles[y * 100 + x].isEnabled == false); + } + } + } + } + + SECTION("normal 3") + { + map = new Map("map", + 100, 200, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 100, 200, + false, + 0, + 0); + for (int x = 0; x < 100; x ++) + { + for (int y = 0; y < 200; y ++) + { + layer->setTile(x, y, img1); + } + } + map->addLayer(layer); + layer->setTileCondition(BlockMask::WATER); + TileInfo *const tiles = layer->getTiles(); + + map->addBlockMask(10, 10, BlockType::WATER); + map->addBlockMask(10, 20, BlockType::WATER); + layer->updateConditionTiles(map->getMetaTiles(), + 100, 200); + for (int x = 0; x < 100; x ++) + { + for (int y = 0; y < 200; y ++) + { + if ((x == 10 && y == 10) || (x == 10 && y == 20)) + { + REQUIRE(tiles[y * 100 + x].isEnabled == true); + } + else + { + REQUIRE(tiles[y * 100 + x].isEnabled == false); + } + } + } + } + + SECTION("normal 4") + { + map = new Map("map", + 100, 200, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 100, 200, + false, + 0, + 0); + layer->setTile(10, 10, img1); + layer->setTile(10, 20, img1); + map->addLayer(layer); + layer->setTileCondition(BlockMask::WATER); + TileInfo *const tiles = layer->getTiles(); + + for (int x = 0; x < 100; x ++) + { + for (int y = 0; y < 200; y ++) + { + map->addBlockMask(x, y, BlockType::WATER); + } + } + + layer->updateConditionTiles(map->getMetaTiles(), + 100, 200); + for (int x = 0; x < 100; x ++) + { + for (int y = 0; y < 200; y ++) + { + if ((x == 10 && y == 10) || (x == 10 && y == 20)) + { + REQUIRE(tiles[y * 100 + x].isEnabled == true); + } + else + { + REQUIRE(tiles[y * 100 + x].isEnabled == false); + } + } + } + } + + delete map; + delete img1; +} + +TEST_CASE("MapLayer draw", "") +{ + Image *const img1 = new Image(32, 32); + Image *const img2 = new Image(32, 32); + Image *const img3 = new Image(32, 32); + Map *map = nullptr; + MapLayer *layer = nullptr; + MockGraphics *const mock = new MockGraphics; + + SECTION("simple 1") + { + map = new Map("map", + 1, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 1, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + map->addLayer(layer); + layer->updateCache(1, 1); + + layer->draw(mock, + 0, 0, + 1, 1, + 0, 0); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[0].image == img1); + + mock->mDraws.clear(); + layer->draw(mock, + 0, 0, + 1, 1, + 10, 5); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == -10); + REQUIRE(mock->mDraws[0].y == -5); + REQUIRE(mock->mDraws[0].image == img1); + + mock->mDraws.clear(); + layer->draw(mock, + 0, 0, + 1, 1, + -10, -5); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 10); + REQUIRE(mock->mDraws[0].y == 5); + REQUIRE(mock->mDraws[0].image == img1); + } + + SECTION("simple 2") + { + map = new Map("map", + 2, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 2, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + map->addLayer(layer); + layer->updateCache(2, 1); + + layer->draw(mock, + 0, 0, + 2, 1, + 0, 0); + + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[0].image == img1); + + mock->mDraws.clear(); + layer->draw(mock, + 0, 0, + 2, 1, + 10, 5); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == -10); + REQUIRE(mock->mDraws[0].y == -5); + REQUIRE(mock->mDraws[0].image == img1); + + mock->mDraws.clear(); + layer->draw(mock, + 0, 0, + 2, 1, + -10, -5); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 10); + REQUIRE(mock->mDraws[0].y == 5); + REQUIRE(mock->mDraws[0].image == img1); + } + + SECTION("simple 3") + { + map = new Map("map", + 2, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 2, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img2); + map->addLayer(layer); + layer->updateCache(2, 1); + + layer->draw(mock, + 0, 0, + 2, 1, + 0, 0); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 32); + REQUIRE(mock->mDraws[1].y == 0); + REQUIRE(mock->mDraws[1].image == img2); + + mock->mDraws.clear(); + layer->draw(mock, + 0, 0, + 2, 1, + -10, -20); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 10); + REQUIRE(mock->mDraws[0].y == 20); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 42); + REQUIRE(mock->mDraws[1].y == 20); + REQUIRE(mock->mDraws[1].image == img2); + } + + SECTION("simple 4") + { + map = new Map("map", + 2, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 2, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img1); + map->addLayer(layer); + layer->updateCache(2, 1); + + layer->draw(mock, + 0, 0, + 2, 1, + 0, 0); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[0].width == 64); + REQUIRE(mock->mDraws[0].height == 32); + REQUIRE(mock->mDraws[0].image == img1); + + mock->mDraws.clear(); + layer->draw(mock, + 0, 0, + 2, 1, + -10, 20); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[0].x == 10); + REQUIRE(mock->mDraws[0].y == -20); + REQUIRE(mock->mDraws[0].width == 64); + REQUIRE(mock->mDraws[0].height == 32); + REQUIRE(mock->mDraws[0].image == img1); + } + + SECTION("simple 4.2") + { + map = new Map("map", + 3, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 3, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(2, 0, img1); + map->addLayer(layer); + layer->updateCache(3, 1); + + layer->draw(mock, + 0, 0, + 3, 1, + 0, 0); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 64); + REQUIRE(mock->mDraws[1].y == 0); + REQUIRE(mock->mDraws[1].image == img1); + + mock->mDraws.clear(); + layer->draw(mock, + 0, 0, + 3, 1, + 10, -20); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == -10); + REQUIRE(mock->mDraws[0].y == 20); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 54); + REQUIRE(mock->mDraws[1].y == 20); + REQUIRE(mock->mDraws[1].image == img1); + } + + SECTION("simple 5") + { + map = new Map("map", + 3, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 3, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img1); + map->addLayer(layer); + layer->updateCache(3, 1); + + layer->draw(mock, + 0, 0, + 3, 1, + 0, 0); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[0].width == 64); + REQUIRE(mock->mDraws[0].height == 32); + REQUIRE(mock->mDraws[0].image == img1); + + mock->mDraws.clear(); + layer->draw(mock, + 0, 0, + 3, 1, + -10, 20); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[0].x == 10); + REQUIRE(mock->mDraws[0].y == -20); + REQUIRE(mock->mDraws[0].width == 64); + REQUIRE(mock->mDraws[0].height == 32); + REQUIRE(mock->mDraws[0].image == img1); + } + + SECTION("simple 6") + { + map = new Map("map", + 3, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 3, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img1); + layer->setTile(2, 0, img2); + map->addLayer(layer); + layer->updateCache(3, 1); + + layer->draw(mock, + 0, 0, + 3, 1, + 0, 0); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[0].width == 64); + REQUIRE(mock->mDraws[0].height == 32); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 64); + REQUIRE(mock->mDraws[1].y == 0); + REQUIRE(mock->mDraws[1].image == img2); + + mock->mDraws.clear(); + layer->draw(mock, + 0, 0, + 3, 1, + -10, 20); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[0].x == 10); + REQUIRE(mock->mDraws[0].y == -20); + REQUIRE(mock->mDraws[0].width == 64); + REQUIRE(mock->mDraws[0].height == 32); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 74); + REQUIRE(mock->mDraws[1].y == -20); + REQUIRE(mock->mDraws[1].image == img2); + } + + SECTION("simple 7") + { + map = new Map("map", + 3, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 3, 1, + false, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img1); + layer->setTile(2, 0, img2); + map->addLayer(layer); + TileInfo *const tiles = layer->getTiles(); + tiles[0].isEnabled = false; + layer->updateCache(3, 1); + + layer->draw(mock, + 0, 0, + 3, 1, + 0, 0); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 32); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 64); + REQUIRE(mock->mDraws[1].y == 0); + REQUIRE(mock->mDraws[1].image == img2); + + mock->mDraws.clear(); + layer->draw(mock, + 0, 0, + 3, 1, + -10, 20); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 42); + REQUIRE(mock->mDraws[0].y == -20); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 74); + REQUIRE(mock->mDraws[1].y == -20); + REQUIRE(mock->mDraws[1].image == img2); + } + + SECTION("normal 1") + { + const int maxX = 100; + const int maxY = 100; + map = new Map("map", + maxX, maxY, + 32, 32); + layer = new MapLayer("test", + 0, 0, + maxX, maxY, + false, + 0, + 0); + layer->setTile(1, 10, img1); + layer->setTile(2, 10, img1); + layer->setTile(3, 10, img1); + layer->setTile(4, 10, img2); + layer->setTile(5, 10, nullptr); + layer->setTile(6, 10, img2); + layer->setTile(7, 10, nullptr); + layer->setTile(8, 10, nullptr); + layer->setTile(9, 10, img2); + layer->setTile(10, 10, img2); + layer->setTile(11, 10, img3); + layer->setTile(12, 10, nullptr); + layer->setTile(13, 10, nullptr); + layer->setTile(14, 10, nullptr); + layer->setTile(15, 10, img1); + layer->setTile(16, 10, img1); + layer->setTile(17, 10, img1); + map->addLayer(layer); + layer->updateCache(maxX, maxY); + + layer->draw(mock, + 0, 0, + maxX, maxY, + 0, 0); + REQUIRE(mock->mDraws.size() == 6); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[0].x == 32 * 1); + REQUIRE(mock->mDraws[0].y == 32 * 10); + REQUIRE(mock->mDraws[0].width == 96); + REQUIRE(mock->mDraws[0].height == 32); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 32 * 4); + REQUIRE(mock->mDraws[1].y == 32 * 10); + REQUIRE(mock->mDraws[1].image == img2); + REQUIRE(mock->mDraws[2].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[2].x == 32 * 6); + REQUIRE(mock->mDraws[2].y == 32 * 10); + REQUIRE(mock->mDraws[2].image == img2); + REQUIRE(mock->mDraws[3].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[3].x == 32 * 9); + REQUIRE(mock->mDraws[3].y == 32 * 10); + REQUIRE(mock->mDraws[3].width == 64); + REQUIRE(mock->mDraws[3].height == 32); + REQUIRE(mock->mDraws[3].image == img2); + REQUIRE(mock->mDraws[4].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[4].x == 32 * 11); + REQUIRE(mock->mDraws[4].y == 32 * 10); + REQUIRE(mock->mDraws[4].image == img3); + REQUIRE(mock->mDraws[5].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[5].x == 32 * 15); + REQUIRE(mock->mDraws[5].y == 32 * 10); + REQUIRE(mock->mDraws[5].width == 96); + REQUIRE(mock->mDraws[5].height == 32); + REQUIRE(mock->mDraws[5].image == img1); + + mock->mDraws.clear(); + layer->draw(mock, + 0, 0, + maxX, maxY, + -10, 20); + REQUIRE(mock->mDraws.size() == 6); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[0].x == 32 * 1 + 10); + REQUIRE(mock->mDraws[0].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[0].width == 96); + REQUIRE(mock->mDraws[0].height == 32); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 32 * 4 + 10); + REQUIRE(mock->mDraws[1].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[1].image == img2); + REQUIRE(mock->mDraws[2].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[2].x == 32 * 6 + 10); + REQUIRE(mock->mDraws[2].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[2].image == img2); + REQUIRE(mock->mDraws[3].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[3].x == 32 * 9 + 10); + REQUIRE(mock->mDraws[3].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[3].width == 64); + REQUIRE(mock->mDraws[3].height == 32); + REQUIRE(mock->mDraws[3].image == img2); + REQUIRE(mock->mDraws[4].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[4].x == 32 * 11 + 10); + REQUIRE(mock->mDraws[4].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[4].image == img3); + REQUIRE(mock->mDraws[5].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[5].x == 32 * 15 + 10); + REQUIRE(mock->mDraws[5].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[5].width == 96); + REQUIRE(mock->mDraws[5].height == 32); + REQUIRE(mock->mDraws[5].image == img1); + } + + SECTION("normal2") + { + const int maxX = 100; + const int maxY = 100; + map = new Map("map", + maxX, maxY, + 32, 32); + layer = new MapLayer("test", + 0, 0, + maxX, maxY, + false, + 0, + 0); + TileInfo *const tiles = layer->getTiles(); + map->addLayer(layer); + for (int x = 0; x < maxX; x ++) + { + for (int y = 0; y < maxY; y ++) + { + layer->setTile(x, y, img1); + tiles[y * maxX + x].isEnabled = false; + } + } + tiles[10 * maxX + 41].isEnabled = true; + layer->updateCache(maxX, maxY); + + layer->draw(mock, + 0, 0, + maxX, maxY, + 0, 0); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 32 * 41); + REQUIRE(mock->mDraws[0].y == 32 * 10); + + mock->mDraws.clear(); + layer->draw(mock, + 0, 0, + maxX, maxY, + -10, 20); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 32 * 41 + 10); + REQUIRE(mock->mDraws[0].y == 32 * 10 - 20); + } + + delete map; + delete img1; + delete img2; + delete img3; + delete mock; +} + +TEST_CASE("MapLayer drawSpecialLayer (specialLayer)", "") +{ + setEnv("SDL_VIDEODRIVER", "dummy"); + + logger = new Logger; + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + imageHelper = new SDLImageHelper; +#ifdef USE_SDL2 + SDLImageHelper::setRenderer(graphicsManager.createRenderer( + graphicsManager.createWindow(640, 480, 0, + SDL_WINDOW_SHOWN | SDL_SWSURFACE), SDL_RENDERER_SOFTWARE)); +#else // USE_SDL2 + + graphicsManager.createWindow(640, 480, 0, SDL_ANYFORMAT | SDL_SWSURFACE); +#endif // USE_SDL2 + + Map *map = nullptr; + MapLayer *layer = nullptr; + SpecialLayer *specialLayer = nullptr; + MockGraphics *const mock = new MockGraphics; + const Actors actors; + + SECTION("simple 1") + { + map = new Map("map", + 1, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 1, 1, + true, + 0, + 0); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + specialLayer = map->getSpecialLayer(); + + layer->drawSpecialLayer(mock, + 0, + 0, 1, + 0, 0); + REQUIRE(mock->mDraws.empty()); + + specialLayer->setTile(0, 0, MapItemType::ARROW_UP); + layer->drawSpecialLayer(mock, + 0, + 0, 1, + 0, 0); +// REQUIRE(mock->mDraws.size() == 1); + } + + SECTION("simple 2") + { + map = new Map("map", + 1, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 1, 1, + true, + 0, + 0); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + specialLayer = map->getSpecialLayer(); + specialLayer->setTile(0, 0, MapItemType::ARROW_UP); + specialLayer->updateCache(); + + layer->drawSpecialLayer(mock, + 0, + 0, 1, + 0, 0); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + } + + SECTION("simple 3") + { + map = new Map("map", + 2, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 2, 1, + true, + 0, + 0); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + specialLayer = map->getSpecialLayer(); + specialLayer->setTile(0, 0, MapItemType::ARROW_UP); + specialLayer->updateCache(); + + layer->drawSpecialLayer(mock, + 0, + 0, 2, + 0, 0); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + } + + SECTION("simple 4") + { + map = new Map("map", + 2, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 2, 1, + true, + 0, + 0); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + specialLayer = map->getSpecialLayer(); + specialLayer->setTile(1, 0, MapItemType::ARROW_UP); + specialLayer->updateCache(); + + layer->drawSpecialLayer(mock, + 0, + 0, 2, + 0, 0); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 32); + REQUIRE(mock->mDraws[0].y == 0); + } + + SECTION("simple 5") + { + map = new Map("map", + 2, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 2, 1, + true, + 0, + 0); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + specialLayer = map->getSpecialLayer(); + specialLayer->setTile(0, 0, MapItemType::ARROW_UP); + specialLayer->setTile(1, 0, MapItemType::ARROW_UP); + specialLayer->updateCache(); + + layer->drawSpecialLayer(mock, + 0, + 0, 2, + 0, 0); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 32); + REQUIRE(mock->mDraws[1].y == 0); + } + + SECTION("simple 6") + { + map = new Map("map", + 3, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 3, 1, + true, + 0, + 0); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + specialLayer = map->getSpecialLayer(); + specialLayer->setTile(0, 0, MapItemType::ARROW_UP); + specialLayer->setTile(2, 0, MapItemType::ARROW_UP); + specialLayer->updateCache(); + + layer->drawSpecialLayer(mock, + 0, + 0, 3, + 0, 0); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 64); + REQUIRE(mock->mDraws[1].y == 0); + } + + SECTION("simple 7") + { + map = new Map("map", + 3, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 3, 1, + true, + 0, + 0); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + specialLayer = map->getSpecialLayer(); + specialLayer->setTile(1, 0, MapItemType::ARROW_UP); + specialLayer->setTile(2, 0, MapItemType::ARROW_UP); + specialLayer->updateCache(); + + layer->drawSpecialLayer(mock, + 0, + 0, 3, + 0, 0); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 32); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 64); + REQUIRE(mock->mDraws[1].y == 0); + } + + SECTION("simple 8") + { + map = new Map("map", + 3, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 3, 1, + true, + 0, + 0); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + specialLayer = map->getSpecialLayer(); + specialLayer->setTile(0, 0, MapItemType::ARROW_UP); + specialLayer->setTile(1, 0, MapItemType::ARROW_DOWN); + specialLayer->setTile(2, 0, MapItemType::ARROW_UP); + specialLayer->updateCache(); + + layer->drawSpecialLayer(mock, + 0, + 0, 3, + 0, 0); + REQUIRE(mock->mDraws.size() == 3); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 32); + REQUIRE(mock->mDraws[1].y == 0); + REQUIRE(mock->mDraws[2].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[2].x == 64); + REQUIRE(mock->mDraws[2].y == 0); + } + + SECTION("normal 1") + { + const int maxX = 100; + const int maxY = 50; + map = new Map("map", + maxX, maxY, + 32, 32); + layer = new MapLayer("test", + 0, 0, + maxX, maxY, + true, + 0, + 0); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + specialLayer = map->getSpecialLayer(); + specialLayer->setTile(0, 5, MapItemType::ARROW_UP); + specialLayer->setTile(1, 5, MapItemType::ARROW_DOWN); + specialLayer->setTile(2, 5, MapItemType::ARROW_UP); + specialLayer->setTile(3, 5, MapItemType::EMPTY); + specialLayer->setTile(4, 5, MapItemType::EMPTY); + specialLayer->setTile(6, 5, MapItemType::ARROW_LEFT); + specialLayer->setTile(10, 20, MapItemType::ARROW_LEFT); + specialLayer->updateCache(); + + layer->drawSpecialLayer(mock, + 5, + 0, maxX, + 0, 0); + REQUIRE(mock->mDraws.size() == 4); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 0 * 32); + REQUIRE(mock->mDraws[0].y == 5 * 32); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 1 * 32); + REQUIRE(mock->mDraws[1].y == 5 * 32); + REQUIRE(mock->mDraws[2].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[2].x == 2 * 32); + REQUIRE(mock->mDraws[2].y == 5 * 32); + REQUIRE(mock->mDraws[3].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[3].x == 6 * 32); + REQUIRE(mock->mDraws[3].y == 5 * 32); + + mock->mDraws.clear(); + layer->drawSpecialLayer(mock, + 4, + 0, maxX, + 0, 0); + REQUIRE(mock->mDraws.empty()); + + layer->drawSpecialLayer(mock, + 6, + 0, maxX, + 0, 0); + REQUIRE(mock->mDraws.empty()); + + layer->drawSpecialLayer(mock, + 20, + 0, maxX, + 0, 0); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 10 * 32); + REQUIRE(mock->mDraws[0].y == 20 * 32); + } + + delete map; + delete mock; + GraphicsManager::deleteRenderers(); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +} + +TEST_CASE("MapLayer drawSpecialLayer (tempLayer)", "") +{ + setEnv("SDL_VIDEODRIVER", "dummy"); + + logger = new Logger; + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + imageHelper = new SDLImageHelper; +#ifdef USE_SDL2 + SDLImageHelper::setRenderer(graphicsManager.createRenderer( + graphicsManager.createWindow(640, 480, 0, + SDL_WINDOW_SHOWN | SDL_SWSURFACE), SDL_RENDERER_SOFTWARE)); +#else // USE_SDL2 + + graphicsManager.createWindow(640, 480, 0, SDL_ANYFORMAT | SDL_SWSURFACE); +#endif // USE_SDL2 + + Map *map = nullptr; + MapLayer *layer = nullptr; + SpecialLayer *specialLayer = nullptr; + MockGraphics *const mock = new MockGraphics; + const Actors actors; + + SECTION("simple 1") + { + map = new Map("map", + 1, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 1, 1, + true, + 0, + 0); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + specialLayer = map->getTempLayer(); + + layer->drawSpecialLayer(mock, + 0, + 0, 1, + 0, 0); + REQUIRE(mock->mDraws.empty()); + + specialLayer->setTile(0, 0, MapItemType::ARROW_UP); + layer->drawSpecialLayer(mock, + 0, + 0, 1, + 0, 0); +// REQUIRE(mock->mDraws.size() == 1); + } + + SECTION("simple 2") + { + map = new Map("map", + 1, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 1, 1, + true, + 0, + 0); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + specialLayer = map->getTempLayer(); + specialLayer->setTile(0, 0, MapItemType::ARROW_UP); + specialLayer->updateCache(); + + layer->drawSpecialLayer(mock, + 0, + 0, 1, + 0, 0); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + } + + SECTION("simple 3") + { + map = new Map("map", + 2, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 2, 1, + true, + 0, + 0); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + specialLayer = map->getTempLayer(); + specialLayer->setTile(0, 0, MapItemType::ARROW_UP); + specialLayer->updateCache(); + + layer->drawSpecialLayer(mock, + 0, + 0, 2, + 0, 0); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + } + + SECTION("simple 4") + { + map = new Map("map", + 2, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 2, 1, + true, + 0, + 0); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + specialLayer = map->getTempLayer(); + const int *const cache = specialLayer->getCache(); + REQUIRE(cache[0] == 10000); + REQUIRE(cache[1] == 10000); + + specialLayer->setTile(1, 0, MapItemType::ARROW_UP); + specialLayer->updateCache(); + REQUIRE(cache[0] == 0); + REQUIRE(cache[1] == 10000); + + layer->drawSpecialLayer(mock, + 0, + 0, 2, + 0, 0); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 32); + REQUIRE(mock->mDraws[0].y == 0); + } + + SECTION("simple 5") + { + map = new Map("map", + 2, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 2, 1, + true, + 0, + 0); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + specialLayer = map->getTempLayer(); + specialLayer->setTile(0, 0, MapItemType::ARROW_UP); + specialLayer->setTile(1, 0, MapItemType::ARROW_UP); + specialLayer->updateCache(); + + layer->drawSpecialLayer(mock, + 0, + 0, 2, + 0, 0); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 32); + REQUIRE(mock->mDraws[1].y == 0); + } + + SECTION("simple 6") + { + map = new Map("map", + 3, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 3, 1, + true, + 0, + 0); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + specialLayer = map->getTempLayer(); + specialLayer->setTile(0, 0, MapItemType::ARROW_UP); + specialLayer->setTile(2, 0, MapItemType::ARROW_UP); + specialLayer->updateCache(); + + layer->drawSpecialLayer(mock, + 0, + 0, 3, + 0, 0); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 64); + REQUIRE(mock->mDraws[1].y == 0); + } + + SECTION("simple 7") + { + map = new Map("map", + 3, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 3, 1, + true, + 0, + 0); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + specialLayer = map->getTempLayer(); + specialLayer->setTile(1, 0, MapItemType::ARROW_UP); + specialLayer->setTile(2, 0, MapItemType::ARROW_UP); + specialLayer->updateCache(); + + layer->drawSpecialLayer(mock, + 0, + 0, 3, + 0, 0); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 32); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 64); + REQUIRE(mock->mDraws[1].y == 0); + } + + SECTION("simple 8") + { + map = new Map("map", + 3, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 3, 1, + true, + 0, + 0); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + specialLayer = map->getTempLayer(); + specialLayer->setTile(0, 0, MapItemType::ARROW_UP); + specialLayer->setTile(1, 0, MapItemType::ARROW_DOWN); + specialLayer->setTile(2, 0, MapItemType::ARROW_UP); + specialLayer->updateCache(); + + layer->drawSpecialLayer(mock, + 0, + 0, 3, + 0, 0); + REQUIRE(mock->mDraws.size() == 3); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 32); + REQUIRE(mock->mDraws[1].y == 0); + REQUIRE(mock->mDraws[2].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[2].x == 64); + REQUIRE(mock->mDraws[2].y == 0); + } + + SECTION("normal 1") + { + const int maxX = 100; + const int maxY = 50; + map = new Map("map", + maxX, maxY, + 32, 32); + layer = new MapLayer("test", + 0, 0, + maxX, maxY, + true, + 0, + 0); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + specialLayer = map->getTempLayer(); + specialLayer->setTile(0, 5, MapItemType::ARROW_UP); + specialLayer->setTile(1, 5, MapItemType::ARROW_DOWN); + specialLayer->setTile(2, 5, MapItemType::ARROW_UP); + specialLayer->setTile(3, 5, MapItemType::EMPTY); + specialLayer->setTile(4, 5, MapItemType::EMPTY); + specialLayer->setTile(6, 5, MapItemType::ARROW_LEFT); + specialLayer->setTile(10, 20, MapItemType::ARROW_LEFT); + specialLayer->updateCache(); + + layer->drawSpecialLayer(mock, + 5, + 0, maxX, + 0, 0); + REQUIRE(mock->mDraws.size() == 4); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 0 * 32); + REQUIRE(mock->mDraws[0].y == 5 * 32); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 1 * 32); + REQUIRE(mock->mDraws[1].y == 5 * 32); + REQUIRE(mock->mDraws[2].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[2].x == 2 * 32); + REQUIRE(mock->mDraws[2].y == 5 * 32); + REQUIRE(mock->mDraws[3].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[3].x == 6 * 32); + REQUIRE(mock->mDraws[3].y == 5 * 32); + + mock->mDraws.clear(); + layer->drawSpecialLayer(mock, + 4, + 0, maxX, + 0, 0); + REQUIRE(mock->mDraws.empty()); + + layer->drawSpecialLayer(mock, + 6, + 0, maxX, + 0, 0); + REQUIRE(mock->mDraws.empty()); + + layer->drawSpecialLayer(mock, + 20, + 0, maxX, + 0, 0); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 10 * 32); + REQUIRE(mock->mDraws[0].y == 20 * 32); + } + + delete map; + delete mock; + GraphicsManager::deleteRenderers(); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +} + +TEST_CASE("MapLayer drawFringe", "") +{ + setEnv("SDL_VIDEODRIVER", "dummy"); + + logger = new Logger; + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + imageHelper = new SDLImageHelper; +#ifdef USE_SDL2 + SDLImageHelper::setRenderer(graphicsManager.createRenderer( + graphicsManager.createWindow(640, 480, 0, + SDL_WINDOW_SHOWN | SDL_SWSURFACE), SDL_RENDERER_SOFTWARE)); +#else // USE_SDL2 + + graphicsManager.createWindow(640, 480, 0, SDL_ANYFORMAT | SDL_SWSURFACE); +#endif // USE_SDL2 + + theme = new Theme; + Theme::selectSkin(); + + localPlayer = new LocalPlayer(static_cast<BeingId>(1), + BeingTypeId_zero); + + Image *const img1 = new Image(32, 32); + Image *const img2 = new Image(32, 32); + Image *const img3 = new Image(32, 32); + Map *map = nullptr; + MapLayer *layer = nullptr; + MockGraphics *const mock = new MockGraphics; + const Actors actors; + + SECTION("simple 1") + { + map = new Map("map", + 1, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 1, 1, + true, + 0, + 0); + layer->setTile(0, 0, img1); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + layer->updateCache(1, 1); + + layer->drawFringe(mock, + 0, 0, + 1, 1, + 0, 0, + actors); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[0].image == img1); + + mock->mDraws.clear(); + layer->drawFringe(mock, + 0, 0, + 1, 1, + 10, 5, + actors); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == -10); + REQUIRE(mock->mDraws[0].y == -5); + REQUIRE(mock->mDraws[0].image == img1); + + mock->mDraws.clear(); + layer->drawFringe(mock, + 0, 0, + 1, 1, + -10, -5, + actors); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 10); + REQUIRE(mock->mDraws[0].y == 5); + REQUIRE(mock->mDraws[0].image == img1); + } + + SECTION("simple 2") + { + map = new Map("map", + 2, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 2, 1, + true, + 0, + 0); + layer->setTile(0, 0, img1); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + layer->updateCache(2, 1); + + layer->drawFringe(mock, + 0, 0, + 2, 1, + 0, 0, + actors); + + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[0].image == img1); + + mock->mDraws.clear(); + layer->drawFringe(mock, + 0, 0, + 2, 1, + 10, 5, + actors); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == -10); + REQUIRE(mock->mDraws[0].y == -5); + REQUIRE(mock->mDraws[0].image == img1); + + mock->mDraws.clear(); + layer->drawFringe(mock, + 0, 0, + 2, 1, + -10, -5, + actors); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 10); + REQUIRE(mock->mDraws[0].y == 5); + REQUIRE(mock->mDraws[0].image == img1); + } + + SECTION("simple 3") + { + map = new Map("map", + 2, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 2, 1, + true, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img2); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + layer->updateCache(2, 1); + + layer->drawFringe(mock, + 0, 0, + 2, 1, + 0, 0, + actors); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 32); + REQUIRE(mock->mDraws[1].y == 0); + REQUIRE(mock->mDraws[1].image == img2); + + mock->mDraws.clear(); + layer->drawFringe(mock, + 0, 0, + 2, 1, + -10, -20, + actors); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 10); + REQUIRE(mock->mDraws[0].y == 20); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 42); + REQUIRE(mock->mDraws[1].y == 20); + REQUIRE(mock->mDraws[1].image == img2); + } + + SECTION("simple 4") + { + map = new Map("map", + 2, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 2, 1, + true, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img1); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + layer->updateCache(2, 1); + + layer->drawFringe(mock, + 0, 0, + 2, 1, + 0, 0, + actors); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[0].width == 64); + REQUIRE(mock->mDraws[0].height == 32); + REQUIRE(mock->mDraws[0].image == img1); + + mock->mDraws.clear(); + layer->drawFringe(mock, + 0, 0, + 2, 1, + -10, 20, + actors); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[0].x == 10); + REQUIRE(mock->mDraws[0].y == -20); + REQUIRE(mock->mDraws[0].width == 64); + REQUIRE(mock->mDraws[0].height == 32); + REQUIRE(mock->mDraws[0].image == img1); + } + + SECTION("simple 4.2") + { + map = new Map("map", + 3, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 3, 1, + true, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(2, 0, img1); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + layer->updateCache(3, 1); + + layer->drawFringe(mock, + 0, 0, + 3, 1, + 0, 0, + actors); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 64); + REQUIRE(mock->mDraws[1].y == 0); + REQUIRE(mock->mDraws[1].image == img1); + + mock->mDraws.clear(); + layer->drawFringe(mock, + 0, 0, + 3, 1, + 10, -20, + actors); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == -10); + REQUIRE(mock->mDraws[0].y == 20); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 54); + REQUIRE(mock->mDraws[1].y == 20); + REQUIRE(mock->mDraws[1].image == img1); + } + + SECTION("simple 5") + { + map = new Map("map", + 3, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 3, 1, + true, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img1); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + layer->updateCache(3, 1); + + layer->drawFringe(mock, + 0, 0, + 3, 1, + 0, 0, + actors); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[0].width == 64); + REQUIRE(mock->mDraws[0].height == 32); + REQUIRE(mock->mDraws[0].image == img1); + + mock->mDraws.clear(); + layer->drawFringe(mock, + 0, 0, + 3, 1, + -10, 20, + actors); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[0].x == 10); + REQUIRE(mock->mDraws[0].y == -20); + REQUIRE(mock->mDraws[0].width == 64); + REQUIRE(mock->mDraws[0].height == 32); + REQUIRE(mock->mDraws[0].image == img1); + } + + SECTION("simple 6") + { + map = new Map("map", + 3, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 3, 1, + true, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img1); + layer->setTile(2, 0, img2); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + layer->updateCache(3, 1); + + layer->drawFringe(mock, + 0, 0, + 3, 1, + 0, 0, + actors); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[0].x == 0); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[0].width == 64); + REQUIRE(mock->mDraws[0].height == 32); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 64); + REQUIRE(mock->mDraws[1].y == 0); + REQUIRE(mock->mDraws[1].image == img2); + + mock->mDraws.clear(); + layer->drawFringe(mock, + 0, 0, + 3, 1, + -10, 20, + actors); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[0].x == 10); + REQUIRE(mock->mDraws[0].y == -20); + REQUIRE(mock->mDraws[0].width == 64); + REQUIRE(mock->mDraws[0].height == 32); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 74); + REQUIRE(mock->mDraws[1].y == -20); + REQUIRE(mock->mDraws[1].image == img2); + } + + SECTION("simple 7") + { + map = new Map("map", + 3, 1, + 32, 32); + layer = new MapLayer("test", + 0, 0, + 3, 1, + true, + 0, + 0); + layer->setTile(0, 0, img1); + layer->setTile(1, 0, img1); + layer->setTile(2, 0, img2); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + TileInfo *const tiles = layer->getTiles(); + tiles[0].isEnabled = false; + layer->updateCache(3, 1); + + layer->drawFringe(mock, + 0, 0, + 3, 1, + 0, 0, + actors); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 32); + REQUIRE(mock->mDraws[0].y == 0); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 64); + REQUIRE(mock->mDraws[1].y == 0); + REQUIRE(mock->mDraws[1].image == img2); + + mock->mDraws.clear(); + layer->drawFringe(mock, + 0, 0, + 3, 1, + -10, 20, + actors); + REQUIRE(mock->mDraws.size() == 2); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 42); + REQUIRE(mock->mDraws[0].y == -20); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 74); + REQUIRE(mock->mDraws[1].y == -20); + REQUIRE(mock->mDraws[1].image == img2); + } + + SECTION("normal 1") + { + const int maxX = 100; + const int maxY = 100; + map = new Map("map", + maxX, maxY, + 32, 32); + layer = new MapLayer("test", + 0, 0, + maxX, maxY, + true, + 0, + 0); + layer->setTile(1, 10, img1); + layer->setTile(2, 10, img1); + layer->setTile(3, 10, img1); + layer->setTile(4, 10, img2); + layer->setTile(5, 10, nullptr); + layer->setTile(6, 10, img2); + layer->setTile(7, 10, nullptr); + layer->setTile(8, 10, nullptr); + layer->setTile(9, 10, img2); + layer->setTile(10, 10, img2); + layer->setTile(11, 10, img3); + layer->setTile(12, 10, nullptr); + layer->setTile(13, 10, nullptr); + layer->setTile(14, 10, nullptr); + layer->setTile(15, 10, img1); + layer->setTile(16, 10, img1); + layer->setTile(17, 10, img1); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + layer->updateCache(maxX, maxY); + + layer->drawFringe(mock, + 0, 0, + maxX, maxY, + 0, 0, + actors); + REQUIRE(mock->mDraws.size() == 6); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[0].x == 32 * 1); + REQUIRE(mock->mDraws[0].y == 32 * 10); + REQUIRE(mock->mDraws[0].width == 96); + REQUIRE(mock->mDraws[0].height == 32); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 32 * 4); + REQUIRE(mock->mDraws[1].y == 32 * 10); + REQUIRE(mock->mDraws[1].image == img2); + REQUIRE(mock->mDraws[2].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[2].x == 32 * 6); + REQUIRE(mock->mDraws[2].y == 32 * 10); + REQUIRE(mock->mDraws[2].image == img2); + REQUIRE(mock->mDraws[3].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[3].x == 32 * 9); + REQUIRE(mock->mDraws[3].y == 32 * 10); + REQUIRE(mock->mDraws[3].width == 64); + REQUIRE(mock->mDraws[3].height == 32); + REQUIRE(mock->mDraws[3].image == img2); + REQUIRE(mock->mDraws[4].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[4].x == 32 * 11); + REQUIRE(mock->mDraws[4].y == 32 * 10); + REQUIRE(mock->mDraws[4].image == img3); + REQUIRE(mock->mDraws[5].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[5].x == 32 * 15); + REQUIRE(mock->mDraws[5].y == 32 * 10); + REQUIRE(mock->mDraws[5].width == 96); + REQUIRE(mock->mDraws[5].height == 32); + REQUIRE(mock->mDraws[5].image == img1); + + mock->mDraws.clear(); + layer->drawFringe(mock, + 0, 0, + maxX, maxY, + -10, 20, + actors); + REQUIRE(mock->mDraws.size() == 6); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[0].x == 32 * 1 + 10); + REQUIRE(mock->mDraws[0].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[0].width == 96); + REQUIRE(mock->mDraws[0].height == 32); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 32 * 4 + 10); + REQUIRE(mock->mDraws[1].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[1].image == img2); + REQUIRE(mock->mDraws[2].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[2].x == 32 * 6 + 10); + REQUIRE(mock->mDraws[2].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[2].image == img2); + REQUIRE(mock->mDraws[3].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[3].x == 32 * 9 + 10); + REQUIRE(mock->mDraws[3].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[3].width == 64); + REQUIRE(mock->mDraws[3].height == 32); + REQUIRE(mock->mDraws[3].image == img2); + REQUIRE(mock->mDraws[4].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[4].x == 32 * 11 + 10); + REQUIRE(mock->mDraws[4].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[4].image == img3); + REQUIRE(mock->mDraws[5].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[5].x == 32 * 15 + 10); + REQUIRE(mock->mDraws[5].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[5].width == 96); + REQUIRE(mock->mDraws[5].height == 32); + REQUIRE(mock->mDraws[5].image == img1); + } + + SECTION("normal2") + { + const int maxX = 100; + const int maxY = 100; + map = new Map("map", + maxX, maxY, + 32, 32); + layer = new MapLayer("test", + 0, 0, + maxX, maxY, + true, + 0, + 0); + TileInfo *const tiles = layer->getTiles(); + map->addLayer(layer); + layer->setSpecialLayer(map->getSpecialLayer()); + layer->setTempLayer(map->getTempLayer()); + for (int x = 0; x < maxX; x ++) + { + for (int y = 0; y < maxY; y ++) + { + layer->setTile(x, y, img1); + tiles[y * maxX + x].isEnabled = false; + } + } + tiles[10 * maxX + 41].isEnabled = true; + layer->updateCache(maxX, maxY); + + layer->drawFringe(mock, + 0, 0, + maxX, maxY, + 0, 0, + actors); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 32 * 41); + REQUIRE(mock->mDraws[0].y == 32 * 10); + + mock->mDraws.clear(); + layer->drawFringe(mock, + 0, 0, + maxX, maxY, + -10, 20, + actors); + REQUIRE(mock->mDraws.size() == 1); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 32 * 41 + 10); + REQUIRE(mock->mDraws[0].y == 32 * 10 - 20); + } + + SECTION("normal 3") + { + const int maxX = 100; + const int maxY = 100; + map = new Map("map", + maxX, maxY, + 32, 32); + layer = new MapLayer("test", + 0, 0, + maxX, maxY, + true, + 0, + 0); + layer->setTile(1, 10, img1); + layer->setTile(2, 10, img1); + layer->setTile(3, 10, img1); + layer->setTile(4, 10, img2); + layer->setTile(5, 10, nullptr); + layer->setTile(6, 10, img2); + layer->setTile(7, 10, nullptr); + layer->setTile(8, 10, nullptr); + layer->setTile(9, 10, img2); + layer->setTile(10, 10, img2); + layer->setTile(11, 10, img3); + layer->setTile(12, 10, nullptr); + layer->setTile(13, 10, nullptr); + layer->setTile(14, 10, nullptr); + layer->setTile(15, 10, img1); + layer->setTile(16, 10, img1); + layer->setTile(17, 10, img1); + map->addLayer(layer); + SpecialLayer *const specialLayer = map->getSpecialLayer(); + SpecialLayer *const tempLayer = map->getTempLayer(); + layer->setSpecialLayer(specialLayer); + layer->setTempLayer(tempLayer); + specialLayer->setTile(1, 10, MapItemType::ARROW_UP); + specialLayer->setTile(10, 10, MapItemType::ARROW_DOWN); + specialLayer->updateCache(); + layer->updateCache(maxX, maxY); + + layer->drawFringe(mock, + 0, 0, + maxX, maxY, + 0, 0, + actors); + REQUIRE(mock->mDraws.size() == 8); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[0].x == 32 * 1); + REQUIRE(mock->mDraws[0].y == 32 * 10); + REQUIRE(mock->mDraws[0].width == 96); + REQUIRE(mock->mDraws[0].height == 32); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 32 * 1); + REQUIRE(mock->mDraws[1].y == 32 * 10); +// REQUIRE(mock->mDraws[1].image == img2); + REQUIRE(mock->mDraws[2].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[2].x == 32 * 4); + REQUIRE(mock->mDraws[2].y == 32 * 10); + REQUIRE(mock->mDraws[2].image == img2); + REQUIRE(mock->mDraws[3].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[3].x == 32 * 6); + REQUIRE(mock->mDraws[3].y == 32 * 10); + REQUIRE(mock->mDraws[3].image == img2); + REQUIRE(mock->mDraws[4].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[4].x == 32 * 9); + REQUIRE(mock->mDraws[4].y == 32 * 10); + REQUIRE(mock->mDraws[4].width == 64); + REQUIRE(mock->mDraws[4].height == 32); + REQUIRE(mock->mDraws[4].image == img2); + REQUIRE(mock->mDraws[5].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[5].x == 32 * 10); + REQUIRE(mock->mDraws[5].y == 32 * 10); +// REQUIRE(mock->mDraws[5].image == img2); + REQUIRE(mock->mDraws[6].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[6].x == 32 * 11); + REQUIRE(mock->mDraws[6].y == 32 * 10); + REQUIRE(mock->mDraws[6].image == img3); + REQUIRE(mock->mDraws[7].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[7].x == 32 * 15); + REQUIRE(mock->mDraws[7].y == 32 * 10); + REQUIRE(mock->mDraws[7].width == 96); + REQUIRE(mock->mDraws[7].height == 32); + REQUIRE(mock->mDraws[7].image == img1); + + mock->mDraws.clear(); + layer->drawFringe(mock, + 0, 0, + maxX, maxY, + -10, 20, + actors); + REQUIRE(mock->mDraws.size() == 8); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[0].x == 32 * 1 + 10); + REQUIRE(mock->mDraws[0].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[0].width == 96); + REQUIRE(mock->mDraws[0].height == 32); + REQUIRE(mock->mDraws[0].image == img1); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[1].x == 32 * 1 + 10); + REQUIRE(mock->mDraws[1].y == 32 * 10 - 20); +// REQUIRE(mock->mDraws[1].image == img2); + REQUIRE(mock->mDraws[2].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[2].x == 32 * 4 + 10); + REQUIRE(mock->mDraws[2].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[2].image == img2); + REQUIRE(mock->mDraws[3].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[3].x == 32 * 6 + 10); + REQUIRE(mock->mDraws[3].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[3].image == img2); + REQUIRE(mock->mDraws[4].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[4].x == 32 * 9 + 10); + REQUIRE(mock->mDraws[4].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[4].width == 64); + REQUIRE(mock->mDraws[4].height == 32); + REQUIRE(mock->mDraws[4].image == img2); + REQUIRE(mock->mDraws[5].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[5].x == 32 * 10 + 10); + REQUIRE(mock->mDraws[5].y == 32 * 10 - 20); +// REQUIRE(mock->mDraws[5].image == img2); + REQUIRE(mock->mDraws[6].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[6].x == 32 * 11 + 10); + REQUIRE(mock->mDraws[6].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[6].image == img3); + REQUIRE(mock->mDraws[7].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[7].x == 32 * 15 + 10); + REQUIRE(mock->mDraws[7].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[7].width == 96); + REQUIRE(mock->mDraws[7].height == 32); + REQUIRE(mock->mDraws[7].image == img1); + } + + SECTION("normal 4") + { + const int maxX = 100; + const int maxY = 100; + map = new Map("map", + maxX, maxY, + 32, 32); + layer = new MapLayer("test", + 0, 0, + maxX, maxY, + true, + 0, + 0); + layer->setTile(1, 10, img1); + layer->setTile(2, 10, img1); + layer->setTile(3, 10, img1); + layer->setTile(4, 10, img2); + layer->setTile(5, 10, nullptr); + layer->setTile(6, 10, img2); + layer->setTile(7, 10, nullptr); + layer->setTile(8, 10, nullptr); + layer->setTile(9, 10, img2); + layer->setTile(10, 10, img2); + layer->setTile(11, 10, img3); + layer->setTile(12, 10, nullptr); + layer->setTile(13, 10, nullptr); + layer->setTile(14, 10, nullptr); + layer->setTile(15, 10, img1); + layer->setTile(16, 10, img1); + layer->setTile(17, 10, img1); + map->addLayer(layer); + SpecialLayer *const specialLayer = map->getSpecialLayer(); + SpecialLayer *const tempLayer = map->getTempLayer(); + layer->setSpecialLayer(specialLayer); + layer->setTempLayer(tempLayer); + specialLayer->setTile(0, 10, MapItemType::ARROW_UP); + specialLayer->setTile(10, 10, MapItemType::ARROW_DOWN); + specialLayer->setTile(90, 10, MapItemType::ARROW_DOWN); + specialLayer->updateCache(); + layer->updateCache(maxX, maxY); + + layer->drawFringe(mock, + 0, 0, + maxX - 20, maxY, + 0, 0, + actors); + REQUIRE(mock->mDraws.size() == 8); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 32 * 0); + REQUIRE(mock->mDraws[0].y == 32 * 10); +// REQUIRE(mock->mDraws[0].image == img2); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[1].x == 32 * 1); + REQUIRE(mock->mDraws[1].y == 32 * 10); + REQUIRE(mock->mDraws[1].width == 96); + REQUIRE(mock->mDraws[1].height == 32); + REQUIRE(mock->mDraws[1].image == img1); + REQUIRE(mock->mDraws[2].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[2].x == 32 * 4); + REQUIRE(mock->mDraws[2].y == 32 * 10); + REQUIRE(mock->mDraws[2].image == img2); + REQUIRE(mock->mDraws[3].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[3].x == 32 * 6); + REQUIRE(mock->mDraws[3].y == 32 * 10); + REQUIRE(mock->mDraws[3].image == img2); + REQUIRE(mock->mDraws[4].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[4].x == 32 * 9); + REQUIRE(mock->mDraws[4].y == 32 * 10); + REQUIRE(mock->mDraws[4].width == 64); + REQUIRE(mock->mDraws[4].height == 32); + REQUIRE(mock->mDraws[4].image == img2); + REQUIRE(mock->mDraws[5].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[5].x == 32 * 10); + REQUIRE(mock->mDraws[5].y == 32 * 10); +// REQUIRE(mock->mDraws[5].image == img2); + REQUIRE(mock->mDraws[6].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[6].x == 32 * 11); + REQUIRE(mock->mDraws[6].y == 32 * 10); + REQUIRE(mock->mDraws[6].image == img3); + REQUIRE(mock->mDraws[7].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[7].x == 32 * 15); + REQUIRE(mock->mDraws[7].y == 32 * 10); + REQUIRE(mock->mDraws[7].width == 96); + REQUIRE(mock->mDraws[7].height == 32); + REQUIRE(mock->mDraws[7].image == img1); + + mock->mDraws.clear(); + layer->drawFringe(mock, + 0, 0, + maxX - 20, maxY, + -10, 20, + actors); + REQUIRE(mock->mDraws.size() == 8); + REQUIRE(mock->mDraws[0].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[0].x == 32 * 0 + 10); + REQUIRE(mock->mDraws[0].y == 32 * 10 - 20); +// REQUIRE(mock->mDraws[0].image == img2); + REQUIRE(mock->mDraws[1].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[1].x == 32 * 1 + 10); + REQUIRE(mock->mDraws[1].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[1].width == 96); + REQUIRE(mock->mDraws[1].height == 32); + REQUIRE(mock->mDraws[1].image == img1); + REQUIRE(mock->mDraws[2].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[2].x == 32 * 4 + 10); + REQUIRE(mock->mDraws[2].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[2].image == img2); + REQUIRE(mock->mDraws[3].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[3].x == 32 * 6 + 10); + REQUIRE(mock->mDraws[3].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[3].image == img2); + REQUIRE(mock->mDraws[4].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[4].x == 32 * 9 + 10); + REQUIRE(mock->mDraws[4].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[4].width == 64); + REQUIRE(mock->mDraws[4].height == 32); + REQUIRE(mock->mDraws[4].image == img2); + REQUIRE(mock->mDraws[5].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[5].x == 32 * 10 + 10); + REQUIRE(mock->mDraws[5].y == 32 * 10 - 20); +// REQUIRE(mock->mDraws[5].image == img2); + REQUIRE(mock->mDraws[6].drawType == MockDrawType::DrawImage); + REQUIRE(mock->mDraws[6].x == 32 * 11 + 10); + REQUIRE(mock->mDraws[6].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[6].image == img3); + REQUIRE(mock->mDraws[7].drawType == MockDrawType::DrawPattern); + REQUIRE(mock->mDraws[7].x == 32 * 15 + 10); + REQUIRE(mock->mDraws[7].y == 32 * 10 - 20); + REQUIRE(mock->mDraws[7].width == 96); + REQUIRE(mock->mDraws[7].height == 32); + REQUIRE(mock->mDraws[7].image == img1); + } + + delete2(localPlayer); + delete map; + delete img1; + delete img2; + delete img3; + delete mock; + delete2(theme); + GraphicsManager::deleteRenderers(); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +} diff --git a/src/unittests/resources/map/speciallayer_unittest.cc b/src/unittests/resources/map/speciallayer_unittest.cc new file mode 100644 index 000000000..0461a98c4 --- /dev/null +++ b/src/unittests/resources/map/speciallayer_unittest.cc @@ -0,0 +1,291 @@ +/* + * The ManaPlus Client + * Copyright (C) 2016-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "client.h" +#include "logger.h" + +#include "graphicsmanager.h" + +#include "being/actorsprite.h" + +#include "enums/resources/map/mapitemtype.h" + +#include "fs/virtfs/fs.h" + +#include "gui/gui.h" + +#include "utils/delete2.h" +#include "utils/env.h" + +#include "resources/sdlimagehelper.h" + +#include "resources/map/speciallayer.h" + +#include "resources/resourcemanager/resourcemanager.h" + +#include "debug.h" + +TEST_CASE("SpecialLayer leak test1", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} + +TEST_CASE("SpecialLayer updateCache", "") +{ + setEnv("SDL_VIDEODRIVER", "dummy"); + + logger = new Logger; + client = new Client; + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + imageHelper = new SDLImageHelper; +#ifdef USE_SDL2 + SDLImageHelper::setRenderer(graphicsManager.createRenderer( + graphicsManager.createWindow(640, 480, 0, + SDL_WINDOW_SHOWN | SDL_SWSURFACE), SDL_RENDERER_SOFTWARE)); +#else // USE_SDL2 + + graphicsManager.createWindow(640, 480, 0, SDL_ANYFORMAT | SDL_SWSURFACE); +#endif // USE_SDL2 + + ActorSprite::load(); + + SpecialLayer *layer = nullptr; + + SECTION("simple 1") + { + layer = new SpecialLayer("test", + 1, 1); + const int *const cache = layer->getCache(); + REQUIRE(cache[0] == 10000); + layer->setTile(0, 0, MapItemType::ARROW_UP); + layer->updateCache(); + REQUIRE(cache[0] == 10000); + } + + SECTION("simple 2") + { + layer = new SpecialLayer("test", + 2, 1); + const int *const cache = layer->getCache(); + REQUIRE(cache[0] == 10000); + REQUIRE(cache[1] == 10000); + layer->setTile(0, 0, MapItemType::ARROW_UP); + layer->updateCache(); + REQUIRE(cache[0] == 10000); + REQUIRE(cache[1] == 10000); + } + + SECTION("simple 3") + { + layer = new SpecialLayer("test", + 2, 1); + layer->setTile(0, 0, MapItemType::ARROW_UP); + layer->setTile(1, 0, MapItemType::ARROW_DOWN); + const int *const cache = layer->getCache(); + layer->updateCache(); + REQUIRE(cache[0] == 0); + REQUIRE(cache[1] == 10000); + } + + SECTION("simple 4") + { + layer = new SpecialLayer("test", + 2, 1); + layer->setTile(0, 0, MapItemType::ARROW_UP); + layer->setTile(1, 0, MapItemType::ARROW_UP); + const int *const cache = layer->getCache(); + layer->updateCache(); + REQUIRE(cache[0] == 0); + REQUIRE(cache[1] == 10000); + } + + SECTION("simple 4.2") + { + layer = new SpecialLayer("test", + 3, 1); + layer->setTile(0, 0, MapItemType::ARROW_UP); + layer->setTile(2, 0, MapItemType::ARROW_UP); + const int *const cache = layer->getCache(); + layer->updateCache(); + REQUIRE(cache[0] == 1); + REQUIRE(cache[1] == 0); + REQUIRE(cache[2] == 10000); + } + + SECTION("simple 5") + { + layer = new SpecialLayer("test", + 3, 1); + layer->setTile(0, 0, MapItemType::ARROW_UP); + layer->setTile(1, 0, MapItemType::ARROW_UP); + const int *const cache = layer->getCache(); + layer->updateCache(); + REQUIRE(cache[0] == 0); + REQUIRE(cache[1] == 10000); + REQUIRE(cache[2] == 10000); + } + + SECTION("simple 6") + { + layer = new SpecialLayer("test", + 3, 1); + layer->setTile(0, 0, MapItemType::ARROW_UP); + layer->setTile(1, 0, MapItemType::ARROW_UP); + layer->setTile(2, 0, MapItemType::ARROW_DOWN); + const int *const cache = layer->getCache(); + layer->updateCache(); + REQUIRE(cache[0] == 0); + REQUIRE(cache[1] == 0); + REQUIRE(cache[2] == 10000); + } + + SECTION("simple 7") + { + layer = new SpecialLayer("test", + 3, 1); + const int *const cache = layer->getCache(); + layer->updateCache(); + REQUIRE(cache[0] == 10000); + REQUIRE(cache[1] == 10000); + REQUIRE(cache[2] == 10000); + } + + SECTION("simple 8") + { + layer = new SpecialLayer("test", + 3, 1); + layer->setTile(0, 0, MapItemType::EMPTY); + layer->setTile(1, 0, MapItemType::EMPTY); + layer->setTile(2, 0, MapItemType::EMPTY); + const int *const cache = layer->getCache(); + layer->updateCache(); + REQUIRE(cache[0] == 10000); + REQUIRE(cache[1] == 10000); + REQUIRE(cache[2] == 10000); + } + + SECTION("simple 9") + { + layer = new SpecialLayer("test", + 2, 1); + const int *const cache = layer->getCache(); + REQUIRE(cache[0] == 10000); + REQUIRE(cache[1] == 10000); + layer->setTile(1, 0, MapItemType::ARROW_UP); + layer->updateCache(); + REQUIRE(cache[0] == 0); + REQUIRE(cache[1] == 10000); + } + + SECTION("normal 1") + { + layer = new SpecialLayer("test", + 100, 100); + layer->setTile(1, 10, MapItemType::ARROW_UP); + layer->setTile(2, 10, MapItemType::ARROW_UP); + layer->setTile(3, 10, MapItemType::ARROW_UP); + layer->setTile(4, 10, MapItemType::ARROW_DOWN); + layer->setTile(5, 10, MapItemType::EMPTY); + layer->setTile(6, 10, MapItemType::ARROW_DOWN); + layer->setTile(7, 10, MapItemType::EMPTY); + layer->setTile(8, 10, MapItemType::EMPTY); + layer->setTile(9, 10, MapItemType::ARROW_DOWN); + layer->setTile(10, 10, MapItemType::ARROW_DOWN); + layer->setTile(11, 10, MapItemType::ARROW_LEFT); + layer->setTile(12, 10, MapItemType::EMPTY); + layer->setTile(13, 10, MapItemType::EMPTY); + layer->setTile(14, 10, MapItemType::EMPTY); + layer->setTile(15, 10, MapItemType::ARROW_UP); + layer->setTile(16, 10, MapItemType::ARROW_UP); + layer->setTile(17, 10, MapItemType::ARROW_UP); + const int *const cache = layer->getCache(); + layer->updateCache(); + + REQUIRE(cache[10 * 100 + 0] == 0); + REQUIRE(cache[10 * 100 + 1] == 0); + REQUIRE(cache[10 * 100 + 2] == 0); + REQUIRE(cache[10 * 100 + 3] == 0); + REQUIRE(cache[10 * 100 + 4] == 1); + REQUIRE(cache[10 * 100 + 5] == 0); + REQUIRE(cache[10 * 100 + 6] == 2); + REQUIRE(cache[10 * 100 + 7] == 1); + REQUIRE(cache[10 * 100 + 8] == 0); + REQUIRE(cache[10 * 100 + 9] == 0); + REQUIRE(cache[10 * 100 + 10] == 0); + REQUIRE(cache[10 * 100 + 11] == 3); + REQUIRE(cache[10 * 100 + 12] == 2); + REQUIRE(cache[10 * 100 + 13] == 1); + REQUIRE(cache[10 * 100 + 14] == 0); + REQUIRE(cache[10 * 100 + 15] == 0); + REQUIRE(cache[10 * 100 + 16] == 0); + REQUIRE(cache[10 * 100 + 17] == 10000); + } + + SECTION("normal2") + { + const int maxX = 100; + const int maxY = 100; + layer = new SpecialLayer("test", + maxX, maxY); + const int *const cache = layer->getCache(); + for (int x = 0; x < maxX; x ++) + { + for (int y = 0; y < maxY; y ++) + { + layer->setTile(x, y, MapItemType::ARROW_UP); + REQUIRE(layer->getTiles()[x + y * maxX] != nullptr); + } + } + layer->updateCache(); + + for (int y = 0; y < maxY; y ++) + { + for (int x = 0; x < maxX - 1; x ++) + { + REQUIRE(cache[y * maxX + x] == 0); + } + REQUIRE(cache[y * maxX + maxX - 1] == 10000); + } + } + + delete layer; + ResourceManager::cleanOrphans(); + delete2(client); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +} + +TEST_CASE("SpecialLayer leak test2", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} diff --git a/src/unittests/resources/mstack_unittest.cc b/src/unittests/resources/mstack_unittest.cc new file mode 100644 index 000000000..1d2233803 --- /dev/null +++ b/src/unittests/resources/mstack_unittest.cc @@ -0,0 +1,165 @@ +/* + * The ManaPlus Client + * Copyright (C) 2015-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "gui/cliprect.h" + +#include "resources/mstack.h" + +#include "debug.h" + +TEST_CASE("mstack push 1", "") +{ + MStack<ClipRect> stack(10); + REQUIRE(-1 == (stack.mPointer - stack.mStack)); + REQUIRE(0 == stack.mStack[0].xOffset); + + ClipRect &val1 = stack.push(); + val1.xOffset = 10; + ClipRect &val2 = stack.top(); + REQUIRE(0 == stack.mPointer - stack.mStack); + REQUIRE(10 == val2.xOffset); + REQUIRE(10 == stack.mStack[0].xOffset); + REQUIRE(0 == stack.mStack[1].xOffset); + + val2.yOffset = 2; + REQUIRE(2 == val1.yOffset); +} + +TEST_CASE("mstack push 2", "") +{ + MStack<ClipRect> stack(10); + ClipRect &val1 = stack.push(); + val1.xOffset = 10; + const ClipRect &val2 = stack.top(); + REQUIRE(10 == val2.xOffset); + REQUIRE(10 == stack.mStack[0].xOffset); + + val1.yOffset = 2; + REQUIRE(2 == val2.yOffset); + REQUIRE(2 == stack.mStack[0].yOffset); +} + +TEST_CASE("mstack push 3", "") +{ + MStack<ClipRect> stack(10); + ClipRect &val1 = stack.push(); + val1.xOffset = 10; + ClipRect &val2 = stack.top(); + REQUIRE(10 == val2.xOffset); + REQUIRE(10 == stack.mStack[0].xOffset); +} + +TEST_CASE("mstack push 4", "") +{ + MStack<ClipRect> stack(10); + ClipRect &val1 = stack.push(); + val1.xOffset = 10; + REQUIRE(10 == val1.xOffset); + REQUIRE(10 == stack.mStack[0].xOffset); + REQUIRE(0 == stack.mStack[1].xOffset); + REQUIRE(0 == stack.mStack[2].xOffset); + + ClipRect &val2 = stack.push(); + val2.xOffset = 20; + REQUIRE(20 == val2.xOffset); + REQUIRE(10 == stack.mStack[0].xOffset); + REQUIRE(20 == stack.mStack[1].xOffset); + REQUIRE(0 == stack.mStack[2].xOffset); + + ClipRect &val3 = stack.push(); + val3.xOffset = 30; + REQUIRE(30 == val3.xOffset); + REQUIRE(10 == stack.mStack[0].xOffset); + REQUIRE(20 == stack.mStack[1].xOffset); + REQUIRE(30 == stack.mStack[2].xOffset); +} + +TEST_CASE("mstack pop 1", "") +{ + MStack<ClipRect> stack(10); + ClipRect &val1 = stack.push(); + val1.xOffset = 10; + REQUIRE(10 == stack.mStack[0].xOffset); + + stack.pop(); + REQUIRE(-1 == stack.mPointer - stack.mStack); +} + +TEST_CASE("mstack pop 2", "") +{ + MStack<ClipRect> stack(10); + ClipRect &val1 = stack.push(); + REQUIRE(0 == stack.mPointer - stack.mStack); + + val1.xOffset = 10; + REQUIRE(10 == stack.mStack[0].xOffset); + + ClipRect &val2 = stack.push(); + REQUIRE(1 == stack.mPointer - stack.mStack); + + val2.xOffset = 20; + REQUIRE(10 == stack.mStack[0].xOffset); + REQUIRE(20 == stack.mStack[1].xOffset); + + stack.pop(); + REQUIRE(0 == stack.mPointer - stack.mStack); + REQUIRE(10 == stack.mStack[0].xOffset); + REQUIRE(20 == stack.mStack[1].xOffset); + + ClipRect &val3 = stack.top(); + REQUIRE(0 == stack.mPointer - stack.mStack); + REQUIRE(10 == val1.xOffset); + REQUIRE(20 == val2.xOffset); + REQUIRE(10 == val3.xOffset); + REQUIRE(10 == stack.mStack[0].xOffset); + REQUIRE(20 == stack.mStack[1].xOffset); + REQUIRE(0 == stack.mStack[2].xOffset); +} + +TEST_CASE("mstack clear 1", "") +{ + MStack<ClipRect> stack(10); + REQUIRE(-1 == stack.mPointer - stack.mStack); + REQUIRE(0 == stack.mStack[0].xOffset); + + ClipRect &val1 = stack.push(); + val1.xOffset = 10; + + stack.clear(); + REQUIRE(-1 == stack.mPointer - stack.mStack); + REQUIRE(10 == stack.mStack[0].xOffset); + REQUIRE(0 == stack.mStack[1].xOffset); +} + +TEST_CASE("mstack getpop 1", "") +{ + MStack<ClipRect> stack(10); + ClipRect &val1 = stack.push(); + val1.xOffset = 10; + REQUIRE(10 == stack.mStack[0].xOffset); + REQUIRE(10 == val1.xOffset); + + ClipRect &val2 = stack.getPop(); + REQUIRE(-1 == stack.mPointer - stack.mStack); + REQUIRE(10 == stack.mStack[0].xOffset); + REQUIRE(10 == val2.xOffset); +} diff --git a/src/unittests/resources/resourcemanager/resourcemanager_unittest.cc b/src/unittests/resources/resourcemanager/resourcemanager_unittest.cc new file mode 100644 index 000000000..90bc873ab --- /dev/null +++ b/src/unittests/resources/resourcemanager/resourcemanager_unittest.cc @@ -0,0 +1,701 @@ +/* + * The ManaPlus Client + * Copyright (C) 2013-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "client.h" +#include "dirs.h" +#include "logger.h" +#include "graphicsmanager.h" + +#include "being/actorsprite.h" + +#include "fs/virtfs/fs.h" + +#include "gui/gui.h" + +#include "resources/sdlimagehelper.h" + +#include "resources/resourcemanager/resourcemanager.h" + +#include "utils/env.h" +#include "utils/delete2.h" + +#include <unistd.h> + +PRAGMA48(GCC diagnostic push) +PRAGMA48(GCC diagnostic ignored "-Wshadow") +#ifndef USE_SDL2 +#include <SDL.h> +#endif // USE_SDL2 +PRAGMA48(GCC diagnostic pop) + +#include "debug.h" + +namespace +{ + int testResouceCounter = 0; + + class TestResource : public Resource + { + public: + TestResource() : + Resource() + { + testResouceCounter ++; + } + + ~TestResource() + { + testResouceCounter --; + } + }; + + struct TestLoader final + { + std::string path; + static Resource *load(const void *const v) + { + BLOCK_START("TestLoader::load") + if (v == nullptr) + { + BLOCK_END("TestLoader::load") + return nullptr; + } + + Resource *const res = new TestResource(); + BLOCK_END("TestLoader::load") + return res; + } + }; + +} // namespace + +TEST_CASE("resourcemanager leak test1", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} + +TEST_CASE("resourcemanager", "resourcemanager") +{ + setEnv("SDL_VIDEODRIVER", "dummy"); + + client = new Client; + XML::initXML(); + SDL_Init(SDL_INIT_VIDEO); + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + imageHelper = new SDLImageHelper(); +#ifdef USE_SDL2 + SDLImageHelper::setRenderer(graphicsManager.createRenderer( + graphicsManager.createWindow(640, 480, 0, + SDL_WINDOW_SHOWN | SDL_SWSURFACE), SDL_RENDERER_SOFTWARE)); +#else // USE_SDL2 + + graphicsManager.createWindow(640, 480, 0, SDL_ANYFORMAT | SDL_SWSURFACE); +#endif // USE_SDL2 + + ActorSprite::load(); + + Dirs::initRootDir(); + Dirs::initHomeDir(); + +// ConfigManager::initConfiguration(); +// getConfigDefaults2(config.getDefaultValues()); + + while (ResourceManager::cleanOrphans(true)) + continue; + + testResouceCounter = 0; + const size_t resSize = ResourceManager::getResources().size(); + + SECTION("resourcemanager get 0") + { + REQUIRE(testResouceCounter == 0); + REQUIRE(ResourceManager::getResources().size() == 0 + resSize); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + } + + SECTION("resourcemanager get 1") + { + REQUIRE(testResouceCounter == 0); + TestLoader rl = { "test1" }; + Resource *res = ResourceManager::get("test1", + TestLoader::load, &rl); + REQUIRE(testResouceCounter == 1); + REQUIRE(res != nullptr); + REQUIRE(res->mRefCount == 1); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + res->decRef(); + REQUIRE(res->mRefCount == 0); + } + + SECTION("resourcemanager get 2") + { + TestLoader rl = { "test1" }; + Resource *const res = ResourceManager::get("test1", + TestLoader::load, &rl); + REQUIRE(res != nullptr); + REQUIRE(testResouceCounter == 1); + REQUIRE(res->mRefCount == 1); + res->mSource = "source 1"; + REQUIRE(res->mSource == "source 1"); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + Resource *const res2 = ResourceManager::get("test1", + TestLoader::load, &rl); + REQUIRE(res2 != nullptr); + REQUIRE(testResouceCounter == 1); + REQUIRE(res->mRefCount == 2); + REQUIRE(res2->mRefCount == 2); + REQUIRE(res->mIdPath == res2->mIdPath); + REQUIRE(res2->mSource == "source 1"); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res2); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + res->decRef(); + res2->decRef(); + REQUIRE(res->mRefCount == 0); + } + + SECTION("resourcemanager get 3") + { + TestLoader rl = { "test1" }; + Resource *res = ResourceManager::get("test1", + TestLoader::load, &rl); + REQUIRE(res != nullptr); + REQUIRE(testResouceCounter == 1); + REQUIRE(res->mRefCount == 1); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + res->mSource = "source 1"; + res->decRef(); + REQUIRE(ResourceManager::getResources().size() == 0 + resSize); + REQUIRE(ResourceManager::getOrphanedResources()["test1"] == res); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + REQUIRE(res->mRefCount == 0); + } + + SECTION("resourcemanager get 4") + { + TestLoader rl = { "test1" }; + Resource *res = ResourceManager::get("test1", + TestLoader::load, &rl); + REQUIRE(res != nullptr); + REQUIRE(testResouceCounter == 1); + REQUIRE(res->mRefCount == 1); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + res->mSource = "source 1"; + res->decRef(); + REQUIRE(res->mRefCount == 0); + REQUIRE(ResourceManager::getResources().size() == 0 + resSize); + REQUIRE(ResourceManager::getOrphanedResources()["test1"] == res); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + + Resource *const res2 = ResourceManager::get("test1", + TestLoader::load, &rl); + REQUIRE(res2 != nullptr); + REQUIRE(testResouceCounter == 1); + REQUIRE(res2->mRefCount == 1); + REQUIRE(res->mIdPath == res2->mIdPath); + REQUIRE(res2->mSource == "source 1"); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res2); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + res2->decRef(); + REQUIRE(res->mRefCount == 0); + } + + SECTION("resourcemanager get 5") + { + TestLoader rl = { "test1" }; + Resource *res = ResourceManager::get("test1", + TestLoader::load, &rl); + REQUIRE(ResourceManager::isInCache("test1") == true); + REQUIRE(res != nullptr); + REQUIRE(testResouceCounter == 1); + REQUIRE(res->mRefCount == 1); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + res->mSource = "source 1"; + res->decRef(); + REQUIRE(res->mRefCount == 0); + REQUIRE(ResourceManager::getResources().size() == 0 + resSize); + REQUIRE(ResourceManager::getOrphanedResources().size() == 1); + REQUIRE(ResourceManager::getOrphanedResources()["test1"] == res); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + + sleep(33); + ResourceManager::cleanOrphans(); + REQUIRE(ResourceManager::isInCache("test1") == false); + REQUIRE(testResouceCounter == 0); + REQUIRE(ResourceManager::getResources().size() == 0 + resSize); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + + Resource *const res2 = ResourceManager::get("test1", + TestLoader::load, &rl); + REQUIRE(ResourceManager::isInCache("test1") == true); + REQUIRE(res2 != nullptr); + REQUIRE(testResouceCounter == 1); + REQUIRE(res2->mRefCount == 1); + REQUIRE(res2->mSource.empty()); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res2); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + res2->decRef(); + REQUIRE(res2->mRefCount == 0); + } + + SECTION("resourcemanager get 6") + { + TestLoader rl = { "test1" }; + Resource *res = ResourceManager::get("test1", + TestLoader::load, &rl); + REQUIRE(res != nullptr); + REQUIRE(testResouceCounter == 1); + REQUIRE(res->mRefCount == 1); + res->mSource = "source 1"; + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + + Resource *const res2 = ResourceManager::get("test2", + TestLoader::load, &rl); + REQUIRE(res2 != nullptr); + REQUIRE(testResouceCounter == 2); + REQUIRE(res2->mRefCount == 1); + REQUIRE(res2->mSource.empty()); + REQUIRE(ResourceManager::getResources().size() == 2 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getResources()["test2"] == res2); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + res->decRef(); + res2->decRef(); + REQUIRE(res->mRefCount == 0); + REQUIRE(res2->mRefCount == 0); + } + + SECTION("resourcemanager getFromCache 1") + { + TestLoader rl = { "test1" }; + Resource *res = ResourceManager::get("test1", + TestLoader::load, &rl); + REQUIRE(res != nullptr); + REQUIRE(testResouceCounter == 1); + REQUIRE(res->mRefCount == 1); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + Resource *const res2 = ResourceManager::getFromCache("test1"); + REQUIRE(res2 != nullptr); + REQUIRE(testResouceCounter == 1); + REQUIRE(res2->mRefCount == 2); + REQUIRE(res == res2); + REQUIRE(res2->mSource.empty()); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res2); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + res->decRef(); + res->decRef(); + REQUIRE(res->mRefCount == 0); + } + + SECTION("resourcemanager getFromCache 2") + { + TestLoader rl = { "test1" }; + Resource *res = ResourceManager::get("test1", + TestLoader::load, &rl); + REQUIRE(res != nullptr); + REQUIRE(testResouceCounter == 1); + REQUIRE(res->mRefCount == 1); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + res->decRef(); + REQUIRE(res->mRefCount == 0); + Resource *const res2 = ResourceManager::getFromCache("test1"); + REQUIRE(res2 != nullptr); + REQUIRE(testResouceCounter == 1); + REQUIRE(res2->mRefCount == 1); + REQUIRE(res == res2); + REQUIRE(res2->mSource.empty()); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res2); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + res->decRef(); + REQUIRE(res->mRefCount == 0); + } + + SECTION("resourcemanager getFromCache 3") + { + TestLoader rl = { "test1" }; + Resource *res = ResourceManager::get("test1", + TestLoader::load, &rl); + REQUIRE(res != nullptr); + REQUIRE(testResouceCounter == 1); + REQUIRE(res->mRefCount == 1); + res->mSource = "source 1"; + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + + Resource *const res2 = ResourceManager::get("test2", + TestLoader::load, &rl); + REQUIRE(res2 != nullptr); + REQUIRE(testResouceCounter == 2); + REQUIRE(res2->mRefCount == 1); + REQUIRE(res2->mSource.empty()); + REQUIRE(ResourceManager::getResources().size() == 2 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getResources()["test2"] == res2); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + + Resource *const resC = ResourceManager::getFromCache("test1"); + Resource *const res2C = ResourceManager::getFromCache("test2"); + REQUIRE(resC != nullptr); + REQUIRE(res2C != nullptr); + REQUIRE(testResouceCounter == 2); + REQUIRE(res == resC); + REQUIRE(res2 == res2C); + REQUIRE(resC->mRefCount == 2); + REQUIRE(res2C->mRefCount == 2); + REQUIRE(ResourceManager::getResources().size() == 2 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == resC); + REQUIRE(ResourceManager::getResources()["test2"] == res2C); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + + res->decRef(); + res->decRef(); + res2->decRef(); + res2->decRef(); + REQUIRE(res->mRefCount == 0); + REQUIRE(res2->mRefCount == 0); + } + + SECTION("resourcemanager addResource 1") + { + REQUIRE(testResouceCounter == 0); + Resource *res = new TestResource(); + REQUIRE(testResouceCounter == 1); + ResourceManager::addResource("test1", res); + REQUIRE(res != nullptr); + REQUIRE(res->mRefCount == 1); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + res->decRef(); + REQUIRE(res->mRefCount == 0); + } + + SECTION("resourcemanager isInCache 1") + { + REQUIRE(testResouceCounter == 0); + TestLoader rl = { "test1" }; + REQUIRE(ResourceManager::isInCache("test1") == false); + Resource *res = ResourceManager::get("test1", + TestLoader::load, &rl); + REQUIRE(ResourceManager::isInCache("test1") == true); + REQUIRE(ResourceManager::isInCache("test2") == false); + REQUIRE(testResouceCounter == 1); + REQUIRE(res != nullptr); + REQUIRE(res->mRefCount == 1); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + res->decRef(); + REQUIRE(res->mRefCount == 0); + } + + SECTION("resourcemanager getTempResource 1") + { + TestLoader rl = { "test1" }; + REQUIRE(ResourceManager::getTempResource("test1") == nullptr); + Resource *res = ResourceManager::get("test1", + TestLoader::load, &rl); + REQUIRE(res != nullptr); + REQUIRE(testResouceCounter == 1); + REQUIRE(res->mRefCount == 1); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + Resource *const res2 = ResourceManager::getTempResource("test1"); + REQUIRE(ResourceManager::getTempResource("test2") == nullptr); + REQUIRE(res2 != nullptr); + REQUIRE(testResouceCounter == 1); + REQUIRE(res2->mRefCount == 1); + REQUIRE(res == res2); + REQUIRE(res2->mSource.empty()); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res2); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + res->decRef(); + REQUIRE(res->mRefCount == 0); + } + + SECTION("resourcemanager moveToDeleted 1") + { + REQUIRE(testResouceCounter == 0); + TestLoader rl = { "test1" }; + Resource *res = ResourceManager::get("test1", + TestLoader::load, &rl); + REQUIRE(testResouceCounter == 1); + REQUIRE(res != nullptr); + REQUIRE(res->mRefCount == 1); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + ResourceManager::moveToDeleted(res); + REQUIRE(testResouceCounter == 0); + REQUIRE(ResourceManager::getResources().size() == 0 + resSize); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + } + + SECTION("resourcemanager moveToDeleted 2") + { + REQUIRE(testResouceCounter == 0); + TestLoader rl = { "test1" }; + Resource *res = ResourceManager::get("test1", + TestLoader::load, &rl); + res->incRef(); + REQUIRE(testResouceCounter == 1); + REQUIRE(res != nullptr); + REQUIRE(res->mRefCount == 2); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + ResourceManager::moveToDeleted(res); + REQUIRE(testResouceCounter == 1); + REQUIRE(res->mRefCount == 1); + REQUIRE(ResourceManager::getResources().size() == 0 + resSize); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().size() == 1); + res->decRef(); + } + + SECTION("resourcemanager moveToDeleted 3") + { + REQUIRE(testResouceCounter == 0); + TestLoader rl = { "test1" }; + Resource *res = ResourceManager::get("test1", + TestLoader::load, &rl); + REQUIRE(testResouceCounter == 1); + REQUIRE(res != nullptr); + REQUIRE(res->mRefCount == 1); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + + res->decRef(); + REQUIRE(testResouceCounter == 1); + REQUIRE(res->mRefCount == 0); + REQUIRE(ResourceManager::getResources().size() == 0 + resSize); + REQUIRE(ResourceManager::getOrphanedResources().size() == 1); + REQUIRE(ResourceManager::getOrphanedResources()["test1"] == res); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + + ResourceManager::moveToDeleted(res); + REQUIRE(testResouceCounter == 0); + REQUIRE(ResourceManager::getResources().size() == 0 + resSize); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + } + + SECTION("resourcemanager decRefDelete 1") + { + REQUIRE(testResouceCounter == 0); + TestLoader rl = { "test1" }; + Resource *res = ResourceManager::get("test1", + TestLoader::load, &rl); + REQUIRE(testResouceCounter == 1); + REQUIRE(res != nullptr); + REQUIRE(res->mRefCount == 1); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + + ResourceManager::decRefDelete(res); + REQUIRE(testResouceCounter == 0); + REQUIRE(ResourceManager::getResources().size() == 0 + resSize); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + } + + SECTION("resourcemanager cleanUp 1") + { + REQUIRE(testResouceCounter == 0); + TestLoader rl = { "test1" }; + Resource *res = ResourceManager::get("test1", + TestLoader::load, &rl); + REQUIRE(testResouceCounter == 1); + REQUIRE(res != nullptr); + REQUIRE(res->mRefCount == 1); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + res->decRef(); + + ResourceManager::cleanUp(res); + REQUIRE(testResouceCounter == 0); + REQUIRE(ResourceManager::getResources().size() == 0 + resSize); + REQUIRE(ResourceManager::getOrphanedResources().size() == 1); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + ResourceManager::getOrphanedResources().clear(); + } + + SECTION("resourcemanager cleanProtected 1") + { + REQUIRE(testResouceCounter == 0); + TestLoader rl = { "test1" }; + Resource *res = ResourceManager::get("test1", + TestLoader::load, &rl); + REQUIRE(testResouceCounter == 1); + REQUIRE(res != nullptr); + REQUIRE(res->mRefCount == 1); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + res->mProtected = true; + ResourceManager::cleanProtected(); + + REQUIRE(testResouceCounter == 1); + REQUIRE(ResourceManager::getResources().size() == 0 + resSize); + REQUIRE(ResourceManager::getOrphanedResources().size() == 1); + REQUIRE(ResourceManager::getOrphanedResources()["test1"] == res); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + res->decRef(); + } + + SECTION("resourcemanager clearDeleted 1") + { + REQUIRE(testResouceCounter == 0); + TestLoader rl = { "test1" }; + Resource *res = ResourceManager::get("test1", + TestLoader::load, &rl); + res->incRef(); + REQUIRE(testResouceCounter == 1); + REQUIRE(res != nullptr); + REQUIRE(res->mRefCount == 2); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + ResourceManager::moveToDeleted(res); + REQUIRE(testResouceCounter == 1); + REQUIRE(res->mRefCount == 1); + REQUIRE(ResourceManager::getResources().size() == 0 + resSize); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().size() == 1); + + ResourceManager::clearDeleted(); + REQUIRE(testResouceCounter == 1); + REQUIRE(res->mRefCount == 1); + REQUIRE(ResourceManager::getResources().size() == 0 + resSize); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().size() == 1); + res->decRef(); + } + + SECTION("resourcemanager clearDeleted 2") + { + REQUIRE(testResouceCounter == 0); + TestLoader rl = { "test1" }; + Resource *res = ResourceManager::get("test1", + TestLoader::load, &rl); + res->incRef(); + REQUIRE(testResouceCounter == 1); + REQUIRE(res != nullptr); + REQUIRE(res->mRefCount == 2); + REQUIRE(ResourceManager::getResources().size() == 1 + resSize); + REQUIRE(ResourceManager::getResources()["test1"] == res); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + ResourceManager::moveToDeleted(res); + REQUIRE(testResouceCounter == 1); + REQUIRE(res->mRefCount == 1); + REQUIRE(ResourceManager::getResources().size() == 0 + resSize); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().size() == 1); + + res->decRef(); + ResourceManager::clearDeleted(); + REQUIRE(testResouceCounter == 0); + REQUIRE(ResourceManager::getResources().size() == 0 + resSize); + REQUIRE(ResourceManager::getOrphanedResources().empty() == true); + REQUIRE(ResourceManager::getDeletedResources().empty() == true); + } + + delete2(client); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +// VirtFs::deinit(); +} + +TEST_CASE("resourcemanager leak test2", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} diff --git a/src/unittests/resources/sdlimagehelper_unittest.cc b/src/unittests/resources/sdlimagehelper_unittest.cc new file mode 100644 index 000000000..2a3aec45b --- /dev/null +++ b/src/unittests/resources/sdlimagehelper_unittest.cc @@ -0,0 +1,541 @@ +/* + * The ManaPlus Client + * Copyright (C) 2014-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef USE_SDL2 +#include "localconsts.h" +PRAGMA48(GCC diagnostic push) +PRAGMA48(GCC diagnostic ignored "-Wshadow") +#include <SDL_endian.h> +PRAGMA48(GCC diagnostic pop) +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + +#include "unittests/unittests.h" + +#include "client.h" +#include "graphicsmanager.h" + +#include "being/actorsprite.h" + +#include "fs/virtfs/fs.h" + +#include "utils/delete2.h" +#include "utils/env.h" + +#include "render/sdlgraphics.h" + +#include "resources/sdlimagehelper.h" + +#include "debug.h" + +static SDL_Surface *createSoftware32BitSurface(int width, + int height) +{ +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + const int rmask = 0xff000000; + const int gmask = 0x00ff0000; + const int bmask = 0x0000ff00; + const int amask = 0x000000ff; +#else // SDL_BYTEORDER == SDL_BIG_ENDIAN + + const int rmask = 0x000000ff; + const int gmask = 0x0000ff00; + const int bmask = 0x00ff0000; + const int amask = 0xff000000; +#endif // SDL_BYTEORDER == SDL_BIG_ENDIAN + + return MSDL_CreateRGBSurface(SDL_SWSURFACE, + width, height, 32, rmask, gmask, bmask, amask); +} + +TEST_CASE("sdlimagehelper combineSurface", "") +{ + setEnv("SDL_VIDEODRIVER", "dummy"); + + client = new Client; + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + mainGraphics = new SDLGraphics; + imageHelper = new SDLImageHelper; +#ifdef USE_SDL2 + SDLImageHelper::setRenderer(graphicsManager.createRenderer( + graphicsManager.createWindow(640, 480, 0, + SDL_WINDOW_SHOWN | SDL_SWSURFACE), SDL_RENDERER_SOFTWARE)); +#else // USE_SDL2 + + graphicsManager.createWindow(640, 480, 0, SDL_ANYFORMAT | SDL_SWSURFACE); +#endif // USE_SDL2 + + ActorSprite::load(); + + SECTION("empty copy1") + { + SDL_Surface *surface1 = createSoftware32BitSurface(2, 2); + uint32_t *ptr1 = static_cast<uint32_t*>(surface1->pixels); + for (int f = 0; f < 2 * 2; f ++) + ptr1[f] = 0xff000000; + SDL_Surface *surface2 = createSoftware32BitSurface(2, 2); + uint32_t *ptr2 = static_cast<uint32_t*>(surface2->pixels); + + ptr2[0] = 0xff000000; + ptr2[1] = 0x00ff0000; + ptr2[2] = 0x0000ff00; + ptr2[3] = 0x000000ff; + + SDLImageHelper::combineSurface(surface2, + nullptr, + surface1, + nullptr); + + // src image test + REQUIRE(ptr2[0] == 0xff000000); + REQUIRE(ptr2[1] == 0x00ff0000); + REQUIRE(ptr2[2] == 0x0000ff00); + REQUIRE(ptr2[3] == 0x000000ff); + + REQUIRE(ptr1[0] == 0xff000000); + REQUIRE(ptr1[1] == 0xff000000); + REQUIRE(ptr1[2] == 0xff000000); + REQUIRE(ptr1[3] == 0xff000000); + MSDL_FreeSurface(surface1); + MSDL_FreeSurface(surface2); + } + + SECTION("empty copy2") + { + SDL_Surface *surface1 = createSoftware32BitSurface(2, 2); + uint32_t *ptr1 = static_cast<uint32_t*>(surface1->pixels); + for (int f = 0; f < 2 * 2; f ++) + ptr1[f] = 0xff000000; + SDL_Surface *surface2 = createSoftware32BitSurface(2, 2); + uint32_t *ptr2 = static_cast<uint32_t*>(surface2->pixels); + + ptr2[0] = 0xff112233; + ptr2[1] = 0xff003344; + ptr2[2] = 0xff330055; + ptr2[3] = 0xff445500; + + SDLImageHelper::combineSurface(surface2, + nullptr, + surface1, + nullptr); + + REQUIRE(ptr1[0] == 0xff112233); + REQUIRE(ptr1[1] == 0xff003344); + REQUIRE(ptr1[2] == 0xff330055); + REQUIRE(ptr1[3] == 0xff445500); + MSDL_FreeSurface(surface1); + MSDL_FreeSurface(surface2); + } + + SECTION("empty copy3") + { + SDL_Surface *surface1 = createSoftware32BitSurface(2, 2); + uint32_t *ptr1 = static_cast<uint32_t*>(surface1->pixels); + for (int f = 0; f < 2 * 2; f ++) + ptr1[f] = 0x00000000; + SDL_Surface *surface2 = createSoftware32BitSurface(2, 2); + uint32_t *ptr2 = static_cast<uint32_t*>(surface2->pixels); + + ptr2[0] = 0xff112233; + ptr2[1] = 0xff003344; + ptr2[2] = 0xff330055; + ptr2[3] = 0xff445500; + + SDLImageHelper::combineSurface(surface2, + nullptr, + surface1, + nullptr); + + REQUIRE(ptr1[0] == 0xff112233); + REQUIRE(ptr1[1] == 0xff003344); + REQUIRE(ptr1[2] == 0xff330055); + REQUIRE(ptr1[3] == 0xff445500); + MSDL_FreeSurface(surface1); + MSDL_FreeSurface(surface2); + } + + SECTION("empty copy4") + { + SDL_Surface *surface1 = createSoftware32BitSurface(2, 2); + uint32_t *ptr1 = static_cast<uint32_t*>(surface1->pixels); + for (int f = 0; f < 2 * 2; f ++) + ptr1[f] = 0xff000000; + SDL_Surface *surface2 = createSoftware32BitSurface(2, 2); + uint32_t *ptr2 = static_cast<uint32_t*>(surface2->pixels); + + ptr2[0] = 0x50112233; + ptr2[1] = 0x50003344; + ptr2[2] = 0x50330055; + ptr2[3] = 0x50445500; + + SDLImageHelper::combineSurface(surface2, + nullptr, + surface1, + nullptr); + + REQUIRE(ptr1[0] == 0xff09121c); + REQUIRE(ptr1[1] == 0xff001c25); + REQUIRE(ptr1[2] == 0xff1c002f); + REQUIRE(ptr1[3] == 0xff252f00); + MSDL_FreeSurface(surface1); + MSDL_FreeSurface(surface2); + } + + SECTION("empty copy5") + { + SDL_Surface *surface1 = createSoftware32BitSurface(2, 2); + uint32_t *ptr1 = static_cast<uint32_t*>(surface1->pixels); + for (int f = 0; f < 2 * 2; f ++) + ptr1[f] = 0x00000000; + SDL_Surface *surface2 = createSoftware32BitSurface(2, 2); + uint32_t *ptr2 = static_cast<uint32_t*>(surface2->pixels); + + ptr2[0] = 0x50112233; + ptr2[1] = 0x50003344; + ptr2[2] = 0x50330055; + ptr2[3] = 0x50445500; + + SDLImageHelper::combineSurface(surface2, + nullptr, + surface1, + nullptr); + + REQUIRE(ptr1[0] == 0x8e09121c); + REQUIRE(ptr1[1] == 0x8e001c25); + REQUIRE(ptr1[2] == 0x8e1c002f); + REQUIRE(ptr1[3] == 0x8e252f00); + MSDL_FreeSurface(surface1); + MSDL_FreeSurface(surface2); + } + + SECTION("empty copy6") + { + SDL_Surface *surface1 = createSoftware32BitSurface(2, 2); + uint32_t *ptr1 = static_cast<uint32_t*>(surface1->pixels); + ptr1[0] = 0x50112233; + ptr1[1] = 0x50003344; + ptr1[2] = 0x50330055; + ptr1[3] = 0x50445500; + SDL_Surface *surface2 = createSoftware32BitSurface(2, 2); + uint32_t *ptr2 = static_cast<uint32_t*>(surface2->pixels); + + for (int f = 0; f < 2 * 2; f ++) + ptr2[f] = 0x00000000; + + SDLImageHelper::combineSurface(surface2, + nullptr, + surface1, + nullptr); + + REQUIRE(ptr1[0] == 0x50112233); + REQUIRE(ptr1[1] == 0x50003344); + REQUIRE(ptr1[2] == 0x50330055); + REQUIRE(ptr1[3] == 0x50445500); + MSDL_FreeSurface(surface1); + MSDL_FreeSurface(surface2); + } + + SECTION("mix 1") + { + SDL_Surface *surface1 = createSoftware32BitSurface(2, 2); + uint32_t *ptr1 = static_cast<uint32_t*>(surface1->pixels); + ptr1[0] = 0x50112233; + ptr1[1] = 0x50003344; + ptr1[2] = 0x50330055; + ptr1[3] = 0x50445500; + SDL_Surface *surface2 = createSoftware32BitSurface(2, 2); + uint32_t *ptr2 = static_cast<uint32_t*>(surface2->pixels); + + ptr2[0] = 0x50003344; + ptr2[1] = 0x50330055; + ptr2[2] = 0x50445500; + ptr2[3] = 0x50112233; + + SDLImageHelper::combineSurface(surface2, + nullptr, + surface1, + nullptr); + + REQUIRE(ptr1[0] == 0xdf082b3c); + REQUIRE(ptr1[1] == 0xdf1d174d); + REQUIRE(ptr1[2] == 0xdf3d2f26); + REQUIRE(ptr1[3] == 0xdf29391c); + MSDL_FreeSurface(surface1); + MSDL_FreeSurface(surface2); + } + + SECTION("mix 2") + { + SDL_Surface *surface1 = createSoftware32BitSurface(2, 2); + uint32_t *ptr1 = static_cast<uint32_t*>(surface1->pixels); + ptr1[0] = 0x10112233; + ptr1[1] = 0x20003344; + ptr1[2] = 0x30330055; + ptr1[3] = 0x40445500; + SDL_Surface *surface2 = createSoftware32BitSurface(2, 2); + uint32_t *ptr2 = static_cast<uint32_t*>(surface2->pixels); + + ptr2[0] = 0x50003344; + ptr2[1] = 0x60330055; + ptr2[2] = 0x70445500; + ptr2[3] = 0x80112233; + + SDLImageHelper::combineSurface(surface2, + nullptr, + surface1, + nullptr); + + REQUIRE(ptr1[0] == 0x9f082b3c); + REQUIRE(ptr1[1] == 0xbd1f144e); + REQUIRE(ptr1[2] == 0xb93f391e); + REQUIRE(ptr1[3] == 0xf5213224); + MSDL_FreeSurface(surface1); + MSDL_FreeSurface(surface2); + } + + SECTION("part mix 1") + { +// 11 11 00 00 +// 11 11 00 00 +// 00 00 00 00 +// 00 00 00 00 + + SDL_Surface *surface1 = createSoftware32BitSurface(4, 4); + uint32_t *ptr1 = static_cast<uint32_t*>(surface1->pixels); + ptr1[0] = 0x10112233; + ptr1[1] = 0x20003344; + ptr1[2] = 0x10203040; + ptr1[3] = 0x20304050; + ptr1[4] = 0x30330055; + ptr1[5] = 0x40445500; + ptr1[6] = 0x30405060; + ptr1[7] = 0x708090a0; + + ptr1[8] = 0x8090a0b0; + ptr1[9] = 0x90a0b0c0; + ptr1[10] = 0xa0b0c0d0; + ptr1[11] = 0xb0c0d0e0; + ptr1[12] = 0xc0d0e0f0; + ptr1[13] = 0xd0e0f000; + ptr1[14] = 0xe0f00010; + ptr1[15] = 0xf0001020; + + SDL_Surface *surface2 = createSoftware32BitSurface(2, 2); + uint32_t *ptr2 = static_cast<uint32_t*>(surface2->pixels); + + ptr2[0] = 0x50003344; + ptr2[1] = 0x60330055; + ptr2[2] = 0x70445500; + ptr2[3] = 0x80112233; + + SDLImageHelper::combineSurface(surface2, + nullptr, + surface1, + nullptr); + + REQUIRE(ptr1[0] == 0x9f082b3c); + REQUIRE(ptr1[1] == 0xbd1f144e); + REQUIRE(ptr1[2] == 0x10203040); + REQUIRE(ptr1[3] == 0x20304050); + REQUIRE(ptr1[4] == 0xb93f391e); + REQUIRE(ptr1[5] == 0xf5213224); + REQUIRE(ptr1[6] == 0x30405060); + REQUIRE(ptr1[7] == 0x708090a0); + + REQUIRE(ptr1[8] == 0x8090a0b0); + REQUIRE(ptr1[9] == 0x90a0b0c0); + REQUIRE(ptr1[10] == 0xa0b0c0d0); + REQUIRE(ptr1[11] == 0xb0c0d0e0); + REQUIRE(ptr1[12] == 0xc0d0e0f0); + REQUIRE(ptr1[13] == 0xd0e0f000); + REQUIRE(ptr1[14] == 0xe0f00010); + REQUIRE(ptr1[15] == 0xf0001020); + + MSDL_FreeSurface(surface1); + MSDL_FreeSurface(surface2); + } + + SECTION("part mix 2") + { +// 00 00 00 00 +// 00 11 11 00 +// 00 11 11 00 +// 00 00 00 00 + + SDL_Surface *surface1 = createSoftware32BitSurface(4, 4); + uint32_t *ptr1 = static_cast<uint32_t*>(surface1->pixels); + + ptr1[0] = 0x10203040; + ptr1[1] = 0x20304050; + ptr1[2] = 0x30405060; + ptr1[3] = 0x708090a0; + ptr1[4] = 0x8090a0b0; + + ptr1[5] = 0x10112233; // + + ptr1[6] = 0x20003344; // + + + ptr1[7] = 0x90a0b0c0; + ptr1[8] = 0xa0b0c0d0; + + ptr1[9] = 0x30330055; // + + ptr1[10] = 0x40445500; // + + + ptr1[11] = 0xb0c0d0e0; + ptr1[12] = 0xc0d0e0f0; + ptr1[13] = 0xd0e0f000; + ptr1[14] = 0xe0f00010; + ptr1[15] = 0xf0001020; + + SDL_Surface *surface2 = createSoftware32BitSurface(2, 2); + uint32_t *ptr2 = static_cast<uint32_t*>(surface2->pixels); + + ptr2[0] = 0x50003344; + ptr2[1] = 0x60330055; + ptr2[2] = 0x70445500; + ptr2[3] = 0x80112233; + + SDL_Rect rect1; + SDL_Rect rect2; + rect1.x = 1; + rect1.y = 1; + rect1.w = 2; + rect1.h = 2; + rect2.x = 0; + rect2.y = 0; + rect2.w = 2; + rect2.h = 2; + SDLImageHelper::combineSurface(surface2, + &rect2, + surface1, + &rect1); + + REQUIRE(ptr1[0] == 0x10203040); + REQUIRE(ptr1[1] == 0x20304050); + REQUIRE(ptr1[2] == 0x30405060); + REQUIRE(ptr1[3] == 0x708090a0); + REQUIRE(ptr1[4] == 0x8090a0b0); + + REQUIRE(ptr1[5] == 0x9f082b3c); // + + REQUIRE(ptr1[6] == 0xbd1f144e); // + + + REQUIRE(ptr1[7] == 0x90a0b0c0); + REQUIRE(ptr1[8] == 0xa0b0c0d0); + + REQUIRE(ptr1[9] == 0xb93f391e); // + + REQUIRE(ptr1[10] == 0xf5213224); // + + + REQUIRE(ptr1[11] == 0xb0c0d0e0); + REQUIRE(ptr1[12] == 0xc0d0e0f0); + REQUIRE(ptr1[13] == 0xd0e0f000); + REQUIRE(ptr1[14] == 0xe0f00010); + REQUIRE(ptr1[15] == 0xf0001020); + + MSDL_FreeSurface(surface1); + MSDL_FreeSurface(surface2); + } + + SECTION("part mix 3") + { + SDL_Surface *surface1 = createSoftware32BitSurface(4, 4); + uint32_t *ptr1 = static_cast<uint32_t*>(surface1->pixels); + + ptr1[0] = 0x10203040; + ptr1[1] = 0x20304050; + ptr1[2] = 0x30405060; + ptr1[3] = 0x708090a0; + ptr1[4] = 0x8090a0b0; + ptr1[5] = 0x10112233; + ptr1[6] = 0x20003344; + ptr1[7] = 0x90a0b0c0; + ptr1[8] = 0xa0b0c0d0; + ptr1[9] = 0x30330055; + ptr1[10] = 0x40445500; + ptr1[11] = 0xb0c0d0e0; + ptr1[12] = 0xc0d0e0f0; + ptr1[13] = 0xd0e0f000; + ptr1[14] = 0xe0f00010; + ptr1[15] = 0xf0001020; + + SDL_Surface *surface2 = createSoftware32BitSurface(4, 4); + uint32_t *ptr2 = static_cast<uint32_t*>(surface2->pixels); + + ptr2[0] = 0x50003344; + ptr2[1] = 0x60330055; + ptr2[2] = 0x70445500; + ptr2[3] = 0x80112233; + ptr2[4] = 0x90111111; + ptr2[5] = 0x90111111; + ptr2[6] = 0xff000000; + ptr2[7] = 0xff000000; + ptr2[8] = 0xff000000; + ptr2[9] = 0xff000000; + ptr2[10] = 0xff000000; + ptr2[11] = 0xff000000; + ptr2[12] = 0xff000000; + ptr2[13] = 0xff000000; + ptr2[14] = 0xff000000; + ptr2[15] = 0xff000000; + + SDL_Rect rect1; + SDL_Rect rect2; + rect1.x = 1; + rect1.y = 1; + rect1.w = 2; + rect1.h = 2; + rect2.x = 0; + rect2.y = 0; + rect2.w = 2; + rect2.h = 2; + SDLImageHelper::combineSurface(surface2, + &rect2, + surface1, + &rect1); + + REQUIRE(ptr1[0] == 0x10203040); + REQUIRE(ptr1[1] == 0x20304050); + REQUIRE(ptr1[2] == 0x30405060); + REQUIRE(ptr1[3] == 0x708090a0); + REQUIRE(ptr1[4] == 0x8090a0b0); + REQUIRE(ptr1[5] == 0x9f082b3c); + REQUIRE(ptr1[6] == 0xbd1f144e); + REQUIRE(ptr1[7] == 0x90a0b0c0); + REQUIRE(ptr1[8] == 0xa0b0c0d0); + REQUIRE(ptr1[9] == 0xbf1b0d23); + REQUIRE(ptr1[10] == 0xff1f230c); + REQUIRE(ptr1[11] == 0xb0c0d0e0); + REQUIRE(ptr1[12] == 0xc0d0e0f0); + REQUIRE(ptr1[13] == 0xd0e0f000); + REQUIRE(ptr1[14] == 0xe0f00010); + REQUIRE(ptr1[15] == 0xf0001020); + + MSDL_FreeSurface(surface1); + MSDL_FreeSurface(surface2); + } + + delete2(client); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +} + +#endif // SDL_BYTEORDER == SDL_LIL_ENDIAN +#endif // USE_SDL2 diff --git a/src/unittests/resources/sprite/animatedsprite_unittest.cc b/src/unittests/resources/sprite/animatedsprite_unittest.cc new file mode 100644 index 000000000..3e4a1826c --- /dev/null +++ b/src/unittests/resources/sprite/animatedsprite_unittest.cc @@ -0,0 +1,220 @@ +/* + * The ManaPlus Client + * Copyright (C) 2013-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "configuration.h" +#include "configmanager.h" +#include "client.h" +#include "dirs.h" +#include "graphicsmanager.h" + +#include "const/resources/spriteaction.h" + +#include "being/actorsprite.h" + +#include "fs/virtfs/fs.h" + +#include "gui/gui.h" +#include "gui/theme.h" + +#include "render/sdlgraphics.h" + +#include "resources/sdlimagehelper.h" + +#include "resources/animation/animation.h" + +#include "resources/resourcemanager/resourcemanager.h" + +#include "resources/sprite/animatedsprite.h" + +#include "utils/env.h" +#include "utils/delete2.h" +#include "utils/mrand.h" + +PRAGMA48(GCC diagnostic push) +PRAGMA48(GCC diagnostic ignored "-Wshadow") +#ifndef USE_SDL2 +#include <SDL.h> +#endif // USE_SDL2 +PRAGMA48(GCC diagnostic pop) + +#include "debug.h" + +TEST_CASE("AnimatedSprite leak test1", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} + +TEST_CASE("AnimatedSprite tests", "animatedsprite") +{ + setEnv("SDL_VIDEODRIVER", "dummy"); + + initRand(); + client = new Client; + XML::initXML(); + SDL_Init(SDL_INIT_VIDEO); + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + mainGraphics = new SDLGraphics; + imageHelper = new SDLImageHelper(); +#ifdef USE_SDL2 + SDLImageHelper::setRenderer(graphicsManager.createRenderer( + graphicsManager.createWindow(640, 480, 0, + SDL_WINDOW_SHOWN | SDL_SWSURFACE), SDL_RENDERER_SOFTWARE)); +#else // USE_SDL2 + + graphicsManager.createWindow(640, 480, 0, SDL_ANYFORMAT | SDL_SWSURFACE); +#endif // USE_SDL2 + + theme = new Theme; + Theme::selectSkin(); + + Dirs::initRootDir(); + Dirs::initHomeDir(); + + ConfigManager::initConfiguration(); + getConfigDefaults2(config.getDefaultValues()); + branding.setDefaultValues(getBrandingDefaults()); + + ActorSprite::load(); + gui = new Gui(); + gui->postInit(mainGraphics); + + SECTION("basic test 1") + { + AnimatedSprite *sprite = AnimatedSprite::load( + "graphics/sprites/error.xml", 0); + sprite->play(SpriteAction::DEFAULT); + + REQUIRE_FALSE(sprite == nullptr); + REQUIRE_FALSE(sprite->getSprite() == nullptr); + REQUIRE_FALSE(sprite->getAnimation() == nullptr); + REQUIRE_FALSE(sprite->getFrame() == nullptr); + REQUIRE(0 == sprite->getFrameIndex()); + REQUIRE(0 == sprite->getFrameTime()); + REQUIRE(false == sprite->update(1)); + REQUIRE(0 == sprite->getFrameTime()); + REQUIRE(false == sprite->update(11)); + REQUIRE(10 == sprite->getFrameTime()); + REQUIRE(0 == sprite->getFrameIndex()); + delete sprite; + logger->log("test4"); + } + + SECTION("basic test 2") + { + AnimatedSprite *sprite = AnimatedSprite::load( + "graphics/sprites/test.xml", 0); + sprite->play(SpriteAction::STAND); + + REQUIRE(10 == const_cast<Animation*>(sprite->getAnimation()) + ->getFrames().size()); + + REQUIRE_FALSE(nullptr == sprite); + + REQUIRE(false == sprite->update(1)); + REQUIRE(0 == sprite->getFrameTime()); + REQUIRE(10 == sprite->getFrame()->delay); + + REQUIRE(false == sprite->update(1 + 10)); + REQUIRE(0 == sprite->getFrameIndex()); + REQUIRE(10 == sprite->getFrameTime()); + + REQUIRE(true == sprite->update(1 + 10 + 5)); + REQUIRE(1 == sprite->getFrameIndex()); + REQUIRE(5 == sprite->getFrameTime()); + + REQUIRE(false == sprite->update(1 + 10 + 5)); + REQUIRE(1 == sprite->getFrameIndex()); + REQUIRE(5 == sprite->getFrameTime()); + + REQUIRE(false == sprite->update(1 + 10 + 20)); + REQUIRE(1 == sprite->getFrameIndex()); + REQUIRE(20 == sprite->getFrameTime()); + + REQUIRE(true == sprite->update(1 + 10 + 20 + 1)); + REQUIRE(2 == sprite->getFrameIndex()); + REQUIRE(1 == sprite->getFrameTime()); + + REQUIRE(false == sprite->update(1 + 10 + 20 + 10)); + REQUIRE(2 == sprite->getFrameIndex()); + REQUIRE(10 == sprite->getFrameTime()); + + REQUIRE(true == sprite->update(1 + 10 + 20 + 10 + 1)); + REQUIRE(4 == sprite->getFrameIndex()); + REQUIRE(1 == sprite->getFrameTime()); + + REQUIRE(false == sprite->update(1 + 10 + 20 + 10 + 25)); + REQUIRE(4 == sprite->getFrameIndex()); + REQUIRE(25 == sprite->getFrameTime()); + + REQUIRE(true == sprite->update(1 + 10 + 20 + 10 + 25 + 1)); + REQUIRE(6 == sprite->getFrameIndex()); + REQUIRE(1 == sprite->getFrameTime()); + + REQUIRE(true == sprite->update(1 + 10 + 20 + 10 + 25 + 10 + 1)); + REQUIRE(8 == sprite->getFrameIndex()); + REQUIRE(1 == sprite->getFrameTime()); + + REQUIRE(true == sprite->update(1 + 10 + 20 + 10 + 25 + 10 + 10 + 1)); + REQUIRE(4 == sprite->getFrameIndex()); + REQUIRE(1 == sprite->getFrameTime()); + delete sprite; + } + + SECTION("basic test 3") + { + AnimatedSprite *sprite2 = AnimatedSprite::load( + "graphics/sprites/test.xml", 0); + sprite2->play(SpriteAction::SIT); + + REQUIRE(false == sprite2->update(1)); + REQUIRE(2 == const_cast<Animation*>(sprite2->getAnimation()) + ->getFrames().size()); + REQUIRE(0 == sprite2->getFrameTime()); + REQUIRE(85 == sprite2->getFrame()->delay); + + REQUIRE(true == sprite2->update(1 + 10 + 20 + 10 + 25 + 10 + 10 + 1)); + REQUIRE(1 == sprite2->getFrameIndex()); + REQUIRE(1 == sprite2->getFrameTime()); + delete sprite2; + } + + delete2(client); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +// VirtFs::deinit(); +} + +TEST_CASE("AnimatedSprite leak test2", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} diff --git a/src/unittests/unittests.h b/src/unittests/unittests.h new file mode 100644 index 000000000..13be1b9c0 --- /dev/null +++ b/src/unittests/unittests.h @@ -0,0 +1,52 @@ +/* + * The ManaPlus Client + * Copyright (C) 2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef UNITTESTS_H +#define UNITTESTS_H + +#include "localconsts.h" + +#ifdef UNITTESTS_CATCH +#include "test/catch.hpp" +#endif // UNITTESTS_CATCH + +#ifdef UNITTESTS_DOCTEST + +#ifdef __GNUC__ +#if GCC_VERSION >= 50000 +#define PRAGMA5(str) _Pragma(#str) +#elif defined(__clang__) +#define PRAGMA5(str) _Pragma(#str) +#else // GCC_VERSION > 50000 +#define PRAGMA5(str) +#endif // GCC_VERSION > 50000 +#endif // __GNUC__ + +PRAGMA5(GCC diagnostic push) +PRAGMA5(GCC diagnostic ignored "-Wsuggest-override") +#include "test/doctest.h" +PRAGMA5(GCC diagnostic pop) + +#undef TEST_CASE +#define TEST_CASE(name, tags) DOCTEST_TEST_CASE(tags " " name) +#define SECTION(name) DOCTEST_SUBCASE(name) +#endif // UNITTESTS_DOCTEST + +#endif // UNITTESTS_H diff --git a/src/unittests/utils/chatutils_unittest.cc b/src/unittests/utils/chatutils_unittest.cc new file mode 100644 index 000000000..681d91d3e --- /dev/null +++ b/src/unittests/utils/chatutils_unittest.cc @@ -0,0 +1,287 @@ +/* + * The ManaPlus Client + * Copyright (C) 2012-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "client.h" +#include "configuration.h" +#include "configmanager.h" +#include "dirs.h" + +#include "actormanager.h" +#include "graphicsmanager.h" +#include "party.h" + +#include "being/localplayer.h" + +#include "fs/virtfs/fs.h" + +#include "gui/gui.h" +#include "gui/theme.h" + +#include "utils/chatutils.h" +#include "utils/delete2.h" +#include "utils/env.h" + +#include "render/sdlgraphics.h" + +#include "resources/sdlimagehelper.h" + +#include "resources/resourcemanager/resourcemanager.h" + +PRAGMA48(GCC diagnostic push) +PRAGMA48(GCC diagnostic ignored "-Wshadow") +#ifndef USE_SDL2 +#include <SDL.h> +#endif // USE_SDL2 +PRAGMA48(GCC diagnostic pop) + +#include "debug.h" + +TEST_CASE("chatutils leak test1", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} + +TEST_CASE("chatutils replaceVars", "") +{ + setEnv("SDL_VIDEODRIVER", "dummy"); + + client = new Client; + XML::initXML(); + SDL_Init(SDL_INIT_VIDEO); + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + theme = new Theme; + Theme::selectSkin(); + imageHelper = new SDLImageHelper(); + mainGraphics = new SDLGraphics; + +#ifdef USE_SDL2 + SDLImageHelper::setRenderer(graphicsManager.createRenderer( + graphicsManager.createWindow(640, 480, 0, + SDL_WINDOW_SHOWN | SDL_SWSURFACE), SDL_RENDERER_SOFTWARE)); +#else // USE_SDL2 + + graphicsManager.createWindow(640, 480, 0, SDL_ANYFORMAT | SDL_SWSURFACE); +#endif // USE_SDL2 + + Dirs::initRootDir(); + Dirs::initHomeDir(); + + ConfigManager::initConfiguration(); + getConfigDefaults2(config.getDefaultValues()); + branding.setDefaultValues(getBrandingDefaults()); + + gui = new Gui(); + gui->postInit(mainGraphics); + + ActorSprite::load(); + localPlayer = new LocalPlayer(static_cast<BeingId>(1), + BeingTypeId_zero); + actorManager = new ActorManager; + std::string str; + + SECTION("empty") + { + replaceVars(str); + REQUIRE(str.empty()); + + str = "test line"; + replaceVars(str); + REQUIRE(str == "test line"); + + str = "test <PLAYER>"; + replaceVars(str); + REQUIRE(str == "test "); + + str = "test <MONSTER>"; + replaceVars(str); + REQUIRE(str == "test "); + + str = "test <PEOPLE>"; + replaceVars(str); + REQUIRE(str == "test "); + + str = "test <PARTY>"; + replaceVars(str); + REQUIRE(str == "test "); + + str = "test <SOMETHING>"; + replaceVars(str); + REQUIRE(str == "test <SOMETHING>"); + } + + SECTION("player") + { + Being *player1 = Being::createBeing(static_cast<BeingId>(2), + ActorType::Player, + BeingTypeId_zero, + nullptr); + player1->setName("player1"); + actorManager->mActors.insert(player1); + + localPlayer->setTarget(player1); + str = "test <PLAYER>"; + replaceVars(str); + REQUIRE(str == "test player1"); + } + + SECTION("monster") + { + Being *const monster = Being::createBeing(static_cast<BeingId>(3), + ActorType::Monster, + BeingTypeId_zero, + nullptr); + monster->setName("monster1"); + actorManager->mActors.insert(monster); + + localPlayer->setTarget(monster); + str = "test <MONSTER>"; + replaceVars(str); + REQUIRE(str == "test monster1"); + } + + SECTION("people") + { + actorManager->mActors.insert(localPlayer); + str = "test <PEOPLE>"; + replaceVars(str); + REQUIRE(str == "test "); + + Being *const player1 = Being::createBeing(static_cast<BeingId>(2), + ActorType::Player, + BeingTypeId_zero, + nullptr); + player1->setName("player1"); + actorManager->mActors.insert(player1); + + str = "test <PEOPLE>"; + replaceVars(str); + REQUIRE(str == "test player1"); + + Being *const player2 = Being::createBeing(static_cast<BeingId>(4), + ActorType::Player, + BeingTypeId_zero, + nullptr); + player2->setName("player2"); + actorManager->mActors.insert(player2); + + str = "test <PEOPLE>"; + replaceVars(str); + const bool correct = str == "test player1,player2" || + str == "test player2,player1"; + REQUIRE(correct == true); + } + + SECTION("party") + { + actorManager->mActors.insert(localPlayer); + + Party *const party1 = Party::getParty(1); + localPlayer->setParty(party1); + + str = "test <PARTY>"; + replaceVars(str); + REQUIRE(str == "test "); + + Being *const player1 = Being::createBeing(static_cast<BeingId>(2), + ActorType::Player, + BeingTypeId_zero, + nullptr); + player1->setName("player1"); + actorManager->mActors.insert(player1); + player1->setParty(party1); + + str = "test <PARTY>"; + replaceVars(str); + REQUIRE(str == "test player1"); + + Being *const player2 = Being::createBeing(static_cast<BeingId>(4), + ActorType::Player, + BeingTypeId_zero, + nullptr); + player2->setName("player2"); + actorManager->mActors.insert(player2); + player2->setParty(party1); + + str = "test <PARTY>"; + replaceVars(str); + REQUIRE(str == "test player1,player2"); + + Party *const party2 = Party::getParty(2); + + Being *const player3 = Being::createBeing(static_cast<BeingId>(5), + ActorType::Player, + BeingTypeId_zero, + nullptr); + player3->setName("player3"); + actorManager->mActors.insert(player3); + player3->setParty(party2); + + str = "test <PARTY>"; + replaceVars(str); + REQUIRE(str == "test player1,player2"); + + player3->setParty(party1); + + str = "test <PARTY>"; + replaceVars(str); + REQUIRE(str == "test player1,player2,player3"); + + player2->setParty(party2); + + str = "test <PARTY>"; + replaceVars(str); + REQUIRE(str == "test player1,player3"); + + Party::clearParties(); + } + + delete2(actorManager); + delete2(localPlayer); + delete2(client); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +// VirtFs::deinit(); +} + +TEST_CASE("chatutils textToMe", "") +{ + REQUIRE(textToMe("") == "**"); + REQUIRE(textToMe("123") == "*123*"); + REQUIRE(textToMe("*") == "***"); + REQUIRE(textToMe("test line") == "*test line*"); +} + +TEST_CASE("chatutils leak test2", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} diff --git a/src/unittests/utils/checkutils_unittest.cc b/src/unittests/utils/checkutils_unittest.cc new file mode 100644 index 000000000..c54dcf9fc --- /dev/null +++ b/src/unittests/utils/checkutils_unittest.cc @@ -0,0 +1,179 @@ +/* + * The ManaPlus Client + * Copyright (C) 2016-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "utils/checkutils.h" +#include "utils/delete2.h" + +#include "debug.h" + +namespace +{ + bool flag = false; +} // namespace + +static void testReturnFalseV(const bool val) +{ + flag = false; + returnFalseVReal(val); + flag = true; +} + +static void testReturnTrueV(const bool val) +{ + flag = false; + returnTrueVReal(val); + flag = true; +} + +static int testReturnFalse(const bool val) +{ + returnFalseReal(0, val); + return 1; +} + +static int testReturnTrue(const bool val) +{ + returnTrueReal(0, val); + return 1; +} + +static int testReturnNullptr(void *val) +{ + returnNullptrReal(0, val); + return 1; +} + +static void testReturnNullptrV(void *val) +{ + flag = false; + returnNullptrVReal(val); + flag = true; +} + +static bool testFailAlways1() +{ + failAlways("test fail"); + return false; +} + +static bool testFailAlways2() +{ + reportAlways("test fail"); + return false; +} + +TEST_CASE("CheckUtils", "") +{ + logger = new Logger; + + SECTION("reportFalse") + { + REQUIRE(reportFalseReal(false) == false); + REQUIRE(reportFalseReal(true) == true); + } + + SECTION("reportTrue") + { + REQUIRE(reportTrueReal(false) == false); + REQUIRE(reportTrueReal(true) == true); + } + + SECTION("reportAlways") + { + reportAlwaysReal("test report"); + } + + SECTION("failFalse") + { +PRAGMA4(GCC diagnostic push) +PRAGMA4(GCC diagnostic ignored "-Wunused-value") + REQUIRE_THROWS(failFalse(false)); + REQUIRE(failFalse(true) == true); + REQUIRE_THROWS(reportFalse(false)); + REQUIRE(reportFalse(true) == true); +PRAGMA4(GCC diagnostic pop) + } + + SECTION("failTrue") + { +PRAGMA4(GCC diagnostic push) +PRAGMA4(GCC diagnostic ignored "-Wunused-value") + REQUIRE(failTrue(false) == false); + REQUIRE_THROWS(failTrue(true)); + REQUIRE(reportTrue(false) == false); + REQUIRE_THROWS(reportTrue(true)); +PRAGMA4(GCC diagnostic pop) + } + + SECTION("failAlways") + { +PRAGMA4(GCC diagnostic push) +PRAGMA4(GCC diagnostic ignored "-Wunused-value") + REQUIRE_THROWS(testFailAlways1()); + REQUIRE_THROWS(testFailAlways2()); +PRAGMA4(GCC diagnostic pop) + } + + SECTION("returnFalseV") + { + testReturnFalseV(false); + REQUIRE(flag == false); + testReturnFalseV(true); + REQUIRE(flag == true); + } + + SECTION("returnTrueV") + { + testReturnTrueV(false); + REQUIRE(flag == true); + testReturnTrueV(true); + REQUIRE(flag == false); + } + + SECTION("returnFalse") + { + REQUIRE(testReturnFalse(false) == 0); + REQUIRE(testReturnFalse(true) == 1); + } + + SECTION("returnTrue") + { + REQUIRE(testReturnTrue(false) == 1); + REQUIRE(testReturnTrue(true) == 0); + } + + SECTION("returnNullptr") + { + REQUIRE(testReturnNullptr(nullptr) == 0); + REQUIRE(testReturnNullptr(reinterpret_cast<void*>(1)) == 1); + } + + SECTION("returnNullptrV") + { + testReturnNullptrV(nullptr); + REQUIRE(flag == false); + testReturnNullptrV(reinterpret_cast<void*>(1)); + REQUIRE(flag == true); + } + + delete2(logger); +} diff --git a/src/unittests/utils/dumplibs_unittest.cc b/src/unittests/utils/dumplibs_unittest.cc new file mode 100644 index 000000000..35b80c710 --- /dev/null +++ b/src/unittests/utils/dumplibs_unittest.cc @@ -0,0 +1,145 @@ +/* + * The ManaPlus Client + * Copyright (C) 2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "logger.h" + +#include "utils/delete2.h" +#include "utils/stringutils.h" + +PRAGMA48(GCC diagnostic push) +PRAGMA48(GCC diagnostic ignored "-Wshadow") +#include <SDL_image.h> +#include <SDL_mixer.h> +PRAGMACLANG6GCC(GCC diagnostic push) +PRAGMACLANG6GCC(GCC diagnostic ignored "-Wold-style-cast") +#include <SDL_net.h> +PRAGMACLANG6GCC(GCC diagnostic pop) +#include <SDL_ttf.h> +PRAGMA48(GCC diagnostic pop) + +#include <zlib.h> + +#include "debug.h" + +TEST_CASE("dumplibs tests", "") +{ + logger = new Logger(); + + SECTION("zlib") + { + const std::string build = ZLIB_VERSION; + const std::string link = zlibVersion(); + REQUIRE(build == link); + } + + SECTION("sdl") + { + const SDL_version *linkVersion = nullptr; +#ifdef USE_SDL2 + SDL_version sdlVersion; + sdlVersion.major = 0; + sdlVersion.minor = 0; + sdlVersion.patch = 0; + SDL_GetVersion(&sdlVersion); + linkVersion = &sdlVersion; +#else // USE_SDL2 + linkVersion = SDL_Linked_Version(); +#endif // USE_SDL2 + + const std::string build = strprintf("%d.%d.%d", + SDL_MAJOR_VERSION, + SDL_MINOR_VERSION, + SDL_PATCHLEVEL); + const std::string link = strprintf("%d.%d.%d", + linkVersion->major, + linkVersion->minor, + linkVersion->patch); + + REQUIRE(build == link); + } + + SECTION("sdl_net") + { + const SDL_version *const linkVersion = SDLNet_Linked_Version(); + + const std::string build = strprintf("%d.%d.%d", + SDL_NET_MAJOR_VERSION, + SDL_NET_MINOR_VERSION, + SDL_NET_PATCHLEVEL); + const std::string link = strprintf("%d.%d.%d", + linkVersion->major, + linkVersion->minor, + linkVersion->patch); + + REQUIRE(build == link); + } + + SECTION("sdl_image") + { + const SDL_version *const linkVersion = IMG_Linked_Version(); + + const std::string build = strprintf("%d.%d.%d", + SDL_IMAGE_MAJOR_VERSION, + SDL_IMAGE_MINOR_VERSION, + SDL_IMAGE_PATCHLEVEL); + const std::string link = strprintf("%d.%d.%d", + linkVersion->major, + linkVersion->minor, + linkVersion->patch); + + REQUIRE(build == link); + } + + SECTION("sdl_mixer") + { + const SDL_version *const linkVersion = Mix_Linked_Version(); + + const std::string build = strprintf("%d.%d.%d", + SDL_MIXER_MAJOR_VERSION, + SDL_MIXER_MINOR_VERSION, + SDL_MIXER_PATCHLEVEL); + const std::string link = strprintf("%d.%d.%d", + linkVersion->major, + linkVersion->minor, + linkVersion->patch); + + REQUIRE(build == link); + } + + SECTION("sdl_ttf") + { + const SDL_version *const linkVersion = TTF_Linked_Version(); + + const std::string build = strprintf("%d.%d.%d", + SDL_TTF_MAJOR_VERSION, + SDL_TTF_MINOR_VERSION, + SDL_TTF_PATCHLEVEL); + const std::string link = strprintf("%d.%d.%d", + linkVersion->major, + linkVersion->minor, + linkVersion->patch); + + REQUIRE(build == link); + } + + delete2(logger); +} diff --git a/src/unittests/utils/langs_unittest.cc b/src/unittests/utils/langs_unittest.cc new file mode 100644 index 000000000..d9ff6eded --- /dev/null +++ b/src/unittests/utils/langs_unittest.cc @@ -0,0 +1,115 @@ +/* + * The ManaPlus Client + * Copyright (C) 2013-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "configuration.h" + +#include "utils/env.h" +#include "utils/langs.h" + +#include "debug.h" + +TEST_CASE("Langs getLang", "") +{ + LangVect langs; + + config.setValue("lang", "C"); + langs = getLang(); + REQUIRE(langs.size() == 1); + REQUIRE(langs[0] == "C"); + + config.setValue("lang", "ru_RU"); + langs = getLang(); + REQUIRE(langs.size() == 2); + REQUIRE(langs[0] == "ru_RU"); + REQUIRE(langs[1] == "ru"); + + config.setValue("lang", "ru_RU.UTF-8"); + langs = getLang(); + REQUIRE(langs.size() == 2); + REQUIRE(langs[0] == "ru_RU"); + REQUIRE(langs[1] == "ru"); + + config.setValue("lang", ""); + + setEnv("LANG", "C"); + langs = getLang(); + REQUIRE(langs.size() == 1); + REQUIRE(langs[0] == "C"); + + setEnv("LANG", "ru_RU"); + langs = getLang(); + REQUIRE(langs.size() == 2); + REQUIRE(langs[0] == "ru_RU"); + REQUIRE(langs[1] == "ru"); + + setEnv("LANG", "ru_RU.UTF-8"); + langs = getLang(); + REQUIRE(langs.size() == 2); + REQUIRE(langs[0] == "ru_RU"); + REQUIRE(langs[1] == "ru"); +} + +TEST_CASE("Langs getLangSimple", "") +{ + config.setValue("lang", "C"); + REQUIRE(getLangSimple() == "C"); + + config.setValue("lang", "ru_RU"); + REQUIRE(getLangSimple() == "ru_RU"); + + config.setValue("lang", "ru_RU.UTF-8"); + REQUIRE(getLangSimple() == "ru_RU.UTF-8"); + + config.setValue("lang", ""); + + setEnv("LANG", "C"); + REQUIRE(getLangSimple() == "C"); + + setEnv("LANG", "ru_RU"); + REQUIRE(getLangSimple() == "ru_RU"); + + setEnv("LANG", "ru_RU.UTF-8"); + REQUIRE(getLangSimple() == "ru_RU.UTF-8"); +} + +TEST_CASE("Langs getLangShort", "") +{ + config.setValue("lang", "C"); + REQUIRE(getLangShort() == "C"); + + config.setValue("lang", "ru_RU"); + REQUIRE(getLangShort() == "ru"); + + config.setValue("lang", "ru_RU.UTF-8"); + REQUIRE(getLangShort() == "ru"); + + config.setValue("lang", ""); + + setEnv("LANG", "C"); + REQUIRE(getLangShort() == "C"); + + setEnv("LANG", "ru_RU"); + REQUIRE(getLangShort() == "ru"); + + setEnv("LANG", "ru_RU.UTF-8"); + REQUIRE(getLangShort() == "ru"); +} diff --git a/src/unittests/utils/mathutils_unittest.cc b/src/unittests/utils/mathutils_unittest.cc new file mode 100644 index 000000000..3eb0214ef --- /dev/null +++ b/src/unittests/utils/mathutils_unittest.cc @@ -0,0 +1,102 @@ +/* + * The ManaPlus Client + * Copyright (C) 2013-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "utils/mathutils.h" + +#include "debug.h" + +TEST_CASE("MathUtils powerOfTwo", "") +{ + REQUIRE(powerOfTwo(0) == 1); + REQUIRE(powerOfTwo(1) == 1); + REQUIRE(powerOfTwo(2) == 2); + REQUIRE(powerOfTwo(3) == 4); + REQUIRE(powerOfTwo(4) == 4); + REQUIRE(powerOfTwo(5) == 8); + REQUIRE(powerOfTwo(6) == 8); + REQUIRE(powerOfTwo(7) == 8); + REQUIRE(powerOfTwo(8) == 8); + REQUIRE(powerOfTwo(9) == 16); + REQUIRE(powerOfTwo(10) == 16); + REQUIRE(powerOfTwo(11) == 16); + REQUIRE(powerOfTwo(12) == 16); + REQUIRE(powerOfTwo(13) == 16); + REQUIRE(powerOfTwo(14) == 16); + REQUIRE(powerOfTwo(15) == 16); + REQUIRE(powerOfTwo(16) == 16); + REQUIRE(powerOfTwo(17) == 32); + REQUIRE(powerOfTwo(18) == 32); + REQUIRE(powerOfTwo(19) == 32); + REQUIRE(powerOfTwo(20) == 32); + REQUIRE(powerOfTwo(21) == 32); + REQUIRE(powerOfTwo(22) == 32); + REQUIRE(powerOfTwo(23) == 32); + REQUIRE(powerOfTwo(24) == 32); + REQUIRE(powerOfTwo(25) == 32); + REQUIRE(powerOfTwo(26) == 32); + REQUIRE(powerOfTwo(27) == 32); + REQUIRE(powerOfTwo(28) == 32); + REQUIRE(powerOfTwo(29) == 32); + REQUIRE(powerOfTwo(30) == 32); + REQUIRE(powerOfTwo(31) == 32); + REQUIRE(powerOfTwo(32) == 32); + REQUIRE(powerOfTwo(33) == 64); + REQUIRE(powerOfTwo(34) == 64); + REQUIRE(powerOfTwo(35) == 64); + REQUIRE(powerOfTwo(36) == 64); + REQUIRE(powerOfTwo(37) == 64); + REQUIRE(powerOfTwo(38) == 64); + REQUIRE(powerOfTwo(39) == 64); + REQUIRE(powerOfTwo(41) == 64); + REQUIRE(powerOfTwo(42) == 64); + REQUIRE(powerOfTwo(43) == 64); + REQUIRE(powerOfTwo(44) == 64); + REQUIRE(powerOfTwo(45) == 64); + REQUIRE(powerOfTwo(46) == 64); + REQUIRE(powerOfTwo(47) == 64); + REQUIRE(powerOfTwo(48) == 64); + REQUIRE(powerOfTwo(49) == 64); + REQUIRE(powerOfTwo(50) == 64); + REQUIRE(powerOfTwo(51) == 64); + REQUIRE(powerOfTwo(52) == 64); + REQUIRE(powerOfTwo(53) == 64); + REQUIRE(powerOfTwo(54) == 64); + REQUIRE(powerOfTwo(55) == 64); + REQUIRE(powerOfTwo(56) == 64); + REQUIRE(powerOfTwo(57) == 64); + REQUIRE(powerOfTwo(58) == 64); + REQUIRE(powerOfTwo(59) == 64); + REQUIRE(powerOfTwo(60) == 64); + REQUIRE(powerOfTwo(61) == 64); + REQUIRE(powerOfTwo(62) == 64); + REQUIRE(powerOfTwo(63) == 64); + REQUIRE(powerOfTwo(64) == 64); + REQUIRE(powerOfTwo(65) == 128); + + REQUIRE(powerOfTwo(1000000) == 1048576); +} + +TEST_CASE("MathUtils tests fastSqrtInt", "") +{ + for (int f = 0; f < 1005; f ++) + REQUIRE(fastSqrtInt(f) == CAST_S32(sqrt(f))); +} diff --git a/src/unittests/utils/parameters_unittest.cc b/src/unittests/utils/parameters_unittest.cc new file mode 100644 index 000000000..90d872d5a --- /dev/null +++ b/src/unittests/utils/parameters_unittest.cc @@ -0,0 +1,327 @@ +/* + * The ManaPlus Client + * Copyright (C) 2012-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "utils/parameters.h" + +#include "debug.h" + +TEST_CASE("parameters basic 1", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "", ",", '\"') == true); + REQUIRE(pars.empty()); +} + +TEST_CASE("parameters basic 2", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "one,two, tree", ",", '\"') == true); + REQUIRE(pars.size() == 3); + REQUIRE(pars[0] == "one"); + REQUIRE(pars[1] == "two"); + REQUIRE(pars[2] == "tree"); +} + +TEST_CASE("parameters basic 3", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, ", ,,,", ",", '\"') == true); + REQUIRE(pars.empty()); +} + +TEST_CASE("parameters basic 4", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "one,,two, tree", ",", '\"') == true); + REQUIRE(pars.size() == 3); + REQUIRE(pars[0] == "one"); + REQUIRE(pars[1] == "two"); + REQUIRE(pars[2] == "tree"); +} + +TEST_CASE("parameters escape 1", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\\\"", ",", '\"') == true); + REQUIRE(pars.size() == 1); + REQUIRE(pars[0] == "\""); +} + +TEST_CASE("parameters escape 2", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\\\", test", ",", '\"') == true); + REQUIRE(pars.size() == 2); + REQUIRE(pars[0] == "\""); + REQUIRE(pars[1] == "test"); +} + +TEST_CASE("parameters escape 3", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "test,\\\"", ",", '\"') == true); + REQUIRE(pars.size() == 2); + REQUIRE(pars[0] == "test"); + REQUIRE(pars[1] == "\""); +} + +TEST_CASE("parameters quote 1", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\"one\",,two, tree", ",", '\"') == true); + REQUIRE(pars.size() == 3); + REQUIRE(pars[0] == "one"); + REQUIRE(pars[1] == "two"); + REQUIRE(pars[2] == "tree"); +} + +TEST_CASE("parameters quote 2", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\"\",,two, tree", ",", '\"') == true); + REQUIRE(pars.size() == 3); + REQUIRE(pars[0].empty()); + REQUIRE(pars[1] == "two"); + REQUIRE(pars[2] == "tree"); +} + +TEST_CASE("parameters quote 3", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\"one test\",,two, tree", ",", '\"') == + true); + REQUIRE(pars.size() == 3); + REQUIRE(pars[0] == "one test"); + REQUIRE(pars[1] == "two"); + REQUIRE(pars[2] == "tree"); +} + +TEST_CASE("parameters quote 4", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\"\\\"one test\\\"\",,two, tree", ",", '\"') + == true); + REQUIRE(pars.size() == 3); + REQUIRE(pars[0] == "\"one test\""); + REQUIRE(pars[1] == "two"); + REQUIRE(pars[2] == "tree"); +} + +TEST_CASE("parameters quote 5", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\"\\\"one \\\"test\\\"\",,two, tree", + ",", '\"') == true); + REQUIRE(pars.size() == 3); + REQUIRE(pars[0] == "\"one \"test\""); + REQUIRE(pars[1] == "two"); + REQUIRE(pars[2] == "tree"); +} + +TEST_CASE("parameters quote 6", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\"one, test\",,two, tree", ",", '\"') + == true); + REQUIRE(pars.size() == 3); + REQUIRE(pars[0] == "one, test"); + REQUIRE(pars[1] == "two"); + REQUIRE(pars[2] == "tree"); +} + +TEST_CASE("parameters quote 7", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\"\\\"one, test\\\"\",,two, tree", + ",", '\"') == true); + REQUIRE(pars.size() == 3); + REQUIRE(pars[0] == "\"one, test\""); + REQUIRE(pars[1] == "two"); + REQUIRE(pars[2] == "tree"); +} + +TEST_CASE("parameters quote 8", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\"\\\"\",,two, tree", ",", '\"') + == true); + REQUIRE(pars.size() == 3); + REQUIRE(pars[0] == "\""); + REQUIRE(pars[1] == "two"); + REQUIRE(pars[2] == "tree"); +} + +TEST_CASE("parameters quote 9", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\"\\\",,two, tree", ",", '\"') + == true); + REQUIRE(pars.size() == 1); + REQUIRE(pars[0] == "\"\",,two, tree"); +} + +TEST_CASE("parameters quote 10", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\"", ",", '\"') + == true); + REQUIRE(pars.size() == 1); + REQUIRE(pars[0] == "\""); +} + +TEST_CASE("parameters quote 11", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\\\"", ",", '\"') + == true); + REQUIRE(pars.size() == 1); + REQUIRE(pars[0] == "\""); +} + +TEST_CASE("parameters quote 12", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, ",\"", ",", '\"') + == true); + REQUIRE(pars.size() == 1); + REQUIRE(pars[0] == "\""); +} + +TEST_CASE("parameters quote 13", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\",", ",", '\"') + == true); + REQUIRE(pars.size() == 1); + REQUIRE(pars[0] == "\","); +} + +TEST_CASE("parameters quote 14", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\\\",", ",", '\"') + == true); + REQUIRE(pars.size() == 1); + REQUIRE(pars[0] == "\""); +} + +TEST_CASE("parameters quote 15", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, ",\\\"", ",", '\"') + == true); + REQUIRE(pars.size() == 1); + REQUIRE(pars[0] == "\""); +} + +TEST_CASE("parameters quote 16", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\"one test\"", ",", '\"') == + true); + REQUIRE(pars.size() == 1); + REQUIRE(pars[0] == "one test"); +} + +TEST_CASE("parameters quote 17", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\"one, test\"", ",", '\"') == + true); + REQUIRE(pars.size() == 1); + REQUIRE(pars[0] == "one, test"); +} + +TEST_CASE("parameters quote 18", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\"one\\\" test\"", ",", '\"') == + true); + REQUIRE(pars.size() == 1); + REQUIRE(pars[0] == "one\" test"); +} + +TEST_CASE("parameters quote 19", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\"one\\\" ,test\"", ",", '\"') == + true); + REQUIRE(pars.size() == 1); + REQUIRE(pars[0] == "one\" ,test"); +} + +TEST_CASE("parameters quote 20", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\"one\\\" test,\"", ",", '\"') == + true); + REQUIRE(pars.size() == 1); + REQUIRE(pars[0] == "one\" test,"); +} + +TEST_CASE("parameters complex 1", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\"test\" \"line\"", ",", '\"') == true); + REQUIRE(pars.size() == 1); + REQUIRE(pars[0] == "test\" \"line"); +} + +TEST_CASE("parameters complex 2", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\"test\", \"line\"", ",", '\"') == true); + REQUIRE(pars.size() == 2); + REQUIRE(pars[0] == "test"); + REQUIRE(pars[1] == "line"); +} + +TEST_CASE("parameters complex 3", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\"test,\" \"line\"", ",", '\"') == true); + REQUIRE(pars.size() == 1); + REQUIRE(pars[0] == "test,\" \"line"); +} + +TEST_CASE("parameters broken 1", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, "\"", ",", '\"') == true); + REQUIRE(pars.size() == 1); + REQUIRE(pars[0] == "\""); +} + +TEST_CASE("parameters broken 2", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, ",", ",", '\"') == true); + REQUIRE(pars.empty()); +} + +TEST_CASE("parameters broken 3", "") +{ + StringVect pars; + REQUIRE(splitParameters(pars, + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,", ",", '\"') == true); + REQUIRE(pars.empty()); +} diff --git a/src/unittests/utils/stringutils_unittest.cc b/src/unittests/utils/stringutils_unittest.cc new file mode 100644 index 000000000..b137ef30d --- /dev/null +++ b/src/unittests/utils/stringutils_unittest.cc @@ -0,0 +1,1724 @@ +/* + * The ManaPlus Client + * Copyright (C) 2012-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "configuration.h" +#include "logger.h" + +#include "const/utils/utf8.h" + +#include "fs/virtfs/fs.h" + +#include "utils/delete2.h" +#include "utils/dtor.h" + +#include "resources/iteminfo.h" + +#include "resources/db/itemdb.h" + +#include "resources/resourcemanager/resourcemanager.h" + +#include "debug.h" + +TEST_CASE("stringuntils trim 1", "") +{ + std::string str = "str"; + REQUIRE("str" == trim(str)); + + str = " str"; + REQUIRE("str" == trim(str)); + REQUIRE("str" == trim(str)); + + str = " str this IS Long Стринг " + "~!@#$%^&*()_+`-=[]\\{}|;':\",./<>? "; + REQUIRE("str this IS Long Стринг ~!@#$%^&*()_+`-=[]\\{}|;':\",./<>?" == + trim(str)); + + str = ""; + REQUIRE(trim(str).empty()); +} + +TEST_CASE("stringuntils toLower 1", "") +{ + std::string str = "str"; + REQUIRE("str" == toLower(str)); + + str = " StR"; + REQUIRE(" str" == toLower(str)); + + str = " str this IS Long " + "~!@#$%^&*()_+`-=[]\\{}|;':\",./<>? "; + + REQUIRE(" str this is long ~!@#$%^&*()_+`-=[]\\{}|;':\",./<>? " == + toLower(str)); + + str = ""; + REQUIRE(toLower(str).empty()); +} + +TEST_CASE("stringuntils toUpper 1", "") +{ + std::string str = "str"; + REQUIRE("STR" == toUpper(str)); + + str = " StR"; + REQUIRE(" STR" == toUpper(str)); + + str = " str this IS Long " + "~!@#$%^&*()_+`-=[]\\{}|;':,./<>? "; + + REQUIRE(" STR THIS IS LONG ~!@#$%^&*()_+`-=[]\\{}|;':,./<>? " == + toUpper(str)); + + str = ""; + REQUIRE(toUpper(str).empty()); +} + +TEST_CASE("stringuntils atox 1", "") +{ + std::string str = "0x10"; + REQUIRE(16 == atox(str)); + + str = "0x0"; + REQUIRE(0 == atox(str)); + + str = "0x1"; + REQUIRE(1 == atox(str)); + + str = "0x0x0x0x0x0x0x0"; + REQUIRE(0 == atox(str)); + + str = "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + const int k = atox(str); + printf("%d\n", k); // for avoid warning + + str = ""; + REQUIRE(0 == atox(str)); + + str = "0"; + REQUIRE(0 == atox(str)); + + str = "0x"; + REQUIRE(0 == atox(str)); + + str = "zzz"; + REQUIRE(0 == atox(str)); +} + +TEST_CASE("stringuntils ipToString 1", "") +{ + REQUIRE("0.0.0.0" == std::string(ipToString(0))); + REQUIRE("219.255.210.73" == std::string(ipToString(1238564827))); +} + +TEST_CASE("stringuntils toString 1", "") +{ + REQUIRE(strprintf("%d", 0) == toString(0)); + REQUIRE(strprintf("%d", -1) == toString(-1)); + REQUIRE(strprintf("%d", 30000000) == toString(30000000)); + REQUIRE(strprintf("%d", -10000000) == toString(-10000000)); + REQUIRE(strprintf("%d", 30000000) == toString( + static_cast<signed int>(30000000))); + REQUIRE(strprintf("%d", 3000) == toString(CAST_U16(3000))); + REQUIRE(strprintf("%d", 123) == toString(CAST_U8(123))); + REQUIRE(strprintf("%u", static_cast<uint32_t>(30000000)) == toString( + static_cast<uint32_t>(30000000))); + REQUIRE(strprintf("%f", 3.1f) == toString(3.1f)); + REQUIRE(strprintf("%f", 3.1) == toString(3.1)); +} + +TEST_CASE("stringuntils toStringPrint 1", "") +{ + REQUIRE(toStringPrint(0) == "0 0x0"); + REQUIRE(toStringPrint(10) == "10 0xa"); + REQUIRE(toStringPrint(255) == "255 0xff"); +} + +TEST_CASE("stringuntils parse2Int 1", "") +{ + int a = -1; + int b = -1; + + REQUIRE(parse2Int("", a, b) == false); + REQUIRE(a == -1); + REQUIRE(b == -1); + + a = -1; + b = -1; + REQUIRE(parse2Int(",", a, b) == false); + REQUIRE(a == -1); + REQUIRE(b == -1); + + a = -1; + b = -1; + REQUIRE(parse2Int("10,20", a, b) == true); + REQUIRE(a == 10); + REQUIRE(b == 20); + + a = -1; + b = -1; + REQUIRE(parse2Int("10 20", a, b) == true); + REQUIRE(a == 10); + REQUIRE(b == 20); + + a = -1; + b = -1; + REQUIRE(parse2Int("10 z20", a, b) == true); + REQUIRE(a == 10); + REQUIRE(b == 0); +} + +TEST_CASE("stringuntils parse2Str 1", "") +{ + std::string str1 = "-"; + std::string str2 = "-"; + + REQUIRE(parse2Str("", str1, str2) == false); + REQUIRE(str1 == "-"); + REQUIRE(str2 == "-"); + + REQUIRE(parse2Str(",", str1, str2) == false); + REQUIRE(str1 == "-"); + REQUIRE(str2 == "-"); + + str1 = "-"; + str2 = "-"; + REQUIRE(parse2Str("test line", str1, str2) == true); + REQUIRE(str1 == "test"); + REQUIRE(str2 == "line"); + + str1 = "-"; + str2 = "-"; + REQUIRE(parse2Str("test,line", str1, str2) == true); + REQUIRE(str1 == "test"); + REQUIRE(str2 == "line"); +} + +TEST_CASE("stringuntils parseNumber 1", "") +{ + REQUIRE(parseNumber("") == 0); + REQUIRE(parseNumber("0x") == 0); + REQUIRE(parseNumber("10") == 10); + REQUIRE(parseNumber("h10") == 16); + REQUIRE(parseNumber("x100") == 256); + REQUIRE(parseNumber("0x20") == 32); +} + +TEST_CASE("stringuntils removeToken 1", "") +{ + std::string str; + + REQUIRE(removeToken(str, " ").empty()); + REQUIRE(str.empty()); + + str = "test"; + REQUIRE(removeToken(str, " ").empty()); + REQUIRE(str.empty()); + + str = "test line"; + REQUIRE(removeToken(str, " ") == "line"); + REQUIRE(str == "line"); + + str = "test,line"; + REQUIRE(removeToken(str, ",") == "line"); + REQUIRE(str == "line"); + + str = "test line"; + REQUIRE(removeToken(str, ",").empty()); + REQUIRE(str.empty()); + + str = ",line"; + REQUIRE(removeToken(str, ",").empty()); + REQUIRE(str.empty()); +} + +TEST_CASE("stringuntils strprintf 1", "") +{ + REQUIRE(strprintf("%s very long string. 123456789012345678901234567890" + "+++++++++++++++++++++++++++++++++++++++" + "________________________________" + "***********************************" + "----------------------------------------" + "|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| %s", + "test", "end of test") == + "test very long string. 123456789012345678901234567890" + "+++++++++++++++++++++++++++++++++++++++" + "________________________________" + "***********************************" + "----------------------------------------" + "|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| " + "end of test"); +} + +TEST_CASE("stringuntils toString 2", "") +{ + for (int f = 0; f < 10000000; f += 123) + { + REQUIRE(strprintf("%d", f) == toString(f)); + } +} + +TEST_CASE("stringuntils removeColors 1", "") +{ + REQUIRE(removeColors("").empty()); + REQUIRE("#" == removeColors("#")); + REQUIRE("##" == removeColors("##")); + REQUIRE(removeColors("##1").empty()); + REQUIRE("2" == removeColors("##12")); + REQUIRE("1##" == removeColors("1##")); + REQUIRE("1" == removeColors("1##2")); + REQUIRE("13" == removeColors("1##23")); + REQUIRE("#1#2" == removeColors("#1#2")); + REQUIRE("#1" == removeColors("#1##2")); +} + +TEST_CASE("stringuntils compareStrI 1", "") +{ + std::string str1; + std::string str2; + REQUIRE(0 == compareStrI(str1, str2)); + + str1 = "test"; + str2 = "test"; + REQUIRE(0 == compareStrI(str1, str2)); + + str1 = "test"; + str2 = "test1"; + REQUIRE(0 > compareStrI(str1, str2)); + + str1 = "test"; + str2 = "aest1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + REQUIRE(0 < compareStrI(str1, str2)); + + str1 = "testaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + str2 = "testaa"; + REQUIRE(0 < compareStrI(str1, str2)); +} + +TEST_CASE("stringuntils isWordSeparator 1", "") +{ + REQUIRE(isWordSeparator(' ')); + REQUIRE(isWordSeparator(',')); + REQUIRE(isWordSeparator('.')); + REQUIRE(isWordSeparator('\"')); + REQUIRE(!isWordSeparator(0)); + REQUIRE(!isWordSeparator('a')); + REQUIRE(!isWordSeparator('-')); +} + +TEST_CASE("stringuntils findSameSubstring", "") +{ + std::string str1; + std::string str2; + + REQUIRE(findSameSubstring("", "").empty()); + + str1 = "test line"; + str2 = "test line"; + REQUIRE("test line" == findSameSubstring(str1, str2)); + + str1 = "test li"; + str2 = "test line"; + REQUIRE("test li" == findSameSubstring(str1, str2)); + + str1 = "test li"; + str2 = "est li"; + REQUIRE(findSameSubstring(str1, str2).empty()); +} + +TEST_CASE("stringuntils findSameSubstringI", "") +{ + std::string str1; + std::string str2; + + REQUIRE(findSameSubstringI("", "").empty()); + + str1 = "tEst line"; + str2 = "tesT line"; + REQUIRE("tEst line" == findSameSubstringI(str1, str2)); + + str1 = "test Li"; + str2 = "test lINe"; + REQUIRE("test Li" == findSameSubstringI(str1, str2)); + + str1 = "test lINe"; + str2 = "test Li"; + REQUIRE("test lI" == findSameSubstringI(str1, str2)); + + str1 = "teSt li"; + str2 = "est li"; + REQUIRE(findSameSubstringI(str1, str2).empty()); +} + +TEST_CASE("stringuntils findI 1", "") +{ + REQUIRE(0 == findI("", "")); + REQUIRE(std::string::npos == findI("test", "line")); + REQUIRE(0 == findI("test line", "t")); + REQUIRE(0 == findI("test line", "te")); + REQUIRE(3 == findI("test line", "t l")); +} + +TEST_CASE("stringuntils findI 2", "") +{ + std::vector <std::string> vect1; + vect1.push_back("test"); + vect1.push_back("line"); + vect1.push_back("qwe"); + + REQUIRE(std::string::npos == findI("", vect1)); + REQUIRE(0 == findI("test", vect1)); + REQUIRE(0 == findI("tesT lIne", vect1)); + REQUIRE(5 == findI("teoT line", vect1)); + REQUIRE(std::string::npos == findI("zzz", vect1)); +} + +TEST_CASE("stringuntils encodeStr 1", "") +{ + std::string str = encodeStr(10, 1); + REQUIRE(10 == decodeStr(str)); + + str.clear(); + REQUIRE(0 == decodeStr(str)); + + str = encodeStr(10, 2); + REQUIRE(10 == decodeStr(str)); + + str = encodeStr(100, 3); + REQUIRE(100 == decodeStr(str)); + + str = encodeStr(1000, 4); + REQUIRE(1000 == decodeStr(str)); +} + +TEST_CASE("stringuntils extractNameFromSprite 1", "") +{ + REQUIRE(extractNameFromSprite("").empty()); + REQUIRE("test" == extractNameFromSprite("test")); + REQUIRE("test" == extractNameFromSprite("test.qwe")); + REQUIRE("line" == extractNameFromSprite("test/line.zzz")); + REQUIRE("line" == extractNameFromSprite("test\\line.zzz")); + REQUIRE("line" == extractNameFromSprite("test/test2\\line.zzz")); + REQUIRE("line" == extractNameFromSprite("test\\test2/line.zzz")); +} + +TEST_CASE("stringuntils removeSpriteIndex 1", "") +{ + REQUIRE(removeSpriteIndex("").empty()); + REQUIRE("test" == removeSpriteIndex("test")); + REQUIRE("test" == removeSpriteIndex("test[1]")); + REQUIRE("line" == removeSpriteIndex("test/line[12]")); + REQUIRE("line" == removeSpriteIndex("test\\line[12]")); + REQUIRE("line" == removeSpriteIndex("test/test2\\line[12]")); + REQUIRE("line" == removeSpriteIndex("test\\test2/line[1]")); +} + +TEST_CASE("stringutils getSafeUtf8String 1", "") +{ + const char *str; + str = getSafeUtf8String(""); + REQUIRE(str != nullptr); + REQUIRE(strcmp("", str) == 0); + REQUIRE(str[0] == '\0'); + REQUIRE(str[UTF8_MAX_SIZE - 1] == '\0'); + delete [] str; + + str = getSafeUtf8String("test line"); + REQUIRE(str != nullptr); + REQUIRE(strcmp("test line", str) == 0); + REQUIRE(str[strlen("test line")] == '\0'); + REQUIRE(str[UTF8_MAX_SIZE - 1] == '\0'); + delete [] str; + + str = getSafeUtf8String("1"); + REQUIRE(str != nullptr); + REQUIRE(strcmp("1", str) == 0); + REQUIRE(str[1] == '\0'); + REQUIRE(str[UTF8_MAX_SIZE - 1] == '\0'); + delete [] str; +} + +TEST_CASE("stringutils getSafeUtf8String 2", "") +{ + char *str; + + getSafeUtf8String("test", nullptr); + + str = new char[65535]; + getSafeUtf8String("", str); + REQUIRE(str != nullptr); + REQUIRE(strcmp("", str) == 0); + REQUIRE(str[0] == '\0'); + REQUIRE(str[UTF8_MAX_SIZE - 1] == '\0'); + delete [] str; + + str = new char[65535]; + getSafeUtf8String("test line", str); + REQUIRE(str != nullptr); + REQUIRE(strcmp("test line", str) == 0); + REQUIRE(str[strlen("test line")] == '\0'); + REQUIRE(str[UTF8_MAX_SIZE - 1] == '\0'); + delete [] str; + + str = new char[65535]; + getSafeUtf8String("1", str); + REQUIRE(str != nullptr); + REQUIRE(strcmp("1", str) == 0); + REQUIRE(str[1] == '\0'); + REQUIRE(str[UTF8_MAX_SIZE - 1] == '\0'); + delete [] str; + + str = new char[65535]; + char *data1 = new char[65510]; + memset(data1, 'a', 65510); + data1[65509] = '\0'; + char *data2 = new char[65510]; + memset(data2, 'a', 65500); + data2[65500] = '\0'; + getSafeUtf8String(data1, str); + REQUIRE(str != nullptr); + REQUIRE(strcmp(data2, str) == 0); + REQUIRE(str[65500] == '\0'); + delete [] data1; + delete [] data2; + delete [] str; +} + +TEST_CASE("stringuntils getFileName 1", "") +{ + REQUIRE(getFileName("").empty()); + REQUIRE("file" == getFileName("file")); + REQUIRE("file" == getFileName("test/file1\\file")); + REQUIRE("file" == getFileName("test\\file1/file")); + REQUIRE(getFileName("file/").empty()); + REQUIRE("file" == getFileName("/file")); +} + +TEST_CASE("stringuntils getFileDir 1", "") +{ + REQUIRE(getFileDir("").empty()); + REQUIRE("file" == getFileDir("file")); + REQUIRE("test/file1" == getFileDir("test/file1\\file")); + REQUIRE("test\\file1" == getFileDir("test\\file1/file")); + REQUIRE("file" == getFileDir("file/")); + REQUIRE(getFileDir("/file").empty()); +} + +TEST_CASE("stringuntils replaceAll 1", "") +{ + std::string str1; + std::string str2; + std::string str3; + + REQUIRE(replaceAll(str1, str2, str3).empty()); + + str1 = "this is test line"; + str2 = ""; + str3 = ""; + REQUIRE("this is test line" == replaceAll(str1, str2, str3)); + + str1 = "this is test line"; + str2 = "is "; + str3 = ""; + REQUIRE("thtest line" == replaceAll(str1, str2, str3)); + + str1 = "this is test line"; + str2 = ""; + str3 = "1"; + REQUIRE("this is test line" == replaceAll(str1, str2, str3)); +} + +TEST_CASE("stringuntils replaceRecursiveAll 1", "") +{ + std::string str; + str = ""; + replaceRecursiveAll(str, "line", '.'); + REQUIRE(str.empty()); + str = "test line"; + replaceRecursiveAll(str, "line", '.'); + REQUIRE(str == "test ."); + str = "11112222"; + replaceRecursiveAll(str, "11", '1'); + REQUIRE(str == "12222"); + str = "122221"; + replaceRecursiveAll(str, "11", '1'); + REQUIRE(str == "122221"); + str = "1222211"; + replaceRecursiveAll(str, "11", '1'); + REQUIRE(str == "122221"); + str = "11112222"; + replaceRecursiveAll(str, "112", '1'); + REQUIRE(str == "111222"); + str = "111122224"; + replaceRecursiveAll(str, "112", '1'); + REQUIRE(str == "1112224"); + str = "3111122224"; + replaceRecursiveAll(str, "112", '1'); + REQUIRE(str == "31112224"); + str = "121212"; + replaceRecursiveAll(str, "12", '1'); + REQUIRE(str == "111"); + str = "1121212"; + replaceRecursiveAll(str, "12", '1'); + REQUIRE(str == "1111"); + str = "11212122"; + replaceRecursiveAll(str, "12", '1'); + REQUIRE(str == "1111"); + str = "112121222"; + replaceRecursiveAll(str, "12", '1'); + REQUIRE(str == "1111"); + str = "112211221122"; + replaceRecursiveAll(str, "12", '1'); + REQUIRE(str == "111111"); +} + +TEST_CASE("stringuntils getBoolFromString 1", "") +{ + REQUIRE(getBoolFromString("true")); + REQUIRE(getBoolFromString("yes")); + REQUIRE(getBoolFromString("on")); + REQUIRE(!getBoolFromString("false")); + REQUIRE(!getBoolFromString("no")); + REQUIRE(!getBoolFromString("off")); + REQUIRE(getBoolFromString("1")); + REQUIRE(!getBoolFromString("0")); + REQUIRE(getBoolFromString("2")); + + REQUIRE(getBoolFromString(" true")); + REQUIRE(getBoolFromString("yes ")); + REQUIRE(getBoolFromString(" on")); + REQUIRE(!getBoolFromString("false ")); + REQUIRE(!getBoolFromString(" no")); + REQUIRE(!getBoolFromString("off ")); + REQUIRE(getBoolFromString(" 1")); + REQUIRE(!getBoolFromString("0 ")); + REQUIRE(getBoolFromString(" 2")); + + REQUIRE(getBoolFromString("tRue ")); + REQUIRE(getBoolFromString(" Yes")); + REQUIRE(getBoolFromString("ON ")); + REQUIRE(!getBoolFromString(" fALse")); + REQUIRE(!getBoolFromString("nO ")); + REQUIRE(!getBoolFromString(" oFF")); +} + +TEST_CASE("stringuntils parseBoolean 1", "") +{ + REQUIRE(parseBoolean("true") == 1); + REQUIRE(parseBoolean("yes") == 1); + REQUIRE(parseBoolean("on") == 1); + REQUIRE(parseBoolean("false") == 0); + REQUIRE(parseBoolean("no") == 0); + REQUIRE(parseBoolean("off") == 0); + REQUIRE(parseBoolean("1") == 1); + REQUIRE(parseBoolean("0") == 0); + REQUIRE(parseBoolean("2") == -1); + REQUIRE(parseBoolean("test") == -1); + REQUIRE(parseBoolean("") == -1); + + REQUIRE(parseBoolean("true ") == 1); + REQUIRE(parseBoolean(" yes") == 1); + REQUIRE(parseBoolean("on ") == 1); + REQUIRE(parseBoolean(" false") == 0); + REQUIRE(parseBoolean("no ") == 0); + REQUIRE(parseBoolean(" off") == 0); + REQUIRE(parseBoolean("1 ") == 1); + REQUIRE(parseBoolean(" 0") == 0); + REQUIRE(parseBoolean("2 ") == -1); + REQUIRE(parseBoolean(" test") == -1); + REQUIRE(parseBoolean(" ") == -1); + + REQUIRE(parseBoolean(" tRue") == 1); + REQUIRE(parseBoolean("Yes ") == 1); + REQUIRE(parseBoolean(" ON") == 1); + REQUIRE(parseBoolean("FaLse ") == 0); + REQUIRE(parseBoolean(" nO") == 0); + REQUIRE(parseBoolean("oFf ") == 0); + REQUIRE(parseBoolean(" tEst") == -1); +} + +TEST_CASE("stringuntils splitToIntSet 1", "") +{ + std::set<int> tokens; + splitToIntSet(tokens, "", ','); + REQUIRE(tokens.empty() == true); + + tokens.clear(); + splitToIntSet(tokens, "10z,aa,-1", ','); + REQUIRE(tokens.size() == 3); + REQUIRE(tokens.find(10) != tokens.end()); + REQUIRE(tokens.find(0) != tokens.end()); + REQUIRE(tokens.find(-1) != tokens.end()); + + tokens.clear(); + splitToIntSet(tokens, "10,2,30", ','); + REQUIRE(tokens.size() == 3); + REQUIRE(tokens.find(10) != tokens.end()); + REQUIRE(tokens.find(2) != tokens.end()); + REQUIRE(tokens.find(30) != tokens.end()); + + tokens.clear(); + splitToIntSet(tokens, "10,2,30,", ','); + REQUIRE(tokens.size() == 3); + REQUIRE(tokens.find(10) != tokens.end()); + REQUIRE(tokens.find(2) != tokens.end()); + REQUIRE(tokens.find(30) != tokens.end()); + + tokens.clear(); + splitToIntSet(tokens, "10,2;30", ','); + REQUIRE(tokens.size() == 2); + REQUIRE(tokens.find(10) != tokens.end()); + REQUIRE(tokens.find(2) != tokens.end()); + + tokens.clear(); + splitToIntSet(tokens, "10;20;30", ';'); + REQUIRE(tokens.size() == 3); + REQUIRE(tokens.find(10) != tokens.end()); + REQUIRE(tokens.find(20) != tokens.end()); + REQUIRE(tokens.find(30) != tokens.end()); +} + +TEST_CASE("stringuntils splitToIntList 1", "") +{ + std::list<int> tokens; + tokens = splitToIntList("", ','); + REQUIRE(tokens.empty() == true); + + tokens.clear(); + tokens = splitToIntList("10z,a,-1", ','); + REQUIRE(tokens.size() == 3); + REQUIRE(tokens.front() == 10); + tokens.pop_front(); + REQUIRE(tokens.front() == 0); + tokens.pop_front(); + REQUIRE(tokens.front() == -1); + tokens.pop_front(); + + tokens.clear(); + tokens = splitToIntList("10,2,30", ','); + REQUIRE(tokens.size() == 3); + REQUIRE(tokens.front() == 10); + tokens.pop_front(); + REQUIRE(tokens.front() == 2); + tokens.pop_front(); + REQUIRE(tokens.front() == 30); + tokens.pop_front(); + + tokens.clear(); + tokens = splitToIntList("10,2,30,", ','); + REQUIRE(tokens.size() == 3); + REQUIRE(tokens.front() == 10); + tokens.pop_front(); + REQUIRE(tokens.front() == 2); + tokens.pop_front(); + REQUIRE(tokens.front() == 30); + tokens.pop_front(); + + tokens.clear(); + tokens = splitToIntList("10,2;30", ','); + REQUIRE(tokens.size() == 2); + REQUIRE(tokens.front() == 10); + tokens.pop_front(); + REQUIRE(tokens.front() == 2); + tokens.pop_front(); + + tokens.clear(); + tokens = splitToIntList("10;20;30", ';'); + REQUIRE(tokens.size() == 3); + REQUIRE(tokens.front() == 10); + tokens.pop_front(); + REQUIRE(tokens.front() == 20); + tokens.pop_front(); + REQUIRE(tokens.front() == 30); + tokens.pop_front(); +} + +TEST_CASE("stringuntils splitToStringSet 1", "") +{ + std::set<std::string> tokens; + splitToStringSet(tokens, "", ','); + REQUIRE(tokens.empty() == true); + + tokens.clear(); + splitToStringSet(tokens, "10q,2w,30e", ','); + REQUIRE(tokens.size() == 3); + REQUIRE(tokens.find("10q") != tokens.end()); + REQUIRE(tokens.find("2w") != tokens.end()); + REQUIRE(tokens.find("30e") != tokens.end()); + + tokens.clear(); + splitToStringSet(tokens, "10q,2w,30e,", ','); + REQUIRE(tokens.size() == 3); + REQUIRE(tokens.find("10q") != tokens.end()); + REQUIRE(tokens.find("2w") != tokens.end()); + REQUIRE(tokens.find("30e") != tokens.end()); + + tokens.clear(); + splitToStringSet(tokens, "10q,,30e", ','); + REQUIRE(tokens.size() == 2); + REQUIRE(tokens.find("10q") != tokens.end()); + REQUIRE(tokens.find("30e") != tokens.end()); + + tokens.clear(); + splitToStringSet(tokens, "10q,2w,30e,", ','); + REQUIRE(tokens.size() == 3); + REQUIRE(tokens.find("10q") != tokens.end()); + REQUIRE(tokens.find("2w") != tokens.end()); + REQUIRE(tokens.find("30e") != tokens.end()); + + tokens.clear(); + splitToStringSet(tokens, "10w,2w;30e", ','); + REQUIRE(tokens.size() == 2); + REQUIRE(tokens.find("10w") != tokens.end()); + REQUIRE(tokens.find("2w;30e") != tokens.end()); + + tokens.clear(); + splitToStringSet(tokens, "10q;20w;30e", ';'); + REQUIRE(tokens.size() == 3); + REQUIRE(tokens.find("10q") != tokens.end()); + REQUIRE(tokens.find("20w") != tokens.end()); + REQUIRE(tokens.find("30e") != tokens.end()); +} + +TEST_CASE("stringuntils splitToIntVector 1", "") +{ + std::vector<int> tokens; + splitToIntVector(tokens, "", ','); + REQUIRE(tokens.empty() == true); + + tokens.clear(); + splitToIntVector(tokens, "10,2,30", ','); + REQUIRE(tokens.size() == 3); + REQUIRE(tokens[0] == 10); + REQUIRE(tokens[1] == 2); + REQUIRE(tokens[2] == 30); + + tokens.clear(); + splitToIntVector(tokens, "10,2a,z30", ','); + REQUIRE(tokens.size() == 3); + REQUIRE(tokens[0] == 10); + REQUIRE(tokens[1] == 2); + REQUIRE(tokens[2] == 0); + + tokens.clear(); + splitToIntVector(tokens, "10,2,30,", ','); + REQUIRE(tokens.size() == 3); + REQUIRE(tokens[0] == 10); + REQUIRE(tokens[1] == 2); + REQUIRE(tokens[2] == 30); + + tokens.clear(); + splitToIntVector(tokens, "10,,30", ','); + REQUIRE(tokens.size() == 2); + REQUIRE(tokens[0] == 10); + REQUIRE(tokens[1] == 30); + + tokens.clear(); + splitToIntVector(tokens, "10,2;30", ','); + REQUIRE(tokens.size() == 2); + REQUIRE(tokens[0] == 10); + REQUIRE(tokens[1] == 2); + + tokens.clear(); + splitToIntVector(tokens, "10;20;30", ';'); + REQUIRE(tokens.size() == 3); + REQUIRE(tokens[0] == 10); + REQUIRE(tokens[1] == 20); + REQUIRE(tokens[2] == 30); +} + +TEST_CASE("stringuntils splitToStringVector 1", "") +{ + std::vector<std::string> tokens; + splitToStringVector(tokens, "", ','); + REQUIRE(tokens.empty() == true); + + tokens.clear(); + splitToStringVector(tokens, "t,line,zz", ','); + REQUIRE(tokens.size() == 3); + REQUIRE(tokens[0] == "t"); + REQUIRE(tokens[1] == "line"); + REQUIRE(tokens[2] == "zz"); + + tokens.clear(); + splitToStringVector(tokens, "t,line,zz,", ','); + REQUIRE(tokens.size() == 3); + REQUIRE(tokens[0] == "t"); + REQUIRE(tokens[1] == "line"); + REQUIRE(tokens[2] == "zz"); + + tokens.clear(); + splitToStringVector(tokens, "t,,zz", ','); + REQUIRE(tokens.size() == 2); + REQUIRE(tokens[0] == "t"); + REQUIRE(tokens[1] == "zz"); + + tokens.clear(); + splitToStringVector(tokens, "10,a2;30", ','); + REQUIRE(tokens.size() == 2); + REQUIRE(tokens[0] == "10"); + REQUIRE(tokens[1] == "a2;30"); + + tokens.clear(); + splitToStringVector(tokens, "a10;b;3line", ';'); + REQUIRE(tokens.size() == 3); + REQUIRE(tokens[0] == "a10"); + REQUIRE(tokens[1] == "b"); + REQUIRE(tokens[2] == "3line"); +} + +TEST_CASE("stringuntils replaceSpecialChars 1", "") +{ + std::string str; + + str = ""; + replaceSpecialChars(str); + REQUIRE(str.empty()); + + str = "test"; + replaceSpecialChars(str); + REQUIRE("test" == str); + + str = "&"; + replaceSpecialChars(str); + REQUIRE("&" == str); + + str = "&1"; + replaceSpecialChars(str); + REQUIRE("&1" == str); + + str = "&33"; + replaceSpecialChars(str); + REQUIRE("&33" == str); + + str = "&33;"; + replaceSpecialChars(str); + REQUIRE("!" == str); + + str = "&33z;"; + replaceSpecialChars(str); + REQUIRE("&33z;" == str); + + str = "1&33;"; + replaceSpecialChars(str); + REQUIRE("1!" == str); + + str = "&33;2"; + replaceSpecialChars(str); + REQUIRE("!2" == str); + + str = "&33;&"; + replaceSpecialChars(str); + REQUIRE("!&" == str); + + str = "test line&33;"; + replaceSpecialChars(str); + REQUIRE("test line!" == str); +} + +TEST_CASE("stringuntils normalize 1", "") +{ + REQUIRE(normalize("").empty()); + REQUIRE(normalize("test") == "test"); + REQUIRE(normalize("Test") == "test"); + REQUIRE(normalize(" test line") == "test line"); + REQUIRE(normalize("test line ") == "test line"); + REQUIRE(normalize(" tEst line") == "test line"); + REQUIRE(normalize("test lIne ") == "test line"); +} + +TEST_CASE("stringuntils combineDye 1", "") +{ + REQUIRE(combineDye("", "").empty()); + REQUIRE("test" == combineDye("test", "")); + REQUIRE("|line" == combineDye("", "line")); + REQUIRE("test|line" == combineDye("test", "line")); + REQUIRE("|line" == combineDye("|w", "line")); + REQUIRE("aaa|line" == combineDye("aaa|w", "line")); + REQUIRE("test|line" == combineDye("test|w", "line")); +} + +TEST_CASE("stringuntils combineDye 2", "") +{ + REQUIRE(combineDye2("", "").empty()); + REQUIRE("test" == combineDye2("test", "")); + REQUIRE("test" == combineDye2("test", "W")); + REQUIRE(combineDye2("", "line").empty()); + REQUIRE("test.xml" == combineDye2("test.xml", "123")); + REQUIRE("test.xml|#43413d,59544f,7a706c" == + combineDye2("test.xml|#43413d,59544f,7a706c", "")); + REQUIRE("test.xml|#43413d,59544f,7a706c:W;" == + combineDye2("test.xml|#43413d,59544f,7a706c", "W")); + REQUIRE("test.xml|#43413d,59544f,7a706c:W;#123456:B;" == + combineDye2("test.xml|#43413d,59544f,7a706c;#123456", "W;B")); +} + +TEST_CASE("stringuntils combineDye 3", "") +{ + REQUIRE(combineDye3("", "").empty()); + REQUIRE("test" == combineDye3("test", "")); + REQUIRE(combineDye3("", "line").empty()); + REQUIRE("test.xml|123" == combineDye3("test.xml", "123")); + REQUIRE("test.xml|#43413d,59544f,7a706c" == + combineDye3("test.xml|#43413d,59544f,7a706c", "")); + REQUIRE("test.xml|#43413d,59544f,7a706c:W;" == + combineDye3("test.xml|#43413d,59544f,7a706c", "W")); + REQUIRE("test.xml|#43413d,59544f,7a706c:W;#123456:B;" == + combineDye3("test.xml|#43413d,59544f,7a706c;#123456", "W;B")); +} + +TEST_CASE("stringuntils packList 1", "") +{ + std::list <std::string> list; + REQUIRE(packList(list).empty()); + + list.push_back(std::string()); + REQUIRE("|" == packList(list)); + + list.clear(); + list.push_back("test"); + REQUIRE("test" == packList(list)); + + list.push_back("line"); + REQUIRE("test|line" == packList(list)); + + list.push_back("2"); + REQUIRE("test|line|2" == packList(list)); + + list.clear(); + list.push_back("|test"); + list.push_back("line"); + REQUIRE("|test|line" == packList(list)); +} + +TEST_CASE("stringuntils stringToHexPath 1", "") +{ + std::string str; + + str = ""; + REQUIRE(stringToHexPath(str).empty()); + + str = "a"; + REQUIRE("%61/" == stringToHexPath(str)); + + str = "ab"; + REQUIRE("%61/%62" == stringToHexPath(str)); + + str = "abc"; + REQUIRE("%61/%62%63" == stringToHexPath(str)); + + str = "abcd"; + REQUIRE("%61/%62%63%64" == stringToHexPath(str)); +} + +TEST_CASE("stringuntils deleteCharLeft 1", "") +{ + std::string str; + unsigned int pos = 0; + + str = ""; + deleteCharLeft(str, nullptr); + REQUIRE(str.empty()); + + str = "test line"; + pos = 4; + deleteCharLeft(str, &pos); + REQUIRE("tes line" == str); + + str = "тест line"; + pos = 8; + deleteCharLeft(str, &pos); + REQUIRE("тес line" == str); + + str = "test line\x0"; + pos = 4; + deleteCharLeft(str, &pos); + REQUIRE("tes line\x0" == str); +} + +TEST_CASE("stringuntils findLast 1", "") +{ + std::string str; + + str = ""; + REQUIRE(findLast(str, "")); + + str = "test line"; + REQUIRE(findLast(str, "line")); + + str = "test line"; + REQUIRE(!findLast(str, "lin")); +} + +TEST_CASE("stringuntils findFirst 1", "") +{ + std::string str; + + str = ""; + REQUIRE(findFirst(str, "")); + + str = "test line"; + REQUIRE(findFirst(str, "test")); + + str = "test"; + REQUIRE(findFirst(str, "test line") == false); + + str = "test line"; + REQUIRE(findFirst(str, "est") == false); +} + +TEST_CASE("stringuntils findCutLast 1", "") +{ + std::string str; + + str = ""; + REQUIRE(findCutLast(str, "")); + REQUIRE(str.empty()); + + str = "test line"; + REQUIRE(findCutLast(str, "line")); + REQUIRE("test " == str); + + str = "test line"; + REQUIRE(findCutLast(str, "lin") == false); + REQUIRE("test line" == str); + + str = "test"; + REQUIRE(findCutLast(str, "test line") == false); + REQUIRE("test" == str); +} + +TEST_CASE("stringuntils CutLast 1", "") +{ + std::string str; + + str = ""; + cutLast(str, ""); + REQUIRE(str.empty()); + + str = "test line"; + cutLast(str, "line"); + REQUIRE("test " == str); + + str = "test line"; + cutLast(str, "lin"); + REQUIRE("test line" == str); + + str = "test"; + cutLast(str, "test line"); + REQUIRE("test" == str); +} + +TEST_CASE("stringuntils findCutFirst 1", "") +{ + std::string str; + + str = ""; + REQUIRE(findCutFirst(str, "")); + REQUIRE(str.empty()); + + str = "test line"; + REQUIRE(findCutFirst(str, "test")); + REQUIRE(" line" == str); + + str = "test line"; + REQUIRE(findCutFirst(str, "est") == false); + REQUIRE("test line" == str); + + str = "test"; + REQUIRE(findCutFirst(str, "test line") == false); + REQUIRE("test" == str); +} + +TEST_CASE("stringuntils cutFirst 1", "") +{ + std::string str; + + str = ""; + cutFirst(str, ""); + REQUIRE(str.empty()); + + str = "test line"; + cutFirst(str, "test"); + REQUIRE(" line" == str); + + str = "test line"; + cutFirst(str, "est"); + REQUIRE("test line" == str); + + str = "test"; + cutFirst(str, "test line"); + REQUIRE("test" == str); +} + +TEST_CASE("stringuntils removeProtocol 1", "") +{ + std::string str; + + str = ""; + REQUIRE(removeProtocol(str).empty()); + + str = "http://"; + REQUIRE(removeProtocol(str).empty()); + + str = "http://test"; + REQUIRE("test" == removeProtocol(str)); +} + +TEST_CASE("stringuntils strStartWith 1", "") +{ + REQUIRE(strStartWith("", "")); + REQUIRE(!strStartWith("", "1")); + REQUIRE(strStartWith("test line", "test")); + REQUIRE(strStartWith("test line", "test line")); + REQUIRE(!strStartWith("test line", "est")); +} + +TEST_CASE("stringuntils encodeLinkText", "") +{ + std::string str; + + str = encodeLinkText("test line"); + REQUIRE(str == "test line"); + str = encodeLinkText("test|line"); + REQUIRE(str == "test\342\235\230line"); + str = encodeLinkText("test||line"); + REQUIRE(str == "test\342\235\230\342\235\230line"); +} + +TEST_CASE("stringuntils decodeLinkText", "") +{ + std::string str; + + str = encodeLinkText("test|line"); + REQUIRE(str == "test\342\235\230line"); + str = decodeLinkText(str); + REQUIRE(str == "test|line"); +} + +TEST_CASE("stringuntils isDigit", "") +{ + std::string str; + + REQUIRE_FALSE(isDigit("")); + REQUIRE(isDigit("1")); + REQUIRE(isDigit("123")); + REQUIRE_FALSE(isDigit("+123")); + REQUIRE_FALSE(isDigit("-123")); + REQUIRE_FALSE(isDigit("1.23")); + REQUIRE_FALSE(isDigit("12-34")); +} + +TEST_CASE("stringuntils findAny", "") +{ + std::string str; + + REQUIRE(findAny("test line", ",", 0) == std::string::npos); + REQUIRE(findAny("test line", " ", 0) == 4U); + REQUIRE(findAny("test, line", ", ", 0) == 4U); + REQUIRE(findAny("test ,line", ", ", 0) == 4U); + REQUIRE(findAny("test, line", " ,", 2) == 4U); + REQUIRE(findAny("test ,line", " ,", 3) == 4U); + REQUIRE(findAny("\"one\",,two, tree", ",", 5) == 5U); +} + +TEST_CASE("stringuntils escapeString", "") +{ + REQUIRE(escapeString("") == "\"\""); + REQUIRE(escapeString("1") == "\"1\""); + REQUIRE(escapeString(" ") == "\" \""); + REQUIRE(escapeString("\"") == "\"\\\"\""); + REQUIRE(escapeString("123") == "\"123\""); + REQUIRE(escapeString("12\"3") == "\"12\\\"3\""); + REQUIRE(escapeString("12\"\"3") == "\"12\\\"\\\"3\""); + REQUIRE(escapeString("\"123\"") == "\"\\\"123\\\"\""); + REQUIRE(escapeString("\\") == "\"\\\""); + REQUIRE(escapeString("12\\3") == "\"12\\3\""); +} + +TEST_CASE("stringuntils sanitizePath", "") +{ + std::string path; + const std::string sep = dirSeparator; + path = ""; + sanitizePath(path); + REQUIRE(path.empty()); + path = "/"; + sanitizePath(path); + REQUIRE(path == dirSeparator); + path = "/\\"; + sanitizePath(path); + REQUIRE(path == dirSeparator); + path = "\\/"; + sanitizePath(path); + REQUIRE(path == dirSeparator); + path = "//"; + sanitizePath(path); + REQUIRE(path == dirSeparator); + path = "///"; + sanitizePath(path); + REQUIRE(path == dirSeparator); + path = "//\\/"; + sanitizePath(path); + REQUIRE(path == dirSeparator); + path = "///\\"; + sanitizePath(path); + REQUIRE(path == dirSeparator); + path = "\\"; + sanitizePath(path); + REQUIRE(path == dirSeparator); + path = "\\\\"; + sanitizePath(path); + REQUIRE(path == dirSeparator); + path = "\\/\\"; + sanitizePath(path); + REQUIRE(path == dirSeparator); + path = "\\\\/"; + sanitizePath(path); + REQUIRE(path == dirSeparator); + path = "test"; + sanitizePath(path); + REQUIRE(path == "test"); + path = "./test"; + sanitizePath(path); + REQUIRE(path == "." + sep + "test"); + path = "test line"; + sanitizePath(path); + REQUIRE(path == "test line"); + path = "dir/test"; + sanitizePath(path); + REQUIRE(path == "dir" + sep + "test"); + path = "/dir/test"; + sanitizePath(path); + REQUIRE(path == sep + "dir" + sep + "test"); + path = "dir//test"; + sanitizePath(path); + REQUIRE(path == "dir" + sep + "test"); + path = "dir///test"; + sanitizePath(path); + REQUIRE(path == "dir" + sep + "test"); + path = "dir///\\test"; + sanitizePath(path); + REQUIRE(path == "dir" + sep + "test"); + path = "dir/\\//test"; + sanitizePath(path); + REQUIRE(path == "dir" + sep + "test"); + path = "dir\\test"; + sanitizePath(path); + REQUIRE(path == "dir" + sep + "test"); + path = "dir/test/"; + sanitizePath(path); + REQUIRE(path == "dir" + sep + "test" + sep); + path = "dir/test\\"; + sanitizePath(path); + REQUIRE(path == "dir" + sep + "test" + sep); + path = "/very\\long/dir\\with\\sepa/ra/tors"; + sanitizePath(path); + REQUIRE(path == sep + "very" + sep + "long" + sep + \ + "dir" + sep + "with" + sep + "sepa" + sep + "ra" + sep + "tors"); + path = "/very\\long/dir\\\\with\\sepa//ra/tors"; + sanitizePath(path); + REQUIRE(path == sep + "very" + sep + "long" + sep + \ + "dir" + sep + "with" + sep + "sepa" + sep + "ra" + sep + "tors"); +} + +TEST_CASE("stringuntils pathJoin1", "") +{ + const std::string sep = dirSeparator; + + REQUIRE(pathJoin("", "") == sep); + REQUIRE(pathJoin(sep, "") == sep); + REQUIRE(pathJoin("", sep) == sep); + REQUIRE(pathJoin(sep, sep) == sep); + REQUIRE(pathJoin("dir1", "dir2") == "dir1" + sep + "dir2"); + REQUIRE(pathJoin("dir1" + sep, "dir2") == "dir1" + sep + "dir2"); + REQUIRE(pathJoin("dir1", sep + "dir2") == "dir1" + sep + "dir2"); + REQUIRE(pathJoin("dir1" + sep, sep + "dir2") == "dir1" + sep + "dir2"); + REQUIRE(pathJoin("dir1" + sep + "dir2" + sep + "dir3", "dir4") == + "dir1" + sep + "dir2" + sep + "dir3" + sep + "dir4"); + REQUIRE(pathJoin("dir1" + sep + "dir2" + sep, "dir3" + sep + "dir4") == + "dir1" + sep + "dir2" + sep + "dir3" + sep + "dir4"); + REQUIRE(pathJoin("dir1" + sep + "dir2", "dir3" + sep + "dir4") == + "dir1" + sep + "dir2" + sep + "dir3" + sep + "dir4"); + REQUIRE(pathJoin("dir1" + sep + "dir2", sep + "dir3" + sep + "dir4") == + "dir1" + sep + "dir2" + sep + "dir3" + sep + "dir4"); +} + +TEST_CASE("stringuntils pathJoin2", "") +{ + const std::string sep = dirSeparator; + + REQUIRE(pathJoin("", "", "") == sep); + REQUIRE(pathJoin(sep, "", "") == sep); + REQUIRE(pathJoin("", sep, "") == sep); + REQUIRE(pathJoin("", "", sep) == sep); + REQUIRE(pathJoin(sep, sep, "") == sep); + REQUIRE(pathJoin(sep, "", sep) == sep); + REQUIRE(pathJoin("", sep, sep) == sep); + REQUIRE(pathJoin(sep, sep, sep) == sep); + + REQUIRE(pathJoin("dir1", "dir2", "dir3") == + "dir1" + sep + "dir2" + sep + "dir3"); + REQUIRE(pathJoin("dir1" + sep, "dir2", "dir3") == + "dir1" + sep + "dir2" + sep + "dir3"); + REQUIRE(pathJoin("dir1", sep + "dir2", "dir3") == + "dir1" + sep + "dir2" + sep + "dir3"); + REQUIRE(pathJoin("dir1", "dir2" + sep, "dir3") == + "dir1" + sep + "dir2" + sep + "dir3"); + REQUIRE(pathJoin("dir1", "dir2", sep + "dir3") == + "dir1" + sep + "dir2" + sep + "dir3"); + REQUIRE(pathJoin("dir1", "dir2", "dir3" + sep) == + "dir1" + sep + "dir2" + sep + "dir3" + sep); + REQUIRE(pathJoin("dir1" + sep, sep + "dir2", "dir3") == + "dir1" + sep + "dir2" + sep + "dir3"); + REQUIRE(pathJoin("dir1" + sep, "dir2" + sep, "dir3") == + "dir1" + sep + "dir2" + sep + "dir3"); + REQUIRE(pathJoin("dir1" + sep, "dir2", sep + "dir3") == + "dir1" + sep + "dir2" + sep + "dir3"); + REQUIRE(pathJoin("dir1" + sep, sep + "dir2" + sep, "dir3") == + "dir1" + sep + "dir2" + sep + "dir3"); + REQUIRE(pathJoin("dir1" + sep, sep + "dir2", sep + "dir3") == + "dir1" + sep + "dir2" + sep + "dir3"); + REQUIRE(pathJoin("dir1" + sep, sep + "dir2" + sep, "dir3") == + "dir1" + sep + "dir2" + sep + "dir3"); + REQUIRE(pathJoin("dir1" + sep, sep + "dir2" + sep, sep + "dir3") == + "dir1" + sep + "dir2" + sep + "dir3"); + REQUIRE(pathJoin("dir1" + sep + "dir2" + sep + "dir3", "dir4", "dir5") == + "dir1" + sep + "dir2" + sep + "dir3" + sep + "dir4" + sep + "dir5"); + REQUIRE(pathJoin("dir1" + sep + "dir2" + sep, + "dir3" + sep + "dir4", + "dir5") == + "dir1" + sep + "dir2" + sep + "dir3" + sep + "dir4" + sep + "dir5"); + REQUIRE(pathJoin("dir1" + sep + "dir2", + "dir3", + sep + "dir4" + sep + "dir5") == + "dir1" + sep + "dir2" + sep + "dir3" + sep + "dir4" + sep + "dir5"); + REQUIRE(pathJoin("dir1" + sep + "dir2", + sep + "dir3" + sep + "dir4", + sep + "dir5") == + "dir1" + sep + "dir2" + sep + "dir3" + sep + "dir4" + sep + "dir5"); +} + +TEST_CASE("stringuntils urlJoin", "") +{ + REQUIRE(urlJoin("", "") == "/"); + REQUIRE(urlJoin("/", "") == "/"); + REQUIRE(urlJoin("", "/") == "/"); + REQUIRE(urlJoin("/", "/") == "/"); + REQUIRE(urlJoin("dir1", "dir2") == "dir1/dir2"); + REQUIRE(urlJoin("dir1/", "dir2") == "dir1/dir2"); + REQUIRE(urlJoin("dir1", "/dir2") == "dir1/dir2"); + REQUIRE(urlJoin("dir1/", "/dir2") == "dir1/dir2"); + REQUIRE(urlJoin("dir1/dir2/dir3", "dir4") == "dir1/dir2/dir3/dir4"); + REQUIRE(urlJoin("dir1/dir2/", "dir3/dir4") == "dir1/dir2/dir3/dir4"); + REQUIRE(urlJoin("dir1/dir2", "dir3/dir4") == "dir1/dir2/dir3/dir4"); + REQUIRE(urlJoin("dir1/dir2", "/dir3/dir4") == "dir1/dir2/dir3/dir4"); +} + +TEST_CASE("stringuntils secureChatCommand", "") +{ + std::string str; + secureChatCommand(str); + REQUIRE(str.empty()); + str = "test"; + secureChatCommand(str); + REQUIRE(str == "test"); + str = "test line"; + secureChatCommand(str); + REQUIRE(str == "test line"); + str = "/test"; + secureChatCommand(str); + REQUIRE(str == "_/test"); + str = "@test"; + secureChatCommand(str); + REQUIRE(str == "_@test"); + str = "#test"; + secureChatCommand(str); + REQUIRE(str == "_#test"); +} + +#ifdef ENABLE_NLS +TEST_CASE("stringuntils timeDiffToString", "") +{ + REQUIRE(timeDiffToString(60 * 60 * 24 * 7) == "1 week"); + REQUIRE(timeDiffToString(60 * 60 * 24 * 7 * 2 + + 60 * 60 * 24 * 3 + ) == "2 weeks, 3 days"); + REQUIRE(timeDiffToString(60 * 60 * 24 * 7 * 2 + + 60 * 60 * 24 * 3 + + 60 * 60 * 4 + ) == "2 weeks, 3 days, 4 hours"); + REQUIRE(timeDiffToString(60 * 60 * 24 * 7 * 2 + + 60 * 60 * 24 * 3 + + 60 * 60 * 4 + + 60 * 7 + ) == "2 weeks, 3 days, 4 hours, 7 minutes"); + REQUIRE(timeDiffToString(60 * 60 * 24 * 7 * 2 + + 60 * 60 * 24 * 3 + + 60 * 60 * 4 + + 60 * 7 + + 10 + ) == "2 weeks, 3 days, 4 hours, 7 minutes, 10 seconds"); + REQUIRE(timeDiffToString(5) == "5 seconds"); + REQUIRE(timeDiffToString(0) == "0 seconds"); + REQUIRE(timeDiffToString(60 * 60 * 24 * 3 + ) == "3 days"); + REQUIRE(timeDiffToString(60 * 60 * 4 + ) == "4 hours"); + REQUIRE(timeDiffToString(60 * 7 + ) == "7 minutes"); +} +#endif // ENABLE_NLS + +TEST_CASE("stringuntils replaceItemLinks", "") +{ + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + VirtFs::mountDirSilent("data/test", Append_false); + VirtFs::mountDirSilent("../data/test", Append_false); + + ItemDB::NamedItemInfos &namedInfos = ItemDB::getNamedItemInfosTest(); + ItemDB::ItemInfos &infos = ItemDB::getItemInfosTest(); + paths.setDefaultValues(getPathsDefaults()); + ItemInfo *info = new ItemInfo; + info->setId(123456); + info->setName("test name 1"); + namedInfos["test name 1"] = info; + infos[123456] = info; + + info = new ItemInfo; + info->setId(123); + info->setName("test name 2"); + namedInfos["test name 2"] = info; + namedInfos["qqq"] = info; + infos[123] = info; + + std::string str; + + SECTION("empty") + { + str = "test line"; + replaceItemLinks(str); + REQUIRE(str == "test line"); + + str = ""; + replaceItemLinks(str); + REQUIRE(str.empty()); + + str = "[]"; + replaceItemLinks(str); + REQUIRE(str == "[]"); + + str = "[qqq]"; + replaceItemLinks(str); + REQUIRE(str == "[@@123|qqq@@]"); + + str = "[,]"; + replaceItemLinks(str); + REQUIRE(str == "[,]"); + + str = "[, ]"; + replaceItemLinks(str); + REQUIRE(str == "[, ]"); + } + + SECTION("simple") + { + str = "[test name 1]"; + replaceItemLinks(str); + REQUIRE(str == "[@@123456|test name 1@@]"); + + str = "text1 [test name 1] text2"; + replaceItemLinks(str); + REQUIRE(str == "text1 [@@123456|test name 1@@] text2"); + + str = "[test name 1][test name 1]"; + replaceItemLinks(str); + REQUIRE(str == "[@@123456|test name 1@@][@@123456|test name 1@@]"); + + str = "[test name 1] [test name 1]"; + replaceItemLinks(str); + REQUIRE(str == "[@@123456|test name 1@@] [@@123456|test name 1@@]"); + + str = "test1 [test name 1]test2[test name 1] test3"; + replaceItemLinks(str); + REQUIRE(str == "test1 [@@123456|test name 1@@]test2" + "[@@123456|test name 1@@] test3"); + +// failing because assert +// str = "[test name 1] [no link]"; +// replaceItemLinks(str); +// REQUIRE(str == "[@@123456|test name 1@@] [no link]"); + + str = "[test name 1,test name 2]"; + replaceItemLinks(str); + REQUIRE(str == "[@@123456,123|@@]"); + + str = "[test name 1, test name 2 ]"; + replaceItemLinks(str); + REQUIRE(str == "[@@123456,123|@@]"); + } + + SECTION("broken") + { + str = "["; + replaceItemLinks(str); + REQUIRE(str == "["); + + str = "]"; + replaceItemLinks(str); + REQUIRE(str == "]"); + + str = "]["; + replaceItemLinks(str); + REQUIRE(str == "]["); + + str = "]]"; + replaceItemLinks(str); + REQUIRE(str == "]]"); + + str = "]t"; + replaceItemLinks(str); + REQUIRE(str == "]t"); + + str = "t["; + replaceItemLinks(str); + REQUIRE(str == "t["); + + str = "t]"; + replaceItemLinks(str); + REQUIRE(str == "t]"); + + str = "[[["; + replaceItemLinks(str); + REQUIRE(str == "[[["); + + str = "[[]"; + replaceItemLinks(str); + REQUIRE(str == "[[]"); + + str = "[[t"; + replaceItemLinks(str); + REQUIRE(str == "[[t"); + + str = "[]["; + replaceItemLinks(str); + REQUIRE(str == "[]["); + + str = "[]]"; + replaceItemLinks(str); + REQUIRE(str == "[]]"); + + str = "[]t"; + replaceItemLinks(str); + REQUIRE(str == "[]t"); + + str = "[t["; + replaceItemLinks(str); + REQUIRE(str == "[t["); + +// failing because assert +// str = "[t]"; +// replaceItemLinks(str); +// REQUIRE(str == "[t]"); + + str = "t[["; + replaceItemLinks(str); + REQUIRE(str == "t[["); + + str = "t[]"; + replaceItemLinks(str); + REQUIRE(str == "t[]"); + + str = "t[["; + replaceItemLinks(str); + REQUIRE(str == "t[["); + + str = "]]]"; + replaceItemLinks(str); + REQUIRE(str == "]]]"); + } + + SECTION("broken2") + { + str = "[][]"; + replaceItemLinks(str); + REQUIRE(str == "[][]"); + + str = "[[]]"; + replaceItemLinks(str); + REQUIRE(str == "[[]]"); + + str = "][[]"; + replaceItemLinks(str); + REQUIRE(str == "][[]"); + } + + SECTION("broken3") + { + str = "[[test name 1]]"; + replaceItemLinks(str); + REQUIRE(str == "[[@@123456|test name 1@@]]"); + + str = "[[test name 1]"; + replaceItemLinks(str); + REQUIRE(str == "[[@@123456|test name 1@@]"); + + str = "[[qqq] name 1]"; + replaceItemLinks(str); + REQUIRE(str == "[[@@123|qqq@@] name 1]"); + + str = "[[test name 1]test name 1]"; + replaceItemLinks(str); + REQUIRE(str == "[[@@123456|test name 1@@]test name 1]"); + + str = "[[test name 1[]test name 1]"; + replaceItemLinks(str); + REQUIRE(str == "[[test name 1[]test name 1]"); + + str = "[[test name 1],test name2,test name 1]"; + replaceItemLinks(str); + REQUIRE(str == "[[@@123456|test name 1@@],test name2,test name 1]"); + + str = "[[ test name 1], test name2,test name 1 ]"; + replaceItemLinks(str); + REQUIRE(str == "[[@@123456|test name 1@@], test name2,test name 1 ]"); + + str = "[[test name 1,test name2[]test name 1]"; + replaceItemLinks(str); + REQUIRE(str == "[[test name 1,test name2[]test name 1]"); + + str = "[[test name 1 ,test name2[] test name 1]"; + replaceItemLinks(str); + REQUIRE(str == "[[test name 1 ,test name2[] test name 1]"); + } + ResourceManager::deleteInstance(); + delete_all(infos); + infos.clear(); + namedInfos.clear(); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + VirtFs::unmountDirSilent("data/test"); + VirtFs::unmountDirSilent("../data/test"); + delete2(logger); +// VirtFs::deinit(); +} diff --git a/src/unittests/utils/timer_unittest.cc b/src/unittests/utils/timer_unittest.cc new file mode 100644 index 000000000..b5cfc692e --- /dev/null +++ b/src/unittests/utils/timer_unittest.cc @@ -0,0 +1,88 @@ +/* + * The ManaPlus Client + * Copyright (C) 2012-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "const/utils/timer.h" + +#include "utils/timer.h" + +#include <climits> + +#include "debug.h" + +static const int MAX_TICK_VALUE = INT_MAX / 2; + +TEST_CASE("timer const", "") +{ + REQUIRE(MILLISECONDS_IN_A_TICK != 0); +} + +TEST_CASE("timer get_elapsed_time", "") +{ + tick_time = 0; + REQUIRE(get_elapsed_time(0) == 0); + REQUIRE(get_elapsed_time(MAX_TICK_VALUE - 1) == 1 * MILLISECONDS_IN_A_TICK); + REQUIRE(get_elapsed_time(MAX_TICK_VALUE - 2) == 2 * MILLISECONDS_IN_A_TICK); + + tick_time = 1; + REQUIRE(get_elapsed_time(0) == 1 * MILLISECONDS_IN_A_TICK); + REQUIRE(get_elapsed_time(1) == 0 * MILLISECONDS_IN_A_TICK); + REQUIRE(get_elapsed_time(MAX_TICK_VALUE - 1) == 2 * MILLISECONDS_IN_A_TICK); + REQUIRE(get_elapsed_time(MAX_TICK_VALUE - 2) == 3 * MILLISECONDS_IN_A_TICK); + + tick_time = 10; + REQUIRE(get_elapsed_time(0) == 10 * MILLISECONDS_IN_A_TICK); + REQUIRE(get_elapsed_time(10) == 0 * MILLISECONDS_IN_A_TICK); + REQUIRE(get_elapsed_time(MAX_TICK_VALUE - 1) == + 11 * MILLISECONDS_IN_A_TICK); + + tick_time = 10000; + REQUIRE(get_elapsed_time(0) == 10000 * MILLISECONDS_IN_A_TICK); + REQUIRE(get_elapsed_time(10) == 9990 * MILLISECONDS_IN_A_TICK); + REQUIRE(get_elapsed_time(10000) == 0 * MILLISECONDS_IN_A_TICK); + REQUIRE(get_elapsed_time(MAX_TICK_VALUE - 1) == + 10001 * MILLISECONDS_IN_A_TICK); +} + +TEST_CASE("timer get_elapsed_time1", "") +{ + tick_time = 0; + REQUIRE(get_elapsed_time1(0) == 0); + REQUIRE(get_elapsed_time1(MAX_TICK_VALUE - 1) == 1); + REQUIRE(get_elapsed_time1(MAX_TICK_VALUE - 2) == 2); + + tick_time = 1; + REQUIRE(get_elapsed_time1(0) == 1); + REQUIRE(get_elapsed_time1(1) == 0); + REQUIRE(get_elapsed_time1(MAX_TICK_VALUE - 1) == 2); + REQUIRE(get_elapsed_time1(MAX_TICK_VALUE - 2) == 3); + + tick_time = 10; + REQUIRE(get_elapsed_time1(0) == 10); + REQUIRE(get_elapsed_time1(10) == 0); + REQUIRE(get_elapsed_time1(MAX_TICK_VALUE - 1) == 11); + + tick_time = 10000; + REQUIRE(get_elapsed_time1(0) == 10000); + REQUIRE(get_elapsed_time1(10) == 9990); + REQUIRE(get_elapsed_time1(10000) == 0); + REQUIRE(get_elapsed_time1(MAX_TICK_VALUE - 1) == 10001); +} diff --git a/src/unittests/utils/translation/poparser_unittest.cc b/src/unittests/utils/translation/poparser_unittest.cc new file mode 100644 index 000000000..f724e66fb --- /dev/null +++ b/src/unittests/utils/translation/poparser_unittest.cc @@ -0,0 +1,158 @@ +/* + * The ManaPlus Client + * Copyright (C) 2016-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "client.h" +#include "configuration.h" +#include "configmanager.h" +#include "dirs.h" +#include "graphicsmanager.h" + +#include "being/actorsprite.h" + +#include "fs/virtfs/fs.h" + +#include "gui/gui.h" +#include "gui/theme.h" + +#include "utils/delete2.h" +#include "utils/env.h" + +#include "utils/translation/podict.h" +#include "utils/translation/poparser.h" + +#include "render/sdlgraphics.h" + +#include "resources/sdlimagehelper.h" + +#include "resources/resourcemanager/resourcemanager.h" + +#include "debug.h" + +TEST_CASE("PoParser leak test1", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} + +TEST_CASE("PoParser tests", "PoParser") +{ + setEnv("SDL_VIDEODRIVER", "dummy"); + + client = new Client; + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + mainGraphics = new SDLGraphics; + imageHelper = new SDLImageHelper(); +#ifdef USE_SDL2 + SDLImageHelper::setRenderer(graphicsManager.createRenderer( + graphicsManager.createWindow(640, 480, 0, + SDL_WINDOW_SHOWN | SDL_SWSURFACE), SDL_RENDERER_SOFTWARE)); +#else // USE_SDL2 + + graphicsManager.createWindow(640, 480, 0, SDL_ANYFORMAT | SDL_SWSURFACE); +#endif // USE_SDL2 + + theme = new Theme; + Theme::selectSkin(); + + Dirs::initRootDir(); + Dirs::initHomeDir(); + + ConfigManager::initConfiguration(); + getConfigDefaults2(config.getDefaultValues()); + branding.setDefaultValues(getBrandingDefaults()); + + ActorSprite::load(); + gui = new Gui(); + gui->postInit(mainGraphics); + + SECTION("PoParser empty") + { + PoParser *parser = new PoParser; + PoDict *dict = parser->load("ru", + "unknownfilename.po", + nullptr); + + REQUIRE(dict != nullptr); + REQUIRE(dict->getMap() != nullptr); + REQUIRE(dict->getMap()->empty()); + + delete parser; + delete dict; + } + + SECTION("PoParser normal") + { + PoParser *parser = new PoParser; + PoDict *dict = parser->load("ru", + "test/test1", + nullptr); + + REQUIRE(dict != nullptr); + REQUIRE(dict->getMap() != nullptr); + REQUIRE(dict->getMap()->size() == 1786); + REQUIRE(dict->getStr("Unknown skill message.") == + "Неизвестная ошибка скилов."); + REQUIRE(dict->getStr("Full strip failed because of coating.") == + "Full strip failed because of coating."); + REQUIRE(dict->getStr("You picked up %d [@@%d|%s@@].") == + "Вы подняли %d [@@%d|%s@@]."); + + delete parser; + delete dict; + } + + SECTION("PoParser fuzzy") + { + PoParser *parser = new PoParser; + PoDict *dict = parser->load("ru", + "test/test1", + nullptr); + + REQUIRE(dict != nullptr); + REQUIRE(dict->getMap() != nullptr); + REQUIRE(dict->getMap()->size() == 1786); + REQUIRE(dict->getStr("Atk +100%.") == "Atk +100%."); + + delete parser; + delete dict; + } + delete2(client); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +// VirtFs::deinit(); +} + +TEST_CASE("PoParser leak test2", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} diff --git a/src/unittests/utils/xml_unittest.cc b/src/unittests/utils/xml_unittest.cc new file mode 100644 index 000000000..f9f7990f8 --- /dev/null +++ b/src/unittests/utils/xml_unittest.cc @@ -0,0 +1,400 @@ +/* + * The ManaPlus Client + * Copyright (C) 2014-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "client.h" +#include "configuration.h" +#include "configmanager.h" +#include "dirs.h" +#include "graphicsmanager.h" + +#include "being/actorsprite.h" + +#include "fs/virtfs/fs.h" + +#include "gui/gui.h" +#include "gui/theme.h" + +#include "utils/delete2.h" +#include "utils/env.h" +#ifdef ENABLE_PUGIXML +#include "utils/xmlwriter.h" +#endif // ENABLE_PUGIXML + +#include "render/sdlgraphics.h" + +#include "resources/sdlimagehelper.h" + +#include "resources/resourcemanager/resourcemanager.h" + +#include "debug.h" + +TEST_CASE("xml test1", "") +{ + logger = new Logger(); + REQUIRE(client == nullptr); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} + +TEST_CASE("xml doc", "") +{ + setEnv("SDL_VIDEODRIVER", "dummy"); + + logger = new Logger(); + client = new Client; + XML::initXML(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + mainGraphics = new SDLGraphics; + imageHelper = new SDLImageHelper(); +#ifdef USE_SDL2 + SDLImageHelper::setRenderer(graphicsManager.createRenderer( + graphicsManager.createWindow(640, 480, 0, + SDL_WINDOW_SHOWN | SDL_SWSURFACE), SDL_RENDERER_SOFTWARE)); +#else // USE_SDL2 + + graphicsManager.createWindow(640, 480, 0, SDL_ANYFORMAT | SDL_SWSURFACE); +#endif // USE_SDL2 + + Dirs::initRootDir(); + Dirs::initHomeDir(); + + ConfigManager::initConfiguration(); + getConfigDefaults2(config.getDefaultValues()); + branding.setDefaultValues(getBrandingDefaults()); + + theme = new Theme; + Theme::selectSkin(); + + const char *const tempXmlName = "tempxml.xml"; + ActorSprite::load(); + gui = new Gui(); + gui->postInit(mainGraphics); + + SECTION("load1") + { + XML::Document doc("graphics/gui/browserbox.xml", + UseVirtFs_true, + SkipError_false); + REQUIRE(doc.isLoaded() == true); + REQUIRE(doc.isValid() == true); + REQUIRE(doc.rootNode() != nullptr); + REQUIRE(xmlNameEqual(doc.rootNode(), "skinset") == true); + REQUIRE(xmlNameEqual(doc.rootNode(), "skinset123") == false); + REQUIRE(xmlTypeEqual(doc.rootNode(), XML_ELEMENT_NODE) == true); +// REQUIRE(XmlHaveChildContent(doc.rootNode()) == true); + } + + SECTION("load2") + { + const char *const xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<root><data option1=\"false\" option2=\"true\"/>" + "<cont>this is test</cont></root>"; + XML::Document doc(xml, strlen(xml)); + REQUIRE(doc.isLoaded() == true); + REQUIRE(doc.isValid() == true); + REQUIRE(doc.rootNode() != nullptr); + REQUIRE(xmlNameEqual(doc.rootNode(), "root") == true); + REQUIRE(xmlNameEqual(doc.rootNode(), "root123") == false); + REQUIRE(xmlTypeEqual(doc.rootNode(), XML_ELEMENT_NODE) == true); + REQUIRE(XmlHasProp(doc.rootNode(), "option1") == false); + REQUIRE(XmlHasProp(doc.rootNode(), "option123") == false); + REQUIRE(XmlHaveChildContent(doc.rootNode()) == false); + } + + SECTION("load3") + { + const std::string xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<!-- comment here\nand here -->" + "<root><data option1=\"false\" option2=\"true\"/></root>"; + XML::Document doc(xml.c_str(), xml.size()); + REQUIRE(doc.isLoaded() == true); + REQUIRE(doc.isValid() == true); + REQUIRE(doc.rootNode() != nullptr); + REQUIRE(xmlNameEqual(doc.rootNode(), "root") == true); + REQUIRE(xmlNameEqual(doc.rootNode(), "root123") == false); + REQUIRE(xmlTypeEqual(doc.rootNode(), XML_ELEMENT_NODE) == true); + REQUIRE(XmlHasProp(doc.rootNode(), "option1") == false); + REQUIRE(XmlHasProp(doc.rootNode(), "option123") == false); + REQUIRE(XmlHaveChildContent(doc.rootNode()) == false); + } + + SECTION("load4") + { + const char *const xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<root>this is test</root>"; + XML::Document doc(xml, strlen(xml)); + REQUIRE(doc.isLoaded() == true); + REQUIRE(doc.isValid() == true); + REQUIRE(doc.rootNode() != nullptr); + REQUIRE(xmlNameEqual(doc.rootNode(), "root") == true); + REQUIRE(xmlNameEqual(doc.rootNode(), "root123") == false); + REQUIRE(xmlTypeEqual(doc.rootNode(), XML_ELEMENT_NODE) == true); + REQUIRE(XmlHasProp(doc.rootNode(), "option1") == false); + REQUIRE(XmlHasProp(doc.rootNode(), "option123") == false); + REQUIRE(XmlHaveChildContent(doc.rootNode()) == true); + REQUIRE(!strcmp(XmlChildContent(doc.rootNode()), "this is test")); + } + + SECTION("properties") + { + XML::Document doc("graphics/gui/browserbox.xml", + UseVirtFs_true, + SkipError_false); + + XmlNodeConstPtr rootNode = doc.rootNode(); + REQUIRE(XML::getProperty(rootNode, "image", "") == "window.png"); + } + + SECTION("for each") + { + XML::Document doc("graphics/gui/browserbox.xml", + UseVirtFs_true, + SkipError_false); + + XmlNodeConstPtr rootNode = doc.rootNode(); +// REQUIRE(XmlHaveChildContent(rootNode) == true); + XmlNodePtr node = XmlNodeDefault; + for_each_xml_child_node(widgetNode, rootNode) + { + node = widgetNode; + if (xmlNameEqual(node, "widget")) + break; + } + REQUIRE(node != nullptr); + REQUIRE(xmlTypeEqual(node, XML_ELEMENT_NODE) == true); + REQUIRE(xmlNameEqual(node, "widget") == true); +// REQUIRE(XmlHaveChildContent(node) == true); + for_each_xml_child_node(optionNode, node) + { + node = optionNode; + if (xmlNameEqual(node, "option")) + break; + } + REQUIRE(node != nullptr); + REQUIRE(xmlTypeEqual(node, XML_ELEMENT_NODE) == true); + REQUIRE(xmlNameEqual(node, "option") == true); + REQUIRE(XmlHaveChildContent(node) == false); + REQUIRE(XmlHasProp(node, "name") == true); + REQUIRE(XmlHasProp(node, "value") == true); + REQUIRE(XmlHasProp(node, "option123") == false); + REQUIRE(XML::getProperty(node, "name", "") == "padding"); + REQUIRE(XML::langProperty(node, "name", "") == "padding"); + REQUIRE(XML::getProperty(node, "value", 0) == 1); + REQUIRE(XML::getBoolProperty(node, "value", true) == true); + REQUIRE(XML::getBoolProperty(node, "value", false) == false); + REQUIRE(XML::getIntProperty(node, "value", -1, -10, 100) == 1); + } + + SECTION("child1") + { + XML::Document doc("graphics/gui/browserbox.xml", + UseVirtFs_true, + SkipError_false); + + XmlNodeConstPtr rootNode = doc.rootNode(); + XmlNodePtr node = XML::findFirstChildByName(rootNode, "widget"); + REQUIRE(node != nullptr); + REQUIRE(xmlTypeEqual(node, XML_ELEMENT_NODE) == true); + REQUIRE(xmlNameEqual(node, "widget") == true); +// REQUIRE(XmlHaveChildContent(node) == true); + node = XML::findFirstChildByName(node, "option"); + REQUIRE(node != nullptr); + REQUIRE(xmlTypeEqual(node, XML_ELEMENT_NODE) == true); + REQUIRE(xmlNameEqual(node, "option") == true); + REQUIRE(XmlHaveChildContent(node) == false); + REQUIRE(XmlHasProp(node, "name") == true); + REQUIRE(XmlHasProp(node, "value") == true); + REQUIRE(XmlHasProp(node, "option123") == false); + REQUIRE(XML::getProperty(node, "name", "") == "padding"); + REQUIRE(XML::langProperty(node, "name", "") == "padding"); + REQUIRE(XML::langProperty(node, "name123", "").empty()); + REQUIRE(XML::getProperty(node, "value", 0) == 1); + REQUIRE(XML::getProperty(node, "value123", -1) == -1); + REQUIRE(XML::getBoolProperty(node, "value", true) == true); + REQUIRE(XML::getBoolProperty(node, "value", false) == false); + REQUIRE(XML::getBoolProperty(node, "value123", true) == true); + REQUIRE(XML::getIntProperty(node, "value", -1, -10, 100) == 1); + REQUIRE(XML::getIntProperty(node, "value123", -1, -10, 100) == -1); + } + + SECTION("child2") + { + const char *const xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<root><data option1=\"false\" option2=\"true\" " + "option3=\"10.5\"/></root>"; + XML::Document doc(xml, strlen(xml)); + XmlNodeConstPtr rootNode = doc.rootNode(); + REQUIRE(XmlHaveChildContent(rootNode) == false); + XmlNodePtr node = XML::findFirstChildByName(rootNode, "data"); + REQUIRE(node != nullptr); + REQUIRE(xmlTypeEqual(node, XML_ELEMENT_NODE) == true); + REQUIRE(xmlNameEqual(node, "data") == true); + REQUIRE(XmlHaveChildContent(node) == false); + REQUIRE(XmlHasProp(node, "option1") == true); + REQUIRE(XmlHasProp(node, "option123") == false); + REQUIRE(XML::getBoolProperty(node, "option1", true) == false); + REQUIRE(XML::getBoolProperty(node, "option2", false) == true); + const float opt3 = XML::getFloatProperty(node, "option3", 0.0); + REQUIRE(opt3 > 10); + REQUIRE(opt3 < 11); + } + + SECTION("child3") + { + const std::string xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<!-- comment --><root><!-- comment -->" + "<data option1=\"false\" option2=\"true\" " + "option3=\"10.5\"/><!-- comment --></root>"; + XML::Document doc(xml.c_str(), xml.size()); + XmlNodeConstPtr rootNode = doc.rootNode(); +// REQUIRE(XmlHaveChildContent(rootNode) == true); + XmlNodePtr node = XML::findFirstChildByName(rootNode, "data"); + REQUIRE(node != nullptr); + REQUIRE(xmlTypeEqual(node, XML_ELEMENT_NODE) == true); + REQUIRE(xmlNameEqual(node, "data") == true); + REQUIRE(XmlHaveChildContent(node) == false); + REQUIRE(XmlHasProp(node, "option1") == true); + REQUIRE(XmlHasProp(node, "option123") == false); + REQUIRE(XML::getBoolProperty(node, "option1", true) == false); + REQUIRE(XML::getBoolProperty(node, "option2", false) == true); + const float opt3 = XML::getFloatProperty(node, "option3", 0.0); + REQUIRE(opt3 > 10); + REQUIRE(opt3 < 11); + } + + SECTION("validate") + { +// REQUIRE(XML::Document::validateXml( +// "graphics/gui/browserbox.xml") == true); + REQUIRE(XML::Document::validateXml( + "graphics/gui/bubble.png") == false); + REQUIRE(XML::Document::validateXml( + "graphics/gui/testfile123.xml") == false); + } + + SECTION("save1") + { + // clean + ::remove(tempXmlName); + + // save + FILE *const testFile = fopen(tempXmlName, "w"); + REQUIRE(testFile); + fclose(testFile); + XmlTextWriterPtr writer = XmlNewTextWriterFilename( + tempXmlName, + 0); + XmlTextWriterSetIndent(writer, 1); + XmlTextWriterStartDocument(writer, nullptr, nullptr, nullptr); + XmlTextWriterStartRootElement(writer, "root"); + XmlTextWriterEndDocument(writer); + XmlSaveTextWriterFilename(writer, tempXmlName); + XmlFreeTextWriter(writer); + + // load + XML::Document doc(tempXmlName, + UseVirtFs_false, + SkipError_false); + REQUIRE(doc.isLoaded() == true); + REQUIRE(doc.isValid() == true); + REQUIRE(doc.rootNode() != nullptr); + REQUIRE(xmlNameEqual(doc.rootNode(), "root") == true); + REQUIRE(xmlNameEqual(doc.rootNode(), "skinset123") == false); + REQUIRE(xmlTypeEqual(doc.rootNode(), XML_ELEMENT_NODE) == true); +// REQUIRE(XmlHaveChildContent(doc.rootNode()) == true); + + // clean again + ::remove(tempXmlName); + } + + SECTION("save2") + { + // clean + ::remove(tempXmlName); + + // save + FILE *const testFile = fopen(tempXmlName, "w"); + REQUIRE(testFile); + fclose(testFile); + XmlTextWriterPtr writer = XmlNewTextWriterFilename( + tempXmlName, + 0); + XmlTextWriterSetIndent(writer, 1); + XmlTextWriterStartDocument(writer, nullptr, nullptr, nullptr); + XmlTextWriterStartRootElement(writer, "root"); + + XmlTextWriterStartElement(writer, "option"); + XmlTextWriterWriteAttribute(writer, "name", "the name"); + XmlTextWriterWriteAttribute(writer, "value", "the value"); + XmlTextWriterEndElement(writer); + + XmlTextWriterEndDocument(writer); + XmlSaveTextWriterFilename(writer, tempXmlName); + XmlFreeTextWriter(writer); + + // load + XML::Document doc(tempXmlName, + UseVirtFs_false, + SkipError_false); + REQUIRE(doc.isLoaded() == true); + REQUIRE(doc.isValid() == true); + REQUIRE(doc.rootNode() != nullptr); + REQUIRE(xmlNameEqual(doc.rootNode(), "root") == true); + REQUIRE(xmlNameEqual(doc.rootNode(), "skinset123") == false); + REQUIRE(xmlTypeEqual(doc.rootNode(), XML_ELEMENT_NODE) == true); +// REQUIRE(XmlHaveChildContent(doc.rootNode()) == true); + XmlNodePtr node = XML::findFirstChildByName(doc.rootNode(), "option"); + REQUIRE(node != nullptr); + REQUIRE(xmlTypeEqual(node, XML_ELEMENT_NODE) == true); + REQUIRE(xmlNameEqual(node, "option") == true); + REQUIRE(XmlHaveChildContent(node) == false); + REQUIRE(XmlHasProp(node, "name") == true); + REQUIRE(XmlHasProp(node, "value") == true); + REQUIRE(XmlHasProp(node, "option123") == false); + REQUIRE(XML::getProperty(node, "name", "") == "the name"); + REQUIRE(XML::getProperty(node, "value", "") == "the value"); + + // clean again + ::remove(tempXmlName); + } + + delete2(theme); + delete2(client); + ResourceManager::deleteInstance(); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + + delete2(logger); +// VirtFs::deinit(); +} + +TEST_CASE("xml test2", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} diff --git a/src/unittests/utils/xmlutils_unittest.cc b/src/unittests/utils/xmlutils_unittest.cc new file mode 100644 index 000000000..014730e95 --- /dev/null +++ b/src/unittests/utils/xmlutils_unittest.cc @@ -0,0 +1,203 @@ +/* + * The ManaPlus Client + * Copyright (C) 2014-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "unittests/unittests.h" + +#include "client.h" +#include "graphicsmanager.h" + +#include "being/actorsprite.h" + +#include "fs/virtfs/fs.h" + +#include "gui/gui.h" + +#include "utils/delete2.h" +#include "utils/env.h" +#include "utils/xmlutils.h" + +#include "render/sdlgraphics.h" + +#include "resources/resourcemanager/resourcemanager.h" + +#include "resources/sdlimagehelper.h" + +#include "debug.h" + +TEST_CASE("xmlutils leak test1", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} + +TEST_CASE("xmlutils readXmlIntVector 1", "") +{ + setEnv("SDL_VIDEODRIVER", "dummy"); + + client = new Client; + XML::initXML(); + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + mainGraphics = new SDLGraphics; + imageHelper = new SDLImageHelper(); +#ifdef USE_SDL2 + SDLImageHelper::setRenderer(graphicsManager.createRenderer( + graphicsManager.createWindow(640, 480, 0, + SDL_WINDOW_SHOWN | SDL_SWSURFACE), SDL_RENDERER_SOFTWARE)); +#else // USE_SDL2 + + graphicsManager.createWindow(640, 480, 0, SDL_ANYFORMAT | SDL_SWSURFACE); +#endif // USE_SDL2 + + ActorSprite::load(); + + std::vector<int> arr; + + readXmlIntVector("graphics/gui/browserbox.xml", + "skinset", + "widget", + "option", + "value", + arr, + SkipError_false); + + REQUIRE(5 == arr.size()); + REQUIRE(1 == arr[0]); + REQUIRE(15 == arr[1]); + REQUIRE(0 == arr[2]); + REQUIRE(1 == arr[3]); + REQUIRE(1 == arr[4]); + delete2(client); + ResourceManager::deleteInstance(); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +// VirtFs::deinit(); +} + +TEST_CASE("xmlutils readXmlStringMap 1", "") +{ + setEnv("SDL_VIDEODRIVER", "dummy"); + + client = new Client; + XML::initXML(); + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + + mainGraphics = new SDLGraphics; + imageHelper = new SDLImageHelper(); +#ifdef USE_SDL2 + SDLImageHelper::setRenderer(graphicsManager.createRenderer( + graphicsManager.createWindow(640, 480, 0, + SDL_WINDOW_SHOWN | SDL_SWSURFACE), SDL_RENDERER_SOFTWARE)); +#else // USE_SDL2 + + graphicsManager.createWindow(640, 480, 0, SDL_ANYFORMAT | SDL_SWSURFACE); +#endif // USE_SDL2 + + ActorSprite::load(); + + std::map<std::string, std::string> arr; + + readXmlStringMap("graphics/sprites/manaplus_emotes.xml", + "emotes", + "emote", + "sprite", + "name", + "variant", + arr, + SkipError_false); + + REQUIRE(arr.size() == 27); + REQUIRE(arr["Kitty"] == "0"); + REQUIRE(arr["xD"] == "1"); + REQUIRE(arr["Metal"] == "26"); + delete2(client); + ResourceManager::deleteInstance(); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +// VirtFs::deinit(); +} + +TEST_CASE("xmlutils readXmlIntMap 1", "") +{ + setEnv("SDL_VIDEODRIVER", "dummy"); + + client = new Client; + XML::initXML(); + logger = new Logger(); + VirtFs::mountDirSilent("data", Append_false); + VirtFs::mountDirSilent("../data", Append_false); + VirtFs::mountDirSilent("data/test", Append_false); + VirtFs::mountDirSilent("../data/test", Append_false); + + mainGraphics = new SDLGraphics; + imageHelper = new SDLImageHelper(); +#ifdef USE_SDL2 + SDLImageHelper::setRenderer(graphicsManager.createRenderer( + graphicsManager.createWindow(640, 480, 0, + SDL_WINDOW_SHOWN | SDL_SWSURFACE), SDL_RENDERER_SOFTWARE)); +#else // USE_SDL2 + + graphicsManager.createWindow(640, 480, 0, SDL_ANYFORMAT | SDL_SWSURFACE); +#endif // USE_SDL2 + + ActorSprite::load(); + + std::map<int32_t, int32_t> arr; + + readXmlIntMap("testintmap.xml", + "tests", + "sub", + "item", + "id", + "val", + arr, + SkipError_false); + + REQUIRE(arr.size() == 3); + REQUIRE(arr[1] == 2); + REQUIRE(arr[10] == 20); + REQUIRE(arr[3] == 0); + delete2(client); + ResourceManager::deleteInstance(); + VirtFs::unmountDirSilent("data/test"); + VirtFs::unmountDirSilent("../data/test"); + VirtFs::unmountDirSilent("data"); + VirtFs::unmountDirSilent("../data"); + delete2(logger); +// VirtFs::deinit(); +} + +TEST_CASE("xmlutils leak test2", "") +{ + logger = new Logger(); + REQUIRE(gui == nullptr); + ResourceManager::cleanOrphans(true); + ResourceManager::deleteInstance(); + delete2(logger); +} |