From 9b0811564df18ab4f84c9ea5f853667086d6fdb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Chastanet?= Date: Fri, 22 Dec 2023 10:06:29 +0100 Subject: [PATCH 1/9] compile scope options variable --- bin/compile | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/bin/compile b/bin/compile index 0f3e15ad..8fdf6c08 100755 --- a/bin/compile +++ b/bin/compile @@ -159,17 +159,17 @@ declare -agx _COMPILE_FILE_ARGUMENTS=() # read command parameters # $@ is all command line parameters passed to the script. -# -o is for short options like -h -# -l is for long options with double dash like --help -# the comma separates different long options +# -o is for short compileOptions like -h +# -l is for long compileOptions with double dash like --help +# the comma separates different long compileOptions longOpts="help,src-dir:,template-dir:,bin-dir:,root-dir:,src-path:,bin-file:,keep-temp-files,verbose,vv,vvv" shortOpts="hks:t:b:r:f:v" -options=$(getopt -l "${longOpts}" -o "${shortOpts}" -a -- "${BASH_FRAMEWORK_ARGV[@]}" 2>/dev/null) || { +compileOptions=$(getopt -l "${longOpts}" -o "${shortOpts}" -a -- "${BASH_FRAMEWORK_ARGV[@]}" 2>/dev/null) || { showHelp - Log::fatal "invalid options specified" + Log::fatal "invalid compileOptions specified" } -eval set -- "${options}" +eval set -- "${compileOptions}" while true; do case $1 in -h | --help) @@ -251,7 +251,7 @@ done # add framework src dir by default srcDirs+=("${_COMPILE_SRC_DIR}") _COMPILE_FILE_ARGUMENTS+=(-s "${_COMPILE_SRC_DIR}") -# add temporary generated functions src dir(Options) +# add temporary generated functions src dir(compileOptions) mkdir -p "${TMPDIR}/src" || true srcDirs+=("${TMPDIR}/src") _COMPILE_FILE_ARGUMENTS+=(-s "${TMPDIR}/src") From 0c866e43e50cdc1666d547b394aa1a0b3853efe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Chastanet?= Date: Fri, 22 Dec 2023 10:09:32 +0100 Subject: [PATCH 2/9] Object::create initial version --- manualTests/Object::create.sh | 44 +++++++++ src/Object/create.bats | 176 ++++++++++++++++++++++++++++++++++ src/Object/create.sh | 126 ++++++++++++++++++++++++ 3 files changed, 346 insertions(+) create mode 100755 manualTests/Object::create.sh create mode 100644 src/Object/create.bats create mode 100644 src/Object/create.sh diff --git a/manualTests/Object::create.sh b/manualTests/Object::create.sh new file mode 100755 index 00000000..4afbaced --- /dev/null +++ b/manualTests/Object::create.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash + +rootDir="$(cd "$(readlink -e "${BASH_SOURCE[0]%/*}")/.." && pwd -P)" +export FRAMEWORK_ROOT_DIR="${rootDir}" +export _COMPILE_ROOT_DIR="${rootDir}" + +srcDir="$(cd "${rootDir}/src" && pwd -P)" + +# shellcheck source=src/Options2/__all.sh +source "${srcDir}/Options2/__all.sh" +# shellcheck source=/src/Log/__all.sh +source "${srcDir}/Log/__all.sh" + + +#set -x +set -o errexit +set -o pipefail +export TMPDIR="/tmp" + +Object::create \ + --type group \ + --property-title "GLOBAL OPTIONS:" \ + --function-name zzzGroupGlobalOptionsFunction + +Object::create \ + --type "Group" \ + --function-name "simpleObjectFunction" + +Object::create \ + --type "Group" \ + --property-title "title" \ + --property-help "help" \ + --function-name "groupObjectFunction" + +BASH_FRAMEWORK_DISPLAY_LEVEL=__LEVEL_DEBUG + +Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableName "varName" + +declare -f optionFunction +set -x +Options2::validateOptionObject optionFunction \ No newline at end of file diff --git a/src/Object/create.bats b/src/Object/create.bats new file mode 100644 index 00000000..90459838 --- /dev/null +++ b/src/Object/create.bats @@ -0,0 +1,176 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2154 +# shellcheck disable=SC2034 + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Object/create.sh +source "${srcDir}/Object/create.sh" +# shellcheck source=src/Assert/posixFunctionName.sh +source "${srcDir}/Assert/posixFunctionName.sh" +# shellcheck source=src/Array/contains.sh +source "${srcDir}/Array/contains.sh" + +function Object::create::simpleObject { #@test + Object::create \ + --type "simpleObjectType" \ + --function-name "simpleObjectFunction" \ + --property-property "propertyValue" + + run simpleObjectFunction type + assert_output "simpleObjectType" + + run simpleObjectFunction strict + assert_output "1" + + run simpleObjectFunction functionName + assert_output "simpleObjectFunction" + + run simpleObjectFunction get property + assert_output "propertyValue" + + run simpleObjectFunction invalidCommand + assert_output --partial "ERROR - invalid command invalidCommand" + assert_failure 1 + + run simpleObjectFunction get propertyUnknown + assert_output --partial "ERROR - unknown property propertyUnknown" + assert_failure 2 +} + +function Object::create::simpleObjectNonStrict { #@test + Object::create \ + --strict 0 \ + --type "simpleObjectType" \ + --function-name "simpleObjectFunction" \ + --property-property "propertyValue" + + run simpleObjectFunction strict + assert_output "0" + + run simpleObjectFunction get propertyUnknown + assert_output "" + assert_success +} + +function Object::create::invalidProperty { #@test + run Object::create \ + --type "simpleObjectType" \ + --function-name "simpleObjectFunction" \ + --propertyInvalid-property "propertyValue" 2>&1 + + assert_output --partial "ERROR - invalid object property --propertyInvalid-property" + assert_failure 1 +} + +function Object::create::duplicatedProperty { #@test + run Object::create \ + --type "simpleObjectType" \ + --function-name "simpleObjectFunction" \ + --property-property "propertyValue1" \ + --property-property "propertyValue2" 2>&1 + + assert_output --partial "ERROR - property property is provided more than one time" + assert_failure 6 +} + +function Object::create::invalidFunctionName { #@test + run Object::create \ + --type "simpleObjectType" \ + --function-name "invalidéFunctionName" \ + --property-property "propertyValue" 2>&1 + + assert_output --partial "ERROR - invalid object function name invalidéFunctionName" + assert_failure 4 +} + +function Object::create::missingFunctionName { #@test + run Object::create \ + --type "simpleObjectType" \ + --property-property "propertyValue" 2>&1 + + assert_output --partial "ERROR - missing object function name" + assert_failure 3 +} + + +function Object::create::invalidObjectType { #@test + run Object::create \ + --type "invalidéObjectType" \ + --function-name "simpleFunctionName" \ + --property-property "propertyValue" 2>&1 + + assert_output --partial "ERROR - invalid object type invalidéObjectType" + assert_failure 5 +} + +function Object::create::missingObjectType { #@test + run Object::create \ + --function-name "simpleFunctionName" \ + --property-property "propertyValue" 2>&1 + + assert_output --partial "ERROR - missing object type" + assert_failure 2 +} + +function Object::create::propertyArrayOrdered { #@test + Object::create \ + --type "simpleObjectType" \ + --function-name "simpleObjectFunction" \ + --property-property "propertyValue" \ + --array-list "value1" \ + --array-list "value2" + + run simpleObjectFunction type + assert_success + assert_output "simpleObjectType" + + run simpleObjectFunction functionName + assert_success + assert_output "simpleObjectFunction" + + run simpleObjectFunction get property + assert_success + assert_output "propertyValue" + + run simpleObjectFunction get list + assert_success + assert_lines_count 2 + assert_line --index 0 "value1" + assert_line --index 1 "value2" +} + +function Object::create::propertyArrayUnordered { #@test + Object::create \ + --type "simpleObjectType" \ + --array-list "value1" \ + --function-name "simpleObjectFunction" \ + --array-list "value2" \ + --property-property "propertyValue" \ + --array-list "value3" + + run simpleObjectFunction type + assert_success + assert_output "simpleObjectType" + + run simpleObjectFunction functionName + assert_success + assert_output "simpleObjectFunction" + + run simpleObjectFunction get property + assert_success + assert_output "propertyValue" + + run simpleObjectFunction get list + assert_success + assert_lines_count 3 + assert_line --index 0 "value1" + assert_line --index 1 "value2" + assert_line --index 2 "value3" + + run simpleObjectFunction getMembers + assert_success + assert_lines_count 2 + assert_line --index 0 "list" + assert_line --index 1 "property" +} \ No newline at end of file diff --git a/src/Object/create.sh b/src/Object/create.sh new file mode 100644 index 00000000..cafe1230 --- /dev/null +++ b/src/Object/create.sh @@ -0,0 +1,126 @@ +#!/bin/bash + +Object::create() { + createTemplateFunction() { + local type="$1" + local functionName="$2" + shift 2 || true + local -a properties=("$@") + local propertiesLength="${#properties[@]}" + + local -a allMembers=() + ((i=0)) || true + mapfile -t allMembers < <( + while ((i < propertiesLength)); do + echo "${properties[${i}]}" | sed -E 's/--(property|array)-//' + ((i=i+2)) + done | sort -u + ) + echo "${functionName}() {" + # shellcheck disable=SC2016 + echo ' local command="$1"' + echo " local strict='${strict}'" + echo -n ' '; declare -p properties + # shellcheck disable=SC2016 + echo ' if [[ "${command}" = "type" ]]; then' + echo " echo '${type}'" + # shellcheck disable=SC2016 + echo ' elif [[ "${command}" = "functionName" ]]; then' + echo " echo '${functionName}'" + # shellcheck disable=SC2016 + echo ' elif [[ "${command}" = "strict" ]]; then' + echo " echo '${strict}'" + # shellcheck disable=SC2016 + echo ' elif [[ "${command}" = "get" ]]; then' + echo ' local i=0 || true' + # shellcheck disable=SC2016 + echo ' local propertyName="$2"' + # shellcheck disable=SC2016 + echo ' local propertyFound="0"' + echo " while ((i < ${propertiesLength})); do" + # shellcheck disable=SC2016 + echo ' if [[ "${properties[${i}]}" =~ ^--property- && "${properties[${i}]#--property-}" = "${propertyName}" ]]; then' + # shellcheck disable=SC2016 + echo ' echo "${properties[$((i+1))]}"' + echo ' return 0' + # shellcheck disable=SC2016 + echo ' elif [[ "${properties[${i}]}" =~ ^--array- && "${properties[${i}]#--array-}" = "${propertyName}" ]]; then' + echo ' propertyFound="1"' + # shellcheck disable=SC2016 + echo ' echo "${properties[$((i+1))]}"' + echo ' fi' + echo ' ((i=i+2))' + echo ' done' + # shellcheck disable=SC2016 + echo ' if [[ "${strict}" = "1" && "${propertyFound}" = "0" ]]; then' + # shellcheck disable=SC2016 + echo ' Log::displayError "unknown property ${propertyName}"' + echo ' return 2' + echo ' fi' + # shellcheck disable=SC2016 + echo ' elif [[ "${command}" = "getMembers" ]]; then' + # shellcheck disable=SC2028 + echo " printf '%s\n' ${allMembers[*]}" + echo ' else' + # shellcheck disable=SC2016 + echo ' Log::displayError "invalid command ${command}"' + echo ' return 1' + echo ' fi' + echo '}' + } + local type functionName + local strict="1" + local -a properties=() + while (($#>0)); do + case "$1" in + --type) + shift || true + type="$1" + ;; + --function-name) + shift || true + functionName="$1" + ;; + --strict) + # strict means that property non existence is failing with error + shift || true + strict="$1" + ;; + --property-*) + if Array::contains "$1" "${properties[@]}"; then + Log::displayError "property ${1#--property-} is provided more than one time" + return 6 + fi + properties+=("$1" "$2") + shift || true + ;; + --array-*) + properties+=("$1" "$2") + shift || true + ;; + *) + Log::displayError "invalid object property $1" + return 1 + esac + shift || true + done + + if [[ -z "${type}" ]]; then + Log::displayError "missing object type" + return 2 + fi + if ! Assert::posixFunctionName "${type}"; then + Log::displayError "invalid object type ${type}" + return 5 + fi + if [[ -z "${functionName}" ]]; then + Log::displayError "missing object function name" + return 3 + fi + if ! Assert::posixFunctionName "${functionName}"; then + Log::displayError "invalid object function name ${functionName}" + return 4 + fi + + eval "$(createTemplateFunction "${type}" "${functionName}" "${properties[@]}")" +} From b32ad9191ec3a57f4fe011de4e134de5b33dfcc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Chastanet?= Date: Fri, 22 Dec 2023 10:10:48 +0100 Subject: [PATCH 3/9] Options2 options using bash Object but not using templating anymore --- src/Options2/__all.sh | 48 ++++ src/Options2/renderArgHelp.bats | 62 +++++ src/Options2/renderArgHelp.sh | 111 ++++++++ src/Options2/renderGroupHelp.bats | 34 +++ src/Options2/renderGroupHelp.sh | 65 +++++ src/Options2/renderOptionHelp.bats | 61 +++++ src/Options2/renderOptionHelp.sh | 121 ++++++++ src/Options2/validateArgObject.bats | 270 ++++++++++++++++++ src/Options2/validateArgObject.sh | 139 ++++++++++ src/Options2/validateCommandObject.bats | 230 ++++++++++++++++ src/Options2/validateCommandObject.sh | 164 +++++++++++ src/Options2/validateGroupObject.bats | 64 +++++ src/Options2/validateGroupObject.sh | 62 +++++ src/Options2/validateOptionObject.bats | 348 ++++++++++++++++++++++++ src/Options2/validateOptionObject.sh | 201 ++++++++++++++ 15 files changed, 1980 insertions(+) create mode 100755 src/Options2/__all.sh create mode 100755 src/Options2/renderArgHelp.bats create mode 100755 src/Options2/renderArgHelp.sh create mode 100755 src/Options2/renderGroupHelp.bats create mode 100755 src/Options2/renderGroupHelp.sh create mode 100755 src/Options2/renderOptionHelp.bats create mode 100755 src/Options2/renderOptionHelp.sh create mode 100755 src/Options2/validateArgObject.bats create mode 100755 src/Options2/validateArgObject.sh create mode 100755 src/Options2/validateCommandObject.bats create mode 100755 src/Options2/validateCommandObject.sh create mode 100755 src/Options2/validateGroupObject.bats create mode 100755 src/Options2/validateGroupObject.sh create mode 100755 src/Options2/validateOptionObject.bats create mode 100755 src/Options2/validateOptionObject.sh diff --git a/src/Options2/__all.sh b/src/Options2/__all.sh new file mode 100755 index 00000000..6dcfeb36 --- /dev/null +++ b/src/Options2/__all.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash + +# shellcheck source=src/UI/theme.sh +source "${FRAMEWORK_ROOT_DIR}/src/UI/theme.sh" +# shellcheck source=src/Options/bashTpl.sh +source "${FRAMEWORK_ROOT_DIR}/src/Options/bashTpl.sh" + # shellcheck source=src/Options/assertAlt.sh + source "${FRAMEWORK_ROOT_DIR}/src/Options/assertAlt.sh" +# shellcheck source=/src/Assert/posixFunctionName.sh +source "${FRAMEWORK_ROOT_DIR}/src/Assert/posixFunctionName.sh" +# shellcheck source=/src/Assert/bashFrameworkFunction.sh +source "${FRAMEWORK_ROOT_DIR}/src/Assert/bashFrameworkFunction.sh" +# shellcheck source=/src/Assert/validVariableName.sh +source "${FRAMEWORK_ROOT_DIR}/src/Assert/validVariableName.sh" +# shellcheck source=/src/Array/contains.sh +source "${FRAMEWORK_ROOT_DIR}/src/Array/contains.sh" +# shellcheck source=/src/Array/join.sh +source "${FRAMEWORK_ROOT_DIR}/src/Array/join.sh" +# shellcheck source=/src/Filters/removeAnsiCodes.sh +source "${FRAMEWORK_ROOT_DIR}/src/Filters/removeAnsiCodes.sh" +# shellcheck source=/src/Array/wrap2.sh +source "${FRAMEWORK_ROOT_DIR}/src/Array/wrap2.sh" +# shellcheck source=/src/Framework/createTempFile.sh +source "${FRAMEWORK_ROOT_DIR}/src/Framework/createTempFile.sh" +# shellcheck source=/src/Crypto/uuidV4.sh +source "${FRAMEWORK_ROOT_DIR}/src/Crypto/uuidV4.sh" +# shellcheck source=src/Options/generateFunction.sh +source "${FRAMEWORK_ROOT_DIR}/src/Options/generateFunction.sh" +# shellcheck source=src/Object/create.sh +source "${FRAMEWORK_ROOT_DIR}/src/Object/create.sh" + +# shellcheck source=src/Options2/validateCommandObject.sh +source "${FRAMEWORK_ROOT_DIR}/src/Options2/validateCommandObject.sh" + +# shellcheck source=src/Options2/validateGroupObject.sh +source "${FRAMEWORK_ROOT_DIR}/src/Options2/validateGroupObject.sh" +# shellcheck source=src/Options2/renderGroupHelp.sh +source "${FRAMEWORK_ROOT_DIR}/src/Options2/renderGroupHelp.sh" + +# shellcheck source=src/Options2/validateArgObject.sh +source "${FRAMEWORK_ROOT_DIR}/src/Options2/validateArgObject.sh" +# shellcheck source=src/Options2/renderArgHelp.sh +source "${FRAMEWORK_ROOT_DIR}/src/Options2/renderArgHelp.sh" + +# shellcheck source=src/Options2/validateOptionObject.sh +source "${FRAMEWORK_ROOT_DIR}/src/Options2/validateOptionObject.sh" +# shellcheck source=src/Options2/renderOptionHelp.sh +source "${FRAMEWORK_ROOT_DIR}/src/Options2/renderOptionHelp.sh" diff --git a/src/Options2/renderArgHelp.bats b/src/Options2/renderArgHelp.bats new file mode 100755 index 00000000..55742d1a --- /dev/null +++ b/src/Options2/renderArgHelp.bats @@ -0,0 +1,62 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Options/_bats.sh +source "${srcDir}/Options/_bats.sh" +# shellcheck source=src/Options2/__all.sh +source "${srcDir}/Options2/__all.sh" + +function setup() { + export TMPDIR="${BATS_TEST_TMPDIR}" + export _COMPILE_ROOT_DIR="${FRAMEWORK_ROOT_DIR}" +} + +function Options2::renderArgHelp::noOption { #@test + run Options2::renderArgHelp + assert_lines_count 1 + assert_output --partial "ERROR - Options2::renderArgHelp - exactly one parameter has to be provided" + assert_failure 1 +} + +function Options2::renderArgHelp::invalidObject { #@test + function invalidObject() { + : + } + run Options2::renderArgHelp invalidObject + assert_lines_count 1 + assert_output --partial "ERROR - Options2::validateArgObject - passed object is not an argument" + assert_failure 2 +} + +function Options2::renderArgHelp::notAnOption { #@test + Object::create \ + --type "NotAnOption" \ + --function-name "notAnOptionFunction" + + run Options2::renderArgHelp notAnOptionFunction + assert_lines_count 1 + assert_output --partial "ERROR - Options2::validateArgObject - passed object is not an argument" + assert_failure 2 +} + +function Options::renderArgHelp::OptionValid { #@test + local status=0 + callback() { + : + } + Object::create \ + --function-name "argFunction" \ + --type "Arg" \ + --property-variableName "var" \ + --property-name "name" \ + --property-help "help" \ + --property-title "Global options" + + run Options2::renderArgHelp argFunction 2>&1 + assert_success + assert_line --index 0 "[${__HELP_OPTION_COLOR}name${__HELP_NORMAL} {list} (optional)]" + assert_line --index 1 "Global options" + assert_line --index 2 "help" + assert_lines_count 3 +} diff --git a/src/Options2/renderArgHelp.sh b/src/Options2/renderArgHelp.sh new file mode 100755 index 00000000..3a50c81b --- /dev/null +++ b/src/Options2/renderArgHelp.sh @@ -0,0 +1,111 @@ +#!/usr/bin/env bash + +# @description Generates a function that allows to manipulate a group of options. +# function generated allows group options using `--group` option when +# using `Options::generateOption` +# +# #### Output on stdout +# +# By default the name of the random generated function name +# is displayed as output of this function. +# By providing the option `--function-name`, the output of this +# function will be the generated function itself with the chosen name. +# +# #### Syntax +# +# ```text +# Usage: Options2::renderOptionHelp [OPTIONS] +# +# OPTIONS: +# --title +# [--help ] +# [--function-name ] +# ``` +# +# #### Example +# +# ```bash +# declare optionGroup="$( +# Options2::renderOptionHelp \ +# --title "Command global options" \ +# --help "The Console component adds some predefined options to all commands:" +# )" +# Options::sourceFunction "${optionGroup}" +# "${optionGroup}" help +# ``` +# +# @option --title (mandatory) provides group title +# @option --help (optional) provides command description help +# @option --function-name (optional) the name of the function that will be generated +# @exitcode 1 if error during option parsing +# @exitcode 1 if bash-tpl error during template rendering +# @exitcode 2 if file generation error (only if functionName argument empty) +# @stderr diagnostics information is displayed +# @see [generateCommand function](#/doc/guides/Options/generateCommand) +# @see [generateOption function](#/doc/guides/Options/generateOption) +# @see [group function](#/doc/guides/Options/functionGroup) +Options2::renderArgHelp() { + if (( $# != 1 )); then + Log::displayError "Options2::renderArgHelp - exactly one parameter has to be provided" + return 1 + fi + + local optionArgObject=$1 + if ! Options2::validateArgObject "${optionArgObject}"; then + return 2 + fi + local help title min max name + title="$("${optionArgObject}" get title 2>/dev/null)" + help="$("${optionArgObject}" get help 2>/dev/null || echo '')" + name="$("${optionArgObject}" get name 2>/dev/null|| echo '')" + min="$("${optionArgObject}" get min 2>/dev/null|| echo '0')" + max="$("${optionArgObject}" get max 2>/dev/null|| echo '-1')" + + displayHelp() { + echo -e "${__HELP_TITLE_COLOR}${title}${__RESET_COLOR}" + if [[ -z "${help}" ]]; then + echo "No help available'" + elif [[ $(type -t "${help}") == "function" ]]; then + local -a helpArray + # shellcheck disable=SC2054,SC2206 + mapfile -t helpArray < <(${help}) + Array::wrap2 " " 76 4 "${helpArray[@]}" + else + local -a helpArray + local helpEscaped + printf -v helpEscaped '%q' "${help}" + # shellcheck disable=SC2054,SC2206 + helpArray=(${helpEscaped}) + Array::wrap2 " " 76 4 "${helpArray[@]}" + fi + } + + helpArg() { + local spec="" + spec+="${__HELP_OPTION_COLOR}${name}${__HELP_NORMAL}" + if ((max == 1)); then + spec+=' {single}' + if ((min == 1)); then + spec+=' (mandatory)' + fi + else + spec+=' {list}' + if ((min > 0)); then + spec+=" (at least ${min} times)" + else + spec+=' (optional)' + fi + if ((max > 0)); then + spec+=" (at most ${max} times)" + fi + fi + local helpArg="" + ((min == 0)) && helpArg+="[" + helpArg+="${spec//^[[:blank:]]/}" + ((min == 0)) && helpArg+="]" + echo -e "${helpArg}" + } + + helpArg + displayHelp +} diff --git a/src/Options2/renderGroupHelp.bats b/src/Options2/renderGroupHelp.bats new file mode 100755 index 00000000..1d8ae63d --- /dev/null +++ b/src/Options2/renderGroupHelp.bats @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Options/_bats.sh +source "${srcDir}/Options/_bats.sh" +# shellcheck source=src/Options2/__all.sh +source "${srcDir}/Options2/__all.sh" + +function setup() { + export TMPDIR="${BATS_TEST_TMPDIR}" + export _COMPILE_ROOT_DIR="${FRAMEWORK_ROOT_DIR}" +} + +function Options2::renderGroupHelp::noOption { #@test + run Options2::renderGroupHelp + assert_lines_count 1 + assert_output --partial "ERROR - Options2::renderGroupHelp - exactly one parameter has to be provided" + assert_failure 1 +} + + +function Options2::renderGroupHelp::groupOptionValid { #@test + local status=0 + Object::create \ + --type "Group" \ + --property-title "Global options" \ + --property-help "help" \ + --function-name "groupObjectFunction" + run Options2::renderGroupHelp groupObjectFunction >"${BATS_TEST_TMPDIR}/result" 2>&1 + assert_success + assert_line --index 0 "$(echo -e "${__HELP_TITLE_COLOR}Global options${__RESET_COLOR}")" + assert_line --index 1 "help" +} diff --git a/src/Options2/renderGroupHelp.sh b/src/Options2/renderGroupHelp.sh new file mode 100755 index 00000000..e8b36130 --- /dev/null +++ b/src/Options2/renderGroupHelp.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash + +# @description Generates a function that allows to manipulate a group of options. +# function generated allows group options using `--group` option when +# using `Options::generateOption` +# +# #### Output on stdout +# +# By default the name of the random generated function name +# is displayed as output of this function. +# By providing the option `--function-name`, the output of this +# function will be the generated function itself with the chosen name. +# +# #### Syntax +# +# ```text +# Usage: Options2::renderGroupHelp [OPTIONS] +# +# OPTIONS: +# --title +# [--help ] +# [--function-name ] +# ``` +# +# #### Example +# +# ```bash +# declare optionGroup="$( +# Options2::renderGroupHelp \ +# --title "Command global options" \ +# --help "The Console component adds some predefined options to all commands:" +# )" +# Options::sourceFunction "${optionGroup}" +# "${optionGroup}" help +# ``` +# +# @option --title (mandatory) provides group title +# @option --help (optional) provides command description help +# @option --function-name (optional) the name of the function that will be generated +# @exitcode 1 if error during option parsing +# @exitcode 1 if bash-tpl error during template rendering +# @exitcode 2 if file generation error (only if functionName argument empty) +# @stderr diagnostics information is displayed +# @see [generateCommand function](#/doc/guides/Options/generateCommand) +# @see [generateOption function](#/doc/guides/Options/generateOption) +# @see [group function](#/doc/guides/Options/functionGroup) +Options2::renderGroupHelp() { + if (( $# != 1 )); then + Log::displayError "Options2::renderGroupHelp - exactly one parameter has to be provided" + return 1 + fi + + local groupInstanceObject=$1 + if ! Options2::validateGroupObject "${groupInstanceObject}"; then + return 2 + fi + local help title + title="$("${groupInstanceObject}" get title 2>/dev/null)" + help="$("${groupInstanceObject}" get help 2>/dev/null || echo '')" + + echo -e "${__HELP_TITLE_COLOR}${title}${__RESET_COLOR}" + if [[ -n "${help}" ]]; then + echo -e "${help}" + fi +} diff --git a/src/Options2/renderOptionHelp.bats b/src/Options2/renderOptionHelp.bats new file mode 100755 index 00000000..600666f7 --- /dev/null +++ b/src/Options2/renderOptionHelp.bats @@ -0,0 +1,61 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Options/_bats.sh +source "${srcDir}/Options/_bats.sh" +# shellcheck source=src/Options2/__all.sh +source "${srcDir}/Options2/__all.sh" + +function setup() { + export TMPDIR="${BATS_TEST_TMPDIR}" + export _COMPILE_ROOT_DIR="${FRAMEWORK_ROOT_DIR}" +} + +function Options2::renderOptionHelp::noOption { #@test + run Options2::renderOptionHelp + assert_lines_count 1 + assert_output --partial "ERROR - Options2::renderOptionHelp - exactly one parameter has to be provided" + assert_failure 1 +} + +function Options2::renderOptionHelp::invalidObject { #@test + function invalidObject() { + : + } + run Options2::renderOptionHelp invalidObject + assert_lines_count 1 + assert_output --partial "ERROR - Options2::validateOptionObject - passed object is not an option" + assert_failure 2 +} + +function Options2::renderOptionHelp::notAnOption { #@test + Object::create \ + --type "NotAnOption" \ + --function-name "notAnOptionFunction" + + run Options2::renderOptionHelp notAnOptionFunction + assert_lines_count 1 + assert_output --partial "ERROR - Options2::validateOptionObject - passed object is not an option" + assert_failure 2 +} + +function Options::renderOptionHelp::OptionValid { #@test + local status=0 + callback() { + : + } + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableName "var" \ + --property-variableType "Boolean" \ + --property-help "help" \ + --property-title "Global options" \ + --array-alt "--help" + + run Options2::renderOptionHelp optionFunction 2>&1 + assert_success + assert_line --index 0 "$(echo -e "${__HELP_TITLE_COLOR}Global options${__RESET_COLOR}")" + assert_line --index 1 "help" +} diff --git a/src/Options2/renderOptionHelp.sh b/src/Options2/renderOptionHelp.sh new file mode 100755 index 00000000..feff762d --- /dev/null +++ b/src/Options2/renderOptionHelp.sh @@ -0,0 +1,121 @@ +#!/usr/bin/env bash + +# @description Generates a function that allows to manipulate a group of options. +# function generated allows group options using `--group` option when +# using `Options::generateOption` +# +# #### Output on stdout +# +# By default the name of the random generated function name +# is displayed as output of this function. +# By providing the option `--function-name`, the output of this +# function will be the generated function itself with the chosen name. +# +# #### Syntax +# +# ```text +# Usage: Options2::renderOptionHelp [OPTIONS] +# +# OPTIONS: +# --title +# [--help ] +# [--function-name ] +# ``` +# +# #### Example +# +# ```bash +# declare optionGroup="$( +# Options2::renderOptionHelp \ +# --title "Command global options" \ +# --help "The Console component adds some predefined options to all commands:" +# )" +# Options::sourceFunction "${optionGroup}" +# "${optionGroup}" help +# ``` +# +# @option --title (mandatory) provides group title +# @option --help (optional) provides command description help +# @option --function-name (optional) the name of the function that will be generated +# @exitcode 1 if error during option parsing +# @exitcode 1 if bash-tpl error during template rendering +# @exitcode 2 if file generation error (only if functionName argument empty) +# @stderr diagnostics information is displayed +# @see [generateCommand function](#/doc/guides/Options/generateCommand) +# @see [generateOption function](#/doc/guides/Options/generateOption) +# @see [group function](#/doc/guides/Options/functionGroup) +Options2::renderOptionHelp() { + if (( $# != 1 )); then + Log::displayError "Options2::renderOptionHelp - exactly one parameter has to be provided" + return 1 + fi + + local optionInstanceObject=$1 + if ! Options2::validateOptionObject "${optionInstanceObject}"; then + return 2 + fi + local help title variableType helpValueName min max + title="$("${optionInstanceObject}" get title 2>/dev/null)" + help="$("${optionInstanceObject}" get help 2>/dev/null || echo '')" + variableType="$("${optionInstanceObject}" get variableType)" + helpValueName="$("${optionInstanceObject}" get helpValueName 2>/dev/null|| echo '')" + min="$("${optionInstanceObject}" get min 2>/dev/null|| echo '')" + max="$("${optionInstanceObject}" get max 2>/dev/null|| echo '')" + + displayHelp() { + echo -e "${__HELP_TITLE_COLOR}${title}${__RESET_COLOR}" + if [[ -z "${help}" ]]; then + echo "No help available'" + elif [[ $(type -t "${help}") == "function" ]]; then + local -a helpArray + # shellcheck disable=SC2054,SC2206 + mapfile -t helpArray < <(${help}) + Array::wrap2 " " 76 4 "${helpArray[@]}" + else + local -a helpArray + local helpEscaped + printf -v helpEscaped '%q' "${help}" + # shellcheck disable=SC2054,SC2206 + helpArray=(${helpEscaped}) + Array::wrap2 " " 76 4 "${helpArray[@]}" + fi + } + + helpOpt() { + local spec="" + spec+="${__HELP_OPTION_COLOR}" + spec+="$(Array::join "${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}" "${alts[@]}")" + if [[ "${variableType}" != "Boolean" ]]; then + spec+=" <${helpValueName}>" + fi + spec+="${__HELP_NORMAL}" + if ((max == 1)); then + spec+=' {single}' + if ((min == 1)); then + spec+=' (mandatory)' + fi + else + spec+=' {list}' + if ((min > 0)); then + spec+=" (at least ${min} times)" + else + spec+=' (optional)' + fi + if ((max > 0)); then + spec+=" (at most ${max} times)" + fi + fi + local helpOpt="" + helpOpt+="${spec//^[[:blank:]]/}" + echo -e "${helpOpt}" + } + + displayHelp + helpOpt + if [[ -n "${defaultValue}" ]]; then + echo "Default value: ${defaultValue}" + fi + if [[ -n "${authorizedValues}" ]]; then + echo "Possible values: ${authorizedValues}" + fi +} diff --git a/src/Options2/validateArgObject.bats b/src/Options2/validateArgObject.bats new file mode 100755 index 00000000..8e9df126 --- /dev/null +++ b/src/Options2/validateArgObject.bats @@ -0,0 +1,270 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Options/_bats.sh +source "${srcDir}/Options/_bats.sh" +# shellcheck source=src/Options2/__all.sh +source "${srcDir}/Options2/__all.sh" + +function setup() { + export TMPDIR="${BATS_TEST_TMPDIR}" + export _COMPILE_ROOT_DIR="${FRAMEWORK_ROOT_DIR}" +} + +function Options2::validateArgObject::noOption { #@test + run Options2::validateArgObject + assert_lines_count 1 + assert_output --partial "ERROR - Options2::validateArgObject - exactly one parameter has to be provided" + assert_failure 1 +} + +function Options2::validateArgObject::missingValue { #@test + run Options2::validateArgObject invalidObject + assert_lines_count 1 + assert_output --partial "ERROR - Options2::validateArgObject - passed object is not an argument" + assert_failure 2 +} + +function Options2::validateArgObject::tooMuchArgs { #@test + Object::create \ + --function-name "argFunction" \ + --type "Arg" + run Options2::validateArgObject argFunction argFunction + assert_lines_count 1 + assert_output --partial "ERROR - Options2::validateArgObject - exactly one parameter has to be provided" + assert_failure 1 +} + +function Options2::validateArgObject::invalidObjectType { #@test + Object::create \ + --function-name "notAnargFunction" \ + --type "NotAnOption" + + run Options2::validateArgObject notAnargFunction + assert_lines_count 1 + assert_output --partial "ERROR - Options2::validateArgObject - passed object is not an argument" + assert_failure 2 +} + +function Options2::validateArgObject::variableNameMandatory { #@test + Object::create \ + --function-name "argFunction" \ + --type "Arg" \ + --property-variableType "String" + + run Options2::validateArgObject argFunction + assert_output --partial "ERROR - Options2::validateArgObject - variableName is mandatory" + assert_failure 1 + assert_lines_count 1 +} + +function Options2::validateArgObject::variableNameInvalid { #@test + Object::create \ + --function-name "argFunction" \ + --type "Arg" \ + --property-name "valid" \ + --property-variableName "François" + + run Options2::validateArgObject argFunction + assert_output --partial "ERROR - Options2::validateArgObject - invalid variableName François" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateArgObject::nameMandatory { #@test + Object::create \ + --function-name "argFunction" \ + --type "Arg" \ + --property-variableName "validVariableName" + + run Options2::validateArgObject argFunction + assert_output --partial "ERROR - Options2::validateArgObject - name is mandatory" + assert_failure 1 + assert_lines_count 1 +} + + +function Options2::validateArgObject::nameInvalid { #@test + Object::create \ + --function-name "argFunction" \ + --type "Arg" \ + --property-variableName "validVariableName" \ + --property-name "François" + + run Options2::validateArgObject argFunction + assert_output --partial "ERROR - Options2::validateArgObject - invalid name François" + assert_failure 2 + assert_lines_count 1 +} + + +function Options2::validateArgObject::callbackInvalid { #@test + Object::create \ + --function-name "argFunction" \ + --type "Arg" \ + --property-variableName "varName" \ + --property-variableType "String" \ + --array-alt "--help" \ + --property-name "valid" \ + --array-callback "François" + + run Options2::validateArgObject argFunction + assert_output --partial "ERROR - Options2::validateArgObject - only posix or bash framework function name are accepted - invalid 'François'" + assert_lines_count 1 + assert_failure 2 +} + +function Options2::validateArgObject::callbackValid { #@test + callback() { + : + } + Object::create \ + --function-name "argFunction" \ + --type "Arg" \ + --property-variableName "varName" \ + --property-variableType "String" \ + --array-alt "--help" \ + --property-name "valid" \ + --array-callback "callback" + run Options2::validateArgObject argFunction + assert_output "" + assert_success +} + +function Options2::validateArgObject::String::authorizedValuesValueInvalidValue { #@test + Object::create \ + --function-name "argFunction" \ + --type "Arg" \ + --property-variableType "String" \ + --property-variableName "varName" \ + --property-name "valid" \ + --property-authorizedValues " invalid | valid" \ + --array-alt "--help" + run Options2::validateArgObject argFunction + assert_output --partial "ERROR - Options2::validateArgObject - authorizedValues invalid regexp ' invalid | valid'" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateArgObject::StringArray::authorizedValuesValueInvalidValue { #@test + Object::create \ + --function-name "argFunction" \ + --type "Arg" \ + --property-variableType "StringArray" \ + --property-variableName "varName" \ + --property-name "valid" \ + --property-authorizedValues " invalid | valid" \ + --array-alt "--help" + run Options2::validateArgObject argFunction + assert_output --partial "ERROR - Options2::validateArgObject - authorizedValues invalid regexp ' invalid | valid'" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateArgObject::regexpInvalid { #@test + Object::create \ + --function-name "argFunction" \ + --type "Arg" \ + --property-variableType "StringArray" \ + --property-variableName "varName" \ + --property-name "valid" \ + --property-regexp " " \ + --array-alt "--help" + run Options2::validateArgObject argFunction + assert_output --partial "ERROR - Options2::validateArgObject - regexp invalid regexp ' '" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateArgObject::String::helpValueNameInvalidOption { #@test + Object::create \ + --function-name "argFunction" \ + --type "Arg" \ + --property-variableType "String" \ + --property-variableName "varName" \ + --property-name "valid" \ + --property-helpValueName "invalid help" \ + --array-alt "--help" + run Options2::validateArgObject argFunction + assert_output --partial "ERROR - Options2::validateArgObject - helpValueName should be a single word 'invalid help'" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateArgObject::StringArray::helpValueNameInvalidOption { #@test + Object::create \ + --function-name "argFunction" \ + --type "Arg" \ + --property-variableType "StringArray" \ + --property-variableName "varName" \ + --property-name "valid" \ + --property-helpValueName "invalid help" \ + --array-alt "--help" + run Options2::validateArgObject argFunction + assert_output --partial "ERROR - Options2::validateArgObject - helpValueName should be a single word 'invalid help'" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateArgObject::StringArray::minValueEmpty { #@test + Object::create \ + --function-name "argFunction" \ + --type "Arg" \ + --property-variableType "StringArray" \ + --property-variableName "varName" \ + --property-name "valid" \ + --property-min "" \ + --array-alt "--help" + run Options2::validateArgObject argFunction + assert_output --partial "ERROR - Options2::validateArgObject - min value should be an integer greater than or equal to 0" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateArgObject::StringArray::minValueInvalid { #@test + Object::create \ + --function-name "argFunction" \ + --type "Arg" \ + --property-variableType "StringArray" \ + --property-variableName "varName" \ + --property-name "valid" \ + --property-min "François" \ + --array-alt "--help" + run Options2::validateArgObject argFunction + assert_output --partial "ERROR - Options2::validateArgObject - min value should be an integer greater than or equal to 0" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateArgObject::StringArray::minValueLessThan0 { #@test + Object::create \ + --function-name "argFunction" \ + --type "Arg" \ + --property-variableType "StringArray" \ + --property-variableName "varName" \ + --property-name "valid" \ + --property-min "-1" \ + --array-alt "--help" + run Options2::validateArgObject argFunction + assert_output --partial "ERROR - Options2::validateArgObject - min value should be an integer greater than or equal to 0" + assert_failure 2 + assert_lines_count 1 +} + + +function Options2::validateArgObject::StringArray::minValueGreaterThanMaxValue { #@test + Object::create \ + --function-name "argFunction" \ + --type "Arg" \ + --property-variableType "StringArray" \ + --property-variableName "varName" \ + --property-name "valid" \ + --property-min "3" \ + --property-max "1" \ + --array-alt "--help" + run Options2::validateArgObject argFunction + assert_output --partial "ERROR - Options2::validateArgObject - max value should be greater than min value" + assert_failure 2 + assert_lines_count 1 +} \ No newline at end of file diff --git a/src/Options2/validateArgObject.sh b/src/Options2/validateArgObject.sh new file mode 100755 index 00000000..a8648d61 --- /dev/null +++ b/src/Options2/validateArgObject.sh @@ -0,0 +1,139 @@ +#!/usr/bin/env bash + +# @description Validates options properties created +# using `Object::create` +# +# #### Example +# +# ```bash +# declare Object::create \ +# --function-name "optionFunction" \ +# --type "Option" \ +# --property-variableName "varName" +# +# Options2::validateArgObject "${optionFunction}" +# ``` +# #### Arg Structure +# +# - --function-name (optional) the name of the function that will be generated +# - --type "Arg" +# - --property-variableType automatically computed based on min/max +# - --property-variableName (mandatory) provides the variable name that will be used to store the parsed options. +# - --property-name (optional) provides the name of the argument (default: variableName) +# - --property-mandatory (optional) as its name indicates, by default an option is optional. But using `--mandatory` you can make the option mandatory. An error will be generated if the option is not found during parsing arguments. +# - --property-help (optional) provides option help description (Default: Empty string) +# - --array-callback (0 or several times) the callback called if the option is parsed successfully. The option value will be passed as parameter (several parameters if type StringArray). +# - --property-regexp (optional) regexp to use to validate the option value +# - --property-authorizedValues (optional) Indicates the possible value list separated by | character (Default: "" means no check) +# - --property-helpValueName (optional) Indicates the name of value of the option to display in help (Default: "String") +# - --property-mandatory (optional) if 1 then will set min value to 1 (except if min is already set) (Default: "0") +# - --property-min (optional) minimum number of options to provide (Defaults to 0 or 1 if mandatory). +# - --property-max (optional) maximum number of options to provide (Default "" means no limit) +# +# Example: +# ```bash +# Object::create \ +# --function-name "optionFunction" \ +# --type "Option" \ +# --property-variableType "Boolean" \ +# --property-variableName "varName" \ +# --array-alt "--help" \ +# --array-alt "-h" \ +# --array-callback "callback" +# ``` +# +# @exitcode 1 if mandatory parameter missing +# @exitcode 2 if invalid parameter provided +# @stderr diagnostics information is displayed +Options2::validateArgObject() { + if (( $# != 1 )); then + Log::displayError "Options2::validateArgObject - exactly one parameter has to be provided" + return 1 + fi + + local argInstanceObject=$1 + if [[ "$("${argInstanceObject}" type 2>/dev/null || echo '')" != "Arg" ]]; then + Log::displayError "Options2::validateArgObject - passed object is not an argument" + return 2 + fi + + # variable name + if ! "${argInstanceObject}" get variableName &>/dev/null; then + Log::displayError "Options2::validateArgObject - variableName is mandatory" + return 1 + fi + local variableName + variableName="$("${argInstanceObject}" get variableName)" + if ! Assert::validVariableName "${variableName}"; then + Log::displayError "Options2::validateArgObject - invalid variableName ${variableName}" + return 2 + fi + + # name + if ! "${argInstanceObject}" get name &>/dev/null; then + Log::displayError "Options2::validateArgObject - name is mandatory" + return 1 + fi + local name + name="$("${argInstanceObject}" get name)" + if ! Assert::validVariableName "${name}"; then + Log::displayError "Options2::validateArgObject - invalid name ${name}" + return 2 + fi + + # callback + if "${argInstanceObject}" get callback &>/dev/null; then + local callbacks + callbacks="$("${argInstanceObject}" get callback)" + local callback + while IFS= read -r callback ; do + if + ! Assert::posixFunctionName "${callback}" && + ! Assert::bashFrameworkFunction "${callback}" + then + Log::displayError "Options2::validateArgObject - only posix or bash framework function name are accepted - invalid '${callback}'" + return 2 + fi + done <<< "${callbacks}" + fi + + local authorizedValues + authorizedValues="$("${argInstanceObject}" get authorizedValues 2>/dev/null)" || authorizedValues="" + if [[ "${authorizedValues}" =~ [[:space:]] ]]; then + Log::displayError "Options2::validateArgObject - authorizedValues invalid regexp '${authorizedValues}'" + return 2 + fi + + local regexp + regexp="$("${argInstanceObject}" get regexp 2>/dev/null)" || regexp="" + if [[ "${regexp}" =~ [[:space:]] ]]; then + Log::displayError "Options2::validateArgObject - regexp invalid regexp '${regexp}'" + return 2 + fi + + local helpValueName + helpValueName="$("${argInstanceObject}" get helpValueName 2>/dev/null)" || helpValueName="" + if [[ -n "${helpValueName}" && ! "${helpValueName}" =~ ^[A-Za-z0-9_-]+$ ]]; then + Log::displayError "Options2::validateArgObject - helpValueName should be a single word '${helpValueName}'" + return 2 + fi + + local min + min="$("${argInstanceObject}" get min 2>/dev/null)" || min="0" + if [[ ! "${min}" =~ ^[0-9]+$ ]]; then + Log::displayError "Options2::validateArgObject - min value should be an integer greater than or equal to 0" + return 2 + fi + + local max + max="$("${argInstanceObject}" get max 2>/dev/null)" || max="-1" + if [[ -n "${max}" && ! "${max}" =~ ^([1-9][0-9]*|-1)$ ]]; then + Log::displayError "Options2::validateArgObject - max value should be an integer greater than 0 or -1" + return 2 + fi + + if ((max != -1 && min > max)); then + Log::displayError "Options2::validateArgObject - max value should be greater than min value" + return 2 + fi +} diff --git a/src/Options2/validateCommandObject.bats b/src/Options2/validateCommandObject.bats new file mode 100755 index 00000000..a64416cc --- /dev/null +++ b/src/Options2/validateCommandObject.bats @@ -0,0 +1,230 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Options/_bats.sh +source "${srcDir}/Options/_bats.sh" +# shellcheck source=src/Options2/__all.sh +source "${srcDir}/Options2/__all.sh" + +function setup() { + export TMPDIR="${BATS_TEST_TMPDIR}" + export _COMPILE_ROOT_DIR="${FRAMEWORK_ROOT_DIR}" +} + +function Options2::validateCommandObject::noOption { #@test + run Options2::validateCommandObject + assert_lines_count 1 + assert_output --partial "ERROR - Options2::validateCommandObject - exactly one parameter has to be provided" + assert_failure 1 +} + +function Options2::validateCommandObject::missingValue { #@test + run Options2::validateCommandObject invalidObject + assert_lines_count 1 + assert_output --partial "ERROR - Options2::validateCommandObject - passed object is not a command" + assert_failure 2 +} + +function Options2::validateCommandObject::tooMuchArgs { #@test + Object::create \ + --function-name "argFunction" \ + --type "Command" + run Options2::validateCommandObject argFunction argFunction + assert_lines_count 1 + assert_output --partial "ERROR - Options2::validateCommandObject - exactly one parameter has to be provided" + assert_failure 1 +} + +function Options2::validateCommandObject::invalidObjectType { #@test + Object::create \ + --function-name "notAnargFunction" \ + --type "NotACommand" + + run Options2::validateCommandObject notAnargFunction + assert_lines_count 1 + assert_output --partial "ERROR - Options2::validateCommandObject - passed object is not a command" + assert_failure 2 +} + +function Options2::validateCommandObject::nameInvalid { #@test + Object::create \ + --function-name "argFunction" \ + --type "Command" \ + --property-name "François" + + run Options2::validateCommandObject argFunction + assert_output --partial "ERROR - Options2::validateCommandObject - invalid command name François" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateCommandObject::callbackInvalid { #@test + Object::create \ + --function-name "argFunction" \ + --type "Command" \ + --property-variableName "varName" \ + --property-variableType "String" \ + --array-alt "--help" \ + --property-name "valid" \ + --array-callback "François" + + run Options2::validateCommandObject argFunction + assert_output --partial "ERROR - Options2::validateCommandObject - only posix or bash framework function name are accepted - invalid 'François'" + assert_lines_count 1 + assert_failure 2 +} + +function Options2::validateCommandObject::callbackValid { #@test + callback() { + : + } + Object::create \ + --function-name "argFunction" \ + --type "Command" \ + --property-variableName "varName" \ + --property-variableType "String" \ + --array-alt "--help" \ + --property-name "valid" \ + --array-callback "callback" + run Options2::validateCommandObject argFunction + assert_output "" + assert_success +} + +function Options2::validateCommandObject::String::authorizedValuesValueInvalidValue { #@test + Object::create \ + --function-name "argFunction" \ + --type "Command" \ + --property-variableType "String" \ + --property-variableName "varName" \ + --property-name "valid" \ + --property-authorizedValues " invalid | valid" \ + --array-alt "--help" + run Options2::validateCommandObject argFunction + assert_output --partial "ERROR - Options2::validateCommandObject - authorizedValues invalid regexp ' invalid | valid'" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateCommandObject::StringArray::authorizedValuesValueInvalidValue { #@test + Object::create \ + --function-name "argFunction" \ + --type "Command" \ + --property-variableType "StringArray" \ + --property-variableName "varName" \ + --property-name "valid" \ + --property-authorizedValues " invalid | valid" \ + --array-alt "--help" + run Options2::validateCommandObject argFunction + assert_output --partial "ERROR - Options2::validateCommandObject - authorizedValues invalid regexp ' invalid | valid'" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateCommandObject::regexpInvalid { #@test + Object::create \ + --function-name "argFunction" \ + --type "Command" \ + --property-variableType "StringArray" \ + --property-variableName "varName" \ + --property-name "valid" \ + --property-regexp " " \ + --array-alt "--help" + run Options2::validateCommandObject argFunction + assert_output --partial "ERROR - Options2::validateCommandObject - regexp invalid regexp ' '" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateCommandObject::String::helpValueNameInvalidOption { #@test + Object::create \ + --function-name "argFunction" \ + --type "Command" \ + --property-variableType "String" \ + --property-variableName "varName" \ + --property-name "valid" \ + --property-helpValueName "invalid help" \ + --array-alt "--help" + run Options2::validateCommandObject argFunction + assert_output --partial "ERROR - Options2::validateCommandObject - helpValueName should be a single word 'invalid help'" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateCommandObject::StringArray::helpValueNameInvalidOption { #@test + Object::create \ + --function-name "argFunction" \ + --type "Command" \ + --property-variableType "StringArray" \ + --property-variableName "varName" \ + --property-name "valid" \ + --property-helpValueName "invalid help" \ + --array-alt "--help" + run Options2::validateCommandObject argFunction + assert_output --partial "ERROR - Options2::validateCommandObject - helpValueName should be a single word 'invalid help'" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateCommandObject::StringArray::minValueEmpty { #@test + Object::create \ + --function-name "argFunction" \ + --type "Command" \ + --property-variableType "StringArray" \ + --property-variableName "varName" \ + --property-name "valid" \ + --property-min "" \ + --array-alt "--help" + run Options2::validateCommandObject argFunction + assert_output --partial "ERROR - Options2::validateCommandObject - min value should be an integer greater than or equal to 0" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateCommandObject::StringArray::minValueInvalid { #@test + Object::create \ + --function-name "argFunction" \ + --type "Command" \ + --property-variableType "StringArray" \ + --property-variableName "varName" \ + --property-name "valid" \ + --property-min "François" \ + --array-alt "--help" + run Options2::validateCommandObject argFunction + assert_output --partial "ERROR - Options2::validateCommandObject - min value should be an integer greater than or equal to 0" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateCommandObject::StringArray::minValueLessThan0 { #@test + Object::create \ + --function-name "argFunction" \ + --type "Command" \ + --property-variableType "StringArray" \ + --property-variableName "varName" \ + --property-name "valid" \ + --property-min "-1" \ + --array-alt "--help" + run Options2::validateCommandObject argFunction + assert_output --partial "ERROR - Options2::validateCommandObject - min value should be an integer greater than or equal to 0" + assert_failure 2 + assert_lines_count 1 +} + + +function Options2::validateCommandObject::StringArray::minValueGreaterThanMaxValue { #@test + Object::create \ + --function-name "argFunction" \ + --type "Command" \ + --property-variableType "StringArray" \ + --property-variableName "varName" \ + --property-name "valid" \ + --property-min "3" \ + --property-max "1" \ + --array-alt "--help" + run Options2::validateCommandObject argFunction + assert_output --partial "ERROR - Options2::validateCommandObject - max value should be greater than min value" + assert_failure 2 + assert_lines_count 1 +} \ No newline at end of file diff --git a/src/Options2/validateCommandObject.sh b/src/Options2/validateCommandObject.sh new file mode 100755 index 00000000..b2ce2704 --- /dev/null +++ b/src/Options2/validateCommandObject.sh @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +# @description Validates command properties created +# using `Object::create` +# +# #### Example +# +# ```bash +# declare Object::create \ +# --function-name "commandFunction" \ +# --type "Option" \ +# --property-variableName "varName" +# +# Options2::validateCommandObject "${commandFunction}" +# ``` +# #### Arg Structure +# +# - --function-name (optional) the name of the function that will be generated +# - --type "Command" +# - --property-name (optional) provides the name of the command (Default: name of current command file without path) +# - --property-shortDescription (optional) provides command short description (Default: Empty string) +# - --property-longDescription (optional) provides command long description (Default: Empty string) +# - --property-version (optional) provides version section help. Section not generated if not provided. (Default: Empty string) +# - --property-author (optional) provides author section help. Section not generated if not provided. +# - --property-license (optional) provides License section. Section not generated if not provided. +# - --property-sourceFile (optional) provides Source file section. Section not generated if not provided. +# - --property-copyright (optional) provides copyright section. Section not generated if not provided. +# +# - --array-unknownOptionCallback (0 or more) the callback called when an option is unknown (Default: options parser display error message if option provided does not match any specified options). +# - --array-unknownArgumentCallback (0 or more) the callback called when an argument is unknown (Default: parser does not report any error). +# - --array-everyOptionCallback (0 or more) the callback called for every option. +# - --array-everyArgumentCallback (0 or more) the callback called for every argument. +# - --array-callback (0 or more) the callback called when all options and arguments have been parsed. +# +# - --array-element (1 or more) list of option/arguments objects +# +# Example: +# ```bash +# Object::create \ +# --function-name command" \ +# --type "Command" \ +# --array-callback "callback" +# Options2::validateCommandObject +# +# @exitcode 1 if mandatory parameter missing +# @exitcode 2 if invalid parameter provided +# @stderr diagnostics information is displayed +Options2::validateCommandObject() { + if (( $# != 1 )); then + Log::displayError "Options2::validateCommandObject - exactly one parameter has to be provided" + return 1 + fi + + local cmdInstanceObject=$1 + if [[ "$("${cmdInstanceObject}" type 2>/dev/null || echo '')" != "Command" ]]; then + Log::displayError "Options2::validateCommandObject - passed object is not a command" + return 2 + fi + + # name + local name + if "${cmdInstanceObject}" get name &>/dev/null; then + name="$("${cmdInstanceObject}" get name)" + if ! Assert::validVariableName "${name}"; then + Log::displayError "Options2::validateCommandObject - invalid command name ${name}" + return 2 + fi + fi + + # callback + checkCallbacks() { + local callbackType="$1" + if "${cmdInstanceObject}" get "${callbackType}" &>/dev/null; then + local callbacks + callbacks="$("${cmdInstanceObject}" get "${callbackType}")" + local callback + while IFS= read -r callback ; do + if [[ $(type -t "${callback}") = "function" ]]; then + Log::displayError "Options2::validateCommandObject - only function can be passed as callback - invalid '${callback}'" + return 2 + fi + done <<< "${callbacks}" + fi + } + checkCallbacks "unknownOptionCallback" + checkCallbacks "unknownArgumentCallback" + checkCallbacks "everyOptionCallback" + checkCallbacks "everyArgumentCallback" + checkCallbacks "callback" + + # option/argument list + if ! "${cmdInstanceObject}" get element &>/dev/null; then + Log::displayError "Options2::validateCommandObject - at least one option or argument must be provided" + return 1 + fi + local -& argumentList=() + local elements + elements="$("${cmdInstanceObject}" get element)" + local element + while IFS= read -r element ; do + # chekc element type is Option or Arg + if "${element}" type &>/dev/null; then + Log::displayError "Options2::validateCommandObject - only object can be passed as element - invalid '${element}'" + return 2 + fi + local elementType + elementType="$("${element}" type 2>/dev/null)" + if Array::contains "${elementType}" "Option" "Arg"; then + Log::displayError "Options2::validateOptionObject - Element ${elementType} is not a valid object type" + return 2 + fi + + # check variable name is not used by another option/argument + local variableName + variableName="$("${element}" get variableName)" || { + Log::displayError "Options2::validateOptionObject - ${elementType} ${element} - command variableName failed" + return 1 + } + if Array::contains "${variableName}" "${variableNameList[@]}"; then + Log::displayError "Options2::validateOptionObject - ${elementType} ${element} - variable name ${variableName} is already used by a previous option/argument" + return 2 + fi + variableNameList+=("${variableName}") + + # check alts not duplicated + if [[ "${elementType}" = "Option" ]]; then + local optionAlts + optionAlts="$("${element}" get alt)" || { + Log::displayError "Options2::validateOptionObject - Option ${element} - command alt failed" + return 1 + } + local optionAlt + while IFS= read -r optionAlt ; do + if Array::contains "${optionAlt}" "${altList[@]}"; then + Log::displayError "Options2::validateOptionObject - Option ${element} - alt ${optionAlt} is already used by a previous Option" + return 1 + fi + altList+=("${optionAlt}") + done <<< "${optionAlts}" + elif [[ "${elementType}" = "Arg" ]]; then + argumentList+=("${element}") + fi + done <<< "${elements}" + + # check arguments coherence + local currentArg currentArgMin currentArgMax + local optionalArg="" + for currentArg in "${argumentList[@]}"; do + currentArgMin="$("${currentArg}" get min)" || { + Log::displayError "Options2::validateOptionObject - Argument ${currentArg} - command min failed" + return 1 + } + currentArgMax="$("${currentArg}" get max)" || { + Log::displayError "Options2::validateOptionObject - Argument ${currentArg} - command max failed" + return 1 + } + if ((currentArgMin != currentArgMax)); then + optionalArg="$("${currentArg}" variableName)" + elif [[ -n "${optionalArg}" ]]; then + Log::displayError "Options2::validateOptionObject - variable list argument $("${currentArg}" variableName) after an other variable list argument ${optionalArg}, it would not be possible to discriminate them" + return 1 + fi + done +} diff --git a/src/Options2/validateGroupObject.bats b/src/Options2/validateGroupObject.bats new file mode 100755 index 00000000..e084fe6f --- /dev/null +++ b/src/Options2/validateGroupObject.bats @@ -0,0 +1,64 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Options/_bats.sh +source "${srcDir}/Options/_bats.sh" +# shellcheck source=src/Options2/__all.sh +source "${srcDir}/Options2/__all.sh" + +function setup() { + export TMPDIR="${BATS_TEST_TMPDIR}" + export _COMPILE_ROOT_DIR="${FRAMEWORK_ROOT_DIR}" +} + +function Options2::validateGroupObject::noOption { #@test + run Options2::validateGroupObject + assert_lines_count 1 + assert_output --partial "ERROR - Options2::validateGroupObject - exactly one parameter has to be provided" + assert_failure 1 +} + +function Options2::validateGroupObject::invalidObject { #@test + function invalidObject() { + : + } + run Options2::validateGroupObject invalidObject + assert_lines_count 1 + assert_output --partial "ERROR - Options2::validateGroupObject - passed object is not a group" + assert_failure 2 +} + +function Options2::validateGroupObject::notAGroup { #@test + Object::create \ + --type "NotAGroup" \ + --function-name "notAGroupFunction" + + run Options2::validateGroupObject notAGroupFunction + assert_lines_count 1 + assert_output --partial "ERROR - Options2::validateGroupObject - passed object is not a group" + assert_failure 2 +} + +function Options2::validateGroupObject::missingTitle { #@test + Object::create \ + --type "Group" \ + --function-name "simpleObjectFunction" + + run Options2::validateGroupObject simpleObjectFunction + assert_output --partial "ERROR - Options2::validateGroupObject - title is mandatory" + assert_failure 3 + assert_lines_count 1 +} + +function Options::validateGroupObject::groupOptionValid { #@test + local status=0 + Object::create \ + --type "Group" \ + --property-title "Global options" \ + --property-help "help" \ + --function-name "groupObjectFunction" + run Options2::validateGroupObject groupObjectFunction >"${BATS_TEST_TMPDIR}/result" 2>&1 + assert_success + assert_output "" +} diff --git a/src/Options2/validateGroupObject.sh b/src/Options2/validateGroupObject.sh new file mode 100755 index 00000000..e5f0767b --- /dev/null +++ b/src/Options2/validateGroupObject.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash + +# @description Generates a function that allows to manipulate a group of options. +# function generated allows group options using `--group` option when +# using `Options::generateOption` +# +# #### Output on stdout +# +# By default the name of the random generated function name +# is displayed as output of this function. +# By providing the option `--function-name`, the output of this +# function will be the generated function itself with the chosen name. +# +# #### Syntax +# +# ```text +# Usage: Options2::validateGroupObject [OPTIONS] +# +# OPTIONS: +# --title +# [--help ] +# [--function-name ] +# ``` +# +# #### Example +# +# ```bash +# declare optionGroup="$( +# Options2::validateGroupObject \ +# --title "Command global options" \ +# --help "The Console component adds some predefined options to all commands:" +# )" +# Options::sourceFunction "${optionGroup}" +# "${optionGroup}" help +# ``` +# +# @option --title (mandatory) provides group title +# @option --help (optional) provides command description help +# @option --function-name (optional) the name of the function that will be generated +# @exitcode 1 if error during option parsing +# @exitcode 1 if bash-tpl error during template rendering +# @exitcode 2 if file generation error (only if functionName argument empty) +# @stderr diagnostics information is displayed +# @see [generateCommand function](#/doc/guides/Options/generateCommand) +# @see [generateOption function](#/doc/guides/Options/generateOption) +# @see [group function](#/doc/guides/Options/functionGroup) +Options2::validateGroupObject() { + if (( $# != 1 )); then + Log::displayError "Options2::validateGroupObject - exactly one parameter has to be provided" + return 1 + fi + + local groupInstanceObject=$1 + if [[ "$("${groupInstanceObject}" type 2>/dev/null || echo '')" != "Group" ]]; then + Log::displayError "Options2::validateGroupObject - passed object is not a group" + return 2 + fi + if ! "${groupInstanceObject}" get title &>/dev/null; then + Log::displayError "Options2::validateGroupObject - title is mandatory" + return 3 + fi +} diff --git a/src/Options2/validateOptionObject.bats b/src/Options2/validateOptionObject.bats new file mode 100755 index 00000000..c129010d --- /dev/null +++ b/src/Options2/validateOptionObject.bats @@ -0,0 +1,348 @@ +#!/usr/bin/env bash + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Options/_bats.sh +source "${srcDir}/Options/_bats.sh" +# shellcheck source=src/Options2/__all.sh +source "${srcDir}/Options2/__all.sh" + +function setup() { + export TMPDIR="${BATS_TEST_TMPDIR}" + export _COMPILE_ROOT_DIR="${FRAMEWORK_ROOT_DIR}" +} + +function Options2::validateOptionObject::noOption { #@test + run Options2::validateOptionObject + assert_lines_count 1 + assert_output --partial "ERROR - Options2::validateOptionObject - exactly one parameter has to be provided" + assert_failure 1 +} + +function Options2::validateOptionObject::missingValue { #@test + run Options2::validateOptionObject invalidObject + assert_lines_count 1 + assert_output --partial "ERROR - Options2::validateOptionObject - passed object is not an option" + assert_failure 2 +} + +function Options2::validateOptionObject::tooMuchArgs { #@test + Object::create \ + --function-name "optionFunction" \ + --type "Option" + run Options2::validateOptionObject optionFunction optionFunction + assert_lines_count 1 + assert_output --partial "ERROR - Options2::validateOptionObject - exactly one parameter has to be provided" + assert_failure 1 +} + +function Options2::validateOptionObject::invalidObjectType { #@test + Object::create \ + --function-name "notAnOptionFunction" \ + --type "NotAnOption" + + run Options2::validateOptionObject notAnOptionFunction + assert_lines_count 1 + assert_output --partial "ERROR - Options2::validateOptionObject - passed object is not an option" + assert_failure 2 +} + +function Options2::validateOptionObject::variableTypeMandatory { #@test + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableName "varName" + + run Options2::validateOptionObject optionFunction + assert_output --partial "ERROR - Options2::validateOptionObject - variableType is mandatory" + assert_lines_count 1 + assert_failure 1 +} + +function Options2::validateOptionObject::variableTypeInvalid { #@test + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableType "invalid" \ + --property-variableName "varName" + + run Options2::validateOptionObject optionFunction + assert_output --partial "ERROR - Options2::validateOptionObject - invalid variableType invalid" + assert_lines_count 1 + assert_failure 2 +} + +function Options2::validateOptionObject::variableNameMandatory { #@test + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableType "String" + + run Options2::validateOptionObject optionFunction + assert_output --partial "ERROR - Options2::validateOptionObject - variableName is mandatory" + assert_failure 1 + assert_lines_count 1 +} + +function Options2::validateOptionObject::variableNameInvalid { #@test + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableName "François" + + run Options2::validateOptionObject optionFunction + assert_output --partial "ERROR - Options2::validateOptionObject - invalid variableName François" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateOptionObject::missingAltOption { #@test + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableName "varName" \ + --property-variableType "String" + + run Options2::validateOptionObject optionFunction + assert_output --partial "ERROR - Options2::validateOptionObject - you must provide at least one alt option" + assert_lines_count 1 + assert_failure 1 +} + +function Options2::validateOptionObject::invalidAltValue { #@test + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableName "varName" \ + --property-variableType "String" \ + --array-alt "François" + + run Options2::validateOptionObject optionFunction + assert_output --partial "ERROR - Options2::validateOptionObject - invalid alt option value 'François'" + assert_lines_count 1 + assert_failure 2 +} + +function Options2::validateOptionObject::groupOptionInvalid { #@test + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableName "varName" \ + --property-variableType "String" \ + --property-group "invalidGroup" \ + --array-alt "--help" + + run Options2::validateOptionObject optionFunction + assert_output --partial "ERROR - Options2::validateOptionObject - Group invalidGroup - is not a valid group object" + assert_lines_count 1 + assert_failure 2 +} + +function Options2::validateOptionObject::groupOptionValid { #@test + Object::create \ + --type "Group" \ + --property-title "Global options" \ + --property-help "help" \ + --function-name "groupObjectFunction" + + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableName "varName" \ + --property-variableType "String" \ + --property-group "groupObjectFunction" \ + --array-alt "--help" + + local status=0 + run Options2::validateOptionObject optionFunction + assert_output "" + assert_success +} + +function Options2::validateOptionObject::callbackOptionInvalid { #@test + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableName "varName" \ + --property-variableType "String" \ + --array-alt "--help" \ + --array-callback "François" + + run Options2::validateOptionObject optionFunction + assert_output --partial "ERROR - Options2::validateOptionObject - only posix or bash framework function name are accepted - invalid 'François'" + assert_lines_count 1 + assert_failure 2 +} + +function Options2::validateOptionObject::callbackOptionValid { #@test + callback() { + : + } + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableName "varName" \ + --property-variableType "String" \ + --array-alt "--help" \ + --array-callback "callback" + run Options2::validateOptionObject optionFunction + assert_output "" + assert_success +} + +function Options2::validateOptionObject::Boolean::onValueMissingValue { #@test + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableType "Boolean" \ + --property-variableName "varName" \ + --property-onValue "" \ + --array-alt "--help" + run Options2::validateOptionObject optionFunction + assert_output --partial "ERROR - Options2::validateOptionObject - onValue cannot be empty" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateOptionObject::Boolean::offValueMissingValue { #@test + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableType "Boolean" \ + --property-variableName "varName" \ + --property-offValue "" \ + --array-alt "--help" + run Options2::validateOptionObject optionFunction + assert_output --partial "ERROR - Options2::validateOptionObject - offValue cannot be empty" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateOptionObject::Boolean::onOffSameValue { #@test + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableType "Boolean" \ + --property-variableName "varName" \ + --property-offValue "1" \ + --property-onValue "1" \ + --array-alt "--help" + run Options2::validateOptionObject optionFunction + assert_output --partial "ERROR - Options2::validateOptionObject - onValue and offValue cannot be equal" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateOptionObject::String::authorizedValuesValueInvalidValue { #@test + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableType "String" \ + --property-variableName "varName" \ + --property-authorizedValues " invalid | valid" \ + --array-alt "--help" + run Options2::validateOptionObject optionFunction + assert_output --partial "ERROR - Options2::validateOptionObject - authorizedValues invalid regexp ' invalid | valid'" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateOptionObject::StringArray::authorizedValuesValueInvalidValue { #@test + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableType "StringArray" \ + --property-variableName "varName" \ + --property-authorizedValues " invalid | valid" \ + --array-alt "--help" + run Options2::validateOptionObject optionFunction + assert_output --partial "ERROR - Options2::validateOptionObject - authorizedValues invalid regexp ' invalid | valid'" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateOptionObject::String::helpValueNameInvalidOption { #@test + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableType "String" \ + --property-variableName "varName" \ + --property-helpValueName "invalid help" \ + --array-alt "--help" + run Options2::validateOptionObject optionFunction + assert_output --partial "ERROR - Options2::validateOptionObject - helpValueName should be a single word 'invalid help'" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateOptionObject::StringArray::helpValueNameInvalidOption { #@test + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableType "StringArray" \ + --property-variableName "varName" \ + --property-helpValueName "invalid help" \ + --array-alt "--help" + run Options2::validateOptionObject optionFunction + assert_output --partial "ERROR - Options2::validateOptionObject - helpValueName should be a single word 'invalid help'" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateOptionObject::StringArray::minValueEmpty { #@test + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableType "StringArray" \ + --property-variableName "varName" \ + --property-min "" \ + --array-alt "--help" + run Options2::validateOptionObject optionFunction + assert_output --partial "ERROR - Options2::validateOptionObject - min value should be an integer greater than or equal to 0" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateOptionObject::StringArray::minValueInvalid { #@test + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableType "StringArray" \ + --property-variableName "varName" \ + --property-min "François" \ + --array-alt "--help" + run Options2::validateOptionObject optionFunction + assert_output --partial "ERROR - Options2::validateOptionObject - min value should be an integer greater than or equal to 0" + assert_failure 2 + assert_lines_count 1 +} + +function Options2::validateOptionObject::StringArray::minValueLessThan0 { #@test + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableType "StringArray" \ + --property-variableName "varName" \ + --property-min "-1" \ + --array-alt "--help" + run Options2::validateOptionObject optionFunction + assert_output --partial "ERROR - Options2::validateOptionObject - min value should be an integer greater than or equal to 0" + assert_failure 2 + assert_lines_count 1 +} + + +function Options2::validateOptionObject::StringArray::minValueGreaterThanMaxValue { #@test + Object::create \ + --function-name "optionFunction" \ + --type "Option" \ + --property-variableType "StringArray" \ + --property-variableName "varName" \ + --property-min "3" \ + --property-max "1" \ + --array-alt "--help" + run Options2::validateOptionObject optionFunction + assert_output --partial "ERROR - Options2::validateOptionObject - max value should be greater than min value" + assert_failure 2 + assert_lines_count 1 +} \ No newline at end of file diff --git a/src/Options2/validateOptionObject.sh b/src/Options2/validateOptionObject.sh new file mode 100755 index 00000000..9688480f --- /dev/null +++ b/src/Options2/validateOptionObject.sh @@ -0,0 +1,201 @@ +#!/usr/bin/env bash + +# @description Validates options properties created +# using `Object::create` +# +# #### Example +# +# ```bash +# declare Object::create \ +# --function-name "optionFunction" \ +# --type "Option" \ +# --property-variableName "varName" +# +# Options2::validateOptionObject "${optionFunction}" +# ``` +# #### Option Common Structure +# +# - --function-name (optional) the name of the function that will be generated +# - --type "Option" +# - --property-variableType (optional) option type (default: Boolean) +# - --property-variableName | --var (mandatory) provides the variable name that will be used to store the parsed options. +# - --property-mandatory (optional) as its name indicates, by default an option is optional. But using `--mandatory` you can make the option mandatory. An error will be generated if the option is not found during parsing arguments. +# - --property-help (optional) provides option help description (Default: Empty string) +# - --property-group (optional) the group to which the option will be attached. Grouped option will be displayed under that group. (Default: no group) +# - --array-alt (mandatory at least one) option name possibility, the string allowing to discriminate the option. +# - --array-callback (0 or several times) the callback called if the option is parsed successfully. The option value will be passed as parameter (several parameters if type StringArray). +# - --* (optional) Others options are passed to specific option handler depending on variable type +# +# #### Option Boolean +# +# Structure: +# +# - --property-offValue (optional) value set by default on the variable (Default: 0) +# - --property-onValue (optional) value set on the variable if option provided (Default: 1) +# +# #### Option String/StringArray +# +# Common Structure to String/StringArray: +# +# - --property-authorizedValues (optional) Indicates the possible value list separated by | character (Default: "" means no check) +# - --property-helpValueName (optional) Indicates the name of value of the option to display in help (Default: "String") +# - --property-mandatory (optional) if 1 then will set min value to 1 (except if min is already set) (Default: "0") +# +# Structure specific to String only +# +# - --property-defaultValue (optional) value set by default on the variable (Default: "") +# +# Structure specific to StringArray only +# +# - --property-min (optional) minimum number of options to provide (Defaults to 0 or 1 if mandatory). +# - --property-max (optional) maximum number of options to provide (Default "" means no limit) +# +# Example: +# ```bash +# Object::create \ +# --function-name "optionFunction" \ +# --type "Option" \ +# --property-variableType "Boolean" \ +# --property-variableName "varName" \ +# --array-alt "--help" \ +# --array-alt "-h" \ +# --array-callback "callback" +# ``` +# +# @exitcode 1 if mandatory parameter missing +# @exitcode 2 if invalid parameter provided +# @stderr diagnostics information is displayed +Options2::validateOptionObject() { + if (( $# != 1 )); then + Log::displayError "Options2::validateOptionObject - exactly one parameter has to be provided" + return 1 + fi + + local optionInstanceObject=$1 + if [[ "$("${optionInstanceObject}" type 2>/dev/null || echo '')" != "Option" ]]; then + Log::displayError "Options2::validateOptionObject - passed object is not an option" + return 2 + fi + + # variable name + if ! "${optionInstanceObject}" get variableName &>/dev/null; then + Log::displayError "Options2::validateOptionObject - variableName is mandatory" + return 1 + fi + local variableName + variableName="$("${optionInstanceObject}" get variableName)" + if ! Assert::validVariableName "${variableName}"; then + Log::displayError "Options2::validateOptionObject - invalid variableName ${variableName}" + return 2 + fi + + # variable type + if ! "${optionInstanceObject}" get variableType &>/dev/null; then + Log::displayError "Options2::validateOptionObject - variableType is mandatory" + return 1 + fi + local variableType + variableType="$("${optionInstanceObject}" get variableType)" + if ! Array::contains "${variableType}" "Boolean" "String" "StringArray"; then + Log::displayError "Options2::validateOptionObject - invalid variableType ${variableType}" + return 2 + fi + + # group + if "${optionInstanceObject}" get group &>/dev/null; then + local groupFunction + groupFunction="$("${optionInstanceObject}" get group)" + if [[ "$("${groupFunction}" type 2>/dev/null)" != "Group" ]]; then + Log::displayError "Options2::validateOptionObject - Group ${groupFunction} - is not a valid group object" + return 2 + fi + fi + + # alts + if ! "${optionInstanceObject}" get alt &>/dev/null; then + Log::displayError "Options2::validateOptionObject - you must provide at least one alt option" + return 1 + fi + local alts + alts="$("${optionInstanceObject}" get alt)" + local alt + while IFS= read -r alt ; do + if ! Options::assertAlt "${alt}"; then + Log::displayError "Options2::validateOptionObject - invalid alt option value '${alt}'" + return 2 + fi + done <<< "${alts}" + + # callback + if "${optionInstanceObject}" get callback &>/dev/null; then + local callbacks + callbacks="$("${optionInstanceObject}" get callback)" + local callback + while IFS= read -r callback ; do + if + ! Assert::posixFunctionName "${callback}" && + ! Assert::bashFrameworkFunction "${callback}" + then + Log::displayError "Options2::validateOptionObject - only posix or bash framework function name are accepted - invalid '${callback}'" + return 2 + fi + done <<< "${callbacks}" + fi + + if [[ "${variableType}" = "Boolean" ]]; then + local onValue + onValue="$("${optionInstanceObject}" get onValue 2>/dev/null)" || onValue="1" + if [[ -z "${onValue}" ]]; then + Log::displayError "Options2::validateOptionObject - onValue cannot be empty" + return 2 + fi + local offValue + offValue="$("${optionInstanceObject}" get offValue 2>/dev/null)" || offValue="0" + if [[ -z "${offValue}" ]]; then + Log::displayError "Options2::validateOptionObject - offValue cannot be empty" + return 2 + fi + if [[ "${onValue}" = "${offValue}" ]]; then + Log::displayError "Options2::validateOptionObject - onValue and offValue cannot be equal" + return 2 + fi + elif [[ "${variableType}" = "String" || "${variableType}" = "StringArray" ]]; then + + local authorizedValues + authorizedValues="$("${optionInstanceObject}" get authorizedValues 2>/dev/null)" || authorizedValues="" + if [[ "${authorizedValues}" =~ [[:space:]] ]]; then + Log::displayError "Options2::validateOptionObject - authorizedValues invalid regexp '${authorizedValues}'" + return 2 + fi + + local helpValueName + helpValueName="$("${optionInstanceObject}" get helpValueName 2>/dev/null)" || helpValueName="" + if [[ -n "${helpValueName}" && ! "${helpValueName}" =~ ^[A-Za-z0-9_-]+$ ]]; then + Log::displayError "Options2::validateOptionObject - helpValueName should be a single word '${helpValueName}'" + return 2 + fi + + if [[ "${variableType}" = "StringArray" ]]; then + + local min + min="$("${optionInstanceObject}" get min 2>/dev/null)" || min="0" + if [[ ! "${min}" =~ ^[0-9]+$ ]]; then + Log::displayError "Options2::validateOptionObject - min value should be an integer greater than or equal to 0" + return 2 + fi + + local max + max="$("${optionInstanceObject}" get max 2>/dev/null)" || max="-1" + if [[ -n "${max}" && ! "${max}" =~ ^([1-9][0-9]*|-1)$ ]]; then + Log::displayError "Options2::validateOptionObject - max value should be an integer greater than 0 or -1" + return 2 + fi + + if ((max != -1 && min > max)); then + Log::displayError "Options2::validateOptionObject - max value should be greater than min value" + return 2 + fi + fi + + fi +} From 8c81c477bf0378107008028267a9aa7ce33c123f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Chastanet?= Date: Fri, 22 Dec 2023 11:45:20 +0100 Subject: [PATCH 4/9] Object::create version 2 --- src/Object/__all.sh | 6 ++ src/Object/create.bats | 123 ++++++++++++++++---------------- src/Object/create.sh | 157 +++++++++++++++++++++++++---------------- 3 files changed, 163 insertions(+), 123 deletions(-) create mode 100755 src/Object/__all.sh diff --git a/src/Object/__all.sh b/src/Object/__all.sh new file mode 100755 index 00000000..5c49b61d --- /dev/null +++ b/src/Object/__all.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +# shellcheck source=src/Object/create.sh +source "${FRAMEWORK_ROOT_DIR}/src/Object/create.sh" +# shellcheck source=/src/Crypto/uuidV4.sh +source "${FRAMEWORK_ROOT_DIR}/src/Crypto/uuidV4.sh" diff --git a/src/Object/create.bats b/src/Object/create.bats index 90459838..1025bd3e 100644 --- a/src/Object/create.bats +++ b/src/Object/create.bats @@ -4,59 +4,69 @@ # shellcheck source=src/batsHeaders.sh source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" -# shellcheck source=src/Object/create.sh -source "${srcDir}/Object/create.sh" +# shellcheck source=src/Object/__all.sh +source "${srcDir}/Object/__all.sh" # shellcheck source=src/Assert/posixFunctionName.sh source "${srcDir}/Assert/posixFunctionName.sh" # shellcheck source=src/Array/contains.sh source "${srcDir}/Array/contains.sh" function Object::create::simpleObject { #@test - Object::create \ + declare simpleObjectFunction + Object::create simpleObjectFunction \ --type "simpleObjectType" \ - --function-name "simpleObjectFunction" \ --property-property "propertyValue" - run simpleObjectFunction type + run ${simpleObjectFunction} type assert_output "simpleObjectType" - run simpleObjectFunction strict + run ${simpleObjectFunction} strict assert_output "1" - run simpleObjectFunction functionName - assert_output "simpleObjectFunction" + run ${simpleObjectFunction} functionName + [[ "${simpleObjectFunction}" =~ ^[0-9a-f]{32}$ ]] - run simpleObjectFunction get property + run ${simpleObjectFunction} getProperty property assert_output "propertyValue" - run simpleObjectFunction invalidCommand + run ${simpleObjectFunction} invalidCommand assert_output --partial "ERROR - invalid command invalidCommand" assert_failure 1 - run simpleObjectFunction get propertyUnknown + run ${simpleObjectFunction} getProperty propertyUnknown assert_output --partial "ERROR - unknown property propertyUnknown" assert_failure 2 } +function Object::create::missingPositionalArg { #@test + declare missingPositionalArg + run Object::create \ + --type "simpleObjectType" \ + --propertyInvalid-property "propertyValue" 2>&1 + + assert_output --partial "local: \`--type': invalid variable name for name reference" + assert_failure 1 +} + function Object::create::simpleObjectNonStrict { #@test - Object::create \ + declare simpleObjectType + Object::create simpleObjectType \ --strict 0 \ --type "simpleObjectType" \ - --function-name "simpleObjectFunction" \ --property-property "propertyValue" - run simpleObjectFunction strict + run ${simpleObjectType} strict assert_output "0" - run simpleObjectFunction get propertyUnknown + run ${simpleObjectType} getProperty propertyUnknown assert_output "" assert_success } function Object::create::invalidProperty { #@test - run Object::create \ + declare simpleObjectType + run Object::create simpleObjectType \ --type "simpleObjectType" \ - --function-name "simpleObjectFunction" \ --propertyInvalid-property "propertyValue" 2>&1 assert_output --partial "ERROR - invalid object property --propertyInvalid-property" @@ -64,76 +74,66 @@ function Object::create::invalidProperty { #@test } function Object::create::duplicatedProperty { #@test - run Object::create \ + declare duplicatedProperty + run Object::create duplicatedProperty \ --type "simpleObjectType" \ - --function-name "simpleObjectFunction" \ --property-property "propertyValue1" \ --property-property "propertyValue2" 2>&1 assert_output --partial "ERROR - property property is provided more than one time" - assert_failure 6 -} - -function Object::create::invalidFunctionName { #@test - run Object::create \ - --type "simpleObjectType" \ - --function-name "invalidéFunctionName" \ - --property-property "propertyValue" 2>&1 - - assert_output --partial "ERROR - invalid object function name invalidéFunctionName" - assert_failure 4 -} - -function Object::create::missingFunctionName { #@test - run Object::create \ - --type "simpleObjectType" \ - --property-property "propertyValue" 2>&1 - - assert_output --partial "ERROR - missing object function name" - assert_failure 3 + assert_failure 1 } - function Object::create::invalidObjectType { #@test - run Object::create \ + declare invalidObjectType + run Object::create invalidObjectType \ --type "invalidéObjectType" \ - --function-name "simpleFunctionName" \ --property-property "propertyValue" 2>&1 assert_output --partial "ERROR - invalid object type invalidéObjectType" - assert_failure 5 + assert_failure 1 } function Object::create::missingObjectType { #@test - run Object::create \ - --function-name "simpleFunctionName" \ + run Object::create missingObjectType \ --property-property "propertyValue" 2>&1 assert_output --partial "ERROR - missing object type" + assert_failure 1 +} + +function Object::create::unknownArray { #@test + declare unknownArray + Object::create unknownArray \ + --type "simpleObjectType" \ + --array-list "unknownArray" 2>&1 + + run ${unknownArray} getArray "unknownArray" + + assert_output --partial "ERROR - unknown array unknownArray" assert_failure 2 } function Object::create::propertyArrayOrdered { #@test - Object::create \ + declare propertyArrayOrdered + Object::create propertyArrayOrdered \ --type "simpleObjectType" \ - --function-name "simpleObjectFunction" \ --property-property "propertyValue" \ --array-list "value1" \ --array-list "value2" - run simpleObjectFunction type + run ${propertyArrayOrdered} type assert_success assert_output "simpleObjectType" - run simpleObjectFunction functionName - assert_success - assert_output "simpleObjectFunction" + run ${propertyArrayOrdered} functionName + [[ "${output}" =~ ^[0-9a-f]{32}$ ]] - run simpleObjectFunction get property + run ${propertyArrayOrdered} getProperty property assert_success assert_output "propertyValue" - run simpleObjectFunction get list + run ${propertyArrayOrdered} getArray list assert_success assert_lines_count 2 assert_line --index 0 "value1" @@ -141,34 +141,33 @@ function Object::create::propertyArrayOrdered { #@test } function Object::create::propertyArrayUnordered { #@test - Object::create \ + declare propertyArrayUnordered + Object::create propertyArrayUnordered \ --type "simpleObjectType" \ --array-list "value1" \ - --function-name "simpleObjectFunction" \ --array-list "value2" \ --property-property "propertyValue" \ --array-list "value3" - run simpleObjectFunction type + run ${propertyArrayUnordered} type assert_success assert_output "simpleObjectType" - run simpleObjectFunction functionName - assert_success - assert_output "simpleObjectFunction" + run ${propertyArrayUnordered} functionName + [[ "${output}" =~ ^[0-9a-f]{32}$ ]] - run simpleObjectFunction get property + run ${propertyArrayUnordered} getProperty property assert_success assert_output "propertyValue" - run simpleObjectFunction get list + run ${propertyArrayUnordered} getArray list assert_success assert_lines_count 3 assert_line --index 0 "value1" assert_line --index 1 "value2" assert_line --index 2 "value3" - run simpleObjectFunction getMembers + run ${propertyArrayUnordered} getMembers assert_success assert_lines_count 2 assert_line --index 0 "list" diff --git a/src/Object/create.sh b/src/Object/create.sh index cafe1230..45889ea1 100644 --- a/src/Object/create.sh +++ b/src/Object/create.sh @@ -1,73 +1,116 @@ #!/bin/bash +# @description create a simili object based on function generation +# @exitcode 1 invalid command or invalid parameter +# @warning this function is using eval feature which can be dangerous +# with unchecked data Object::create() { + local -n objectCreateVariable=$1 + shift || true + # shellcheck disable=SC2016 createTemplateFunction() { local type="$1" local functionName="$2" shift 2 || true local -a properties=("$@") - local propertiesLength="${#properties[@]}" - - local -a allMembers=() - ((i=0)) || true - mapfile -t allMembers < <( - while ((i < propertiesLength)); do - echo "${properties[${i}]}" | sed -E 's/--(property|array)-//' - ((i=i+2)) - done | sort -u - ) + echo "${functionName}() {" - # shellcheck disable=SC2016 echo ' local command="$1"' echo " local strict='${strict}'" echo -n ' '; declare -p properties - # shellcheck disable=SC2016 + echo ' local -i propertiesLength="${#properties[@]}"' echo ' if [[ "${command}" = "type" ]]; then' echo " echo '${type}'" - # shellcheck disable=SC2016 echo ' elif [[ "${command}" = "functionName" ]]; then' echo " echo '${functionName}'" - # shellcheck disable=SC2016 echo ' elif [[ "${command}" = "strict" ]]; then' echo " echo '${strict}'" - # shellcheck disable=SC2016 - echo ' elif [[ "${command}" = "get" ]]; then' - echo ' local i=0 || true' - # shellcheck disable=SC2016 - echo ' local propertyName="$2"' - # shellcheck disable=SC2016 - echo ' local propertyFound="0"' - echo " while ((i < ${propertiesLength})); do" - # shellcheck disable=SC2016 - echo ' if [[ "${properties[${i}]}" =~ ^--property- && "${properties[${i}]#--property-}" = "${propertyName}" ]]; then' - # shellcheck disable=SC2016 - echo ' echo "${properties[$((i+1))]}"' - echo ' return 0' - # shellcheck disable=SC2016 - echo ' elif [[ "${properties[${i}]}" =~ ^--array- && "${properties[${i}]#--array-}" = "${propertyName}" ]]; then' - echo ' propertyFound="1"' - # shellcheck disable=SC2016 - echo ' echo "${properties[$((i+1))]}"' - echo ' fi' - echo ' ((i=i+2))' - echo ' done' - # shellcheck disable=SC2016 - echo ' if [[ "${strict}" = "1" && "${propertyFound}" = "0" ]]; then' - # shellcheck disable=SC2016 - echo ' Log::displayError "unknown property ${propertyName}"' - echo ' return 2' - echo ' fi' - # shellcheck disable=SC2016 + echo ' elif [[ "${command}" = "getProperty" ]]; then' + echo ' local -i i=0 || true' + echo ' local propertyName="$2"' + echo ' local propertyFound="0"' + echo ' while ((i < propertiesLength)); do' + echo ' if [[ "${properties[${i}]}" = "--property-${propertyName}" ]]; then' + echo ' echo "${properties[$((i+1))]}"' + echo ' return 0' + echo ' fi' + echo ' ((i=i+2))' + echo ' done' + echo ' if [[ "${strict}" = "1" && "${propertyFound}" = "0" ]]; then' + echo ' Log::displayError "unknown property ${propertyName}"' + echo ' return 2' + echo ' fi' + echo ' elif [[ "${command}" = "setProperty" ]]; then' + echo ' local i=0 || true' + echo ' local propertyName="$2"' + echo ' local propertyValue="$3"' + echo ' local -a newProperties=()' + echo ' local propertyFound="0"' + echo ' while ((i < propertiesLength)); do' + echo ' if [[ "${properties[${i}]}" = "--property-${propertyName}" ]]; then' + echo ' propertyFound="1"' + echo ' newProperties+=("${properties[${i}]}" "${propertyValue}" "${properties[@]:i+2}")' + echo ' if ((i < propertiesLength-2)); then' + echo ' newProperties+=("${properties[${i}]}" "${properties[$((i + 1))]}")' + echo ' fi' + echo ' break' + echo ' fi' + echo ' newProperties+=("${properties[${i}]}" "${properties[$((i + 1))]}")' + echo ' ((i=i+2))' + echo ' done' + echo ' if [[ "${propertyFound}" = "0" ]]; then' + echo ' newProperties+=("--property-${propertyName}" "${propertyValue}")' + echo ' fi' + echo " eval \"\$(createTemplateFunction \"${type}\" \"${functionName}\" \"\${newProperties[@]}\")\"" + echo ' elif [[ "${command}" = "getArray" ]]; then' + echo ' local -i i=0 || true' + echo ' local propertyName="$2"' + echo ' local propertyFound="0"' + echo ' while ((i < propertiesLength)); do' + echo ' if [[ "${properties[${i}]}" = "--array-${propertyName}" ]]; then' + echo ' propertyFound="1"' + echo ' echo "${properties[$((i+1))]}"' + echo ' fi' + echo ' ((i=i+2))' + echo ' done' + echo ' if [[ "${strict}" = "1" && "${propertyFound}" = "0" ]]; then' + echo ' Log::displayError "unknown array ${propertyName}"' + echo ' return 2' + echo ' fi' + echo ' elif [[ "${command}" = "setArray" ]]; then' + echo ' local -i i=0 || true' + echo ' local arrayName="$2"' + echo ' local -a arrayValues=("$@")' + echo ' local -a newProperties=()' + echo ' local propertyFound="0"' + echo ' while ((i < propertiesLength)); do' + echo ' if [[ "${properties[${i}]}" = "--array-${propertyName}" ]]; then' + echo ' propertyFound="1"' + echo ' newProperties+=("${properties[${i}]}" "${propertyValue}")' + echo ' if ((i < propertiesLength-2)); then' + echo ' newProperties+=("${properties[@]:i+2}");' + echo ' fi' + echo ' break' + echo ' fi' + echo ' newProperties+=("${properties[${i}]}" "${properties[$((i + 1))]}")' + echo ' ((i=i+2))' + echo ' done' + echo ' if [[ "${propertyFound}" = "0" ]]; then' + echo ' newProperties+=("--property-${propertyName}" "${propertyValue}")' + echo ' fi' + echo " eval \"\$(createTemplateFunction \"${type}\" \"${functionName}\" \"\${newProperties[@]}\")\"" echo ' elif [[ "${command}" = "getMembers" ]]; then' - # shellcheck disable=SC2028 - echo " printf '%s\n' ${allMembers[*]}" + echo ' while ((i < propertiesLength)); do' + echo ' echo "${properties[${i}]}" | sed -E "s/--(property|array)-//"' + echo ' ((i=i+2))' + echo ' done | sort -u' echo ' else' - # shellcheck disable=SC2016 echo ' Log::displayError "invalid command ${command}"' echo ' return 1' echo ' fi' echo '}' } + local type functionName local strict="1" local -a properties=() @@ -77,10 +120,6 @@ Object::create() { shift || true type="$1" ;; - --function-name) - shift || true - functionName="$1" - ;; --strict) # strict means that property non existence is failing with error shift || true @@ -89,7 +128,7 @@ Object::create() { --property-*) if Array::contains "$1" "${properties[@]}"; then Log::displayError "property ${1#--property-} is provided more than one time" - return 6 + return 1 fi properties+=("$1" "$2") shift || true @@ -107,20 +146,16 @@ Object::create() { if [[ -z "${type}" ]]; then Log::displayError "missing object type" - return 2 + return 1 fi if ! Assert::posixFunctionName "${type}"; then Log::displayError "invalid object type ${type}" - return 5 + return 1 fi - if [[ -z "${functionName}" ]]; then - Log::displayError "missing object function name" - return 3 - fi - if ! Assert::posixFunctionName "${functionName}"; then - Log::displayError "invalid object function name ${functionName}" - return 4 - fi - + functionName="$(Crypto::uuidV4)" + functionName="${functionName//-/}" + eval "$(createTemplateFunction "${type}" "${functionName}" "${properties[@]}")" + # shellcheck disable=SC2034 + objectCreateVariable=${functionName} } From 401a9eba23c598500216a1f1e644e69800e9d337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Chastanet?= Date: Fri, 22 Dec 2023 14:05:55 +0100 Subject: [PATCH 5/9] New way to create objects with array variable instead of function templating and removing the need of eval new functions: - Object::getArray - Object::setArray - Object::getProperty - Object::setProperty --- manualTests/Object::setProperty.sh | 19 ++++++++++ src/Object/__all.sh | 8 ++++ src/Object/create.sh | 8 ++-- src/Object/getArray.bats | 60 ++++++++++++++++++++++++++++++ src/Object/getArray.sh | 22 +++++++++++ src/Object/getProperty.bats | 40 ++++++++++++++++++++ src/Object/getProperty.sh | 22 +++++++++++ src/Object/setArray.bats | 52 ++++++++++++++++++++++++++ src/Object/setArray.sh | 26 +++++++++++++ src/Object/setProperty.bats | 49 ++++++++++++++++++++++++ src/Object/setProperty.sh | 30 +++++++++++++++ testCreateObject.sh | 41 ++++++++++++++++++++ 12 files changed, 374 insertions(+), 3 deletions(-) create mode 100755 manualTests/Object::setProperty.sh create mode 100644 src/Object/getArray.bats create mode 100644 src/Object/getArray.sh create mode 100644 src/Object/getProperty.bats create mode 100644 src/Object/getProperty.sh create mode 100644 src/Object/setArray.bats create mode 100644 src/Object/setArray.sh create mode 100644 src/Object/setProperty.bats create mode 100644 src/Object/setProperty.sh create mode 100755 testCreateObject.sh diff --git a/manualTests/Object::setProperty.sh b/manualTests/Object::setProperty.sh new file mode 100755 index 00000000..c80ab8e2 --- /dev/null +++ b/manualTests/Object::setProperty.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +rootDir="$(cd "$(readlink -e "${BASH_SOURCE[0]%/*}")/.." && pwd -P)" +export FRAMEWORK_ROOT_DIR="${rootDir}" +export _COMPILE_ROOT_DIR="${rootDir}" + +srcDir="$(cd "${rootDir}/src" && pwd -P)" + +# shellcheck source=src/Object/__all.sh +source "${srcDir}/Object/__all.sh" +# shellcheck source=/src/Log/__all.sh +source "${srcDir}/Log/__all.sh" + +declare -a newPropertyObject=( + --type "simpleObjectType" + --property-property "propertyValue" +) +Object::setProperty newPropertyObject newProperty "value" +declare -p newPropertyObject \ No newline at end of file diff --git a/src/Object/__all.sh b/src/Object/__all.sh index 5c49b61d..057922ab 100755 --- a/src/Object/__all.sh +++ b/src/Object/__all.sh @@ -2,5 +2,13 @@ # shellcheck source=src/Object/create.sh source "${FRAMEWORK_ROOT_DIR}/src/Object/create.sh" +# shellcheck source=src/Object/getProperty.sh +source "${FRAMEWORK_ROOT_DIR}/src/Object/getProperty.sh" +# shellcheck source=src/Object/setProperty.sh +source "${FRAMEWORK_ROOT_DIR}/src/Object/setProperty.sh" +# shellcheck source=src/Object/getArray.sh +source "${FRAMEWORK_ROOT_DIR}/src/Object/getArray.sh" +# shellcheck source=src/Object/setArray.sh +source "${FRAMEWORK_ROOT_DIR}/src/Object/setArray.sh" # shellcheck source=/src/Crypto/uuidV4.sh source "${FRAMEWORK_ROOT_DIR}/src/Crypto/uuidV4.sh" diff --git a/src/Object/create.sh b/src/Object/create.sh index 45889ea1..3c0911fd 100644 --- a/src/Object/create.sh +++ b/src/Object/create.sh @@ -3,7 +3,9 @@ # @description create a simili object based on function generation # @exitcode 1 invalid command or invalid parameter # @warning this function is using eval feature which can be dangerous -# with unchecked data +# with unchecked data +# @deprecated as this version is using eval, prefer to use +# Object::getProperty version Object::create() { local -n objectCreateVariable=$1 shift || true @@ -49,9 +51,9 @@ Object::create() { echo ' while ((i < propertiesLength)); do' echo ' if [[ "${properties[${i}]}" = "--property-${propertyName}" ]]; then' echo ' propertyFound="1"' - echo ' newProperties+=("${properties[${i}]}" "${propertyValue}" "${properties[@]:i+2}")' + echo ' newProperties+=("${properties[${i}]}" "${propertyValue}")' echo ' if ((i < propertiesLength-2)); then' - echo ' newProperties+=("${properties[${i}]}" "${properties[$((i + 1))]}")' + echo ' newProperties+=("${properties[@]:i+2}")' echo ' fi' echo ' break' echo ' fi' diff --git a/src/Object/getArray.bats b/src/Object/getArray.bats new file mode 100644 index 00000000..d9f73565 --- /dev/null +++ b/src/Object/getArray.bats @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2154 +# shellcheck disable=SC2034 + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Object/__all.sh +source "${srcDir}/Object/__all.sh" +# shellcheck source=src/Assert/posixFunctionName.sh +source "${srcDir}/Assert/posixFunctionName.sh" +# shellcheck source=src/Array/contains.sh +source "${srcDir}/Array/contains.sh" + +function Object::getArray::simpleObject { #@test + declare -a simpleObject=( + --type "simpleObjectType" + --array-myList "elem1" + ) + run Object::getArray simpleObject myList 1 + assert_output "elem1" + assert_success + + run Object::getArray simpleObject myList 0 + assert_output "elem1" + assert_success +} + +function Object::getArray::multipleArrayValues { #@test + declare -a multipleArrayValues=( + --type "multipleArrayValuesType" + --array-myList "elem1" + --property-type "type" + --array-myList "elem2" + ) + run Object::getArray multipleArrayValues myList 1 + assert_lines_count 2 + assert_line --index 0 "elem1" + assert_line --index 1 "elem2" + assert_success + + run Object::getArray multipleArrayValues myList 0 + assert_lines_count 2 + assert_line --index 0 "elem1" + assert_line --index 1 "elem2" + assert_success +} + +function Object::getArray::unknownProperty { #@test + declare -a simpleObject=( + --type "simpleObjectType" + --property-property "propertyValue" + ) + run Object::getArray simpleObject unknownArray 1 + assert_output --partial "ERROR - unknown array unknownArray" + assert_failure 1 + + run Object::getArray simpleObject unknownArray 0 + assert_output "" + assert_success +} diff --git a/src/Object/getArray.sh b/src/Object/getArray.sh new file mode 100644 index 00000000..2a59b5f5 --- /dev/null +++ b/src/Object/getArray.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +Object::getArray() { + local -n object_get_array_objectData=$1 + local arrayName="${2:-}" + local strict="${3:-0}" + + local -i propertiesLength="${#object_get_array_objectData[@]}" + local -i i=0 || true + local arrayFound="0" + while ((i < propertiesLength)); do + if [[ "${object_get_array_objectData[${i}]}" = "--array-${arrayName}" ]]; then + arrayFound="1" + echo "${object_get_array_objectData[$((i+1))]}" + fi + ((i=i+2)) + done + if [[ "${strict}" = "1" && "${arrayFound}" = "0" ]]; then + Log::displayError "unknown array ${arrayName}" + return 1 + fi +} \ No newline at end of file diff --git a/src/Object/getProperty.bats b/src/Object/getProperty.bats new file mode 100644 index 00000000..82f92406 --- /dev/null +++ b/src/Object/getProperty.bats @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2154 +# shellcheck disable=SC2034 + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Object/__all.sh +source "${srcDir}/Object/__all.sh" +# shellcheck source=src/Assert/posixFunctionName.sh +source "${srcDir}/Assert/posixFunctionName.sh" +# shellcheck source=src/Array/contains.sh +source "${srcDir}/Array/contains.sh" + +function Object::getProperty::simpleObject { #@test + declare -a simpleObject=( + --type "simpleObjectType" + --property-property "propertyValue" + ) + run Object::getProperty simpleObject property 1 + assert_output "propertyValue" + assert_success + + run Object::getProperty simpleObject property 0 + assert_output "propertyValue" + assert_success +} + +function Object::getProperty::unknownProperty { #@test + declare -a simpleObject=( + --type "simpleObjectType" + --property-property "propertyValue" + ) + run Object::getProperty simpleObject unknownProperty 1 + assert_output --partial "ERROR - unknown property unknownProperty" + assert_failure 1 + + run Object::getProperty simpleObject unknownProperty 0 + assert_output "" + assert_success +} diff --git a/src/Object/getProperty.sh b/src/Object/getProperty.sh new file mode 100644 index 00000000..c60a68ee --- /dev/null +++ b/src/Object/getProperty.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +Object::getProperty() { + local -n object_get_property_objectData=$1 + local propertyName="${2:-}" + local strict="${3:-0}" + + local -i propertiesLength="${#object_get_property_objectData[@]}" + local -i i=0 || true + local propertyFound="0" + while ((i < propertiesLength)); do + if [[ "${object_get_property_objectData[${i}]}" = "--property-${propertyName}" ]]; then + echo "${object_get_property_objectData[$((i+1))]}" + return 0 + fi + ((i=i+2)) + done + if [[ "${strict}" = "1" && "${propertyFound}" = "0" ]]; then + Log::displayError "unknown property ${propertyName}" + return 1 + fi +} \ No newline at end of file diff --git a/src/Object/setArray.bats b/src/Object/setArray.bats new file mode 100644 index 00000000..d7ad367d --- /dev/null +++ b/src/Object/setArray.bats @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2154 +# shellcheck disable=SC2034 + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Object/__all.sh +source "${srcDir}/Object/__all.sh" +# shellcheck source=src/Assert/posixFunctionName.sh +source "${srcDir}/Assert/posixFunctionName.sh" +# shellcheck source=src/Array/contains.sh +source "${srcDir}/Array/contains.sh" + +function Object::setArray::simpleObject { #@test + declare -a simpleObject=( + --type "simpleObjectType" + --array-list "elem1" + --property-property "propertyValue" + ) + local status=0 + Object::setArray simpleObject list "newElem1" "newElem2" || status=1 + [[ "${status}" = "0" ]] + run echo "${simpleObject[@]}" + assert_output "--type simpleObjectType --property-property propertyValue --array-list newElem1 --array-list newElem2" +} + +function Object::setArray::multipleElements { #@test + declare -a multipleElements=( + --type "multipleElementsType" + --property-property "propertyValue" + --array-list "elem1" + --array-list "elem2" + --array-list "elem3" + ) + local status=0 + Object::setArray multipleElements list "newElem1" "newElem2" || status=1 + [[ "${status}" = "0" ]] + run echo "${multipleElements[@]}" + assert_output "--type multipleElementsType --property-property propertyValue --array-list newElem1 --array-list newElem2" +} + +function Object::setArray::newProperty { #@test + declare -a newPropertyObject=( + --type "simpleObjectType" + --property-property "propertyValue" + ) + local status=0 + Object::setArray newPropertyObject list "newElem1" "newElem2" || status=1 + [[ "${status}" = "0" ]] + run echo "${newPropertyObject[@]}" + assert_output "--type simpleObjectType --property-property propertyValue --array-list newElem1 --array-list newElem2" +} diff --git a/src/Object/setArray.sh b/src/Object/setArray.sh new file mode 100644 index 00000000..4e836f87 --- /dev/null +++ b/src/Object/setArray.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +Object::setArray() { + local -n object_set_array_objectData=$1 + local arrayName="${2:-}" + shift 2 || true + local -a arrayValues=("$@") + + local -i propertiesLength="${#object_set_array_objectData[@]}" + local -a newProperties=() + + # remove all array element + while ((i < propertiesLength)); do + if [[ "${object_set_array_objectData[${i}]}" != "--array-${arrayName}" ]]; then + newProperties+=("${object_set_array_objectData[@]:i:2}") + fi + ((i=i+2)) + done + + # add all new values + local arrayValue + for arrayValue in "${arrayValues[@]}"; do + newProperties+=("--array-${arrayName}" "${arrayValue}") + done + object_set_array_objectData=("${newProperties[@]}") +} \ No newline at end of file diff --git a/src/Object/setProperty.bats b/src/Object/setProperty.bats new file mode 100644 index 00000000..c29fc8ab --- /dev/null +++ b/src/Object/setProperty.bats @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2154 +# shellcheck disable=SC2034 + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Object/__all.sh +source "${srcDir}/Object/__all.sh" +# shellcheck source=src/Assert/posixFunctionName.sh +source "${srcDir}/Assert/posixFunctionName.sh" +# shellcheck source=src/Array/contains.sh +source "${srcDir}/Array/contains.sh" + +function Object::setProperty::simpleObject { #@test + declare -a simpleObject=( + --type "simpleObjectType" + --property-property "propertyValue" + ) + local status=0 + Object::setProperty simpleObject property "newPropertyValue" || status=1 + [[ "${status}" = "0" ]] + run echo "${simpleObject[@]}" + assert_output "--type simpleObjectType --property-property newPropertyValue" +} + +function Object::setProperty::multipleProperties { #@test + declare -a multipleProperties=( + --type "multiplePropertiesType" + --property-property "propertyValue" + --property-property2 "propertyValue2" + ) + local status=0 + Object::setProperty multipleProperties property "newPropertyValue" || status=1 + [[ "${status}" = "0" ]] + run echo "${multipleProperties[@]}" + assert_output "--type multiplePropertiesType --property-property newPropertyValue --property-property2 propertyValue2" +} + +function Object::setProperty::newProperty { #@test + declare -a newPropertyObject=( + --type "simpleObjectType" + --property-property "propertyValue" + ) + local status=0 + Object::setProperty newPropertyObject newProperty "value" || status=1 + [[ "${status}" = "0" ]] + run echo "${newPropertyObject[@]}" + assert_output "--type simpleObjectType --property-property propertyValue --property-newProperty value" +} diff --git a/src/Object/setProperty.sh b/src/Object/setProperty.sh new file mode 100644 index 00000000..22877c7a --- /dev/null +++ b/src/Object/setProperty.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +Object::setProperty() { + local -n object_set_property_objectData=$1 + local propertyName="${2:-}" + local propertyValue="${3:-}" + + local i=0 || true + local -i propertiesLength="${#object_set_property_objectData[@]}" + local -a newProperties=() + local propertyFound="0" + while ((i < propertiesLength)); do + if [[ "${object_set_property_objectData[${i}]}" = "--property-${propertyName}" ]]; then + propertyFound="1" + newProperties+=( + "${object_set_property_objectData[${i}]}" "${propertyValue}" + ) + if ((i < propertiesLength-2)); then + newProperties+=("${object_set_property_objectData[@]:i+2}") + fi + break + fi + newProperties+=("${object_set_property_objectData[@]:i:2}") + ((i=i+2)) + done + if [[ "${propertyFound}" = "0" ]]; then + newProperties+=("--property-${propertyName}" "${propertyValue}") + fi + object_set_property_objectData=("${newProperties[@]}") +} \ No newline at end of file diff --git a/testCreateObject.sh b/testCreateObject.sh new file mode 100755 index 00000000..4b02bedb --- /dev/null +++ b/testCreateObject.sh @@ -0,0 +1,41 @@ +#!/bin/bash +FRAMEWORK_ROOT_DIR=. +source src/Log/__all.sh +source src/Crypto/uuidV4.sh +source src/Object/create.sh +source src/Options2/__all.sh + +declare myFunction +Object::create myFunction \ + --type "Command" \ + --property-name "François" +declare myFunction2 +Object::create myFunction2 \ + --array-list "a" \ + --type "Command2" \ + --property-name "François2" \ + --array-list "b" \ + --array-list "c" + +echo "--------------------------------------------" +${myFunction} getProperty name +${myFunction2} getProperty name +${myFunction} getProperty name +${myFunction2} getProperty list + +echo "------------------- setProperty -------------------------" +${myFunction} setProperty name "myFunctionFrançois3" +${myFunction} getProperty name +${myFunction2} setProperty name "myFunction2François3" +${myFunction2} getProperty name +echo -n "name2 " +${myFunction2} setProperty name2 "newProperty name2" + +${myFunction2} getProperty name2 + +echo "--------------------------------------------" +Object::create myFunction2 \ + --function-name "argFunction2Overload" \ + --type "Command2Overload" \ + --property-name "François2Overload" +${myFunction2} getProperty name \ No newline at end of file From e092af191e5454fd0590bbf65ea461db79ff0bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Chastanet?= Date: Fri, 22 Dec 2023 18:39:53 +0100 Subject: [PATCH 6/9] Object array type with list terminator --- manualTests/Object::setArray.sh | 22 +++++++++++++++++++ src/Object/create.bats | 0 src/Object/create.sh | 0 src/Object/getArray.bats | 22 +++++++++++++++++-- src/Object/getArray.sh | 22 +++++++++++++------ src/Object/getProperty.bats | 31 +++++++++++++++++++++++++++ src/Object/getProperty.sh | 8 +++---- src/Object/setArray.bats | 38 +++++++++++++++++++++++++++------ src/Object/setArray.sh | 36 ++++++++++++++++++++----------- src/Object/setProperty.bats | 16 +++++++++++++- src/Object/setProperty.sh | 12 +++++------ 11 files changed, 168 insertions(+), 39 deletions(-) create mode 100755 manualTests/Object::setArray.sh mode change 100644 => 100755 src/Object/create.bats mode change 100644 => 100755 src/Object/create.sh mode change 100644 => 100755 src/Object/getArray.bats mode change 100644 => 100755 src/Object/getArray.sh mode change 100644 => 100755 src/Object/getProperty.bats mode change 100644 => 100755 src/Object/getProperty.sh mode change 100644 => 100755 src/Object/setArray.bats mode change 100644 => 100755 src/Object/setArray.sh mode change 100644 => 100755 src/Object/setProperty.bats mode change 100644 => 100755 src/Object/setProperty.sh diff --git a/manualTests/Object::setArray.sh b/manualTests/Object::setArray.sh new file mode 100755 index 00000000..39fd946c --- /dev/null +++ b/manualTests/Object::setArray.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +rootDir="$(cd "$(readlink -e "${BASH_SOURCE[0]%/*}")/.." && pwd -P)" +export FRAMEWORK_ROOT_DIR="${rootDir}" +export _COMPILE_ROOT_DIR="${rootDir}" + +srcDir="$(cd "${rootDir}/src" && pwd -P)" + +# shellcheck source=src/Object/__all.sh +source "${srcDir}/Object/__all.sh" +# shellcheck source=/src/Log/__all.sh +source "${srcDir}/Log/__all.sh" + +declare -a missingArrayTerminator=( + --type "missingArrayTerminatorType" + --array-list "elem1" "elem2" "elem3" + --property-property "propertyValue" +) +set -x +Object::setArray missingArrayTerminator list "newElem1" "newElem2" + +declare -p missingArrayTerminator diff --git a/src/Object/create.bats b/src/Object/create.bats old mode 100644 new mode 100755 diff --git a/src/Object/create.sh b/src/Object/create.sh old mode 100644 new mode 100755 diff --git a/src/Object/getArray.bats b/src/Object/getArray.bats old mode 100644 new mode 100755 index d9f73565..3633093e --- a/src/Object/getArray.bats +++ b/src/Object/getArray.bats @@ -28,9 +28,8 @@ function Object::getArray::simpleObject { #@test function Object::getArray::multipleArrayValues { #@test declare -a multipleArrayValues=( --type "multipleArrayValuesType" - --array-myList "elem1" + --array-myList "elem1" "elem2" -- --property-type "type" - --array-myList "elem2" ) run Object::getArray multipleArrayValues myList 1 assert_lines_count 2 @@ -58,3 +57,22 @@ function Object::getArray::unknownProperty { #@test assert_output "" assert_success } + +function Object::getArray::customTerminator { #@test + declare -a simpleObject=( + --type "simpleObjectType" + --array-myList "elem1" "elem2" "@@@" + --property-property "propertyValue" + ) + OBJECT_TEMPLATE_ARRAY_TERMINATOR="@@@" run Object::getArray simpleObject myList 1 + assert_line --index 0 "elem1" + assert_line --index 1 "elem2" + assert_lines_count 2 + assert_success + + OBJECT_TEMPLATE_ARRAY_TERMINATOR="@@@" run Object::getArray simpleObject myList 0 + assert_line --index 0 "elem1" + assert_line --index 1 "elem2" + assert_lines_count 2 + assert_success +} diff --git a/src/Object/getArray.sh b/src/Object/getArray.sh old mode 100644 new mode 100755 index 2a59b5f5..456a144b --- a/src/Object/getArray.sh +++ b/src/Object/getArray.sh @@ -4,19 +4,27 @@ Object::getArray() { local -n object_get_array_objectData=$1 local arrayName="${2:-}" local strict="${3:-0}" - + local -i propertiesLength="${#object_get_array_objectData[@]}" local -i i=0 || true - local arrayFound="0" while ((i < propertiesLength)); do if [[ "${object_get_array_objectData[${i}]}" = "--array-${arrayName}" ]]; then - arrayFound="1" - echo "${object_get_array_objectData[$((i+1))]}" + ((++i)) + # eat next elements until finding terminator + while ((i < propertiesLength)); do + if [[ "${object_get_array_objectData[${i}]}" = "${OBJECT_TEMPLATE_ARRAY_TERMINATOR:---}" ]]; then + return 0 + fi + echo "${object_get_array_objectData[${i}]}" + ((++i)) + done + return 0 fi - ((i=i+2)) + ((++i)) done - if [[ "${strict}" = "1" && "${arrayFound}" = "0" ]]; then + + if [[ "${strict}" = "1" ]]; then Log::displayError "unknown array ${arrayName}" return 1 fi -} \ No newline at end of file +} diff --git a/src/Object/getProperty.bats b/src/Object/getProperty.bats old mode 100644 new mode 100755 index 82f92406..4c7c47d7 --- a/src/Object/getProperty.bats +++ b/src/Object/getProperty.bats @@ -38,3 +38,34 @@ function Object::getProperty::unknownProperty { #@test assert_output "" assert_success } + +function Object::getProperty::withArray { #@test + declare -a simpleObject=( + --type "simpleObjectType" + --array-list "elem1" -- + --property-property "propertyValue" + ) + run Object::getProperty simpleObject property 1 + assert_output "propertyValue" + assert_success + + run Object::getProperty simpleObject property 0 + assert_output "propertyValue" + assert_success +} + +function Object::getProperty::property2 { #@test + declare -a simpleObject=( + --type "simpleObjectType" + --array-list "elem1" -- + --property-property "propertyValue" + --property-property2 "propertyValue2" + ) + run Object::getProperty simpleObject property2 1 + assert_output "propertyValue2" + assert_success + + run Object::getProperty simpleObject property2 0 + assert_output "propertyValue2" + assert_success +} diff --git a/src/Object/getProperty.sh b/src/Object/getProperty.sh old mode 100644 new mode 100755 index c60a68ee..da105656 --- a/src/Object/getProperty.sh +++ b/src/Object/getProperty.sh @@ -4,19 +4,19 @@ Object::getProperty() { local -n object_get_property_objectData=$1 local propertyName="${2:-}" local strict="${3:-0}" - + local -i propertiesLength="${#object_get_property_objectData[@]}" local -i i=0 || true local propertyFound="0" while ((i < propertiesLength)); do if [[ "${object_get_property_objectData[${i}]}" = "--property-${propertyName}" ]]; then - echo "${object_get_property_objectData[$((i+1))]}" + echo "${object_get_property_objectData[$((i + 1))]}" return 0 fi - ((i=i+2)) + ((i = i + 1)) done if [[ "${strict}" = "1" && "${propertyFound}" = "0" ]]; then Log::displayError "unknown property ${propertyName}" return 1 fi -} \ No newline at end of file +} diff --git a/src/Object/setArray.bats b/src/Object/setArray.bats old mode 100644 new mode 100755 index d7ad367d..1897a247 --- a/src/Object/setArray.bats +++ b/src/Object/setArray.bats @@ -14,29 +14,53 @@ source "${srcDir}/Array/contains.sh" function Object::setArray::simpleObject { #@test declare -a simpleObject=( --type "simpleObjectType" - --array-list "elem1" + --array-list "elem1" -- --property-property "propertyValue" ) local status=0 Object::setArray simpleObject list "newElem1" "newElem2" || status=1 [[ "${status}" = "0" ]] run echo "${simpleObject[@]}" - assert_output "--type simpleObjectType --property-property propertyValue --array-list newElem1 --array-list newElem2" + assert_output "--type simpleObjectType --property-property propertyValue --array-list newElem1 newElem2 --" } function Object::setArray::multipleElements { #@test declare -a multipleElements=( --type "multipleElementsType" + --array-list "elem1" "elem2" "elem3" -- --property-property "propertyValue" - --array-list "elem1" - --array-list "elem2" - --array-list "elem3" ) local status=0 Object::setArray multipleElements list "newElem1" "newElem2" || status=1 [[ "${status}" = "0" ]] run echo "${multipleElements[@]}" - assert_output "--type multipleElementsType --property-property propertyValue --array-list newElem1 --array-list newElem2" + assert_output "--type multipleElementsType --property-property propertyValue --array-list newElem1 newElem2 --" +} + +function Object::setArray::missingArrayTerminator { #@test + declare -a missingArrayTerminator=( + --type "missingArrayTerminatorType" + --array-list "elem1" "elem2" "elem3" + --property-property "propertyValue" + ) + local status=0 + Object::setArray missingArrayTerminator list "newElem1" "newElem2" || status=1 + [[ "${status}" = "0" ]] + run echo "${missingArrayTerminator[@]}" + assert_output "--type missingArrayTerminatorType --array-list newElem1 newElem2 --" +} + +function Object::setArray::customArrayTerminator { #@test + declare -a customArrayTerminator=( + --type "customArrayTerminatorType" + --array-list "elem1" "elem2" "elem3" "@@@" + --property-property "propertyValue" + ) + local status=0 + OBJECT_TEMPLATE_ARRAY_TERMINATOR="@@@" Object::setArray customArrayTerminator list "newElem1" "newElem2" || status=1 + [[ "${status}" = "0" ]] + run echo "${customArrayTerminator[@]}" + assert_output "--type customArrayTerminatorType --property-property "propertyValue" --array-list newElem1 newElem2 @@@" } function Object::setArray::newProperty { #@test @@ -48,5 +72,5 @@ function Object::setArray::newProperty { #@test Object::setArray newPropertyObject list "newElem1" "newElem2" || status=1 [[ "${status}" = "0" ]] run echo "${newPropertyObject[@]}" - assert_output "--type simpleObjectType --property-property propertyValue --array-list newElem1 --array-list newElem2" + assert_output "--type simpleObjectType --property-property propertyValue --array-list newElem1 newElem2 --" } diff --git a/src/Object/setArray.sh b/src/Object/setArray.sh old mode 100644 new mode 100755 index 4e836f87..a3a8d7d6 --- a/src/Object/setArray.sh +++ b/src/Object/setArray.sh @@ -5,22 +5,34 @@ Object::setArray() { local arrayName="${2:-}" shift 2 || true local -a arrayValues=("$@") - + local -i propertiesLength="${#object_set_array_objectData[@]}" local -a newProperties=() - - # remove all array element + while ((i < propertiesLength)); do - if [[ "${object_set_array_objectData[${i}]}" != "--array-${arrayName}" ]]; then - newProperties+=("${object_set_array_objectData[@]:i:2}") + if [[ "${object_set_array_objectData[${i}]}" = "--array-${arrayName}" ]]; then + ((++i)) + # eat next elements until finding terminator + while ((i < propertiesLength)); do + if [[ "${object_set_array_objectData[${i}]}" = "${OBJECT_TEMPLATE_ARRAY_TERMINATOR:---}" ]]; then + ((++i)) + break + fi + ((++i)) + done + break fi - ((i=i+2)) + newProperties+=("${object_set_array_objectData[${i}]}") + ((++i)) done - - # add all new values - local arrayValue - for arrayValue in "${arrayValues[@]}"; do - newProperties+=("--array-${arrayName}" "${arrayValue}") + + # copy rest of the properties if any + while ((i < propertiesLength)); do + newProperties+=("${object_set_array_objectData[${i}]}") + ((++i)) done + + # finally set the array + newProperties+=("--array-${arrayName}" "${arrayValues[@]}" "${OBJECT_TEMPLATE_ARRAY_TERMINATOR:---}") object_set_array_objectData=("${newProperties[@]}") -} \ No newline at end of file +} diff --git a/src/Object/setProperty.bats b/src/Object/setProperty.bats old mode 100644 new mode 100755 index c29fc8ab..4c70c629 --- a/src/Object/setProperty.bats +++ b/src/Object/setProperty.bats @@ -36,6 +36,20 @@ function Object::setProperty::multipleProperties { #@test assert_output "--type multiplePropertiesType --property-property newPropertyValue --property-property2 propertyValue2" } +function Object::setProperty::withArray { #@test + declare -a withArray=( + --type "withArrayType" + --property-property "propertyValue" + --array-list "elem1" "elem2" -- + --property-property2 "propertyValue2" + ) + local status=0 + Object::setProperty withArray property2 "newPropertyValue" || status=1 + [[ "${status}" = "0" ]] + run echo "${withArray[@]}" + assert_output "--type withArrayType --property-property propertyValue --array-list "elem1" "elem2" -- --property-property2 newPropertyValue" +} + function Object::setProperty::newProperty { #@test declare -a newPropertyObject=( --type "simpleObjectType" @@ -45,5 +59,5 @@ function Object::setProperty::newProperty { #@test Object::setProperty newPropertyObject newProperty "value" || status=1 [[ "${status}" = "0" ]] run echo "${newPropertyObject[@]}" - assert_output "--type simpleObjectType --property-property propertyValue --property-newProperty value" + assert_output "--type simpleObjectType --property-property propertyValue --property-newProperty value" } diff --git a/src/Object/setProperty.sh b/src/Object/setProperty.sh old mode 100644 new mode 100755 index 22877c7a..dbfe51fc --- a/src/Object/setProperty.sh +++ b/src/Object/setProperty.sh @@ -4,7 +4,7 @@ Object::setProperty() { local -n object_set_property_objectData=$1 local propertyName="${2:-}" local propertyValue="${3:-}" - + local i=0 || true local -i propertiesLength="${#object_set_property_objectData[@]}" local -a newProperties=() @@ -13,18 +13,18 @@ Object::setProperty() { if [[ "${object_set_property_objectData[${i}]}" = "--property-${propertyName}" ]]; then propertyFound="1" newProperties+=( - "${object_set_property_objectData[${i}]}" "${propertyValue}" + "${object_set_property_objectData[${i}]}" "${propertyValue}" ) - if ((i < propertiesLength-2)); then + if ((i < propertiesLength - 2)); then newProperties+=("${object_set_property_objectData[@]:i+2}") fi break fi - newProperties+=("${object_set_property_objectData[@]:i:2}") - ((i=i+2)) + newProperties+=("${object_set_property_objectData[${i}]}") + ((i = i + 1)) done if [[ "${propertyFound}" = "0" ]]; then newProperties+=("--property-${propertyName}" "${propertyValue}") fi object_set_property_objectData=("${newProperties[@]}") -} \ No newline at end of file +} From 4ec079768550da3a5886f4dce786a9ebcdf0decd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Chastanet?= Date: Sat, 6 Jan 2024 10:32:28 +0100 Subject: [PATCH 7/9] Better configuration loading management. Short 3 lines summary tag: 2.2.0 # Breaking changes # Bug fixes - fixed regression - global options passed to the command was not taken into account(--verbose, -no-color, --log-level, ...) # Compiler changes # Binaries changes - all binaries are using - shopt -s lastpipe headers change # Updated Bash framework functions # New Bash framework functions # Documentation # Validation/Tooling --- bin/awkLint | 2 +- bin/buildBinFiles | 2 +- bin/buildPushDockerImage | 8 ++++---- bin/definitionLint | 4 ++-- bin/doc | 8 ++++---- bin/dockerLint | 2 +- bin/findShebangFiles | 2 +- bin/frameworkLint | 4 ++-- bin/megalinter | 8 ++++---- bin/plantuml | 2 +- bin/runBuildContainer | 8 ++++---- bin/shellcheckLint | 4 ++-- bin/test | 8 ++++---- 13 files changed, 31 insertions(+), 31 deletions(-) diff --git a/bin/awkLint b/bin/awkLint index 85f3425b..c0761e09 100755 --- a/bin/awkLint +++ b/bin/awkLint @@ -1236,7 +1236,7 @@ Result in checkstyle format.")" # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/buildBinFiles b/bin/buildBinFiles index 06af60d6..9a5784cd 100755 --- a/bin/buildBinFiles +++ b/bin/buildBinFiles @@ -1275,7 +1275,7 @@ INTERNAL TOOL")" # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/buildPushDockerImage b/bin/buildPushDockerImage index e628daa2..2f9812ea 100755 --- a/bin/buildPushDockerImage +++ b/bin/buildPushDockerImage @@ -1396,21 +1396,21 @@ INTERNAL # shellcheck disable=SC2054 helpArray=(vendor\ image\ to\ use:\ alpine\|ubuntu) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: ubuntu' + echo " Default value: ubuntu" echo ' Possible values: alpine|ubuntu' echo -e " ${__HELP_OPTION_COLOR}--bash-version ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(version\ of\ bash\ to\ use:\ 4.4\|5.0\|5.1\|5.2) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: 5.1' + echo " Default value: 5.1" echo ' Possible values: 4.4|5.0|5.1|5.2' echo -e " ${__HELP_OPTION_COLOR}--bash-base-image ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(bash\ bash\ image\ to\ use\ \(eg:\ ubuntu:20.04\,\ amd64/bash:4.4-alpine3.18\)) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: ubuntu:20.04' + echo " Default value: ubuntu:20.04" echo -e " ${__HELP_OPTION_COLOR}--branch-name ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 @@ -1463,7 +1463,7 @@ INTERNAL # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/definitionLint b/bin/definitionLint index cafbcd2f..ed80ba3a 100755 --- a/bin/definitionLint +++ b/bin/definitionLint @@ -1457,7 +1457,7 @@ definitionLintCommand() { # shellcheck disable=SC2054 helpArray=(define\ output\ format\ of\ this\ command) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: plain' + echo " Default value: plain" echo ' Possible values: plain|checkstyle' echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" @@ -1501,7 +1501,7 @@ definitionLintCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/doc b/bin/doc index d91a7fe3..3aaf85c9 100755 --- a/bin/doc +++ b/bin/doc @@ -1933,21 +1933,21 @@ docCommand() { # shellcheck disable=SC2054 helpArray=(vendor\ image\ to\ use:\ alpine\|ubuntu) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: ubuntu' + echo " Default value: ubuntu" echo ' Possible values: alpine|ubuntu' echo -e " ${__HELP_OPTION_COLOR}--bash-version ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(version\ of\ bash\ to\ use:\ 4.4\|5.0\|5.1\|5.2) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: 5.1' + echo " Default value: 5.1" echo ' Possible values: 4.4|5.0|5.1|5.2' echo -e " ${__HELP_OPTION_COLOR}--bash-base-image ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(bash\ bash\ image\ to\ use\ \(eg:\ ubuntu:20.04\,\ amd64/bash:4.4-alpine3.18\)) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: ubuntu:20.04' + echo " Default value: ubuntu:20.04" echo -e " ${__HELP_OPTION_COLOR}--branch-name ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 @@ -2005,7 +2005,7 @@ docCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/dockerLint b/bin/dockerLint index 0eb45df9..4053bf23 100755 --- a/bin/dockerLint +++ b/bin/dockerLint @@ -1562,7 +1562,7 @@ dockerLintCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/findShebangFiles b/bin/findShebangFiles index 8bc6782d..469c96ee 100755 --- a/bin/findShebangFiles +++ b/bin/findShebangFiles @@ -1270,7 +1270,7 @@ findShebangFiles() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/frameworkLint b/bin/frameworkLint index 46fc49b8..ff185f42 100755 --- a/bin/frameworkLint +++ b/bin/frameworkLint @@ -1379,7 +1379,7 @@ frameworkLintCommand() { # shellcheck disable=SC2054 helpArray=(define\ output\ format\ of\ this\ command) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: plain' + echo " Default value: plain" echo ' Possible values: plain|checkstyle' echo -e " ${__HELP_OPTION_COLOR}--expected-warnings-count ${__HELP_NORMAL} {single}" local -a helpArray @@ -1428,7 +1428,7 @@ frameworkLintCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/megalinter b/bin/megalinter index 69496b18..ade3be9d 100755 --- a/bin/megalinter +++ b/bin/megalinter @@ -1497,7 +1497,7 @@ megalinterCommand() { # shellcheck disable=SC2054 helpArray=(define\ output\ format\ of\ this\ command) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: plain' + echo " Default value: plain" echo ' Possible values: plain|json' echo -e " ${__HELP_OPTION_COLOR}--fix${__HELP_NORMAL} {single}" local -a helpArray @@ -1519,7 +1519,7 @@ megalinterCommand() { # shellcheck disable=SC2054 helpArray=(Specify\ docker\ megalinter\ image\ name\ to\ use) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: oxsecurity/megalinter-terraform:v7.4.0' + echo " Default value: oxsecurity/megalinter-terraform:v7.4.0" echo -e " ${__HELP_OPTION_COLOR}--check-megalinter-version${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 @@ -1530,7 +1530,7 @@ megalinterCommand() { # shellcheck disable=SC2054 helpArray=(Specify\ megalinter\ config\ filename\ to\ use) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: .mega-linter.yml' + echo " Default value: .mega-linter.yml" echo echo -e "${__HELP_TITLE_COLOR}GLOBAL OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--bash-framework-config ${__HELP_NORMAL} {single}" @@ -1573,7 +1573,7 @@ megalinterCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/plantuml b/bin/plantuml index b78baaec..1b047482 100755 --- a/bin/plantuml +++ b/bin/plantuml @@ -1334,7 +1334,7 @@ plantumlCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/runBuildContainer b/bin/runBuildContainer index b451141d..94008453 100755 --- a/bin/runBuildContainer +++ b/bin/runBuildContainer @@ -1530,21 +1530,21 @@ runBuildContainerCommand() { # shellcheck disable=SC2054 helpArray=(vendor\ image\ to\ use:\ alpine\|ubuntu) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: ubuntu' + echo " Default value: ubuntu" echo ' Possible values: alpine|ubuntu' echo -e " ${__HELP_OPTION_COLOR}--bash-version ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(version\ of\ bash\ to\ use:\ 4.4\|5.0\|5.1\|5.2) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: 5.1' + echo " Default value: 5.1" echo ' Possible values: 4.4|5.0|5.1|5.2' echo -e " ${__HELP_OPTION_COLOR}--bash-base-image ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(bash\ bash\ image\ to\ use\ \(eg:\ ubuntu:20.04\,\ amd64/bash:4.4-alpine3.18\)) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: ubuntu:20.04' + echo " Default value: ubuntu:20.04" echo -e " ${__HELP_OPTION_COLOR}--branch-name ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 @@ -1602,7 +1602,7 @@ runBuildContainerCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/shellcheckLint b/bin/shellcheckLint index 8dfde0d0..5e4da78f 100755 --- a/bin/shellcheckLint +++ b/bin/shellcheckLint @@ -1635,7 +1635,7 @@ shellcheckLintCommand() { # shellcheck disable=SC2054 helpArray=(define\ output\ format\ of\ this\ command) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: tty' + echo " Default value: tty" echo ' Possible values: checkstyle|diff|gcc|json|json1|quiet|tty' echo -e " ${__HELP_OPTION_COLOR}--staged${__HELP_NORMAL} {single}" local -a helpArray @@ -1689,7 +1689,7 @@ shellcheckLintCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray diff --git a/bin/test b/bin/test index 1bde5341..d5206f6d 100755 --- a/bin/test +++ b/bin/test @@ -1707,21 +1707,21 @@ testCommand() { # shellcheck disable=SC2054 helpArray=(vendor\ image\ to\ use:\ alpine\|ubuntu) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: ubuntu' + echo " Default value: ubuntu" echo ' Possible values: alpine|ubuntu' echo -e " ${__HELP_OPTION_COLOR}--bash-version ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(version\ of\ bash\ to\ use:\ 4.4\|5.0\|5.1\|5.2) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: 5.1' + echo " Default value: 5.1" echo ' Possible values: 4.4|5.0|5.1|5.2' echo -e " ${__HELP_OPTION_COLOR}--bash-base-image ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 helpArray=(bash\ bash\ image\ to\ use\ \(eg:\ ubuntu:20.04\,\ amd64/bash:4.4-alpine3.18\)) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: ubuntu:20.04' + echo " Default value: ubuntu:20.04" echo -e " ${__HELP_OPTION_COLOR}--branch-name ${__HELP_NORMAL} {single}" local -a helpArray # shellcheck disable=SC2054 @@ -1779,7 +1779,7 @@ testCommand() { # shellcheck disable=SC2054 helpArray=(choose\ color\ theme\ -\ default-force\ means\ colors\ will\ be\ produced\ even\ if\ command\ is\ piped) echo -e " $(Array::wrap2 " " 76 4 "${helpArray[@]}")" - echo ' Default value: default' + echo " Default value: default" echo ' Possible values: default|default-force|noColor' echo -e " ${__HELP_OPTION_COLOR}--help${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-h${__HELP_NORMAL} {single}" local -a helpArray From 678806269fea74996c50289ad00cc0f1980ea4ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Chastanet?= Date: Sat, 6 Jan 2024 10:37:39 +0100 Subject: [PATCH 8/9] Options2 commit as is --- manualTests/Object::create.sh | 22 +- manualTests/Object::setArray.sh | 3 +- manualTests/Object::setProperty.sh | 2 +- manualTests/Options2::renderHelpArg.sh | 45 +++ .../testCreateObject.sh | 16 +- src/Object/__all.sh | 2 + src/Object/getArray.bats | 18 +- src/Object/getArray.sh | 5 +- src/Object/getProperty.bats | 18 +- src/Object/getProperty.sh | 5 +- src/Object/initFromTemplate.bats | 63 ++++ src/Object/initFromTemplate.sh | 32 ++ src/Object/memberExists.bats | 56 ++++ src/Object/memberExists.sh | 16 + src/Object/setArray.bats | 10 +- src/Object/setArray.sh | 4 +- src/Object/setProperty.bats | 8 +- src/Object/setProperty.sh | 4 +- src/Options/templates/option.tpl | 2 +- src/Options2/__all.sh | 2 + src/Options2/renderArgHelp.bats | 43 +-- src/Options2/renderArgHelp.sh | 23 +- src/Options2/renderGroupHelp.bats | 26 +- src/Options2/renderGroupHelp.sh | 9 +- src/Options2/renderOptionHelp.bats | 30 +- src/Options2/renderOptionHelp.sh | 21 +- src/Options2/validateArgObject.bats | 237 +++++++------- src/Options2/validateArgObject.sh | 46 +-- src/Options2/validateCommandObject.bats | 215 ++++--------- src/Options2/validateCommandObject.sh | 55 ++-- src/Options2/validateGroupObject.sh | 7 +- src/Options2/validateOptionObject.bats | 299 +++++++++--------- src/Options2/validateOptionObject.sh | 51 ++- 33 files changed, 779 insertions(+), 616 deletions(-) create mode 100755 manualTests/Options2::renderHelpArg.sh rename testCreateObject.sh => manualTests/testCreateObject.sh (72%) create mode 100755 src/Object/initFromTemplate.bats create mode 100755 src/Object/initFromTemplate.sh create mode 100755 src/Object/memberExists.bats create mode 100755 src/Object/memberExists.sh diff --git a/manualTests/Object::create.sh b/manualTests/Object::create.sh index 4afbaced..ec200361 100755 --- a/manualTests/Object::create.sh +++ b/manualTests/Object::create.sh @@ -17,28 +17,22 @@ set -o errexit set -o pipefail export TMPDIR="/tmp" -Object::create \ +Object::create zzzGroupGlobalOptionsFunction \ --type group \ - --property-title "GLOBAL OPTIONS:" \ - --function-name zzzGroupGlobalOptionsFunction + --property-title "GLOBAL OPTIONS:" -Object::create \ - --type "Group" \ - --function-name "simpleObjectFunction" +Object::create simpleObjectFunction \ + --type "Group" -Object::create \ +Object::create groupObjectFunction \ --type "Group" \ --property-title "title" \ - --property-help "help" \ - --function-name "groupObjectFunction" + --property-help "help" BASH_FRAMEWORK_DISPLAY_LEVEL=__LEVEL_DEBUG -Object::create \ - --function-name "optionFunction" \ +Object::create optionFunction \ --type "Option" \ --property-variableName "varName" -declare -f optionFunction -set -x -Options2::validateOptionObject optionFunction \ No newline at end of file +Options2::validateOptionObject "${optionFunction}" \ No newline at end of file diff --git a/manualTests/Object::setArray.sh b/manualTests/Object::setArray.sh index 39fd946c..bc5b6efa 100755 --- a/manualTests/Object::setArray.sh +++ b/manualTests/Object::setArray.sh @@ -16,7 +16,6 @@ declare -a missingArrayTerminator=( --array-list "elem1" "elem2" "elem3" --property-property "propertyValue" ) -set -x -Object::setArray missingArrayTerminator list "newElem1" "newElem2" +Object::setArray missingArrayTerminator --array-list "newElem1" "newElem2" declare -p missingArrayTerminator diff --git a/manualTests/Object::setProperty.sh b/manualTests/Object::setProperty.sh index c80ab8e2..cdd0c6d1 100755 --- a/manualTests/Object::setProperty.sh +++ b/manualTests/Object::setProperty.sh @@ -15,5 +15,5 @@ declare -a newPropertyObject=( --type "simpleObjectType" --property-property "propertyValue" ) -Object::setProperty newPropertyObject newProperty "value" +Object::setProperty newPropertyObject --property-newProperty "value" declare -p newPropertyObject \ No newline at end of file diff --git a/manualTests/Options2::renderHelpArg.sh b/manualTests/Options2::renderHelpArg.sh new file mode 100755 index 00000000..f1461194 --- /dev/null +++ b/manualTests/Options2::renderHelpArg.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +rootDir="$(cd "$(readlink -e "${BASH_SOURCE[0]%/*}")/.." && pwd -P)" +export FRAMEWORK_ROOT_DIR="${rootDir}" +export _COMPILE_ROOT_DIR="${rootDir}" + +srcDir="$(cd "${rootDir}/src" && pwd -P)" + +# shellcheck source=src/Object/__all.sh +source "${srcDir}/Object/__all.sh" +# shellcheck source=src/Options2/__all.sh +source "${srcDir}/Options2/__all.sh" +# shellcheck source=/src/Log/__all.sh +source "${srcDir}/Log/__all.sh" +# shellcheck source=/src/UI/theme.sh +source "${srcDir}/UI/theme.sh" +# shellcheck source=/src/Assert/tty.sh +source "${srcDir}/Assert/tty.sh" + +declare -a arg=( + --type "Arg" + --property-variableName "var" + --property-name "name" + --property-help "help" + --property-title "Global options" + --property-mandatory 1 + --property-max 2 +) +declare -a group=( + --type "Group" + --property-title "Global options" + --property-help "help" +) +Options2::renderGroupHelp group +declare -a arg=( + --type "Arg" + --property-variableName "varName" + --property-variableType "String" + --array-alt "--help" + --property-name "valid" + --array-callback "François" +) +Options2::validateArgObject arg +UI::theme "default" +Options2::renderArgHelp arg 2>&1 \ No newline at end of file diff --git a/testCreateObject.sh b/manualTests/testCreateObject.sh similarity index 72% rename from testCreateObject.sh rename to manualTests/testCreateObject.sh index 4b02bedb..649b97b5 100755 --- a/testCreateObject.sh +++ b/manualTests/testCreateObject.sh @@ -18,24 +18,24 @@ Object::create myFunction2 \ --array-list "c" echo "--------------------------------------------" -${myFunction} getProperty name -${myFunction2} getProperty name -${myFunction} getProperty name -${myFunction2} getProperty list +${myFunction} getProperty --property-name +${myFunction2} getProperty --property-name +${myFunction} getProperty --property-name +${myFunction2} getProperty --property-list echo "------------------- setProperty -------------------------" ${myFunction} setProperty name "myFunctionFrançois3" -${myFunction} getProperty name +${myFunction} getProperty --property-name ${myFunction2} setProperty name "myFunction2François3" -${myFunction2} getProperty name +${myFunction2} getProperty --property-name echo -n "name2 " ${myFunction2} setProperty name2 "newProperty name2" -${myFunction2} getProperty name2 +${myFunction2} getProperty --property-name2 echo "--------------------------------------------" Object::create myFunction2 \ --function-name "argFunction2Overload" \ --type "Command2Overload" \ --property-name "François2Overload" -${myFunction2} getProperty name \ No newline at end of file +${myFunction2} getProperty --property-name \ No newline at end of file diff --git a/src/Object/__all.sh b/src/Object/__all.sh index 057922ab..9d5c869b 100755 --- a/src/Object/__all.sh +++ b/src/Object/__all.sh @@ -2,6 +2,8 @@ # shellcheck source=src/Object/create.sh source "${FRAMEWORK_ROOT_DIR}/src/Object/create.sh" +# shellcheck source=src/Object/memberExists.sh +source "${FRAMEWORK_ROOT_DIR}/src/Object/memberExists.sh" # shellcheck source=src/Object/getProperty.sh source "${FRAMEWORK_ROOT_DIR}/src/Object/getProperty.sh" # shellcheck source=src/Object/setProperty.sh diff --git a/src/Object/getArray.bats b/src/Object/getArray.bats index 3633093e..861a5b72 100755 --- a/src/Object/getArray.bats +++ b/src/Object/getArray.bats @@ -16,11 +16,11 @@ function Object::getArray::simpleObject { #@test --type "simpleObjectType" --array-myList "elem1" ) - run Object::getArray simpleObject myList 1 + run Object::getArray simpleObject --array-myList 1 assert_output "elem1" assert_success - run Object::getArray simpleObject myList 0 + run Object::getArray simpleObject --array-myList 0 assert_output "elem1" assert_success } @@ -31,13 +31,13 @@ function Object::getArray::multipleArrayValues { #@test --array-myList "elem1" "elem2" -- --property-type "type" ) - run Object::getArray multipleArrayValues myList 1 + run Object::getArray multipleArrayValues --array-myList 1 assert_lines_count 2 assert_line --index 0 "elem1" assert_line --index 1 "elem2" assert_success - run Object::getArray multipleArrayValues myList 0 + run Object::getArray multipleArrayValues --array-myList 0 assert_lines_count 2 assert_line --index 0 "elem1" assert_line --index 1 "elem2" @@ -49,11 +49,11 @@ function Object::getArray::unknownProperty { #@test --type "simpleObjectType" --property-property "propertyValue" ) - run Object::getArray simpleObject unknownArray 1 - assert_output --partial "ERROR - unknown array unknownArray" + run Object::getArray simpleObject --array-unknownArray 1 + assert_output --partial "ERROR - unknown array --array-unknownArray" assert_failure 1 - run Object::getArray simpleObject unknownArray 0 + run Object::getArray simpleObject --array-unknownArray 0 assert_output "" assert_success } @@ -64,13 +64,13 @@ function Object::getArray::customTerminator { #@test --array-myList "elem1" "elem2" "@@@" --property-property "propertyValue" ) - OBJECT_TEMPLATE_ARRAY_TERMINATOR="@@@" run Object::getArray simpleObject myList 1 + OBJECT_TEMPLATE_ARRAY_TERMINATOR="@@@" run Object::getArray simpleObject --array-myList 1 assert_line --index 0 "elem1" assert_line --index 1 "elem2" assert_lines_count 2 assert_success - OBJECT_TEMPLATE_ARRAY_TERMINATOR="@@@" run Object::getArray simpleObject myList 0 + OBJECT_TEMPLATE_ARRAY_TERMINATOR="@@@" run Object::getArray simpleObject --array-myList 0 assert_line --index 0 "elem1" assert_line --index 1 "elem2" assert_lines_count 2 diff --git a/src/Object/getArray.sh b/src/Object/getArray.sh index 456a144b..533e0bb2 100755 --- a/src/Object/getArray.sh +++ b/src/Object/getArray.sh @@ -8,7 +8,7 @@ Object::getArray() { local -i propertiesLength="${#object_get_array_objectData[@]}" local -i i=0 || true while ((i < propertiesLength)); do - if [[ "${object_get_array_objectData[${i}]}" = "--array-${arrayName}" ]]; then + if [[ "${object_get_array_objectData[${i}]}" = "${arrayName}" ]]; then ((++i)) # eat next elements until finding terminator while ((i < propertiesLength)); do @@ -23,8 +23,7 @@ Object::getArray() { ((++i)) done - if [[ "${strict}" = "1" ]]; then - Log::displayError "unknown array ${arrayName}" + if [[ "${strict}" != "0" ]]; then return 1 fi } diff --git a/src/Object/getProperty.bats b/src/Object/getProperty.bats index 4c7c47d7..ca10e592 100755 --- a/src/Object/getProperty.bats +++ b/src/Object/getProperty.bats @@ -16,11 +16,11 @@ function Object::getProperty::simpleObject { #@test --type "simpleObjectType" --property-property "propertyValue" ) - run Object::getProperty simpleObject property 1 + run Object::getProperty simpleObject --property-property 1 assert_output "propertyValue" assert_success - run Object::getProperty simpleObject property 0 + run Object::getProperty simpleObject --property-property 0 assert_output "propertyValue" assert_success } @@ -30,11 +30,11 @@ function Object::getProperty::unknownProperty { #@test --type "simpleObjectType" --property-property "propertyValue" ) - run Object::getProperty simpleObject unknownProperty 1 - assert_output --partial "ERROR - unknown property unknownProperty" + run Object::getProperty simpleObject --property-unknownProperty 1 + assert_output --partial "ERROR - unknown property --property-unknownProperty" assert_failure 1 - run Object::getProperty simpleObject unknownProperty 0 + run Object::getProperty simpleObject --property-unknownProperty 0 assert_output "" assert_success } @@ -45,11 +45,11 @@ function Object::getProperty::withArray { #@test --array-list "elem1" -- --property-property "propertyValue" ) - run Object::getProperty simpleObject property 1 + run Object::getProperty simpleObject --property-property 1 assert_output "propertyValue" assert_success - run Object::getProperty simpleObject property 0 + run Object::getProperty simpleObject --property-property 0 assert_output "propertyValue" assert_success } @@ -61,11 +61,11 @@ function Object::getProperty::property2 { #@test --property-property "propertyValue" --property-property2 "propertyValue2" ) - run Object::getProperty simpleObject property2 1 + run Object::getProperty simpleObject --property-property2 1 assert_output "propertyValue2" assert_success - run Object::getProperty simpleObject property2 0 + run Object::getProperty simpleObject --property-property2 0 assert_output "propertyValue2" assert_success } diff --git a/src/Object/getProperty.sh b/src/Object/getProperty.sh index da105656..0e240c1a 100755 --- a/src/Object/getProperty.sh +++ b/src/Object/getProperty.sh @@ -9,14 +9,13 @@ Object::getProperty() { local -i i=0 || true local propertyFound="0" while ((i < propertiesLength)); do - if [[ "${object_get_property_objectData[${i}]}" = "--property-${propertyName}" ]]; then + if [[ "${object_get_property_objectData[${i}]}" = "${propertyName}" ]]; then echo "${object_get_property_objectData[$((i + 1))]}" return 0 fi ((i = i + 1)) done - if [[ "${strict}" = "1" && "${propertyFound}" = "0" ]]; then - Log::displayError "unknown property ${propertyName}" + if [[ "${strict}" != "0" && "${propertyFound}" = "0" ]]; then return 1 fi } diff --git a/src/Object/initFromTemplate.bats b/src/Object/initFromTemplate.bats new file mode 100755 index 00000000..8efe7a42 --- /dev/null +++ b/src/Object/initFromTemplate.bats @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2154 +# shellcheck disable=SC2034 + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Object/__all.sh +source "${srcDir}/Object/__all.sh" +# shellcheck source=src/Assert/posixFunctionName.sh +source "${srcDir}/Assert/posixFunctionName.sh" +# shellcheck source=src/Array/contains.sh +source "${srcDir}/Array/contains.sh" + +function Object::setProperty::simpleObject { #@test + declare -a simpleObject=( + --type "simpleObjectType" + --property-property "propertyValue" + ) + local status=0 + Object::setProperty simpleObject --property-property "newPropertyValue" || status=1 + [[ "${status}" = "0" ]] + run echo "${simpleObject[@]}" + assert_output "--type simpleObjectType --property-property newPropertyValue" +} + +function Object::setProperty::multipleProperties { #@test + declare -a multipleProperties=( + --type "multiplePropertiesType" + --property-property "propertyValue" + --property-property2 "propertyValue2" + ) + local status=0 + Object::setProperty multipleProperties --property-property "newPropertyValue" || status=1 + [[ "${status}" = "0" ]] + run echo "${multipleProperties[@]}" + assert_output "--type multiplePropertiesType --property-property newPropertyValue --property-property2 propertyValue2" +} + +function Object::setProperty::withArray { #@test + declare -a withArray=( + --type "withArrayType" + --property-property "propertyValue" + --array-list "elem1" "elem2" -- + --property-property2 "propertyValue2" + ) + local status=0 + Object::setProperty withArray --property-property2 "newPropertyValue" || status=1 + [[ "${status}" = "0" ]] + run echo "${withArray[@]}" + assert_output "--type withArrayType --property-property propertyValue --array-list "elem1" "elem2" -- --property-property2 newPropertyValue" +} + +function Object::setProperty::newProperty { #@test + declare -a newPropertyObject=( + --type "simpleObjectType" + --property-property "propertyValue" + ) + local status=0 + Object::setProperty newPropertyObject --property-newProperty "value" || status=1 + [[ "${status}" = "0" ]] + run echo "${newPropertyObject[@]}" + assert_output "--type simpleObjectType --property-property propertyValue --property-newProperty value" +} diff --git a/src/Object/initFromTemplate.sh b/src/Object/initFromTemplate.sh new file mode 100755 index 00000000..05f93a95 --- /dev/null +++ b/src/Object/initFromTemplate.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +Object::initFromTemplate() { + local -n object_init_from_template_template=$1 + local -n object_init_from_template_object=$2 + shift 2 || true + local propertyName="${2:-}" + local propertyValue="${3:-}" + + local i=0 || true + local -i propertiesLength="${#object_set_property_objectData[@]}" + local -a newProperties=() + local propertyFound="0" + while ((i < propertiesLength)); do + if [[ "${object_set_property_objectData[${i}]}" = "--property-${propertyName}" ]]; then + propertyFound="1" + newProperties+=( + "${object_set_property_objectData[${i}]}" "${propertyValue}" + ) + if ((i < propertiesLength - 2)); then + newProperties+=("${object_set_property_objectData[@]:i+2}") + fi + break + fi + newProperties+=("${object_set_property_objectData[${i}]}") + ((i = i + 1)) + done + if [[ "${propertyFound}" = "0" ]]; then + newProperties+=("--property-${propertyName}" "${propertyValue}") + fi + object_set_property_objectData=("${newProperties[@]}") +} diff --git a/src/Object/memberExists.bats b/src/Object/memberExists.bats new file mode 100755 index 00000000..6302ae46 --- /dev/null +++ b/src/Object/memberExists.bats @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2154 +# shellcheck disable=SC2034 + +# shellcheck source=src/batsHeaders.sh +source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" +# shellcheck source=src/Object/__all.sh +source "${srcDir}/Object/__all.sh" +# shellcheck source=src/Assert/posixFunctionName.sh +source "${srcDir}/Assert/posixFunctionName.sh" +# shellcheck source=src/Array/contains.sh +source "${srcDir}/Array/contains.sh" + +function Object::memberExists::simpleObject { #@test + declare -a simpleObject=( + --type "simpleObjectType" + --property-property "propertyValue" + ) + run Object::memberExists simpleObject --property-property + assert_output "" + assert_success +} + +function Object::memberExists::unknownProperty { #@test + declare -a simpleObject=( + --type "simpleObjectType" + --property-property "propertyValue" + ) + run Object::memberExists simpleObject --property-unknownProperty + assert_output "" + assert_failure 1 +} + +function Object::memberExists::withArray { #@test + declare -a simpleObject=( + --type "simpleObjectType" + --array-list "elem1" -- + --property-property "propertyValue" + ) + run Object::memberExists simpleObject --property-property + assert_output "" + assert_success + +} + +function Object::memberExists::property2 { #@test + declare -a simpleObject=( + --type "simpleObjectType" + --array-list "elem1" -- + --property-property "propertyValue" + --property-property2 "propertyValue2" + ) + run Object::memberExists simpleObject --property-property2 + assert_output "" + assert_success +} diff --git a/src/Object/memberExists.sh b/src/Object/memberExists.sh new file mode 100755 index 00000000..ec3dfb8c --- /dev/null +++ b/src/Object/memberExists.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +Object::memberExists() { + local -n object_member_exists_objectData=$1 + local propertyName="${2:-}" + + local -i propertiesLength="${#object_member_exists_objectData[@]}" + local -i i=0 || true + while ((i < propertiesLength)); do + if [[ "${object_member_exists_objectData[${i}]}" = "${propertyName}" ]]; then + return 0 + fi + ((i = i + 1)) + done + return 1 +} diff --git a/src/Object/setArray.bats b/src/Object/setArray.bats index 1897a247..c23d4e97 100755 --- a/src/Object/setArray.bats +++ b/src/Object/setArray.bats @@ -18,7 +18,7 @@ function Object::setArray::simpleObject { #@test --property-property "propertyValue" ) local status=0 - Object::setArray simpleObject list "newElem1" "newElem2" || status=1 + Object::setArray simpleObject --array-list "newElem1" "newElem2" || status=1 [[ "${status}" = "0" ]] run echo "${simpleObject[@]}" assert_output "--type simpleObjectType --property-property propertyValue --array-list newElem1 newElem2 --" @@ -31,7 +31,7 @@ function Object::setArray::multipleElements { #@test --property-property "propertyValue" ) local status=0 - Object::setArray multipleElements list "newElem1" "newElem2" || status=1 + Object::setArray multipleElements --array-list "newElem1" "newElem2" || status=1 [[ "${status}" = "0" ]] run echo "${multipleElements[@]}" assert_output "--type multipleElementsType --property-property propertyValue --array-list newElem1 newElem2 --" @@ -44,7 +44,7 @@ function Object::setArray::missingArrayTerminator { #@test --property-property "propertyValue" ) local status=0 - Object::setArray missingArrayTerminator list "newElem1" "newElem2" || status=1 + Object::setArray missingArrayTerminator --array-list "newElem1" "newElem2" || status=1 [[ "${status}" = "0" ]] run echo "${missingArrayTerminator[@]}" assert_output "--type missingArrayTerminatorType --array-list newElem1 newElem2 --" @@ -57,7 +57,7 @@ function Object::setArray::customArrayTerminator { #@test --property-property "propertyValue" ) local status=0 - OBJECT_TEMPLATE_ARRAY_TERMINATOR="@@@" Object::setArray customArrayTerminator list "newElem1" "newElem2" || status=1 + OBJECT_TEMPLATE_ARRAY_TERMINATOR="@@@" Object::setArray customArrayTerminator --array-list "newElem1" "newElem2" || status=1 [[ "${status}" = "0" ]] run echo "${customArrayTerminator[@]}" assert_output "--type customArrayTerminatorType --property-property "propertyValue" --array-list newElem1 newElem2 @@@" @@ -69,7 +69,7 @@ function Object::setArray::newProperty { #@test --property-property "propertyValue" ) local status=0 - Object::setArray newPropertyObject list "newElem1" "newElem2" || status=1 + Object::setArray newPropertyObject --array-list "newElem1" "newElem2" || status=1 [[ "${status}" = "0" ]] run echo "${newPropertyObject[@]}" assert_output "--type simpleObjectType --property-property propertyValue --array-list newElem1 newElem2 --" diff --git a/src/Object/setArray.sh b/src/Object/setArray.sh index a3a8d7d6..77a98ca7 100755 --- a/src/Object/setArray.sh +++ b/src/Object/setArray.sh @@ -10,7 +10,7 @@ Object::setArray() { local -a newProperties=() while ((i < propertiesLength)); do - if [[ "${object_set_array_objectData[${i}]}" = "--array-${arrayName}" ]]; then + if [[ "${object_set_array_objectData[${i}]}" = "${arrayName}" ]]; then ((++i)) # eat next elements until finding terminator while ((i < propertiesLength)); do @@ -33,6 +33,6 @@ Object::setArray() { done # finally set the array - newProperties+=("--array-${arrayName}" "${arrayValues[@]}" "${OBJECT_TEMPLATE_ARRAY_TERMINATOR:---}") + newProperties+=("${arrayName}" "${arrayValues[@]}" "${OBJECT_TEMPLATE_ARRAY_TERMINATOR:---}") object_set_array_objectData=("${newProperties[@]}") } diff --git a/src/Object/setProperty.bats b/src/Object/setProperty.bats index 4c70c629..8efe7a42 100755 --- a/src/Object/setProperty.bats +++ b/src/Object/setProperty.bats @@ -17,7 +17,7 @@ function Object::setProperty::simpleObject { #@test --property-property "propertyValue" ) local status=0 - Object::setProperty simpleObject property "newPropertyValue" || status=1 + Object::setProperty simpleObject --property-property "newPropertyValue" || status=1 [[ "${status}" = "0" ]] run echo "${simpleObject[@]}" assert_output "--type simpleObjectType --property-property newPropertyValue" @@ -30,7 +30,7 @@ function Object::setProperty::multipleProperties { #@test --property-property2 "propertyValue2" ) local status=0 - Object::setProperty multipleProperties property "newPropertyValue" || status=1 + Object::setProperty multipleProperties --property-property "newPropertyValue" || status=1 [[ "${status}" = "0" ]] run echo "${multipleProperties[@]}" assert_output "--type multiplePropertiesType --property-property newPropertyValue --property-property2 propertyValue2" @@ -44,7 +44,7 @@ function Object::setProperty::withArray { #@test --property-property2 "propertyValue2" ) local status=0 - Object::setProperty withArray property2 "newPropertyValue" || status=1 + Object::setProperty withArray --property-property2 "newPropertyValue" || status=1 [[ "${status}" = "0" ]] run echo "${withArray[@]}" assert_output "--type withArrayType --property-property propertyValue --array-list "elem1" "elem2" -- --property-property2 newPropertyValue" @@ -56,7 +56,7 @@ function Object::setProperty::newProperty { #@test --property-property "propertyValue" ) local status=0 - Object::setProperty newPropertyObject newProperty "value" || status=1 + Object::setProperty newPropertyObject --property-newProperty "value" || status=1 [[ "${status}" = "0" ]] run echo "${newPropertyObject[@]}" assert_output "--type simpleObjectType --property-property propertyValue --property-newProperty value" diff --git a/src/Object/setProperty.sh b/src/Object/setProperty.sh index dbfe51fc..c0f8e3b7 100755 --- a/src/Object/setProperty.sh +++ b/src/Object/setProperty.sh @@ -10,7 +10,7 @@ Object::setProperty() { local -a newProperties=() local propertyFound="0" while ((i < propertiesLength)); do - if [[ "${object_set_property_objectData[${i}]}" = "--property-${propertyName}" ]]; then + if [[ "${object_set_property_objectData[${i}]}" = "${propertyName}" ]]; then propertyFound="1" newProperties+=( "${object_set_property_objectData[${i}]}" "${propertyValue}" @@ -24,7 +24,7 @@ Object::setProperty() { ((i = i + 1)) done if [[ "${propertyFound}" = "0" ]]; then - newProperties+=("--property-${propertyName}" "${propertyValue}") + newProperties+=("${propertyName}" "${propertyValue}") fi object_set_property_objectData=("${newProperties[@]}") } diff --git a/src/Options/templates/option.tpl b/src/Options/templates/option.tpl index bace6af2..5beb6f61 100755 --- a/src/Options/templates/option.tpl +++ b/src/Options/templates/option.tpl @@ -63,7 +63,7 @@ echo 'echo -e " <%% helpOpt "1" %>"' .INCLUDE "${tplDir}/helpArg.tpl" % if [[ -n "${defaultValue}" ]]; then - echo "echo ' Default value: <% ${defaultValue} %>'" + echo 'echo " Default value: <% ${defaultValue} %>"' % fi % if [[ -n "${authorizedValues}" ]]; then echo "echo ' Possible values: <% ${authorizedValues} %>'" diff --git a/src/Options2/__all.sh b/src/Options2/__all.sh index 6dcfeb36..ba2d956c 100755 --- a/src/Options2/__all.sh +++ b/src/Options2/__all.sh @@ -28,6 +28,8 @@ source "${FRAMEWORK_ROOT_DIR}/src/Crypto/uuidV4.sh" source "${FRAMEWORK_ROOT_DIR}/src/Options/generateFunction.sh" # shellcheck source=src/Object/create.sh source "${FRAMEWORK_ROOT_DIR}/src/Object/create.sh" +# shellcheck source=src/Object/getProperty.sh +source "${FRAMEWORK_ROOT_DIR}/src/Object/getProperty.sh" # shellcheck source=src/Options2/validateCommandObject.sh source "${FRAMEWORK_ROOT_DIR}/src/Options2/validateCommandObject.sh" diff --git a/src/Options2/renderArgHelp.bats b/src/Options2/renderArgHelp.bats index 55742d1a..3464738a 100755 --- a/src/Options2/renderArgHelp.bats +++ b/src/Options2/renderArgHelp.bats @@ -19,20 +19,26 @@ function Options2::renderArgHelp::noOption { #@test assert_failure 1 } -function Options2::renderArgHelp::invalidObject { #@test - function invalidObject() { - : - } - run Options2::renderArgHelp invalidObject +function Options2::renderArgHelp::invalidObject1 { #@test + declare -a invalidObject1=() + run Options2::renderArgHelp invalidObject1 + assert_lines_count 1 + assert_output --partial "ERROR - Options2::validateArgObject - passed object is not an argument" + assert_failure 2 +} + +function Options2::renderArgHelp::invalidObject2 { #@test + invalidObject2() { :; } + run Options2::renderArgHelp invalidObject2 assert_lines_count 1 assert_output --partial "ERROR - Options2::validateArgObject - passed object is not an argument" assert_failure 2 } function Options2::renderArgHelp::notAnOption { #@test - Object::create \ - --type "NotAnOption" \ - --function-name "notAnOptionFunction" + declare -a notAnOption=( + --type "NotAnOption" + ) run Options2::renderArgHelp notAnOptionFunction assert_lines_count 1 @@ -42,18 +48,17 @@ function Options2::renderArgHelp::notAnOption { #@test function Options::renderArgHelp::OptionValid { #@test local status=0 - callback() { - : - } - Object::create \ - --function-name "argFunction" \ - --type "Arg" \ - --property-variableName "var" \ - --property-name "name" \ - --property-help "help" \ + declare -a arg=( + --type "Arg" + --property-variableName "var" + --property-name "name" + --property-help "help" --property-title "Global options" - - run Options2::renderArgHelp argFunction 2>&1 + ) + Options2::validateArgObject() { + return 0 + } + run Options2::renderArgHelp arg 2>&1 assert_success assert_line --index 0 "[${__HELP_OPTION_COLOR}name${__HELP_NORMAL} {list} (optional)]" assert_line --index 1 "Global options" diff --git a/src/Options2/renderArgHelp.sh b/src/Options2/renderArgHelp.sh index 3a50c81b..2902572d 100755 --- a/src/Options2/renderArgHelp.sh +++ b/src/Options2/renderArgHelp.sh @@ -50,16 +50,23 @@ Options2::renderArgHelp() { return 1 fi - local optionArgObject=$1 - if ! Options2::validateArgObject "${optionArgObject}"; then + # shellcheck disable=SC2034 + local -n renderArgHelpObject=$1 + if ! Options2::validateArgObject renderArgHelpObject; then return 2 fi - local help title min max name - title="$("${optionArgObject}" get title 2>/dev/null)" - help="$("${optionArgObject}" get help 2>/dev/null || echo '')" - name="$("${optionArgObject}" get name 2>/dev/null|| echo '')" - min="$("${optionArgObject}" get min 2>/dev/null|| echo '0')" - max="$("${optionArgObject}" get max 2>/dev/null|| echo '-1')" + local help title min max name mandatory + title="$(Object::getProperty renderArgHelpObject --property-title)" + help="$(Object::getProperty renderArgHelpObject --property-help "strict" || echo '')" + name="$(Object::getProperty renderArgHelpObject --property-name "strict" || echo '')" + min="$(Object::getProperty renderArgHelpObject --property-min "strict" || echo '0')" + max="$(Object::getProperty renderArgHelpObject --property-max "strict" || echo '-1')" + if [[ "${min}" = "0" ]]; then + mandatory="$(Object::getProperty renderArgHelpObject --property-mandatory "strict" || echo '0')" + if [[ "${mandatory}" = "1" ]]; then + min="1" + fi + fi displayHelp() { echo -e "${__HELP_TITLE_COLOR}${title}${__RESET_COLOR}" diff --git a/src/Options2/renderGroupHelp.bats b/src/Options2/renderGroupHelp.bats index 1d8ae63d..73bcced0 100755 --- a/src/Options2/renderGroupHelp.bats +++ b/src/Options2/renderGroupHelp.bats @@ -22,13 +22,27 @@ function Options2::renderGroupHelp::noOption { #@test function Options2::renderGroupHelp::groupOptionValid { #@test local status=0 - Object::create \ - --type "Group" \ - --property-title "Global options" \ - --property-help "help" \ - --function-name "groupObjectFunction" - run Options2::renderGroupHelp groupObjectFunction >"${BATS_TEST_TMPDIR}/result" 2>&1 + declare -a group=( + --type "Group" + --property-title "Global options" + --property-help "help" + ) + Options2::validateGroupObject() { + return 0 + } + run Options2::renderGroupHelp group >"${BATS_TEST_TMPDIR}/result" 2>&1 assert_success assert_line --index 0 "$(echo -e "${__HELP_TITLE_COLOR}Global options${__RESET_COLOR}")" assert_line --index 1 "help" } + +function Options2::renderGroupHelp::groupObjectInvalid { #@test + local status=0 + declare -a group=() + Options2::validateGroupObject() { + return 1 + } + run Options2::renderGroupHelp group 2>&1 + assert_output "" + assert_failure 2 +} diff --git a/src/Options2/renderGroupHelp.sh b/src/Options2/renderGroupHelp.sh index e8b36130..802ec9ed 100755 --- a/src/Options2/renderGroupHelp.sh +++ b/src/Options2/renderGroupHelp.sh @@ -50,13 +50,14 @@ Options2::renderGroupHelp() { return 1 fi - local groupInstanceObject=$1 - if ! Options2::validateGroupObject "${groupInstanceObject}"; then + # shellcheck disable=SC2034 + local -n renderGroupHelpObject=$1 + if ! Options2::validateGroupObject renderGroupHelpObject; then return 2 fi local help title - title="$("${groupInstanceObject}" get title 2>/dev/null)" - help="$("${groupInstanceObject}" get help 2>/dev/null || echo '')" + title="$(Object::getProperty renderGroupHelpObject --property-title)" + help="$(Object::getProperty renderGroupHelpObject --property-help)" echo -e "${__HELP_TITLE_COLOR}${title}${__RESET_COLOR}" if [[ -n "${help}" ]]; then diff --git a/src/Options2/renderOptionHelp.bats b/src/Options2/renderOptionHelp.bats index 600666f7..28ab1b3d 100755 --- a/src/Options2/renderOptionHelp.bats +++ b/src/Options2/renderOptionHelp.bats @@ -4,6 +4,8 @@ source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" # shellcheck source=src/Options/_bats.sh source "${srcDir}/Options/_bats.sh" +# shellcheck source=src/Object/__all.sh +source "${srcDir}/Object/__all.sh" # shellcheck source=src/Options2/__all.sh source "${srcDir}/Options2/__all.sh" @@ -30,31 +32,31 @@ function Options2::renderOptionHelp::invalidObject { #@test } function Options2::renderOptionHelp::notAnOption { #@test - Object::create \ - --type "NotAnOption" \ - --function-name "notAnOptionFunction" + declare -a object=( + --type "NotAnOption" + ) - run Options2::renderOptionHelp notAnOptionFunction + run Options2::renderOptionHelp object assert_lines_count 1 assert_output --partial "ERROR - Options2::validateOptionObject - passed object is not an option" assert_failure 2 } -function Options::renderOptionHelp::OptionValid { #@test +function Options2::renderOptionHelp::OptionValid { #@test local status=0 - callback() { + callback() { : } - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ - --property-variableName "var" \ - --property-variableType "Boolean" \ - --property-help "help" \ - --property-title "Global options" \ + declare -a object=( + --type "Option" + --property-variableName "var" + --property-variableType "Boolean" + --property-help "help" + --property-title "Global options" --array-alt "--help" + ) - run Options2::renderOptionHelp optionFunction 2>&1 + run Options2::renderOptionHelp object 2>&1 assert_success assert_line --index 0 "$(echo -e "${__HELP_TITLE_COLOR}Global options${__RESET_COLOR}")" assert_line --index 1 "help" diff --git a/src/Options2/renderOptionHelp.sh b/src/Options2/renderOptionHelp.sh index feff762d..5a6b570b 100755 --- a/src/Options2/renderOptionHelp.sh +++ b/src/Options2/renderOptionHelp.sh @@ -49,18 +49,21 @@ Options2::renderOptionHelp() { Log::displayError "Options2::renderOptionHelp - exactly one parameter has to be provided" return 1 fi - - local optionInstanceObject=$1 - if ! Options2::validateOptionObject "${optionInstanceObject}"; then + + # shellcheck disable=SC2034 + local -n renderOptionHelpInstanceObject=$1 + if ! Options2::validateOptionObject renderOptionHelpInstanceObject; then return 2 fi local help title variableType helpValueName min max - title="$("${optionInstanceObject}" get title 2>/dev/null)" - help="$("${optionInstanceObject}" get help 2>/dev/null || echo '')" - variableType="$("${optionInstanceObject}" get variableType)" - helpValueName="$("${optionInstanceObject}" get helpValueName 2>/dev/null|| echo '')" - min="$("${optionInstanceObject}" get min 2>/dev/null|| echo '')" - max="$("${optionInstanceObject}" get max 2>/dev/null|| echo '')" + title="$(Object::getProperty renderOptionHelpInstanceObject --property-title)" + help="$(Object::getProperty renderOptionHelpInstanceObject --property-help)" + variableType="$(Object::getProperty renderOptionHelpInstanceObject --property-variableType)" + helpValueName="$(Object::getProperty renderOptionHelpInstanceObject --property-helpValueName)" + min="$(Object::getProperty renderOptionHelpInstanceObject --property-min)" + max="$(Object::getProperty renderOptionHelpInstanceObject --property-max)" + local -a alts + readarray -t alts < <(Object::getArray renderOptionHelpInstanceObject --array-alt) displayHelp() { echo -e "${__HELP_TITLE_COLOR}${title}${__RESET_COLOR}" diff --git a/src/Options2/validateArgObject.bats b/src/Options2/validateArgObject.bats index 8e9df126..948076d9 100755 --- a/src/Options2/validateArgObject.bats +++ b/src/Options2/validateArgObject.bats @@ -5,6 +5,8 @@ source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" # shellcheck source=src/Options/_bats.sh source "${srcDir}/Options/_bats.sh" # shellcheck source=src/Options2/__all.sh +source "${srcDir}/Object/__all.sh" +# shellcheck source=src/Options2/__all.sh source "${srcDir}/Options2/__all.sh" function setup() { @@ -27,72 +29,71 @@ function Options2::validateArgObject::missingValue { #@test } function Options2::validateArgObject::tooMuchArgs { #@test - Object::create \ - --function-name "argFunction" \ + declare -a arg=( --type "Arg" - run Options2::validateArgObject argFunction argFunction + ) + run Options2::validateArgObject arg arg assert_lines_count 1 assert_output --partial "ERROR - Options2::validateArgObject - exactly one parameter has to be provided" assert_failure 1 } function Options2::validateArgObject::invalidObjectType { #@test - Object::create \ - --function-name "notAnargFunction" \ - --type "NotAnOption" - - run Options2::validateArgObject notAnargFunction + declare -a arg=( + --type "notAnArg" + ) + + run Options2::validateArgObject arg assert_lines_count 1 assert_output --partial "ERROR - Options2::validateArgObject - passed object is not an argument" assert_failure 2 } function Options2::validateArgObject::variableNameMandatory { #@test - Object::create \ - --function-name "argFunction" \ - --type "Arg" \ + declare -a arg=( + --type "Arg" --property-variableType "String" + ) - run Options2::validateArgObject argFunction + run Options2::validateArgObject arg 2>&1 assert_output --partial "ERROR - Options2::validateArgObject - variableName is mandatory" assert_failure 1 assert_lines_count 1 } function Options2::validateArgObject::variableNameInvalid { #@test - Object::create \ - --function-name "argFunction" \ - --type "Arg" \ - --property-name "valid" \ + declare -a arg=( + --type "Arg" + --property-name "valid" --property-variableName "François" + ) - run Options2::validateArgObject argFunction + run Options2::validateArgObject arg assert_output --partial "ERROR - Options2::validateArgObject - invalid variableName François" assert_failure 2 assert_lines_count 1 } function Options2::validateArgObject::nameMandatory { #@test - Object::create \ - --function-name "argFunction" \ - --type "Arg" \ + declare -a arg=( + --type "Arg" --property-variableName "validVariableName" + ) - run Options2::validateArgObject argFunction + run Options2::validateArgObject arg assert_output --partial "ERROR - Options2::validateArgObject - name is mandatory" assert_failure 1 assert_lines_count 1 } - function Options2::validateArgObject::nameInvalid { #@test - Object::create \ - --function-name "argFunction" \ - --type "Arg" \ - --property-variableName "validVariableName" \ + declare -a arg=( + --type "Arg" --property-name "François" + --property-variableName "validVariableName" + ) - run Options2::validateArgObject argFunction + run Options2::validateArgObject arg assert_output --partial "ERROR - Options2::validateArgObject - invalid name François" assert_failure 2 assert_lines_count 1 @@ -100,17 +101,17 @@ function Options2::validateArgObject::nameInvalid { #@test function Options2::validateArgObject::callbackInvalid { #@test - Object::create \ - --function-name "argFunction" \ - --type "Arg" \ - --property-variableName "varName" \ - --property-variableType "String" \ - --array-alt "--help" \ - --property-name "valid" \ + declare -a arg2=( + --type "Arg" + --property-variableName "varName" + --property-variableType "String" + --array-alt "--help" + --property-name "valid" --array-callback "François" - - run Options2::validateArgObject argFunction - assert_output --partial "ERROR - Options2::validateArgObject - only posix or bash framework function name are accepted - invalid 'François'" + ) + + run Options2::validateArgObject arg2 2>&1 + assert_output --partial "ERROR - Options2::validateArgObject - callback 'François' - function does not exists" assert_lines_count 1 assert_failure 2 } @@ -119,134 +120,134 @@ function Options2::validateArgObject::callbackValid { #@test callback() { : } - Object::create \ - --function-name "argFunction" \ - --type "Arg" \ - --property-variableName "varName" \ - --property-variableType "String" \ - --array-alt "--help" \ - --property-name "valid" \ + declare -a arg=( + --type "Arg" + --property-variableName "varName" + --property-variableType "String" + --array-alt "--help" + --property-name "valid" --array-callback "callback" - run Options2::validateArgObject argFunction + ) + run Options2::validateArgObject arg assert_output "" assert_success } function Options2::validateArgObject::String::authorizedValuesValueInvalidValue { #@test - Object::create \ - --function-name "argFunction" \ - --type "Arg" \ - --property-variableType "String" \ - --property-variableName "varName" \ - --property-name "valid" \ - --property-authorizedValues " invalid | valid" \ + declare -a arg=( + --type "Arg" + --property-variableType "String" + --property-variableName "varName" + --property-name "valid" + --property-authorizedValues " invalid | valid" --array-alt "--help" - run Options2::validateArgObject argFunction + ) + run Options2::validateArgObject arg assert_output --partial "ERROR - Options2::validateArgObject - authorizedValues invalid regexp ' invalid | valid'" assert_failure 2 assert_lines_count 1 } function Options2::validateArgObject::StringArray::authorizedValuesValueInvalidValue { #@test - Object::create \ - --function-name "argFunction" \ - --type "Arg" \ - --property-variableType "StringArray" \ - --property-variableName "varName" \ - --property-name "valid" \ - --property-authorizedValues " invalid | valid" \ + declare -a arg=( + --type "Arg" + --property-variableType "StringArray" + --property-variableName "varName" + --property-name "valid" + --property-authorizedValues " invalid | valid" --array-alt "--help" - run Options2::validateArgObject argFunction + ) + run Options2::validateArgObject arg assert_output --partial "ERROR - Options2::validateArgObject - authorizedValues invalid regexp ' invalid | valid'" assert_failure 2 assert_lines_count 1 } function Options2::validateArgObject::regexpInvalid { #@test - Object::create \ - --function-name "argFunction" \ - --type "Arg" \ - --property-variableType "StringArray" \ - --property-variableName "varName" \ - --property-name "valid" \ - --property-regexp " " \ + declare -a arg=( + --type "Arg" + --property-variableType "StringArray" + --property-variableName "varName" + --property-name "valid" + --property-regexp " " --array-alt "--help" - run Options2::validateArgObject argFunction + ) + run Options2::validateArgObject arg assert_output --partial "ERROR - Options2::validateArgObject - regexp invalid regexp ' '" assert_failure 2 assert_lines_count 1 } function Options2::validateArgObject::String::helpValueNameInvalidOption { #@test - Object::create \ - --function-name "argFunction" \ - --type "Arg" \ - --property-variableType "String" \ - --property-variableName "varName" \ - --property-name "valid" \ - --property-helpValueName "invalid help" \ + declare -a arg=( + --type "Arg" + --property-variableType "String" + --property-variableName "varName" + --property-name "valid" + --property-helpValueName "invalid help" --array-alt "--help" - run Options2::validateArgObject argFunction + ) + run Options2::validateArgObject arg assert_output --partial "ERROR - Options2::validateArgObject - helpValueName should be a single word 'invalid help'" assert_failure 2 assert_lines_count 1 } function Options2::validateArgObject::StringArray::helpValueNameInvalidOption { #@test - Object::create \ - --function-name "argFunction" \ - --type "Arg" \ - --property-variableType "StringArray" \ - --property-variableName "varName" \ - --property-name "valid" \ - --property-helpValueName "invalid help" \ + declare -a arg=( + --type "Arg" + --property-variableType "StringArray" + --property-variableName "varName" + --property-name "valid" + --property-helpValueName "invalid help" --array-alt "--help" - run Options2::validateArgObject argFunction + ) + run Options2::validateArgObject arg assert_output --partial "ERROR - Options2::validateArgObject - helpValueName should be a single word 'invalid help'" assert_failure 2 assert_lines_count 1 } function Options2::validateArgObject::StringArray::minValueEmpty { #@test - Object::create \ - --function-name "argFunction" \ - --type "Arg" \ - --property-variableType "StringArray" \ - --property-variableName "varName" \ - --property-name "valid" \ - --property-min "" \ + declare -a arg=( + --type "Arg" + --property-variableType "StringArray" + --property-variableName "varName" + --property-name "valid" + --property-min "" --array-alt "--help" - run Options2::validateArgObject argFunction + ) + run Options2::validateArgObject arg assert_output --partial "ERROR - Options2::validateArgObject - min value should be an integer greater than or equal to 0" assert_failure 2 assert_lines_count 1 } function Options2::validateArgObject::StringArray::minValueInvalid { #@test - Object::create \ - --function-name "argFunction" \ - --type "Arg" \ - --property-variableType "StringArray" \ - --property-variableName "varName" \ - --property-name "valid" \ - --property-min "François" \ + declare -a arg=( + --type "Arg" + --property-variableType "StringArray" + --property-variableName "varName" + --property-name "valid" + --property-min "François" --array-alt "--help" - run Options2::validateArgObject argFunction + ) + run Options2::validateArgObject arg assert_output --partial "ERROR - Options2::validateArgObject - min value should be an integer greater than or equal to 0" assert_failure 2 assert_lines_count 1 } function Options2::validateArgObject::StringArray::minValueLessThan0 { #@test - Object::create \ - --function-name "argFunction" \ - --type "Arg" \ - --property-variableType "StringArray" \ - --property-variableName "varName" \ - --property-name "valid" \ - --property-min "-1" \ + declare -a arg=( + --type "Arg" + --property-variableType "StringArray" + --property-variableName "varName" + --property-name "valid" + --property-min "-1" --array-alt "--help" - run Options2::validateArgObject argFunction + ) + run Options2::validateArgObject arg assert_output --partial "ERROR - Options2::validateArgObject - min value should be an integer greater than or equal to 0" assert_failure 2 assert_lines_count 1 @@ -254,16 +255,16 @@ function Options2::validateArgObject::StringArray::minValueLessThan0 { #@test function Options2::validateArgObject::StringArray::minValueGreaterThanMaxValue { #@test - Object::create \ - --function-name "argFunction" \ - --type "Arg" \ - --property-variableType "StringArray" \ - --property-variableName "varName" \ - --property-name "valid" \ - --property-min "3" \ - --property-max "1" \ + declare -a arg=( + --type "Arg" + --property-variableType "StringArray" + --property-variableName "varName" + --property-name "valid" + --property-min "3" + --property-max "1" --array-alt "--help" - run Options2::validateArgObject argFunction + ) + run Options2::validateArgObject arg assert_output --partial "ERROR - Options2::validateArgObject - max value should be greater than min value" assert_failure 2 assert_lines_count 1 diff --git a/src/Options2/validateArgObject.sh b/src/Options2/validateArgObject.sh index a8648d61..ceabbfad 100755 --- a/src/Options2/validateArgObject.sh +++ b/src/Options2/validateArgObject.sh @@ -51,82 +51,82 @@ Options2::validateArgObject() { return 1 fi - local argInstanceObject=$1 - if [[ "$("${argInstanceObject}" type 2>/dev/null || echo '')" != "Arg" ]]; then + # shellcheck disable=SC2034 + local -n validateArgObject=$1 + if [[ "$(Object::getProperty validateArgObject --type)" != "Arg" ]]; then Log::displayError "Options2::validateArgObject - passed object is not an argument" return 2 fi # variable name - if ! "${argInstanceObject}" get variableName &>/dev/null; then + if ! Object::memberExists validateArgObject --property-variableName; then Log::displayError "Options2::validateArgObject - variableName is mandatory" return 1 fi local variableName - variableName="$("${argInstanceObject}" get variableName)" + variableName="$(Object::getProperty validateArgObject --property-variableName)" if ! Assert::validVariableName "${variableName}"; then Log::displayError "Options2::validateArgObject - invalid variableName ${variableName}" return 2 fi # name - if ! "${argInstanceObject}" get name &>/dev/null; then + if ! Object::memberExists validateArgObject --property-name; then Log::displayError "Options2::validateArgObject - name is mandatory" return 1 fi local name - name="$("${argInstanceObject}" get name)" + name="$(Object::getProperty validateArgObject --property-name)" if ! Assert::validVariableName "${name}"; then Log::displayError "Options2::validateArgObject - invalid name ${name}" return 2 fi # callback - if "${argInstanceObject}" get callback &>/dev/null; then + if Object::memberExists validateArgObject --array-callback; then local callbacks - callbacks="$("${argInstanceObject}" get callback)" - local callback - while IFS= read -r callback ; do - if - ! Assert::posixFunctionName "${callback}" && - ! Assert::bashFrameworkFunction "${callback}" - then - Log::displayError "Options2::validateArgObject - only posix or bash framework function name are accepted - invalid '${callback}'" - return 2 - fi - done <<< "${callbacks}" + callbacks="$(Object::getArray validateArgObject --array-callback)" + if [[ -n "${callbacks}" ]]; then + local callback + while IFS= read -r callback ; do + if ! declare -F "${callback}" &>/dev/null; then + Log::displayError "Options2::validateArgObject - callback '${callback}' - function does not exists" + return 2 + fi + done <<< "${callbacks}" + fi fi local authorizedValues - authorizedValues="$("${argInstanceObject}" get authorizedValues 2>/dev/null)" || authorizedValues="" + authorizedValues="$(Object::getProperty validateArgObject --property-authorizedValues "strict")" || authorizedValues="" if [[ "${authorizedValues}" =~ [[:space:]] ]]; then Log::displayError "Options2::validateArgObject - authorizedValues invalid regexp '${authorizedValues}'" return 2 fi local regexp - regexp="$("${argInstanceObject}" get regexp 2>/dev/null)" || regexp="" + regexp="$(Object::getProperty validateArgObject --property-regexp)" if [[ "${regexp}" =~ [[:space:]] ]]; then Log::displayError "Options2::validateArgObject - regexp invalid regexp '${regexp}'" return 2 fi local helpValueName - helpValueName="$("${argInstanceObject}" get helpValueName 2>/dev/null)" || helpValueName="" + helpValueName="$(Object::getProperty validateArgObject --property-helpValueName)" if [[ -n "${helpValueName}" && ! "${helpValueName}" =~ ^[A-Za-z0-9_-]+$ ]]; then Log::displayError "Options2::validateArgObject - helpValueName should be a single word '${helpValueName}'" return 2 fi local min - min="$("${argInstanceObject}" get min 2>/dev/null)" || min="0" + min="$(Object::getProperty validateArgObject --property-min "strict")" || min="0" if [[ ! "${min}" =~ ^[0-9]+$ ]]; then Log::displayError "Options2::validateArgObject - min value should be an integer greater than or equal to 0" return 2 fi local max - max="$("${argInstanceObject}" get max 2>/dev/null)" || max="-1" + max="$(Object::getProperty validateArgObject --property-max "strict")" || max="-1" if [[ -n "${max}" && ! "${max}" =~ ^([1-9][0-9]*|-1)$ ]]; then Log::displayError "Options2::validateArgObject - max value should be an integer greater than 0 or -1" return 2 diff --git a/src/Options2/validateCommandObject.bats b/src/Options2/validateCommandObject.bats index a64416cc..d42c7f50 100755 --- a/src/Options2/validateCommandObject.bats +++ b/src/Options2/validateCommandObject.bats @@ -4,6 +4,8 @@ source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" # shellcheck source=src/Options/_bats.sh source "${srcDir}/Options/_bats.sh" +# shellcheck source=src/Object/__all.sh +source "${srcDir}/Object/__all.sh" # shellcheck source=src/Options2/__all.sh source "${srcDir}/Options2/__all.sh" @@ -27,204 +29,115 @@ function Options2::validateCommandObject::missingValue { #@test } function Options2::validateCommandObject::tooMuchArgs { #@test - Object::create \ - --function-name "argFunction" \ + declare -a object=( --type "Command" - run Options2::validateCommandObject argFunction argFunction + ) + run Options2::validateCommandObject object object assert_lines_count 1 assert_output --partial "ERROR - Options2::validateCommandObject - exactly one parameter has to be provided" assert_failure 1 } function Options2::validateCommandObject::invalidObjectType { #@test - Object::create \ - --function-name "notAnargFunction" \ + declare -a object=( --type "NotACommand" + ) - run Options2::validateCommandObject notAnargFunction + run Options2::validateCommandObject object assert_lines_count 1 assert_output --partial "ERROR - Options2::validateCommandObject - passed object is not a command" assert_failure 2 } function Options2::validateCommandObject::nameInvalid { #@test - Object::create \ - --function-name "argFunction" \ + declare -a object=( --type "Command" \ --property-name "François" + ) - run Options2::validateCommandObject argFunction + run Options2::validateCommandObject object assert_output --partial "ERROR - Options2::validateCommandObject - invalid command name François" assert_failure 2 assert_lines_count 1 } function Options2::validateCommandObject::callbackInvalid { #@test - Object::create \ - --function-name "argFunction" \ - --type "Command" \ - --property-variableName "varName" \ - --property-variableType "String" \ - --array-alt "--help" \ - --property-name "valid" \ + declare -a object=( + --type "Command" + --property-variableName "varName" + --property-variableType "String" + --array-alt "--help" + --property-name "valid" --array-callback "François" + ) - run Options2::validateCommandObject argFunction - assert_output --partial "ERROR - Options2::validateCommandObject - only posix or bash framework function name are accepted - invalid 'François'" + run Options2::validateCommandObject object + assert_output --partial "ERROR - Options2::validateCommandObject - only function can be passed as callback - invalid 'François'" assert_lines_count 1 assert_failure 2 } -function Options2::validateCommandObject::callbackValid { #@test - callback() { - : - } - Object::create \ - --function-name "argFunction" \ - --type "Command" \ - --property-variableName "varName" \ - --property-variableType "String" \ - --array-alt "--help" \ - --property-name "valid" \ - --array-callback "callback" - run Options2::validateCommandObject argFunction - assert_output "" - assert_success -} - -function Options2::validateCommandObject::String::authorizedValuesValueInvalidValue { #@test - Object::create \ - --function-name "argFunction" \ - --type "Command" \ - --property-variableType "String" \ - --property-variableName "varName" \ - --property-name "valid" \ - --property-authorizedValues " invalid | valid" \ +function Options2::validateCommandObject::unknownOptionCallbackInvalid { #@test + declare -a object=( + --type "Command" + --property-variableName "varName" + --property-variableType "String" --array-alt "--help" - run Options2::validateCommandObject argFunction - assert_output --partial "ERROR - Options2::validateCommandObject - authorizedValues invalid regexp ' invalid | valid'" - assert_failure 2 - assert_lines_count 1 -} + --property-name "valid" + --array-unknownOptionCallback "François" + ) -function Options2::validateCommandObject::StringArray::authorizedValuesValueInvalidValue { #@test - Object::create \ - --function-name "argFunction" \ - --type "Command" \ - --property-variableType "StringArray" \ - --property-variableName "varName" \ - --property-name "valid" \ - --property-authorizedValues " invalid | valid" \ - --array-alt "--help" - run Options2::validateCommandObject argFunction - assert_output --partial "ERROR - Options2::validateCommandObject - authorizedValues invalid regexp ' invalid | valid'" - assert_failure 2 + run Options2::validateCommandObject object + assert_output --partial "ERROR - Options2::validateCommandObject - only function can be passed as callback - invalid 'François'" assert_lines_count 1 -} - -function Options2::validateCommandObject::regexpInvalid { #@test - Object::create \ - --function-name "argFunction" \ - --type "Command" \ - --property-variableType "StringArray" \ - --property-variableName "varName" \ - --property-name "valid" \ - --property-regexp " " \ - --array-alt "--help" - run Options2::validateCommandObject argFunction - assert_output --partial "ERROR - Options2::validateCommandObject - regexp invalid regexp ' '" assert_failure 2 - assert_lines_count 1 } -function Options2::validateCommandObject::String::helpValueNameInvalidOption { #@test - Object::create \ - --function-name "argFunction" \ - --type "Command" \ - --property-variableType "String" \ - --property-variableName "varName" \ - --property-name "valid" \ - --property-helpValueName "invalid help" \ +function Options2::validateCommandObject::unknownArgumentCallbackInvalid { #@test + declare -a object=( + --type "Command" + --property-variableName "varName" + --property-variableType "String" --array-alt "--help" - run Options2::validateCommandObject argFunction - assert_output --partial "ERROR - Options2::validateCommandObject - helpValueName should be a single word 'invalid help'" - assert_failure 2 - assert_lines_count 1 -} + --property-name "valid" + --array-unknownArgumentCallback "François" + ) -function Options2::validateCommandObject::StringArray::helpValueNameInvalidOption { #@test - Object::create \ - --function-name "argFunction" \ - --type "Command" \ - --property-variableType "StringArray" \ - --property-variableName "varName" \ - --property-name "valid" \ - --property-helpValueName "invalid help" \ - --array-alt "--help" - run Options2::validateCommandObject argFunction - assert_output --partial "ERROR - Options2::validateCommandObject - helpValueName should be a single word 'invalid help'" - assert_failure 2 + run Options2::validateCommandObject object + assert_output --partial "ERROR - Options2::validateCommandObject - only function can be passed as callback - invalid 'François'" assert_lines_count 1 -} - -function Options2::validateCommandObject::StringArray::minValueEmpty { #@test - Object::create \ - --function-name "argFunction" \ - --type "Command" \ - --property-variableType "StringArray" \ - --property-variableName "varName" \ - --property-name "valid" \ - --property-min "" \ - --array-alt "--help" - run Options2::validateCommandObject argFunction - assert_output --partial "ERROR - Options2::validateCommandObject - min value should be an integer greater than or equal to 0" assert_failure 2 - assert_lines_count 1 } -function Options2::validateCommandObject::StringArray::minValueInvalid { #@test - Object::create \ - --function-name "argFunction" \ - --type "Command" \ - --property-variableType "StringArray" \ - --property-variableName "varName" \ - --property-name "valid" \ - --property-min "François" \ +function Options2::validateCommandObject::everyOptionCallbackInvalid { #@test + declare -a object=( + --type "Command" + --property-variableName "varName" + --property-variableType "String" --array-alt "--help" - run Options2::validateCommandObject argFunction - assert_output --partial "ERROR - Options2::validateCommandObject - min value should be an integer greater than or equal to 0" - assert_failure 2 + --property-name "valid" + --array-everyOptionCallback "François" + ) + + run Options2::validateCommandObject object + assert_output --partial "ERROR - Options2::validateCommandObject - only function can be passed as callback - invalid 'François'" assert_lines_count 1 + assert_failure 2 } -function Options2::validateCommandObject::StringArray::minValueLessThan0 { #@test - Object::create \ - --function-name "argFunction" \ - --type "Command" \ - --property-variableType "StringArray" \ - --property-variableName "varName" \ - --property-name "valid" \ - --property-min "-1" \ +function Options2::validateCommandObject::everyArgumentCallbackInvalid { #@test + declare -a object=( + --type "Command" + --property-variableName "varName" + --property-variableType "String" --array-alt "--help" - run Options2::validateCommandObject argFunction - assert_output --partial "ERROR - Options2::validateCommandObject - min value should be an integer greater than or equal to 0" - assert_failure 2 + --property-name "valid" + --array-everyArgumentCallback "François" + ) + + run Options2::validateCommandObject object + assert_output --partial "ERROR - Options2::validateCommandObject - only function can be passed as callback - invalid 'François'" assert_lines_count 1 + assert_failure 2 } - -function Options2::validateCommandObject::StringArray::minValueGreaterThanMaxValue { #@test - Object::create \ - --function-name "argFunction" \ - --type "Command" \ - --property-variableType "StringArray" \ - --property-variableName "varName" \ - --property-name "valid" \ - --property-min "3" \ - --property-max "1" \ - --array-alt "--help" - run Options2::validateCommandObject argFunction - assert_output --partial "ERROR - Options2::validateCommandObject - max value should be greater than min value" - assert_failure 2 - assert_lines_count 1 -} \ No newline at end of file diff --git a/src/Options2/validateCommandObject.sh b/src/Options2/validateCommandObject.sh index b2ce2704..57a734d7 100755 --- a/src/Options2/validateCommandObject.sh +++ b/src/Options2/validateCommandObject.sh @@ -51,16 +51,17 @@ Options2::validateCommandObject() { return 1 fi - local cmdInstanceObject=$1 - if [[ "$("${cmdInstanceObject}" type 2>/dev/null || echo '')" != "Command" ]]; then + # shellcheck disable=SC2034 + local -n cmdInstanceObject=$1 + if [[ "$(Object::getProperty cmdInstanceObject --type)" != "Command" ]]; then Log::displayError "Options2::validateCommandObject - passed object is not a command" return 2 fi # name local name - if "${cmdInstanceObject}" get name &>/dev/null; then - name="$("${cmdInstanceObject}" get name)" + if Object::memberExists cmdInstanceObject --property-name; then + name="$(Object::getProperty cmdInstanceObject --property-name)" if ! Assert::validVariableName "${name}"; then Log::displayError "Options2::validateCommandObject - invalid command name ${name}" return 2 @@ -70,41 +71,41 @@ Options2::validateCommandObject() { # callback checkCallbacks() { local callbackType="$1" - if "${cmdInstanceObject}" get "${callbackType}" &>/dev/null; then + if Object::memberExists cmdInstanceObject "${callbackType}"; then local callbacks - callbacks="$("${cmdInstanceObject}" get "${callbackType}")" + callbacks="$(Object::getArray cmdInstanceObject "${callbackType}")" local callback while IFS= read -r callback ; do - if [[ $(type -t "${callback}") = "function" ]]; then + if [[ $(type -t "${callback}") != "function" ]]; then Log::displayError "Options2::validateCommandObject - only function can be passed as callback - invalid '${callback}'" return 2 fi done <<< "${callbacks}" fi } - checkCallbacks "unknownOptionCallback" - checkCallbacks "unknownArgumentCallback" - checkCallbacks "everyOptionCallback" - checkCallbacks "everyArgumentCallback" - checkCallbacks "callback" + checkCallbacks --array-unknownOptionCallback || return 2 + checkCallbacks --array-unknownArgumentCallback || return 2 + checkCallbacks --array-everyOptionCallback || return 2 + checkCallbacks --array-everyArgumentCallback || return 2 + checkCallbacks --array-callback || return 2 # option/argument list - if ! "${cmdInstanceObject}" get element &>/dev/null; then + if ! Object::memberExists cmdInstanceObject --array-element; then Log::displayError "Options2::validateCommandObject - at least one option or argument must be provided" return 1 fi - local -& argumentList=() + local -a argumentList=() local elements - elements="$("${cmdInstanceObject}" get element)" + elements="$(Object::getArray cmdInstanceObject --array-element)" local element while IFS= read -r element ; do - # chekc element type is Option or Arg - if "${element}" type &>/dev/null; then + # check element type is Option or Arg + if [[ ! "$(declare -p "${element}")" =~ declare\ -a ]]; then Log::displayError "Options2::validateCommandObject - only object can be passed as element - invalid '${element}'" return 2 fi local elementType - elementType="$("${element}" type 2>/dev/null)" + elementType="$(Object::getProperty element --type)" if Array::contains "${elementType}" "Option" "Arg"; then Log::displayError "Options2::validateOptionObject - Element ${elementType} is not a valid object type" return 2 @@ -112,7 +113,7 @@ Options2::validateCommandObject() { # check variable name is not used by another option/argument local variableName - variableName="$("${element}" get variableName)" || { + variableName="$(Object::getProperty element --property-variableName "strict")" || { Log::displayError "Options2::validateOptionObject - ${elementType} ${element} - command variableName failed" return 1 } @@ -125,7 +126,7 @@ Options2::validateCommandObject() { # check alts not duplicated if [[ "${elementType}" = "Option" ]]; then local optionAlts - optionAlts="$("${element}" get alt)" || { + optionAlts="$(Object::getArray element --array-alt)" || { Log::displayError "Options2::validateOptionObject - Option ${element} - command alt failed" return 1 } @@ -142,18 +143,28 @@ Options2::validateCommandObject() { fi done <<< "${elements}" + # check min/max coherence + # check arguments coherence local currentArg currentArgMin currentArgMax local optionalArg="" for currentArg in "${argumentList[@]}"; do - currentArgMin="$("${currentArg}" get min)" || { + currentArgMin="$(Object::getProperty currentArg --property-min "strict")" || { Log::displayError "Options2::validateOptionObject - Argument ${currentArg} - command min failed" return 1 } - currentArgMax="$("${currentArg}" get max)" || { + if [[ ! "${currentArgMin}" =~ ^[0-9]+$ ]]; then + Log::displayError "Options::generateArg - Option --property-min - should be an int >= 0" + return 1 + fi + currentArgMax="$(Object::getProperty currentArg --property-max "strict")" || { Log::displayError "Options2::validateOptionObject - Argument ${currentArg} - command max failed" return 1 } + if [[ ! "${currentArgMax}" =~ ^([0-9]+|-1)$ ]]; then + Log::displayError "Options::generateArg - Option --property-max - should be an int >=0 or -1(infinite)" + return 1 + fi if ((currentArgMin != currentArgMax)); then optionalArg="$("${currentArg}" variableName)" elif [[ -n "${optionalArg}" ]]; then diff --git a/src/Options2/validateGroupObject.sh b/src/Options2/validateGroupObject.sh index e5f0767b..ef89d1f0 100755 --- a/src/Options2/validateGroupObject.sh +++ b/src/Options2/validateGroupObject.sh @@ -50,12 +50,13 @@ Options2::validateGroupObject() { return 1 fi - local groupInstanceObject=$1 - if [[ "$("${groupInstanceObject}" type 2>/dev/null || echo '')" != "Group" ]]; then + # shellcheck disable=SC2034 + local -n validateGroupObject=$1 + if [[ "$(Object::getProperty validateGroupObject --type)" != "Group" ]]; then Log::displayError "Options2::validateGroupObject - passed object is not a group" return 2 fi - if ! "${groupInstanceObject}" get title &>/dev/null; then + if ! Object::memberExists validateGroupObject --property-title; then Log::displayError "Options2::validateGroupObject - title is mandatory" return 3 fi diff --git a/src/Options2/validateOptionObject.bats b/src/Options2/validateOptionObject.bats index c129010d..e5946a2e 100755 --- a/src/Options2/validateOptionObject.bats +++ b/src/Options2/validateOptionObject.bats @@ -4,6 +4,8 @@ source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" # shellcheck source=src/Options/_bats.sh source "${srcDir}/Options/_bats.sh" +# shellcheck source=src/Object/__all.sh +source "${srcDir}/Object/__all.sh" # shellcheck source=src/Options2/__all.sh source "${srcDir}/Options2/__all.sh" @@ -27,149 +29,148 @@ function Options2::validateOptionObject::missingValue { #@test } function Options2::validateOptionObject::tooMuchArgs { #@test - Object::create \ - --function-name "optionFunction" \ + declare -a object=( --type "Option" - run Options2::validateOptionObject optionFunction optionFunction + ) + run Options2::validateOptionObject object object assert_lines_count 1 assert_output --partial "ERROR - Options2::validateOptionObject - exactly one parameter has to be provided" assert_failure 1 } function Options2::validateOptionObject::invalidObjectType { #@test - Object::create \ - --function-name "notAnOptionFunction" \ + declare -a notAnOption=( --type "NotAnOption" + ) - run Options2::validateOptionObject notAnOptionFunction + run Options2::validateOptionObject notAnOption assert_lines_count 1 assert_output --partial "ERROR - Options2::validateOptionObject - passed object is not an option" assert_failure 2 } function Options2::validateOptionObject::variableTypeMandatory { #@test - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ + declare -a object=( + --type "Option" --property-variableName "varName" + ) - run Options2::validateOptionObject optionFunction + run Options2::validateOptionObject object assert_output --partial "ERROR - Options2::validateOptionObject - variableType is mandatory" assert_lines_count 1 assert_failure 1 } function Options2::validateOptionObject::variableTypeInvalid { #@test - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ - --property-variableType "invalid" \ + declare -a object=( + --type "Option" + --property-variableType "invalid" --property-variableName "varName" + ) - run Options2::validateOptionObject optionFunction + run Options2::validateOptionObject object assert_output --partial "ERROR - Options2::validateOptionObject - invalid variableType invalid" assert_lines_count 1 assert_failure 2 } function Options2::validateOptionObject::variableNameMandatory { #@test - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ + declare -a object=( + --type "Option" --property-variableType "String" + ) - run Options2::validateOptionObject optionFunction + run Options2::validateOptionObject object assert_output --partial "ERROR - Options2::validateOptionObject - variableName is mandatory" assert_failure 1 assert_lines_count 1 } function Options2::validateOptionObject::variableNameInvalid { #@test - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ + declare -a object=( + --type "Option" --property-variableName "François" + ) - run Options2::validateOptionObject optionFunction + run Options2::validateOptionObject object assert_output --partial "ERROR - Options2::validateOptionObject - invalid variableName François" assert_failure 2 assert_lines_count 1 } function Options2::validateOptionObject::missingAltOption { #@test - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ - --property-variableName "varName" \ + declare -a object=( + --type "Option" + --property-variableName "varName" --property-variableType "String" + ) - run Options2::validateOptionObject optionFunction + run Options2::validateOptionObject object assert_output --partial "ERROR - Options2::validateOptionObject - you must provide at least one alt option" assert_lines_count 1 assert_failure 1 } function Options2::validateOptionObject::invalidAltValue { #@test - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ - --property-variableName "varName" \ - --property-variableType "String" \ + declare -a object=( + --type "Option" + --property-variableName "varName" + --property-variableType "String" --array-alt "François" - - run Options2::validateOptionObject optionFunction + ) + run Options2::validateOptionObject object assert_output --partial "ERROR - Options2::validateOptionObject - invalid alt option value 'François'" assert_lines_count 1 assert_failure 2 } function Options2::validateOptionObject::groupOptionInvalid { #@test - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ - --property-variableName "varName" \ - --property-variableType "String" \ - --property-group "invalidGroup" \ + declare -a object=( + --type "Option" + --property-variableName "varName" + --property-variableType "String" + --property-group "invalidGroup" --array-alt "--help" - - run Options2::validateOptionObject optionFunction - assert_output --partial "ERROR - Options2::validateOptionObject - Group invalidGroup - is not a valid group object" + ) + run Options2::validateOptionObject object + assert_output --partial "ERROR - Options2::validateOptionObject - Group invalidGroup is not a valid group object" assert_lines_count 1 assert_failure 2 } function Options2::validateOptionObject::groupOptionValid { #@test - Object::create \ - --type "Group" \ - --property-title "Global options" \ - --property-help "help" \ + declare -a group=( + --type "Group" + --property-title "Global options" + --property-help "help" --function-name "groupObjectFunction" + ) - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ - --property-variableName "varName" \ - --property-variableType "String" \ - --property-group "groupObjectFunction" \ + declare -a object=( + --type "Option" + --property-variableName "varName" + --property-variableType "String" + --property-group group --array-alt "--help" + ) local status=0 - run Options2::validateOptionObject optionFunction + run Options2::validateOptionObject object assert_output "" assert_success } function Options2::validateOptionObject::callbackOptionInvalid { #@test - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ - --property-variableName "varName" \ - --property-variableType "String" \ - --array-alt "--help" \ + declare -a object=( + --type "Option" + --property-variableName "varName" + --property-variableType "String" + --array-alt "--help" --array-callback "François" + ) - run Options2::validateOptionObject optionFunction - assert_output --partial "ERROR - Options2::validateOptionObject - only posix or bash framework function name are accepted - invalid 'François'" + run Options2::validateOptionObject object + assert_output --partial "ERROR - Options2::validateOptionObject - invalid alt option value 'François'" assert_lines_count 1 assert_failure 2 } @@ -178,154 +179,154 @@ function Options2::validateOptionObject::callbackOptionValid { #@test callback() { : } - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ - --property-variableName "varName" \ - --property-variableType "String" \ - --array-alt "--help" \ + declare -a object=( + --type "Option" + --property-variableName "varName" + --property-variableType "String" + --array-alt "--help" --array-callback "callback" - run Options2::validateOptionObject optionFunction + ) + run Options2::validateOptionObject object assert_output "" assert_success } function Options2::validateOptionObject::Boolean::onValueMissingValue { #@test - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ - --property-variableType "Boolean" \ - --property-variableName "varName" \ - --property-onValue "" \ + declare -a object=( + --type "Option" + --property-variableType "Boolean" + --property-variableName "varName" + --property-onValue "" --array-alt "--help" - run Options2::validateOptionObject optionFunction + ) + run Options2::validateOptionObject object assert_output --partial "ERROR - Options2::validateOptionObject - onValue cannot be empty" assert_failure 2 assert_lines_count 1 } function Options2::validateOptionObject::Boolean::offValueMissingValue { #@test - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ - --property-variableType "Boolean" \ - --property-variableName "varName" \ - --property-offValue "" \ + declare -a object=( + --type "Option" + --property-variableType "Boolean" + --property-variableName "varName" + --property-offValue "" --array-alt "--help" - run Options2::validateOptionObject optionFunction + ) + run Options2::validateOptionObject object assert_output --partial "ERROR - Options2::validateOptionObject - offValue cannot be empty" assert_failure 2 assert_lines_count 1 } function Options2::validateOptionObject::Boolean::onOffSameValue { #@test - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ - --property-variableType "Boolean" \ - --property-variableName "varName" \ - --property-offValue "1" \ - --property-onValue "1" \ + declare -a object=( + --type "Option" + --property-variableType "Boolean" + --property-variableName "varName" + --property-offValue "1" + --property-onValue "1" --array-alt "--help" - run Options2::validateOptionObject optionFunction + ) + run Options2::validateOptionObject object assert_output --partial "ERROR - Options2::validateOptionObject - onValue and offValue cannot be equal" assert_failure 2 assert_lines_count 1 } function Options2::validateOptionObject::String::authorizedValuesValueInvalidValue { #@test - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ - --property-variableType "String" \ - --property-variableName "varName" \ - --property-authorizedValues " invalid | valid" \ + declare -a object=( + --type "Option" + --property-variableType "String" + --property-variableName "varName" + --property-authorizedValues " invalid | valid" --array-alt "--help" - run Options2::validateOptionObject optionFunction + ) + run Options2::validateOptionObject object assert_output --partial "ERROR - Options2::validateOptionObject - authorizedValues invalid regexp ' invalid | valid'" assert_failure 2 assert_lines_count 1 } function Options2::validateOptionObject::StringArray::authorizedValuesValueInvalidValue { #@test - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ - --property-variableType "StringArray" \ - --property-variableName "varName" \ - --property-authorizedValues " invalid | valid" \ + declare -a object=( + --type "Option" + --property-variableType "StringArray" + --property-variableName "varName" + --property-authorizedValues " invalid | valid" --array-alt "--help" - run Options2::validateOptionObject optionFunction + ) + run Options2::validateOptionObject object assert_output --partial "ERROR - Options2::validateOptionObject - authorizedValues invalid regexp ' invalid | valid'" assert_failure 2 assert_lines_count 1 } function Options2::validateOptionObject::String::helpValueNameInvalidOption { #@test - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ - --property-variableType "String" \ - --property-variableName "varName" \ - --property-helpValueName "invalid help" \ + declare -a object=( + --type "Option" + --property-variableType "String" + --property-variableName "varName" + --property-helpValueName "invalid help" --array-alt "--help" - run Options2::validateOptionObject optionFunction + ) + run Options2::validateOptionObject object assert_output --partial "ERROR - Options2::validateOptionObject - helpValueName should be a single word 'invalid help'" assert_failure 2 assert_lines_count 1 } function Options2::validateOptionObject::StringArray::helpValueNameInvalidOption { #@test - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ - --property-variableType "StringArray" \ - --property-variableName "varName" \ - --property-helpValueName "invalid help" \ + declare -a object=( + --type "Option" + --property-variableType "StringArray" + --property-variableName "varName" + --property-helpValueName "invalid help" --array-alt "--help" - run Options2::validateOptionObject optionFunction + ) + run Options2::validateOptionObject object assert_output --partial "ERROR - Options2::validateOptionObject - helpValueName should be a single word 'invalid help'" assert_failure 2 assert_lines_count 1 } function Options2::validateOptionObject::StringArray::minValueEmpty { #@test - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ - --property-variableType "StringArray" \ - --property-variableName "varName" \ - --property-min "" \ + declare -a object=( + --type "Option" + --property-variableType "StringArray" + --property-variableName "varName" + --property-min "" --array-alt "--help" - run Options2::validateOptionObject optionFunction + ) + run Options2::validateOptionObject object assert_output --partial "ERROR - Options2::validateOptionObject - min value should be an integer greater than or equal to 0" assert_failure 2 assert_lines_count 1 } function Options2::validateOptionObject::StringArray::minValueInvalid { #@test - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ - --property-variableType "StringArray" \ - --property-variableName "varName" \ - --property-min "François" \ + declare -a object=( + --type "Option" + --property-variableType "StringArray" + --property-variableName "varName" + --property-min "François" --array-alt "--help" - run Options2::validateOptionObject optionFunction + ) + run Options2::validateOptionObject object assert_output --partial "ERROR - Options2::validateOptionObject - min value should be an integer greater than or equal to 0" assert_failure 2 assert_lines_count 1 } function Options2::validateOptionObject::StringArray::minValueLessThan0 { #@test - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ - --property-variableType "StringArray" \ - --property-variableName "varName" \ - --property-min "-1" \ + declare -a object=( + --type "Option" + --property-variableType "StringArray" + --property-variableName "varName" + --property-min "-1" --array-alt "--help" - run Options2::validateOptionObject optionFunction + ) + run Options2::validateOptionObject object assert_output --partial "ERROR - Options2::validateOptionObject - min value should be an integer greater than or equal to 0" assert_failure 2 assert_lines_count 1 @@ -333,15 +334,15 @@ function Options2::validateOptionObject::StringArray::minValueLessThan0 { #@test function Options2::validateOptionObject::StringArray::minValueGreaterThanMaxValue { #@test - Object::create \ - --function-name "optionFunction" \ - --type "Option" \ - --property-variableType "StringArray" \ - --property-variableName "varName" \ - --property-min "3" \ - --property-max "1" \ + declare -a object=( + --type "Option" + --property-variableType "StringArray" + --property-variableName "varName" + --property-min "3" + --property-max "1" --array-alt "--help" - run Options2::validateOptionObject optionFunction + ) + run Options2::validateOptionObject object assert_output --partial "ERROR - Options2::validateOptionObject - max value should be greater than min value" assert_failure 2 assert_lines_count 1 diff --git a/src/Options2/validateOptionObject.sh b/src/Options2/validateOptionObject.sh index 9688480f..4df243f9 100755 --- a/src/Options2/validateOptionObject.sh +++ b/src/Options2/validateOptionObject.sh @@ -71,53 +71,54 @@ Options2::validateOptionObject() { return 1 fi - local optionInstanceObject=$1 - if [[ "$("${optionInstanceObject}" type 2>/dev/null || echo '')" != "Option" ]]; then + # shellcheck disable=SC2034 + local -n validateOptionObject=$1 + if [[ "$(Object::getProperty validateOptionObject --type)" != "Option" ]]; then Log::displayError "Options2::validateOptionObject - passed object is not an option" return 2 fi # variable name - if ! "${optionInstanceObject}" get variableName &>/dev/null; then + if ! Object::memberExists validateOptionObject --property-variableName; then Log::displayError "Options2::validateOptionObject - variableName is mandatory" return 1 fi local variableName - variableName="$("${optionInstanceObject}" get variableName)" + variableName="$(Object::getProperty validateOptionObject --property-variableName)" if ! Assert::validVariableName "${variableName}"; then Log::displayError "Options2::validateOptionObject - invalid variableName ${variableName}" return 2 fi # variable type - if ! "${optionInstanceObject}" get variableType &>/dev/null; then + if ! Object::memberExists validateOptionObject --property-variableType; then Log::displayError "Options2::validateOptionObject - variableType is mandatory" return 1 fi local variableType - variableType="$("${optionInstanceObject}" get variableType)" + variableType="$(Object::getProperty validateOptionObject --property-variableType)" if ! Array::contains "${variableType}" "Boolean" "String" "StringArray"; then Log::displayError "Options2::validateOptionObject - invalid variableType ${variableType}" return 2 fi # group - if "${optionInstanceObject}" get group &>/dev/null; then - local groupFunction - groupFunction="$("${optionInstanceObject}" get group)" - if [[ "$("${groupFunction}" type 2>/dev/null)" != "Group" ]]; then - Log::displayError "Options2::validateOptionObject - Group ${groupFunction} - is not a valid group object" + local groupObject + groupObject="$(Object::getProperty validateOptionObject --property-group)" + if [[ -n "${groupObject}" ]]; then + if [[ "$(Object::getProperty "${groupObject}" --type)" != "Group" ]]; then + Log::displayError "Options2::validateOptionObject - Group ${groupObject} is not a valid group object" return 2 fi fi # alts - if ! "${optionInstanceObject}" get alt &>/dev/null; then + if ! Object::memberExists validateOptionObject --array-alt; then Log::displayError "Options2::validateOptionObject - you must provide at least one alt option" return 1 fi local alts - alts="$("${optionInstanceObject}" get alt)" + alts="$(Object::getArray validateOptionObject --array-alt)" local alt while IFS= read -r alt ; do if ! Options::assertAlt "${alt}"; then @@ -127,16 +128,13 @@ Options2::validateOptionObject() { done <<< "${alts}" # callback - if "${optionInstanceObject}" get callback &>/dev/null; then + if Object::memberExists validateOptionObject --array-callback; then local callbacks - callbacks="$("${optionInstanceObject}" get callback)" + callbacks="$(Object::getProperty validateOptionObject --array-callback)" local callback while IFS= read -r callback ; do - if - ! Assert::posixFunctionName "${callback}" && - ! Assert::bashFrameworkFunction "${callback}" - then - Log::displayError "Options2::validateOptionObject - only posix or bash framework function name are accepted - invalid '${callback}'" + if ! declare -F "${callback}" &>/dev/null; then + Log::displayError "Options2::validateOptionObject - callback '${callback}' - function does not exists" return 2 fi done <<< "${callbacks}" @@ -144,13 +142,13 @@ Options2::validateOptionObject() { if [[ "${variableType}" = "Boolean" ]]; then local onValue - onValue="$("${optionInstanceObject}" get onValue 2>/dev/null)" || onValue="1" + onValue="$(Object::getProperty validateOptionObject --property-onValue "strict")" || onValue="1" if [[ -z "${onValue}" ]]; then Log::displayError "Options2::validateOptionObject - onValue cannot be empty" return 2 fi local offValue - offValue="$("${optionInstanceObject}" get offValue 2>/dev/null)" || offValue="0" + offValue="$(Object::getProperty validateOptionObject --property-offValue "strict")" || offValue="0" if [[ -z "${offValue}" ]]; then Log::displayError "Options2::validateOptionObject - offValue cannot be empty" return 2 @@ -160,16 +158,15 @@ Options2::validateOptionObject() { return 2 fi elif [[ "${variableType}" = "String" || "${variableType}" = "StringArray" ]]; then - local authorizedValues - authorizedValues="$("${optionInstanceObject}" get authorizedValues 2>/dev/null)" || authorizedValues="" + authorizedValues="$(Object::getProperty validateOptionObject --property-authorizedValues "strict")" || authorizedValues="" if [[ "${authorizedValues}" =~ [[:space:]] ]]; then Log::displayError "Options2::validateOptionObject - authorizedValues invalid regexp '${authorizedValues}'" return 2 fi local helpValueName - helpValueName="$("${optionInstanceObject}" get helpValueName 2>/dev/null)" || helpValueName="" + helpValueName="$(Object::getProperty validateOptionObject --property-helpValueName "strict")" || helpValueName="" if [[ -n "${helpValueName}" && ! "${helpValueName}" =~ ^[A-Za-z0-9_-]+$ ]]; then Log::displayError "Options2::validateOptionObject - helpValueName should be a single word '${helpValueName}'" return 2 @@ -178,14 +175,14 @@ Options2::validateOptionObject() { if [[ "${variableType}" = "StringArray" ]]; then local min - min="$("${optionInstanceObject}" get min 2>/dev/null)" || min="0" + min="$(Object::getProperty validateOptionObject --property-min "strict")" || min="0" if [[ ! "${min}" =~ ^[0-9]+$ ]]; then Log::displayError "Options2::validateOptionObject - min value should be an integer greater than or equal to 0" return 2 fi local max - max="$("${optionInstanceObject}" get max 2>/dev/null)" || max="-1" + max="$(Object::getProperty validateOptionObject --property-max "strict")" || max="-1" if [[ -n "${max}" && ! "${max}" =~ ^([1-9][0-9]*|-1)$ ]]; then Log::displayError "Options2::validateOptionObject - max value should be an integer greater than 0 or -1" return 2 From 11c07a0af157f97a2d2dca1dc7b996e98d1dfbec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Chastanet?= Date: Sun, 7 Jan 2024 16:29:06 +0100 Subject: [PATCH 9/9] Options2 - commit as is --- manualTests/Object::create.sh | 12 ++--- manualTests/Object::setProperty.sh | 2 +- manualTests/Options2::renderHelpArg.sh | 3 +- manualTests/testCreateObject.sh | 24 +++++----- src/Object/create.bats | 26 +++++----- src/Object/getArray.bats | 4 +- src/Object/getArray.sh | 6 +++ src/Object/getProperty.bats | 2 +- src/Object/getProperty.sh | 6 +++ src/Object/initFromTemplate.bats | 63 ------------------------- src/Object/initFromTemplate.sh | 32 ------------- src/Object/memberExists.sh | 8 +++- src/Object/setArray.sh | 4 ++ src/Object/setProperty.sh | 4 ++ src/Options2/validateArgObject.bats | 10 ++-- src/Options2/validateCommandObject.bats | 5 +- src/Options2/validateGroupObject.bats | 30 ++++++------ src/Options2/validateOptionObject.bats | 7 ++- 18 files changed, 88 insertions(+), 160 deletions(-) delete mode 100755 src/Object/initFromTemplate.bats delete mode 100755 src/Object/initFromTemplate.sh diff --git a/manualTests/Object::create.sh b/manualTests/Object::create.sh index ec200361..b1945642 100755 --- a/manualTests/Object::create.sh +++ b/manualTests/Object::create.sh @@ -11,7 +11,6 @@ source "${srcDir}/Options2/__all.sh" # shellcheck source=/src/Log/__all.sh source "${srcDir}/Log/__all.sh" - #set -x set -o errexit set -o pipefail @@ -22,12 +21,12 @@ Object::create zzzGroupGlobalOptionsFunction \ --property-title "GLOBAL OPTIONS:" Object::create simpleObjectFunction \ - --type "Group" + --type "Group" Object::create groupObjectFunction \ - --type "Group" \ - --property-title "title" \ - --property-help "help" + --type "Group" \ + --property-title "title" \ + --property-help "help" BASH_FRAMEWORK_DISPLAY_LEVEL=__LEVEL_DEBUG @@ -35,4 +34,5 @@ Object::create optionFunction \ --type "Option" \ --property-variableName "varName" -Options2::validateOptionObject "${optionFunction}" \ No newline at end of file +# shellcheck disable=SC2154 +Options2::validateOptionObject "${optionFunction}" diff --git a/manualTests/Object::setProperty.sh b/manualTests/Object::setProperty.sh index cdd0c6d1..e527d550 100755 --- a/manualTests/Object::setProperty.sh +++ b/manualTests/Object::setProperty.sh @@ -16,4 +16,4 @@ declare -a newPropertyObject=( --property-property "propertyValue" ) Object::setProperty newPropertyObject --property-newProperty "value" -declare -p newPropertyObject \ No newline at end of file +declare -p newPropertyObject diff --git a/manualTests/Options2::renderHelpArg.sh b/manualTests/Options2::renderHelpArg.sh index f1461194..8928dce2 100755 --- a/manualTests/Options2::renderHelpArg.sh +++ b/manualTests/Options2::renderHelpArg.sh @@ -26,6 +26,7 @@ declare -a arg=( --property-mandatory 1 --property-max 2 ) +# shellcheck disable=SC2034 declare -a group=( --type "Group" --property-title "Global options" @@ -42,4 +43,4 @@ declare -a arg=( ) Options2::validateArgObject arg UI::theme "default" -Options2::renderArgHelp arg 2>&1 \ No newline at end of file +Options2::renderArgHelp arg 2>&1 diff --git a/manualTests/testCreateObject.sh b/manualTests/testCreateObject.sh index 649b97b5..5db579f0 100755 --- a/manualTests/testCreateObject.sh +++ b/manualTests/testCreateObject.sh @@ -7,15 +7,15 @@ source src/Options2/__all.sh declare myFunction Object::create myFunction \ - --type "Command" \ - --property-name "François" + --type "Command" \ + --property-name "François" declare myFunction2 Object::create myFunction2 \ - --array-list "a" \ - --type "Command2" \ - --property-name "François2" \ - --array-list "b" \ - --array-list "c" + --array-list "a" \ + --type "Command2" \ + --property-name "François2" \ + --array-list "b" \ + --array-list "c" echo "--------------------------------------------" ${myFunction} getProperty --property-name @@ -30,12 +30,12 @@ ${myFunction2} setProperty name "myFunction2François3" ${myFunction2} getProperty --property-name echo -n "name2 " ${myFunction2} setProperty name2 "newProperty name2" - + ${myFunction2} getProperty --property-name2 echo "--------------------------------------------" Object::create myFunction2 \ - --function-name "argFunction2Overload" \ - --type "Command2Overload" \ - --property-name "François2Overload" -${myFunction2} getProperty --property-name \ No newline at end of file + --function-name "argFunction2Overload" \ + --type "Command2Overload" \ + --property-name "François2Overload" +${myFunction2} getProperty --property-name diff --git a/src/Object/create.bats b/src/Object/create.bats index 1025bd3e..c2101568 100755 --- a/src/Object/create.bats +++ b/src/Object/create.bats @@ -16,7 +16,7 @@ function Object::create::simpleObject { #@test Object::create simpleObjectFunction \ --type "simpleObjectType" \ --property-property "propertyValue" - + run ${simpleObjectFunction} type assert_output "simpleObjectType" @@ -43,7 +43,7 @@ function Object::create::missingPositionalArg { #@test run Object::create \ --type "simpleObjectType" \ --propertyInvalid-property "propertyValue" 2>&1 - + assert_output --partial "local: \`--type': invalid variable name for name reference" assert_failure 1 } @@ -54,7 +54,7 @@ function Object::create::simpleObjectNonStrict { #@test --strict 0 \ --type "simpleObjectType" \ --property-property "propertyValue" - + run ${simpleObjectType} strict assert_output "0" @@ -68,7 +68,7 @@ function Object::create::invalidProperty { #@test run Object::create simpleObjectType \ --type "simpleObjectType" \ --propertyInvalid-property "propertyValue" 2>&1 - + assert_output --partial "ERROR - invalid object property --propertyInvalid-property" assert_failure 1 } @@ -79,17 +79,17 @@ function Object::create::duplicatedProperty { #@test --type "simpleObjectType" \ --property-property "propertyValue1" \ --property-property "propertyValue2" 2>&1 - + assert_output --partial "ERROR - property property is provided more than one time" assert_failure 1 } function Object::create::invalidObjectType { #@test - declare invalidObjectType + declare invalidObjectType run Object::create invalidObjectType \ --type "invalidéObjectType" \ --property-property "propertyValue" 2>&1 - + assert_output --partial "ERROR - invalid object type invalidéObjectType" assert_failure 1 } @@ -97,7 +97,7 @@ function Object::create::invalidObjectType { #@test function Object::create::missingObjectType { #@test run Object::create missingObjectType \ --property-property "propertyValue" 2>&1 - + assert_output --partial "ERROR - missing object type" assert_failure 1 } @@ -107,9 +107,9 @@ function Object::create::unknownArray { #@test Object::create unknownArray \ --type "simpleObjectType" \ --array-list "unknownArray" 2>&1 - + run ${unknownArray} getArray "unknownArray" - + assert_output --partial "ERROR - unknown array unknownArray" assert_failure 2 } @@ -121,7 +121,7 @@ function Object::create::propertyArrayOrdered { #@test --property-property "propertyValue" \ --array-list "value1" \ --array-list "value2" - + run ${propertyArrayOrdered} type assert_success assert_output "simpleObjectType" @@ -148,7 +148,7 @@ function Object::create::propertyArrayUnordered { #@test --array-list "value2" \ --property-property "propertyValue" \ --array-list "value3" - + run ${propertyArrayUnordered} type assert_success assert_output "simpleObjectType" @@ -172,4 +172,4 @@ function Object::create::propertyArrayUnordered { #@test assert_lines_count 2 assert_line --index 0 "list" assert_line --index 1 "property" -} \ No newline at end of file +} diff --git a/src/Object/getArray.bats b/src/Object/getArray.bats index 861a5b72..52dc16e5 100755 --- a/src/Object/getArray.bats +++ b/src/Object/getArray.bats @@ -44,13 +44,13 @@ function Object::getArray::multipleArrayValues { #@test assert_success } -function Object::getArray::unknownProperty { #@test +function Object::getArray::unknownArray { #@test declare -a simpleObject=( --type "simpleObjectType" --property-property "propertyValue" ) run Object::getArray simpleObject --array-unknownArray 1 - assert_output --partial "ERROR - unknown array --array-unknownArray" + assert_output "" assert_failure 1 run Object::getArray simpleObject --array-unknownArray 0 diff --git a/src/Object/getArray.sh b/src/Object/getArray.sh index 533e0bb2..1db9181a 100755 --- a/src/Object/getArray.sh +++ b/src/Object/getArray.sh @@ -1,5 +1,11 @@ #!/bin/bash +# @description get array elements from object +# @arg $1 object_get_array_objectData:&String[] the object +# @arg $2 arrayName:String the name of the array property to search (eg: --array-property) +# @arg $3 strict:Boolean if !0 then return code 1 if array property not found +# @stdout the array property values if array property found(one value by line) +# @exitcode 1 if array property not found Object::getArray() { local -n object_get_array_objectData=$1 local arrayName="${2:-}" diff --git a/src/Object/getProperty.bats b/src/Object/getProperty.bats index ca10e592..bfb7df19 100755 --- a/src/Object/getProperty.bats +++ b/src/Object/getProperty.bats @@ -31,7 +31,7 @@ function Object::getProperty::unknownProperty { #@test --property-property "propertyValue" ) run Object::getProperty simpleObject --property-unknownProperty 1 - assert_output --partial "ERROR - unknown property --property-unknownProperty" + assert_output "" assert_failure 1 run Object::getProperty simpleObject --property-unknownProperty 0 diff --git a/src/Object/getProperty.sh b/src/Object/getProperty.sh index 0e240c1a..049dcd15 100755 --- a/src/Object/getProperty.sh +++ b/src/Object/getProperty.sh @@ -1,5 +1,11 @@ #!/bin/bash +# @description get property value from object +# @arg $1 object_get_property_objectData:&String[] the object +# @arg $2 propertyName:String the name of the property to search (eg: --property) +# @arg $3 strict:Boolean if !0 then return code 1 if property not found +# @stdout the property value if property found +# @exitcode 1 if property not found Object::getProperty() { local -n object_get_property_objectData=$1 local propertyName="${2:-}" diff --git a/src/Object/initFromTemplate.bats b/src/Object/initFromTemplate.bats deleted file mode 100755 index 8efe7a42..00000000 --- a/src/Object/initFromTemplate.bats +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env bash -# shellcheck disable=SC2154 -# shellcheck disable=SC2034 - -# shellcheck source=src/batsHeaders.sh -source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" -# shellcheck source=src/Object/__all.sh -source "${srcDir}/Object/__all.sh" -# shellcheck source=src/Assert/posixFunctionName.sh -source "${srcDir}/Assert/posixFunctionName.sh" -# shellcheck source=src/Array/contains.sh -source "${srcDir}/Array/contains.sh" - -function Object::setProperty::simpleObject { #@test - declare -a simpleObject=( - --type "simpleObjectType" - --property-property "propertyValue" - ) - local status=0 - Object::setProperty simpleObject --property-property "newPropertyValue" || status=1 - [[ "${status}" = "0" ]] - run echo "${simpleObject[@]}" - assert_output "--type simpleObjectType --property-property newPropertyValue" -} - -function Object::setProperty::multipleProperties { #@test - declare -a multipleProperties=( - --type "multiplePropertiesType" - --property-property "propertyValue" - --property-property2 "propertyValue2" - ) - local status=0 - Object::setProperty multipleProperties --property-property "newPropertyValue" || status=1 - [[ "${status}" = "0" ]] - run echo "${multipleProperties[@]}" - assert_output "--type multiplePropertiesType --property-property newPropertyValue --property-property2 propertyValue2" -} - -function Object::setProperty::withArray { #@test - declare -a withArray=( - --type "withArrayType" - --property-property "propertyValue" - --array-list "elem1" "elem2" -- - --property-property2 "propertyValue2" - ) - local status=0 - Object::setProperty withArray --property-property2 "newPropertyValue" || status=1 - [[ "${status}" = "0" ]] - run echo "${withArray[@]}" - assert_output "--type withArrayType --property-property propertyValue --array-list "elem1" "elem2" -- --property-property2 newPropertyValue" -} - -function Object::setProperty::newProperty { #@test - declare -a newPropertyObject=( - --type "simpleObjectType" - --property-property "propertyValue" - ) - local status=0 - Object::setProperty newPropertyObject --property-newProperty "value" || status=1 - [[ "${status}" = "0" ]] - run echo "${newPropertyObject[@]}" - assert_output "--type simpleObjectType --property-property propertyValue --property-newProperty value" -} diff --git a/src/Object/initFromTemplate.sh b/src/Object/initFromTemplate.sh deleted file mode 100755 index 05f93a95..00000000 --- a/src/Object/initFromTemplate.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -Object::initFromTemplate() { - local -n object_init_from_template_template=$1 - local -n object_init_from_template_object=$2 - shift 2 || true - local propertyName="${2:-}" - local propertyValue="${3:-}" - - local i=0 || true - local -i propertiesLength="${#object_set_property_objectData[@]}" - local -a newProperties=() - local propertyFound="0" - while ((i < propertiesLength)); do - if [[ "${object_set_property_objectData[${i}]}" = "--property-${propertyName}" ]]; then - propertyFound="1" - newProperties+=( - "${object_set_property_objectData[${i}]}" "${propertyValue}" - ) - if ((i < propertiesLength - 2)); then - newProperties+=("${object_set_property_objectData[@]:i+2}") - fi - break - fi - newProperties+=("${object_set_property_objectData[${i}]}") - ((i = i + 1)) - done - if [[ "${propertyFound}" = "0" ]]; then - newProperties+=("--property-${propertyName}" "${propertyValue}") - fi - object_set_property_objectData=("${newProperties[@]}") -} diff --git a/src/Object/memberExists.sh b/src/Object/memberExists.sh index ec3dfb8c..59b3fc94 100755 --- a/src/Object/memberExists.sh +++ b/src/Object/memberExists.sh @@ -1,13 +1,17 @@ #!/bin/bash +# @description check if member(property or array property) exists on given object +# @arg $1 object_member_exists_objectData:&String[] the object +# @arg $2 memberName:String the name of the member to search (eg: --property) +# @exitcode 1 if member not found Object::memberExists() { local -n object_member_exists_objectData=$1 - local propertyName="${2:-}" + local memberName="${2:-}" local -i propertiesLength="${#object_member_exists_objectData[@]}" local -i i=0 || true while ((i < propertiesLength)); do - if [[ "${object_member_exists_objectData[${i}]}" = "${propertyName}" ]]; then + if [[ "${object_member_exists_objectData[${i}]}" = "${memberName}" ]]; then return 0 fi ((i = i + 1)) diff --git a/src/Object/setArray.sh b/src/Object/setArray.sh index 77a98ca7..0224132a 100755 --- a/src/Object/setArray.sh +++ b/src/Object/setArray.sh @@ -1,5 +1,9 @@ #!/bin/bash +# @description create or overwrite array property on object +# @arg $1 object_set_array_objectData:&String[] the object +# @arg $2 arrayName:String the name of the array property to search (eg: --array-property) +# @arg $@ arrayValues:String[] array values to set Object::setArray() { local -n object_set_array_objectData=$1 local arrayName="${2:-}" diff --git a/src/Object/setProperty.sh b/src/Object/setProperty.sh index c0f8e3b7..a9566592 100755 --- a/src/Object/setProperty.sh +++ b/src/Object/setProperty.sh @@ -1,5 +1,9 @@ #!/bin/bash +# @description create or overwrite property value on object +# @arg $1 object_set_property_objectData:&String[] the object +# @arg $2 propertyName:String the name of the property to search (eg: --property) +# @arg $3 propertyValue:String property value to set Object::setProperty() { local -n object_set_property_objectData=$1 local propertyName="${2:-}" diff --git a/src/Options2/validateArgObject.bats b/src/Options2/validateArgObject.bats index 948076d9..9a032084 100755 --- a/src/Options2/validateArgObject.bats +++ b/src/Options2/validateArgObject.bats @@ -32,7 +32,7 @@ function Options2::validateArgObject::tooMuchArgs { #@test declare -a arg=( --type "Arg" ) - run Options2::validateArgObject arg arg + run Options2::validateArgObject arg arg assert_lines_count 1 assert_output --partial "ERROR - Options2::validateArgObject - exactly one parameter has to be provided" assert_failure 1 @@ -42,7 +42,7 @@ function Options2::validateArgObject::invalidObjectType { #@test declare -a arg=( --type "notAnArg" ) - + run Options2::validateArgObject arg assert_lines_count 1 assert_output --partial "ERROR - Options2::validateArgObject - passed object is not an argument" @@ -99,7 +99,6 @@ function Options2::validateArgObject::nameInvalid { #@test assert_lines_count 1 } - function Options2::validateArgObject::callbackInvalid { #@test declare -a arg2=( --type "Arg" @@ -109,7 +108,7 @@ function Options2::validateArgObject::callbackInvalid { #@test --property-name "valid" --array-callback "François" ) - + run Options2::validateArgObject arg2 2>&1 assert_output --partial "ERROR - Options2::validateArgObject - callback 'François' - function does not exists" assert_lines_count 1 @@ -253,7 +252,6 @@ function Options2::validateArgObject::StringArray::minValueLessThan0 { #@test assert_lines_count 1 } - function Options2::validateArgObject::StringArray::minValueGreaterThanMaxValue { #@test declare -a arg=( --type "Arg" @@ -268,4 +266,4 @@ function Options2::validateArgObject::StringArray::minValueGreaterThanMaxValue { assert_output --partial "ERROR - Options2::validateArgObject - max value should be greater than min value" assert_failure 2 assert_lines_count 1 -} \ No newline at end of file +} diff --git a/src/Options2/validateCommandObject.bats b/src/Options2/validateCommandObject.bats index d42c7f50..f3ff75c0 100755 --- a/src/Options2/validateCommandObject.bats +++ b/src/Options2/validateCommandObject.bats @@ -32,7 +32,7 @@ function Options2::validateCommandObject::tooMuchArgs { #@test declare -a object=( --type "Command" ) - run Options2::validateCommandObject object object + run Options2::validateCommandObject object object assert_lines_count 1 assert_output --partial "ERROR - Options2::validateCommandObject - exactly one parameter has to be provided" assert_failure 1 @@ -51,7 +51,7 @@ function Options2::validateCommandObject::invalidObjectType { #@test function Options2::validateCommandObject::nameInvalid { #@test declare -a object=( - --type "Command" \ + --type "Command" --property-name "François" ) @@ -140,4 +140,3 @@ function Options2::validateCommandObject::everyArgumentCallbackInvalid { #@test assert_lines_count 1 assert_failure 2 } - diff --git a/src/Options2/validateGroupObject.bats b/src/Options2/validateGroupObject.bats index e084fe6f..3c7355a8 100755 --- a/src/Options2/validateGroupObject.bats +++ b/src/Options2/validateGroupObject.bats @@ -6,6 +6,8 @@ source "$(cd "${BATS_TEST_DIRNAME}/.." && pwd)/batsHeaders.sh" source "${srcDir}/Options/_bats.sh" # shellcheck source=src/Options2/__all.sh source "${srcDir}/Options2/__all.sh" +# shellcheck source=src/Object/memberExists.sh +source "${srcDir}/Object/memberExists.sh" function setup() { export TMPDIR="${BATS_TEST_TMPDIR}" @@ -30,22 +32,22 @@ function Options2::validateGroupObject::invalidObject { #@test } function Options2::validateGroupObject::notAGroup { #@test - Object::create \ - --type "NotAGroup" \ - --function-name "notAGroupFunction" + local -a notAGroup=( + --type "NotAGroup" + ) - run Options2::validateGroupObject notAGroupFunction + run Options2::validateGroupObject notAGroup assert_lines_count 1 assert_output --partial "ERROR - Options2::validateGroupObject - passed object is not a group" assert_failure 2 } function Options2::validateGroupObject::missingTitle { #@test - Object::create \ - --type "Group" \ - --function-name "simpleObjectFunction" + local -a simpleObject=( + --type "Group" + ) - run Options2::validateGroupObject simpleObjectFunction + run Options2::validateGroupObject simpleObject assert_output --partial "ERROR - Options2::validateGroupObject - title is mandatory" assert_failure 3 assert_lines_count 1 @@ -53,12 +55,12 @@ function Options2::validateGroupObject::missingTitle { #@test function Options::validateGroupObject::groupOptionValid { #@test local status=0 - Object::create \ - --type "Group" \ - --property-title "Global options" \ - --property-help "help" \ - --function-name "groupObjectFunction" - run Options2::validateGroupObject groupObjectFunction >"${BATS_TEST_TMPDIR}/result" 2>&1 + local -a groupObject=( + --type "Group" + --property-title "Global options" + --property-help "help" + ) + run Options2::validateGroupObject groupObject >"${BATS_TEST_TMPDIR}/result" 2>&1 assert_success assert_output "" } diff --git a/src/Options2/validateOptionObject.bats b/src/Options2/validateOptionObject.bats index e5946a2e..d0b02e35 100755 --- a/src/Options2/validateOptionObject.bats +++ b/src/Options2/validateOptionObject.bats @@ -32,7 +32,7 @@ function Options2::validateOptionObject::tooMuchArgs { #@test declare -a object=( --type "Option" ) - run Options2::validateOptionObject object object + run Options2::validateOptionObject object object assert_lines_count 1 assert_output --partial "ERROR - Options2::validateOptionObject - exactly one parameter has to be provided" assert_failure 1 @@ -104,7 +104,7 @@ function Options2::validateOptionObject::missingAltOption { #@test --property-variableName "varName" --property-variableType "String" ) - + run Options2::validateOptionObject object assert_output --partial "ERROR - Options2::validateOptionObject - you must provide at least one alt option" assert_lines_count 1 @@ -332,7 +332,6 @@ function Options2::validateOptionObject::StringArray::minValueLessThan0 { #@test assert_lines_count 1 } - function Options2::validateOptionObject::StringArray::minValueGreaterThanMaxValue { #@test declare -a object=( --type "Option" @@ -346,4 +345,4 @@ function Options2::validateOptionObject::StringArray::minValueGreaterThanMaxValu assert_output --partial "ERROR - Options2::validateOptionObject - max value should be greater than min value" assert_failure 2 assert_lines_count 1 -} \ No newline at end of file +}