Add process unit tests

This commit is contained in:
SirLynix 2024-01-23 15:11:02 +01:00 committed by Jérôme Leclercq
parent a02990beff
commit a228325bd5
7 changed files with 265 additions and 13 deletions

View File

@ -78,6 +78,7 @@
#include <Nazara/Core/PoolByteStream.hpp>
#include <Nazara/Core/Primitive.hpp>
#include <Nazara/Core/PrimitiveList.hpp>
#include <Nazara/Core/Process.hpp>
#include <Nazara/Core/RefCounted.hpp>
#include <Nazara/Core/Resource.hpp>
#include <Nazara/Core/ResourceLoader.hpp>

View File

@ -33,6 +33,7 @@ namespace Nz
NAZARA_FORMAT_IMPLEM(std::filesystem::path);
NAZARA_FORMAT_IMPLEM(std::string);
NAZARA_FORMAT_IMPLEM(std::string_view);
NAZARA_FORMAT_IMPLEM(char*);
NAZARA_FORMAT_IMPLEM(const char*);
NAZARA_FORMAT_IMPLEM(short);
NAZARA_FORMAT_IMPLEM(int);

View File

@ -0,0 +1,119 @@
#include <Nazara/Core/File.hpp>
#include <Nazara/Core/Format.hpp>
#include <Nazara/Core/Process.hpp>
#include <NazaraUtils/PathUtils.hpp>
#include <array>
#include <charconv>
#include <chrono>
#include <string>
#include <thread>
#include <catch2/catch_test_macros.hpp>
SCENARIO("Process", "[CORE][PROCESS]")
{
WHEN("Checking if the current process exists")
{
if (Nz::Result result = Nz::Process::Exists(Nz::Process::GetCurrentPid()))
CHECK(result.GetValue());
else
{
INFO(result.GetError());
CHECK(false);
}
}
WHEN("Creating a detached process")
{
std::array<std::string, 3> args = { "simple_arg", "space \\arg", "okay\n\\\\\"_wt\"f\\" };
std::filesystem::path path = Nz::Utf8Path("ProcessTests");
if (std::filesystem::exists(path))
REQUIRE(std::filesystem::remove_all(path));
REQUIRE(std::filesystem::create_directory(path));
Nz::Result spawnResult = Nz::Process::SpawnDetached(Nz::Utf8Path("UnitTests_sub1"), args, path);
if (!spawnResult)
{
INFO(spawnResult.GetError());
REQUIRE(false);
}
std::this_thread::sleep_for(std::chrono::seconds(1));
// Some files were written in the ProcessTests directory
auto ReadFile = [&](std::string_view filename, std::string_view failureName = {})
{
std::filesystem::path filePath = path / Nz::Utf8Path(filename);
auto fileContentOpt = Nz::File::ReadWhole(filePath);
if (!fileContentOpt)
{
if (!failureName.empty())
{
fileContentOpt = Nz::File::ReadWhole(path / Nz::Utf8Path(failureName));
if (fileContentOpt)
{
std::string_view error(reinterpret_cast<const char*>(fileContentOpt->data()), fileContentOpt->size());
INFO(failureName << ": " << error);
REQUIRE(false);
}
else
{
INFO(filename << " nor " << failureName << " exist");
REQUIRE(false);
}
}
else
{
INFO(filename << " doesn't exist");
REQUIRE(false);
}
}
return std::string(reinterpret_cast<const char*>(fileContentOpt->data()), fileContentOpt->size());
};
auto CheckStep = [&](std::string_view filename, std::string_view expected, std::string_view failureName = {})
{
std::string content = ReadFile(filename, failureName);
INFO("checking " << filename << " content");
REQUIRE(content == expected);
};
CheckStep("step1_success.txt", "1", "step1_failure.txt");
// Parameter passing check
for (std::size_t i = 0; i < args.size(); ++i)
CheckStep(Nz::Format("step2_param{}.txt", i + 1), args[i]);
CHECK(!std::filesystem::exists(path / Nz::Utf8Path(Nz::Format("step2_param{}.txt", args.size() + 1))));
std::string pidStr = ReadFile("step3_pid.txt", "step3_failure.txt");
Nz::Pid pid;
if (auto pidParse = std::from_chars(pidStr.data(), pidStr.data() + pidStr.size(), pid); pidParse.ec == std::errc())
{
Nz::Result result = Nz::Process::Exists(pid);
if (result)
{
INFO("checking that grand-child process still exists");
CHECK(result.GetValue());
}
else
{
INFO("failed to retrieve grand-child status: " << result.GetError());
CHECK(false);
}
}
else
{
INFO("failed to parse pid from step3_pid.txt: " << pidStr);
CHECK(false);
}
CheckStep("step4_success.txt", "1", "step4_failure.txt");
CheckStep("step5_success.txt", "1", "step5_failure.txt");
CheckStep("step6_success.txt", "1", "step6_failure.txt");
}
}

View File

@ -0,0 +1,39 @@
#include <Nazara/Core/File.hpp>
#include <Nazara/Core/Format.hpp>
#include <Nazara/Core/Process.hpp>
#include <NazaraUtils/PathUtils.hpp>
#include <chrono>
#include <string>
#include <thread>
int main(int argc, char* argv[])
{
{
Nz::File file(Nz::Utf8Path("step1_success.txt"), Nz::OpenMode::Write);
file.Write("1");
}
for (int i = 1; i < argc; ++i)
{
Nz::File file(Nz::Utf8Path(Nz::Format("step2_param{}.txt", i)), Nz::OpenMode::Write);
file.Write(argv[i]);
}
std::vector<std::string> parameters;
parameters.push_back(std::to_string(Nz::Process::GetCurrentPid()));
Nz::Result result = Nz::Process::SpawnDetached("../UnitTests_sub2", parameters);
if (result)
{
Nz::File file(Nz::Utf8Path("step3_pid.txt"), Nz::OpenMode::Write);
file.Write(std::to_string(result.GetValue()));
}
else
{
Nz::File file(Nz::Utf8Path("step3_failure.txt"), Nz::OpenMode::Write);
file.Write(result.GetError());
}
// Wait for our child process to start and check for our existence
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}

View File

@ -0,0 +1,78 @@
#include <Nazara/Core/File.hpp>
#include <Nazara/Core/Format.hpp>
#include <Nazara/Core/Process.hpp>
#include <NazaraUtils/PathUtils.hpp>
#include <charconv>
#include <chrono>
#include <cstring>
#include <string>
#include <thread>
int main(int argc, char* argv[])
{
if (argc != 2)
{
Nz::File errFile(Nz::Utf8Path("step4_failure.txt"), Nz::OpenMode::Write);
errFile.Write(Nz::Format("unexpected argc: {}", argc));
return EXIT_FAILURE;
}
Nz::Pid pid;
if (auto pidParse = std::from_chars(argv[1], argv[1] + std::strlen(argv[1]), pid); pidParse.ec != std::errc())
{
Nz::File errFile(Nz::Utf8Path("step4_failure.txt"), Nz::OpenMode::Write);
errFile.Write(Nz::Format("invalid pid: {}", argv[1]));
return EXIT_FAILURE;
}
Nz::File successFile4(Nz::Utf8Path("step4_success.txt"), Nz::OpenMode::Write);
successFile4.Write("1");
Nz::Result result = Nz::Process::Exists(pid);
if (!result)
{
Nz::File errFile(Nz::Utf8Path("step5_failure.txt"), Nz::OpenMode::Write);
errFile.Write(Nz::Format("failed to retrieve parent process status: {}", result.GetError()));
return EXIT_FAILURE;
}
if (!result.GetValue())
{
Nz::File file(Nz::Utf8Path("step5_failure.txt"), Nz::OpenMode::Write);
file.Write("parent process is already dead");
return EXIT_FAILURE;
}
Nz::File successFile5(Nz::Utf8Path("step5_success.txt"), Nz::OpenMode::Write);
successFile5.Write("1");
// Wait until parent dies
std::this_thread::sleep_for(std::chrono::milliseconds(500));
result = Nz::Process::Exists(pid);
if (!result)
{
Nz::File errFile(Nz::Utf8Path("step6_failure.txt"), Nz::OpenMode::Write);
errFile.Write(Nz::Format("failed to retrieve parent process status after waiting: {}", result.GetError()));
return EXIT_FAILURE;
}
if (result.GetValue())
{
Nz::File errFile(Nz::Utf8Path("step6_failure.txt"), Nz::OpenMode::Write);
errFile.Write("parent process is still alive");
return EXIT_FAILURE;
}
Nz::File successFile6(Nz::Utf8Path("step6_success.txt"), Nz::OpenMode::Write);
successFile6.Write("1");
// Wait for the unit tests process to check our existence
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
}

View File

@ -1,22 +1,35 @@
add_requires("catch2 >=3.x")
if has_config("asan") then
add_defines("CATCH_CONFIG_NO_WINDOWS_SEH")
add_defines("CATCH_CONFIG_NO_POSIX_SIGNALS")
end
target("UnitTests_sub1", function ()
add_deps("NazaraCore")
add_deps("NazaraAudio", "NazaraCore", "NazaraNetwork", "NazaraChipmunkPhysics2D")
add_packages("catch2", "entt", "frozen")
add_headerfiles("Engine/**.hpp", { prefixdir = "private", install = false })
add_files("resources.cpp")
add_files("Engine/**.cpp")
add_includedirs(".")
add_files("subprocess1.cpp")
end)
if has_config("unitybuild") then
add_rules("c++.unity_build")
end
target("UnitTests_sub2", function ()
add_deps("NazaraCore")
add_files("subprocess2.cpp")
end)
target("UnitTests", function ()
if has_config("asan") then
add_defines("CATCH_CONFIG_NO_WINDOWS_SEH")
add_defines("CATCH_CONFIG_NO_POSIX_SIGNALS")
end
add_deps("NazaraAudio", "NazaraCore", "NazaraNetwork", "NazaraChipmunkPhysics2D")
add_deps("UnitTests_sub1", "UnitTests_sub2", { links = {} })
add_packages("catch2", "entt", "frozen")
add_headerfiles("Engine/**.hpp", { prefixdir = "private", install = false })
add_files("resources.cpp")
add_files("Engine/**.cpp")
add_includedirs(".")
if has_config("unitybuild") then
add_rules("c++.unity_build")
end
add_files("main.cpp", {unity_ignored = true})
if has_config("usepch") then

View File

@ -43,6 +43,7 @@ local systemHeaders = {
["poll.h"] = true,
["process.h"] = true,
["pthread.h"] = true,
["spawn.h"] = true,
["unistd.h"] = true,
["windows.h"] = true,
["winsock2"] = true,