Line data Source code
1 : // Copyright (c) 2012-2022 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/eventdispatcher
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 :
20 : // self
21 : //
22 : #include "catch_main.h"
23 :
24 :
25 : // cppprocess lib
26 : //
27 : #include <cppprocess/io_capture_pipe.h>
28 : #include <cppprocess/io_data_pipe.h>
29 : #include <cppprocess/io_input_file.h>
30 : #include <cppprocess/io_output_file.h>
31 : #include <cppprocess/process.h>
32 :
33 :
34 : // snapdev lib
35 : //
36 : #include <snapdev/file_contents.h>
37 :
38 :
39 : // C++ lib
40 : //
41 : #include <fstream>
42 :
43 :
44 : // last include
45 : //
46 : #include <snapdev/poison.h>
47 :
48 :
49 :
50 8 : CATCH_TEST_CASE("Process", "[process]")
51 : {
52 12 : CATCH_START_SECTION("simple cat")
53 : {
54 2 : cppprocess::process p("simple-cat");
55 :
56 1 : CATCH_REQUIRE(p.get_name() == "simple-cat");
57 :
58 1 : CATCH_REQUIRE_FALSE(p.get_forced_environment());
59 1 : p.set_forced_environment(true);
60 1 : CATCH_REQUIRE(p.get_forced_environment());
61 1 : p.set_forced_environment(false);
62 1 : CATCH_REQUIRE_FALSE(p.get_forced_environment());
63 :
64 1 : CATCH_REQUIRE(p.get_command() == std::string());
65 1 : p.set_command("cat");
66 1 : CATCH_REQUIRE(p.get_command() == "cat");
67 :
68 1 : CATCH_REQUIRE(p.get_arguments().empty());
69 1 : p.add_argument("/proc/self/comm");
70 1 : CATCH_REQUIRE(p.get_arguments().size() == 1);
71 :
72 1 : CATCH_REQUIRE(p.get_environ().empty());
73 :
74 1 : CATCH_REQUIRE(p.get_input_io() == nullptr);
75 1 : CATCH_REQUIRE(p.get_output_io() == nullptr);
76 1 : CATCH_REQUIRE(p.get_error_io() == nullptr);
77 :
78 2 : cppprocess::io_capture_pipe::pointer_t capture(std::make_shared<cppprocess::io_capture_pipe>());
79 1 : p.set_output_io(capture);
80 1 : CATCH_REQUIRE(p.get_output_io() == capture);
81 :
82 1 : CATCH_REQUIRE(p.get_next_processes().empty());
83 :
84 1 : CATCH_REQUIRE(p.start() == 0);
85 :
86 1 : int const code(p.wait());
87 1 : CATCH_REQUIRE(code == 0);
88 :
89 1 : CATCH_REQUIRE(p.get_input_io() == nullptr);
90 1 : CATCH_REQUIRE(p.get_output_io() == capture);
91 1 : CATCH_REQUIRE(p.get_error_io() == nullptr);
92 :
93 1 : CATCH_REQUIRE(capture->get_output() == "cat\n");
94 1 : CATCH_REQUIRE(capture->get_trimmed_output() == "cat");
95 :
96 2 : cppprocess::buffer_t const output(capture->get_binary_output());
97 1 : CATCH_REQUIRE(output.size() == 4);
98 1 : CATCH_REQUIRE(output[0] == 'c');
99 1 : CATCH_REQUIRE(output[1] == 'a');
100 1 : CATCH_REQUIRE(output[2] == 't');
101 1 : CATCH_REQUIRE(output[3] == '\n');
102 : }
103 : CATCH_END_SECTION()
104 :
105 12 : CATCH_START_SECTION("simple logger, we pipe the input as the message")
106 : {
107 2 : cppprocess::process p("in-logger");
108 :
109 1 : CATCH_REQUIRE(p.get_name() == "in-logger");
110 :
111 1 : CATCH_REQUIRE(p.get_command() == std::string());
112 1 : p.set_command("logger");
113 1 : CATCH_REQUIRE(p.get_command() == "logger");
114 :
115 1 : CATCH_REQUIRE(p.get_arguments().empty());
116 :
117 1 : CATCH_REQUIRE(p.get_environ().empty());
118 :
119 1 : CATCH_REQUIRE(p.get_input_io() == nullptr);
120 1 : CATCH_REQUIRE(p.get_output_io() == nullptr);
121 1 : CATCH_REQUIRE(p.get_error_io() == nullptr);
122 :
123 2 : cppprocess::io_data_pipe::pointer_t input(std::make_shared<cppprocess::io_data_pipe>());
124 1 : CATCH_REQUIRE_FALSE(input->is_writer());
125 1 : input->add_input("Event Dispatcher Process Test\n");
126 1 : CATCH_REQUIRE(input->is_writer());
127 :
128 1 : CATCH_REQUIRE(input->get_input() == std::string("Event Dispatcher Process Test\n"));
129 1 : CATCH_REQUIRE(input->get_binary_input().size() == 30);
130 :
131 1 : p.set_input_io(input);
132 1 : CATCH_REQUIRE(p.get_input_io() == input);
133 :
134 1 : CATCH_REQUIRE(p.start() == 0);
135 :
136 1 : int const code(p.wait());
137 1 : CATCH_REQUIRE(code == 0);
138 : }
139 : CATCH_END_SECTION()
140 :
141 12 : CATCH_START_SECTION("in | sed | out")
142 : {
143 2 : cppprocess::process p("in-sed-out");
144 :
145 1 : CATCH_REQUIRE(p.get_name() == "in-sed-out");
146 :
147 1 : CATCH_REQUIRE_FALSE(p.get_forced_environment());
148 1 : p.set_forced_environment(true);
149 1 : CATCH_REQUIRE(p.get_forced_environment());
150 1 : p.set_forced_environment(false);
151 1 : CATCH_REQUIRE_FALSE(p.get_forced_environment());
152 :
153 1 : CATCH_REQUIRE(p.get_command() == std::string());
154 1 : p.set_command("sed");
155 1 : CATCH_REQUIRE(p.get_command() == "sed");
156 :
157 1 : CATCH_REQUIRE(p.get_arguments().empty());
158 1 : p.add_argument("-e");
159 1 : p.add_argument("s/Hello/Hi/");
160 1 : p.add_argument("-");
161 1 : CATCH_REQUIRE(p.get_arguments().size() == 3);
162 :
163 1 : CATCH_REQUIRE(p.get_environ().empty());
164 :
165 1 : CATCH_REQUIRE(p.get_input_io() == nullptr);
166 1 : CATCH_REQUIRE(p.get_output_io() == nullptr);
167 1 : CATCH_REQUIRE(p.get_error_io() == nullptr);
168 :
169 2 : cppprocess::io_data_pipe::pointer_t input(std::make_shared<cppprocess::io_data_pipe>());
170 1 : CATCH_REQUIRE_FALSE(input->is_writer());
171 1 : input->add_input("Hello World!\n");
172 1 : CATCH_REQUIRE(input->is_writer());
173 :
174 1 : CATCH_REQUIRE(input->get_input() == std::string("Hello World!\n"));
175 1 : CATCH_REQUIRE(input->get_binary_input().size() == 14);
176 :
177 1 : p.set_input_io(input);
178 1 : CATCH_REQUIRE(p.get_input_io() == input);
179 :
180 2 : cppprocess::io_capture_pipe::pointer_t capture(std::make_shared<cppprocess::io_capture_pipe>());
181 1 : p.set_output_io(capture);
182 1 : CATCH_REQUIRE(p.get_output_io() == capture);
183 :
184 1 : CATCH_REQUIRE(capture->get_output().empty());
185 1 : CATCH_REQUIRE(capture->get_trimmed_output().empty());
186 1 : CATCH_REQUIRE(capture->get_binary_output().empty());
187 1 : CATCH_REQUIRE(p.get_next_processes().empty());
188 :
189 1 : CATCH_REQUIRE(p.start() == 0);
190 :
191 1 : int const code(p.wait());
192 1 : CATCH_REQUIRE(code == 0);
193 :
194 1 : CATCH_REQUIRE(capture->get_output() == "Hi World!\n");
195 1 : CATCH_REQUIRE(capture->get_trimmed_output(true) == "Hi World!");
196 :
197 2 : cppprocess::buffer_t const output(capture->get_binary_output());
198 1 : CATCH_REQUIRE(output.size() == 11);
199 1 : CATCH_REQUIRE(output[ 0] == 'H');
200 1 : CATCH_REQUIRE(output[ 1] == 'i');
201 1 : CATCH_REQUIRE(output[ 2] == ' ');
202 1 : CATCH_REQUIRE(output[ 3] == ' ');
203 1 : CATCH_REQUIRE(output[ 4] == 'W');
204 1 : CATCH_REQUIRE(output[ 5] == 'o');
205 1 : CATCH_REQUIRE(output[ 6] == 'r');
206 1 : CATCH_REQUIRE(output[ 7] == 'l');
207 1 : CATCH_REQUIRE(output[ 8] == 'd');
208 1 : CATCH_REQUIRE(output[ 9] == '!');
209 1 : CATCH_REQUIRE(output[10] == '\n');
210 : }
211 : CATCH_END_SECTION()
212 :
213 12 : CATCH_START_SECTION("ls unknown-file, expect an error")
214 : {
215 2 : cppprocess::process p("ls-unknown-file");
216 :
217 1 : CATCH_REQUIRE(p.get_name() == "ls-unknown-file");
218 :
219 1 : p.set_command("ls");
220 1 : CATCH_REQUIRE(p.get_command() == "ls");
221 :
222 1 : p.add_argument("unknown-file");
223 1 : CATCH_REQUIRE(p.get_arguments().size() == 1);
224 :
225 1 : CATCH_REQUIRE(p.get_environ().empty());
226 :
227 2 : cppprocess::io_capture_pipe::pointer_t error(std::make_shared<cppprocess::io_capture_pipe>());
228 1 : p.set_error_io(error);
229 1 : CATCH_REQUIRE(p.get_error_io() == error);
230 :
231 1 : CATCH_REQUIRE(error->get_output().empty());
232 1 : CATCH_REQUIRE(error->get_trimmed_output().empty());
233 1 : CATCH_REQUIRE(error->get_binary_output().empty());
234 :
235 1 : CATCH_REQUIRE(p.start() == 0);
236 :
237 1 : int const code(p.wait());
238 1 : CATCH_REQUIRE(code != 0);
239 :
240 1 : CATCH_REQUIRE(p.get_output_io() == nullptr);
241 1 : CATCH_REQUIRE(p.get_error_io() == error);
242 :
243 1 : CATCH_REQUIRE_FALSE(error->get_output().empty());
244 : // the error message can change under our feet so at this time
245 : // do not compare to a specific message
246 : }
247 : CATCH_END_SECTION()
248 :
249 12 : CATCH_START_SECTION("cat | tr")
250 : {
251 2 : cppprocess::process::pointer_t tr(std::make_shared<cppprocess::process>("tr"));
252 1 : tr->set_command("tr");
253 1 : tr->add_argument("TASP");
254 1 : tr->add_argument("tasp");
255 :
256 2 : cppprocess::io_data_pipe::pointer_t input(std::make_shared<cppprocess::io_data_pipe>());
257 1 : CATCH_REQUIRE_FALSE(input->is_writer());
258 1 : input->add_input("Test A Simple Pipeline\n");
259 1 : CATCH_REQUIRE(input->is_writer());
260 :
261 2 : cppprocess::io_capture_pipe::pointer_t capture(std::make_shared<cppprocess::io_capture_pipe>());
262 1 : tr->set_output_io(capture);
263 1 : CATCH_REQUIRE(tr->get_output_io() == capture);
264 :
265 2 : cppprocess::process p("cat");
266 1 : p.set_command("cat");
267 1 : p.add_argument("-");
268 1 : p.set_input_io(input);
269 1 : CATCH_REQUIRE(p.get_input_io() == input);
270 1 : p.add_next_process(tr);
271 :
272 1 : CATCH_REQUIRE(p.start() == 0);
273 :
274 1 : int const code(p.wait());
275 1 : CATCH_REQUIRE(code == 0);
276 :
277 1 : CATCH_REQUIRE(capture->get_output() == "test a simple pipeline\n");
278 : }
279 : CATCH_END_SECTION()
280 :
281 12 : CATCH_START_SECTION("file based: cat | tr")
282 : {
283 : // Equivalent to:
284 : //
285 : // cat - < input.data | tr TASP tasp > output.data
286 : //
287 1 : std::string & tmpdir(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
288 2 : std::string const input_filename(tmpdir + "/input.data");
289 2 : std::string const output_filename(tmpdir + "/output.data");
290 : {
291 2 : std::ofstream input_data(input_filename);
292 1 : input_data << "Test A Simple Pipeline\n";
293 : }
294 :
295 2 : cppprocess::process::pointer_t tr(std::make_shared<cppprocess::process>("tr"));
296 1 : tr->set_command("tr");
297 1 : tr->add_argument("TASP");
298 1 : tr->add_argument("tasp");
299 :
300 2 : cppprocess::io_output_file::pointer_t output(std::make_shared<cppprocess::io_output_file>(output_filename));
301 1 : output->set_truncate(true);
302 1 : tr->set_output_io(output);
303 :
304 : // we could directly cat the file here, obviously but we want
305 : // to test the `< <filename>` functionality
306 : //
307 2 : cppprocess::process p("cat");
308 1 : p.set_command("cat");
309 1 : p.add_argument("-");
310 :
311 2 : cppprocess::io_input_file::pointer_t input(std::make_shared<cppprocess::io_input_file>(input_filename));
312 1 : p.set_input_io(input);
313 :
314 1 : p.add_next_process(tr);
315 :
316 1 : CATCH_REQUIRE(p.start() == 0);
317 :
318 1 : int const code(p.wait());
319 1 : CATCH_REQUIRE(code == 0);
320 :
321 2 : snapdev::file_contents final_output(output_filename);
322 1 : CATCH_REQUIRE(final_output.read_all());
323 1 : CATCH_REQUIRE(final_output.contents() == "test a simple pipeline\n");
324 : }
325 : CATCH_END_SECTION()
326 12 : }
327 :
328 :
329 : // vim: ts=4 sw=4 et
|