[elbe-devel] [PATCH 5/5] filesystem: Add dodctests

Olivier Dion dion at linutronix.de
Mon May 18 16:10:00 CEST 2020


Most of the tests are trivial and ensure that that all code paths are
executed and proper exceptions are thrown.

Some test are less easier to do.  For example disk_usage(), which
would requires to assume the size of small directories on a
system.

Also, to avoid clashing between files of different tests, each file
created are prefix with the method tested.

Signed-off-by: Olivier Dion <dion at linutronix.de>
---
 elbepack/filesystem.py | 172 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 172 insertions(+)

diff --git a/elbepack/filesystem.py b/elbepack/filesystem.py
index 99c5a013..09baf5ee 100644
--- a/elbepack/filesystem.py
+++ b/elbepack/filesystem.py
@@ -56,6 +56,11 @@ class Filesystem(object):
     # pylint: disable=too-many-public-methods
 
     def __init__(self, path, clean=False):
+        """
+        >>> os.path.isdir(this.path)
+        True
+        """
+
         self.path = os.path.abspath(path)
 
         if clean:
@@ -63,39 +68,149 @@ class Filesystem(object):
             os.makedirs(self.path)
 
     def fname(self, path):
+        """
+        >>> this.fname('/fname')
+        '/tmp/elbe-doctests/fname'
+        """
         if path.startswith('/'):
             path = path[1:]
         return os.path.join(self.path, path)
 
     def open(self, path, mode="r"):
+        """
+        >>> this.open("open") # doctest: +ELLIPSIS
+        Traceback (most recent call last):
+        ...
+        FileNotFoundError: [Errno 2] ...
+
+        >>> this.open("open", mode="w") # doctest: +ELLIPSIS
+        <_io.TextIOWrapper ...>
+
+        >>> _.close()
+        """
         return open(self.fname(path), mode)
 
     def open_gz(self, path, mode="r"):
+        """
+        >>> this.open_gz("open_gz") # doctest: +ELLIPSIS
+        Traceback (most recent call last):
+        ...
+        FileNotFoundError: [Errno 2] ...
+
+        >>> this.open_gz("open_gz", mode="w") # doctest: +ELLIPSIS
+        <gzip _io.BufferedWriter ...>
+
+        >>> _.close()
+        """
         return gzip.open(self.fname(path), mode)
 
     def isdir(self, path):
+        """
+        >>> this.isdir("isdir")
+        False
+
+        >>> os.makedirs(this.fname("isdir"))
+        >>> this.isdir("isdir")
+        True
+        """
         return os.path.isdir(self.fname(path))
 
     def islink(self, path):
+        """
+        >>> this.islink("islink")
+        False
+
+        >>> os.symlink("target", this.fname("islink"))
+        >>> this.islink("islink")
+        True
+        """
         return os.path.islink(self.fname(path))
 
     def isfile(self, path):
+        """
+        >>> this.isfile("isfile")
+        False
+
+        >>> open(this.fname("isfile"), mode="w").close()
+        >>> this.isfile("isfile")
+        True
+        """
         return os.path.isfile(self.fname(path))
 
     def exists(self, path):
+        """
+        >>> this.exists("exists")
+        False
+
+        >>> os.symlink("broken", this.fname("exixsts-broken-link"))
+        >>> this.exists("exists-broken-link")
+        False
+
+        >>> open(this.fname("exists"), mode="w").close()
+        >>> this.exists("exists")
+        True
+        """
         return os.path.exists(self.fname(path))
 
     def lexists(self, path):
+        """
+        >>> this.lexists("lexists")
+        False
+
+        >>> os.symlink("target", this.fname("lexists"))
+        >>> os.path.lexists(this.fname("lexists"))
+        True
+        """
         return os.path.lexists(self.fname(path))
 
     def mkdir(self, path):
+        """
+        >>> os.path.isdir(this.fname("mkdir"))
+        False
+        >>> this.mkdir("mkdir")
+        >>> os.path.isdir(this.fname("mkdir"))
+        True
+        """
         os.makedirs(self.realpath(path))
 
     def readlink(self, path):
+        """
+        >>> this.symlink("target", "readlink")
+        >>> this.readlink("readlink")
+        'target'
+        """
         return os.readlink(self.fname(path))
 
     def realpath(self, path):
+        """
+        >>> this.realpath(".")
+        '/tmp/elbe-doctests'
+
+        >>> this.realpath("..")
+        '/tmp/elbe-doctests'
+
+        >>> this.realpath("/realpath")
+        '/tmp/elbe-doctests/realpath'
 
+        >>> this.symlink("/target", "realpath-abs-symlink")
+        >>> this.realpath("realpath-abs-symlink")
+        '/tmp/elbe-doctests/target'
+
+        >>> this.symlink("target", "/realpath-symlink")
+        >>> this.realpath("realpath-symlink")
+        '/tmp/elbe-doctests/target'
+
+        >>> this.symlink(".././realpath-symlink", "realpath-multi-symlink")
+        >>> this.realpath("realpath-multi-symlink")
+        '/tmp/elbe-doctests/target'
+
+        >>> this.symlink("realpath-loop-A", "realpath-loop-B")
+        >>> this.symlink("realpath-loop-B", "realpath-loop-A")
+        >>> this.realpath("realpath-loop-A")
+        '/tmp/elbe-doctests/realpath-loop-A'
+        >>> this.realpath("realpath-loop-B")
+        '/tmp/elbe-doctests/realpath-loop-B'
+        """
         path = path.split(os.sep)
         path.reverse()
         following = []
@@ -142,6 +257,23 @@ class Filesystem(object):
         return os.sep.join(real_path)
 
     def symlink(self, src, path, allow_exists=False):
+        """
+        >>> this.symlink("target", "symlink-link")
+        >>> os.readlink(this.fname("symlink-link"))
+        'target'
+
+        >>> this.symlink("target", "symlink-link") # doctest: +ELLIPSIS
+        Traceback (most recent call last):
+        ...
+        FileExistsError: [Errno 17] ...
+
+        >>> os.readlink(this.fname("not-a-link")) # doctest: +ELLIPSIS
+        Traceback (most recent call last):
+        ...
+        FileNotFoundError: [Errno 2] ...
+
+        >>> this.symlink("target", "symlink-link", allow_exists=True)
+        """
         try:
             os.symlink(src, self.fname(path))
         except OSError as e:
@@ -173,6 +305,20 @@ class Filesystem(object):
         return content
 
     def remove(self, path, noerr=False):
+        """
+        >>> this.remove("remove") # doctest: +ELLIPSIS
+        Traceback (most recent call last):
+        ...
+        FileNotFoundError: [Errno 2] ...
+
+        >>> this.remove("remove", noerr=True)
+
+        >>> open(this.fname("remove"), "w").close()
+        >>> this.remove("remove")
+
+        >>> this.lexists("remove")
+        False
+        """
         try:
             return os.remove(self.fname(path))
         except BaseException:
@@ -180,6 +326,14 @@ class Filesystem(object):
                 raise
 
     def rmtree(self, path):
+        """
+        >>> this.mkdir("/rmtree/rmtree")
+        >>> this.rmtree("/rmtree")
+        >>> this.lexists("/rmtree/rmtree")
+        False
+        >>> this.lexists("/rmtree")
+        False
+        """
         shutil.rmtree(self.fname(path))
 
     def listdir(self, path='', ignore=None, skiplinks=False):
@@ -239,6 +393,24 @@ class Filesystem(object):
                 - already exists, silently complete
                 - regular file in the way, raise an exception
                 - parent directory(ies) does not exist, make them as well
+
+        --
+        >>> this.mkdir_p("mkdir_p/foo/bar")
+        >>> this.isdir("mkdir_p")
+        True
+
+        >>> this.isdir("mkdir_p/foo")
+        True
+
+        >>> this.isdir("mkdir_p/foo/bar")
+        True
+
+        >>> open(this.fname("mkdir_p/foo/bar/baz"), "w").close()
+
+        >>> this.mkdir_p("mkdir_p/foo/bar/baz") # doctest: +ELLIPSIS
+        Traceback (most recent call last):
+        ...
+        OSError: a file with the same name as the desired dir, ...
         """
         if self.isdir(newdir):
             pass
-- 
2.26.2




More information about the elbe-devel mailing list