Line data Source code
1 : // Copyright (c) 2011-2023 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/as2js
4 : // contact@m2osw.com
5 : //
6 : // This program is free software: you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation, either version 3 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License
17 : // along with this program. If not, see <https://www.gnu.org/licenses/>.
18 :
19 : // as2js
20 : //
21 : #include <as2js/string.h>
22 : #include <as2js/exception.h>
23 :
24 :
25 : // self
26 : //
27 : #include "catch_main.h"
28 :
29 :
30 : // C++
31 : //
32 : #include <algorithm>
33 : #include <cstring>
34 : #include <iomanip>
35 :
36 :
37 : // last include
38 : //
39 : #include <snapdev/poison.h>
40 :
41 :
42 :
43 : namespace
44 : {
45 :
46 :
47 :
48 10215 : bool close_double(double a, double b, double epsilon)
49 : {
50 10215 : return a >= b - epsilon && a <= b + epsilon;
51 : }
52 :
53 :
54 :
55 : }
56 : // no name namespace
57 :
58 :
59 :
60 :
61 1 : CATCH_TEST_CASE("string_empty", "[string][type]")
62 : {
63 1 : CATCH_START_SECTION("string: empty string validity")
64 : {
65 : // a little extra test, make sure a string is empty on
66 : // creation without anything
67 : //
68 1 : std::string str1;
69 1 : CATCH_REQUIRE(as2js::valid(str1));
70 1 : }
71 1 : CATCH_END_SECTION()
72 1 : }
73 :
74 :
75 1 : CATCH_TEST_CASE("string_bad_utf8", "[string][type]")
76 : {
77 1 : CATCH_START_SECTION("string: bad UTF-8 sequences")
78 : {
79 : // UTF-8 starts with 0xC0 to 0xF4 and those must be followed by
80 : // 0x80 to 0xBF bytes anything else is incorrect
81 : //
82 54 : for(int i(0xC0); i <= 0xF4; ++i)
83 : {
84 : // too small a number just after 0xA0 to 0xF4
85 : //
86 6784 : for(int j(0x01); j <= 0x7F; ++j)
87 : {
88 6731 : char const buf[3]{
89 : static_cast<char>(i),
90 : static_cast<char>(j),
91 : '\0'
92 6731 : };
93 13462 : std::string const bad_utf8(buf);
94 6731 : CATCH_REQUIRE_FALSE(as2js::valid(bad_utf8));
95 :
96 6731 : std::string const start_string(SNAP_CATCH2_NAMESPACE::random_string(1, 100, SNAP_CATCH2_NAMESPACE::character_t::CHARACTER_ASCII));
97 6731 : std::string const end_string(SNAP_CATCH2_NAMESPACE::random_string(1, 100, SNAP_CATCH2_NAMESPACE::character_t::CHARACTER_ASCII));
98 6731 : CATCH_REQUIRE(as2js::valid(start_string));
99 6731 : CATCH_REQUIRE(as2js::valid(end_string));
100 :
101 : // make sure it gets caught anywhere in a string
102 : //
103 13462 : std::string const complete_string(start_string + bad_utf8 + end_string);
104 6731 : CATCH_REQUIRE_FALSE(as2js::valid(complete_string));
105 6731 : }
106 :
107 : // too large a number just after 0xA0 to 0xFF
108 : //
109 3445 : for(int j(0xC0); j <= 0xFF; ++j)
110 : {
111 3392 : char buf[3]{
112 : static_cast<char>(i),
113 : static_cast<char>(j),
114 : '\0'
115 3392 : };
116 6784 : std::string const bad_utf8(buf);
117 3392 : CATCH_REQUIRE_FALSE(as2js::valid(bad_utf8));
118 :
119 3392 : std::string const start_string(SNAP_CATCH2_NAMESPACE::random_string(1, 100, SNAP_CATCH2_NAMESPACE::character_t::CHARACTER_ASCII));
120 3392 : std::string const end_string(SNAP_CATCH2_NAMESPACE::random_string(1, 100, SNAP_CATCH2_NAMESPACE::character_t::CHARACTER_ASCII));
121 3392 : CATCH_REQUIRE(as2js::valid(start_string));
122 3392 : CATCH_REQUIRE(as2js::valid(end_string));
123 :
124 : // make sure it gets caught anywhere in a string
125 : //
126 6784 : std::string const complete_string(start_string + bad_utf8 + end_string);
127 3392 : CATCH_REQUIRE_FALSE(as2js::valid(complete_string));
128 3392 : }
129 :
130 : // note: the libutf8 already has many tests so I won't check
131 : // every single possibility of invalid UTF-8; if there is
132 : // an issue with such, we should verify with libutf8 instead
133 : }
134 : }
135 1 : CATCH_END_SECTION()
136 1 : }
137 :
138 :
139 3 : CATCH_TEST_CASE("string", "[string][type]")
140 : {
141 3 : CATCH_START_SECTION("string: check valid characters")
142 : {
143 1112065 : for(char32_t c(0); c < 0x110000; ++c)
144 : {
145 : // skip the surrogates at once
146 : //
147 1112064 : if(c == 0xD800)
148 : {
149 1 : c = 0xE000;
150 : }
151 1112064 : CATCH_REQUIRE(as2js::valid_character(c));
152 : }
153 : }
154 3 : CATCH_END_SECTION()
155 :
156 3 : CATCH_START_SECTION("string: check surrogates (not valid UTF-32)")
157 : {
158 2049 : for(char32_t c(0xD800); c < 0xE000; ++c)
159 : {
160 2048 : CATCH_REQUIRE_FALSE(as2js::valid_character(c));
161 : }
162 : }
163 3 : CATCH_END_SECTION()
164 :
165 3 : CATCH_START_SECTION("string: check outside range (not valid UTF-32)")
166 : {
167 1001 : for(int i(0); i < 1000; ++i)
168 : {
169 1000 : char32_t c(0);
170 : do
171 : {
172 1000 : SNAP_CATCH2_NAMESPACE::random(c);
173 : }
174 1000 : while(c < 0x110000);
175 1000 : CATCH_REQUIRE_FALSE(as2js::valid_character(c));
176 : }
177 : }
178 3 : CATCH_END_SECTION()
179 3 : }
180 :
181 :
182 9 : CATCH_TEST_CASE("string_number", "[string][type][number]")
183 : {
184 9 : CATCH_START_SECTION("string_number: empty string is 0, 0.0, and false")
185 : {
186 1 : std::string str;
187 1 : CATCH_REQUIRE(as2js::is_integer(str));
188 1 : CATCH_REQUIRE(as2js::is_floating_point(str));
189 1 : CATCH_REQUIRE(as2js::is_number(str));
190 1 : CATCH_REQUIRE(as2js::to_integer(str) == 0);
191 : #pragma GCC diagnostic push
192 : #pragma GCC diagnostic ignored "-Wfloat-equal"
193 1 : bool const is_equal(as2js::to_floating_point(str) == 0.0);
194 : #pragma GCC diagnostic pop
195 1 : CATCH_REQUIRE(is_equal);
196 1 : CATCH_REQUIRE_FALSE(as2js::is_true(str));
197 1 : }
198 9 : CATCH_END_SECTION()
199 :
200 9 : CATCH_START_SECTION("string_number: a period alone is not a floating point number")
201 : {
202 2 : std::string str(".");
203 1 : CATCH_REQUIRE_FALSE(as2js::is_integer(str));
204 1 : CATCH_REQUIRE_FALSE(as2js::is_floating_point(str));
205 1 : CATCH_REQUIRE_FALSE(as2js::is_number(str));
206 1 : CATCH_REQUIRE(as2js::is_true(str));
207 1 : }
208 9 : CATCH_END_SECTION()
209 :
210 9 : CATCH_START_SECTION("string_number: no integral part means not a floating point")
211 : {
212 2 : std::string str("xyz");
213 1 : CATCH_REQUIRE_FALSE(as2js::is_integer(str));
214 1 : CATCH_REQUIRE_FALSE(as2js::is_floating_point(str));
215 1 : CATCH_REQUIRE_FALSE(as2js::is_number(str));
216 1 : CATCH_REQUIRE(as2js::is_true(str));
217 1 : }
218 9 : CATCH_END_SECTION()
219 :
220 9 : CATCH_START_SECTION("string_number: an exponent must be followed by a number")
221 : {
222 2 : std::string str("31.4159e");
223 1 : CATCH_REQUIRE_FALSE(as2js::is_integer(str));
224 1 : CATCH_REQUIRE_FALSE(as2js::is_floating_point(str));
225 1 : CATCH_REQUIRE_FALSE(as2js::is_number(str));
226 1 : CATCH_REQUIRE(as2js::is_true(str));
227 :
228 : // adding a sign is not enough
229 : //
230 1 : str += '+';
231 1 : CATCH_REQUIRE_FALSE(as2js::is_integer(str));
232 1 : CATCH_REQUIRE_FALSE(as2js::is_floating_point(str));
233 1 : CATCH_REQUIRE_FALSE(as2js::is_number(str));
234 1 : CATCH_REQUIRE(as2js::is_true(str));
235 :
236 1 : str[str.length() - 1] = '-';
237 1 : CATCH_REQUIRE_FALSE(as2js::is_integer(str));
238 1 : CATCH_REQUIRE_FALSE(as2js::is_floating_point(str));
239 1 : CATCH_REQUIRE_FALSE(as2js::is_number(str));
240 1 : CATCH_REQUIRE(as2js::is_true(str));
241 1 : }
242 9 : CATCH_END_SECTION()
243 :
244 9 : CATCH_START_SECTION("string_number: 0x and 0X are not hexadecimal numbers")
245 : {
246 : {
247 2 : std::string str("0x");
248 1 : CATCH_REQUIRE_FALSE(as2js::is_integer(str));
249 1 : CATCH_REQUIRE_FALSE(as2js::is_floating_point(str));
250 1 : CATCH_REQUIRE_FALSE(as2js::is_number(str));
251 1 : CATCH_REQUIRE_THROWS_MATCHES(
252 : as2js::to_integer(str)
253 : , as2js::internal_error
254 : , Catch::Matchers::ExceptionMessage(
255 : "internal_error: to_integer(std::string const & s) called with an invalid integer."));
256 1 : CATCH_REQUIRE(std::isnan(as2js::to_floating_point(str)));
257 1 : CATCH_REQUIRE(as2js::is_true(str));
258 1 : }
259 :
260 : {
261 2 : std::string str("0X");
262 1 : CATCH_REQUIRE_FALSE(as2js::is_integer(str));
263 1 : CATCH_REQUIRE_FALSE(as2js::is_floating_point(str));
264 1 : CATCH_REQUIRE_FALSE(as2js::is_number(str));
265 1 : CATCH_REQUIRE_THROWS_MATCHES(
266 : as2js::to_integer(str)
267 : , as2js::internal_error
268 : , Catch::Matchers::ExceptionMessage(
269 : "internal_error: to_integer(std::string const & s) called with an invalid integer."));
270 1 : CATCH_REQUIRE(std::isnan(as2js::to_floating_point(str)));
271 1 : CATCH_REQUIRE(as2js::is_true(str));
272 1 : }
273 : }
274 9 : CATCH_END_SECTION()
275 :
276 9 : CATCH_START_SECTION("string_number: integers -100,000 to +100,000")
277 : {
278 200002 : for(int64_t i(-100'000); i <= 100'000; ++i)
279 : {
280 : // decimal
281 : {
282 200001 : std::stringstream ss;
283 200001 : ss << (i >= 0 && (rand() & 1) ? "+" : "") << i;
284 200001 : std::string str(ss.str());
285 200001 : CATCH_REQUIRE(as2js::is_integer(str));
286 200001 : CATCH_REQUIRE(as2js::is_floating_point(str));
287 200001 : CATCH_REQUIRE(as2js::is_number(str));
288 200001 : CATCH_REQUIRE(as2js::to_integer(str) == i);
289 : #pragma GCC diagnostic push
290 : #pragma GCC diagnostic ignored "-Wfloat-equal"
291 200001 : bool const is_equal(as2js::to_floating_point(str) == static_cast<double>(i));
292 : #pragma GCC diagnostic pop
293 200001 : CATCH_REQUIRE(is_equal);
294 200001 : CATCH_REQUIRE(as2js::is_true(str));
295 200001 : }
296 :
297 : // hexadecimal
298 : {
299 : // not that in C/C++ hexadecimal numbers cannot really be
300 : // negative; in JavaScript it's fine
301 : //
302 200001 : std::stringstream ss;
303 200001 : ss << (i < 0 ? "-" : (rand() & 1 ? "+" : "")) << "0" << (rand() & 1 ? "x" : "X") << std::hex << labs(i);
304 200001 : std::string const str(ss.str());
305 200001 : CATCH_REQUIRE(as2js::is_integer(str));
306 200001 : CATCH_REQUIRE_FALSE(as2js::is_floating_point(str));
307 200001 : CATCH_REQUIRE(as2js::is_number(str));
308 200001 : CATCH_REQUIRE(as2js::to_integer(str) == i);
309 200001 : CATCH_REQUIRE(std::isnan(as2js::to_floating_point(str)));
310 200001 : CATCH_REQUIRE(as2js::is_true(str));
311 200001 : }
312 : }
313 : }
314 9 : CATCH_END_SECTION()
315 :
316 9 : CATCH_START_SECTION("string_number: floating points")
317 : {
318 3406 : for(double i(-1000.00); i <= 1000.00; i += (rand() % 120) / 100.0)
319 : {
320 3405 : std::stringstream ss;
321 3405 : ss << i;
322 6810 : if(ss.str().find('e') != std::string::npos
323 6810 : || ss.str().find('E') != std::string::npos)
324 : {
325 : // this happens with numbers very close to zero and the
326 : // system decides to write them as '1e-12' for example
327 : //
328 : continue; // LCOV_EXCL_LINE -- does not matter if it does not happen
329 : }
330 3405 : std::string const str1(ss.str());
331 3405 : std::int64_t const integer1(lrint(i));
332 3405 : bool const is_integer1(std::find(str1.cbegin(), str1.cend(), '.') == str1.cend());
333 :
334 3405 : CATCH_REQUIRE(as2js::is_integer(str1) == is_integer1);
335 3405 : CATCH_REQUIRE(as2js::is_floating_point(str1));
336 3405 : CATCH_REQUIRE(as2js::is_number(str1));
337 3405 : CATCH_REQUIRE(as2js::is_true(str1));
338 3405 : if(is_integer1)
339 : {
340 25 : CATCH_REQUIRE(as2js::to_integer(str1) == integer1);
341 : }
342 : else
343 : {
344 3380 : CATCH_REQUIRE_THROWS_MATCHES(
345 : as2js::to_integer(str1)
346 : , as2js::internal_error
347 : , Catch::Matchers::ExceptionMessage(
348 : "internal_error: to_integer(std::string const & s) called with an invalid integer."));
349 : }
350 3405 : CATCH_REQUIRE(close_double(as2js::to_floating_point(str1), i, 0.01));
351 :
352 : // add x 1000 as an exponent
353 3405 : ss << "e" << ((rand() & 1) != 0 ? "+" : "") << "3";
354 3405 : std::string const str2(ss.str());
355 : // the 'e' "breaks" the integer test in JavaScript
356 3405 : CATCH_REQUIRE_FALSE(as2js::is_integer(str2));
357 3405 : CATCH_REQUIRE(as2js::is_floating_point(str2));
358 3405 : CATCH_REQUIRE(as2js::is_number(str2));
359 3405 : CATCH_REQUIRE(as2js::is_true(str2));
360 3405 : CATCH_REQUIRE_THROWS_MATCHES(
361 : as2js::to_integer(str2)
362 : , as2js::internal_error
363 : , Catch::Matchers::ExceptionMessage(
364 : "internal_error: to_integer(std::string const & s) called with an invalid integer."));
365 3405 : CATCH_REQUIRE(close_double(as2js::to_floating_point(str2), i * 1000.0, 0.01));
366 :
367 : // add / 1000 as an exponent
368 3405 : ss.str(""); // reset the string
369 3405 : ss << i << "e-3";
370 3405 : std::string const str3(ss.str());
371 : // the 'e' "breaks" the integer test in JavaScript
372 3405 : CATCH_REQUIRE_FALSE(as2js::is_integer(str3));
373 3405 : CATCH_REQUIRE(as2js::is_floating_point(str3));
374 3405 : CATCH_REQUIRE(as2js::is_number(str3));
375 3405 : CATCH_REQUIRE(as2js::is_true(str3));
376 3405 : CATCH_REQUIRE_THROWS_MATCHES(
377 : as2js::to_integer(str3)
378 : , as2js::internal_error
379 : , Catch::Matchers::ExceptionMessage(
380 : "internal_error: to_integer(std::string const & s) called with an invalid integer."));
381 3405 : CATCH_REQUIRE(close_double(as2js::to_floating_point(str3), i / 1000.0, 0.00001));
382 3405 : }
383 : }
384 9 : CATCH_END_SECTION()
385 :
386 9 : CATCH_START_SECTION("string_number: random 64 bits integers")
387 : {
388 : // a few more using random
389 100001 : for(int i(0); i < 100000; ++i)
390 : {
391 100000 : std::int64_t value(0);
392 100000 : SNAP_CATCH2_NAMESPACE::random(value);
393 100000 : std::stringstream ss;
394 100000 : ss << value;
395 100000 : std::string const str(ss.str());
396 100000 : CATCH_REQUIRE(as2js::is_integer(str));
397 100000 : CATCH_REQUIRE(as2js::is_floating_point(str));
398 100000 : CATCH_REQUIRE(as2js::is_number(str));
399 100000 : CATCH_REQUIRE(as2js::is_true(str));
400 100000 : CATCH_REQUIRE(as2js::to_integer(str) == value);
401 :
402 : // this is important since double mantissa is only 52 bits
403 : // and here our integral numbers are 64 bits
404 : //
405 100000 : as2js::floating_point const flt1(as2js::to_floating_point(str));
406 100000 : as2js::floating_point const flt2(static_cast<as2js::floating_point::value_type>(value));
407 100000 : CATCH_REQUIRE(flt1.nearly_equal(flt2, 0.0001));
408 100000 : CATCH_REQUIRE(flt2.nearly_equal(flt1, 0.0001));
409 100000 : }
410 : }
411 9 : CATCH_END_SECTION()
412 :
413 9 : CATCH_START_SECTION("string_number: NULL value")
414 : {
415 : // test a few non-hexadecimal numbers
416 : //
417 101 : for(int i(0); i < 100; ++i)
418 : {
419 : // get a character which is not a valid hex digit and not '\0'
420 : // and not 0x7F (Del)
421 : //
422 : char c;
423 : do
424 : {
425 114 : c = static_cast<char>(rand() % 0x7D + 1);
426 : }
427 61 : while((c >= '0' && c <= '9')
428 107 : || (c >= 'a' && c <= 'f')
429 217 : || (c >= 'A' && c <= 'F'));
430 :
431 : // bad character is right at the beginning of the hex number
432 100 : std::stringstream ss1;
433 100 : ss1 << "0" << (rand() & 1 ? "x" : "X") << c << "123ABC";
434 100 : std::string str1(ss1.str());
435 100 : CATCH_REQUIRE_FALSE(as2js::is_integer(str1));
436 100 : CATCH_REQUIRE_FALSE(as2js::is_floating_point(str1));
437 100 : CATCH_REQUIRE_FALSE(as2js::is_number(str1));
438 100 : CATCH_REQUIRE(as2js::is_true(str1));
439 100 : CATCH_REQUIRE_THROWS_MATCHES(
440 : as2js::to_integer(str1)
441 : , as2js::internal_error
442 : , Catch::Matchers::ExceptionMessage(
443 : "internal_error: to_integer(std::string const & s) called with an invalid integer."));
444 100 : CATCH_REQUIRE(std::isnan(as2js::to_floating_point(str1)));
445 :
446 : // invalid character is in the middle of the hex number
447 : //
448 100 : std::stringstream ss2;
449 100 : ss2 << "0" << (rand() & 1 ? "x" : "X") << "123" << c << "ABC";
450 100 : std::string str2(ss2.str());
451 100 : CATCH_REQUIRE_FALSE(as2js::is_integer(str2));
452 100 : CATCH_REQUIRE_FALSE(as2js::is_floating_point(str2));
453 100 : CATCH_REQUIRE_FALSE(as2js::is_number(str2));
454 100 : CATCH_REQUIRE(as2js::is_true(str2));
455 100 : CATCH_REQUIRE_THROWS_MATCHES(
456 : as2js::to_integer(str2)
457 : , as2js::internal_error
458 : , Catch::Matchers::ExceptionMessage(
459 : "internal_error: to_integer(std::string const & s) called with an invalid integer."));
460 100 : CATCH_REQUIRE(std::isnan(as2js::to_floating_point(str2)));
461 :
462 : // invalid character is at the very end of the hex number
463 : //
464 100 : std::stringstream ss3;
465 100 : ss3 << "0" << (rand() & 1 ? "x" : "X") << "123ABC" << c;
466 100 : std::string str3(ss3.str());
467 100 : CATCH_REQUIRE_FALSE(as2js::is_integer(str3));
468 100 : CATCH_REQUIRE_FALSE(as2js::is_floating_point(str3));
469 100 : CATCH_REQUIRE_FALSE(as2js::is_number(str3));
470 100 : CATCH_REQUIRE(as2js::is_true(str3));
471 100 : CATCH_REQUIRE_THROWS_MATCHES(
472 : as2js::to_integer(str3)
473 : , as2js::internal_error
474 : , Catch::Matchers::ExceptionMessage(
475 : "internal_error: to_integer(std::string const & s) called with an invalid integer."));
476 100 : CATCH_REQUIRE(std::isnan(as2js::to_floating_point(str3)));
477 100 : }
478 : }
479 9 : CATCH_END_SECTION()
480 9 : }
481 :
482 :
483 17 : CATCH_TEST_CASE("string_simplify", "[string][type]")
484 : {
485 17 : CATCH_START_SECTION("string_simplify: starting spaces")
486 : {
487 2 : std::string const str(" blah");
488 1 : std::string const simplified(as2js::simplify(str));
489 1 : CATCH_REQUIRE(simplified == "blah");
490 1 : }
491 17 : CATCH_END_SECTION()
492 :
493 17 : CATCH_START_SECTION("string_simplify: ending spaces")
494 : {
495 2 : std::string const str("blah ");
496 1 : std::string const simplified(as2js::simplify(str));
497 1 : CATCH_REQUIRE(simplified == "blah");
498 1 : }
499 17 : CATCH_END_SECTION()
500 :
501 17 : CATCH_START_SECTION("string_simplify: starting & ending spaces")
502 : {
503 2 : std::string const str(" blah ");
504 1 : std::string const simplified(as2js::simplify(str));
505 1 : CATCH_REQUIRE(simplified == "blah");
506 1 : }
507 17 : CATCH_END_SECTION()
508 :
509 17 : CATCH_START_SECTION("string_simplify: inside spaces")
510 : {
511 2 : std::string const str("blah foo");
512 1 : std::string const simplified(as2js::simplify(str));
513 1 : CATCH_REQUIRE(simplified == "blah foo");
514 1 : }
515 17 : CATCH_END_SECTION()
516 :
517 17 : CATCH_START_SECTION("string_simplify: simplify starting, inside, and ending spaces")
518 : {
519 2 : std::string const str(" blah foo ");
520 1 : std::string const simplified(as2js::simplify(str));
521 1 : CATCH_REQUIRE(simplified == "blah foo");
522 1 : }
523 17 : CATCH_END_SECTION()
524 :
525 17 : CATCH_START_SECTION("string_simplify: simplify spaces including newlines")
526 : {
527 2 : std::string const str("blah \n foo");
528 1 : std::string const simplified(as2js::simplify(str));
529 1 : CATCH_REQUIRE(simplified == "blah foo");
530 1 : }
531 17 : CATCH_END_SECTION()
532 :
533 17 : CATCH_START_SECTION("string_simplify: empty string becomes zero")
534 : {
535 1 : std::string const str;
536 1 : std::string const simplified(as2js::simplify(str));
537 1 : CATCH_REQUIRE(simplified == "0");
538 1 : }
539 17 : CATCH_END_SECTION()
540 :
541 17 : CATCH_START_SECTION("string_simplify: spaces only string becomes zero")
542 : {
543 2 : std::string const str(" ");
544 1 : std::string const simplified(as2js::simplify(str));
545 1 : CATCH_REQUIRE(simplified == "0");
546 1 : }
547 17 : CATCH_END_SECTION()
548 :
549 17 : CATCH_START_SECTION("string_simplify: simplify number with spaces around")
550 : {
551 2 : std::string const str(" 3.14159 ");
552 1 : std::string const simplified(as2js::simplify(str));
553 1 : CATCH_REQUIRE(simplified == "3.14159");
554 1 : CATCH_REQUIRE_FALSE(as2js::is_integer(simplified));
555 1 : CATCH_REQUIRE(as2js::is_floating_point(simplified));
556 1 : CATCH_REQUIRE(as2js::is_number(simplified));
557 1 : CATCH_REQUIRE(as2js::floating_point(as2js::to_floating_point(simplified)).nearly_equal(3.14159, 1.0e-8));
558 1 : }
559 17 : CATCH_END_SECTION()
560 :
561 17 : CATCH_START_SECTION("string_simplify: simplify number with left over")
562 : {
563 2 : std::string const str(" 3.14159 ignore that part ");
564 1 : std::string const simplified(as2js::simplify(str));
565 1 : CATCH_REQUIRE(simplified == "3.14159");
566 1 : CATCH_REQUIRE_FALSE(as2js::is_integer(simplified));
567 1 : CATCH_REQUIRE(as2js::is_floating_point(simplified));
568 1 : CATCH_REQUIRE(as2js::is_number(simplified));
569 1 : CATCH_REQUIRE(as2js::floating_point(as2js::to_floating_point(simplified)).nearly_equal(3.14159, 1.0e-8));
570 1 : }
571 17 : CATCH_END_SECTION()
572 :
573 17 : CATCH_START_SECTION("string_simplify: simplify positive number with left over")
574 : {
575 2 : std::string const str(" +3.14159 ignore that part ");
576 1 : std::string const simplified(as2js::simplify(str));
577 1 : CATCH_REQUIRE(simplified == "+3.14159");
578 1 : CATCH_REQUIRE(as2js::is_floating_point(simplified));
579 1 : CATCH_REQUIRE(as2js::is_number(simplified));
580 1 : CATCH_REQUIRE(as2js::floating_point(as2js::to_floating_point(simplified)).nearly_equal(3.14159, 1.0e-8));
581 1 : }
582 17 : CATCH_END_SECTION()
583 :
584 17 : CATCH_START_SECTION("string_simplify: simplify negative integer with left over")
585 : {
586 2 : std::string const str(" -314159 ignore that part ");
587 1 : std::string const simplified(as2js::simplify(str));
588 1 : CATCH_REQUIRE(simplified == "-314159");
589 1 : CATCH_REQUIRE(as2js::is_integer(simplified));
590 1 : CATCH_REQUIRE(as2js::to_integer(simplified) == -314159);
591 1 : CATCH_REQUIRE(as2js::is_floating_point(simplified));
592 1 : CATCH_REQUIRE(as2js::is_number(simplified));
593 1 : CATCH_REQUIRE(as2js::floating_point(as2js::to_floating_point(simplified)).nearly_equal(-314159.0, 1.0e-8));
594 1 : }
595 17 : CATCH_END_SECTION()
596 :
597 17 : CATCH_START_SECTION("string_simplify: simplify the positive number with exponent and left over")
598 : {
599 2 : std::string const str(" +0.00314159e3 ignore that part ");
600 1 : std::string const simplified(as2js::simplify(str));
601 1 : CATCH_REQUIRE(simplified == "+0.00314159e3");
602 1 : CATCH_REQUIRE(as2js::is_floating_point(simplified));
603 1 : CATCH_REQUIRE(as2js::is_number(simplified));
604 1 : CATCH_REQUIRE(as2js::floating_point(as2js::to_floating_point(simplified)).nearly_equal(3.14159, 1e-8));
605 1 : }
606 17 : CATCH_END_SECTION()
607 :
608 17 : CATCH_START_SECTION("string_simplify: simplify the positive number with positive exponent and left over")
609 : {
610 2 : std::string const str(" +0.00314159e+3 ignore that part ");
611 1 : std::string const simplified(as2js::simplify(str));
612 1 : CATCH_REQUIRE(simplified == "+0.00314159e+3");
613 1 : CATCH_REQUIRE(as2js::is_floating_point(simplified));
614 1 : CATCH_REQUIRE(as2js::is_number(simplified));
615 1 : CATCH_REQUIRE(as2js::floating_point(as2js::to_floating_point(simplified)).nearly_equal(3.14159, 1e-8));
616 1 : }
617 17 : CATCH_END_SECTION()
618 :
619 17 : CATCH_START_SECTION("string_simplify: simplify the negative number with negative exponent and left over")
620 : {
621 2 : std::string const str(" -314159e-5 ignore that part ");
622 1 : std::string const simplified(as2js::simplify(str));
623 1 : CATCH_REQUIRE(simplified == "-314159");
624 1 : CATCH_REQUIRE(as2js::is_integer(simplified));
625 1 : CATCH_REQUIRE(as2js::to_integer(simplified) == -314159);
626 1 : CATCH_REQUIRE(as2js::is_floating_point(simplified));
627 1 : CATCH_REQUIRE(as2js::is_number(simplified));
628 1 : CATCH_REQUIRE(as2js::floating_point(as2js::to_floating_point(simplified)).nearly_equal(-314159, 1e-8));
629 1 : }
630 17 : CATCH_END_SECTION()
631 :
632 17 : CATCH_START_SECTION("string_simplify: simplify negative number with negative exponent and left over")
633 : {
634 2 : std::string str(" -314159.e-5 ignore that part ");
635 1 : std::string simplified(as2js::simplify(str));
636 1 : CATCH_REQUIRE(simplified == "-314159.e-5");
637 1 : CATCH_REQUIRE(as2js::is_floating_point(simplified));
638 1 : CATCH_REQUIRE(as2js::is_number(simplified));
639 1 : CATCH_REQUIRE(as2js::floating_point(as2js::to_floating_point(simplified)).nearly_equal(-3.14159, 1e-8));
640 1 : }
641 17 : CATCH_END_SECTION()
642 :
643 17 : CATCH_START_SECTION("string_simplify: simplify negative number with large negative exponent and left over")
644 : {
645 2 : std::string str(" -314159.0e-105ignorethatpart");
646 1 : std::string simplified(as2js::simplify(str));
647 1 : CATCH_REQUIRE(simplified == "-314159.0e-105");
648 1 : CATCH_REQUIRE(as2js::is_floating_point(simplified));
649 1 : CATCH_REQUIRE(as2js::is_number(simplified));
650 1 : CATCH_REQUIRE(as2js::floating_point(as2js::to_floating_point(simplified)).nearly_equal(-3.14159e-100, 1e-8));
651 1 : }
652 17 : CATCH_END_SECTION()
653 17 : }
654 :
655 :
656 :
657 : // vim: ts=4 sw=4 et
|