Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/workflows/zsh-n.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ on:
- "tests/fixtures/plugin-standard-callbacks/**"
- "tests/self-update-reload.zsh"
- "tests/snippet-directory-mirror.zsh"
- "tests/source-hygiene.zsh"
- "tests/subst-nesting.zsh"
- "tests/version-reporting.zsh"
pull_request:
Expand All @@ -47,6 +48,7 @@ on:
- "tests/fixtures/plugin-standard-callbacks/**"
- "tests/self-update-reload.zsh"
- "tests/snippet-directory-mirror.zsh"
- "tests/source-hygiene.zsh"
- "tests/subst-nesting.zsh"
- "tests/version-reporting.zsh"
workflow_dispatch: {}
Expand Down Expand Up @@ -259,6 +261,17 @@ jobs:
- name: Test message formatting
run: zsh -f tests/message-formatting.zsh

source-hygiene:
name: Source Hygiene
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install Zsh
run: sudo apt update && sudo apt-get install -yq zsh
- name: Test source hygiene
run: zsh -f tests/source-hygiene.zsh

subst-nesting:
name: Subst Nesting
runs-on: ubuntu-latest
Expand Down
10 changes: 1 addition & 9 deletions lib/zsh/autoload.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -299,14 +299,6 @@ ZI[EXTENDED_GLOB]=""
fi
return 0
} # ]]]
# FUNCTION: .zi-at-eval [[[
.zi-at-eval() {
local atclone="$2" atpull="$1"
integer retval
@zi-substitute atclone atpull
[[ $atpull = "%atclone" ]] && { eval "$atclone"; retval=$?; } || { eval "$atpull"; retval=$?; }
return $retval
} # ]]]

#
# Format functions
Expand Down Expand Up @@ -1917,7 +1909,7 @@ ZI[EXTENDED_GLOB]=""
+zi-message "{mmdsh}{happy} Zi{rst} » {info3}update took {num}$SECONDS{info3} seconds{rst}{…}"
return "$retval"
} # ]]]
# FUNCTION: .zi-update-in-parallel [[[
# FUNCTION: .zi-update-all-parallel [[[
.zi-update-all-parallel() {
builtin emulate -LR zsh ${=${options[xtrace]:#off}:+-o xtrace}
builtin setopt extended_glob warn_create_global typeset_silent no_short_loops no_monitor no_notify
Expand Down
80 changes: 80 additions & 0 deletions tests/source-hygiene.zsh
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#!/usr/bin/env zsh
# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
# vim: ft=zsh sw=2 ts=2 et
#
# Structural checks over the shipped sources. Neither can be caught by a
# behavioural test: a duplicate definition whose copies agree behaves correctly
# until they drift, and a wrong header misleads only the next reader. Both are
# cheap to assert and expensive to rediscover.

builtin emulate -R zsh
setopt extended_glob pipe_fail

fail() {
builtin print -u2 -r -- "not ok - $1"
exit 1
}

typeset project_root="${ZI_TEST_CHECKOUT:-${0:A:h:h}}"
builtin cd -q "$project_root" || fail "enter the project root"

typeset -a sources
sources=( zi.zsh lib/zsh/*.zsh(N) )
(( ${#sources} )) || fail "locate the shipped sources"

# A top-level definition: a name in column one followed by `()'. Indented
# definitions are anonymous or nested helpers and are deliberately not counted.
typeset -r name_class='[A-Za-z_@.:+][A-Za-z0-9_@.:+-]#'

typeset -A seen_in
typeset -a duplicates mismatches
typeset src name header defined
typeset -a lines
typeset -i i j

for src in "${sources[@]}"; do
lines=( "${(@f)$(<$src)}" )

for (( i = 1; i <= ${#lines}; i++ )); do
# Every function is defined exactly once across the shipped sources. Both
# libraries are sourced conditionally and in different orders depending on
# the command, so a second definition does not reliably override the first:
# which one wins varies by code path. `.zi-at-eval' was defined in both
# lib/zsh/autoload.zsh and lib/zsh/install.zsh with matching behaviour and
# different wording, exactly the shape that becomes a heisenbug once the
# two drift.
if [[ ${lines[i]} == (#b)(${~name_class})[[:space:]]#'()'* ]]; then
name="${match[1]}"
if [[ -n ${seen_in[$name]} ]]; then
duplicates+=( "${name}: ${seen_in[$name]} and ${src}:${i}" )
else
seen_in[$name]="${src}:${i}"
fi
continue
fi

# Every `# FUNCTION: <name>' header names the function it precedes.
if [[ ${lines[i]} == (#b)'#'[[:space:]]#'FUNCTION:'[[:space:]]#(${~name_class})* ]]; then
header="${match[1]%.}"
for (( j = i + 1; j <= i + 6 && j <= ${#lines}; j++ )); do
[[ ${lines[j]} == (#b)(${~name_class})[[:space:]]#'()'* ]] || continue
defined="${match[1]}"
[[ $header == $defined ]] ||
mismatches+=( "${src}:${i} header '${header}' precedes '${defined}'" )
break
done
fi
done
done

if (( ${#duplicates} )); then
builtin print -u2 -rl -- "functions defined more than once:" "${duplicates[@]}"
fail "a function is defined in more than one shipped source"
fi

if (( ${#mismatches} )); then
builtin print -u2 -rl -- "FUNCTION headers naming a different function:" "${mismatches[@]}"
fail "a FUNCTION header does not match the function it precedes"
fi

builtin print -r -- "ok - every function is defined once and every FUNCTION header matches (${#seen_in} functions)"
2 changes: 1 addition & 1 deletion zi.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -2379,7 +2379,7 @@ builtin setopt no_aliases
"the list of the {cmd}subcommands$bcol.{rst}"
}
} # ]]]
# FUNCTION: +zi-parse-opts. [[[
# FUNCTION: .zi-parse-opts. [[[
.zi-parse-opts() {
builtin emulate -LR zsh ${=${options[xtrace]:#off}:+-o xtrace}
builtin setopt extended_glob typeset_silent no_short_loops rc_quotes no_auto_pushd
Expand Down
Loading