210
217
osutils.set_or_unset_env(var, value)
220
def _clear__type_equality_funcs(test):
221
"""Cleanup bound methods stored on TestCase instances
223
Clear the dict breaking a few (mostly) harmless cycles in the affected
224
unittests released with Python 2.6 and initial Python 2.7 versions.
226
For a few revisions between Python 2.7.1 and Python 2.7.2 that annoyingly
227
shipped in Oneiric, an object with no clear method was used, hence the
228
extra complications, see bug 809048 for details.
230
type_equality_funcs = getattr(test, "_type_equality_funcs", None)
231
if type_equality_funcs is not None:
232
tef_clear = getattr(type_equality_funcs, "clear", None)
233
if tef_clear is None:
234
tef_instance_dict = getattr(type_equality_funcs, "__dict__", None)
235
if tef_instance_dict is not None:
236
tef_clear = tef_instance_dict.clear
237
if tef_clear is not None:
213
241
class ExtendedTestResult(testtools.TextTestResult):
214
242
"""Accepts, reports and accumulates the results of running tests.
989
1031
# is addressed -- vila 20110219
990
1032
self.overrideAttr(config, '_expand_default_value', None)
991
1033
self._log_files = set()
1034
# Each key in the ``_counters`` dict holds a value for a different
1035
# counter. When the test ends, addDetail() should be used to output the
1036
# counter values. This happens in install_counter_hook().
1038
if 'config_stats' in selftest_debug_flags:
1039
self._install_config_stats_hooks()
1040
# Do not use i18n for tests (unless the test reverses this)
993
1043
def debug(self):
994
1044
# debug a frame up.
996
pdb.Pdb().set_trace(sys._getframe().f_back)
1046
# The sys preserved stdin/stdout should allow blackbox tests debugging
1047
pdb.Pdb(stdin=sys.__stdin__, stdout=sys.__stdout__
1048
).set_trace(sys._getframe().f_back)
998
1050
def discardDetail(self, name):
999
1051
"""Extend the addDetail, getDetails api so we can remove a detail.
1011
1063
if name in details:
1012
1064
del details[name]
1066
def install_counter_hook(self, hooks, name, counter_name=None):
1067
"""Install a counting hook.
1069
Any hook can be counted as long as it doesn't need to return a value.
1071
:param hooks: Where the hook should be installed.
1073
:param name: The hook name that will be counted.
1075
:param counter_name: The counter identifier in ``_counters``, defaults
1078
_counters = self._counters # Avoid closing over self
1079
if counter_name is None:
1081
if _counters.has_key(counter_name):
1082
raise AssertionError('%s is already used as a counter name'
1084
_counters[counter_name] = 0
1085
self.addDetail(counter_name, content.Content(content.UTF8_TEXT,
1086
lambda: ['%d' % (_counters[counter_name],)]))
1087
def increment_counter(*args, **kwargs):
1088
_counters[counter_name] += 1
1089
label = 'count %s calls' % (counter_name,)
1090
hooks.install_named_hook(name, increment_counter, label)
1091
self.addCleanup(hooks.uninstall_named_hook, name, label)
1093
def _install_config_stats_hooks(self):
1094
"""Install config hooks to count hook calls.
1097
for hook_name in ('get', 'set', 'remove', 'load', 'save'):
1098
self.install_counter_hook(config.ConfigHooks, hook_name,
1099
'config.%s' % (hook_name,))
1101
# The OldConfigHooks are private and need special handling to protect
1102
# against recursive tests (tests that run other tests), so we just do
1103
# manually what registering them into _builtin_known_hooks will provide
1105
self.overrideAttr(config, 'OldConfigHooks', config._OldConfigHooks())
1106
for hook_name in ('get', 'set', 'remove', 'load', 'save'):
1107
self.install_counter_hook(config.OldConfigHooks, hook_name,
1108
'old_config.%s' % (hook_name,))
1014
1110
def _clear_debug_flags(self):
1015
1111
"""Prevent externally set debug flags affecting tests.
1070
1166
# break some locks on purpose and should be taken into account by
1071
1167
# considering that breaking a lock is just a dirty way of releasing it.
1072
1168
if len(acquired_locks) != (len(released_locks) + len(broken_locks)):
1073
message = ('Different number of acquired and '
1074
'released or broken locks. (%s, %s + %s)' %
1075
(acquired_locks, released_locks, broken_locks))
1170
'Different number of acquired and '
1171
'released or broken locks.\n'
1175
(acquired_locks, released_locks, broken_locks))
1076
1176
if not self._lock_check_thorough:
1077
1177
# Rather than fail, just warn
1078
1178
print "Broken test %s: %s" % (self, message)
1703
1802
self.addCleanup(osutils.set_or_unset_env, name, value)
1805
def recordCalls(self, obj, attr_name):
1806
"""Monkeypatch in a wrapper that will record calls.
1808
The monkeypatch is automatically removed when the test concludes.
1810
:param obj: The namespace holding the reference to be replaced;
1811
typically a module, class, or object.
1812
:param attr_name: A string for the name of the attribute to
1814
:returns: A list that will be extended with one item every time the
1815
function is called, with a tuple of (args, kwargs).
1819
def decorator(*args, **kwargs):
1820
calls.append((args, kwargs))
1821
return orig(*args, **kwargs)
1822
orig = self.overrideAttr(obj, attr_name, decorator)
1706
1825
def _cleanEnvironment(self):
1707
1826
for name, value in isolated_environ.iteritems():
1708
1827
self.overrideEnv(name, value)
1715
1834
self._preserved_lazy_hooks.clear()
1717
1836
def knownFailure(self, reason):
1718
"""This test has failed for some known reason."""
1719
raise KnownFailure(reason)
1837
"""Declare that this test fails for a known reason
1839
Tests that are known to fail should generally be using expectedFailure
1840
with an appropriate reverse assertion if a change could cause the test
1841
to start passing. Conversely if the test has no immediate prospect of
1842
succeeding then using skip is more suitable.
1844
When this method is called while an exception is being handled, that
1845
traceback will be used, otherwise a new exception will be thrown to
1846
provide one but won't be reported.
1848
self._add_reason(reason)
1850
exc_info = sys.exc_info()
1851
if exc_info != (None, None, None):
1852
self._report_traceback(exc_info)
1855
raise self.failureException(reason)
1856
except self.failureException:
1857
exc_info = sys.exc_info()
1858
# GZ 02-08-2011: Maybe cleanup this err.exc_info attribute too?
1859
raise testtools.testcase._ExpectedFailure(exc_info)
1721
1863
def _suppress_log(self):
1722
1864
"""Remove the log info from details."""
2271
2420
class TestCaseWithMemoryTransport(TestCase):
2272
2421
"""Common test class for tests that do not need disk resources.
2274
Tests that need disk resources should derive from TestCaseWithTransport.
2423
Tests that need disk resources should derive from TestCaseInTempDir
2424
orTestCaseWithTransport.
2276
2426
TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
2278
For TestCaseWithMemoryTransport the test_home_dir is set to the name of
2428
For TestCaseWithMemoryTransport the ``test_home_dir`` is set to the name of
2279
2429
a directory which does not exist. This serves to help ensure test isolation
2280
is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
2281
must exist. However, TestCaseWithMemoryTransport does not offer local
2282
file defaults for the transport in tests, nor does it obey the command line
2430
is preserved. ``test_dir`` is set to the TEST_ROOT, as is cwd, because they
2431
must exist. However, TestCaseWithMemoryTransport does not offer local file
2432
defaults for the transport in tests, nor does it obey the command line
2283
2433
override, so tests that accidentally write to the common directory should
2286
:cvar TEST_ROOT: Directory containing all temporary directories, plus
2287
a .bzr directory that stops us ascending higher into the filesystem.
2436
:cvar TEST_ROOT: Directory containing all temporary directories, plus a
2437
``.bzr`` directory that stops us ascending higher into the filesystem.
2290
2440
TEST_ROOT = None
2449
2600
root = TestCaseWithMemoryTransport.TEST_ROOT
2450
bzrdir.BzrDir.create_standalone_workingtree(root)
2601
# Make sure we get a readable and accessible home for .bzr.log
2602
# and/or config files, and not fallback to weird defaults (see
2603
# http://pad.lv/825027).
2604
self.assertIs(None, os.environ.get('BZR_HOME', None))
2605
os.environ['BZR_HOME'] = root
2606
wt = bzrdir.BzrDir.create_standalone_workingtree(root)
2607
del os.environ['BZR_HOME']
2608
# Hack for speed: remember the raw bytes of the dirstate file so that
2609
# we don't need to re-open the wt to check it hasn't changed.
2610
TestCaseWithMemoryTransport._SAFETY_NET_PRISTINE_DIRSTATE = (
2611
wt.control_transport.get_bytes('dirstate'))
2452
2613
def _check_safety_net(self):
2453
2614
"""Check that the safety .bzr directory have not been touched.
2500
2661
def make_branch(self, relpath, format=None):
2501
2662
"""Create a branch on the transport at relpath."""
2502
2663
repo = self.make_repository(relpath, format=format)
2503
return repo.bzrdir.create_branch()
2664
return repo.bzrdir.create_branch(append_revisions_only=False)
2666
def get_default_format(self):
2669
def resolve_format(self, format):
2670
"""Resolve an object to a ControlDir format object.
2672
The initial format object can either already be
2673
a ControlDirFormat, None (for the default format),
2674
or a string with the name of the control dir format.
2676
:param format: Object to resolve
2677
:return A ControlDirFormat instance
2680
format = self.get_default_format()
2681
if isinstance(format, basestring):
2682
format = bzrdir.format_registry.make_bzrdir(format)
2505
2685
def make_bzrdir(self, relpath, format=None):
2510
2690
t = _mod_transport.get_transport(maybe_a_url)
2511
2691
if len(segments) > 1 and segments[-1] not in ('', '.'):
2512
2692
t.ensure_base()
2515
if isinstance(format, basestring):
2516
format = bzrdir.format_registry.make_bzrdir(format)
2693
format = self.resolve_format(format)
2517
2694
return format.initialize_on_transport(t)
2518
2695
except errors.UninitializableFormat:
2519
2696
raise TestSkipped("Format %s is not initializable." % format)
2521
def make_repository(self, relpath, shared=False, format=None):
2698
def make_repository(self, relpath, shared=None, format=None):
2522
2699
"""Create a repository on our default transport at relpath.
2524
2701
Note that relpath must be a relative path, not a full url.
2558
2735
def setUp(self):
2559
2736
super(TestCaseWithMemoryTransport, self).setUp()
2560
# Ensure that ConnectedTransport doesn't leak sockets
2561
def get_transport_with_cleanup(*args, **kwargs):
2562
t = orig_get_transport(*args, **kwargs)
2563
if isinstance(t, _mod_transport.ConnectedTransport):
2564
self.addCleanup(t.disconnect)
2567
orig_get_transport = self.overrideAttr(_mod_transport, 'get_transport',
2568
get_transport_with_cleanup)
2738
def _add_disconnect_cleanup(transport):
2739
"""Schedule disconnection of given transport at test cleanup
2741
This needs to happen for all connected transports or leaks occur.
2743
Note reconnections may mean we call disconnect multiple times per
2744
transport which is suboptimal but seems harmless.
2746
self.addCleanup(transport.disconnect)
2748
_mod_transport.Transport.hooks.install_named_hook('post_connect',
2749
_add_disconnect_cleanup, None)
2569
2751
self._make_test_root()
2570
2752
self.addCleanup(os.chdir, os.getcwdu())
2571
2753
self.makeAndChdirToTestDir()
3199
3400
class TestDecorator(TestUtil.TestSuite):
3200
3401
"""A decorator for TestCase/TestSuite objects.
3202
Usually, subclasses should override __iter__(used when flattening test
3203
suites), which we do to filter, reorder, parallelise and so on, run() and
3403
Contains rather than flattening suite passed on construction
3207
def __init__(self, suite):
3208
TestUtil.TestSuite.__init__(self)
3211
def countTestCases(self):
3214
cases += test.countTestCases()
3221
def run(self, result):
3222
# Use iteration on self, not self._tests, to allow subclasses to hook
3225
if result.shouldStop:
3406
def __init__(self, suite=None):
3407
super(TestDecorator, self).__init__()
3408
if suite is not None:
3411
# Don't need subclass run method with suite emptying
3412
run = unittest.TestSuite.run
3231
3415
class CountingDecorator(TestDecorator):
3242
3426
"""A decorator which excludes test matching an exclude pattern."""
3244
3428
def __init__(self, suite, exclude_pattern):
3245
TestDecorator.__init__(self, suite)
3246
self.exclude_pattern = exclude_pattern
3247
self.excluded = False
3251
return iter(self._tests)
3252
self.excluded = True
3253
suite = exclude_tests_by_re(self, self.exclude_pattern)
3255
self.addTests(suite)
3256
return iter(self._tests)
3429
super(ExcludeDecorator, self).__init__(
3430
exclude_tests_by_re(suite, exclude_pattern))
3259
3433
class FilterTestsDecorator(TestDecorator):
3260
3434
"""A decorator which filters tests to those matching a pattern."""
3262
3436
def __init__(self, suite, pattern):
3263
TestDecorator.__init__(self, suite)
3264
self.pattern = pattern
3265
self.filtered = False
3269
return iter(self._tests)
3270
self.filtered = True
3271
suite = filter_suite_by_re(self, self.pattern)
3273
self.addTests(suite)
3274
return iter(self._tests)
3437
super(FilterTestsDecorator, self).__init__(
3438
filter_suite_by_re(suite, pattern))
3277
3441
class RandomDecorator(TestDecorator):
3278
3442
"""A decorator which randomises the order of its tests."""
3280
3444
def __init__(self, suite, random_seed, stream):
3281
TestDecorator.__init__(self, suite)
3282
self.random_seed = random_seed
3283
self.randomised = False
3284
self.stream = stream
3288
return iter(self._tests)
3289
self.randomised = True
3290
self.stream.write("Randomizing test order using seed %s\n\n" %
3291
(self.actual_seed()))
3445
random_seed = self.actual_seed(random_seed)
3446
stream.write("Randomizing test order using seed %s\n\n" %
3292
3448
# Initialise the random number generator.
3293
random.seed(self.actual_seed())
3294
suite = randomize_suite(self)
3296
self.addTests(suite)
3297
return iter(self._tests)
3449
random.seed(random_seed)
3450
super(RandomDecorator, self).__init__(randomize_suite(suite))
3299
def actual_seed(self):
3300
if self.random_seed == "now":
3453
def actual_seed(seed):
3301
3455
# We convert the seed to a long to make it reuseable across
3302
3456
# invocations (because the user can reenter it).
3303
self.random_seed = long(time.time())
3457
return long(time.time())
3305
3459
# Convert the seed to a long if we can
3307
self.random_seed = long(self.random_seed)
3462
except (TypeError, ValueError):
3310
return self.random_seed
3313
3467
class TestFirstDecorator(TestDecorator):
3314
3468
"""A decorator which moves named tests to the front."""
3316
3470
def __init__(self, suite, pattern):
3317
TestDecorator.__init__(self, suite)
3318
self.pattern = pattern
3319
self.filtered = False
3323
return iter(self._tests)
3324
self.filtered = True
3325
suites = split_suite_by_re(self, self.pattern)
3327
self.addTests(suites)
3328
return iter(self._tests)
3471
super(TestFirstDecorator, self).__init__()
3472
self.addTests(split_suite_by_re(suite, pattern))
3331
3475
def partition_tests(suite, count):
3376
3520
ProtocolTestCase.run(self, result)
3378
os.waitpid(self.pid, 0)
3522
pid, status = os.waitpid(self.pid, 0)
3523
# GZ 2011-10-18: If status is nonzero, should report to the result
3524
# that something went wrong.
3380
3526
test_blocks = partition_tests(suite, concurrency)
3527
# Clear the tests from the original suite so it doesn't keep them alive
3528
suite._tests[:] = []
3381
3529
for process_tests in test_blocks:
3382
process_suite = TestUtil.TestSuite()
3383
process_suite.addTests(process_tests)
3530
process_suite = TestUtil.TestSuite(process_tests)
3531
# Also clear each split list so new suite has only reference
3532
process_tests[:] = []
3384
3533
c2pread, c2pwrite = os.pipe()
3385
3534
pid = os.fork()
3387
workaround_zealous_crypto_random()
3537
stream = os.fdopen(c2pwrite, 'wb', 1)
3538
workaround_zealous_crypto_random()
3389
3539
os.close(c2pread)
3390
3540
# Leave stderr and stdout open so we can see test noise
3391
3541
# Close stdin so that the child goes away if it decides to
3392
3542
# read from stdin (otherwise its a roulette to see what
3393
3543
# child actually gets keystrokes for pdb etc).
3394
3544
sys.stdin.close()
3396
stream = os.fdopen(c2pwrite, 'wb', 1)
3397
3545
subunit_result = AutoTimingTestResultDecorator(
3398
TestProtocolClient(stream))
3546
SubUnitBzrProtocolClient(stream))
3399
3547
process_suite.run(subunit_result)
3549
# Try and report traceback on stream, but exit with error even
3550
# if stream couldn't be created or something else goes wrong.
3551
# The traceback is formatted to a string and written in one go
3552
# to avoid interleaving lines from multiple failing children.
3554
stream.write(traceback.format_exc())
3403
3559
os.close(c2pwrite)
3404
3560
stream = os.fdopen(c2pread, 'rb', 1)
3819
3978
'bzrlib.tests.test_email_message',
3820
3979
'bzrlib.tests.test_eol_filters',
3821
3980
'bzrlib.tests.test_errors',
3981
'bzrlib.tests.test_estimate_compressed_size',
3822
3982
'bzrlib.tests.test_export',
3823
3983
'bzrlib.tests.test_export_pot',
3824
3984
'bzrlib.tests.test_extract',
3985
'bzrlib.tests.test_features',
3825
3986
'bzrlib.tests.test_fetch',
3826
3987
'bzrlib.tests.test_fixtures',
3827
3988
'bzrlib.tests.test_fifo_cache',
3828
3989
'bzrlib.tests.test_filters',
3990
'bzrlib.tests.test_filter_tree',
3829
3991
'bzrlib.tests.test_ftp_transport',
3830
3992
'bzrlib.tests.test_foreign',
3831
3993
'bzrlib.tests.test_generate_docs',
4268
4433
% (os.path.basename(dirname), printable_e))
4271
class Feature(object):
4272
"""An operating system Feature."""
4275
self._available = None
4277
def available(self):
4278
"""Is the feature available?
4280
:return: True if the feature is available.
4282
if self._available is None:
4283
self._available = self._probe()
4284
return self._available
4287
"""Implement this method in concrete features.
4289
:return: True if the feature is available.
4291
raise NotImplementedError
4294
if getattr(self, 'feature_name', None):
4295
return self.feature_name()
4296
return self.__class__.__name__
4299
class _SymlinkFeature(Feature):
4302
return osutils.has_symlinks()
4304
def feature_name(self):
4307
SymlinkFeature = _SymlinkFeature()
4310
class _HardlinkFeature(Feature):
4313
return osutils.has_hardlinks()
4315
def feature_name(self):
4318
HardlinkFeature = _HardlinkFeature()
4321
class _OsFifoFeature(Feature):
4324
return getattr(os, 'mkfifo', None)
4326
def feature_name(self):
4327
return 'filesystem fifos'
4329
OsFifoFeature = _OsFifoFeature()
4332
class _UnicodeFilenameFeature(Feature):
4333
"""Does the filesystem support Unicode filenames?"""
4337
# Check for character combinations unlikely to be covered by any
4338
# single non-unicode encoding. We use the characters
4339
# - greek small letter alpha (U+03B1) and
4340
# - braille pattern dots-123456 (U+283F).
4341
os.stat(u'\u03b1\u283f')
4342
except UnicodeEncodeError:
4344
except (IOError, OSError):
4345
# The filesystem allows the Unicode filename but the file doesn't
4349
# The filesystem allows the Unicode filename and the file exists,
4353
UnicodeFilenameFeature = _UnicodeFilenameFeature()
4356
class _CompatabilityThunkFeature(Feature):
4357
"""This feature is just a thunk to another feature.
4359
It issues a deprecation warning if it is accessed, to let you know that you
4360
should really use a different feature.
4363
def __init__(self, dep_version, module, name,
4364
replacement_name, replacement_module=None):
4365
super(_CompatabilityThunkFeature, self).__init__()
4366
self._module = module
4367
if replacement_module is None:
4368
replacement_module = module
4369
self._replacement_module = replacement_module
4371
self._replacement_name = replacement_name
4372
self._dep_version = dep_version
4373
self._feature = None
4376
if self._feature is None:
4377
depr_msg = self._dep_version % ('%s.%s'
4378
% (self._module, self._name))
4379
use_msg = ' Use %s.%s instead.' % (self._replacement_module,
4380
self._replacement_name)
4381
symbol_versioning.warn(depr_msg + use_msg, DeprecationWarning)
4382
# Import the new feature and use it as a replacement for the
4384
self._feature = pyutils.get_named_object(
4385
self._replacement_module, self._replacement_name)
4389
return self._feature._probe()
4392
class ModuleAvailableFeature(Feature):
4393
"""This is a feature than describes a module we want to be available.
4395
Declare the name of the module in __init__(), and then after probing, the
4396
module will be available as 'self.module'.
4398
:ivar module: The module if it is available, else None.
4401
def __init__(self, module_name):
4402
super(ModuleAvailableFeature, self).__init__()
4403
self.module_name = module_name
4407
self._module = __import__(self.module_name, {}, {}, [''])
4414
if self.available(): # Make sure the probe has been done
4418
def feature_name(self):
4419
return self.module_name
4422
4436
def probe_unicode_in_user_encoding():
4423
4437
"""Try to encode several unicode strings to use in unicode-aware tests.
4424
4438
Return first successfull match.
4455
class _HTTPSServerFeature(Feature):
4456
"""Some tests want an https Server, check if one is available.
4458
Right now, the only way this is available is under python2.6 which provides
4469
def feature_name(self):
4470
return 'HTTPSServer'
4473
HTTPSServerFeature = _HTTPSServerFeature()
4476
class _UnicodeFilename(Feature):
4477
"""Does the filesystem support Unicode filenames?"""
4482
except UnicodeEncodeError:
4484
except (IOError, OSError):
4485
# The filesystem allows the Unicode filename but the file doesn't
4489
# The filesystem allows the Unicode filename and the file exists,
4493
UnicodeFilename = _UnicodeFilename()
4496
class _ByteStringNamedFilesystem(Feature):
4497
"""Is the filesystem based on bytes?"""
4500
if os.name == "posix":
4504
ByteStringNamedFilesystem = _ByteStringNamedFilesystem()
4507
class _UTF8Filesystem(Feature):
4508
"""Is the filesystem UTF-8?"""
4511
if osutils._fs_enc.upper() in ('UTF-8', 'UTF8'):
4515
UTF8Filesystem = _UTF8Filesystem()
4518
class _BreakinFeature(Feature):
4519
"""Does this platform support the breakin feature?"""
4522
from bzrlib import breakin
4523
if breakin.determine_signal() is None:
4525
if sys.platform == 'win32':
4526
# Windows doesn't have os.kill, and we catch the SIGBREAK signal.
4527
# We trigger SIGBREAK via a Console api so we need ctypes to
4528
# access the function
4535
def feature_name(self):
4536
return "SIGQUIT or SIGBREAK w/ctypes on win32"
4539
BreakinFeature = _BreakinFeature()
4542
class _CaseInsCasePresFilenameFeature(Feature):
4543
"""Is the file-system case insensitive, but case-preserving?"""
4546
fileno, name = tempfile.mkstemp(prefix='MixedCase')
4548
# first check truly case-preserving for created files, then check
4549
# case insensitive when opening existing files.
4550
name = osutils.normpath(name)
4551
base, rel = osutils.split(name)
4552
found_rel = osutils.canonical_relpath(base, name)
4553
return (found_rel == rel
4554
and os.path.isfile(name.upper())
4555
and os.path.isfile(name.lower()))
4560
def feature_name(self):
4561
return "case-insensitive case-preserving filesystem"
4563
CaseInsCasePresFilenameFeature = _CaseInsCasePresFilenameFeature()
4566
class _CaseInsensitiveFilesystemFeature(Feature):
4567
"""Check if underlying filesystem is case-insensitive but *not* case
4570
# Note that on Windows, Cygwin, MacOS etc, the file-systems are far
4571
# more likely to be case preserving, so this case is rare.
4574
if CaseInsCasePresFilenameFeature.available():
4577
if TestCaseWithMemoryTransport.TEST_ROOT is None:
4578
root = osutils.mkdtemp(prefix='testbzr-', suffix='.tmp')
4579
TestCaseWithMemoryTransport.TEST_ROOT = root
4581
root = TestCaseWithMemoryTransport.TEST_ROOT
4582
tdir = osutils.mkdtemp(prefix='case-sensitive-probe-', suffix='',
4584
name_a = osutils.pathjoin(tdir, 'a')
4585
name_A = osutils.pathjoin(tdir, 'A')
4587
result = osutils.isdir(name_A)
4588
_rmtree_temp_dir(tdir)
4591
def feature_name(self):
4592
return 'case-insensitive filesystem'
4594
CaseInsensitiveFilesystemFeature = _CaseInsensitiveFilesystemFeature()
4597
class _CaseSensitiveFilesystemFeature(Feature):
4600
if CaseInsCasePresFilenameFeature.available():
4602
elif CaseInsensitiveFilesystemFeature.available():
4607
def feature_name(self):
4608
return 'case-sensitive filesystem'
4610
# new coding style is for feature instances to be lowercase
4611
case_sensitive_filesystem_feature = _CaseSensitiveFilesystemFeature()
4614
4469
# Only define SubUnitBzrRunner if subunit is available.
4616
4471
from subunit import TestProtocolClient
4617
4472
from subunit.test_results import AutoTimingTestResultDecorator
4618
4473
class SubUnitBzrProtocolClient(TestProtocolClient):
4475
def stopTest(self, test):
4476
super(SubUnitBzrProtocolClient, self).stopTest(test)
4477
_clear__type_equality_funcs(test)
4620
4479
def addSuccess(self, test, details=None):
4621
4480
# The subunit client always includes the details in the subunit
4622
4481
# stream, but we don't want to include it in ours.
4634
4493
except ImportError:
4637
class _PosixPermissionsFeature(Feature):
4641
# create temporary file and check if specified perms are maintained.
4644
write_perms = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR
4645
f = tempfile.mkstemp(prefix='bzr_perms_chk_')
4648
os.chmod(name, write_perms)
4650
read_perms = os.stat(name).st_mode & 0777
4652
return (write_perms == read_perms)
4654
return (os.name == 'posix') and has_perms()
4656
def feature_name(self):
4657
return 'POSIX permissions support'
4659
posix_permissions_feature = _PosixPermissionsFeature()
4497
# API compatibility for old plugins; see bug 892622.
4500
'HTTPServerFeature',
4501
'ModuleAvailableFeature',
4502
'HTTPSServerFeature', 'SymlinkFeature', 'HardlinkFeature',
4503
'OsFifoFeature', 'UnicodeFilenameFeature',
4504
'ByteStringNamedFilesystem', 'UTF8Filesystem',
4505
'BreakinFeature', 'CaseInsCasePresFilenameFeature',
4506
'CaseInsensitiveFilesystemFeature', 'case_sensitive_filesystem_feature',
4507
'posix_permissions_feature',
4509
globals()[name] = _CompatabilityThunkFeature(
4510
symbol_versioning.deprecated_in((2, 5, 0)),
4511
'bzrlib.tests', name,
4512
name, 'bzrlib.tests.features')
4515
for (old_name, new_name) in [
4516
('UnicodeFilename', 'UnicodeFilenameFeature'),
4518
globals()[name] = _CompatabilityThunkFeature(
4519
symbol_versioning.deprecated_in((2, 5, 0)),
4520
'bzrlib.tests', old_name,
4521
new_name, 'bzrlib.tests.features')