Skip to content

Commit

Permalink
Increase testing coverage of rcutils
Browse files Browse the repository at this point in the history
Signed-off-by: Stephen Brawner <[email protected]>
  • Loading branch information
brawner committed Jun 2, 2020
1 parent 00529de commit 52d56a5
Show file tree
Hide file tree
Showing 19 changed files with 700 additions and 10 deletions.
54 changes: 51 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -413,20 +413,68 @@ if(BUILD_TESTING)
rcutils_custom_add_gtest(test_logging_custom_env test/test_logging_custom_env.cpp
ENV
RCUTILS_CONSOLE_OUTPUT_FORMAT="[{severity}] [{time},{time_as_nanoseconds}] [{name},{function_name},{file_name}]: {line_number}-{message}"
RCUTILS_CONSOLE_STDOUT_LINE_BUFFERED=1
RCUTILS_COLORIZED_OUTPUT=1
RCUTILS_CONSOLE_STDOUT_LINE_BUFFERED="1"
RCUTILS_LOGGING_USE_STDOUT="1"
RCUTILS_COLORIZED_OUTPUT="1"
RCUTILS_LOGGING_BUFFERED_STREAM="1"
)
if(TARGET test_logging_custom_env)
target_link_libraries(test_logging_custom_env ${PROJECT_NAME} osrf_testing_tools_cpp::memory_tools)
endif()

# RCUTILS_LOGGING_MAX_OUTPUT_FORMAT_LEN is defined as 2048, truncation should occur
foreach(i RANGE 0 100)
set(_output_format "${_output_format} [{severity}] [{time},{time_as_nanoseconds}] [{name},{function_name},{file_name}]: {line_number}-{message}")
endforeach(i)
rcutils_custom_add_gtest(test_logging_custom_env2 test/test_logging_custom_env.cpp
ENV
RCUTILS_CONSOLE_OUTPUT_FORMAT="${_output_format}"
RCUTILS_CONSOLE_STDOUT_LINE_BUFFERED="0"
RCUTILS_LOGGING_USE_STDOUT="0"
RCUTILS_COLORIZED_OUTPUT="0"
RCUTILS_LOGGING_BUFFERED_STREAM="0"
)
if(TARGET test_logging_custom_env2)
target_link_libraries(test_logging_custom_env2 ${PROJECT_NAME} osrf_testing_tools_cpp::memory_tools)
endif()

rcutils_custom_add_gtest(test_logging_bad_env test/test_logging_bad_env.cpp
ENV
RCUTILS_LOGGING_USE_STDOUT=42
)
if(TARGET test_logging_bad_env)
target_link_libraries(test_logging_bad_env ${PROJECT_NAME})
endif()

rcutils_custom_add_gtest(test_logging_bad_env2 test/test_logging_bad_env.cpp
ENV
RCUTILS_COLORIZED_OUTPUT=42
)
if(TARGET test_logging_bad_env2)
target_link_libraries(test_logging_bad_env2 ${PROJECT_NAME})
endif()

rcutils_custom_add_gtest(test_logging_bad_env3 test/test_logging_bad_env.cpp
ENV
RCUTILS_LOGGING_BUFFERED_STREAM=42
)
if(TARGET test_logging_bad_env3)
target_link_libraries(test_logging_bad_env3 ${PROJECT_NAME})
endif()

rcutils_custom_add_gtest(test_logging_enable_for
test/test_logging_enable_for.cpp
)
if(TARGET test_logging_enable_for)
target_link_libraries(test_logging_enable_for ${PROJECT_NAME})
target_link_libraries(test_logging_enable_for ${PROJECT_NAME} osrf_testing_tools_cpp::memory_tools)
endif()

rcutils_custom_add_gtest(test_logging_console_output_handler
test/test_logging_console_output_handler.cpp
)
if(TARGET test_logging_console_output_handler)
target_link_libraries(test_logging_console_output_handler ${PROJECT_NAME} osrf_testing_tools_cpp::memory_tools)
endif()

endif()

Expand Down
146 changes: 146 additions & 0 deletions include/rcutils/testing_utils/time_bomb_allocator_testing_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef RCUTILS__TESTING_UTILS__TIME_BOMB_ALLOCATOR_TESTING_UTILS_H_
#define RCUTILS__TESTING_UTILS__TIME_BOMB_ALLOCATOR_TESTING_UTILS_H_

#ifdef __cplusplus
extern "C"
{
#endif

#include <stddef.h>

#include "rcutils/allocator.h"

typedef struct __time_bomb_allocator_state
{
// Set these to negative if you want to disable time bomb for the associated function call.
int malloc_count_until_failure;
int realloc_count_until_failure;
int free_count_until_failure;
int calloc_count_until_failure;
} __time_bomb_allocator_state;

static void *
time_bomb_malloc(size_t size, void * state)
{
if (((__time_bomb_allocator_state *)state)->malloc_count_until_failure >= 0 &&
((__time_bomb_allocator_state *)state)->malloc_count_until_failure-- == 0)
{
printf("Malloc time bomb countdown reached 0, returning nullptr\n");
return nullptr;
}
return rcutils_get_default_allocator().allocate(size, rcutils_get_default_allocator().state);
}

static void *
time_bomb_realloc(void * pointer, size_t size, void * state)
{
if (((__time_bomb_allocator_state *)state)->realloc_count_until_failure >= 0 &&
((__time_bomb_allocator_state *)state)->realloc_count_until_failure-- == 0)
{
printf("Realloc time bomb countdown reached 0, returning nullptr\n");
return nullptr;
}
return rcutils_get_default_allocator().reallocate(
pointer, size, rcutils_get_default_allocator().state);
}

static void
time_bomb_free(void * pointer, void * state)
{
if (((__time_bomb_allocator_state *)state)->free_count_until_failure >= 0 &&
((__time_bomb_allocator_state *)state)->free_count_until_failure-- == 0)
{
printf("Free time bomb countdown reached 0, not freeing memory\n");
return;
}
rcutils_get_default_allocator().deallocate(pointer, rcutils_get_default_allocator().state);
}

static void *
time_bomb_calloc(size_t number_of_elements, size_t size_of_element, void * state)
{
if (((__time_bomb_allocator_state *)state)->calloc_count_until_failure >= 0 &&
((__time_bomb_allocator_state *)state)->calloc_count_until_failure-- == 0)
{
printf("Calloc time bomb countdown reached 0, returning nullptr\n");
return nullptr;
}
return rcutils_get_default_allocator().zero_allocate(
number_of_elements, size_of_element, rcutils_get_default_allocator().state);
}

/**
* This allocator uses the rcutils default allocator functions, but decrements a time bomb counter
* for each function call. When the counter reaches 0, that call will fail.
* In the case of the allocating functions, it will return a nullptr. In the case of free,
* it will fail to free the memory.
*
* Use this allocator when you need a fixed amount of calls to succeed before it fails.
*
* Set the count to negative for the time bomb effect to be disabled for that function.
*/
static inline rcutils_allocator_t
get_time_bomb_allocator(void)
{
static __time_bomb_allocator_state state;
state.malloc_count_until_failure = -1;
state.realloc_count_until_failure = -1;
state.free_count_until_failure = -1;
state.calloc_count_until_failure = -1;
auto time_bomb_allocator = rcutils_get_default_allocator();
time_bomb_allocator.allocate = time_bomb_malloc;
time_bomb_allocator.deallocate = time_bomb_free;
time_bomb_allocator.reallocate = time_bomb_realloc;
time_bomb_allocator.zero_allocate = time_bomb_calloc;
time_bomb_allocator.state = &state;
return time_bomb_allocator;
}

/**
* Set count to the number of times you want the call to succeed before it fails.
* After it fails once, it will succeed until this count is reset.
* Set it to a negative value to disable the time bomb effect for that function.
*/
static inline void
set_time_bomb_allocator_malloc_count(rcutils_allocator_t & time_bomb_allocator, int count)
{
((__time_bomb_allocator_state *)time_bomb_allocator.state)->malloc_count_until_failure = count;
}

static inline void
set_time_bomb_allocator_realloc_count(rcutils_allocator_t & time_bomb_allocator, int count)
{
((__time_bomb_allocator_state *)time_bomb_allocator.state)->realloc_count_until_failure = count;
}

static inline void
set_time_bomb_allocator_free_count(rcutils_allocator_t & time_bomb_allocator, int count)
{
((__time_bomb_allocator_state *)time_bomb_allocator.state)->free_count_until_failure = count;
}

static inline void
set_time_bomb_allocator_calloc_count(rcutils_allocator_t & time_bomb_allocator, int count)
{
((__time_bomb_allocator_state *)time_bomb_allocator.state)->calloc_count_until_failure = count;
}

#ifdef __cplusplus
}
#endif

#endif // RCUTILS__TESTING_UTILS__TIME_BOMB_ALLOCATOR_TESTING_UTILS_H_
23 changes: 23 additions & 0 deletions test/test_array_list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@
#include <string>

#include "./allocator_testing_utils.h"
#include "rcutils/testing_utils/time_bomb_allocator_testing_utils.h"
#include "rcutils/allocator.h"
#include "rcutils/error_handling.h"
#include "rcutils/types/array_list.h"

auto failing_allocator = get_failing_allocator();
auto time_bomb_allocator = get_time_bomb_allocator();

class ArrayListTest : public ::testing::Test
{
Expand Down Expand Up @@ -80,6 +82,20 @@ TEST_F(ArrayListTest, init_null_allocator_fails) {
EXPECT_EQ(RCUTILS_RET_INVALID_ARGUMENT, ret) << rcutils_get_error_string().str;
}

TEST_F(ArrayListTest, fail_allocate_impl) {
rcutils_allocator_t time_bomb_allocator = get_time_bomb_allocator();
set_time_bomb_allocator_malloc_count(time_bomb_allocator, 0);
rcutils_ret_t ret = rcutils_array_list_init(&list, 2, sizeof(uint32_t), &time_bomb_allocator);
EXPECT_EQ(RCUTILS_RET_BAD_ALLOC, ret) << rcutils_get_error_string().str;
}

TEST_F(ArrayListTest, fail_allocate_impl_list) {
rcutils_allocator_t time_bomb_allocator = get_time_bomb_allocator();
set_time_bomb_allocator_malloc_count(time_bomb_allocator, 1);
rcutils_ret_t ret = rcutils_array_list_init(&list, 2, sizeof(uint32_t), &time_bomb_allocator);
EXPECT_EQ(RCUTILS_RET_BAD_ALLOC, ret) << rcutils_get_error_string().str;
}

TEST_F(ArrayListTest, init_success) {
rcutils_ret_t ret = rcutils_array_list_init(&list, 2, sizeof(uint32_t), &allocator);
EXPECT_EQ(RCUTILS_RET_OK, ret) << rcutils_get_error_string().str;
Expand Down Expand Up @@ -364,8 +380,15 @@ TEST_F(ArrayListPreInitTest, init_list_twice_fails) {
}

TEST_F(ArrayListTest, init_list_bad_allocator_fail) {
// Allocating array-list->impl fails
set_time_bomb_allocator_malloc_count(time_bomb_allocator, 0);
rcutils_ret_t ret = rcutils_array_list_init(&list, 2, sizeof(uint32_t), &failing_allocator);
EXPECT_EQ(RCUTILS_RET_BAD_ALLOC, ret) << rcutils_get_error_string().str;

// Allocating array-list->impl->list fails
set_time_bomb_allocator_malloc_count(time_bomb_allocator, 1);
ret = rcutils_array_list_init(&list, 2, sizeof(uint32_t), &failing_allocator);
EXPECT_EQ(RCUTILS_RET_BAD_ALLOC, ret) << rcutils_get_error_string().str;
}

typedef struct allocator_state
Expand Down
19 changes: 18 additions & 1 deletion test/test_char_array.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ TEST_F(ArrayCharTest, resize) {
EXPECT_EQ(11lu, char_array.buffer_capacity);
EXPECT_EQ(5lu, char_array.buffer_length);

// Resize to same capacity, nothing to be done
ret = rcutils_char_array_resize(&char_array, 11);
ASSERT_EQ(RCUTILS_RET_OK, ret);
EXPECT_EQ(11lu, char_array.buffer_capacity);
EXPECT_EQ(5lu, char_array.buffer_length);

char_array.buffer_length = snprintf(
char_array.buffer, char_array.buffer_capacity, "0987654321") + 1;
EXPECT_STREQ("0987654321", char_array.buffer);
Expand All @@ -95,6 +101,18 @@ TEST_F(ArrayCharTest, resize) {

// cleanup only 3 fields
EXPECT_EQ(RCUTILS_RET_OK, rcutils_char_array_fini(&char_array));

allocator = get_failing_allocator();
ret = rcutils_char_array_init(&char_array, 0, &allocator);
ASSERT_EQ(RCUTILS_RET_OK, ret);

// Force a failing allocation on resizing
char_array.owns_buffer = false;
ret = rcutils_char_array_resize(&char_array, 3);
ASSERT_EQ(RCUTILS_RET_BAD_ALLOC, ret);

// Nothing to cleanup, but it should be ok
EXPECT_EQ(RCUTILS_RET_OK, rcutils_char_array_fini(&char_array));
}

TEST_F(ArrayCharTest, vsprintf_fail) {
Expand All @@ -107,7 +125,6 @@ TEST_F(ArrayCharTest, vsprintf_fail) {
EXPECT_EQ(RCUTILS_RET_BAD_ALLOC, ret);
rcutils_reset_error();

char_array.allocator = allocator;
EXPECT_EQ(RCUTILS_RET_OK, rcutils_char_array_fini(&char_array));
}

Expand Down
13 changes: 13 additions & 0 deletions test/test_filesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ class TestFilesystemFixture : public ::testing::Test
TEST_F(TestFilesystemFixture, get_cwd_nullptr) {
EXPECT_FALSE(rcutils_get_cwd(NULL, sizeof(this->cwd)));
EXPECT_FALSE(rcutils_get_cwd(this->cwd, 0));

// ERANGE, including a null terminating character, cwd should always be longer than 1 char
EXPECT_FALSE(rcutils_get_cwd(this->cwd, 1));
}

TEST_F(TestFilesystemFixture, join_path) {
Expand Down Expand Up @@ -241,6 +244,16 @@ TEST_F(TestFilesystemFixture, is_readable_and_writable) {
ASSERT_FALSE(nullptr == path);
EXPECT_TRUE(rcutils_is_readable_and_writable(path));
}
{
char * path =
rcutils_join_path(this->test_path, "dummy_readable_file.txt", g_allocator);
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
{
g_allocator.deallocate(path, g_allocator.state);
});
ASSERT_FALSE(nullptr == path);
EXPECT_TRUE(rcutils_is_readable_and_writable(path));
}
{
char * path =
rcutils_join_path(this->test_path, "dummy_readable_writable_file.txt", g_allocator);
Expand Down
9 changes: 9 additions & 0 deletions test/test_format_string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ TEST(test_format_string_limit, nominal) {
allocator.deallocate(formatted, allocator.state);
}
}

{
auto allocator = rcutils_get_default_allocator();
char * formatted = rcutils_format_string_limit(allocator, 3, "string is too long %s", "test");
EXPECT_STREQ("st", formatted);
if (formatted) {
allocator.deallocate(formatted, allocator.state);
}
}
}

TEST(test_format_string_limit, invalid_arguments) {
Expand Down
13 changes: 13 additions & 0 deletions test/test_get_env.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include <string>

#include "rcutils/env.h"
#include "rcutils/get_env.h"

/* Tests rcutils_get_env.
Expand Down Expand Up @@ -49,4 +50,16 @@ TEST(TestGetEnv, test_get_env) {

TEST(TestGetEnv, test_get_home) {
EXPECT_STRNE(NULL, rcutils_get_home_dir());

const char * home = NULL;
const char * ret = rcutils_get_env("HOME", &home);
EXPECT_EQ(NULL, ret);

#ifdef _WIN32
EXPECT_TRUE(rcutils_set_env("USERPROFILE", NULL));
EXPECT_EQ(NULL, rcutils_get_home_dir());
#else
EXPECT_TRUE(rcutils_set_env("HOME", NULL));
EXPECT_EQ(NULL, rcutils_get_home_dir());
#endif
}
Loading

0 comments on commit 52d56a5

Please sign in to comment.