summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-06-14 22:39:17 +0300
committerPaul Buetow <paul@buetow.org>2026-06-14 22:39:17 +0300
commit0f0662850ad2df3502241cd1bdfcb366dd68d717 (patch)
tree68ecdf0b67127ef6ce2fabca2c2ccefe8305de76 /tests
parentcbfedd8f51d605ae8851b767ac21c00b877c33b7 (diff)
um0 add per-camera filter pages
Implement render_camera_pages <html_dir> <backhref> in stats.source.sh: one camera-<slug>.html per camera in STATS_CAMERA_SLUGS, reusing the aggregation's collision-resolved slugs and per-camera photo lists so filenames match pm0's leaderboard links. Each page reuses the shared header/footer chrome plus a new camera.tmpl that renders an HTML-escaped camera heading, a pre-built thumbnail grid, and a back-to-stats link. Thumbnails reuse preview.tmpl's markup style (thumb image from thumbs/) but link to the full-size image under photos/ rather than a per-photo view page, since the view-page name is not derivable outside the album pagination loop. The photos and thumbs dir names are fixed to match generate()'s render_album_pages call. Cameras are walked in LC_ALL=C label order for reproducible output, and cameras with no recorded photos are skipped. Adds the camera_name/camera_thumbs render field specs and a tests/cli.sh case covering per-camera files, slug collisions, HTML escaping, thumbnail link targets, and determinism. This provides the function + template + tests only; wiring into generate() and the STATS_PAGE toggle remain for rm0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'tests')
-rwxr-xr-xtests/cli.sh105
1 files changed, 105 insertions, 0 deletions
diff --git a/tests/cli.sh b/tests/cli.sh
index 48efc17..50a61f3 100755
--- a/tests/cli.sh
+++ b/tests/cli.sh
@@ -3821,6 +3821,108 @@ BASH
test::teardown
}
+test_render_camera_pages_renders_one_page_per_camera() {
+ local html
+ local html_again
+ local dist_dir
+
+ test::setup
+ dist_dir="$TEST_TMPDIR/dist"
+ mkdir -p "$dist_dir"
+
+ # Feed synthetic EXIF straight into accumulate_photo_stats (same approach as
+ # the stats-page test) to exercise three cameras: one whose label needs
+ # HTML-escaping (& and <), and a slug-collision pair ("Canon EOS 5D" vs
+ # "Canon EOS-5D" both slug to canon-eos-5d, so the second gets -2). Then
+ # render the per-camera pages twice into separate dirs to assert determinism.
+ bash -euo pipefail -s \
+ "$TEST_SHURIKEN" \
+ "$TEST_REPO_ROOT/share/templates/default" \
+ "$dist_dir" \
+ <<'BASH'
+shuriken="$1"; shift
+template_dir="$1"; shift
+dist_dir="$1"; shift
+
+# shellcheck source=/dev/null
+source <(sed '$d' "$shuriken")
+
+DIST_DIR="$dist_dir"
+TEMPLATE_DIR="$template_dir"
+TITLE='Stats album'
+HEIGHT=600
+THUMBHEIGHT=120
+MAXPREVIEWS=40
+ORIGINAL_BASEPATH=''
+TARBALL_INCLUDE=no
+SHURIKEN_OUTPUT_MODE=quiet
+apply_config_defaults
+
+feed() {
+ reset_photo_exif_stats
+ accumulate_photo_stats 'a.jpg' <<'EXIF'
+ Geometry: 6000x4000+0+0
+ exif:Make: Canon
+ exif:Model: Canon EOS 5D
+EXIF
+ accumulate_photo_stats 'b.jpg' <<'EXIF'
+ Geometry: 6000x4000+0+0
+ exif:Make: Canon
+ exif:Model: Canon EOS 5D
+EXIF
+ accumulate_photo_stats 'c.png' <<'EXIF'
+ Geometry: 4000x6000+0+0
+ exif:Make: Nikon & Co
+ exif:Model: <Z6>
+EXIF
+ accumulate_photo_stats 'd.jpg' <<'EXIF'
+ Geometry: 6000x4000+0+0
+ exif:Make: Canon
+ exif:Model: Canon EOS-5D
+EXIF
+}
+
+mkdir -p "$dist_dir/run1" "$dist_dir/run2"
+feed
+render_camera_pages run1 ..
+feed
+render_camera_pages run2 ..
+BASH
+
+ # One page per camera, named with the slugs the aggregation stored. The
+ # colliding labels get distinct files (canon-eos-5d and canon-eos-5d-2).
+ test::assert_file_exists "$dist_dir/run1/camera-canon-eos-5d.html"
+ test::assert_file_exists "$dist_dir/run1/camera-canon-eos-5d-2.html"
+ test::assert_file_exists "$dist_dir/run1/camera-nikon-co-z6.html"
+
+ # The Canon EOS 5D page lists exactly its two photos as thumbnails linking to
+ # the full images under photos/, and not the other camera's photo.
+ html=$(cat "$dist_dir/run1/camera-canon-eos-5d.html")
+ test::assert_contains '<a href="../photos/a.jpg">' "$html"
+ test::assert_contains '<img class="thumb" src="../thumbs/a.jpg" />' "$html"
+ test::assert_contains '<a href="../photos/b.jpg">' "$html"
+ test::assert_not_contains 'photos/c.png' "$html"
+ test::assert_not_contains 'photos/d.jpg' "$html"
+ # Heading shows the (trusted) camera label and a back-to-stats link.
+ test::assert_contains 'Canon EOS 5D' "$html"
+ test::assert_contains '<a href="../stats.html">Back to stats</a>' "$html"
+
+ # The EXIF-derived label with & and < is HTML-escaped in the heading.
+ html=$(cat "$dist_dir/run1/camera-nikon-co-z6.html")
+ test::assert_contains 'Nikon &amp; Co &lt;Z6&gt;' "$html"
+ test::assert_not_contains 'Nikon & Co <Z6>' "$html"
+ test::assert_contains '<a href="../photos/c.png">' "$html"
+
+ # Output is deterministic: the second run is byte-identical to the first.
+ html=$(cat "$dist_dir/run1/camera-canon-eos-5d.html")
+ html_again=$(cat "$dist_dir/run2/camera-canon-eos-5d.html")
+ if [ "$html" != "$html_again" ]; then
+ printf 'FAIL: camera page not reproducible across runs\n' >&2
+ exit 1
+ fi
+ test::teardown
+}
+
test_template_context_validator_fails_fast_without_errexit() {
local output
local -i status=0
@@ -5419,6 +5521,9 @@ main() {
'render_stats_page renders sections and escapes EXIF labels' \
test_render_stats_page_renders_sections_and_escapes
test::run_case \
+ 'render_camera_pages renders one page per camera' \
+ test_render_camera_pages_renders_one_page_per_camera
+ test::run_case \
'template context validator fails fast without errexit' \
test_template_context_validator_fails_fast_without_errexit
test::run_case \