#!/bin/sh
# Unit tests for ci/publish/release-notes.sh — the extractor whose output becomes a PUBLISHED
# release body. Drives the real script over fixture changelogs; every case asserts a failure mode
# that actually reached publication or would have.
# [unit->REQ-RELEASE-NOTES-FROM-CHANGELOG]
set -u
ROOT=$(CDPATH= cd "$(dirname "$0")/.." && pwd)
cd "$ROOT" || exit 2
rc=0
ok()   { printf 'ok   %s\n' "$1"; }
fail() { printf 'FAIL: %s\n' "$1"; rc=1; }

TMP="${TMPDIR:-/tmp}/sptc-release-notes-$$"
mkdir -p "$TMP" || exit 2
FIX="$TMP/CHANGELOG.md"
cat > "$FIX" <<'EOF'
# Changelog

Preamble that belongs to no release.

## [0.28.0] - 2026-08-21

> Requires spt-core **v0.27.0 or newer**.

### Fixed
- The newest thing.

## [0.27.0] - 2026-08-21

### Fixed
- The older thing.

## [0.26.2] - 2026-08-05

### Fixed
- The oldest thing.
EOF

out=$(sh ci/publish/release-notes.sh 0.28.0 --changelog "$FIX" 2>/dev/null)

# 1. The section's own header is NOT part of the body (the runbook's stated shape).
case "$out" in
  *"## [0.28.0]"*) fail "extraction leaked the section header into the body" ;;
  *) ok "section header stripped" ;;
esac

# 2. It carries THIS version's content...
case "$out" in
  *"The newest thing."*) ok "carries the requested version's content" ;;
  *) fail "requested version's content missing: $out" ;;
esac

# 3. ...and NOTHING from the neighbouring sections. This is the defect that shipped: a body that
#    belongs to some other release reads perfectly well and is wrong.
case "$out" in
  *"The older thing."*|*"The oldest thing."*|*"Preamble"*)
    fail "extraction bled into a neighbouring section: $out" ;;
  *) ok "stops at the next release header" ;;
esac

# 4. A middle section is bounded on BOTH sides (not just 'everything after the header').
mid=$(sh ci/publish/release-notes.sh 0.27.0 --changelog "$FIX" 2>/dev/null)
case "$mid" in
  *"The older thing."*) case "$mid" in
      *"The newest thing."*|*"The oldest thing."*) fail "middle section not bounded: $mid" ;;
      *) ok "middle section bounded on both sides" ;;
    esac ;;
  *) fail "middle section not extracted: $mid" ;;
esac

# 5. A leading `v` is accepted (release tags carry it, changelog headers do not).
tagform=$(sh ci/publish/release-notes.sh v0.28.0 --changelog "$FIX" 2>/dev/null)
[ "$tagform" = "$out" ] && ok "tag form (vX.Y.Z) resolves the same section" \
                        || fail "tag form differs from bare version"

# 6. A version with no section FAILS LOUDLY and prints nothing — never an empty body that would
#    publish as a blank release.
if miss=$(sh ci/publish/release-notes.sh 9.9.9 --changelog "$FIX" 2>/dev/null); then
  fail "missing version exited 0 (would publish an empty body)"
else
  [ -z "$miss" ] && ok "missing version fails loudly with no stdout" \
                 || fail "missing version printed a body: $miss"
fi

# 7. A section that exists but is EMPTY is also refused (the changelog step was skipped).
cat > "$TMP/EMPTY.md" <<'EOF'
# Changelog

## [0.29.0] - 2026-08-22

## [0.28.0] - 2026-08-21

### Fixed
- Something.
EOF
if sh ci/publish/release-notes.sh 0.29.0 --changelog "$TMP/EMPTY.md" >/dev/null 2>&1; then
  fail "an empty section was accepted as a release body"
else
  ok "empty section refused"
fi

# 8. A missing changelog file is a loud usage failure, not a silent empty body.
if sh ci/publish/release-notes.sh 0.28.0 --changelog "$TMP/nope.md" >/dev/null 2>&1; then
  fail "missing changelog accepted"
else
  ok "missing changelog refused"
fi

# 9. The REAL changelog resolves the CURRENT manifest version — the release about to be cut always
#    has notes. (Guards the 'forgot the changelog section' path on the actual files we ship.)
ver=$(grep -m1 '^version = ' adapter/claude-spt.toml | sed 's/.*"\(.*\)".*/\1/')
if [ -n "$ver" ]; then
  if sh ci/publish/release-notes.sh "$ver" >/dev/null 2>&1; then
    ok "real CHANGELOG has a section for the manifest version ($ver)"
  else
    fail "no CHANGELOG section for the shipped manifest version $ver"
  fi
else
  fail "could not read the manifest version"
fi

rm -rf "$TMP"
exit $rc
