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

String tests #179

Merged
merged 6 commits into from
Dec 8, 2016
Merged
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
2 changes: 2 additions & 0 deletions rosidl_generator_c/test/test_interfaces.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,8 @@ void test_strings(void)
EXPECT_EQ(0, strcmp(strings->empty_string.data, TEST_STRING));
EXPECT_EQ(0, strcmp(strings->def_string.data, "Hello world!"));
// since upper-bound checking is not implemented yet, we restrict the string copying
// TODO(mikaelarguedas) Test string length properly instead of cheating copy
// res = rosidl_generator_c__String__assign(&strings->ub_string, TEST_STRING);
res = rosidl_generator_c__String__assignn(&strings->ub_string, TEST_STRING, 22);
EXPECT_EQ(true, res);
EXPECT_EQ(0, strcmp(strings->ub_string.data, "Deep into that darknes"));
Expand Down
4 changes: 4 additions & 0 deletions rosidl_generator_cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ if(BUILD_TESTING)
"msg/StaticArrayStatic.msg"
"msg/StaticArrayUnbounded.msg"

"msg/String.msg"
"msg/StringBounded.msg"
"msg/StringArrayStatic.msg"

"msg/UnboundedArrayBounded.msg"
"msg/UnboundedArrayStatic.msg"
"msg/UnboundedArrayUnbounded.msg"
Expand Down
26 changes: 13 additions & 13 deletions rosidl_generator_cpp/msg/PrimitiveStaticArrays.msg
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
bool[3] bool_value
byte[3] byte_value
char[3] char_value
float32[3] float32_value
float64[3] float64_value
int8[3] int8_value
uint8[3] uint8_value
int16[3] int16_value
uint16[3] uint16_value
int32[3] int32_value
uint32[3] uint32_value
int64[3] int64_value
uint64[3] uint64_value
bool[10] bool_value
byte[10] byte_value
char[10] char_value
float32[10] float32_value
float64[10] float64_value
int8[10] int8_value
uint8[10] uint8_value
int16[10] int16_value
uint16[10] uint16_value
int32[10] int32_value
uint32[10] uint32_value
int64[10] int64_value
uint64[10] uint64_value
2 changes: 1 addition & 1 deletion rosidl_generator_cpp/msg/PrimitivesBounded.msg
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ int32[<=10] int32_value
uint32[<=10] uint32_value
int64[<=10] int64_value
uint64[<=10] uint64_value
string<=10 string_value
string<=10[<=10] string_values
2 changes: 1 addition & 1 deletion rosidl_generator_cpp/msg/PrimitivesUnbounded.msg
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ int32[] int32_value
uint32[] uint32_value
int64[] int64_value
uint64[] uint64_value
string string_value
string[] string_value
1 change: 1 addition & 0 deletions rosidl_generator_cpp/msg/String.msg
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
string string_value
1 change: 1 addition & 0 deletions rosidl_generator_cpp/msg/StringArrayStatic.msg
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
string[10] string_value
1 change: 1 addition & 0 deletions rosidl_generator_cpp/msg/StringBounded.msg
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
string<=10 string_value
51 changes: 45 additions & 6 deletions rosidl_generator_cpp/test/test_array_generator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include <climits>
#include <random>
#include <string>
#include <type_traits>

/**
Expand Down Expand Up @@ -49,8 +50,8 @@ void test_vector_fill(C * container, size_t size, bool val1 = true,
* Mininum and maximum values for the type and random values in the middle.
* @param C Container (vector, array, etc) to be filled
* @param size How many elements to fill in. Must size<=container_size
* @param min Minimum value in the rage to fill.
* @param max Maximum value in the rage to fill.
* @param min Minimum value in the range to fill.
* @param max Maximum value in the range to fill.
*/
template<
typename C,
Expand Down Expand Up @@ -84,8 +85,8 @@ void test_vector_fill(C * container, size_t size,
* Mininum and maximum values for the type and random values in the middle.
* @param C Container (vector, array, etc) to be filled
* @param size How many elements to fill in. Must size<=container_size
* @param min Minimum value in the rage to fill.
* @param max Maximum value in the rage to fill.
* @param min Minimum value in the range to fill.
* @param max Maximum value in the range to fill.
*/
template<
typename C,
Expand Down Expand Up @@ -115,8 +116,8 @@ void test_vector_fill(C * container, size_t size,
* Mininum and maximum values for the type and random numbers in the middle.
* @param C Container (vector, array, etc) to be filled
* @param size How many elements to fill in. Must size<=container_size
* @param min Minimum value in the rage to fill.
* @param max Maximum value in the rage to fill.
* @param min Minimum value in the range to fill.
* @param max Maximum value in the range to fill.
*/
template<
typename C,
Expand All @@ -139,4 +140,42 @@ void test_vector_fill(C * container, size_t size,
}
}

/**
* Helper function to generate a test pattern for string types.
* Mininum and maximum values for the type and random numbers in the middle.
* @param C Container (vector, array, etc) to be filled
* @param size How many elements to fill in. Must size<=container_size
* @param min Minimum value in the range to fill.
* @param max Maximum value in the range to fill.
* @param minlength Minimum length of the generated strings.
* @param maxlength Maximum length of the generated strings.
*/
template<
typename C,
typename std::enable_if<
std::is_same<typename C::value_type, typename std::string>::value
>::type * = nullptr
>
void test_vector_fill(C * container, size_t size,
int min, int max,
int minlength, const int maxlength)
{
std::default_random_engine rand_generator;
std::uniform_int_distribution<int> randnum(min, max);
std::uniform_int_distribution<int> randlen(minlength, maxlength);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would recommend not to use random numbers for any tests. The problem is that the test will be flaky of the result depends on the values. Instead use a "known" pattern, e.g. increment numbers, or ascii characters.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'll ticket it and change it to use known patterns in a follow-up to keep the scope of this PR narrowed to string testing

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ticketed here #181

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for not using fuzz values. I'm ok with doing it in a follow up if that's what you want.


if (size > 0) {
char * tmpstr = reinterpret_cast<char *>(malloc(maxlength));
std::snprintf(tmpstr, minlength, "%*d", minlength, min);
(*container)[0] = std::string(tmpstr);
for (size_t i = 1; i < size - 1; i++) {
int length = randlen(rand_generator);
std::snprintf(tmpstr, length, "%*d", length, randnum(rand_generator));
(*container)[i] = std::string(tmpstr);
}
std::snprintf(tmpstr, maxlength, "%*d", maxlength, max);
(*container)[size - 1] = std::string(tmpstr);
}
}

#endif // TEST_ARRAY_GENERATOR_HPP_
119 changes: 115 additions & 4 deletions rosidl_generator_cpp/test/test_interfaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,16 @@
#include "rosidl_generator_cpp/msg/static_array_static.hpp"
#include "rosidl_generator_cpp/msg/static_array_unbounded.hpp"

#include "rosidl_generator_cpp/msg/string.hpp"
#include "rosidl_generator_cpp/msg/string_bounded.hpp"
#include "rosidl_generator_cpp/msg/string_array_static.hpp"

#include "rosidl_generator_cpp/msg/unbounded_array_bounded.hpp"
#include "rosidl_generator_cpp/msg/unbounded_array_static.hpp"
#include "rosidl_generator_cpp/msg/unbounded_array_unbounded.hpp"

#define PRIMITIVES_ARRAY_SIZE 10
#define BOUNDED_STRING_LENGTH 10
#define SUBMESSAGE_ARRAY_SIZE 3

TEST(Test_rosidl_generator_traits, has_fixed_size) {
Expand Down Expand Up @@ -90,6 +95,19 @@ TEST(Test_rosidl_generator_traits, has_fixed_size) {
rosidl_generator_cpp::msg::StaticArrayUnbounded>::value,
"StaticArrayUnbounded::has_fixed_size is true");

static_assert(
!rosidl_generator_traits::has_fixed_size<rosidl_generator_cpp::msg::String>::value,
"String::has_fixed_size is true");

static_assert(
!rosidl_generator_traits::has_fixed_size<rosidl_generator_cpp::msg::StringBounded>::value,
"StringBounded::has_fixed_size is true");

static_assert(
!rosidl_generator_traits::has_fixed_size<
rosidl_generator_cpp::msg::StringArrayStatic>::value,
"StringArrayStatic::has_fixed_size is true");

static_assert(
!rosidl_generator_traits::has_fixed_size<rosidl_generator_cpp::msg::BoundedArrayStatic>::value,
"BoundedArrayStatic::has_fixed_size is true");
Expand Down Expand Up @@ -166,6 +184,16 @@ void test_message_primitives_static(rosidl_generator_cpp::msg::PrimitivesStatic
std::copy_n(pattern_ ## FieldName.begin(), Message.FieldName.size(), Message.FieldName.begin()); \
ASSERT_EQ(pattern_ ## FieldName, Message.FieldName); \

#define TEST_BOUNDED_ARRAY_STRING( \
Message, FieldName, PrimitiveType, ArraySize, MinVal, MaxVal, MinLength, MaxLength) \
rosidl_generator_cpp::BoundedVector<PrimitiveType, ArraySize> pattern_ ## FieldName; \
Message.FieldName.resize(ArraySize); \
pattern_ ## FieldName.resize(ArraySize); \
test_vector_fill<decltype(pattern_ ## FieldName)>( \
&pattern_ ## FieldName, ArraySize, MinVal, MaxVal, MinLength, MaxLength); \
std::copy_n(pattern_ ## FieldName.begin(), Message.FieldName.size(), Message.FieldName.begin()); \
ASSERT_EQ(pattern_ ## FieldName, Message.FieldName); \

void test_message_primitives_bounded(rosidl_generator_cpp::msg::PrimitivesBounded message)
{
TEST_BOUNDED_ARRAY_PRIMITIVE(message, bool_value, bool, PRIMITIVES_ARRAY_SIZE, \
Expand Down Expand Up @@ -194,8 +222,8 @@ void test_message_primitives_bounded(rosidl_generator_cpp::msg::PrimitivesBounde
INT64_MIN, INT64_MAX)
TEST_BOUNDED_ARRAY_PRIMITIVE(message, uint64_value, uint64_t, PRIMITIVES_ARRAY_SIZE, \
0, UINT64_MAX)
// Arrays of strings not supported yet
TEST_STRING_FIELD_ASSIGNMENT(message, string_value, "", "Deep into that darkness peering")
TEST_BOUNDED_ARRAY_STRING(message, string_values, std::string, PRIMITIVES_ARRAY_SIZE, \
0, UINT32_MAX, 0, BOUNDED_STRING_LENGTH)
}

#define TEST_UNBOUNDED_ARRAY_PRIMITIVE( \
Expand All @@ -208,6 +236,16 @@ void test_message_primitives_bounded(rosidl_generator_cpp::msg::PrimitivesBounde
std::copy_n(pattern_ ## FieldName.begin(), ArraySize, Message.FieldName.begin()); \
ASSERT_EQ(pattern_ ## FieldName, Message.FieldName); \

#define TEST_UNBOUNDED_ARRAY_STRING( \
Message, FieldName, PrimitiveType, ArraySize, MinVal, MaxVal, MinLength, MaxLength) \
std::vector<PrimitiveType> pattern_ ## FieldName; \
Message.FieldName.resize(ArraySize); \
pattern_ ## FieldName.resize(ArraySize); \
test_vector_fill<decltype(pattern_ ## FieldName)>( \
&pattern_ ## FieldName, ArraySize, MinVal, MaxVal, MinLength, MaxLength); \
std::copy_n(pattern_ ## FieldName.begin(), Message.FieldName.size(), Message.FieldName.begin()); \
ASSERT_EQ(pattern_ ## FieldName, Message.FieldName); \

void test_message_primitives_unbounded(rosidl_generator_cpp::msg::PrimitivesUnbounded message)
{
TEST_UNBOUNDED_ARRAY_PRIMITIVE(message, bool_value, bool, PRIMITIVES_ARRAY_SIZE, \
Expand Down Expand Up @@ -236,8 +274,46 @@ void test_message_primitives_unbounded(rosidl_generator_cpp::msg::PrimitivesUnbo
INT64_MIN, INT64_MAX)
TEST_UNBOUNDED_ARRAY_PRIMITIVE(message, uint64_value, uint64_t, PRIMITIVES_ARRAY_SIZE, \
0, UINT64_MAX)
// Arrays of strings not supported yet
TEST_STRING_FIELD_ASSIGNMENT(message, string_value, "", "Deep into that darkness peering")
TEST_UNBOUNDED_ARRAY_STRING(message, string_value, std::string, PRIMITIVES_ARRAY_SIZE, \
0, UINT32_MAX, 0, UINT16_MAX)
}

#define TEST_STATIC_ARRAY_PRIMITIVE( \
Message, FieldName, PrimitiveType, ArraySize, MinVal, MaxVal) \
std::array<PrimitiveType, ArraySize> pattern_ ## FieldName; \
test_vector_fill<decltype(pattern_ ## FieldName)>( \
&pattern_ ## FieldName, ArraySize, MinVal, MaxVal); \
std::copy_n(pattern_ ## FieldName.begin(), ArraySize, Message.FieldName.begin()); \
ASSERT_EQ(pattern_ ## FieldName, Message.FieldName); \

void test_message_primitives_static_arrays(rosidl_generator_cpp::msg::PrimitiveStaticArrays message)
{
TEST_STATIC_ARRAY_PRIMITIVE(message, bool_value, bool, PRIMITIVES_ARRAY_SIZE, \
false, true)
TEST_STATIC_ARRAY_PRIMITIVE(message, char_value, char, PRIMITIVES_ARRAY_SIZE, \
CHAR_MIN, CHAR_MAX)
TEST_STATIC_ARRAY_PRIMITIVE(message, byte_value, uint8_t, PRIMITIVES_ARRAY_SIZE, \
0, UINT8_MAX)
TEST_STATIC_ARRAY_PRIMITIVE(message, float32_value, float, PRIMITIVES_ARRAY_SIZE, \
FLT_MIN, FLT_MAX)
TEST_STATIC_ARRAY_PRIMITIVE(message, float64_value, double, PRIMITIVES_ARRAY_SIZE, \
DBL_MIN, DBL_MAX)
TEST_STATIC_ARRAY_PRIMITIVE(message, int8_value, int8_t, PRIMITIVES_ARRAY_SIZE, \
INT8_MIN, INT8_MAX)
TEST_STATIC_ARRAY_PRIMITIVE(message, uint8_value, uint8_t, PRIMITIVES_ARRAY_SIZE, \
0, UINT8_MAX)
TEST_STATIC_ARRAY_PRIMITIVE(message, int16_value, int16_t, PRIMITIVES_ARRAY_SIZE, \
INT16_MIN, INT16_MAX)
TEST_STATIC_ARRAY_PRIMITIVE(message, uint16_value, uint16_t, PRIMITIVES_ARRAY_SIZE, \
0, UINT16_MAX)
TEST_STATIC_ARRAY_PRIMITIVE(message, int32_value, int32_t, PRIMITIVES_ARRAY_SIZE, \
INT32_MIN, INT32_MAX)
TEST_STATIC_ARRAY_PRIMITIVE(message, uint32_value, uint32_t, PRIMITIVES_ARRAY_SIZE, \
0, UINT32_MAX)
TEST_STATIC_ARRAY_PRIMITIVE(message, int64_value, int64_t, PRIMITIVES_ARRAY_SIZE, \
INT64_MIN, INT64_MAX)
TEST_STATIC_ARRAY_PRIMITIVE(message, uint64_value, uint64_t, PRIMITIVES_ARRAY_SIZE, \
0, UINT64_MAX)
}

// Primitives static
Expand All @@ -246,6 +322,12 @@ TEST(Test_messages, primitives_static) {
test_message_primitives_static(message);
}

// Primitives static arrays
TEST(Test_messages, primitives_static_arrays) {
rosidl_generator_cpp::msg::PrimitiveStaticArrays message;
test_message_primitives_static_arrays(message);
}

// Primitives bounded arrays
TEST(Test_messages, primitives_bounded) {
rosidl_generator_cpp::msg::PrimitivesBounded message;
Expand Down Expand Up @@ -382,3 +464,32 @@ TEST(Test_messages, primitives_default) {
TEST_PRIMITIVE_FIELD_ASSIGNMENT(message, uint64_value, 50000000ull, UINT64_MAX);
TEST_STRING_FIELD_ASSIGNMENT(message, string_value, "bar", "Hello World!")
}

// TODO(mikaelarguedas) reenable this test when bounded strings enforce length
TEST(Test_messages, DISABLED_Test_bounded_strings) {
rosidl_generator_cpp::msg::StringBounded message;
TEST_STRING_FIELD_ASSIGNMENT(message, string_value, "", "Deep into")
std::string tooLongString = std::string("Too long string");
message.string_value = tooLongString;
tooLongString.resize(BOUNDED_STRING_LENGTH);
ASSERT_STREQ(tooLongString.c_str(), message.string_value.c_str());
}

TEST(Test_messages, Test_string) {
rosidl_generator_cpp::msg::String message;
TEST_STRING_FIELD_ASSIGNMENT(message, string_value, "", "Deep into")
}

#define TEST_STATIC_ARRAY_STRING( \
Message, FieldName, PrimitiveType, ArraySize, MinVal, MaxVal, MinLength, MaxLength) \
std::array<PrimitiveType, ArraySize> pattern_ ## FieldName; \
test_vector_fill<decltype(pattern_ ## FieldName)>( \
&pattern_ ## FieldName, ArraySize, MinVal, MaxVal, MinLength, MaxLength); \
std::copy_n(pattern_ ## FieldName.begin(), Message.FieldName.size(), Message.FieldName.begin()); \
ASSERT_EQ(pattern_ ## FieldName, Message.FieldName); \

TEST(Test_messages, Test_string_array_static) {
rosidl_generator_cpp::msg::StringArrayStatic message;
TEST_STATIC_ARRAY_STRING(message, string_value, std::string, PRIMITIVES_ARRAY_SIZE, \
0, UINT32_MAX, 0, UINT16_MAX)
}
2 changes: 0 additions & 2 deletions rosidl_generator_py/msg/Primitives.msg
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,4 @@ int64 int64_value
uint64 uint64_value
string string_value
string string_value_with_default 'default'
#string<=5[3] fixed_length_string_value
#string<=5[<=10] upper_bound_string_value
string unbound_string_value
3 changes: 3 additions & 0 deletions rosidl_generator_py/msg/Strings.msg
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ string empty_string
string def_string "Hello world!"
string<=22 ub_string
string<=22 ub_def_string "Upper bounded string."
string<=5[3] ub_string_static_array_value
string<=5[<=10] ub_string_ub_array_value
string<=5[] ub_string_dynamic_array_value
3 changes: 3 additions & 0 deletions rosidl_generator_py/resource/_msg.py.em
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ class @(spec.base_type.type)(metaclass=Metaclass):
isinstance(value, UserList)) and
not isinstance(value, str) and
not isinstance(value, UserString) and
@[ if field.type.type == 'string' and field.type.string_upper_bound]@
all([len(val) <= @field.type.string_upper_bound for val in value]) and
@[ end if]@
@[ if field.type.array_size]@
@[ if field.type.is_upper_bound]@
len(value) <= @(field.type.array_size) and
Expand Down
Loading