Skip to content

chdir() not intercepted — fails on mocked directories #312

@toddr-bot

Description

@toddr-bot

Summary

chdir() is not overridden via CORE::GLOBAL::chdir, so calling chdir on a mocked directory falls through to the real filesystem and fails with ENOENT, even when -d confirms the mock directory exists.

Reproduction

use Test::MockFile;

my $dir = Test::MockFile->new_dir("/tmp/mock_chdir_test");

print -d "/tmp/mock_chdir_test" ? "exists" : "missing";  # "exists"
chdir("/tmp/mock_chdir_test") or warn "chdir failed: $!";  # fails: No such file or directory

Impact

Code under test that uses chdir before relative file operations won't work correctly with mocked directories. This includes:

  • Programs that chdir into a working directory before processing files
  • Build tools and installers that change directories
  • Any code pattern like chdir($dir); open(my $fh, '<', 'config.yml')

Implementation notes

CORE::GLOBAL::chdir is overridable (unlike fcntl/ioctl). A mock chdir would need to:

  1. Track a "virtual cwd" when the target is a mocked directory
  2. Use the virtual cwd in _abs_path_to_file() for resolving relative paths
  3. Fall through to CORE::chdir for non-mocked directories
  4. Handle chdir() with no args ($ENV{HOME}) and chdir("-") (previous dir)
  5. Override Cwd::cwd/Cwd::getcwd to return the virtual cwd when active

This is non-trivial because it changes how ALL relative path resolution works. It might be better suited for the MockFileSys layer (#115) rather than the base module.


🤖 Found by Kōan during file-operation audit

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions