@@ -231,10 +231,10 @@ pub fn glob_files<R: PathResolver>(
231231 let truncated = total > limit;
232232
233233 if total <= limit {
234- entries. sort_by ( |a, b| b. 1 . cmp ( & a. 1 ) ) ;
234+ entries. sort_by ( |a, b| b. 1 . cmp ( & a. 1 ) . then_with ( || a . 0 . cmp ( & b . 0 ) ) ) ;
235235 } else {
236- entries. select_nth_unstable_by ( limit - 1 , |a, b| b. 1 . cmp ( & a. 1 ) ) ;
237- entries[ ..limit] . sort_by ( |a, b| b. 1 . cmp ( & a. 1 ) ) ;
236+ entries. select_nth_unstable_by ( limit - 1 , |a, b| b. 1 . cmp ( & a. 1 ) . then_with ( || a . 0 . cmp ( & b . 0 ) ) ) ;
237+ entries[ ..limit] . sort_by ( |a, b| b. 1 . cmp ( & a. 1 ) . then_with ( || a . 0 . cmp ( & b . 0 ) ) ) ;
238238 }
239239
240240 let files: Vec < String > = entries[ ..limit. min ( total) ]
@@ -427,6 +427,53 @@ mod tests {
427427 ) ;
428428 }
429429
430+ #[ rstest]
431+ #[ case:: within_limit(
432+ & [ "c.txt" , "a.txt" , "b.txt" ] ,
433+ 1000 ,
434+ vec![ "a.txt" , "b.txt" , "c.txt" ] ,
435+ false ,
436+ ) ]
437+ #[ case:: truncated(
438+ & [ "e.txt" , "c.txt" , "a.txt" , "d.txt" , "b.txt" ] ,
439+ 3 ,
440+ vec![ "a.txt" , "b.txt" , "c.txt" ] ,
441+ true ,
442+ ) ]
443+ fn glob_sorts_deterministically_with_identical_mtimes (
444+ #[ case] files : & [ & str ] ,
445+ #[ case] limit : usize ,
446+ #[ case] expected : Vec < & str > ,
447+ #[ case] expected_truncated : bool ,
448+ ) {
449+ let dir = TempDir :: new ( ) . unwrap ( ) ;
450+ let base = dir. path ( ) ;
451+ let resolver = AbsolutePathResolver ;
452+
453+ let same_time = SystemTime :: UNIX_EPOCH + Duration :: from_secs ( 100 ) ;
454+ for name in files {
455+ let f = File :: create ( base. join ( name) ) . unwrap ( ) ;
456+ f. set_times ( FileTimes :: new ( ) . set_modified ( same_time) )
457+ . unwrap ( ) ;
458+ }
459+
460+ let result = glob_files (
461+ & resolver,
462+ GlobRequest {
463+ pattern : "**/*.txt" . to_string ( ) ,
464+ path : base. to_str ( ) . unwrap ( ) . to_string ( ) ,
465+ } ,
466+ & GlobSettings :: new ( ) . with_limit ( limit) . unwrap ( ) ,
467+ )
468+ . unwrap ( ) ;
469+
470+ assert_eq ! (
471+ result. files, expected,
472+ "entries with identical mtimes must be sorted lexicographically by path"
473+ ) ;
474+ assert_eq ! ( result. truncated, expected_truncated) ;
475+ }
476+
430477 #[ test]
431478 fn glob_returns_forward_slash_paths ( ) {
432479 // Patterns and returned paths use forward slashes on all platforms
0 commit comments