32 changes: 32 additions & 0 deletions libc/test/src/sys/stat/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,38 @@ add_libc_testsuite(libc_sys_stat_unittests)

add_subdirectory(testdata)

add_libc_unittest(
chmod_test
SUITE
libc_sys_stat_unittests
SRCS
chmod_test.cpp
DEPENDS
libc.include.errno
libc.include.fcntl
libc.include.sys_stat
libc.src.fcntl.open
libc.src.sys.stat.chmod
libc.src.unistd.close
libc.src.unistd.write
)

add_libc_unittest(
fchmod_test
SUITE
libc_sys_stat_unittests
SRCS
fchmod_test.cpp
DEPENDS
libc.include.errno
libc.include.fcntl
libc.include.sys_stat
libc.src.fcntl.open
libc.src.sys.stat.fchmod
libc.src.unistd.close
libc.src.unistd.write
)

add_libc_unittest(
mkdirat_test
SUITE
Expand Down
64 changes: 64 additions & 0 deletions libc/test/src/sys/stat/chmod_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//===-- Unittests for chmod -----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/fcntl/open.h"
#include "src/sys/stat/chmod.h"
#include "src/unistd/close.h"
#include "src/unistd/write.h"
#include "test/ErrnoSetterMatcher.h"
#include "utils/UnitTest/Test.h"
#include "utils/testutils/FDReader.h"

#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>

TEST(LlvmLibcChmodTest, ChangeAndOpen) {
using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;

// The test file is initially writable. We open it for writing and ensure
// that it indeed can be opened for writing. Next, we close the file and
// make it readonly using chmod. We test that chmod actually succeeded by
// trying to open the file for writing and failing.
constexpr const char *TEST_FILE = "testdata/chmod.test";
const char WRITE_DATA[] = "test data";
constexpr ssize_t WRITE_SIZE = ssize_t(sizeof(WRITE_DATA));
errno = 0;

int fd = __llvm_libc::open(TEST_FILE, O_APPEND | O_WRONLY);
ASSERT_GT(fd, 0);
ASSERT_EQ(errno, 0);
ASSERT_EQ(__llvm_libc::write(fd, WRITE_DATA, sizeof(WRITE_DATA)), WRITE_SIZE);
ASSERT_THAT(__llvm_libc::close(fd), Succeeds(0));

fd = __llvm_libc::open(TEST_FILE, O_PATH);
ASSERT_GT(fd, 0);
ASSERT_EQ(errno, 0);
ASSERT_THAT(__llvm_libc::close(fd), Succeeds(0));
EXPECT_THAT(__llvm_libc::chmod(TEST_FILE, S_IRUSR), Succeeds(0));

// Opening for writing should fail.
EXPECT_EQ(__llvm_libc::open(TEST_FILE, O_APPEND | O_WRONLY), -1);
EXPECT_NE(errno, 0);
errno = 0;
// But opening for reading should succeed.
fd = __llvm_libc::open(TEST_FILE, O_APPEND | O_RDONLY);
EXPECT_GT(fd, 0);
EXPECT_EQ(errno, 0);

EXPECT_THAT(__llvm_libc::close(fd), Succeeds(0));
EXPECT_THAT(__llvm_libc::chmod(TEST_FILE, S_IRWXU), Succeeds(0));
}

TEST(LlvmLibcChmodTest, NonExistentFile) {
errno = 0;
using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
ASSERT_THAT(__llvm_libc::chmod("non-existent-file", S_IRUSR), Fails(ENOENT));
errno = 0;
}
64 changes: 64 additions & 0 deletions libc/test/src/sys/stat/fchmod_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//===-- Unittests for fchmod ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/fcntl/open.h"
#include "src/sys/stat/fchmod.h"
#include "src/unistd/close.h"
#include "src/unistd/write.h"
#include "test/ErrnoSetterMatcher.h"
#include "utils/UnitTest/Test.h"
#include "utils/testutils/FDReader.h"

#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>

TEST(LlvmLibcChmodTest, ChangeAndOpen) {
using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;

// The test file is initially writable. We open it for writing and ensure
// that it indeed can be opened for writing. Next, we close the file and
// make it readonly using chmod. We test that chmod actually succeeded by
// trying to open the file for writing and failing.
constexpr const char *TEST_FILE = "testdata/fchmod.test";
const char WRITE_DATA[] = "test data";
constexpr ssize_t WRITE_SIZE = ssize_t(sizeof(WRITE_DATA));
errno = 0;

int fd = __llvm_libc::open(TEST_FILE, O_APPEND | O_WRONLY);
ASSERT_GT(fd, 0);
ASSERT_EQ(errno, 0);
ASSERT_EQ(__llvm_libc::write(fd, WRITE_DATA, sizeof(WRITE_DATA)), WRITE_SIZE);
ASSERT_THAT(__llvm_libc::close(fd), Succeeds(0));

fd = __llvm_libc::open(TEST_FILE, O_APPEND | O_WRONLY);
ASSERT_GT(fd, 0);
ASSERT_EQ(errno, 0);
EXPECT_THAT(__llvm_libc::fchmod(fd, S_IRUSR), Succeeds(0));
ASSERT_THAT(__llvm_libc::close(fd), Succeeds(0));

// Opening for writing should fail.
EXPECT_EQ(__llvm_libc::open(TEST_FILE, O_APPEND | O_WRONLY), -1);
EXPECT_NE(errno, 0);
errno = 0;
// But opening for reading should succeed.
fd = __llvm_libc::open(TEST_FILE, O_APPEND | O_RDONLY);
EXPECT_GT(fd, 0);
EXPECT_EQ(errno, 0);

EXPECT_THAT(__llvm_libc::fchmod(fd, S_IRWXU), Succeeds(0));
EXPECT_THAT(__llvm_libc::close(fd), Succeeds(0));
}

TEST(LlvmLibcChmodTest, NonExistentFile) {
errno = 0;
ASSERT_EQ(__llvm_libc::fchmod(-1, S_IRUSR), -1);
ASSERT_NE(errno, 0);
errno = 0;
}
6 changes: 4 additions & 2 deletions libc/test/src/sys/stat/testdata/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
# This directory will be used to create test files and delete them
# from tests.
# This directory will be used to create test files.

file(GENERATE OUTPUT chmod.test CONTENT "chmod test")
file(GENERATE OUTPUT fchmod.test CONTENT "fchmod test")
30 changes: 30 additions & 0 deletions libc/test/src/unistd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,36 @@ add_libc_testsuite(libc_unistd_unittests)

add_subdirectory(testdata)

add_libc_unittest(
chdir_test
SUITE
libc_unistd_unittests
SRCS
chdir_test.cpp
DEPENDS
libc.include.errno
libc.include.unistd
libc.src.fcntl.open
libc.src.unistd.chdir
libc.src.unistd.close
libc.test.errno_setter_matcher
)

add_libc_unittest(
fchdir_test
SUITE
libc_unistd_unittests
SRCS
fchdir_test.cpp
DEPENDS
libc.include.errno
libc.include.unistd
libc.src.fcntl.open
libc.src.unistd.fchdir
libc.src.unistd.close
libc.test.errno_setter_matcher
)

add_libc_unittest(
read_write_test
SUITE
Expand Down
47 changes: 47 additions & 0 deletions libc/test/src/unistd/chdir_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//===-- Unittests for chdir -----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/fcntl/open.h"
#include "src/unistd/chdir.h"
#include "src/unistd/close.h"
#include "test/ErrnoSetterMatcher.h"
#include "utils/UnitTest/Test.h"
#include "utils/testutils/FDReader.h"

#include <errno.h>
#include <fcntl.h>

TEST(LlvmLibcChdirTest, ChangeAndOpen) {
// The idea of this test is that we will first open an existing test file
// without changing the directory to make sure it exists. Next, we change
// directory and open the same file to make sure that the "chdir" operation
// succeeded.
using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
constexpr const char *TEST_DIR = "testdata";
constexpr const char *TEST_FILE = "testdata/chdir.test";
constexpr const char *TEST_FILE_BASE = "chdir.test";
errno = 0;

int fd = __llvm_libc::open(TEST_FILE, O_PATH);
ASSERT_GT(fd, 0);
ASSERT_EQ(errno, 0);
ASSERT_THAT(__llvm_libc::close(fd), Succeeds(0));

ASSERT_THAT(__llvm_libc::chdir(TEST_DIR), Succeeds(0));
fd = __llvm_libc::open(TEST_FILE_BASE, O_PATH);
ASSERT_GT(fd, 0);
ASSERT_EQ(errno, 0);
ASSERT_THAT(__llvm_libc::close(fd), Succeeds(0));
}

TEST(LlvmLibcChdirTest, ChangeToNonExistentDir) {
errno = 0;
using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
ASSERT_THAT(__llvm_libc::chdir("non-existent-dir"), Fails(ENOENT));
errno = 0;
}
52 changes: 52 additions & 0 deletions libc/test/src/unistd/fchdir_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//===-- Unittests for fchdir ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/fcntl/open.h"
#include "src/unistd/close.h"
#include "src/unistd/fchdir.h"
#include "test/ErrnoSetterMatcher.h"
#include "utils/UnitTest/Test.h"
#include "utils/testutils/FDReader.h"

#include <errno.h>
#include <fcntl.h>

TEST(LlvmLibcChdirTest, ChangeAndOpen) {
// The idea of this test is that we will first open an existing test file
// without changing the directory to make sure it exists. Next, we change
// directory and open the same file to make sure that the "fchdir" operation
// succeeded.
using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
constexpr const char *TEST_DIR = "testdata";
constexpr const char *TEST_FILE = "testdata/fchdir.test";
constexpr const char *TEST_FILE_BASE = "fchdir.test";
errno = 0;

int dir_fd = __llvm_libc::open(TEST_DIR, O_DIRECTORY);
ASSERT_GT(dir_fd, 0);
ASSERT_EQ(errno, 0);
int file_fd = __llvm_libc::open(TEST_FILE, O_PATH);
ASSERT_GT(file_fd, 0);
ASSERT_EQ(errno, 0);
ASSERT_THAT(__llvm_libc::close(file_fd), Succeeds(0));

ASSERT_THAT(__llvm_libc::fchdir(dir_fd), Succeeds(0));
file_fd = __llvm_libc::open(TEST_FILE_BASE, O_PATH);
ASSERT_GT(file_fd, 0);
ASSERT_EQ(errno, 0);
ASSERT_THAT(__llvm_libc::close(file_fd), Succeeds(0));
ASSERT_THAT(__llvm_libc::close(dir_fd), Succeeds(0));
}

TEST(LlvmLibcChdirTest, ChangeToNonExistentDir) {
using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
errno = 0;
ASSERT_EQ(__llvm_libc::fchdir(0), -1);
ASSERT_NE(errno, 0);
errno = 0;
}
5 changes: 3 additions & 2 deletions libc/test/src/unistd/testdata/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# This directory will be used to create test files and delete them
# from tests.
# This directory will be used to create test files.

file(GENERATE OUTPUT lseek.test CONTENT "lseek test")
file(GENERATE OUTPUT chdir.test CONTENT "chdir test")
file(GENERATE OUTPUT fchdir.test CONTENT "fchdir test")