diff options
Diffstat (limited to 'src/zentest-appstub/zentest-appstub.cpp')
| -rw-r--r-- | src/zentest-appstub/zentest-appstub.cpp | 98 |
1 files changed, 94 insertions, 4 deletions
diff --git a/src/zentest-appstub/zentest-appstub.cpp b/src/zentest-appstub/zentest-appstub.cpp index 509629739..8f7c2b166 100644 --- a/src/zentest-appstub/zentest-appstub.cpp +++ b/src/zentest-appstub/zentest-appstub.cpp @@ -24,6 +24,11 @@ #include <system_error> #include <thread> +#if ZEN_PLATFORM_WINDOWS +# include <fcntl.h> +# include <io.h> +#endif + using namespace std::literals; using namespace zen; @@ -33,6 +38,13 @@ using namespace zen; // Some basic functions to implement some test "compute" functions +struct ForcedExitException : std::exception +{ + int Code; + explicit ForcedExitException(int InCode) : Code(InCode) {} + const char* what() const noexcept override { return "forced exit"; } +}; + std::string Rot13Function(std::string_view InputString) { @@ -111,6 +123,16 @@ DescribeFunctions() << "Sleep"sv; Versions << "Version"sv << Guid::FromString("88888888-8888-8888-8888-888888888888"sv); Versions.EndObject(); + Versions.BeginObject(); + Versions << "Name"sv + << "Fail"sv; + Versions << "Version"sv << Guid::FromString("fa11fa11-fa11-fa11-fa11-fa11fa11fa11"sv); + Versions.EndObject(); + Versions.BeginObject(); + Versions << "Name"sv + << "Crash"sv; + Versions << "Version"sv << Guid::FromString("c4a50000-c4a5-c4a5-c4a5-c4a5c4a5c4a5"sv); + Versions.EndObject(); Versions.EndArray(); return Versions.Save(); @@ -201,6 +223,38 @@ ExecuteFunction(CbObject Action, ContentResolver ChunkResolver) zen::Sleep(static_cast<int>(SleepTimeMs)); return Apply(IdentityFunction); } + else if (Function == "Fail"sv) + { + int FailExitCode = static_cast<int>(Action["Constants"sv].AsObjectView()["ExitCode"sv].AsUInt64()); + if (FailExitCode == 0) + { + FailExitCode = 1; + } + throw ForcedExitException(FailExitCode); + } + else if (Function == "Crash"sv) + { + // Crash modes: + // "abort" - calls std::abort() (SIGABRT / process termination) + // "nullptr" - dereferences a null pointer (SIGSEGV / access violation) + std::string_view Mode = Action["Constants"sv].AsObjectView()["Mode"sv].AsString(); + + printf("[zentest] crashing with mode: %.*s\n", int(Mode.size()), Mode.data()); + fflush(stdout); + + if (Mode == "nullptr"sv) + { + volatile int* Ptr = nullptr; + *Ptr = 42; + } + + // Default crash mode (also reached after nullptr write on platforms + // that don't immediately fault on null dereference) +#if defined(_MSC_VER) + _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); +#endif + std::abort(); + } else { return {}; @@ -221,10 +275,10 @@ main(int argc, char* argv[]) try { - std::filesystem::path BasePath = std::filesystem::current_path(); - std::filesystem::path InputPath = std::filesystem::current_path() / "Inputs"; - std::filesystem::path OutputPath = std::filesystem::current_path() / "Outputs"; - std::filesystem::path VersionPath = std::filesystem::current_path() / "Versions"; + std::filesystem::path BasePath = std::filesystem::current_path(); + std::filesystem::path InputPath = std::filesystem::current_path() / "Inputs"; + std::filesystem::path OutputPath = std::filesystem::current_path() / "Outputs"; + std::filesystem::path VersionPath; std::vector<std::filesystem::path> ActionPaths; /* @@ -291,6 +345,36 @@ main(int argc, char* argv[]) std::string_view ErrorArg = SplitArg(argv[i]); ExitCode = ParseIntArg(ErrorArg); } + else if (std::strncmp(argv[i], "-echo=", 6) == 0) + { + // Write a message to stdout. Useful for testing pipe capture. + std::string_view Message = SplitArg(argv[i]); + printf("%.*s", static_cast<int>(Message.size()), Message.data()); + fflush(stdout); + } + else if (std::strncmp(argv[i], "-echoerr=", 9) == 0) + { + // Write a message to stderr. Useful for testing separate stderr pipe capture. + std::string_view Message = SplitArg(argv[i]); + fprintf(stderr, "%.*s", static_cast<int>(Message.size()), Message.data()); + fflush(stderr); + } + else if (std::strcmp(argv[i], "-stdin_echo") == 0) + { + // Read stdin to EOF and echo it to stdout. Useful for testing stdin pipe wiring. + // Switch to binary mode on Windows so CRLF translation doesn't mangle the bytes. +#if ZEN_PLATFORM_WINDOWS + _setmode(_fileno(stdin), _O_BINARY); + _setmode(_fileno(stdout), _O_BINARY); +#endif + char Buffer[4096]; + size_t Bytes = 0; + while ((Bytes = fread(Buffer, 1, sizeof(Buffer), stdin)) > 0) + { + fwrite(Buffer, 1, Bytes, stdout); + } + fflush(stdout); + } else if ((_strnicmp(argv[i], "-input=", 7) == 0) || (_strnicmp(argv[i], "-i=", 3) == 0)) { /* mimic DDC2 @@ -407,6 +491,12 @@ main(int argc, char* argv[]) } } } + catch (ForcedExitException& Ex) + { + printf("[zentest] forced exit with code: %d\n", Ex.Code); + + ExitCode = Ex.Code; + } catch (std::exception& Ex) { printf("[zentest] exception caught in main: '%s'\n", Ex.what()); |