1754
1761
self.addCleanup(osutils.set_or_unset_env, name, value)
1764
def recordCalls(self, obj, attr_name):
1765
"""Monkeypatch in a wrapper that will record calls.
1767
The monkeypatch is automatically removed when the test concludes.
1769
:param obj: The namespace holding the reference to be replaced;
1770
typically a module, class, or object.
1771
:param attr_name: A string for the name of the attribute to
1773
:returns: A list that will be extended with one item every time the
1774
function is called, with a tuple of (args, kwargs).
1778
def decorator(*args, **kwargs):
1779
calls.append((args, kwargs))
1780
return orig(*args, **kwargs)
1781
orig = self.overrideAttr(obj, attr_name, decorator)
1757
1784
def _cleanEnvironment(self):
1758
1785
for name, value in isolated_environ.iteritems():
1759
1786
self.overrideEnv(name, value)
2614
2641
def setUp(self):
2615
2642
super(TestCaseWithMemoryTransport, self).setUp()
2616
2643
# Ensure that ConnectedTransport doesn't leak sockets
2617
def get_transport_with_cleanup(*args, **kwargs):
2618
t = orig_get_transport(*args, **kwargs)
2644
def get_transport_from_url_with_cleanup(*args, **kwargs):
2645
t = orig_get_transport_from_url(*args, **kwargs)
2619
2646
if isinstance(t, _mod_transport.ConnectedTransport):
2620
2647
self.addCleanup(t.disconnect)
2623
orig_get_transport = self.overrideAttr(_mod_transport, 'get_transport',
2624
get_transport_with_cleanup)
2650
orig_get_transport_from_url = self.overrideAttr(
2651
_mod_transport, 'get_transport_from_url',
2652
get_transport_from_url_with_cleanup)
2625
2653
self._make_test_root()
2626
2654
self.addCleanup(os.chdir, os.getcwdu())
2627
2655
self.makeAndChdirToTestDir()
4333
4363
% (os.path.basename(dirname), printable_e))
4336
class Feature(object):
4337
"""An operating system Feature."""
4340
self._available = None
4342
def available(self):
4343
"""Is the feature available?
4345
:return: True if the feature is available.
4347
if self._available is None:
4348
self._available = self._probe()
4349
return self._available
4352
"""Implement this method in concrete features.
4354
:return: True if the feature is available.
4356
raise NotImplementedError
4359
if getattr(self, 'feature_name', None):
4360
return self.feature_name()
4361
return self.__class__.__name__
4364
class _SymlinkFeature(Feature):
4367
return osutils.has_symlinks()
4369
def feature_name(self):
4372
SymlinkFeature = _SymlinkFeature()
4375
class _HardlinkFeature(Feature):
4378
return osutils.has_hardlinks()
4380
def feature_name(self):
4383
HardlinkFeature = _HardlinkFeature()
4386
class _OsFifoFeature(Feature):
4389
return getattr(os, 'mkfifo', None)
4391
def feature_name(self):
4392
return 'filesystem fifos'
4394
OsFifoFeature = _OsFifoFeature()
4397
class _UnicodeFilenameFeature(Feature):
4398
"""Does the filesystem support Unicode filenames?"""
4402
# Check for character combinations unlikely to be covered by any
4403
# single non-unicode encoding. We use the characters
4404
# - greek small letter alpha (U+03B1) and
4405
# - braille pattern dots-123456 (U+283F).
4406
os.stat(u'\u03b1\u283f')
4407
except UnicodeEncodeError:
4409
except (IOError, OSError):
4410
# The filesystem allows the Unicode filename but the file doesn't
4414
# The filesystem allows the Unicode filename and the file exists,
4418
UnicodeFilenameFeature = _UnicodeFilenameFeature()
4421
class _CompatabilityThunkFeature(Feature):
4422
"""This feature is just a thunk to another feature.
4424
It issues a deprecation warning if it is accessed, to let you know that you
4425
should really use a different feature.
4428
def __init__(self, dep_version, module, name,
4429
replacement_name, replacement_module=None):
4430
super(_CompatabilityThunkFeature, self).__init__()
4431
self._module = module
4432
if replacement_module is None:
4433
replacement_module = module
4434
self._replacement_module = replacement_module
4436
self._replacement_name = replacement_name
4437
self._dep_version = dep_version
4438
self._feature = None
4441
if self._feature is None:
4442
depr_msg = self._dep_version % ('%s.%s'
4443
% (self._module, self._name))
4444
use_msg = ' Use %s.%s instead.' % (self._replacement_module,
4445
self._replacement_name)
4446
symbol_versioning.warn(depr_msg + use_msg, DeprecationWarning)
4447
# Import the new feature and use it as a replacement for the
4449
self._feature = pyutils.get_named_object(
4450
self._replacement_module, self._replacement_name)
4454
return self._feature._probe()
4457
class ModuleAvailableFeature(Feature):
4458
"""This is a feature than describes a module we want to be available.
4460
Declare the name of the module in __init__(), and then after probing, the
4461
module will be available as 'self.module'.
4463
:ivar module: The module if it is available, else None.
4466
def __init__(self, module_name):
4467
super(ModuleAvailableFeature, self).__init__()
4468
self.module_name = module_name
4472
self._module = __import__(self.module_name, {}, {}, [''])
4479
if self.available(): # Make sure the probe has been done
4483
def feature_name(self):
4484
return self.module_name
4487
4366
def probe_unicode_in_user_encoding():
4488
4367
"""Try to encode several unicode strings to use in unicode-aware tests.
4489
4368
Return first successfull match.
4520
class _HTTPSServerFeature(Feature):
4521
"""Some tests want an https Server, check if one is available.
4523
Right now, the only way this is available is under python2.6 which provides
4534
def feature_name(self):
4535
return 'HTTPSServer'
4538
HTTPSServerFeature = _HTTPSServerFeature()
4541
class _UnicodeFilename(Feature):
4542
"""Does the filesystem support Unicode filenames?"""
4547
except UnicodeEncodeError:
4549
except (IOError, OSError):
4550
# The filesystem allows the Unicode filename but the file doesn't
4554
# The filesystem allows the Unicode filename and the file exists,
4558
UnicodeFilename = _UnicodeFilename()
4561
class _ByteStringNamedFilesystem(Feature):
4562
"""Is the filesystem based on bytes?"""
4565
if os.name == "posix":
4569
ByteStringNamedFilesystem = _ByteStringNamedFilesystem()
4572
class _UTF8Filesystem(Feature):
4573
"""Is the filesystem UTF-8?"""
4576
if osutils._fs_enc.upper() in ('UTF-8', 'UTF8'):
4580
UTF8Filesystem = _UTF8Filesystem()
4583
class _BreakinFeature(Feature):
4584
"""Does this platform support the breakin feature?"""
4587
from bzrlib import breakin
4588
if breakin.determine_signal() is None:
4590
if sys.platform == 'win32':
4591
# Windows doesn't have os.kill, and we catch the SIGBREAK signal.
4592
# We trigger SIGBREAK via a Console api so we need ctypes to
4593
# access the function
4600
def feature_name(self):
4601
return "SIGQUIT or SIGBREAK w/ctypes on win32"
4604
BreakinFeature = _BreakinFeature()
4607
class _CaseInsCasePresFilenameFeature(Feature):
4608
"""Is the file-system case insensitive, but case-preserving?"""
4611
fileno, name = tempfile.mkstemp(prefix='MixedCase')
4613
# first check truly case-preserving for created files, then check
4614
# case insensitive when opening existing files.
4615
name = osutils.normpath(name)
4616
base, rel = osutils.split(name)
4617
found_rel = osutils.canonical_relpath(base, name)
4618
return (found_rel == rel
4619
and os.path.isfile(name.upper())
4620
and os.path.isfile(name.lower()))
4625
def feature_name(self):
4626
return "case-insensitive case-preserving filesystem"
4628
CaseInsCasePresFilenameFeature = _CaseInsCasePresFilenameFeature()
4631
class _CaseInsensitiveFilesystemFeature(Feature):
4632
"""Check if underlying filesystem is case-insensitive but *not* case
4635
# Note that on Windows, Cygwin, MacOS etc, the file-systems are far
4636
# more likely to be case preserving, so this case is rare.
4639
if CaseInsCasePresFilenameFeature.available():
4642
if TestCaseWithMemoryTransport.TEST_ROOT is None:
4643
root = osutils.mkdtemp(prefix='testbzr-', suffix='.tmp')
4644
TestCaseWithMemoryTransport.TEST_ROOT = root
4646
root = TestCaseWithMemoryTransport.TEST_ROOT
4647
tdir = osutils.mkdtemp(prefix='case-sensitive-probe-', suffix='',
4649
name_a = osutils.pathjoin(tdir, 'a')
4650
name_A = osutils.pathjoin(tdir, 'A')
4652
result = osutils.isdir(name_A)
4653
_rmtree_temp_dir(tdir)
4656
def feature_name(self):
4657
return 'case-insensitive filesystem'
4659
CaseInsensitiveFilesystemFeature = _CaseInsensitiveFilesystemFeature()
4662
class _CaseSensitiveFilesystemFeature(Feature):
4665
if CaseInsCasePresFilenameFeature.available():
4667
elif CaseInsensitiveFilesystemFeature.available():
4672
def feature_name(self):
4673
return 'case-sensitive filesystem'
4675
# new coding style is for feature instances to be lowercase
4676
case_sensitive_filesystem_feature = _CaseSensitiveFilesystemFeature()
4679
4399
# Only define SubUnitBzrRunner if subunit is available.
4681
4401
from subunit import TestProtocolClient
4699
4419
except ImportError:
4702
class _PosixPermissionsFeature(Feature):
4706
# create temporary file and check if specified perms are maintained.
4709
write_perms = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR
4710
f = tempfile.mkstemp(prefix='bzr_perms_chk_')
4713
os.chmod(name, write_perms)
4715
read_perms = os.stat(name).st_mode & 0777
4717
return (write_perms == read_perms)
4719
return (os.name == 'posix') and has_perms()
4721
def feature_name(self):
4722
return 'POSIX permissions support'
4724
posix_permissions_feature = _PosixPermissionsFeature()
4423
@deprecated_function(deprecated_in((2, 5, 0)))
4424
def ModuleAvailableFeature(name):
4425
from bzrlib.tests import features
4426
return features.ModuleAvailableFeature(name)