-
Notifications
You must be signed in to change notification settings - Fork 2
/
runner.py
137 lines (103 loc) · 4.4 KB
/
runner.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import sublime
import sublime_plugin
from itertools import chain
import io
import os
import tempfile
import unittest
# A tuple: (low level file_descriptor, path) as returned by `tempfile.mkstemp()`.
TEST_DATA_PATH = None
def make_temp_file():
global TEST_DATA_PATH
TEST_DATA_PATH = tempfile.mkstemp()
class TestsState(object):
running = False
view = None
suite = None
@staticmethod
def reset():
TestsState.suite = None
@staticmethod
def reset_window_settings(names):
for name in names:
TestsState.view.window().settings().erase(name)
@staticmethod
def reset_view_settings(names):
for name in names:
TestsState.view.settings().erase(name)
def combine(suite):
# Combine all tests under one key for convenience. Ignore keys starting with an underscore. Use
# these for subsets of all the remaining tests that you don't want repeated under '_all_'.
# Convert to list so the 'chain' doesn't get exhausted after the first use.
all_tests = list(chain(*(data for (key, data)
in suite.items()
if not key.startswith('_'))))
suite['_all_'] = all_tests
return suite
def register_tests(suite):
_xpt_show_suites.suite = combine(suite)
class _xpt_show_suites(sublime_plugin.WindowCommand):
'''Displays a quick panel listing all available test stuites.
'''
suite = None
def run(self):
TestsState.running = True
self.window.show_quick_panel(sorted(_xpt_show_suites.suite.keys()), self.on_done)
def on_done(self, idx):
if idx == -1:
sublime.status_message('_PackageTesting: No test suite selected.')
return
suite_name = sorted(_xpt_show_suites.suite.keys())[idx]
TestsState.suite = suite_name
self.window.run_command('_xpt_run_tests')
class _xpt_print_results(sublime_plugin.TextCommand):
def run(self, edit, content):
view = sublime.active_window().new_file()
view.insert(edit, 0, content)
view.set_scratch(True)
class _xpt_run_tests(sublime_plugin.WindowCommand):
def run(self):
make_temp_file()
# We open the file here, but Sublime Text loads it asynchronously, so we continue in an
# event handler, once it's been fully loaded.
self.window.open_file(TEST_DATA_PATH[1])
class _xpt_test_data_dispatcher(sublime_plugin.EventListener):
def on_load(self, view):
if TEST_DATA_PATH:
try:
if (view.file_name() and view.file_name() == TEST_DATA_PATH[1] and
TestsState.running):
TestsState.running = False
TestsState.view = view
suite_names = _xpt_show_suites.suite[TestsState.suite]
suite = unittest.TestLoader().loadTestsFromNames(suite_names)
bucket = io.StringIO()
unittest.TextTestRunner(stream=bucket, verbosity=1).run(suite)
view.run_command('_xpt_print_results', {'content': bucket.getvalue()})
w = sublime.active_window()
# Close data view.
w.run_command('prev_view')
TestsState.view.set_scratch(True)
w.run_command('close')
w.run_command('next_view')
# Ugly hack to return focus to the results view.
w.run_command('show_panel', {'panel': 'console', 'toggle': True})
w.run_command('show_panel', {'panel': 'console', 'toggle': True})
except Exception as e:
print(e)
finally:
try:
os.close(TEST_DATA_PATH[0])
except Exception as e:
print('Could not close temp file...')
print(e)
class WriteToBuffer(sublime_plugin.TextCommand):
'''Replaces the buffer's content with the specified `text`.
`text`: Text to be written to the buffer.
`file_name`: If this file name does not match the receiving view's, abort.
'''
def run(self, edit, file_name='', text=''):
if not file_name:
return
if self.view.file_name().lower() == file_name.lower():
self.view.replace(edit, sublime.Region(0, self.view.size()), text)