-
Notifications
You must be signed in to change notification settings - Fork 115
/
test_runner.py
149 lines (116 loc) · 4.89 KB
/
test_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
138
139
140
141
142
143
144
145
146
147
148
149
from threading import Thread
import contextlib
import os
import unittest
import sublime
import sublime_plugin
class __vi_tests_write_buffer(sublime_plugin.TextCommand):
"""Replaces the buffer's content with the specified `text`.
`text`: Text to be written to the buffer.
"""
def run(self, edit, text=''):
self.view.replace(edit, sublime.Region(0, self.view.size()), text)
class __vi_tests_erase_all(sublime_plugin.TextCommand):
"""Replaces the buffer's content with the specified `text`.
"""
def run(self, edit):
self.view.erase(edit, sublime.Region(0, self.view.size()))
class OutputPanel(object):
def __init__(self, name,
file_regex='',
line_regex='',
base_dir=None,
word_wrap=False,
line_numbers=False,
gutter=False,
scroll_past_end=False,
syntax='',
):
self.name = name
self.window = sublime.active_window()
if not hasattr(self, 'output_view'):
# Try not to call get_output_panel until the regexes are assigned
self.output_view = self.window.create_output_panel(self.name)
# Default to the current file directory
if (not base_dir and self.window.active_view() and
self.window.active_view().file_name()):
base_dir = os.path.dirname(
self.window.active_view().file_name()
)
self.output_view.settings().set('result_file_regex', file_regex)
self.output_view.settings().set('result_line_regex', line_regex)
self.output_view.settings().set('result_base_dir', base_dir)
self.output_view.settings().set('word_wrap', word_wrap)
self.output_view.settings().set('line_numbers', line_numbers)
self.output_view.settings().set('gutter', gutter)
self.output_view.settings().set('scroll_past_end', scroll_past_end)
self.output_view.settings().set('syntax', syntax)
# Call create_output_panel a second time after assigning the above
# settings, so that it'll be picked up as a result buffer
self.window.create_output_panel(self.name)
def write(self, s):
f = lambda: self.output_view.run_command('append', {'characters': s})
sublime.set_timeout(f, 0)
def flush(self):
pass
def show(self):
self.window.run_command(
'show_panel', {'panel': 'output.' + self.name}
)
def close(self):
pass
class RunVintageousTests(sublime_plugin.WindowCommand):
'''
Runs tests and displays the results.
- Do not use Sublime Text while tests are running.
@working_dir
Required. Should be the parent of the top-level directory for `tests`.
@loader_pattern
Optional. Only run tests matching this glob.
@tests_dir
Name of the directory containing tests.
@active_file_only
Optional. Only run tests in the active file in ST. Shadows
@loader_pattern.
To use this runner conveniently, open the command palette and select one
of the `Build: Vintageous - Test *` commands.
'''
def run(self, working_dir,
loader_pattern="test*.py",
tests_dir="tests",
**kwargs):
assert os.path.exists(working_dir), 'working_dir must exist'
with self.chdir(working_dir):
p = os.path.join(os.getcwd(), tests_dir)
patt = loader_pattern
# TODO(guillermooo): I can't get $file to expand in the build
# system. It should be possible to make the following code simpler
# with it.
if kwargs.get('active_file_only') is True:
patt = os.path.basename(self.window.active_view().file_name())
# run text-based tests
if patt.endswith(('.cmd-test', '.cmd-test-solo')):
patt = 'test_all_cmds.py'
suite = unittest.TestLoader().discover(p, pattern=patt)
file_regex = r'^\s*File\s*"([^.].*?)",\s*line\s*(\d+),.*$'
display = OutputPanel('vintageous.tests',
file_regex=file_regex,
word_wrap=True
)
display.show()
runner = unittest.TextTestRunner(stream=display, verbosity=1)
def run_and_display():
runner.run(suite)
# XXX: If we don't do this, custom mappings won't be available
# after running the test suite.
self.window.run_command('reset_vintageous')
Thread(target=run_and_display).start()
@contextlib.contextmanager
def chdir(self, path=None):
old_path = os.getcwd()
if path:
assert os.path.exists(path), "'path' is invalid {}".format(path)
os.chdir(path)
yield
if path is not None:
os.chdir(old_path)