@@ -36,6 +36,14 @@ The following functions are available in your tests (see below for detailed docu
3636* `assert_not_matches <unexpected-regex> <actual> [message]`
3737* `assert_within_delta <expected num> <actual num> <max delta> [message]`
3838* `assert_no_diff <expected> <actual> [message]`
39+ * `run <command> [args...]`
40+ * `assert_run_success [message]`
41+ * `assert_run_fails [message]`
42+ * `assert_run_status_code <expected_status_code> [message]`
43+ * `assert_run_output_equals <expected> [message]`
44+ * `assert_run_output_matches <expected-regex> [message]`
45+ * `assert_run_error_equals <expected> [message]`
46+ * `assert_run_error_matches <expected-regex> [message]`
3947* `skip_if <condition> <pattern>`
4048* `fake <command> [replacement code]`
4149
@@ -189,6 +197,22 @@ Running tests in tests/test_core.sh
189197 Running test_assert_not_equals_succeeds_when_not_equal ... SUCCESS
190198 Running test_assert_not_matches_fails_when_matching ... SUCCESS
191199 Running test_assert_not_matches_succeed_when_not_matching ... SUCCESS
200+ Running test_assert_run_error_equals_fails_when_mismatch ... SUCCESS
201+ Running test_assert_run_error_equals_succeeds ... SUCCESS
202+ Running test_assert_run_error_matches_fails_when_no_match ... SUCCESS
203+ Running test_assert_run_error_matches_succeeds ... SUCCESS
204+ Running test_assert_run_fails_fails_when_zero ... SUCCESS
205+ Running test_assert_run_fails_succeeds ... SUCCESS
206+ Running test_assert_run_output_equals_fails_when_mismatch ... SUCCESS
207+ Running test_assert_run_output_equals_handles_multiline ... SUCCESS
208+ Running test_assert_run_output_equals_succeeds ... SUCCESS
209+ Running test_assert_run_output_matches_fails_when_no_match ... SUCCESS
210+ Running test_assert_run_output_matches_succeeds ... SUCCESS
211+ Running test_assert_run_status_code_fails_when_mismatch ... SUCCESS
212+ Running test_assert_run_status_code_succeeds ... SUCCESS
213+ Running test_assert_run_success_fails_when_nonzero ... SUCCESS
214+ Running test_assert_run_success_shows_custom_message ... SUCCESS
215+ Running test_assert_run_success_succeeds ... SUCCESS
192216 Running test_assert_shows_stderr_on_failure ... SUCCESS
193217 Running test_assert_shows_stdout_on_failure ... SUCCESS
194218 Running test_assert_status_code_fails ... SUCCESS
@@ -205,6 +229,10 @@ Running tests in tests/test_core.sh
205229 Running test_fake_exports_faked_in_subshells ... SUCCESS
206230 Running test_fake_transmits_params_to_fake_code ... SUCCESS
207231 Running test_fake_transmits_params_to_fake_code_as_array ... SUCCESS
232+ Running test_run_clears_previous_state ... SUCCESS
233+ Running test_run_combined_assertions ... SUCCESS
234+ Running test_run_handles_command_with_arguments ... SUCCESS
235+ Running test_run_handles_commands_with_pipes ... SUCCESS
208236 Running test_should_pretty_format_even_when_LANG_is_unset ... SUCCESS
209237 Running test_should_pretty_format_even_with_pipefail_set ... SUCCESS
210238Overall result: SUCCESS
@@ -233,6 +261,22 @@ Running tests in tests/test_core.sh
233261 Running test_assert_not_equals_succeeds_when_not_equal ... SUCCESS
234262 Running test_assert_not_matches_fails_when_matching ... SUCCESS
235263 Running test_assert_not_matches_succeed_when_not_matching ... SUCCESS
264+ Running test_assert_run_error_equals_fails_when_mismatch ... SUCCESS
265+ Running test_assert_run_error_equals_succeeds ... SUCCESS
266+ Running test_assert_run_error_matches_fails_when_no_match ... SUCCESS
267+ Running test_assert_run_error_matches_succeeds ... SUCCESS
268+ Running test_assert_run_fails_fails_when_zero ... SUCCESS
269+ Running test_assert_run_fails_succeeds ... SUCCESS
270+ Running test_assert_run_output_equals_fails_when_mismatch ... SUCCESS
271+ Running test_assert_run_output_equals_handles_multiline ... SUCCESS
272+ Running test_assert_run_output_equals_succeeds ... SUCCESS
273+ Running test_assert_run_output_matches_fails_when_no_match ... SUCCESS
274+ Running test_assert_run_output_matches_succeeds ... SUCCESS
275+ Running test_assert_run_status_code_fails_when_mismatch ... SUCCESS
276+ Running test_assert_run_status_code_succeeds ... SUCCESS
277+ Running test_assert_run_success_fails_when_nonzero ... SUCCESS
278+ Running test_assert_run_success_shows_custom_message ... SUCCESS
279+ Running test_assert_run_success_succeeds ... SUCCESS
236280 Running test_assert_shows_stderr_on_failure ... SUCCESS
237281 Running test_assert_shows_stdout_on_failure ... SUCCESS
238282 Running test_assert_status_code_fails ... SUCCESS
@@ -241,6 +285,7 @@ Running tests in tests/test_core.sh
241285 Running test_assert_within_delta_fails ... SUCCESS
242286 Running test_assert_within_delta_succeeds ... SUCCESS
243287 Running test_fail_fails ... SUCCESS
288+ Running test_run_combined_assertions ... SUCCESS
244289Overall result: SUCCESS
245290```
246291
@@ -261,19 +306,41 @@ Running tests in tests/test_core.sh
261306 Running test_assert_not_equals_succeeds_when_not_equal ... SKIPPED
262307 Running test_assert_not_matches_fails_when_matching ... SKIPPED
263308 Running test_assert_not_matches_succeed_when_not_matching ... SKIPPED
309+ Running test_assert_run_error_matches_fails_when_no_match ... SKIPPED
310+ Running test_assert_run_output_matches_fails_when_no_match ... SKIPPED
311+ Running test_assert_run_status_code_fails_when_mismatch ... SKIPPED
312+ Running test_assert_run_status_code_succeeds ... SKIPPED
313+ Running test_assert_run_success_fails_when_nonzero ... SKIPPED
264314 Running test_assert_status_code_fails ... SKIPPED
265315 Running test_assert_status_code_succeeds ... SKIPPED
266316 Running test_assert_equals_succeed_when_equal ... SUCCESS
267317 Running test_assert_fails ... SUCCESS
268318 Running test_assert_fails_fails ... SUCCESS
269319 Running test_assert_fails_succeeds ... SUCCESS
270320 Running test_assert_matches_succeed_when_matching ... SUCCESS
321+ Running test_assert_run_error_equals_fails_when_mismatch ... SUCCESS
322+ Running test_assert_run_error_equals_succeeds ... SUCCESS
323+ Running test_assert_run_error_matches_succeeds ... SUCCESS
324+ Running test_assert_run_fails_fails_when_zero ... SUCCESS
325+ Running test_assert_run_fails_succeeds ... SUCCESS
326+ Running test_assert_run_output_equals_fails_when_mismatch ... SUCCESS
327+ Running test_assert_run_output_equals_handles_multiline ... SUCCESS
328+ Running test_assert_run_output_equals_succeeds ... SUCCESS
329+ Running test_assert_run_output_matches_succeeds ... SUCCESS
330+ Running test_assert_run_success_shows_custom_message ... SUCCESS
331+ Running test_assert_run_success_succeeds ... SUCCESS
271332 Running test_assert_shows_stderr_on_failure ... SUCCESS
272333 Running test_assert_shows_stdout_on_failure ... SUCCESS
273334 Running test_assert_succeeds ... SUCCESS
274335 Running test_assert_within_delta_fails ... SUCCESS
275336 Running test_assert_within_delta_succeeds ... SUCCESS
276337 Running test_fail_fails ... SUCCESS
338+ Running test_run_combined_assertions ... SUCCESS
339+ Overall result: SUCCESS
340+ ```
341+ Running test_assert_within_delta_fails ... SUCCESS
342+ Running test_assert_within_delta_succeeds ... SUCCESS
343+ Running test_fail_fails ... SUCCESS
277344Overall result: SUCCESS
278345```
279346
@@ -299,6 +366,22 @@ ok - test_assert_not_equals_fails_when_equal
299366ok - test_assert_not_equals_succeeds_when_not_equal
300367ok - test_assert_not_matches_fails_when_matching
301368ok - test_assert_not_matches_succeed_when_not_matching
369+ ok - test_assert_run_error_equals_fails_when_mismatch
370+ ok - test_assert_run_error_equals_succeeds
371+ ok - test_assert_run_error_matches_fails_when_no_match
372+ ok - test_assert_run_error_matches_succeeds
373+ ok - test_assert_run_fails_fails_when_zero
374+ ok - test_assert_run_fails_succeeds
375+ ok - test_assert_run_output_equals_fails_when_mismatch
376+ ok - test_assert_run_output_equals_handles_multiline
377+ ok - test_assert_run_output_equals_succeeds
378+ ok - test_assert_run_output_matches_fails_when_no_match
379+ ok - test_assert_run_output_matches_succeeds
380+ ok - test_assert_run_status_code_fails_when_mismatch
381+ ok - test_assert_run_status_code_succeeds
382+ ok - test_assert_run_success_fails_when_nonzero
383+ ok - test_assert_run_success_shows_custom_message
384+ ok - test_assert_run_success_succeeds
302385ok - test_assert_shows_stderr_on_failure
303386ok - test_assert_shows_stdout_on_failure
304387ok - test_assert_status_code_fails
@@ -315,9 +398,13 @@ ok - test_fake_echo_stdin_when_no_params
315398ok - test_fake_exports_faked_in_subshells
316399ok - test_fake_transmits_params_to_fake_code
317400ok - test_fake_transmits_params_to_fake_code_as_array
401+ ok - test_run_clears_previous_state
402+ ok - test_run_combined_assertions
403+ ok - test_run_handles_command_with_arguments
404+ ok - test_run_handles_commands_with_pipes
318405ok - test_should_pretty_format_even_when_LANG_is_unset
319406ok - test_should_pretty_format_even_with_pipefail_set
320- 1..31
407+ 1..51
321408```
322409
323410== How to write tests
@@ -659,6 +746,213 @@ out> > bar
659746doc:2:test_obvious_notmatching_with_assert_no_diff()
660747```
661748
749+ === *run*
750+
751+ run <command> [args...]
752+
753+ Executes _command_ with the given arguments and captures:
754+
755+ * Exit status in `$BASH_UNIT_RUN_STATUS`
756+ * Standard output in `$BASH_UNIT_RUN_OUTPUT`
757+ * Standard error in `$BASH_UNIT_RUN_ERROR`
758+
759+ Each call to `run` clears the previous values, so these variables always contain the results of the most recent command.
760+
761+ Use this function in combination with the `assert_run_*` functions to test command behavior.
762+
763+ === *assert_run_success*
764+
765+ assert_run_success [message]
766+
767+ Asserts that the last command executed with `run` succeeded (exit status 0).
768+
769+ ```test
770+ test_command_succeeds(){
771+ run echo "hello"
772+ assert_run_success
773+ }
774+
775+ test_command_fails_when_expected_success(){
776+ run false
777+ assert_run_success
778+ }
779+ ```
780+
781+ ```output
782+ Running test_command_fails_when_expected_success ... FAILURE
783+ expected run command to succeed but status was 1
784+ doc:8:test_command_fails_when_expected_success()
785+ Running test_command_succeeds ... SUCCESS
786+ ```
787+
788+ === *assert_run_fails*
789+
790+ assert_run_fails [message]
791+
792+ Asserts that the last command executed with `run` failed (exit status not 0).
793+
794+ ```test
795+ test_command_fails(){
796+ run false
797+ assert_run_fails
798+ }
799+
800+ test_command_succeeds_when_expected_failure(){
801+ run true
802+ assert_run_fails
803+ }
804+ ```
805+
806+ ```output
807+ Running test_command_fails ... SUCCESS
808+ Running test_command_succeeds_when_expected_failure ... FAILURE
809+ expected run command to fail but status was 0
810+ doc:8:test_command_succeeds_when_expected_failure()
811+ ```
812+
813+ === *assert_run_status_code*
814+
815+ assert_run_status_code <expected_status_code> [message]
816+
817+ Asserts that the last command executed with `run` exited with a specific status code.
818+
819+ ```test
820+ test_specific_exit_code(){
821+ run sh -c 'exit 42'
822+ assert_run_status_code 42
823+ }
824+
825+ test_wrong_exit_code(){
826+ run sh -c 'exit 1'
827+ assert_run_status_code 0
828+ }
829+ ```
830+
831+ ```output
832+ Running test_specific_exit_code ... SUCCESS
833+ Running test_wrong_exit_code ... FAILURE
834+ expected run command to have status code 0 but was 1
835+ doc:8:test_wrong_exit_code()
836+ ```
837+
838+ === *assert_run_output_equals*
839+
840+ assert_run_output_equals <expected> [message]
841+
842+ Asserts that the standard output from the last `run` command exactly matches _expected_.
843+
844+ ```test
845+ test_output_matches(){
846+ run echo "hello world"
847+ assert_run_output_equals "hello world"
848+ }
849+
850+ test_output_differs(){
851+ run echo "actual"
852+ assert_run_output_equals "expected"
853+ }
854+ ```
855+
856+ ```output
857+ Running test_output_differs ... FAILURE
858+ expected run output [expected] but was [actual]
859+ doc:8:test_output_differs()
860+ Running test_output_matches ... SUCCESS
861+ ```
862+
863+ === *assert_run_output_matches*
864+
865+ assert_run_output_matches <expected-regex> [message]
866+
867+ Asserts that the standard output from the last `run` command matches the given regex pattern.
868+
869+ ```test
870+ test_output_matches_pattern(){
871+ run echo "Error: file not found"
872+ assert_run_output_matches "Error:.*not found"
873+ }
874+
875+ test_output_does_not_match(){
876+ run echo "Success"
877+ assert_run_output_matches "Error:"
878+ }
879+ ```
880+
881+ ```output
882+ Running test_output_does_not_match ... FAILURE
883+ expected run output to match regex [Error:] but was [Success]
884+ doc:8:test_output_does_not_match()
885+ Running test_output_matches_pattern ... SUCCESS
886+ ```
887+
888+ === *assert_run_error_equals*
889+
890+ assert_run_error_equals <expected> [message]
891+
892+ Asserts that the standard error from the last `run` command exactly matches _expected_.
893+
894+ ```test
895+ test_error_matches(){
896+ run sh -c 'echo "error message" >&2'
897+ assert_run_error_equals "error message"
898+ }
899+
900+ test_error_differs(){
901+ run sh -c 'echo "actual error" >&2'
902+ assert_run_error_equals "expected error"
903+ }
904+ ```
905+
906+ ```output
907+ Running test_error_differs ... FAILURE
908+ expected run error [expected error] but was [actual error]
909+ doc:8:test_error_differs()
910+ Running test_error_matches ... SUCCESS
911+ ```
912+
913+ === *assert_run_error_matches*
914+
915+ assert_run_error_matches <expected-regex> [message]
916+
917+ Asserts that the standard error from the last `run` command matches the given regex pattern.
918+
919+ ```test
920+ test_error_matches_pattern(){
921+ run sh -c 'echo "Warning: disk space low" >&2'
922+ assert_run_error_matches "Warning:.*low"
923+ }
924+
925+ test_error_does_not_match(){
926+ run sh -c 'echo "Info: all good" >&2'
927+ assert_run_error_matches "Warning:"
928+ }
929+ ```
930+
931+ ```output
932+ Running test_error_does_not_match ... FAILURE
933+ expected run error to match regex [Warning:] but was [Info: all good]
934+ doc:8:test_error_does_not_match()
935+ Running test_error_matches_pattern ... SUCCESS
936+ ```
937+
938+ === Combined usage example
939+
940+ You can combine multiple assertions to thoroughly test a command's behavior:
941+
942+ ```test
943+ test_complete_command_verification(){
944+ run sh -c 'echo "output"; echo "error" >&2; exit 0'
945+
946+ assert_run_success
947+ assert_run_output_equals "output"
948+ assert_run_error_equals "error"
949+ }
950+ ```
951+
952+ ```output
953+ Running test_complete_command_verification ... SUCCESS
954+ ```
955+
662956== *skip_if* function
663957
664958 skip_if <condition> <pattern>
0 commit comments