mirror of
https://github.com/aaddrick/claude-desktop-debian.git
synced 2026-05-17 00:26:21 +03:00
* feat(linux): hybrid titlebar mode for clickable in-app topbar Default `CLAUDE_TITLEBAR_STYLE` is now `hybrid`: native OS frame plus a BrowserView preload shim that convinces claude.ai's bundle to render its in-app topbar (hamburger / sidebar / search / nav / Cowork ghost). Stacked layout instead of Windows's combined bar, but every button is clickable. Why not the upstream `frame:false` + WCO config: investigation (see docs/learnings/linux-topbar-shim.md) ruled out `titleBarOverlay`, `titleBarStyle:'hidden'`, and the `.draggable` CSS class as the source of the topbar click-eating drag region. The remaining cause is a Chromium-level implicit drag region for `frame:false` windows that exists on both X11 and Wayland and has no Electron-API knob. With `frame:true` the OS handles dragging and Chromium pushes no drag-region map, so the buttons receive mouse events normally. Modes: - `hybrid` (default) — system frame + shim, topbar visible and clickable - `native` — system frame, no shim, no in-app topbar - `hidden` — frameless + WCO config, matches Windows/macOS upstream; topbar visible but not clickable on Linux. Kept for Wayland comparison and future investigation Tests: tests/launcher-common.bats grew 16 cases covering `_resolve_titlebar_style`, `build_electron_args` flag selection per mode, and `setup_electron_env` env-var wiring per mode. `claude-desktop --doctor` now reports the resolved mode and warns when `hidden` is set. Co-Authored-By: Claude <claude@anthropic.com> * docs(learnings): add hybrid-mode screenshot Visual reference of the stacked layout: DE-drawn titlebar on top with native window controls, claude.ai's in-app topbar (hamburger / search / back-forward) immediately below it. Co-Authored-By: Claude <claude@anthropic.com> * docs(learnings): fix codespell hit (Pre-emptive → Preemptive) Codespell flags hyphenated "Pre-emptive" as a misspelling of "Preemptive". Drops the hyphen to clear the spellcheck CI gate on PR #538. Co-Authored-By: Claude <claude@anthropic.com> --------- Co-authored-by: Claude <claude@anthropic.com>
586 lines
17 KiB
Bash
586 lines
17 KiB
Bash
#!/usr/bin/env bats
|
|
#
|
|
# launcher-common.bats
|
|
# Tests for launcher utility functions in scripts/launcher-common.sh
|
|
#
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BATS_TEST_FILENAME}")" && pwd)"
|
|
|
|
# Check whether a value exists in the electron_args array.
|
|
# Supports glob patterns (e.g., '*WaylandWindowDecorations*').
|
|
has_electron_arg() {
|
|
local pattern="$1"
|
|
local arg
|
|
for arg in "${electron_args[@]}"; do
|
|
# shellcheck disable=SC2254
|
|
[[ $arg == $pattern ]] && return 0
|
|
done
|
|
return 1
|
|
}
|
|
|
|
setup() {
|
|
TEST_TMP=$(mktemp -d)
|
|
export TEST_TMP
|
|
|
|
# Redirect all filesystem-touching functions to temp dirs
|
|
export HOME="$TEST_TMP/home"
|
|
export XDG_CACHE_HOME="$TEST_TMP/cache"
|
|
export XDG_CONFIG_HOME="$TEST_TMP/config"
|
|
export XDG_RUNTIME_DIR="$TEST_TMP/run"
|
|
mkdir -p "$HOME" "$XDG_CACHE_HOME" "$XDG_CONFIG_HOME" "$XDG_RUNTIME_DIR"
|
|
|
|
# Clear display/wayland variables to avoid leaking host state
|
|
unset DISPLAY
|
|
unset WAYLAND_DISPLAY
|
|
unset CLAUDE_USE_WAYLAND
|
|
unset NIRI_SOCKET
|
|
unset XDG_CURRENT_DESKTOP
|
|
unset CLAUDE_MENU_BAR
|
|
unset CLAUDE_TITLEBAR_STYLE
|
|
unset COWORK_VM_BACKEND
|
|
unset ELECTRON_USE_SYSTEM_TITLE_BAR
|
|
|
|
# shellcheck source=scripts/launcher-common.sh
|
|
source "$SCRIPT_DIR/../scripts/launcher-common.sh"
|
|
}
|
|
|
|
teardown() {
|
|
if [[ -n "$TEST_TMP" && -d "$TEST_TMP" ]]; then
|
|
rm -rf "$TEST_TMP"
|
|
fi
|
|
}
|
|
|
|
# =============================================================================
|
|
# setup_logging
|
|
# =============================================================================
|
|
|
|
@test "setup_logging: creates log directory and sets log_file" {
|
|
run setup_logging
|
|
[[ $status -eq 0 ]]
|
|
[[ -d "$XDG_CACHE_HOME/claude-desktop-debian" ]]
|
|
}
|
|
|
|
@test "setup_logging: sets log_file under XDG_CACHE_HOME" {
|
|
setup_logging
|
|
[[ $log_file == "$XDG_CACHE_HOME/claude-desktop-debian/launcher.log" ]]
|
|
}
|
|
|
|
@test "setup_logging: falls back to HOME/.cache when XDG_CACHE_HOME unset" {
|
|
unset XDG_CACHE_HOME
|
|
setup_logging
|
|
[[ $log_dir == "$HOME/.cache/claude-desktop-debian" ]]
|
|
[[ -d "$HOME/.cache/claude-desktop-debian" ]]
|
|
}
|
|
|
|
# =============================================================================
|
|
# log_message
|
|
# =============================================================================
|
|
|
|
@test "log_message: appends message to log file" {
|
|
setup_logging
|
|
log_message "test message one"
|
|
log_message "test message two"
|
|
[[ -f $log_file ]]
|
|
run cat "$log_file"
|
|
[[ "${lines[0]}" == "test message one" ]]
|
|
[[ "${lines[1]}" == "test message two" ]]
|
|
}
|
|
|
|
# =============================================================================
|
|
# check_display
|
|
# =============================================================================
|
|
|
|
@test "check_display: fails when no display variables set" {
|
|
unset DISPLAY
|
|
unset WAYLAND_DISPLAY
|
|
run check_display
|
|
[[ $status -ne 0 ]]
|
|
}
|
|
|
|
@test "check_display: succeeds with DISPLAY set" {
|
|
DISPLAY=":0"
|
|
run check_display
|
|
[[ $status -eq 0 ]]
|
|
}
|
|
|
|
@test "check_display: succeeds with WAYLAND_DISPLAY set" {
|
|
WAYLAND_DISPLAY="wayland-0"
|
|
run check_display
|
|
[[ $status -eq 0 ]]
|
|
}
|
|
|
|
@test "check_display: succeeds with both set" {
|
|
DISPLAY=":0"
|
|
WAYLAND_DISPLAY="wayland-0"
|
|
run check_display
|
|
[[ $status -eq 0 ]]
|
|
}
|
|
|
|
# =============================================================================
|
|
# detect_display_backend
|
|
# =============================================================================
|
|
|
|
@test "detect_display_backend: X11 session sets is_wayland=false" {
|
|
DISPLAY=":0"
|
|
setup_logging
|
|
detect_display_backend
|
|
[[ $is_wayland == false ]]
|
|
}
|
|
|
|
@test "detect_display_backend: Wayland session sets is_wayland=true" {
|
|
WAYLAND_DISPLAY="wayland-0"
|
|
setup_logging
|
|
detect_display_backend
|
|
[[ $is_wayland == true ]]
|
|
}
|
|
|
|
@test "detect_display_backend: defaults to XWayland on Wayland" {
|
|
WAYLAND_DISPLAY="wayland-0"
|
|
setup_logging
|
|
detect_display_backend
|
|
[[ $is_wayland == true ]]
|
|
[[ $use_x11_on_wayland == true ]]
|
|
}
|
|
|
|
@test "detect_display_backend: CLAUDE_USE_WAYLAND=1 forces native Wayland" {
|
|
WAYLAND_DISPLAY="wayland-0"
|
|
CLAUDE_USE_WAYLAND=1
|
|
setup_logging
|
|
detect_display_backend
|
|
[[ $is_wayland == true ]]
|
|
[[ $use_x11_on_wayland == false ]]
|
|
}
|
|
|
|
@test "detect_display_backend: Niri detected via NIRI_SOCKET forces native Wayland" {
|
|
WAYLAND_DISPLAY="wayland-0"
|
|
NIRI_SOCKET="/tmp/niri.sock"
|
|
setup_logging
|
|
detect_display_backend
|
|
[[ $use_x11_on_wayland == false ]]
|
|
}
|
|
|
|
@test "detect_display_backend: Niri detected via XDG_CURRENT_DESKTOP forces native Wayland" {
|
|
WAYLAND_DISPLAY="wayland-0"
|
|
XDG_CURRENT_DESKTOP="niri"
|
|
setup_logging
|
|
detect_display_backend
|
|
[[ $use_x11_on_wayland == false ]]
|
|
}
|
|
|
|
@test "detect_display_backend: Niri in colon-separated XDG_CURRENT_DESKTOP" {
|
|
WAYLAND_DISPLAY="wayland-0"
|
|
XDG_CURRENT_DESKTOP="niri:GNOME"
|
|
setup_logging
|
|
detect_display_backend
|
|
[[ $use_x11_on_wayland == false ]]
|
|
}
|
|
|
|
@test "detect_display_backend: Niri case-insensitive detection" {
|
|
WAYLAND_DISPLAY="wayland-0"
|
|
XDG_CURRENT_DESKTOP="NIRI"
|
|
setup_logging
|
|
detect_display_backend
|
|
[[ $use_x11_on_wayland == false ]]
|
|
}
|
|
|
|
@test "detect_display_backend: non-Niri Wayland keeps XWayland default" {
|
|
WAYLAND_DISPLAY="wayland-0"
|
|
XDG_CURRENT_DESKTOP="sway"
|
|
setup_logging
|
|
detect_display_backend
|
|
[[ $use_x11_on_wayland == true ]]
|
|
}
|
|
|
|
@test "detect_display_backend: Niri not forced when CLAUDE_USE_WAYLAND already set" {
|
|
# CLAUDE_USE_WAYLAND=1 already forces native, Niri detection shouldn't conflict
|
|
WAYLAND_DISPLAY="wayland-0"
|
|
CLAUDE_USE_WAYLAND=1
|
|
NIRI_SOCKET="/tmp/niri.sock"
|
|
setup_logging
|
|
detect_display_backend
|
|
[[ $use_x11_on_wayland == false ]]
|
|
}
|
|
|
|
# =============================================================================
|
|
# build_electron_args
|
|
# =============================================================================
|
|
|
|
@test "build_electron_args: X11 deb - only CustomTitlebar disabled" {
|
|
is_wayland=false
|
|
setup_logging
|
|
build_electron_args deb
|
|
has_electron_arg '--disable-features=CustomTitlebar'
|
|
# shellcheck disable=SC2314 # last command in test, ! works correctly
|
|
! has_electron_arg '--no-sandbox'
|
|
}
|
|
|
|
@test "build_electron_args: X11 appimage - includes --no-sandbox" {
|
|
is_wayland=false
|
|
setup_logging
|
|
build_electron_args appimage
|
|
has_electron_arg '--no-sandbox'
|
|
}
|
|
|
|
@test "build_electron_args: Wayland XWayland deb - includes x11 platform and no-sandbox" {
|
|
is_wayland=true
|
|
use_x11_on_wayland=true
|
|
setup_logging
|
|
build_electron_args deb
|
|
has_electron_arg '--ozone-platform=x11'
|
|
has_electron_arg '--no-sandbox'
|
|
}
|
|
|
|
@test "build_electron_args: Wayland native deb - includes wayland platform flags" {
|
|
is_wayland=true
|
|
use_x11_on_wayland=false
|
|
setup_logging
|
|
build_electron_args deb
|
|
has_electron_arg '--ozone-platform=wayland'
|
|
has_electron_arg '--enable-wayland-ime'
|
|
has_electron_arg '*WaylandWindowDecorations*'
|
|
}
|
|
|
|
@test "build_electron_args: Wayland appimage - always includes --no-sandbox" {
|
|
is_wayland=true
|
|
use_x11_on_wayland=true
|
|
setup_logging
|
|
build_electron_args appimage
|
|
has_electron_arg '--no-sandbox'
|
|
}
|
|
|
|
@test "build_electron_args: Wayland native nix - includes --no-sandbox" {
|
|
is_wayland=true
|
|
use_x11_on_wayland=false
|
|
setup_logging
|
|
build_electron_args nix
|
|
has_electron_arg '--no-sandbox'
|
|
}
|
|
|
|
@test "build_electron_args: Wayland native includes text-input-version=3" {
|
|
is_wayland=true
|
|
use_x11_on_wayland=false
|
|
setup_logging
|
|
build_electron_args deb
|
|
has_electron_arg '--wayland-text-input-version=3'
|
|
}
|
|
|
|
# =============================================================================
|
|
# setup_electron_env
|
|
# =============================================================================
|
|
|
|
@test "setup_electron_env: sets ELECTRON_FORCE_IS_PACKAGED" {
|
|
setup_electron_env
|
|
[[ $ELECTRON_FORCE_IS_PACKAGED == 'true' ]]
|
|
}
|
|
|
|
@test "setup_electron_env: sets ELECTRON_USE_SYSTEM_TITLE_BAR in hybrid mode (default)" {
|
|
setup_electron_env
|
|
[[ $ELECTRON_USE_SYSTEM_TITLE_BAR == '1' ]]
|
|
}
|
|
|
|
@test "setup_electron_env: sets ELECTRON_USE_SYSTEM_TITLE_BAR in native mode" {
|
|
CLAUDE_TITLEBAR_STYLE=native setup_electron_env
|
|
[[ $ELECTRON_USE_SYSTEM_TITLE_BAR == '1' ]]
|
|
}
|
|
|
|
@test "setup_electron_env: skips ELECTRON_USE_SYSTEM_TITLE_BAR in hidden mode" {
|
|
CLAUDE_TITLEBAR_STYLE=hidden setup_electron_env
|
|
[[ -z ${ELECTRON_USE_SYSTEM_TITLE_BAR:-} ]]
|
|
}
|
|
|
|
@test "setup_electron_env: skips ELECTRON_USE_SYSTEM_TITLE_BAR for invalid value (falls back to hybrid)" {
|
|
CLAUDE_TITLEBAR_STYLE=garbage setup_electron_env
|
|
[[ $ELECTRON_USE_SYSTEM_TITLE_BAR == '1' ]]
|
|
}
|
|
|
|
# =============================================================================
|
|
# _resolve_titlebar_style
|
|
# =============================================================================
|
|
|
|
@test "_resolve_titlebar_style: returns 'hybrid' when unset" {
|
|
[[ $(_resolve_titlebar_style) == 'hybrid' ]]
|
|
}
|
|
|
|
@test "_resolve_titlebar_style: returns 'hybrid' for hybrid" {
|
|
CLAUDE_TITLEBAR_STYLE=hybrid
|
|
[[ $(_resolve_titlebar_style) == 'hybrid' ]]
|
|
}
|
|
|
|
@test "_resolve_titlebar_style: returns 'native' for native" {
|
|
CLAUDE_TITLEBAR_STYLE=native
|
|
[[ $(_resolve_titlebar_style) == 'native' ]]
|
|
}
|
|
|
|
@test "_resolve_titlebar_style: returns 'hidden' for hidden" {
|
|
CLAUDE_TITLEBAR_STYLE=hidden
|
|
[[ $(_resolve_titlebar_style) == 'hidden' ]]
|
|
}
|
|
|
|
@test "_resolve_titlebar_style: case-insensitive (HYBRID)" {
|
|
CLAUDE_TITLEBAR_STYLE=HYBRID
|
|
[[ $(_resolve_titlebar_style) == 'hybrid' ]]
|
|
}
|
|
|
|
@test "_resolve_titlebar_style: case-insensitive (Native)" {
|
|
CLAUDE_TITLEBAR_STYLE=Native
|
|
[[ $(_resolve_titlebar_style) == 'native' ]]
|
|
}
|
|
|
|
@test "_resolve_titlebar_style: case-insensitive (Hidden)" {
|
|
CLAUDE_TITLEBAR_STYLE=Hidden
|
|
[[ $(_resolve_titlebar_style) == 'hidden' ]]
|
|
}
|
|
|
|
@test "_resolve_titlebar_style: falls back to hybrid for invalid value" {
|
|
CLAUDE_TITLEBAR_STYLE=garbage
|
|
[[ $(_resolve_titlebar_style) == 'hybrid' ]]
|
|
}
|
|
|
|
@test "_resolve_titlebar_style: falls back to hybrid for empty value" {
|
|
CLAUDE_TITLEBAR_STYLE=''
|
|
[[ $(_resolve_titlebar_style) == 'hybrid' ]]
|
|
}
|
|
|
|
# =============================================================================
|
|
# build_electron_args: titlebar mode flag selection
|
|
# =============================================================================
|
|
|
|
@test "build_electron_args: hybrid mode (default) disables CustomTitlebar" {
|
|
is_wayland=false
|
|
setup_logging
|
|
build_electron_args deb
|
|
has_electron_arg '--disable-features=CustomTitlebar'
|
|
# shellcheck disable=SC2314
|
|
! has_electron_arg '--enable-features=WindowControlsOverlay'
|
|
}
|
|
|
|
@test "build_electron_args: native mode disables CustomTitlebar" {
|
|
CLAUDE_TITLEBAR_STYLE=native
|
|
is_wayland=false
|
|
setup_logging
|
|
build_electron_args deb
|
|
has_electron_arg '--disable-features=CustomTitlebar'
|
|
# shellcheck disable=SC2314
|
|
! has_electron_arg '--enable-features=WindowControlsOverlay'
|
|
}
|
|
|
|
@test "build_electron_args: hidden mode enables WindowControlsOverlay" {
|
|
CLAUDE_TITLEBAR_STYLE=hidden
|
|
is_wayland=false
|
|
setup_logging
|
|
build_electron_args deb
|
|
has_electron_arg '--enable-features=WindowControlsOverlay'
|
|
# shellcheck disable=SC2314
|
|
! has_electron_arg '--disable-features=CustomTitlebar'
|
|
}
|
|
|
|
@test "build_electron_args: invalid titlebar value falls back to hybrid flags" {
|
|
CLAUDE_TITLEBAR_STYLE=garbage
|
|
is_wayland=false
|
|
setup_logging
|
|
build_electron_args deb
|
|
has_electron_arg '--disable-features=CustomTitlebar'
|
|
}
|
|
|
|
# =============================================================================
|
|
# cleanup_stale_lock
|
|
# =============================================================================
|
|
|
|
@test "cleanup_stale_lock: no lock file - returns 0" {
|
|
mkdir -p "$XDG_CONFIG_HOME/Claude"
|
|
run cleanup_stale_lock
|
|
[[ $status -eq 0 ]]
|
|
}
|
|
|
|
@test "cleanup_stale_lock: removes stale lock (dead PID)" {
|
|
local config_dir="$XDG_CONFIG_HOME/Claude"
|
|
mkdir -p "$config_dir"
|
|
# Use PID 99999999 which almost certainly doesn't exist
|
|
ln -s "myhost-99999999" "$config_dir/SingletonLock"
|
|
setup_logging
|
|
cleanup_stale_lock
|
|
[[ ! -L "$config_dir/SingletonLock" ]]
|
|
}
|
|
|
|
@test "cleanup_stale_lock: keeps lock for running process" {
|
|
local config_dir="$XDG_CONFIG_HOME/Claude"
|
|
mkdir -p "$config_dir"
|
|
# Use our own PID (guaranteed to be running)
|
|
ln -s "myhost-$$" "$config_dir/SingletonLock"
|
|
setup_logging
|
|
cleanup_stale_lock
|
|
# Lock should still exist
|
|
[[ -L "$config_dir/SingletonLock" ]]
|
|
}
|
|
|
|
@test "cleanup_stale_lock: handles non-numeric PID in lock target" {
|
|
local config_dir="$XDG_CONFIG_HOME/Claude"
|
|
mkdir -p "$config_dir"
|
|
ln -s "myhost-notanumber" "$config_dir/SingletonLock"
|
|
setup_logging
|
|
run cleanup_stale_lock
|
|
[[ $status -eq 0 ]]
|
|
# Lock should still exist (function returns early on non-numeric)
|
|
[[ -L "$config_dir/SingletonLock" ]]
|
|
}
|
|
|
|
@test "cleanup_stale_lock: handles regular file (not symlink)" {
|
|
local config_dir="$XDG_CONFIG_HOME/Claude"
|
|
mkdir -p "$config_dir"
|
|
echo "not a symlink" > "$config_dir/SingletonLock"
|
|
setup_logging
|
|
run cleanup_stale_lock
|
|
[[ $status -eq 0 ]]
|
|
# Regular file should not be touched
|
|
[[ -f "$config_dir/SingletonLock" ]]
|
|
}
|
|
|
|
# =============================================================================
|
|
# cleanup_stale_cowork_socket
|
|
# =============================================================================
|
|
|
|
@test "cleanup_stale_cowork_socket: no socket - returns 0" {
|
|
run cleanup_stale_cowork_socket
|
|
[[ $status -eq 0 ]]
|
|
}
|
|
|
|
@test "cleanup_stale_cowork_socket: removes stale socket file" {
|
|
# Create a socket-like file (not a real socket, but -S check needs a socket)
|
|
# Use python to create a real unix socket for the test
|
|
local sock="$XDG_RUNTIME_DIR/cowork-vm-service.sock"
|
|
python3 -c "
|
|
import socket, sys
|
|
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
s.bind(sys.argv[1])
|
|
s.close()
|
|
" "$sock" 2>/dev/null || skip "Cannot create test unix socket"
|
|
|
|
setup_logging
|
|
# socat connection should fail since nothing is listening
|
|
cleanup_stale_cowork_socket
|
|
[[ ! -S "$sock" ]]
|
|
}
|
|
|
|
# =============================================================================
|
|
# Doctor helper functions
|
|
# =============================================================================
|
|
|
|
@test "_doctor_colors: sets color vars when stdout is a terminal" {
|
|
# Force non-terminal to test the else branch
|
|
_doctor_colors
|
|
# When not a terminal, all should be empty
|
|
[[ -z $_green ]]
|
|
[[ -z $_red ]]
|
|
[[ -z $_yellow ]]
|
|
[[ -z $_bold ]]
|
|
[[ -z $_reset ]]
|
|
}
|
|
|
|
@test "_pass: outputs PASS with message" {
|
|
_doctor_colors
|
|
run _pass "test passed"
|
|
[[ $output == *"[PASS]"* ]]
|
|
[[ $output == *"test passed"* ]]
|
|
}
|
|
|
|
@test "_fail: outputs FAIL with message and increments counter" {
|
|
_doctor_colors
|
|
_doctor_failures=0
|
|
_fail "something broke"
|
|
[[ $_doctor_failures -eq 1 ]]
|
|
}
|
|
|
|
@test "_warn: outputs WARN with message" {
|
|
_doctor_colors
|
|
run _warn "warning message"
|
|
[[ $output == *"[WARN]"* ]]
|
|
[[ $output == *"warning message"* ]]
|
|
}
|
|
|
|
@test "_info: outputs indented message" {
|
|
_doctor_colors
|
|
run _info "info message"
|
|
[[ $output == *"info message"* ]]
|
|
}
|
|
|
|
# =============================================================================
|
|
# _cowork_distro_id
|
|
# =============================================================================
|
|
|
|
@test "_cowork_distro_id: reads ID from /etc/os-release" {
|
|
# This test uses the real /etc/os-release on the test system
|
|
[[ -f /etc/os-release ]] || skip "No /etc/os-release"
|
|
local result
|
|
result=$(_cowork_distro_id)
|
|
# Should return something non-empty
|
|
[[ -n $result ]]
|
|
[[ $result != 'unknown' ]]
|
|
}
|
|
|
|
# =============================================================================
|
|
# _cowork_pkg_hint
|
|
# =============================================================================
|
|
|
|
@test "_cowork_pkg_hint: debian uses apt" {
|
|
local result
|
|
result=$(_cowork_pkg_hint debian bubblewrap)
|
|
[[ $result == "sudo apt install bubblewrap" ]]
|
|
}
|
|
|
|
@test "_cowork_pkg_hint: ubuntu uses apt" {
|
|
local result
|
|
result=$(_cowork_pkg_hint ubuntu socat)
|
|
[[ $result == "sudo apt install socat" ]]
|
|
}
|
|
|
|
@test "_cowork_pkg_hint: fedora uses dnf" {
|
|
local result
|
|
result=$(_cowork_pkg_hint fedora bubblewrap)
|
|
[[ $result == "sudo dnf install bubblewrap" ]]
|
|
}
|
|
|
|
@test "_cowork_pkg_hint: arch uses pacman" {
|
|
local result
|
|
result=$(_cowork_pkg_hint arch socat)
|
|
[[ $result == "sudo pacman -S socat" ]]
|
|
}
|
|
|
|
@test "_cowork_pkg_hint: qemu maps to distro-specific packages" {
|
|
local result
|
|
result=$(_cowork_pkg_hint debian qemu)
|
|
[[ $result == "sudo apt install qemu-system-x86 qemu-utils" ]]
|
|
|
|
result=$(_cowork_pkg_hint fedora qemu)
|
|
[[ $result == "sudo dnf install qemu-kvm qemu-img" ]]
|
|
|
|
result=$(_cowork_pkg_hint arch qemu)
|
|
[[ $result == "sudo pacman -S qemu-full" ]]
|
|
}
|
|
|
|
@test "_cowork_pkg_hint: unknown distro gives generic message" {
|
|
local result
|
|
result=$(_cowork_pkg_hint gentoo bubblewrap)
|
|
[[ $result == "Install bubblewrap using your package manager" ]]
|
|
}
|
|
|
|
# =============================================================================
|
|
# _electron_version
|
|
# =============================================================================
|
|
|
|
@test "_electron_version: reads version from file beside binary" {
|
|
mkdir -p "$TEST_TMP/electron"
|
|
echo "33.4.0" > "$TEST_TMP/electron/version"
|
|
touch "$TEST_TMP/electron/electron"
|
|
local result
|
|
result=$(_electron_version "$TEST_TMP/electron/electron")
|
|
[[ $result == "33.4.0" ]]
|
|
}
|
|
|
|
@test "_electron_version: returns empty when version file missing" {
|
|
mkdir -p "$TEST_TMP/electron"
|
|
touch "$TEST_TMP/electron/electron"
|
|
local result
|
|
result=$(_electron_version "$TEST_TMP/electron/electron") || true
|
|
[[ -z $result ]]
|
|
}
|