--- /dev/null
+#!/usr/bin/env python3
+"""Coverage of -C / --cvs-exclude at depth.
+
+-C ignores the usual CVS cruft (object files, core, editor backups, VCS dirs,
+...) and also honours a per-directory .cvsignore. Verify both the built-in
+patterns and a deep .cvsignore on a >=3-level tree.
+"""
+
+from rsyncfns import (
+ FROMDIR, TODIR,
+ assert_exists, assert_not_exists, makepath, rmtree, run_rsync,
+)
+
+src = FROMDIR
+rmtree(src)
+rmtree(TODIR)
+makepath(src / 'd1' / 'd2' / 'd3')
+
+# A real file plus default-CVS-cruft at every level.
+cur = src
+for lvl in range(4):
+ (cur / f'real{lvl}.c').write_text('code\n')
+ (cur / f'obj{lvl}.o').write_text('obj\n') # *.o is built-in cruft
+ (cur / f'back{lvl}~').write_text('backup\n') # *~ is built-in cruft
+ cur = cur / f'd{lvl + 1}'
+
+# A per-directory .cvsignore deep in the tree adds "*.junk" for that subtree.
+(src / 'd1' / 'd2' / '.cvsignore').write_text('*.junk\n')
+(src / 'd1' / 'd2' / 'local.junk').write_text('j\n')
+(src / 'top.junk').write_text('j\n') # not covered by that .cvsignore
+
+run_rsync('-aC', f'{src}/', f'{TODIR}/')
+
+cur = TODIR
+for lvl in range(4):
+ assert_exists(cur / f'real{lvl}.c', label=f'-C kept real L{lvl}')
+ assert_not_exists(cur / f'obj{lvl}.o', label=f'-C dropped *.o L{lvl}')
+ assert_not_exists(cur / f'back{lvl}~', label=f'-C dropped *~ L{lvl}')
+ cur = cur / f'd{lvl + 1}'
+
+# .cvsignore is scoped to its directory subtree.
+assert_not_exists(TODIR / 'd1' / 'd2' / 'local.junk',
+ label='-C deep .cvsignore applied')
+assert_exists(TODIR / 'top.junk', label='-C deep .cvsignore not applied above')
+
+print("cvs-exclude: built-in patterns + deep .cvsignore honoured at depth")
--- /dev/null
+#!/usr/bin/env python3
+"""Coverage of --files-from, -0/--from0, --exclude-from, --include-from at depth.
+
+--files-from selects exactly the listed source-relative paths (creating their
+implied parent dirs); --from0 makes the list NUL-delimited; --exclude-from /
+--include-from read filter patterns from a file. All resolve names several
+levels deep.
+"""
+
+from rsyncfns import (
+ FROMDIR, SCRATCHDIR, TODIR,
+ assert_exists, assert_not_exists, assert_same, make_tree, rmtree,
+ run_rsync,
+)
+
+src = FROMDIR
+listed = ['d1/f1', 'd1/d2/d3/f3']
+unlisted = ['f0', 'd1/d2/f2']
+
+
+def seed():
+ rmtree(src)
+ rmtree(TODIR)
+ make_tree(src, depth=3)
+
+
+# --- --files-from selects only the listed deep paths ------------------------
+seed()
+lf = SCRATCHDIR / 'files.lst'
+lf.write_text('\n'.join(listed) + '\n')
+run_rsync('-a', f'--files-from={lf}', f'{src}/', f'{TODIR}/')
+for rel in listed:
+ assert_same(TODIR / rel, src / rel, label=f'--files-from {rel}')
+for rel in unlisted:
+ assert_not_exists(TODIR / rel, label=f'--files-from excluded {rel}')
+
+# --- --from0: the same list, NUL-delimited ----------------------------------
+rmtree(TODIR)
+lf0 = SCRATCHDIR / 'files0.lst'
+lf0.write_bytes(b'\0'.join(p.encode() for p in listed) + b'\0')
+run_rsync('-a', '--from0', f'--files-from={lf0}', f'{src}/', f'{TODIR}/')
+for rel in listed:
+ assert_same(TODIR / rel, src / rel, label=f'--from0 {rel}')
+for rel in unlisted:
+ assert_not_exists(TODIR / rel, label=f'--from0 excluded {rel}')
+
+# --- --exclude-from drops matching files at depth ---------------------------
+seed()
+(src / 'a.skip').write_text('s\n')
+(src / 'd1' / 'd2' / 'a.skip').write_text('s\n')
+ef = SCRATCHDIR / 'excl.lst'
+ef.write_text('*.skip\n')
+run_rsync('-a', f'--exclude-from={ef}', f'{src}/', f'{TODIR}/')
+assert_not_exists(TODIR / 'a.skip', label='--exclude-from top')
+assert_not_exists(TODIR / 'd1' / 'd2' / 'a.skip', label='--exclude-from deep')
+assert_same(TODIR / 'd1' / 'd2' / 'f2', src / 'd1' / 'd2' / 'f2',
+ label='--exclude-from kept others')
+
+# --- --include-from keeps only matching files at depth ----------------------
+seed()
+(src / 'd1' / 'd2' / 'k.keepme').write_text('k\n')
+inc = SCRATCHDIR / 'inc.lst'
+inc.write_text('*/\n*.keepme\n')
+run_rsync('-a', f'--include-from={inc}', '--exclude=*', f'{src}/', f'{TODIR}/')
+assert_exists(TODIR / 'd1' / 'd2' / 'k.keepme', label='--include-from kept')
+assert_not_exists(TODIR / 'd1' / 'd2' / 'f2', label='--include-from excluded rest')
+
+print("files-from-depth: --files-from/--from0/--exclude-from/--include-from at depth")
--- /dev/null
+#!/usr/bin/env python3
+"""Coverage of --exclude / --include / --filter / -F at depth.
+
+The interesting case for the resolver restructure is a per-directory merge file
+(-F reads .rsync-filter from each directory as it descends): the rule set is
+loaded from a file several levels deep and must apply to that directory and
+below, but not above. Also check plain --exclude / --include precedence on
+files spread through the tree.
+"""
+
+import os
+
+from rsyncfns import (
+ FROMDIR, TODIR,
+ assert_exists, assert_not_exists, assert_same, makepath, rmtree, run_rsync,
+)
+
+src = FROMDIR
+
+
+def seed_ext():
+ """A tree with a .log and a .txt at every level."""
+ rmtree(src)
+ rmtree(TODIR)
+ cur = src
+ for lvl in range(4):
+ cur.mkdir(parents=True, exist_ok=True)
+ (cur / f'keep{lvl}.txt').write_text(f'txt {lvl}\n')
+ (cur / f'drop{lvl}.log').write_text(f'log {lvl}\n')
+ cur = cur / f'd{lvl + 1}'
+
+
+# --- --exclude drops matching files at every level --------------------------
+seed_ext()
+run_rsync('-a', '--exclude=*.log', f'{src}/', f'{TODIR}/')
+cur = TODIR
+for lvl in range(4):
+ assert_exists(cur / f'keep{lvl}.txt', label=f'--exclude kept txt L{lvl}')
+ assert_not_exists(cur / f'drop{lvl}.log', label=f'--exclude dropped log L{lvl}')
+ cur = cur / f'd{lvl + 1}'
+
+# --- --include before --exclude='*' keeps only .txt at every level ----------
+seed_ext()
+run_rsync('-a', '--include=*/', '--include=*.txt', '--exclude=*',
+ f'{src}/', f'{TODIR}/')
+cur = TODIR
+for lvl in range(4):
+ assert_exists(cur / f'keep{lvl}.txt', label=f'--include txt L{lvl}')
+ assert_not_exists(cur / f'drop{lvl}.log', label=f'--include excluded log L{lvl}')
+ cur = cur / f'd{lvl + 1}'
+
+# --- -F per-directory merge file loaded from a deep directory ---------------
+# .rsync-filter at d1/d2 excludes "secret*" for d1/d2 and below only.
+rmtree(src)
+rmtree(TODIR)
+makepath(src / 'd1' / 'd2' / 'd3')
+for rel in ('secret.top', 'd1/secret.mid', 'd1/d2/secret.deep',
+ 'd1/d2/d3/secret.deeper'):
+ (src / rel).write_text('x\n')
+(src / 'd1' / 'd2' / '.rsync-filter').write_text('- secret*\n')
+
+run_rsync('-aF', f'{src}/', f'{TODIR}/')
+# Above the merge file: not affected.
+assert_exists(TODIR / 'secret.top', label='-F above merge dir')
+assert_exists(TODIR / 'd1' / 'secret.mid', label='-F above merge dir')
+# At and below the merge file: excluded.
+assert_not_exists(TODIR / 'd1' / 'd2' / 'secret.deep', label='-F at merge dir')
+assert_not_exists(TODIR / 'd1' / 'd2' / 'd3' / 'secret.deeper',
+ label='-F below merge dir')
+
+print("filter-depth: --exclude/--include precedence and -F per-dir merge at depth")
--- /dev/null
+#!/usr/bin/env python3
+"""Coverage of --max-size / --min-size at depth.
+
+A small and a large file at every level; --max-size must transfer only the
+small ones and --min-size only the large ones, the selection holding all the
+way down the tree.
+"""
+
+import os
+
+from rsyncfns import (
+ FROMDIR, TODIR,
+ assert_exists, assert_not_exists, make_data_file, rmtree, run_rsync,
+)
+
+src = FROMDIR
+SMALL = 500
+LARGE = 5000
+
+
+def seed():
+ rmtree(src)
+ rmtree(TODIR)
+ cur = src
+ for lvl in range(4):
+ cur.mkdir(parents=True, exist_ok=True)
+ make_data_file(cur / f'small{lvl}', SMALL)
+ make_data_file(cur / f'large{lvl}', LARGE)
+ cur = cur / f'd{lvl + 1}'
+
+
+# --- --max-size keeps only the small files at every level -------------------
+seed()
+run_rsync('-a', '--max-size=1000', f'{src}/', f'{TODIR}/')
+cur = TODIR
+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}'
+
+# --- --min-size keeps only the large files at every level -------------------
+seed()
+run_rsync('-a', '--min-size=1000', f'{src}/', f'{TODIR}/')
+cur = TODIR
+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}'
+
+print("size-filter: --max-size / --min-size select correctly at depth")