aboutsummaryrefslogtreecommitdiffstats
path: root/cli/test.sh
blob: 357beeba3f3faff1a327ca2bcac3f898cfc75fe6 (plain) (blame)
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
#!/usr/bin/env bash
# Test runner for ugi-cli against cases.json
set -uo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
UGI="$SCRIPT_DIR/ugi"

if [[ $# -ne 2 ]]; then
    echo "Usage: $0 <ugi_registry_v0.json> <cases.json>" >&2
    exit 1
fi

REGISTRY="$1"
CASES="$2"

if [[ ! -f "$REGISTRY" ]]; then echo "error: registry not found: $REGISTRY" >&2; exit 1; fi
if [[ ! -f "$CASES" ]]; then echo "error: cases not found: $CASES" >&2; exit 1; fi
if [[ ! -x "$UGI" ]]; then echo "error: ugi not found at $UGI" >&2; exit 1; fi

export UGI_REGISTRY="$REGISTRY"

pass=0 fail=0 skip=0
failures=()

# ── Helpers ──────────────────────────────────────────────────────────────────

expect_field_label() {
    local case_id="$1" field_code="$2"
    jq -r --arg id "$case_id" --arg fc "$field_code" '
        .cases[] | select(.id == $id) | .decoded.fields[$fc] //empty |
        if .type == "direct" then .label
        elif .type == "special" and .dimensions then
            [.dimensions | to_entries[] | "\(.key): \(.value.label)"] | join("; ")
        elif .type == "special" and .domains then
            [.domains[] | .name + (if .paid then " ($)" else "" end)] | join(", ")
        elif .entries then
            [.entries[] |
                .name + (if .value != null then "=\(.label)" else "" end) +
                (if .paid then " [$]" else "" end) +
                (if .aspire then " [+\(.aspire)]" else "" end)
            ] | join(", ")
        else empty end
    ' "$CASES"
}

run_decode_test() {
    local case_id="$1" uri="$2"
    local output
    output=$("$UGI" decode "$uri" 2>&1) || true

    local exp_ver
    exp_ver=$(jq -r --arg id "$case_id" '.cases[] | select(.id == $id) | .decoded.version' "$CASES")
    if ! echo "$output" | grep -qF "Version: $exp_ver"; then
        failures+=("$case_id/decode/version: expected '$exp_ver'")
        return 1
    fi

    local exp_handle
    exp_handle=$(jq -r --arg id "$case_id" '.cases[] | select(.id == $id) | .decoded.handle' "$CASES")
    if ! echo "$output" | grep -qF "Handle:  @$exp_handle"; then
        failures+=("$case_id/decode/handle: expected '@$exp_handle'")
        return 1
    fi

    local field_codes
    field_codes=$(jq -r --arg id "$case_id" '.cases[] | select(.id == $id) | .decoded.fields | keys[]' "$CASES" 2>/dev/null) || return 0

    for fc in $field_codes; do
        local exp_label
        exp_label=$(expect_field_label "$case_id" "$fc")
        [[ -z "$exp_label" ]] && continue

        local entry_count
        entry_count=$(jq -r --arg id "$case_id" --arg fc "$fc" '
            .cases[] | select(.id == $id) | .decoded.fields[$fc].entries // [] | length
        ' "$CASES")

        if [[ "$entry_count" -gt 0 ]]; then
            local entry_names
            entry_names=$(jq -r --arg id "$case_id" --arg fc "$fc" '
                .cases[] | select(.id == $id) | .decoded.fields[$fc].entries[]? | .name
            ' "$CASES")
            for ename in $entry_names; do
                if ! echo "$output" | grep -qF "$ename"; then
                    failures+=("$case_id/decode/$fc: missing entry name '$ename' in output")
                    return 1
                fi
            done
        elif [[ -n "$exp_label" ]]; then
            IFS=';' read -ra label_parts <<< "$exp_label"
            for lp in "${label_parts[@]}"; do
                lp="${lp## }"
                if ! echo "$output" | grep -qF "$lp"; then
                    failures+=("$case_id/decode/$fc: missing '$lp' in output")
                    return 1
                fi
            done
        fi
    done

    return 0
}

run_convert_test() {
    local case_id="$1" uri="$2" expected_block="$3"

    local block_output
    block_output=$("$UGI" convert "$uri" 2>&1) || true

    if ! echo "$block_output" | grep -qF "BEGIN UGI BLOCK"; then
        failures+=("$case_id/convert-uri2block: missing BEGIN header")
        return 1
    fi
    if ! echo "$block_output" | grep -qF "END UGI BLOCK"; then
        failures+=("$case_id/convert-uri2block: missing END footer")
        return 1
    fi

    local exp_handle
    exp_handle=$(jq -r --arg id "$case_id" '.cases[] | select(.id == $id) | .decoded.handle' "$CASES")
    if ! echo "$block_output" | grep -qF "@$exp_handle"; then
        failures+=("$case_id/convert-uri2block: missing handle '@$exp_handle'")
        return 1
    fi

    local uri_output
    uri_output=$("$UGI" convert "$block_output" 2>&1) || true

    if [[ "${uri_output,,}" != "ugi:"* ]]; then
        failures+=("$case_id/convert-block2uri: output doesn't start with 'ugi:' got '$uri_output'")
        return 1
    fi

    if ! echo "$uri_output" | grep -qF "@$exp_handle"; then
        failures+=("$case_id/convert-block2uri: missing handle in roundtrip")
        return 1
    fi

    return 0
}

# ── Run tests ────────────────────────────────────────────────────────────────

echo "=== UGI CLI Test Suite ==="
echo "Registry: $REGISTRY"
echo "Cases:    $CASES"
echo "CLI:      $UGI"
echo

case_ids=$(jq -r '.cases[].id' "$CASES")

for cid in $case_ids; do
    uri=$(jq -r --arg id "$cid" '.cases[] | select(.id == $id) | .uri // empty' "$CASES")
    has_decoded=$(jq -r --arg id "$cid" '.cases[] | select(.id == $id) | .decoded // empty | if . then "yes" else "no" end' "$CASES")

    if [[ -z "$uri" ]]; then
        printf "  SKIP  %-35s (no single URI)\n" "$cid"
        skip=$((skip + 1))
        continue
    fi

    if [[ "$has_decoded" == "no" || -z "$has_decoded" ]]; then
        printf "  SKIP  %-35s (no decoded expectations)\n" "$cid"
        skip=$((skip + 1))
        continue
    fi

    if run_decode_test "$cid" "$uri"; then
        printf "  PASS  %-35s decode\n" "$cid"
        pass=$((pass + 1))
    else
        printf "  FAIL  %-35s decode\n" "$cid"
        fail=$((fail + 1))
    fi

    block=$(jq -r --arg id "$cid" '.cases[] | select(.id == $id) | .block // empty' "$CASES")
    if [[ -n "$block" ]]; then
        if run_convert_test "$cid" "$uri" "$block"; then
            printf "  PASS  %-35s convert roundtrip\n" "$cid"
            pass=$((pass + 1))
        else
            printf "  FAIL  %-35s convert roundtrip\n" "$cid"
            fail=$((fail + 1))
        fi
    fi
done

echo
echo "=== Results: $pass passed, $fail failed, $skip skipped ==="

if [[ ${#failures[@]} -gt 0 ]]; then
    echo
    echo "Failures:"
    for f in "${failures[@]}"; do
        echo "  - $f"
    done
    exit 1
fi

exit 0