aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.clang-format9
-rw-r--r--.clang-tidy1
-rw-r--r--nihil.generator/nihil.generator.ccm6
-rw-r--r--nihil.monad/monad.ccm6
-rw-r--r--nihil.posix/CMakeLists.txt7
-rw-r--r--nihil.posix/execlp.test.cc14
-rw-r--r--nihil.posix/execvp.ccm9
-rw-r--r--nihil.posix/execvp.test.cc79
-rw-r--r--nihil.posix/find_in_path.ccm39
-rw-r--r--nihil.posix/find_in_path.test.cc70
-rw-r--r--nihil.posix/open.test.cc38
-rw-r--r--nihil.posix/open_in_path.ccm39
-rw-r--r--nihil.posix/open_in_path.test.cc82
-rw-r--r--nihil.posix/posix.ccm1
-rw-r--r--nihil.posix/stat.ccm36
-rw-r--r--nihil.posix/stat.test.cc59
-rw-r--r--nihil.posix/test.spawn.cc77
17 files changed, 451 insertions, 121 deletions
diff --git a/.clang-format b/.clang-format
index 390acb9..ff932d0 100644
--- a/.clang-format
+++ b/.clang-format
@@ -13,6 +13,7 @@ ReflowComments: Always
SeparateDefinitionBlocks: Leave
AllowShortFunctionsOnASingleLine: None
+AllowShortLambdasOnASingleLine: Inline
BreakConstructorInitializers: BeforeComma
ConstructorInitializerIndentWidth: 8
@@ -21,6 +22,14 @@ BreakAfterReturnType: Automatic
PenaltyReturnTypeOnItsOwnLine: 0
BreakTemplateDeclarations: Yes
+ForEachMacros:
+ - GIVEN
+ - AND_GIVEN
+ - THEN
+ - AND_THEN
+ - WHEN
+ - AND_WHEN
+
BracedInitializerIndentWidth: 8
BreakBeforeBraces: Custom
BraceWrapping:
diff --git a/.clang-tidy b/.clang-tidy
index c84c230..76636f6 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -22,6 +22,7 @@ Checks: >
readability-*,
-readability-braces-around-statements,
-readability-convert-member-functions-to-static,
+ -readability-else-after-return,
-readability-magic-numbers,
-readability-named-parameter,
-readability-identifier-length,
diff --git a/nihil.generator/nihil.generator.ccm b/nihil.generator/nihil.generator.ccm
index ac9076b..550a4c7 100644
--- a/nihil.generator/nihil.generator.ccm
+++ b/nihil.generator/nihil.generator.ccm
@@ -17,15 +17,9 @@ module;
export module nihil.generator;
-export import :byte_allocator;
export import :coroutine_traits;
export import :elements_of;
-export import :forward;
export import :generator;
-export import :generator_promise_base;
-export import :manual_lifetime;
-export import :promise_base_alloc;
-export import :util;
export namespace std::ranges { // NOLINT
diff --git a/nihil.monad/monad.ccm b/nihil.monad/monad.ccm
index b462e4c..898f1ee 100644
--- a/nihil.monad/monad.ccm
+++ b/nihil.monad/monad.ccm
@@ -39,10 +39,10 @@ namespace nihil {
*/
// An object that starts out unitialized. Initialized by a call to emplace.
-template <typename T>
+export template <typename T>
using deferred = std::optional<T>;
-template <typename T>
+export template <typename T>
struct return_object_holder {
// The staging object that is returned (by copy/move) to the caller of
// the coroutine.
@@ -95,7 +95,7 @@ struct return_object_holder {
}
};
-template <typename T>
+export template <typename T>
auto make_return_object_holder(return_object_holder<T>*& p)
{
return return_object_holder<T>{p};
diff --git a/nihil.posix/CMakeLists.txt b/nihil.posix/CMakeLists.txt
index 61e83df..1fcc365 100644
--- a/nihil.posix/CMakeLists.txt
+++ b/nihil.posix/CMakeLists.txt
@@ -27,6 +27,7 @@ target_sources(nihil.posix
read_file.ccm
rename.ccm
spawn.ccm
+ stat.ccm
tempfile.ccm
write_file.ccm
)
@@ -40,9 +41,13 @@ if(NIHIL_TESTS)
execlp.test.cc
execshell.test.cc
execv.test.cc
+ execvp.test.cc
fd.test.cc
+ find_in_path.test.cc
getenv.test.cc
- test.spawn.cc
+ open.test.cc
+ open_in_path.test.cc
+ stat.test.cc
tempfile.test.cc
)
diff --git a/nihil.posix/execlp.test.cc b/nihil.posix/execlp.test.cc
index cedf871..aa32253 100644
--- a/nihil.posix/execlp.test.cc
+++ b/nihil.posix/execlp.test.cc
@@ -64,4 +64,18 @@ SCENARIO("nihil::execlp() returns the shell's exit code")
}
}
+SCENARIO("nihil::execlp() returns an error if the executable is not in $PATH")
+{
+ GIVEN("An execlp object for a non-existent executable")
+ {
+ auto exec = nihil::execlp("nihil_no_such_executable", "x");
+
+ THEN("A no_such_file_or_directory error is returned")
+ {
+ REQUIRE(!exec);
+ REQUIRE(exec.error().root_cause() == std::errc::no_such_file_or_directory);
+ }
+ }
+}
+
} // anonymous namespace
diff --git a/nihil.posix/execvp.ccm b/nihil.posix/execvp.ccm
index 680a13e..270e311 100644
--- a/nihil.posix/execvp.ccm
+++ b/nihil.posix/execvp.ccm
@@ -1,6 +1,7 @@
// This source code is released into the public domain.
module;
+#include <coroutine>
#include <string>
#include <expected>
#include <format>
@@ -8,6 +9,7 @@ module;
export module nihil.posix:execvp;
import nihil.error;
+import nihil.monad;
import :argv;
import :execv;
import :find_in_path;
@@ -20,11 +22,8 @@ namespace nihil {
export [[nodiscard]] auto
execvp(std::string_view file, argv &&argv) -> std::expected<execv, error>
{
- auto filename = nihil::find_in_path(file);
- if (!filename)
- return std::unexpected(nihil::error(
- std::format("executable not found in path: {}", file)));
- return execv(std::move(*filename), std::move(argv));
+ auto filename = co_await find_in_path(file);
+ co_return execv(std::move(filename), std::move(argv));
}
} // namespace nihil
diff --git a/nihil.posix/execvp.test.cc b/nihil.posix/execvp.test.cc
new file mode 100644
index 0000000..e34823d
--- /dev/null
+++ b/nihil.posix/execvp.test.cc
@@ -0,0 +1,79 @@
+// This source code is released into the public domain.
+
+#include <catch2/catch_test_macros.hpp>
+
+import nihil.posix;
+
+namespace {
+
+SCENARIO("nihil::execvp() can be used to spawn a shell")
+{
+ GIVEN("An execvp object")
+ {
+ auto exec = nihil::execvp("sh", nihil::argv{"sh", "-c", "x=1; echo $x"});
+
+ THEN("sh was found in $PATH")
+ {
+ if (!exec)
+ FAIL(exec.error());
+ }
+
+ WHEN("The shell is executed")
+ {
+ auto output = std::string();
+ auto capture = nihil::make_capture(nihil::stdout_fileno, output).value();
+ auto status = nihil::spawn(exec.value(), capture).value().wait().value();
+
+ THEN("The exit code is 0")
+ {
+ REQUIRE(status.status() == 0);
+ }
+ AND_THEN("The expected output was captured")
+ {
+ REQUIRE(output == "1\n");
+ }
+ }
+ }
+}
+
+SCENARIO("nihil::execvp() returns the shell's exit code")
+{
+ GIVEN("An execvp object")
+ {
+ auto exec = nihil::execvp("sh", nihil::argv{"sh", "-c", "x=42; exit $x"});
+
+ THEN("sh was found in $PATH")
+ {
+ if (!exec)
+ FAIL(exec.error());
+ }
+
+ WHEN("The shell is executed")
+ {
+ auto output = std::string();
+ auto capture = nihil::make_capture(nihil::stdout_fileno, output).value();
+ auto status = nihil::spawn(exec.value(), capture).value().wait().value();
+
+ THEN("The exit code is 1")
+ {
+ REQUIRE(status.status() == 42);
+ }
+ }
+ }
+}
+
+SCENARIO("nihil::execvp() returns an error if the executable is not in $PATH")
+{
+ GIVEN("An execvp object for a non-existent executable")
+ {
+ auto exec = nihil::execvp("nihil_no_such_executable", nihil::argv{"x"});
+
+ THEN("A no_such_file_or_directory error is returned")
+ {
+ REQUIRE(!exec);
+ REQUIRE(exec.error().root_cause() == std::errc::no_such_file_or_directory);
+ }
+ }
+}
+
+} // anonymous namespace
diff --git a/nihil.posix/find_in_path.ccm b/nihil.posix/find_in_path.ccm
index 7bfa3b9..61df669 100644
--- a/nihil.posix/find_in_path.ccm
+++ b/nihil.posix/find_in_path.ccm
@@ -1,6 +1,7 @@
// This source code is released into the public domain.
module;
+#include <expected>
#include <filesystem>
#include <optional>
#include <ranges>
@@ -16,27 +17,26 @@ import :getenv;
namespace nihil {
-/*
- * Find an executable in $PATH and return the full path. If $PATH is not set, uses _PATH_DEFPATH.
- * If the file can't be found or is not executable, returns std::nullopt.
- */
-export [[nodiscard]] auto
-find_in_path(std::filesystem::path const &file) -> std::optional<std::filesystem::path>
+// Find an executable by searching the given path string, which should be a colon-separated list of
+// directories, and return the full path. If the file can't be found or is not executable, returns
+// an appropriate error.
+export [[nodiscard]] auto find_in_path(std::filesystem::path const &file, std::string_view path)
+ -> std::expected<std::filesystem::path, error>
{
- using namespace std::literals;
-
- auto try_return = [](std::filesystem::path file) -> std::optional<std::filesystem::path> {
+ auto try_return =
+ [](std::filesystem::path file) -> std::expected<std::filesystem::path, error> {
auto ret = ::access(file.string().c_str(), X_OK);
if (ret == 0)
return {std::move(file)};
- return {};
+ return std::unexpected(error(std::errc(errno)));
};
// Absolute pathname skips the search.
if (file.is_absolute())
return try_return(file);
- auto const path = getenv("PATH").value_or(_PATH_DEFPATH); // NOLINT
+ // Default to ENOENT as the error.
+ auto err = error(std::errc::no_such_file_or_directory);
for (auto &&dir : path | std::views::split(':')) {
// An empty $PATH element means cwd.
@@ -44,10 +44,23 @@ find_in_path(std::filesystem::path const &file) -> std::optional<std::filesystem
: std::filesystem::path(std::string_view(dir));
if (auto ret = try_return(sdir / file); ret)
- return {ret};
+ return ret;
+ // If we get an error other than ENOENT, cache it to return to the caller.
+ // This means we can propagate access() errors.
+ else if (ret.error().root_cause() != std::errc::no_such_file_or_directory)
+ err = std::move(ret.error());
}
- return {};
+ return std::unexpected(std::move(err));
+}
+
+// Find an executable in $PATH and return the full path. If $PATH is not set, uses _PATH_DEFPATH.
+// If the file can't be found or is not executable, returns an appropriate error.
+export [[nodiscard]] auto
+find_in_path(std::filesystem::path const &file) -> std::expected<std::filesystem::path, error>
+{
+ auto const path = getenv("PATH").value_or(_PATH_DEFPATH); // NOLINT
+ return find_in_path(file, path);
}
} // namespace nihil
diff --git a/nihil.posix/find_in_path.test.cc b/nihil.posix/find_in_path.test.cc
new file mode 100644
index 0000000..b2f6240
--- /dev/null
+++ b/nihil.posix/find_in_path.test.cc
@@ -0,0 +1,70 @@
+// This source code is released into the public domain.
+
+#include <catch2/catch_test_macros.hpp>
+
+import nihil.error;
+import nihil.posix;
+
+namespace {
+
+SCENARIO("nihil::find_in_path can find /bin/sh in the default path")
+{
+ GIVEN ("A call to find_in_path for /bin/sh") {
+ auto ret = nihil::find_in_path("sh");
+
+ THEN ("The return value should be /bin/sh") {
+ REQUIRE(ret);
+ REQUIRE(ret.value() == "/bin/sh");
+ }
+ }
+}
+
+SCENARIO("nihil::find_in_path works with an explicit path")
+{
+ GIVEN ("A call to find_in_path with an explicit path") {
+ auto ret = nihil::find_in_path("sh", "/bin:/usr/bin");
+
+ THEN ("The return value should be /bin/sh") {
+ REQUIRE(ret);
+ REQUIRE(ret.value() == "/bin/sh");
+ }
+ }
+}
+
+SCENARIO("nihil::find_in_path works with an absolute path")
+{
+ GIVEN ("A call to find_in_path with an absolute filename and an empty path") {
+ auto ret = nihil::find_in_path("/bin/sh", "");
+
+ THEN ("The return value should be /bin/sh") {
+ REQUIRE(ret);
+ REQUIRE(ret.value() == "/bin/sh");
+ }
+ }
+}
+
+SCENARIO("nihil::find_in_path returns ENOENT when the executable is not found")
+{
+ GIVEN ("A call to find_in_path for a non-existent executable") {
+ auto ret = nihil::find_in_path("nihil_no_such_executable");
+
+ THEN ("The return value should be std::errc::no_such_file_or_directory") {
+ REQUIRE(!ret);
+ REQUIRE(ret.error() == std::errc::no_such_file_or_directory);
+ }
+ }
+}
+
+SCENARIO("nihil::find_in_path returns errors from access(2)")
+{
+ GIVEN ("A call to find_in_path for a non-executable file") {
+ auto ret = nihil::find_in_path("passwd", "/etc");
+
+ THEN ("The return value should be std::errc::permission_denied") {
+ REQUIRE(!ret);
+ REQUIRE(ret.error() == std::errc::permission_denied);
+ }
+ }
+}
+
+} // anonymous namespace
diff --git a/nihil.posix/open.test.cc b/nihil.posix/open.test.cc
new file mode 100644
index 0000000..bb8bcc9
--- /dev/null
+++ b/nihil.posix/open.test.cc
@@ -0,0 +1,38 @@
+// This source code is released into the public domain.
+
+#include <catch2/catch_test_macros.hpp>
+
+import nihil.error;
+import nihil.posix;
+
+namespace {
+
+SCENARIO("nihil::open() can open an existing file")
+{
+ GIVEN ("A call to open() for /bin/sh") {
+ auto ret = nihil::open("/bin/sh", nihil::open_read);
+
+ THEN ("The returned file descriptor should be /bin/sh") {
+ REQUIRE(ret);
+
+ auto sb1 = nihil::stat(*ret).value();
+ auto sb2 = nihil::stat("/bin/sh").value();
+ REQUIRE(sb1.st_ino == sb2.st_ino);
+ REQUIRE(sb1.st_dev == sb2.st_dev);
+ }
+ }
+}
+
+SCENARIO("nihil::open_in_path returns ENOENT when the file is not found")
+{
+ GIVEN ("A call to open for a non-existent file") {
+ auto ret = nihil::open("/nihil_no_such_file", nihil::open_read);
+
+ THEN ("The return value should be std::errc::no_such_file_or_directory") {
+ REQUIRE(!ret);
+ REQUIRE(ret.error() == std::errc::no_such_file_or_directory);
+ }
+ }
+}
+
+} // anonymous namespace
diff --git a/nihil.posix/open_in_path.ccm b/nihil.posix/open_in_path.ccm
index 7ff5812..e8c1761 100644
--- a/nihil.posix/open_in_path.ccm
+++ b/nihil.posix/open_in_path.ccm
@@ -1,6 +1,7 @@
// This source code is released into the public domain.
module;
+#include <expected>
#include <filesystem>
#include <optional>
#include <ranges>
@@ -17,35 +18,41 @@ import :open;
namespace nihil {
-// Find an executable in $PATH and open it with O_EXEC. If $PATH is not set, uses _PATH_DEFPATH.
-// If the file can't be found or opened, returns std::nullopt.
-export [[nodiscard]] auto open_in_path(std::filesystem::path const &file) -> std::optional<fd>
+// Find an executable in the given path, which should be a colon-separated list of directories, and
+// open it with O_EXEC. If the file can't be found or can't be opened, returns an appropriate error.
+export [[nodiscard]] auto
+open_in_path(std::filesystem::path const &file, std::string_view path) -> std::expected<fd, error>
{
- using namespace std::literals;
-
- auto try_open = [](std::filesystem::path const &file) -> std::optional<fd> {
- auto ret = open(file, open_exec);
- if (ret)
- return {std::move(*ret)};
- return {};
- };
-
// Absolute pathname skips the search.
if (file.is_absolute())
- return try_open(file);
+ return open(file, open_exec);
- auto path = getenv("PATH").value_or(_PATH_DEFPATH); // NOLINT
+ // Default to ENOENT as the error.
+ auto err = error(std::errc::no_such_file_or_directory);
for (auto &&dir : path | std::views::split(':')) {
// An empty $PATH element means cwd.
auto sdir = dir.empty() ? std::filesystem::path(".")
: std::filesystem::path(std::string_view(dir));
- if (auto ret = try_open(sdir / file); ret)
+ if (auto ret = open(sdir / file, open_exec); ret)
return ret;
+ // If we get an error other than ENOENT, cache it to return to the caller.
+ // This means we can propagate open() errors.
+ else if (ret.error().root_cause() != std::errc::no_such_file_or_directory)
+ err = std::move(ret.error());
}
- return {};
+ return std::unexpected(std::move(err));
+}
+
+// Find an executable in $PATH and open it. If $PATH is not set, uses _PATH_DEFPATH.
+// If the file can't be found or can't be opened, returns an appropriate error.
+export [[nodiscard]] auto
+open_in_path(std::filesystem::path const &file) -> std::expected<fd, error>
+{
+ auto const path = getenv("PATH").value_or(_PATH_DEFPATH); // NOLINT
+ return open_in_path(file, path);
}
} // namespace nihil
diff --git a/nihil.posix/open_in_path.test.cc b/nihil.posix/open_in_path.test.cc
new file mode 100644
index 0000000..13d6b49
--- /dev/null
+++ b/nihil.posix/open_in_path.test.cc
@@ -0,0 +1,82 @@
+// This source code is released into the public domain.
+
+#include <catch2/catch_test_macros.hpp>
+
+import nihil.error;
+import nihil.posix;
+
+namespace {
+
+SCENARIO("nihil::open_in_path can find /bin/sh in the default path")
+{
+ GIVEN ("A call to open_in_path for /bin/sh") {
+ auto ret = nihil::open_in_path("sh");
+
+ THEN ("The returned file descriptor should be /bin/sh") {
+ REQUIRE(ret);
+
+ auto sb1 = nihil::stat(*ret).value();
+ auto sb2 = nihil::stat("/bin/sh").value();
+ REQUIRE(sb1.st_ino == sb2.st_ino);
+ REQUIRE(sb1.st_dev == sb2.st_dev);
+ }
+ }
+}
+
+SCENARIO("nihil::open_in_path works with an explicit path")
+{
+ GIVEN ("A call to open_in_path with an explicit path") {
+ auto ret = nihil::open_in_path("sh", "/bin:/usr/bin");
+
+ THEN ("The returned file descriptor should be /bin/sh") {
+ REQUIRE(ret);
+
+ auto sb1 = nihil::stat(*ret).value();
+ auto sb2 = nihil::stat("/bin/sh").value();
+ REQUIRE(sb1.st_ino == sb2.st_ino);
+ REQUIRE(sb1.st_dev == sb2.st_dev);
+ }
+ }
+}
+
+SCENARIO("nihil::open_in_path works with an absolute path")
+{
+ GIVEN ("A call to open_in_path with an absolute filename and an empty path") {
+ auto ret = nihil::open_in_path("/bin/sh", "");
+
+ THEN ("The returned file descriptor should be /bin/sh") {
+ REQUIRE(ret);
+
+ auto sb1 = nihil::stat(*ret).value();
+ auto sb2 = nihil::stat("/bin/sh").value();
+ REQUIRE(sb1.st_ino == sb2.st_ino);
+ REQUIRE(sb1.st_dev == sb2.st_dev);
+ }
+ }
+}
+
+SCENARIO("nihil::open_in_path returns ENOENT when the executable is not found")
+{
+ GIVEN ("A call to open_in_path for a non-existent executable") {
+ auto ret = nihil::open_in_path("nihil_no_such_executable");
+
+ THEN ("The return value should be std::errc::no_such_file_or_directory") {
+ REQUIRE(!ret);
+ REQUIRE(ret.error() == std::errc::no_such_file_or_directory);
+ }
+ }
+}
+
+SCENARIO("nihil::open_in_path returns errors from open(2)")
+{
+ GIVEN ("A call to open_in_path for a non-executable file") {
+ auto ret = nihil::open_in_path("passwd", "/etc");
+
+ THEN ("The return value should be std::errc::permission_denied") {
+ REQUIRE(!ret);
+ REQUIRE(ret.error() == std::errc::permission_denied);
+ }
+ }
+}
+
+} // anonymous namespace
diff --git a/nihil.posix/posix.ccm b/nihil.posix/posix.ccm
index 3e13d5a..c49a992 100644
--- a/nihil.posix/posix.ccm
+++ b/nihil.posix/posix.ccm
@@ -23,5 +23,6 @@ export import :process;
export import :read_file;
export import :rename;
export import :spawn;
+export import :stat;
export import :tempfile;
export import :write_file;
diff --git a/nihil.posix/stat.ccm b/nihil.posix/stat.ccm
new file mode 100644
index 0000000..6a0cabf
--- /dev/null
+++ b/nihil.posix/stat.ccm
@@ -0,0 +1,36 @@
+// This source code is released into the public domain.
+module;
+
+// Basic wrappers around stat() and fstat().
+
+#include <expected>
+#include <filesystem>
+
+#include <sys/stat.h>
+
+export module nihil.posix:stat;
+
+import :fd;
+
+namespace nihil {
+
+export [[nodiscard]] auto
+stat(std::filesystem::path const &path) -> std::expected<struct ::stat, error>
+{
+ struct ::stat sb{};
+ auto ret = ::stat(path.string().c_str(), &sb);
+ if (ret == -1)
+ return std::unexpected(error(std::errc(errno)));
+ return sb;
+}
+
+export [[nodiscard]] auto stat(fd const &fd) -> std::expected<struct ::stat, error>
+{
+ struct ::stat sb{};
+ auto ret = ::fstat(fd.get(), &sb);
+ if (ret == -1)
+ return std::unexpected(error(std::errc(errno)));
+ return sb;
+}
+
+} // namespace nihil
diff --git a/nihil.posix/stat.test.cc b/nihil.posix/stat.test.cc
new file mode 100644
index 0000000..cf1e29c
--- /dev/null
+++ b/nihil.posix/stat.test.cc
@@ -0,0 +1,59 @@
+// This source code is released into the public domain.
+
+import nihil.error;
+import nihil.posix;
+
+#include <sys/stat.h>
+
+#include <catch2/catch_test_macros.hpp>
+
+namespace {
+
+SCENARIO("nihil::stat() on an existing file")
+{
+ GIVEN("A call to stat() on /etc/passwd")
+ {
+ auto sb = nihil::stat("/etc/passwd");
+
+ THEN("The returned struct is correct")
+ {
+ REQUIRE(sb);
+ REQUIRE(S_ISREG(sb->st_mode));
+ }
+ }
+}
+
+SCENARIO("nihil::stat() on a non-existent file")
+{
+ GIVEN("A call to stat() on /nonesuchfile")
+ {
+ auto sb = nihil::stat("/nonesuchfile");
+
+ THEN("std::errc::no_such_file_or_directory is returned")
+ {
+ REQUIRE(!sb);
+ REQUIRE(sb.error() == std::errc::no_such_file_or_directory);
+ }
+ }
+}
+
+SCENARIO("nihil::stat() on an open file descriptor")
+{
+ GIVEN("An fd referring to /etc/password")
+ {
+ auto fd = nihil::open("/etc/passwd", nihil::open_read).value();
+
+ WHEN("nihil::stat() is called on the fd")
+ {
+ auto sb = nihil::stat(fd);
+
+ THEN("The returned struct is correct")
+ {
+ REQUIRE(sb);
+ REQUIRE(S_ISREG(sb->st_mode));
+ }
+ }
+ }
+}
+
+} // anonymous namespace
diff --git a/nihil.posix/test.spawn.cc b/nihil.posix/test.spawn.cc
deleted file mode 100644
index c5b4f53..0000000
--- a/nihil.posix/test.spawn.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * This source code is released into the public domain.
- */
-
-#include <catch2/catch_test_macros.hpp>
-
-import nihil.posix;
-
-TEST_CASE("spawn: execv", "[spawn]") {
- using namespace nihil;
-
- auto args = argv({"sh", "-c", "x=1; echo $x"});
- auto exec = execv("/bin/sh", std::move(args));
-
- auto output = std::string();
- auto capture = make_capture(stdout_fileno, output);
- REQUIRE(capture);
-
- auto proc = spawn(exec, *capture);
- REQUIRE(proc);
-
- auto status = std::move(*proc).wait();
- if (!status)
- FAIL(to_string(status.error()));
-
- REQUIRE(status->okay());
- REQUIRE(output == "1\n");
-}
-
-TEST_CASE("spawn: execvp", "[spawn]") {
- using namespace nihil;
-
- auto args = argv({"sh", "-c", "x=1; echo $x"});
- auto exec = execvp("sh", std::move(args));
- REQUIRE(exec);
-
- auto output = std::string();
- auto capture = make_capture(stdout_fileno, output);
- REQUIRE(capture);
-
- auto proc = spawn(*exec, *capture);
- REQUIRE(proc);
-
- auto status = std::move(*proc).wait();
- REQUIRE(status);
-
- REQUIRE(status->okay());
- REQUIRE(output == "1\n");
-}
-
-
-TEST_CASE("spawn: execlp", "[spawn]") {
- using namespace nihil;
-
- auto exec = execlp("sh", "sh", "-c", "x=1; echo $x");
- REQUIRE(exec);
-
- auto output = std::string();
- auto capture = make_capture(stdout_fileno, output);
- REQUIRE(capture);
-
- auto proc = spawn(*exec, *capture);
- REQUIRE(proc);
-
- auto status = std::move(*proc).wait();
- REQUIRE(status);
-
- REQUIRE(status->okay());
- REQUIRE(output == "1\n");
-}
-
-TEST_CASE("spawn: execlp failure", "[spawn]") {
- using namespace nihil;
-
- auto exec = execlp("nihil_no_such_executable", "x");
- REQUIRE(!exec);
-}