Skip to content

[libc] Update integration tests to use the C functions directly #81866

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 0 additions & 41 deletions libc/test/IntegrationTest/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,47 +9,6 @@
#include <stddef.h>
#include <stdint.h>

// Integration tests rely on the following memory functions. This is because the
// compiler code generation can emit calls to them. We want to map the external
// entrypoint to the internal implementation of the function used for testing.
// This is done manually as not all targets support aliases.

namespace LIBC_NAMESPACE {

int bcmp(const void *lhs, const void *rhs, size_t count);
void bzero(void *ptr, size_t count);
int memcmp(const void *lhs, const void *rhs, size_t count);
void *memcpy(void *__restrict, const void *__restrict, size_t);
void *memmove(void *dst, const void *src, size_t count);
void *memset(void *ptr, int value, size_t count);
int atexit(void (*func)(void));

} // namespace LIBC_NAMESPACE

extern "C" {

int bcmp(const void *lhs, const void *rhs, size_t count) {
return LIBC_NAMESPACE::bcmp(lhs, rhs, count);
}
void bzero(void *ptr, size_t count) { LIBC_NAMESPACE::bzero(ptr, count); }
int memcmp(const void *lhs, const void *rhs, size_t count) {
return LIBC_NAMESPACE::memcmp(lhs, rhs, count);
}
void *memcpy(void *__restrict dst, const void *__restrict src, size_t count) {
return LIBC_NAMESPACE::memcpy(dst, src, count);
}
void *memmove(void *dst, const void *src, size_t count) {
return LIBC_NAMESPACE::memmove(dst, src, count);
}
void *memset(void *ptr, int value, size_t count) {
return LIBC_NAMESPACE::memset(ptr, value, count);
}

// This is needed if the test was compiled with '-fno-use-cxa-atexit'.
int atexit(void (*func)(void)) { return LIBC_NAMESPACE::atexit(func); }

} // extern "C"

// Integration tests cannot use the SCUDO standalone allocator as SCUDO pulls
// various other parts of the libc. Since SCUDO development does not use
// LLVM libc build rules, it is very hard to keep track or pull all that SCUDO
Expand Down
50 changes: 43 additions & 7 deletions libc/test/IntegrationTest/test.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@
#include "src/__support/OSUtil/io.h"
#include "src/__support/OSUtil/quick_exit.h"

inline static bool streq(const char *lhs, const char *rhs) {
if (lhs == rhs)
return true;
if ((!lhs && rhs) || (lhs && !rhs))
return false;
const char *l, *r;
for (l = lhs, r = rhs; *l != '\0' && *r != '\0'; ++l, ++r)
if (*l != *r)
return false;
return *l == '\0' && *r == '\0';
}

#define __AS_STRING(val) #val
#define __CHECK_TRUE(file, line, val, should_exit) \
if (!(val)) { \
Expand Down Expand Up @@ -45,9 +57,24 @@
LIBC_NAMESPACE::quick_exit(127); \
}

#define __CHECK_STREQ(file, line, val1, val2, should_exit) \
if (streq((val1), (val2)) == false) { \
LIBC_NAMESPACE::write_to_stderr(file ":" __AS_STRING( \
line) ": Expected '" #val1 "' to be equal to '" #val2 "'\n"); \
if (should_exit) \
LIBC_NAMESPACE::quick_exit(127); \
}

#define __CHECK_STRNE(file, line, val1, val2, should_exit) \
if (streq((val1), (val2)) == true) { \
LIBC_NAMESPACE::write_to_stderr(file ":" __AS_STRING( \
line) ": Expected '" #val1 "' to not be equal to '" #val2 "'\n"); \
if (should_exit) \
LIBC_NAMESPACE::quick_exit(127); \
}

////////////////////////////////////////////////////////////////////////////////
// Boolean checks are handled as comparison to the true / false values.

#define EXPECT_TRUE(val) __CHECK_TRUE(__FILE__, __LINE__, val, false)
#define ASSERT_TRUE(val) __CHECK_TRUE(__FILE__, __LINE__, val, true)
#define EXPECT_FALSE(val) __CHECK_FALSE(__FILE__, __LINE__, val, false)
Expand All @@ -65,15 +92,24 @@
#define ASSERT_NE(val1, val2) \
__CHECK_NE(__FILE__, __LINE__, (val1), (val2), true)

////////////////////////////////////////////////////////////////////////////////
// String equality / inequality.

#define EXPECT_STREQ(val1, val2) \
__CHECK_STREQ(__FILE__, __LINE__, (val1), (val2), false)
#define ASSERT_STREQ(val1, val2) \
__CHECK_STREQ(__FILE__, __LINE__, (val1), (val2), true)
#define EXPECT_STRNE(val1, val2) \
__CHECK_STRNE(__FILE__, __LINE__, (val1), (val2), false)
#define ASSERT_STRNE(val1, val2) \
__CHECK_STRNE(__FILE__, __LINE__, (val1), (val2), true)

////////////////////////////////////////////////////////////////////////////////
// Errno checks.

#define ASSERT_ERRNO_EQ(VAL) \
ASSERT_EQ(VAL, static_cast<int>(LIBC_NAMESPACE::libc_errno))
#define ASSERT_ERRNO_SUCCESS() \
ASSERT_EQ(0, static_cast<int>(LIBC_NAMESPACE::libc_errno))
#define ASSERT_ERRNO_FAILURE() \
ASSERT_NE(0, static_cast<int>(LIBC_NAMESPACE::libc_errno))
#define ASSERT_ERRNO_EQ(VAL) ASSERT_EQ(VAL, errno)
#define ASSERT_ERRNO_SUCCESS() ASSERT_EQ(0, errno)
#define ASSERT_ERRNO_FAILURE() ASSERT_NE(0, errno)

// Integration tests are compiled with -ffreestanding which stops treating
// the main function as a non-overloadable special function. Hence, we use a
Expand Down
48 changes: 8 additions & 40 deletions libc/test/integration/src/stdio/sprintf_size_test.cpp
Original file line number Diff line number Diff line change
@@ -1,60 +1,28 @@
//===-- Unittests for getenv ----------------------------------------------===//
//===-- Unittests for sprintf ---------------------------------------------===//
//
// 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 <stddef.h>

#ifndef INTEGRATION_DISABLE_PRINTF
#include "src/stdio/sprintf.h"
#include <stdio.h> // sprintf
#endif

#include "test/IntegrationTest/test.h"

static bool my_streq(const char *lhs, const char *rhs) {
if (lhs == rhs)
return true;
if (((lhs == static_cast<char *>(nullptr)) &&
(rhs != static_cast<char *>(nullptr))) ||
((lhs != static_cast<char *>(nullptr)) &&
(rhs == static_cast<char *>(nullptr)))) {
return false;
}
const char *l, *r;
for (l = lhs, r = rhs; *l != '\0' && *r != '\0'; ++l, ++r)
if (*l != *r)
return false;

return *l == '\0' && *r == '\0';
}

static int my_strlen(const char *str) {
const char *other = str;
while (*other)
++other;
return static_cast<int>(other - str);
}

TEST_MAIN(int argc, char **argv, char **envp) {
ASSERT_EQ(argc, 5);
ASSERT_TRUE(my_streq(argv[1], "%s %c %d"));
ASSERT_EQ(my_strlen(argv[1]), 8);
ASSERT_TRUE(my_streq(argv[2], "First arg"));
ASSERT_EQ(my_strlen(argv[2]), 9);
ASSERT_TRUE(my_streq(argv[3], "a"));
ASSERT_EQ(my_strlen(argv[3]), 1);
ASSERT_TRUE(my_streq(argv[4], "0"));
ASSERT_EQ(my_strlen(argv[4]), 1);
ASSERT_STREQ(argv[1], "%s %c %d");
ASSERT_STREQ(argv[2], "First arg");
ASSERT_STREQ(argv[3], "a");
ASSERT_STREQ(argv[4], "0");

#ifndef INTEGRATION_DISABLE_PRINTF
char buf[100];
ASSERT_EQ(
LIBC_NAMESPACE::sprintf(buf, argv[1], argv[2], argv[3][0], argv[4][0]),
14);
ASSERT_TRUE(my_streq(buf, "First arg a 48"));
ASSERT_EQ(sprintf(buf, argv[1], argv[2], argv[3][0], argv[4][0]), 14);
ASSERT_STREQ(buf, "First arg a 48");
#endif

return 0;
Expand Down
44 changes: 10 additions & 34 deletions libc/test/integration/src/stdlib/getenv_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,19 @@
//
//===----------------------------------------------------------------------===//

#include "src/stdlib/getenv.h"

#include "test/IntegrationTest/test.h"

static bool my_streq(const char *lhs, const char *rhs) {
if (lhs == rhs)
return true;
if (((lhs == static_cast<char *>(nullptr)) &&
(rhs != static_cast<char *>(nullptr))) ||
((lhs != static_cast<char *>(nullptr)) &&
(rhs == static_cast<char *>(nullptr)))) {
return false;
}
const char *l, *r;
for (l = lhs, r = rhs; *l != '\0' && *r != '\0'; ++l, ++r)
if (*l != *r)
return false;

return *l == '\0' && *r == '\0';
}
#include <stdlib.h> // getenv

TEST_MAIN(int argc, char **argv, char **envp) {
ASSERT_TRUE(
my_streq(LIBC_NAMESPACE::getenv(""), static_cast<char *>(nullptr)));
ASSERT_TRUE(
my_streq(LIBC_NAMESPACE::getenv("="), static_cast<char *>(nullptr)));
ASSERT_TRUE(my_streq(LIBC_NAMESPACE::getenv("MISSING ENV VARIABLE"),
static_cast<char *>(nullptr)));
ASSERT_FALSE(
my_streq(LIBC_NAMESPACE::getenv("PATH"), static_cast<char *>(nullptr)));
ASSERT_TRUE(my_streq(LIBC_NAMESPACE::getenv("FRANCE"), "Paris"));
ASSERT_FALSE(my_streq(LIBC_NAMESPACE::getenv("FRANCE"), "Berlin"));
ASSERT_TRUE(my_streq(LIBC_NAMESPACE::getenv("GERMANY"), "Berlin"));
ASSERT_TRUE(
my_streq(LIBC_NAMESPACE::getenv("FRANC"), static_cast<char *>(nullptr)));
ASSERT_TRUE(my_streq(LIBC_NAMESPACE::getenv("FRANCE1"),
static_cast<char *>(nullptr)));

ASSERT_STREQ(getenv(""), nullptr);
ASSERT_STREQ(getenv("="), nullptr);
ASSERT_STREQ(getenv("MISSING ENV VARIABLE"), nullptr);
ASSERT_STRNE(getenv("PATH"), nullptr);
ASSERT_STREQ(getenv("FRANCE"), "Paris");
ASSERT_STRNE(getenv("FRANCE"), "Berlin");
ASSERT_STREQ(getenv("GERMANY"), "Berlin");
ASSERT_STREQ(getenv("FRANC"), nullptr);
ASSERT_STREQ(getenv("FRANCE1"), nullptr);
return 0;
}
42 changes: 14 additions & 28 deletions libc/test/integration/src/threads/call_once_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,6 @@
//===----------------------------------------------------------------------===//

#include "src/__support/CPP/atomic.h"
#include "src/threads/call_once.h"
#include "src/threads/mtx_destroy.h"
#include "src/threads/mtx_init.h"
#include "src/threads/mtx_lock.h"
#include "src/threads/mtx_unlock.h"
#include "src/threads/thrd_create.h"
#include "src/threads/thrd_join.h"

#include "test/IntegrationTest/test.h"

Expand All @@ -27,10 +20,8 @@ static void call_once_func() { ++call_count; }

static int func(void *) {
static once_flag flag = ONCE_FLAG_INIT;
LIBC_NAMESPACE::call_once(&flag, call_once_func);

call_once(&flag, call_once_func);
thread_count.fetch_add(1);

return 0;
}

Expand All @@ -41,14 +32,13 @@ void call_from_5_threads() {

thrd_t threads[NUM_THREADS];
for (unsigned int i = 0; i < NUM_THREADS; ++i) {
ASSERT_EQ(LIBC_NAMESPACE::thrd_create(threads + i, func, nullptr),
ASSERT_EQ(thrd_create(threads + i, func, nullptr),
static_cast<int>(thrd_success));
}

for (unsigned int i = 0; i < NUM_THREADS; ++i) {
int retval;
ASSERT_EQ(LIBC_NAMESPACE::thrd_join(threads[i], &retval),
static_cast<int>(thrd_success));
ASSERT_EQ(thrd_join(threads[i], &retval), static_cast<int>(thrd_success));
ASSERT_EQ(retval, 0);
}

Expand All @@ -58,16 +48,16 @@ void call_from_5_threads() {

static mtx_t once_func_blocker;
static void blocking_once_func() {
LIBC_NAMESPACE::mtx_lock(&once_func_blocker);
LIBC_NAMESPACE::mtx_unlock(&once_func_blocker);
mtx_lock(&once_func_blocker);
mtx_unlock(&once_func_blocker);
}

static LIBC_NAMESPACE::cpp::Atomic<unsigned int> start_count;
static LIBC_NAMESPACE::cpp::Atomic<unsigned int> done_count;
static int once_func_caller(void *) {
static once_flag flag;
start_count.fetch_add(1);
LIBC_NAMESPACE::call_once(&flag, blocking_once_func);
call_once(&flag, blocking_once_func);
done_count.fetch_add(1);
return 0;
}
Expand All @@ -79,16 +69,15 @@ void test_synchronization() {
start_count = 0;
done_count = 0;

ASSERT_EQ(LIBC_NAMESPACE::mtx_init(&once_func_blocker, mtx_plain),
ASSERT_EQ(mtx_init(&once_func_blocker, mtx_plain),
static_cast<int>(thrd_success));
// Lock the blocking mutex so that the once func blocks.
ASSERT_EQ(LIBC_NAMESPACE::mtx_lock(&once_func_blocker),
static_cast<int>(thrd_success));
ASSERT_EQ(mtx_lock(&once_func_blocker), static_cast<int>(thrd_success));

thrd_t t1, t2;
ASSERT_EQ(LIBC_NAMESPACE::thrd_create(&t1, once_func_caller, nullptr),
ASSERT_EQ(thrd_create(&t1, once_func_caller, nullptr),
static_cast<int>(thrd_success));
ASSERT_EQ(LIBC_NAMESPACE::thrd_create(&t2, once_func_caller, nullptr),
ASSERT_EQ(thrd_create(&t2, once_func_caller, nullptr),
static_cast<int>(thrd_success));

while (start_count.load() != 2)
Expand All @@ -98,20 +87,17 @@ void test_synchronization() {
EXPECT_EQ(done_count.val, 0U);

// Unlock the blocking mutex so that the once func blocks.
ASSERT_EQ(LIBC_NAMESPACE::mtx_unlock(&once_func_blocker),
static_cast<int>(thrd_success));
ASSERT_EQ(mtx_unlock(&once_func_blocker), static_cast<int>(thrd_success));

int retval;
ASSERT_EQ(LIBC_NAMESPACE::thrd_join(t1, &retval),
static_cast<int>(thrd_success));
ASSERT_EQ(thrd_join(t1, &retval), static_cast<int>(thrd_success));
ASSERT_EQ(retval, 0);
ASSERT_EQ(LIBC_NAMESPACE::thrd_join(t2, &retval),
static_cast<int>(thrd_success));
ASSERT_EQ(thrd_join(t2, &retval), static_cast<int>(thrd_success));
ASSERT_EQ(retval, 0);

ASSERT_EQ(done_count.val, 2U);

LIBC_NAMESPACE::mtx_destroy(&once_func_blocker);
mtx_destroy(&once_func_blocker);
}

TEST_MAIN() {
Expand Down
Loading