-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathtest_justfile.py
executable file
·265 lines (214 loc) · 10.6 KB
/
test_justfile.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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Simple harness for automating the task of testing that the justfile works
reasonably properly after a refactoring.
"""
from __future__ import (absolute_import, division, print_function,
with_statement, unicode_literals)
__author__ = "Stephan Sokolow (deitarion/SSokolow)"
__appname__ = "Test harness for justfile"
__version__ = "0.1"
__license__ = "Apache-2.0 OR MIT"
import logging, os, re, shutil, subprocess, unittest
from gzip import GzipFile
from gen_justfile_reference import get_evaluated_variables
log = logging.getLogger(__name__)
class TestJustfile(unittest.TestCase):
"""Test suite for rust-cli-boilerplate justfile"""
def __init__(self, methodName='runTest'):
super(TestJustfile, self).__init__(methodName=methodName)
self.vars = get_evaluated_variables(include_private=True)
def _assert_task(self, task, regex):
"""Run a just task and assert the exit code and output printed"""
output = subprocess.check_output(['just'] + task,
stderr=subprocess.STDOUT)
self.assertRegex(output, regex)
return output
def _assert_file_contains(self, path, substr, count=None):
"""Check that a given file contains a string `count` times"""
opener = GzipFile if os.path.splitext(path)[1] == '.gz' else open
with opener(path) as fobj:
found = fobj.read().count(substr)
# Quick hack to support "any number is OK"
if count is None:
count = found = min(found, 1)
count_str = "at least 1"
else:
count_str = count
self.assertEqual(count, found, "Expected %s occurrence(s) of %r "
"(got %s)" % (count_str, substr, found))
def test_a_invariants(self):
"""invariants required by tests
(The _a_ in the name is just to make it run first)
"""
variables = get_evaluated_variables(include_private=True)
self.assertNotIn('--release', variables['_build_flags'],
"--release shouldn't be in the default build flags, since they "
"get used by dev-mode commands.")
def test_bloat(self):
"""just bloat"""
self._assert_task(['bloat'], b'Crate Name\n')
self._assert_task(['bloat', '--', '--crates'], b'Size Name\n')
def test_build(self):
"""just build"""
if os.path.exists(self.vars['_dbg_bin_path']):
os.remove(self.vars['_dbg_bin_path'])
self._assert_task(['build'], br'Finished dev \[unoptimized')
self.assertTrue(os.path.isfile(self.vars['_dbg_bin_path']))
def test_build_release(self):
"""just build-dist"""
for ext in ('', '.stripped', '.packed'):
if os.path.exists(self.vars['_rls_bin_path']):
os.remove(self.vars['_rls_bin_path'] + ext)
self._assert_task(['build-dist', '--set', 'upx_flags', ''],
b'--== Final Result ==--')
for ext in ('', '.stripped', '.packed'):
self.assertTrue(os.path.isfile(self.vars['_rls_bin_path'] + ext))
def test_check(self):
"""just check"""
self._assert_task(['check'], br'Finished dev \[unoptimized')
self._assert_task(['check', '--', '--message-format', 'json'],
br'\s*"target"\s*:\s*{')
def test_clean(self):
"""just clean
NOTE: Overrides _cargo to test what matters quickly.
"""
self._assert_task(['clean', '--set', '_cargo', 'echo'],
b'echo clean -v \nclean -v\n'
b'export CARGO_TARGET_DIR="target/kcov" && echo clean -v\n'
b'clean -v\nrm -rf dist\n')
self._assert_task(['clean', '--set', '_cargo',
'echo', '--', '--release'],
b'echo clean -v --release\nclean -v --release\n'
b'export CARGO_TARGET_DIR="target/kcov" && '
b'echo clean -v\n'
b'clean -v\nrm -rf dist\n')
def test_dist(self):
"""just dist"""
outpath = 'dist/{}'.format(self.vars['_pkgname'])
if os.path.exists(outpath):
os.remove(outpath)
self._assert_task(['dist', '--set', 'upx_flags', ''],
br'Finished release \[optimized\]')
self.assertTrue(os.path.isfile(outpath))
def test_dist_supplemental(self):
"""just dist-supplemental"""
artifacts = ['boilerplate.1.gz', 'boilerplate.bash', 'boilerplate.zsh',
'boilerplate.elvish', 'boilerplate.powershell',
'boilerplate.fish']
for fname in artifacts:
if os.path.exists('dist/' + fname):
os.remove('dist/' + fname)
self._assert_task(['dist-supplemental'],
br'Finished release \[optimized\]')
for fname in artifacts:
self.assertTrue(os.path.isfile('dist/' + fname))
# Trust that help2man and clap will do their own testing and just
# verify that we're successfully invoking the proper functionality
# (count=1 on the manpage to account for how help2man fails
# if you accidentally include --help in the base command)
self._assert_file_contains('dist/boilerplate.1.gz',
b'\n.SS "USAGE:"\n', count=1)
self._assert_file_contains('dist/boilerplate.bash',
'COMPREPLY=()')
self._assert_file_contains('dist/boilerplate.elvish',
'edit:complex-candidate')
self._assert_file_contains('dist/boilerplate.fish',
'__fish_use_subcommand')
self._assert_file_contains('dist/boilerplate.powershell',
'[CompletionResult]::new')
self._assert_file_contains('dist/boilerplate.zsh',
'typeset -A opt_args')
def test_doc(self):
"""just doc"""
for command, expected in (
(['doc'], br' Finished dev \[unoptimized'),
(['doc', '--', '--message-format', 'json'],
br'\s*"target"\s*:\s*{')):
# Save time by trusting that, if `cargo doc` regenerates
# part of the docs, it's indicative of full proper function
outpath = ("target/{}/doc/log/index.html"
.format(self.vars['CARGO_BUILD_TARGET']))
if os.path.exists(outpath):
os.remove(outpath)
self._assert_task(command, expected)
self.assertTrue(os.path.isfile(outpath),
'%s not a file (%s)' % (outpath, command))
def test_fmt(self):
"""just fmt"""
# Avoid having to save and restore the un-formatted versions by only
# testing that the expected command gets emitted without error
self._assert_task(['fmt', '--set', '_cargo_cmd', 'echo'],
b'(^|\n)echo [+]nightly fmt --\s*(\n|$)')
self._assert_task(['fmt', '--set', '_cargo_cmd', 'echo', '--', '-V'],
b'(^|\n)echo [+]nightly fmt -- -V\s*(\n|$)')
# TODO: Decide how to actually test that the files would be modified
def test_fmt_check(self):
"""just fmt-check"""
self._assert_task(['fmt-check'],
b'\n(' + re.escape(b'\x1b[m\x0f\x1b[31m\x1b[1m') + b')?' +
br'warning: (' + re.escape(b'\x1b[m\x0f\x1b[1m') +
br')?found TODO')
self._assert_task(['fmt-check', '--', '-V'],
br'\nrustfmt \S+-nightly \(\S+ 2\d\d\d-\d\d-\d\d\)')
# TODO: Assert that the files were not modified
# TODO: I need to decide how best to test these commands:
# - add, rm, and update
# TODO: The following commands need to be tested by overriding the commands
# to simulate --dry-run:
# - install, install-cargo-deps, install-rustup-deps, uninstall,
# install-deps, install-apt-deps
def test_kcachegrind(self):
"""just kcachegrind
NOTE: Overrides _cargo to test what matters quickly.
"""
callgrind_temp = self.vars['callgrind_out_file']
for arg in ([], ['--set', 'build_flags', ' --release']):
# TODO: Remove the target binary to verify correct paths get built
if os.path.exists(callgrind_temp):
os.remove(callgrind_temp)
# The justfile echoing and the command output are both checked
# to ensure a --release can't sneak in.
output = self._assert_task(['kcachegrind'] + arg + [
'--set', 'kcachegrind', 'echo kcachegrind-foo'],
b'\necho kcachegrind-foo \'callgrind.out.justfile\'\n'
b'kcachegrind-foo callgrind.out.justfile\n')
self.assertNotIn(b'--release', output)
self.assertTrue(os.path.isfile(callgrind_temp))
os.remove(callgrind_temp)
output = self._assert_task(['kcachegrind'] + arg + [
'--set', 'kcachegrind',
'echo kcachegrind-bar', '--', '--help'], b'.*USAGE:.*')
self.assertNotIn(b'--release', output)
self.assertTrue(os.path.isfile(callgrind_temp))
def test_kcov(self):
"""just kcov"""
outdir = 'target/kcov/html'
for arg in ([], ['--set', 'build_flags', ' --release']):
if os.path.exists(outdir):
shutil.rmtree(outdir)
# The justfile echoing and the command output are both checked
# to ensure a --release can't sneak in.
output = self._assert_task(['kcov'] + arg, br'\ntest result:')
self.assertNotIn(b'--release', output)
self.assertTrue(os.path.isdir(outdir))
def test_run(self):
"""just run"""
self._assert_task(['run', '--', '--help'], br'\nUSAGE:')
try:
subprocess.check_output(['just', 'run', '/bin/sh'],
stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as err:
self.assertIn(b"panicked at 'not yet implemented'", err.output)
else:
self.fail("Called process should have panic'd at `unimplemented!`")
def test_test(self):
"""just test (and the default command)"""
for subcommand in ([], ['test']):
self._assert_task(subcommand, br'\ntest result: ')
if __name__ == '__main__':
print("NOTE: This test suite will currently fail unless you manually edit "
"Cargo.toml to set a valid package name.")
os.chdir(os.path.join(os.path.dirname(__file__), 'template'))
unittest.main()
# vim: set sw=4 sts=4 expandtab :