403 lines
12 KiB
C
403 lines
12 KiB
C
#include "test_utils.h"
|
|
#include "scanner.h"
|
|
#include "file.h"
|
|
#include "utils.h"
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
static void create_test_file(const char* path, const char* content) {
|
|
(void)to_disk(path, content, strlen(content));
|
|
}
|
|
|
|
static void test_scanner_single_file() {
|
|
const char* dir = "test_scan_dir_single";
|
|
const char* file1 = "test_scan_dir_single/file1.txt";
|
|
const char* content1 = "hello scanner";
|
|
|
|
EXPECT_EQ_INT(mkdir(dir, 0755), 0);
|
|
create_test_file(file1, content1);
|
|
|
|
DirectoryScanner* scanner =
|
|
directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0, 0);
|
|
EXPECT_NOT_NULL(scanner);
|
|
|
|
Chunk* chunk = directory_scanner_next(scanner);
|
|
EXPECT_NOT_NULL(chunk);
|
|
EXPECT_EQ_INT(chunk->element_count, 1);
|
|
EXPECT_EQ_STR(chunk->items[0]->path, file1);
|
|
|
|
const Chunk* next = directory_scanner_next(scanner);
|
|
EXPECT_NULL(next);
|
|
|
|
chunk_destroy(chunk);
|
|
directory_scanner_destroy(scanner);
|
|
unlink(file1);
|
|
rmdir(dir);
|
|
}
|
|
|
|
static void test_scanner_multiple_files() {
|
|
const char* dir = "test_scan_dir_multi";
|
|
const char* file1 = "test_scan_dir_multi/a.txt";
|
|
const char* file2 = "test_scan_dir_multi/b.txt";
|
|
const char* content1 = "alpha";
|
|
const char* content2 = "beta";
|
|
|
|
EXPECT_EQ_INT(mkdir(dir, 0755), 0);
|
|
create_test_file(file1, content1);
|
|
create_test_file(file2, content2);
|
|
|
|
DirectoryScanner* scanner =
|
|
directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0, 0);
|
|
EXPECT_NOT_NULL(scanner);
|
|
|
|
const Chunk* chunk = directory_scanner_next(scanner);
|
|
EXPECT_NOT_NULL(chunk);
|
|
EXPECT_EQ_INT(chunk->element_count, 2);
|
|
|
|
int found1 = 0, found2 = 0;
|
|
for (int i = 0; i < chunk->element_count; i++) {
|
|
if (strcmp(chunk->items[i]->path, file1) == 0)
|
|
found1 = 1;
|
|
if (strcmp(chunk->items[i]->path, file2) == 0)
|
|
found2 = 1;
|
|
}
|
|
EXPECT_TRUE(found1);
|
|
EXPECT_TRUE(found2);
|
|
|
|
const Chunk* next = directory_scanner_next(scanner);
|
|
EXPECT_NULL(next);
|
|
|
|
chunk_destroy((void*)chunk);
|
|
directory_scanner_destroy(scanner);
|
|
unlink(file1);
|
|
unlink(file2);
|
|
rmdir(dir);
|
|
}
|
|
|
|
static void test_scanner_subdirectory() {
|
|
const char* root = "test_scan_sub";
|
|
const char* sub = "test_scan_sub/sub";
|
|
const char* root_file = "test_scan_sub/root.txt";
|
|
const char* sub_file = "test_scan_sub/sub/sub_file.txt";
|
|
const char* content = "nested content";
|
|
|
|
EXPECT_EQ_INT(mkdir(root, 0755), 0);
|
|
EXPECT_EQ_INT(mkdir(sub, 0755), 0);
|
|
create_test_file(root_file, content);
|
|
create_test_file(sub_file, content);
|
|
|
|
DirectoryScanner* scanner =
|
|
directory_scanner_create((char*)root, false, 0, NULL, 0, NULL, 0, 0, 0, 0);
|
|
EXPECT_NOT_NULL(scanner);
|
|
|
|
int total_files = 0;
|
|
Chunk* chunk;
|
|
while ((chunk = directory_scanner_next(scanner)) != NULL) {
|
|
total_files += chunk->element_count;
|
|
chunk_destroy(chunk);
|
|
}
|
|
EXPECT_EQ_INT(total_files, 2);
|
|
|
|
directory_scanner_destroy(scanner);
|
|
unlink(root_file);
|
|
unlink(sub_file);
|
|
rmdir(sub);
|
|
rmdir(root);
|
|
}
|
|
|
|
static void test_scanner_empty_directory() {
|
|
const char* dir = "test_scan_empty";
|
|
|
|
EXPECT_EQ_INT(mkdir(dir, 0755), 0);
|
|
|
|
DirectoryScanner* scanner =
|
|
directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0, 0);
|
|
EXPECT_NOT_NULL(scanner);
|
|
|
|
const Chunk* chunk = directory_scanner_next(scanner);
|
|
EXPECT_NULL(chunk);
|
|
|
|
directory_scanner_destroy(scanner);
|
|
rmdir(dir);
|
|
}
|
|
|
|
/* --- Exclude/include pattern and size filter edge cases (Issue #56) --- */
|
|
|
|
static void test_scanner_exclude_pattern() {
|
|
const char* dir = "test_scan_excl";
|
|
const char* f_txt = "test_scan_excl/keep.txt";
|
|
const char* f_tmp = "test_scan_excl/remove.tmp";
|
|
const char* content = "data";
|
|
|
|
EXPECT_EQ_INT(mkdir(dir, 0755), 0);
|
|
create_test_file(f_txt, content);
|
|
create_test_file(f_tmp, content);
|
|
|
|
char* exclude[] = {"*.tmp"};
|
|
DirectoryScanner* scanner =
|
|
directory_scanner_create((char*)dir, false, 0, exclude, 1, NULL, 0, 0, 0, 0);
|
|
EXPECT_NOT_NULL(scanner);
|
|
|
|
Chunk* chunk = directory_scanner_next(scanner);
|
|
EXPECT_NOT_NULL(chunk);
|
|
EXPECT_EQ_INT(chunk->element_count, 1);
|
|
EXPECT_EQ_STR(chunk->items[0]->path, f_txt);
|
|
|
|
chunk_destroy(chunk);
|
|
EXPECT_NULL(directory_scanner_next(scanner));
|
|
|
|
directory_scanner_destroy(scanner);
|
|
unlink(f_txt);
|
|
unlink(f_tmp);
|
|
rmdir(dir);
|
|
}
|
|
|
|
static void test_scanner_exclude_subdirectory() {
|
|
const char* root = "test_scan_excl_sub";
|
|
const char* sub = "test_scan_excl_sub/sub";
|
|
const char* root_txt = "test_scan_excl_sub/root.txt";
|
|
const char* sub_txt = "test_scan_excl_sub/sub/data.txt";
|
|
const char* sub_tmp = "test_scan_excl_sub/sub/temp.tmp";
|
|
const char* content = "data";
|
|
|
|
EXPECT_EQ_INT(mkdir(root, 0755), 0);
|
|
EXPECT_EQ_INT(mkdir(sub, 0755), 0);
|
|
create_test_file(root_txt, content);
|
|
create_test_file(sub_txt, content);
|
|
create_test_file(sub_tmp, content);
|
|
|
|
char* exclude[] = {"*.tmp"};
|
|
DirectoryScanner* scanner =
|
|
directory_scanner_create((char*)root, false, 0, exclude, 1, NULL, 0, 0, 0, 0);
|
|
EXPECT_NOT_NULL(scanner);
|
|
|
|
int total = 0;
|
|
Chunk* chunk;
|
|
while ((chunk = directory_scanner_next(scanner)) != NULL) {
|
|
total += chunk->element_count;
|
|
for (int i = 0; i < chunk->element_count; i++) {
|
|
size_t len = strlen(chunk->items[i]->path);
|
|
EXPECT_TRUE(len < 4 || strcmp(chunk->items[i]->path + len - 4, ".tmp") != 0);
|
|
}
|
|
chunk_destroy(chunk);
|
|
}
|
|
EXPECT_EQ_INT(total, 2);
|
|
|
|
directory_scanner_destroy(scanner);
|
|
unlink(root_txt);
|
|
unlink(sub_txt);
|
|
unlink(sub_tmp);
|
|
rmdir(sub);
|
|
rmdir(root);
|
|
}
|
|
|
|
static void test_scanner_include_and_exclude() {
|
|
const char* dir = "test_scan_inc_exc";
|
|
const char* f_txt = "test_scan_inc_exc/a.txt";
|
|
const char* f_log = "test_scan_inc_exc/b.log";
|
|
const char* f_bak = "test_scan_inc_exc/c.bak";
|
|
const char* content = "filter";
|
|
|
|
EXPECT_EQ_INT(mkdir(dir, 0755), 0);
|
|
create_test_file(f_txt, content);
|
|
create_test_file(f_log, content);
|
|
create_test_file(f_bak, content);
|
|
|
|
char* exclude[] = {"*.bak"};
|
|
char* include[] = {"*.txt", "*.log"};
|
|
DirectoryScanner* scanner =
|
|
directory_scanner_create((char*)dir, false, 0, exclude, 1, include, 2, 0, 0, 0);
|
|
EXPECT_NOT_NULL(scanner);
|
|
|
|
Chunk* chunk = directory_scanner_next(scanner);
|
|
EXPECT_NOT_NULL(chunk);
|
|
EXPECT_EQ_INT(chunk->element_count, 2);
|
|
|
|
int found_txt = 0, found_log = 0;
|
|
for (int i = 0; i < chunk->element_count; i++) {
|
|
if (strstr(chunk->items[i]->path, "a.txt"))
|
|
found_txt = 1;
|
|
if (strstr(chunk->items[i]->path, "b.log"))
|
|
found_log = 1;
|
|
}
|
|
EXPECT_TRUE(found_txt);
|
|
EXPECT_TRUE(found_log);
|
|
|
|
chunk_destroy(chunk);
|
|
EXPECT_NULL(directory_scanner_next(scanner));
|
|
|
|
directory_scanner_destroy(scanner);
|
|
unlink(f_txt);
|
|
unlink(f_log);
|
|
unlink(f_bak);
|
|
rmdir(dir);
|
|
}
|
|
|
|
static void test_scanner_max_size() {
|
|
const char* dir = "test_scan_max";
|
|
const char* small = "test_scan_max/small.txt";
|
|
const char* large = "test_scan_max/large.txt";
|
|
EXPECT_EQ_INT(mkdir(dir, 0755), 0);
|
|
create_test_file(small, "tiny");
|
|
create_test_file(large, "this_content_is_longer_than_ten_chars");
|
|
|
|
/* max_size = 10 — only files <= 10 bytes */
|
|
DirectoryScanner* scanner =
|
|
directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 10, 0, 0);
|
|
EXPECT_NOT_NULL(scanner);
|
|
|
|
Chunk* chunk = directory_scanner_next(scanner);
|
|
EXPECT_NOT_NULL(chunk);
|
|
EXPECT_EQ_INT(chunk->element_count, 1);
|
|
EXPECT_EQ_STR(chunk->items[0]->path, small);
|
|
|
|
chunk_destroy(chunk);
|
|
EXPECT_NULL(directory_scanner_next(scanner));
|
|
|
|
directory_scanner_destroy(scanner);
|
|
unlink(small);
|
|
unlink(large);
|
|
rmdir(dir);
|
|
}
|
|
|
|
static void test_scanner_min_size() {
|
|
const char* dir = "test_scan_min";
|
|
const char* empty_f = "test_scan_min/empty.txt";
|
|
const char* data_f = "test_scan_min/data.txt";
|
|
|
|
EXPECT_EQ_INT(mkdir(dir, 0755), 0);
|
|
create_test_file(empty_f, "");
|
|
create_test_file(data_f, "some content here");
|
|
|
|
/* min_size = 1 — only files >= 1 byte */
|
|
DirectoryScanner* scanner =
|
|
directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 1, 0);
|
|
EXPECT_NOT_NULL(scanner);
|
|
|
|
Chunk* chunk = directory_scanner_next(scanner);
|
|
EXPECT_NOT_NULL(chunk);
|
|
EXPECT_EQ_INT(chunk->element_count, 1);
|
|
EXPECT_EQ_STR(chunk->items[0]->path, data_f);
|
|
|
|
chunk_destroy(chunk);
|
|
EXPECT_NULL(directory_scanner_next(scanner));
|
|
|
|
directory_scanner_destroy(scanner);
|
|
unlink(empty_f);
|
|
unlink(data_f);
|
|
rmdir(dir);
|
|
}
|
|
|
|
static void test_scanner_size_range() {
|
|
const char* dir = "test_scan_range";
|
|
const char* tiny = "test_scan_range/tiny.txt";
|
|
const char* medium = "test_scan_range/med.txt";
|
|
const char* huge = "test_scan_range/huge.txt";
|
|
|
|
EXPECT_EQ_INT(mkdir(dir, 0755), 0);
|
|
create_test_file(tiny, "ab");
|
|
create_test_file(medium, "hello world");
|
|
create_test_file(huge, "this is a much larger file for testing size filters");
|
|
|
|
/* Only files between 3 and 20 bytes */
|
|
DirectoryScanner* scanner =
|
|
directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 20, 3, 0);
|
|
EXPECT_NOT_NULL(scanner);
|
|
|
|
Chunk* chunk = directory_scanner_next(scanner);
|
|
EXPECT_NOT_NULL(chunk);
|
|
EXPECT_EQ_INT(chunk->element_count, 1);
|
|
EXPECT_EQ_STR(chunk->items[0]->path, medium);
|
|
|
|
chunk_destroy(chunk);
|
|
EXPECT_NULL(directory_scanner_next(scanner));
|
|
|
|
directory_scanner_destroy(scanner);
|
|
unlink(tiny);
|
|
unlink(medium);
|
|
unlink(huge);
|
|
rmdir(dir);
|
|
}
|
|
|
|
static void test_scanner_mixed_patterns() {
|
|
/* Combine exclude, include, and size filters together */
|
|
const char* dir = "test_scan_mixed";
|
|
const char* a_txt = "test_scan_mixed/a.txt"; /* size ~= 5 */
|
|
const char* b_bin = "test_scan_mixed/b.bin"; /* size ~= 13 */
|
|
const char* c_txt = "test_scan_mixed/c.txt"; /* size ~= 5 */
|
|
const char* d_bak = "test_scan_mixed/d.bak"; /* size ~= 42 */
|
|
|
|
EXPECT_EQ_INT(mkdir(dir, 0755), 0);
|
|
create_test_file(a_txt, "aaaaa");
|
|
create_test_file(b_bin, "bbbbbbbbbbbbb");
|
|
create_test_file(c_txt, "ccccc");
|
|
create_test_file(d_bak, "dddddddddddddddddddddddddddddddddddddddddd");
|
|
|
|
/* Exclude *.bak, include *.txt, min_size=3, max_size=10 */
|
|
char* exclude[] = {"*.bak"};
|
|
char* include[] = {"*.txt"};
|
|
DirectoryScanner* scanner =
|
|
directory_scanner_create((char*)dir, false, 0, exclude, 1, include, 1, 10, 3, 0);
|
|
EXPECT_NOT_NULL(scanner);
|
|
|
|
Chunk* chunk = directory_scanner_next(scanner);
|
|
EXPECT_NOT_NULL(chunk);
|
|
/* Both a.txt and c.txt meet the criteria: .txt extension, size 5 <= 10 and >= 3 */
|
|
EXPECT_EQ_INT(chunk->element_count, 2);
|
|
|
|
chunk_destroy(chunk);
|
|
EXPECT_NULL(directory_scanner_next(scanner));
|
|
|
|
directory_scanner_destroy(scanner);
|
|
unlink(a_txt);
|
|
unlink(b_bin);
|
|
unlink(c_txt);
|
|
unlink(d_bak);
|
|
rmdir(dir);
|
|
}
|
|
|
|
static void test_scanner_no_patterns() {
|
|
/* Explicit test with no exclude/include patterns and no size filters.
|
|
* This verifies that NULL/0 for all pattern parameters works correctly. */
|
|
const char* dir = "test_scan_none";
|
|
const char* f1 = "test_scan_none/f1.txt";
|
|
const char* f2 = "test_scan_none/f2.txt";
|
|
|
|
EXPECT_EQ_INT(mkdir(dir, 0755), 0);
|
|
create_test_file(f1, "first");
|
|
create_test_file(f2, "second");
|
|
|
|
DirectoryScanner* scanner =
|
|
directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0, 0);
|
|
EXPECT_NOT_NULL(scanner);
|
|
|
|
Chunk* chunk = directory_scanner_next(scanner);
|
|
EXPECT_NOT_NULL(chunk);
|
|
EXPECT_EQ_INT(chunk->element_count, 2);
|
|
|
|
chunk_destroy(chunk);
|
|
EXPECT_NULL(directory_scanner_next(scanner));
|
|
|
|
directory_scanner_destroy(scanner);
|
|
unlink(f1);
|
|
unlink(f2);
|
|
rmdir(dir);
|
|
}
|
|
|
|
void test_scanner() {
|
|
test_scanner_single_file();
|
|
test_scanner_multiple_files();
|
|
test_scanner_subdirectory();
|
|
test_scanner_empty_directory();
|
|
/* Issue #56: scanner pattern edge cases */
|
|
test_scanner_exclude_pattern();
|
|
test_scanner_exclude_subdirectory();
|
|
test_scanner_include_and_exclude();
|
|
test_scanner_max_size();
|
|
test_scanner_min_size();
|
|
test_scanner_size_range();
|
|
test_scanner_mixed_patterns();
|
|
test_scanner_no_patterns();
|
|
}
|