#!/usr/bin/env bash
# misc_anonymize_roundtrip — three properties of `nucleos anonymize`:
#
#   1. PARSE ROUND-TRIP: the anonymized output must still be a
#      well-formed .dzn — `nucleos parse` accepts it.
#   2. IDEMPOTENCE: anonymizing an already-anonymized file leaves
#      it unchanged. (`_<N>` tokens pass through verbatim.)
#   3. DETERMINISM: two `anonymize` runs on the same input produce
#      byte-identical output.
#
# Avoids the `int` type — it's not in dzn's preserved-keyword set
# and gets mangled, breaking parse round-trip. The fixture uses
# only `void`/`bool` (preserved by both dzn and nucleos
# anonymizers) so the round-trip assertion is meaningful.
set -euo pipefail

cat > "$NUCTEST_TMPDIR/Foo.dzn" <<'EOF'
// A non-trivial input: interface with an enum state machine,
// component with a system instance. Exercises identifier
// mangling across interfaces, components, ports, enum types,
// and enum members.
interface IFoo {
    in void start();
    in void stop();
    out void notify();
    behavior {
        enum State { Idle, Running, Stopping };
        State s = State.Idle;
        [s.Idle]     on start: s = State.Running;
        [s.Running]  on stop:  s = State.Stopping;
        [s.Stopping] on inevitable: { notify; s = State.Idle; }
    }
}

component Foo {
    provides IFoo p;
    behavior {
        on p.start(): {}
        on p.stop():  {}
    }
}
EOF

# 1. Anonymize once.
"$NUCLEOS" anonymize "$NUCTEST_TMPDIR/Foo.dzn" > "$NUCTEST_TMPDIR/Foo.anon.dzn"

# Positive evidence the anonymizer actually ran: output must be
# non-empty AND contain at least one `_<digit>` token (the
# anonymizer's signature output shape). Without this, a broken
# anonymizer that produces an empty file would trivially pass the
# parse + idempotence + determinism + no-original-identifiers
# checks below.
if [ ! -s "$NUCTEST_TMPDIR/Foo.anon.dzn" ]; then
    echo "FAIL: anonymized output is empty (anonymizer ran but produced nothing)" >&2
    exit 1
fi
if ! grep -qE '_[0-9]+' "$NUCTEST_TMPDIR/Foo.anon.dzn"; then
    echo "FAIL: anonymized output has no _<N> tokens (didn't rename anything)" >&2
    cat "$NUCTEST_TMPDIR/Foo.anon.dzn" >&2
    exit 1
fi

# Parse round-trip: anonymized output must still be well-formed.
if ! "$NUCLEOS" parse "$NUCTEST_TMPDIR/Foo.anon.dzn" \
        > "$NUCTEST_TMPDIR/parse.out" 2> "$NUCTEST_TMPDIR/parse.err"; then
    echo "FAIL: anonymized output does not parse cleanly" >&2
    cat "$NUCTEST_TMPDIR/parse.err" >&2
    echo "--- anonymized file ---" >&2
    cat "$NUCTEST_TMPDIR/Foo.anon.dzn" >&2
    exit 1
fi

# 2. Idempotence: anonymizing twice = anonymizing once.
"$NUCLEOS" anonymize "$NUCTEST_TMPDIR/Foo.anon.dzn" > "$NUCTEST_TMPDIR/Foo.anon2.dzn"
if ! diff -q "$NUCTEST_TMPDIR/Foo.anon.dzn" "$NUCTEST_TMPDIR/Foo.anon2.dzn" > /dev/null; then
    echo "FAIL: anonymize not idempotent" >&2
    diff -u "$NUCTEST_TMPDIR/Foo.anon.dzn" "$NUCTEST_TMPDIR/Foo.anon2.dzn" >&2 || true
    exit 1
fi

# 3. Determinism: two fresh runs on the original give identical output.
"$NUCLEOS" anonymize "$NUCTEST_TMPDIR/Foo.dzn" > "$NUCTEST_TMPDIR/Foo.anon-b.dzn"
if ! diff -q "$NUCTEST_TMPDIR/Foo.anon.dzn" "$NUCTEST_TMPDIR/Foo.anon-b.dzn" > /dev/null; then
    echo "FAIL: anonymize not deterministic across runs" >&2
    diff -u "$NUCTEST_TMPDIR/Foo.anon.dzn" "$NUCTEST_TMPDIR/Foo.anon-b.dzn" >&2 || true
    exit 1
fi

# Sanity: anonymized output must NOT contain the original
# identifiers (so we're actually doing the renaming).
for needle in "IFoo" "Foo" "start" "stop" "notify" "State" "Idle" "Running" "Stopping"; do
    if grep -qw "$needle" "$NUCTEST_TMPDIR/Foo.anon.dzn"; then
        echo "FAIL: anonymized output still contains original identifier '$needle'" >&2
        echo "--- anonymized file ---" >&2
        cat "$NUCTEST_TMPDIR/Foo.anon.dzn" >&2
        exit 1
    fi
done
