Skip to content

Commit 30e60cc

Browse files
committed
iox-#2055 Add edge test cases for floating point
Signed-off-by: Dennis Liu <[email protected]>
1 parent 40a1224 commit 30e60cc

File tree

1 file changed

+182
-1
lines changed

1 file changed

+182
-1
lines changed

iceoryx_hoofs/test/moduletests/test_utility_convert.cpp

Lines changed: 182 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#include "iox/std_string_support.hpp"
2222
#include "test.hpp"
2323

24-
24+
#include <cmath>
2525
#include <cstdint>
2626
namespace
2727
{
@@ -38,6 +38,15 @@ class convert_test : public Test
3838
void TearDown() override
3939
{
4040
}
41+
template <typename T>
42+
std::string fp_to_string(T value)
43+
{
44+
static_assert(std::is_floating_point<T>::value, "fp_to_string requires floating point type");
45+
46+
std::ostringstream oss;
47+
oss << std::scientific << std::setprecision(std::numeric_limits<T>::max_digits10) << value;
48+
return oss.str();
49+
}
4150
};
4251

4352

@@ -549,6 +558,178 @@ TEST_F(convert_test, fromString_EdgeCase_UnSignedLongLong)
549558

550559
/// UNSINGED INTEGRAL EDGE CASES END
551560

561+
/// NORMAL FLOATING POINT TYPE EDGE CASES START
562+
563+
TEST_F(convert_test, fromString_EdgeCase_Float)
564+
{
565+
::testing::Test::RecordProperty("TEST_ID", "68d4f096-a93c-406b-b081-fe50e4b1a2c9");
566+
567+
std::string source = fp_to_string(std::numeric_limits<float>::min());
568+
auto float_min = iox::convert::from_string<float>(source.c_str());
569+
ASSERT_THAT(float_min.has_value(), Eq(true));
570+
EXPECT_THAT(float_min.value(), FloatEq(std::numeric_limits<float>::min()));
571+
572+
// strtof will trigger ERANGE if the input is a subnormal float, resulting in a nullopt return value.
573+
auto normal_float_min_eps = std::nextafter(std::numeric_limits<float>::min(), 0.0F);
574+
source = fp_to_string(std::numeric_limits<float>::min() - normal_float_min_eps);
575+
auto float_min_dec_eps = iox::convert::from_string<float>(source.c_str());
576+
ASSERT_THAT(float_min_dec_eps.has_value(), Eq(false));
577+
578+
source = fp_to_string(std::numeric_limits<float>::lowest());
579+
auto float_lowest = iox::convert::from_string<float>(source.c_str());
580+
ASSERT_THAT(float_lowest.has_value(), Eq(true));
581+
EXPECT_THAT(float_lowest.value(), FloatEq(std::numeric_limits<float>::lowest()));
582+
583+
source = fp_to_string(std::numeric_limits<float>::max());
584+
auto float_max = iox::convert::from_string<float>(source.c_str());
585+
ASSERT_THAT(float_max.has_value(), Eq(true));
586+
EXPECT_THAT(float_max.value(), FloatEq(std::numeric_limits<float>::max()));
587+
}
588+
589+
TEST_F(convert_test, fromString_EdgeCase_Double)
590+
{
591+
::testing::Test::RecordProperty("TEST_ID", "af7ca2e6-ba7e-41f7-a321-5f68617d3566");
592+
593+
std::string source = fp_to_string(std::numeric_limits<double>::min());
594+
auto double_min = iox::convert::from_string<double>(source.c_str());
595+
ASSERT_THAT(double_min.has_value(), Eq(true));
596+
EXPECT_THAT(double_min.value(), DoubleEq(std::numeric_limits<double>::min()));
597+
598+
auto normal_double_min_eps = std::nextafter(std::numeric_limits<double>::min(), 0.0);
599+
source = fp_to_string(std::numeric_limits<double>::min() - normal_double_min_eps);
600+
auto double_min_dec_eps = iox::convert::from_string<double>(source.c_str());
601+
ASSERT_THAT(double_min_dec_eps.has_value(), Eq(false));
602+
603+
source = fp_to_string(std::numeric_limits<double>::lowest());
604+
auto double_lowest = iox::convert::from_string<double>(source.c_str());
605+
ASSERT_THAT(double_lowest.has_value(), Eq(true));
606+
EXPECT_THAT(double_lowest.value(), DoubleEq(std::numeric_limits<double>::lowest()));
607+
608+
source = fp_to_string(std::numeric_limits<double>::max());
609+
auto double_max = iox::convert::from_string<double>(source.c_str());
610+
ASSERT_THAT(double_max.has_value(), Eq(true));
611+
EXPECT_THAT(double_max.value(), DoubleEq(std::numeric_limits<double>::max()));
612+
}
613+
614+
TEST_F(convert_test, fromString_EdgeCase_LongDouble)
615+
{
616+
::testing::Test::RecordProperty("TEST_ID", "fb96e526-8fb6-4af9-87f0-dfd4193237a5");
617+
618+
std::string source = fp_to_string(std::numeric_limits<long double>::min());
619+
auto long_double_min = iox::convert::from_string<long double>(source.c_str());
620+
ASSERT_THAT(long_double_min.has_value(), Eq(true));
621+
// There's no LongDoubleEq
622+
EXPECT_THAT(long_double_min.value(), Eq(std::numeric_limits<long double>::min()));
623+
624+
auto normal_long_double_min_eps = std::nextafter(std::numeric_limits<long double>::min(), 0.0L);
625+
source = fp_to_string(std::numeric_limits<long double>::min() - normal_long_double_min_eps);
626+
auto long_double_min_dec_eps = iox::convert::from_string<long double>(source.c_str());
627+
ASSERT_THAT(long_double_min_dec_eps.has_value(), Eq(false));
628+
629+
source = fp_to_string(std::numeric_limits<long double>::lowest());
630+
auto long_double_lowest = iox::convert::from_string<long double>(source.c_str());
631+
ASSERT_THAT(long_double_lowest.has_value(), Eq(true));
632+
EXPECT_THAT(long_double_lowest.value(), Eq(std::numeric_limits<long double>::lowest()));
633+
634+
source = fp_to_string(std::numeric_limits<long double>::max());
635+
auto long_double_max = iox::convert::from_string<long double>(source.c_str());
636+
ASSERT_THAT(long_double_max.has_value(), Eq(true));
637+
EXPECT_THAT(long_double_max.value(), Eq(std::numeric_limits<long double>::max()));
638+
}
639+
640+
/// NORMAL FLOATING POINT TYPE EDGE CASES END
641+
642+
/// SPECIAL FLOATING POINT TYPE EDGE CASES START
643+
644+
TEST_F(convert_test, fromString_EdgeCase_Float_NaN)
645+
{
646+
::testing::Test::RecordProperty("TEST_ID", "772bcbc3-d55b-464f-873f-82754ad543f3");
647+
648+
std::vector<std::string> nan_vec = {"NaN", "nan"};
649+
650+
for (const auto& v : nan_vec)
651+
{
652+
auto nan_ret = iox::convert::from_string<float>(v.c_str());
653+
ASSERT_THAT(nan_ret.has_value(), Eq(true));
654+
ASSERT_THAT(std::isnan(nan_ret.value()), Eq(true));
655+
}
656+
}
657+
658+
TEST_F(convert_test, fromString_EdgeCase_Double_NaN)
659+
{
660+
::testing::Test::RecordProperty("TEST_ID", "a27c8575-658c-465d-a1a2-4f2f6b9a723a");
661+
662+
std::vector<std::string> nan_vec = {"NaN", "nan"};
663+
664+
for (const auto& v : nan_vec)
665+
{
666+
auto nan_ret = iox::convert::from_string<double>(v.c_str());
667+
ASSERT_THAT(nan_ret.has_value(), Eq(true));
668+
ASSERT_THAT(std::isnan(nan_ret.value()), Eq(true));
669+
}
670+
}
671+
672+
TEST_F(convert_test, fromString_EdgeCase_LongDouble_NaN)
673+
{
674+
::testing::Test::RecordProperty("TEST_ID", "486f4e78-6000-4401-bb66-62d26b1d0cce");
675+
676+
std::vector<std::string> nan_vec = {"NaN", "nan"};
677+
678+
for (const auto& v : nan_vec)
679+
{
680+
auto nan_ret = iox::convert::from_string<long double>(v.c_str());
681+
ASSERT_THAT(nan_ret.has_value(), Eq(true));
682+
ASSERT_THAT(std::isnan(nan_ret.value()), Eq(true));
683+
}
684+
}
685+
686+
TEST_F(convert_test, fromString_EdgeCase_Float_Inf)
687+
{
688+
::testing::Test::RecordProperty("TEST_ID", "82dba3ae-5802-4fbc-aa91-15f4a2953573");
689+
690+
std::vector<std::string> inf_vec = {
691+
"INF", "Inf", "inf", "INFINITY", "Infinity", "-INF", "-Inf", "-inf", "-INFINITY", "-Infinity"};
692+
693+
for (const auto& v : inf_vec)
694+
{
695+
auto inf_ret = iox::convert::from_string<float>(v.c_str());
696+
ASSERT_THAT(inf_ret.has_value(), Eq(true));
697+
ASSERT_THAT(std::isinf(inf_ret.value()), Eq(true));
698+
}
699+
}
700+
701+
TEST_F(convert_test, fromString_EdgeCase_Double_Inf)
702+
{
703+
::testing::Test::RecordProperty("TEST_ID", "e4ccd01d-b1d1-433e-ba04-548dcc479bb1");
704+
705+
std::vector<std::string> inf_vec = {
706+
"INF", "Inf", "inf", "INFINITY", "Infinity", "-INF", "-Inf", "-inf", "-INFINITY", "-Infinity"};
707+
708+
for (const auto& v : inf_vec)
709+
{
710+
auto inf_ret = iox::convert::from_string<double>(v.c_str());
711+
ASSERT_THAT(inf_ret.has_value(), Eq(true));
712+
ASSERT_THAT(std::isinf(inf_ret.value()), Eq(true));
713+
}
714+
}
715+
716+
TEST_F(convert_test, fromString_EdgeCase_LongDouble_Inf)
717+
{
718+
::testing::Test::RecordProperty("TEST_ID", "6b8a3284-5f20-4cd6-9958-a2abb348ebe2");
719+
720+
std::vector<std::string> inf_vec = {
721+
"INF", "Inf", "inf", "INFINITY", "Infinity", "-INF", "-Inf", "-inf", "-INFINITY", "-Infinity"};
722+
723+
for (const auto& v : inf_vec)
724+
{
725+
auto inf_ret = iox::convert::from_string<long double>(v.c_str());
726+
ASSERT_THAT(inf_ret.has_value(), Eq(true));
727+
ASSERT_THAT(std::isinf(inf_ret.value()), Eq(true));
728+
}
729+
}
730+
731+
/// SPECIAL FLOATING POINT TYPE EDGE CASES END
732+
552733
TEST_F(convert_test, fromString_cxxString)
553734
{
554735
::testing::Test::RecordProperty("TEST_ID", "dbf015bb-5f51-47e1-9d0e-0525f65e7803");

0 commit comments

Comments
 (0)