1 /* 2 * Copyright (C) 2010 Tommi Maekitalo 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * As a special exception, you may use this file as part of a free 10 * software library without restriction. Specifically, if other files 11 * instantiate templates or use macros or inline functions from this 12 * file, or you compile this file and link it with other files to 13 * produce an executable, this file does not by itself cause the 14 * resulting executable to be covered by the GNU General Public 15 * License. This exception does not however invalidate any other 16 * reasons why the executable file might be covered by the GNU Library 17 * General Public License. 18 * 19 * This library is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 * Lesser General Public License for more details. 23 * 24 * You should have received a copy of the GNU Lesser General Public 25 * License along with this library; if not, write to the Free Software 26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 27 */ 28 29 #include "cxxtools/convert.h" 30 #include "cxxtools/unit/testsuite.h" 31 #include "cxxtools/unit/registertest.h" 32 #include "cxxtools/string.h" 33 #include "cxxtools/log.h" 34 #include <limits> 35 #include <string.h> 36 37 log_define("cxxtools.test.convert") 38 39 namespace 40 { nearBy(double v1,double v2,double e=1e-6)41 bool nearBy(double v1, double v2, double e = 1e-6) 42 { 43 double q = v1 / v2; 44 return q > 1 - e && q < 1 + e; 45 } 46 } 47 48 class ConvertTest : public cxxtools::unit::TestSuite 49 { 50 public: ConvertTest()51 ConvertTest() 52 : cxxtools::unit::TestSuite("convert") 53 { 54 registerMethod("successTest", *this, &ConvertTest::successTest); 55 registerMethod("failTest", *this, &ConvertTest::failTest); 56 registerMethod("nanTest", *this, &ConvertTest::nanTest); 57 registerMethod("infTest", *this, &ConvertTest::infTest); 58 registerMethod("emptyTest", *this, &ConvertTest::emptyTest); 59 registerMethod("floatTest", *this, &ConvertTest::floatTest); 60 } 61 successTest()62 void successTest() 63 { 64 std::string s(" -15 "); 65 int n = 0; 66 CXXTOOLS_UNIT_ASSERT_NOTHROW(n = cxxtools::convert<int>(s)); 67 CXXTOOLS_UNIT_ASSERT_EQUALS(n, -15); 68 69 cxxtools::String S(L" -42 "); 70 CXXTOOLS_UNIT_ASSERT_NOTHROW(n = cxxtools::convert<int>(S)); 71 CXXTOOLS_UNIT_ASSERT_EQUALS(n, -42); 72 73 } 74 failTest()75 void failTest() 76 { 77 std::string s(" -15 a"); 78 CXXTOOLS_UNIT_ASSERT_THROW(cxxtools::convert<int>(s), cxxtools::ConversionError); 79 80 cxxtools::String S(L" -42 a"); 81 CXXTOOLS_UNIT_ASSERT_THROW(cxxtools::convert<int>(S), cxxtools::ConversionError); 82 83 } 84 nanTest()85 void nanTest() 86 { 87 // test string to number 88 89 // test nan 90 91 double d = cxxtools::convert<double>(std::string("NaN")); 92 CXXTOOLS_UNIT_ASSERT(d != d); 93 94 float f = cxxtools::convert<float>(std::string("NaN")); 95 CXXTOOLS_UNIT_ASSERT(f != f); 96 97 d = cxxtools::convert<double>(cxxtools::String(L"NaN")); 98 CXXTOOLS_UNIT_ASSERT(d != d); 99 100 f = cxxtools::convert<float>(cxxtools::String(L"NaN")); 101 CXXTOOLS_UNIT_ASSERT(f != f); 102 103 // test quiet nan 104 105 d = cxxtools::convert<double>(std::string("NaNQ")); 106 CXXTOOLS_UNIT_ASSERT(d != d); 107 108 f = cxxtools::convert<float>(std::string("NaNQ")); 109 CXXTOOLS_UNIT_ASSERT(f != f); 110 111 d = cxxtools::convert<double>(cxxtools::String(L"NaNQ")); 112 CXXTOOLS_UNIT_ASSERT(d != d); 113 114 f = cxxtools::convert<float>(cxxtools::String(L"NaNQ")); 115 CXXTOOLS_UNIT_ASSERT(f != f); 116 117 // test signaling nan 118 119 d = cxxtools::convert<double>(std::string("NaNS")); 120 CXXTOOLS_UNIT_ASSERT(d != d); 121 122 f = cxxtools::convert<float>(std::string("NaNS")); 123 CXXTOOLS_UNIT_ASSERT(f != f); 124 125 d = cxxtools::convert<double>(cxxtools::String(L"NaNS")); 126 CXXTOOLS_UNIT_ASSERT(d != d); 127 128 f = cxxtools::convert<float>(cxxtools::String(L"NaNS")); 129 CXXTOOLS_UNIT_ASSERT(f != f); 130 131 CXXTOOLS_UNIT_ASSERT_THROW(cxxtools::convert<float>(cxxtools::String(L"NaNF")), cxxtools::ConversionError); 132 133 // test number to string 134 135 std::string s = cxxtools::convert<std::string>(d); 136 CXXTOOLS_UNIT_ASSERT_EQUALS(s, "nan"); 137 138 s = cxxtools::convert<std::string>(f); 139 CXXTOOLS_UNIT_ASSERT_EQUALS(s, "nan"); 140 141 cxxtools::String ss = cxxtools::convert<cxxtools::String>(d); 142 CXXTOOLS_UNIT_ASSERT_EQUALS(ss.narrow(), "nan"); 143 144 ss = cxxtools::convert<cxxtools::String>(f); 145 CXXTOOLS_UNIT_ASSERT_EQUALS(ss.narrow(), "nan"); 146 147 } 148 infTest()149 void infTest() 150 { 151 // test string to number 152 153 double d = cxxtools::convert<double>(std::string("inf")); 154 CXXTOOLS_UNIT_ASSERT_EQUALS(d, std::numeric_limits<double>::infinity()); 155 156 d = cxxtools::convert<double>(std::string("infinity")); 157 CXXTOOLS_UNIT_ASSERT_EQUALS(d, std::numeric_limits<double>::infinity()); 158 159 float f = cxxtools::convert<float>(std::string("inf")); 160 CXXTOOLS_UNIT_ASSERT_EQUALS(d, std::numeric_limits<float>::infinity()); 161 162 d = cxxtools::convert<double>(cxxtools::String(L"iNf")); 163 CXXTOOLS_UNIT_ASSERT_EQUALS(d, std::numeric_limits<double>::infinity()); 164 165 f = cxxtools::convert<float>(cxxtools::String(L"inF")); 166 CXXTOOLS_UNIT_ASSERT_EQUALS(d, std::numeric_limits<float>::infinity()); 167 168 // test number to string 169 170 std::string s = cxxtools::convert<std::string>(d); 171 CXXTOOLS_UNIT_ASSERT_EQUALS(s, "inf"); 172 173 s = cxxtools::convert<std::string>(f); 174 CXXTOOLS_UNIT_ASSERT(strcasecmp(s.c_str(), "inf") == 0); 175 176 cxxtools::String ss = cxxtools::convert<cxxtools::String>(d); 177 CXXTOOLS_UNIT_ASSERT(strcasecmp(ss.narrow().c_str(), "inf") == 0); 178 179 ss = cxxtools::convert<cxxtools::String>(f); 180 CXXTOOLS_UNIT_ASSERT(strcasecmp(ss.narrow().c_str(), "inf") == 0); 181 182 // negative inf 183 184 // string to number 185 d = cxxtools::convert<double>(std::string("-inf")); 186 CXXTOOLS_UNIT_ASSERT_EQUALS(d, -std::numeric_limits<double>::infinity()); 187 188 f = cxxtools::convert<float>(std::string("-inf")); 189 CXXTOOLS_UNIT_ASSERT_EQUALS(d, -std::numeric_limits<float>::infinity()); 190 191 d = cxxtools::convert<double>(cxxtools::String(L"-iNf")); 192 CXXTOOLS_UNIT_ASSERT_EQUALS(d, -std::numeric_limits<double>::infinity()); 193 194 f = cxxtools::convert<float>(cxxtools::String(L"-INF")); 195 CXXTOOLS_UNIT_ASSERT_EQUALS(d, -std::numeric_limits<float>::infinity()); 196 197 // test number to string 198 s = cxxtools::convert<std::string>(d); 199 CXXTOOLS_UNIT_ASSERT_EQUALS(s, "-inf"); 200 201 s = cxxtools::convert<std::string>(f); 202 CXXTOOLS_UNIT_ASSERT(strcasecmp(s.c_str(), "-inf") == 0); 203 204 ss = cxxtools::convert<cxxtools::String>(d); 205 CXXTOOLS_UNIT_ASSERT(strcasecmp(ss.narrow().c_str(), "-inf") == 0); 206 207 ss = cxxtools::convert<cxxtools::String>(f); 208 CXXTOOLS_UNIT_ASSERT(strcasecmp(ss.narrow().c_str(), "-inf") == 0); 209 210 } 211 emptyTest()212 void emptyTest() 213 { 214 std::string emptyString; 215 CXXTOOLS_UNIT_ASSERT_THROW(cxxtools::convert<int>(std::string()), cxxtools::ConversionError); 216 CXXTOOLS_UNIT_ASSERT_THROW(cxxtools::convert<int>(cxxtools::String()), cxxtools::ConversionError); 217 CXXTOOLS_UNIT_ASSERT_THROW(cxxtools::convert<unsigned>(std::string()), cxxtools::ConversionError); 218 CXXTOOLS_UNIT_ASSERT_THROW(cxxtools::convert<unsigned>(cxxtools::String()), cxxtools::ConversionError); 219 CXXTOOLS_UNIT_ASSERT_THROW(cxxtools::convert<double>(std::string()), cxxtools::ConversionError); 220 CXXTOOLS_UNIT_ASSERT_THROW(cxxtools::convert<double>(cxxtools::String()), cxxtools::ConversionError); 221 } 222 t(double d)223 void t(double d) 224 { 225 std::string s = cxxtools::convert<std::string>(d); 226 double r = cxxtools::convert<double>(s); 227 if (r == 0) 228 { 229 CXXTOOLS_UNIT_ASSERT_EQUALS(d, 0); 230 } 231 else 232 { 233 double q = d / r; 234 log_debug("d=" << d << " s=\"" << s << "\" r=" << r << " q=" << q); 235 if (q < 0.999999999999 || q > 1.0000000000001) 236 { 237 CXXTOOLS_UNIT_ASSERT_EQUALS(d, r); 238 } 239 } 240 } 241 floatTest()242 void floatTest() 243 { 244 double d; 245 246 d = cxxtools::convert<double>("1.5"); 247 CXXTOOLS_UNIT_ASSERT_EQUALS(d, 1.5); 248 249 d = cxxtools::convert<double>(" -345.75 "); 250 CXXTOOLS_UNIT_ASSERT_EQUALS(d, -345.75); 251 252 d = cxxtools::convert<double>("\n1e6\r"); 253 CXXTOOLS_UNIT_ASSERT_EQUALS(d, 1e6); 254 255 d = cxxtools::convert<double>("7.0e4"); 256 CXXTOOLS_UNIT_ASSERT_EQUALS(d, 7e4); 257 258 d = cxxtools::convert<double>("-2e-3"); 259 CXXTOOLS_UNIT_ASSERT(nearBy(d, -2e-3)); 260 261 d = cxxtools::convert<double>("-8E-5"); 262 CXXTOOLS_UNIT_ASSERT(nearBy(d, -8e-5)); 263 264 d = cxxtools::convert<double>("-3.0e-12"); 265 CXXTOOLS_UNIT_ASSERT(nearBy(d, -3e-12)); 266 267 d = cxxtools::convert<double>("-8.5E-23"); 268 CXXTOOLS_UNIT_ASSERT(nearBy(d, -8.5e-23)); 269 270 t(3.141592653579893); 271 t(0.314); 272 t(0.0314); 273 t(0.00123); 274 t(123456789.55555555); 275 t(0); 276 t(1); 277 t(1.4567e17); 278 t(12345); 279 t(1.4567e-17); 280 t(0.2); 281 t(12); 282 } 283 284 }; 285 286 cxxtools::unit::RegisterTest<ConvertTest> register_ConvertTest; 287