]> git.localhorst.tv Git - blank.git/blob - tst/integration/TestInstance.cpp
test missing option arguments
[blank.git] / tst / integration / TestInstance.cpp
1 #include "TestInstance.hpp"
2
3 #include <cppunit/extensions/HelperMacros.h>
4
5 using namespace std;
6
7
8 namespace blank {
9 namespace test {
10
11 namespace {
12
13 Process::Arguments combine_args(
14         const TempDir &dir,
15         const Process::Arguments &in,
16         bool cmd,
17         bool temp_save
18 ) {
19         Process::Arguments out;
20         out.reserve(in.size() + (cmd ? 5 : 3));
21         out.emplace_back("blank");
22         out.insert(out.end(), in.begin(), in.end());
23         if (temp_save) {
24                 out.emplace_back("--save-path");
25                 out.emplace_back(dir.Path());
26         }
27         if (cmd) {
28                 out.emplace_back("--cmd-port");
29                 out.emplace_back("12354");
30         }
31         return out;
32 }
33
34 }
35
36 TestInstance::TestInstance(const Process::Arguments &args, bool cmd, bool temp_save)
37 : dir()
38 , proc("./blank" BLANK_SUFFIX, combine_args(dir, args, cmd, temp_save))
39 , conn()
40 , out_buf()
41 , err_buf()
42 , cmd_buf()
43 , name("blank" BLANK_SUFFIX) {
44         if (cmd) {
45                 // wait for command service startup
46                 WaitOutputLine("listening on TCP port 12354");
47                 // connect to command service
48                 conn = tcp::Socket("localhost", 12354);
49         }
50         for (const auto &arg : args) {
51                 name += ' ';
52                 name += arg;
53         }
54 }
55
56 TestInstance::~TestInstance() {
57         proc.Terminate();
58 }
59
60
61 void TestInstance::WriteInput(const string &data) {
62         AssertRunning();
63         const char *i = data.c_str();
64         const char *end = i + data.length();
65         while (i != end) {
66                 size_t len = proc.WriteIn(i, end - i);
67                 if (len == 0) {
68                         throw runtime_error("failed write to stdin of " + name);
69                 }
70                 i += len;
71         }
72 }
73
74 void TestInstance::ReadOutputLine(string &line) {
75         while (!out_buf.Extract(line)) {
76                 // buffer exhausted, fetch more data
77                 int len = proc.ReadOut(out_buf.WriteHead(), out_buf.Remain(), 10000);
78                 if (len == 0) {
79                         throw runtime_error("failed read from stdout of " + name);
80                 }
81                 out_buf.Update(len);
82         }
83 }
84
85 void TestInstance::AssertOutputLine(const string &expected) {
86         string line;
87         if (past_out.empty()) {
88                 ReadOutputLine(line);
89         } else {
90                 line = past_out.front();
91                 past_out.pop_front();
92         }
93         CPPUNIT_ASSERT_EQUAL_MESSAGE(
94                 "unexpected line in stdout of " + name,
95                 expected, line);
96 }
97
98 void TestInstance::WaitOutputLine(const string &expected) {
99         for (list<string>::iterator i(past_out.begin()); i != past_out.end(); ++i) {
100                 if (*i == expected) {
101                         past_out.erase(i);
102                         return;
103                 }
104         }
105         string line;
106         while (true) {
107                 ReadOutputLine(line);
108                 if (line == expected) {
109                         return;
110                 } else {
111                         past_out.push_back(line);
112                 }
113         }
114 }
115
116 void TestInstance::ExhaustOutput(string &output) {
117         output.clear();
118         for (const auto &line : past_out) {
119                 output += line;
120                 output += '\n';
121         }
122         past_out.clear();
123         string line;
124         while (true) {
125                 if (out_buf.Extract(line)) {
126                         output += line;
127                         output += '\n';
128                 } else {
129                         // buffer exhausted, fetch more data
130                         int len = proc.ReadOut(out_buf.WriteHead(), out_buf.Remain(), 10000);
131                         if (len == 0) {
132                                 // eof
133                                 return;
134                         }
135                         out_buf.Update(len);
136                 }
137         }
138 }
139
140 void TestInstance::AssertNoOutput() {
141         string output;
142         ExhaustOutput(output);
143         CPPUNIT_ASSERT_EQUAL_MESSAGE(
144                 "unexpected output of test instance " + name,
145                 string(""), output);
146 }
147
148
149 void TestInstance::ReadErrorLine(string &line) {
150         while (!err_buf.Extract(line)) {
151                 // buffer exhausted, fetch more data
152                 int len = proc.ReadErr(err_buf.WriteHead(), err_buf.Remain(), 10000);
153                 if (len == 0) {
154                         throw runtime_error("failed read from stderr of " + name);
155                 }
156                 err_buf.Update(len);
157         }
158 }
159
160 void TestInstance::AssertErrorLine(const string &expected) {
161         string line;
162         if (past_err.empty()) {
163                 ReadErrorLine(line);
164         } else {
165                 line = past_err.front();
166                 past_err.pop_front();
167         }
168         CPPUNIT_ASSERT_EQUAL_MESSAGE(
169                 "unexpected line in stderr",
170                 expected, line);
171 }
172
173 void TestInstance::WaitErrorLine(const string &expected) {
174         for (list<string>::iterator i(past_err.begin()); i != past_err.end(); ++i) {
175                 if (*i == expected) {
176                         past_err.erase(i);
177                         return;
178                 }
179         }
180         string line;
181         while (true) {
182                 ReadErrorLine(line);
183                 if (line == expected) {
184                         return;
185                 } else {
186                         past_err.push_back(line);
187                 }
188         }
189 }
190
191 void TestInstance::ExhaustError(string &error) {
192         error.clear();
193         for (const auto &line : past_err) {
194                 error += line;
195                 error += '\n';
196         }
197         past_err.clear();
198         string line;
199         while (true) {
200                 if (err_buf.Extract(line)) {
201                         error += line;
202                         error += '\n';
203                 } else {
204                         // buffer exhausted, fetch more data
205                         int len = proc.ReadErr(err_buf.WriteHead(), err_buf.Remain(), 10000);
206                         if (len == 0) {
207                                 // eof
208                                 return;
209                         }
210                         err_buf.Update(len);
211                 }
212         }
213 }
214
215 void TestInstance::AssertNoError() {
216         string error;
217         ExhaustError(error);
218         CPPUNIT_ASSERT_EQUAL_MESSAGE(
219                 "unexpected error output of test instance " + name,
220                 string(""), error);
221 }
222
223
224 void TestInstance::Terminate() {
225         if (!proc.Terminated()) {
226                 proc.Terminate();
227         }
228 }
229
230 void TestInstance::AssertRunning() {
231         CPPUNIT_ASSERT_MESSAGE(
232                 "test instance " + name + " terminated unexpectedly",
233                 !proc.Terminated());
234 }
235
236 void TestInstance::AssertTerminated() {
237         CPPUNIT_ASSERT_MESSAGE(
238                 "test instance " + name + " did not terminate as expected",
239                 proc.Terminated());
240 }
241
242 void TestInstance::AssertExitStatus(int expected) {
243         CPPUNIT_ASSERT_EQUAL_MESSAGE(
244                 "unexpected exit status from child program " + name,
245                 expected, proc.Join());
246 }
247
248
249 void TestInstance::WaitCommandMessage(const string &line) {
250         WaitCommandLine(" > " + line);
251 }
252
253 void TestInstance::WaitCommandError(const string &line) {
254         WaitCommandLine(" ! " + line);
255 }
256
257 void TestInstance::WaitCommandBroadcast(const string &line) {
258         WaitCommandLine(" @ " + line);
259 }
260
261 void TestInstance::WaitCommandLine(const string &expected) {
262         string line;
263         while (true) {
264                 if (!cmd_buf.Extract(line)) {
265                         // buffer exhausted, fetch more data
266                         cmd_buf.Update(conn.Recv(cmd_buf.WriteHead(), cmd_buf.Remain()));
267                         continue;
268                 }
269                 if (line == expected) {
270                         return;
271                 }
272         }
273 }
274
275 }
276 }