#include "prx/libc/include/FileStream.hpp" #include "prx/libc/include/general/VabiMacros.hpp" #include #include #include #include #include #include extern "C" { FileStream* APS5_VABI fopen_nid_postfix(const char* filename, const char* mode); int APS5_VABI fclose_nid_postfix(FileStream* stream); std::size_t APS5_VABI fread_nid_postfix(void* buffer, std::size_t size, std::size_t count, FileStream* stream); std::size_t APS5_VABI fwrite_nid_postfix(const void* buffer, std::size_t size, std::size_t count, FileStream* stream); int APS5_VABI fseek_nid_postfix(FileStream* stream, std::int64_t offset, int origin); std::int64_t APS5_VABI ftell_nid_postfix(FileStream* stream); int APS5_VABI fputs_nid_postfix(const char* str, FileStream* stream); int APS5_VABI fflush_nid_postfix(FileStream* stream); } static void Require(bool condition) { if (!condition) throw std::runtime_error("File stream check failed"); } template static void ExpectException(TAction action) { try { action(); } catch (const std::runtime_error&) { return; } throw std::runtime_error("Expected a stream exception"); } int main(int argc, char** argv) { Require(argc == 2); Require(_Stdout_nid_postfix.GetHandle() == stdout); Require(_Stderr_nid_postfix.GetHandle() == stderr); Require(fputs_nid_postfix("stdout object works\n", &_Stdout_nid_postfix) >= 0); Require(fputs_nid_postfix("stderr object works\n", &_Stderr_nid_postfix) >= 0); Require(fflush_nid_postfix(nullptr) == 0); auto* stream = fopen_nid_postfix(argv[1], "w+b"); constexpr char payload[] = "stream round trip"; Require(fputs_nid_postfix(payload, stream) >= 0); Require(fwrite_nid_postfix(payload, 1, sizeof(payload), stream) == sizeof(payload)); const auto expectedSize = sizeof(payload) * 2 - 1; Require(ftell_nid_postfix(stream) == static_cast(expectedSize)); Require(fflush_nid_postfix(stream) == 0); Require(fseek_nid_postfix(stream, 0, SEEK_SET) == 0); std::array buffer{}; Require(fread_nid_postfix(buffer.data(), 1, sizeof(payload) - 1, stream) == sizeof(payload) - 1); Require(std::strcmp(buffer.data(), payload) == 0); Require(fread_nid_postfix(buffer.data(), 1, buffer.size(), stream) == buffer.size()); Require(std::strcmp(buffer.data(), payload) == 0); Require(fread_nid_postfix(buffer.data(), 1, buffer.size(), stream) == 0); ExpectException([&] { fputs_nid_postfix(nullptr, stream); }); ExpectException([&] { fwrite_nid_postfix(nullptr, 1, sizeof(payload), stream); }); errno = 0; Require(fseek_nid_postfix(stream, 0, -1) == -1); Require(errno == EINVAL); Require(fclose_nid_postfix(stream) == 0); ExpectException([] { fputs_nid_postfix("invalid stream", nullptr); }); ExpectException([] { fopen_nid_postfix(nullptr, "r"); }); FileStream closed(std::tmpfile()); closed.Close(); ExpectException([&] { fflush_nid_postfix(&closed); }); Require(std::remove(argv[1]) == 0); errno = 0; Require(fopen_nid_postfix(argv[1], "rb") == nullptr); Require(errno == ENOENT); std::cout << "PASS: stream objects, file operations, EOF and error handling\n"; }