#291: - Compile --exclude/--include/--exclude-from/--include-from into the SAME ordered rule list as --filter/-f (first match wins), so the common `--include='*.txt' --exclude='*'` idiom and include-alone semantics match rsync. The legacy per-kind scanner arrays are no longer applied. - -x/--one-file-system emits the cross-device mount-point directory entry (empty) instead of dropping it, in both the sequential and parallel scanners. - Stop passing the legacy arrays to the scanner; document -f is --filter. #292: - New src/shared/format.c/.h: rsync "big_num" (comma-grouped integers) and decimal -h human sizes, %M/%t timestamp, and the STATUS_DEST_INFO codec. - Receiver answers each STATUS_CHECK with a pre-transfer destination snapshot (new report_dest_info wire field + STATUS_DEST_INFO, PROTOCOL_VERSION 2.23.0) so the sender can render true itemize columns. - Itemize now emits rsync-correct update/type chars and c/s/t/p/o/g columns for files, dirs, symlinks and hard links, comparing size/time/perms/owner/ group against the reported destination. - --out-format gains %i %n %f %l %b %M %t %o %p %B %U %G %L; %f is the relative display path, %M the YYYY/MM/DD-HH:MM:SS form, %b the literal bytes sent. - --list-only prints transfer-relative names, directory entries and ls-style grouped sizes. - --stats prints rsync's multi-line block on stdout; -h uses decimal units. Tests: unit tests for the filter ordering, format primitives, itemize columns; integration + differential tests against real rsync 3.4.1 for itemize/out-format/list-only/selection and -x. Golden wire len/hash and protocol version strings updated for 2.23.0.
This commit is contained in:
+106
-16
@@ -1,5 +1,6 @@
|
||||
#include "test_change_list.h"
|
||||
#include "change_list.h"
|
||||
#include "config.h"
|
||||
#include "test_utils.h"
|
||||
#include "utils.h"
|
||||
#include <stdlib.h>
|
||||
@@ -9,64 +10,150 @@
|
||||
static ChangeEvent sample_event(void) {
|
||||
ChangeEvent event;
|
||||
memset(&event, 0, sizeof(event));
|
||||
event.path = "/srv/root/sub/file.txt";
|
||||
event.path = "src/sub/file.txt";
|
||||
event.name = "sub/file.txt";
|
||||
event.decision = CHANGE_SENT;
|
||||
event.is_directory = false;
|
||||
event.size = 12345;
|
||||
event.bytes_sent = 999;
|
||||
event.mtime_sec = 1700000000;
|
||||
event.mtime_nsec = 0;
|
||||
event.mode = 0100644;
|
||||
event.uid = 1000;
|
||||
event.gid = 1000;
|
||||
return event;
|
||||
}
|
||||
|
||||
/* Expected %M expansion computed independently with localtime_r. */
|
||||
static void expected_mtime(time_t when, char out[32]) {
|
||||
struct tm broken_down;
|
||||
localtime_r(&when, &broken_down);
|
||||
strftime(out, 32, "%Y/%m/%d-%H:%M:%S", &broken_down);
|
||||
}
|
||||
|
||||
static void test_format_tokens() {
|
||||
ChangeEvent event = sample_event();
|
||||
char* line = change_render_format("%f %n %l %b %M %%", &event);
|
||||
Config* config = config_create();
|
||||
char when[32];
|
||||
expected_mtime(event.mtime_sec, when);
|
||||
char* line = change_render_format("%f %n %l %b %M %%", config, &event);
|
||||
EXPECT_NOT_NULL(line);
|
||||
EXPECT_EQ_STR(line, "/srv/root/sub/file.txt file.txt 12345 999 1700000000 %");
|
||||
char expected[256];
|
||||
snprintf(expected, sizeof(expected), "src/sub/file.txt sub/file.txt 12345 999 %s %%", when);
|
||||
EXPECT_EQ_STR(line, expected);
|
||||
free(line);
|
||||
config_delete(config);
|
||||
}
|
||||
|
||||
static void test_format_unknown_tokens_preserved() {
|
||||
ChangeEvent event = sample_event();
|
||||
char* line = change_render_format("x%q=%f%z", &event);
|
||||
Config* config = config_create();
|
||||
char* line = change_render_format("x%q=%f%z", config, &event);
|
||||
EXPECT_NOT_NULL(line);
|
||||
EXPECT_EQ_STR(line, "x%q=/srv/root/sub/file.txt%z");
|
||||
EXPECT_EQ_STR(line, "x%q=src/sub/file.txt%z");
|
||||
free(line);
|
||||
config_delete(config);
|
||||
}
|
||||
|
||||
static void test_format_leaf_name() {
|
||||
static void test_format_directory_name_has_trailing_slash() {
|
||||
ChangeEvent event = sample_event();
|
||||
event.path = "bare.txt";
|
||||
char* line = change_render_format("%n|%f", &event);
|
||||
event.is_directory = true;
|
||||
event.path = "src/sub";
|
||||
event.name = "sub";
|
||||
Config* config = config_create();
|
||||
char* line = change_render_format("%n|%f", config, &event);
|
||||
EXPECT_NOT_NULL(line);
|
||||
EXPECT_EQ_STR(line, "bare.txt|bare.txt");
|
||||
EXPECT_EQ_STR(line, "sub/|src/sub");
|
||||
free(line);
|
||||
config_delete(config);
|
||||
}
|
||||
|
||||
static void test_render_itemize_sent_file() {
|
||||
ChangeEvent event = sample_event();
|
||||
char* line = change_render_itemize(&event);
|
||||
Config* config = config_create();
|
||||
char* line = change_render_itemize(config, &event);
|
||||
EXPECT_NOT_NULL(line);
|
||||
EXPECT_EQ_STR(line, ">f+++++++++ /srv/root/sub/file.txt");
|
||||
EXPECT_EQ_STR(line, ">f+++++++++ sub/file.txt");
|
||||
free(line);
|
||||
config_delete(config);
|
||||
}
|
||||
|
||||
static void test_render_itemize_directory() {
|
||||
ChangeEvent event = sample_event();
|
||||
event.is_directory = true;
|
||||
event.path = "src/sub";
|
||||
event.name = "sub";
|
||||
Config* config = config_create();
|
||||
char* line = change_render_itemize(config, &event);
|
||||
EXPECT_NOT_NULL(line);
|
||||
EXPECT_EQ_STR(line, "cd+++++++++ sub/");
|
||||
free(line);
|
||||
config_delete(config);
|
||||
}
|
||||
|
||||
static void test_render_itemize_symlink() {
|
||||
ChangeEvent event = sample_event();
|
||||
event.is_symlink = true;
|
||||
event.path = "src/link";
|
||||
event.name = "link";
|
||||
event.symlink_target = "a.txt";
|
||||
Config* config = config_create();
|
||||
char* line = change_render_itemize(config, &event);
|
||||
EXPECT_NOT_NULL(line);
|
||||
EXPECT_EQ_STR(line, "cL+++++++++ link -> a.txt");
|
||||
free(line);
|
||||
config_delete(config);
|
||||
}
|
||||
|
||||
static void test_render_itemize_compares_destination() {
|
||||
ChangeEvent event = sample_event();
|
||||
Config* config = config_create();
|
||||
config->preserve_perms = true;
|
||||
config->preserve_owner = true;
|
||||
config->preserve_group = true;
|
||||
event.dest.known = true;
|
||||
event.dest.existed = true;
|
||||
event.dest.size = 1;
|
||||
event.dest.mtime_sec = 1700000000;
|
||||
event.dest.mtime_nsec = 0;
|
||||
event.dest.mode = 0100600;
|
||||
event.dest.uid = 1;
|
||||
event.dest.gid = 2;
|
||||
char* line = change_render_itemize(config, &event);
|
||||
EXPECT_NOT_NULL(line);
|
||||
/* size, perms, owner and group differ; time matches. */
|
||||
EXPECT_EQ_STR(line, ">f.s.pog... sub/file.txt");
|
||||
free(line);
|
||||
config_delete(config);
|
||||
}
|
||||
|
||||
static void test_render_itemize_up_to_date_is_empty() {
|
||||
ChangeEvent event = sample_event();
|
||||
Config* config = config_create();
|
||||
event.decision = CHANGE_UP_TO_DATE;
|
||||
char* line = change_render_itemize(&event);
|
||||
char* line = change_render_itemize(config, &event);
|
||||
EXPECT_NOT_NULL(line);
|
||||
EXPECT_EQ_STR(line, "");
|
||||
free(line);
|
||||
config_delete(config);
|
||||
}
|
||||
|
||||
static void test_render_list_line() {
|
||||
char* line = change_render_list_line(0100644, 4096, 1700000000, "/srv/x.txt");
|
||||
ChangeEvent event;
|
||||
memset(&event, 0, sizeof(event));
|
||||
Config* config = config_create();
|
||||
event.name = "sub/x.txt";
|
||||
event.path = "sub/x.txt";
|
||||
event.mode = 0100644;
|
||||
event.size = 4096;
|
||||
event.mtime_sec = 1700000000;
|
||||
char* line = change_render_list_line(config, &event);
|
||||
EXPECT_NOT_NULL(line);
|
||||
EXPECT_TRUE(strncmp(line, "-rw-r--r--", 10) == 0);
|
||||
EXPECT_TRUE(strstr(line, "4096") != NULL);
|
||||
EXPECT_TRUE(strstr(line, "/srv/x.txt") != NULL);
|
||||
EXPECT_TRUE(strstr(line, "4,096") != NULL);
|
||||
EXPECT_TRUE(strstr(line, "sub/x.txt") != NULL);
|
||||
free(line);
|
||||
config_delete(config);
|
||||
}
|
||||
|
||||
static void test_change_list_enabled() {
|
||||
@@ -93,8 +180,11 @@ static void test_change_list_enabled() {
|
||||
void test_change_list() {
|
||||
test_format_tokens();
|
||||
test_format_unknown_tokens_preserved();
|
||||
test_format_leaf_name();
|
||||
test_format_directory_name_has_trailing_slash();
|
||||
test_render_itemize_sent_file();
|
||||
test_render_itemize_directory();
|
||||
test_render_itemize_symlink();
|
||||
test_render_itemize_compares_destination();
|
||||
test_render_itemize_up_to_date_is_empty();
|
||||
test_render_list_line();
|
||||
test_change_list_enabled();
|
||||
|
||||
Reference in New Issue
Block a user