Skip to content
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

Increase testing coverage of rcutils to 95% #258

Merged
merged 6 commits into from
Jun 8, 2020
Merged
Show file tree
Hide file tree
Changes from 2 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
42 changes: 39 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -415,30 +415,66 @@ if(BUILD_TESTING)
RCUTILS_CONSOLE_OUTPUT_FORMAT="[{severity}] [{time},{time_as_nanoseconds}] [{name},{function_name},{file_name}]: {line_number}-{message}"
RCUTILS_CONSOLE_STDOUT_LINE_BUFFERED=1
RCUTILS_LOGGING_BUFFERED_STREAM=1
RCUTILS_LOGGING_USE_STDOUT=1
RCUTILS_COLORIZED_OUTPUT=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="[{severity}] [{time},{time_as_nanoseconds}] [{name},{function_name},{file_name}]: {line_number}-{message}"
RCUTILS_CONSOLE_OUTPUT_FORMAT="${_output_format}"
RCUTILS_CONSOLE_STDOUT_LINE_BUFFERED=0
RCUTILS_LOGGING_BUFFERED_STREAM=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_
21 changes: 16 additions & 5 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 @@ -363,11 +379,6 @@ TEST_F(ArrayListPreInitTest, init_list_twice_fails) {
EXPECT_EQ(RCUTILS_RET_INVALID_ARGUMENT, ret) << rcutils_get_error_string().str;
}

TEST_F(ArrayListTest, init_list_bad_allocator_fail) {
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;
}

typedef struct allocator_state
{
bool is_failing;
Expand Down
18 changes: 18 additions & 0 deletions 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 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);
brawner marked this conversation as resolved.
Show resolved Hide resolved
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);
brawner marked this conversation as resolved.
Show resolved Hide resolved

#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
}
13 changes: 11 additions & 2 deletions test/test_hash_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

#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/hash_map.h"
Expand Down Expand Up @@ -131,11 +131,20 @@ TEST_F(HashMapBaseTest, init_map_allocator_NULL_fails) {
}

TEST_F(HashMapBaseTest, init_map_failing_allocator) {
rcutils_allocator_t failing_allocator = get_failing_allocator();
rcutils_allocator_t failing_allocator = get_time_bomb_allocator();
// Check allocating hash_map->impl fails
set_time_bomb_allocator_malloc_count(failing_allocator, 0);
rcutils_ret_t ret = rcutils_hash_map_init(
&map, 2, sizeof(uint32_t), sizeof(uint32_t),
test_hash_map_uint32_hash_func, test_uint32_cmp, &failing_allocator);
EXPECT_EQ(RCUTILS_RET_BAD_ALLOC, ret) << rcutils_get_error_string().str;

// Check allocate hash_map->impl->map fails
set_time_bomb_allocator_malloc_count(failing_allocator, 1);
ret = rcutils_hash_map_init(
&map, 2, sizeof(uint32_t), sizeof(uint32_t),
test_hash_map_uint32_hash_func, test_uint32_cmp, &failing_allocator);
EXPECT_EQ(RCUTILS_RET_BAD_ALLOC, ret) << rcutils_get_error_string().str;
}

TEST_F(HashMapBaseTest, init_map_success) {
Expand Down
Loading