test: xxHash equal-size gate, basis priority, size-only/ignore-times, oversize

- unit: config basis-path normalization (trailing slash, a//b, ./x/./y collapse;
  degenerate inputs rejected).
- integration: same-size/same-mtime/different-content fixtures prove the xxHash
  gate -- the basis changed.txt now has the SAME byte size as the source so the
  size short-circuit can no longer mask the hash comparison, plus a dedicated
  parametrized same-size mismatch test asserting link/copy never use a
  content-mismatched basis and compare-dest transfers.
- basis-dir priority is first-match-wins: two link-dest dirs (inode of the
  first), and compare-dest before link-dest stays sparse while the reverse
  order hard-links.
- --size-only links a same-content basis file with a different mtime;
  --ignore-times never links even an exact match.
- --delay-updates + --delete removes extras inside a nested .fastsync-stage
  dir (regression guard) while keeping the real staging dir and basis tree.
- a basis run containing a file above the whole-file limit fails up front with
  a clear error and transfers nothing.
This commit is contained in:
2026-09-06 19:43:21 +02:00
parent 4799d12e25
commit e0e0ea6eac
2 changed files with 206 additions and 18 deletions
+24
View File
@@ -528,6 +528,29 @@ static void test_config_basis_wire_rejects_escaping() {
config_delete(c);
}
/* Basis-dir paths are canonicalized on the way in: trailing slashes and
interior empty / "." components are dropped so validation, the delete-walker
prefix and the receiver lookup all agree on one stored form. */
static void test_config_basis_normalization() {
Config* c = config_create();
EXPECT_NOT_NULL(c);
EXPECT_EQ_INT(config_basis_append(c, BASIS_DEST_LINK, "prior/"), 0);
EXPECT_EQ_INT(config_basis_append(c, BASIS_DEST_LINK, "a//b"), 0);
EXPECT_EQ_INT(config_basis_append(c, BASIS_DEST_LINK, "./x/./y/"), 0);
EXPECT_EQ_INT(c->basis_count, 3);
EXPECT_EQ_STR(c->basis_dirs[0].path, "prior");
EXPECT_EQ_STR(c->basis_dirs[1].path, "a/b");
EXPECT_EQ_STR(c->basis_dirs[2].path, "x/y");
/* Degenerate values that normalize away to nothing stay rejected. */
EXPECT_EQ_INT(config_basis_append(c, BASIS_DEST_LINK, "."), -1);
EXPECT_EQ_INT(config_basis_append(c, BASIS_DEST_LINK, ".."), -1);
EXPECT_EQ_INT(config_basis_append(c, BASIS_DEST_LINK, "/abs"), -1);
EXPECT_EQ_INT(config_basis_append(c, BASIS_DEST_LINK, "a/../b"), -1);
EXPECT_EQ_INT(config_basis_append(c, BASIS_DEST_LINK, ""), -1);
config_delete(c);
}
static void test_config_is_remote_dest() {
/* Valid SSH-style destinations */
EXPECT_TRUE(config_is_remote_dest("user@host:/path"));
@@ -566,6 +589,7 @@ void test_config() {
test_config_delay_updates_reserved_backup_rejected();
test_config_basis_roundtrip();
test_config_basis_wire_rejects_escaping();
test_config_basis_normalization();
}
test_config_is_remote_dest();
}