From 66e036f66fbb034c862f06cca557804fba80d932 Mon Sep 17 00:00:00 2001 From: Stephen Brawner Date: Thu, 14 May 2020 16:13:15 -0700 Subject: [PATCH] More coverage Signed-off-by: Stephen Brawner --- rcl_lifecycle/src/default_state_machine.c | 1 + rcl_lifecycle/src/rcl_lifecycle.c | 9 +- rcl_lifecycle/src/transition_map.c | 17 +- .../test/test_default_state_machine.cpp | 2 + rcl_lifecycle/test/test_rcl_lifecycle.cpp | 173 +++++++++++------- rcl_lifecycle/test/test_transition_map.cpp | 47 ++++- 6 files changed, 173 insertions(+), 76 deletions(-) diff --git a/rcl_lifecycle/src/default_state_machine.c b/rcl_lifecycle/src/default_state_machine.c index 26e0261b48..e32d39b30d 100644 --- a/rcl_lifecycle/src/default_state_machine.c +++ b/rcl_lifecycle/src/default_state_machine.c @@ -691,6 +691,7 @@ rcl_lifecycle_init_default_state_machine( return ret; fail: + // if rcl_lifecycle_transition_map_fini() fails, it will clobber the error string here, twice if (rcl_lifecycle_transition_map_fini(&state_machine->transition_map, allocator) != RCL_RET_OK) { RCL_SET_ERROR_MSG("could not free lifecycle transition map. Leaking memory!\n"); } diff --git a/rcl_lifecycle/src/rcl_lifecycle.c b/rcl_lifecycle/src/rcl_lifecycle.c index a052fd9e44..ce6c076281 100644 --- a/rcl_lifecycle/src/rcl_lifecycle.c +++ b/rcl_lifecycle/src/rcl_lifecycle.c @@ -236,15 +236,12 @@ rcl_lifecycle_state_machine_init( } if (default_states) { - rcl_ret_t ret = - rcl_lifecycle_init_default_state_machine(state_machine, allocator); + ret = rcl_lifecycle_init_default_state_machine(state_machine, allocator); if (ret != RCL_RET_OK) { // init default state machine might have allocated memory, // so we have to call fini - if (rcl_lifecycle_state_machine_fini(state_machine, node_handle, allocator) != RCL_RET_OK) { - // error already set - return RCL_RET_ERROR; - } + ret = rcl_lifecycle_state_machine_fini(state_machine, node_handle, allocator); + return RCL_RET_ERROR; } } diff --git a/rcl_lifecycle/src/transition_map.c b/rcl_lifecycle/src/transition_map.c index 210694af3a..aa5ac51f5d 100644 --- a/rcl_lifecycle/src/transition_map.c +++ b/rcl_lifecycle/src/transition_map.c @@ -92,15 +92,16 @@ rcl_lifecycle_register_state( allocator, "invalid allocator", return RCUTILS_RET_INVALID_ARGUMENT) // add new primary state memory - transition_map->states_size += 1; + unsigned int new_states_size = transition_map->states_size + 1; rcl_lifecycle_state_t * new_states = allocator->reallocate( transition_map->states, - transition_map->states_size * sizeof(rcl_lifecycle_state_t), + new_states_size * sizeof(rcl_lifecycle_state_t), allocator->state); if (!new_states) { RCL_SET_ERROR_MSG("failed to reallocate memory for new states"); return RCL_RET_ERROR; } + transition_map->states_size = new_states_size; transition_map->states = new_states; transition_map->states[transition_map->states_size - 1] = state; @@ -127,16 +128,17 @@ rcl_lifecycle_register_transition( RCL_SET_ERROR_MSG_WITH_FORMAT_STRING("state %u is not registered\n", transition.goal->id); return RCL_RET_ERROR; } - // we add a new transition, so increase the size - transition_map->transitions_size += 1; + // Attempt to add new transition, don't update map if it fails + unsigned int new_transitions_size = transition_map->transitions_size + 1; rcl_lifecycle_transition_t * new_transitions = allocator->reallocate( transition_map->transitions, - transition_map->transitions_size * sizeof(rcl_lifecycle_transition_t), + new_transitions_size * sizeof(rcl_lifecycle_transition_t), allocator->state); if (!new_transitions) { RCL_SET_ERROR_MSG("failed to reallocate memory for new transitions"); return RCL_RET_BAD_ALLOC; } + transition_map->transitions_size = new_transitions_size; transition_map->transitions = new_transitions; // finally set the new transition to the end of the array transition_map->transitions[transition_map->transitions_size - 1] = transition; @@ -144,15 +146,16 @@ rcl_lifecycle_register_transition( // we have to copy the transitons here once more to the actual state // as we can't assign only the pointer. This pointer gets invalidated whenever // we add a new transition and re-shuffle/re-allocate new memory for it. - state->valid_transition_size += 1; + unsigned int new_valid_transitions_size = state->valid_transition_size + 1; rcl_lifecycle_transition_t * new_valid_transitions = allocator->reallocate( state->valid_transitions, - state->valid_transition_size * sizeof(rcl_lifecycle_transition_t), + new_valid_transitions_size * sizeof(rcl_lifecycle_transition_t), allocator->state); if (!new_valid_transitions) { RCL_SET_ERROR_MSG("failed to reallocate memory for new transitions on state"); return RCL_RET_ERROR; } + state->valid_transition_size = new_valid_transitions_size; state->valid_transitions = new_valid_transitions; state->valid_transitions[state->valid_transition_size - 1] = transition; diff --git a/rcl_lifecycle/test/test_default_state_machine.cpp b/rcl_lifecycle/test/test_default_state_machine.cpp index c13cec1b55..afd66c3e05 100644 --- a/rcl_lifecycle/test/test_default_state_machine.cpp +++ b/rcl_lifecycle/test/test_default_state_machine.cpp @@ -113,6 +113,8 @@ TEST_F(TestDefaultStateMachine, zero_init) { TEST_F(TestDefaultStateMachine, default_init) { rcl_lifecycle_state_machine_t state_machine = rcl_lifecycle_get_zero_initialized_state_machine(); + // Because this init method is so complex, the succession of failures caused by a null + // allocator will result in several error messages overwriting themselves. auto ret = rcl_lifecycle_init_default_state_machine(&state_machine, nullptr); EXPECT_EQ(RCL_RET_ERROR, ret); rcutils_reset_error(); diff --git a/rcl_lifecycle/test/test_rcl_lifecycle.cpp b/rcl_lifecycle/test/test_rcl_lifecycle.cpp index 3ccea48bba..0404acadb1 100644 --- a/rcl_lifecycle/test/test_rcl_lifecycle.cpp +++ b/rcl_lifecycle/test/test_rcl_lifecycle.cpp @@ -28,6 +28,22 @@ #include "lifecycle_msgs/srv/get_available_transitions.h" #include "lifecycle_msgs/srv/get_state.h" +static void * bad_malloc(size_t, void *) +{ + return nullptr; +} + +static void * bad_realloc(void *, size_t, void *) +{ + return nullptr; +} + +void swap_pointer(void ** ptr1, void ** ptr2) { + void * tmp = *ptr1; + *ptr1 = ptr2; + *ptr2 = tmp; +} + TEST(TestRclLifecycle, lifecycle_state) { rcl_lifecycle_state_t state = rcl_lifecycle_get_zero_initialized_state(); EXPECT_EQ(state.id, 0u); @@ -48,6 +64,13 @@ TEST(TestRclLifecycle, lifecycle_state) { EXPECT_EQ(ret, RCL_RET_ERROR); rcutils_reset_error(); + rcl_allocator_t bad_allocator = rcl_get_default_allocator(); + bad_allocator.allocate = bad_malloc; + bad_allocator.reallocate = bad_realloc; + ret = rcl_lifecycle_state_init(&state, expected_id, &expected_label[0], &bad_allocator); + EXPECT_EQ(ret, RCL_RET_ERROR); + rcutils_reset_error(); + ret = rcl_lifecycle_state_init(&state, expected_id, &expected_label[0], &allocator); EXPECT_EQ(state.id, expected_id); EXPECT_STREQ(state.label, &expected_label[0]); @@ -75,11 +98,11 @@ TEST(TestRclLifecycle, lifecycle_transition) { // These need to be allocated on heap so rcl_lifecycle_transition_fini doesn't free a stack // allocated variable - rcl_lifecycle_state_t * start = reinterpret_cast( + rcl_lifecycle_state_t * start = reinterpret_cast( allocator.allocate(sizeof(rcl_lifecycle_state_t), allocator.state)); EXPECT_NE(start, nullptr); - rcl_lifecycle_state_t * end = reinterpret_cast( - allocator.allocate(sizeof(rcl_lifecycle_state_t), allocator.state)); + rcl_lifecycle_state_t * end = reinterpret_cast( + allocator.allocate(sizeof(rcl_lifecycle_state_t), allocator.state)); EXPECT_NE(end, nullptr); const char start_label[] = "start"; const char end_label[] = "end"; @@ -124,6 +147,14 @@ TEST(TestRclLifecycle, lifecycle_transition) { EXPECT_EQ(ret, RCL_RET_ERROR); rcutils_reset_error(); + rcl_allocator_t bad_allocator = rcl_get_default_allocator(); + bad_allocator.allocate = bad_malloc; + bad_allocator.reallocate = bad_realloc; + ret = rcl_lifecycle_transition_init( + &transition, expected_id, &expected_label[0], start, end, &bad_allocator); + EXPECT_EQ(ret, RCL_RET_ERROR); + rcutils_reset_error(); + ret = rcl_lifecycle_transition_init( &transition, expected_id, &expected_label[0], start, end, &allocator); EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str; @@ -142,6 +173,21 @@ TEST(TestRclLifecycle, lifecycle_transition) { ret = rcl_lifecycle_transition_fini(nullptr, &allocator); EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str; + + rcl_lifecycle_state_t * start_ptr = nullptr; + swap_pointer(&start_ptr, &transition.start); + ret = rcl_lifecycle_transition_fini(&transition, &allocator); + EXPECT_EQ(ret, RCL_RET_ERROR); + rcutils_reset_error(); + swap_pointer(&start_ptr, &transition.start); + + rcl_lifecycle_goal_t * goal_ptr = nullptr; + swap_pointer(&goal_ptr, &transition.goal); + ret = rcl_lifecycle_transition_fini(&transition, &allocator); + EXPECT_EQ(ret, RCL_RET_ERROR); + rcutils_reset_error(); + swap_pointer(&goal_ptr, &transition.goal); + ret = rcl_lifecycle_transition_fini(&transition, &allocator); EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str; } @@ -175,38 +221,37 @@ TEST(TestRclLifecycle, state_machine) { EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str; const rosidl_message_type_support_t * pn = - ROSIDL_GET_MSG_TYPE_SUPPORT(lifecycle_msgs, msg, TransitionEvent); + ROSIDL_GET_MSG_TYPE_SUPPORT(lifecycle_msgs, msg, TransitionEvent); const rosidl_service_type_support_t * cs = - ROSIDL_GET_SRV_TYPE_SUPPORT(lifecycle_msgs, srv, ChangeState); + ROSIDL_GET_SRV_TYPE_SUPPORT(lifecycle_msgs, srv, ChangeState); const rosidl_service_type_support_t * gs = - ROSIDL_GET_SRV_TYPE_SUPPORT(lifecycle_msgs, srv, GetState); + ROSIDL_GET_SRV_TYPE_SUPPORT(lifecycle_msgs, srv, GetState); const rosidl_service_type_support_t * gas = - ROSIDL_GET_SRV_TYPE_SUPPORT(lifecycle_msgs, srv, GetAvailableStates); + ROSIDL_GET_SRV_TYPE_SUPPORT(lifecycle_msgs, srv, GetAvailableStates); const rosidl_service_type_support_t * gat = - ROSIDL_GET_SRV_TYPE_SUPPORT(lifecycle_msgs, srv, GetAvailableTransitions); + ROSIDL_GET_SRV_TYPE_SUPPORT(lifecycle_msgs, srv, GetAvailableTransitions); const rosidl_service_type_support_t * gtg = - ROSIDL_GET_SRV_TYPE_SUPPORT(lifecycle_msgs, srv, GetAvailableTransitions); + ROSIDL_GET_SRV_TYPE_SUPPORT(lifecycle_msgs, srv, GetAvailableTransitions); + // Check various arguments are null ret = rcl_lifecycle_state_machine_init( nullptr, &node, pn, cs, gs, gas, gat, gtg, false, &allocator); EXPECT_EQ(ret, RCL_RET_ERROR); rcutils_reset_error(); - EXPECT_EQ(rcl_lifecycle_state_machine_is_initialized(&state_machine), RCL_RET_ERROR); rcutils_reset_error(); + ret = rcl_lifecycle_state_machine_init( &state_machine, nullptr, pn, cs, gs, gas, gat, gtg, false, &allocator); - EXPECT_EQ(ret, RCL_RET_ERROR); rcutils_reset_error(); - EXPECT_EQ(rcl_lifecycle_state_machine_is_initialized(&state_machine), RCL_RET_ERROR); rcutils_reset_error(); + ret = rcl_lifecycle_state_machine_init( &state_machine, &node, nullptr, cs, gs, gas, gat, gtg, false, &allocator); EXPECT_EQ(ret, RCL_RET_ERROR); rcutils_reset_error(); - EXPECT_EQ(rcl_lifecycle_state_machine_is_initialized(&state_machine), RCL_RET_ERROR); rcutils_reset_error(); @@ -214,14 +259,13 @@ TEST(TestRclLifecycle, state_machine) { &state_machine, &node, pn, nullptr, gs, gas, gat, gtg, false, &allocator); EXPECT_EQ(ret, RCL_RET_ERROR); rcutils_reset_error(); - EXPECT_EQ(rcl_lifecycle_state_machine_is_initialized(&state_machine), RCL_RET_ERROR); rcutils_reset_error(); + ret = rcl_lifecycle_state_machine_init( &state_machine, &node, pn, cs, nullptr, gas, gat, gtg, false, &allocator); EXPECT_EQ(ret, RCL_RET_ERROR); rcutils_reset_error(); - EXPECT_EQ(rcl_lifecycle_state_machine_is_initialized(&state_machine), RCL_RET_ERROR); rcutils_reset_error(); @@ -229,7 +273,6 @@ TEST(TestRclLifecycle, state_machine) { &state_machine, &node, pn, cs, gs, nullptr, gat, gtg, false, &allocator); EXPECT_EQ(ret, RCL_RET_ERROR); rcutils_reset_error(); - EXPECT_EQ(rcl_lifecycle_state_machine_is_initialized(&state_machine), RCL_RET_ERROR); rcutils_reset_error(); @@ -237,7 +280,6 @@ TEST(TestRclLifecycle, state_machine) { &state_machine, &node, pn, cs, gs, gas, nullptr, gtg, false, &allocator); EXPECT_EQ(ret, RCL_RET_ERROR); rcutils_reset_error(); - EXPECT_EQ(rcl_lifecycle_state_machine_is_initialized(&state_machine), RCL_RET_ERROR); rcutils_reset_error(); @@ -245,30 +287,45 @@ TEST(TestRclLifecycle, state_machine) { &state_machine, &node, pn, cs, gs, gas, gat, nullptr, false, &allocator); EXPECT_EQ(ret, RCL_RET_ERROR); rcutils_reset_error(); - EXPECT_EQ(rcl_lifecycle_state_machine_is_initialized(&state_machine), RCL_RET_ERROR); rcutils_reset_error(); + ret = rcl_lifecycle_state_machine_init( &state_machine, &node, pn, cs, gs, gas, gat, gtg, false, nullptr); EXPECT_EQ(ret, RCL_RET_ERROR); rcutils_reset_error(); + EXPECT_EQ(rcl_lifecycle_state_machine_is_initialized(&state_machine), RCL_RET_ERROR); + rcutils_reset_error(); + + // Everything should be good ret = rcl_lifecycle_state_machine_init( &state_machine, &node, pn, cs, gs, gas, gat, gtg, false, &allocator); EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str; + // Transition_map is not initialized + EXPECT_EQ(rcl_lifecycle_state_machine_is_initialized(&state_machine), RCL_RET_ERROR); + rcutils_reset_error(); + + void * temp_function = state_machine.com_interface.srv_change_state.impl; + state_machine.com_interface.srv_change_state.impl = nullptr; + // get_state service is valid, but not change_state service + EXPECT_EQ(rcl_lifecycle_state_machine_is_initialized(&state_machine), RCL_RET_ERROR); + rcutils_reset_error(); + state_machine.com_interface.srv_change_state.impl = + reinterpret_cast(temp_function); + // Allocate some memory and initialize states and transitions so is_initialized will pass state_machine.transition_map.states_size = 1u; - state_machine.transition_map.states = reinterpret_cast( - allocator.allocate( - state_machine.transition_map.states_size * sizeof(rcl_lifecycle_state_t), - allocator.state)); + state_machine.transition_map.states = reinterpret_cast( + allocator.allocate(state_machine.transition_map.states_size * sizeof(rcl_lifecycle_state_t), + allocator.state)); ASSERT_NE(state_machine.transition_map.states, nullptr); state_machine.transition_map.states[0] = rcl_lifecycle_get_zero_initialized_state(); state_machine.transition_map.transitions_size = 1u; state_machine.transition_map.transitions = - reinterpret_cast(allocator.allocate( + reinterpret_cast(allocator.allocate( state_machine.transition_map.transitions_size * sizeof(rcl_lifecycle_transition_t), allocator.state)); ASSERT_NE(state_machine.transition_map.transitions, nullptr); @@ -276,12 +333,20 @@ TEST(TestRclLifecycle, state_machine) { EXPECT_EQ(rcl_lifecycle_state_machine_is_initialized(&state_machine), RCL_RET_OK); + // allocator is nullptr ret = rcl_lifecycle_state_machine_fini(&state_machine, &node, nullptr); EXPECT_EQ(ret, RCL_RET_ERROR); rcutils_reset_error(); ret = rcl_lifecycle_state_machine_fini(&state_machine, &node, &allocator); EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str; + + state_machine = rcl_lifecycle_get_zero_initialized_state_machine(); + + // Node is null + ret = rcl_lifecycle_state_machine_fini(&state_machine, nullptr, &allocator); + EXPECT_EQ(ret, RCL_RET_ERROR); + std::cout << "state_machine: " << __LINE__ << std::endl; } TEST(TestRclLifecycle, state_transitions) { @@ -327,40 +392,9 @@ TEST(TestRclLifecycle, state_transitions) { ROSIDL_GET_SRV_TYPE_SUPPORT(lifecycle_msgs, srv, GetAvailableTransitions); ret = rcl_lifecycle_state_machine_init( - &state_machine, &node, pn, cs, gs, gas, gat, gtg, false, &allocator); + &state_machine, &node, pn, cs, gs, gas, gat, gtg, true, &allocator); EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str; - // Allocate some memory and initialize states and transitions so is_initialized will pass - state_machine.transition_map.states_size = 1u; - state_machine.transition_map.states = reinterpret_cast( - allocator.allocate( - state_machine.transition_map.states_size * sizeof(rcl_lifecycle_state_t), - allocator.state)); - ASSERT_NE(state_machine.transition_map.states, nullptr); - state_machine.transition_map.states[0] = rcl_lifecycle_get_zero_initialized_state(); - ret = rcl_lifecycle_state_init(&state_machine.transition_map.states[0], 0, "START", &allocator); - EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str; - rcl_lifecycle_state_t * start = &state_machine.transition_map.states[0]; - - state_machine.transition_map.transitions_size = 1u; - state_machine.transition_map.transitions = - reinterpret_cast(allocator.allocate( - state_machine.transition_map.transitions_size * sizeof(rcl_lifecycle_transition_t), - allocator.state)); - ASSERT_NE(state_machine.transition_map.transitions, nullptr); - state_machine.transition_map.transitions[0] = rcl_lifecycle_get_zero_initialized_transition(); - ret = rcl_lifecycle_transition_init( - &state_machine.transition_map.transitions[0], 0, "TRANSITION", start, start, &allocator); - rcl_lifecycle_transition_t * expected_transition = &state_machine.transition_map.transitions[0]; - - start->valid_transition_size = 1; - start->valid_transitions = reinterpret_cast( - allocator.allocate( - start->valid_transition_size * sizeof(rcl_lifecycle_transition_t), - allocator.state)); - EXPECT_NE(start->valid_transitions, nullptr) << rcl_get_error_string().str; - start->valid_transitions[0] = *expected_transition; - ret = rcl_lifecycle_state_machine_is_initialized(&state_machine); EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str; @@ -368,16 +402,17 @@ TEST(TestRclLifecycle, state_transitions) { EXPECT_EQ(transition, nullptr) << rcl_get_error_string().str; rcutils_reset_error(); - state_machine.current_state = start; - transition = rcl_lifecycle_get_transition_by_id(state_machine.current_state, 0); - EXPECT_EQ(transition, &start->valid_transitions[0]); + transition = rcl_lifecycle_get_transition_by_id( + state_machine.current_state, lifecycle_msgs__msg__Transition__TRANSITION_CONFIGURE); + EXPECT_EQ(transition->id, lifecycle_msgs__msg__Transition__TRANSITION_CONFIGURE); + // Update this test with a new invalid number if 42 ever becomes a valid state id transition = rcl_lifecycle_get_transition_by_id(state_machine.current_state, 42); EXPECT_EQ(transition, nullptr) << rcl_get_error_string().str; rcutils_reset_error(); - transition = rcl_lifecycle_get_transition_by_label(state_machine.current_state, "TRANSITION"); - EXPECT_EQ(transition, &start->valid_transitions[0]); + transition = rcl_lifecycle_get_transition_by_label(state_machine.current_state, "configure"); + EXPECT_STREQ(transition->label, "configure"); transition = rcl_lifecycle_get_transition_by_label(state_machine.current_state, "NOT A LABEL"); EXPECT_EQ(transition, nullptr) << rcl_get_error_string().str; @@ -387,12 +422,26 @@ TEST(TestRclLifecycle, state_transitions) { EXPECT_EQ(ret, RCL_RET_ERROR); rcutils_reset_error(); - ret = rcl_lifecycle_trigger_transition_by_id(&state_machine, 0, false); + ret = rcl_lifecycle_trigger_transition_by_id( + &state_machine, lifecycle_msgs__msg__Transition__TRANSITION_CONFIGURE, false); EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str; - ret = rcl_lifecycle_trigger_transition_by_label(&state_machine, "TRANSITION", true); + ret = rcl_lifecycle_trigger_transition_by_label(nullptr, "transition_success", true); + EXPECT_EQ(ret, RCL_RET_ERROR); + rcutils_reset_error(); + + ret = rcl_lifecycle_trigger_transition_by_label(&state_machine, "transition_success", true); EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str; + // If using the public interface to register transitions, this case should already be checked. + state_machine.current_state->valid_transitions[0].goal = nullptr; + ret = rcl_lifecycle_trigger_transition_by_label(&state_machine, "transition_success", true); + EXPECT_EQ(ret, RCL_RET_ERROR); + rcutils_reset_error(); + rcl_print_state_machine(&state_machine); EXPECT_FALSE(rcutils_error_is_set()); + + ret = rcl_lifecycle_state_machine_fini(&state_machine, &node, &allocator); + EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str; } diff --git a/rcl_lifecycle/test/test_transition_map.cpp b/rcl_lifecycle/test/test_transition_map.cpp index e4442bc961..9904603676 100644 --- a/rcl_lifecycle/test/test_transition_map.cpp +++ b/rcl_lifecycle/test/test_transition_map.cpp @@ -35,11 +35,22 @@ class TestTransitionMap : public ::testing::Test } }; +static void * bad_malloc(size_t, void *) +{ + return nullptr; +} + +static void * bad_realloc(void *, size_t, void *) +{ + return nullptr; +} + TEST_F(TestTransitionMap, zero_initialized) { rcl_lifecycle_transition_map_t transition_map = rcl_lifecycle_get_zero_initialized_transition_map(); EXPECT_EQ(RCL_RET_ERROR, rcl_lifecycle_transition_map_is_initialized(&transition_map)); + rcutils_reset_error(); rcl_allocator_t allocator = rcl_get_default_allocator(); EXPECT_EQ(RCL_RET_OK, rcl_lifecycle_transition_map_fini(&transition_map, &allocator)); @@ -57,7 +68,7 @@ TEST_F(TestTransitionMap, initialized) { EXPECT_EQ(RCL_RET_OK, rcl_lifecycle_transition_map_is_initialized(&transition_map)); ret = rcl_lifecycle_register_state(&transition_map, state0, &allocator); - EXPECT_EQ(RCL_RET_ERROR, ret) << rcl_get_error_string().str; + EXPECT_EQ(RCL_RET_ERROR, ret); rcutils_reset_error(); rcl_lifecycle_state_t state1 = {"my_state_1", 1, NULL, 0}; @@ -65,6 +76,17 @@ TEST_F(TestTransitionMap, initialized) { rcl_lifecycle_state_t unregistered = {"my_state_2", 2, NULL, 0}; + rcl_allocator_t bad_allocator = rcl_get_default_allocator(); + bad_allocator.allocate = bad_malloc; + bad_allocator.reallocate = bad_realloc; + rcl_lifecycle_state_t * original_ptr = transition_map.states; + size_t original_size = transition_map.states_size; + ret = rcl_lifecycle_register_state(&transition_map, unregistered, &bad_allocator); + EXPECT_EQ(RCL_RET_ERROR, ret); + rcutils_reset_error(); + EXPECT_EQ(transition_map.states, original_ptr); + EXPECT_EQ(original_size, transition_map.states_size); + rcl_lifecycle_state_t * start_state = rcl_lifecycle_get_state(&transition_map, state0.id); rcl_lifecycle_state_t * goal_state = @@ -74,29 +96,52 @@ TEST_F(TestTransitionMap, initialized) { rcl_lifecycle_transition_t transition01 = {"from0to1", 0, start_state, goal_state}; + original_size = transition_map.transitions_size; ret = rcl_lifecycle_register_transition( &transition_map, transition01, &allocator); EXPECT_EQ(RCL_RET_OK, ret); + EXPECT_EQ(1u, transition_map.transitions_size); rcl_lifecycle_transition_t transition10 = {"from1to0", 1, goal_state, start_state}; + original_size = transition_map.transitions_size; ret = rcl_lifecycle_register_transition( &transition_map, transition10, &allocator); EXPECT_EQ(RCL_RET_OK, ret); + EXPECT_EQ(2u, transition_map.transitions_size); + rcl_lifecycle_transition_t * old_transitions_ptr = transition_map.transitions; + original_size = transition_map.transitions_size; rcl_lifecycle_transition_t transition_bad1 = {"from0tobad", 2, start_state, &unregistered}; ret = rcl_lifecycle_register_transition( &transition_map, transition_bad1, &allocator); EXPECT_EQ(RCL_RET_ERROR, ret); rcutils_reset_error(); + EXPECT_EQ(old_transitions_ptr, transition_map.transitions); + EXPECT_EQ(original_size, transition_map.transitions_size); + old_transitions_ptr = transition_map.transitions; + original_size = transition_map.transitions_size; rcl_lifecycle_transition_t transition_bad2 = {"frombadto1", 3, &unregistered, goal_state}; ret = rcl_lifecycle_register_transition( &transition_map, transition_bad2, &allocator); EXPECT_EQ(RCL_RET_ERROR, ret); rcutils_reset_error(); + EXPECT_EQ(old_transitions_ptr, transition_map.transitions); + EXPECT_EQ(original_size, transition_map.transitions_size); + + old_transitions_ptr = transition_map.transitions; + original_size = transition_map.transitions_size; + rcl_lifecycle_transition_t transition00 = {"from0to0", 4, + start_state, start_state}; + ret = rcl_lifecycle_register_transition( + &transition_map, transition00, &bad_allocator); + EXPECT_EQ(RCL_RET_BAD_ALLOC, ret); + rcutils_reset_error(); + EXPECT_EQ(old_transitions_ptr, transition_map.transitions); + EXPECT_EQ(original_size, transition_map.transitions_size); const rcl_lifecycle_transition_t * trans = rcl_lifecycle_get_transition_by_id(start_state, 0);