##// END OF EJS Templates
testing: expand Hypothesis tests with branch commands...
David R. MacIver -
r28256:55325bdf default
parent child Browse files
Show More
@@ -1,404 +1,438 b''
1 from __future__ import print_function, absolute_import
1 from __future__ import print_function, absolute_import
2
2
3 """Fuzz testing for operations against a Mercurial repository
3 """Fuzz testing for operations against a Mercurial repository
4
4
5 This uses Hypothesis's stateful testing to generate random repository
5 This uses Hypothesis's stateful testing to generate random repository
6 operations and test Mercurial using them, both to see if there are any
6 operations and test Mercurial using them, both to see if there are any
7 unexpected errors and to compare different versions of it."""
7 unexpected errors and to compare different versions of it."""
8
8
9 import os
9 import os
10 import sys
10 import sys
11
11
12 # These tests require Hypothesis and pytz to be installed.
12 # These tests require Hypothesis and pytz to be installed.
13 # Running 'pip install hypothesis pytz' will achieve that.
13 # Running 'pip install hypothesis pytz' will achieve that.
14 # Note: This won't work if you're running Python < 2.7.
14 # Note: This won't work if you're running Python < 2.7.
15 try:
15 try:
16 from hypothesis.extra.datetime import datetimes
16 from hypothesis.extra.datetime import datetimes
17 except ImportError:
17 except ImportError:
18 sys.stderr.write("skipped: hypothesis or pytz not installed" + os.linesep)
18 sys.stderr.write("skipped: hypothesis or pytz not installed" + os.linesep)
19 sys.exit(80)
19 sys.exit(80)
20
20
21 # If you are running an old version of pip you may find that the enum34
21 # If you are running an old version of pip you may find that the enum34
22 # backport is not installed automatically. If so 'pip install enum34' will
22 # backport is not installed automatically. If so 'pip install enum34' will
23 # fix this problem.
23 # fix this problem.
24 try:
24 try:
25 import enum
25 import enum
26 assert enum # Silence pyflakes
26 assert enum # Silence pyflakes
27 except ImportError:
27 except ImportError:
28 sys.stderr.write("skipped: enum34 not installed" + os.linesep)
28 sys.stderr.write("skipped: enum34 not installed" + os.linesep)
29 sys.exit(80)
29 sys.exit(80)
30
30
31 import binascii
31 import binascii
32 from contextlib import contextmanager
32 from contextlib import contextmanager
33 import errno
33 import errno
34 import pipes
34 import pipes
35 import shutil
35 import shutil
36 import silenttestrunner
36 import silenttestrunner
37 import subprocess
37 import subprocess
38
38
39 from hypothesis.errors import HypothesisException
39 from hypothesis.errors import HypothesisException
40 from hypothesis.stateful import rule, RuleBasedStateMachine, Bundle
40 from hypothesis.stateful import rule, RuleBasedStateMachine, Bundle
41 from hypothesis import settings, note, strategies as st
41 from hypothesis import settings, note, strategies as st
42 from hypothesis.configuration import set_hypothesis_home_dir
42 from hypothesis.configuration import set_hypothesis_home_dir
43
43
44 testdir = os.path.abspath(os.environ["TESTDIR"])
44 testdir = os.path.abspath(os.environ["TESTDIR"])
45
45
46 # We store Hypothesis examples here rather in the temporary test directory
46 # We store Hypothesis examples here rather in the temporary test directory
47 # so that when rerunning a failing test this always results in refinding the
47 # so that when rerunning a failing test this always results in refinding the
48 # previous failure. This directory is in .hgignore and should not be checked in
48 # previous failure. This directory is in .hgignore and should not be checked in
49 # but is useful to have for development.
49 # but is useful to have for development.
50 set_hypothesis_home_dir(os.path.join(testdir, ".hypothesis"))
50 set_hypothesis_home_dir(os.path.join(testdir, ".hypothesis"))
51
51
52 runtests = os.path.join(os.environ["RUNTESTDIR"], "run-tests.py")
52 runtests = os.path.join(os.environ["RUNTESTDIR"], "run-tests.py")
53 testtmp = os.environ["TESTTMP"]
53 testtmp = os.environ["TESTTMP"]
54 assert os.path.isdir(testtmp)
54 assert os.path.isdir(testtmp)
55
55
56 generatedtests = os.path.join(testdir, "hypothesis-generated")
56 generatedtests = os.path.join(testdir, "hypothesis-generated")
57
57
58 try:
58 try:
59 os.makedirs(generatedtests)
59 os.makedirs(generatedtests)
60 except OSError:
60 except OSError:
61 pass
61 pass
62
62
63 # We write out generated .t files to a file in order to ease debugging and to
63 # We write out generated .t files to a file in order to ease debugging and to
64 # give a starting point for turning failures Hypothesis finds into normal
64 # give a starting point for turning failures Hypothesis finds into normal
65 # tests. In order to ensure that multiple copies of this test can be run in
65 # tests. In order to ensure that multiple copies of this test can be run in
66 # parallel we use atomic file create to ensure that we always get a unique
66 # parallel we use atomic file create to ensure that we always get a unique
67 # name.
67 # name.
68 file_index = 0
68 file_index = 0
69 while True:
69 while True:
70 file_index += 1
70 file_index += 1
71 savefile = os.path.join(generatedtests, "test-generated-%d.t" % (
71 savefile = os.path.join(generatedtests, "test-generated-%d.t" % (
72 file_index,
72 file_index,
73 ))
73 ))
74 try:
74 try:
75 os.close(os.open(savefile, os.O_CREAT | os.O_EXCL | os.O_WRONLY))
75 os.close(os.open(savefile, os.O_CREAT | os.O_EXCL | os.O_WRONLY))
76 break
76 break
77 except OSError as e:
77 except OSError as e:
78 if e.errno != errno.EEXIST:
78 if e.errno != errno.EEXIST:
79 raise
79 raise
80 assert os.path.exists(savefile)
80 assert os.path.exists(savefile)
81
81
82 hgrc = os.path.join(".hg", "hgrc")
82 hgrc = os.path.join(".hg", "hgrc")
83
83
84 filecharacters = (
84 filecharacters = (
85 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
85 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
86 "[]^_`;=@{}~ !#$%&'()+,-"
86 "[]^_`;=@{}~ !#$%&'()+,-"
87 )
87 )
88
88
89 files = st.text(filecharacters, min_size=1).map(lambda x: x.strip()).filter(
89 files = st.text(filecharacters, min_size=1).map(lambda x: x.strip()).filter(
90 bool).map(lambda s: s.encode('ascii'))
90 bool).map(lambda s: s.encode('ascii'))
91
91
92 safetext = st.text(st.characters(
92 safetext = st.text(st.characters(
93 min_codepoint=1, max_codepoint=127,
93 min_codepoint=1, max_codepoint=127,
94 blacklist_categories=('Cc', 'Cs')), min_size=1).map(
94 blacklist_categories=('Cc', 'Cs')), min_size=1).map(
95 lambda s: s.encode('utf-8')
95 lambda s: s.encode('utf-8')
96 )
96 )
97
97
98 @contextmanager
98 @contextmanager
99 def acceptableerrors(*args):
99 def acceptableerrors(*args):
100 """Sometimes we know an operation we're about to perform might fail, and
100 """Sometimes we know an operation we're about to perform might fail, and
101 we're OK with some of the failures. In those cases this may be used as a
101 we're OK with some of the failures. In those cases this may be used as a
102 context manager and will swallow expected failures, as identified by
102 context manager and will swallow expected failures, as identified by
103 substrings of the error message Mercurial emits."""
103 substrings of the error message Mercurial emits."""
104 try:
104 try:
105 yield
105 yield
106 except subprocess.CalledProcessError as e:
106 except subprocess.CalledProcessError as e:
107 if not any(a in e.output for a in args):
107 if not any(a in e.output for a in args):
108 note(e.output)
108 note(e.output)
109 raise
109 raise
110
110
111 class verifyingstatemachine(RuleBasedStateMachine):
111 class verifyingstatemachine(RuleBasedStateMachine):
112 """This defines the set of acceptable operations on a Mercurial repository
112 """This defines the set of acceptable operations on a Mercurial repository
113 using Hypothesis's RuleBasedStateMachine.
113 using Hypothesis's RuleBasedStateMachine.
114
114
115 The general concept is that we manage multiple repositories inside a
115 The general concept is that we manage multiple repositories inside a
116 repos/ directory in our temporary test location. Some of these are freshly
116 repos/ directory in our temporary test location. Some of these are freshly
117 inited, some are clones of the others. Our current working directory is
117 inited, some are clones of the others. Our current working directory is
118 always inside one of these repositories while the tests are running.
118 always inside one of these repositories while the tests are running.
119
119
120 Hypothesis then performs a series of operations against these repositories,
120 Hypothesis then performs a series of operations against these repositories,
121 including hg commands, generating contents and editing the .hgrc file.
121 including hg commands, generating contents and editing the .hgrc file.
122 If these operations fail in unexpected ways or behave differently in
122 If these operations fail in unexpected ways or behave differently in
123 different configurations of Mercurial, the test will fail and a minimized
123 different configurations of Mercurial, the test will fail and a minimized
124 .t test file will be written to the hypothesis-generated directory to
124 .t test file will be written to the hypothesis-generated directory to
125 exhibit that failure.
125 exhibit that failure.
126
126
127 Operations are defined as methods with @rule() decorators. See the
127 Operations are defined as methods with @rule() decorators. See the
128 Hypothesis documentation at
128 Hypothesis documentation at
129 http://hypothesis.readthedocs.org/en/release/stateful.html for more
129 http://hypothesis.readthedocs.org/en/release/stateful.html for more
130 details."""
130 details."""
131
131
132 # A bundle is a reusable collection of previously generated data which may
132 # A bundle is a reusable collection of previously generated data which may
133 # be provided as arguments to future operations.
133 # be provided as arguments to future operations.
134 paths = Bundle('paths')
134 paths = Bundle('paths')
135 contents = Bundle('contents')
135 contents = Bundle('contents')
136 branches = Bundle('branches')
136 committimes = Bundle('committimes')
137 committimes = Bundle('committimes')
137
138
138 def __init__(self):
139 def __init__(self):
139 super(verifyingstatemachine, self).__init__()
140 super(verifyingstatemachine, self).__init__()
140 self.repodir = os.path.join(testtmp, "repo")
141 self.repodir = os.path.join(testtmp, "repo")
141 if os.path.exists(self.repodir):
142 if os.path.exists(self.repodir):
142 shutil.rmtree(self.repodir)
143 shutil.rmtree(self.repodir)
143 os.chdir(testtmp)
144 os.chdir(testtmp)
144 self.log = []
145 self.log = []
145 self.failed = False
146 self.failed = False
146
147
147 self.mkdirp("repo")
148 self.mkdirp("repo")
148 self.cd("repo")
149 self.cd("repo")
149 self.hg("init")
150 self.hg("init")
150
151
151 def teardown(self):
152 def teardown(self):
152 """On teardown we clean up after ourselves as usual, but we also
153 """On teardown we clean up after ourselves as usual, but we also
153 do some additional testing: We generate a .t file based on our test
154 do some additional testing: We generate a .t file based on our test
154 run using run-test.py -i to get the correct output.
155 run using run-test.py -i to get the correct output.
155
156
156 We then test it in a number of other configurations, verifying that
157 We then test it in a number of other configurations, verifying that
157 each passes the same test."""
158 each passes the same test."""
158 super(verifyingstatemachine, self).teardown()
159 super(verifyingstatemachine, self).teardown()
159 try:
160 try:
160 shutil.rmtree(self.repodir)
161 shutil.rmtree(self.repodir)
161 except OSError:
162 except OSError:
162 pass
163 pass
163 ttest = os.linesep.join(" " + l for l in self.log)
164 ttest = os.linesep.join(" " + l for l in self.log)
164 os.chdir(testtmp)
165 os.chdir(testtmp)
165 path = os.path.join(testtmp, "test-generated.t")
166 path = os.path.join(testtmp, "test-generated.t")
166 with open(path, 'w') as o:
167 with open(path, 'w') as o:
167 o.write(ttest + os.linesep)
168 o.write(ttest + os.linesep)
168 with open(os.devnull, "w") as devnull:
169 with open(os.devnull, "w") as devnull:
169 rewriter = subprocess.Popen(
170 rewriter = subprocess.Popen(
170 [runtests, "--local", "-i", path], stdin=subprocess.PIPE,
171 [runtests, "--local", "-i", path], stdin=subprocess.PIPE,
171 stdout=devnull, stderr=devnull,
172 stdout=devnull, stderr=devnull,
172 )
173 )
173 rewriter.communicate("yes")
174 rewriter.communicate("yes")
174 with open(path, 'r') as i:
175 with open(path, 'r') as i:
175 ttest = i.read()
176 ttest = i.read()
176
177
177 e = None
178 e = None
178 if not self.failed:
179 if not self.failed:
179 try:
180 try:
180 output = subprocess.check_output([
181 output = subprocess.check_output([
181 runtests, path, "--local", "--pure"
182 runtests, path, "--local", "--pure"
182 ], stderr=subprocess.STDOUT)
183 ], stderr=subprocess.STDOUT)
183 assert "Ran 1 test" in output, output
184 assert "Ran 1 test" in output, output
184 except subprocess.CalledProcessError as e:
185 except subprocess.CalledProcessError as e:
185 note(e.output)
186 note(e.output)
186 finally:
187 finally:
187 os.unlink(path)
188 os.unlink(path)
188 try:
189 try:
189 os.unlink(path + ".err")
190 os.unlink(path + ".err")
190 except OSError:
191 except OSError:
191 pass
192 pass
192 if self.failed or e is not None:
193 if self.failed or e is not None:
193 with open(savefile, "wb") as o:
194 with open(savefile, "wb") as o:
194 o.write(ttest)
195 o.write(ttest)
195 if e is not None:
196 if e is not None:
196 raise e
197 raise e
197
198
198 def execute_step(self, step):
199 def execute_step(self, step):
199 try:
200 try:
200 return super(verifyingstatemachine, self).execute_step(step)
201 return super(verifyingstatemachine, self).execute_step(step)
201 except (HypothesisException, KeyboardInterrupt):
202 except (HypothesisException, KeyboardInterrupt):
202 raise
203 raise
203 except Exception:
204 except Exception:
204 self.failed = True
205 self.failed = True
205 raise
206 raise
206
207
207 # Section: Basic commands.
208 # Section: Basic commands.
208 def mkdirp(self, path):
209 def mkdirp(self, path):
209 if os.path.exists(path):
210 if os.path.exists(path):
210 return
211 return
211 self.log.append(
212 self.log.append(
212 "$ mkdir -p -- %s" % (pipes.quote(os.path.relpath(path)),))
213 "$ mkdir -p -- %s" % (pipes.quote(os.path.relpath(path)),))
213 os.makedirs(path)
214 os.makedirs(path)
214
215
215 def cd(self, path):
216 def cd(self, path):
216 path = os.path.relpath(path)
217 path = os.path.relpath(path)
217 if path == ".":
218 if path == ".":
218 return
219 return
219 os.chdir(path)
220 os.chdir(path)
220 self.log.append("$ cd -- %s" % (pipes.quote(path),))
221 self.log.append("$ cd -- %s" % (pipes.quote(path),))
221
222
222 def hg(self, *args):
223 def hg(self, *args):
223 self.command("hg", *args)
224 self.command("hg", *args)
224
225
225 def command(self, *args):
226 def command(self, *args):
226 self.log.append("$ " + ' '.join(map(pipes.quote, args)))
227 self.log.append("$ " + ' '.join(map(pipes.quote, args)))
227 subprocess.check_output(args, stderr=subprocess.STDOUT)
228 subprocess.check_output(args, stderr=subprocess.STDOUT)
228
229
229 # Section: Set up basic data
230 # Section: Set up basic data
230 # This section has no side effects but generates data that we will want
231 # This section has no side effects but generates data that we will want
231 # to use later.
232 # to use later.
232 @rule(
233 @rule(
233 target=paths,
234 target=paths,
234 source=st.lists(files, min_size=1).map(lambda l: os.path.join(*l)))
235 source=st.lists(files, min_size=1).map(lambda l: os.path.join(*l)))
235 def genpath(self, source):
236 def genpath(self, source):
236 return source
237 return source
237
238
238 @rule(
239 @rule(
239 target=committimes,
240 target=committimes,
240 when=datetimes(min_year=1970, max_year=2038) | st.none())
241 when=datetimes(min_year=1970, max_year=2038) | st.none())
241 def gentime(self, when):
242 def gentime(self, when):
242 return when
243 return when
243
244
244 @rule(
245 @rule(
245 target=contents,
246 target=contents,
246 content=st.one_of(
247 content=st.one_of(
247 st.binary(),
248 st.binary(),
248 st.text().map(lambda x: x.encode('utf-8'))
249 st.text().map(lambda x: x.encode('utf-8'))
249 ))
250 ))
250 def gencontent(self, content):
251 def gencontent(self, content):
251 return content
252 return content
252
253
254 @rule(
255 target=branches,
256 name=safetext,
257 )
258 def genbranch(self, name):
259 return name
260
253 @rule(target=paths, source=paths)
261 @rule(target=paths, source=paths)
254 def lowerpath(self, source):
262 def lowerpath(self, source):
255 return source.lower()
263 return source.lower()
256
264
257 @rule(target=paths, source=paths)
265 @rule(target=paths, source=paths)
258 def upperpath(self, source):
266 def upperpath(self, source):
259 return source.upper()
267 return source.upper()
260
268
261 # Section: Basic path operations
269 # Section: Basic path operations
262 @rule(path=paths, content=contents)
270 @rule(path=paths, content=contents)
263 def writecontent(self, path, content):
271 def writecontent(self, path, content):
264 self.unadded_changes = True
272 self.unadded_changes = True
265 if os.path.isdir(path):
273 if os.path.isdir(path):
266 return
274 return
267 parent = os.path.dirname(path)
275 parent = os.path.dirname(path)
268 if parent:
276 if parent:
269 try:
277 try:
270 self.mkdirp(parent)
278 self.mkdirp(parent)
271 except OSError:
279 except OSError:
272 # It may be the case that there is a regular file that has
280 # It may be the case that there is a regular file that has
273 # previously been created that has the same name as an ancestor
281 # previously been created that has the same name as an ancestor
274 # of the current path. This will cause mkdirp to fail with this
282 # of the current path. This will cause mkdirp to fail with this
275 # error. We just turn this into a no-op in that case.
283 # error. We just turn this into a no-op in that case.
276 return
284 return
277 with open(path, 'wb') as o:
285 with open(path, 'wb') as o:
278 o.write(content)
286 o.write(content)
279 self.log.append((
287 self.log.append((
280 "$ python -c 'import binascii; "
288 "$ python -c 'import binascii; "
281 "print(binascii.unhexlify(\"%s\"))' > %s") % (
289 "print(binascii.unhexlify(\"%s\"))' > %s") % (
282 binascii.hexlify(content),
290 binascii.hexlify(content),
283 pipes.quote(path),
291 pipes.quote(path),
284 ))
292 ))
285
293
286 @rule(path=paths)
294 @rule(path=paths)
287 def addpath(self, path):
295 def addpath(self, path):
288 if os.path.exists(path):
296 if os.path.exists(path):
289 self.hg("add", "--", path)
297 self.hg("add", "--", path)
290
298
291 @rule(path=paths)
299 @rule(path=paths)
292 def forgetpath(self, path):
300 def forgetpath(self, path):
293 if os.path.exists(path):
301 if os.path.exists(path):
294 with acceptableerrors(
302 with acceptableerrors(
295 "file is already untracked",
303 "file is already untracked",
296 ):
304 ):
297 self.hg("forget", "--", path)
305 self.hg("forget", "--", path)
298
306
299 @rule(s=st.none() | st.integers(0, 100))
307 @rule(s=st.none() | st.integers(0, 100))
300 def addremove(self, s):
308 def addremove(self, s):
301 args = ["addremove"]
309 args = ["addremove"]
302 if s is not None:
310 if s is not None:
303 args.extend(["-s", str(s)])
311 args.extend(["-s", str(s)])
304 self.hg(*args)
312 self.hg(*args)
305
313
306 @rule(path=paths)
314 @rule(path=paths)
307 def removepath(self, path):
315 def removepath(self, path):
308 if os.path.exists(path):
316 if os.path.exists(path):
309 with acceptableerrors(
317 with acceptableerrors(
310 'file is untracked',
318 'file is untracked',
311 'file has been marked for add',
319 'file has been marked for add',
312 'file is modified',
320 'file is modified',
313 ):
321 ):
314 self.hg("remove", "--", path)
322 self.hg("remove", "--", path)
315
323
316 @rule(
324 @rule(
317 message=safetext,
325 message=safetext,
318 amend=st.booleans(),
326 amend=st.booleans(),
319 when=committimes,
327 when=committimes,
320 addremove=st.booleans(),
328 addremove=st.booleans(),
321 secret=st.booleans(),
329 secret=st.booleans(),
322 close_branch=st.booleans(),
330 close_branch=st.booleans(),
323 )
331 )
324 def maybecommit(
332 def maybecommit(
325 self, message, amend, when, addremove, secret, close_branch
333 self, message, amend, when, addremove, secret, close_branch
326 ):
334 ):
327 command = ["commit"]
335 command = ["commit"]
328 errors = ["nothing changed"]
336 errors = ["nothing changed"]
329 if amend:
337 if amend:
330 errors.append("cannot amend public changesets")
338 errors.append("cannot amend public changesets")
331 command.append("--amend")
339 command.append("--amend")
332 command.append("-m" + pipes.quote(message))
340 command.append("-m" + pipes.quote(message))
333 if secret:
341 if secret:
334 command.append("--secret")
342 command.append("--secret")
335 if close_branch:
343 if close_branch:
336 command.append("--close-branch")
344 command.append("--close-branch")
337 errors.append("can only close branch heads")
345 errors.append("can only close branch heads")
338 if addremove:
346 if addremove:
339 command.append("--addremove")
347 command.append("--addremove")
340 if when is not None:
348 if when is not None:
341 if when.year == 1970:
349 if when.year == 1970:
342 errors.append('negative date value')
350 errors.append('negative date value')
343 if when.year == 2038:
351 if when.year == 2038:
344 errors.append('exceeds 32 bits')
352 errors.append('exceeds 32 bits')
345 command.append("--date=%s" % (
353 command.append("--date=%s" % (
346 when.strftime('%Y-%m-%d %H:%M:%S %z'),))
354 when.strftime('%Y-%m-%d %H:%M:%S %z'),))
347
355
348 with acceptableerrors(*errors):
356 with acceptableerrors(*errors):
349 self.hg(*command)
357 self.hg(*command)
350
358
351 # Section: Simple side effect free "check" operations
359 # Section: Simple side effect free "check" operations
352 @rule()
360 @rule()
353 def log(self):
361 def log(self):
354 self.hg("log")
362 self.hg("log")
355
363
356 @rule()
364 @rule()
357 def verify(self):
365 def verify(self):
358 self.hg("verify")
366 self.hg("verify")
359
367
360 @rule()
368 @rule()
361 def diff(self):
369 def diff(self):
362 self.hg("diff", "--nodates")
370 self.hg("diff", "--nodates")
363
371
364 @rule()
372 @rule()
365 def status(self):
373 def status(self):
366 self.hg("status")
374 self.hg("status")
367
375
368 @rule()
376 @rule()
369 def export(self):
377 def export(self):
370 self.hg("export")
378 self.hg("export")
371
379
380 # Section: Branch management
381 @rule()
382 def checkbranch(self):
383 self.hg("branch")
384
385 @rule(branch=branches)
386 def switchbranch(self, branch):
387 with acceptableerrors(
388 'cannot use an integer as a name',
389 'cannot be used in a name',
390 'a branch of the same name already exists',
391 'is reserved',
392 ):
393 self.hg("branch", "--", branch)
394
395 @rule(branch=branches, clean=st.booleans())
396 def update(self, branch, clean):
397 with acceptableerrors(
398 'unknown revision',
399 'parse error',
400 ):
401 if clean:
402 self.hg("update", "-C", "--", branch)
403 else:
404 self.hg("update", "--", branch)
405
372 settings.register_profile(
406 settings.register_profile(
373 'default', settings(
407 'default', settings(
374 timeout=300,
408 timeout=300,
375 stateful_step_count=50,
409 stateful_step_count=50,
376 max_examples=10,
410 max_examples=10,
377 )
411 )
378 )
412 )
379
413
380 settings.register_profile(
414 settings.register_profile(
381 'fast', settings(
415 'fast', settings(
382 timeout=10,
416 timeout=10,
383 stateful_step_count=20,
417 stateful_step_count=20,
384 max_examples=5,
418 max_examples=5,
385 min_satisfying_examples=1,
419 min_satisfying_examples=1,
386 max_shrinks=0,
420 max_shrinks=0,
387 )
421 )
388 )
422 )
389
423
390 settings.load_profile(os.getenv('HYPOTHESIS_PROFILE', 'default'))
424 settings.load_profile(os.getenv('HYPOTHESIS_PROFILE', 'default'))
391
425
392 verifyingtest = verifyingstatemachine.TestCase
426 verifyingtest = verifyingstatemachine.TestCase
393
427
394 verifyingtest.settings = settings.default
428 verifyingtest.settings = settings.default
395
429
396 if __name__ == '__main__':
430 if __name__ == '__main__':
397 try:
431 try:
398 silenttestrunner.main(__name__)
432 silenttestrunner.main(__name__)
399 finally:
433 finally:
400 # So as to prevent proliferation of useless test files, if we never
434 # So as to prevent proliferation of useless test files, if we never
401 # actually wrote a failing test we clean up after ourselves and delete
435 # actually wrote a failing test we clean up after ourselves and delete
402 # the file for doing so that we owned.
436 # the file for doing so that we owned.
403 if os.path.exists(savefile) and os.path.getsize(savefile) == 0:
437 if os.path.exists(savefile) and os.path.getsize(savefile) == 0:
404 os.unlink(savefile)
438 os.unlink(savefile)
General Comments 0
You need to be logged in to leave comments. Login now