Skip to content

Comments

feat: add symlink() and link() overrides for mocked files (#16)#206

Open
Koan-Bot wants to merge 2 commits intocpanel:masterfrom
atoomic:koan.atoomic/implement-symlink-link
Open

feat: add symlink() and link() overrides for mocked files (#16)#206
Koan-Bot wants to merge 2 commits intocpanel:masterfrom
atoomic:koan.atoomic/implement-symlink-link

Conversation

@Koan-Bot
Copy link
Contributor

Summary

Adds CORE::GLOBAL::symlink and CORE::GLOBAL::link overrides so that calling the Perl builtins on mocked paths operates within the mock filesystem instead of touching disk.

Closes #16

symlink($target, $link_path)

  • Converts a non-existent file/dir/symlink mock into a symlink pointing to $target
  • Returns EEXIST if the destination already exists (file, dir, or symlink)
  • Creates dangling symlinks without complaint (matching real symlink behavior)
  • Passes through to CORE::symlink for unmocked paths

link($source, $dest)

  • Copies contents and metadata (mode, uid, gid, inode, dev) from source to destination
  • Increments nlink on both source and destination
  • Follows symlinks on the source path (matching Perl's link() semantics)
  • Returns EPERM for directory sources, EEXIST if dest exists, EXDEV if dest is unmocked

Limitations

  • Hard links copy contents rather than sharing them — writes to one file won't propagate to the other (documented in POD)
  • Destination path must be a pre-declared mock

Changes

  • lib/Test/MockFile.pm: __symlink(), __link(), BEGIN block registration, file_arg_position_for_command entries, SYNOPSIS examples, CAVEATS documentation
  • t/symlink_link.t: 22 test cases covering success paths, error conditions, symlink following, parent directory updates

Test plan

  • CI passes on Perl matrix (5.14–5.40)
  • symlink() builtin converts non-existent mock to symlink
  • link() builtin copies file contents between mocks
  • Error cases: EEXIST, ENOENT, EPERM, EXDEV
  • Strict mode reports violations for unmocked paths
  • Passthrough to real filesystem for unmocked paths in nostrict mode

🤖 Generated with Claude Code

@atoomic atoomic marked this pull request as ready for review February 22, 2026 16:50
@Koan-Bot Koan-Bot force-pushed the koan.atoomic/implement-symlink-link branch from 0ef25dc to 6c06202 Compare February 23, 2026 04:59
Override CORE::GLOBAL::symlink and CORE::GLOBAL::link so that calling
the builtins on mocked paths works within the mock filesystem.

symlink($target, $link_path):
- Converts a non-existent mock into a symlink pointing to $target
- Fails with EEXIST if destination already exists
- Passes through to CORE::symlink for unmocked paths

link($source, $dest):
- Copies contents and metadata from source mock to destination mock
- Follows symlinks on source (matching Perl's link() behavior)
- Fails with EPERM for directories, EEXIST if dest exists
- Documented limitation: writes to one don't propagate to the other

Both functions are registered in file_arg_position_for_command for
strict mode support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Koan-Bot Koan-Bot force-pushed the koan.atoomic/implement-symlink-link branch from 6c06202 to c91f566 Compare February 24, 2026 21:30
S_IFLNK (0120000) and S_IFREG (0100000) share bit 0100000, so
a bare `$mode & S_IFLNK` test matches regular files too. This caused
contents() to return undef for all file mocks, breaking 23 test files.

Use `($mode & S_IFMT) == S_IFLNK` — the same pattern is_dir() and
is_file() already use correctly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Add support for symlink and link

1 participant