#!/usr/bin/env bash # # check-lockfiles-selftest.sh — check-lockfiles.sh can fail. # # A check that cannot fail is decoration. This builds a scratch workspace of two # crates, one depending on the other by path, and asserts that the check # 1. passes when the lock is current; # 2. fails when the dependency's version is bumped and the lock is not # regenerated (the case this check exists for); # 3. fails when a dependency is added and the lock is not regenerated; # 4. fails when the lock is missing; # 5. fails, and says it could not check, when the manifest does not parse: # an error is never read as "current". # The scratch crates have no registry dependency, so nothing here needs a # network. set -uo pipefail here=$(cd "$(dirname "$0")" && pwd) check="$here/check-lockfiles.sh" tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT mk() { rm -rf "$tmp/ws"; mkdir -p "$tmp/ws/a/src" "$tmp/ws/b/src" "$tmp/ws/c/src" printf '[workspace]\nmembers = ["a", "b"]\nresolver = "2"\n' > "$tmp/ws/Cargo.toml" printf '[package]\nname = "selftest-a"\nversion = "0.1.0"\nedition = "2021"\n\n[dependencies]\nselftest-b = { path = "../b" }\n' > "$tmp/ws/a/Cargo.toml" printf '[package]\nname = "selftest-b"\nversion = "0.1.0"\nedition = "2021"\n' > "$tmp/ws/b/Cargo.toml" printf '[package]\nname = "selftest-c"\nversion = "0.1.0"\nedition = "2021"\n' > "$tmp/ws/c/Cargo.toml" : > "$tmp/ws/a/src/lib.rs"; : > "$tmp/ws/b/src/lib.rs"; : > "$tmp/ws/c/src/lib.rs" (cd "$tmp/ws" && cargo generate-lockfile --offline) >/dev/null 2>&1 || { echo "selftest: could not make the scratch lockfile" >&2; exit 2; } } fails=0 expect() { # expect [text the output must hold] local want=$1 what=$2 needle=${3:-} out rc out=$("$check" "$tmp/ws" 2>&1); rc=$? if [ "$want" = pass ] && [ $rc -ne 0 ]; then echo "FAIL $what: the check failed"; printf '%s\n' "$out" | sed 's/^/ /'; fails=$((fails+1)); return; fi if [ "$want" = fail ] && [ $rc -eq 0 ]; then echo "FAIL $what: the check passed"; fails=$((fails+1)); return; fi if [ -n "$needle" ] && ! grep -q -- "$needle" <<<"$out"; then echo "FAIL $what: the output does not say '$needle'"; printf '%s\n' "$out" | sed 's/^/ /'; fails=$((fails+1)); return; fi echo "ok $what" } mk; expect pass "a current lock passes" mk; sed -i.bak 's/^version = "0.1.0"/version = "0.2.0"/' "$tmp/ws/b/Cargo.toml" expect fail "a bumped path dependency with the old lock fails" "STALE" mk; printf 'selftest-c = { path = "../c" }\n' >> "$tmp/ws/a/Cargo.toml" expect fail "an added dependency with the old lock fails" "STALE" mk; rm "$tmp/ws/Cargo.lock" expect fail "a missing lock fails" "STALE" mk; printf 'this is not toml\n' >> "$tmp/ws/a/Cargo.toml" expect fail "a manifest that does not parse fails as unchecked, not as current" "ERROR" if [ $fails -ne 0 ]; then echo "check-lockfiles-selftest: $fails failure(s)"; exit 1; fi echo "check-lockfiles-selftest: the check passes a current lock and fails each broken one."