uvco/test/stream_test.cc
Kimapr 741f9184fd
Some checks failed
Actions CI + Docs / uvco (clang++) (push) Has been cancelled
Actions CI + Docs / uvco (g++-14) (push) Has been cancelled
Fix failing tests and SelectSet
additionally, add constexpr to IoVec constructor, just in case...
2026-03-20 18:42:01 +05:00

156 lines
3.4 KiB
C++

#include <boost/assert.hpp>
#include <gtest/gtest.h>
#include <uv.h>
#include "test_util.h"
#include "uvco/exception.h"
#include "uvco/loop/loop.h"
#include "uvco/pipe.h"
#include "uvco/promise/promise.h"
#include "uvco/stream.h"
#include <array>
#include <cstdint>
#include <cstdio>
#include <fstream>
#include <ios>
#include <optional>
#include <string>
#include <utility>
#include <vector>
namespace {
using namespace uvco;
// Doesn't work on Github Actions because no TTY is attached.
TEST(TtyTest, DISABLED_stdioTest) {
uint64_t counter = 0;
auto setup = [&counter](const Loop &loop) -> Promise<void> {
std::vector<TtyStream> ttys;
ttys.emplace_back(TtyStream::stdin(loop));
ttys.emplace_back(TtyStream::stdout(loop));
ttys.emplace_back(TtyStream::stderr(loop));
for (auto &tty : ttys) {
co_await tty.write(" ");
++counter;
tty.close();
++counter;
}
};
run_loop(setup);
EXPECT_EQ(counter, 6);
}
TEST(TtyTest, stdoutNoClose) {
uint64_t counter = 0;
auto setup = [&](const Loop &loop) -> Promise<void> {
TtyStream stdout = TtyStream::stdout(loop);
co_await stdout.write(" ");
++counter;
};
run_loop(setup);
EXPECT_EQ(counter, 1);
}
TEST(TtyTest, invalidFd) {
auto setup = [](const Loop &loop) -> Promise<void> {
EXPECT_THROW({ TtyStream tty = TtyStream::tty(loop, -1); }, UvcoException);
co_return;
};
run_loop(setup);
}
TEST(TtyTest, closeWhileReading) {
auto setup = [](const Loop &loop) -> Promise<void> {
TtyStream tty = TtyStream::stdin(loop);
Promise<std::optional<std::string>> reader = tty.read();
tty.close();
EXPECT_FALSE((co_await reader).has_value());
};
run_loop(setup);
}
TEST(PipeTest, pipePingPong) {
auto setup = [](const Loop &loop) -> Promise<void> {
auto [read, write] = pipe(loop);
co_await write.write("Hello\n");
co_await write.write("Hello");
EXPECT_EQ(co_await read.read(), std::make_optional("Hello\nHello"));
read.close();
write.close();
};
run_loop(setup);
}
TEST(PipeTest, doubleReadDies) {
auto setup = [](const Loop &loop) -> Promise<void> {
auto [read, write] = pipe(loop);
Promise<std::optional<std::string>> readPromise = read.read();
EXPECT_THROW({ co_await read.read(); }, UvcoException);
read.close();
write.close();
};
run_loop(setup);
}
TEST(PipeTest, largeWriteRead) {
std::ifstream urandom("/dev/urandom", std::ios::binary);
std::array<char, 1024> buffer{};
urandom.read(buffer.data(), buffer.size());
auto setup = [&](const Loop &loop) -> Promise<void> {
auto [read, write] = pipe(loop);
for (unsigned i = 0; i < 10; ++i) {
co_await write.write(
std::string(buffer.data(), buffer.size()));
}
write.close();
[[maybe_unused]]
size_t bytesRead{};
while (true) {
// Read random chunk size.
auto chunk = co_await read.read(732);
if (!chunk.has_value()) {
break;
}
bytesRead += chunk->size();
}
BOOST_ASSERT(bytesRead == 10240);
read.close();
};
run_loop(setup);
}
TEST(PipeTest, readIntoBuffer) {
auto setup = [](const Loop &loop) -> Promise<void> {
auto [read, write] = pipe(loop);
co_await write.write("Hello");
std::array<char, 32> buffer{};
size_t bytesRead = co_await read.read(buffer);
EXPECT_EQ(bytesRead, 5);
EXPECT_EQ(std::string(buffer.data(), bytesRead), "Hello");
read.close();
write.close();
};
run_loop(setup);
}
} // namespace