summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-06-03 19:57:19 +0300
committerPaul Buetow <paul@buetow.org>2026-06-03 19:57:19 +0300
commit9b3f994be65fe37516c74a60aa158b5bb340b20d (patch)
treedc461b452003d25b815a542867a584bc99ee80c9
parent11da40444ce1bf74545f87a4bfe339f61b4660f0 (diff)
Add print-config mode for task 0j0
-rw-r--r--README.md27
-rwxr-xr-xbin/photoalbum83
-rwxr-xr-xsrc/photoalbum.sh83
-rwxr-xr-xtests/cli.sh308
4 files changed, 480 insertions, 21 deletions
diff --git a/README.md b/README.md
index 7b471a4..83d7218 100644
--- a/README.md
+++ b/README.md
@@ -22,6 +22,7 @@ modern `magick` command and falls back to `convert` when needed.
photoalbum --init
photoalbum --generate [--config PATH] [OPTIONS]
photoalbum --dry-run [--config PATH] [OPTIONS]
+photoalbum --print-config [--config PATH] [OPTIONS]
photoalbum --clean [--config PATH] [OPTIONS]
photoalbum --version
```
@@ -32,14 +33,17 @@ photoalbum --version
* `--dry-run` loads the config and overrides, validates the planned generation,
and prints the effective paths, image count, tarball plan, and generated file
plan without writing output or running ImageMagick or tar.
+* `--print-config` loads the config and overrides, validates basic config values,
+ and prints the effective configuration without writing output, running
+ ImageMagick, running tar, cleaning, or initializing.
* `--clean` removes the configured output directory.
* `--version` prints the program version.
-* `--config PATH` selects the config file for `--generate`, `--dry-run`, or
- `--clean`.
+* `--config PATH` selects the config file for `--generate`, `--dry-run`,
+ `--print-config`, or `--clean`.
-When `--config PATH` is not provided, `--generate`, `--dry-run`, and `--clean`
-read `./photoalbum.conf`. If the file is missing, run `photoalbum --init`
-first.
+When `--config PATH` is not provided, `--generate`, `--dry-run`,
+`--print-config`, and `--clean` read `./photoalbum.conf`. If the file is
+missing, run `photoalbum --init` first.
The config file is a Bash file with assignments such as `INCOMING_DIR`,
`DIST_DIR`, `TEMPLATE_DIR`, `TITLE`, `HEIGHT`, `THUMBHEIGHT`, `MAXPREVIEWS`,
@@ -60,6 +64,14 @@ notes, are ignored with a warning so generation can continue.
values that generation would use after applying command-line overrides. Its
tarball filename uses `<timestamp>` as a placeholder so the output is stable.
+`--print-config` writes stable shell-style assignments to stdout in this order:
+`CONFIG_SOURCE`, `INCOMING_DIR`, `DIST_DIR`, `TEMPLATE_DIR`, `TITLE`, `HEIGHT`,
+`THUMBHEIGHT`, `MAXPREVIEWS`, `SHUFFLE`, `TARBALL_INCLUDE`, `TARBALL_SUFFIX`,
+`TAR_OPTS`, and `ORIGINAL_BASEPATH`. Scalar values use Bash `%q` quoting and
+`TAR_OPTS` is normalized to a Bash array assignment, so the output can be parsed
+by shell tooling. `--quiet` does not suppress this output, and `--verbose` does
+not add human-readable diagnostics to it.
+
Successful generation writes `photoalbum.json` into the output directory. This
metadata records the generator version and timestamp, config source, template
directory, supported source image and generated file counts, tarball status, and
@@ -81,8 +93,9 @@ The following long options override config values:
| `--tarball` | `TARBALL_INCLUDE=yes` |
| `--no-tarball` | `TARBALL_INCLUDE=no` |
-`--dry-run` accepts the same override options as `--generate`. `--clean` accepts
-the same override options, but only `--dist` changes what it removes.
+`--dry-run` and `--print-config` accept the same override options as
+`--generate`. `--clean` accepts the same override options, but only `--dist`
+changes what it removes.
Output is human-readable by default and reports routine generation progress.
Use `--quiet` to suppress routine progress while still writing errors to stderr.
diff --git a/bin/photoalbum b/bin/photoalbum
index a16b660..a388e41 100755
--- a/bin/photoalbum
+++ b/bin/photoalbum
@@ -13,6 +13,7 @@ usage() {
Usage:
$0 --generate [--config PATH] [OPTIONS]
$0 --dry-run [--config PATH] [OPTIONS]
+ $0 --print-config [--config PATH] [OPTIONS]
$0 --clean [--config PATH] [OPTIONS]
$0 --version
$0 --init
@@ -840,6 +841,44 @@ dry_run() {
fi
}
+print_shell_assignment() {
+ local -r name="$1"; shift
+ local -r value="$1"; shift
+
+ printf '%s=%q\n' "$name" "$value"
+}
+
+print_shell_array_assignment() {
+ local -r name="$1"; shift
+ local value
+
+ printf '%s=(' "$name"
+ for value in "$@"; do
+ printf ' %q' "$value"
+ done
+ printf ' )\n'
+}
+
+print_config() {
+ local -a tar_opts=()
+
+ resolve_tar_opts tar_opts
+
+ print_shell_assignment CONFIG_SOURCE "${PHOTOALBUM_CONFIG_SOURCE:-}"
+ print_shell_assignment INCOMING_DIR "$INCOMING_DIR"
+ print_shell_assignment DIST_DIR "$DIST_DIR"
+ print_shell_assignment TEMPLATE_DIR "$TEMPLATE_DIR"
+ print_shell_assignment TITLE "$TITLE"
+ print_shell_assignment HEIGHT "${HEIGHT:-}"
+ print_shell_assignment THUMBHEIGHT "$THUMBHEIGHT"
+ print_shell_assignment MAXPREVIEWS "$MAXPREVIEWS"
+ print_shell_assignment SHUFFLE "${SHUFFLE:-no}"
+ print_shell_assignment TARBALL_INCLUDE "${TARBALL_INCLUDE:-no}"
+ print_shell_assignment TARBALL_SUFFIX "${TARBALL_SUFFIX:-.tar}"
+ print_shell_array_assignment TAR_OPTS "${tar_opts[@]}"
+ print_shell_assignment ORIGINAL_BASEPATH "${ORIGINAL_BASEPATH:-}"
+}
+
existing_parent_dir() {
local -r path="$1"; shift
local existing_parent
@@ -1216,6 +1255,30 @@ validate_generation_config() {
fi
}
+validate_print_config() {
+ local required_var
+ local -a required_vars=(
+ TITLE
+ THUMBHEIGHT
+ MAXPREVIEWS
+ INCOMING_DIR
+ DIST_DIR
+ TEMPLATE_DIR
+ )
+ local -a tar_opts=()
+
+ for required_var in "${required_vars[@]}"; do
+ require_config_var "$required_var"
+ done
+
+ validate_optional_positive_integer_config_var HEIGHT
+ validate_positive_integer_config_var THUMBHEIGHT
+ validate_positive_integer_config_var MAXPREVIEWS
+ validate_yes_no_config_var SHUFFLE
+ validate_yes_no_config_var TARBALL_INCLUDE
+ resolve_tar_opts tar_opts
+}
+
main() {
local action=''
local config_file=''
@@ -1309,7 +1372,7 @@ main() {
--quiet)
PHOTOALBUM_OUTPUT_MODE=quiet
;;
- --version|--init|--clean|--generate|--dry-run)
+ --version|--init|--clean|--generate|--dry-run|--print-config)
if [ -n "$action" ]; then
usage
exit 1
@@ -1341,7 +1404,7 @@ main() {
init_config
;;
- --clean|--generate|--dry-run)
+ --clean|--generate|--dry-run|--print-config)
rc_file="$(resolve_config_file "$config_file")"
if [ ! -f "$rc_file" ]; then
@@ -1353,11 +1416,13 @@ main() {
apply_cli_overrides
PHOTOALBUM_CONFIG_SOURCE="$rc_file"
export PHOTOALBUM_CONFIG_SOURCE
- log_verbose "Selected config file: $rc_file"
- log_verbose "Effective incoming directory: ${INCOMING_DIR:-}"
- log_verbose "Effective output directory: ${DIST_DIR:-}"
- log_verbose "Effective template directory: ${TEMPLATE_DIR:-}"
- log_verbose "Effective tarball setting: ${TARBALL_INCLUDE:-no}"
+ if [ "$action" != --print-config ]; then
+ log_verbose "Selected config file: $rc_file"
+ log_verbose "Effective incoming directory: ${INCOMING_DIR:-}"
+ log_verbose "Effective output directory: ${DIST_DIR:-}"
+ log_verbose "Effective template directory: ${TEMPLATE_DIR:-}"
+ log_verbose "Effective tarball setting: ${TARBALL_INCLUDE:-no}"
+ fi
case "$action" in
--clean)
@@ -1376,6 +1441,10 @@ main() {
validate_generation_config no
dry_run
;;
+ --print-config)
+ validate_print_config
+ print_config
+ ;;
esac
;;
*)
diff --git a/src/photoalbum.sh b/src/photoalbum.sh
index e2beffb..1f33ea2 100755
--- a/src/photoalbum.sh
+++ b/src/photoalbum.sh
@@ -13,6 +13,7 @@ usage() {
Usage:
$0 --generate [--config PATH] [OPTIONS]
$0 --dry-run [--config PATH] [OPTIONS]
+ $0 --print-config [--config PATH] [OPTIONS]
$0 --clean [--config PATH] [OPTIONS]
$0 --version
$0 --init
@@ -840,6 +841,44 @@ dry_run() {
fi
}
+print_shell_assignment() {
+ local -r name="$1"; shift
+ local -r value="$1"; shift
+
+ printf '%s=%q\n' "$name" "$value"
+}
+
+print_shell_array_assignment() {
+ local -r name="$1"; shift
+ local value
+
+ printf '%s=(' "$name"
+ for value in "$@"; do
+ printf ' %q' "$value"
+ done
+ printf ' )\n'
+}
+
+print_config() {
+ local -a tar_opts=()
+
+ resolve_tar_opts tar_opts
+
+ print_shell_assignment CONFIG_SOURCE "${PHOTOALBUM_CONFIG_SOURCE:-}"
+ print_shell_assignment INCOMING_DIR "$INCOMING_DIR"
+ print_shell_assignment DIST_DIR "$DIST_DIR"
+ print_shell_assignment TEMPLATE_DIR "$TEMPLATE_DIR"
+ print_shell_assignment TITLE "$TITLE"
+ print_shell_assignment HEIGHT "${HEIGHT:-}"
+ print_shell_assignment THUMBHEIGHT "$THUMBHEIGHT"
+ print_shell_assignment MAXPREVIEWS "$MAXPREVIEWS"
+ print_shell_assignment SHUFFLE "${SHUFFLE:-no}"
+ print_shell_assignment TARBALL_INCLUDE "${TARBALL_INCLUDE:-no}"
+ print_shell_assignment TARBALL_SUFFIX "${TARBALL_SUFFIX:-.tar}"
+ print_shell_array_assignment TAR_OPTS "${tar_opts[@]}"
+ print_shell_assignment ORIGINAL_BASEPATH "${ORIGINAL_BASEPATH:-}"
+}
+
existing_parent_dir() {
local -r path="$1"; shift
local existing_parent
@@ -1216,6 +1255,30 @@ validate_generation_config() {
fi
}
+validate_print_config() {
+ local required_var
+ local -a required_vars=(
+ TITLE
+ THUMBHEIGHT
+ MAXPREVIEWS
+ INCOMING_DIR
+ DIST_DIR
+ TEMPLATE_DIR
+ )
+ local -a tar_opts=()
+
+ for required_var in "${required_vars[@]}"; do
+ require_config_var "$required_var"
+ done
+
+ validate_optional_positive_integer_config_var HEIGHT
+ validate_positive_integer_config_var THUMBHEIGHT
+ validate_positive_integer_config_var MAXPREVIEWS
+ validate_yes_no_config_var SHUFFLE
+ validate_yes_no_config_var TARBALL_INCLUDE
+ resolve_tar_opts tar_opts
+}
+
main() {
local action=''
local config_file=''
@@ -1309,7 +1372,7 @@ main() {
--quiet)
PHOTOALBUM_OUTPUT_MODE=quiet
;;
- --version|--init|--clean|--generate|--dry-run)
+ --version|--init|--clean|--generate|--dry-run|--print-config)
if [ -n "$action" ]; then
usage
exit 1
@@ -1341,7 +1404,7 @@ main() {
init_config
;;
- --clean|--generate|--dry-run)
+ --clean|--generate|--dry-run|--print-config)
rc_file="$(resolve_config_file "$config_file")"
if [ ! -f "$rc_file" ]; then
@@ -1353,11 +1416,13 @@ main() {
apply_cli_overrides
PHOTOALBUM_CONFIG_SOURCE="$rc_file"
export PHOTOALBUM_CONFIG_SOURCE
- log_verbose "Selected config file: $rc_file"
- log_verbose "Effective incoming directory: ${INCOMING_DIR:-}"
- log_verbose "Effective output directory: ${DIST_DIR:-}"
- log_verbose "Effective template directory: ${TEMPLATE_DIR:-}"
- log_verbose "Effective tarball setting: ${TARBALL_INCLUDE:-no}"
+ if [ "$action" != --print-config ]; then
+ log_verbose "Selected config file: $rc_file"
+ log_verbose "Effective incoming directory: ${INCOMING_DIR:-}"
+ log_verbose "Effective output directory: ${DIST_DIR:-}"
+ log_verbose "Effective template directory: ${TEMPLATE_DIR:-}"
+ log_verbose "Effective tarball setting: ${TARBALL_INCLUDE:-no}"
+ fi
case "$action" in
--clean)
@@ -1376,6 +1441,10 @@ main() {
validate_generation_config no
dry_run
;;
+ --print-config)
+ validate_print_config
+ print_config
+ ;;
esac
;;
*)
diff --git a/tests/cli.sh b/tests/cli.sh
index 590afa4..26470e6 100755
--- a/tests/cli.sh
+++ b/tests/cli.sh
@@ -752,6 +752,288 @@ test_repeated_output_flags_use_last_value() {
test::teardown
}
+test_print_config_reflects_defaults() {
+ local expected
+ local output
+
+ test::setup
+
+ output=$(
+ cd "$TEST_TMPDIR"
+ "$TEST_PHOTOALBUM" \
+ --print-config \
+ --config "$TEST_REPO_ROOT/src/photoalbum.default.conf"
+ )
+ expected=$(cat <<EOF
+CONFIG_SOURCE=$TEST_REPO_ROOT/src/photoalbum.default.conf
+INCOMING_DIR=$TEST_TMPDIR/incoming
+DIST_DIR=$TEST_TMPDIR/dist
+TEMPLATE_DIR=/usr/share/photoalbum/templates/default
+TITLE=A\\ simple\\ Photoalbum
+HEIGHT=1200
+THUMBHEIGHT=300
+MAXPREVIEWS=40
+SHUFFLE=no
+TARBALL_INCLUDE=yes
+TARBALL_SUFFIX=.tar
+TAR_OPTS=( -c )
+ORIGINAL_BASEPATH=''
+EOF
+)
+
+ test "$output" = "$expected"
+ test::teardown
+}
+
+test_print_config_reads_selected_config() {
+ local config_file
+ local expected
+ local output
+
+ test::setup
+ config_file="$TEST_TMPDIR/custom.conf"
+ test::write_album_config \
+ "$config_file" "$TEST_TMPDIR/custom-incoming" \
+ "$TEST_TMPDIR/custom-dist" 'Selected config' 7
+ printf 'SHUFFLE=yes\n' >> "$config_file"
+
+ output=$(
+ cd "$TEST_TMPDIR"
+ "$TEST_PHOTOALBUM" --print-config --config "$config_file"
+ )
+ expected=$(cat <<EOF
+CONFIG_SOURCE=$config_file
+INCOMING_DIR=$TEST_TMPDIR/custom-incoming
+DIST_DIR=$TEST_TMPDIR/custom-dist
+TEMPLATE_DIR=$TEST_REPO_ROOT/share/templates/default
+TITLE=Selected\\ config
+HEIGHT=120
+THUMBHEIGHT=30
+MAXPREVIEWS=7
+SHUFFLE=yes
+TARBALL_INCLUDE=no
+TARBALL_SUFFIX=.tar
+TAR_OPTS=( -c )
+ORIGINAL_BASEPATH=''
+EOF
+)
+
+ test "$output" = "$expected"
+ test::teardown
+}
+
+test_print_config_reads_current_directory_config() {
+ local expected
+ local output
+
+ test::setup
+ test::write_album_config \
+ "$TEST_TMPDIR/photoalbum.conf" "$TEST_TMPDIR/incoming" \
+ "$TEST_TMPDIR/dist" 'Current directory config' 8
+
+ output=$(
+ cd "$TEST_TMPDIR"
+ "$TEST_PHOTOALBUM" --print-config
+ )
+ expected=$(cat <<EOF
+CONFIG_SOURCE=./photoalbum.conf
+INCOMING_DIR=$TEST_TMPDIR/incoming
+DIST_DIR=$TEST_TMPDIR/dist
+TEMPLATE_DIR=$TEST_REPO_ROOT/share/templates/default
+TITLE=Current\\ directory\\ config
+HEIGHT=120
+THUMBHEIGHT=30
+MAXPREVIEWS=8
+SHUFFLE=no
+TARBALL_INCLUDE=no
+TARBALL_SUFFIX=.tar
+TAR_OPTS=( -c )
+ORIGINAL_BASEPATH=''
+EOF
+)
+
+ test "$output" = "$expected"
+ test::teardown
+}
+
+test_print_config_applies_cli_overrides_without_writes() {
+ local config_file
+ local dist_dir
+ local expected
+ local fake_bin
+ local forbidden_log
+ local output
+
+ test::setup
+ fake_bin="$TEST_TMPDIR/bin"
+ config_file="$TEST_TMPDIR/photoalbum.conf"
+ dist_dir="$TEST_TMPDIR/cli-dist"
+ forbidden_log="$TEST_TMPDIR/forbidden-tools.log"
+
+ test::install_failing_generation_tools "$fake_bin"
+ test::write_album_config \
+ "$config_file" "$TEST_TMPDIR/config-incoming" \
+ "$TEST_TMPDIR/config-dist" 'Config title' 40
+
+ output=$(
+ cd "$TEST_TMPDIR"
+ PATH="$fake_bin:$PATH" \
+ TEST_FORBIDDEN_TOOL_LOG="$forbidden_log" \
+ "$TEST_PHOTOALBUM" \
+ --print-config \
+ --incoming "$TEST_TMPDIR/cli-incoming" \
+ --dist "$dist_dir" \
+ --template "$TEST_TMPDIR/cli-template" \
+ --title 'CLI title' \
+ --height 456 \
+ --thumbheight 45 \
+ --maxpreviews 9 \
+ --shuffle \
+ --tarball
+ )
+ expected=$(cat <<EOF
+CONFIG_SOURCE=./photoalbum.conf
+INCOMING_DIR=$TEST_TMPDIR/cli-incoming
+DIST_DIR=$dist_dir
+TEMPLATE_DIR=$TEST_TMPDIR/cli-template
+TITLE=CLI\\ title
+HEIGHT=456
+THUMBHEIGHT=45
+MAXPREVIEWS=9
+SHUFFLE=yes
+TARBALL_INCLUDE=yes
+TARBALL_SUFFIX=.tar
+TAR_OPTS=( -c )
+ORIGINAL_BASEPATH=''
+EOF
+)
+
+ test "$output" = "$expected"
+ test::assert_path_absent "$dist_dir"
+ test::assert_path_absent "$TEST_TMPDIR/config-dist"
+ test::assert_path_absent "$forbidden_log"
+ test::assert_no_staging_dirs "$TEST_TMPDIR"
+ test::teardown
+}
+
+test_print_config_applies_negative_cli_overrides() {
+ local config_file
+ local output
+
+ test::setup
+ config_file="$TEST_TMPDIR/photoalbum.conf"
+ test::write_album_config \
+ "$config_file" "$TEST_TMPDIR/incoming" "$TEST_TMPDIR/dist" \
+ 'Negative overrides' 40
+ {
+ printf 'SHUFFLE=yes\n'
+ printf 'TARBALL_INCLUDE=yes\n'
+ } >> "$config_file"
+
+ output=$(
+ cd "$TEST_TMPDIR"
+ "$TEST_PHOTOALBUM" --print-config --no-shuffle --no-tarball
+ )
+
+ test::assert_contains 'SHUFFLE=no' "$output"
+ test::assert_contains 'TARBALL_INCLUDE=no' "$output"
+ test::teardown
+}
+
+test_print_config_normalizes_scalar_and_array_tar_opts() {
+ local array_config
+ local array_output
+ local scalar_config
+ local scalar_output
+
+ test::setup
+ scalar_config="$TEST_TMPDIR/scalar.conf"
+ array_config="$TEST_TMPDIR/array.conf"
+ test::write_album_config \
+ "$scalar_config" "$TEST_TMPDIR/incoming" "$TEST_TMPDIR/dist" \
+ 'Scalar tar opts' 40
+ {
+ printf 'TARBALL_INCLUDE=yes\n'
+ printf 'TAR_OPTS=%q\n' '--sort=name --mtime=@0 -c'
+ } >> "$scalar_config"
+ test::write_album_config \
+ "$array_config" "$TEST_TMPDIR/incoming" "$TEST_TMPDIR/dist" \
+ 'Array tar opts' 40
+ printf 'TAR_OPTS=(--sort=name --mtime=@0 -c)\n' >> "$array_config"
+
+ scalar_output=$("$TEST_PHOTOALBUM" --print-config --config "$scalar_config")
+ array_output=$("$TEST_PHOTOALBUM" --print-config --config "$array_config")
+
+ test::assert_contains \
+ 'TAR_OPTS=( --sort=name --mtime=@0 -c )' \
+ "$scalar_output"
+ test::assert_contains \
+ 'TAR_OPTS=( --sort=name --mtime=@0 -c )' \
+ "$array_output"
+ test::teardown
+}
+
+test_print_config_quiet_and_verbose_keep_machine_output() {
+ local config_file
+ local plain_output
+ local quiet_output
+ local verbose_output
+
+ test::setup
+ config_file="$TEST_TMPDIR/photoalbum.conf"
+ test::write_album_config \
+ "$config_file" "$TEST_TMPDIR/incoming" "$TEST_TMPDIR/dist" \
+ 'Output mode config' 40
+
+ plain_output=$(
+ cd "$TEST_TMPDIR"
+ "$TEST_PHOTOALBUM" --print-config
+ )
+ quiet_output=$(
+ cd "$TEST_TMPDIR"
+ "$TEST_PHOTOALBUM" --quiet --print-config
+ )
+ verbose_output=$(
+ cd "$TEST_TMPDIR"
+ "$TEST_PHOTOALBUM" --verbose --print-config
+ )
+
+ test "$quiet_output" = "$plain_output"
+ test "$verbose_output" = "$plain_output"
+ test::assert_not_contains 'Verbose:' "$verbose_output"
+ test::teardown
+}
+
+test_print_config_validates_basic_values_without_generation_preflight() {
+ local config_file
+ local output
+
+ test::setup
+ config_file="$TEST_TMPDIR/photoalbum.conf"
+ test::write_album_config \
+ "$config_file" "$TEST_TMPDIR/missing-incoming" \
+ "$TEST_TMPDIR/missing-parent/dist" 'Printable missing paths' 40
+ printf 'TEMPLATE_DIR=%q\n' "$TEST_TMPDIR/missing-template" >> "$config_file"
+
+ output=$(
+ cd "$TEST_TMPDIR"
+ "$TEST_PHOTOALBUM" --print-config
+ )
+ test::assert_contains "INCOMING_DIR=$TEST_TMPDIR/missing-incoming" "$output"
+ test::assert_contains "DIST_DIR=$TEST_TMPDIR/missing-parent/dist" "$output"
+ test::assert_contains "TEMPLATE_DIR=$TEST_TMPDIR/missing-template" "$output"
+
+ printf 'MAXPREVIEWS=not-a-number\n' >> "$config_file"
+ output=$(
+ cd "$TEST_TMPDIR"
+ test::capture_failure_output "$TEST_PHOTOALBUM" --print-config
+ )
+ test::assert_contains 'ERROR: MAXPREVIEWS must be a positive integer' \
+ "$output"
+ test::assert_path_absent "$TEST_TMPDIR/missing-parent"
+ test::teardown
+}
+
test_dry_run_reports_cli_overrides_without_writes() {
local config_file
local dist_dir
@@ -1686,6 +1968,8 @@ test_unknown_options_and_conflicting_actions_fail() {
"$TEST_PHOTOALBUM" --generate --init
test::assert_failure 'clean/version conflict is rejected' \
"$TEST_PHOTOALBUM" --clean --version
+ test::assert_failure 'print-config/dry-run conflict is rejected' \
+ "$TEST_PHOTOALBUM" --print-config --dry-run
}
test_empty_args_fail() {
@@ -1781,6 +2065,30 @@ main() {
'repeated output flags use last value' \
test_repeated_output_flags_use_last_value
test::run_case \
+ '--print-config reflects defaults' \
+ test_print_config_reflects_defaults
+ test::run_case \
+ '--print-config reads selected config' \
+ test_print_config_reads_selected_config
+ test::run_case \
+ '--print-config reads current directory config' \
+ test_print_config_reads_current_directory_config
+ test::run_case \
+ '--print-config applies CLI overrides without writes' \
+ test_print_config_applies_cli_overrides_without_writes
+ test::run_case \
+ '--print-config applies negative CLI overrides' \
+ test_print_config_applies_negative_cli_overrides
+ test::run_case \
+ '--print-config normalizes scalar and array TAR_OPTS' \
+ test_print_config_normalizes_scalar_and_array_tar_opts
+ test::run_case \
+ '--print-config quiet and verbose keep machine output' \
+ test_print_config_quiet_and_verbose_keep_machine_output
+ test::run_case \
+ '--print-config validates values without generation preflight' \
+ test_print_config_validates_basic_values_without_generation_preflight
+ test::run_case \
'--dry-run reports CLI overrides without writes' \
test_dry_run_reports_cli_overrides_without_writes
test::run_case \