diff --git a/libs/core/test/assert_exit_code b/libs/core/test/assert_exit_code index 4c75a4b..039f706 100644 --- a/libs/core/test/assert_exit_code +++ b/libs/core/test/assert_exit_code @@ -15,6 +15,8 @@ # limitations under the License. # +#include core/test/run_without_exit_on_error + # core::test::assert_exit_code # Asserts that a command exits with a specific exit code. # @@ -37,8 +39,8 @@ function core::test::assert_exit_code() { local expectedCode=${1:-${expectedCode:?must be set}} shift - "$@" &>/dev/null - local actualCode=$? + local actualCode + actualCode=$(core::test::run_without_exit_on_error "$@") if [[ $actualCode -eq $expectedCode ]]; then echo "✅ Assertion passed: command '$*' exited with status $actualCode" diff --git a/libs/core/test/assert_failure b/libs/core/test/assert_failure index b691115..975a87a 100644 --- a/libs/core/test/assert_failure +++ b/libs/core/test/assert_failure @@ -15,6 +15,8 @@ # limitations under the License. # +#include core/test/run_without_exit_on_error + # core::test::assert_failure # Asserts that a command exits with a non-zero exit code. # @@ -33,12 +35,12 @@ # core::test::assert_failure ls /nonexistent function core::test::assert_failure() { local exitCode - if ! "$@" &>/dev/null; then - exitCode=$? + exitCode=$(core::test::run_without_exit_on_error "$@") + + if [[ $exitCode -ne 0 ]]; then echo "✅ Assertion passed: command '$*' exited with status $exitCode" return 0 else - exitCode=$? echo "⛔ Assertion failed: command '$*' exited with status $exitCode (expected non-zero)" >&2 return 1 fi diff --git a/libs/core/test/assert_success b/libs/core/test/assert_success index 6c77cc9..820e758 100644 --- a/libs/core/test/assert_success +++ b/libs/core/test/assert_success @@ -15,6 +15,8 @@ # limitations under the License. # +#include core/test/run_without_exit_on_error + # core::test::assert_success # Asserts that a command exits successfully (exit code 0). # @@ -32,12 +34,12 @@ # core::test::assert_success ls /tmp function core::test::assert_success() { local exitCode - if "$@" &>/dev/null; then - exitCode=0 + exitCode=$(core::test::run_without_exit_on_error "$@") + + if [[ $exitCode -eq 0 ]]; then echo "✅ Assertion passed: command '$*' exited with status $exitCode" return 0 else - exitCode=$? echo "⛔ Assertion failed: command '$*' exited with status $exitCode (expected 0)" >&2 return 1 fi diff --git a/libs/core/test/run_without_exit_on_error b/libs/core/test/run_without_exit_on_error new file mode 100644 index 0000000..7509bbc --- /dev/null +++ b/libs/core/test/run_without_exit_on_error @@ -0,0 +1,69 @@ +# shellcheck shell=bash +# +# Copyright 2025 The Linux Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# core::test::run_without_exit_on_error +# Executes a command with 'set -e' and 'set -u' temporarily disabled, then restores the original state. +# +# Description: +# This helper function temporarily disables the 'set -e' (errexit) and 'set -u' (nounset) +# shell options before executing a command, allowing the command to return any exit code +# and reference undefined variables without causing the shell to exit. After execution, +# it restores the original shell option states and outputs the exit code to stdout. +# The function itself always returns 0 to prevent triggering 'set -e'. +# This is particularly useful in test assertions that need to capture and validate +# specific exit codes. +# +# Usage: +# exitCode=$(core::test::run_without_exit_on_error [args...]) +# +# Parameters: +# command - The command or function to execute. +# args... - Optional arguments to pass to the command. +# +# Outputs: +# The exit code of the executed command (to stdout). +# +# Example: +# exitCode=$(core::test::run_without_exit_on_error some_command arg1 arg2) +function core::test::run_without_exit_on_error() { + local restoreExitOnError=false + local restoreUnsetVarError=false + + if [[ $- =~ e ]]; then + restoreExitOnError=true + fi + + if [[ $- =~ u ]]; then + restoreUnsetVarError=true + fi + + set +e + set +u + "$@" &>/dev/null + local exitCode=$? + + if [[ $restoreExitOnError == true ]]; then + set -e + fi + + if [[ $restoreUnsetVarError == true ]]; then + set -u + fi + + echo "$exitCode" + return 0 +}