110110
111111* `@has-dir PATH` checks for the existence of the given directory.
112112
113+ * `@files FOLDER_PATH [ENTRIES]`, checks that `FOLDER_PATH` contains exactly
114+ `[ENTRIES]`.
115+
113116All conditions can be negated with `!`. `@!has foo/type.NoSuch.html`
114117checks if the given file does not exist, for example.
115118
@@ -321,12 +324,15 @@ def resolve_path(self, path):
321324 else :
322325 return self .last_path
323326
327+ def get_absolute_path (self , path ):
328+ return os .path .join (self .root , path )
329+
324330 def get_file (self , path ):
325331 path = self .resolve_path (path )
326332 if path in self .files :
327333 return self .files [path ]
328334
329- abspath = os . path . join ( self .root , path )
335+ abspath = self .get_absolute_path ( path )
330336 if not (os .path .exists (abspath ) and os .path .isfile (abspath )):
331337 raise FailedCheck ('File does not exist {!r}' .format (path ))
332338
@@ -340,7 +346,7 @@ def get_tree(self, path):
340346 if path in self .trees :
341347 return self .trees [path ]
342348
343- abspath = os . path . join ( self .root , path )
349+ abspath = self .get_absolute_path ( path )
344350 if not (os .path .exists (abspath ) and os .path .isfile (abspath )):
345351 raise FailedCheck ('File does not exist {!r}' .format (path ))
346352
@@ -356,7 +362,7 @@ def get_tree(self, path):
356362
357363 def get_dir (self , path ):
358364 path = self .resolve_path (path )
359- abspath = os . path . join ( self .root , path )
365+ abspath = self .get_absolute_path ( path )
360366 if not (os .path .exists (abspath ) and os .path .isdir (abspath )):
361367 raise FailedCheck ('Directory does not exist {!r}' .format (path ))
362368
@@ -538,6 +544,41 @@ def get_nb_matching_elements(cache, c, regexp, stop_at_first):
538544 return check_tree_text (cache .get_tree (c .args [0 ]), pat , c .args [2 ], regexp , stop_at_first )
539545
540546
547+ def check_files_in_folder (c , cache , folder , files ):
548+ files = files .strip ()
549+ if not files .startswith ('[' ) or not files .endswith (']' ):
550+ raise InvalidCheck ("Expected list as second argument of @{} (ie '[]')" .format (c .cmd ))
551+
552+ folder = cache .get_absolute_path (folder )
553+
554+ # First we create a set of files to check if there are duplicates.
555+ files = shlex .split (files [1 :- 1 ].replace ("," , "" ))
556+ files_set = set ()
557+ for file in files :
558+ if file in files_set :
559+ raise InvalidCheck ("Duplicated file `{}` in @{}" .format (file , c .cmd ))
560+ files_set .add (file )
561+ folder_set = set ([f for f in os .listdir (folder ) if f != "." and f != ".." ])
562+
563+ # Then we remove entries from both sets (we clone `folder_set` so we can iterate it while
564+ # removing its elements).
565+ for entry in set (folder_set ):
566+ if entry in files_set :
567+ files_set .remove (entry )
568+ folder_set .remove (entry )
569+
570+ error = 0
571+ if len (files_set ) != 0 :
572+ print_err (c .lineno , c .context , "Entries not found in folder `{}`: `{}`" .format (
573+ folder , files_set ))
574+ error += 1
575+ if len (folder_set ) != 0 :
576+ print_err (c .lineno , c .context , "Extra entries in folder `{}`: `{}`" .format (
577+ folder , folder_set ))
578+ error += 1
579+ return error == 0
580+
581+
541582ERR_COUNT = 0
542583
543584
@@ -566,6 +607,13 @@ def check_command(c, cache):
566607 else :
567608 raise InvalidCheck ('Invalid number of @{} arguments' .format (c .cmd ))
568609
610+ elif c .cmd == 'files' : # check files in given folder
611+ if len (c .args ) != 2 : # @files <folder path> <file list>
612+ raise InvalidCheck ("Invalid number of @{} arguments" .format (c .cmd ))
613+ elif c .negated :
614+ raise InvalidCheck ("@{} doesn't support negative check" .format (c .cmd ))
615+ ret = check_files_in_folder (c , cache , c .args [0 ], c .args [1 ])
616+
569617 elif c .cmd == 'count' : # count test
570618 if len (c .args ) == 3 : # @count <path> <pat> <count> = count test
571619 expected = int (c .args [2 ])
0 commit comments