forked from heavy-duty/ceremony
88 lines
3.8 KiB
Bash
88 lines
3.8 KiB
Bash
|
|
#!/usr/bin/env bash
|
||
|
|
# Contract tests for lib/closes_references.sh (issue #188, term 3).
|
||
|
|
# set -u, not -e: failing commands are behavior for the harness to inspect.
|
||
|
|
set -u
|
||
|
|
|
||
|
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||
|
|
# shellcheck source=test/harness.sh
|
||
|
|
. "$ROOT/test/harness.sh"
|
||
|
|
# issue_references (the LOCAL/CROSS classifier) lives here; closes_references
|
||
|
|
# calls it, exactly as refs_references does.
|
||
|
|
# shellcheck source=actions/issueflow-reconcile/issueflow-reconcile.sh
|
||
|
|
. "$ROOT/actions/issueflow-reconcile/issueflow-reconcile.sh"
|
||
|
|
# shellcheck source=lib/closes_references.sh
|
||
|
|
. "$ROOT/lib/closes_references.sh"
|
||
|
|
|
||
|
|
# closes <want-newline-separated> <body> — the parse of <body> is exactly
|
||
|
|
# <want>. Exact, not substring: "12" is contained in "123".
|
||
|
|
closes() {
|
||
|
|
local want="$1" body="$2" got
|
||
|
|
got="$(printf '%s' "$body" | closes_references)"
|
||
|
|
[ "$got" = "$want" ]
|
||
|
|
}
|
||
|
|
|
||
|
|
# --- the three verbs, the three tenses ----------------------------------
|
||
|
|
# GitHub's documented keyword set. All of them, because a body that says
|
||
|
|
# "Fixed #4" and goes unclosed is a silent failure of the post-merge
|
||
|
|
# transition, not a loud one.
|
||
|
|
|
||
|
|
check "closes" 0 "" closes 1 'Closes #1'
|
||
|
|
check "close" 0 "" closes 1 'Close #1'
|
||
|
|
check "closed" 0 "" closes 1 'Closed #1'
|
||
|
|
check "fixes" 0 "" closes 2 'Fixes #2'
|
||
|
|
check "fix" 0 "" closes 2 'Fix #2'
|
||
|
|
check "fixed" 0 "" closes 2 'Fixed #2'
|
||
|
|
check "resolves" 0 "" closes 3 'Resolves #3'
|
||
|
|
check "resolve" 0 "" closes 3 'Resolve #3'
|
||
|
|
check "resolved" 0 "" closes 3 'Resolved #3'
|
||
|
|
check "case-insensitive" 0 "" closes 4 'CLOSES #4'
|
||
|
|
check "lowercase" 0 "" closes 4 'closes #4'
|
||
|
|
check "colon form" 0 "" closes 5 'Closes: #5'
|
||
|
|
|
||
|
|
# --- Refs is NOT a closing link -----------------------------------------
|
||
|
|
# The relation this file must not swallow. refs_references owns Refs, and
|
||
|
|
# conflating them makes every referenced issue look closeable — the
|
||
|
|
# post-merge transition #151 was reopened by hand over exactly that
|
||
|
|
# distinction.
|
||
|
|
|
||
|
|
check "Refs is not a close" 0 "" closes '' 'Refs #7'
|
||
|
|
check "Refs and Closes in one body keeps only the close" 0 "" \
|
||
|
|
closes 8 $'Refs #7\nCloses #8'
|
||
|
|
|
||
|
|
# --- cross-repo references stay out (#61) -------------------------------
|
||
|
|
# rig#112 must never be read as local #112. The classifier is shared with
|
||
|
|
# refs_references precisely so this rule has one implementation.
|
||
|
|
|
||
|
|
check "qualified reference is not local" 0 "" closes '' 'Closes rig#112'
|
||
|
|
check "owner-qualified reference is not local" 0 "" \
|
||
|
|
closes '' 'Closes heavy-duty/rig#112'
|
||
|
|
check "a local and a cross reference keep only the local" 0 "" \
|
||
|
|
closes 9 $'Closes rig#112\nCloses #9'
|
||
|
|
|
||
|
|
# --- every occurrence contributes ---------------------------------------
|
||
|
|
# Binding to the first occurrence is the defect #184 fixed in
|
||
|
|
# blocked_reference_records; this parser must not reintroduce it.
|
||
|
|
|
||
|
|
check "two closes on one line" 0 "" closes $'1\n2' 'Closes #1. Closes #2.'
|
||
|
|
check "two closes on two lines" 0 "" closes $'1\n2' $'Closes #1\nCloses #2'
|
||
|
|
check "sorted and deduplicated" 0 "" closes $'2\n10' $'Closes #10\nCloses #2\nCloses #10'
|
||
|
|
|
||
|
|
# --- prose must not be swallowed ----------------------------------------
|
||
|
|
|
||
|
|
check "trailing prose is not part of the reference" 0 "" \
|
||
|
|
closes 12 'Closes #12, and adds the guard'
|
||
|
|
check "a sentence terminator ends the reference" 0 "" closes 13 'Closes #13.'
|
||
|
|
check "no reference means no output" 0 "" closes '' 'Closes the door behind it'
|
||
|
|
check "a bare issue mention is not a close" 0 "" closes '' 'See #14 for context'
|
||
|
|
# "unclosed" contains "close" — a naive word match would fire on it.
|
||
|
|
check "a word merely containing a verb does not fire" 0 "" \
|
||
|
|
closes '' 'This left #15 unclosed'
|
||
|
|
|
||
|
|
# --- the shapes a real PR body carries ----------------------------------
|
||
|
|
|
||
|
|
check "the template's leading declaration" 0 "" \
|
||
|
|
closes 188 $'Closes #188\n\n## Acceptance criteria\n\n- [ ] a thing'
|
||
|
|
check "an empty body yields nothing" 0 "" closes '' ''
|
||
|
|
|
||
|
|
summary
|