1 // 2 // Copyright © 2020 Arm Ltd. All rights reserved. 3 // SPDX-License-Identifier: MIT 4 // 5 6 7 #define ARMNN_POLYMORPHIC_CAST_TESTABLE 8 #define ARMNN_NUMERIC_CAST_TESTABLE 9 10 #include <armnn/Exceptions.hpp> 11 #include <armnn/utility/IgnoreUnused.hpp> 12 #include <armnn/utility/PolymorphicDowncast.hpp> 13 #include <armnn/utility/NumericCast.hpp> 14 #include <armnn/utility/StringUtils.hpp> 15 16 #include <doctest/doctest.h> 17 18 #include <limits> 19 20 // Tests of include/Utility files 21 TEST_SUITE("UtilityTests") 22 { 23 TEST_CASE("PolymorphicDowncast") 24 { 25 using namespace armnn; 26 class Base 27 { 28 public: ~Base()29 virtual ~Base(){} 30 float v; 31 }; 32 33 class Child1 : public Base 34 { 35 public: 36 int j; 37 }; 38 39 class Child2 : public Base 40 { 41 public: 42 char b; 43 }; 44 45 Child1 child1; 46 Base* base1 = &child1; 47 auto ptr1 = dynamic_cast<Child1*>(base1); 48 CHECK(ptr1 != nullptr); 49 CHECK_NOTHROW(armnn::PolymorphicDowncast<Child1*>(base1)); 50 CHECK(armnn::PolymorphicDowncast<Child1*>(base1) == ptr1); 51 52 auto ptr2 = dynamic_cast<Child2*>(base1); 53 CHECK(ptr2 == nullptr); 54 CHECK_THROWS_AS(armnn::PolymorphicDowncast<Child2*>(base1), std::bad_cast); 55 56 armnn::IgnoreUnused(ptr1, ptr2); 57 } 58 59 60 TEST_CASE("PolymorphicPointerDowncast_SharedPointer") 61 { 62 using namespace armnn; 63 class Base 64 { 65 public: ~Base()66 virtual ~Base(){} 67 float v; 68 }; 69 70 class Child1 : public Base 71 { 72 public: 73 int j; 74 }; 75 76 class Child2 : public Base 77 { 78 public: 79 char b; 80 }; 81 82 std::shared_ptr<Base> base1 = std::make_shared<Child1>(); 83 84 std::shared_ptr<Child1> ptr1 = std::static_pointer_cast<Child1>(base1); 85 CHECK(ptr1); 86 CHECK_NOTHROW(armnn::PolymorphicPointerDowncast<Child1>(base1)); 87 CHECK(armnn::PolymorphicPointerDowncast<Child1>(base1) == ptr1); 88 89 auto ptr2 = std::dynamic_pointer_cast<Child2>(base1); 90 CHECK(!ptr2); 91 CHECK_THROWS_AS(armnn::PolymorphicPointerDowncast<Child2>(base1), std::bad_cast); 92 93 armnn::IgnoreUnused(ptr1, ptr2); 94 } 95 96 97 TEST_CASE("PolymorphicPointerDowncast_BuildInPointer") 98 { 99 using namespace armnn; 100 class Base 101 { 102 public: ~Base()103 virtual ~Base(){} 104 float v; 105 }; 106 107 class Child1 : public Base 108 { 109 public: 110 int j; 111 }; 112 113 class Child2 : public Base 114 { 115 public: 116 char b; 117 }; 118 119 Child1 child1; 120 Base* base1 = &child1; 121 auto ptr1 = dynamic_cast<Child1*>(base1); 122 CHECK(ptr1 != nullptr); 123 CHECK_NOTHROW(armnn::PolymorphicPointerDowncast<Child1>(base1)); 124 CHECK(armnn::PolymorphicPointerDowncast<Child1>(base1) == ptr1); 125 126 auto ptr2 = dynamic_cast<Child2*>(base1); 127 CHECK(ptr2 == nullptr); 128 CHECK_THROWS_AS(armnn::PolymorphicPointerDowncast<Child2>(base1), std::bad_cast); 129 130 armnn::IgnoreUnused(ptr1, ptr2); 131 } 132 133 134 TEST_CASE("NumericCast") 135 { 136 using namespace armnn; 137 138 // To 8 bit 139 CHECK_THROWS_AS(numeric_cast<unsigned char>(-1), std::bad_cast); 140 CHECK_THROWS_AS(numeric_cast<unsigned char>(1 << 8), std::bad_cast); 141 CHECK_THROWS_AS(numeric_cast<unsigned char>(1L << 16), std::bad_cast); 142 CHECK_THROWS_AS(numeric_cast<unsigned char>(1LL << 32), std::bad_cast); 143 144 CHECK_THROWS_AS(numeric_cast<signed char>((1L << 8)*-1), std::bad_cast); 145 CHECK_THROWS_AS(numeric_cast<signed char>((1L << 15)*-1), std::bad_cast); 146 CHECK_THROWS_AS(numeric_cast<signed char>((1LL << 31)*-1), std::bad_cast); 147 148 CHECK_NOTHROW(numeric_cast<unsigned char>(1U)); 149 CHECK_NOTHROW(numeric_cast<unsigned char>(1L)); 150 CHECK_NOTHROW(numeric_cast<signed char>(-1)); 151 CHECK_NOTHROW(numeric_cast<signed char>(-1L)); 152 CHECK_NOTHROW(numeric_cast<signed char>((1 << 7)*-1)); 153 154 // To 16 bit 155 CHECK_THROWS_AS(numeric_cast<uint16_t>(-1), std::bad_cast); 156 CHECK_THROWS_AS(numeric_cast<uint16_t>(1L << 16), std::bad_cast); 157 CHECK_THROWS_AS(numeric_cast<uint16_t>(1LL << 32), std::bad_cast); 158 159 CHECK_THROWS_AS(numeric_cast<int16_t>(1L << 15), std::bad_cast); 160 CHECK_THROWS_AS(numeric_cast<int16_t>(1LL << 31), std::bad_cast); 161 162 CHECK_NOTHROW(numeric_cast<uint16_t>(1L << 8)); 163 CHECK_NOTHROW(numeric_cast<int16_t>(1L << 7)); 164 CHECK_NOTHROW(numeric_cast<int16_t>((1L << 15)*-1)); 165 166 CHECK_NOTHROW(numeric_cast<int16_t>(1U << 8)); 167 CHECK_NOTHROW(numeric_cast<int16_t>(1U << 14)); 168 169 // To 32 bit 170 CHECK_NOTHROW(numeric_cast<uint32_t>(1)); 171 CHECK_NOTHROW(numeric_cast<uint32_t>(1 << 8)); 172 CHECK_NOTHROW(numeric_cast<uint32_t>(1L << 16)); 173 CHECK_NOTHROW(numeric_cast<uint32_t>(1LL << 31)); 174 175 CHECK_NOTHROW(numeric_cast<int32_t>(-1)); 176 CHECK_NOTHROW(numeric_cast<int32_t>((1L << 8)*-1)); 177 CHECK_NOTHROW(numeric_cast<int32_t>((1L << 16)*-1)); 178 CHECK_NOTHROW(numeric_cast<int32_t>((1LL << 31)*-1)); 179 180 CHECK_NOTHROW(numeric_cast<int32_t>(1U)); 181 CHECK_NOTHROW(numeric_cast<int32_t>(1U << 8)); 182 CHECK_NOTHROW(numeric_cast<int32_t>(1U << 16)); 183 CHECK_NOTHROW(numeric_cast<int32_t>(1U << 30)); 184 185 float float_max = std::numeric_limits<float>::max(); 186 float float_min = std::numeric_limits<float>::lowest(); 187 auto int8_max = std::numeric_limits<int8_t>::max(); 188 auto int16_max = std::numeric_limits<int16_t>::max(); 189 auto int32_max = std::numeric_limits<int32_t>::max(); 190 auto int8_min = std::numeric_limits<int8_t>::lowest(); 191 auto int16_min = std::numeric_limits<int16_t>::lowest(); 192 auto int32_min = std::numeric_limits<int32_t>::lowest(); 193 auto uint8_max = std::numeric_limits<uint8_t>::max(); 194 auto uint16_max = std::numeric_limits<uint16_t>::max(); 195 auto uint32_max = std::numeric_limits<uint32_t>::max(); 196 auto double_max = std::numeric_limits<double>::max(); 197 198 // Float to signed integer 199 CHECK_NOTHROW(numeric_cast<int32_t>(1.324f)); 200 CHECK(1 == numeric_cast<int32_t>(1.324f)); 201 CHECK_NOTHROW(numeric_cast<int32_t>(-1.0f)); 202 CHECK(-1 == numeric_cast<int32_t>(-1.0f)); 203 204 CHECK_NOTHROW(numeric_cast<int8_t>(static_cast<float>(int8_max))); 205 CHECK_NOTHROW(numeric_cast<int16_t>(static_cast<float>(int16_max))); 206 CHECK_NOTHROW(numeric_cast<int32_t>(static_cast<double>(int32_max))); 207 208 CHECK_THROWS_AS(numeric_cast<int8_t>(float_max), std::bad_cast); 209 CHECK_THROWS_AS(numeric_cast<int16_t>(float_max), std::bad_cast); 210 CHECK_THROWS_AS(numeric_cast<int32_t>(float_max), std::bad_cast); 211 212 CHECK_THROWS_AS(numeric_cast<int8_t>(float_min), std::bad_cast); 213 CHECK_THROWS_AS(numeric_cast<int16_t>(float_min), std::bad_cast); 214 CHECK_THROWS_AS(numeric_cast<int32_t>(float_min), std::bad_cast); 215 216 // Signed integer to float 217 CHECK_NOTHROW(numeric_cast<float>(1)); 218 CHECK(1.0 == numeric_cast<float>(1)); 219 CHECK_NOTHROW(numeric_cast<float>(-1)); 220 CHECK(-1.0 == numeric_cast<float>(-1)); 221 222 CHECK_NOTHROW(numeric_cast<float>(int8_max)); 223 CHECK_NOTHROW(numeric_cast<float>(int16_max)); 224 CHECK_NOTHROW(numeric_cast<float>(int32_max)); 225 226 CHECK_NOTHROW(numeric_cast<float>(int8_min)); 227 CHECK_NOTHROW(numeric_cast<float>(int16_min)); 228 CHECK_NOTHROW(numeric_cast<float>(int32_min)); 229 230 // Unsigned integer to float 231 CHECK_NOTHROW(numeric_cast<float>(1U)); 232 CHECK(1.0 == numeric_cast<float>(1U)); 233 234 CHECK_NOTHROW(numeric_cast<float>(uint8_max)); 235 CHECK_NOTHROW(numeric_cast<float>(uint16_max)); 236 CHECK_NOTHROW(numeric_cast<float>(uint32_max)); 237 238 // Float to unsigned integer 239 CHECK_NOTHROW(numeric_cast<uint32_t>(1.43243f)); 240 CHECK(1 == numeric_cast<uint32_t>(1.43243f)); 241 242 CHECK_THROWS_AS(numeric_cast<uint32_t>(-1.1f), std::bad_cast); 243 CHECK_THROWS_AS(numeric_cast<uint32_t>(float_max), std::bad_cast); 244 245 // Double checks 246 CHECK_THROWS_AS(numeric_cast<int32_t>(double_max), std::bad_cast); 247 CHECK_THROWS_AS(numeric_cast<int32_t>(double_max), std::bad_cast); 248 CHECK_THROWS_AS(numeric_cast<float>(double_max), std::bad_cast); 249 CHECK_NOTHROW(numeric_cast<double>(int32_max)); 250 CHECK_NOTHROW(numeric_cast<long double>(int32_max)); 251 252 } 253 254 TEST_CASE("StringToBool") 255 { 256 CHECK(true == armnn::stringUtils::StringToBool("1")); 257 CHECK(false == armnn::stringUtils::StringToBool("0")); 258 // Any number larger than 1 will be a failure. 259 CHECK_THROWS_AS(armnn::stringUtils::StringToBool("2"), armnn::InvalidArgumentException); 260 CHECK_THROWS_AS(armnn::stringUtils::StringToBool("23456567"), armnn::InvalidArgumentException); 261 CHECK_THROWS_AS(armnn::stringUtils::StringToBool("-23456567"), armnn::InvalidArgumentException); 262 CHECK_THROWS_AS(armnn::stringUtils::StringToBool("Not a number"), armnn::InvalidArgumentException); 263 // Empty string should be a failure. 264 CHECK_THROWS_AS(armnn::stringUtils::StringToBool(""), armnn::InvalidArgumentException); 265 CHECK(true == armnn::stringUtils::StringToBool("true")); 266 CHECK(false == armnn::stringUtils::StringToBool("false")); 267 // Should be case agnostic. 268 CHECK(true == armnn::stringUtils::StringToBool("TrUe")); 269 CHECK(false == armnn::stringUtils::StringToBool("fAlSe")); 270 271 // Same negative test cases with throw_on_error set to false. 272 CHECK(false == armnn::stringUtils::StringToBool("2", false)); 273 CHECK(false == armnn::stringUtils::StringToBool("23456567", false)); 274 CHECK(false == armnn::stringUtils::StringToBool("-23456567", false)); 275 CHECK(false == armnn::stringUtils::StringToBool("Not a number", false)); 276 CHECK(false == armnn::stringUtils::StringToBool("", false)); 277 } 278 } 279