Skip to content

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

Merged
atoomic merged 2 commits intocpanel:masterfrom
atoomic:koan.atoomic/implement-symlink-link
Feb 27, 2026
Merged

feat: add symlink() and link() overrides for mocked files (#16)#206
atoomic merged 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 2 times, most recently from 6c06202 to c91f566 Compare February 24, 2026 21:30
@Koan-Bot Koan-Bot force-pushed the koan.atoomic/implement-symlink-link branch 5 times, most recently from 3b3fea9 to 3a65959 Compare February 26, 2026 21:01
@toddr
Copy link
Member

toddr commented Feb 27, 2026

@Koan-Bot rebase

@Koan-Bot Koan-Bot force-pushed the koan.atoomic/implement-symlink-link branch from 3a65959 to f5ce7de Compare February 27, 2026 02:14
Koan-Bot and others added 2 commits February 26, 2026 20:26
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>
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>
@Koan-Bot Koan-Bot force-pushed the koan.atoomic/implement-symlink-link branch from f5ce7de to d9cae5d Compare February 27, 2026 03:26
@Koan-Bot
Copy link
Contributor Author

Rebase Complete

Branch koan.atoomic/implement-symlink-link rebased onto latest master (8da6bad) and force-pushed.

Actions

  • Rebased 2 commits cleanly onto upstream/master
  • Force-pushed d9cae5d

Automated by Kōan

@atoomic atoomic merged commit 8b6c090 into cpanel:master Feb 27, 2026
18 checks passed
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

3 participants