aboutsummaryrefslogtreecommitdiff
path: root/Client/ThirdParty/fpm/tests/input.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Client/ThirdParty/fpm/tests/input.cpp')
-rw-r--r--Client/ThirdParty/fpm/tests/input.cpp312
1 files changed, 312 insertions, 0 deletions
diff --git a/Client/ThirdParty/fpm/tests/input.cpp b/Client/ThirdParty/fpm/tests/input.cpp
new file mode 100644
index 0000000..16445db
--- /dev/null
+++ b/Client/ThirdParty/fpm/tests/input.cpp
@@ -0,0 +1,312 @@
+#include "common.hpp"
+#include <fpm/ios.hpp>
+#include <sstream>
+
+using ::testing::Combine;
+using ::testing::Values;
+
+namespace
+{
+ class fake_numpunct : public std::numpunct<char>
+ {
+ public:
+ fake_numpunct(char decimal_point, char thousands_sep, std::string grouping)
+ : m_decimal_point(decimal_point)
+ , m_thousands_sep(thousands_sep)
+ , m_grouping(grouping)
+ {}
+
+ protected:
+ char do_decimal_point() const override { return m_decimal_point; }
+ char do_thousands_sep() const override { return m_thousands_sep; }
+ std::string do_grouping() const override { return m_grouping; }
+ std::string do_truename() const override { return "unused"; }
+ std::string do_falsename() const override { return "unused"; }
+
+ private:
+ char m_decimal_point;
+ char m_thousands_sep;
+ std::string m_grouping;
+ };
+
+ class input : public ::testing::Test
+ {
+ protected:
+ input() : m_locale("C")
+ {
+ }
+
+ void setlocale(std::locale locale)
+ {
+ m_locale = locale;
+ }
+
+ template <typename B, typename I, unsigned int F>
+ void test_conversion(const std::string& text, fpm::fixed<B, I, F> expected, const std::string& expected_remaining = "")
+ {
+ std::istringstream ss(text);
+ ss.imbue(m_locale);
+
+ fpm::fixed<B, I, F> value;
+ ss >> value;
+
+ // Values should match
+ EXPECT_EQ(value, expected) << "for text: \"" << text << "\"";
+ EXPECT_TRUE(ss);
+
+ EXPECT_EQ(get_remainder(ss), expected_remaining) << "for text: \"" << text << "\"";
+ }
+
+ void test_invalid_conversion(const std::string& text, const std::string& expected_remaining = "")
+ {
+ std::istringstream ss(text);
+ ss.imbue(m_locale);
+
+ fpm::fixed_16_16 value;
+ ss >> value;
+
+ // Stream should have a parse error
+ EXPECT_TRUE(ss.fail()) << "for text: \"" << text << "\"";;
+ EXPECT_FALSE(ss.bad()) << "for text: \"" << text << "\"";;
+ EXPECT_FALSE(ss.good()) << "for text: \"" << text << "\"";;
+
+ EXPECT_EQ(get_remainder(ss), expected_remaining) << "for text: \"" << text << "\"";
+ }
+
+ private:
+ static std::string get_remainder(std::istream& is)
+ {
+ std::string remaining;
+ is.clear();
+ is >> std::noskipws >> remaining;
+ return remaining;
+ }
+
+ std::locale m_locale;
+ };
+}
+
+TEST_F(input, integers)
+{
+ using P = fpm::fixed_16_16;
+ test_conversion("0", P(0));
+ test_conversion("+0", P(0));
+ test_conversion("-0", P(0));
+
+ test_conversion("1", P(1));
+ test_conversion("+1", P(1));
+ test_conversion("-1", P(-1));
+
+ test_conversion("12795", P(12795));
+ test_conversion("+12795", P(12795));
+ test_conversion("-12795", P(-12795));
+}
+
+TEST_F(input, fixed_notation)
+{
+ using P = fpm::fixed_16_16;
+ test_conversion("0.0", P(0));
+ test_conversion("+0.0", P(0));
+ test_conversion("-0.0", P(0));
+
+ test_conversion("0.5", P(0.5));
+ test_conversion("+0.5", P(0.5));
+ test_conversion("-0.5", P(-0.5));
+
+ test_conversion(".5", P(0.5));
+ test_conversion("+.5", P(0.5));
+ test_conversion("-.5", P(-0.5));
+
+ test_conversion("3.", P(3));
+ test_conversion("+3.", P(3));
+ test_conversion("-3.", P(-3));
+
+ test_conversion("1467.0125", P(1467.0125));
+ test_conversion("+1467.0125", P(1467.0125));
+ test_conversion("-1467.0125", P(-1467.0125));
+}
+
+TEST_F(input, scientific_notation)
+{
+ using P = fpm::fixed_16_16;
+ test_conversion("0.e0", P(0));
+ test_conversion("+0.e0", P(0));
+ test_conversion("-0.e0", P(0));
+
+ test_conversion(".5e1", P(5));
+ test_conversion("+.5e1", P(5));
+ test_conversion("-.5e1", P(-5));
+
+ test_conversion("1.125e2", P(112.5));
+ test_conversion("+1.125e2", P(112.5));
+ test_conversion("-1.125e2", P(-112.5));
+
+ test_conversion("1.125E+2", P(112.5));
+ test_conversion("+1.125E+2", P(112.5));
+ test_conversion("-1.125E+2", P(-112.5));
+
+ test_conversion("9.765625e-4", P(0.0009765625));
+ test_conversion("-9.765625e-4", P(-0.0009765625));
+}
+
+TEST_F(input, hexfloat_notation)
+{
+ using P = fpm::fixed_16_16;
+ test_conversion("0x0", P(0));
+ test_conversion("+0x0", P(0));
+ test_conversion("-0x0", P(0));
+
+ test_conversion("0x1a", P(26));
+ test_conversion("+0x1a", P(26));
+ test_conversion("-0x1a", P(-26));
+
+ test_conversion("0xbcdP3", P(24168));
+ test_conversion("+0xbcdP3", P(24168));
+ test_conversion("-0xbcdP3", P(-24168));
+
+ test_conversion("0x1.bcdP-3", P(0.217193603515625));
+ test_conversion("+0x1.bcdP-3", P(0.217193603515625));
+ test_conversion("-0x1.bcdP-3", P(-0.217193603515625));
+}
+
+TEST_F(input, decimal_point)
+{
+ using P = fpm::fixed_16_16;
+
+ // Multiple decimal points stop parsing after the first one
+ test_conversion("1..5", P(1), ".5");
+
+ // Switch to a fake locale with a specific decimal separator
+ setlocale(std::locale(std::locale(""), new fake_numpunct('\'', ',', "\001\002")));
+ test_conversion("1\'234", P(1.234));
+}
+
+TEST_F(input, thousands_separator)
+{
+ using P = fpm::fixed_16_16;
+
+ // Switch to a fake locale with an english thousands separator
+ setlocale(std::locale(std::locale(""), new fake_numpunct('.', ',', "\003")));
+
+ // Thousands groupings before decimal point are ignored
+ test_conversion("12,345.67", P(12345.67));
+
+ // Thousands groupings after decimal point stop parsing
+ test_conversion("1.234,567", P(1.234), ",567");
+ test_conversion("1.25,56", P(1.25), ",56");
+ test_conversion("1.,125", P(1), ",125");
+
+ // Switch to a fake locale with a specific thousands separator
+ setlocale(std::locale(std::locale(""), new fake_numpunct('.', '\'', "\001\002")));
+ test_conversion("12\'345.67", P(12345.67));
+}
+
+TEST_F(input, fails_on_badbit)
+{
+ using P = fpm::fixed_16_16;
+
+ // operator>> is a FormattedInputFunction which is supposed to set failbit if badbit is set.
+ std::istringstream ss("12345");
+ ss.exceptions(std::ios::failbit);
+ ss.setstate(std::ios::badbit);
+ P x;
+ EXPECT_THROW(ss >> x, std::ios::failure);
+}
+
+TEST_F(input, handles_eof)
+{
+ using P = fpm::fixed_16_16;
+
+ // operator>> is a FormattedInputFunction which is supposed to handle EOF correctly
+ // (in this case, by throwing an exception)
+ std::istringstream ss("1");
+ ss.exceptions(std::ios::eofbit);
+ P x;
+ EXPECT_THROW(ss >> x, std::ios::failure);
+}
+
+TEST_F(input, skips_whitespace)
+{
+ using P = fpm::fixed_16_16;
+ test_conversion(" \t\r\n\v\f 1.125E+2", P(112.5));
+}
+
+TEST_F(input, ignored_remainder)
+{
+ using P = fpm::fixed_16_16;
+
+ // Hexadecimal exponent in decimal number
+ test_conversion("1.5p1", P(1.5), "p1");
+
+ // Hexadecimal char in decimal exponent
+ test_conversion("1e1a", P(10), "a");
+ test_conversion("1e1f", P(10), "f");
+
+ // Hexadecimal char in decimal number
+ test_conversion("1a", P(1), "a");
+ test_conversion("1f", P(1), "f");
+}
+
+TEST_F(input, incorrect_inputs)
+{
+ // Empty sequence
+ test_invalid_conversion("");
+ test_invalid_conversion("u1", "u1");
+
+ // Decimal point by itself
+ test_invalid_conversion(".");
+
+ // Missing exponent value
+ test_invalid_conversion("1e");
+ test_invalid_conversion("1ee1", "e1");
+ test_invalid_conversion("1ea", "a");
+ test_invalid_conversion("1ef", "f");
+ test_invalid_conversion("1e-e1", "e1");
+ test_invalid_conversion("1e--1", "-1");
+ test_invalid_conversion("1e++1", "+1");
+ test_invalid_conversion("1e+-1", "-1");
+ test_invalid_conversion("1e-+1", "+1");
+
+ // Missing significand
+ test_invalid_conversion("--1", "-1");
+ test_invalid_conversion("++1", "+1");
+ test_invalid_conversion("+-1", "-1");
+ test_invalid_conversion("-+1", "+1");
+}
+
+TEST_F(input, overflow)
+{
+ using P = fpm::fixed_16_16;
+
+ test_conversion("1e100", std::numeric_limits<P>::max());
+ test_conversion("-1e100", std::numeric_limits<P>::min());
+
+ test_conversion("100000", std::numeric_limits<P>::max());
+ test_conversion("-100000", std::numeric_limits<P>::min());
+
+ test_conversion("1000000000000000000000000000000000000000000000", std::numeric_limits<P>::max());
+ test_conversion("-1000000000000000000000000000000000000000000000", std::numeric_limits<P>::min());
+}
+
+TEST_F(input, infinity)
+{
+ using P = fpm::fixed_16_16;
+
+ test_conversion("inf", std::numeric_limits<P>::max());
+ test_conversion("infinity", std::numeric_limits<P>::max());
+
+ test_conversion("-inf", std::numeric_limits<P>::min());
+ test_conversion("-infinity", std::numeric_limits<P>::min());
+
+ test_invalid_conversion("infinit", "");
+ test_invalid_conversion("infini", "");
+ test_invalid_conversion("infin", "");
+ test_invalid_conversion("infi", "");
+ test_invalid_conversion("in", "");
+ test_invalid_conversion("i", "");
+
+ test_conversion("infa", std::numeric_limits<P>::max(), "a");
+ test_invalid_conversion("infinix", "x");
+ test_invalid_conversion("ib", "b");
+ test_invalid_conversion("-ic", "c");
+} \ No newline at end of file