coreutils / tests /mkdir /tests_for_process_dir.c
AryaWu's picture
Upload folder using huggingface_hub
78d2150 verified
#include "../../unity/unity.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
/* Unity setup/teardown */
void setUp(void) {
/* No global setup needed */
}
void tearDown(void) {
/* No global teardown needed */
}
/* Helpers */
static char *make_temp_dir(void)
{
char *tmpl = strdup("/tmp/cu_mkdir_process_dir_XXXXXX");
if (!tmpl)
return NULL;
if (!mkdtemp(tmpl)) {
free(tmpl);
return NULL;
}
return tmpl; /* caller must free string after rmdir-ing dir */
}
static char *path_join2(const char *a, const char *b)
{
size_t la = strlen(a);
size_t lb = strlen(b);
int need_slash = (la == 0 || a[la - 1] != '/');
size_t len = la + (need_slash ? 1 : 0) + lb + 1;
char *res = (char *)malloc(len);
if (!res) return NULL;
strcpy(res, a);
if (need_slash) strcat(res, "/");
strcat(res, b);
return res;
}
static int exists_is_dir(const char *path)
{
struct stat st;
if (stat(path, &st) != 0)
return 0;
return S_ISDIR(st.st_mode);
}
static int ensure_dir_absent(const char *path)
{
/* Try rmdir; ignore errors if not present */
if (rmdir(path) == 0)
return 0;
if (errno == ENOENT || errno == ENOTEMPTY)
return 0;
return -1;
}
/* Because process_dir may modify its dir argument, provide a fresh modifiable buffer */
static char *dup_cstr(const char *s)
{
size_t n = strlen(s);
char *p = (char *)malloc(n + 1);
if (!p) return NULL;
memcpy(p, s, n + 1);
return p;
}
/* Build a default options struct with no SELinux and no announcements. */
static void init_options_no_selinux(struct mkdir_options *o, int with_parents)
{
memset(o, 0, sizeof(*o));
mode_t old = umask(0);
umask(old);
o->make_ancestor_function = with_parents ? make_ancestor : NULL;
o->umask_ancestor = old;
o->umask_self = old;
o->mode = S_IRWXU | S_IRWXG | S_IRWXO; /* 0777 */
o->mode_bits = S_IRWXU | S_IRWXG | S_IRWXO;/* affect all rwx bits */
o->set_security_context = NULL;
o->created_directory_format = NULL; /* avoid printing */
}
/* Tests */
static void test_process_dir_creates_directory_when_parent_exists(void)
{
char *base = make_temp_dir();
TEST_ASSERT_NOT_NULL(base);
char *target = path_join2(base, "simple");
TEST_ASSERT_NOT_NULL(target);
/* Ensure target does not exist */
ensure_dir_absent(target);
struct mkdir_options o;
init_options_no_selinux(&o, 0); /* no -p */
char *mutable_path = dup_cstr(target);
TEST_ASSERT_NOT_NULL(mutable_path);
int ret = process_dir(mutable_path, NULL, &o);
free(mutable_path);
TEST_ASSERT_EQUAL_INT(EXIT_SUCCESS, ret);
TEST_ASSERT_TRUE_MESSAGE(exists_is_dir(target), "Target directory should exist");
/* Cleanup */
TEST_ASSERT_EQUAL_INT(0, rmdir(target));
TEST_ASSERT_EQUAL_INT(0, rmdir(base));
free(target);
free(base);
}
static void test_process_dir_existing_directory_without_parents_fails(void)
{
char *base = make_temp_dir();
TEST_ASSERT_NOT_NULL(base);
char *target = path_join2(base, "exists");
TEST_ASSERT_NOT_NULL(target);
/* Pre-create the directory */
int mk = mkdir(target, 0700);
TEST_ASSERT_TRUE_MESSAGE(mk == 0 || errno == EEXIST, "mkdir pre-create failed");
struct mkdir_options o;
init_options_no_selinux(&o, 0); /* no -p */
char *mutable_path = dup_cstr(target);
TEST_ASSERT_NOT_NULL(mutable_path);
int ret = process_dir(mutable_path, NULL, &o);
free(mutable_path);
TEST_ASSERT_EQUAL_INT_MESSAGE(EXIT_FAILURE, ret, "Expected failure when directory already exists without -p");
/* Cleanup */
TEST_ASSERT_EQUAL_INT(0, rmdir(target));
TEST_ASSERT_EQUAL_INT(0, rmdir(base));
free(target);
free(base);
}
static void test_process_dir_with_parents_creates_nested_directories(void)
{
char *base = make_temp_dir();
TEST_ASSERT_NOT_NULL(base);
char *p1 = path_join2(base, "p1");
char *p2 = path_join2(p1, "p2");
char *p3 = path_join2(p2, "p3");
TEST_ASSERT_NOT_NULL(p1);
TEST_ASSERT_NOT_NULL(p2);
TEST_ASSERT_NOT_NULL(p3);
struct mkdir_options o;
init_options_no_selinux(&o, 1); /* with -p behavior */
char *mutable_path = dup_cstr(p3);
TEST_ASSERT_NOT_NULL(mutable_path);
int ret = process_dir(mutable_path, NULL, &o);
free(mutable_path);
TEST_ASSERT_EQUAL_INT(EXIT_SUCCESS, ret);
TEST_ASSERT_TRUE_MESSAGE(exists_is_dir(p1), "p1 should exist");
TEST_ASSERT_TRUE_MESSAGE(exists_is_dir(p2), "p2 should exist");
TEST_ASSERT_TRUE_MESSAGE(exists_is_dir(p3), "p3 should exist");
/* Cleanup in reverse order */
TEST_ASSERT_EQUAL_INT(0, rmdir(p3));
TEST_ASSERT_EQUAL_INT(0, rmdir(p2));
TEST_ASSERT_EQUAL_INT(0, rmdir(p1));
TEST_ASSERT_EQUAL_INT(0, rmdir(base));
free(p3);
free(p2);
free(p1);
free(base);
}
static void test_process_dir_no_parents_missing_parent_fails(void)
{
char *base = make_temp_dir();
TEST_ASSERT_NOT_NULL(base);
char *p1 = path_join2(base, "m1");
char *p2 = path_join2(p1, "m2");
TEST_ASSERT_NOT_NULL(p1);
TEST_ASSERT_NOT_NULL(p2);
/* Do not create m1: ensure missing parent */
struct mkdir_options o;
init_options_no_selinux(&o, 0); /* no -p */
char *mutable_path = dup_cstr(p2);
TEST_ASSERT_NOT_NULL(mutable_path);
int ret = process_dir(mutable_path, NULL, &o);
free(mutable_path);
TEST_ASSERT_EQUAL_INT_MESSAGE(EXIT_FAILURE, ret, "Expected failure when parent is missing without -p");
TEST_ASSERT_FALSE_MESSAGE(exists_is_dir(p2), "Leaf directory should not have been created");
TEST_ASSERT_FALSE_MESSAGE(exists_is_dir(p1), "Parent directory should not have been created");
/* Cleanup: just the base temp directory */
TEST_ASSERT_EQUAL_INT(0, rmdir(base));
free(p2);
free(p1);
free(base);
}
/* Unity main */
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_process_dir_creates_directory_when_parent_exists);
RUN_TEST(test_process_dir_existing_directory_without_parents_fails);
RUN_TEST(test_process_dir_with_parents_creates_nested_directories);
RUN_TEST(test_process_dir_no_parents_missing_parent_fails);
return UNITY_END();
}