mirror of
https://github.com/arun11299/cpp-subprocess.git
synced 2025-09-16 18:54:39 -04:00
Compare commits
57 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ad47657ddd | ||
![]() |
60d4ad8d52 | ||
![]() |
777cfa77d1 | ||
![]() |
f6232a7f26 | ||
![]() |
9974ff69cd | ||
![]() |
625a877579 | ||
![]() |
ed313971c0 | ||
![]() |
98a88e2499 | ||
![]() |
38d98d9d20 | ||
![]() |
778543b2f2 | ||
![]() |
34033d03de | ||
![]() |
04b015a8e5 | ||
![]() |
2d8a8eebb0 | ||
![]() |
beda7b5244 | ||
![]() |
3afe581c1f | ||
![]() |
4025693dec | ||
![]() |
40cd59c097 | ||
![]() |
40bcc2daa9 | ||
![]() |
06858e5fd7 | ||
![]() |
d19cce111c | ||
![]() |
46d2b244c4 | ||
![]() |
d809374661 | ||
![]() |
64f4dfc2e5 | ||
![]() |
5a8adeb758 | ||
![]() |
af23f33880 | ||
![]() |
d9ed0d606f | ||
![]() |
1392c47cbb | ||
![]() |
cbc9e82158 | ||
![]() |
399616b408 | ||
![]() |
2ef9f168d3 | ||
![]() |
bf4289c1a0 | ||
![]() |
2bec886e79 | ||
![]() |
0218c51b8c | ||
![]() |
fa58db9d6e | ||
![]() |
5f43a237dc | ||
![]() |
718d0c816a | ||
![]() |
dafa7dd36b | ||
![]() |
2f6bb248c6 | ||
![]() |
f1a698b50e | ||
![]() |
a458bcfc4a | ||
![]() |
9c624ce4e3 | ||
![]() |
126ee2978f | ||
![]() |
a5cc965f72 | ||
![]() |
6931e3d69f | ||
![]() |
3ab04aecaa | ||
![]() |
785ff230a8 | ||
![]() |
f6799fcc34 | ||
![]() |
871577770a | ||
![]() |
5d92f48492 | ||
![]() |
de5f791d04 | ||
![]() |
3e29149ad1 | ||
![]() |
e6cb89cb6e | ||
![]() |
d74481c564 | ||
![]() |
7ebcd80c05 | ||
![]() |
ced3d53e3a | ||
![]() |
0894e7f6db | ||
![]() |
899e9b997d |
20
.editorconfig
Normal file
20
.editorconfig
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# EditorConfig is awesome: http://EditorConfig.org
|
||||||
|
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# Unix-style newlines with a newline ending every file
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
|
||||||
|
[*.{c,cppi,cc,h,hpp}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
# Tab indentation (no size specified)
|
||||||
|
[Makefile,makefile,GNUmakefile]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
#[*.{js,py}]
|
76
.github/workflows/cmake-multi-platform.yml
vendored
Normal file
76
.github/workflows/cmake-multi-platform.yml
vendored
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# This starter workflow is for a CMake project running on multiple platforms. There is a different starter workflow if you just want a single platform.
|
||||||
|
# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml
|
||||||
|
name: CMake on multiple platforms
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "master" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "master" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
# Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable.
|
||||||
|
fail-fast: false
|
||||||
|
|
||||||
|
# Set up a matrix to run the following 3 configurations:
|
||||||
|
# 1. <Windows, Debug, latest MSVC compiler toolchain on the default runner image, default generator>
|
||||||
|
# 2. <Linux, Debug, latest GCC compiler toolchain on the default runner image, default generator>
|
||||||
|
# 3. <Linux, Debug, latest Clang compiler toolchain on the default runner image, default generator>
|
||||||
|
#
|
||||||
|
# To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the build_type list.
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
build_type: [Debug]
|
||||||
|
c_compiler: [gcc, clang, cl]
|
||||||
|
include:
|
||||||
|
- os: windows-latest
|
||||||
|
c_compiler: cl
|
||||||
|
cpp_compiler: cl
|
||||||
|
- os: ubuntu-latest
|
||||||
|
c_compiler: gcc
|
||||||
|
cpp_compiler: g++
|
||||||
|
- os: ubuntu-latest
|
||||||
|
c_compiler: clang
|
||||||
|
cpp_compiler: clang++
|
||||||
|
exclude:
|
||||||
|
- os: windows-latest
|
||||||
|
c_compiler: gcc
|
||||||
|
- os: windows-latest
|
||||||
|
c_compiler: clang
|
||||||
|
- os: ubuntu-latest
|
||||||
|
c_compiler: cl
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set reusable strings
|
||||||
|
# Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file.
|
||||||
|
id: strings
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
|
||||||
|
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
|
||||||
|
run: >
|
||||||
|
cmake -B ${{ steps.strings.outputs.build-output-dir }}
|
||||||
|
-DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }}
|
||||||
|
-DCMAKE_C_COMPILER=${{ matrix.c_compiler }}
|
||||||
|
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
|
||||||
|
-DSUBPROCESS_TESTS=ON
|
||||||
|
-S ${{ github.workspace }}
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
# Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator).
|
||||||
|
run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }}
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
working-directory: ${{ steps.strings.outputs.build-output-dir }}
|
||||||
|
# Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator).
|
||||||
|
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
|
||||||
|
run: ctest --build-config ${{ matrix.build_type }} --timeout 10 -j4
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
build
|
||||||
|
.vscode
|
63
CMakeLists.txt
Normal file
63
CMakeLists.txt
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
project(subprocess VERSION 2.2 LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 11 CACHE STRING "C++ standard to use")
|
||||||
|
option(EXPORT_COMPILE_COMMANDS "create clang compile database" ON)
|
||||||
|
option(SUBPROCESS_TESTS "enable subprocess tests" OFF)
|
||||||
|
option(SUBPROCESS_INSTALL "enable subprocess install" OFF)
|
||||||
|
|
||||||
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
|
add_library(subprocess INTERFACE)
|
||||||
|
target_link_libraries(subprocess INTERFACE Threads::Threads)
|
||||||
|
target_sources(subprocess PUBLIC
|
||||||
|
FILE_SET HEADERS
|
||||||
|
FILES
|
||||||
|
cpp-subprocess/subprocess.hpp
|
||||||
|
BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/
|
||||||
|
)
|
||||||
|
add_library(cpp-subprocess::subprocess ALIAS subprocess)
|
||||||
|
|
||||||
|
if(SUBPROCESS_INSTALL)
|
||||||
|
install(
|
||||||
|
TARGETS subprocess COMPONENT subprocess
|
||||||
|
EXPORT subprocess
|
||||||
|
FILE_SET HEADERS DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
|
|
||||||
|
configure_package_config_file(
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/subprocess-config.cmake.in"
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/subprocess-config.cmake"
|
||||||
|
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/subprocess"
|
||||||
|
PATH_VARS PROJECT_NAME PROJECT_VERSION
|
||||||
|
)
|
||||||
|
|
||||||
|
write_basic_package_version_file(
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/beman.exemplar-version.cmake"
|
||||||
|
VERSION ${PROJECT_VERSION}
|
||||||
|
COMPATIBILITY ExactVersion
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/subprocess-config.cmake"
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/subprocess-version.cmake"
|
||||||
|
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/subprocess"
|
||||||
|
COMPONENT subprocess
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
EXPORT subprocess
|
||||||
|
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/beman.exemplar"
|
||||||
|
NAMESPACE cpp-subprocess::
|
||||||
|
FILE subprocess-targets.cmake
|
||||||
|
COMPONENT subprocess
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(SUBPROCESS_TESTS)
|
||||||
|
include(CTest)
|
||||||
|
add_subdirectory(test)
|
||||||
|
endif()
|
27
README.md
27
README.md
@ -1,4 +1,4 @@
|
|||||||
![Subprocessing in C++]
|
## [Subprocessing in C++]
|
||||||
|
|
||||||
## Design Goals
|
## Design Goals
|
||||||
The only goal was to develop something that is as close as python2.7 subprocess module in dealing with processes.
|
The only goal was to develop something that is as close as python2.7 subprocess module in dealing with processes.
|
||||||
@ -13,14 +13,16 @@ This library had these design goals:
|
|||||||
|
|
||||||
|
|
||||||
## Supported Platforms
|
## Supported Platforms
|
||||||
Unlike python2.7 subprocess module, this library currently only supports MAC OS and Linux.
|
This library supports MAC OS and Linux.
|
||||||
It has no support for Windows in its current state.
|
|
||||||
|
Support for Windows is limited at this time. Please report any specific use-cases that fail,
|
||||||
|
and they will be fixed as they are reported.
|
||||||
|
|
||||||
## Integration
|
## Integration
|
||||||
Subprocess library has just a single source `subprocess.hpp` present at the top directory of this repository. All you need to do is add
|
Subprocess library has just a single source `subprocess.hpp` present at the top directory of this repository. All you need to do is add
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
#inlcude "subprocess.hpp"
|
#include "cpp-subprocess/subprocess.hpp"
|
||||||
|
|
||||||
using namespace subprocess;
|
using namespace subprocess;
|
||||||
// OR
|
// OR
|
||||||
@ -31,9 +33,24 @@ to the files where you want to make use of subprocessing. Make sure to add neces
|
|||||||
|
|
||||||
Checkout http://templated-thoughts.blogspot.in/2016/03/sub-processing-with-modern-c.html as well.
|
Checkout http://templated-thoughts.blogspot.in/2016/03/sub-processing-with-modern-c.html as well.
|
||||||
|
|
||||||
|
## CMake Projects
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(
|
||||||
|
cpp-subprocess
|
||||||
|
GIT_REPOSITORY https://github.com/arun11299/cpp-subprocess.git
|
||||||
|
GIT_TAG v2.2
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(cpp-subprocess)
|
||||||
|
|
||||||
|
target_link_libraries(<your_target> PRIVATE cpp-subprocess::subprocess)
|
||||||
|
```
|
||||||
|
|
||||||
## Compiler Support
|
## Compiler Support
|
||||||
Linux - g++ 4.8 and above
|
Linux - g++ 4.8 and above
|
||||||
Mac OS - Clang 3.4 and later
|
Mac OS - Clang 3.4 and later
|
||||||
|
Windows - MSVC 2015 and above
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
Here are few examples to show how to get started:
|
Here are few examples to show how to get started:
|
||||||
@ -48,7 +65,7 @@ std::cout << "Data len: " << obuf.length << std::endl;
|
|||||||
|
|
||||||
More detailed way:
|
More detailed way:
|
||||||
```cpp
|
```cpp
|
||||||
auto p = Popen({"ls", "-l"});
|
auto p = Popen({"ls", "-l"}, output{PIPE});
|
||||||
auto obuf = p.communicate().first;
|
auto obuf = p.communicate().first;
|
||||||
std::cout << "Data : " << obuf.buf.data() << std::endl;
|
std::cout << "Data : " << obuf.buf.data() << std::endl;
|
||||||
std::cout << "Data len: " << obuf.length << std::endl;
|
std::cout << "Data len: " << obuf.length << std::endl;
|
||||||
|
7
cmake/subprocess-config.cmake
Normal file
7
cmake/subprocess-config.cmake
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
set(SUBPROCESS_VERSION @PROJECT_VERSION@)
|
||||||
|
|
||||||
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
|
include(${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake)
|
||||||
|
|
||||||
|
check_required_components(@PROJECT_NAME@)
|
913
subprocess.hpp → cpp-subprocess/subprocess.hpp
Executable file → Normal file
913
subprocess.hpp → cpp-subprocess/subprocess.hpp
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
35
test/CMakeLists.txt
Normal file
35
test/CMakeLists.txt
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
set(test_names test_subprocess test_cat test_double_quotes test_env test_err_redirection test_exception test_split test_main test_ret_code)
|
||||||
|
set(test_files env_script.sh write_err.sh write_err.txt)
|
||||||
|
|
||||||
|
|
||||||
|
foreach(test_name IN LISTS test_names)
|
||||||
|
add_executable(${test_name} ${test_name}.cc)
|
||||||
|
target_link_libraries(${test_name} PRIVATE subprocess)
|
||||||
|
|
||||||
|
add_test(
|
||||||
|
NAME ${test_name}
|
||||||
|
COMMAND $<TARGET_FILE:${test_name}>
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
foreach(test_file IN LISTS test_files)
|
||||||
|
configure_file(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/${test_file}
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/${test_file}
|
||||||
|
COPYONLY
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
|
||||||
|
set(TEST_REDIRECTION_PYTHON_SCRIPT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/test_redirection.py)
|
||||||
|
configure_file(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/test_redirection.cc.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/test_redirection.cc
|
||||||
|
@ONLY
|
||||||
|
)
|
||||||
|
add_executable(test_redirection ${CMAKE_CURRENT_BINARY_DIR}/test_redirection.cc)
|
||||||
|
target_link_libraries(test_redirection PRIVATE subprocess)
|
||||||
|
add_test(
|
||||||
|
NAME test_redirection
|
||||||
|
COMMAND $<TARGET_FILE:test_redirection>
|
||||||
|
)
|
@ -1 +1 @@
|
|||||||
through stdin to stdoutthrough stdin to stdoutthrough stdin to stdoutthrough stdin to stdout
|
through stdin to stdout
|
@ -1,5 +1,5 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "../subprocess.hpp"
|
#include <cpp-subprocess/subprocess.hpp>
|
||||||
|
|
||||||
namespace sp = subprocess;
|
namespace sp = subprocess;
|
||||||
|
|
||||||
@ -23,6 +23,24 @@ void test_cat_file_redirection()
|
|||||||
std::cout << "END_TEST" << std::endl;
|
std::cout << "END_TEST" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_cat_send_terminate()
|
||||||
|
{
|
||||||
|
std::cout << "Test::test_cat_send_terminate" << std::endl;
|
||||||
|
std::vector<sp::Popen> pops;
|
||||||
|
|
||||||
|
for (int i=0; i < 5; i++) {
|
||||||
|
pops.emplace_back(sp::Popen({"cat", "-"}, sp::input{sp::PIPE}));
|
||||||
|
pops[i].send("3 5\n", 5);
|
||||||
|
pops[i].close_input();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i < 5; i++) {
|
||||||
|
pops[i].wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "END_TEST" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
void test_buffer_growth()
|
void test_buffer_growth()
|
||||||
{
|
{
|
||||||
auto obuf = sp::check_output({"cat", "../subprocess.hpp"});
|
auto obuf = sp::check_output({"cat", "../subprocess.hpp"});
|
||||||
@ -40,9 +58,17 @@ void test_buffer_growth_threaded_comm()
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
test_cat_pipe_redirection();
|
#ifndef __USING_WINDOWS__
|
||||||
|
|
||||||
|
// test_cat_pipe_redirection();
|
||||||
|
test_cat_send_terminate();
|
||||||
|
/*
|
||||||
test_cat_file_redirection();
|
test_cat_file_redirection();
|
||||||
test_buffer_growth();
|
test_buffer_growth();
|
||||||
test_buffer_growth_threaded_comm();
|
test_buffer_growth_threaded_comm();
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
30
test/test_double_quotes.cc
Normal file
30
test/test_double_quotes.cc
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include <cpp-subprocess/subprocess.hpp>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace sp = subprocess;
|
||||||
|
|
||||||
|
// JSON requires the use of double quotes (see: https://json.org/).
|
||||||
|
// This test verifies proper handling of them.
|
||||||
|
void test_double_quotes()
|
||||||
|
{
|
||||||
|
// A simple JSON object.
|
||||||
|
const std::string expected{"{\"name\": \"value\"}"};
|
||||||
|
#ifdef __USING_WINDOWS__
|
||||||
|
const std::string command{"cmd.exe /c echo "};
|
||||||
|
#else
|
||||||
|
const std::string command{"echo "};
|
||||||
|
#endif
|
||||||
|
auto p = sp::Popen(command + expected, sp::output{sp::PIPE});
|
||||||
|
const auto out = p.communicate().first;
|
||||||
|
std::string result{out.buf.begin(), out.buf.end()};
|
||||||
|
// The `echo` command appends a newline.
|
||||||
|
result.erase(result.find_last_not_of(" \n\r\t") + 1);
|
||||||
|
assert(result == expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
test_double_quotes();
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1,8 +1,10 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "../subprocess.hpp"
|
#include <cpp-subprocess/subprocess.hpp>
|
||||||
|
|
||||||
using namespace subprocess;
|
using namespace subprocess;
|
||||||
|
|
||||||
|
#ifndef __USING_WINDOWS__
|
||||||
|
|
||||||
void test_env()
|
void test_env()
|
||||||
{
|
{
|
||||||
int st= Popen("./env_script.sh", environment{{
|
int st= Popen("./env_script.sh", environment{{
|
||||||
@ -13,7 +15,11 @@ void test_env()
|
|||||||
assert (st == 0);
|
assert (st == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
#ifndef __USING_WINDOWS__
|
||||||
test_env();
|
test_env();
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "../subprocess.hpp"
|
#include <cpp-subprocess/subprocess.hpp>
|
||||||
|
|
||||||
using namespace subprocess;
|
using namespace subprocess;
|
||||||
|
|
||||||
@ -11,6 +11,8 @@ void test_redirect()
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
#ifndef __USING_WINDOWS__
|
||||||
test_redirect();
|
test_redirect();
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
27
test/test_exception.cc
Normal file
27
test/test_exception.cc
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cpp-subprocess/subprocess.hpp>
|
||||||
|
|
||||||
|
namespace sp = subprocess;
|
||||||
|
|
||||||
|
void test_exception()
|
||||||
|
{
|
||||||
|
bool caught = false;
|
||||||
|
try {
|
||||||
|
auto p = sp::Popen("invalid_command");
|
||||||
|
assert(false); // Expected to throw
|
||||||
|
} catch (sp::CalledProcessError& e) {
|
||||||
|
#ifdef __USING_WINDOWS__
|
||||||
|
assert(std::strstr(e.what(), "CreateProcess failed: The system cannot find the file specified."));
|
||||||
|
#else
|
||||||
|
assert(std::strstr(e.what(), "execve failed: No such file or directory"));
|
||||||
|
#endif
|
||||||
|
caught = true;
|
||||||
|
}
|
||||||
|
assert(caught);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
test_exception();
|
||||||
|
return 0;
|
||||||
|
}
|
23
test/test_redirection.cc.in
Normal file
23
test/test_redirection.cc.in
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#include <cpp-subprocess/subprocess.hpp>
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
using namespace subprocess;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
auto p = Popen("python3 @TEST_REDIRECTION_PYTHON_SCRIPT_PATH@", output{PIPE}, error{PIPE});
|
||||||
|
OutBuffer out_buf;
|
||||||
|
ErrBuffer err_buf;
|
||||||
|
std::tie(out_buf, err_buf) = p.communicate();
|
||||||
|
std::string out{out_buf.buf.data()};
|
||||||
|
std::string err{err_buf.buf.data()};
|
||||||
|
|
||||||
|
if (out.find("Hello message.") == std::string::npos) return EXIT_FAILURE;
|
||||||
|
if (err.find("Hello message.") != std::string::npos) return EXIT_FAILURE;
|
||||||
|
if (out.find("Error report.") != std::string::npos) return EXIT_FAILURE;
|
||||||
|
if (err.find("Error report.") == std::string::npos) return EXIT_FAILURE;
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
7
test/test_redirection.py
Executable file
7
test/test_redirection.py
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("Hello message.")
|
||||||
|
print("Error report.", file=sys.stderr)
|
@ -1,14 +1,26 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "../subprocess.hpp"
|
#include <cpp-subprocess/subprocess.hpp>
|
||||||
|
|
||||||
|
#ifdef __USING_WINDOWS__
|
||||||
|
#include <Windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace sp = subprocess;
|
namespace sp = subprocess;
|
||||||
|
|
||||||
void test_ret_code()
|
void test_ret_code()
|
||||||
{
|
{
|
||||||
std::cout << "Test::test_poll_ret_code" << std::endl;
|
std::cout << "Test::test_poll_ret_code" << std::endl;
|
||||||
|
#ifdef __USING_WINDOWS__
|
||||||
|
auto p = sp::Popen({"cmd.exe", "/c", "exit", "1"});
|
||||||
|
#else
|
||||||
auto p = sp::Popen({"/usr/bin/false"});
|
auto p = sp::Popen({"/usr/bin/false"});
|
||||||
|
#endif
|
||||||
while (p.poll() == -1) {
|
while (p.poll() == -1) {
|
||||||
|
#ifdef __USING_WINDOWS__
|
||||||
|
Sleep(100);
|
||||||
|
#else
|
||||||
usleep(1000 * 100);
|
usleep(1000 * 100);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
assert (p.retcode() == 1);
|
assert (p.retcode() == 1);
|
||||||
}
|
}
|
||||||
@ -25,9 +37,27 @@ void test_ret_code_comm()
|
|||||||
std::cout << "retcode: " << cut.retcode() << std::endl;
|
std::cout << "retcode: " << cut.retcode() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_ret_code_check_output()
|
||||||
|
{
|
||||||
|
using namespace sp;
|
||||||
|
bool caught = false;
|
||||||
|
try {
|
||||||
|
auto obuf = check_output({"/bin/false"}, shell{false});
|
||||||
|
assert(false); // Expected to throw
|
||||||
|
} catch (CalledProcessError &e) {
|
||||||
|
std::cout << "retcode: " << e.retcode << std::endl;
|
||||||
|
assert (e.retcode == 1);
|
||||||
|
caught = true;
|
||||||
|
}
|
||||||
|
assert(caught);
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
test_ret_code();
|
test_ret_code();
|
||||||
|
#ifndef __USING_WINDOWS__
|
||||||
test_ret_code_comm();
|
test_ret_code_comm();
|
||||||
|
test_ret_code_check_output();
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
BIN
test/test_split
BIN
test/test_split
Binary file not shown.
@ -1,11 +1,15 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "../subprocess.hpp"
|
#include <cpp-subprocess/subprocess.hpp>
|
||||||
|
|
||||||
using namespace subprocess;
|
using namespace subprocess;
|
||||||
|
|
||||||
void test_exename()
|
void test_exename()
|
||||||
{
|
{
|
||||||
|
#ifdef __USING_WINDOWS__
|
||||||
|
auto ret = call({"--version"}, executable{"cmake"}, shell{false});
|
||||||
|
#else
|
||||||
auto ret = call({"-l"}, executable{"ls"}, shell{false});
|
auto ret = call({"-l"}, executable{"ls"}, shell{false});
|
||||||
|
#endif
|
||||||
std::cout << ret << std::endl;
|
std::cout << ret << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +39,11 @@ void test_easy_piping()
|
|||||||
|
|
||||||
void test_shell()
|
void test_shell()
|
||||||
{
|
{
|
||||||
auto obuf = check_output({"ls", "-l"}, shell{false});
|
#ifdef __USING_WINDOWS__
|
||||||
|
auto obuf = check_output({"cmake", "--version"}, shell{false});
|
||||||
|
#else
|
||||||
|
auto obuf = check_output({"ls", "-l"}, shell{false});
|
||||||
|
#endif
|
||||||
std::cout << obuf.buf.data() << std::endl;
|
std::cout << obuf.buf.data() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,20 +51,49 @@ void test_sleep()
|
|||||||
{
|
{
|
||||||
auto p = Popen({"sleep", "30"}, shell{true});
|
auto p = Popen({"sleep", "30"}, shell{true});
|
||||||
|
|
||||||
while (p.poll() == -1) {
|
while (p.poll() == -1)
|
||||||
|
{
|
||||||
std::cout << "Waiting..." << std::endl;
|
std::cout << "Waiting..." << std::endl;
|
||||||
|
#ifdef __USING_WINDOWS__
|
||||||
|
#else
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Sleep ended: ret code = " << p.retcode() << std::endl;
|
std::cout << "Sleep ended: ret code = " << p.retcode() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_read_all()
|
||||||
|
{
|
||||||
|
Popen p = Popen({"echo", "12345678"}, output{PIPE});
|
||||||
|
|
||||||
|
std::vector<char> buf(6);
|
||||||
|
int rbytes = util::read_all(p.output(), buf);
|
||||||
|
|
||||||
|
std::string out(buf.begin(), buf.end());
|
||||||
|
|
||||||
|
assert(out == "12345678\n" && rbytes == 9); // echo puts a new line at the end of output
|
||||||
|
std::cout << "read_all() succeeded" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_simple_cmd()
|
||||||
|
{
|
||||||
|
auto p = Popen({"ls", "-l"}, output{PIPE});
|
||||||
|
auto obuf = p.communicate().first;
|
||||||
|
std::cout << "Data : " << obuf.buf.data() << std::endl;
|
||||||
|
std::cout << "Data len: " << obuf.length << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
/*
|
||||||
test_exename();
|
test_exename();
|
||||||
test_input();
|
test_input();
|
||||||
test_piping();
|
test_piping();
|
||||||
test_easy_piping();
|
test_easy_piping();
|
||||||
test_shell();
|
test_shell();
|
||||||
test_sleep();
|
test_sleep();
|
||||||
|
test_read_all();
|
||||||
|
*/
|
||||||
|
test_simple_cmd();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user