From 304a22ad5963e79d67e75a8e660a21ddca0ba7fd Mon Sep 17 00:00:00 2001 From: Jake Lodwick <25925+jakelodwick@users.noreply.github.com> Date: Wed, 18 Feb 2026 14:29:52 -0700 Subject: [PATCH] [Refactor] `nvm_alias`: use [[:space:]] instead of literal tab [Tests] `nvm_alias`: add edge-case tests for hostile file content --- nvm.sh | 5 ++--- ...vm_alias handles alias with spaces in name | 17 ++++++++++++++ ...vm_alias handles binary data after version | 20 +++++++++++++++++ .../Aliases/nvm_alias handles carriage return | 22 +++++++++++++++++++ .../Aliases/nvm_alias handles embedded NUL | 22 +++++++++++++++++++ ...m_alias handles form feed and vertical tab | 22 +++++++++++++++++++ .../nvm_alias handles no trailing newline | 16 ++++++++++++++ .../Aliases/nvm_alias handles very long line | 17 ++++++++++++++ 8 files changed, 138 insertions(+), 3 deletions(-) create mode 100755 test/fast/Aliases/nvm_alias handles alias with spaces in name create mode 100755 test/fast/Aliases/nvm_alias handles binary data after version create mode 100755 test/fast/Aliases/nvm_alias handles carriage return create mode 100755 test/fast/Aliases/nvm_alias handles embedded NUL create mode 100755 test/fast/Aliases/nvm_alias handles form feed and vertical tab create mode 100755 test/fast/Aliases/nvm_alias handles no trailing newline create mode 100755 test/fast/Aliases/nvm_alias handles very long line diff --git a/nvm.sh b/nvm.sh index 37e39668..f6f5cca0 100755 --- a/nvm.sh +++ b/nvm.sh @@ -1374,13 +1374,12 @@ nvm_alias() { while IFS= read -r NVM_ALIAS_LINE || [ -n "${NVM_ALIAS_LINE}" ]; do NVM_ALIAS_LINE="${NVM_ALIAS_LINE%%#*}" case "${NVM_ALIAS_LINE}" in - *[!\ \ ]*) ;; + *[![:space:]]*) ;; *) continue ;; esac while : ; do case "${NVM_ALIAS_LINE}" in - *' ') NVM_ALIAS_LINE="${NVM_ALIAS_LINE% }" ;; - *' ') NVM_ALIAS_LINE="${NVM_ALIAS_LINE% }" ;; + *[[:space:]]) NVM_ALIAS_LINE="${NVM_ALIAS_LINE%[[:space:]]}" ;; *) break ;; esac done diff --git a/test/fast/Aliases/nvm_alias handles alias with spaces in name b/test/fast/Aliases/nvm_alias handles alias with spaces in name new file mode 100755 index 00000000..645461a8 --- /dev/null +++ b/test/fast/Aliases/nvm_alias handles alias with spaces in name @@ -0,0 +1,17 @@ +#!/bin/sh + +die () { echo "$@" ; exit 1; } + +export NVM_DIR="$(cd ../../.. && pwd)" + +: nvm.sh +\. "${NVM_DIR}/nvm.sh" + +# Create an alias file whose name contains spaces +mkdir -p ../../../alias +printf 'v22.1.0\n' > "../../../alias/test edge spaces" +ACTUAL="$(nvm_alias "test edge spaces")" +EXPECTED='v22.1.0' +[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<" + +rm -f "../../../alias/test edge spaces" diff --git a/test/fast/Aliases/nvm_alias handles binary data after version b/test/fast/Aliases/nvm_alias handles binary data after version new file mode 100755 index 00000000..7c9de414 --- /dev/null +++ b/test/fast/Aliases/nvm_alias handles binary data after version @@ -0,0 +1,20 @@ +#!/bin/sh + +die () { echo "$@" ; exit 1; } + +export NVM_DIR="$(cd ../../.. && pwd)" + +: nvm.sh +\. "${NVM_DIR}/nvm.sh" + +# Create an alias file where the first line has a valid version +# followed by a second line of binary-like data +printf 'v22.1.0\n' > ../../../alias/test-edge-binary +printf '\001\002\003\377\n' >> ../../../alias/test-edge-binary +ACTUAL="$(nvm_alias test-edge-binary)" +# nvm_alias emits every non-blank, non-comment line — first line should be the version +FIRST_LINE="$(nvm_echo "${ACTUAL}" | command head -n 1)" +EXPECTED='v22.1.0' +[ "${FIRST_LINE}" = "${EXPECTED}" ] || die "expected first line >${EXPECTED}<, got >${FIRST_LINE}<" + +rm -f ../../../alias/test-edge-binary diff --git a/test/fast/Aliases/nvm_alias handles carriage return b/test/fast/Aliases/nvm_alias handles carriage return new file mode 100755 index 00000000..ba44f1c8 --- /dev/null +++ b/test/fast/Aliases/nvm_alias handles carriage return @@ -0,0 +1,22 @@ +#!/bin/sh + +die () { echo "$@" ; exit 1; } + +export NVM_DIR="$(cd ../../.. && pwd)" + +: nvm.sh +\. "${NVM_DIR}/nvm.sh" + +# Create an alias file with Windows-style line endings (CRLF) +printf 'v22.1.0\r\n' > ../../../alias/test-edge-cr +ACTUAL="$(nvm_alias test-edge-cr)" +EXPECTED='v22.1.0' +[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<" + +# Create an alias file with bare carriage return (no newline) +printf 'v22.2.0\r' > ../../../alias/test-edge-cr-bare +ACTUAL="$(nvm_alias test-edge-cr-bare)" +EXPECTED='v22.2.0' +[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for bare CR, got >${ACTUAL}<" + +rm -f ../../../alias/test-edge-cr ../../../alias/test-edge-cr-bare diff --git a/test/fast/Aliases/nvm_alias handles embedded NUL b/test/fast/Aliases/nvm_alias handles embedded NUL new file mode 100755 index 00000000..28b3dbb6 --- /dev/null +++ b/test/fast/Aliases/nvm_alias handles embedded NUL @@ -0,0 +1,22 @@ +#!/bin/sh + +die () { echo "$@" ; exit 1; } + +export NVM_DIR="$(cd ../../.. && pwd)" + +: nvm.sh +\. "${NVM_DIR}/nvm.sh" + +# Create an alias file with an embedded NUL byte after the version. +# NUL handling varies by shell: some stop at NUL, others read through it. +# The function must not crash, and must emit output starting with the version. +printf 'v22.1.0\000garbage\n' > ../../../alias/test-edge-nul +ACTUAL="$(nvm_alias test-edge-nul)" +EXIT_CODE=$? +[ "${EXIT_CODE}" = '0' ] || die "expected exit code 0, got ${EXIT_CODE}" +case "${ACTUAL}" in + v22.1.0*) ;; # OK — starts with the version regardless of NUL handling + *) die "expected output starting with >v22.1.0<, got >${ACTUAL}<" ;; +esac + +rm -f ../../../alias/test-edge-nul diff --git a/test/fast/Aliases/nvm_alias handles form feed and vertical tab b/test/fast/Aliases/nvm_alias handles form feed and vertical tab new file mode 100755 index 00000000..c2612418 --- /dev/null +++ b/test/fast/Aliases/nvm_alias handles form feed and vertical tab @@ -0,0 +1,22 @@ +#!/bin/sh + +die () { echo "$@" ; exit 1; } + +export NVM_DIR="$(cd ../../.. && pwd)" + +: nvm.sh +\. "${NVM_DIR}/nvm.sh" + +# Create an alias file with trailing form feed +printf 'v22.1.0\f\n' > ../../../alias/test-edge-ff +ACTUAL="$(nvm_alias test-edge-ff)" +EXPECTED='v22.1.0' +[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for form feed, got >${ACTUAL}<" + +# Create an alias file with trailing vertical tab +printf 'v22.2.0\v\n' > ../../../alias/test-edge-vt +ACTUAL="$(nvm_alias test-edge-vt)" +EXPECTED='v22.2.0' +[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for vertical tab, got >${ACTUAL}<" + +rm -f ../../../alias/test-edge-ff ../../../alias/test-edge-vt diff --git a/test/fast/Aliases/nvm_alias handles no trailing newline b/test/fast/Aliases/nvm_alias handles no trailing newline new file mode 100755 index 00000000..c87a22ae --- /dev/null +++ b/test/fast/Aliases/nvm_alias handles no trailing newline @@ -0,0 +1,16 @@ +#!/bin/sh + +die () { echo "$@" ; exit 1; } + +export NVM_DIR="$(cd ../../.. && pwd)" + +: nvm.sh +\. "${NVM_DIR}/nvm.sh" + +# Create an alias file with no trailing newline +printf 'v22.1.0' > ../../../alias/test-edge-no-newline +ACTUAL="$(nvm_alias test-edge-no-newline)" +EXPECTED='v22.1.0' +[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<" + +rm -f ../../../alias/test-edge-no-newline diff --git a/test/fast/Aliases/nvm_alias handles very long line b/test/fast/Aliases/nvm_alias handles very long line new file mode 100755 index 00000000..face2e51 --- /dev/null +++ b/test/fast/Aliases/nvm_alias handles very long line @@ -0,0 +1,17 @@ +#!/bin/sh + +die () { echo "$@" ; exit 1; } + +export NVM_DIR="$(cd ../../.. && pwd)" + +: nvm.sh +\. "${NVM_DIR}/nvm.sh" + +# Create an alias file with a very long line (version followed by a long comment) +LONG_COMMENT="$(printf '%0*d' 10000 0 | command tr '0' 'x')" +printf 'v22.1.0 #%s\n' "${LONG_COMMENT}" > ../../../alias/test-edge-long +ACTUAL="$(nvm_alias test-edge-long)" +EXPECTED='v22.1.0' +[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<" + +rm -f ../../../alias/test-edge-long