diff options
| author | Paul Buetow <paul@buetow.org> | 2026-06-14 23:07:12 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-06-14 23:07:12 +0300 |
| commit | b7d5c1102c3679b67532f30f2613e4d2d61c59ba (patch) | |
| tree | 573548dc8762aeb7c642fed804894d280425f84c /tests | |
| parent | 0f0662850ad2df3502241cd1bdfcb366dd68d717 (diff) | |
rm0 wire stats feature into generate with STATS_PAGE toggle
Final integration of the stats-site feature:
- Add STATS_PAGE config (default yes) mirroring SPLASH_PAGE through every
layer: shuriken.default.conf, apply_config_defaults, CLI_OPTION_SPEC
(--stats/--no-stats), the CLI_CONFIG_OVERRIDE_TARGETS allowlist (without
which the flag was silently ignored), usage text, yes/no validation,
print_config, the action config list + effective-setting log, the
generation metadata, and the dry-run plan.
- generate() now calls a gated generate_stats_pages helper after the album
pages (and before archiving, so the stats/camera pages are tarballed):
collect_photo_exif_stats + render_stats_page . . + render_camera_pages . .
- Emit "stats_page" in shuriken.json next to "splash_page".
- Gate the header Stats nav link behind STATS_PAGE via a new
render_stats_page_html config_html field, so it is hidden (no 404) when
stats are disabled.
- Document STATS_PAGE and --stats/--no-stats in the README.
- Tests: full --generate produces stats.html + camera-<slug>.html + the nav
link and stats_page=true; --no-stats suppresses all three and sets
stats_page=false; print-config and metadata expectations updated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'tests')
| -rwxr-xr-x | tests/cli.sh | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/tests/cli.sh b/tests/cli.sh index 50a61f3..6f56dad 100755 --- a/tests/cli.sh +++ b/tests/cli.sh @@ -142,6 +142,7 @@ assert metadata["settings"]["maxpreviews"] == maxpreviews assert metadata["settings"]["image_jobs"] == "3" assert metadata["settings"]["shuffle"] is False assert isinstance(metadata["settings"]["splash_page"], bool) +assert isinstance(metadata["settings"]["stats_page"], bool) assert "original_basepath" in metadata["settings"] PY } @@ -1308,6 +1309,7 @@ IMAGEMAGICK_TIMEOUT=60 RANDOM_SEED='' SHUFFLE=no SPLASH_PAGE=yes +STATS_PAGE=yes TARBALL_INCLUDE=yes TARBALL_SUFFIX=.tar TAR_TIMEOUT=120 @@ -1354,6 +1356,7 @@ IMAGEMAGICK_TIMEOUT=60 RANDOM_SEED='' SHUFFLE=no SPLASH_PAGE=yes +STATS_PAGE=yes TARBALL_INCLUDE=no TARBALL_SUFFIX=.tar TAR_TIMEOUT=120 @@ -1493,6 +1496,7 @@ IMAGEMAGICK_TIMEOUT=60 RANDOM_SEED='' SHUFFLE=yes SPLASH_PAGE=yes +STATS_PAGE=yes TARBALL_INCLUDE=no TARBALL_SUFFIX=.tar TAR_TIMEOUT=120 @@ -1534,6 +1538,7 @@ IMAGEMAGICK_TIMEOUT=60 RANDOM_SEED='' SHUFFLE=no SPLASH_PAGE=yes +STATS_PAGE=yes TARBALL_INCLUDE=no TARBALL_SUFFIX=.tar TAR_TIMEOUT=120 @@ -1600,6 +1605,7 @@ IMAGEMAGICK_TIMEOUT=60 RANDOM_SEED=cli-seed SHUFFLE=yes SPLASH_PAGE=no +STATS_PAGE=yes TARBALL_INCLUDE=yes TARBALL_SUFFIX=.tar TAR_TIMEOUT=120 @@ -3005,6 +3011,112 @@ test_generate_cli_no_splash_overrides_config() { test::teardown } +# Synthetic `identify -verbose` output with EXIF the stats aggregation can parse, +# so a full --generate produces a real camera leaderboard + per-camera page. +test::stats_identify_output() { + printf '%s\n' \ + ' Format: JPEG (Joint Photographic Experts Group JFIF format)' \ + ' Geometry: 160x90+0+0' \ + ' exif:Make: Canon' \ + ' exif:Model: EOS R5' \ + ' exif:FNumber: 28/10' \ + ' exif:ExposureTime: 1/250' \ + ' exif:PhotographicSensitivity: 400' \ + ' exif:FocalLength: 50/1' \ + ' exif:DateTimeOriginal: 2023:07:15 14:30:00' +} + +test_generate_stats_pages_created_and_nav_linked() { + local config_file + local fake_bin + local -i nav_links + + test::setup + fake_bin="$TEST_TMPDIR/bin" + config_file="$TEST_TMPDIR/shuriken.conf" + + test::install_fake_imagemagick "$fake_bin" + PATH="$fake_bin:$PATH" \ + test::generate_fixture_images "$TEST_TMPDIR/incoming" + test::write_album_config \ + "$config_file" "$TEST_TMPDIR/incoming" "$TEST_TMPDIR/dist" \ + 'Stats album' 40 + + ( + cd "$TEST_TMPDIR" + PATH="$fake_bin:$PATH" \ + TEST_IMAGEMAGICK_IDENTIFY_OUTPUT="$(test::stats_identify_output)" \ + "$TEST_SHURIKEN" --generate --random-seed stats-seed + ) + + # Stats page and the per-camera page (Canon EOS R5 -> canon-eos-r5) exist. + test::assert_file_exists "$TEST_TMPDIR/dist/stats.html" + test::assert_file_exists "$TEST_TMPDIR/dist/camera-canon-eos-r5.html" + test::assert_contains 'Canon EOS R5' "$(<"$TEST_TMPDIR/dist/stats.html")" + test::assert_not_contains '<script' "$(<"$TEST_TMPDIR/dist/stats.html")" + + # The header bar links to the stats page on at least one generated page. + nav_links=$(grep -lF 'stats.html">Stats' "$TEST_TMPDIR"/dist/*.html | wc -l) + test "$nav_links" -gt 0 + + python3 - "$TEST_TMPDIR/dist/shuriken.json" <<'PY' +import json +import pathlib +import sys + +metadata = json.loads(pathlib.Path(sys.argv[1]).read_text()) +assert metadata["settings"]["stats_page"] is True +PY + + test::teardown +} + +test_generate_no_stats_suppresses_pages_and_nav() { + local config_file + local fake_bin + + test::setup + fake_bin="$TEST_TMPDIR/bin" + config_file="$TEST_TMPDIR/shuriken.conf" + + test::install_fake_imagemagick "$fake_bin" + PATH="$fake_bin:$PATH" \ + test::generate_fixture_images "$TEST_TMPDIR/incoming" + test::write_album_config \ + "$config_file" "$TEST_TMPDIR/incoming" "$TEST_TMPDIR/dist" \ + 'No stats album' 40 + + ( + cd "$TEST_TMPDIR" + PATH="$fake_bin:$PATH" \ + TEST_IMAGEMAGICK_IDENTIFY_OUTPUT="$(test::stats_identify_output)" \ + "$TEST_SHURIKEN" --generate --no-stats --random-seed stats-seed + ) + + # No stats page, no per-camera pages. + test::assert_path_absent "$TEST_TMPDIR/dist/stats.html" + if compgen -G "$TEST_TMPDIR/dist/camera-*.html" >/dev/null; then + printf 'FAIL: --no-stats still produced camera pages\n' >&2 + exit 1 + fi + # No stats nav link anywhere. + if grep -RF 'stats.html">Stats' "$TEST_TMPDIR"/dist/*.html; then + printf 'FAIL: --no-stats still rendered the Stats nav link\n' >&2 + exit 1 + fi + + python3 - "$TEST_TMPDIR/dist/shuriken.json" <<'PY' +import json +import pathlib +import sys + +metadata = json.loads(pathlib.Path(sys.argv[1]).read_text()) +assert metadata["settings"]["stats_page"] is False +PY + + test::teardown +} + test_refresh_splash_rewrites_only_index_from_existing_assets() { local after_index local after_metadata @@ -5464,6 +5576,12 @@ main() { '--generate --no-splash keeps root index redirect' \ test_generate_cli_no_splash_overrides_config test::run_case \ + '--generate creates stats and per-camera pages with nav link' \ + test_generate_stats_pages_created_and_nav_linked + test::run_case \ + '--generate --no-stats suppresses stats pages and nav link' \ + test_generate_no_stats_suppresses_pages_and_nav + test::run_case \ '--refresh-splash rewrites only root index from existing assets' \ test_refresh_splash_rewrites_only_index_from_existing_assets test::run_case \ |
