aboutsummaryrefslogtreecommitdiff
path: root/src/zentest-appstub/zentest-appstub.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/zentest-appstub/zentest-appstub.cpp')
-rw-r--r--src/zentest-appstub/zentest-appstub.cpp98
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());