LCOV - code coverage report
Current view: top level - src/test - system_tests.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 97.3 % 37 36
Test Date: 2026-02-25 05:45:00 Functions: 100.0 % 4 4
Branches: 48.5 % 202 98

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2019-present The Bitcoin Core developers
       2                 :             : // Distributed under the MIT software license, see the accompanying
       3                 :             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4                 :             : //
       5                 :             : 
       6                 :             : #include <bitcoin-build-config.h> // IWYU pragma: keep
       7                 :             : 
       8                 :             : #include <common/run_command.h>
       9                 :             : #include <test/util/setup_common.h>
      10                 :             : #include <univalue.h>
      11                 :             : #include <util/string.h>
      12                 :             : 
      13                 :             : #ifdef ENABLE_EXTERNAL_SIGNER
      14                 :             : #include <util/subprocess.h>
      15                 :             : #endif // ENABLE_EXTERNAL_SIGNER
      16                 :             : 
      17                 :             : #include <boost/test/unit_test.hpp>
      18                 :             : 
      19                 :             : BOOST_FIXTURE_TEST_SUITE(system_tests, BasicTestingSetup)
      20                 :             : 
      21                 :             : #ifdef ENABLE_EXTERNAL_SIGNER
      22                 :             : 
      23   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(run_command)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
      24                 :             : {
      25                 :           1 :     {
      26         [ +  - ]:           1 :         const UniValue result = RunCommandParseJSON({});
      27   [ +  -  +  - ]:           2 :         BOOST_CHECK(result.isNull());
      28                 :           1 :     }
      29                 :           1 :     {
      30                 :             : #ifdef WIN32
      31                 :             :         const UniValue result = RunCommandParseJSON({"cmd.exe", "/c", "echo", "{\"success\":", "true}"}); // The command is intentionally split "incorrectly", to exactly preserve previous behavior. This is due to the cmd.exe internal echo quoting strings with spaces in it, unlike the normal 'echo' below.
      32                 :             : #else
      33   [ +  -  +  - ]:           1 :         const UniValue result = RunCommandParseJSON({"echo", "{\"success\": true}"});
      34                 :             : #endif
      35   [ +  -  +  -  :           2 :         BOOST_CHECK(result.isObject());
                   +  - ]
      36         [ +  - ]:           1 :         const UniValue& success = result.find_value("success");
      37   [ +  -  +  -  :           2 :         BOOST_CHECK(!success.isNull());
                   +  - ]
      38   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(success.get_bool(), true);
                   +  - ]
      39                 :           1 :     }
      40                 :           1 :     {
      41                 :             :         // An invalid command is handled by cpp-subprocess
      42                 :             : #ifdef WIN32
      43                 :             :         const std::string expected{"CreateProcess failed: "};
      44                 :             : #else
      45                 :           1 :         const std::string expected{"execve failed: "};
      46                 :             : #endif
      47   [ +  -  +  -  :           3 :         BOOST_CHECK_EXCEPTION(RunCommandParseJSON({"invalid_command"}), subprocess::CalledProcessError, HasReason(expected));
          +  -  -  +  -  
          -  -  -  -  +  
          +  -  -  +  +  
                -  +  - ]
      48                 :           0 :     }
      49                 :           1 :     {
      50                 :             :         // Return non-zero exit code, no output to stderr
      51                 :             : #ifdef WIN32
      52                 :             :         const std::vector<std::string> command = {"cmd.exe", "/c", "exit 1"};
      53                 :             : #else
      54                 :           1 :         const std::vector<std::string> command = {"false"};
      55                 :             : #endif
      56   [ +  -  +  -  :           6 :         BOOST_CHECK_EXCEPTION(RunCommandParseJSON(command), std::runtime_error, [&](const std::runtime_error& e) {
          +  +  +  -  -  
          -  -  +  +  -  
             +  -  +  - ]
      57                 :             :             const std::string what{e.what()};
      58                 :             :             BOOST_CHECK(what.find(strprintf("RunCommandParseJSON error: process(%s) returned 1: \n", util::Join(command, " "))) != std::string::npos);
      59                 :             :             return true;
      60                 :             :         });
      61                 :           1 :     }
      62                 :           1 :     {
      63                 :             :         // Return non-zero exit code, with error message for stderr
      64                 :             : #ifdef WIN32
      65                 :             :         const std::vector<std::string> command = {"cmd.exe", "/c", "echo err 1>&2 && exit 1"};
      66                 :             : #else
      67                 :           1 :         const std::vector<std::string> command = {"sh", "-c", "echo err 1>&2 && false"};
      68                 :             : #endif
      69         [ +  - ]:           1 :         const std::string expected{"err"};
      70   [ +  -  +  -  :           8 :         BOOST_CHECK_EXCEPTION(RunCommandParseJSON(command), std::runtime_error, [&](const std::runtime_error& e) {
          +  +  +  -  +  
          -  -  +  +  -  
             +  -  +  - ]
      71                 :             :             const std::string what(e.what());
      72                 :             :             BOOST_CHECK(what.find(strprintf("RunCommandParseJSON error: process(%s) returned %s: %s", util::Join(command, " "), 1, "err")) != std::string::npos);
      73                 :             :             BOOST_CHECK(what.find(expected) != std::string::npos);
      74                 :             :             return true;
      75                 :             :         });
      76                 :           1 :     }
      77                 :           1 :     {
      78                 :             :         // Unable to parse JSON
      79                 :             : #ifdef WIN32
      80                 :             :         const std::vector<std::string> command = {"cmd.exe", "/c", "echo {"};
      81                 :             : #else
      82                 :           1 :         const std::vector<std::string> command = {"echo", "{"};
      83                 :             : #endif
      84   [ +  -  +  -  :           3 :         BOOST_CHECK_EXCEPTION(RunCommandParseJSON(command), std::runtime_error, HasReason("Unable to parse JSON: {"));
          -  +  -  -  -  
          -  -  +  +  -  
             +  -  +  - ]
      85                 :           1 :     }
      86                 :             : #ifndef WIN32
      87                 :           1 :     {
      88                 :             :         // Test stdin
      89   [ +  -  +  - ]:           1 :         const UniValue result = RunCommandParseJSON({"cat"}, "{\"success\": true}");
      90   [ +  -  +  -  :           2 :         BOOST_CHECK(result.isObject());
                   +  - ]
      91         [ +  - ]:           1 :         const UniValue& success = result.find_value("success");
      92   [ +  -  +  -  :           2 :         BOOST_CHECK(!success.isNull());
                   +  - ]
      93   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(success.get_bool(), true);
                   +  - ]
      94                 :           1 :     }
      95                 :             : #endif
      96                 :           1 : }
      97                 :             : #endif // ENABLE_EXTERNAL_SIGNER
      98                 :             : 
      99                 :             : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1