mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	Added custom implementation of strtod() (issue #453)
				
					
				
			This commit is contained in:
		
							
								
								
									
										2
									
								
								.github/ISSUE_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/ISSUE_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							| @@ -3,7 +3,7 @@ Thanks for using ArduinoJson :-) | ||||
|  | ||||
| Before opening an issue, please make sure you've read these: | ||||
| https://bblanchon.github.io/ArduinoJson/faq/ | ||||
| https://github.com/bblanchon/ArduinoJson/wiki/Avoiding-pitfalls | ||||
| https://bblanchon.github.io/ArduinoJson/doc/pitfalls/ | ||||
|  | ||||
| Next, make sure you provide all the relevant information: platform, code snippet, and error messages. | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,11 @@ | ||||
| ArduinoJson: change log | ||||
| ======================= | ||||
|  | ||||
| HEAD | ||||
| ---- | ||||
|  | ||||
| * Added custom implementation of `strtod()` (issue #453) | ||||
|  | ||||
| v5.8.3 | ||||
| ------ | ||||
|  | ||||
|   | ||||
| @@ -7,7 +7,7 @@ all: \ | ||||
| 	$(OUT)/json_fuzzer_seed_corpus.zip \ | ||||
| 	$(OUT)/json_fuzzer.options | ||||
|  | ||||
| $(OUT)/json_fuzzer: fuzzer.cpp | ||||
| $(OUT)/json_fuzzer: fuzzer.cpp $(shell find ../include -type f) | ||||
| 	$(CXX) $(CXXFLAGS) $< -o$@ $(LIB_FUZZING_ENGINE) | ||||
|  | ||||
| $(OUT)/json_fuzzer_seed_corpus.zip: seed_corpus/* | ||||
|   | ||||
| @@ -14,5 +14,11 @@ | ||||
|   12.34e+56, | ||||
|   12.34E56, | ||||
|   12.34E-56, | ||||
|   12.34E+56 | ||||
|   12.34E+56, | ||||
|   NaN, | ||||
|   -NaN, | ||||
|   +NaN, | ||||
|   Infinity, | ||||
|   +Infinity, | ||||
|   -Infinity | ||||
| ] | ||||
| @@ -1,66 +0,0 @@ | ||||
| // Copyright Benoit Blanchon 2014-2017 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
| // If you like this project, please add a star! | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <stdlib.h> | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
| template <typename TFloat> | ||||
| TFloat parse(const char *); | ||||
|  | ||||
| template <> | ||||
| inline float parse<float>(const char *s) { | ||||
|   return static_cast<float>(strtod(s, NULL)); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| inline double parse<double>(const char *s) { | ||||
|   return strtod(s, NULL); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| inline long parse<long>(const char *s) { | ||||
|   return strtol(s, NULL, 10); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| inline unsigned long parse<unsigned long>(const char *s) { | ||||
|   return strtoul(s, NULL, 10); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| inline int parse<int>(const char *s) { | ||||
|   return atoi(s); | ||||
| } | ||||
|  | ||||
| #if ARDUINOJSON_USE_LONG_LONG | ||||
| template <> | ||||
| inline long long parse<long long>(const char *s) { | ||||
|   return strtoll(s, NULL, 10); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| inline unsigned long long parse<unsigned long long>(const char *s) { | ||||
|   return strtoull(s, NULL, 10); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #if ARDUINOJSON_USE_INT64 | ||||
| template <> | ||||
| inline __int64 parse<__int64>(const char *s) { | ||||
|   return _strtoi64(s, NULL, 10); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| inline unsigned __int64 parse<unsigned __int64>(const char *s) { | ||||
|   return _strtoui64(s, NULL, 10); | ||||
| } | ||||
| #endif | ||||
| } | ||||
| } | ||||
| @@ -8,10 +8,12 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "Configuration.hpp" | ||||
| #include "Data/Parse.hpp" | ||||
| #include "JsonArray.hpp" | ||||
| #include "JsonObject.hpp" | ||||
| #include "JsonVariant.hpp" | ||||
| #include "Polyfills/isFloat.hpp" | ||||
| #include "Polyfills/parseFloat.hpp" | ||||
| #include "Polyfills/parseInteger.hpp" | ||||
|  | ||||
| #include <errno.h>   // for errno | ||||
| #include <stdlib.h>  // for strtol, strtod | ||||
| @@ -56,14 +58,14 @@ inline Internals::JsonInteger JsonVariant::variantAsInteger() const { | ||||
|     case JSON_BOOLEAN: | ||||
|       return _content.asInteger; | ||||
|     case JSON_NEGATIVE_INTEGER: | ||||
|       return -static_cast<Internals::JsonInteger>(_content.asInteger); | ||||
|       return -static_cast<JsonInteger>(_content.asInteger); | ||||
|     case JSON_STRING: | ||||
|     case JSON_UNPARSED: | ||||
|       if (!_content.asString) return 0; | ||||
|       if (!strcmp("true", _content.asString)) return 1; | ||||
|       return parse<Internals::JsonInteger>(_content.asString); | ||||
|       return Polyfills::parseInteger<JsonInteger>(_content.asString); | ||||
|     default: | ||||
|       return static_cast<Internals::JsonInteger>(_content.asFloat); | ||||
|       return static_cast<JsonInteger>(_content.asFloat); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -80,9 +82,9 @@ inline Internals::JsonUInt JsonVariant::asUnsignedInteger() const { | ||||
|     case JSON_UNPARSED: | ||||
|       if (!_content.asString) return 0; | ||||
|       if (!strcmp("true", _content.asString)) return 1; | ||||
|       return parse<Internals::JsonUInt>(_content.asString); | ||||
|       return Polyfills::parseInteger<JsonUInt>(_content.asString); | ||||
|     default: | ||||
|       return static_cast<Internals::JsonUInt>(_content.asFloat); | ||||
|       return static_cast<JsonUInt>(_content.asFloat); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -107,7 +109,9 @@ inline Internals::JsonFloat JsonVariant::variantAsFloat() const { | ||||
|       return -static_cast<JsonFloat>(_content.asInteger); | ||||
|     case JSON_STRING: | ||||
|     case JSON_UNPARSED: | ||||
|       return _content.asString ? parse<JsonFloat>(_content.asString) : 0; | ||||
|       return _content.asString | ||||
|                  ? Polyfills::parseFloat<JsonFloat>(_content.asString) | ||||
|                  : 0; | ||||
|     default: | ||||
|       return _content.asFloat; | ||||
|   } | ||||
| @@ -143,11 +147,7 @@ inline bool JsonVariant::isFloat() const { | ||||
|  | ||||
|   if (_type != JSON_UNPARSED || _content.asString == NULL) return false; | ||||
|  | ||||
|   char *end; | ||||
|   errno = 0; | ||||
|   strtod(_content.asString, &end); | ||||
|  | ||||
|   return *end == '\0' && errno == 0 && !is<long>(); | ||||
|   return Polyfills::isFloat(_content.asString); | ||||
| } | ||||
|  | ||||
| #if ARDUINOJSON_ENABLE_STD_STREAM | ||||
|   | ||||
							
								
								
									
										21
									
								
								include/ArduinoJson/Polyfills/ctype.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								include/ArduinoJson/Polyfills/ctype.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| // Copyright Benoit Blanchon 2014-2017 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
| // If you like this project, please add a star! | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Polyfills { | ||||
|  | ||||
| inline bool isdigit(char c) { | ||||
|   return '0' <= c && c <= '9'; | ||||
| } | ||||
|  | ||||
| inline bool issign(char c) { | ||||
|   return '-' == c || c == '+'; | ||||
| } | ||||
| } | ||||
| } | ||||
							
								
								
									
										40
									
								
								include/ArduinoJson/Polyfills/isFloat.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								include/ArduinoJson/Polyfills/isFloat.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| // Copyright Benoit Blanchon 2014-2017 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
| // If you like this project, please add a star! | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "./ctype.hpp" | ||||
| #include "./math.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Polyfills { | ||||
|  | ||||
| inline bool isFloat(const char* s) { | ||||
|   if (!strcmp(s, "NaN")) return true; | ||||
|   if (issign(*s)) s++; | ||||
|   if (!strcmp(s, "Infinity")) return true; | ||||
|  | ||||
|   while (isdigit(*s)) s++; | ||||
|  | ||||
|   bool has_dot = *s == '.'; | ||||
|   if (has_dot) { | ||||
|     s++; | ||||
|     while (isdigit(*s)) s++; | ||||
|   } | ||||
|  | ||||
|   bool has_exponent = *s == 'e' || *s == 'E'; | ||||
|   if (has_exponent) { | ||||
|     s++; | ||||
|     if (issign(*s)) s++; | ||||
|     if (!isdigit(*s)) return false; | ||||
|     while (isdigit(*s)) s++; | ||||
|   } | ||||
|  | ||||
|   return (has_dot || has_exponent) && *s == '\0'; | ||||
| } | ||||
| } | ||||
| } | ||||
| @@ -7,10 +7,11 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| // If Visual Studo <= 2012 | ||||
| #if defined(_MSC_VER) && _MSC_VER <= 1700 | ||||
| // If Visual Studo | ||||
| #if defined(_MSC_VER) | ||||
|  | ||||
| #include <float.h> | ||||
| #include <limits> | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Polyfills { | ||||
| @@ -23,6 +24,16 @@ template <typename T> | ||||
| bool isInfinity(T x) { | ||||
|   return !_finite(x); | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| T nan() { | ||||
|   return std::numeric_limits<T>::quiet_NaN(); | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| T inf() { | ||||
|   return std::numeric_limits<T>::infinity(); | ||||
| } | ||||
| } | ||||
| } | ||||
|  | ||||
| @@ -101,6 +112,16 @@ inline bool isInfinity<float>(float x) { | ||||
| } | ||||
| #endif | ||||
|  | ||||
| template <typename T> | ||||
| T nan() { | ||||
|   return static_cast<T>(NAN); | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| T inf() { | ||||
|   return static_cast<T>(INFINITY); | ||||
| } | ||||
|  | ||||
| #if defined(__GNUC__) | ||||
| #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) | ||||
| #pragma GCC diagnostic pop | ||||
|   | ||||
							
								
								
									
										87
									
								
								include/ArduinoJson/Polyfills/parseFloat.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								include/ArduinoJson/Polyfills/parseFloat.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| // Copyright Benoit Blanchon 2014-2017 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
| // If you like this project, please add a star! | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../TypeTraits/FloatTraits.hpp" | ||||
| #include "./ctype.hpp" | ||||
| #include "./math.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Polyfills { | ||||
|  | ||||
| template <typename T> | ||||
| inline T parseFloat(const char* s) { | ||||
|   typedef TypeTraits::FloatTraits<T> traits; | ||||
|   typedef typename traits::mantissa_type mantissa_t; | ||||
|   typedef typename traits::exponent_type exponent_t; | ||||
|  | ||||
|   bool negative_result = false; | ||||
|   switch (*s) { | ||||
|     case '-': | ||||
|       negative_result = true; | ||||
|     case '+': | ||||
|       s++; | ||||
|   } | ||||
|  | ||||
|   if (*s == 'n' || *s == 'N') return traits::nan(); | ||||
|   if (*s == 'i' || *s == 'I') | ||||
|     return negative_result ? -traits::inf() : traits::inf(); | ||||
|  | ||||
|   mantissa_t mantissa = 0; | ||||
|   exponent_t exponent_offset = 0; | ||||
|  | ||||
|   while (isdigit(*s)) { | ||||
|     if (mantissa < traits::mantissa_max / 10) | ||||
|       mantissa = mantissa * 10 + (*s - '0'); | ||||
|     else | ||||
|       exponent_offset++; | ||||
|     s++; | ||||
|   } | ||||
|  | ||||
|   if (*s == '.') { | ||||
|     s++; | ||||
|     while (isdigit(*s)) { | ||||
|       if (mantissa < traits::mantissa_max / 10) { | ||||
|         mantissa = mantissa * 10 + (*s - '0'); | ||||
|         exponent_offset--; | ||||
|       } | ||||
|       s++; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   int exponent = 0; | ||||
|   if (*s == 'e' || *s == 'E') { | ||||
|     s++; | ||||
|     bool negative_exponent = false; | ||||
|     if (*s == '-') { | ||||
|       negative_exponent = true; | ||||
|       s++; | ||||
|     } else if (*s == '+') { | ||||
|       s++; | ||||
|     } | ||||
|  | ||||
|     while (isdigit(*s)) { | ||||
|       exponent = exponent * 10 + (*s - '0'); | ||||
|       if (exponent + exponent_offset > traits::exponent_max) { | ||||
|         if (negative_exponent) | ||||
|           return negative_result ? -0.0f : 0.0f; | ||||
|         else | ||||
|           return negative_result ? -traits::inf() : traits::inf(); | ||||
|       } | ||||
|       s++; | ||||
|     } | ||||
|     if (negative_exponent) exponent = -exponent; | ||||
|   } | ||||
|   exponent += exponent_offset; | ||||
|  | ||||
|   T result = traits::make_float(static_cast<T>(mantissa), exponent); | ||||
|  | ||||
|   return negative_result ? -result : result; | ||||
| } | ||||
| } | ||||
| } | ||||
							
								
								
									
										56
									
								
								include/ArduinoJson/Polyfills/parseInteger.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								include/ArduinoJson/Polyfills/parseInteger.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| // Copyright Benoit Blanchon 2014-2017 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
| // If you like this project, please add a star! | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <stdlib.h> | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Polyfills { | ||||
| template <typename T> | ||||
| T parseInteger(const char *s); | ||||
|  | ||||
| template <> | ||||
| inline long parseInteger<long>(const char *s) { | ||||
|   return ::strtol(s, NULL, 10); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| inline unsigned long parseInteger<unsigned long>(const char *s) { | ||||
|   return ::strtoul(s, NULL, 10); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| inline int parseInteger<int>(const char *s) { | ||||
|   return ::atoi(s); | ||||
| } | ||||
|  | ||||
| #if ARDUINOJSON_USE_LONG_LONG | ||||
| template <> | ||||
| inline long long parseInteger<long long>(const char *s) { | ||||
|   return ::strtoll(s, NULL, 10); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| inline unsigned long long parseInteger<unsigned long long>(const char *s) { | ||||
|   return ::strtoull(s, NULL, 10); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #if ARDUINOJSON_USE_INT64 | ||||
| template <> | ||||
| inline __int64 parseInteger<__int64>(const char *s) { | ||||
|   return ::_strtoi64(s, NULL, 10); | ||||
| } | ||||
|  | ||||
| template <> | ||||
| inline unsigned __int64 parseInteger<unsigned __int64>(const char *s) { | ||||
|   return ::_strtoui64(s, NULL, 10); | ||||
| } | ||||
| #endif | ||||
| } | ||||
| } | ||||
							
								
								
									
										83
									
								
								include/ArduinoJson/TypeTraits/FloatTraits.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								include/ArduinoJson/TypeTraits/FloatTraits.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| // Copyright Benoit Blanchon 2014-2017 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
| // If you like this project, please add a star! | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <stdint.h> | ||||
| #include "../Polyfills/math.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace TypeTraits { | ||||
|  | ||||
| template <typename T, size_t = sizeof(T)> | ||||
| struct FloatTraits {}; | ||||
|  | ||||
| #ifndef ARDUINO_ARCH_AVR  // double is 32 bits, so 1e64 gives a warning | ||||
| template <typename T> | ||||
| struct FloatTraits<T, 8 /*64bits*/> { | ||||
|   typedef int64_t mantissa_type; | ||||
|   static const short mantissa_bits = 52; | ||||
|   static const mantissa_type mantissa_max = | ||||
|       (static_cast<mantissa_type>(1) << mantissa_bits) - 1; | ||||
|  | ||||
|   typedef int16_t exponent_type; | ||||
|   static const exponent_type exponent_max = 308; | ||||
|  | ||||
|   template <typename TExponent> | ||||
|   static T make_float(T m, TExponent e) { | ||||
|     if (e >= 0) | ||||
|       return m * (e & 1 ? 1e1 : 1) * (e & 2 ? 1e2 : 1) * (e & 4 ? 1e4 : 1) * | ||||
|              (e & 8 ? 1e8 : 1) * (e & 16 ? 1e16 : 1) * (e & 32 ? 1e32 : 1) * | ||||
|              (e & 64 ? 1e64 : 1) * (e & 128 ? 1e128 : 1) * | ||||
|              (e & 256 ? 1e256 : 1); | ||||
|     e = -e; | ||||
|     return m * (e & 1 ? 1e-1 : 1) * (e & 2 ? 1e-2 : 1) * (e & 4 ? 1e-4 : 1) * | ||||
|            (e & 8 ? 1e-8 : 1) * (e & 16 ? 1e-16 : 1) * (e & 32 ? 1e-32 : 1) * | ||||
|            (e & 64 ? 1e-64 : 1) * (e & 128 ? 1e-128 : 1) * | ||||
|            (e & 256 ? 1e-256 : 1); | ||||
|   } | ||||
|  | ||||
|   static T nan() { | ||||
|     return Polyfills::nan<T>(); | ||||
|   } | ||||
|  | ||||
|   static T inf() { | ||||
|     return Polyfills::inf<T>(); | ||||
|   } | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| template <typename T> | ||||
| struct FloatTraits<T, 4 /*32bits*/> { | ||||
|   typedef int32_t mantissa_type; | ||||
|   static const short mantissa_bits = 23; | ||||
|   static const mantissa_type mantissa_max = | ||||
|       (static_cast<mantissa_type>(1) << mantissa_bits) - 1; | ||||
|  | ||||
|   typedef int8_t exponent_type; | ||||
|   static const exponent_type exponent_max = 38; | ||||
|  | ||||
|   template <typename TExponent> | ||||
|   static T make_float(T m, TExponent e) { | ||||
|     if (e > 0) | ||||
|       return m * (e & 1 ? 1e1f : 1) * (e & 2 ? 1e2f : 1) * (e & 4 ? 1e4f : 1) * | ||||
|              (e & 8 ? 1e8f : 1) * (e & 16 ? 1e16f : 1) * (e & 32 ? 1e32f : 1); | ||||
|     e = -e; | ||||
|     return m * (e & 1 ? 1e-1f : 1) * (e & 2 ? 1e-2f : 1) * (e & 4 ? 1e-4f : 1) * | ||||
|            (e & 8 ? 1e-8f : 1) * (e & 16 ? 1e-16f : 1) * (e & 32 ? 1e-32f : 1); | ||||
|   } | ||||
|  | ||||
|   static T nan() { | ||||
|     return Polyfills::nan<T>(); | ||||
|   } | ||||
|  | ||||
|   static T inf() { | ||||
|     return Polyfills::inf<T>(); | ||||
|   } | ||||
| }; | ||||
| } | ||||
| } | ||||
							
								
								
									
										1
									
								
								scripts/oss-fuzz/Vagrantfile
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								scripts/oss-fuzz/Vagrantfile
									
									
									
									
										vendored
									
									
								
							| @@ -26,6 +26,7 @@ Vagrant.configure(2) do |config| | ||||
|     echo "export PROJECT_NAME='arduinojson'" >> $HOME/.profile | ||||
|     echo "export CC='clang'" >> $HOME/.profile | ||||
|     echo "export CXX='clang++'" >> $HOME/.profile | ||||
|     echo "export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/" >> $HOME/.profile | ||||
|  | ||||
|     echo "Run /host/ArduinoJson/fuzzing/fuzz.sh" | sudo tee /etc/motd | ||||
|   SHELL | ||||
|   | ||||
							
								
								
									
										81
									
								
								test/Polyfills_IsFloat_Tests.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								test/Polyfills_IsFloat_Tests.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | ||||
| // Copyright Benoit Blanchon 2014-2017 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
| // If you like this project, please add a star! | ||||
|  | ||||
| #include <gtest/gtest.h> | ||||
| #include <ArduinoJson/Polyfills/isFloat.hpp> | ||||
|  | ||||
| using namespace ArduinoJson::Polyfills; | ||||
|  | ||||
| struct Polyfills_IsFloat_Tests : testing::Test { | ||||
|   void check(bool expected, const char* input) { | ||||
|     bool actual = isFloat(input); | ||||
|     EXPECT_EQ(expected, actual) << input; | ||||
|   } | ||||
| }; | ||||
| #define TEST_(X) TEST_F(Polyfills_IsFloat_Tests, X) | ||||
|  | ||||
| TEST_(NoExponent) { | ||||
|   check(true, "3.14"); | ||||
|   check(true, "-3.14"); | ||||
|   check(true, "+3.14"); | ||||
| } | ||||
|  | ||||
| TEST_(IntegralPartMissing) { | ||||
|   check(true, ".14"); | ||||
|   check(true, "-.14"); | ||||
|   check(true, "+.14"); | ||||
| } | ||||
|  | ||||
| TEST_(FractionalPartMissing) { | ||||
|   check(true, "3."); | ||||
|   check(true, "-3.e14"); | ||||
|   check(true, "+3.e-14"); | ||||
| } | ||||
|  | ||||
| TEST_(NoDot) { | ||||
|   check(true, "3e14"); | ||||
|   check(true, "3e-14"); | ||||
|   check(true, "3e+14"); | ||||
| } | ||||
|  | ||||
| TEST_(Integer) { | ||||
|   check(false, "14"); | ||||
|   check(false, "-14"); | ||||
|   check(false, "+14"); | ||||
| } | ||||
|  | ||||
| TEST_(ExponentMissing) { | ||||
|   check(false, "3.14e"); | ||||
|   check(false, "3.14e-"); | ||||
|   check(false, "3.14e+"); | ||||
| } | ||||
|  | ||||
| TEST_(JustASign) { | ||||
|   check(false, "-"); | ||||
|   check(false, "+"); | ||||
| } | ||||
|  | ||||
| TEST_(Empty) { | ||||
|   check(false, ""); | ||||
| } | ||||
|  | ||||
| TEST_(NaN) { | ||||
|   check(true, "NaN"); | ||||
|   check(false, "n"); | ||||
|   check(false, "N"); | ||||
|   check(false, "nan"); | ||||
|   check(false, "-NaN"); | ||||
|   check(false, "+NaN"); | ||||
| } | ||||
|  | ||||
| TEST_(Infinity) { | ||||
|   check(true, "Infinity"); | ||||
|   check(true, "+Infinity"); | ||||
|   check(true, "-Infinity"); | ||||
|   check(false, "infinity"); | ||||
|   check(false, "Inf"); | ||||
| } | ||||
							
								
								
									
										175
									
								
								test/Polyfills_ParseFloat_Tests.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								test/Polyfills_ParseFloat_Tests.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,175 @@ | ||||
| // Copyright Benoit Blanchon 2014-2017 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
| // If you like this project, please add a star! | ||||
|  | ||||
| #include <gtest/gtest.h> | ||||
| #include <ArduinoJson/Polyfills/parseFloat.hpp> | ||||
|  | ||||
| using namespace ArduinoJson::Polyfills; | ||||
|  | ||||
| struct Polyfills_ParseFloat_Float_Tests : testing::Test { | ||||
|   void check(const char* input, float expected) { | ||||
|     float actual = parseFloat<float>(input); | ||||
|     EXPECT_FLOAT_EQ(expected, actual) << input; | ||||
|   } | ||||
|  | ||||
|   void checkNaN(const char* input) { | ||||
|     float result = parseFloat<float>(input); | ||||
|     EXPECT_TRUE(result != result) << input; | ||||
|   } | ||||
|  | ||||
|   void checkInf(const char* input, bool negative) { | ||||
|     float x = parseFloat<float>(input); | ||||
|     if (negative) | ||||
|       EXPECT_TRUE(x < 0) << input; | ||||
|     else | ||||
|       EXPECT_TRUE(x > 0) << input; | ||||
|     EXPECT_TRUE(x == x && x * 2 == x) << input; | ||||
|   } | ||||
| }; | ||||
| #define TEST_FLOAT(X) TEST_F(Polyfills_ParseFloat_Float_Tests, X) | ||||
|  | ||||
| struct Polyfills_ParseFloat_Double_Tests : testing::Test { | ||||
|   void check(const char* input, double expected) { | ||||
|     double actual = parseFloat<double>(input); | ||||
|     EXPECT_DOUBLE_EQ(expected, actual) << input; | ||||
|   } | ||||
|  | ||||
|   void checkNaN(const char* input) { | ||||
|     double result = parseFloat<double>(input); | ||||
|     EXPECT_TRUE(result != result) << input; | ||||
|   } | ||||
|  | ||||
|   void checkInf(const char* input, bool negative) { | ||||
|     double x = parseFloat<double>(input); | ||||
|     if (negative) | ||||
|       EXPECT_TRUE(x < 0) << input; | ||||
|     else | ||||
|       EXPECT_TRUE(x > 0) << input; | ||||
|     EXPECT_TRUE(x == x && x * 2 == x) << input; | ||||
|   } | ||||
| }; | ||||
| #define TEST_DOUBLE(X) TEST_F(Polyfills_ParseFloat_Double_Tests, X) | ||||
|  | ||||
| TEST_DOUBLE(Short_NoExponent) { | ||||
|   check("3.14", 3.14); | ||||
|   check("-3.14", -3.14); | ||||
|   check("+3.14", +3.14); | ||||
| } | ||||
|  | ||||
| TEST_FLOAT(Float_Short_NoExponent) { | ||||
|   check("3.14", 3.14f); | ||||
|   check("-3.14", -3.14f); | ||||
|   check("+3.14", +3.14f); | ||||
| } | ||||
|  | ||||
| TEST_DOUBLE(Short_NoDot) { | ||||
|   check("1E+308", 1E+308); | ||||
|   check("-1E+308", -1E+308); | ||||
|   check("+1E-308", +1E-308); | ||||
|   check("+1e+308", +1e+308); | ||||
|   check("-1e-308", -1e-308); | ||||
| } | ||||
|  | ||||
| TEST_FLOAT(Short_NoDot) { | ||||
|   check("1E+38", 1E+38f); | ||||
|   check("-1E+38", -1E+38f); | ||||
|   check("+1E-38", +1E-38f); | ||||
|   check("+1e+38", +1e+38f); | ||||
|   check("-1e-38", -1e-38f); | ||||
| } | ||||
|  | ||||
| TEST_FLOAT(Max) { | ||||
|   check("340.2823e+36", 3.402823e+38f); | ||||
|   check("34.02823e+37", 3.402823e+38f); | ||||
|   check("3.402823e+38", 3.402823e+38f); | ||||
|   check("0.3402823e+39", 3.402823e+38f); | ||||
|   check("00.3402823e+40", 3.402823e+38f); | ||||
|   check("000.3402823e+41", 3.402823e+38f); | ||||
| } | ||||
|  | ||||
| TEST_DOUBLE(Max) { | ||||
|   check(".017976931348623147e+310", 1.7976931348623147e+308); | ||||
|   check(".17976931348623147e+309", 1.7976931348623147e+308); | ||||
|   check("1.7976931348623147e+308", 1.7976931348623147e+308); | ||||
|   check("17.976931348623147e+307", 1.7976931348623147e+308); | ||||
|   check("179.76931348623147e+306", 1.7976931348623147e+308); | ||||
| } | ||||
|  | ||||
| TEST_DOUBLE(Min) { | ||||
|   check(".022250738585072014e-306", 2.2250738585072014e-308); | ||||
|   check(".22250738585072014e-307", 2.2250738585072014e-308); | ||||
|   check("2.2250738585072014e-308", 2.2250738585072014e-308); | ||||
|   check("22.250738585072014e-309", 2.2250738585072014e-308); | ||||
|   check("222.50738585072014e-310", 2.2250738585072014e-308); | ||||
| } | ||||
|  | ||||
| TEST_DOUBLE(VeryLong) { | ||||
|   check("0.00000000000000000000000000000001", 1e-32); | ||||
|   check("100000000000000000000000000000000.0", 1e+32); | ||||
|   check("100000000000000000000000000000000.00000000000000000000000000000", | ||||
|         1e+32); | ||||
| } | ||||
|  | ||||
| TEST_FLOAT(VeryLong) { | ||||
|   check("0.00000000000000000000000000000001", 1e-32f); | ||||
|   check("100000000000000000000000000000000.0", 1e+32f); | ||||
|   check("100000000000000000000000000000000.00000000000000000000000000000", | ||||
|         1e+32f); | ||||
| } | ||||
|  | ||||
| TEST_DOUBLE(MantissaTooLongToFit) { | ||||
|   check("0.179769313486231571111111111111", 0.17976931348623157); | ||||
|   check("17976931348623157.11111111111111", 17976931348623157.0); | ||||
|   check("1797693.134862315711111111111111", 1797693.1348623157); | ||||
|  | ||||
|   check("-0.179769313486231571111111111111", -0.17976931348623157); | ||||
|   check("-17976931348623157.11111111111111", -17976931348623157.0); | ||||
|   check("-1797693.134862315711111111111111", -1797693.1348623157); | ||||
| } | ||||
|  | ||||
| TEST_FLOAT(MantissaTooLongToFit) { | ||||
|   check("0.340282346638528861111111111111", 0.34028234663852886f); | ||||
|   check("34028234663852886.11111111111111", 34028234663852886.0f); | ||||
|   check("34028234.66385288611111111111111", 34028234.663852886f); | ||||
|  | ||||
|   check("-0.340282346638528861111111111111", -0.34028234663852886f); | ||||
|   check("-34028234663852886.11111111111111", -34028234663852886.0f); | ||||
|   check("-34028234.66385288611111111111111", -34028234.663852886f); | ||||
| } | ||||
|  | ||||
| TEST_DOUBLE(ExponentTooBig) { | ||||
|   checkInf("1e309", false); | ||||
|   checkInf("-1e309", true); | ||||
|   checkInf("1e65535", false); | ||||
|   check("1e-65535", 0.0); | ||||
| } | ||||
|  | ||||
| TEST_FLOAT(ExponentTooBig) { | ||||
|   checkInf("1e39", false); | ||||
|   checkInf("-1e39", true); | ||||
|   checkInf("1e255", false); | ||||
|   check("1e-255", 0.0f); | ||||
| } | ||||
|  | ||||
| TEST_DOUBLE(NaN) { | ||||
|   checkNaN("NaN"); | ||||
|   checkNaN("nan"); | ||||
| } | ||||
|  | ||||
| TEST_FLOAT(NaN) { | ||||
|   checkNaN("NaN"); | ||||
|   checkNaN("nan"); | ||||
| } | ||||
|  | ||||
| TEST_FLOAT(Infinity) { | ||||
|   checkInf("Infinity", false); | ||||
|   checkInf("+Infinity", false); | ||||
|   checkInf("-Infinity", true); | ||||
|   checkInf("inf", false); | ||||
|   checkInf("+inf", false); | ||||
|   checkInf("-inf", true); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user