[Tests] use a better JSON parsing implementation

This commit is contained in:
Jordan Harband 2024-06-10 11:33:12 -07:00
parent aa427ad396
commit e597bb208e
No known key found for this signature in database
GPG Key ID: 9F6A681E35EF8B56
2 changed files with 141 additions and 99 deletions

View File

@ -102,104 +102,146 @@ watch() {
return $EXIT_CODE return $EXIT_CODE
} }
parse_json() {
local json
json="$1"
local key
key=""
local value
value=""
local output
output=""
local in_key
in_key=0
local in_value
in_value=0
local in_string
in_string=0
local escaped
escaped=0
local buffer
buffer=""
local char
local len
len=${#json}
local arr_index
arr_index=0
local in_array
in_array=0
for ((i = 0; i < len; i++)); do # JSON parsing from https://gist.github.com/assaf/ee377a186371e2e269a7
char="${json:i:1}" nvm_json_throw() {
nvm_err "$*"
exit 1
}
if [ "$in_string" -eq 1 ]; then nvm_json_awk_egrep() {
if [ "$escaped" -eq 1 ]; then local pattern_string
buffer="$buffer$char" pattern_string="${1}"
escaped=0
elif [ "$char" = "\\" ]; then
escaped=1
elif [ "$char" = "\"" ]; then
in_string=0
if [ "$in_key" -eq 1 ]; then
key="$buffer"
buffer=""
in_key=0
elif [ "$in_value" -eq 1 ]; then
value="$buffer"
buffer=""
output="$output$key=\"$value\"\n"
in_value=0
elif [ "$in_array" -eq 1 ]; then
value="$buffer"
buffer=""
output="$output$arr_index=\"$value\"\n"
arr_index=$((arr_index + 1))
fi
else
buffer="$buffer$char"
fi
continue
fi
case "$char" in awk '{
"\"") while ($0) {
in_string=1 start=match($0, pattern);
buffer="" token=substr($0, start, RLENGTH);
if [ "$in_value" -eq 0 ] && [ "$in_array" -eq 0 ]; then print token;
in_key=1 $0=substr($0, start+RLENGTH);
fi }
;; }' "pattern=${pattern_string}"
":") }
in_value=1
;; nvm_json_tokenize() {
",") local GREP
if [ "$in_value" -eq 1 ]; then GREP='grep -Eao'
in_value=0
fi local ESCAPE
;; local CHAR
"[")
in_array=1 # if echo "test string" | grep -Eo "test" > /dev/null 2>&1; then
;; # ESCAPE='(\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})'
"]") # CHAR='[^[:cntrl:]"\\]'
in_array=0 # else
;; GREP=nvm_json_awk_egrep
"{" | "}") ESCAPE='(\\\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})'
;; CHAR='[^[:cntrl:]"\\\\]'
# fi
local STRING
STRING="\"${CHAR}*(${ESCAPE}${CHAR}*)*\""
local NUMBER
NUMBER='-?(0|[1-9][0-9]*)([.][0-9]*)?([eE][+-]?[0-9]*)?'
local KEYWORD
KEYWORD='null|false|true'
local SPACE
SPACE='[[:space:]]+'
$GREP "${STRING}|${NUMBER}|${KEYWORD}|${SPACE}|." | TERM=dumb grep -Ev "^${SPACE}$"
}
_json_parse_array() {
local index=0
local ary=''
read -r token
case "$token" in
']') ;;
*) *)
if [ "$in_value" -eq 1 ] && [ "$char" != " " ] && [ "$char" != "\n" ] && [ "$char" != "\t" ]; then while :; do
buffer="$buffer$char" _json_parse_value "${1}" "${index}"
fi index=$((index+1))
ary="${ary}${value}"
read -r token
case "${token}" in
']') break ;;
',') ary="${ary}," ;;
*) nvm_json_throw "EXPECTED , or ] GOT ${token:-EOF}" ;;
esac
read -r token
done
;; ;;
esac esac
done :
printf "%b" "$output"
} }
extract_value() { _json_parse_object() {
local key local key
key="$1" local obj=''
local parsed read -r token
parsed="$2" case "$token" in
echo "$parsed" | grep "^$key=" | cut -d'=' -f2 | tr -d '"' '}') ;;
*)
while :; do
case "${token}" in
'"'*'"') key="${token}" ;;
*) nvm_json_throw "EXPECTED string GOT ${token:-EOF}" ;;
esac
read -r token
case "${token}" in
':') ;;
*) nvm_json_throw "EXPECTED : GOT ${token:-EOF}" ;;
esac
read -r token
_json_parse_value "${1}" "${key}"
obj="${obj}${key}:${value}"
read -r token
case "${token}" in
'}') break ;;
',') obj="${obj}," ;;
*) nvm_json_throw "EXPECTED , or } GOT ${token:-EOF}" ;;
esac
read -r token
done
;;
esac
:
}
_json_parse_value() {
local jpath="${1:+$1,}$2"
local isleaf=0
local isempty=0
local print=0
case "$token" in
'{') _json_parse_object "${jpath}" ;;
'[') _json_parse_array "${jpath}" ;;
# At this point, the only valid single-character tokens are digits.
''|[!0-9]) nvm_json_throw "EXPECTED value GOT >${token:-EOF}<" ;;
*)
value=$token
isleaf=1
[ "${value}" = '""' ] && isempty=1
;;
esac
[ "${value}" = '' ] && return
[ "${isleaf}" -eq 1 ] && [ $isempty -eq 0 ] && print=1
[ "${print}" -eq 1 ] && printf "[%s]\t%s\n" "${jpath}" "${value}"
:
}
_json_parse() {
read -r token
_json_parse_value
read -r token
case "${token}" in
'') ;;
*) nvm_json_throw "EXPECTED EOF GOT >${token}<" ;;
esac
}
nvm_json_extract() {
nvm_json_tokenize | _json_parse | grep -e "${1}" | awk '{print $2 $3}'
} }

View File

@ -14,7 +14,7 @@ for f in ../../../test/fixtures/nvmrc/test/fixtures/valid/*; do
STDOUT="$(nvm_process_nvmrc $f/.nvmrc 2>/dev/null)" STDOUT="$(nvm_process_nvmrc $f/.nvmrc 2>/dev/null)"
EXIT_CODE="$(nvm_process_nvmrc $f/.nvmrc >/dev/null 2>/dev/null; echo $?)" EXIT_CODE="$(nvm_process_nvmrc $f/.nvmrc >/dev/null 2>/dev/null; echo $?)"
EXPECTED="$(extract_value node "$(parse_json "$(cat "$f/expected.json")")")" EXPECTED="$(nvm_json_extract node < "${f}/expected.json" | tr -d '"')"
[ "${EXIT_CODE}" = "0" ] || die "$(basename "${f}"): expected exit code of 0 but got ${EXIT_CODE}" [ "${EXIT_CODE}" = "0" ] || die "$(basename "${f}"): expected exit code of 0 but got ${EXIT_CODE}"
@ -26,7 +26,7 @@ for f in ../../../test/fixtures/nvmrc/test/fixtures/invalid/*; do
STDERR="$(nvm_process_nvmrc $f/.nvmrc 2>&1 >/dev/null | awk '{if(NR > 8) print $0}' | strip_colors)" STDERR="$(nvm_process_nvmrc $f/.nvmrc 2>&1 >/dev/null | awk '{if(NR > 8) print $0}' | strip_colors)"
EXIT_CODE="$(nvm_process_nvmrc $f/.nvmrc >/dev/null 2>/dev/null; echo $?)" EXIT_CODE="$(nvm_process_nvmrc $f/.nvmrc >/dev/null 2>/dev/null; echo $?)"
EXPECTED="$(parse_json "$(cat "$f/expected.json")" | sed 's/^[0-9]*="//;s/"$//')" EXPECTED="$(nvm_json_extract < "${f}/expected.json" | tr -d '"')"
[ "${EXIT_CODE}" != "0" ] || die "$(basename "${f}"): expected exit code of 'not 0' but got ${EXIT_CODE}" [ "${EXIT_CODE}" != "0" ] || die "$(basename "${f}"): expected exit code of 'not 0' but got ${EXIT_CODE}"