@@ -76,6 +76,14 @@ def touch(self, filepath: str) -> Path:
7676 f .touch ()
7777 return f
7878
79+ def mkdir (self , dirpath : str ) -> Path :
80+ """
81+ Creates a directory in the test's tmpdir and returns the ``Path`` to the created directory
82+ """
83+ d = self .tmpdir / dirpath
84+ d .mkdir (parents = True , exist_ok = True )
85+ return d
86+
7987 def write (self , filepath : str , content : Iterable [str ]) -> Path :
8088 """
8189 Creates a file given the filepath (can be a file name or a relative path) in the test's tmpdir
@@ -136,6 +144,109 @@ def read(self, filepath: Union[str, Path]) -> List[str]:
136144 with open (self .tmpdir / filepath , "r" ) as fin :
137145 return fin .readlines ()
138146
147+ def assertDirIsEmpty (self , directory : str | Path ) -> None :
148+ """
149+ Asserts that the given directory exists but is empty.
150+ If ``dir`` is a relative path, it is assumed to be relative to this test's ``tmpdir``.
151+ """
152+ directory = Path (directory )
153+ d = directory if directory .is_absolute () else self .tmpdir / directory
154+ self .assertTrue (d .is_dir (), f"{ d } is not a directory" )
155+ self .assertEqual (0 , len (list (d .iterdir ())), f"{ d } is not empty" )
156+
157+ def assertDirTree (self , root : str | Path , tree : dict [str , object ]) -> None :
158+ """
159+ Asserts that the given ``root`` has the directory structure as specified by ``tree``.
160+ If ``root`` is a relative path, it is assumed to be relative to this test's ``tmpdir``
161+
162+ Usage:
163+
164+ .. code-block:: python
165+ self.assertDirTree(
166+ "out",
167+ {
168+ "setup.py": "",
169+ "torchx": {
170+ "__init__.py": "",
171+ "version.py": "0.8.0dev0",
172+ "specs": {
173+ "__init__.py": "",
174+ "api.py": "",
175+ },
176+ },
177+ },
178+ )
179+ """
180+ root = Path (root )
181+ d = root if root .is_absolute () else self .tmpdir / root
182+ self .assertTrue (d .is_dir (), f"{ d } is not a directory" )
183+
184+ def _assert_tree (current_dir : Path , subtree : dict [str , object ]) -> None :
185+ # Check that the directory contains exactly the keys in subtree
186+ actual_entries = {p .name for p in current_dir .iterdir ()}
187+ expected_entries = set (subtree .keys ())
188+ self .assertSetEqual (
189+ expected_entries ,
190+ actual_entries ,
191+ f"contents of the dir `{ current_dir } ` do not match the expected" ,
192+ )
193+ for name , value in subtree .items ():
194+ path = current_dir / name
195+ if isinstance (value , dict ):
196+ self .assertTrue (path .is_dir (), f"{ path } is not a directory" )
197+ _assert_tree (path , value )
198+ else :
199+ self .assertTrue (path .is_file (), f"{ path } is not a file" )
200+ if value != "" :
201+ with open (path , "r" ) as f :
202+ content = f .read ().strip ()
203+ self .assertEqual (
204+ content ,
205+ value ,
206+ f"file { path } content { content !r} does not match expected { value !r} " ,
207+ )
208+
209+ _assert_tree (d , tree )
210+
211+ def create_dir_tree (self , root : str , tree : dict [str , object ]) -> Path :
212+ """
213+ Creates the directory structure as specified by ``tree`` under ``self.tmpdir / root``
214+
215+ Usage:
216+
217+ .. code-block:: python
218+ self.createDirTree(
219+ "out",
220+ {
221+ "README.md": "foobar",
222+ "torchx": {
223+ "__init__.py": "",
224+ "version.py": "0.8.0dev0",
225+ "specs": {
226+ "__init__.py": "",
227+ "api.py": "",
228+ },
229+ },
230+ },
231+ )
232+ """
233+ d = self .tmpdir / root
234+ d .mkdir (parents = True , exist_ok = True )
235+
236+ def _create_tree (current_dir : Path , subtree : dict [str , object ]) -> None :
237+ for name , value in subtree .items ():
238+ path = current_dir / name
239+ if isinstance (value , dict ):
240+ path .mkdir (parents = True , exist_ok = True )
241+ _create_tree (path , value )
242+ else :
243+ path .parent .mkdir (parents = True , exist_ok = True )
244+ with open (path , "w" ) as f :
245+ f .write (str (value ))
246+
247+ _create_tree (d , tree )
248+ return d
249+
139250
140251Ret = TypeVar ("Ret" )
141252
0 commit comments