#!/usr/bin/env bash set -exE -o errtrace dump_cache() { printf '\nTest failure: contents of cache:\n\n' >&2 cat "$l_out" >&2 } expect_fail() { set +e "$@" local status=$? set -e (( status != 0 )) } if ! (( NO_PID_NAMESPACE )) && (( EUID )); then export _UNSHARED=1 exec unshare --user --map-root-user --pid --mount --fork --mount-proc "$0" "$@" fi if (( _UNSHARED )); then # Get our own tmp mount -t tmpfs unshared_tmp /tmp fi cd "${0%/*}"/.. make clean debug cd src export PATH=$PWD:$PATH expect_fail env CM_CONFIG=relative CM_DIR="$(mktemp -d)" clipmenu expect_fail env CM_DIR=relative CM_CONFIG="$(mktemp)" clipmenu export CM_CONFIG=$(mktemp) export CM_DIR=$(mktemp -d) export CM_DEBUG=1 export ASAN_OPTIONS='halt_on_error=1:abort_on_error=1' export UBSAN_OPTIONS='halt_on_error=1:abort_on_error=1' uid=$(id -u) [[ "$(clipctl version)" == 7 ]] [[ "$(clipctl cache-dir)" == "$CM_DIR/clipmenu.7.$uid" ]] launcher=$(mktemp) l_out=$(mktemp) trap dump_cache ERR cat > "$launcher" << EOF #!/bin/bash cat > "$l_out" if [[ \$SELECT ]]; then printf '%s\\n' "\$SELECT" fi EOF chmod a+x "$launcher" export CM_LAUNCHER="$launcher" tilde_home=$(mktemp -d) tilde_dir="$tilde_home/clipmenu_tilde" mkdir -p "$tilde_dir" HOME="$tilde_home" CM_DIR="~/clipmenu_tilde" CM_CONFIG="$(mktemp)" \ clipmenu || true [[ -d "$tilde_dir/clipmenu.7.$uid" ]] rm -rf "$tilde_home" tilde_conf_home=$(mktemp -d) printf 'max_clips nope\n' > "$tilde_conf_home/bad.conf" err=$(HOME="$tilde_conf_home" CM_CONFIG="~/bad.conf" CM_DIR="$(mktemp -d)" \ clipmenu 2>&1 || true) [[ "$err" == *"for max_clips"* ]] rm -rf "$tilde_conf_home" kill_background_jobs() { local -a bg readarray -t bg < <(jobs -p) (( ${#bg[@]} )) && kill -- "${bg[@]}" 2>/dev/null } primary() { printf '%s' "${1?}" | xsel -p } trap 'kill_background_jobs' EXIT settle() { sleep 0.2 } long_settle() { sleep 2 } check_nr_clips() { if [[ $SELECT ]]; then clipmenu else # On no selection, we exit 1. Avoid masking real problems by only doing # it when no selection is specified. clipmenu || true fi (( $(wc -l < "$l_out") == "${1?}" )) } wait_nr_clips() { local want=${1?} local deadline=$((SECONDS + 5)) while (( SECONDS < deadline )); do if check_nr_clips "$want"; then return 0 fi sleep 0.1 done check_nr_clips "$want" } if ! (( USE_CURRENT_DISPLAY )); then export DISPLAY=:1911 Xvfb "$DISPLAY" & sleep 2 fi # Clear selections xsel -bc xsel -pc xsel -sc clipmenud & clipmenud_pid=$! settle # Should be empty check_nr_clips 0 primary foo settle check_nr_clips 1 # Put the same one repeatedly, should ignore it primary foo primary foo primary foo settle settle check_nr_clips 1 [[ "$(< "$l_out")" == "[1] foo" ]] # Put possible partials, should update it primary fooa primary fooab primary fooabc # Should have replaced the old one settle check_nr_clips 1 [[ "$(< "$l_out")" == "[1] fooabc" ]] primary fooab primary fooa primary foo # Should have replaced the old one settle check_nr_clips 1 [[ "$(< "$l_out")" == "[1] foo" ]] # Put some more content on the clipboard for testing primary bar primary baz settle check_nr_clips 3 # Nothing gets deleted, but we recognise the right clips [[ $(clipdel a) == $'bar\nbaz' ]] check_nr_clips 3 # Likewise but inversion [[ $(clipdel -v a) == foo ]] check_nr_clips 3 # Real delete with inversion [[ $(clipdel -dv a) == foo ]] check_nr_clips 2 # Test literal match primary '*foo' settle check_nr_clips 3 [[ $(clipdel -dF '*') == '*foo' ]] check_nr_clips 2 # Test -n primary latest settle check_nr_clips 3 # Should delete the newest entry [[ $(clipdel -dn 1) == 'latest' ]] check_nr_clips 2 # Test -N primary wibble primary wobble settle check_nr_clips 4 # Should delete everything other than the oldest 2 entries [[ $(clipdel -dvN 2) == $'wibble\nwobble' ]] check_nr_clips 2 # Test clipdelmenu primary test1 primary test2 primary test3 settle check_nr_clips 5 # Should delete the selected entry SELECT='[4] test2' clipdelmenu settle check_nr_clips 4 # Verify test2 is gone and test1, test3 remain clipmenu || true [[ "$(< "$l_out")" == *"test1"* ]] [[ "$(< "$l_out")" == *"test3"* ]] [[ "$(< "$l_out")" != *"test2"* ]] # Delete the others SELECT='[3] test1' clipdelmenu SELECT='[3] test3' clipdelmenu # Test multi-select deletion primary multi1 primary multi2 settle check_nr_clips 4 SELECT=$'[3] multi1\n[4] multi2' clipdelmenu check_nr_clips 2 # Check selecting starts serving xsel -pc SELECT='[1] bar' clipmenu settle [[ "$(xsel -po)" == bar ]] SELECT='[2] baz' clipmenu settle [[ "$(xsel -po)" == baz ]] # Disable populates no new clips clipctl disable [[ "$(clipctl status)" == disabled ]] primary wibble primary wobble settle check_nr_clips 2 # Enable enables again clipctl enable [[ "$(clipctl status)" == enabled ]] primary wibble primary wobble settle check_nr_clips 4 # Toggle works both ways clipctl toggle [[ "$(clipctl status)" == disabled ]] clipctl toggle [[ "$(clipctl status)" == enabled ]] # Test INCR support set +x printf '%.0sa' {1..9999999} | xsel -p set -x long_settle # This is a big one, give it some time len_before=$(xsel -po | wc -c) check_nr_clips 5 SELECT='[5] aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...' \ clipmenu long_settle len_after=$(xsel -po | wc -c) # Make sure we got the whole thing (( len_before == len_after )) # Issue #241. Put a large clipboard selection via INCR, then put something else # small immediately after. xsel -bc settle check_nr_clips 5 # Large selection (INCR) printf '%.0sa' {1..4001} | xsel -b wait_nr_clips 6 # After large selection is stored, put something small that's a possible # # partial (non-INCR) printf a | xsel -b settle check_nr_clips 6 # own_selections: default does not own PRIMARY kill "$clipmenud_pid" wait "$clipmenud_pid" || true pkill -x clipserve 2>/dev/null || true CM_OWN_CLIPBOARD=1 CM_OWN_SELECTIONS=clipboard clipmenud & clipmenud_pid=$! settle xsel -bc xsel -pc printf 'primary_stale' | xsel -p printf 'clip_default' | xsel -b settle [[ "$(xsel -bo)" == clip_default ]] primary_out=$(xsel -po 2>/dev/null || true) [[ "$primary_out" != clip_default ]] # own_selections: owns all listed selections kill "$clipmenud_pid" wait "$clipmenud_pid" || true pkill -x clipserve 2>/dev/null || true CM_OWN_CLIPBOARD=1 CM_OWN_SELECTIONS='clipboard primary' clipmenud & clipmenud_pid=$! settle xsel -bc xsel -pc printf 'primary_stale' | xsel -p printf 'own_both' | xsel -b settle [[ "$(xsel -bo)" == own_both ]] [[ "$(xsel -po)" == own_both ]] if (( _UNSHARED )); then umount -l /tmp fi