~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/blackbox/test_selftest.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-01-25 05:18:17 UTC
  • mfrom: (2241.1.3 repoformats)
  • Revision ID: pqm@pqm.ubuntu.com-20070125051817-53a80525dbdf87b4
(mbp) Change RepositoryFormat to use a registry (r=john)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
"""UI tests for the test framework."""
 
18
 
 
19
import os
 
20
import signal
 
21
import sys
 
22
 
 
23
import bzrlib
 
24
from bzrlib import (
 
25
    osutils,
 
26
    )
 
27
from bzrlib.errors import ParamikoNotPresent
 
28
from bzrlib.tests import (
 
29
                          TestCase,
 
30
                          TestCaseInTempDir,
 
31
                          TestCaseWithMemoryTransport,
 
32
                          TestCaseWithTransport,
 
33
                          TestSkipped,
 
34
                          )
 
35
from bzrlib.tests.blackbox import ExternalBase
 
36
 
 
37
 
 
38
class TestOptions(TestCase):
 
39
 
 
40
    current_test = None
 
41
 
 
42
    def test_transport_set_to_sftp(self):
 
43
        # test the --transport option has taken effect from within the
 
44
        # test_transport test
 
45
        try:
 
46
            import bzrlib.transport.sftp
 
47
        except ParamikoNotPresent:
 
48
            raise TestSkipped("Paramiko not present")
 
49
        if TestOptions.current_test != "test_transport_set_to_sftp":
 
50
            return
 
51
        self.assertEqual(bzrlib.transport.sftp.SFTPAbsoluteServer,
 
52
                         bzrlib.tests.default_transport)
 
53
 
 
54
    def test_transport_set_to_memory(self):
 
55
        # test the --transport option has taken effect from within the
 
56
        # test_transport test
 
57
        import bzrlib.transport.memory
 
58
        if TestOptions.current_test != "test_transport_set_to_memory":
 
59
            return
 
60
        self.assertEqual(bzrlib.transport.memory.MemoryServer,
 
61
                         bzrlib.tests.default_transport)
 
62
 
 
63
    def test_transport(self):
 
64
        # test that --transport=sftp works
 
65
        try:
 
66
            import bzrlib.transport.sftp
 
67
        except ParamikoNotPresent:
 
68
            raise TestSkipped("Paramiko not present")
 
69
        old_transport = bzrlib.tests.default_transport
 
70
        old_root = TestCaseWithMemoryTransport.TEST_ROOT
 
71
        TestCaseWithMemoryTransport.TEST_ROOT = None
 
72
        try:
 
73
            TestOptions.current_test = "test_transport_set_to_sftp"
 
74
            stdout = self.capture('selftest --transport=sftp test_transport_set_to_sftp')
 
75
            
 
76
            self.assertContainsRe(stdout, 'Ran 1 test')
 
77
            self.assertEqual(old_transport, bzrlib.tests.default_transport)
 
78
 
 
79
            TestOptions.current_test = "test_transport_set_to_memory"
 
80
            stdout = self.capture('selftest --transport=memory test_transport_set_to_memory')
 
81
            self.assertContainsRe(stdout, 'Ran 1 test')
 
82
            self.assertEqual(old_transport, bzrlib.tests.default_transport)
 
83
        finally:
 
84
            bzrlib.tests.default_transport = old_transport
 
85
            TestOptions.current_test = None
 
86
            TestCaseWithMemoryTransport.TEST_ROOT = old_root
 
87
 
 
88
 
 
89
class TestRunBzr(ExternalBase):
 
90
 
 
91
    def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None,
 
92
                         working_dir=None):
 
93
        """Override run_bzr_captured to test how it is invoked by run_bzr.
 
94
 
 
95
        We test how run_bzr_captured actually invokes bzr in another location.
 
96
        Here we only need to test that it is run_bzr passes the right
 
97
        parameters to run_bzr_captured.
 
98
        """
 
99
        self.argv = argv
 
100
        self.retcode = retcode
 
101
        self.encoding = encoding
 
102
        self.stdin = stdin
 
103
        self.working_dir = working_dir
 
104
 
 
105
    def test_args(self):
 
106
        """Test that run_bzr passes args correctly to run_bzr_captured"""
 
107
        self.run_bzr('arg1', 'arg2', 'arg3', retcode=1)
 
108
        self.assertEqual(('arg1', 'arg2', 'arg3'), self.argv)
 
109
 
 
110
    def test_encoding(self):
 
111
        """Test that run_bzr passes encoding to run_bzr_captured"""
 
112
        self.run_bzr('foo', 'bar')
 
113
        self.assertEqual(None, self.encoding)
 
114
        self.assertEqual(('foo', 'bar'), self.argv)
 
115
 
 
116
        self.run_bzr('foo', 'bar', encoding='baz')
 
117
        self.assertEqual('baz', self.encoding)
 
118
        self.assertEqual(('foo', 'bar'), self.argv)
 
119
 
 
120
    def test_retcode(self):
 
121
        """Test that run_bzr passes retcode to run_bzr_captured"""
 
122
        # Default is retcode == 0
 
123
        self.run_bzr('foo', 'bar')
 
124
        self.assertEqual(0, self.retcode)
 
125
        self.assertEqual(('foo', 'bar'), self.argv)
 
126
 
 
127
        self.run_bzr('foo', 'bar', retcode=1)
 
128
        self.assertEqual(1, self.retcode)
 
129
        self.assertEqual(('foo', 'bar'), self.argv)
 
130
 
 
131
        self.run_bzr('foo', 'bar', retcode=None)
 
132
        self.assertEqual(None, self.retcode)
 
133
        self.assertEqual(('foo', 'bar'), self.argv)
 
134
 
 
135
        self.run_bzr('foo', 'bar', retcode=3)
 
136
        self.assertEqual(3, self.retcode)
 
137
        self.assertEqual(('foo', 'bar'), self.argv)
 
138
 
 
139
    def test_stdin(self):
 
140
        # test that the stdin keyword to run_bzr is passed through to
 
141
        # run_bzr_captured as-is. We do this by overriding
 
142
        # run_bzr_captured in this class, and then calling run_bzr,
 
143
        # which is a convenience function for run_bzr_captured, so 
 
144
        # should invoke it.
 
145
        self.run_bzr('foo', 'bar', stdin='gam')
 
146
        self.assertEqual('gam', self.stdin)
 
147
        self.assertEqual(('foo', 'bar'), self.argv)
 
148
 
 
149
        self.run_bzr('foo', 'bar', stdin='zippy')
 
150
        self.assertEqual('zippy', self.stdin)
 
151
        self.assertEqual(('foo', 'bar'), self.argv)
 
152
 
 
153
    def test_working_dir(self):
 
154
        """Test that run_bzr passes working_dir to run_bzr_captured"""
 
155
        self.run_bzr('foo', 'bar')
 
156
        self.assertEqual(None, self.working_dir)
 
157
        self.assertEqual(('foo', 'bar'), self.argv)
 
158
 
 
159
        self.run_bzr('foo', 'bar', working_dir='baz')
 
160
        self.assertEqual('baz', self.working_dir)
 
161
        self.assertEqual(('foo', 'bar'), self.argv)
 
162
 
 
163
 
 
164
class TestBenchmarkTests(TestCaseWithTransport):
 
165
 
 
166
    def test_benchmark_runs_benchmark_tests(self):
 
167
        """bzr selftest --benchmark should not run the default test suite."""
 
168
        # We test this by passing a regression test name to --benchmark, which
 
169
        # should result in 0 rests run.
 
170
        old_root = TestCaseWithMemoryTransport.TEST_ROOT
 
171
        try:
 
172
            TestCaseWithMemoryTransport.TEST_ROOT = None
 
173
            out, err = self.run_bzr('selftest', '--benchmark', 'workingtree_implementations')
 
174
        finally:
 
175
            TestCaseWithMemoryTransport.TEST_ROOT = old_root
 
176
        self.assertContainsRe(out, 'Ran 0 tests.*\n\nOK')
 
177
        self.assertEqual(
 
178
            'tests passed\n',
 
179
            err)
 
180
        benchfile = open(".perf_history", "rt")
 
181
        try:
 
182
            lines = benchfile.readlines()
 
183
        finally:
 
184
            benchfile.close()
 
185
        self.assertEqual(1, len(lines))
 
186
        self.assertContainsRe(lines[0], "--date [0-9.]+")
 
187
 
 
188
 
 
189
class TestRunBzrCaptured(ExternalBase):
 
190
 
 
191
    def apply_redirected(self, stdin=None, stdout=None, stderr=None,
 
192
                         a_callable=None, *args, **kwargs):
 
193
        self.stdin = stdin
 
194
        self.factory_stdin = getattr(bzrlib.ui.ui_factory, "stdin", None)
 
195
        self.factory = bzrlib.ui.ui_factory
 
196
        self.working_dir = osutils.getcwd()
 
197
        stdout.write('foo\n')
 
198
        stderr.write('bar\n')
 
199
        return 0
 
200
 
 
201
    def test_stdin(self):
 
202
        # test that the stdin keyword to run_bzr_captured is passed through to
 
203
        # apply_redirected as a StringIO. We do this by overriding
 
204
        # apply_redirected in this class, and then calling run_bzr_captured,
 
205
        # which calls apply_redirected. 
 
206
        self.run_bzr_captured(['foo', 'bar'], stdin='gam')
 
207
        self.assertEqual('gam', self.stdin.read())
 
208
        self.assertTrue(self.stdin is self.factory_stdin)
 
209
        self.run_bzr_captured(['foo', 'bar'], stdin='zippy')
 
210
        self.assertEqual('zippy', self.stdin.read())
 
211
        self.assertTrue(self.stdin is self.factory_stdin)
 
212
 
 
213
    def test_ui_factory(self):
 
214
        # each invocation of self.run_bzr_captured should get its own UI
 
215
        # factory, which is an instance of TestUIFactory, with stdout and
 
216
        # stderr attached to the stdout and stderr of the invoked
 
217
        # run_bzr_captured
 
218
        current_factory = bzrlib.ui.ui_factory
 
219
        self.run_bzr_captured(['foo'])
 
220
        self.failIf(current_factory is self.factory)
 
221
        self.assertNotEqual(sys.stdout, self.factory.stdout)
 
222
        self.assertNotEqual(sys.stderr, self.factory.stderr)
 
223
        self.assertEqual('foo\n', self.factory.stdout.getvalue())
 
224
        self.assertEqual('bar\n', self.factory.stderr.getvalue())
 
225
        self.assertIsInstance(self.factory, bzrlib.tests.blackbox.TestUIFactory)
 
226
 
 
227
    def test_working_dir(self):
 
228
        self.build_tree(['one/', 'two/'])
 
229
        cwd = osutils.getcwd()
 
230
 
 
231
        # Default is to work in the current directory
 
232
        self.run_bzr_captured(['foo', 'bar'])
 
233
        self.assertEqual(cwd, self.working_dir)
 
234
 
 
235
        self.run_bzr_captured(['foo', 'bar'], working_dir=None)
 
236
        self.assertEqual(cwd, self.working_dir)
 
237
 
 
238
        # The function should be run in the alternative directory
 
239
        # but afterwards the current working dir shouldn't be changed
 
240
        self.run_bzr_captured(['foo', 'bar'], working_dir='one')
 
241
        self.assertNotEqual(cwd, self.working_dir)
 
242
        self.assertEndsWith(self.working_dir, 'one')
 
243
        self.assertEqual(cwd, osutils.getcwd())
 
244
 
 
245
        self.run_bzr_captured(['foo', 'bar'], working_dir='two')
 
246
        self.assertNotEqual(cwd, self.working_dir)
 
247
        self.assertEndsWith(self.working_dir, 'two')
 
248
        self.assertEqual(cwd, osutils.getcwd())
 
249
 
 
250
 
 
251
class TestRunBzrSubprocess(TestCaseWithTransport):
 
252
 
 
253
    def test_run_bzr_subprocess(self):
 
254
        """The run_bzr_helper_external comand behaves nicely."""
 
255
        result = self.run_bzr_subprocess('--version')
 
256
        result = self.run_bzr_subprocess('--version', retcode=None)
 
257
        self.assertContainsRe(result[0], 'is free software')
 
258
        self.assertRaises(AssertionError, self.run_bzr_subprocess, 
 
259
                          '--versionn')
 
260
        result = self.run_bzr_subprocess('--versionn', retcode=3)
 
261
        result = self.run_bzr_subprocess('--versionn', retcode=None)
 
262
        self.assertContainsRe(result[1], 'unknown command')
 
263
        err = self.run_bzr_subprocess('merge', '--merge-type', 'magic merge', 
 
264
                                      retcode=3)[1]
 
265
        self.assertContainsRe(err, 'No known merge type magic merge')
 
266
 
 
267
    def test_run_bzr_subprocess_env(self):
 
268
        """run_bzr_subprocess can set environment variables in the child only.
 
269
 
 
270
        These changes should not change the running process, only the child.
 
271
        """
 
272
        # The test suite should unset this variable
 
273
        self.assertEqual(None, os.environ.get('BZR_EMAIL'))
 
274
        out, err = self.run_bzr_subprocess('whoami', env_changes={
 
275
                                            'BZR_EMAIL':'Joe Foo <joe@foo.com>'
 
276
                                          }, universal_newlines=True)
 
277
        self.assertEqual('', err)
 
278
        self.assertEqual('Joe Foo <joe@foo.com>\n', out)
 
279
        # And it should not be modified
 
280
        self.assertEqual(None, os.environ.get('BZR_EMAIL'))
 
281
 
 
282
        # Do it again with a different address, just to make sure
 
283
        # it is actually changing
 
284
        out, err = self.run_bzr_subprocess('whoami', env_changes={
 
285
                                            'BZR_EMAIL':'Barry <bar@foo.com>'
 
286
                                          }, universal_newlines=True)
 
287
        self.assertEqual('', err)
 
288
        self.assertEqual('Barry <bar@foo.com>\n', out)
 
289
        self.assertEqual(None, os.environ.get('BZR_EMAIL'))
 
290
 
 
291
    def test_run_bzr_subprocess_env_del(self):
 
292
        """run_bzr_subprocess can remove environment variables too."""
 
293
        # Create a random email, so we are sure this won't collide
 
294
        rand_bzr_email = 'John Doe <jdoe@%s.com>' % (osutils.rand_chars(20),)
 
295
        rand_email = 'Jane Doe <jdoe@%s.com>' % (osutils.rand_chars(20),)
 
296
        os.environ['BZR_EMAIL'] = rand_bzr_email
 
297
        os.environ['EMAIL'] = rand_email
 
298
        try:
 
299
            # By default, the child will inherit the current env setting
 
300
            out, err = self.run_bzr_subprocess('whoami', universal_newlines=True)
 
301
            self.assertEqual('', err)
 
302
            self.assertEqual(rand_bzr_email + '\n', out)
 
303
 
 
304
            # Now that BZR_EMAIL is not set, it should fall back to EMAIL
 
305
            out, err = self.run_bzr_subprocess('whoami',
 
306
                                               env_changes={'BZR_EMAIL':None},
 
307
                                               universal_newlines=True)
 
308
            self.assertEqual('', err)
 
309
            self.assertEqual(rand_email + '\n', out)
 
310
 
 
311
            # This switches back to the default email guessing logic
 
312
            # Which shouldn't match either of the above addresses
 
313
            out, err = self.run_bzr_subprocess('whoami',
 
314
                           env_changes={'BZR_EMAIL':None, 'EMAIL':None},
 
315
                           universal_newlines=True)
 
316
 
 
317
            self.assertEqual('', err)
 
318
            self.assertNotEqual(rand_bzr_email + '\n', out)
 
319
            self.assertNotEqual(rand_email + '\n', out)
 
320
        finally:
 
321
            # TestCase cleans up BZR_EMAIL, and EMAIL at startup
 
322
            del os.environ['BZR_EMAIL']
 
323
            del os.environ['EMAIL']
 
324
 
 
325
    def test_run_bzr_subprocess_env_del_missing(self):
 
326
        """run_bzr_subprocess won't fail if deleting a nonexistant env var"""
 
327
        self.failIf('NON_EXISTANT_ENV_VAR' in os.environ)
 
328
        out, err = self.run_bzr_subprocess('rocks',
 
329
                        env_changes={'NON_EXISTANT_ENV_VAR':None},
 
330
                        universal_newlines=True)
 
331
        self.assertEqual('it sure does!\n', out)
 
332
        self.assertEqual('', err)
 
333
 
 
334
    def test_run_bzr_subprocess_working_dir(self):
 
335
        """Test that we can specify the working dir for the child"""
 
336
        cwd = osutils.getcwd()
 
337
 
 
338
        self.make_branch_and_tree('.')
 
339
        self.make_branch_and_tree('one')
 
340
        self.make_branch_and_tree('two')
 
341
 
 
342
        def get_root(**kwargs):
 
343
            """Spawn a process to get the 'root' of the tree.
 
344
 
 
345
            You can pass in arbitrary new arguments. This just makes
 
346
            sure that the returned path doesn't have trailing whitespace.
 
347
            """
 
348
            return self.run_bzr_subprocess('root', **kwargs)[0].rstrip()
 
349
 
 
350
        self.assertEqual(cwd, get_root())
 
351
        self.assertEqual(cwd, get_root(working_dir=None))
 
352
        # Has our path changed?
 
353
        self.assertEqual(cwd, osutils.getcwd())
 
354
 
 
355
        dir1 = get_root(working_dir='one')
 
356
        self.assertEndsWith(dir1, 'one')
 
357
        self.assertEqual(cwd, osutils.getcwd())
 
358
 
 
359
        dir2 = get_root(working_dir='two')
 
360
        self.assertEndsWith(dir2, 'two')
 
361
        self.assertEqual(cwd, osutils.getcwd())
 
362
 
 
363
 
 
364
class _DontSpawnProcess(Exception):
 
365
    """A simple exception which just allows us to skip unnecessary steps"""
 
366
 
 
367
 
 
368
class TestRunBzrSubprocessCommands(TestCaseWithTransport):
 
369
 
 
370
    def _popen(self, *args, **kwargs):
 
371
        """Record the command that is run, so that we can ensure it is correct"""
 
372
        self._popen_args = args
 
373
        self._popen_kwargs = kwargs
 
374
        raise _DontSpawnProcess()
 
375
 
 
376
    def test_run_bzr_subprocess_no_plugins(self):
 
377
        self.assertRaises(_DontSpawnProcess, self.run_bzr_subprocess)
 
378
        command = self._popen_args[0]
 
379
        self.assertEqual(sys.executable, command[0])
 
380
        self.assertEqual(self.get_bzr_path(), command[1])
 
381
        self.assertEqual(['--no-plugins'], command[2:])
 
382
 
 
383
    def test_allow_plugins(self):
 
384
        self.assertRaises(_DontSpawnProcess,
 
385
                          self.run_bzr_subprocess, allow_plugins=True)
 
386
        command = self._popen_args[0]
 
387
        self.assertEqual([], command[2:])
 
388
 
 
389
 
 
390
class TestBzrSubprocess(TestCaseWithTransport):
 
391
 
 
392
    def test_start_and_stop_bzr_subprocess(self):
 
393
        """We can start and perform other test actions while that process is
 
394
        still alive.
 
395
        """
 
396
        process = self.start_bzr_subprocess(['--version'])
 
397
        result = self.finish_bzr_subprocess(process)
 
398
        self.assertContainsRe(result[0], 'is free software')
 
399
        self.assertEqual('', result[1])
 
400
 
 
401
    def test_start_and_stop_bzr_subprocess_with_error(self):
 
402
        """finish_bzr_subprocess allows specification of the desired exit code.
 
403
        """
 
404
        process = self.start_bzr_subprocess(['--versionn'])
 
405
        result = self.finish_bzr_subprocess(process, retcode=3)
 
406
        self.assertEqual('', result[0])
 
407
        self.assertContainsRe(result[1], 'unknown command')
 
408
 
 
409
    def test_start_and_stop_bzr_subprocess_ignoring_retcode(self):
 
410
        """finish_bzr_subprocess allows the exit code to be ignored."""
 
411
        process = self.start_bzr_subprocess(['--versionn'])
 
412
        result = self.finish_bzr_subprocess(process, retcode=None)
 
413
        self.assertEqual('', result[0])
 
414
        self.assertContainsRe(result[1], 'unknown command')
 
415
 
 
416
    def test_start_and_stop_bzr_subprocess_with_unexpected_retcode(self):
 
417
        """finish_bzr_subprocess raises self.failureException if the retcode is
 
418
        not the expected one.
 
419
        """
 
420
        process = self.start_bzr_subprocess(['--versionn'])
 
421
        self.assertRaises(self.failureException, self.finish_bzr_subprocess,
 
422
                          process, retcode=0)
 
423
        
 
424
    def test_start_and_stop_bzr_subprocess_send_signal(self):
 
425
        """finish_bzr_subprocess raises self.failureException if the retcode is
 
426
        not the expected one.
 
427
        """
 
428
        process = self.start_bzr_subprocess(['wait-until-signalled'],
 
429
                                            skip_if_plan_to_signal=True)
 
430
        self.assertEqual('running\n', process.stdout.readline())
 
431
        result = self.finish_bzr_subprocess(process, send_signal=signal.SIGINT,
 
432
                                            retcode=3)
 
433
        self.assertEqual('', result[0])
 
434
        self.assertEqual('bzr: interrupted\n', result[1])
 
435
 
 
436
    def test_start_and_stop_working_dir(self):
 
437
        cwd = osutils.getcwd()
 
438
 
 
439
        self.make_branch_and_tree('one')
 
440
 
 
441
        process = self.start_bzr_subprocess(['root'], working_dir='one')
 
442
        result = self.finish_bzr_subprocess(process, universal_newlines=True)
 
443
        self.assertEndsWith(result[0], 'one\n')
 
444
        self.assertEqual('', result[1])
 
445
 
 
446
 
 
447
class TestRunBzrError(ExternalBase):
 
448
 
 
449
    def test_run_bzr_error(self):
 
450
        out, err = self.run_bzr_error(['^$'], 'rocks', retcode=0)
 
451
        self.assertEqual(out, 'it sure does!\n')
 
452
 
 
453
        out, err = self.run_bzr_error(["bzr: ERROR: foobarbaz is not versioned"],
 
454
                                      'file-id', 'foobarbaz')
 
455
 
 
456
 
 
457
class TestSelftestCleanOutput(TestCaseInTempDir):
 
458
 
 
459
    def test_clean_output(self):
 
460
        # check that 'bzr selftest --clean-output' works correct
 
461
        dirs = ('test0000.tmp', 'test0001.tmp', 'bzrlib', 'tests')
 
462
        files = ('bzr', 'setup.py', 'test9999.tmp')
 
463
        for i in dirs:
 
464
            os.mkdir(i)
 
465
        for i in files:
 
466
            f = file(i, 'wb')
 
467
            f.write('content of ')
 
468
            f.write(i)
 
469
            f.close()
 
470
 
 
471
        root = os.getcwdu()
 
472
        before = os.listdir(root)
 
473
        before.sort()
 
474
        self.assertEquals(['bzr','bzrlib','setup.py',
 
475
                           'test0000.tmp','test0001.tmp',
 
476
                           'test9999.tmp','tests'],
 
477
                           before)
 
478
 
 
479
        out,err = self.run_bzr_captured(['selftest','--clean-output'],
 
480
                                        working_dir=root)
 
481
 
 
482
        self.assertEquals(['delete directory: test0000.tmp',
 
483
                          'delete directory: test0001.tmp'],
 
484
                          sorted(out.splitlines()))
 
485
        self.assertEquals('', err)
 
486
 
 
487
        after = os.listdir(root)
 
488
        after.sort()
 
489
        self.assertEquals(['bzr','bzrlib','setup.py',
 
490
                           'test9999.tmp','tests'],
 
491
                           after)