1 # Copyright (c) 2009-2012 testtools developers. See LICENSE for details.
3 """Matchers for things related to the filesystem."""
18 from ._basic
import Equals
19 from ._higherorder
import (
29 """Matches if the given path exists.
33 assertThat('/some/path', PathExists())
35 return MatchesPredicate(os
.path
.exists
, "%s does not exist.")
39 """Matches if the path exists and is a directory."""
42 MatchesPredicate(os
.path
.isdir
, "%s is not a directory."),
47 """Matches if the given path exists and is a file."""
50 MatchesPredicate(os
.path
.isfile
, "%s is not a file."),
54 class DirContains(Matcher
):
55 """Matches if the given directory contains files with the given names.
57 That is, is the directory listing exactly equal to the given files?
60 def __init__(self
, filenames
=None, matcher
=None):
61 """Construct a ``DirContains`` matcher.
63 Can be used in a basic mode where the whole directory listing is
64 matched against an expected directory listing (by passing
65 ``filenames``). Can also be used in a more advanced way where the
66 whole directory listing is matched against an arbitrary matcher (by
67 passing ``matcher`` instead).
69 :param filenames: If specified, match the sorted directory listing
70 against this list of filenames, sorted.
71 :param matcher: If specified, match the sorted directory listing
74 if filenames
== matcher
== None:
76 "Must provide one of `filenames` or `matcher`.")
77 if None not in (filenames
, matcher
):
79 "Must provide either `filenames` or `matcher`, not both.")
81 self
.matcher
= matcher
83 self
.matcher
= Equals(sorted(filenames
))
85 def match(self
, path
):
86 mismatch
= DirExists().match(path
)
87 if mismatch
is not None:
89 return self
.matcher
.match(sorted(os
.listdir(path
)))
92 class FileContains(Matcher
):
93 """Matches if the given file has the specified contents."""
95 def __init__(self
, contents
=None, matcher
=None):
96 """Construct a ``FileContains`` matcher.
98 Can be used in a basic mode where the file contents are compared for
99 equality against the expected file contents (by passing ``contents``).
100 Can also be used in a more advanced way where the file contents are
101 matched against an arbitrary matcher (by passing ``matcher`` instead).
103 :param contents: If specified, match the contents of the file with
105 :param matcher: If specified, match the contents of the file against
108 if contents
== matcher
== None:
109 raise AssertionError(
110 "Must provide one of `contents` or `matcher`.")
111 if None not in (contents
, matcher
):
112 raise AssertionError(
113 "Must provide either `contents` or `matcher`, not both.")
115 self
.matcher
= Equals(contents
)
117 self
.matcher
= matcher
119 def match(self
, path
):
120 mismatch
= PathExists().match(path
)
121 if mismatch
is not None:
125 actual_contents
= f
.read()
126 return self
.matcher
.match(actual_contents
)
131 return "File at path exists and contains %s" % self
.contents
134 class HasPermissions(Matcher
):
135 """Matches if a file has the given permissions.
137 Permissions are specified and matched as a four-digit octal string.
140 def __init__(self
, octal_permissions
):
141 """Construct a HasPermissions matcher.
143 :param octal_permissions: A four digit octal string, representing the
144 intended access permissions. e.g. '0775' for rwxrwxr-x.
146 super(HasPermissions
, self
).__init
__()
147 self
.octal_permissions
= octal_permissions
149 def match(self
, filename
):
150 permissions
= oct(os
.stat(filename
).st_mode
)[-4:]
151 return Equals(self
.octal_permissions
).match(permissions
)
154 class SamePath(Matcher
):
155 """Matches if two paths are the same.
157 That is, the paths are equal, or they point to the same file but in
158 different ways. The paths do not have to exist.
161 def __init__(self
, path
):
162 super(SamePath
, self
).__init
__()
165 def match(self
, other_path
):
166 f
= lambda x
: os
.path
.abspath(os
.path
.realpath(x
))
167 return Equals(f(self
.path
)).match(f(other_path
))
170 class TarballContains(Matcher
):
171 """Matches if the given tarball contains the given paths.
173 Uses TarFile.getnames() to get the paths out of the tarball.
176 def __init__(self
, paths
):
177 super(TarballContains
, self
).__init
__()
179 self
.path_matcher
= Equals(sorted(self
.paths
))
181 def match(self
, tarball_path
):
182 # Open underlying file first to ensure it's always closed:
183 # <http://bugs.python.org/issue10233>
184 f
= open(tarball_path
, "rb")
186 tarball
= tarfile
.open(tarball_path
, fileobj
=f
)
188 return self
.path_matcher
.match(sorted(tarball
.getnames()))