LCOV - code coverage report
Current view: top level - tests - catch_process.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 193 193
Test Date: 2025-05-30 15:24:13 Functions: 100.0 % 1 1
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright (c) 2012-2024  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
      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
      35              : //
      36              : #include    <snapdev/file_contents.h>
      37              : 
      38              : 
      39              : // C++
      40              : //
      41              : #include    <fstream>
      42              : 
      43              : 
      44              : // last include
      45              : //
      46              : #include    <snapdev/poison.h>
      47              : 
      48              : 
      49              : 
      50            6 : CATCH_TEST_CASE("Process", "[process]")
      51              : {
      52            6 :     CATCH_START_SECTION("simple cat")
      53              :     {
      54            3 :         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            3 :         p.set_command("cat");
      66            1 :         CATCH_REQUIRE(p.get_command() == "cat");
      67              : 
      68            1 :         CATCH_REQUIRE(p.get_arguments().empty());
      69            3 :         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            1 :         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            1 :         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            1 :     }
     103            6 :     CATCH_END_SECTION()
     104              : 
     105            6 :     CATCH_START_SECTION("simple logger, we pipe the input as the message")
     106              :     {
     107            3 :         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            3 :         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            1 :         cppprocess::io_data_pipe::pointer_t input(std::make_shared<cppprocess::io_data_pipe>());
     124            1 :         CATCH_REQUIRE_FALSE(input->is_writer());
     125            3 :         input->add_input("Event Dispatcher Process Test\n");
     126            1 :         CATCH_REQUIRE(input->is_writer());
     127              : 
     128            3 :         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            1 :     }
     139            6 :     CATCH_END_SECTION()
     140              : 
     141            6 :     CATCH_START_SECTION("in | sed | out")
     142              :     {
     143            3 :         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            3 :         p.set_command("sed");
     155            1 :         CATCH_REQUIRE(p.get_command() == "sed");
     156              : 
     157            1 :         CATCH_REQUIRE(p.get_arguments().empty());
     158            3 :         p.add_argument("-e");
     159            3 :         p.add_argument("s/Hello/Hi/");
     160            3 :         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            1 :         cppprocess::io_data_pipe::pointer_t input(std::make_shared<cppprocess::io_data_pipe>());
     170            1 :         CATCH_REQUIRE_FALSE(input->is_writer());
     171            3 :         input->add_input("Hello  World!\n");
     172            1 :         CATCH_REQUIRE(input->is_writer());
     173              : 
     174            3 :         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            1 :         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            1 :         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            1 :     }
     211            6 :     CATCH_END_SECTION()
     212              : 
     213            6 :     CATCH_START_SECTION("ls unknown-file, expect an error")
     214              :     {
     215            3 :         cppprocess::process p("ls-unknown-file");
     216              : 
     217            1 :         CATCH_REQUIRE(p.get_name() == "ls-unknown-file");
     218              : 
     219            3 :         p.set_command("ls");
     220            1 :         CATCH_REQUIRE(p.get_command() == "ls");
     221              : 
     222            3 :         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            1 :         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            1 :     }
     247            6 :     CATCH_END_SECTION()
     248              : 
     249            6 :     CATCH_START_SECTION("cat | tr")
     250              :     {
     251            1 :         cppprocess::process::pointer_t tr(std::make_shared<cppprocess::process>("tr"));
     252            3 :         tr->set_command("tr");
     253            3 :         tr->add_argument("TASP");
     254            3 :         tr->add_argument("tasp");
     255              : 
     256            1 :         cppprocess::io_data_pipe::pointer_t input(std::make_shared<cppprocess::io_data_pipe>());
     257            1 :         CATCH_REQUIRE_FALSE(input->is_writer());
     258            3 :         input->add_input("Test A Simple Pipeline\n");
     259            1 :         CATCH_REQUIRE(input->is_writer());
     260              : 
     261            1 :         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            3 :         cppprocess::process p("cat");
     266            3 :         p.set_command("cat");
     267            3 :         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            1 :     }
     279            6 :     CATCH_END_SECTION()
     280              : 
     281            6 :     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            1 :         std::string const input_filename(tmpdir + "/input.data");
     289            1 :         std::string const output_filename(tmpdir + "/output.data");
     290              :         {
     291            1 :             std::ofstream input_data(input_filename);
     292            1 :             input_data << "Test A Simple Pipeline\n";
     293            1 :         }
     294              : 
     295            1 :         cppprocess::process::pointer_t tr(std::make_shared<cppprocess::process>("tr"));
     296            3 :         tr->set_command("tr");
     297            3 :         tr->add_argument("TASP");
     298            3 :         tr->add_argument("tasp");
     299              : 
     300            1 :         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            3 :         cppprocess::process p("cat");
     308            3 :         p.set_command("cat");
     309            3 :         p.add_argument("-");
     310              : 
     311            1 :         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            1 :         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            1 :     }
     325            6 :     CATCH_END_SECTION()
     326            6 : }
     327              : 
     328              : 
     329              : // vim: ts=4 sw=4 et
        

Generated by: LCOV version 2.0-1

Snap C++ | List of projects | List of versions