Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion lib/Test/MockFile.pm
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use IO::File ();
use Test::MockFile::FileHandle ();
use Test::MockFile::DirHandle ();
use Text::Glob ();
use File::Glob ();
use Scalar::Util ();

use Symbol;
Expand Down Expand Up @@ -1747,7 +1748,24 @@ sub __glob {
@mocked_files = sort @mocked_files;

my @results = map Text::Glob::match_glob( $_, @mocked_files ), @patterns;
return @results;

# In nostrict mode, also return real filesystem matches (issue #158).
# In strict mode, only mocked files are visible — no real FS access.
if ( !is_strict_mode() ) {
my @real_results = File::Glob::bsd_glob($spec);

# Merge real results, excluding any paths that are being mocked
# (mocked paths take precedence whether they exist or not)
my %seen = map { $_ => 1 } @results;
foreach my $real_path (@real_results) {
my $abs = _abs_path_to_file($real_path);
next if $files_being_mocked{$abs};
next if $seen{$real_path}++;
push @results, $real_path;
}
}

return sort @results;
}

sub __open (*;$@) {
Expand Down Expand Up @@ -2446,6 +2464,7 @@ sub __flock (*$) {
}

BEGIN {
no warnings 'redefine';
*CORE::GLOBAL::glob = !$^V || $^V lt 5.18.0
? sub {
pop;
Expand Down
56 changes: 56 additions & 0 deletions t/glob_real_files.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use strict;
use warnings;

use Test2::Bundle::Extended;
use Test2::Tools::Explain;
use Test2::Plugin::NoWarnings;

use File::Temp;

use Test::MockFile qw< nostrict >;

# Issue #158: glob should return real files when nothing is mocked
# for the given pattern.

my $dir = File::Temp->newdir();

# Create real files on disk
my $log_file = "$dir/file.log";
open( my $fh, '>', $log_file ) or die "Cannot create $log_file: $!";
print {$fh} "test";
close $fh;

my $txt_file = "$dir/file.txt";
open( $fh, '>', $txt_file ) or die "Cannot create $txt_file: $!";
print {$fh} "test";
close $fh;

# Test 1: glob should find real files when nothing is mocked
my @logs = glob("$dir/*.log");
is \@logs, [$log_file], 'glob finds real .log file on disk';

# Test 2: glob with multiple results
my @all = sort glob("$dir/*");
is \@all, [ sort( $log_file, $txt_file ) ], 'glob finds all real files on disk';

# Test 3: glob returns empty for non-matching pattern
my @none = glob("$dir/*.xyz");
is \@none, [], 'glob returns empty for non-matching pattern';

# Test 4: diamond operator (angle bracket) glob should also work
my @diamond = <$dir/*.log>;
is \@diamond, [$log_file], 'angle bracket glob finds real .log file on disk';

# Test 5: mocked files should still work alongside real files, results sorted
my $mock = Test::MockFile->file("$dir/mock.log", "mocked");
my @mixed = glob("$dir/*.log");
is \@mixed, [ sort( $log_file, "$dir/mock.log" ) ],
'glob returns both real and mocked files in sorted order';

# Test 6: mocked file that shadows a real file (no duplicates)
my $shadow = Test::MockFile->file($log_file, "shadow");
my @shadowed = glob("$dir/*.log");
is \@shadowed, [ sort( $log_file, "$dir/mock.log" ) ],
'glob returns mocked files that shadow real files without duplicates';

done_testing();