)
finally:
os.chdir(saved)
+
+# check=True only proves a zero exit; confirm the env-var path actually copied
+# both files (as the explicit --old-args case above does).
+if not (TODIR / 'one').is_file() or not (TODIR / 'two').is_file():
+ test_fail("RSYNC_OLD_ARGS=1 copy of 'one two' failed")
out_path = TMPDIR / 'out1'
proc = run_capture('-n', '-r', '--ignore-non-existing', '-vv',
f'{FROMDIR}/', f'{TODIR}/')
+if proc.returncode != 0:
+ test_fail(f"test 1 failed: dry-run errored (rc={proc.returncode})")
out_path.write_text(proc.stdout)
for line in proc.stdout.splitlines():
if 'not creating new' in line and 'subdir/file' in line:
# 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
deep_dir = Path('to/foo/bar/baz/down/deep')
-def assert_file(path: Path, label: str) -> None:
+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'))
# 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)")
+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.
import sys
from pathlib import Path
-from rsyncfns import TMPDIR, run_rsync, test_skipped
+from rsyncfns import TMPDIR, run_rsync, test_fail, test_skipped
pr_path = Path('/proc/sys/fs/protected_regular')
subprocess.run(['ls', '-al', str(workdir)])
run_rsync('--inplace', str(workdir / 'src'), str(workdir / 'dst'))
+
+# A zero exit isn't enough: confirm --inplace actually wrote the source bytes
+# into the protected destination (a no-op/short write would also exit 0).
+dst_content = (workdir / 'dst').read_text()
+if dst_content != "Source\n":
+ test_fail(f"--inplace did not write the source content into the protected "
+ f"dst: got {dst_content!r}")
from rsyncfns import (
FROMDIR, TODIR,
- assert_exists, assert_not_exists, make_data_file, rmtree, run_rsync,
+ assert_not_exists, assert_same, make_data_file, rmtree, run_rsync,
)
src = FROMDIR
# --- --max-size keeps only the small files at every level -------------------
+# Compare content (not just existence) so a kept file is proven to be the
+# transferred source, not an empty/stale placeholder.
seed()
run_rsync('-a', '--max-size=1000', f'{src}/', f'{TODIR}/')
-cur = TODIR
+dcur, scur = TODIR, src
for lvl in range(4):
- assert_exists(cur / f'small{lvl}', label=f'--max-size kept small L{lvl}')
- assert_not_exists(cur / f'large{lvl}', label=f'--max-size dropped large L{lvl}')
- cur = cur / f'd{lvl + 1}'
+ assert_same(dcur / f'small{lvl}', scur / f'small{lvl}',
+ label=f'--max-size kept small L{lvl}')
+ assert_not_exists(dcur / f'large{lvl}', label=f'--max-size dropped large L{lvl}')
+ dcur, scur = dcur / f'd{lvl + 1}', scur / f'd{lvl + 1}'
# --- --min-size keeps only the large files at every level -------------------
seed()
run_rsync('-a', '--min-size=1000', f'{src}/', f'{TODIR}/')
-cur = TODIR
+dcur, scur = TODIR, src
for lvl in range(4):
- assert_exists(cur / f'large{lvl}', label=f'--min-size kept large L{lvl}')
- assert_not_exists(cur / f'small{lvl}', label=f'--min-size dropped small L{lvl}')
- cur = cur / f'd{lvl + 1}'
+ assert_same(dcur / f'large{lvl}', scur / f'large{lvl}',
+ label=f'--min-size kept large L{lvl}')
+ assert_not_exists(dcur / f'small{lvl}', label=f'--min-size dropped small L{lvl}')
+ dcur, scur = dcur / f'd{lvl + 1}', scur / f'd{lvl + 1}'
print("size-filter: --max-size / --min-size select correctly at depth")