#!/bin/bash # # Copyright (C) 2026 Danilo M. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The one runnable check for kdeconnect-state.sh. It puts a stub qdbus6 on # PATH and runs the real script against it, so nothing here touches the live # daemon and the whole thing runs in milliseconds. # # Fixture: idA a reachable phone with a battery, idB a laptop whose name # contains a tab and which has no battery plugin, idC an unpaired phone with # an incoming pairing request and a verification key. # # Usage: ./test-kdeconnect-state.sh (exit 0 = all passed) set -u here="$(cd "$(dirname "$0")" && pwd)" stub="$(mktemp -d)" trap 'rm -rf "$stub"' EXIT cat > "$stub/qdbus6" <<'STUB' #!/bin/bash path="$2"; m="$3"; a="$4"; b="$5" if [[ "${FAIL_DEVICES:-}" == 1 && "$m" == "org.kde.kdeconnect.daemon.devices" ]]; then exit 1 fi if [[ "${ZERO_DEVICES:-}" == 1 && "$m" == "org.kde.kdeconnect.daemon.devices" ]]; then exit 0 fi case "$path:$m" in "/modules/kdeconnect:org.kde.kdeconnect.daemon.devices") printf '%s\n' idA idB idC ;; "/modules/kdeconnect:org.freedesktop.DBus.Properties.Get") if [[ "$a" == "org.kde.kdeconnect.daemon" && "$b" == "pairingRequests" ]]; then [[ "${ZERO_DEVICES:-}" == 1 ]] || printf '%s\n' idC fi ;; "/modules/kdeconnect/devices/idA:org.kde.kdeconnect.device.name") printf 'Pixel 6 Pro\n' ;; "/modules/kdeconnect/devices/idA:org.kde.kdeconnect.device.type") printf 'phone\n' ;; "/modules/kdeconnect/devices/idA:org.kde.kdeconnect.device.isPaired") printf 'true\n' ;; "/modules/kdeconnect/devices/idA:org.kde.kdeconnect.device.isReachable") printf 'true\n' ;; "/modules/kdeconnect/devices/idA:org.kde.kdeconnect.device.isPairRequested") printf 'false\n' ;; "/modules/kdeconnect/devices/idA:org.kde.kdeconnect.device.isPairRequestedByPeer") printf 'false\n' ;; "/modules/kdeconnect/devices/idA/battery:org.freedesktop.DBus.Properties.Get") [[ "$b" == charge ]] && printf '50\n' || printf 'true\n' ;; "/modules/kdeconnect/devices/idB:org.kde.kdeconnect.device.name") printf 'kali\tlaptop\n' ;; "/modules/kdeconnect/devices/idB:org.kde.kdeconnect.device.type") printf 'desktop\n' ;; "/modules/kdeconnect/devices/idB:org.kde.kdeconnect.device.isPaired") printf 'true\n' ;; "/modules/kdeconnect/devices/idB:org.kde.kdeconnect.device.isReachable") printf 'false\n' ;; "/modules/kdeconnect/devices/idB:org.kde.kdeconnect.device.isPairRequested") printf 'false\n' ;; "/modules/kdeconnect/devices/idB:org.kde.kdeconnect.device.isPairRequestedByPeer") printf 'false\n' ;; "/modules/kdeconnect/devices/idB/battery:org.freedesktop.DBus.Properties.Get") exit 1 ;; "/modules/kdeconnect/devices/idC:org.kde.kdeconnect.device.name") printf 'New Phone\n' ;; "/modules/kdeconnect/devices/idC:org.kde.kdeconnect.device.type") printf 'phone\n' ;; "/modules/kdeconnect/devices/idC:org.kde.kdeconnect.device.isPaired") printf 'false\n' ;; "/modules/kdeconnect/devices/idC:org.kde.kdeconnect.device.isReachable") printf 'true\n' ;; "/modules/kdeconnect/devices/idC:org.kde.kdeconnect.device.isPairRequested") printf 'false\n' ;; "/modules/kdeconnect/devices/idC:org.kde.kdeconnect.device.isPairRequestedByPeer") printf 'true\n' ;; "/modules/kdeconnect/devices/idC:org.kde.kdeconnect.device.verificationKey") printf '1826C6D4\n' ;; "/modules/kdeconnect/devices/idC/battery:org.freedesktop.DBus.Properties.Get") exit 1 ;; esac STUB chmod +x "$stub/qdbus6" pass=0 fail=0 check() { local name="$1" want="$2" got="$3" if [[ "$want" == "$got" ]]; then pass=$((pass + 1)) else fail=$((fail + 1)) printf 'FAIL: %s\n want: %q\n got: %q\n' "$name" "$want" "$got" fi } # The full line protocol for the fixture. The name with a tab is one field # after sanitizing; the two battery-less devices leave the charge and # charging fields empty and zero respectively. want="$(printf 'request\tidC') $(printf 'device\tidA\tPixel 6 Pro\tphone\t1\t1\t0\t0\t\t50\t1') $(printf 'device\tidB\tkali laptop\tdesktop\t1\t0\t0\t0\t\t\t0') $(printf 'device\tidC\tNew Phone\tphone\t0\t1\t0\t1\t1826C6D4\t\t0')" got="$(PATH="$stub:$PATH" bash "$here/kdeconnect-state.sh")" check "the line protocol" "$want" "$got" # A daemon that is down is not an empty device list. got="$(PATH="$stub:$PATH" FAIL_DEVICES=1 bash "$here/kdeconnect-state.sh")" rc=$? check "a failed query prints nothing" "" "$got" check "a failed query exits non-zero" "1" "$([[ $rc -ne 0 ]] && echo 1 || echo 0)" # A reachable daemon with no devices is a valid empty list. got="$(PATH="$stub:$PATH" ZERO_DEVICES=1 bash "$here/kdeconnect-state.sh")" rc=$? check "zero devices prints nothing" "" "$got" check "zero devices exits zero" "0" "$rc" printf '\n%d passed, %d failed\n' "$pass" "$fail" [[ "$fail" -eq 0 ]]