mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 19:07:04 +01:00
Location/curfew goes to daemon_location.sh, the derived state files to daemon_state.sh, the app layer to daemon_apps.sh. All 23 functions moved verbatim -- nothing restructured, which matters more here than anywhere else in this session. focus_daemon.sh has five `while IFS= read -r pkg; do ... done <file` loops and EVERY body calls pm. Piping any of them in lets pm inherit and drain the loop's stdin, so it would process one package instead of all of them -- measured elsewhere in this repo as 1 of 54. That audit ran BEFORE the extraction, not after coverage came back short, and all five moved untouched with a note above them saying why. CURRENT_MODE and _CURFEW_TICK_CACHED are each written in both the entry script and a library, so both stay declared with main, same call as NET_BUILT in the curfew split. 110 assertions and 33 mutations, all killed. Two survived the first run and both were defects in my own tests: the whitelist and sysprotect exactness checks used a SUPERSTRING of a listed entry, which fails under grep -qF and grep -qxF alike and so proved nothing about which was in use. Two subjects are NOT at 100%, and the numbers are reported as measured: daemon_state.sh 67/67 = 100.00% daemon_location.sh 26/40 = 65.00% daemon_apps.sh 71/76 = 93.42% Both shortfalls are kcov attribution failures, shown to be artifacts rather than gaps. daemon_location.sh's missing lines are all inside the embedded awk Haversine; mutating the Earth radius and dropping the longitude term both fail the suite, and an isolated probe shows a one-line awk measuring 100% where the identical multi-line one measures 0%. Collapsing the formula to satisfy the tool would cost the readability of the only real mathematics in the repo, so it stays. daemon_apps.sh's five are the trailing `done <file` of the very loops described above. That is the same artifact piping fixed in curfew_net.sh, and it is exactly what must NOT be done here. Redirecting two of them from /dev/null fails the suite, so the lines run; all three are pinned in the mutation spec instead. Over-cap count 19 -> 18. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011w2Pj4Ek3ZNMQVYcFHgXDY
161 lines
4.3 KiB
Bash
Executable File
161 lines
4.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# lib/tests/daemon_libs_harness.sh — the fake device behind the three
|
|
# libraries split out of focus_daemon.sh.
|
|
#
|
|
# Sourced, not executed. All three drive the phone through real binaries — pm,
|
|
# dumpsys, cmd, date — so the stubs go on PATH.
|
|
#
|
|
# `date` is stubbed rather than mocked as a function because is_curfew_now
|
|
# calls it in a command substitution; a shell function would work here but
|
|
# would not survive the subject being run any other way, and the point of the
|
|
# midnight-wrap cases is to pin the clock precisely.
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
readonly SCRIPT_DIR
|
|
readonly PHONE_DIR="${SCRIPT_DIR}/../.."
|
|
|
|
PASS=0
|
|
FAIL=0
|
|
|
|
_t_pass() {
|
|
PASS=$((PASS + 1))
|
|
printf ' OK: %s\n' "$1"
|
|
}
|
|
|
|
_t_fail() {
|
|
FAIL=$((FAIL + 1))
|
|
printf ' FAIL: %s\n' "$1"
|
|
}
|
|
|
|
_t_eq() {
|
|
local want="$1" got="$2" what="$3"
|
|
if [[ "$got" == "$want" ]]; then
|
|
_t_pass "$what"
|
|
else
|
|
_t_fail "$what (want '${want}', got '${got}')"
|
|
fi
|
|
}
|
|
|
|
RUN="$(mktemp -d)"
|
|
trap 'rm -rf "${RUN}"' EXIT
|
|
mkdir -p "${RUN}/bin" "${RUN}/state" "${RUN}/dev"
|
|
|
|
readonly DEV="${RUN}/dev"
|
|
|
|
# --- stubs ------------------------------------------------------------------
|
|
|
|
# pm records every call and honours a per-package failure flag, so the
|
|
# "disable refused" branches are reachable.
|
|
cat >"${RUN}/bin/pm" <<'STUB'
|
|
#!/usr/bin/env bash
|
|
printf 'pm %s\n' "$*" >>"${DEV}/calls.log"
|
|
case "$1" in
|
|
list)
|
|
[[ -f "${DEV}/pm_list" ]] && cat "${DEV}/pm_list"
|
|
exit 0
|
|
;;
|
|
disable-user)
|
|
pkg="${*: -1}"
|
|
grep -qxF "${pkg}" "${DEV}/pm_undisableable" 2>/dev/null && exit 1
|
|
printf '%s\n' "${pkg}" >>"${DEV}/disabled"
|
|
exit 0
|
|
;;
|
|
enable)
|
|
pkg="${*: -1}"
|
|
grep -qxF "${pkg}" "${DEV}/pm_unenableable" 2>/dev/null && exit 1
|
|
printf '%s\n' "${pkg}" >>"${DEV}/enabled"
|
|
exit 0
|
|
;;
|
|
esac
|
|
exit 0
|
|
STUB
|
|
chmod +x "${RUN}/bin/pm"
|
|
|
|
cat >"${RUN}/bin/dumpsys" <<'STUB'
|
|
#!/usr/bin/env bash
|
|
printf 'dumpsys %s\n' "$*" >>"${DEV}/calls.log"
|
|
[[ -f "${DEV}/dumpsys_out" ]] && cat "${DEV}/dumpsys_out"
|
|
exit 0
|
|
STUB
|
|
chmod +x "${RUN}/bin/dumpsys"
|
|
|
|
cat >"${RUN}/bin/cmd" <<'STUB'
|
|
#!/usr/bin/env bash
|
|
printf 'cmd %s\n' "$*" >>"${DEV}/calls.log"
|
|
[[ -f "${DEV}/cmd_out" ]] && cat "${DEV}/cmd_out"
|
|
exit 0
|
|
STUB
|
|
chmod +x "${RUN}/bin/cmd"
|
|
|
|
# `date` answers from a pinned clock when one is set, so the curfew-window
|
|
# cases are deterministic rather than dependent on when the suite runs.
|
|
cat >"${RUN}/bin/date" <<'STUB'
|
|
#!/usr/bin/env bash
|
|
if [[ -f "${DEV}/now" && "$1" == "+%H%M" ]]; then
|
|
cat "${DEV}/now"
|
|
exit 0
|
|
fi
|
|
exec /usr/bin/date "$@"
|
|
STUB
|
|
chmod +x "${RUN}/bin/date"
|
|
|
|
export DEV
|
|
export PATH="${RUN}/bin:${PATH}"
|
|
|
|
# --- ambient definitions the libraries expect from the daemon --------------
|
|
|
|
log() { printf '%s\n' "$*" >>"${DEV}/log"; }
|
|
|
|
STATE_DIR="${RUN}/state"
|
|
STATUS_FILE="${RUN}/state/status.json"
|
|
MODE_FILE="${RUN}/state/mode"
|
|
DISABLED_APPS_FILE="${RUN}/state/disabled_apps.txt"
|
|
CURFEW_FORCE_FILE="${RUN}/state/curfew_force"
|
|
CURFEW_OVERRIDE_FILE="${RUN}/state/curfew_override"
|
|
NIGHT_CURFEW_ENABLED=1
|
|
NIGHT_CURFEW_START="2300"
|
|
NIGHT_CURFEW_END="0500"
|
|
WHITELIST="com.allowed.one com.allowed.two"
|
|
NIGHT_WHITELIST="com.night.only"
|
|
SYSTEM_NEVER_DISABLE="com.android."
|
|
BLOCKED_SYSTEM_APPS="com.android.browser"
|
|
RADIUS=100
|
|
|
|
# Written by init/enable/disable in the entry script and read by main, so it
|
|
# lives there; the harness stands in for that ownership.
|
|
CURRENT_MODE="normal"
|
|
_CURFEW_TICK_CACHED=""
|
|
_CURFEW_TICK_RESULT=0
|
|
|
|
# shellcheck source=../../daemon_location.sh
|
|
. "${PHONE_DIR}/daemon_location.sh"
|
|
# shellcheck source=../../daemon_state.sh
|
|
. "${PHONE_DIR}/daemon_state.sh"
|
|
# shellcheck source=../../daemon_apps.sh
|
|
. "${PHONE_DIR}/daemon_apps.sh"
|
|
|
|
# --- helpers ----------------------------------------------------------------
|
|
|
|
_reset_dev() {
|
|
rm -rf "${DEV}"
|
|
mkdir -p "${DEV}"
|
|
_CURFEW_TICK_CACHED=""
|
|
_CURFEW_TICK_RESULT=0
|
|
}
|
|
|
|
_set_now() { printf '%s\n' "$1" >"${DEV}/now"; }
|
|
_calls() { cat "${DEV}/calls.log" 2>/dev/null || printf ''; }
|
|
_log() { cat "${DEV}/log" 2>/dev/null || printf ''; }
|
|
_disabled() { cat "${DEV}/disabled" 2>/dev/null || printf ''; }
|
|
_enabled() { cat "${DEV}/enabled" 2>/dev/null || printf ''; }
|
|
|
|
# Seed the installed third-party package list `pm list packages -3 -e` returns.
|
|
_seed_packages() {
|
|
local pkg=""
|
|
: >"${DEV}/pm_list"
|
|
for pkg in "$@"; do
|
|
printf 'package:%s\n' "${pkg}" >>"${DEV}/pm_list"
|
|
done
|
|
}
|