From 1a8d578cdacbff191a0580c30b1d55521a2d499e Mon Sep 17 00:00:00 2001 From: Daniel Ruthardt Date: Fri, 14 Nov 2025 10:56:30 +0100 Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=90=9B=20Fix=20assert=5Fexit=5Fcode,?= =?UTF-8?q?=20improve=20exit=20code=20handling=20for=20all?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/core/test/assert_exit_code | 10 ++++++++++ libs/core/test/assert_failure | 18 ++++++++++++++---- libs/core/test/assert_success | 18 ++++++++++++++---- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/libs/core/test/assert_exit_code b/libs/core/test/assert_exit_code index 4c75a4b..40ba0f6 100644 --- a/libs/core/test/assert_exit_code +++ b/libs/core/test/assert_exit_code @@ -37,8 +37,18 @@ function core::test::assert_exit_code() { local expectedCode=${1:-${expectedCode:?must be set}} shift + local restoreExitOnError=false + if [[ $- =~ e ]]; then + restoreExitOnError=true + fi + + set +e "$@" &>/dev/null local actualCode=$? + + if [[ $restoreExitOnError == true ]]; then + set -e + fi 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..b569e72 100644 --- a/libs/core/test/assert_failure +++ b/libs/core/test/assert_failure @@ -32,13 +32,23 @@ # Example: # core::test::assert_failure ls /nonexistent function core::test::assert_failure() { - local exitCode - if ! "$@" &>/dev/null; then - exitCode=$? + local restoreExitOnError=false + if [[ $- =~ e ]]; then + restoreExitOnError=true + fi + + set +e + "$@" &>/dev/null + local exitCode=$? + + if [[ $restoreExitOnError == true ]]; then + set -e + fi + + 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..321f6d0 100644 --- a/libs/core/test/assert_success +++ b/libs/core/test/assert_success @@ -31,13 +31,23 @@ # Example: # core::test::assert_success ls /tmp function core::test::assert_success() { - local exitCode - if "$@" &>/dev/null; then - exitCode=0 + local restoreExitOnError=false + if [[ $- =~ e ]]; then + restoreExitOnError=true + fi + + set +e + "$@" &>/dev/null + local exitCode=$? + + if [[ $restoreExitOnError == true ]]; then + set -e + fi + + 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 From 1c2c46e55a7990cf8a2359538bea999d2fe7a915 Mon Sep 17 00:00:00 2001 From: Daniel Ruthardt Date: Fri, 14 Nov 2025 11:03:31 +0100 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=8E=A8=20Remove=20trailing=20whitespa?= =?UTF-8?q?ce?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- libs/core/test/assert_exit_code | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/core/test/assert_exit_code b/libs/core/test/assert_exit_code index 40ba0f6..d5b6db7 100644 --- a/libs/core/test/assert_exit_code +++ b/libs/core/test/assert_exit_code @@ -45,7 +45,6 @@ function core::test::assert_exit_code() { set +e "$@" &>/dev/null local actualCode=$? - if [[ $restoreExitOnError == true ]]; then set -e fi From 707f00ca2cacae62be739d8f98c704395af776ab Mon Sep 17 00:00:00 2001 From: Daniel Ruthardt Date: Fri, 14 Nov 2025 11:03:51 +0100 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=8E=A8=20Remove=20trailing=20whitespa?= =?UTF-8?q?ce?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- libs/core/test/assert_success | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/core/test/assert_success b/libs/core/test/assert_success index 321f6d0..aa5bc37 100644 --- a/libs/core/test/assert_success +++ b/libs/core/test/assert_success @@ -39,7 +39,6 @@ function core::test::assert_success() { set +e "$@" &>/dev/null local exitCode=$? - if [[ $restoreExitOnError == true ]]; then set -e fi From 92a47669436008663049bc5a486dba1faa33da00 Mon Sep 17 00:00:00 2001 From: Daniel Ruthardt Date: Fri, 14 Nov 2025 11:03:59 +0100 Subject: [PATCH 4/5] =?UTF-8?q?=F0=9F=8E=A8=20Remove=20trailing=20whitespa?= =?UTF-8?q?ce?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- libs/core/test/assert_failure | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/core/test/assert_failure b/libs/core/test/assert_failure index b569e72..ddb43ef 100644 --- a/libs/core/test/assert_failure +++ b/libs/core/test/assert_failure @@ -40,7 +40,6 @@ function core::test::assert_failure() { set +e "$@" &>/dev/null local exitCode=$? - if [[ $restoreExitOnError == true ]]; then set -e fi From 3442ab944caeb731f44fdeb902cad91431d4046c Mon Sep 17 00:00:00 2001 From: Daniel Ruthardt Date: Fri, 14 Nov 2025 11:14:12 +0100 Subject: [PATCH 5/5] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor,=20improve,?= =?UTF-8?q?=20and=20centralize=20exit=20code=20handling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/core/test/assert_exit_code | 15 ++---- libs/core/test/assert_failure | 15 ++---- libs/core/test/assert_success | 15 ++---- libs/core/test/run_without_exit_on_error | 69 ++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 33 deletions(-) create mode 100644 libs/core/test/run_without_exit_on_error diff --git a/libs/core/test/assert_exit_code b/libs/core/test/assert_exit_code index d5b6db7..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,17 +39,8 @@ function core::test::assert_exit_code() { local expectedCode=${1:-${expectedCode:?must be set}} shift - local restoreExitOnError=false - if [[ $- =~ e ]]; then - restoreExitOnError=true - fi - - set +e - "$@" &>/dev/null - local actualCode=$? - if [[ $restoreExitOnError == true ]]; then - set -e - fi + 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 ddb43ef..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. # @@ -32,17 +34,8 @@ # Example: # core::test::assert_failure ls /nonexistent function core::test::assert_failure() { - local restoreExitOnError=false - if [[ $- =~ e ]]; then - restoreExitOnError=true - fi - - set +e - "$@" &>/dev/null - local exitCode=$? - if [[ $restoreExitOnError == true ]]; then - set -e - fi + local exitCode + exitCode=$(core::test::run_without_exit_on_error "$@") if [[ $exitCode -ne 0 ]]; then echo "✅ Assertion passed: command '$*' exited with status $exitCode" diff --git a/libs/core/test/assert_success b/libs/core/test/assert_success index aa5bc37..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). # @@ -31,17 +33,8 @@ # Example: # core::test::assert_success ls /tmp function core::test::assert_success() { - local restoreExitOnError=false - if [[ $- =~ e ]]; then - restoreExitOnError=true - fi - - set +e - "$@" &>/dev/null - local exitCode=$? - if [[ $restoreExitOnError == true ]]; then - set -e - fi + local exitCode + exitCode=$(core::test::run_without_exit_on_error "$@") if [[ $exitCode -eq 0 ]]; then echo "✅ Assertion passed: command '$*' exited with status $exitCode" 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 +}