aboutsummaryrefslogtreecommitdiffhomepage
path: root/org/test_shell_script_ssp_document_abstraction.org
blob: ccbe6dd76c9367205c4228421c3138db31fbfb9d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
-*- mode: org -*-
#+TITLE:       test shell script ssp document abstraction
#+DESCRIPTION: env envrc used by make & nix
#+FILETAGS:    :spine:build:tools:
#+AUTHOR:      Ralph Amissah
#+EMAIL:       [[mailto:ralph.amissah@gmail.com][ralph.amissah@gmail.com]]
#+COPYRIGHT:   Copyright (C) 2015 (continuously updated, current 2026) Ralph Amissah
#+LANGUAGE:    en
#+STARTUP:     content hideblocks hidestars noindent entitiespretty
#+PROPERTY:    header-args+ :eval never-export :exports code
#+PROPERTY:    header-args+ :noweb yes :padline no
#+PROPERTY:    header-args+ :results silent :cache no
#+PROPERTY:    header-args+ :mkdirp yes
#+OPTIONS:     H:3 num:nil toc:t \n:t ::t |:t ^:nil -:t f:t *:t
- magic single double-quote → " ← FIX changes hilighting behavior (occuring
  after it) in org document. INVESTIGATE (org-mode CONFIG?) FIND & FIX

* test shell script ssp document abstraction test/test-abstraction-ssp.sh

#+HEADER: :tangle ../test/test-abstraction-ssp.sh
#+HEADER: :tangle-mode (identity #o755)
#+HEADER: :shebang "#!/usr/bin/env sh"
#+BEGIN_SRC shell
# test-abstraction-ssp.sh
#
# Regression test for spine's document abstraction.
# Generates .ssp files for all sample documents and diffs
# against committed reference files.
# Also checks that a parallel run and a serial run of the same documents
# produce identical .ssp (guards against per-document state leaking
# between documents or between worker threads).
#
# Usage:
#   ./test/test-abstraction-ssp.sh                # uses result/bin/spine
#   ./test/test-abstraction-ssp.sh ./bin/spine-ldc # specify binary
#
# Exit codes:
#   0  all .ssp files match reference
#   1  differences found (printed to stdout)
#   2  missing reference directory (run with --generate first)
#
# To generate/update reference files:
#   ./test/test-abstraction-ssp.sh --generate
#   ./test/test-abstraction-ssp.sh --generate ./bin/spine-ldc

set -e

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SPINE_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"

# $SpinePOD names the sample pod directory, relative to the spine directory.
# Unset, "$SPINE_DIR/$SpinePOD" is the spine directory itself, which exists,
# so the "sample documents not found" check below would not catch it and
# spine would be handed every file in the spine tree.
if [ -z "$SpinePOD" ]; then
  echo "ERROR: \$SpinePOD is not set." >&2
  echo "  Set it to the sample pod directory, relative to $SPINE_DIR" >&2
  echo "  e.g. SpinePOD=../../markup/sisudoc-spine-samples/markup/pod-samples/pod" >&2
  exit 2
fi

SAMPLES_RAW="$SPINE_DIR/$SpinePOD"
if [ -d "$SAMPLES_RAW" ]; then
  SAMPLES_DIR="$(cd "$SAMPLES_RAW" && pwd)"
else
  SAMPLES_DIR="$SAMPLES_RAW"
fi
REF_DIR="$SCRIPT_DIR/reference/abstraction"
TMP_DIR="$SCRIPT_DIR/current/abstraction"

# parse arguments
GENERATE=false
SPINE_BIN=""
for arg in "$@"; do
  case "$arg" in
    --generate) GENERATE=true ;;
    *) SPINE_BIN="$arg" ;;
  esac
done

# find spine binary
if [ -z "$SPINE_BIN" ]; then
  if [ -x "$SPINE_DIR/result/bin/spine" ]; then
    SPINE_BIN="$SPINE_DIR/result/bin/spine"
  elif [ -x "$SPINE_DIR/bin/spine-ldc" ]; then
    SPINE_BIN="$SPINE_DIR/bin/spine-ldc"
  elif [ -x "$SPINE_DIR/bin/spine" ]; then
    SPINE_BIN="$SPINE_DIR/bin/spine"
  else
    echo "ERROR: spine binary not found. Specify path as argument." >&2
    exit 2
  fi
fi

# check samples exist
if [ ! -d "$SAMPLES_DIR" ]; then
  echo "ERROR: sample documents not found at $SAMPLES_DIR" >&2
  exit 2
fi

echo "spine binary: $SPINE_BIN"
echo "samples: $SAMPLES_DIR"

if [ "$GENERATE" = true ]; then
  echo "Generating reference .ssp files..."
  rm -rf "$REF_DIR"
  mkdir -p "$REF_DIR"
  $SPINE_BIN --show-abstraction --skip-output --output="$SCRIPT_DIR/reference" "$SAMPLES_DIR"/* 2>&1 | tail -1
  # flatten language subdirs into reference dir
  find "$SCRIPT_DIR/reference" -name "*.ssp" ! -path "$REF_DIR/*" -exec mv {} "$REF_DIR/" \;
  # clean up empty language dirs
  find "$SCRIPT_DIR/reference" -mindepth 1 -type d -empty -delete 2>/dev/null || true
  COUNT=$(ls "$REF_DIR"/*.ssp 2>/dev/null | wc -l)
  echo "Generated $COUNT reference .ssp files in $REF_DIR"
  exit 0
fi

# check reference exists
if [ ! -d "$REF_DIR" ] || [ -z "$(ls "$REF_DIR"/*.ssp 2>/dev/null)" ]; then
  echo "ERROR: no reference files found at $REF_DIR" >&2
  echo "Run with --generate first to create reference files." >&2
  exit 2
fi

# generate current .ssp files
echo "Generating current .ssp files..."
rm -rf "$TMP_DIR"
mkdir -p "$TMP_DIR"
$SPINE_BIN --abstraction --show-abstraction --skip-output --output="$SCRIPT_DIR/current" "$SAMPLES_DIR"/* 2>&1 | tail -1
# flatten
find "$SCRIPT_DIR/current" -name "*.ssp" ! -path "$TMP_DIR/*" -exec mv {} "$TMP_DIR/" \;
find "$SCRIPT_DIR/current" -mindepth 1 -type d -empty -delete 2>/dev/null || true

# generate the same .ssp serially, to check that parallel and serial
# processing agree (per-document state leaking between documents, or
# between worker threads, shows up here)
SER_DIR="$SCRIPT_DIR/current-serial/abstraction"
echo "Generating current .ssp files (serial)..."
rm -rf "$SCRIPT_DIR/current-serial"
mkdir -p "$SER_DIR"
$SPINE_BIN --show-abstraction --serial --skip-output --output="$SCRIPT_DIR/current-serial" "$SAMPLES_DIR"/* 2>&1 | tail -1
find "$SCRIPT_DIR/current-serial" -name "*.ssp" ! -path "$SER_DIR/*" -exec mv {} "$SER_DIR/" \;
find "$SCRIPT_DIR/current-serial" -mindepth 1 -type d -empty -delete 2>/dev/null || true

# diff
echo "Comparing against reference..."
FAILURES=0
for ref_file in "$REF_DIR"/*.ssp; do
  basename=$(basename "$ref_file")
  cur_file="$TMP_DIR/$basename"
  if [ ! -f "$cur_file" ]; then
    echo "MISSING: $basename (in reference but not generated)"
    FAILURES=$((FAILURES + 1))
    continue
  fi
  if ! diff -q "$ref_file" "$cur_file" > /dev/null 2>&1; then
    echo "CHANGED: $basename"
    diff --unified=3 "$ref_file" "$cur_file" | head -30
    echo "  ..."
    FAILURES=$((FAILURES + 1))
  fi
done

# check for new files not in reference
for cur_file in "$TMP_DIR"/*.ssp; do
  basename=$(basename "$cur_file")
  ref_file="$REF_DIR/$basename"
  if [ ! -f "$ref_file" ]; then
    echo "NEW: $basename (generated but not in reference)"
    FAILURES=$((FAILURES + 1))
  fi
done

# parallel vs serial determinism
for cur_file in "$TMP_DIR"/*.ssp; do
  basename=$(basename "$cur_file")
  ser_file="$SER_DIR/$basename"
  if [ ! -f "$ser_file" ]; then
    echo "MISSING (serial run): $basename"
    FAILURES=$((FAILURES + 1))
    continue
  fi
  if ! diff -q "$cur_file" "$ser_file" > /dev/null 2>&1; then
    echo "NON-DETERMINISTIC: $basename (parallel and serial runs differ)"
    diff --unified=3 "$cur_file" "$ser_file" | head -30
    echo "  ..."
    FAILURES=$((FAILURES + 1))
  fi
done

# clean up
rm -rf "$SCRIPT_DIR/current" "$SCRIPT_DIR/current-serial"

if [ "$FAILURES" -eq 0 ]; then
  REF_COUNT=$(ls "$REF_DIR"/*.ssp | wc -l)
  echo "PASS: all $REF_COUNT .ssp files match reference (parallel and serial agree)"
  exit 0
else
  echo "FAIL: $FAILURES difference(s) found"
  exit 1
fi
#+END_SRC