]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - packages/Python/lldbsuite/test_event/formatter/curses.py
Vendor import of lldb trunk r290819:
[FreeBSD/FreeBSD.git] / packages / Python / lldbsuite / test_event / formatter / curses.py
1 """
2                      The LLVM Compiler Infrastructure
3
4  This file is distributed under the University of Illinois Open Source
5  License. See LICENSE.TXT for details.
6 """
7
8 from __future__ import absolute_import
9 from __future__ import print_function
10
11 # System modules
12 import curses
13 import datetime
14 import math
15 import sys
16 import time
17
18 # Third-party modules
19
20 # LLDB modules
21 from lldbsuite.test import lldbcurses
22
23 from . import results_formatter
24 from ..event_builder import EventBuilder
25
26
27 class Curses(results_formatter.ResultsFormatter):
28     """Receives live results from tests that are running and reports them to the terminal in a curses GUI"""
29
30     def __init__(self, out_file, options, file_is_stream):
31         # Initialize the parent
32         super(Curses, self).__init__(out_file, options, file_is_stream)
33         self.using_terminal = True
34         self.have_curses = True
35         self.initialize_event = None
36         self.jobs = [None] * 64
37         self.job_tests = [None] * 64
38         self.results = list()
39         try:
40             self.main_window = lldbcurses.intialize_curses()
41             self.main_window.add_key_action(
42                 '\t',
43                 self.main_window.select_next_first_responder,
44                 "Switch between views that can respond to keyboard input")
45             self.main_window.refresh()
46             self.job_panel = None
47             self.results_panel = None
48             self.status_panel = None
49             self.info_panel = None
50             self.hide_status_list = list()
51             self.start_time = time.time()
52         except:
53             self.have_curses = False
54             lldbcurses.terminate_curses()
55             self.using_terminal = False
56             print("Unexpected error:", sys.exc_info()[0])
57             raise
58
59         self.line_dict = dict()
60         # self.events_file = open("/tmp/events.txt", "w")
61         # self.formatters = list()
62         # if tee_results_formatter:
63         #     self.formatters.append(tee_results_formatter)
64
65     def status_to_short_str(self, status, test_event):
66         if status == EventBuilder.STATUS_SUCCESS:
67             return '.'
68         elif status == EventBuilder.STATUS_FAILURE:
69             return 'F'
70         elif status == EventBuilder.STATUS_UNEXPECTED_SUCCESS:
71             return '?'
72         elif status == EventBuilder.STATUS_EXPECTED_FAILURE:
73             return 'X'
74         elif status == EventBuilder.STATUS_SKIP:
75             return 'S'
76         elif status == EventBuilder.STATUS_ERROR:
77             if test_event.get("issue_phase", None) == "build":
78                 # Build failure
79                 return 'B'
80             else:
81                 return 'E'
82         elif status == EventBuilder.STATUS_TIMEOUT:
83             return 'T'
84         elif status == EventBuilder.STATUS_EXPECTED_TIMEOUT:
85             return 't'
86         else:
87             return status
88
89     def show_info_panel(self):
90         selected_idx = self.results_panel.get_selected_idx()
91         if selected_idx >= 0 and selected_idx < len(self.results):
92             if self.info_panel is None:
93                 info_frame = self.results_panel.get_contained_rect(
94                     top_inset=10, left_inset=10, right_inset=10, height=30)
95                 self.info_panel = lldbcurses.BoxedPanel(
96                     info_frame, "Result Details")
97                 # Add a key action for any key that will hide this panel when
98                 # any key is pressed
99                 self.info_panel.add_key_action(-1,
100                                                self.hide_info_panel,
101                                                'Hide the info panel')
102                 self.info_panel.top()
103             else:
104                 self.info_panel.show()
105
106             self.main_window.push_first_responder(self.info_panel)
107             test_start = self.results[selected_idx][0]
108             test_result = self.results[selected_idx][1]
109             self.info_panel.set_line(
110                 0, "File: %s" %
111                 (test_start['test_filename']))
112             self.info_panel.set_line(
113                 1, "Test: %s.%s" %
114                 (test_start['test_class'], test_start['test_name']))
115             self.info_panel.set_line(
116                 2, "Time: %s" %
117                 (test_result['elapsed_time']))
118             self.info_panel.set_line(3, "Status: %s" % (test_result['status']))
119
120     def hide_info_panel(self):
121         self.main_window.pop_first_responder(self.info_panel)
122         self.info_panel.hide()
123         self.main_window.refresh()
124
125     def toggle_status(self, status):
126         if status:
127             # Toggle showing and hiding results whose status matches "status"
128             # in "Results" window
129             if status in self.hide_status_list:
130                 self.hide_status_list.remove(status)
131             else:
132                 self.hide_status_list.append(status)
133             self.update_results()
134
135     def update_results(self, update=True):
136         '''Called after a category of test have been show/hidden to update the results list with
137            what the user desires to see.'''
138         self.results_panel.clear(update=False)
139         for result in self.results:
140             test_result = result[1]
141             status = test_result['status']
142             if status in self.hide_status_list:
143                 continue
144             name = test_result['test_class'] + '.' + test_result['test_name']
145             self.results_panel.append_line(
146                 '%s (%6.2f sec) %s' %
147                 (self.status_to_short_str(
148                     status,
149                     test_result),
150                     test_result['elapsed_time'],
151                     name))
152         if update:
153             self.main_window.refresh()
154
155     def handle_event(self, test_event):
156         with self.lock:
157             super(Curses, self).handle_event(test_event)
158             # for formatter in self.formatters:
159             #     formatter.process_event(test_event)
160             if self.have_curses:
161                 worker_index = -1
162                 if 'worker_index' in test_event:
163                     worker_index = test_event['worker_index']
164                 if 'event' in test_event:
165                     check_for_one_key = True
166                     #print(str(test_event), file=self.events_file)
167                     event = test_event['event']
168                     if self.status_panel:
169                         self.status_panel.update_status(
170                             'time', str(
171                                 datetime.timedelta(
172                                     seconds=math.floor(
173                                         time.time() - self.start_time))))
174                     if event == 'test_start':
175                         name = test_event['test_class'] + \
176                             '.' + test_event['test_name']
177                         self.job_tests[worker_index] = test_event
178                         if 'pid' in test_event:
179                             line = 'pid: %5d ' % (test_event['pid']) + name
180                         else:
181                             line = name
182                         self.job_panel.set_line(worker_index, line)
183                         self.main_window.refresh()
184                     elif event == 'test_result':
185                         status = test_event['status']
186                         self.status_panel.increment_status(status)
187                         if 'pid' in test_event:
188                             line = 'pid: %5d ' % (test_event['pid'])
189                         else:
190                             line = ''
191                         self.job_panel.set_line(worker_index, line)
192                         name = test_event['test_class'] + \
193                             '.' + test_event['test_name']
194                         elapsed_time = test_event[
195                             'event_time'] - self.job_tests[worker_index]['event_time']
196                         if status not in self.hide_status_list:
197                             self.results_panel.append_line(
198                                 '%s (%6.2f sec) %s' %
199                                 (self.status_to_short_str(
200                                     status, test_event), elapsed_time, name))
201                         self.main_window.refresh()
202                         # Append the result pairs
203                         test_event['elapsed_time'] = elapsed_time
204                         self.results.append(
205                             [self.job_tests[worker_index], test_event])
206                         self.job_tests[worker_index] = ''
207                     elif event == 'job_begin':
208                         self.jobs[worker_index] = test_event
209                         if 'pid' in test_event:
210                             line = 'pid: %5d ' % (test_event['pid'])
211                         else:
212                             line = ''
213                         self.job_panel.set_line(worker_index, line)
214                     elif event == 'job_end':
215                         self.jobs[worker_index] = ''
216                         self.job_panel.set_line(worker_index, '')
217                     elif event == 'initialize':
218                         self.initialize_event = test_event
219                         num_jobs = test_event['worker_count']
220                         job_frame = self.main_window.get_contained_rect(
221                             height=num_jobs + 2)
222                         results_frame = self.main_window.get_contained_rect(
223                             top_inset=num_jobs + 2, bottom_inset=1)
224                         status_frame = self.main_window.get_contained_rect(
225                             height=1, top_inset=self.main_window.get_size().h - 1)
226                         self.job_panel = lldbcurses.BoxedPanel(
227                             frame=job_frame, title="Jobs")
228                         self.results_panel = lldbcurses.BoxedPanel(
229                             frame=results_frame, title="Results")
230
231                         self.results_panel.add_key_action(
232                             curses.KEY_UP,
233                             self.results_panel.select_prev,
234                             "Select the previous list entry")
235                         self.results_panel.add_key_action(
236                             curses.KEY_DOWN, self.results_panel.select_next, "Select the next list entry")
237                         self.results_panel.add_key_action(
238                             curses.KEY_HOME,
239                             self.results_panel.scroll_begin,
240                             "Scroll to the start of the list")
241                         self.results_panel.add_key_action(
242                             curses.KEY_END, self.results_panel.scroll_end, "Scroll to the end of the list")
243                         self.results_panel.add_key_action(
244                             curses.KEY_ENTER,
245                             self.show_info_panel,
246                             "Display info for the selected result item")
247                         self.results_panel.add_key_action(
248                             '.',
249                             lambda: self.toggle_status(
250                                 EventBuilder.STATUS_SUCCESS),
251                             "Toggle showing/hiding tests whose status is 'success'")
252                         self.results_panel.add_key_action(
253                             'e',
254                             lambda: self.toggle_status(
255                                 EventBuilder.STATUS_ERROR),
256                             "Toggle showing/hiding tests whose status is 'error'")
257                         self.results_panel.add_key_action(
258                             'f',
259                             lambda: self.toggle_status(
260                                 EventBuilder.STATUS_FAILURE),
261                             "Toggle showing/hiding tests whose status is 'failure'")
262                         self.results_panel.add_key_action('s', lambda: self.toggle_status(
263                             EventBuilder.STATUS_SKIP), "Toggle showing/hiding tests whose status is 'skip'")
264                         self.results_panel.add_key_action(
265                             'x',
266                             lambda: self.toggle_status(
267                                 EventBuilder.STATUS_EXPECTED_FAILURE),
268                             "Toggle showing/hiding tests whose status is 'expected_failure'")
269                         self.results_panel.add_key_action(
270                             '?',
271                             lambda: self.toggle_status(
272                                 EventBuilder.STATUS_UNEXPECTED_SUCCESS),
273                             "Toggle showing/hiding tests whose status is 'unexpected_success'")
274                         self.status_panel = lldbcurses.StatusPanel(
275                             frame=status_frame)
276
277                         self.main_window.add_child(self.job_panel)
278                         self.main_window.add_child(self.results_panel)
279                         self.main_window.add_child(self.status_panel)
280                         self.main_window.set_first_responder(
281                             self.results_panel)
282
283                         self.status_panel.add_status_item(
284                             name="time",
285                             title="Elapsed",
286                             format="%s",
287                             width=20,
288                             value="0:00:00",
289                             update=False)
290                         self.status_panel.add_status_item(
291                             name=EventBuilder.STATUS_SUCCESS,
292                             title="Success",
293                             format="%u",
294                             width=20,
295                             value=0,
296                             update=False)
297                         self.status_panel.add_status_item(
298                             name=EventBuilder.STATUS_FAILURE,
299                             title="Failure",
300                             format="%u",
301                             width=20,
302                             value=0,
303                             update=False)
304                         self.status_panel.add_status_item(
305                             name=EventBuilder.STATUS_ERROR,
306                             title="Error",
307                             format="%u",
308                             width=20,
309                             value=0,
310                             update=False)
311                         self.status_panel.add_status_item(
312                             name=EventBuilder.STATUS_SKIP,
313                             title="Skipped",
314                             format="%u",
315                             width=20,
316                             value=0,
317                             update=True)
318                         self.status_panel.add_status_item(
319                             name=EventBuilder.STATUS_EXPECTED_FAILURE,
320                             title="Expected Failure",
321                             format="%u",
322                             width=30,
323                             value=0,
324                             update=False)
325                         self.status_panel.add_status_item(
326                             name=EventBuilder.STATUS_UNEXPECTED_SUCCESS,
327                             title="Unexpected Success",
328                             format="%u",
329                             width=30,
330                             value=0,
331                             update=False)
332                         self.main_window.refresh()
333                     elif event == 'terminate':
334                         # self.main_window.key_event_loop()
335                         lldbcurses.terminate_curses()
336                         check_for_one_key = False
337                         self.using_terminal = False
338                         # Check for 1 keypress with no delay
339
340                     # Check for 1 keypress with no delay
341                     if check_for_one_key:
342                         self.main_window.key_event_loop(0, 1)