class Process {
+public:
+ using Arguments = std::vector<std::string>;
+ using Environment = std::vector<std::string>;
+
public:
/// launch process executing the file at given path with
/// given arguments and environment
Process(
const std::string &path,
- const std::vector<std::string> &args,
- const std::vector<std::string> &env);
+ const Arguments &args,
+ const Environment &env);
~Process();
public:
Impl(
const string &path_in,
- const vector<string> &args,
- const vector<string> &env);
+ const Arguments &args,
+ const Environment &env);
~Impl();
size_t WriteIn(const void *buffer, size_t max_len);
Process::Process(
const string &path,
- const vector<string> &args,
- const vector<string> &env)
+ const Arguments &args,
+ const Environment &env)
: impl(new Impl(path, args, env))
, joined(false)
, status(0) {
Process::Impl::Impl(
const string &path_in,
- const vector<string> &args,
- const vector<string> &env
+ const Arguments &args,
+ const Environment &env
) {
const char *path = path_in.c_str();
char *envp[env.size() + 1];
--- /dev/null
+#include "InvocationTest.hpp"
+
+#include "TestInstance.hpp"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(blank::test::InvocationTest);
+
+
+namespace blank {
+namespace test {
+
+void InvocationTest::setUp() {
+
+}
+
+void InvocationTest::tearDown() {
+
+}
+
+
+void InvocationTest::testUnknownArg() {
+ TestInstance prog({ "--worscht" });
+ prog.AssertErrorLine("unknown option --worscht");
+ prog.AssertExitStatus(1);
+}
+
+}
+}
--- /dev/null
+#ifndef BLANK_TEST_INTEGRATION_INVOCATIONTEST_HPP_
+#define BLANK_TEST_INTEGRATION_INVOCATIONTEST_HPP_
+
+#include <cppunit/extensions/HelperMacros.h>
+
+
+namespace blank {
+namespace test {
+
+class InvocationTest
+: public CppUnit::TestFixture {
+
+CPPUNIT_TEST_SUITE(InvocationTest);
+
+CPPUNIT_TEST(testUnknownArg);
+
+CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp();
+ void tearDown();
+
+ void testUnknownArg();
+
+};
+
+}
+}
+
+#endif
#include "ServerTest.hpp"
-#include "TestServer.hpp"
+#include "TestInstance.hpp"
CPPUNIT_TEST_SUITE_REGISTRATION(blank::test::ServerTest);
void ServerTest::testStartup() {
- TestServer server;
+ TestInstance server({ "--server" }, true);
}
}
--- /dev/null
+#include "TestInstance.hpp"
+
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+
+namespace blank {
+namespace test {
+
+namespace {
+
+Process::Arguments combine_args(const TempDir &dir, const Process::Arguments &in, bool cmd) {
+ Process::Arguments out;
+ out.reserve(in.size() + (cmd ? 5 : 3));
+ out.emplace_back("blank");
+ out.insert(out.end(), in.begin(), in.end());
+ out.emplace_back("--save-path");
+ out.emplace_back(dir.Path());
+ if (cmd) {
+ out.emplace_back("--cmd-port");
+ out.emplace_back("12354");
+ }
+ return out;
+}
+
+}
+
+TestInstance::TestInstance(const Process::Arguments &args, bool cmd)
+: dir()
+, proc(
+ "./blank" BLANK_SUFFIX,
+ combine_args(dir, args, cmd),
+ { })
+, conn()
+, out_buf()
+, err_buf()
+, cmd_buf() {
+ if (cmd) {
+ // wait for command service startup
+ // TODO: timeouts for reading from process
+ WaitOutputLine("listening on TCP port 12354");
+ // connect to command service
+ conn = tcp::Socket("localhost", 12354);
+ }
+}
+
+TestInstance::~TestInstance() {
+ proc.Terminate();
+}
+
+
+void TestInstance::WriteInput(const string &data) {
+ const char *i = data.c_str();
+ const char *end = i + data.length();
+ while (i != end) {
+ size_t len = proc.WriteIn(i, end - i);
+ i += len;
+ }
+}
+
+void TestInstance::ReadOutputLine(string &line) {
+ while (!out_buf.Extract(line)) {
+ // buffer exhausted, fetch more data
+ out_buf.Update(proc.ReadOut(out_buf.WriteHead(), out_buf.Remain()));
+ }
+}
+
+void TestInstance::AssertOutputLine(const string &expected) {
+ string line;
+ ReadOutputLine(line);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(
+ "unexpected line in stdout",
+ expected, line);
+}
+
+void TestInstance::WaitOutputLine(const string &expected) {
+ string line;
+ while (true) {
+ ReadOutputLine(line);
+ if (line == expected) {
+ return;
+ }
+ }
+}
+
+void TestInstance::ReadErrorLine(string &line) {
+ while (!err_buf.Extract(line)) {
+ // buffer exhausted, fetch more data
+ err_buf.Update(proc.ReadErr(err_buf.WriteHead(), err_buf.Remain()));
+ }
+}
+
+void TestInstance::AssertErrorLine(const string &expected) {
+ string line;
+ ReadErrorLine(line);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(
+ "unexpected line in stderr",
+ expected, line);
+}
+
+void TestInstance::WaitErrorLine(const string &expected) {
+ string line;
+ while (true) {
+ ReadErrorLine(line);
+ if (line == expected) {
+ return;
+ }
+ }
+}
+
+
+void TestInstance::AssertExitStatus(int expected) {
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(
+ "unexpected line in stderr",
+ expected, proc.Join());
+}
+
+
+void TestInstance::WaitCommandMessage(const string &line) {
+ WaitCommandLine(" > " + line);
+}
+
+void TestInstance::WaitCommandError(const string &line) {
+ WaitCommandLine(" ! " + line);
+}
+
+void TestInstance::WaitCommandBroadcast(const string &line) {
+ WaitCommandLine(" @ " + line);
+}
+
+void TestInstance::WaitCommandLine(const string &expected) {
+ string line;
+ while (true) {
+ if (!cmd_buf.Extract(line)) {
+ // buffer exhausted, fetch more data
+ cmd_buf.Update(conn.Recv(cmd_buf.WriteHead(), cmd_buf.Remain()));
+ continue;
+ }
+ if (line == expected) {
+ return;
+ }
+ }
+}
+
+}
+}
--- /dev/null
+#ifndef BLANK_TEST_INTEGRATION_TESTINSTANCE_HPP_
+#define BLANK_TEST_INTEGRATION_TESTINSTANCE_HPP_
+
+#include "app/Process.hpp"
+#include "io/filesystem.hpp"
+#include "io/LineBuffer.hpp"
+#include "net/tcp.hpp"
+
+
+namespace blank {
+namespace test {
+
+class TestInstance {
+
+public:
+ /// Launch a blank instance with given arguments (program name
+ /// will be prepended by the constructor).
+ /// If connect is true, a command service connection will be
+ /// established during construction.
+ explicit TestInstance(const Process::Arguments &args, bool connect = false);
+ ~TestInstance();
+
+public:
+ /// Write given text to program's stdin.
+ /// Data is not modified, so if you want to push a line, be
+ /// sure to include a newline character.
+ void WriteInput(const std::string &data);
+
+ /// read next line from programs stdout
+ void ReadOutputLine(std::string &line);
+ /// assert that the next line the program writes to stdout will
+ /// be the given one (without a trailing newline character)
+ void AssertOutputLine(const std::string &line);
+ /// wait until program writes given line to stdout
+ void WaitOutputLine(const std::string &line);
+
+ /// read next line from programs stderr
+ void ReadErrorLine(std::string &line);
+ /// assert that the next line the program writes to stderr will
+ /// be the given one (without a trailing newline character)
+ void AssertErrorLine(const std::string &line);
+ /// wait until program writes given line to stderr
+ void WaitErrorLine(const std::string &line);
+
+ /// make sure the process terminated with given status
+ void AssertExitStatus(int expected);
+
+ // the following methods are only valid when a command service is connected
+
+ /// wait for given message on the command service
+ void WaitCommandMessage(const std::string &line);
+ /// wait for given error on the command service
+ void WaitCommandError(const std::string &line);
+ /// wait for given broadcast on the command service
+ void WaitCommandBroadcast(const std::string &line);
+ /// wait for given line on the command service
+ void WaitCommandLine(const std::string &line);
+
+ /// send command line to program
+ void SendCommand(const std::string &);
+
+private:
+ TempDir dir;
+ Process proc;
+ tcp::Socket conn;
+ size_t head;
+ LineBuffer<BUFSIZ> out_buf;
+ LineBuffer<BUFSIZ> err_buf;
+ LineBuffer<BUFSIZ> cmd_buf;
+
+};
+
+}
+}
+
+#endif
+++ /dev/null
-#include "TestServer.hpp"
-
-#include <iostream>
-
-
-namespace blank {
-namespace test {
-
-TestServer::TestServer()
-: dir()
-, proc(
- "./blank" BLANK_SUFFIX,
- { "blank", "--server", "--save-path", dir.Path(), "--cmd-port", "12354" },
- { })
-, conn()
-, serv_buf()
-, sock_buf() {
- // wait for command service startup
- // TODO: timeouts for reading from process
- WaitOutputLine("listening on TCP port 12354");
- // connect to command service
- conn = tcp::Socket("localhost", 12354);
-}
-
-TestServer::~TestServer() {
- proc.Terminate();
-}
-
-
-void TestServer::WaitOutputLine(const std::string &expected) {
- std::string line;
- while (true) {
- if (!serv_buf.Extract(line)) {
- // buffer exhausted, fetch more data
- serv_buf.Update(proc.ReadOut(serv_buf.WriteHead(), serv_buf.Remain()));
- continue;
- }
- if (line == expected) {
- return;
- } else {
- std::cerr << "ignoring line: " << line << std::endl;
- }
- }
-}
-
-void TestServer::WaitCommandMessage(const std::string &line) {
- WaitCommandLine(" > " + line);
-}
-
-void TestServer::WaitCommandError(const std::string &line) {
- WaitCommandLine(" ! " + line);
-}
-
-void TestServer::WaitCommandBroadcast(const std::string &line) {
- WaitCommandLine(" @ " + line);
-}
-
-void TestServer::WaitCommandLine(const std::string &expected) {
- std::string line;
- while (true) {
- if (!serv_buf.Extract(line)) {
- // buffer exhausted, fetch more data
- serv_buf.Update(conn.Recv(serv_buf.WriteHead(), serv_buf.Remain()));
- continue;
- }
- if (line == expected) {
- return;
- }
- }
-}
-
-}
-}
+++ /dev/null
-#ifndef BLANK_TEST_INTEGRATION_TESTSERVER_HPP_
-#define BLANK_TEST_INTEGRATION_TESTSERVER_HPP_
-
-#include "app/Process.hpp"
-#include "io/filesystem.hpp"
-#include "io/LineBuffer.hpp"
-#include "net/tcp.hpp"
-
-
-namespace blank {
-namespace test {
-
-class TestServer {
-
-public:
- TestServer();
- ~TestServer();
-
-public:
- /// wait until server writes given line to stdout
- void WaitOutputLine(const std::string &line);
-
- /// wait for given message on the command service
- void WaitCommandMessage(const std::string &line);
- /// wait for given error on the command service
- void WaitCommandError(const std::string &line);
- /// wait for given broadcast on the command service
- void WaitCommandBroadcast(const std::string &line);
- /// wait for given line on the command service
- void WaitCommandLine(const std::string &line);
-
- /// send command line to server
- void SendCommand(const std::string &);
-
-private:
- TempDir dir;
- Process proc;
- tcp::Socket conn;
- size_t head;
- LineBuffer<BUFSIZ> serv_buf;
- LineBuffer<BUFSIZ> sock_buf;
-
-};
-
-}
-}
-
-#endif