mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-06-08 06:05:57 -04:00
Several tests proved only that rsync exited cleanly (or that a file merely
exists), so a no-op/short transfer would pass:
protected-regular compare the dst bytes to the source after --inplace.
00-hello re-assert one/two were copied on the RSYNC_OLD_ARGS=1
env-var path (the explicit --old-args case already did).
missing check the dry-run's exit status in test 1.
mkpath compare transferred bytes (not just existence) and add a
negative control: a transfer WITHOUT --mkpath must fail
and create no intermediate path.
size-filter compare each kept file's content to its source.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
77 lines
3.0 KiB
Python
77 lines
3.0 KiB
Python
#!/usr/bin/env python3
|
|
# Python rewrite of testsuite/mkpath.test.
|
|
#
|
|
# Test the rsync --mkpath option: it should create any missing intermediate
|
|
# destination directories rather than erroring out.
|
|
|
|
import filecmp
|
|
import os
|
|
import shutil
|
|
from pathlib import Path
|
|
|
|
from rsyncfns import (
|
|
FROMDIR, SRCDIR, TMPDIR, TODIR,
|
|
makepath, rmtree, run_rsync, test_fail,
|
|
)
|
|
|
|
|
|
makepath(FROMDIR, TODIR)
|
|
shutil.copy2(SRCDIR / 'rsync.h', FROMDIR / 'text')
|
|
shutil.copy2(SRCDIR / 'configure.ac', FROMDIR / 'extra')
|
|
|
|
# All paths in the rsync invocations below are interpreted relative to
|
|
# TMPDIR, matching the original shell test which did `cd "$tmpdir"`.
|
|
os.chdir(TMPDIR)
|
|
|
|
deep_dir = Path('to/foo/bar/baz/down/deep')
|
|
|
|
|
|
def assert_file(path: Path, label: str, src: str = 'from/text') -> None:
|
|
if not path.is_file():
|
|
test_fail(f"{label}: {path} not found")
|
|
if not filecmp.cmp(path, src, shallow=False):
|
|
test_fail(f"{label}: {path} content differs from {src}")
|
|
|
|
|
|
# Negative control: without --mkpath, a missing intermediate path must fail and
|
|
# create nothing -- otherwise the --mkpath successes below prove nothing.
|
|
rmtree('to/foo')
|
|
proc = run_rsync('-ai', 'from/text', str(deep_dir / 'new'), check=False)
|
|
if proc.returncode == 0 or (deep_dir / 'new').exists():
|
|
test_fail("a transfer WITHOUT --mkpath created the missing intermediate path")
|
|
|
|
# Create several levels of dest dir (file destination — final component
|
|
# is the new filename).
|
|
run_rsync('-aiv', '--mkpath', 'from/text', str(deep_dir / 'new'))
|
|
assert_file(deep_dir / 'new', "'new' file in deep dir")
|
|
rmtree('to/foo')
|
|
|
|
# Trailing slash on the dest means it's a directory; the file keeps its name.
|
|
run_rsync('-aiv', '--mkpath', 'from/text', str(deep_dir) + '/')
|
|
assert_file(deep_dir / 'text', "'text' file in deep dir (trailing-slash dest)")
|
|
(deep_dir / 'text').unlink()
|
|
|
|
# An existing destination directory should also work.
|
|
(deep_dir / 'new').mkdir(parents=True, exist_ok=True)
|
|
run_rsync('-aiv', '--mkpath', 'from/text', str(deep_dir / 'new'))
|
|
assert_file(deep_dir / 'new' / 'text', "'text' file in pre-existing deep/new dir")
|
|
|
|
# ... and an existing path when an alternate dest filename is specified.
|
|
run_rsync('-aiv', '--mkpath', 'from/text', str(deep_dir / 'new' / 'text2'))
|
|
assert_file(deep_dir / 'new' / 'text2', "'text2' renamed file in pre-existing deep/new dir")
|
|
rmtree('to/foo')
|
|
|
|
# Multiple source args (whole directory) — bare dest name.
|
|
run_rsync('-aiv', '--mkpath', 'from/', str(deep_dir))
|
|
assert_file(deep_dir / 'extra', "'extra' file in deep dir (multi-source, no trailing slash)",
|
|
src='from/extra')
|
|
rmtree('to/foo')
|
|
|
|
# Multiple source args (whole directory) — dest with trailing slash.
|
|
run_rsync('-aiv', '--mkpath', 'from/', str(deep_dir) + '/')
|
|
assert_file(deep_dir / 'text', "'text' file in deep dir (multi-source, trailing slash)")
|
|
|
|
# No intermediate path at all — dest is just a file in the current dir.
|
|
run_rsync('-aiv', '--mkpath', 'from/text', 'to_text')
|
|
assert_file(Path('to_text'), "'to_text' file in current dir")
|