#!/usr/bin/env bash # next/tests/rich_verbs.sh — m2 Step 11b test. # # Projection folds for Announce + Endorse activity-types. # announce_state tracks per-cid announcer sets; # endorsement_state tracks per-cid + per-kind + per-actor counters. set -uo pipefail cd "$(git rev-parse --show-toplevel)" SX_SERVER="${SX_SERVER:-hosts/ocaml/_build/default/bin/sx_server.exe}" if [ ! -x "$SX_SERVER" ]; then SX_SERVER="/root/rose-ash/hosts/ocaml/_build/default/bin/sx_server.exe" fi if [ ! -x "$SX_SERVER" ]; then echo "ERROR: sx_server.exe not found." >&2 exit 1 fi VERBOSE="${1:-}" PASS=0; FAIL=0; ERRORS="" TMPFILE=$(mktemp); trap "rm -f $TMPFILE" EXIT # Cid1/Cid2 are the targets being announced/endorsed. SETUP='Cid1 = <<99,49>>, Cid2 = <<99,50>>, Ann_BC1 = [{type, announce}, {actor, bob}, {object, Cid1}], Ann_CC1 = [{type, announce}, {actor, carol}, {object, Cid1}], Ann_BC2 = [{type, announce}, {actor, bob}, {object, Cid2}], End_BLikeC1 = [{type, endorse}, {actor, bob}, {object, Cid1}, {kind, like}], End_CLikeC1 = [{type, endorse}, {actor, carol}, {object, Cid1}, {kind, like}], End_BShareC1 = [{type, endorse}, {actor, bob}, {object, Cid1}, {kind, share}],' cat > "$TMPFILE" < announcer added (epoch 11) (eval "(get (erlang-eval-ast \"${SETUP} S = announce_state:fold(Ann_BC1, announce_state:new()), announce_state:announcers_for(Cid1, S) =:= [bob]\") :name)") ;; Two announces same target -> both announcers (epoch 12) (eval "(get (erlang-eval-ast \"${SETUP} S = announce_state:fold(Ann_CC1, announce_state:fold(Ann_BC1, announce_state:new())), announce_state:announcers_for(Cid1, S) =:= [bob, carol]\") :name)") ;; Duplicate announce by same actor -> no double-add (epoch 13) (eval "(get (erlang-eval-ast \"${SETUP} S = announce_state:fold(Ann_BC1, announce_state:fold(Ann_BC1, announce_state:new())), announce_state:announcers_for(Cid1, S) =:= [bob]\") :name)") ;; announce_count + announced_cids (epoch 14) (eval "(get (erlang-eval-ast \"${SETUP} S = announce_state:fold(Ann_BC2, announce_state:fold(Ann_CC1, announce_state:fold(Ann_BC1, announce_state:new()))), {announce_state:announce_count(Cid1, S), announce_state:announce_count(Cid2, S), announce_state:announced_cids(S)} =:= {2, 1, [Cid1, Cid2]}\") :name)") ;; has_announced predicate (epoch 15) (eval "(get (erlang-eval-ast \"${SETUP} S = announce_state:fold(Ann_BC1, announce_state:new()), {announce_state:has_announced(bob, Cid1, S), announce_state:has_announced(carol, Cid1, S)} =:= {true, false}\") :name)") ;; announce_state fold_fn/0 is fun/2 (epoch 16) (eval "(get (erlang-eval-ast \"is_function(announce_state:fold_fn(), 2)\") :name)") ;; Non-Announce activity passes through (epoch 17) (eval "(get (erlang-eval-ast \"Note = [{type, note}, {actor, alice}, {object, [{content, hi}]}], announce_state:fold(Note, announce_state:new()) =:= []\") :name)") ;; ── endorsement_state ───────────────────────────────────── ;; new/0 (epoch 20) (eval "(get (erlang-eval-ast \"endorsement_state:new() =:= []\") :name)") ;; Endorse -> counter goes to 1 (epoch 21) (eval "(get (erlang-eval-ast \"${SETUP} S = endorsement_state:fold(End_BLikeC1, endorsement_state:new()), endorsement_state:counters_for(Cid1, S) =:= [{like, 1}]\") :name)") ;; Two like-endorses by different actors -> total = 2 (epoch 22) (eval "(get (erlang-eval-ast \"${SETUP} S = endorsement_state:fold(End_CLikeC1, endorsement_state:fold(End_BLikeC1, endorsement_state:new())), endorsement_state:total_for(Cid1, S) =:= 2\") :name)") ;; like + share -> two kinds (epoch 23) (eval "(get (erlang-eval-ast \"${SETUP} S = endorsement_state:fold(End_BShareC1, endorsement_state:fold(End_BLikeC1, endorsement_state:new())), endorsement_state:kinds_for(Cid1, S) =:= [like, share]\") :name)") ;; endorsers_for(Cid, like) (epoch 24) (eval "(get (erlang-eval-ast \"${SETUP} S = endorsement_state:fold(End_CLikeC1, endorsement_state:fold(End_BLikeC1, endorsement_state:new())), endorsement_state:endorsers_for(Cid1, like, S) =:= [bob, carol]\") :name)") ;; has_endorsed predicate (epoch 25) (eval "(get (erlang-eval-ast \"${SETUP} S = endorsement_state:fold(End_BLikeC1, endorsement_state:new()), {endorsement_state:has_endorsed(bob, Cid1, like, S), endorsement_state:has_endorsed(carol, Cid1, like, S), endorsement_state:has_endorsed(bob, Cid1, share, S)} =:= {true, false, false}\") :name)") ;; endorsement_state fold_fn/0 is fun/2 (epoch 26) (eval "(get (erlang-eval-ast \"is_function(endorsement_state:fold_fn(), 2)\") :name)") ;; Non-Endorse activity passes through (epoch 27) (eval "(get (erlang-eval-ast \"Note = [{type, note}, {actor, alice}, {object, [{content, hi}]}], endorsement_state:fold(Note, endorsement_state:new()) =:= []\") :name)") ;; Same actor endorsing twice bumps the counter (additive semantics) (epoch 28) (eval "(get (erlang-eval-ast \"${SETUP} S = endorsement_state:fold(End_BLikeC1, endorsement_state:fold(End_BLikeC1, endorsement_state:new())), endorsement_state:total_for(Cid1, S) =:= 2\") :name)") EPOCHS OUTPUT=$(timeout 280 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) check() { local epoch="$1" desc="$2" expected="$3" local actual actual=$(echo "$OUTPUT" | awk -v e="$epoch" ' $0 ~ "^\\(ok-len " e " " { getline; print; exit } $0 ~ "^\\(ok " e " " { print; exit } $0 ~ "^\\(error " e " " { print; exit } ') [ -z "$actual" ] && actual="" if echo "$actual" | grep -qF -- "$expected"; then PASS=$((PASS+1)) [ "$VERBOSE" = "-v" ] && echo " ok $desc" else FAIL=$((FAIL+1)) ERRORS+=" FAIL [$desc] (epoch $epoch) expected: $expected | actual: $actual " fi } check 3 "announce_state module loaded" "announce_state" check 4 "endorsement_state module loaded" "endorsement_state" check 10 "announce_state:new -> []" "true" check 11 "Announce -> announcer" "true" check 12 "Two announces same target" "true" check 13 "Duplicate announce no-op" "true" check 14 "count / announced_cids" "true" check 15 "has_announced predicate" "true" check 16 "announce fold_fn/0 fun/2" "true" check 17 "Non-Announce passes through" "true" check 20 "endorsement_state:new -> []" "true" check 21 "Endorse -> counter 1" "true" check 22 "Two likes -> total 2" "true" check 23 "like + share -> two kinds" "true" check 24 "endorsers_for(Cid, like)" "true" check 25 "has_endorsed predicate" "true" check 26 "endorse fold_fn/0 fun/2" "true" check 27 "Non-Endorse passes through" "true" check 28 "Same actor endorse twice -> 2" "true" TOTAL=$((PASS+FAIL)) if [ $FAIL -eq 0 ]; then echo "ok $PASS/$TOTAL next/tests/rich_verbs.sh passed" else echo "FAIL $PASS/$TOTAL passed, $FAIL failed:" echo "$ERRORS" fi [ $FAIL -eq 0 ]