Skip to content

Commit 73a3bcf

Browse files
Merge pull request #6 from datalogics-cgreen/pdfcloud-5464-add-tools
PDFCLOUD-5464 Add additional pdfRest tools
2 parents 3c9b205 + 3e7d369 commit 73a3bcf

54 files changed

Lines changed: 10210 additions & 319 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AGENTS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
- `uv run pre-commit run --all-files` — enforce formatting and lint rules before
2020
pushing.
2121
- `uv run pytest` — execute the suite with the active interpreter.
22+
- `scripts/check_test_parity.sh` — run changed tests and report sync/async
23+
parity gaps (accepts optional base/head refs, defaults to
24+
`upstream/main..HEAD`).
2225
- `uv build` — produce wheels and sdists identical to the release workflow.
2326
- `uvx nox -s tests` — create matrix virtualenvs via nox and execute the pytest
2427
session.

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,9 @@ Run the test suite with:
3636
```bash
3737
uv run pytest
3838
```
39+
40+
Check sync/async parity for changed tests (defaults to `upstream/main..HEAD`):
41+
42+
```bash
43+
scripts/check_test_parity.sh
44+
```

TESTING_GUIDELINES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ iteration required.
1313
request customization, validation failures, file helpers, and live calls. Do
1414
not hide the transport behind a parameter; the test name itself should reveal
1515
which client is under test.
16+
- **Check parity regularly.** Run `scripts/check_test_parity.sh` (defaults to
17+
`upstream/main..HEAD`) to spot missing sync/async counterparts, keeping
18+
parameterized test IDs aligned between transports.
1619
- **Exercise both sides of the contract.** Hermetic tests (via
1720
`httpx.MockTransport`) validate serialization and local validation. Live
1821
suites prove the server behaves the same way, including invalid literal

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ requires-python = ">=3.10"
1010
dependencies = [
1111
"exceptiongroup>=1.3.0",
1212
"httpx>=0.28.1",
13+
"langcodes>=3.4.0",
1314
"pydantic>=2.12.0",
1415
]
1516

scripts/check_test_parity.sh

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
IFS=$'\n\t'
4+
5+
base_ref="${1:-upstream/main}"
6+
head_ref="${2:-HEAD}"
7+
8+
if ! git rev-parse --verify "$base_ref" > /dev/null 2>&1; then
9+
echo "Base ref '$base_ref' not found." >&2
10+
exit 1
11+
fi
12+
13+
if ! git rev-parse --verify "$head_ref" > /dev/null 2>&1; then
14+
echo "Head ref '$head_ref' not found." >&2
15+
exit 1
16+
fi
17+
18+
test_files=()
19+
while IFS= read -r file; do
20+
if [[ -n "$file" ]]; then
21+
test_files+=("$file")
22+
fi
23+
done < <(
24+
git diff --name-only --diff-filter=d "$base_ref..$head_ref" -- tests | grep -E '\.py$' || true
25+
)
26+
27+
if [[ ${#test_files[@]} -eq 0 ]]; then
28+
echo "No changed test files under tests/ for $base_ref..$head_ref."
29+
exit 0
30+
fi
31+
32+
tmp_output="$(mktemp)"
33+
tmp_tests="$(mktemp)"
34+
tmp_counts="$(mktemp)"
35+
tmp_missing_sync="$(mktemp)"
36+
tmp_missing_async="$(mktemp)"
37+
tmp_payload="$(mktemp)"
38+
trap 'rm -f "$tmp_output" "$tmp_tests" "$tmp_counts" "$tmp_missing_sync" "$tmp_missing_async" "$tmp_payload"' EXIT
39+
40+
echo "Running pytest on changed tests:"
41+
printf ' - %s\n' "${test_files[@]}"
42+
43+
uv run pytest -vv -rA -n auto "${test_files[@]}" | tee "$tmp_output"
44+
45+
awk '
46+
{
47+
line = $0;
48+
sub(/^\[[^]]+\][[:space:]]+/, "", line);
49+
sub(/[[:space:]]+\[[^]]+\]$/, "", line);
50+
if (line ~ /^(PASSED|FAILED|SKIPPED|XFAIL|XPASS|ERROR)[[:space:]]+tests\/.*::/) {
51+
sub(/^(PASSED|FAILED|SKIPPED|XFAIL|XPASS|ERROR)[[:space:]]+/, "", line);
52+
print line;
53+
} else if (line ~ /^tests\/.*::.*[[:space:]]+(PASSED|FAILED|SKIPPED|XFAIL|XPASS|ERROR)$/) {
54+
sub(/[[:space:]]+(PASSED|FAILED|SKIPPED|XFAIL|XPASS|ERROR)$/, "", line);
55+
print line;
56+
}
57+
}
58+
' "$tmp_output" > "$tmp_tests"
59+
60+
if [[ ! -s "$tmp_tests" ]]; then
61+
echo "No test node IDs detected in pytest output; try rerunning with -vv." >&2
62+
exit 1
63+
fi
64+
65+
awk -v sync_file="$tmp_missing_sync" \
66+
-v async_file="$tmp_missing_async" \
67+
-v payload_file="$tmp_payload" \
68+
-v counts_file="$tmp_counts" '
69+
function is_async(nodeid) {
70+
return (nodeid ~ /::test_.*async_/);
71+
}
72+
function normalize(nodeid) {
73+
sub(/::test_live_async_/, "::test_live_", nodeid);
74+
sub(/::test_async_/, "::test_", nodeid);
75+
return nodeid;
76+
}
77+
{
78+
total++;
79+
if ($0 ~ /::test_.*(payload|validation)/) {
80+
payload_like[$0] = 1;
81+
}
82+
if (is_async($0)) {
83+
async_count++;
84+
norm = normalize($0);
85+
async_norm[norm] = 1;
86+
async_orig[norm] = $0;
87+
} else {
88+
sync_count++;
89+
norm = normalize($0);
90+
sync_norm[norm] = 1;
91+
sync_orig[norm] = $0;
92+
}
93+
}
94+
END {
95+
missing_sync = 0;
96+
missing_async = 0;
97+
98+
for (n in async_norm) {
99+
if (!(n in sync_norm)) {
100+
missing_sync++;
101+
print async_orig[n] >> sync_file;
102+
}
103+
}
104+
for (n in sync_norm) {
105+
if (!(n in async_norm)) {
106+
missing_async++;
107+
print sync_orig[n] >> async_file;
108+
}
109+
}
110+
payload_count = 0;
111+
for (t in payload_like) {
112+
payload_count++;
113+
print t >> payload_file;
114+
}
115+
116+
print "total=" total > counts_file;
117+
print "sync_count=" sync_count >> counts_file;
118+
print "async_count=" async_count >> counts_file;
119+
print "missing_sync=" missing_sync >> counts_file;
120+
print "missing_async=" missing_async >> counts_file;
121+
print "payload_count=" payload_count >> counts_file;
122+
}
123+
' "$tmp_tests"
124+
125+
total=0
126+
sync_count=0
127+
async_count=0
128+
missing_sync=0
129+
missing_async=0
130+
payload_count=0
131+
while IFS='=' read -r key value; do
132+
case "$key" in
133+
total) total="$value" ;;
134+
sync_count) sync_count="$value" ;;
135+
async_count) async_count="$value" ;;
136+
missing_sync) missing_sync="$value" ;;
137+
missing_async) missing_async="$value" ;;
138+
payload_count) payload_count="$value" ;;
139+
esac
140+
done < "$tmp_counts"
141+
142+
echo ""
143+
echo "Test parity report"
144+
echo "Total tests: $total"
145+
echo "Sync tests: $sync_count"
146+
echo "Async tests: $async_count"
147+
echo "Missing sync counterparts: $missing_sync"
148+
if [[ "$missing_sync" -gt 0 ]]; then
149+
sort "$tmp_missing_sync" | while read -r line; do
150+
echo " - $line"
151+
done
152+
fi
153+
echo "Missing async counterparts: $missing_async"
154+
if [[ "$missing_async" -gt 0 ]]; then
155+
sort "$tmp_missing_async" | while read -r line; do
156+
echo " - $line"
157+
done
158+
fi
159+
echo "Payload/validation-style tests (name contains payload/validation): $payload_count"
160+
if [[ "$payload_count" -gt 0 ]]; then
161+
sort "$tmp_payload" | while read -r line; do
162+
echo " - $line"
163+
done
164+
fi

0 commit comments

Comments
 (0)