parent
d96018d299
commit
842e547c17
@ -0,0 +1,206 @@ |
||||
# Terminal emulators all present a pretty similar interface. |
||||
# That gives us an opportunity to easily test their basic functionality with a single codebase. |
||||
# |
||||
# There are two tests run on each terminal emulator |
||||
# - can it successfully execute a command passed on the cmdline? |
||||
# - can it successfully display a colour? |
||||
# the latter is used as a proxy for "can it display text?", without going through all the intricacies of OCR. |
||||
# |
||||
# 256-colour terminal mode is used to display the test colour, since it has a universally-applicable palette (unlike 8- and 16- colour, where the colours are implementation-defined), and it is widely supported (unlike 24-bit colour). |
||||
# |
||||
# Future work: |
||||
# - Wayland support (both for testing the existing terminals, and for testing wayland-only terminals like foot and havoc) |
||||
# - Test keyboard input? (skipped for now, to eliminate the possibility of race conditions and focus issues) |
||||
|
||||
{ system ? builtins.currentSystem, |
||||
config ? {}, |
||||
pkgs ? import ../.. { inherit system config; } |
||||
}: |
||||
|
||||
with import ../lib/testing-python.nix { inherit system pkgs; }; |
||||
with pkgs.lib; |
||||
|
||||
let tests = { |
||||
alacritty.pkg = p: p.alacritty; |
||||
|
||||
contour.pkg = p: p.contour; |
||||
contour.cmd = "contour $command"; |
||||
|
||||
cool-retro-term.pkg = p: p.cool-retro-term; |
||||
cool-retro-term.colourTest = false; # broken by gloss effect |
||||
|
||||
ctx.pkg = p: p.ctx; |
||||
ctx.pinkValue = "#FE0065"; |
||||
|
||||
darktile.pkg = p: p.darktile; |
||||
|
||||
eterm.pkg = p: p.eterm; |
||||
eterm.executable = "Eterm"; |
||||
eterm.pinkValue = "#D40055"; |
||||
|
||||
germinal.pkg = p: p.germinal; |
||||
|
||||
gnome-terminal.pkg = p: p.gnome.gnome-terminal; |
||||
|
||||
guake.pkg = p: p.guake; |
||||
guake.cmd = "SHELL=$command guake --show"; |
||||
guake.kill = true; |
||||
|
||||
hyper.pkg = p: p.hyper; |
||||
|
||||
kermit.pkg = p: p.kermit-terminal; |
||||
|
||||
kgx.pkg = p: p.kgx; |
||||
kgx.cmd = "kgx -e $command"; |
||||
kgx.kill = true; |
||||
|
||||
kitty.pkg = p: p.kitty; |
||||
kitty.cmd = "kitty $command"; |
||||
|
||||
konsole.pkg = p: p.plasma5Packages.konsole; |
||||
|
||||
lxterminal.pkg = p: p.lxterminal; |
||||
|
||||
mate-terminal.pkg = p: p.mate.mate-terminal; |
||||
mate-terminal.cmd = "SHELL=$command mate-terminal --disable-factory"; # factory mode uses dbus, and we don't have a proper dbus session set up |
||||
|
||||
mlterm.pkg = p: p.mlterm; |
||||
|
||||
mrxvt.pkg = p: p.mrxvt; |
||||
|
||||
qterminal.pkg = p: p.lxqt.qterminal; |
||||
qterminal.kill = true; |
||||
|
||||
roxterm.pkg = p: p.roxterm; |
||||
roxterm.cmd = "roxterm -e $command"; |
||||
|
||||
sakura.pkg = p: p.sakura; |
||||
|
||||
st.pkg = p: p.st; |
||||
|
||||
stupidterm.pkg = p: p.stupidterm; |
||||
stupidterm.cmd = "stupidterm -- $command"; |
||||
|
||||
terminator.pkg = p: p.terminator; |
||||
terminator.cmd = "terminator -e $command"; |
||||
|
||||
terminology.pkg = p: p.enlightenment.terminology; |
||||
terminology.cmd = "SHELL=$command terminology --no-wizard=true"; |
||||
terminology.colourTest = false; # broken by gloss effect |
||||
|
||||
termite.pkg = p: p.termite; |
||||
|
||||
termonad.pkg = p: p.termonad; |
||||
|
||||
tilda.pkg = p: p.tilda; |
||||
|
||||
tilix.pkg = p: p.tilix; |
||||
tilix.cmd = "tilix -e $command"; |
||||
|
||||
urxvt.pkg = p: p.rxvt-unicode; |
||||
|
||||
wayst.pkg = p: p.wayst; |
||||
wayst.pinkValue = "#FF0066"; |
||||
|
||||
wezterm.pkg = p: p.wezterm; |
||||
|
||||
xfce4-terminal.pkg = p: p.xfce.xfce4-terminal; |
||||
|
||||
xterm.pkg = p: p.xterm; |
||||
}; |
||||
in mapAttrs (name: { pkg, executable ? name, cmd ? "SHELL=$command ${executable}", colourTest ? true, pinkValue ? "#FF0087", kill ? false }: makeTest |
||||
{ |
||||
name = "terminal-emulator-${name}"; |
||||
meta = with pkgs.stdenv.lib.maintainers; { |
||||
maintainers = [ jjjollyjim ]; |
||||
}; |
||||
|
||||
machine = { pkgsInner, ... }: |
||||
|
||||
{ |
||||
imports = [ ./common/x11.nix ./common/user-account.nix ]; |
||||
|
||||
# Hyper (and any other electron-based terminals) won't run as root |
||||
test-support.displayManager.auto.user = "alice"; |
||||
|
||||
environment.systemPackages = [ |
||||
(pkg pkgs) |
||||
(pkgs.writeShellScriptBin "report-success" '' |
||||
echo 1 > /tmp/term-ran-successfully |
||||
${optionalString kill "pkill ${executable}"} |
||||
'') |
||||
(pkgs.writeShellScriptBin "display-colour" '' |
||||
# A 256-colour background colour code for pink, then spaces. |
||||
# |
||||
# Background is used rather than foreground to minimize the effect of anti-aliasing. |
||||
# |
||||
# Keep adding more in case the window is partially offscreen to the left or requires |
||||
# a change to correctly redraw after initialising the window (as with ctx). |
||||
|
||||
while : |
||||
do |
||||
echo -ne "\e[48;5;198m " |
||||
sleep 0.5 |
||||
done |
||||
sleep infinity |
||||
'') |
||||
(pkgs.writeShellScriptBin "run-in-this-term" "sudo -u alice run-in-this-term-wrapped $1") |
||||
|
||||
(pkgs.writeShellScriptBin "run-in-this-term-wrapped" "command=\"$(which \"$1\")\"; ${cmd}") |
||||
]; |
||||
|
||||
# Helpful reminder to add this test to passthru.tests |
||||
warnings = if !((pkg pkgs) ? "passthru" && (pkg pkgs).passthru ? "tests") then [ "The package for ${name} doesn't have a passthru.tests" ] else [ ]; |
||||
}; |
||||
|
||||
# We need imagemagick, though not tesseract |
||||
enableOCR = true; |
||||
|
||||
testScript = { nodes, ... }: let |
||||
in '' |
||||
with subtest("wait for x"): |
||||
start_all() |
||||
machine.wait_for_x() |
||||
|
||||
with subtest("have the terminal run a command"): |
||||
# We run this command synchronously, so we can be certain the exit codes are happy |
||||
machine.${if kill then "execute" else "succeed"}("run-in-this-term report-success") |
||||
machine.wait_for_file("/tmp/term-ran-successfully") |
||||
${optionalString colourTest '' |
||||
|
||||
import tempfile |
||||
import subprocess |
||||
|
||||
|
||||
def check_for_pink(final=False) -> bool: |
||||
with tempfile.NamedTemporaryFile() as tmpin: |
||||
machine.send_monitor_command("screendump {}".format(tmpin.name)) |
||||
|
||||
cmd = 'convert {} -define histogram:unique-colors=true -format "%c" histogram:info:'.format( |
||||
tmpin.name |
||||
) |
||||
ret = subprocess.run(cmd, shell=True, capture_output=True) |
||||
if ret.returncode != 0: |
||||
raise Exception( |
||||
"image analysis failed with exit code {}".format(ret.returncode) |
||||
) |
||||
|
||||
text = ret.stdout.decode("utf-8") |
||||
return "${pinkValue}" in text |
||||
|
||||
|
||||
with subtest("ensuring no pink is present without the terminal"): |
||||
assert ( |
||||
check_for_pink() == False |
||||
), "Pink was present on the screen before we even launched a terminal!" |
||||
|
||||
with subtest("have the terminal display a colour"): |
||||
# We run this command in the background |
||||
machine.shell.send(b"(run-in-this-term display-colour |& systemd-cat -t terminal) &\n") |
||||
|
||||
with machine.nested("Waiting for the screen to have pink on it:"): |
||||
retry(check_for_pink) |
||||
''}''; |
||||
} |
||||
|
||||
) tests |
Loading…
Reference in new issue