From 23ad95ba19327eb5568d9e223175c9b8a19f24ef Mon Sep 17 00:00:00 2001 From: Mahmood-Sinan Date: Thu, 26 Mar 2026 18:06:54 +0530 Subject: [PATCH 1/3] fix: pass stdin to callback instead or duplicated stderr --- src/system/stdlib_system_subprocess.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/system/stdlib_system_subprocess.F90 b/src/system/stdlib_system_subprocess.F90 index 0d62fdeee..9d13ce5ba 100644 --- a/src/system/stdlib_system_subprocess.F90 +++ b/src/system/stdlib_system_subprocess.F90 @@ -503,7 +503,7 @@ subroutine save_completed_state(process,delete_files) if (associated(process%oncomplete)) & call process%oncomplete(process%id, & process%exit_code, & - process%stderr, & + process%stdin, & process%stdout, & process%stderr, & process%payload) From 83f3352237257678a85dc1554e8c6a3cf7bf9446 Mon Sep 17 00:00:00 2001 From: Mahmood-Sinan Date: Fri, 27 Mar 2026 01:06:19 +0530 Subject: [PATCH 2/3] add test for callback --- test/system/test_subprocess.f90 | 61 +++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/test/system/test_subprocess.f90 b/test/system/test_subprocess.f90 index d025cf5b2..410ec88b5 100644 --- a/test/system/test_subprocess.f90 +++ b/test/system/test_subprocess.f90 @@ -1,9 +1,13 @@ module test_subprocess use testdrive, only : new_unittest, unittest_type, error_type, check, skip_test - use stdlib_system, only: process_type, run, runasync, is_running, wait, update, elapsed, is_windows, kill + use stdlib_system, only: process_type, run, runasync, is_running, wait, update, elapsed, is_windows, kill, process_ID implicit none + type :: payload_wrapper + character(len=20) :: payload(3) ! wrapper type for preserving type info + end type + contains !> Collect all exported unit tests @@ -16,7 +20,8 @@ subroutine collect_suite(testsuite) new_unittest('test_run_asynchronous', test_run_asynchronous), & new_unittest('test_process_kill', test_process_kill), & new_unittest('test_process_state', test_process_state), & - new_unittest('test_input_redirection', test_input_redirection) & + new_unittest('test_input_redirection', test_input_redirection), & + new_unittest('test_callback', test_callback) & ] end subroutine collect_suite @@ -145,6 +150,58 @@ subroutine test_input_redirection(error) end subroutine test_input_redirection + subroutine test_callback(error) + + type(error_type), allocatable, intent(out) :: error + type(process_type) :: process + character(len=:), allocatable :: command + type(payload_wrapper) :: payload_wrapper_ + character(len=*), parameter :: input_string = "test input" + + if (is_windows()) then + command = "sort" + else + command = "cat" + endif + + payload_wrapper_%payload = "" + + process = run(command, stdin=input_string, want_stdout=.true., want_stderr=.true.,& + callback=callback_function, payload=payload_wrapper_) + + call check(error, process%completed, "Process did not complete") + if (allocated(error)) return + call check(error, process%exit_code == 0, "Process exited with non-zero exit code") + if (allocated(error)) return + call check(error, process%stdout == input_string, "Process stdout does not match expected input") + if (allocated(error)) return + call check(error, len_trim(process%stderr) == 0, "Process stderr is not empty") + if (allocated(error)) return + call check(error, trim(payload_wrapper_%payload(1)) == input_string, "Callback stdin mismatch") + if (allocated(error)) return + call check(error, trim(payload_wrapper_%payload(2)) == input_string, "Callback stdout mismatch") + if (allocated(error)) return + call check(error, len_trim(payload_wrapper_%payload(3)) == 0, "Callback stderr is not empty") + if (allocated(error)) return + + end subroutine test_callback + + subroutine callback_function(pid, exitcode, stdin, stdout, stderr, payload) + integer(process_ID), intent(in) :: pid + integer, intent(in) :: exitcode + character(len=*), optional, intent(in) :: stdin, stdout, stderr + class(*), optional, intent(inout) :: payload + + if(present(payload)) then + select type(p=>payload) + type is (payload_wrapper) + if (present(stdin)) p%payload(1) = stdin + if (present(stdout)) p%payload(2) = stdout + if (present(stderr)) p%payload(3) = stderr + end select + end if + + end subroutine callback_function end module test_subprocess program tester From 91be5306fecce080cc1f4e30d42b583b2e723a3c Mon Sep 17 00:00:00 2001 From: Mahmood-Sinan Date: Thu, 2 Apr 2026 23:30:05 +0530 Subject: [PATCH 3/3] minor changes --- test/system/test_subprocess.f90 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/system/test_subprocess.f90 b/test/system/test_subprocess.f90 index 410ec88b5..8f6590846 100644 --- a/test/system/test_subprocess.f90 +++ b/test/system/test_subprocess.f90 @@ -1,6 +1,6 @@ module test_subprocess use testdrive, only : new_unittest, unittest_type, error_type, check, skip_test - use stdlib_system, only: process_type, run, runasync, is_running, wait, update, elapsed, is_windows, kill, process_ID + use stdlib_system, only: process_type, run, runasync, is_running, wait, update, elapsed, is_windows, kill, process_id implicit none @@ -151,7 +151,6 @@ subroutine test_input_redirection(error) end subroutine test_input_redirection subroutine test_callback(error) - type(error_type), allocatable, intent(out) :: error type(process_type) :: process character(len=:), allocatable :: command @@ -187,7 +186,7 @@ subroutine test_callback(error) end subroutine test_callback subroutine callback_function(pid, exitcode, stdin, stdout, stderr, payload) - integer(process_ID), intent(in) :: pid + integer(process_id), intent(in) :: pid integer, intent(in) :: exitcode character(len=*), optional, intent(in) :: stdin, stdout, stderr class(*), optional, intent(inout) :: payload