view tests/test-check-interfaces.py @ 34682:7e3001b74ab3

tersestatus: re-implement the functionality to terse the status The previous terse status implementation was hacking around os.listdir() and was flaky. There have been a lot of instances of mercurial buildbots failing and google's internal builds failing because of the hacky implementation of terse status. Even though I wrote the last implementation but it was hard for me to find the reason for the flake. The new implementation can be slower than the old one but is clean and easy to understand. In this we create a node object for each directory and create a tree like structure starting from the root of the working copy. While building the tree like structure we store some information on the nodes which will be helpful for deciding later whether we can terse the dir or not. Once the whole tree is build we traverse and built the list of files for each status with required tersing. There is no behaviour change as the old test, test-status-terse.t passes with the new implementation. Differential Revision: https://phab.mercurial-scm.org/D985
author Pulkit Goyal <7895pulkit@gmail.com>
date Fri, 06 Oct 2017 20:54:23 +0530
parents afcbc6f64d27
children 31449baf0936
line wrap: on
line source

# Test that certain objects conform to well-defined interfaces.

from __future__ import absolute_import, print_function

from mercurial import (
    bundlerepo,
    httppeer,
    localrepo,
    sshpeer,
    statichttprepo,
    ui as uimod,
    unionrepo,
)

def checkobject(o):
    """Verify a constructed object conforms to interface rules.

    An object must have __abstractmethods__ defined.

    All "public" attributes of the object (attributes not prefixed with
    an underscore) must be in __abstractmethods__ or appear on a base class
    with __abstractmethods__.
    """
    name = o.__class__.__name__

    allowed = set()
    for cls in o.__class__.__mro__:
        if not getattr(cls, '__abstractmethods__', set()):
            continue

        allowed |= cls.__abstractmethods__
        allowed |= {a for a in dir(cls) if not a.startswith('_')}

    if not allowed:
        print('%s does not have abstract methods' % name)
        return

    public = {a for a in dir(o) if not a.startswith('_')}

    for attr in sorted(public - allowed):
        print('public attributes not in abstract interface: %s.%s' % (
            name, attr))

# Facilitates testing localpeer.
class dummyrepo(object):
    def __init__(self):
        self.ui = uimod.ui()
    def filtered(self, name):
        pass
    def _restrictcapabilities(self, caps):
        pass

# Facilitates testing sshpeer without requiring an SSH server.
class testingsshpeer(sshpeer.sshpeer):
    def _validaterepo(self, *args, **kwargs):
        pass

class badpeer(httppeer.httppeer):
    def __init__(self):
        super(badpeer, self).__init__(uimod.ui(), 'http://localhost')
        self.badattribute = True

    def badmethod(self):
        pass

def main():
    ui = uimod.ui()

    checkobject(badpeer())
    checkobject(httppeer.httppeer(ui, 'http://localhost'))
    checkobject(localrepo.localpeer(dummyrepo()))
    checkobject(testingsshpeer(ui, 'ssh://localhost/foo'))
    checkobject(bundlerepo.bundlepeer(dummyrepo()))
    checkobject(statichttprepo.statichttppeer(dummyrepo()))
    checkobject(unionrepo.unionpeer(dummyrepo()))

main()