~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Martin Pool
  • Date: 2011-06-14 01:26:41 UTC
  • mto: (6034.2.1 integration)
  • mto: This revision was merged to the branch mainline in revision 6043.
  • Revision ID: mbp@canonical.com-20110614012641-dnb69zb57ae5je4w
Move all test features into bzrlib.tests.features

Show diffs side-by-side

added added

removed removed

Lines of Context:
3822
3822
        'bzrlib.tests.test_export',
3823
3823
        'bzrlib.tests.test_export_pot',
3824
3824
        'bzrlib.tests.test_extract',
 
3825
        'bzrlib.tests.test_features',
3825
3826
        'bzrlib.tests.test_fetch',
3826
3827
        'bzrlib.tests.test_fixtures',
3827
3828
        'bzrlib.tests.test_fifo_cache',
4222
4223
        the module is available.
4223
4224
    """
4224
4225
 
 
4226
    from bzrlib.tests.features import ModuleAvailableFeature
4225
4227
    py_module = pyutils.get_named_object(py_module_name)
4226
4228
    scenarios = [
4227
4229
        ('python', {'module': py_module}),
4268
4270
                         % (os.path.basename(dirname), printable_e))
4269
4271
 
4270
4272
 
4271
 
class Feature(object):
4272
 
    """An operating system Feature."""
4273
 
 
4274
 
    def __init__(self):
4275
 
        self._available = None
4276
 
 
4277
 
    def available(self):
4278
 
        """Is the feature available?
4279
 
 
4280
 
        :return: True if the feature is available.
4281
 
        """
4282
 
        if self._available is None:
4283
 
            self._available = self._probe()
4284
 
        return self._available
4285
 
 
4286
 
    def _probe(self):
4287
 
        """Implement this method in concrete features.
4288
 
 
4289
 
        :return: True if the feature is available.
4290
 
        """
4291
 
        raise NotImplementedError
4292
 
 
4293
 
    def __str__(self):
4294
 
        if getattr(self, 'feature_name', None):
4295
 
            return self.feature_name()
4296
 
        return self.__class__.__name__
4297
 
 
4298
 
 
4299
 
class _SymlinkFeature(Feature):
4300
 
 
4301
 
    def _probe(self):
4302
 
        return osutils.has_symlinks()
4303
 
 
4304
 
    def feature_name(self):
4305
 
        return 'symlinks'
4306
 
 
4307
 
SymlinkFeature = _SymlinkFeature()
4308
 
 
4309
 
 
4310
 
class _HardlinkFeature(Feature):
4311
 
 
4312
 
    def _probe(self):
4313
 
        return osutils.has_hardlinks()
4314
 
 
4315
 
    def feature_name(self):
4316
 
        return 'hardlinks'
4317
 
 
4318
 
HardlinkFeature = _HardlinkFeature()
4319
 
 
4320
 
 
4321
 
class _OsFifoFeature(Feature):
4322
 
 
4323
 
    def _probe(self):
4324
 
        return getattr(os, 'mkfifo', None)
4325
 
 
4326
 
    def feature_name(self):
4327
 
        return 'filesystem fifos'
4328
 
 
4329
 
OsFifoFeature = _OsFifoFeature()
4330
 
 
4331
 
 
4332
 
class _UnicodeFilenameFeature(Feature):
4333
 
    """Does the filesystem support Unicode filenames?"""
4334
 
 
4335
 
    def _probe(self):
4336
 
        try:
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:
4343
 
            return False
4344
 
        except (IOError, OSError):
4345
 
            # The filesystem allows the Unicode filename but the file doesn't
4346
 
            # exist.
4347
 
            return True
4348
 
        else:
4349
 
            # The filesystem allows the Unicode filename and the file exists,
4350
 
            # for some reason.
4351
 
            return True
4352
 
 
4353
 
UnicodeFilenameFeature = _UnicodeFilenameFeature()
4354
 
 
4355
 
 
4356
 
class _CompatabilityThunkFeature(Feature):
4357
 
    """This feature is just a thunk to another feature.
4358
 
 
4359
 
    It issues a deprecation warning if it is accessed, to let you know that you
4360
 
    should really use a different feature.
4361
 
    """
4362
 
 
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
4370
 
        self._name = name
4371
 
        self._replacement_name = replacement_name
4372
 
        self._dep_version = dep_version
4373
 
        self._feature = None
4374
 
 
4375
 
    def _ensure(self):
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
4383
 
            # deprecated one.
4384
 
            self._feature = pyutils.get_named_object(
4385
 
                self._replacement_module, self._replacement_name)
4386
 
 
4387
 
    def _probe(self):
4388
 
        self._ensure()
4389
 
        return self._feature._probe()
4390
 
 
4391
 
 
4392
 
class ModuleAvailableFeature(Feature):
4393
 
    """This is a feature than describes a module we want to be available.
4394
 
 
4395
 
    Declare the name of the module in __init__(), and then after probing, the
4396
 
    module will be available as 'self.module'.
4397
 
 
4398
 
    :ivar module: The module if it is available, else None.
4399
 
    """
4400
 
 
4401
 
    def __init__(self, module_name):
4402
 
        super(ModuleAvailableFeature, self).__init__()
4403
 
        self.module_name = module_name
4404
 
 
4405
 
    def _probe(self):
4406
 
        try:
4407
 
            self._module = __import__(self.module_name, {}, {}, [''])
4408
 
            return True
4409
 
        except ImportError:
4410
 
            return False
4411
 
 
4412
 
    @property
4413
 
    def module(self):
4414
 
        if self.available(): # Make sure the probe has been done
4415
 
            return self._module
4416
 
        return None
4417
 
 
4418
 
    def feature_name(self):
4419
 
        return self.module_name
4420
 
 
4421
 
 
4422
4273
def probe_unicode_in_user_encoding():
4423
4274
    """Try to encode several unicode strings to use in unicode-aware tests.
4424
4275
    Return first successfull match.
4452
4303
    return None
4453
4304
 
4454
4305
 
4455
 
class _HTTPSServerFeature(Feature):
4456
 
    """Some tests want an https Server, check if one is available.
4457
 
 
4458
 
    Right now, the only way this is available is under python2.6 which provides
4459
 
    an ssl module.
4460
 
    """
4461
 
 
4462
 
    def _probe(self):
4463
 
        try:
4464
 
            import ssl
4465
 
            return True
4466
 
        except ImportError:
4467
 
            return False
4468
 
 
4469
 
    def feature_name(self):
4470
 
        return 'HTTPSServer'
4471
 
 
4472
 
 
4473
 
HTTPSServerFeature = _HTTPSServerFeature()
4474
 
 
4475
 
 
4476
 
class _UnicodeFilename(Feature):
4477
 
    """Does the filesystem support Unicode filenames?"""
4478
 
 
4479
 
    def _probe(self):
4480
 
        try:
4481
 
            os.stat(u'\u03b1')
4482
 
        except UnicodeEncodeError:
4483
 
            return False
4484
 
        except (IOError, OSError):
4485
 
            # The filesystem allows the Unicode filename but the file doesn't
4486
 
            # exist.
4487
 
            return True
4488
 
        else:
4489
 
            # The filesystem allows the Unicode filename and the file exists,
4490
 
            # for some reason.
4491
 
            return True
4492
 
 
4493
 
UnicodeFilename = _UnicodeFilename()
4494
 
 
4495
 
 
4496
 
class _ByteStringNamedFilesystem(Feature):
4497
 
    """Is the filesystem based on bytes?"""
4498
 
 
4499
 
    def _probe(self):
4500
 
        if os.name == "posix":
4501
 
            return True
4502
 
        return False
4503
 
 
4504
 
ByteStringNamedFilesystem = _ByteStringNamedFilesystem()
4505
 
 
4506
 
 
4507
 
class _UTF8Filesystem(Feature):
4508
 
    """Is the filesystem UTF-8?"""
4509
 
 
4510
 
    def _probe(self):
4511
 
        if osutils._fs_enc.upper() in ('UTF-8', 'UTF8'):
4512
 
            return True
4513
 
        return False
4514
 
 
4515
 
UTF8Filesystem = _UTF8Filesystem()
4516
 
 
4517
 
 
4518
 
class _BreakinFeature(Feature):
4519
 
    """Does this platform support the breakin feature?"""
4520
 
 
4521
 
    def _probe(self):
4522
 
        from bzrlib import breakin
4523
 
        if breakin.determine_signal() is None:
4524
 
            return False
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
4529
 
            try:
4530
 
                import ctypes
4531
 
            except OSError:
4532
 
                return False
4533
 
        return True
4534
 
 
4535
 
    def feature_name(self):
4536
 
        return "SIGQUIT or SIGBREAK w/ctypes on win32"
4537
 
 
4538
 
 
4539
 
BreakinFeature = _BreakinFeature()
4540
 
 
4541
 
 
4542
 
class _CaseInsCasePresFilenameFeature(Feature):
4543
 
    """Is the file-system case insensitive, but case-preserving?"""
4544
 
 
4545
 
    def _probe(self):
4546
 
        fileno, name = tempfile.mkstemp(prefix='MixedCase')
4547
 
        try:
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()))
4556
 
        finally:
4557
 
            os.close(fileno)
4558
 
            os.remove(name)
4559
 
 
4560
 
    def feature_name(self):
4561
 
        return "case-insensitive case-preserving filesystem"
4562
 
 
4563
 
CaseInsCasePresFilenameFeature = _CaseInsCasePresFilenameFeature()
4564
 
 
4565
 
 
4566
 
class _CaseInsensitiveFilesystemFeature(Feature):
4567
 
    """Check if underlying filesystem is case-insensitive but *not* case
4568
 
    preserving.
4569
 
    """
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.
4572
 
 
4573
 
    def _probe(self):
4574
 
        if CaseInsCasePresFilenameFeature.available():
4575
 
            return False
4576
 
 
4577
 
        if TestCaseWithMemoryTransport.TEST_ROOT is None:
4578
 
            root = osutils.mkdtemp(prefix='testbzr-', suffix='.tmp')
4579
 
            TestCaseWithMemoryTransport.TEST_ROOT = root
4580
 
        else:
4581
 
            root = TestCaseWithMemoryTransport.TEST_ROOT
4582
 
        tdir = osutils.mkdtemp(prefix='case-sensitive-probe-', suffix='',
4583
 
            dir=root)
4584
 
        name_a = osutils.pathjoin(tdir, 'a')
4585
 
        name_A = osutils.pathjoin(tdir, 'A')
4586
 
        os.mkdir(name_a)
4587
 
        result = osutils.isdir(name_A)
4588
 
        _rmtree_temp_dir(tdir)
4589
 
        return result
4590
 
 
4591
 
    def feature_name(self):
4592
 
        return 'case-insensitive filesystem'
4593
 
 
4594
 
CaseInsensitiveFilesystemFeature = _CaseInsensitiveFilesystemFeature()
4595
 
 
4596
 
 
4597
 
class _CaseSensitiveFilesystemFeature(Feature):
4598
 
 
4599
 
    def _probe(self):
4600
 
        if CaseInsCasePresFilenameFeature.available():
4601
 
            return False
4602
 
        elif CaseInsensitiveFilesystemFeature.available():
4603
 
            return False
4604
 
        else:
4605
 
            return True
4606
 
 
4607
 
    def feature_name(self):
4608
 
        return 'case-sensitive filesystem'
4609
 
 
4610
 
# new coding style is for feature instances to be lowercase
4611
 
case_sensitive_filesystem_feature = _CaseSensitiveFilesystemFeature()
4612
 
 
4613
 
 
4614
4306
# Only define SubUnitBzrRunner if subunit is available.
4615
4307
try:
4616
4308
    from subunit import TestProtocolClient
4633
4325
            return result
4634
4326
except ImportError:
4635
4327
    pass
4636
 
 
4637
 
class _PosixPermissionsFeature(Feature):
4638
 
 
4639
 
    def _probe(self):
4640
 
        def has_perms():
4641
 
            # create temporary file and check if specified perms are maintained.
4642
 
            import tempfile
4643
 
 
4644
 
            write_perms = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR
4645
 
            f = tempfile.mkstemp(prefix='bzr_perms_chk_')
4646
 
            fd, name = f
4647
 
            os.close(fd)
4648
 
            os.chmod(name, write_perms)
4649
 
 
4650
 
            read_perms = os.stat(name).st_mode & 0777
4651
 
            os.unlink(name)
4652
 
            return (write_perms == read_perms)
4653
 
 
4654
 
        return (os.name == 'posix') and has_perms()
4655
 
 
4656
 
    def feature_name(self):
4657
 
        return 'POSIX permissions support'
4658
 
 
4659
 
posix_permissions_feature = _PosixPermissionsFeature()