diff --git a/storm/Error.hpp b/storm/Error.hpp index 1080e0c..934402c 100644 --- a/storm/Error.hpp +++ b/storm/Error.hpp @@ -10,10 +10,12 @@ #endif #if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX) -#define ERROR_SUCCESS 0x0 -#define ERROR_INVALID_HANDLE 0x6 -#define ERROR_NOT_ENOUGH_MEMORY 0x8 -#define ERROR_INVALID_PARAMETER 0x57 +#define ERROR_SUCCESS 0 +#define ERROR_FILE_NOT_FOUND 2 +#define ERROR_INVALID_HANDLE 6 +#define ERROR_NOT_ENOUGH_MEMORY 8 +#define ERROR_HANDLE_EOF 38 +#define ERROR_INVALID_PARAMETER 87 #endif [[noreturn]] void STORMCDECL SErrDisplayAppFatal(const char* format, ...); diff --git a/storm/File.hpp b/storm/File.hpp index 481b959..7f80da7 100644 --- a/storm/File.hpp +++ b/storm/File.hpp @@ -12,18 +12,78 @@ DECLARE_STORM_HANDLE(HSARCHIVE); DECLARE_STORM_HANDLE(HSFILE); -int32_t STORMAPI SFileOpenArchive(const char* archivename, int32_t priority, uint32_t flags, HSARCHIVE* handle); +#define SFILE_ARCHIVE_READ_FROM_CD_ONLY 0x000001 +#define SFILE_ARCHIVE_ENABLE_OVERLAPPED 0x000002 +#define SFILE_ARCHIVE_DONT_CHECKDISK 0x000004 +#define SFILE_ARCHIVE_DONT_SEARCH 0x000008 +#define SFILE_ARCHIVE_ARC4_DECRYPT 0x000010 +#define SFILE_ARCHIVE_DECRYPTION_TYPES 0x000010 +#define SFILE_ARCHIVE_WRITE_PERMISSION 0x000010 +#define SFILE_ARCHIVE_OPEN_LAST_ARCHIVE 0x000020 +#define SFILE_ARCHIVE_LOAD_MD5_VALUES 0x000040 +#define SFILE_ARCHIVE_LOAD_CRC_VALUES 0x000080 +#define SFILE_ARCHIVE_LOAD_TIMESTAMPS 0x000100 +#define SFILE_ARCHIVE_CHECK_MD5_VALUES 0x000200 +#define SFILE_ARCHIVE_USE_NEW_BLOCK_HASH_FORMAT 0x000400 +#define SFILE_ARCHIVE_INIT_TABLE_ON_OPEN 0x000800 +#define SFILE_ARCHIVE_LOAD_DELTA_VALUES 0x001000 +#define SFILE_ARCHIVE_LOAD_DELTA_AS_RAW 0x002000 +#define SFILE_ARCHIVE_DONT_TRUNCATE 0x004000 +#define SFILE_ARCHIVE_DISK_DELETE_CAN_FAIL 0x010000 +#define SFILE_ARCHIVE_SC1161_PERMISSIVE 0x020000 + +#define SFILE_OPENFLAG_CHECKDISK 1 +#define SFILE_OPENFLAG_CHECKDISK_NOPATH 2 +#define SFILE_OPENFLAG_NATIVEHANDLE 4 // made up +#define SFILE_OPENFLAG_PERM_SHARED_WRITE 0x8000 +#define SFILE_OPENFLAG_PRESERVE_PATH_SEPARATORS 0x10000 + +#define SFILE_BEGIN 0 +#define SFILE_CURRENT 1 +#define SFILE_END 2 + +/* // Leaving as documentation + +#define SFILE_AUTH_UNABLETOAUTHENTICATE 0 +#define SFILE_AUTH_NOSIGNATURE 1 +#define SFILE_AUTH_BADSIGNATURE 2 +#define SFILE_AUTH_UNKNOWNSIGNATURE 3 +#define SFILE_AUTH_FIRSTAUTHENTIC 5 +#define SFILE_AUTH_AUTHENTICBLIZZARD 5 + +#define SFILE_DIRECT_ENABLE_RELATIVE 1 +#define SFILE_DIRECT_ENABLE_NOPATH 2 + +#define SFILE_PLATFORM_ANY 0 +#define SFILE_PLATFORM_WIN32 1 +#define SFILE_PLATFORM_MAC 2 + +enum SARCHIVE_TYPE { + SARCHIVE_MPQ, + SARCHIVE_ZIP, +}; + +enum SFILE_TYPE { + SFILE_PLAIN, + SFILE_COMPRESSED, + SFILE_PAQ, + SFILE_OLD_SFILE, + SFILE_ZIP_FILE, +}; +*/ int32_t STORMAPI SFileCloseArchive(HSARCHIVE handle); +int32_t STORMAPI SFileCloseFile(HSFILE handle); + +uint32_t STORMAPI SFileGetFileSize(HSFILE handle, uint32_t* filesizehigh = nullptr); + +int32_t STORMAPI SFileOpenArchive(const char* archivename, int32_t priority, uint32_t flags, HSARCHIVE* handle); + int32_t STORMAPI SFileOpenFileEx(HSARCHIVE archivehandle, const char* filename, uint32_t flags, HSFILE* handle); -int32_t STORMAPI SFileReadFile(HSFILE handle, void* buffer, uint32_t bytestoread, uint32_t* bytesread, LPOVERLAPPED overlapped); - -uint32_t STORMAPI SFileGetFileSize(HSFILE handle, uint32_t* filesizehigh); +int32_t STORMAPI SFileReadFile(HSFILE handle, void* buffer, uint32_t bytestoread, uint32_t* bytesread = nullptr, LPOVERLAPPED overlapped = nullptr); uint32_t STORMAPI SFileSetFilePointer(HSFILE handle, int32_t distancetomove, int32_t* distancetomovehigh, uint32_t movemethod); -int32_t STORMAPI SFileCloseFile(HSFILE handle); - #endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 351b648..9bca269 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -6,6 +6,8 @@ if(WHOA_TEST_STORMDLL) Error.cpp Event.cpp EventTest.cpp + File.cpp + FileTest.cpp Memory.cpp Region.cpp String.cpp @@ -24,6 +26,8 @@ else() ) endif() +file(GLOB TEST_FILES "fixture/*") + if(WHOA_SYSTEM_MAC) set_source_files_properties(${TEST_SOURCES} PROPERTIES COMPILE_FLAGS "-x objective-c++" @@ -54,6 +58,14 @@ target_include_directories(StormTest ${PROJECT_SOURCE_DIR} ) +file(GLOB TEST_FILES "fixture/*") + +add_custom_target(copy_test_files ALL + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${TEST_FILES} + $ +) + # Debug build options if(CMAKE_BUILD_TYPE STREQUAL "Debug") # GCC debug build options diff --git a/test/File.cpp b/test/File.cpp new file mode 100644 index 0000000..a09d8bb --- /dev/null +++ b/test/File.cpp @@ -0,0 +1,401 @@ +#include "FileTest.hpp" + +// most of these only pass against storm.dll for now +#if defined(WHOA_TEST_STORMDLL) +TEST_CASE("SFileCloseArchive", "[file]") { + HSARCHIVE archive = nullptr; + + SECTION("closes an archive") { + SFileOpenArchive("wowtest1.mpq", 0, 0, &archive); + REQUIRE(archive != nullptr); + + HSFILE file; + CHECK(SFileOpenFileEx(nullptr, "test.txt", 0, &file)); + CHECK(SFileCloseFile(file)); + + CHECK(SFileCloseArchive(archive) == 1); + + CHECK_FALSE(SFileOpenFileEx(nullptr, "test.txt", 0, &file)); + } + + // TODO determine how to test this + // SECTION("doesn't delete if there is more than one reference") {} +} + +TEST_CASE("SFileCloseFile", "[file]") { + HSFILE file = nullptr; + + SECTION("closes a MPQ file") { + file = ReadTestFileFromMpq(); + CHECK(SFileCloseFile(file) == 1); + } + + SECTION("closes a filesystem file") { + file = ReadTestFileFromDisk(); + CHECK(SFileCloseFile(file) == 1); + } + + // TODO determine how to test this + // SECTION("doesn't delete if there is more than one reference") {} +} + +TEST_CASE("SFileGetFileSize", "[file]") { + HSARCHIVE archive; + HSFILE file; + + SECTION("retrieves MPQ file size") { + SFileOpenArchive("wowtest1.mpq", 0, 0, &archive); + + REQUIRE(SFileOpenFileEx(archive, "test2.txt", 0, &file)); + CHECK(SFileGetFileSize(file) == 13); + + REQUIRE(SFileOpenFileEx(archive, "empty.txt", 0, &file)); + CHECK(SFileGetFileSize(file) == 0); + + uint32_t filesizehigh = 1234; + REQUIRE(SFileOpenFileEx(archive, "test.txt", 0, &file)); + CHECK(SFileGetFileSize(file, &filesizehigh) == 6); + CHECK(filesizehigh == 0); + } + + SECTION("retrieves filesystem file size") { + REQUIRE(SFileOpenFileEx(nullptr, "empty_diskonly.txt", SFILE_OPENFLAG_CHECKDISK, &file)); + CHECK(SFileGetFileSize(file) == 0); + + uint32_t filesizehigh = 1234; + REQUIRE(SFileOpenFileEx(nullptr, "test_diskonly.txt", SFILE_OPENFLAG_CHECKDISK, &file)); + CHECK(SFileGetFileSize(file, &filesizehigh) == 6); + CHECK(filesizehigh == 0); + } +} + +TEST_CASE("SFileOpenArchive", "[file]") { + HSARCHIVE mpq = nullptr; + SErrSetLastError(ERROR_SUCCESS); + + SECTION("opens a MPQ archive") { + CHECK(SFileOpenArchive("wowtest1.mpq", 0, 0, &mpq) == 1); + CHECK(mpq != nullptr); + } + + // TODO determine how to test this (something about CD ROM drives) + // SECTION("fails if drive is inaccessible") {} + + SECTION("fails if archive file is nonexistent") { + mpq = reinterpret_cast(1234); + CHECK_FALSE(SFileOpenArchive("nice_try.mpq", 0, 0, &mpq)); + + CHECK(mpq == nullptr); + CHECK(SErrGetLastError() == ERROR_SUCCESS); + } + + SECTION("fails if archive file is too small") { + mpq = reinterpret_cast(1234); + CHECK_FALSE(SFileOpenArchive("bad_toosmall.mpq", 0, 0, &mpq)); + CHECK(mpq == nullptr); + + CHECK(SErrGetLastError() == STORM_ERROR_NOT_ARCHIVE); + } + + SECTION("fails if using a directory") { + mpq = reinterpret_cast(1234); + CHECK_FALSE(SFileOpenArchive("directorytest", 0, 0, &mpq)); + CHECK(mpq == nullptr); + + CHECK(SErrGetLastError() == ERROR_SUCCESS); + } + + SECTION("fails if archive header magic doesn't match") { + mpq = reinterpret_cast(1234); + CHECK_FALSE(SFileOpenArchive("bad_nomagic.mpq", 0, 0, &mpq)); + CHECK(mpq == nullptr); + + CHECK(SErrGetLastError() == STORM_ERROR_NOT_ARCHIVE); + } + + SECTION("fails if archive header size doesn't match") { + mpq = reinterpret_cast(1234); + CHECK_FALSE(SFileOpenArchive("bad_headertoosmall.mpq", 0, 0, &mpq)); + CHECK(mpq == nullptr); + + CHECK(SErrGetLastError() == STORM_ERROR_NOT_ARCHIVE); + } +} + +TEST_CASE("SFileOpenFileEx", "[file]") { + SECTION("shared testcases") { + OpenFileTestCase testcase = GENERATE(OpenFromDiskCase, OpenFromMPQCase); + + INFO(testcase.info); + HSARCHIVE archive = testcase.OpenArchiveFn(); + HSFILE file = nullptr; + + SECTION("opens a file") { + CHECK(SFileOpenFileEx(archive, "test.txt", testcase.flags, &file) == 1); + CHECK(file != nullptr); + CHECK(file != reinterpret_cast(1234)); + } + + SECTION("fails if file not found") { + SErrSetLastError(ERROR_SUCCESS); + file = reinterpret_cast(1234); + CHECK_FALSE(SFileOpenFileEx(archive, "nice try buddy but your file is in another castle", testcase.flags, &file)); + CHECK(file == nullptr); + CHECK(SErrGetLastError() == ERROR_FILE_NOT_FOUND); + } + } + + SECTION("fails when trying to open a directory") { + SErrSetLastError(ERROR_SUCCESS); + HSFILE file = reinterpret_cast(1234); + CHECK_FALSE(SFileOpenFileEx(nullptr, "directorytest", SFILE_OPENFLAG_CHECKDISK, &file)); + CHECK(file == nullptr); + CHECK(SErrGetLastError() == ERROR_FILE_NOT_FOUND); + } + + SECTION("mpq testcases") { + HSARCHIVE mpq1, mpq2, mpq3; + HSFILE file; + + SECTION("opens the highest priority file from all MPQs") { + SFileOpenArchive("wowtest1.mpq", 100, 0, &mpq1); + SFileOpenArchive("wowtest2.mpq", 500, 0, &mpq2); + SFileOpenArchive("wowtest3.mpq", 400, 0, &mpq3); + + CHECK(SFileOpenFileEx(nullptr, "test.txt", 0, &file) == 1); + + char result[16] = {}; + SFileReadFile(file, result, sizeof(result)); + + CHECK(std::string(result) == "skibbidy"); + } + + SECTION("opens the most recently opened file from same priority MPQs") { + SFileOpenArchive("wowtest1.mpq", 100, 0, &mpq1); + SFileOpenArchive("wowtest2.mpq", 500, 0, &mpq2); + SFileOpenArchive("wowtest3.mpq", 500, 0, &mpq3); + + CHECK(SFileOpenFileEx(nullptr, "test.txt", 0, &file) == 1); + + char result[16] = {}; + SFileReadFile(file, result, sizeof(result)); + + CHECK(std::string(result) == "rizz"); + } + + // TODO implement after adding SFileSetLocale + // SECTION("opens the file for the currently selected locale") {} + + SECTION("fails if file not found in target MPQ") { + SFileOpenArchive("wowtest1.mpq", 100, 0, &mpq1); + SFileOpenArchive("wowtest2.mpq", 500, 0, &mpq2); + SFileOpenArchive("wowtest3.mpq", 400, 0, &mpq3); + + CHECK(SFileOpenFileEx(nullptr, "test2.txt", 0, &file) == 1); + SFileCloseFile(file); + + SErrSetLastError(ERROR_SUCCESS); + CHECK_FALSE(SFileOpenFileEx(mpq3, "test2.txt", 0, &file)); + CHECK(SErrGetLastError() == ERROR_FILE_NOT_FOUND); + } + + SECTION("fails if file not found in any MPQ") { + SFileOpenArchive("wowtest1.mpq", 100, 0, &mpq1); + SFileOpenArchive("wowtest2.mpq", 500, 0, &mpq2); + SFileOpenArchive("wowtest3.mpq", 400, 0, &mpq3); + + SErrSetLastError(ERROR_SUCCESS); + CHECK_FALSE(SFileOpenFileEx(nullptr, "yep not here", 0, &file)); + CHECK(SErrGetLastError() == ERROR_FILE_NOT_FOUND); + } + + SECTION("can open attributes file") { + SFileOpenArchive("wowtest1.mpq", 100, 0, &mpq1); + CHECK(SFileOpenFileEx(nullptr, "(attributes)", 0, &file) == 1); + } + + SECTION("can open listfile") { + SFileOpenArchive("wowtest1.mpq", 100, 0, &mpq1); + CHECK(SFileOpenFileEx(nullptr, "(listfile)", 0, &file) == 1); + } + } +} + +TEST_CASE("SFileReadFile", "[file]") { + SECTION("shared testcases") { + ReadFileTestCase testcase = GENERATE(ReadFromDiskCase, ReadFromMPQCase); + + INFO(testcase.info); + HSFILE file = testcase.OpenFileFn(); + REQUIRE(file != nullptr); + + SECTION("reads a file") { + char buffer[32] = {}; + CHECK(SFileReadFile(file, buffer, 6, nullptr, nullptr) == 1); + CHECK(std::string(buffer) == "catdog"); + } + + SECTION("reads partial file if bytestoread is too small") { + char buffer[4] = ""; + CHECK(SFileReadFile(file, &buffer, 3, nullptr, nullptr) == 1); + CHECK(std::string(buffer) == "cat"); + } + + SECTION("continues reading from the last stored position") { + char buffer[4] = ""; + CHECK(SFileReadFile(file, &buffer, 3, nullptr, nullptr) == 1); + CHECK(SFileReadFile(file, &buffer, 3, nullptr, nullptr) == 1); + CHECK(std::string(buffer) == "dog"); + } + + SECTION("continues reading from an explicitly set position") { + char buffer[4] = ""; + SFileSetFilePointer(file, 3, nullptr, SFILE_BEGIN); + CHECK(SFileReadFile(file, &buffer, 3, nullptr, nullptr) == 1); + CHECK(std::string(buffer) == "dog"); + } + + SECTION("succeeds if bytestoread is 0") { + char buffer; + CHECK(SFileReadFile(file, &buffer, 0, nullptr, nullptr) == 1); + + uint32_t read = 42; + CHECK(SFileReadFile(file, &buffer, 0, &read, nullptr) == 1); + CHECK(read == 0); + } + + SECTION("succeeds if bytestoread is 0 past eof") { + char buffer[8]; + CHECK_FALSE(SFileReadFile(file, &buffer, 8, nullptr, nullptr)); + + uint32_t read = 42; + CHECK(SFileReadFile(file, &buffer, 0, &read, nullptr) == 1); + CHECK(read == 0); + } + + SECTION("fails when reading past end of file") { + char buffer[8] = ""; + CHECK(SFileReadFile(file, &buffer, 6, nullptr, nullptr) == 1); + CHECK(std::string(buffer) == "catdog"); + + SErrSetLastError(0); + CHECK_FALSE(SFileReadFile(file, &buffer, 1, nullptr, nullptr)); + CHECK(SErrGetLastError() == testcase.eofcode); + + CHECK(std::string(buffer) == "catdog"); + } + + SECTION("fails if bytestoread is larger than file size when reading from disk") { + char buffer[32] = ""; + + SErrSetLastError(0); + CHECK_FALSE(SFileReadFile(file, buffer, sizeof(buffer), nullptr, nullptr)); + CHECK(SErrGetLastError() == testcase.eofcode); + + CHECK(std::string(buffer) == "catdog"); + } + } +} + +TEST_CASE("SFileSetFilePointer", "[file]") { + SECTION("shared testcases") { + ReadFileTestCase testcase = GENERATE(ReadFromDiskCase, ReadFromMPQCase); + + INFO(testcase.info); + HSFILE file = testcase.OpenFileFn(); + REQUIRE(file != nullptr); + + SECTION("sets position from beginning") { + CHECK(SFileSetFilePointer(file, 2, nullptr, SFILE_BEGIN) == 2); + CHECK(SFileSetFilePointer(file, 0, nullptr, SFILE_BEGIN) == 0); + CHECK(SFileSetFilePointer(file, 5, nullptr, SFILE_BEGIN) == 5); + } + + SECTION("returns the cursor position") { + CHECK(SFileSetFilePointer(file, 2, nullptr, SFILE_BEGIN) == 2); + CHECK(SFileSetFilePointer(file, 1, nullptr, SFILE_BEGIN) == 1); + CHECK(SFileSetFilePointer(file, 5, nullptr, SFILE_BEGIN) == 5); + CHECK(SFileSetFilePointer(file, -4, nullptr, SFILE_CURRENT) == 1); + CHECK(SFileSetFilePointer(file, 0, nullptr, SFILE_BEGIN) == 0); + } + + SECTION("sets position from current") { + CHECK(SFileSetFilePointer(file, 0, nullptr, SFILE_CURRENT) == 0); + CHECK(SFileSetFilePointer(file, 1, nullptr, SFILE_CURRENT) == 1); + CHECK(SFileSetFilePointer(file, 1, nullptr, SFILE_CURRENT) == 2); + CHECK(SFileSetFilePointer(file, 1, nullptr, SFILE_CURRENT) == 3); + CHECK(SFileSetFilePointer(file, 0, nullptr, SFILE_CURRENT) == 3); + CHECK(SFileSetFilePointer(file, -2, nullptr, SFILE_CURRENT) == 1); + CHECK(SFileSetFilePointer(file, -1, nullptr, SFILE_CURRENT) == 0); + } + } + + SECTION("cases from filesystem") { + // Probably Windows specific, return values are directly from WinAPI calls + // TODO compare with Mac build results + HSFILE file = ReadTestFileFromDisk(); + REQUIRE(file != nullptr); + + SECTION("sets position from beginning out of bounds") { + CHECK(SFileSetFilePointer(file, -1, nullptr, SFILE_BEGIN) == -1); + CHECK(SFileSetFilePointer(file, -100, nullptr, SFILE_BEGIN) == -1); + CHECK(SFileSetFilePointer(file, 6, nullptr, SFILE_BEGIN) == 6); + CHECK(SFileSetFilePointer(file, 100, nullptr, SFILE_BEGIN) == 100); + } + + SECTION("sets position from current out of bounds") { + CHECK(SFileSetFilePointer(file, -1, nullptr, SFILE_CURRENT) == -1); + CHECK(SFileSetFilePointer(file, -100, nullptr, SFILE_CURRENT) == -1); + CHECK(SFileSetFilePointer(file, 106, nullptr, SFILE_CURRENT) == 106); + CHECK(SFileSetFilePointer(file, 100, nullptr, SFILE_CURRENT) == 206); + } + + SECTION("sets position from end") { + CHECK(SFileSetFilePointer(file, -5, nullptr, SFILE_END) == 1); + CHECK(SFileSetFilePointer(file, -2, nullptr, SFILE_END) == 4); + CHECK(SFileSetFilePointer(file, -1, nullptr, SFILE_END) == 5); + CHECK(SFileSetFilePointer(file, 0, nullptr, SFILE_END) == 6); + } + + SECTION("sets position from end out of bounds") { + CHECK(SFileSetFilePointer(file, -100, nullptr, SFILE_END) == -1); + CHECK(SFileSetFilePointer(file, -10, nullptr, SFILE_END) == -1); + CHECK(SFileSetFilePointer(file, 1, nullptr, SFILE_END) == 7); + CHECK(SFileSetFilePointer(file, 5, nullptr, SFILE_END) == 11); + } + } + + SECTION("cases from MPQ") { + HSFILE file = ReadTestFileFromMpq(); + REQUIRE(file != nullptr); + + SECTION("sets position from beginning out of bounds") { + CHECK(SFileSetFilePointer(file, -1, nullptr, SFILE_BEGIN) == 5); + CHECK(SFileSetFilePointer(file, -100, nullptr, SFILE_BEGIN) == 5); + CHECK(SFileSetFilePointer(file, 6, nullptr, SFILE_BEGIN) == 5); + CHECK(SFileSetFilePointer(file, 100, nullptr, SFILE_BEGIN) == 5); + } + + SECTION("sets position from current out of bounds") { + CHECK(SFileSetFilePointer(file, -1, nullptr, SFILE_CURRENT) == 0); + CHECK(SFileSetFilePointer(file, -100, nullptr, SFILE_CURRENT) == 0); + CHECK(SFileSetFilePointer(file, 106, nullptr, SFILE_CURRENT) == 5); + CHECK(SFileSetFilePointer(file, 100, nullptr, SFILE_CURRENT) == 5); + } + + SECTION("sets position from end") { + CHECK(SFileSetFilePointer(file, -5, nullptr, SFILE_END) == 1); + CHECK(SFileSetFilePointer(file, -2, nullptr, SFILE_END) == 4); + CHECK(SFileSetFilePointer(file, -1, nullptr, SFILE_END) == 5); + CHECK(SFileSetFilePointer(file, 0, nullptr, SFILE_END) == 5); + } + + SECTION("sets position from end out of bounds") { + CHECK(SFileSetFilePointer(file, -100, nullptr, SFILE_END) == 0); + CHECK(SFileSetFilePointer(file, -10, nullptr, SFILE_END) == 0); + CHECK(SFileSetFilePointer(file, 1, nullptr, SFILE_END) == 5); + CHECK(SFileSetFilePointer(file, 5, nullptr, SFILE_END) == 5); + } + } +} +#endif diff --git a/test/FileTest.cpp b/test/FileTest.cpp new file mode 100644 index 0000000..00b3346 --- /dev/null +++ b/test/FileTest.cpp @@ -0,0 +1,33 @@ +#include "FileTest.hpp" + +HSARCHIVE OpenNullArchive() { + return nullptr; +} + +HSARCHIVE OpenTestArchive() { + HSARCHIVE archive = nullptr; + SFileOpenArchive("wowtest1.mpq", 0, 0, &archive); + REQUIRE(archive != nullptr); + return archive; +} + +HSFILE ReadTestFileFromDisk() { + HSFILE file = nullptr; + SFileOpenFileEx(nullptr, "test_diskonly.txt", SFILE_OPENFLAG_CHECKDISK, &file); + return file; +} + +HSFILE ReadTestFileFromMpq() { + HSARCHIVE archive = nullptr; + SFileOpenArchive("wowtest1.mpq", 0, 0, &archive); + + HSFILE file = nullptr; + SFileOpenFileEx(archive, "test.txt", 0, &file); + return file; +} + +OpenFileTestCase OpenFromDiskCase{ "file from disk", OpenNullArchive, SFILE_OPENFLAG_CHECKDISK }; +OpenFileTestCase OpenFromMPQCase{ "file from MPQ", OpenTestArchive, 0 }; + +ReadFileTestCase ReadFromDiskCase{ "file from disk", ReadTestFileFromDisk, ERROR_SUCCESS }; +ReadFileTestCase ReadFromMPQCase{ "file from MPQ", ReadTestFileFromMpq, ERROR_HANDLE_EOF }; diff --git a/test/FileTest.hpp b/test/FileTest.hpp new file mode 100644 index 0000000..c536d91 --- /dev/null +++ b/test/FileTest.hpp @@ -0,0 +1,29 @@ +#include "Test.hpp" +#include "storm/Error.hpp" +#include "storm/File.hpp" + +#include + +struct OpenFileTestCase { + std::string info; + HSARCHIVE (*OpenArchiveFn)(); + uint32_t flags; +}; + +struct ReadFileTestCase { + std::string info; + HSFILE (*OpenFileFn)(); + uint32_t eofcode; +}; + +HSARCHIVE OpenNullArchive(); +HSARCHIVE OpenTestArchive(); + +HSFILE ReadTestFileFromDisk(); +HSFILE ReadTestFileFromMpq(); + +extern OpenFileTestCase OpenFromDiskCase; +extern OpenFileTestCase OpenFromMPQCase; + +extern ReadFileTestCase ReadFromDiskCase; +extern ReadFileTestCase ReadFromMPQCase; diff --git a/test/fixture/bad_headertoosmall.mpq b/test/fixture/bad_headertoosmall.mpq new file mode 100644 index 0000000..0ebcba0 Binary files /dev/null and b/test/fixture/bad_headertoosmall.mpq differ diff --git a/test/fixture/bad_nomagic.mpq b/test/fixture/bad_nomagic.mpq new file mode 100644 index 0000000..ebc2c93 Binary files /dev/null and b/test/fixture/bad_nomagic.mpq differ diff --git a/test/fixture/bad_toosmall.mpq b/test/fixture/bad_toosmall.mpq new file mode 100644 index 0000000..17783b4 Binary files /dev/null and b/test/fixture/bad_toosmall.mpq differ diff --git a/test/fixture/bad_wrongsizes.mpq b/test/fixture/bad_wrongsizes.mpq new file mode 100644 index 0000000..1f4814d Binary files /dev/null and b/test/fixture/bad_wrongsizes.mpq differ diff --git a/test/fixture/broken4.mpq b/test/fixture/broken4.mpq new file mode 100644 index 0000000..1f4814d Binary files /dev/null and b/test/fixture/broken4.mpq differ diff --git a/test/fixture/directorytest/.gitkeep b/test/fixture/directorytest/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/test/fixture/empty_diskonly.txt b/test/fixture/empty_diskonly.txt new file mode 100644 index 0000000..e69de29 diff --git a/test/fixture/test.txt b/test/fixture/test.txt new file mode 100644 index 0000000..338cc63 --- /dev/null +++ b/test/fixture/test.txt @@ -0,0 +1 @@ +catdog \ No newline at end of file diff --git a/test/fixture/test_diskonly.txt b/test/fixture/test_diskonly.txt new file mode 100644 index 0000000..338cc63 --- /dev/null +++ b/test/fixture/test_diskonly.txt @@ -0,0 +1 @@ +catdog \ No newline at end of file diff --git a/test/fixture/wowtest1.mpq b/test/fixture/wowtest1.mpq new file mode 100644 index 0000000..858b119 Binary files /dev/null and b/test/fixture/wowtest1.mpq differ diff --git a/test/fixture/wowtest2.mpq b/test/fixture/wowtest2.mpq new file mode 100644 index 0000000..d88e20c Binary files /dev/null and b/test/fixture/wowtest2.mpq differ diff --git a/test/fixture/wowtest3.mpq b/test/fixture/wowtest3.mpq new file mode 100644 index 0000000..d1d5fb1 Binary files /dev/null and b/test/fixture/wowtest3.mpq differ diff --git a/test/stormdll/storm.def b/test/stormdll/storm.def index ff0d3a4..b17c23d 100644 --- a/test/stormdll/storm.def +++ b/test/stormdll/storm.def @@ -87,8 +87,8 @@ EXPORTS ; File ;SFileAuthenticateArchive @251 NONAME - ;SFileCloseArchive @252 NONAME - ;SFileCloseFile @253 NONAME + SFileCloseArchive @252 NONAME + SFileCloseFile @253 NONAME ;SFileDdaBegin @254 NONAME ;SFileDdaBeginEx @255 NONAME ;SFileDdaDestroy @256 NONAME @@ -100,13 +100,13 @@ EXPORTS ;SFileDestroy @262 NONAME ;SFileEnableDirectAccess @263 NONAME ;SFileGetFileArchive @264 NONAME - ;SFileGetFileSize @265 NONAME - ;SFileOpenArchive @266 NONAME + SFileGetFileSize @265 NONAME + SFileOpenArchive @266 NONAME ;SFileOpenFile @267 NONAME - ;SFileOpenFileEx @268 NONAME - ;SFileReadFile @269 NONAME + SFileOpenFileEx @268 NONAME + SFileReadFile @269 NONAME ;SFileSetBasePath @270 NONAME - ;SFileSetFilePointer @271 NONAME + SFileSetFilePointer @271 NONAME ;SFileSetLocale @272 NONAME ;SFileGetBasePath @273 NONAME ;SFileSetIoErrorMode @274 NONAME @@ -280,7 +280,7 @@ EXPORTS ;SErrGetErrorStr @462 NONAME SErrGetLastError @463 NONAME ;SErrRegisterMessageSource @464 NONAME - ;SErrSetLastError @465 NONAME + SErrSetLastError @465 NONAME ;SErrReportNamedResourceLeak @466 NONAME ;SErrReportResourceLeak @467 NONAME SErrSuppressErrors @468 NONAME diff --git a/test/stormdll/stormstubs.cpp b/test/stormdll/stormstubs.cpp index 9bee1a2..b0b6852 100644 --- a/test/stormdll/stormstubs.cpp +++ b/test/stormdll/stormstubs.cpp @@ -55,6 +55,16 @@ int32_t STORMAPI SEvtRegisterHandler(uint32_t, uint32_t, uint32_t, uint32_t, SEV int32_t STORMAPI SEvtUnregisterHandler(uint32_t, uint32_t, uint32_t, SEVTHANDLER) { return 0; } int32_t STORMAPI SEvtUnregisterType(uint32_t, uint32_t) { return 0; } +#include + +int32_t STORMAPI SFileCloseArchive(HSARCHIVE) { return 0; } +int32_t STORMAPI SFileCloseFile(HSFILE) { return 0; } +uint32_t STORMAPI SFileGetFileSize(HSFILE, uint32_t*) { return 0; } +int32_t STORMAPI SFileOpenArchive(const char*, int32_t, uint32_t, HSARCHIVE*) { return 0; } +int32_t STORMAPI SFileOpenFileEx(HSARCHIVE, const char*, uint32_t, HSFILE*) { return 0; } +int32_t STORMAPI SFileReadFile(HSFILE, void*, uint32_t, uint32_t*, LPOVERLAPPED) { return 0; } +uint32_t STORMAPI SFileSetFilePointer(HSFILE, int32_t, int32_t*, uint32_t) { return 0; } + #include void* STORMAPI SMemAlloc(size_t, const char*, int32_t, uint32_t) { return 0; }