nixVersions.stable: 2.15 -> 2.17
[NixPkgs.git] / nixos / tests / keymap.nix
blobcc45824667edb226c50a3c85bb233b210feb70f9
1 { system ? builtins.currentSystem,
2   config ? {},
3   pkgs ? import ../.. { inherit system config; }
4 }:
6 with import ../lib/testing-python.nix { inherit system pkgs; };
8 let
9   readyFile  = "/tmp/readerReady";
10   resultFile = "/tmp/readerResult";
12   testReader = pkgs.writeScript "test-input-reader" ''
13     rm -f ${resultFile} ${resultFile}.tmp
14     logger "testReader: START: Waiting for $1 characters, expecting '$2'."
15     touch ${readyFile}
16     read -r -N $1 chars
17     rm -f ${readyFile}
19     if [ "$chars" == "$2" ]; then
20       logger -s "testReader: PASS: Got '$2' as expected." 2>${resultFile}.tmp
21     else
22       logger -s "testReader: FAIL: Expected '$2' but got '$chars'." 2>${resultFile}.tmp
23     fi
24     # rename after the file is written to prevent a race condition
25     mv  ${resultFile}.tmp ${resultFile}
26   '';
29   mkKeyboardTest = layout: { extraConfig ? {}, tests }: with pkgs.lib; makeTest {
30     name = "keymap-${layout}";
32     nodes.machine.console.keyMap = mkOverride 900 layout;
33     nodes.machine.services.xserver.desktopManager.xterm.enable = false;
34     nodes.machine.services.xserver.layout = mkOverride 900 layout;
35     nodes.machine.imports = [ ./common/x11.nix extraConfig ];
37     testScript = ''
38       import json
39       import shlex
42       def run_test_case(cmd, xorg_keymap, test_case_name, inputs, expected):
43           with subtest(test_case_name):
44               assert len(inputs) == len(expected)
45               machine.execute("rm -f ${readyFile} ${resultFile}")
47               # set up process that expects all the keys to be entered
48               machine.succeed(
49                   "{} {} {} {} >&2 &".format(
50                       cmd,
51                       "${testReader}",
52                       len(inputs),
53                       shlex.quote("".join(expected)),
54                   )
55               )
57               if xorg_keymap:
58                   # make sure the xterm window is open and has focus
59                   machine.wait_for_window("testterm")
60                   machine.wait_until_succeeds(
61                       "${pkgs.xdotool}/bin/xdotool search --sync --onlyvisible "
62                       "--class testterm windowfocus --sync"
63                   )
65               # wait for reader to be ready
66               machine.wait_for_file("${readyFile}")
68               # send all keys
69               for key in inputs:
70                   machine.send_key(key)
72               # wait for result and check
73               machine.wait_for_file("${resultFile}")
74               machine.succeed("grep -q 'PASS:' ${resultFile}")
77       with open("${pkgs.writeText "tests.json" (builtins.toJSON tests)}") as json_file:
78           tests = json.load(json_file)
80       # These environments used to run in the opposite order, causing the
81       # following error at openvt startup.
82       #
83       # openvt: Couldn't deallocate console 1
84       #
85       # This error did not appear in successful runs.
86       # I don't know the exact cause, but I it seems that openvt and X are
87       # fighting over the virtual terminal. This does not appear to be a problem
88       # when the X test runs first.
89       keymap_environments = {
90           "Xorg Keymap": "DISPLAY=:0 xterm -title testterm -class testterm -fullscreen -e",
91           "VT Keymap": "openvt -sw --",
92       }
94       machine.wait_for_x()
96       for keymap_env_name, command in keymap_environments.items():
97           with subtest(keymap_env_name):
98               for test_case_name, test_data in tests.items():
99                   run_test_case(
100                       command,
101                       False,
102                       test_case_name,
103                       test_data["qwerty"],
104                       test_data["expect"],
105                   )
106     '';
107   };
109 in pkgs.lib.mapAttrs mkKeyboardTest {
110   azerty = {
111     tests = {
112       azqw.qwerty = [ "q" "w" ];
113       azqw.expect = [ "a" "z" ];
114       altgr.qwerty = [ "alt_r-2" "alt_r-3" "alt_r-4" "alt_r-5" "alt_r-6" ];
115       altgr.expect = [ "~"       "#"       "{"       "["       "|"       ];
116     };
118     extraConfig.console.keyMap = "fr";
119     extraConfig.services.xserver.layout = "fr";
120   };
122   bone = {
123     tests = {
124       layer1.qwerty = [ "f"           "j"                     ];
125       layer1.expect = [ "e"           "n"                     ];
126       layer2.qwerty = [ "shift-f"     "shift-j"     "shift-6" ];
127       layer2.expect = [ "E"           "N"           "$"       ];
128       layer3.qwerty = [ "caps_lock-d" "caps_lock-f"           ];
129       layer3.expect = [ "{"           "}"                     ];
130     };
132     extraConfig.console.keyMap = "bone";
133     extraConfig.services.xserver.layout = "de";
134     extraConfig.services.xserver.xkbVariant = "bone";
135   };
137   colemak = {
138     tests = {
139       homerow.qwerty = [ "a" "s" "d" "f" "j" "k" "l" "semicolon" ];
140       homerow.expect = [ "a" "r" "s" "t" "n" "e" "i" "o"         ];
141     };
143     extraConfig.console.keyMap = "colemak";
144     extraConfig.services.xserver.layout = "us";
145     extraConfig.services.xserver.xkbVariant = "colemak";
146   };
148   dvorak = {
149     tests = {
150       homerow.qwerty = [ "a" "s" "d" "f" "j" "k" "l" "semicolon" ];
151       homerow.expect = [ "a" "o" "e" "u" "h" "t" "n" "s"         ];
152       symbols.qwerty = [ "q" "w" "e" "minus" "equal" ];
153       symbols.expect = [ "'" "," "." "["     "]"     ];
154     };
156     extraConfig.console.keyMap = "dvorak";
157     extraConfig.services.xserver.layout = "us";
158     extraConfig.services.xserver.xkbVariant = "dvorak";
159   };
161   dvorak-programmer = {
162     tests = {
163       homerow.qwerty = [ "a" "s" "d" "f" "j" "k" "l" "semicolon" ];
164       homerow.expect = [ "a" "o" "e" "u" "h" "t" "n" "s"         ];
165       numbers.qwerty = map (x: "shift-${x}")
166                        [ "1" "2" "3" "4" "5" "6" "7" "8" "9" "0" "minus" ];
167       numbers.expect = [ "%" "7" "5" "3" "1" "9" "0" "2" "4" "6" "8" ];
168       symbols.qwerty = [ "1" "2" "3" "4" "5" "6" "7" "8" "9" "0" "minus" ];
169       symbols.expect = [ "&" "[" "{" "}" "(" "=" "*" ")" "+" "]" "!" ];
170     };
172     extraConfig.console.keyMap = "dvorak-programmer";
173     extraConfig.services.xserver.layout = "us";
174     extraConfig.services.xserver.xkbVariant = "dvp";
175   };
177   neo = {
178     tests = {
179       layer1.qwerty = [ "f"           "j"                     ];
180       layer1.expect = [ "e"           "n"                     ];
181       layer2.qwerty = [ "shift-f"     "shift-j"     "shift-6" ];
182       layer2.expect = [ "E"           "N"           "$"       ];
183       layer3.qwerty = [ "caps_lock-d" "caps_lock-f"           ];
184       layer3.expect = [ "{"           "}"                     ];
185     };
187     extraConfig.console.keyMap = "neo";
188     extraConfig.services.xserver.layout = "de";
189     extraConfig.services.xserver.xkbVariant = "neo";
190   };
192   qwertz = {
193     tests = {
194       zy.qwerty = [ "z" "y" ];
195       zy.expect = [ "y" "z" ];
196       altgr.qwerty = map (x: "alt_r-${x}")
197                      [ "q" "less" "7" "8" "9" "0" ];
198       altgr.expect = [ "@" "|"    "{" "[" "]" "}" ];
199     };
201     extraConfig.console.keyMap = "de";
202     extraConfig.services.xserver.layout = "de";
203   };
205   custom = {
206     tests = {
207       us.qwerty = [ "a" "b" "g" "d" "z" "shift-2" "shift-3" ];
208       us.expect = [ "a" "b" "g" "d" "z" "@" "#" ];
209       greek.qwerty = map (x: "alt_r-${x}")
210                      [ "a" "b" "g" "d" "z" ];
211       greek.expect = [ "α" "β" "γ" "δ" "ζ" ];
212     };
214     extraConfig.console.useXkbConfig = true;
215     extraConfig.services.xserver.layout = "us-greek";
216     extraConfig.services.xserver.extraLayouts.us-greek =
217       { description = "US layout with alt-gr greek";
218         languages   = [ "eng" ];
219         symbolsFile = pkgs.writeText "us-greek" ''
220           xkb_symbols "us-greek"
221           {
222             include "us(basic)"
223             include "level3(ralt_switch)"
224             key <LatA> { [ a, A, Greek_alpha ] };
225             key <LatB> { [ b, B, Greek_beta  ] };
226             key <LatG> { [ g, G, Greek_gamma ] };
227             key <LatD> { [ d, D, Greek_delta ] };
228             key <LatZ> { [ z, Z, Greek_zeta  ] };
229           };
230         '';
231       };
232   };