test: drop some now-obsolete functions
[platform/upstream/libxkbcommon.git] / test / xkeyboard-config-test.py.in
1 #!/usr/bin/env python3
2 import argparse
3 import sys
4 import subprocess
5 import os
6 import io
7 import xml.etree.ElementTree as ET
8 from multiprocessing import Pool
9
10
11 verbose = True
12
13 DEFAULT_RULES_XML = '@XKB_CONFIG_ROOT@/rules/evdev.xml'
14
15 # Meson needs to fill this in so we can call the tool in the buildir.
16 EXTRA_PATH = '@MESON_BUILD_ROOT@'
17 os.environ['PATH'] = ':'.join([EXTRA_PATH, os.getenv('PATH')])
18
19
20 def noop_progress_bar(x, total):
21     return x
22
23
24 # The function generating the progress bar (if any).
25 progress_bar = noop_progress_bar
26 if os.isatty(sys.stdout.fileno()):
27     try:
28         from tqdm import tqdm
29         progress_bar = tqdm
30
31         verbose = False
32     except ImportError:
33         pass
34
35
36 def xkbcommontool(rmlvo):
37     try:
38         r = rmlvo.get('r', 'evdev')
39         m = rmlvo.get('m', 'pc105')
40         l = rmlvo.get('l', 'us')
41         v = rmlvo.get('v', None)
42         o = rmlvo.get('o', None)
43         args = [
44             'rmlvo-to-keymap',
45             '--rules', r,
46             '--model', m,
47             '--layout', l,
48         ]
49         if v is not None:
50             args += ['--variant', v]
51         if o is not None:
52             args += ['--options', o]
53
54         success = True
55         out = io.StringIO()
56         if verbose:
57             print(':: {}'.format(' '.join(args)), file=out)
58
59         try:
60             output = subprocess.check_output(args, stderr=subprocess.STDOUT,
61                                              universal_newlines=True)
62             if verbose:
63                 print(output, file=out)
64         except subprocess.CalledProcessError as err:
65             print('ERROR: Failed to compile: {}'.format(' '.join(args)), file=out)
66             print(err.output, file=out)
67             success = False
68
69         return success, out.getvalue()
70     except KeyboardInterrupt:
71         pass
72
73
74 def xkbcomp(rmlvo):
75     try:
76         r = rmlvo.get('r', 'evdev')
77         m = rmlvo.get('m', 'pc105')
78         l = rmlvo.get('l', 'us')
79         v = rmlvo.get('v', None)
80         o = rmlvo.get('o', None)
81         args = ['setxkbmap', '-print']
82         if r is not None:
83             args.append('-rules')
84             args.append('{}'.format(r))
85         if m is not None:
86             args.append('-model')
87             args.append('{}'.format(m))
88         if l is not None:
89             args.append('-layout')
90             args.append('{}'.format(l))
91         if v is not None:
92             args.append('-variant')
93             args.append('{}'.format(v))
94         if o is not None:
95             args.append('-option')
96             args.append('{}'.format(o))
97
98         success = True
99         out = io.StringIO()
100         if verbose:
101             print(':: {}'.format(' '.join(args)), file=out)
102
103         try:
104             xkbcomp_args = ['xkbcomp', '-xkb', '-', '-']
105
106             setxkbmap = subprocess.Popen(args, stdout=subprocess.PIPE)
107             xkbcomp = subprocess.Popen(xkbcomp_args, stdin=setxkbmap.stdout,
108                                        stdout=subprocess.PIPE, stderr=subprocess.PIPE,
109                                        universal_newlines=True)
110             setxkbmap.stdout.close()
111             stdout, stderr = xkbcomp.communicate()
112             if xkbcomp.returncode != 0:
113                 print('ERROR: Failed to compile: {}'.format(' '.join(args)), file=out)
114                 success = False
115             if xkbcomp.returncode != 0 or verbose:
116                 print(stdout, file=out)
117                 print(stderr, file=out)
118
119         # This catches setxkbmap errors.
120         except subprocess.CalledProcessError as err:
121             print('ERROR: Failed to compile: {}'.format(' '.join(args)), file=out)
122             print(err.output, file=out)
123             success = False
124
125         return success, out.getvalue()
126     except KeyboardInterrupt:
127         pass
128
129
130 def parse(path):
131     root = ET.fromstring(open(path).read())
132     layouts = root.findall('layoutList/layout')
133
134     options = [
135         e.text
136         for e in root.findall('optionList/group/option/configItem/name')
137     ]
138
139     combos = []
140     for l in layouts:
141         layout = l.find('configItem/name').text
142         combos.append({'l': layout})
143
144         variants = l.findall('variantList/variant')
145         for v in variants:
146             variant = v.find('configItem/name').text
147
148             combos.append({'l': layout, 'v': variant})
149             for option in options:
150                 combos.append({'l': layout, 'v': variant, 'o': option})
151
152     return combos
153
154
155 def run(combos, tool, njobs):
156     failed = False
157     with Pool(njobs) as p:
158         results = p.imap_unordered(tool, combos)
159         for success, output in progress_bar(results, total=len(combos)):
160             if not success:
161                 failed = True
162             if output:
163                 print(output, file=sys.stdout if success else sys.stderr)
164     return failed
165
166
167 def main(args):
168     tools = {
169         'libxkbcommon': xkbcommontool,
170         'xkbcomp': xkbcomp,
171     }
172
173     parser = argparse.ArgumentParser(
174         description='Tool to test all layout/variant/option combinations.'
175     )
176     parser.add_argument('path', metavar='/path/to/evdev.xml',
177                         nargs='?', type=str,
178                         default=DEFAULT_RULES_XML,
179                         help='Path to xkeyboard-config\'s evdev.xml')
180     parser.add_argument('--tool', choices=tools.keys(),
181                         type=str, default='libxkbcommon',
182                         help='parsing tool to use')
183     parser.add_argument('--jobs', '-j', type=int,
184                         default=os.cpu_count() * 4,
185                         help='number of processes to use')
186     args = parser.parse_args()
187
188     tool = tools[args.tool]
189
190     combos = parse(args.path)
191     failed = run(combos, tool, args.jobs)
192     sys.exit(failed)
193
194
195 if __name__ == '__main__':
196     try:
197         main(sys.argv)
198     except KeyboardInterrupt:
199         print('Exiting after Ctrl+C')