From d20bc4e9865002cb3d29d073a6a18e6aebff914b Mon Sep 17 00:00:00 2001 From: ayakael Date: Thu, 11 Jan 2018 10:09:00 -0900 Subject: [PATCH] Renamed config.sh to cfg.sh to match function name Fixed code-breaking bugs for cfg.sh for all base functions (i.e not dispatcher functions) Added test file for cfg function for all base functions (i.e not dispatcher functions) --- lib/cfg.sh | 190 +++++++++++++++++++++++++++++++++++++++++++++++ lib/config.sh | 169 ----------------------------------------- test/test-cfg.sh | 152 +++++++++++++++++++++++++++++++++++++ 3 files changed, 342 insertions(+), 169 deletions(-) create mode 100644 lib/cfg.sh delete mode 100644 lib/config.sh create mode 100644 test/test-cfg.sh diff --git a/lib/cfg.sh b/lib/cfg.sh new file mode 100644 index 0000000..1368a50 --- /dev/null +++ b/lib/cfg.sh @@ -0,0 +1,190 @@ +#!/bin/bash + +# doc cfg { +# +# NAME +# cfg +# +# DESCRIPTION +# Reads and writes config files delimited by tabs, like fstab, using awk. +# +# USAGE +# _cfg +# +# COMMANDS +# set-file +# Sets path to file +# +# create +# Creates config file and assigns . +# +# print +# Prints value from and . +# +# change +# Assigns new to and . +# +# drop or . +# +# insert <...> +# Inserts new row with a value per column. Number of arguments must match number of columns. +# +# query +# Queries which fits the . +# +# +# CONDITIONALS +# +# +# +# EXIT VALUES +# 0 Success +# 1 Syntax or usage error +# 2 File not found +# 3 File already present +# 4 Row or column not found +# 5 Row or column already has value +# +# } + +_cfg_column_to_nf() { + # Argument parser and sanity check + [[ -z ${1+x} ]] && { _msg ECHO "_cfg_column_to_nf(): Expected column name"; return 1; } + local COLUMN=${1} + + # Queries list of columns + local columnList=(all $(awk 'BEGIN {FS="\t"; OFS="\t"}; {if (NR == 1 ) {print $0}}' ${_CFG_PATH})) + + # Checks if queried ${COLUMN} exists + if ! _if_array_contains ${COLUMN} ${columnList[@]}; then + _msg ECHO "_cfg_column_to_nf(): Column does not exist" + return 1 + else + # Finds what NF is associated with ${COLUMN} + local COUNT=0 + for column in ${columnList[@]}; do + [[ "${COLUMN}" == "${column}" ]] && echo "${COUNT}" + local COUNT=$(( ${COUNT} + 1 )) + done + return 0 + fi +} + +_cfg_set_file() { + # Argument parser and sanity check + [[ $# != 1 ]] && { _msg ECHO "_cfg_set_file(): Expected 1 argument"; return 1; } + + # Sets _CFG_PATH globally + _CFG_PATH="${1}" + _CFG_TMP_PATH="$(sed 's|\(.*\)\/|\1/.|' <<<"${_CFG_PATH}")" +} + +_cfg_create() { + # Argument parser and sanity check + [[ -z ${1+x} ]] && { _msg ECHO "_cfg_create(): Expected argument"; return 1; } + local colList=(${@}) + + # Creates config file + printf "%s\t" ${colList[@]} | awk 'BEGIN{OFS="\t";} {printf "%s\n",$0}' >> ${_CFG_PATH} +} + +_cfg_print() { + # Argument parser and sanity check + [[ $# != 2 ]] && { _msg ECHO "_cfg_print(): Expected 2 arguments"; return 1; } + local COLUMN=${1} + local ROW=${2} + + # Prints row of ${_CFG_PATH} + awk 'BEGIN {OFS="\t"}; {if (NR == '${ROW}') {print $'$(_cfg_column_to_nf ${COLUMN})'}}' "${_CFG_PATH}" +} + +_cfg_change() { + # Argument parser and sanity check + [[ $# != 3 ]] && { _msg ECHO "_cfg_change(): Expected 3 arguments"; return 1; } + local COLUMN=${1} + local ROW=${2} + local VALUE=${3} + local COLUMN_NO=$(_cfg_column_to_nf ${COLUMN}) + _if_is_integer ${ROW} || { _msg ECHO "_cfg_change(): Expected integer"; return 1; } + [[ ${ROW} > $(awk 'BEGIN{FS="\t"; OFS="\t"}; {print NR}' ${_CFG_PATH} | wc -l) ]] && { _msg ECHO "_cfg_change(): Row ${ROW} does not exist"; return 1; } + + # Writes new version of file + awk 'BEGIN {OFS="\t"}; {if (NR == '${ROW}') {$'${COLUMN_NO}'="'${VALUE}'"} {print $0}}' "${_CFG_PATH}" > ${_CFG_TMP_PATH} && mv ${_CFG_TMP_PATH} ${_CFG_PATH} + +} + +_cfg_drop() { + # Argument parser and sanity check + [[ $# != 2 ]] && { _msg ECHO "_cfg_drop(): Expected 2 arguments"; return 1; } + local SUBCMD=${1}; shift + [[ ! $(_if_array_contains ${SUBCMD} row column) ]] && { _msg ECHO "_cfg_drop(): Expected 'row' or 'column' as subcommand"; return 1; } + + # Dispatcher + eval _cfg_drop_${SUBCMD} ${1} +} + +_cfg_drop_row() { + # Argument parser and sanity check + local ROW=${1} + [[ ${ROW} > $(awk 'BEGIN {FS="\t"; OFS="\t"}; {print NR}' ${_CFG_PATH} | wc -l) ]] && { _msg ECHO "_cfg_drop_row(): Row ${ROW} does not exist"; return 1; } + + # Writes new version of file + awk 'BEGIN {OFS="\t"}; {if (NR != '${ROW}') {print $0}}' ${_CFG_PATH} > ${_CFG_TMP_PATH} && mv ${_CFG_TMP_PATH} ${_CFG_PATH} + +} + +_cfg_drop_column() { + local COLUMN=${1} + local NF=$(_cfg_column_to_nf "${COLUMN}") + + # Writes new version of file + awk 'BEGIN {OFS="\t"}; {$'${NF}'=""; print $0}' ${_CFG_PATH} > ${_CFG_TMP_PATH} && mv ${_CFG_TMP_PATH} ${_CFG_PATH} +} + +_cfg_insert() { + # Argument parser and sanity check + [[ $# != 2 ]] && { _msg ECHO "_cfg_insert(): Expected 2 arguments"; return 1; } + local SUBCMD=${1}; shift + [[ ! $(_if_array_contains ${SUBCMD} row column) ]] && { _msg ECHO "_cfg_insert(): Expected 'row' or 'column' as subcommand"; return 1; } + + # Dispatcher + eval _cfg_insert_${SUBCMD} ${1} +} + +_cfg_insert_column() { + # Argument parser and sanity check + local VALUE=${1} + local NX_COLUMN=$(( $(awk 'BEGIN{OFS="\t"}; {if (NR == 1) {print NF}}' ${_CFG_PATH}) + 1 )) + + # Write new version of header into file + awk 'BEGIN {OFS="\t"}; {if (NR == 1) {$'${NX_COLUMN}'="'${VALUE}'"} {print $0}}' "${_CFG_PATH}" > ${_CFG_TMP_PATH} && mv ${_CFG_TMP_PATH} ${_CFG_PATH} +} + +_cfg_insert_row() { + # Argument parser and sanity check + local valueList=(${@}) + local COLUMN_NO=$(awk 'BEGIN{OFS="\t"}; {if (NR == 1) {print NF}}' ${_CFG_PATH}) + [[ "${#valueList[@]}" != "${COLUMN_NO}" ]] && { _msg ECHO "_cfg_insert_row(): Number of arguments must be equal to ${COLUMN_NO}"; return 1; } + + # Write row into file + printf "%s\t" ${valueList[@]} | awk 'BEGIN{OFS="\t";} {printf "%s\n",$0}' >> ${_CFG_PATH} +} + +_cfg_query() { + # Argument parser and sanity check + local CONDITION="${1}" + + awk 'BEGIN {FS="\t"; OFS="\t"}; {if ('${CONDITION}') {print NR}}' "${_CFG_PATH}" +} + +_cfg() { + # Sanity check and command parser + [[ -z ${1+x} ]] && { _msg ECHO "_cfg(): Expected command"; return 1; } + local cmdList="(set-file create print change drop insert query)" + local CMD=${1}; shift + [[ ! $(_if_array_contains ${CMD} ${cmdList[@]}) ]] && { _msg ECHO "_cfg(): Command specified not valid"; return 1; } + + # Dispatcher + eval _cfg_$(sed 's|-|_|' <<<"${CMD}") ${@} +} diff --git a/lib/config.sh b/lib/config.sh deleted file mode 100644 index 9742141..0000000 --- a/lib/config.sh +++ /dev/null @@ -1,169 +0,0 @@ -#/bin/bash - -# doc cfg { -# -# NAME -# cfg -# -# DESCRIPTION -# Reads and writes config files delimited by tabs, like fstab, using awk. -# -# USAGE -# _cfg -# -# COMMANDS -# set-file -# Sets path to file -# -# create -# Creates config file and assigns . -# -# print -# Prints value from and . -# -# change -# Assigns new to and . -# -# drop or . -# -# insert <...> -# Inserts new row with a value per column. Number of arguments must match number of columns. -# -# query -# Queries which fits the . -# -# -# CONDITIONALS -# -# -# -# EXIT VALUES -# 0 Success -# 1 Syntax or usage error -# 2 File not found -# 3 File already present -# 4 Row or column not found -# 5 Row or column already has value -# -# } - -_cfg() { - # Sanity check and command parser - [[ ! -z ${1+x} ]] && {_msg ECHO "_cfg(): Expected command"; return 1} - local cmdList="(set-file create print change drop insert query)" - local CMD=${1}; shift - [[ ! _if_array_contains ${CMD} ${cmdList[@]} ]] && {_msg ECHO "_cfg(): Command specified not valid; return 1"} - - # Dispatcher - _cfg_$(sed 's|-|_|' <<<"${CMD}") ${@} -} - -_cfg_column_to_nf() { - # Argument parser and sanity check - [[ ! -z ${1+x} ]] && {_msg ECHO "_cfg(): Expected column name"; return 1} - local COLUMN=${1} - - # Queries list of columns - local columnList=(all $(awk 'BEGIN {FS="\t"; OFS="\t"}; {if (NR = 0) {print '${0}'}}' ${_CFG_PATH})) - - # Checks if queried ${COLUMN} exists - if [ if ! _if_array_contains ${COLUMN} ${columnList[@]} ]; then - _msg ECHO "_cfg_column_to_nf(): Column does not exist" - return 1 - else - # Finds what NF is associated with ${COLUMN} - local COUNT=0 - for column ${columnList[@]}; do - [[ "${COLUMN}" == "${column}" ]] && echo "${COUNT}" - local COUNT=$(( ${COUNT} + 1 )) - return 0 - done - fi -} - -_cfg_set_file() { - # Argument parser and sanity check - [[ $# != 1 ]] && {_msg ECHO "_cfg_set_file(): Expected 1 argument"; return 1} - - # Sets _CFG_PATH globally - _CFG_PATH="${1}" - _CFG_TMP_PATH="$(sed 's|\(.*\)\/|\1/.|' <<<"${CFG_PATH}")" -} - -_cfg_create() { - # Argument parser and sanity check - [[ ! -z ${1+x} ]] && {_msg ECHO "_cfg_create(): Expected argument"; return 1} - local colList=(${@}) - - # Creates config file - printf "%s\t" ${colList[@]} >> ${_CFG_PATH} -} - -_cfg_print() { - # Argument parser and sanity check - [[ $# != 2 ]] && {_msg ECHO "_cfg_print(): Expected 2 arguments"; return 1} - local COLUMN=${1} - local ROW=${2} - - # Prints row of ${_CFG_PATH} - awk 'BEGIN {FS="\t"; OFS="\t"}; {if (NR='${ROW}') {print $'$(_cfg_column_to_nf ${COLUMN})'}}' "${_CFG_PATH}" -} - -_cfg_change() { - # Argument parser and sanity check - [[ $# != 3 ]] && {_msg ECHO "_cfg_change(): Expected 3 arguments"; return 1} - local COLUMN=${1} - local ROW=${2} - local VALUE=${3} - [[ ! _if_is_integer ${ROW} ]] && {_msg ECHO "_cfg_change(): Expected integer; return 1"} - - # Writes new version of file - awk 'BEGIN {OFS="\t"}; {if (NR == '${ROW}') {$'$(_cfg_column_to_nf ${COLUMN})'='${VALUE}'} {print $0}}' "${_CFG_PATH}" > ${_CFG_TMP_PATH} && mv ${_CFG_TMP_PATH} ${_CFG_PATH} - -} - -_cfg_drop() { - # Argument parser and sanity check - [[ -z $# != 2 ]] && {_msg ECHO "_cfg_drop(): Expected 2 arguments"; return 1} - local SUBCMD=${1}; shift - [[ ! _if_array_contains ${SUBCMD} row column ]] && {_msg ECHO "_cfg_drop(): Expected 'row' or 'column' as subcommand"; return 1} - - # Dispatcher - _cfg_drop_${SUBCMD} ${1} -} - -_cfg_drop_row() { - # Argument parser and sanity check - local ROW=${1} - [[ ${ROW} -mt $(awk 'BEGIN {FS="\t"; OFS="\t"}; {print NR}' ${_CFG_PATH}) ]] && {_msg ECHO "_cfg_drop_row(): Row number higher than available"} - - # Writes new version of file - awk 'BEGIN {OFS="\t"}; {if (NR == '${ROW}') {$0="\b") {print $0}}' ${_CFG_PATH} > ${_CFG_TMP_PATH} && mv ${_CFG_TMP_PATH} ${_CFG_PATH} - -} - -_cfg_drop_column() { - local COLUMN=${1} - local NF=$(_cfg_column_to_nf "${COLUMN}") - - # Writes new version of file - awk 'BEGIN {OFS="\t"}; {$'${NF}'="\b"; print &0}' ${_CFG_PATH} > ${_CFG_TMP_PATH} && mv ${_CFG_TMP_PATH} ${_CFG_PATH} -} - -_cfg_insert() { - # Argument parser and sanity check - local valueList=(${@}) - local COLUMN_NO=$(awk 'BEGIN{OFS="\t"}; {if (NR == 1) {print NF}}' ${_CFG_PATH}) - [[ "${#valueList[@]}" =! "${COLUMN_NO}" ]] && {_msg ECHO "_cfg_insert(): Number of arguments must be equal to ${COLUMN_NO}"; return 1} - - # Write row into file - printf "%s\t" ${valueList[@]} >> ${_CFG_PATH} -} - -_cfg_query() { - # Argument parser and sanity check - local CONDITION=${1} - - awk 'BEGIN {FS="\t"; OFS="\t"}; {if ('${CONDITION}') {print NR}}' "{_CFG_PATH}" -} diff --git a/test/test-cfg.sh b/test/test-cfg.sh new file mode 100644 index 0000000..285104d --- /dev/null +++ b/test/test-cfg.sh @@ -0,0 +1,152 @@ +#!/bin/bash + +source ../lib/if.sh +source ../lib/ansi.sh +source ../lib/msg.sh +source ../lib/cfg.sh +TMP=/tmp +testcolList=(COL1 COL2 COL3 COL4 COL5) +# cfg test + +bail() { + cat ${TMP}/test.cfg + rm ${TMP}/test.cfg + exit 1 +} + +_test_cfg_set_file() { + _msg EXEC "Testing _cfg_set_file()" + _cfg_set_file ${TMP}/test.cfg + [[ "${_CFG_PATH}" != "${TMP}/test.cfg" ]] && { _msg FAIL "_test_cfg_set_file(): \${_CFG_PATH} is '${_CFG_PATH}' rather than the expected '${TMP}/test.cfg'"; } + [[ "${_CFG_TMP_PATH}" != "${TMP}/.test.cfg" ]] && { _msg FAIL "_test_cfg_set_file(): \${_CFG_TMP_PATH} is '${_CFG_TMP_PATH}' rather than the expected '${TMP}/.test.cfg"; } + _msg OK +} + +_test_cfg_create() { + _msg EXEC "Testing _cfg_create()" + local CMD="_cfg_create ${testcolList[@]}" + eval ${CMD} >${STDERR} 2>&1 || { _msg FAIL "_test_cfg_create(): Error in function execution"; } + + local FC_OUTPUT="$(cat ${TMP}/test.cfg)" + local EX_OUTPUT="$(printf '%s\t' ${testcolList[@]})" + [[ "${FC_OUTPUT}" != "${EX_OUTPUT}" ]] && { _msg FAIL "_test_cfg_create(): Output '${FC_OUTPUT}' expected to be '${EX_OUTPUT}'"; } + _msg OK +} + +_test_cfg_column_to_nf() { + _msg EXEC "Testing _cfg_column_to_nf()" + local argList=(all ${testcolList[@]}) + _cfg_column_to_nf ${argList[1]} >${STDERR} 2>&1 || { _msg FAIL "test_cfg_column_to_nf(): Error in function execution"; } + + for no in {0..5}; do + local FC_OUTPUT="$(_cfg_column_to_nf ${argList[${no}]})" + local EX_OUTPUT="${no}" + [[ ${FC_OUTPUT} -ne ${EX_OUTPUT} ]] && { _msg FAIL "_test_cfg_column_to_nf(): Output '${FC_OUTPUT}' expected to be '${EX_OUTPUT}'"; } + done + _msg OK +} + +_test_cfg_print() { + _msg EXEC "Testing _cfg_print()" + local argList=(all 1) + local CMD="_cfg_print ${argList[@]}" + eval ${CMD} >${STDERR} 2>&1 || { _msg FAIL "_test_cfg_print(): Error in function execution"; } + + local FC_OUTPUT="$(eval ${CMD})" + local EX_OUTPUT="$(printf '%s\t' ${testcolList[@]})" + [[ "${FC_OUTPUT}" != "${EX_OUTPUT}" ]] && { _msg FAIL "_test_cfg_print(): Output '${FC_OUTPUT}' expected to be '${EX_OUTPUT}'"; } + _msg OK +} + +_test_cfg_insert_row() { + _msg EXEC "Testing _cfg_insert_row()" + local argList=(EL1 EL2 EL3 EL4 EL5) + local CMD="_cfg_insert_row ${argList[@]}" + eval ${CMD} >${STDERR} 2>&1 || { _msg FAIL "_test_cfg_insert_row(): Error in function execution"; } + + local FC_OUTPUT="$(_cfg_print all 2)" + local EX_OUTPUT="$(printf '%s\t' ${argList[@]})" + [[ "${FC_OUTPUT}" != "${EX_OUTPUT}" ]] && { _msg FAIL "_test_cfg_insert_row(): Output '${FC_OUTPUT}' expected to be '${EX_OUTPUT}'"; } + + awk 'BEGIN {OFS="\t"}; {if (NR != 2) {print $0}}' ${_CFG_PATH} > ${_CFG_TMP_PATH} && mv ${_CFG_TMP_PATH} ${_CFG_PATH} + _msg OK +} + +_test_cfg_insert_column() { + _msg EXEC "Testing _cfg_insert_column()" + local argList=(COL6) + local CMD="_cfg_insert_column ${argList[@]}" + eval ${CMD} >${STDERR} 2>&1 || { _msg FAIL "_test_cfg_insert_column(): Error in function execution"; } + + local fcoutputList=($(_cfg_print all 1)) + local exoutputList=(${testcolList[@]} COL6) + + [[ "${fcoutputList[@]}" != "${exoutputList[@]}" ]] && { _msg FAIL "_test_cfg_insert_column(): Output '${fcoutputList[@]}' expected to be '${exoutputList[@]}'"; } + + awk 'BEGIN {OFS="\t"}; {$6=""; print $0}' ${_CFG_PATH} > ${_CFG_TMP_PATH} && mv ${_CFG_TMP_PATH} ${_CFG_PATH} + _msg OK +} + +_test_cfg_change() { + _msg EXEC "Testing _cfg_change()" + _cfg_insert_row ${testcolList[@]} + local argList=(COL1 2 EL1_CH) + local CMD="_cfg_change ${argList[@]}" + eval ${CMD} >${STDERR} 2>&1 || { _msg FAIL "_test_cfg_change(): Error in function execution"; } + local FC_OUTPUT="$(_cfg_print COL1 2)" + local EX_OUTPUT="EL1_CH" + [[ "${FC_OUTPUT}" != "${EX_OUTPUT}" ]] && { _msg FAIL "_test_cfg_change(): Output '${FC_OUTPUT}' expected to be '${EX_OUTPUT}'"; } + _cfg_drop_row 2 + _msg OK +} + +_test_cfg_drop_row() { + _msg EXEC "Testing _cfg_drop_row()" + _cfg_insert_row ${testcolList[@]} + local argList=(2) + local CMD="_cfg_drop_row ${argList[@]}" + eval ${CMD} >${STDERR} 2>&1 || { _msg FAIL "_test_cfg_drop_row(): Error in function execution"; } + + FC_OUTPUT="$(awk '{print NR}' ${TMP}/test.cfg | wc -l)" + EX_OUTPUT=1 + [[ ${FC_OUTPUT} != ${EX_OUTPUT} ]] && { _msg FAIL "_test_cfg_drop_row(): Output '${FC_OUTPUT}' expected to be ${EX_OUTPUT}'"; } + _msg OK +} + +_test_cfg_drop_column() { + _msg EXEC "Testing _cfg_drop_column()" + _cfg_insert_column "COL6" + local argList="COL6" + local CMD="_cfg_drop_column ${argList[@]}" + eval ${CMD} >${STDERR} 2>&1 || { _msg FAIL "_test_cfg_drop_column(): Error in function execution"; } + + FC_OUTPUT="$(printf '%s ' $(awk 'BEGIN{OFS="\t"}; {if (NR == 1) {print $0}}' ${_CFG_PATH}))" + EX_OUTPUT="$(printf '%s ' ${testcolList[@]})" + [[ "${FC_OUTPUT}" != "${EX_OUTPUT}" ]] && { _msg FAIL "_test_cfg_drop_column(): Output '${FC_OUTPUT}' expected to be '${EX_OUTPUT}'"; } + _msg OK +} + +_test_cfg_query() { + _msg EXEC "Testing _cfg_query" + _cfg_insert_row "EL1 EL2 EL3 EL4 EL5" + _cfg_insert_row "EL6 EL7 EL8 EL9 EL10" + local ARG="\$1==\"EL6\"" + local CMD="_cfg_query '${ARG}'" + eval ${CMD} >${STDERR} 2>&1 || { _msg FAIL "_test_cfg_query(): Error in function execution"; } + + FC_OUTPUT=$(eval ${CMD}) + EX_OUTPUT=3 + [[ "${FC_OUTPUT}" != "${EX_OUTPUT}" ]] && { _msg FAIL "_test_cfg_query(): Output '${FC_OUTPUT}' expected to be '${EX_OUTPUT}'"; } + +awk 'BEGIN {OFS="\t"}; {if (NR == 1) {print $0}}' ${_CFG_PATH} > ${_CFG_TMP_PATH} && mv ${_CFG_TMP_PATH} ${_CFG_PATH} + _msg OK +} + +testList=(cfg_set_file cfg_create cfg_column_to_nf cfg_print cfg_query cfg_insert_row cfg_insert_column cfg_drop_row cfg_drop_column cfg_change) + +_msg ECHO "cfg function test suite started" +for test in ${testList[@]}; do + eval _test_${test} +done +rm ${TMP}/test.cfg +_msg ECHO "cfg function test suite ended"