The audit that followed "some things in the settings app don't work". Sixty-five settings reach the compositor and five of them were checked against it. The rest were covered only by tests that read source text, which is exactly where a dead setting hides: the write no-ops, nothing fails, nothing logs, and the row simply does nothing. The sweep drives each setting through SystemSettings.commitPreference -- the entry point a settings row uses -- flips it to a value it does not hold, reads it back from the live compositor, and puts it straight back before touching the next one. Settings Panama stores itself get the same treatment against the store, since a value that fails to persist is the same dead row from the outside. Result: 61 of 63 compositor settings verified against the running compositor, and 51 stored settings round-tripped. No failures. The breakage was confined to the Applications page, which is fixed. Proven able to fail before being trusted: with commitPreference stubbed to return true without applying, 61 settings are reported; with the store stubbed to return nothing, 51 are. A one-second settle window keeps a slow read from being reported as a dead write, which it briefly was. Also here: control-center-contract asserted the literal margin expression that made the panel hang 38 pixels below the bar, so the contract and the code agreed and the bug was invisible to both. And settings-page-registry-contract is deleted -- settings-nav-contract already checked those files and more. It would have caught the Storage page omission if I had run the suite instead of a hand-picked subset. Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L
213 lines
9.4 KiB
Bash
Executable File
213 lines
9.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
source_config_path="$project_root/config/dot/quickshell"
|
|
quicksettings_path="$source_config_path/modules/quicksettings"
|
|
state_home="$(mktemp -d /tmp/panama-control-center-ui.XXXXXX)"
|
|
config_path="$state_home/quickshell"
|
|
helper_log="$state_home/home-helper.log"
|
|
shell_log="$state_home/quickshell.log"
|
|
|
|
fail() {
|
|
printf 'Control Center contract: %s\n' "$1" >&2
|
|
exit 1
|
|
}
|
|
|
|
qs_for_test() {
|
|
QS_CONFIG_PATH="$config_path" XDG_STATE_HOME="$state_home" \
|
|
QS_DISABLE_CRASH_HANDLER=1 \
|
|
PANAMA_HOME_HELPER_LOG="$helper_log" \
|
|
qs -p "$config_path" "$@"
|
|
}
|
|
|
|
stop_test_shell() {
|
|
qs_for_test kill >/dev/null 2>&1 || true
|
|
for _ in $(seq 1 80); do
|
|
if ! qs_for_test list 2>/dev/null | rg '^Instance ' >/dev/null \
|
|
&& ! qs_for_test ipc show >/dev/null 2>&1; then
|
|
return 0
|
|
fi
|
|
sleep 0.1
|
|
done
|
|
return 1
|
|
}
|
|
|
|
cleanup() {
|
|
qs_for_test ipc call quicksettings close >/dev/null 2>&1 || true
|
|
qs_for_test ipc call kdeconnect reset >/dev/null 2>&1 || true
|
|
qs_for_test ipc call home-assistant reset >/dev/null 2>&1 || true
|
|
if stop_test_shell; then
|
|
rm -rf "$state_home"
|
|
else
|
|
printf 'Control Center contract: branch shell did not stop; retained %s\n' \
|
|
"$state_home" >&2
|
|
fi
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
start_test_shell() {
|
|
stop_test_shell || fail 'pre-existing branch shell did not stop cleanly'
|
|
for _attempt in 1 2; do
|
|
qs_for_test --daemonize >"$shell_log" 2>&1
|
|
for _ in $(seq 1 80); do
|
|
if qs_for_test ipc show 2>/dev/null | rg '^target quicksettings$' >/dev/null; then
|
|
return
|
|
fi
|
|
sleep 0.1
|
|
done
|
|
stop_test_shell || fail 'failed branch-shell attempt did not stop cleanly'
|
|
done
|
|
sed -n '1,200p' "$shell_log" >&2
|
|
fail 'isolated branch shell did not start'
|
|
}
|
|
|
|
rg -Fq 'readonly property int controlCenterWidth: 430' \
|
|
"$source_config_path/config/Theme.qml" \
|
|
|| fail 'approved Control Center width is missing'
|
|
rg -Fq 'readonly property int controlCenterTopGap: 2' \
|
|
"$source_config_path/config/Theme.qml" \
|
|
|| fail 'approved top attachment is missing'
|
|
# The margin is the GAP alone. This used to assert the bar height plus the gap,
|
|
# which is what the code said and what made the panel open 38 pixels below a bar
|
|
# it was written to sit 2 pixels under: an exclusiveZone of 0 already places the
|
|
# surface below the bar's reserved space, so naming the bar height again counted
|
|
# it twice. The contract agreed with the code and so the bug was invisible to
|
|
# both. layer-margin-contract now holds that rule for every surface.
|
|
rg -Fq 'margins.top: Theme.controlCenterTopGap' \
|
|
"$quicksettings_path/QuickSettings.qml" \
|
|
|| fail 'Control Center is not tightly attached to the bar'
|
|
rg -Fq 'implicitWidth: Theme.controlCenterWidth' \
|
|
"$quicksettings_path/QuickSettings.qml" \
|
|
|| fail 'Control Center window does not use its geometry token'
|
|
rg -Fq 'HomeControls' \
|
|
"$quicksettings_path/QuickSettingsPanel.qml" \
|
|
|| fail 'Home controls are not mounted'
|
|
rg -Fq 'PhoneControls' \
|
|
"$quicksettings_path/QuickSettingsPanel.qml" \
|
|
|| fail 'Phone controls are not mounted'
|
|
rg -Fq 'visible: KdeConnect.phoneReachable' \
|
|
"$source_config_path/modules/bar/StatusCluster.qml" \
|
|
|| fail 'reachable phone state is absent from the bar'
|
|
|
|
for component in ControlSectionHeader HomeBrightnessSlider HomeControls HomeTile PhoneActions PhoneControls RecentExchange; do
|
|
[[ -f "$quicksettings_path/$component.qml" ]] \
|
|
|| fail "$component is missing"
|
|
done
|
|
|
|
[[ "$(rg -c 'id: "(share|clipboard|ring|messages)"' "$quicksettings_path/PhoneActions.qml")" -eq 4 ]] \
|
|
|| fail 'Phone controls do not expose four stable action models'
|
|
rg -Fq 'columns: 4' "$quicksettings_path/PhoneControls.qml" \
|
|
|| fail 'Phone actions are not arranged in four equal columns'
|
|
if rg -Fq '.filter(' "$quicksettings_path/PhoneActions.qml"; then
|
|
fail 'Phone action columns change when a KDE capability is unavailable'
|
|
fi
|
|
rg -Fq 'SystemSettings.bluebubblesAvailable' "$quicksettings_path/PhoneControls.qml" \
|
|
|| fail 'Messages action is not independently enabled by BlueBubbles'
|
|
rg -Fq 'KdeConnect.phoneReachable' "$quicksettings_path/PhoneControls.qml" \
|
|
|| fail 'KDE action reachability behavior is missing'
|
|
|
|
[[ -f "$quicksettings_path/qmldir" ]] \
|
|
|| fail 'quick-settings module manifest is missing'
|
|
rg -Fq 'HomeBrightnessSlider 1.0 HomeBrightnessSlider.qml' \
|
|
"$quicksettings_path/qmldir" \
|
|
|| fail 'brightness slider is not registered in the quick-settings module'
|
|
rg -Fq 'PhoneActions 1.0 PhoneActions.qml' \
|
|
"$quicksettings_path/qmldir" \
|
|
|| fail 'Phone actions model is not registered in the quick-settings module'
|
|
|
|
[[ "$(rg -c '^[[:space:]]*columns: 2$' "$quicksettings_path/HomeControls.qml")" -ge 2 ]] \
|
|
|| fail 'resting and expanded Home shelves are not both two-column grids'
|
|
rg -Fq 'model: HomeAssistant.visibleEntities' "$quicksettings_path/HomeControls.qml" \
|
|
|| fail 'resting Home shelf does not use the first four selected lights'
|
|
rg -Fq 'model: HomeAssistant.selectedEntities' "$quicksettings_path/HomeControls.qml" \
|
|
|| fail 'expanded Home shelf does not use every selected light'
|
|
rg -Fq 'HomeAssistant.pendingFor(' "$quicksettings_path/HomeControls.qml" \
|
|
|| fail 'Home tiles do not receive per-light pending brightness'
|
|
rg -Fq 'HomeAssistant.setBrightness(' "$quicksettings_path/HomeControls.qml" \
|
|
|| fail 'Home brightness commits are not wired to the service'
|
|
rg -Fq 'ShellState.openSettings("home-phone")' "$quicksettings_path/HomeControls.qml" \
|
|
|| fail 'Manage in Settings does not open Home & Phone'
|
|
|
|
rg -Fq 'signal previewChanged(int value)' "$quicksettings_path/HomeBrightnessSlider.qml" \
|
|
|| fail 'brightness slider has no preview contract'
|
|
rg -Fq 'signal committed(int value)' "$quicksettings_path/HomeBrightnessSlider.qml" \
|
|
|| fail 'brightness slider has no release-commit contract'
|
|
rg -Fq 'onReleased: event =>' "$quicksettings_path/HomeBrightnessSlider.qml" \
|
|
|| fail 'brightness slider does not route pointer release through its interaction state'
|
|
rg -Fq 'root.releasePointerInteraction();' "$quicksettings_path/HomeBrightnessSlider.qml" \
|
|
|| fail 'brightness slider release is not wired to one-shot commit semantics'
|
|
rg -Fq 'onCanceled: root.cancelPointerInteraction()' "$quicksettings_path/HomeBrightnessSlider.qml" \
|
|
|| fail 'brightness slider does not restore its external value when a Flickable steals the pointer'
|
|
if rg -Fq 'preventStealing: true' "$quicksettings_path/HomeBrightnessSlider.qml"; then
|
|
fail 'brightness slider blocks the expanded shelf from stealing vertical drags'
|
|
fi
|
|
rg -Fq 'onWheel:' "$quicksettings_path/HomeBrightnessSlider.qml" \
|
|
|| fail 'brightness slider has no wheel commit path'
|
|
rg -Fq 'onCommitted: value => root.brightnessRequested(value)' "$quicksettings_path/HomeTile.qml" \
|
|
|| fail 'Home tile does not forward the slider release commit'
|
|
rg -Fq 'accessibleName: root.entity.name + " brightness"' "$quicksettings_path/HomeTile.qml" \
|
|
|| fail 'Home tile does not give its dimmer an accessory-specific accessible name'
|
|
|
|
cp -a "$source_config_path" "$config_path"
|
|
: >"$helper_log"
|
|
cat >"$config_path/scripts/panama-home-assistant" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
printf '%s\n' "$*" >>"$PANAMA_HOME_HELPER_LOG"
|
|
case "${1:-}" in
|
|
catalog)
|
|
printf '%s\n' '{"ok":false,"configured":false,"entities":[],"legacyEntityIds":[],"error":"test-helper"}'
|
|
;;
|
|
toggle|brightness)
|
|
printf '%s\n' '{"ok":false,"error":"contract-action-forbidden"}'
|
|
exit 73
|
|
;;
|
|
esac
|
|
EOF
|
|
chmod +x "$config_path/scripts/panama-home-assistant"
|
|
|
|
start_test_shell
|
|
|
|
qs_for_test ipc call home-assistant fixture ready >/dev/null
|
|
home_ready="$(qs_for_test ipc call home-assistant status)"
|
|
jq -e '.fixture == true and .visibleCount == 4 and .configuredCount == 7' \
|
|
<<<"$home_ready" >/dev/null \
|
|
|| fail 'Home fixture does not expose four resting and seven expanded accessories'
|
|
|
|
qs_for_test ipc call kdeconnect fixture reachable >/dev/null
|
|
qs_for_test ipc call quicksettings open >/dev/null
|
|
|
|
hyprctl layers | rg -q 'namespace: qs-popover-quicksettings' \
|
|
|| fail 'Control Center layer did not map'
|
|
jq -e '.open == true and .expandedSection == ""' \
|
|
<<<"$(qs_for_test ipc call quicksettings status)" >/dev/null \
|
|
|| fail 'Control Center did not open in its resting state'
|
|
|
|
qs_for_test ipc call quicksettings section home >/dev/null
|
|
jq -e '.open == true and .expandedSection == "home"' \
|
|
<<<"$(qs_for_test ipc call quicksettings status)" >/dev/null \
|
|
|| fail 'Home section did not expand'
|
|
|
|
qs_for_test ipc call quicksettings section phone >/dev/null
|
|
jq -e '.open == true and .expandedSection == "phone"' \
|
|
<<<"$(qs_for_test ipc call quicksettings status)" >/dev/null \
|
|
|| fail 'Phone did not replace Home as the expanded section'
|
|
|
|
qs_for_test ipc call quicksettings section phone >/dev/null
|
|
jq -e '.open == true and .expandedSection == ""' \
|
|
<<<"$(qs_for_test ipc call quicksettings status)" >/dev/null \
|
|
|| fail 'expanded Phone section did not collapse'
|
|
|
|
if rg '^(toggle|brightness)( |$)' "$helper_log" >&2; then
|
|
fail 'Control Center contract attempted a real Home action path'
|
|
fi
|
|
|
|
trap - EXIT
|
|
cleanup
|
|
[[ ! -e "$state_home" ]] \
|
|
|| fail 'temporary Control Center state was not removed after shell exit'
|
|
printf 'Control Center contract: PASS\n'
|