summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-06-17 22:53:32 +0300
committerPaul Buetow <paul@buetow.org>2026-06-17 22:53:32 +0300
commit7c94be57437ecdc9cadeb95bc4c26a25040163a9 (patch)
tree72f8fbcc6766d7b9f9c57322fe01d58e5e2abbbd /tests
parent140e39466d2f3a69339a00492b0e9061c56ac192 (diff)
pn0 decouple stats from album internals
Stats reached directly into album-module internals: the private global ALBUM_VIEW_PAGE_BY_PHOTO and the EXIF cache reader cached_photo_identify_output. Introduce a clean boundary, behaviour and generated HTML byte-identical. - Promote the EXIF identify cache primitive (cached_photo_identify_output plus its private helpers photo_cache_signature and print_cached_photo_identify_output) out of album-metadata.source.sh into a new shared src/lib/metadata-cache.source.sh, sourced before both album and stats (right after metadata-label in LIB_SOURCES). It is a low-level metadata primitive used by both consumers, so it no longer belongs to album internals. Signature/behaviour unchanged. - Add album_view_page_for_photo accessor in album-render.source.sh as the documented public API; keep ALBUM_VIEW_PAGE_BY_PHOTO as the album's private backing store. stats-filter-album.source.sh now calls the accessor instead of indexing the global, so a change to album page naming/caching stays contained in the album module. - Add test_album_stats_decoupling_boundary asserting the accessor returns the backing-store value and that the assembled bin/shuriken keeps the cache primitive in the shared module and no longer indexes the global from the stats filter section. Existing stats/album tests unchanged. Verified: 3-image fixture (STATS_PAGE=yes, fixed seed) diff -r of stashed original vs new build is byte-identical across all 47 dist files (only the inherent generated_at timestamp normalized). just test, just shellcheck, just check-generated and git diff --check all pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'tests')
-rwxr-xr-xtests/cli.sh58
1 files changed, 58 insertions, 0 deletions
diff --git a/tests/cli.sh b/tests/cli.sh
index 10e9b19..5ac6561 100755
--- a/tests/cli.sh
+++ b/tests/cli.sh
@@ -6104,6 +6104,61 @@ test_stats_collect_reads_cached_identify_output() {
test::teardown
}
+# Boundary test for the album/stats decoupling (task pn0). Proves two things:
+# 1) the album_view_page_for_photo accessor returns exactly what the private
+# ALBUM_VIEW_PAGE_BY_PHOTO backing store holds (and "" for unknown photos), so
+# stats can rely on it instead of indexing the global; and
+# 2) the assembled bin/shuriken keeps the cache primitive in the shared
+# metadata-cache module and the stats filter mini-album code no longer indexes
+# ALBUM_VIEW_PAGE_BY_PHOTO directly. A regression that re-coupled the modules
+# (moving the cache helper back into album, or re-indexing the global from
+# stats) would fail this.
+test_album_stats_decoupling_boundary() {
+ local generated
+ local cache_section
+ local stats_filter_section
+
+ test::setup
+ test::source_shuriken_lib
+
+ # 1) The accessor reflects the private backing store and is the public API.
+ # Seed the album's global directly here (shellcheck cannot see that the
+ # accessor reads it back), then assert the accessor returns it.
+ ALBUM_VIEW_PAGE_BY_PHOTO=()
+ # shellcheck disable=SC2034
+ ALBUM_VIEW_PAGE_BY_PHOTO['shot.jpg']='2-3'
+ test "$(album_view_page_for_photo 'shot.jpg')" = '2-3'
+ test "$(album_view_page_for_photo 'missing.jpg')" = ''
+
+ # 2) Structural assertions on the assembled script.
+ generated=$(<"$TEST_SHURIKEN")
+
+ # The cache primitive must live in the shared metadata-cache module.
+ cache_section=$(awk '
+ /^# Inlined from src\/lib\/metadata-cache.source.sh/ { keep=1; next }
+ /^# Inlined from / { keep=0 }
+ keep { print }
+ ' <<< "$generated")
+ test::assert_contains 'cached_photo_identify_output()' "$cache_section"
+
+ # The stats filter mini-album code must reach the album only through the
+ # accessor, never by indexing the album's private global directly.
+ stats_filter_section=$(awk '
+ /^# Inlined from src\/lib\/stats-filter-album.source.sh/ { keep=1; next }
+ /^# Inlined from / { keep=0 }
+ keep { print }
+ ' <<< "$generated")
+ # Literal needle: we look for the accessor call verbatim in the assembled
+ # script, so the "$photo" must stay unexpanded.
+ # shellcheck disable=SC2016
+ test::assert_contains 'album_view_page_for_photo "$photo"' \
+ "$stats_filter_section"
+ test::assert_not_contains 'ALBUM_VIEW_PAGE_BY_PHOTO[' \
+ "$stats_filter_section"
+
+ test::teardown
+}
+
# STATS_CATEGORIES is the single source of truth (task en0): proves the reset,
# the overview body builder, and the bucket ladders all derive from the registry,
# so a category can no longer be defined in only one place. A regression that
@@ -6568,6 +6623,9 @@ main() {
'stats collect reads cached identify output' \
test_stats_collect_reads_cached_identify_output
test::run_case \
+ 'album/stats decoupling boundary (pn0)' \
+ test_album_stats_decoupling_boundary
+ test::run_case \
'stats categories registry is single source of truth' \
test_stats_categories_registry_is_single_source_of_truth
test::run_case \